v3: added index default tab selection setting, fixed notification pages not loading, reduced invite token length, global player state survives page reloads, many visual fixes
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 44s

This commit is contained in:
khannurien
2026-06-27 19:44:35 +00:00
parent 88f1eb3d03
commit c29f45fbc8
25 changed files with 733 additions and 278 deletions

View File

@@ -207,6 +207,26 @@
color: var(--color-danger);
}
/* On the narrowest viewports the fixed-width action column squeezes the title
into a sliver. Stack the block: title takes the full width on top, the
vote/playlist actions sit in a row beneath it. */
@media (max-width: 512px) {
.dump-header-block {
flex-direction: column;
align-items: stretch;
}
.dump-header-left {
flex-direction: row;
align-items: center;
order: 2;
}
.dump-header-right {
order: 1;
}
}
.dump-comment {
font-size: 1.05rem;
line-height: 1.72;
@@ -1051,6 +1071,90 @@
body.has-player {
padding-bottom: var(--player-height, 0px);
}
/* ── Floating "new dump" button ───────────────────────────────────────
Revealed once the header scrolls out of view. Bottom-right by default, but
moves to the top-right while the global player is mounted (it owns the
bottom of the screen, full-width on mobile). Sits below the player and
modal backdrop (both z-index 1000). */
.dump-fab {
position: fixed;
--fab-size: 3.5rem;
/* Sit just outside the right edge of the centered content lane — in the
margin beside it — rather than over the content or pinned to the viewport
edge. The lane width is `--fab-lane` (860px for most feeds; the journal
grid is wider, see below). Falls back to a 1.25rem viewport gutter once
that margin is too narrow to hold the button. */
right: max(1.25rem, calc(50% - var(--fab-lane, 860px) / 2 - var(--fab-size) - 1rem));
/* Anchored to the bottom-right by default, but expressed via `top` (rather
than `bottom`) so the jump to the top-right when a player mounts can
animate as a slide. `dvh` tracks the visible viewport on mobile; `vh` is
the fallback for browsers without it. */
top: calc(100vh - var(--fab-size) - 1.25rem - env(safe-area-inset-bottom, 0px));
top: calc(100dvh - var(--fab-size) - 1.25rem - env(safe-area-inset-bottom, 0px));
z-index: 900;
width: var(--fab-size);
height: var(--fab-size);
display: flex;
align-items: center;
justify-content: center;
padding: 0;
border: none;
/* Circle by default; a theme can square it off by setting --fab-radius: 0. */
border-radius: var(--fab-radius, 50%);
background: var(--color-accent);
color: var(--color-on-accent);
cursor: pointer;
box-shadow: 0 4px 16px color-mix(in srgb, var(--color-accent) 45%, transparent),
0 2px 6px rgba(0, 0, 0, 0.3);
/* Hidden state: faded out, nudged down, non-interactive. */
opacity: 0;
transform: translateY(1rem) scale(0.9);
pointer-events: none;
transition: opacity 0.2s ease, transform 0.2s ease, background 0.15s ease,
top 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.dump-fab-icon {
width: 1.6rem;
height: 1.6rem;
}
.dump-fab--visible {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: auto;
}
.dump-fab:hover {
background: var(--color-accent-hover);
transform: translateY(-2px) scale(1);
box-shadow: 0 6px 20px color-mix(in srgb, var(--color-accent) 55%, transparent),
0 2px 6px rgba(0, 0, 0, 0.3);
}
.dump-fab:active {
transform: translateY(0) scale(0.96);
}
/* The journal tab lays out its masonry grid in a wider lane than the other
feeds, so the button must track that wider edge to stay aligned with it. */
body:has(.journal-grid) {
--fab-lane: 1180px;
}
/* The player occupies the bottom of the screen (full-width on mobile), so when
one is mounted slide the button up to the top-right corner to stay clear. */
body.has-player .dump-fab {
top: calc(1.25rem + env(safe-area-inset-top, 0px));
}
/* Reserve room at the end of the scroll so the button never hides the last
content when scrolled all the way down. */
body.has-fab .page-content {
padding-bottom: 5rem;
}
.rich-content-thumbnail-btn {
position: relative;
padding: 0;
@@ -1674,10 +1778,6 @@ body.has-player {
display: flex;
align-items: center;
gap: 0.5rem;
background: var(--color-surface);
border: 1px solid var(--color-border-subtle);
border-radius: 6px;
padding: 0.3rem 0.5rem 0.3rem 0.75rem;
max-width: 480px;
}
.invite-url {
@@ -1685,11 +1785,18 @@ body.has-player {
font-family: var(--font-mono, monospace);
color: var(--color-text-muted);
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
overflow-x: auto;
white-space: nowrap;
background: var(--color-surface);
border: 1px solid var(--color-border-subtle);
border-radius: 6px;
padding: 0.35rem 0.6rem;
}
/* Always-visible copy target. Sits first so it's the obvious tap. */
.invite-copy-btn {
order: -1;
flex-shrink: 0;
padding: 0.2rem 0.65rem;
border: 1px solid var(--color-border-subtle);
border-radius: 4px;
@@ -1698,7 +1805,6 @@ body.has-player {
font-size: 0.75rem;
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
transition: background 0.12s;
}
.invite-copy-btn:hover {