feat(editor): gloss the selected element in a panel
This commit is contained in:
@@ -33,6 +33,7 @@ import { type Sample, SAMPLES } from "@/model/samples"
|
|||||||
import { canConnect } from "@/model/validation"
|
import { canConnect } from "@/model/validation"
|
||||||
import { useModelStore } from "@/store/model"
|
import { useModelStore } from "@/store/model"
|
||||||
import { NODE_DND_MIME, type PlaceableKind } from "./palette-dnd"
|
import { NODE_DND_MIME, type PlaceableKind } from "./palette-dnd"
|
||||||
|
import GlossPanel from "./GlossPanel.vue"
|
||||||
import LoopOverlay from "./LoopOverlay.vue"
|
import LoopOverlay from "./LoopOverlay.vue"
|
||||||
import Palette from "./Palette.vue"
|
import Palette from "./Palette.vue"
|
||||||
import InfoLinkEdge from "./edges/InfoLinkEdge.vue"
|
import InfoLinkEdge from "./edges/InfoLinkEdge.vue"
|
||||||
@@ -363,6 +364,7 @@ onBeforeUnmount(() => window.removeEventListener("keydown", onKeydown))
|
|||||||
</VueFlow>
|
</VueFlow>
|
||||||
|
|
||||||
<LoopOverlay />
|
<LoopOverlay />
|
||||||
|
<GlossPanel />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
45
src/components/GlossPanel.vue
Normal file
45
src/components/GlossPanel.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* Gloss-on-selection (F11, G4) — when exactly one element is selected, name it
|
||||||
|
* and define it in a small corner card. Selection is deliberate and singular, so
|
||||||
|
* the canvas stays pixel-clean and silent until you ask — no passive hover noise
|
||||||
|
* on a dense model. Self-contained: reads selection straight from the shared Vue
|
||||||
|
* Flow instance, so it drops into the Editor as one tag.
|
||||||
|
*
|
||||||
|
* A pipe edge stands in for its Flow node, so selecting one glosses the Flow; an
|
||||||
|
* info edge glosses the Information Link. Anything else (nothing, or a multi-
|
||||||
|
* selection) hides the card.
|
||||||
|
*/
|
||||||
|
import { useVueFlow } from "@vue-flow/core"
|
||||||
|
import { computed } from "vue"
|
||||||
|
import { type GlossEntry, INFO_LINK_GLOSS, NODE_GLOSSARY } from "@/model/glossary"
|
||||||
|
import type { EdgeData, NodeData } from "@/model/projection"
|
||||||
|
|
||||||
|
const { getSelectedNodes, getSelectedEdges } = useVueFlow("meadows")
|
||||||
|
|
||||||
|
const gloss = computed<GlossEntry | null>(() => {
|
||||||
|
const nodes = getSelectedNodes.value
|
||||||
|
const edges = getSelectedEdges.value
|
||||||
|
|
||||||
|
if (nodes.length === 1 && edges.length === 0) {
|
||||||
|
const node = (nodes[0].data as NodeData | undefined)?.node
|
||||||
|
return node ? NODE_GLOSSARY[node.kind] : null
|
||||||
|
}
|
||||||
|
if (edges.length === 1 && nodes.length === 0) {
|
||||||
|
const kind = (edges[0].data as EdgeData | undefined)?.kind
|
||||||
|
if (kind === "info") return INFO_LINK_GLOSS
|
||||||
|
if (kind === "pipe") return NODE_GLOSSARY.flow
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="gloss"
|
||||||
|
class="pointer-events-none absolute right-3 bottom-3 z-10 max-w-xs rounded-box border border-base-300 bg-base-100/90 p-3 shadow-md backdrop-blur"
|
||||||
|
>
|
||||||
|
<div class="text-sm font-semibold">{{ gloss.term }}</div>
|
||||||
|
<p class="mt-0.5 text-xs leading-snug text-base-content/70">{{ gloss.short }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user