diff --git a/frontend/src/App.css b/frontend/src/App.css index dbc1c7d..9de3aa1 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -5120,3 +5120,283 @@ a.app-footer__about:hover, .technique-page { animation: pageEnter 250ms ease-out; } + +/* ── Admin Technique Pages ────────────────────────────────────────────────── */ + +.admin-page { + max-width: 1100px; + margin: 0 auto; + padding: 2rem 1rem; +} + +.admin-page__header { + display: flex; + align-items: baseline; + gap: 0.75rem; + margin-bottom: 0.5rem; +} + +.admin-page__header h1 { + color: var(--color-text-primary); + margin: 0; + font-size: 1.5rem; +} + +.admin-page__count { + color: var(--color-text-muted); + font-size: 0.9rem; +} + +.admin-page__description { + color: var(--color-text-muted); + font-size: 0.85rem; + margin: 0 0 1.5rem; + line-height: 1.5; +} + +.admin-page__filters { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 1.25rem; + flex-wrap: wrap; +} + +.admin-page__checkbox { + display: flex; + align-items: center; + gap: 0.4rem; + color: var(--color-text-secondary); + font-size: 0.85rem; + cursor: pointer; + white-space: nowrap; +} + +.admin-page__checkbox input[type="checkbox"] { + appearance: none; + -webkit-appearance: none; + width: 16px; + height: 16px; + border: 1.5px solid var(--color-text-muted); + border-radius: 3px; + background: transparent; + cursor: pointer; + position: relative; + flex-shrink: 0; +} + +.admin-page__checkbox input[type="checkbox"]:hover { + border-color: var(--color-accent); +} + +.admin-page__checkbox input[type="checkbox"]:checked { + background: var(--color-accent); + border-color: var(--color-accent); +} + +.admin-page__checkbox input[type="checkbox"]:checked::after { + content: "✓"; + position: absolute; + top: -1px; + left: 2px; + font-size: 12px; + color: var(--color-bg-page); + font-weight: 700; +} + +.admin-page__search { + padding: 0.4rem 0.75rem; + border-radius: 6px; + border: 1px solid var(--color-border); + background: var(--color-bg-input); + color: var(--color-text-primary); + font-size: 0.85rem; + min-width: 180px; +} + +.admin-page__search::placeholder { + color: var(--color-text-muted); +} + +.admin-page__search:focus { + outline: 2px solid var(--color-accent); + outline-offset: 1px; +} + +.admin-page__select { + padding: 0.4rem 0.75rem; + border-radius: 6px; + border: 1px solid var(--color-border); + background: var(--color-bg-input); + color: var(--color-text-primary); + font-size: 0.85rem; + cursor: pointer; +} + +.admin-page__select:focus { + outline: 2px solid var(--color-accent); + outline-offset: 1px; +} + +.admin-page__error { + background: var(--color-badge-rejected-bg); + color: var(--color-badge-rejected-text); + padding: 0.75rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; + font-size: 0.85rem; +} + +.admin-page__loading, +.admin-page__empty { + color: var(--color-text-muted); + text-align: center; + padding: 3rem 1rem; + font-size: 0.9rem; +} + +.admin-page__table-wrap { + background: var(--color-bg-surface); + border: 1px solid var(--color-border); + border-radius: 8px; + overflow: hidden; +} + +.admin-page__table { + width: 100%; + border-collapse: collapse; + font-size: 0.85rem; +} + +.admin-page__table thead th { + text-align: left; + padding: 0.625rem 0.75rem; + color: var(--color-text-muted); + font-weight: 500; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.04em; + border-bottom: 1px solid var(--color-border); + white-space: nowrap; +} + +.admin-page__table tbody td { + padding: 0.625rem 0.75rem; + color: var(--color-text-secondary); + border-bottom: 1px solid rgba(42, 42, 56, 0.5); + vertical-align: middle; +} + +.admin-page__table tbody tr:last-child td { + border-bottom: none; +} + +.admin-page__row { + transition: background 150ms ease; +} + +.admin-page__row:hover { + background: var(--color-bg-surface-hover); +} + +.admin-page__row--expanded { + background: var(--color-bg-surface-hover); +} + +.admin-page__expand-toggle { + width: 1.5rem; + text-align: center; + color: var(--color-text-muted); + font-size: 0.8rem; +} + +.admin-page__table a { + color: var(--color-accent); + text-decoration: none; +} + +.admin-page__table a:hover { + color: var(--color-accent-hover); + text-decoration: underline; +} + +.admin-page__detail-row td { + padding: 0 !important; + border-bottom: 1px solid var(--color-border) !important; +} + +.admin-page__detail-panel { + padding: 1rem 1.25rem 1.25rem 2.75rem; + background: rgba(15, 15, 20, 0.4); + border-top: 1px solid rgba(42, 42, 56, 0.5); +} + +.admin-page__detail-panel h4 { + color: var(--color-text-primary); + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.04em; + margin: 0.75rem 0 0.5rem; +} + +.admin-page__detail-links { + margin-bottom: 0.5rem; +} + +.admin-page__detail-links a { + color: var(--color-accent); + font-size: 0.8rem; + text-decoration: none; +} + +.admin-page__detail-links a:hover { + text-decoration: underline; +} + +.admin-page__source-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 0.35rem; +} + +.admin-page__source-list li { + font-size: 0.8rem; +} + +.admin-page__source-list a { + color: var(--color-accent); + text-decoration: none; +} + +.admin-page__source-list a:hover { + text-decoration: underline; +} + +.admin-page__muted { + color: var(--color-text-muted); + font-size: 0.8rem; +} + +/* Responsive: stack table on narrow viewports */ +@media (max-width: 768px) { + .admin-page__table-wrap { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .admin-page__table { + min-width: 700px; + } + + .admin-page__filters { + flex-direction: column; + align-items: stretch; + } + + .admin-page__search { + min-width: unset; + } +} diff --git a/frontend/src/pages/AdminTechniquePages.tsx b/frontend/src/pages/AdminTechniquePages.tsx index c5e8eaa..ae1e49d 100644 --- a/frontend/src/pages/AdminTechniquePages.tsx +++ b/frontend/src/pages/AdminTechniquePages.tsx @@ -103,6 +103,10 @@ export default function AdminTechniquePages() {

Technique Pages

{total} pages +

+ Browse all synthesized technique pages. Filter by creator or multi-source status. + Expand a row to see linked source videos and jump to pipeline details. +

{/* Filter bar */}