Fandom count fix + Explore 3-pane workspace + modal rail layout #131
@@ -1,7 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section v-if="img" class="fc-meta" aria-label="Image details">
|
<section v-if="img" class="fc-meta" aria-label="Image details">
|
||||||
<!-- #4a: dimensions / size / type — already on the payload, shown nowhere
|
<!-- #4a: dimensions / size / type sit as a compact top block alongside a
|
||||||
until now. -->
|
small save action (operator-asked 2026-06-26) — meta on the left, the
|
||||||
|
download control shrunk to a floppy-disk icon on the right. -->
|
||||||
<dl class="fc-meta__grid">
|
<dl class="fc-meta__grid">
|
||||||
<div v-if="img.width && img.height" class="fc-meta__item">
|
<div v-if="img.width && img.height" class="fc-meta__item">
|
||||||
<dt>Dimensions</dt><dd>{{ img.width }} × {{ img.height }}</dd>
|
<dt>Dimensions</dt><dd>{{ img.width }} × {{ img.height }}</dd>
|
||||||
@@ -14,21 +15,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<!-- #4b: split Download — default Download, chevron → Copy link. Image-to-
|
<!-- #4b: floppy-disk save icon = download; the kebab menu keeps Copy link.
|
||||||
clipboard is OFF the table on the plain-HTTP origin (rule 95), so the
|
Image-to-clipboard is OFF the table on the plain-HTTP origin (rule 95),
|
||||||
secondary action copies the link TEXT, which works everywhere. -->
|
so the secondary action copies the link TEXT, which works everywhere. -->
|
||||||
<v-btn-group divided density="comfortable" variant="tonal" color="accent" rounded="pill">
|
<div class="fc-meta__actions">
|
||||||
<v-btn prepend-icon="mdi-download" @click="download">Download</v-btn>
|
<v-btn
|
||||||
|
icon="mdi-content-save" size="small" variant="tonal" color="accent"
|
||||||
|
aria-label="Download image" title="Download" @click="download"
|
||||||
|
/>
|
||||||
<v-menu location="bottom end">
|
<v-menu location="bottom end">
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-btn v-bind="props" icon="mdi-chevron-down" aria-label="More download options" />
|
<v-btn
|
||||||
|
v-bind="props" icon="mdi-dots-vertical" size="small" variant="text"
|
||||||
|
aria-label="More download options"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list density="compact">
|
<v-list density="compact">
|
||||||
<v-list-item prepend-icon="mdi-link-variant" title="Copy link" @click="copyLink" />
|
<v-list-item prepend-icon="mdi-link-variant" title="Copy link" @click="copyLink" />
|
||||||
<v-list-item prepend-icon="mdi-download" title="Download" @click="download" />
|
<v-list-item prepend-icon="mdi-content-save" title="Download" @click="download" />
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</v-btn-group>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -83,11 +90,16 @@ async function copyLink () {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.fc-meta {
|
.fc-meta {
|
||||||
padding: 14px 16px 0;
|
padding: 14px 16px 0;
|
||||||
display: flex; flex-direction: column; gap: 10px;
|
display: flex; align-items: flex-start; gap: 12px;
|
||||||
}
|
}
|
||||||
.fc-meta__grid {
|
.fc-meta__grid {
|
||||||
|
flex: 1 1 auto; min-width: 0;
|
||||||
display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0;
|
display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0;
|
||||||
}
|
}
|
||||||
|
.fc-meta__actions {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex; align-items: center; gap: 2px;
|
||||||
|
}
|
||||||
.fc-meta__item { display: flex; flex-direction: column; }
|
.fc-meta__item { display: flex; flex-direction: column; }
|
||||||
.fc-meta__item dt {
|
.fc-meta__item dt {
|
||||||
font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
|
font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
|
||||||
|
|||||||
@@ -73,12 +73,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside v-if="modal.current" class="fc-viewer__side">
|
<aside v-if="modal.current" class="fc-viewer__side">
|
||||||
<ImageMetaBar />
|
<!-- Meta + provenance + tags + suggestions scroll together here… -->
|
||||||
<ProvenancePanel />
|
<div class="fc-viewer__side-main">
|
||||||
<TagPanel />
|
<ImageMetaBar />
|
||||||
<!-- Non-blocking: fetches its own similar set after the modal is up;
|
<ProvenancePanel />
|
||||||
collapses silently if empty/slow/failed (see RelatedStrip). -->
|
<TagPanel />
|
||||||
<RelatedStrip />
|
</div>
|
||||||
|
<!-- …while Related is PINNED to the bottom of the rail so it stays
|
||||||
|
reachable no matter how long Tags/Suggestions run (operator-asked
|
||||||
|
2026-06-26). Non-blocking: fetches its own similar set; collapses
|
||||||
|
silently (and takes no footer space) if empty/slow/failed. -->
|
||||||
|
<RelatedStrip class="fc-viewer__related" />
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -309,6 +314,18 @@ function nextFrame() {
|
|||||||
width: var(--fc-side-w); flex-shrink: 0;
|
width: var(--fc-side-w); flex-shrink: 0;
|
||||||
background: rgb(var(--v-theme-surface));
|
background: rgb(var(--v-theme-surface));
|
||||||
border-left: 1px solid rgb(var(--v-theme-surface-light));
|
border-left: 1px solid rgb(var(--v-theme-surface-light));
|
||||||
|
/* Flex column: a scrolling main area + a pinned Related footer. */
|
||||||
|
display: flex; flex-direction: column; min-height: 0;
|
||||||
|
}
|
||||||
|
.fc-viewer__side-main {
|
||||||
|
flex: 1 1 auto; min-height: 0; overflow-y: auto;
|
||||||
|
}
|
||||||
|
.fc-viewer__related {
|
||||||
|
/* Pinned to the bottom; capped so a tall strip can't swallow the rail —
|
||||||
|
it scrolls internally past the cap. RelatedStrip's own border-top draws
|
||||||
|
the divider; it self-collapses (no space) when there's nothing to show. */
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-height: 45%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,6 +356,10 @@ function nextFrame() {
|
|||||||
border-left: none;
|
border-left: none;
|
||||||
border-top: 1px solid rgb(var(--v-theme-surface-light));
|
border-top: 1px solid rgb(var(--v-theme-surface-light));
|
||||||
}
|
}
|
||||||
|
/* The whole body scrolls on mobile — don't nest scrolls or pin Related; let
|
||||||
|
the rail flow naturally (Related lands at the end). */
|
||||||
|
.fc-viewer__side-main { flex: none; overflow: visible; }
|
||||||
|
.fc-viewer__related { max-height: none; overflow: visible; }
|
||||||
/* Re-center the prev/next arrows over the 55vh image band (their base
|
/* Re-center the prev/next arrows over the 55vh image band (their base
|
||||||
top:50% would land on the scrolling panel); next uses the full width
|
top:50% would land on the scrolling panel); next uses the full width
|
||||||
now that the panel is below, not beside. Close + integrity badge keep
|
now that the panel is below, not beside. Close + integrity badge keep
|
||||||
|
|||||||
@@ -12,10 +12,9 @@
|
|||||||
No suggestions above threshold.
|
No suggestions above threshold.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scroll-capped so a long suggestion set (the General bucket can run to
|
<!-- Flows in the rail's main scroll area; Related is pinned to the bottom
|
||||||
dozens) scrolls WITHIN this box instead of stretching the right rail
|
of the rail (ImageViewer side layout), so a long suggestion set no
|
||||||
and shoving the Related strip below the fold. Mirrors the
|
longer needs an internal scroll cap to keep Related reachable. -->
|
||||||
ProvenancePanel cards/attachments treatment. -->
|
|
||||||
<div v-else class="fc-suggestions__list">
|
<div v-else class="fc-suggestions__list">
|
||||||
<SuggestionsCategoryGroup
|
<SuggestionsCategoryGroup
|
||||||
v-for="cat in peopleCats" :key="cat"
|
v-for="cat in peopleCats" :key="cat"
|
||||||
@@ -137,13 +136,9 @@ async function onRemoveAlias(s) {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.fc-suggestions__list {
|
.fc-suggestions__list {
|
||||||
/* Cap the suggestion run so it scrolls internally rather than pushing the
|
/* No internal scroll cap: the rail now scrolls suggestions in its single
|
||||||
Related strip off the bottom of the rail. Hairline scrollbar matching
|
main scroll area while Related is pinned to the bottom (ImageViewer side
|
||||||
ProvenancePanel's capped regions. */
|
layout), so suggestions flow naturally without a nested scrollbar. */
|
||||||
max-height: 320px;
|
|
||||||
overflow-y: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: rgb(var(--v-theme-surface-light)) transparent;
|
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
.fc-suggestions__skeleton { display: flex; flex-direction: column; gap: 8px; }
|
.fc-suggestions__skeleton { display: flex; flex-direction: column; gap: 8px; }
|
||||||
|
|||||||
Reference in New Issue
Block a user