Files
warpbox-dev/backend/static/css/16-retro.css
Daniel Legt d3b6a86753
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m45s
feat(file-browser): make entire file card clickable in list view
Improve the user experience in the file browser list view by allowing users to click anywhere on a file card to open it, rather than just the specific link.

- Add a click event listener to the file browser to handle navigation when clicking a card in list view.
- Ensure interactive elements (like buttons or inputs) inside the card do not trigger the card-wide click.
- Add `cursor: pointer` to list view file cards to indicate they are clickable.
- Update retro theme CSS to style the entire card on hover and focus.
2026-06-02 14:45:55 +03:00

744 lines
20 KiB
CSS
Raw 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.
/*
* "retro" theme flourishes — modelled on danlegt.com.
*
* Windows 98 chrome over a black pixel-star desktop, PixeloidSans pixel font,
* crisp (non-antialiased, pixelated) rendering. Scoped entirely to
* :root[data-theme="retro"] so it never touches the other themes.
*
* CSP-safe: external stylesheet + self-hosted fonts only (font-src 'self'),
* no inline styles, no remote assets. The starfield is pure CSS so we don't
* depend on img-src for a background gif.
*/
/* Self-hosted pixel fonts (mirrored locally — GGBotNet PixeloidSans is free,
PixelOperator is CC0). ------------------------------------------------- */
@font-face {
font-family: "PixeloidSans";
src: url("/static/fonts/pixeloid_sans/PixeloidSans.ttf") format("truetype");
font-weight: normal;
font-display: swap;
}
@font-face {
font-family: "PixeloidSans";
src: url("/static/fonts/pixeloid_sans/PixeloidSans-Bold.ttf") format("truetype");
font-weight: bold;
font-display: swap;
}
@font-face {
font-family: "PixelOperatorMono";
src: url("/static/fonts/pixel_operator/PixelOperatorMono.ttf") format("truetype");
font-weight: normal;
font-display: swap;
}
@font-face {
font-family: "PixelOperatorMono";
src: url("/static/fonts/pixel_operator/PixelOperatorMono-Bold.ttf") format("truetype");
font-weight: bold;
font-display: swap;
}
/* Crisp, pixelated, non-smoothed rendering like the source site. */
:root[data-theme="retro"] {
font-smooth: never;
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: unset;
}
:root[data-theme="retro"] img,
:root[data-theme="retro"] .thumb-link img,
:root[data-theme="retro"] .preview-stage img {
image-rendering: pixelated;
}
/* Square everything — Win98 had no rounded corners. */
:root[data-theme="retro"] *,
:root[data-theme="retro"] *::before,
:root[data-theme="retro"] *::after {
border-radius: 0 !important;
}
/* Black desktop with the tiled starfield mirrored from danlegt.com. */
:root[data-theme="retro"] body {
background-color: #000000;
background-image: url("/static/backgrounds/stars1.gif");
background-repeat: repeat;
background-attachment: fixed;
image-rendering: pixelated;
}
/* Selection + focus use the classic dotted/navy treatment. */
:root[data-theme="retro"] ::selection {
background: #000078;
color: #ffffff;
}
:root[data-theme="retro"] :focus-visible {
outline: 1px dotted #000000;
outline-offset: -4px;
}
/* Header: thin flat silver toolbar with a bottom bevel. */
:root[data-theme="retro"] .site-header {
background: #c0c0c0;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border-bottom: 2px solid #404040;
box-shadow: inset 0 1px 0 #ffffff;
}
:root[data-theme="retro"] .nav {
min-height: 2.1rem;
}
:root[data-theme="retro"] .site-header .button {
min-height: 1.6rem;
padding: 0.15rem 0.6rem;
}
:root[data-theme="retro"] .brand {
color: #000000;
font-size: 0.95rem;
}
:root[data-theme="retro"] .brand-mark {
width: 1.4rem;
height: 1.4rem;
background: linear-gradient(90deg, #000078, 80%, #0f80cd);
color: #ffffff;
font-size: 0.75rem;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #6f6fff;
}
/* Cards are raised silver windows with black text. */
:root[data-theme="retro"] .card {
background: linear-gradient(to bottom, #ffffff, 4%, #c0c0c0 8%);
background-color: #c0c0c0;
color: #000000;
border: 1px solid #000000;
box-shadow: var(--shadow);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
/* Headings become Win98 active title bars. */
:root[data-theme="retro"] h1 {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
margin: -0.35rem -0.35rem 1rem;
padding: 0.35rem 0.5rem;
background: linear-gradient(to right, #000078, 80%, #0f80cd);
color: #ffffff;
font-size: 1rem;
font-weight: 700;
letter-spacing: 0;
text-shadow: none;
}
/* Fake window control button on the right of every title bar. */
:root[data-theme="retro"] h1::after {
content: "✕";
display: grid;
place-items: center;
width: 1.15rem;
height: 1rem;
background: #c0c0c0;
color: #000000;
font-size: 0.7rem;
font-weight: 700;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #ffffff, inset -2px -2px 0 #808080, inset 2px 2px 0 #dfdfdf;
}
/* Links: classic blue, underlined, purple when visited. Sidebar links and tabs
are styled as their own Win98 controls below, so they're excluded here. */
:root[data-theme="retro"] a:not(.button):not(.brand):not(.sidebar-link):not(.tab):not(.sort-link) {
color: #0000ee;
text-decoration: underline;
}
:root[data-theme="retro"] a:not(.button):not(.brand):not(.sidebar-link):not(.tab):not(.sort-link):visited {
color: #551a8b;
}
:root[data-theme="retro"] a:not(.button):not(.brand):not(.sidebar-link):not(.tab):not(.sort-link):hover {
color: #ee0000;
}
/* Buttons: grey beveled chunks that press in when active. */
:root[data-theme="retro"] .button,
:root[data-theme="retro"] button {
background: #c0c0c0;
color: #000000;
border: 1px solid #000000;
font-weight: 700;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #ffffff, inset -2px -2px 0 #808080, inset 2px 2px 0 #dfdfdf;
}
:root[data-theme="retro"] .button:hover,
:root[data-theme="retro"] button:hover {
background: #d4d0c8;
}
:root[data-theme="retro"] .button:active,
:root[data-theme="retro"] button:active,
:root[data-theme="retro"] .button.is-active {
background: #c0c0c0;
box-shadow: inset 1px 1px 0 #404040, inset -1px -1px 0 #ffffff, inset 2px 2px 0 #808080, inset -2px -2px 0 #dfdfdf;
padding-top: calc(0.45rem + 1px);
padding-left: calc(0.85rem + 1px);
}
/* The primary call-to-action is a glossy raised blue button. A vertical
gradient + strong 3D bevel keeps it clearly a button (and distinct from the
horizontal title-bar gradient). */
:root[data-theme="retro"] .button-primary {
background: linear-gradient(to bottom, #2f86e0 0%, #0a3aa0 52%, #000078 100%);
color: #ffffff;
border: 1px solid #000000;
box-shadow: inset -1px -1px 0 #00003a, inset 1px 1px 0 #7fc0ff, inset -2px -2px 0 #001a6a, inset 2px 2px 0 #3f9fe8;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.4);
}
:root[data-theme="retro"] .button-primary:hover {
filter: brightness(1.08);
}
:root[data-theme="retro"] .button-primary:active {
box-shadow: inset 1px 1px 0 #00003a, inset -1px -1px 0 #7fc0ff;
padding-top: calc(0.45rem + 1px);
padding-left: calc(0.85rem + 1px);
}
:root[data-theme="retro"] .button-danger {
background: #c0c0c0;
color: #c00000;
border-color: #000000;
}
/* Inputs and selects look sunken (inset bevel). */
:root[data-theme="retro"] input,
:root[data-theme="retro"] select,
:root[data-theme="retro"] textarea {
background: #ffffff;
color: #000000;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #ffffff;
}
:root[data-theme="retro"] input:focus,
:root[data-theme="retro"] select:focus {
outline: 1px dotted #000000;
outline-offset: -3px;
}
/* Labels inside windows read black, not muted-grey-on-grey. */
:root[data-theme="retro"] label span,
:root[data-theme="retro"] .stack-form label,
:root[data-theme="retro"] .form-footer p,
:root[data-theme="retro"] .drop-copy,
:root[data-theme="retro"] .drop-meta,
:root[data-theme="retro"] .upload-subtitle,
:root[data-theme="retro"] .download-subtitle,
:root[data-theme="retro"] .muted-copy,
:root[data-theme="retro"] .kicker,
:root[data-theme="retro"] .checkbox-field span {
color: #1a1a1a;
}
/* API / docs page: the header is a real full-width window with the intro text
inside it, and each section card gets a Win98 title bar from its <h2>. */
:root[data-theme="retro"] .docs-header {
max-width: none;
margin-bottom: 1.5rem;
padding: 1.5rem;
background: linear-gradient(to bottom, #ffffff, 4%, #c0c0c0 8%);
background-color: #c0c0c0;
color: #000000;
border: 1px solid #000000;
box-shadow: var(--shadow);
}
:root[data-theme="retro"] .docs-header .kicker {
display: none;
}
:root[data-theme="retro"] .docs-header p,
:root[data-theme="retro"] .docs-header code {
color: #000000;
margin-bottom: 0;
}
:root[data-theme="retro"] .docs-card h2,
:root[data-theme="retro"] .upload-options .options-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
margin: -1.5rem -1.5rem 1rem;
padding: 0.35rem 0.5rem;
background: linear-gradient(to right, #000078, 80%, #0f80cd);
color: #ffffff;
font-size: 1rem;
font-weight: 700;
}
/* Make title bars flush to the window edge (a real Win98 title bar) wherever
the heading is the top of its window: the upload card, the API header, and
the API section cards. Pages where a heading sits below an icon or kicker
(download/preview/login) keep the inset heading from the base h1 rule. */
:root[data-theme="retro"] .card-content > h1:first-child,
:root[data-theme="retro"] .docs-header h1,
:root[data-theme="retro"] .download-view-wide .download-card h1 {
margin: -1.5rem -1.5rem 1rem;
}
:root[data-theme="retro"] .docs-card h2::after,
:root[data-theme="retro"] .upload-options .options-title::after {
content: "✕";
display: grid;
place-items: center;
width: 1.15rem;
height: 1rem;
background: #c0c0c0;
color: #000000;
font-size: 0.7rem;
font-weight: 700;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #ffffff, inset -2px -2px 0 #808080, inset 2px 2px 0 #dfdfdf;
}
/* Drop zone: a sunken white field with a dashed navy border. */
:root[data-theme="retro"] .drop-zone {
background: #ffffff;
border: 2px dashed #000078;
box-shadow: inset 2px 2px 0 #808080, inset -2px -2px 0 #ffffff;
}
:root[data-theme="retro"] .drop-zone:hover,
:root[data-theme="retro"] .drop-zone.is-dragging {
background: #fffff0;
border-color: #0f80cd;
}
:root[data-theme="retro"] .drop-icon {
color: #000078;
}
/* The hero "Welcome" badge becomes a high-contrast blinking pixel sticker
that sits on the black desktop above the window. */
:root[data-theme="retro"] .hero-eyebrow {
background: linear-gradient(to right, #000078, 80%, #0f80cd);
border: 1px solid #000000;
color: #ffffff;
font-weight: 700;
text-transform: uppercase;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #6f6fff;
}
:root[data-theme="retro"] .hero-eyebrow::before {
content: "★ ";
color: #ffff66;
animation: retro-blink 1.1s steps(1, end) infinite;
}
:root[data-theme="retro"] .hero-eyebrow::after {
content: " ★";
color: #ffff66;
animation: retro-blink 1.1s steps(1, end) 0.55s infinite;
}
@keyframes retro-blink {
50% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
:root[data-theme="retro"] .hero-eyebrow::before,
:root[data-theme="retro"] .hero-eyebrow::after {
animation: none;
}
}
/* Badges become square chips. */
:root[data-theme="retro"] .badge {
background: #ffffff;
color: #000000;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #808080;
}
/* File / result rows: flat white with a sunken hairline. */
:root[data-theme="retro"] .download-item,
:root[data-theme="retro"] .result-item {
background: #ffffff;
color: #000000;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #dfdfdf, inset -1px -1px 0 #808080;
}
:root[data-theme="retro"] .file-main,
:root[data-theme="retro"] .download-item small,
:root[data-theme="retro"] .result-item code {
color: #000000;
}
:root[data-theme="retro"] .file-emblem {
background: #000078;
color: #ffffff;
border: 1px solid #000000;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #4a4aff;
}
/* Code blocks use the pixel mono font. */
:root[data-theme="retro"] code,
:root[data-theme="retro"] pre,
:root[data-theme="retro"] pre code {
font-family: "PixelOperatorMono", ui-monospace, monospace;
color: #000000;
}
:root[data-theme="retro"] pre {
background: #ffffff;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #808080;
}
/* Progress bar: blocky segmented Win98 look. */
:root[data-theme="retro"] .progress {
background: #ffffff;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #808080;
}
:root[data-theme="retro"] .progress span {
background: repeating-linear-gradient(90deg, #000078 0 8px, transparent 8px 10px), #0f80cd;
}
/* Chunky retro scrollbars (WebKit/Blink). */
:root[data-theme="retro"] ::-webkit-scrollbar {
width: 16px;
height: 16px;
}
:root[data-theme="retro"] ::-webkit-scrollbar-track {
background: #dfdfdf;
}
:root[data-theme="retro"] ::-webkit-scrollbar-thumb {
background: #c0c0c0;
border: 1px solid #000000;
box-shadow: inset -1px -1px 0 #808080, inset 1px 1px 0 #ffffff;
}
/* Footer sits on the black desktop: white pixel text + a wink to the old web. */
:root[data-theme="retro"] .site-footer {
color: #ffffff;
}
:root[data-theme="retro"] .site-footer a,
:root[data-theme="retro"] .footer-links a:not(.button) {
color: #66ccff;
}
:root[data-theme="retro"] .theme-picker > span {
color: #ffffff;
}
:root[data-theme="retro"] .site-footer::after {
content: "✩ Best viewed in 1024×768 ✩";
font-weight: 700;
}
@media (max-width: 720px) {
:root[data-theme="retro"] .site-footer::after {
display: none;
}
}
/* ------------------------------------------------------------------------- */
/* App / admin shell (dashboard, account, admin pages) */
/* These use dark revamp tokens by default, which are unreadable on the black */
/* retro desktop. Re-skin them as Win98 chrome: a raised silver sidebar with */
/* solid links, light page headers on the desktop, and bevelled stat cards. */
/* ------------------------------------------------------------------------- */
/* Sidebar = raised silver panel. */
:root[data-theme="retro"] .app-sidebar,
:root[data-theme="retro"] .admin-shell .app-sidebar {
background: #c0c0c0;
border: 1px solid #000000;
box-shadow: var(--shadow);
}
:root[data-theme="retro"] .sidebar-link {
color: #000000;
border: 1px solid transparent;
font-weight: 700;
}
:root[data-theme="retro"] .sidebar-link:hover,
:root[data-theme="retro"] .sidebar-link.is-active,
:root[data-theme="retro"] .admin-shell .sidebar-link.is-active {
background: linear-gradient(to right, #000078, 80%, #0f80cd);
color: #ffffff;
border-color: #000000;
}
:root[data-theme="retro"] .sidebar-sep {
background: #808080;
height: 2px;
box-shadow: 0 1px 0 #ffffff;
}
/* Page header sits on the black desktop: light kicker, plain light title
(not a floating title bar), light subtitle. */
:root[data-theme="retro"] .admin-header .kicker {
color: #ffd966;
}
:root[data-theme="retro"] .admin-header .muted-copy {
color: #cfd8ff;
}
:root[data-theme="retro"] .admin-header h1 {
margin: 0;
padding: 0;
display: block;
background: none;
color: #ffffff;
}
:root[data-theme="retro"] .admin-header h1::after {
content: none;
}
/* Collection / nav tabs become small bevelled buttons. */
:root[data-theme="retro"] .tab {
background: #c0c0c0;
color: #000000;
border: 1px solid #000000;
font-weight: 700;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #ffffff, inset -2px -2px 0 #808080, inset 2px 2px 0 #dfdfdf;
}
:root[data-theme="retro"] .tab:hover {
background: #d4d0c8;
color: #000000;
}
:root[data-theme="retro"] .tab.is-active {
background: linear-gradient(to right, #000078, 80%, #0f80cd);
color: #ffffff;
}
/* Metric cards = sunken white stat boxes with crisp black numbers. */
:root[data-theme="retro"] .metric-card {
background: #ffffff;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #ffffff;
}
:root[data-theme="retro"] .metric-card span {
color: #404040;
}
:root[data-theme="retro"] .metric-card strong {
color: #000000;
}
/* The "+ Collection" popover becomes a small floating window. */
:root[data-theme="retro"] .new-collection-body {
background: #c0c0c0;
border: 1px solid #000000;
box-shadow: var(--shadow);
color: #000000;
}
/* The storage inline edit form panel. */
:root[data-theme="retro"] .storage-edit-form {
background: #c0c0c0;
border: 1px solid #000000;
box-shadow: var(--shadow);
}
/* ------------------------------------------------------------------------- */
/* Download / box page */
/* ------------------------------------------------------------------------- */
/* The decorative file glyph above the title doesn't suit a Win98 window. */
:root[data-theme="retro"] .file-emblem {
display: none;
}
/* The download window's content is left-aligned like a real file manager. */
:root[data-theme="retro"] .download-view-wide .download-card {
text-align: left;
}
/* Expiry shown as a sunken status field with a little clock. */
:root[data-theme="retro"] .badge-row {
justify-content: flex-start;
}
:root[data-theme="retro"] .badge-expiry {
background: #ffffff;
color: #000000;
border: 1px solid #000000;
box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #ffffff;
font-weight: 700;
padding: 0.3rem 0.7rem;
}
:root[data-theme="retro"] .badge-expiry::before {
content: "\23F1 ";
}
/* The file browser becomes a Win98 Explorer window: blue titlebar, grey
toolbar, sunken content pane and flat rows. */
:root[data-theme="retro"] .file-browser-window {
border: 1px solid #000000;
border-radius: 0;
background: #c0c0c0;
box-shadow: inset -1px -1px 0 #404040, inset 1px 1px 0 #ffffff, inset -2px -2px 0 #808080, inset 2px 2px 0 #dfdfdf;
}
:root[data-theme="retro"] .file-browser-titlebar {
min-height: 1.8rem;
margin: 3px 3px 0;
padding: 0.2rem 0.45rem;
border: 0;
background: linear-gradient(to right, #000078 0%, #000078 80%, #0f80cd 100%);
color: #ffffff;
}
:root[data-theme="retro"] .file-browser-titlebar strong,
:root[data-theme="retro"] .file-browser-titlebar span {
color: #ffffff;
font-size: 0.78rem;
}
:root[data-theme="retro"] .file-browser-window-actions {
display: none;
}
:root[data-theme="retro"] .file-browser-toolbar {
justify-content: space-between;
margin: 0 3px;
padding: 3px;
border: 0;
border-bottom: 1px solid #808080;
background: #c0c0c0;
}
:root[data-theme="retro"] .view-toolbar {
justify-content: flex-start;
gap: 2px;
margin-top: 0;
padding: 0;
background: #c0c0c0;
border: 0;
box-shadow: none;
}
:root[data-theme="retro"] .view-toolbar .button,
:root[data-theme="retro"] .file-browser-toolbar > .button {
display: inline-grid;
place-items: center;
background: transparent;
border: 1px solid transparent;
box-shadow: none;
font-weight: 400;
}
:root[data-theme="retro"] .view-toolbar .icon-button {
width: 2.2rem;
height: 2rem;
padding: 0;
}
:root[data-theme="retro"] .view-toolbar .icon-button svg {
margin: 0;
display: block;
}
:root[data-theme="retro"] .view-toolbar .button:hover,
:root[data-theme="retro"] .file-browser-toolbar > .button:hover {
background: #c0c0c0;
box-shadow: inset -1px -1px 0 #808080, inset 1px 1px 0 #ffffff;
}
:root[data-theme="retro"] .view-toolbar .button.is-active,
:root[data-theme="retro"] .file-browser-toolbar > .button.is-active {
background: #d4d0c8;
box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #ffffff;
}
:root[data-theme="retro"] .file-browser-head {
margin: 0 3px;
border: 0;
border-bottom: 1px solid #808080;
background: #c0c0c0;
color: #000000;
text-transform: none;
}
:root[data-theme="retro"] .file-browser {
margin: 0 3px 3px;
border: 1px solid #000000;
background: #ffffff;
box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #ffffff;
}
:root[data-theme="retro"] .download-item {
border: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
}
:root[data-theme="retro"] .file-open {
border-radius: 0;
color: #000000;
}
:root[data-theme="retro"] .file-open:hover,
:root[data-theme="retro"] .file-open:focus-visible {
background: transparent;
color: #000000;
outline: 2px solid #000078;
outline-offset: -2px;
}
:root[data-theme="retro"] .file-browser.is-list .file-card:hover,
:root[data-theme="retro"] .file-browser.is-list .file-card:focus-within {
background: transparent;
outline: 2px solid #000078;
outline-offset: -2px;
}
:root[data-theme="retro"] .file-browser.is-list .file-card:hover .file-open,
:root[data-theme="retro"] .file-browser.is-list .file-card:focus-within .file-open {
outline: 0;
}
:root[data-theme="retro"] .file-media {
border: 0;
border-radius: 0;
background: transparent;
}
:root[data-theme="retro"] .file-browser.is-thumbs .file-open {
align-content: start;
justify-content: center;
}
:root[data-theme="retro"] .file-browser.is-thumbs .file-media {
justify-self: center;
align-self: start;
}
:root[data-theme="retro"] .file-type,
:root[data-theme="retro"] .file-size,
:root[data-theme="retro"] .file-main small {
color: inherit;
}