Suggestions perf + UX polish: incremental CCIP + head training, hover label, scroll/toast fixes, dead-preview removal #196

Merged
bvandeusen merged 8 commits from dev into main 2026-07-06 16:41:08 -04:00
3 changed files with 33 additions and 12 deletions
Showing only changes of commit 7939dba9ed - Show all commits
+31 -10
View File
@@ -35,7 +35,10 @@
:class="{ 'fc-canvas__region--whole': !regionStyle }"
:style="regionStyle || {}"
>
<span class="fc-canvas__region-label">{{ regionLabel }}</span>
<span class="fc-canvas__region-label">
<span v-if="regionTag" class="fc-canvas__region-tag">{{ regionTag }}</span>
<span class="fc-canvas__region-origin">{{ regionOrigin }}</span>
</span>
</div>
</div>
</div>
@@ -48,10 +51,12 @@ import { usePanZoom } from '../../composables/usePanZoom.js'
const props = defineProps({
src: String,
alt: String,
// Hovered-suggestion grounding, or null when nothing is hovered:
// null → no overlay
// { g: {bbox,kind,detector} } → highlight that crop region
// { g: null } → whole-image frame (not localized)
// Hovered-suggestion state, or null when nothing is hovered:
// null → no overlay
// { g: {bbox,kind,detector}, tag } → highlight that crop, label with the tag
// { g: null, tag } → whole-image frame (not localized)
// `tag` is the hovered concept's name (primary label line); `g` is where the
// crop came from (secondary provenance line).
hover: { type: Object, default: null },
})
const emit = defineEmits(['close-request'])
@@ -86,7 +91,12 @@ const regionStyle = computed(() => {
width: `${rw * 100}%`, height: `${rh * 100}%`,
}
})
const regionLabel = computed(() => {
// The hovered tag/suggestion name — the PRIMARY label line (what you care about).
const regionTag = computed(() => props.hover?.tag || '')
// Where the winning crop came from (the region's detector_version, else kind) —
// shown small + dimmed beneath the tag as provenance, not the headline. "whole
// image" = null grounding (the global vector won, not a crop).
const regionOrigin = computed(() => {
const g = props.hover?.g
return g ? (g.detector || g.kind || 'region') : 'whole image'
})
@@ -176,15 +186,26 @@ function onCanvasClick(ev) {
position: absolute;
top: 0; left: 0;
transform: translateY(-100%);
font-size: 11px;
font-family: 'JetBrains Mono', monospace;
line-height: 1.4;
padding: 1px 6px;
display: flex; flex-direction: column;
line-height: 1.25;
padding: 2px 6px;
white-space: nowrap;
background: rgb(var(--v-theme-accent));
color: rgb(var(--v-theme-on-surface));
border-radius: 3px 3px 0 0;
}
/* The hovered tag is the headline. */
.fc-canvas__region-tag {
font-size: 12px;
font-weight: 600;
}
/* Crop origin is provenance, not the point — subordinate: smaller, dimmed, and
monospace (it's a detector token like booru:head, not prose). */
.fc-canvas__region-origin {
font-size: 10px;
font-family: 'JetBrains Mono', monospace;
color: rgb(var(--v-theme-on-surface), 0.72);
}
.fc-canvas__region--whole .fc-canvas__region-label {
background: rgb(var(--v-theme-on-surface-variant));
}
@@ -85,7 +85,7 @@ defineEmits(['accept', 'alias', 'remove-alias', 'dismiss', 'undismiss'])
// it highlights that region. Provided by ImageViewer/Explore; a no-op elsewhere.
const hover = inject('fcSuggestionHover', null)
function onEnter () {
if (hover) hover.value = { g: props.suggestion.grounding ?? null }
if (hover) hover.value = { g: props.suggestion.grounding ?? null, tag: props.suggestion.display_name }
}
function onLeave () {
if (hover) hover.value = null
+1 -1
View File
@@ -83,7 +83,7 @@ async function onEnter () {
if (seq !== hoverSeq) return // pointer already left / moved to another chip
// No head → nothing to localize; don't draw an overlay at all. With a head,
// null grounding still draws the whole-image frame ("the global vector won").
if (res.has_head) hover.value = { g: res.grounding ?? null }
if (res.has_head) hover.value = { g: res.grounding ?? null, tag: props.tag.name }
}
function onLeave () {
hoverSeq++