mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
The app and the tray stop polling. pdfs-core adds Request::Subscribe: the connection stays open and carries Event lines (status, transfers, and Changed with a Topic), with a heartbeat while quiet. In pdfs-fuse, an EventHub gives each subscriber a mailbox, code that changes something publishes its topic, and a sampler publishes the status, transfers and sync progress when they differ. The app follows the feed on one thread, paints status and transfers as they arrive, and reloads the page on screen when its topic changes, including after changes made with the pdfs CLI. A hidden window keeps the changes and catches up when focused. Front-ends fall back to polling a daemon that predates subscriptions. Refresh buttons leave the page headers; F5 and Ctrl+R still reload from the server. Photos gets a scrubber overlaid on the right edge of the timeline in place of the slider and scrollbar. It shows the years, appears when the pointer comes near or the timeline scrolls, names the month under the pointer and jumps to it on drag. Upload becomes a split button whose menu holds the Google Photos import. Tiles are pooled per row and rebound instead of rebuilt, hover scales the thumbnail to 1.02 without a shadow, and tiles lose their tooltip. On libadwaita 1.8 or newer the app uses AdwSpinner, AdwToggleGroup, AdwButtonRow and AdwShortcutsDialog, and keeps look-alike stand-ins on older releases (src/compat.rs, widgets/compat.rs). It still builds against libadwaita 1.5 and picks at run time, creating the newer widgets by class name through GtkBuilder, so every package gets them. PDFS_STAND_IN_WIDGETS forces the stand-ins. The Sync and share-link icons draw in full again: GTK drops group transforms from symbolic icons, so their coordinates are baked into the paths. All catalogs are updated and complete.
123 lines
9.1 KiB
CSS
123 lines
9.1 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; }
|
|
.sidebar-account { padding: 4px 4px 4px 8px; }
|
|
/* 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); }
|
|
.browser-statusbar { background-color: alpha(currentColor, 0.025); }
|
|
scale.browser-status-meter trough { min-width: 104px; 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; }
|
|
.viewer-top-bar { background: linear-gradient(to bottom, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0)); padding: 10px 16px 28px 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); }
|
|
.viewer-action-btn { color: white; background-color: rgba(255, 255, 255, 0.12); border-radius: 50%; min-width: 34px; min-height: 34px; margin-left: 4px; }
|
|
.viewer-action-btn:hover { background-color: rgba(255, 255, 255, 0.28); color: white; }
|
|
.viewer-action-btn:checked { background-color: var(--accent-bg-color); color: var(--accent-fg-color); }
|
|
.viewer-close-btn { background-color: rgba(255, 255, 255, 0.2); margin-left: 10px; }
|
|
.viewer-close-btn:hover { background-color: var(--destructive-bg-color); color: var(--destructive-fg-color); }
|
|
.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: 0.82rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: alpha(currentColor, 0.65); padding: 2px 2px 6px 2px; }
|
|
.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-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: 18px; padding-right: 18px; }
|
|
|
|
/* 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); }
|