Files
pinkudex/mockups/context-menu-mockups.html
2026-05-26 22:46:00 +02:00

883 lines
39 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Pinkudex · Context Menu — 10 Improvement Suggestions</title>
<style>
:root {
--bg-0: #0a0710;
--bg-1: #14101e;
--fg: #e8e6f0;
--fg-dim: #a8a4b8;
--fg-muted: #6e6a80;
--cyan: #22d3ee;
--violet: #a78bfa;
--mint: #34d399;
--coral: #fb7185;
--amber: #fbbf24;
--glass: rgba(255,255,255,0.04);
--glass-strong: rgba(255,255,255,0.08);
--border: rgba(255,255,255,0.08);
--border-strong: rgba(255,255,255,0.18);
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg-0);
color: var(--fg);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
line-height: 1.45;
}
.page { max-width: 1600px; margin: 0 auto; padding: 24px; }
.page-header {
margin-bottom: 24px;
padding: 16px 20px;
border-radius: 16px;
background: linear-gradient(135deg, rgba(34,211,238,0.08), rgba(167,139,250,0.05));
border: 1px solid var(--border);
}
.page-header h1 { margin: 0 0 8px 0; font-size: 24px; font-weight: 600; }
.page-header p { margin: 0; color: var(--fg-dim); font-size: 14px; }
/* Side-by-side comparison: current on left, all 10 mockups on right grid */
.layout {
display: grid;
grid-template-columns: 320px 1fr;
gap: 32px;
align-items: start;
}
.current-pane {
position: sticky;
top: 24px;
}
.pane-label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
font-family: ui-monospace, monospace;
color: var(--fg-muted);
margin-bottom: 8px;
}
.grid-mocks {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
}
/* The actual menu */
.menu {
width: 320px;
border-radius: 12px;
border: 1px solid var(--border-strong);
background: rgba(10,7,16,0.96);
backdrop-filter: blur(20px);
overflow: hidden;
font-size: 13px;
box-shadow: 0 16px 32px rgba(0,0,0,0.5);
}
.menu-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
border-bottom: 1px solid var(--border);
}
.menu-header .title {
font-family: ui-monospace, monospace;
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--fg-muted);
}
.menu-link {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
color: var(--fg);
transition: background 0.1s;
}
.menu-link:hover { background: var(--glass); }
.menu-section {
padding: 8px;
border-top: 1px solid var(--border);
}
.section-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4px;
margin-bottom: 4px;
font-family: ui-monospace, monospace;
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--fg-muted);
}
.section-head .count {
background: var(--glass-strong);
padding: 1px 6px;
border-radius: 4px;
font-size: 9px;
}
.menu-row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
cursor: pointer;
color: var(--fg-dim);
}
.menu-row:hover { background: var(--glass); color: var(--fg); }
.menu-row.on { color: var(--violet); }
.menu-row.on .check { color: var(--violet); }
.menu-row .check { width: 12px; }
.menu-row .name { flex: 1; }
.menu-row .meta { font-size: 10px; color: var(--fg-muted); font-family: ui-monospace, monospace; }
.menu-input {
display: block;
width: 100%;
background: rgba(10,7,16,0.6);
border: 1px solid var(--border);
border-radius: 6px;
padding: 6px 8px;
font-size: 12px;
color: var(--fg);
margin-top: 6px;
}
.menu-input::placeholder { color: var(--fg-muted); }
.menu-delete {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
color: var(--coral);
border-top: 1px solid var(--border);
cursor: pointer;
}
.menu-delete:hover { background: rgba(251,113,133,0.08); }
/* Mockup wrapper */
.mock {
background: var(--glass);
border: 1px solid var(--border);
border-radius: 12px;
padding: 14px;
display: flex;
flex-direction: column;
gap: 10px;
}
.mock h2 {
margin: 0;
font-size: 13px;
color: var(--cyan);
font-weight: 600;
}
.mock .meta {
font-size: 11px;
color: var(--fg-dim);
line-height: 1.5;
}
.mock .body {
display: flex;
justify-content: center;
padding: 8px 0;
background: rgba(255,255,255,0.02);
border-radius: 8px;
}
/* Custom mock pieces */
.thumb-preview {
aspect-ratio: 800 / 538;
width: 100%;
background: linear-gradient(45deg, #2a1f3a 0%, #4a2a5a 50%, #2a1f3a 100%);
border-radius: 8px;
margin: 8px 8px 0 8px;
display: flex;
align-items: flex-end;
justify-content: flex-start;
padding: 6px;
color: rgba(255,255,255,0.5);
font-size: 10px;
font-family: ui-monospace, monospace;
}
.pill {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: 999px;
font-size: 10px;
font-family: ui-monospace, monospace;
}
.pill.cyan { background: rgba(34,211,238,0.15); color: var(--cyan); }
.pill.amber { background: rgba(251,191,36,0.15); color: var(--amber); }
.pill.violet { background: rgba(167,139,250,0.15); color: var(--violet); }
.quick-row {
display: flex;
gap: 4px;
padding: 8px 12px;
border-bottom: 1px solid var(--border);
}
.qbtn {
flex: 1 1 0;
min-width: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
padding: 6px 4px;
border-radius: 6px;
background: var(--glass);
color: var(--fg-dim);
font-size: 11px;
cursor: pointer;
white-space: nowrap;
}
.qbtn:hover { background: var(--glass-strong); color: var(--fg); }
.qbtn.active { background: rgba(34,211,238,0.18); color: var(--cyan); }
.qbtn.amber.active { background: rgba(251,191,36,0.18); color: var(--amber); }
.qbtn.mint.active { background: rgba(52,211,153,0.18); color: var(--mint); }
.qbtn.violet.active { background: rgba(167,139,250,0.18); color: var(--violet); }
.star-row {
display: flex;
gap: 2px;
padding: 8px 12px;
border-bottom: 1px solid var(--border);
justify-content: center;
}
.star {
width: 22px; height: 22px;
display: grid; place-items: center;
color: var(--fg-muted);
cursor: pointer;
font-size: 18px;
}
.star.filled { color: var(--cyan); }
.category-header {
font-family: ui-monospace, monospace;
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--cyan);
padding: 6px 4px 2px 4px;
display: flex;
align-items: center;
gap: 6px;
}
.category-header .dot {
width: 6px; height: 6px;
border-radius: 999px;
background: var(--cyan);
}
.recent-row {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 8px 12px 4px 12px;
border-bottom: 1px solid var(--border);
}
.recent-chip {
padding: 3px 8px;
border-radius: 999px;
font-size: 11px;
background: rgba(167,139,250,0.12);
color: var(--violet);
cursor: pointer;
}
.multi-banner {
background: linear-gradient(90deg, rgba(34,211,238,0.18), rgba(167,139,250,0.18));
color: var(--cyan);
padding: 10px 12px;
font-size: 12px;
font-weight: 600;
text-align: center;
border-bottom: 1px solid rgba(34,211,238,0.3);
}
.compact .menu-row { padding: 3px 6px; font-size: 12px; }
.compact .menu-section { padding: 4px; }
.compact .menu-link { padding: 6px 12px; }
.compact-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2px;
padding: 4px;
}
.actress-row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
}
.actress-row .av {
width: 22px; height: 22px;
border-radius: 999px;
background: linear-gradient(135deg, #a78bfa, #4a2a5a);
flex-shrink: 0;
}
.filter-input {
width: 100%;
background: rgba(10,7,16,0.6);
border: 1px solid var(--border);
border-radius: 6px;
padding: 4px 8px;
font-size: 11px;
color: var(--fg);
margin-bottom: 4px;
}
/* Cover-collection action */
.menu-row .pin {
font-size: 10px;
color: var(--amber);
cursor: pointer;
}
.menu-row.cover-of { background: rgba(251,191,36,0.06); }
.menu-row.cover-of .pin { color: var(--amber); }
/* Scrollable list — caps height to ~5 rows, scrolls beyond. */
.menu-list-scroll {
max-height: calc(5 * 30px); /* ~5 menu-row heights at 6px+content+6px */
overflow-y: auto;
/* Slim scrollbar that doesn't fight the dark theme */
scrollbar-width: thin;
scrollbar-color: var(--glass-strong) transparent;
}
.menu-list-scroll::-webkit-scrollbar { width: 6px; }
.menu-list-scroll::-webkit-scrollbar-track { background: transparent; }
.menu-list-scroll::-webkit-scrollbar-thumb { background: var(--glass-strong); border-radius: 3px; }
.menu-list-scroll::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
/* Submenu chevron row */
.submenu-row {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
color: var(--fg);
cursor: pointer;
transition: background 0.1s;
}
.submenu-row:hover, .submenu-row.open {
background: var(--glass);
}
.submenu-row.open {
background: var(--glass-strong);
}
.submenu-row .name {
flex: 1;
}
.submenu-row .count-pill {
font-size: 10px;
font-family: ui-monospace, monospace;
color: var(--fg-muted);
background: var(--glass);
padding: 1px 6px;
border-radius: 4px;
}
.submenu-row.open .count-pill {
background: rgba(34,211,238,0.15);
color: var(--cyan);
}
.submenu-row .chevron {
color: var(--fg-muted);
font-size: 11px;
}
/* Flyout container — sits to the right of the main menu */
.flyout-wrap {
display: flex;
align-items: flex-start;
gap: 8px;
}
.flyout {
width: 320px;
border-radius: 12px;
border: 1px solid var(--border-strong);
background: rgba(10,7,16,0.96);
backdrop-filter: blur(20px);
overflow: hidden;
box-shadow: 0 16px 32px rgba(0,0,0,0.5);
position: relative;
}
.flyout::before {
content: "";
position: absolute;
left: -7px;
top: 36px;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-right: 6px solid var(--border-strong);
}
/* Filter-or-create: input + ghost "Create" affordance shown only when typed
value doesn't match an existing item. */
.filter-create-wrap {
position: relative;
margin-bottom: 6px;
}
.filter-create-wrap .create-hint {
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%);
font-size: 10px;
color: var(--cyan);
background: rgba(34,211,238,0.12);
border: 1px solid rgba(34,211,238,0.3);
padding: 2px 6px;
border-radius: 4px;
cursor: pointer;
font-family: ui-monospace, monospace;
}
</style>
</head>
<body>
<div class="page">
<header class="page-header">
<h1>Right-click context menu — 10 ideas</h1>
<p>Current menu on the left (sticky). Each suggestion below shows the same content reorganised. Click anywhere on the page; the mockups are static.</p>
</header>
<div class="layout">
<!-- ===================== CURRENT ===================== -->
<div class="current-pane">
<div class="pane-label">CURRENT</div>
<div class="menu">
<div class="menu-header">
<span class="title">IMAGE #651</span>
<span class="title" style="cursor:pointer">×</span>
</div>
<div class="menu-link">↗ Open detail</div>
<div class="menu-section">
<div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">anal</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">blowjob</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">gyaru</span></div>
<input class="menu-input" placeholder="New tag…" />
</div>
<div class="menu-section">
<div class="section-head"><span>📁 COLLECTIONS</span><span class="count">2</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">collection 1</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">collection 2</span></div>
<input class="menu-input" placeholder="New collection…" />
</div>
<div class="menu-delete">🗑 Delete image</div>
</div>
</div>
<!-- ===================== MOCKUPS ===================== -->
<div class="grid-mocks">
<!-- ⭐ COMBINED PICK: submenu version -->
<div class="mock" style="grid-column: 1 / -1; border-color: rgba(34,211,238,0.4); background: linear-gradient(135deg, rgba(34,211,238,0.06), rgba(167,139,250,0.04));">
<h2 style="font-size:14px;">⭐ Combined pick — Compact main menu + Tags / Collections as fly-out sub-menus</h2>
<div class="meta">
Main menu shows only the essentials (header, marks, two collapsed entries, delete).
Hovering or clicking <strong style="color:var(--fg);">Tags ▸</strong> or <strong style="color:var(--fg);">Collections ▸</strong> opens a flyout sub-menu to the right with the filter-or-create input,
recent chips, and scrollable list. Significantly reduces noise; sub-menu only renders when needed.
</div>
<div class="body" style="gap: 32px; flex-wrap: wrap; align-items: flex-start;">
<!-- Single-cover view: closed -->
<div>
<div style="font-size:10px; color:var(--fg-muted); font-family:ui-monospace,monospace; text-align:center; margin-bottom:6px; letter-spacing:0.08em;">SINGLE · COMPACT</div>
<div class="menu" style="width: 320px;">
<div class="menu-header" style="flex-direction:column; align-items:flex-start; gap:2px; padding:10px 12px;">
<span style="color:var(--cyan); font-family:ui-monospace,monospace; font-weight:600; font-size:13px;">MIAA-291</span>
<div style="font-size:11px; color:var(--fg-dim);">Kagami Shuna</div>
</div>
<div class="quick-row" style="gap:3px;">
<div class="qbtn active">💎 VIP</div>
<div class="qbtn amber">⭐ Fav</div>
<div class="qbtn mint active">👁 Watched</div>
<div class="qbtn violet active">📦 Owned</div>
</div>
<div class="submenu-row">
<span>🏷</span><span class="name">Tags</span><span class="count-pill">3</span><span class="chevron"></span>
</div>
<div class="submenu-row">
<span>📁</span><span class="name">Collections</span><span class="count-pill">2</span><span class="chevron"></span>
</div>
<div class="menu-delete">🗑 Delete image</div>
</div>
</div>
<!-- Single-cover view: Tags submenu open -->
<div>
<div style="font-size:10px; color:var(--fg-muted); font-family:ui-monospace,monospace; text-align:center; margin-bottom:6px; letter-spacing:0.08em;">SINGLE · TAGS FLYOUT</div>
<div class="flyout-wrap">
<div class="menu" style="width: 320px;">
<div class="menu-header" style="flex-direction:column; align-items:flex-start; gap:2px; padding:10px 12px;">
<span style="color:var(--cyan); font-family:ui-monospace,monospace; font-weight:600; font-size:13px;">MIAA-291</span>
<div style="font-size:11px; color:var(--fg-dim);">Kagami Shuna</div>
</div>
<div class="quick-row" style="gap:3px;">
<div class="qbtn active">💎 VIP</div>
<div class="qbtn amber">⭐ Fav</div>
<div class="qbtn mint active">👁 Watched</div>
<div class="qbtn violet active">📦 Owned</div>
</div>
<div class="submenu-row open">
<span>🏷</span><span class="name">Tags</span><span class="count-pill">3</span><span class="chevron" style="color:var(--cyan);"></span>
</div>
<div class="submenu-row">
<span>📁</span><span class="name">Collections</span><span class="count-pill">2</span><span class="chevron"></span>
</div>
<div class="menu-delete">🗑 Delete image</div>
</div>
<div class="flyout">
<div class="section-head" style="padding:10px 12px 6px 12px; border-bottom:1px solid var(--border); margin-bottom:0;">
<span>🏷 TAGS</span><span class="count">3 / 38</span>
</div>
<div style="padding:8px;">
<div class="filter-create-wrap">
<input class="filter-input" placeholder="🔎 Filter or add new tag…" style="margin-bottom:0; padding-right:60px;" />
<span class="create-hint">+ Create</span>
</div>
<div style="font-size:9px; color:var(--fg-muted); padding:6px 4px 2px 4px; letter-spacing:0.06em;">RECENT</div>
<div class="recent-row" style="border-bottom:none; padding:0 4px 8px 4px; gap:4px;">
<span class="recent-chip">+ shibari</span>
<span class="recent-chip">+ pov</span>
<span class="recent-chip">+ facial</span>
<span class="recent-chip">+ gyaru</span>
<span class="recent-chip">+ ntr</span>
</div>
<div style="border-top:1px solid var(--border); padding-top:4px;">
<div style="font-size:9px; color:var(--fg-muted); padding:2px 4px 4px 4px; letter-spacing:0.06em; display:flex; justify-content:space-between;">
<span>ALL</span>
<span>↕ scroll</span>
</div>
<div class="menu-list-scroll">
<div class="menu-row on"><span class="check"></span><span class="name">anal</span><span class="meta">42</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">blowjob</span><span class="meta">68</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">gyaru</span><span class="meta">21</span></div>
<div class="menu-row"><span class="check"></span><span class="name">bondage</span><span class="meta">19</span></div>
<div class="menu-row"><span class="check"></span><span class="name">creampie</span><span class="meta">95</span></div>
<div class="menu-row"><span class="check"></span><span class="name">facial</span><span class="meta">31</span></div>
<div class="menu-row"><span class="check"></span><span class="name">handjob</span><span class="meta">14</span></div>
<div class="menu-row"><span class="check"></span><span class="name">latex</span><span class="meta">8</span></div>
<div class="menu-row"><span class="check"></span><span class="name">pov</span><span class="meta">40</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bulk-select view: closed -->
<div>
<div style="font-size:10px; color:var(--fg-muted); font-family:ui-monospace,monospace; text-align:center; margin-bottom:6px; letter-spacing:0.08em;">BULK · 12 · COMPACT</div>
<div class="menu" style="width: 320px;">
<div class="multi-banner">⚡ Applying to 12 covers</div>
<div class="quick-row" style="gap:3px;">
<div class="qbtn">💎 VIP</div>
<div class="qbtn amber">⭐ Fav</div>
<div class="qbtn mint">👁 Watched</div>
<div class="qbtn violet">📦 Owned</div>
</div>
<div class="submenu-row">
<span>🏷</span><span class="name">Tags</span><span class="count-pill">mixed</span><span class="chevron"></span>
</div>
<div class="submenu-row">
<span>📁</span><span class="name">Collections</span><span class="count-pill">mixed</span><span class="chevron"></span>
</div>
<div class="menu-delete">🗑 Delete 12 images</div>
</div>
</div>
<!-- Bulk-select view: Collections submenu open -->
<div>
<div style="font-size:10px; color:var(--fg-muted); font-family:ui-monospace,monospace; text-align:center; margin-bottom:6px; letter-spacing:0.08em;">BULK · COLLECTIONS FLYOUT</div>
<div class="flyout-wrap">
<div class="menu" style="width: 320px;">
<div class="multi-banner">⚡ Applying to 12 covers</div>
<div class="quick-row" style="gap:3px;">
<div class="qbtn">💎 VIP</div>
<div class="qbtn amber">⭐ Fav</div>
<div class="qbtn mint">👁 Watched</div>
<div class="qbtn violet">📦 Owned</div>
</div>
<div class="submenu-row">
<span>🏷</span><span class="name">Tags</span><span class="count-pill">mixed</span><span class="chevron"></span>
</div>
<div class="submenu-row open">
<span>📁</span><span class="name">Collections</span><span class="count-pill">mixed</span><span class="chevron" style="color:var(--cyan);"></span>
</div>
<div class="menu-delete">🗑 Delete 12 images</div>
</div>
<div class="flyout" style="margin-top: 60px;">
<div class="section-head" style="padding:10px 12px 6px 12px; border-bottom:1px solid var(--border); margin-bottom:0;">
<span>📁 COLLECTIONS</span><span class="count">mixed</span>
</div>
<div style="padding:8px;">
<div class="filter-create-wrap">
<input class="filter-input" placeholder="🔎 Filter or add new collection…" style="margin-bottom:0; padding-right:60px;" />
<span class="create-hint">+ Create</span>
</div>
<div style="font-size:9px; color:var(--fg-muted); padding:6px 4px 2px 4px; letter-spacing:0.06em;">RECENT</div>
<div class="recent-row" style="border-bottom:none; padding:0 4px 8px 4px; gap:4px;">
<span class="recent-chip" style="background:rgba(34,211,238,0.12); color:var(--cyan);">+ slick &amp; shiny</span>
<span class="recent-chip" style="background:rgba(34,211,238,0.12); color:var(--cyan);">+ marathon 2025</span>
<span class="recent-chip" style="background:rgba(34,211,238,0.12); color:var(--cyan);">+ to rewatch</span>
<span class="recent-chip" style="background:rgba(34,211,238,0.12); color:var(--cyan);">+ collection 1</span>
</div>
<div style="border-top:1px solid var(--border); padding-top:4px;">
<div style="font-size:9px; color:var(--fg-muted); padding:2px 4px 4px 4px; letter-spacing:0.06em; display:flex; justify-content:space-between;">
<span>ALL</span>
<span>↕ scroll</span>
</div>
<div class="menu-list-scroll">
<div class="menu-row on"><span class="check"></span><span class="name">collection 1</span><span class="meta">12 / 12</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">collection 2</span><span class="meta">5 / 12</span></div>
<div class="menu-row"><span class="check"></span><span class="name">slick &amp; shiny</span><span class="meta">0 / 12</span></div>
<div class="menu-row"><span class="check"></span><span class="name">marathon 2025</span><span class="meta">0 / 12</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="meta" style="border-top:1px solid var(--border); padding-top:10px; margin-top:6px;">
<strong style="color:var(--fg);">Behaviour notes:</strong>
<ul style="margin:6px 0 0 18px; padding:0; color:var(--fg-dim); line-height:1.6;">
<li><strong style="color:var(--fg);">Compact main menu</strong>: 4 quick marks, Tags ▸ row, Collections ▸ row, Delete. That&apos;s it.</li>
<li><strong style="color:var(--fg);">Submenu trigger</strong>: hover or click <code>Tags ▸</code> / <code>Collections ▸</code> opens the flyout to the right of the main menu (or to the left if there isn&apos;t room). Closing happens on selecting an item, clicking elsewhere, or pressing ESC.</li>
<li><strong style="color:var(--fg);">Count pill</strong> on the row tells you how many tags/collections are already attached without opening the submenu. In bulk mode it reads <code>mixed</code> when coverage isn&apos;t uniform.</li>
<li><strong style="color:var(--fg);">Filter-or-create input</strong>: typing filters the list as you type. If your input matches no existing item, the cyan <code style="background:rgba(34,211,238,0.1); padding:0 4px; border-radius:3px; color:var(--cyan); font-family:ui-monospace,monospace; font-size:10px;">+ Create</code> chip appears at the right edge — Enter or click commits.</li>
<li><strong style="color:var(--fg);">Scroll cap</strong>: each list shows ~3 rows then becomes a thin scrollbar. Recent tags row is <em>not</em> capped; it stays as a single chip strip.</li>
<li><strong style="color:var(--fg);">VIP / Favorite</strong> stay mutually exclusive (today&apos;s behaviour).</li>
<li><strong style="color:var(--violet);">Owned</strong> is a new boolean — needs <code style="background:rgba(255,255,255,0.05); padding:1px 4px; border-radius:3px; font-family:ui-monospace,monospace; font-size:10px;">is_owned</code> column on <code style="background:rgba(255,255,255,0.05); padding:1px 4px; border-radius:3px; font-family:ui-monospace,monospace; font-size:10px;">images</code>.</li>
<li><strong style="color:var(--fg);">Bulk mode</strong>: tag/collection rows show <code style="background:rgba(255,255,255,0.05); padding:1px 4px; border-radius:3px; font-family:ui-monospace,monospace; font-size:10px;">N / 12</code>. <code></code> indicates partial coverage; click to apply to all, click again to remove from all (tri-state cycle).</li>
</ul>
</div>
</div>
<!-- 1. Thumbnail preview -->
<div class="mock">
<h2>1. Thumbnail preview at top</h2>
<div class="meta">Shows which cover you're acting on. Critical when right-clicking from a dense grid where the mouse position alone doesn't tell you.</div>
<div class="body">
<div class="menu">
<div class="menu-header">
<span class="title">MIAA-291</span>
<span class="title">×</span>
</div>
<div class="thumb-preview">800×538</div>
<div class="menu-link">↗ Open detail</div>
<div class="menu-section"><div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div></div>
<div class="menu-delete">🗑 Delete</div>
</div>
</div>
</div>
<!-- 2. Code + title header -->
<div class="mock">
<h2>2. Code + title header</h2>
<div class="meta">Replace generic "IMAGE #651" with something identifying. Falls back to the ID only when there's no code.</div>
<div class="body">
<div class="menu">
<div class="menu-header" style="flex-direction:column; align-items:flex-start; gap:2px; padding:10px 12px;">
<div style="display:flex; align-items:center; gap:8px; width:100%; justify-content:space-between;">
<span style="color:var(--cyan); font-family:ui-monospace,monospace; font-weight:600; font-size:13px;">MIAA-291</span>
<span class="title">×</span>
</div>
<div style="font-size:11px; color:var(--fg-dim);">Kagami Shuna · 2024-08</div>
</div>
<div class="menu-link">↗ Open detail</div>
<div class="menu-section"><div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div></div>
<div class="menu-delete">🗑 Delete</div>
</div>
</div>
</div>
<!-- 3. Quick marks row -->
<div class="mock">
<h2>3. Quick marks row (VIP / Fav / Watched)</h2>
<div class="meta">Most-used actions promoted to a single click. Currently buried in cover detail page.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="quick-row">
<div class="qbtn active">💎 VIP</div>
<div class="qbtn amber">⭐ Fav</div>
<div class="qbtn mint active">👁 Watched</div>
</div>
<div class="menu-link">↗ Open detail</div>
<div class="menu-section"><div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div></div>
</div>
</div>
</div>
<!-- 4. Star rating row -->
<div class="mock">
<h2>4. Star rating row</h2>
<div class="meta">Set 0-5 rating without opening detail. Click again on highest filled star to clear.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="star-row">
<span class="star filled"></span>
<span class="star filled"></span>
<span class="star filled"></span>
<span class="star filled"></span>
<span class="star"></span>
</div>
<div class="menu-link">↗ Open detail</div>
<div class="menu-section"><div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div></div>
</div>
</div>
</div>
<!-- 5. Actress section -->
<div class="mock">
<h2>5. Actress section</h2>
<div class="meta">Currently no way to add/remove actresses from context menu. Big gap — adds an Actress section between Tags and Collections.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="menu-link">↗ Open detail</div>
<div class="menu-section">
<div class="section-head"><span>👥 ACTRESSES</span><span class="count">2</span></div>
<div class="actress-row"><span class="av"></span><span style="flex:1; font-size:12px;">Kagami Shuna</span><span class="check" style="color:var(--violet)"></span></div>
<div class="actress-row"><span class="av"></span><span style="flex:1; font-size:12px;">Yui Nagase</span><span class="check" style="color:var(--violet)"></span></div>
<input class="menu-input" placeholder="Add actress…" />
</div>
<div class="menu-section"><div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div></div>
</div>
</div>
</div>
<!-- 6. Tags grouped by category -->
<div class="mock">
<h2>6. Tags grouped by category</h2>
<div class="meta">Mirrors the new /tag page. Surfaces structure when the tag list is long.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="menu-section">
<div class="section-head"><span>🏷 TAGS</span><span class="count">12</span></div>
<div class="category-header"><span class="dot" style="background:#fbbf24"></span>BDSM</div>
<div class="menu-row on"><span class="check"></span><span class="name">bondage</span></div>
<div class="menu-row"><span class="check"></span><span class="name">shibari</span></div>
<div class="category-header"><span class="dot" style="background:#a78bfa"></span>BUKKAKE</div>
<div class="menu-row on"><span class="check"></span><span class="name">facial</span></div>
<div class="category-header"><span class="dot" style="background:var(--fg-muted)"></span>UNCATEGORISED</div>
<div class="menu-row on"><span class="check"></span><span class="name">anal</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">blowjob</span></div>
</div>
</div>
</div>
</div>
<!-- 7. Recent / frequent tags pinned -->
<div class="mock">
<h2>7. Recent tags pinned</h2>
<div class="meta">Last-5-used tags surface as one-click chips above the full list. After a tagging spree, the next tag is usually one of the same.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="menu-section">
<div class="section-head"><span>🏷 TAGS</span><span class="count">3</span></div>
<div class="recent-row">
<span class="recent-chip">+ gyaru</span>
<span class="recent-chip">+ shibari</span>
<span class="recent-chip">+ pov</span>
<span class="recent-chip">+ facial</span>
</div>
<div style="font-size:9px; color:var(--fg-muted); padding:4px 8px;">RECENT · click to add</div>
<div class="menu-row on"><span class="check"></span><span class="name">anal</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">blowjob</span></div>
</div>
</div>
</div>
</div>
<!-- 8. Search/filter input -->
<div class="mock">
<h2>8. Search input for long lists</h2>
<div class="meta">Filters the rendered list as you type. Already exists when &gt;5 items but could be more visible — promote to top of section unconditionally.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="menu-section">
<div class="section-head"><span>🏷 TAGS</span><span class="count">38</span></div>
<input class="filter-input" placeholder="🔎 Filter tags…" value="bond" />
<div class="menu-row on"><span class="check"></span><span class="name">bondage</span></div>
<div class="menu-row"><span class="check"></span><span class="name">bondage-gear</span></div>
</div>
</div>
</div>
</div>
<!-- 9. Set-as-collection-cover -->
<div class="mock">
<h2>9. Set as collection cover</h2>
<div class="meta">Each collection row shows a star. Click to designate this image as the collection's hero. Currently there's no in-line way to set a collection's cover.</div>
<div class="body">
<div class="menu">
<div class="menu-header"><span class="title">MIAA-291</span><span class="title">×</span></div>
<div class="menu-section">
<div class="section-head"><span>📁 COLLECTIONS</span><span class="count">2</span></div>
<div class="menu-row on cover-of">
<span class="check"></span>
<span class="name">collection 1</span>
<span class="pin" title="This image is the collection's cover">★ cover</span>
</div>
<div class="menu-row on">
<span class="check"></span>
<span class="name">collection 2</span>
<span class="pin" style="color:var(--fg-muted)" title="Make this the cover"></span>
</div>
</div>
</div>
</div>
</div>
<!-- 10. Multi-select banner + compact tag grid -->
<div class="mock">
<h2>10. Bulk-mode banner + compact tag grid</h2>
<div class="meta">When N&gt;1 selected: bright banner makes scope obvious; tags switch to a 2-column grid so 30 tags fit in the same height.</div>
<div class="body">
<div class="menu compact">
<div class="multi-banner">⚡ Applying to 12 covers</div>
<div class="menu-link">↗ Open first</div>
<div class="menu-section">
<div class="section-head"><span>🏷 TAGS</span><span class="count">12 / mixed</span></div>
<div class="compact-grid">
<div class="menu-row on"><span class="check"></span><span class="name">anal</span></div>
<div class="menu-row"><span class="check"></span><span class="name">blowjob</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">gyaru</span></div>
<div class="menu-row"><span class="check"></span><span class="name">pov</span></div>
<div class="menu-row on"><span class="check"></span><span class="name">facial</span></div>
<div class="menu-row"><span class="check"></span><span class="name">shibari</span></div>
</div>
<div style="font-size:9px; color:var(--fg-muted); padding:4px 8px;">✓ on all · partial · empty = none</div>
</div>
<div class="menu-delete">🗑 Delete 12</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>