From 59a040e56ef5420903ae848e1e70f042a3583640 Mon Sep 17 00:00:00 2001 From: SpliiT Date: Mon, 18 May 2026 17:23:00 +0200 Subject: [PATCH 01/24] feat(ContextMenu): New multiple context menu system --- app/components/Viewer/ContextMenu.vue | 165 +++++++++++++++++- app/components/Viewer/ContextMenuItem.vue | 116 +++++++++++-- app/components/Viewer/Ui.vue | 193 +++++++++++++++++++++- app/composables/project_manager.js | 160 +++++++++--------- app/composables/use_adaptive_styles.js | 28 +++- internal/stores/hybrid_viewer.js | 6 + 6 files changed, 567 insertions(+), 101 deletions(-) diff --git a/app/components/Viewer/ContextMenu.vue b/app/components/Viewer/ContextMenu.vue index 8fece88a9..36eabe4c7 100644 --- a/app/components/Viewer/ContextMenu.vue +++ b/app/components/Viewer/ContextMenu.vue @@ -1,6 +1,8 @@ @@ -181,6 +235,69 @@ function getItemStyle(index) { :style="getItemStyle(index)" @mousedown.stop /> + + + + + + + + +
+ +
+ {{ meta_data.geode_object_type }} +
+
+ {{ meta_data.name || "Unnamed Object" }} +
+
+ ID: {{ meta_data.id }} +
+
+
+
@@ -200,6 +317,8 @@ function getItemStyle(index) { height: 100%; border-radius: 50%; cursor: grab; + user-select: none; + -webkit-user-select: none; } .circular-menu-drag-handle:active { @@ -221,4 +340,46 @@ function getItemStyle(index) { transform-origin: center; will-change: transform, opacity; } + +.central-selector-btn { + background: transparent !important; + border: 2px solid rgba(var(--v-theme-primary), 0.35) !important; + position: relative; + overflow: hidden; + transition: all 0.2s ease; +} + +.central-selector-btn::before { + content: ""; + position: absolute; + inset: 0; + background: rgba(255, 255, 255, var(--adaptive-opacity)); + backdrop-filter: blur(var(--adaptive-blur)) + brightness(var(--adaptive-brightness)); + -webkit-backdrop-filter: blur(var(--adaptive-blur)) + brightness(var(--adaptive-brightness)); + z-index: 0; + pointer-events: none; + border-radius: inherit; + transition: + background-color 0.2s ease, + backdrop-filter 0.2s ease; +} + +.central-selector-btn:hover { + transform: scale(1.08); + border-color: rgba(var(--v-theme-primary), 0.85) !important; +} + +.central-selector-btn:hover::before { + background: rgba(255, 255, 255, calc(var(--adaptive-opacity, 0.15) + 0.15)); +} + +.object-name-popover { + position: absolute; + bottom: 110px; + left: 50%; + transform: translateX(-50%); + z-index: 10; +} diff --git a/app/components/Viewer/ContextMenuItem.vue b/app/components/Viewer/ContextMenuItem.vue index cc3e12197..c71e07ae6 100644 --- a/app/components/Viewer/ContextMenuItem.vue +++ b/app/components/Viewer/ContextMenuItem.vue @@ -2,7 +2,6 @@ import GlassCard from "@ogw_front/components/GlassCard"; import { useMenuStore } from "@ogw_front/stores/menu"; import { useTheme } from "vuetify"; - const CARD_WIDTH = 320; const CARD_HEIGHT = 500; const MARGIN = 60; @@ -12,6 +11,9 @@ const OFFSET = 40; const menuStore = useMenuStore(); const theme = useTheme(); const primaryColor = computed(() => theme.current.value.colors.primary); + +import { useAdaptiveStyles } from "@ogw_front/composables/use_adaptive_styles"; + const { index, itemProps, tooltip, btn_image } = defineProps({ index: { type: Number, required: true }, itemProps: { type: Object, required: true }, @@ -19,11 +21,51 @@ const { index, itemProps, tooltip, btn_image } = defineProps({ btn_image: { type: String, required: true }, }); +const buttonCoords = computed(() => { + const angle = (index / itemProps.totalItems) * 2 * Math.PI; + const dx = Math.cos(angle) * RADIUS; + const dy = Math.sin(angle) * RADIUS; + const size = 40; + return { + x: menuStore.containerLeft + menuStore.menuX + dx - size / 2, + y: menuStore.containerTop + menuStore.menuY + dy - size / 2, + width: size, + height: size, + }; +}); + +const { adaptiveStyles } = useAdaptiveStyles(buttonCoords); + +import { useTreeviewStore } from "@ogw_front/stores/treeview"; + +const treeviewStore = useTreeviewStore(); +const isOverTreeview = computed(() => { + const hasAdditional = treeviewStore.opened_views.some(v => v.id !== "main"); + const hasMain = treeviewStore.opened_views.some(v => v.id === "main"); + const firstColWidth = hasMain ? treeviewStore.panelWidth : 0; + const secondColWidth = hasAdditional ? treeviewStore.additionalPanelWidth : 0; + const treeviewWidth = 10 + 48 + firstColWidth + secondColWidth + 20; + return buttonCoords.value.x < treeviewWidth; +}); + +const computedItemStyles = computed(() => { + if (isOverTreeview.value) { + return { + "--adaptive-blur": "15px", + "--adaptive-opacity": 0.85, + "--adaptive-brightness": 1.15, + }; + } + return adaptiveStyles.value; +}); + const is_active = computed(() => menuStore.active_item_index === index); const optionsRef = ref(undefined); const { height: optionsHeight } = useElementSize(optionsRef); -const maxCardHeight = computed(() => Math.min(CARD_HEIGHT, menuStore.containerHeight - OFFSET)); +const maxCardHeight = computed(() => + Math.min(CARD_HEIGHT, menuStore.containerHeight - OFFSET), +); const optionsStyle = computed(() => { if (!is_active.value || !optionsHeight.value) { @@ -38,8 +80,12 @@ const optionsStyle = computed(() => { if (absoluteButtonY - height / 2 < margin) { offsetY = margin - (absoluteButtonY - height / 2); - } else if (absoluteButtonY + height / 2 > menuStore.containerHeight - margin) { - offsetY = menuStore.containerHeight - margin - (absoluteButtonY + height / 2); + } else if ( + absoluteButtonY + height / 2 > + menuStore.containerHeight - margin + ) { + offsetY = + menuStore.containerHeight - margin - (absoluteButtonY + height / 2); } return { top: `calc(50% + ${offsetY}px)` }; }); @@ -49,11 +95,14 @@ const optionsClass = computed(() => { const margin = MARGIN; const radius = RADIUS; if (loc === "right") { - return menuStore.menuX + radius + margin + CARD_WIDTH > menuStore.containerWidth + return menuStore.menuX + radius + margin + CARD_WIDTH > + menuStore.containerWidth ? "options-left" : "options-right"; } - return menuStore.menuX - radius - margin - CARD_WIDTH < 0 ? "options-right" : "options-left"; + return menuStore.menuX - radius - margin - CARD_WIDTH < 0 + ? "options-right" + : "options-left"; }); function toggleOptions() { @@ -62,17 +111,28 @@ function toggleOptions() {