mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-15 01:41:59 +01:00
A song in a listing showed a generic icon, and the player a music note. Both now show the song's cover: the picture in its tags, read with lofty, or else a cover, folder, front or album image in its folder. Only the tags are downloaded. A song up to 4 MiB comes whole. A larger one brings the ID3v2 tag or the FLAC metadata blocks at its start, an M4A's moov box, the first 4 MiB of an Ogg file, and the last 4 MiB for formats that keep their tags at the end. The parts are laid out in a sparse staging file at their own offsets, as video samples are. A folder cover comes from that image's cached thumbnail, the thumbnail its uploader attached, or the image itself. It is stored under the song. Uploads of songs carry their embedded cover as the Drive thumbnail.
149 lines
11 KiB
CSS
149 lines
11 KiB
CSS
/* Proton Drive for Linux — app stylesheet.
|
||
*
|
||
* Colours come from the libadwaita palette (var(--accent-bg-color),
|
||
* var(--success-color), ...) so the app follows the system accent, light/dark
|
||
* and high contrast. The one exception is the photo viewer, which always sits
|
||
* on a near-black backdrop and so uses fixed light-on-dark colours. The Proton
|
||
* theme is opt-in and lives in its own provider (see main.rs and
|
||
* proton-theme.css).
|
||
*/
|
||
|
||
/* Brand */
|
||
.brand-title { font-size: 1.6rem; font-weight: 800; }
|
||
|
||
/* Sidebar footer */
|
||
.sidebar-footer { padding: 6px 12px 12px 12px; }
|
||
.sidebar-status { padding: 6px 8px; border-radius: 8px; }
|
||
.sidebar-status image.success { color: var(--success-color); }
|
||
.sidebar-status image.warning { color: var(--warning-color); }
|
||
.sidebar-status image.error { color: var(--error-color); }
|
||
.sidebar-quota progressbar trough, .sidebar-quota progressbar progress { min-height: 4px; }
|
||
/* The account row is the main menu's button: a row, not a pushbutton, so
|
||
* the name keeps the text weight. */
|
||
button.sidebar-account { padding: 4px 8px; font-weight: normal; }
|
||
/* A count of what waits on a page, at the end of its sidebar row */
|
||
.sidebar-badge {
|
||
min-width: 10px;
|
||
padding: 0 7px;
|
||
border-radius: 999px;
|
||
background: alpha(currentColor, 0.15);
|
||
font-size: 0.8em;
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* Sync page status card: the state is the headline, the detail explains it */
|
||
.sync-card { padding: 18px 24px; }
|
||
.sync-card-icon { padding: 6px; }
|
||
.sync-card-icon.success { color: var(--success-color); }
|
||
.sync-card-icon.warning { color: var(--warning-color); }
|
||
.sync-card-icon.error { color: var(--error-color); }
|
||
|
||
/* File browser */
|
||
.file-grid { padding: 6px; }
|
||
.file-tile { padding: 8px; border-radius: 10px; }
|
||
.file-tile:hover { background: color-mix(in srgb, var(--accent-bg-color) 10%, transparent); }
|
||
.file-tile:selected, .file-tile:hover:selected { background: color-mix(in srgb, var(--accent-bg-color) 20%, transparent); }
|
||
.file-thumbnail { border-radius: 7px; }
|
||
.file-badge { -gtk-icon-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); }
|
||
.badge-pinned { color: var(--success-color); }
|
||
.badge-cached { color: var(--success-color); }
|
||
.badge-cloud { color: color-mix(in srgb, currentColor 55%, transparent); }
|
||
.badge-issue { color: var(--error-color); }
|
||
.browser-statusbar { background-color: alpha(currentColor, 0.025); }
|
||
/* The folder on screen, last in the breadcrumb trail: a flat button's side
|
||
* padding, so the "›" before it is spaced like the ones between buttons. */
|
||
.crumb-current { padding: 0 10px; }
|
||
scale.browser-status-meter trough { min-width: 140px; min-height: 6px; }
|
||
.bulk-bar { padding: 6px 8px; border-radius: 12px; background: color-mix(in srgb, var(--accent-bg-color) 12%, transparent); }
|
||
.dropzone { border: 2px dashed alpha(currentColor, 0.25); border-radius: 16px; padding: 28px 18px; transition: background 160ms ease, border-color 160ms ease; }
|
||
.dropzone-active { border-color: var(--accent-bg-color); background: color-mix(in srgb, var(--accent-bg-color) 10%, transparent); }
|
||
.files-drop-active { outline: 2px dashed var(--accent-bg-color); outline-offset: -4px; border-radius: 12px; background: color-mix(in srgb, var(--accent-bg-color) 6%, transparent); }
|
||
|
||
/* Photo viewer: always light-on-dark, whatever the system style */
|
||
.photo-viewer-window { background-color: #111014; }
|
||
.media-player-window video { background-color: black; }
|
||
.media-player-note { color: rgba(255, 255, 255, 0.5); }
|
||
.media-player-note .file-thumbnail { border-radius: 12px; }
|
||
.viewer-top-bar { background: linear-gradient(to bottom, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.45) 60%, rgba(0, 0, 0, 0)); padding: 10px 16px 40px 20px; color: white; }
|
||
.viewer-title { font-weight: 700; font-size: 1.05rem; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9); color: white; }
|
||
.viewer-counter { font-size: 0.8rem; color: rgba(255, 255, 255, 0.72); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9); }
|
||
/* Dark discs with a white glyph read on a white photo as well as on a black one. */
|
||
.viewer-action-btn { color: white; background-color: rgba(0, 0, 0, 0.5); border-radius: 50%; min-width: 36px; min-height: 36px; margin-left: 4px; -gtk-icon-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }
|
||
.viewer-action-btn:hover { background-color: rgba(0, 0, 0, 0.75); color: white; }
|
||
.viewer-action-btn:checked { background-color: var(--accent-bg-color); color: var(--accent-fg-color); }
|
||
.viewer-close-btn { margin-left: 12px; }
|
||
.viewer-close-btn:hover { background-color: var(--destructive-bg-color); color: var(--destructive-fg-color); }
|
||
.viewer-group-pill { color: white; background-color: rgba(0, 0, 0, 0.5); border-radius: 999px; min-height: 36px; padding: 0 14px; font-weight: 700; font-size: 0.85rem; }
|
||
.viewer-group-pill:hover { background-color: rgba(0, 0, 0, 0.75); color: white; }
|
||
.viewer-group-pill.lit { background-color: var(--accent-bg-color); color: var(--accent-fg-color); }
|
||
/* The thumbnail strip along the lightbox's bottom edge, the photo on screen ringed in the accent. */
|
||
.viewer-strip-bar { background: linear-gradient(to top, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0)); padding: 28px 12px 10px 12px; }
|
||
.viewer-strip { background: none; }
|
||
.viewer-strip > row { padding: 2px; margin: 0 2px; border-radius: 8px; background: none; }
|
||
.viewer-strip > row:hover { background-color: rgba(255, 255, 255, 0.15); }
|
||
.viewer-strip > row:selected { background-color: var(--accent-bg-color); }
|
||
.viewer-strip-thumb { border-radius: 6px; background-color: rgba(255, 255, 255, 0.08); }
|
||
.viewer-nav-btn { background-color: rgba(0, 0, 0, 0.45); color: white; margin: 20px; min-width: 44px; min-height: 44px; border-radius: 50%; opacity: 0.7; transition: opacity 150ms ease, background-color 150ms ease; }
|
||
.viewer-nav-btn:hover { background-color: rgba(0, 0, 0, 0.85); color: white; opacity: 1; }
|
||
.viewer-nav-btn:disabled { opacity: 0; }
|
||
.photo-scrubber { background: linear-gradient(to left, alpha(var(--window-bg-color), 0.92) 40%, alpha(var(--window-bg-color), 0)); }
|
||
.photo-scrubber-knob { background-color: var(--accent-bg-color); border-radius: 2px; }
|
||
.photo-scrubber-bubble { font-weight: 600; background-color: var(--popover-bg-color); color: var(--popover-fg-color); border-radius: 999px; padding: 4px 12px; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); }
|
||
.viewer-spinner { color: white; }
|
||
.viewer-status { color: white; font-size: 1rem; background-color: rgba(0, 0, 0, 0.75); padding: 12px 24px; border-radius: 12px; }
|
||
.viewer-info-panel { background-color: var(--window-bg-color); border-left: 1px solid alpha(currentColor, 0.12); }
|
||
|
||
/* Photos grid */
|
||
.gallery-day { font-size: 1.1rem; font-weight: 700; padding: 4px 2px 8px 2px; }
|
||
/* The check that picks a whole section: on hover, and always while selecting. */
|
||
.gallery-day-check { opacity: 0; transition: opacity 160ms ease; min-width: 24px; min-height: 24px; margin-bottom: 4px; }
|
||
.gallery-heading:hover .gallery-day-check, .gallery-heading.selecting .gallery-day-check, .gallery-day-check:focus-visible { opacity: 1; }
|
||
/* The section at the top of the grid, floating once its heading scrolled off. */
|
||
.gallery-float-heading { font-weight: 700; padding: 4px 12px; border-radius: 999px; background-color: color-mix(in srgb, var(--popover-bg-color) 92%, transparent); color: var(--popover-fg-color); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); }
|
||
.photo-tile { padding: 0; margin: 0; min-height: 0; min-width: 0; border: none; border-radius: 4px; background: none; box-shadow: none; }
|
||
.photo-tile:focus { outline: 2px solid var(--accent-color); outline-offset: -2px; }
|
||
.photo-thumb { transition: transform 220ms ease; }
|
||
.photo-tile:hover .photo-thumb { transform: scale(1.02); }
|
||
.photo-check { color: white; background: rgba(0, 0, 0, 0.5); border-radius: 999px; padding: 3px; }
|
||
.photo-check-on { background: var(--accent-bg-color); color: var(--accent-fg-color); }
|
||
.photo-tile-selected { outline: 3px solid var(--accent-bg-color); outline-offset: -3px; }
|
||
.photo-placeholder { color: alpha(currentColor, 0.35); background: alpha(currentColor, 0.07); }
|
||
.photo-caption { font-size: 0.78rem; color: white; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9); padding: 22px 10px 6px 10px; opacity: 0; transition: opacity 180ms ease; }
|
||
.photo-tile:hover .photo-caption { opacity: 1; background: linear-gradient(to top, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0)); }
|
||
.photo-video-badge { color: white; background: rgba(0, 0, 0, 0.45); border-radius: 999px; padding: 8px; min-width: 20px; min-height: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5); transition: background 160ms ease; }
|
||
.photo-video-badge-small { padding: 3px; min-width: 0; min-height: 0; }
|
||
.photo-tile:hover .photo-video-badge { background: color-mix(in srgb, var(--accent-bg-color) 85%, transparent); }
|
||
.photo-favorite-badge { color: white; -gtk-icon-shadow: 0 1px 3px rgba(0, 0, 0, 0.9); }
|
||
.photo-group-badge { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; color: white; background: rgba(0, 0, 0, 0.55); border-radius: 6px; padding: 1px 5px; margin: 6px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9); }
|
||
.memory-card { padding: 0; border-radius: 12px; }
|
||
.memory-cover { border-radius: 12px; background: alpha(currentColor, 0.06); }
|
||
.memory-label { font-weight: 700; color: white; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9); padding: 22px 10px 6px 10px; background: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); }
|
||
.album-card { padding: 0; border-radius: 16px; transition: background 180ms ease; }
|
||
.album-card:hover { background: alpha(currentColor, 0.07); }
|
||
.album-cover { border-radius: 16px; background: alpha(currentColor, 0.06); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.32); transition: box-shadow 180ms ease; }
|
||
.album-card:hover .album-cover { box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5); }
|
||
.album-card:hover .photo-thumb { transform: scale(1.05); }
|
||
.view-switch button, .view-switch toggle { padding-left: 12px; padding-right: 12px; }
|
||
|
||
/* Shared with Me: what a share lets me do, as a tinted pill beside the name. */
|
||
.role-pill { padding: 2px 10px; border-radius: 999px; font-weight: 600; color: var(--accent-color); background-color: color-mix(in srgb, var(--accent-bg-color) 16%, transparent); }
|
||
.role-pill.warning-pill { color: var(--warning-color); background-color: color-mix(in srgb, var(--warning-bg-color) 20%, transparent); }
|
||
|
||
/* Activity: the feed sits on the window background as one card per row, under
|
||
* day headings, like a boxed list with its rows set apart. */
|
||
listview.activity-feed { background: none; color: inherit; padding: 0 12px 18px 12px; }
|
||
listview.activity-feed > row { padding: 0; margin-bottom: 6px; background: none; }
|
||
listview.activity-feed > header { padding: 18px 6px 6px 6px; background: none; }
|
||
listview.activity-feed row.card { border-radius: 12px; }
|
||
|
||
/* Photos: how many timeline filters are on, as a small badge on the Filters button. */
|
||
.filter-count { min-width: 18px; padding: 0 5px; border-radius: 999px; font-size: 0.8em; font-weight: 700; color: var(--accent-fg-color); background-color: var(--accent-bg-color); }
|
||
/* The Places map: sea and land come in the map's own colours; markers (drawn
|
||
* in the area's own colour) in the accent. */
|
||
.places-map-frame { border-radius: 12px; }
|
||
.places-map { color: var(--accent-bg-color); }
|
||
/* Credit on the Places street map, in the corner as on every web map. */
|
||
.places-spot-photo { padding: 0; }
|
||
.places-spot-photo picture { border-radius: 6px; overflow: hidden; }
|
||
.places-map-credit { padding: 2px 8px; border-top-left-radius: 8px; color: var(--window-fg-color); background: color-mix(in srgb, var(--window-bg-color) 80%, transparent); }
|