From 914bd7cd6aa14e839332a98d91c30b19865b0cf2 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 17 May 2026 15:25:52 +0300 Subject: Restructure repo: move Go server into player-server/ --- player-server/web/css/layout.css | 729 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 729 insertions(+) create mode 100644 player-server/web/css/layout.css (limited to 'player-server/web/css/layout.css') diff --git a/player-server/web/css/layout.css b/player-server/web/css/layout.css new file mode 100644 index 0000000..bc71bdd --- /dev/null +++ b/player-server/web/css/layout.css @@ -0,0 +1,729 @@ +/* Reset & base */ +*, *::before, *::after { box-sizing: border-box; } +html, body { + height: 100%; +} +body { + margin: 0; + font-family: var(--font-sans); + background: var(--bg-body); + color: var(--text-primary); + line-height: 1.45; +} + +/* Header */ +.site-header { + position: fixed; + inset: 0 0 auto 0; + height: var(--header-height); + background: var(--bg-surface); + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + gap: var(--gap); + padding: 0 1rem; + z-index: 50; + transform: translateY(calc(-100% + 0.45rem)); + transition: transform var(--transition-base); +} +.site-header::after { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: -0.45rem; + height: 0.45rem; +} +.site-header:hover, +.site-header:focus-within { + transform: translateY(0); +} +.header-main { + display: flex; + align-items: center; + gap: var(--gap); + flex: 1 1 auto; + min-width: 0; +} +.site-header .logo { + font-weight: 700; + letter-spacing: 0.04em; + color: var(--text-primary); + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 0.35rem; +} +.site-header .logo-img { + height: 1.5rem; + width: auto; + display: block; +} +.site-header .spacer { flex: 1 1 auto; } + +.scan-indicator { + position: fixed; + top: 0.75rem; + right: 0.75rem; + z-index: 120; + display: inline-flex; + align-items: center; + gap: 0.4rem; + max-width: min(22rem, calc(100vw - 1.5rem)); + padding: 0.25rem 0.55rem; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--bg-elevated); + color: var(--text-secondary); + box-shadow: var(--shadow-sm); + font-size: 0.78rem; + line-height: 1.2; + pointer-events: none; + white-space: nowrap; +} +.scan-indicator.hidden { + display: none; +} +.scan-indicator span:last-child { + overflow: hidden; + text-overflow: ellipsis; +} +.scan-dot { + width: 0.5rem; + height: 0.5rem; + flex: 0 0 auto; + border-radius: 50%; + background: var(--accent); + box-shadow: 0 0 0 0 var(--accent-soft); + animation: scanPulse 1.4s ease-out infinite; +} +@keyframes scanPulse { + 0% { box-shadow: 0 0 0 0 var(--accent-soft); } + 100% { box-shadow: 0 0 0 0.45rem transparent; } +} + +/* Sidebar */ +.sidebar { + position: fixed; + inset: var(--header-height) auto 0 0; + width: var(--sidebar-width); + background: var(--bg-surface); + border-right: 1px solid var(--border); + overflow: auto; + padding: 0.75rem 0.5rem; + display: none; /* hidden by default */ + flex-direction: column; + gap: 0.25rem; + z-index: 40; +} +.sidebar.open { + display: flex; +} +.sidebar h2 { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--text-muted); + margin: 0.5rem 0.5rem 0.25rem; + padding-bottom: 0.25rem; + border-bottom: 1px solid var(--border); +} +.sidebar .set-item { + display: block; + padding: 0.4rem 0.6rem; + border-radius: var(--radius-sm); + color: var(--text-secondary); + text-decoration: none; + cursor: pointer; + user-select: none; +} +.sidebar .set-item:hover, +.sidebar .set-item:focus-visible { + background: var(--bg-surface-hover); + color: var(--text-primary); + outline: none; +} +.sidebar .set-item.active { + background: var(--accent-soft); + color: var(--accent); + font-weight: 600; +} +.sidebar .set-item.selected { + border: 2px solid var(--accent); + background: var(--bg-elevated); + color: var(--text-primary); + font-weight: 600; +} +.sidebar-header { + display: flex; + align-items: center; + justify-content: space-between; +} + +/* Main layout */ +.page { + padding-top: var(--header-height); + min-height: 100vh; +} +.page.has-sidebar { + padding-left: var(--sidebar-width); +} +.main-content { + padding: var(--gap); + max-width: 100%; +} + +/* Breadcrumb bar */ +.breadcrumb-bar { + display: flex; + align-items: center; + gap: 0.35rem; + flex-wrap: wrap; + margin-bottom: 0.75rem; + font-size: 0.85rem; +} +.breadcrumb-bar.hidden { display: none !important; } +.breadcrumb-bar button { + background: transparent; + border: none; + color: var(--accent); + padding: 0.15rem 0.25rem; + cursor: pointer; + font: inherit; + border-radius: var(--radius-sm); +} +.breadcrumb-bar button:hover { background: var(--accent-soft); } +.breadcrumb-bar .breadcrumb-sep { color: var(--text-muted); user-select: none; } + +/* Folder card placeholder */ +.folder-card .thumb-wrap .placeholder { font-size: 3rem; } +.set-card .thumb-wrap .placeholder { font-size: 3rem; } +.set-card .thumb-wrap img + .placeholder { display: none; } + +/* Media grid */ +.media-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); + gap: var(--gap); +} +.media-pager { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + padding: 0.5rem 0.65rem; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--bg-surface); +} +.media-pager-top { + margin-bottom: 0.1rem; +} +.media-pager-bottom { + margin-top: 0.1rem; +} +.media-page-summary { + color: var(--text-secondary); + font-size: 0.85rem; +} +.media-card { + position: relative; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-md); + overflow: hidden; + cursor: pointer; + transition: transform var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast); +} +.media-card:hover { + box-shadow: var(--shadow-md); + border-color: var(--border-strong); +} +.media-card.selected { + border-color: var(--selected-border); + background: var(--selected-bg); +} +.media-card.playing { + border-color: var(--playing-border); + background: var(--playing-bg); +} +.media-card .thumb-wrap { + position: relative; + aspect-ratio: 16 / 9; + background: var(--bg-elevated); + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.media-card .thumb-wrap img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.media-card .thumb-wrap .placeholder { + color: var(--text-muted); + font-size: 0.85rem; +} +.media-card .meta { + padding: 0.55rem 0.65rem; + display: flex; + flex-direction: column; + gap: 0.15rem; + min-height: 3.5rem; +} +.media-card .title { + font-size: 0.9rem; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.media-card .subtitle { + font-size: 0.78rem; + color: var(--text-secondary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.media-card .badge { + position: absolute; + top: 0.35rem; + right: 0.35rem; + font-size: 0.65rem; + padding: 0.15rem 0.4rem; + border-radius: var(--radius-sm); + background: var(--bg-overlay); + color: var(--text-primary); +} + +.media-card .card-actions { + position: absolute; + bottom: 0.35rem; + left: 0; + right: 0; + display: flex; + gap: 0.25rem; + justify-content: center; + opacity: 0; + transition: opacity var(--transition-fast); + z-index: 2; +} +.media-card:hover .card-actions, +.media-card.selected .card-actions, +.media-card.playing .card-actions { + opacity: 1; +} + +/* Audio row variant */ +.media-row { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 0.75rem; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-md); + cursor: pointer; + transition: border-color var(--transition-fast), background var(--transition-fast); +} +.media-row:hover { + background: var(--bg-surface-hover); + border-color: var(--border-strong); +} +.media-row.selected { + border-color: var(--selected-border); + background: var(--selected-bg); +} +.media-row.playing { + border-color: var(--playing-border); + background: var(--playing-bg); +} +.media-row .row-icon { + color: var(--text-muted); + font-size: 1.1rem; +} +.media-row .row-body { + min-width: 0; + flex: 1 1 auto; +} +.media-row .row-title { + font-size: 0.9rem; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.media-row .row-meta { + font-size: 0.78rem; + color: var(--text-secondary); +} +.media-row .row-duration { + font-size: 0.78rem; + color: var(--text-muted); + white-space: nowrap; +} + +.media-row .row-cover { + width: 2.8rem; + height: 2.8rem; + object-fit: cover; + border-radius: var(--radius-sm); + flex-shrink: 0; + background: var(--bg-elevated); +} + +/* Hide row action buttons unless hovered/selected/playing */ +.media-row button[data-action] { + opacity: 0; + transition: opacity var(--transition-fast); +} +.media-row:hover button[data-action], +.media-row.selected button[data-action], +.media-row.playing button[data-action] { + opacity: 1; +} + +/* Modal */ +.modal-overlay { + position: fixed; + inset: 0; + background: var(--bg-overlay); + display: grid; + place-items: center; + z-index: 100; + opacity: 0; + visibility: hidden; + transition: opacity var(--transition-base), visibility var(--transition-base); +} +.modal-overlay.open { + opacity: 1; + visibility: visible; +} +.modal { + background: var(--bg-surface); + border: 1px solid var(--border-strong); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + width: min(40rem, 92vw); + max-height: 86vh; + overflow: auto; + padding: 1.25rem; +} +.modal-header { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.75rem; +} +.modal-header h3 { margin: 0; font-size: 1.1rem; } +.modal-header .spacer { flex: 1 1 auto; } + +/* Help modal */ +.help-modal { + width: min(64rem, 96vw); +} +.help-content { + overflow: auto; +} +.help-shortcuts { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); + gap: 0.35rem 0.75rem; + font-size: 0.88rem; +} +.help-row { + display: grid; + grid-template-columns: minmax(4.6rem, auto) 1fr; + align-items: center; + gap: 0.5rem; + min-height: 2rem; + padding: 0.25rem 0.35rem; + border-bottom: 1px solid var(--border); +} +.help-row > span:first-child { + white-space: nowrap; + font-family: var(--font-mono); +} +.help-content kbd { + display: inline-block; + padding: 0.15rem 0.4rem; + border-radius: var(--radius-sm); + background: var(--bg-elevated); + border: 1px solid var(--border-strong); + font-size: 0.8rem; + min-width: 1.6rem; + text-align: center; +} +.help-shares { + line-height: 1.7; +} + +/* Media info modal */ +.media-info-table { + width: 100%; + border-collapse: collapse; + font-size: 0.9rem; +} +.media-info-table th, +.media-info-table td { + padding: 0.45rem 0.5rem; + border-bottom: 1px solid var(--border); + vertical-align: top; +} +.media-info-table th { + width: 11rem; + color: var(--text-secondary); + font-weight: 600; + text-align: left; +} +.media-info-table td { + color: var(--text-primary); + overflow-wrap: anywhere; +} +.media-info-raw { + margin-top: 1rem; + font-size: 0.85rem; +} +.media-info-raw summary { + cursor: pointer; + color: var(--text-secondary); +} +.media-info-raw pre { + max-height: 18rem; + overflow: auto; + padding: 0.75rem; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--bg-elevated); + color: var(--text-primary); + white-space: pre-wrap; + overflow-wrap: anywhere; +} + +/* Responsive */ +@media (max-width: 860px) { + :root { + --header-height: 3rem; + --sidebar-width: 0; + } + .site-header { + gap: 0.35rem; + padding: 0 0.5rem; + } + .header-main { + gap: 0.35rem; + } + .search-bar { + max-width: none; + min-width: 0; + flex: 1 1 auto; + } + .sidebar { + position: fixed; + inset: var(--header-height) auto auto 0; + width: 100%; + height: auto; + max-height: 70vh; + border-right: none; + border-bottom: 1px solid var(--border); + display: none; + } + .sidebar.open { display: flex; } + .page { padding-left: 0; } + .page.has-sidebar { padding-left: 0; } + .player { inset: auto 0 0 0 !important; } + .toolbar { + flex-wrap: wrap; + gap: 0.35rem; + } + .toolbar .input-sm { + min-width: 4.5rem; + max-width: none; + flex: 1 1 4.5rem; + } + .site-header .logo { + font-size: 0.9rem; + } + #theme-toggle, + #user-name { + display: none; + } + #logout-btn { + padding: 0.3rem 0.5rem; + font-size: 0.75rem; + } + .media-grid { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); } +} + +@media (max-width: 520px) { + .media-grid { grid-template-columns: repeat(2, 1fr); } + .toolbar .input-sm { + min-width: 3.5rem; + } +} + +/* Utilities */ +.hidden { display: none !important; } +.overflow-hidden { overflow: hidden; } + +/* Layout helpers */ +.flex { display: flex; } +.flex-wrap { flex-wrap: wrap; } +.justify-end { justify-content: flex-end; } +.align-center { align-items: center; } +.gap-1 { gap: 0.25rem; } +.gap-2 { gap: 0.5rem; } +.gap-3 { gap: 0.75rem; } +.gap-4 { gap: 1rem; } +.mt-1 { margin-top: 0.25rem; } +.mt-2 { margin-top: 0.5rem; } +.mt-3 { margin-top: 0.75rem; } +.my-1 { margin: 0.25rem 0; } +.mb-2 { margin-bottom: 0.5rem; } +.py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; } +.border-b { border-bottom: 1px solid var(--border); } +.text-sm { font-size: 0.85rem; } +.text-xs { font-size: 0.8rem; } +.text-75 { font-size: 0.75rem; } +.text-90 { font-size: 0.9rem; } +.text-muted { color: var(--text-muted); } +.text-danger { color: var(--danger); } +.flex-1-18 { flex: 1 1 18rem; } +.flex-col { flex-direction: column; } +.truncate { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.set-row { + display: flex; + align-items: center; + gap: 0.25rem; + padding-right: 0.25rem; +} +.tag-chip { + display: inline-flex; + align-items: center; + gap: 0.2rem; + padding: 0.2rem 0.5rem; + border-radius: var(--radius-sm); + background: var(--accent-soft); + color: var(--accent); + font-size: 0.78rem; +} +.grid-full { grid-column: 1 / -1; } + +/* Toolbar */ +.toolbar { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.75rem; +} + +/* Empty state hint */ +.empty-hint { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 50vh; + gap: 0.5rem; + text-align: center; +} +.empty-hint p { + margin: 0; + font-size: 1.1rem; + color: var(--text-secondary); +} +.empty-hint kbd { + display: inline-block; + padding: 0.15rem 0.4rem; + border-radius: var(--radius-sm); + background: var(--bg-elevated); + border: 1px solid var(--border-strong); + font-family: var(--font-mono); + font-size: 0.85rem; +} +.empty-hint.hidden { display: none !important; } + +/* Modal sizes */ +.modal-wide { width: min(56rem, 96vw); } + +/* Admin lists */ +.admin-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 0.35rem; +} +.admin-list li { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.25rem 0.35rem; + border-radius: var(--radius-sm); +} +.admin-list li.is-admin { + background: var(--accent-soft); +} + +#admin-permissions { + max-width: 100%; + overflow-x: auto; +} + +.admin-table { + width: max-content; + min-width: 100%; + border-collapse: collapse; + font-size: 0.82rem; +} + +.admin-table th, +.admin-table td { + padding: 0.35rem 0.45rem; + border-bottom: 1px solid var(--border); + text-align: left; + vertical-align: middle; + white-space: nowrap; +} + +.admin-table th:first-child, +.admin-table td:first-child { + max-width: 12rem; + overflow: hidden; + text-overflow: ellipsis; +} + +.admin-table .perm-select { + min-width: 5.5rem; +} + +.podcast-feed-row { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.35rem 0; + border-bottom: 1px solid var(--border); +} + +.podcast-feed-cover { + width: 2.5rem; + height: 2.5rem; + border-radius: var(--radius-sm); + object-fit: cover; + background: var(--bg-elevated); + border: 1px solid var(--border); + flex: 0 0 auto; +} + +.btn-download-episode { + align-self: flex-start; + margin-top: 0.2rem; +} -- cgit v1.2.3