From 930cbf5a18f5e44199bc10c18bc804c859a43a82 Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Sun, 1 Mar 2026 13:42:01 +0100 Subject: [PATCH] frontend: add item tooltip, refactor with itemicon component --- frontend/assets/css/main.css | 1 + frontend/components/build/ItemRow.vue | 49 +--- frontend/components/item/Box.vue | 49 ---- frontend/components/item/ItemIcon.vue | 137 +++++++++ frontend/components/item/ItemTooltip.vue | 349 +++++++++++++++++++++++ frontend/components/item/Tree.vue | 87 +++--- frontend/types/cdragon.ts | 6 + 7 files changed, 536 insertions(+), 142 deletions(-) delete mode 100644 frontend/components/item/Box.vue create mode 100644 frontend/components/item/ItemIcon.vue create mode 100644 frontend/components/item/ItemTooltip.vue diff --git a/frontend/assets/css/main.css b/frontend/assets/css/main.css index 6f37358..8049550 100644 --- a/frontend/assets/css/main.css +++ b/frontend/assets/css/main.css @@ -4,6 +4,7 @@ --color-surface: #312e2c; --color-on-surface: #b7b8e1; --color-surface-darker: #1f1d1c; + --color-gold: #ffd700; } /* Font setting */ diff --git a/frontend/components/build/ItemRow.vue b/frontend/components/build/ItemRow.vue index 2518a57..ba452cf 100644 --- a/frontend/components/build/ItemRow.vue +++ b/frontend/components/build/ItemRow.vue @@ -1,6 +1,4 @@ - - - - diff --git a/frontend/components/item/ItemIcon.vue b/frontend/components/item/ItemIcon.vue new file mode 100644 index 0000000..80af69d --- /dev/null +++ b/frontend/components/item/ItemIcon.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/frontend/components/item/ItemTooltip.vue b/frontend/components/item/ItemTooltip.vue new file mode 100644 index 0000000..2183d51 --- /dev/null +++ b/frontend/components/item/ItemTooltip.vue @@ -0,0 +1,349 @@ + + + + + diff --git a/frontend/components/item/Tree.vue b/frontend/components/item/Tree.vue index 237e05e..8a471b2 100644 --- a/frontend/components/item/Tree.vue +++ b/frontend/components/item/Tree.vue @@ -12,20 +12,16 @@ const emit = defineEmits<{ parentReady: [] }>() -const { data: items, pending: itemsLoading } = useFetch>( - '/api/cdragon/items', - { - lazy: true, // Don't block rendering - server: false // Client-side only - } -) +const { data: items, pending: itemsLoading } = useFetch>('/api/cdragon/items', { + lazy: true, // Don't block rendering + server: false // Client-side only +}) // Track image loading state const imagesLoaded = ref(false) -const imageElement: Ref = ref(null) // Create item map reactively -const itemMap = reactive(new Map()) +const itemMap = reactive(new Map()) watch( items, newItems => { @@ -39,15 +35,13 @@ watch( { immediate: true } ) -function getItemIconPath(itemId: number): string { - const item = itemMap.get(itemId) - return item ? CDRAGON_BASE + mapPath(item.iconPath) : '' -} - -const start: Ref = useTemplateRef('start') +const startTreeItem = useTemplateRef('start') const arrows: Array = [] const pendingChildMounts: Array = [] +// Get the actual icon element for arrow drawing +const startElement = computed(() => startTreeItem.value?.iconElement ?? null) + // Function to wait for an image to load function waitForImageLoad(imgElement: HTMLImageElement): Promise { return new Promise(resolve => { @@ -91,12 +85,12 @@ onMounted(async () => { } }) - if (start.value) { - const imgElement = start.value as HTMLImageElement - imageElement.value = imgElement - - // Wait for own image to load - await waitForImageLoad(imgElement) + if (startElement.value) { + // Wait for the ItemIcon to load its image + const imgElement = startElement.value.querySelector('img') + if (imgElement) { + await waitForImageLoad(imgElement as HTMLImageElement) + } // Now that image is loaded and DOM is ready, draw arrows imagesLoaded.value = true @@ -108,7 +102,7 @@ onMounted(async () => { if (pendingChildMounts.length > 0) { await nextTick() for (const childEnd of pendingChildMounts) { - drawArrow(start.value!, childEnd) + drawArrow(startElement.value!, childEnd) } pendingChildMounts.length = 0 } @@ -117,7 +111,7 @@ onMounted(async () => { requestAnimationFrame(() => { requestAnimationFrame(() => { refreshArrows() - emit('mount', start.value!) + emit('mount', startElement.value!) }) }) } @@ -133,12 +127,12 @@ onBeforeUpdate(() => { onUpdated(async () => { await nextTick() - if (start.value && imagesLoaded.value) { + if (startElement.value && imagesLoaded.value) { // Redraw arrows after DOM update requestAnimationFrame(() => { requestAnimationFrame(() => { refreshArrows() - emit('mount', start.value!) + emit('mount', startElement.value!) }) }) } @@ -168,7 +162,7 @@ function drawArrow(start: Element, end: Element) { left: 0 } }, - style: 'stroke:var(--color-on-surface);stroke-width:2;fill:transparent;', + style: 'stroke:var(--color-on-surface);stroke-width:2;fill:transparent;pointer-events:none;', appendTo: document.body }) arrows.push(arrow) @@ -194,12 +188,12 @@ addEventListener('scroll', _ => { }) function handleSubtreeMount(end: Element) { - if (start.value) { + if (startElement.value) { if (imagesLoaded.value) { // Parent is ready, draw arrow immediately requestAnimationFrame(() => { requestAnimationFrame(() => { - drawArrow(start.value!, end) + drawArrow(startElement.value!, end) refreshArrows() }) }) @@ -213,7 +207,7 @@ function handleSubtreeMount(end: Element) { function handleParentReady() { // Parent became ready, redraw all our arrows - if (start.value && imagesLoaded.value) { + if (startElement.value && imagesLoaded.value) { requestAnimationFrame(() => { requestAnimationFrame(() => { refreshArrows() @@ -233,13 +227,15 @@ function handleRefresh() {