Files
SealShare/resources/css/app.css
T
Andreas Reinhold / reiniandClaude Opus 5 845bf062ed Let the dashboard's sort dropdown span the shares card
The sort select above the admin dashboard's shares list was capped at
20rem by the admin-shares-sort wrapper. The wrapper and its rule in
app.css are gone, so the select stretches with the card's stack like
the other fields. CHANGELOG (Unreleased) notes it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 15:38:11 +02:00

316 lines
13 KiB
CSS

@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@import '../../vendor/nonameweb/livewire-material/resources/css/foundation.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/grid.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/pane.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/row.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/stack.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/layout/surface.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/account-menu.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/alert.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/badge.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/button.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/card.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/checkbox.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/divider.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/empty-state.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/file.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/form.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/group.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/icon.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/input.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/list-item.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/list.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/loading.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/menu-item.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/modal.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/pagination.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/password.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/progress.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/scheme-picker.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/section-nav.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/select.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/shape.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/stat.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/textarea.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/theme-toggle.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/toast.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/toggle.css';
@import '../../vendor/nonameweb/livewire-material/resources/css/components/toolbar.css';
@import './material-scheme.css';
/*
* SealShare's own rules, unlayered so they outrank every package rule: one section per view, in
* the order a visitor meets them — the layout and the page template, the share flow (upload,
* share created, download), the settings pages in their navigation's order, then admin.
*/
/*
* resources/views/layouts/app.blade.php: every page's main region.
*
* `<x-pane as="main">` gives the region its horizontal M3 margin (16px below `medium`, 24px from
* it); the page inside (components/page.blade.php) sets its own width and centres itself. The
* vertical rhythm is the app's own. The bottom padding clears the floating toolbar in
* partials/toolbar.blade.php by what the toolbar publishes as `--material-bottom-toolbar` (its top
* edge's distance from the window's bottom, safe area included), plus 16px. Never set
* `--material-bottom-bar` here: the toolbar reads it to place itself.
*/
.app-main {
padding-block-start: var(--md-sys-measurement-space400);
padding-block-end: calc(var(--material-bottom-toolbar, 0px) + var(--md-sys-measurement-space200));
}
@media (width >= 600px) {
.app-main {
padding-block-start: var(--md-sys-measurement-space600);
}
}
/* resources/views/components/page.blade.php: the site's own logo above the title on a `brand` page, at 1.x's 5rem-tall size, its width following the image. */
.page-logo {
block-size: 5rem;
}
/*
* resources/views/livewire/file-uploader.blade.php: the drop zone's dashed outline and its
* primary tint while dragging. `data-dragging` is Alpine's, not the package's, since no
* component tracks a native drag over an arbitrary drop target; disabled where uploads cannot run
* (no secure context) blocks pointer events and dims to M3's disabled-content opacity, as a code dims elsewhere while
* busy (.settings-recovery-code--loading).
*/
.upload-drop-zone {
padding: var(--md-sys-measurement-space400);
border: 2px dashed var(--md-sys-color-outline-variant);
border-radius: var(--md-sys-shape-corner-xl);
transition: border-color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default), background-color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
}
.upload-drop-zone[data-dragging='true'] {
border-color: var(--md-sys-color-primary);
background-color: color-mix(in srgb, var(--md-sys-color-primary-container) 40%, transparent);
}
.upload-drop-zone[aria-disabled='true'] {
pointer-events: none;
opacity: var(--md-sys-state-disabled-content-opacity);
}
/*
* resources/views/livewire/file-uploader.blade.php: the drop zone's shape morphs into a burst
* while files are dragged over it — SealShare's signature, kept from 1.x (docs/reference/m3/styles.md
* § Shape: "Shape morph should respond to user interaction"). Two `<x-shape>`s sit
* stacked (`inset: 0` on an absolutely positioned element sizes it to the box, no width/height
* class needed) and cross-fade/scale on the spatial-slow spring the shape's size warrants
* (docs/reference/m3/styles.md § Motion: "larger elements may use slow"); opacity rides the
* effects-slow spring beside it, since a colour or fade must never overshoot. Reduced motion needs
* no local override: the tokens themselves zero out under it (tokens/motion.css).
*/
.upload-drop-shapes {
position: relative;
display: grid;
place-items: center;
inline-size: 7rem;
block-size: 7rem;
}
.upload-drop-shape {
position: absolute;
inset: 0;
transition: scale var(--md-sys-motion-spatial-slow-duration) var(--md-sys-motion-spatial-slow), rotate var(--md-sys-motion-spatial-slow-duration) var(--md-sys-motion-spatial-slow), opacity var(--md-sys-motion-effects-slow-duration) var(--md-sys-motion-effects-slow);
}
.upload-drop-shape--idle {
scale: 1;
rotate: 0deg;
opacity: 1;
color: var(--md-sys-color-secondary-container);
}
.upload-drop-zone[data-dragging='true'] .upload-drop-shape--idle {
scale: 0.5;
rotate: 45deg;
opacity: 0;
}
.upload-drop-shape--burst {
scale: 0.5;
rotate: -45deg;
opacity: 0;
color: var(--md-sys-color-primary-container);
}
.upload-drop-zone[data-dragging='true'] .upload-drop-shape--burst {
scale: 1.1;
rotate: 0deg;
opacity: 1;
}
.upload-drop-icon {
position: relative;
color: var(--md-sys-color-on-secondary-container);
transition: color var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
}
.upload-drop-zone[data-dragging='true'] .upload-drop-icon {
color: var(--md-sys-color-on-primary-container);
}
/* resources/views/livewire/file-uploader.blade.php: the selected-files list scrolls on its own past 1.x's cap instead of pushing the options and the submit button down the page. */
.upload-file-list {
max-block-size: 18rem;
overflow-y: auto;
}
/*
* resources/views/livewire/share-created.blade.php: the check that settles onto its Expressive
* shape once the link is ready (the `share-ready`/`share-ready-fade` keyframes after it). The shape
* sits at the box's edges (`inset: 0` on an absolutely positioned element sizes it, no width/height
* class needed); both colours are container roles `md-ink-*` has no class for, so they are the
* application's own CSS rather than a component prop.
*/
.share-check {
position: relative;
display: grid;
place-items: center;
inline-size: 6rem;
block-size: 6rem;
animation:
share-ready var(--md-sys-motion-spatial-slow-duration) var(--md-sys-motion-spatial-slow) both,
share-ready-fade var(--md-sys-motion-effects-slow-duration) var(--md-sys-motion-effects-slow) both;
}
.share-check-shape {
position: absolute;
inset: 0;
color: var(--md-sys-color-primary-container);
}
.share-check-icon {
/* Without this the icon, though later in the DOM, is a non-positioned in-flow child: it paints
before the absolutely positioned shape beside it (CSS's stacking order for z-index:auto) and
sits hidden underneath it, as .upload-drop-icon's own position: relative is there to avoid. */
position: relative;
color: var(--md-sys-color-on-primary-container);
}
/*
* resources/views/livewire/share-created.blade.php: the check settling onto its shape, run by
* .share-check — rotate and scale on the spatial spring (shape motion), opacity on effects beside
* it, since M3 never lets a colour or fade overshoot; reduced motion needs no local override, the
* duration tokens themselves zero out under it.
*/
@keyframes share-ready {
from {
rotate: -90deg;
scale: 0.4;
}
to {
rotate: 0deg;
scale: 1;
}
}
@keyframes share-ready-fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*
* resources/views/livewire/share-created.blade.php: the QR code dialog. `App\Services\QrCodeService`
* already draws its SVG black on white with a four-module quiet zone, so the container adds no
* colour of its own — no colour class or literal colour could give it one that also holds in dark
* mode. The corner only rounds the container that clips it, exactly as .settings-two-factor-qr's does.
*/
.share-qr {
display: grid;
place-items: center;
inline-size: 100%;
max-inline-size: 20rem;
aspect-ratio: 1;
margin-inline: auto;
overflow: hidden;
border-radius: var(--md-sys-shape-corner-lg);
}
.share-qr svg {
inline-size: 100%;
block-size: 100%;
}
/*
* resources/views/pages/settings/two-factor.blade.php: the setup QR code. Fortify's own
* twoFactorQrCodeSvg() draws no quiet zone, so the SVG comes from App\Services\QrCodeService
* against the same otpauth URL instead, which bakes in its own white field and four-module quiet
* zone — the only way to guarantee one in dark mode, since no colour class or literal colour can
* paint it onto 2.0.0's foundation. Sized at 1.x's 16rem square, corners rounded and clipped to
* match the settings surfaces around it.
*/
.settings-two-factor-qr {
display: grid;
place-items: center;
inline-size: 16rem;
aspect-ratio: 1;
overflow: hidden;
border-radius: var(--md-sys-shape-corner-lg);
}
.settings-two-factor-qr svg {
inline-size: 100%;
block-size: 100%;
}
/*
* resources/views/pages/settings/two-factor/recovery-codes.blade.php: a code dims to M3's disabled
* content opacity while regenerateRecoveryCodes() is in flight, and back, on the effects spring
* instead of Tailwind's animate-pulse loop — 2.0.0 keeps no keyframe utility for it. The
* transition sits on the code itself so the way back eases too; under reduced motion the token's
* duration is 0ms.
*/
.settings-recovery-code {
transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
}
.settings-recovery-code--loading {
opacity: var(--md-sys-state-disabled-content-opacity);
}
/*
* resources/views/pages/settings/appearance.blade.php: the theme picker stays a comfortable
* width instead of stretching across the settings card. No `<x-group>` width prop caps it, and
* 24rem matches no `<x-pane>` preset.
*/
.settings-appearance-picker {
max-inline-size: 24rem;
}
/*
* resources/views/livewire/admin/admin-dashboard.blade.php: a share's details are two lines of
* their own (its files, size and downloads; its expiry), and they wrap rather than clip. The
* package clamps a list item's description at two lines with an ellipsis, which on a phone hid
* the expiry with no way to read it.
*/
.admin-shares [data-md-list-item-description] {
display: block;
overflow: visible;
}
.admin-share-detail {
display: block;
}
/*
* resources/views/livewire/admin/admin-settings.blade.php: the current and previewed site logo,
* at 1.x's 4rem height with its width following the image's own ratio. M3 keeps no size scale for
* a plain <img>.
*/
.admin-settings-logo {
block-size: 4rem;
border-radius: var(--md-sys-shape-corner-sm);
}