Commit Graph
4503 Commits
Author SHA1 Message Date
vicrodh 1ad08f2de8 feat(discovery-v2): pagination by DOM slice (no scroll containers)
Replaces the inline grid (and the prior horizontal-scroll-carousel
attempt) with chevron-paginated sections that mount only the current
page's cards. Each section is a generic component over T with two key
props: `items: T[]` and `renderItem: Snippet<[T]>`. Internal state:

  - `itemsPerPage` = `floor((containerWidth + gap) / (cardWidth + gap))`
    computed on mount + on resize via ResizeObserver. Responsive: 4
    cards at 1280px, ~12 at 4K maximize.
  - `page` advances/retreats on chevron click. Maximum is clamped to
    `ceil(items.length / itemsPerPage) - 1`.
  - The visible slice is `items.slice(page * itemsPerPage, …)`. Only
    those cards are mounted; off-page cards never enter the DOM.

The `.row` is a plain `display: flex` — no `overflow-x: auto`, no
transform, no scroll handler, no extra backing surface under software
compositing. That was the structural issue with both the original
HorizontalScrollRow.svelte and the Cider-pattern attempt: N nested
scroll containers each materializing their own paint surface in the
vertical scroll path. This approach has zero such containers.

DiscoveryView extracts per-card-type snippets (`albumCard`, `trackCard`,
`playlistCard`, `artistTile`) and passes each section the appropriate
data array + snippet. ArtistTile passes `cardWidth: 140` so the per-page
math matches the circular tile's actual width.

cc
2026-05-11 21:34:21 -06:00
vicrodh 368f0b4266 Revert "feat(discovery-v2): horizontal-scroll sections (Cider pattern)"
This reverts commit 612384ae4c.
2026-05-11 21:28:33 -06:00
vicrodh 612384ae4c feat(discovery-v2): horizontal-scroll sections (Cider pattern)
Replaces the inline CSS grid with a native horizontal scroller and
chevron-paged navigation, mirroring the pattern Cider uses for Apple
Music shelves:

  - `overflow-x: auto` native scroll (no transform-based carousel, no
    virtualization).
  - Two reactive booleans (`canScrollLeft`/`canScrollRight`) recomputed
    on every scroll + on resize via ResizeObserver. They drive chevron
    disabled state AND the `.scrollable-left`/`.scrollable-right`
    classes on the scroller.
  - Those classes apply `mask-image: linear-gradient(…)` fade gradients
    at the active edges. Pure CSS mask — GPU-implementable on accelerated
    backends, low-cost CPU rasterize otherwise. Replaces "I need a hover
    overlay to discover more content" with a static visual hint.
  - Page-step scroll: chevrons advance N items where N = items per
    viewport (computed from cardWidth / clientWidth). Smooth-scrolled
    via `scrollBy({behavior: 'smooth'})`.
  - Scrollbar hidden — chevrons + edge fades carry the affordance.

`see-all` link, when present, sits alongside the chevrons in the header
actions area. Section header is `display: flex` with `justify-content:
space-between` (title left, actions right).

The cards inside still carry `content-visibility: auto`, which means
off-viewport cards in the same scroller skip their render — the
horizontal-scroll perf cost is bounded to what's currently visible.

cc
2026-05-11 21:25:38 -06:00
vicrodh f6ac95ec6b feat(discovery-v2): highlight currently-playing track in continue listening
TrackCardLite already accepted an `isPlaying` prop and styled `.title`
with `--accent-primary` when set. DiscoveryView now passes it for the
Continue Listening section by comparing each track's id against the
parent's `activeTrackId` (combined with `isPlaybackActive`).

Album-level sections don't get the highlight yet — the cards carry an
albumId, but `activeTrackId` is at the track level and we'd need to
resolve the currently-playing track's parent albumId from the parent
playback context. That wires once the parent surfaces a
`currentAlbumId` derivation.

cc
2026-05-11 21:06:37 -06:00
vicrodh fcdd602149 feat(discovery-v2): wire genre filter button into toolbar
Mounts the existing `GenreFilterButton` (with its own popup and store
subscription) into the toolbar's right-side slot. On filter change,
re-runs the discover-index fetch with the new genre IDs — the V2
endpoint already accepts `genreIds` and the response containers come
back filtered.

Release-watch and home-resolved are not re-fetched on genre change:
the former is personalized (followed-artists feed, genre-agnostic) and
the latter draws from local reco-store state that the user's local
play history doesn't get retroactively filtered by browse-time genre.
Matches HomeView.svelte's existing behavior (only the discover-index
sections re-filter).

Extracted the on-mount load into `loadAll()` so the genre-change handler
can call it directly without duplicating the parallel-fetch logic.

cc
2026-05-11 21:05:16 -06:00
vicrodh 5c30ced81f feat(discovery-v2): gate scroll-area by active tab
The toolbar exposes three tabs (Home / Editor's Picks / For You) but V1
of Discovery only populates the Home tab. Clicks on the other two were
toggling `homeTab` but the scroll-area kept rendering the Home sections
— misleading UI.

This commit gates the section block: when `homeTab !== 'home'`, render
only the "under construction" placeholder. Editor Picks and For You tab
content will land in follow-up commits with their own data fetches
(`v2_get_discover_index` already brings what Editor Picks needs; For You
uses the dailyq/weeklyq/topq/favq recommendation set).

cc
2026-05-11 21:03:06 -06:00
vicrodh e40400449a feat(discovery-v2): wire personalized + playlist + artist sections
Adds three new card components and five more sections, completing the
Home tab's section coverage at V1 minimum:

New cards:
  - TrackCardLite: identical layout to AlbumCardLite, separate file so
    future track-only metadata lands here without bleeding into album
    cards.
  - PlaylistCardLite: same 180px square, ListMusic placeholder when no
    cover, single title line (no description, owner, track count).
  - ArtistTileLite: circular 140px avatar + name. No play count.

data.ts additions:
  - `fetchHomeResolved` — wraps `v2_reco_get_home_resolved` with explicit
    per-section limit args (Rust signature uses limitRecentAlbums,
    limitContinueTracks, limitTopArtists, limitFavorites). Maps the
    backend-resolved minimal shapes (AlbumCardMeta, TrackDisplayMeta,
    ArtistCardMeta) into Discovery card types. Single round-trip yields
    four lists.
  - `DiscoverIndexSections.playlists` — the discover-index response
    already carries a playlists container; we now extract it instead of
    making a second call to `v2_get_discover_playlists`.

DiscoveryView fires three parallel fetches via Promise.all (release-watch
+ discover-index + home-resolved) on mount and renders eleven conditional
sections in display order: recently played, continue listening, release
watch, new releases, most streamed, editor picks, qobuzissimes, press
awards, Qobuz playlists, top artists, favorite albums.

cc
2026-05-11 21:01:33 -06:00
vicrodh aa526fb894 feat(discovery-v2): wire editorial sections from discover-index
Renames `fetchNewReleases` to `fetchReleaseWatch` to match what the V2
command actually returns (followed-artists release radar, not editorial
new releases). Adds `fetchDiscoverIndex` which calls `v2_get_discover_index`
once and splits the response's five containers into per-section card
arrays. One round-trip yields:

  - newReleases (editorial)
  - pressAwards
  - mostStreamed
  - qobuzissimes
  - editorPicks (album_of_the_week)

DiscoveryView mounts release-watch and discover-index in parallel via
Promise.all, then renders six sections in display order (release-watch,
new releases, most streamed, editor picks, qobuzissimes, press awards).
Each section is conditional on having items, so empty containers don't
render an empty title row. The `discoverAlbumToCard` mapper drops every
field except albumId/title/artist/artistId/artwork — V1 doesn't render
quality, awards, parental_warning, etc., so we don't carry them around.

An inline `albumGrid` snippet keeps the per-section markup DRY without
introducing another wrapper component.

cc
2026-05-11 20:57:16 -06:00
vicrodh b6d2c12125 feat(discovery-v2): first section — new releases
Adds `src/lib/discovery-v2/data.ts` with `fetchNewReleases(limit)`, a pure
wrapper around `v2_get_release_watch`. The V2 command already returns full
`SearchResultsPage<Album>` payloads in a single round-trip — the original
HomeView did N+1 calls (release-watch followed by `v2_get_album` per id),
which Discovery sidesteps. The mapping reduces each QobuzAlbum to the
minimal shape AlbumCardLite needs (id, title, artist name + id, artwork
URL via getQobuzImageForSize 'small'), dropping fields V1 doesn't render
(quality, bitDepth, samplingRate, awards, parental_warning, etc).

Wires the section into DiscoveryView: on mount, fetch 8 new releases and
render via DiscoverySection + AlbumCardLite. Click on a card calls
onAlbumClick, the permanent play button calls onAlbumPlay, and the artist
text link calls onArtistClick — all forwarded from the props +page.svelte
already passes through. "Ver todo" routes to the existing release-watch
full grid view via onNavigateNewReleases.

cc
2026-05-11 20:50:44 -06:00
vicrodh 373018a1ea feat(discovery-v2): scaffold clean-room rebuild of home view
Establishes the skeleton for a Discovery rebuild under "cero efectos"
constraint after a perf debug session confirmed the original home view's
vertical scroll cost was structural and accumulative, not a single
offender. Spec: qbz-nix-docs/specs/2026-05-11-discovery-v2-clean-room.md.

Adds:
  - src/lib/discovery-v2/AlbumCardLite.svelte: 5-element card (cover,
    title, artist, permanent play button). Cero `transition`, cero
    `:hover` paint, cero `will-change`, cero `backdrop-filter`.
  - src/lib/discovery-v2/DiscoverySection.svelte: titled inline CSS grid
    of cards + "See all" link. No `overflow-x: auto` carousel — sections
    wrap onto rows naturally.
  - src/lib/discovery-v2/DiscoveryView.svelte: top-level. Same Props as
    `HomeView.svelte` for drop-in mount swap. Toolbar with three tab
    buttons (Home / Editor's Picks / For You) on the left and a slot
    for the genre selector on the right — fixed 56px height, static
    (no `position: sticky`), part of the main paint pass.
  - i18n keys `discovery.{comingSoon,seeAll}` across en/es/de/fr/pt.

Swaps the mount in `src/routes/+page.svelte:5826` from `<HomeView>` to
`<DiscoveryView>`. `HomeView.svelte` stays in the tree as rollback. Real
sections will be wired incrementally in follow-up commits, each measured
against the perf baseline established by the scripts/measure-cpu-window.sh
tooling.

cc
2026-05-11 20:44:02 -06:00
vicrodh 03af983a1b chore(scripts): add measure-cpu-window for structured perf sampling
Samples /proc/PID/stat directly (no pidstat dependency) for the qbz binary
and any WebKit child processes. Outputs mean/p50/p95/max per process plus
appends a CSV row to /tmp/qbz-cpu-measurements.csv for cross-run comparison.

Usage:
  ./scripts/measure-cpu-window.sh <label> [duration_seconds]

Built during the 2026-05-11 perf debug session to replace seat-of-the-pants
"does it feel faster?" with comparable numbers across changes.

cc
2026-05-11 20:43:49 -06:00
vicrodh 3c6f5f9023 perf(now-playing-bar): drop invisible backdrop-filter
The bar declared `background: var(--bg-secondary); backdrop-filter: blur(20px)`.
`--bg-secondary` is opaque across all themes, so the blur was computed for
nothing — WebKit applied the per-frame blur computation to pixels under the
bar that the opaque bg then completely overdrew. Pure waste under software
compositing.

cc
2026-05-11 20:43:43 -06:00
vicrodh efcdad553c perf(cached-image): drop forced compositing layer on every artwork
The action was applying `will-change: transform` + `transform: translateZ(0)`
to every cached <img> as a workaround for WebKitGTK 2.50+ texture eviction
flicker on hover/scroll.

Under hardware-accelerated compositing this is cheap — each image is a GPU
texture handle. Under software compositing (QBZ's default), each forced
layer materializes its own CPU framebuffer. With 100+ AlbumCards in the
home view, that's 100+ extra buffers the compositor must manage every
frame, dominating the structural paint cost of scroll.

User confirmed in the 2026-05-11 perf session that the flicker the hack
was meant to prevent does not reappear after removal on his setup. If it
shows up again on other reports, the re-introduction should be guarded by
the hardware-acceleration setting (apply only when GPU is on).

cc
2026-05-11 20:43:37 -06:00
vicrodh 82b3217c4f perf(playlist-card): drop blur(30px) on artwork backdrop
The `.artwork-bg` layer rendered the playlist cover scaled-up + heavily
blurred behind the contain-fitted main image. Under software compositing,
filter:blur(30px) saturate(1.5) on N playlist cards × visible row = paint
cost proportional to card surface, paid every frame the row repaints
during vertical scroll.

For square playlist art (the common case) `.artwork-main object-fit: cover`
covers the whole container — the blurred bg was invisible anyway. For
non-square art the original cover shows through at the letterbox edges
without the blur. Acceptable trade.

cc
2026-05-11 20:43:23 -06:00
vicrodh 9aa10e9573 perf(album-card): drop hover marquee, decorative blurs, add content-visibility
Removed under software compositing the changes that proved either wasteful
or hot during scroll:

- `:hover` marquee animations on title/artist (infinite keyframes that kept
  WebKit's paint loop alive while hovered, especially across cards passed
  during scroll)
- `.action-overlay` `backdrop-filter: blur(12px)` (computed every frame even
  at opacity 0; the bumped opaque background covers visually)
- `.editorial-ribbon` `backdrop-filter: blur(4px)` (multiplied by N cards
  with badges; minor individually, significant in aggregate)

Added `content-visibility: auto` + `contain-intrinsic-size: 230px 320px` on
`.album-card`. Confirmed in the 2026-05-11 perf session to substantially
help horizontal scroll under software compositing by skipping offscreen
card render entirely.

cc
2026-05-11 20:43:15 -06:00
vicrodh 6029e93f5f Revert "Merge pull request #407 from afonsojramos/fix-glued-top-animation"
This reverts commit 08acd304a1, reversing
changes made to f7623154f4.
2026-05-11 17:51:21 -06:00
vicrodh 43a35647fe Merge branch 'bugfix/unavailable-track-row-dim' into pre-release 2026-05-11 16:01:52 -06:00
vicrodh 03d1142fc1 fix(ui): dim unavailable tracks across all track list views
Wire isTrackRemovedFromQobuz into TrackRow consumers (VirtualizedTrackList,
AlbumDetail, DynamicSuggest, TopQ, WeeklySuggest). Tracks marked unstreamable
by the API or hit by a TrackUnavailable error this session now render dimmed,
non-draggable, non-clickable, with the i18n tooltip player.trackUnavailable.

Reactivity for the {@const} reads uses a $state counter bumped from the
unavailable-tracks store subscription so the dim state updates live without
forcing the whole list to re-render.

cc
2026-05-11 16:01:47 -06:00
Afonso Jorge Ramos 4fd85b5b2f fix(ci): suffix macOS .app.tar.gz bundles with arch to fix auto-updater 2026-05-11 16:17:07 +02:00
Afonso Jorge Ramos 1edde8a28a fix(audio): rephrase CoreAudio rate-mismatch errors for end users
The error strings flow up through stream_error and end up in user-
visible logs. Replace the internal-shaped messages ("opened at XHz
while device nominal rate is YHz") with text that names the cause,
the remediation, and the reason the fallback path is refused.
2026-05-11 15:19:30 +02:00
Afonso Jorge Ramos 9e632386b9 fix(audio): retry CoreAudio shared-mode open on rate mismatch
CPAL caches device configs and can briefly return a stale sample rate
right after CoreAudio changes the device nominal rate. Before this
change, opening at the stale rate failed the post-open validation and
returned Err, leaving the user with no audio on the first track after
a rate change.

Drop the bad sink, re-resolve the device, re-query nominal rate and
try once more with a 50ms backoff. Two attempts in total. Turns the
racy window into transparent recovery.
2026-05-11 15:16:46 +02:00
Afonso Jorge Ramos c408ea73cb test(player): cover compute_needs_new_stream decision rule
Extract the boolean decision out of evaluate_stream_recreate into a
pure function so the truth table can be tested without faking a
MixerDeviceSink or AudioSettings mutex. Eight cases cover the matrix:
no stream, unchanged format, format change with and without each
bit-perfect backend, and the CoreAudio shared-mode rate-mismatch path.
2026-05-11 15:15:57 +02:00
Afonso Jorge Ramos ac60113cdd refactor(player): extract StreamRecreateDecision helper
The rate-mismatch detection block was duplicated between the Play and
Stream handlers, and each handler acquired thread_settings.lock() three
times in a row. Extract into one helper that reads settings once and
returns every flag the recreate decision needs.

Also drops a dead else-branch that logged "Creating initial audio
stream" — unreachable inside if stream_opt.is_some() — and the
redundant info-log that re-announced the rate-mismatch reason at
recreate time (the warn-level log inside the helper already says
"Recreating stream to avoid wrong-speed playback").
2026-05-11 15:14:54 +02:00
Afonso Jorge Ramos 3b34a734b4 refactor(player): rename current_sample_rate to current_track_sample_rate
The field tracks the decoded source format, not the output stream's
hardware rate. The names are now explicit so future readers don't
conflate the two — on macOS shared mode these can legitimately differ
since Rodio resamples internally.
2026-05-11 15:13:29 +02:00
Vudgekek 7bad704e21 fix(audio): fix macOS Shared Mode playback from changing speed 2026-05-09 23:43:26 -05:00
vicrodh d44ee7c086 build(flake): bump qbz to v1.2.12
cc
2026-05-09 19:14:45 -06:00
vicrodh e920c350c4 Merge pre-release into main for v1.2.12 hotfix release 2026-05-09 18:14:44 -06:00
vicrodh 19c2912851 chore(snap): bump source-tag to v1.2.12
Was lagging at v1.2.10 since the v1.2.10 release; v1.2.11 missed it.
Snap CI builds from this tag, so it must match the version field.

cc
2026-05-09 18:12:15 -06:00
vicrodh 0c9e4ee5fc chore(release): bump version to 1.2.12
Hotfix release. Reverts titlebar-mode-selector and PR #406 (broken
window chrome on Linux); preserves PR #407 (sticky home header) and
adds PR #408 (macOS native icon and tray variants by @Vudgekek).

cc
2026-05-09 18:11:24 -06:00
vicrodh 2fdec2ca57 Merge pull request #408 from Vudgekek/feature/external/macos-qol
feat(style): add macOS native app icon and tray icon variants
2026-05-09 18:06:27 -06:00
vicrodh f1ef161560 Merge branch 'bugfix/titlebar-rollback-1.2.12' into pre-release
v1.2.12 hotfix: revert the titlebar-mode-selector merge and PR #406
which together caused all titlebar modes to render incorrectly in the
production binary (empty top space, gap above now-playing bar). The
v1.2.10 model (use_system_titlebar + hide_title_bar booleans) is
restored; Plasma mode is dropped pending a less brittle redesign.

PR #407 (sticky home header fix) is preserved.
2026-05-09 18:06:14 -06:00
vicrodh ee54c49aef revert: roll back PR #406 (linux-titlebar-draggable)
Reverts merge f7623154 which built macOS support on top of the variant
rendering infrastructure introduced by titlebar-mode-selector. With the
variant system gone (previous revert), PR #406's changes (class:macos,
stripped strip with traffic-light reservation, macOS-aware drag bands)
reference dead architecture.

Most of PR #406 was already removed by the previous revert via file
checkouts; this commit cleans up the residual macOS-specific cosmetics
in Sidebar.svelte and +page.svelte (padding-top 36→32, drag-region
height 32→28, macos main-content padding restored to generic rule).

PR #407 (sticky home header fix, ac627d43) is preserved — independent
from titlebar work, only touches HomeView.svelte.

cc
2026-05-09 17:49:07 -06:00
vicrodh e3bdbc9ab4 revert: roll back titlebar-mode-selector merge
Reverts merge 1be46f1a which introduced the 4-mode titlebar enum
(qbz/system/plasma/hidden), variant-aware rendering (full/stripped),
GDK_BACKEND=x11 coercion for Plasma, and per-mode mounting in +page.

The "stripped strip mounted alongside Plasma SSD" architecture caused
all titlebar modes to render incorrectly in the production binary —
empty space at top, separation gap above the now-playing bar, controls
visible without a backing strip. Reverting restores v1.2.10 behavior:
two booleans (use_system_titlebar + hide_title_bar), no variants, no
GDK coercion. Plasma support is dropped pending a less brittle redesign.

Conflicts in SettingsView.svelte resolved by taking the pre-merge side
for the four titlebar UI blocks; non-titlebar additions in this cycle
(Discord RPC settings, reserve-DAC, offline cache nav) preserved.

cc
2026-05-09 17:48:37 -06:00
Vudgekek 491807e1f1 Merge branch 'pre-release' into feature/external/macos-qol 2026-05-09 17:50:47 -05:00
vicrodh f65248a917 build(flake): bump qbz to v1.2.11
Update qbzVersion + srcHash + npmHash for the v1.2.11 tag (commit
cc98b7f7). Hashes computed via 'nix-prefetch-url --unpack' and
'prefetch-npm-deps package-lock.json' against the tagged tree.

cc
2026-05-09 16:36:58 -06:00
vicrodh cc98b7f7e6 docs(release-1.2.11): correct PR attribution for sticky home header (#406 → #407)
PR #406 was the macOS titlebar unification (mentioned separately in the
Title bar section); the sticky home header pop-in fix is PR #407. Both
from @afonsojramos in the same merge round.

cc
2026-05-09 15:51:07 -06:00
Vudgekek 855bbdfae1 feature(app-icon): add macOS style .icns pack 2026-05-09 15:36:16 -05:00
Vudgekek b51fbc8209 fix(menu-bar): add macOS support for the "Tray icon variant" setting 2026-05-09 15:35:35 -05:00
vicrodh fd7a6e2f89 docs(release): add 1.2.11 TAG_DETAILS and metainfo entry
cc
2026-05-09 14:33:11 -06:00
vicrodh ea6167babb chore(release): bump version to 1.2.11
cc
2026-05-09 14:33:11 -06:00
vicrodh 667153624f chore(about): bump codename to Exclusive Hardening, add Vudgekek and DoubleGate
cc
2026-05-09 14:33:11 -06:00
Victor RH 08acd304a1 Merge pull request #407 from afonsojramos/fix-glued-top-animation
fix(home): unify sticky tab header to avoid pop-in animation
2026-05-09 12:45:31 -06:00
Victor RH f7623154f4 Merge pull request #406 from afonsojramos/linux-titlebar-draggable
feat(titlebar): unify macOS layout with Linux qbz titlebar
2026-05-09 12:45:28 -06:00
vicrodh a8b5d3e8f5 Merge branch 'feature/internal/discord-rpc-flatpak-symlinks' into pre-release
Discord RPC now reaches Discord-Flatpak's IPC socket without making the
integration opt-out at the sandbox layer. Bridge symlinks are created
lazily on first connect after the user enables the toggle; users who
never enable Discord RPC see no sandbox changes.

* prepare_flatpak_discord_socket_links in discord_rpc.rs runs from the
  lazy connect path, gated on FLATPAK_ID env var
* Manifest gains xdg-run/app/com.discordapp.Discord:create filesystem
  permission, kept alongside the existing static path
2026-05-09 12:38:25 -06:00
vicrodh e2e4fb8cab feat(discord-rpc): lazy Flatpak socket bridge keeps the integration opt-in
Discord-Flatpak writes its IPC socket to
\$XDG_RUNTIME_DIR/app/com.discordapp.Discord/discord-ipc-N rather than
the \$XDG_RUNTIME_DIR/discord-ipc-N path the discord-rich-presence crate
searches by default. The naive way to bridge that gap — a startup
wrapper that unconditionally symlinks every iteration before the binary
launches — works, but it pulls the integration off-script: every other
optional integration in QBZ (Last.fm, ListenBrainz, MusicBrainz, Plex)
is opt-in, with zero telemetry and zero filesystem reach until the user
flips the toggle. A startup wrapper would silently turn Discord RPC
into opt-out at the sandbox layer; the symlinks would exist for users
who never touched the integrations panel.

Move the bridge into the lazy connect path instead. The first time the
user actually connects — i.e. the first track plays after they enabled
the toggle — prepare_flatpak_discord_socket_links runs:

* No-op outside Flatpak (no FLATPAK_ID env var)
* No-op when \$XDG_RUNTIME_DIR/discord-ipc-N already exists (native
  Discord, or a previous lazy run in this Flatpak instance)
* No-op when the Discord-Flatpak source path doesn't exist (Discord
  not running)
* Otherwise, symlinks 0..9 from \$XDG_RUNTIME_DIR/discord-ipc-N to
  \$XDG_RUNTIME_DIR/app/com.discordapp.Discord/discord-ipc-N

Symlinks die with the Flatpak instance — \$XDG_RUNTIME_DIR is per-
instance, so there's no cross-session pollution. Users who never enable
Discord RPC keep the same sandbox surface as before.

Manifest: keep the static xdg-run/discord-ipc-0 permission for native
Discord, add xdg-run/app/com.discordapp.Discord:create so the lazy
symlink path is allowed when the user opts in. The two coexist; the
crate's default search path covers Discord-native, the symlinks cover
Discord-Flatpak.

cc
2026-05-09 12:38:25 -06:00
Afonso Jorge Ramos ac627d432b fix(home): unify sticky tab header to avoid pop-in animation 2026-05-09 17:52:39 +02:00
vicrodh 0274f2b030 chore: clean svelte-check warnings (CSS, a11y, types)
Drains the wiki "23 warnings" baseline back to zero so future regressions
stand out:

* Drop 16 unprefixed \`app-region\` CSS lines across TitleBar, TitleBarNav,
  ImmersiveHeader, ImmersivePlayer, MiniPlayerFooter and MiniPlayerWindowControls.
  Tauri's webview is WebKit / Chromium on every platform we ship to, so
  \`-webkit-app-region\` already covers the chrome-drag region; the
  unprefixed property only existed to keep stylelint quiet but the CSS
  spec doesn't define it and svelte-check warns on every site.
* Remove 2 empty rulesets in AlbumCreditsModal and NowPlayingBar (leftover
  comment-only blocks from earlier refactors).
* Pair \`-moz-appearance: textfield\` with the standard \`appearance: textfield\`
  in LocalLibraryTagEditorModal so the rule no longer trips the
  property-companion warning.
* Delete the unused \`.quality-text\` selector in NowPlayingBar.backup.svelte
  (file is a frozen snapshot of an older NPB iteration; the live NPB
  doesn't use that class).
* Annotate Tooltip.svelte and immersive/panels/VinylPanel.svelte with
  \`svelte-ignore a11y_no_static_element_interactions\` plus a comment
  explaining the context — both are decorative wrappers (a tooltip hit
  area; a 3D tilt effect on artwork) where adding an ARIA role would
  misrepresent the semantics.
* Add \`@types/node\` as a devDependency (^22) so the tsconfig resolution
  for the SvelteKit-extended config stops complaining about the missing
  type definition.

cc
2026-05-09 09:46:43 -06:00
Afonso Jorge Ramos 8ed62676c2 fix(titlebar): tune macos drag band to 32px 2026-05-09 17:45:46 +02:00
Afonso Jorge Ramos ac5fc25944 fix(titlebar): match macos drag band height to sidebar top padding 2026-05-09 17:37:04 +02:00
Afonso Jorge Ramos be67fffb28 feat(titlebar): expose hide-title-bar toggle on macOS 2026-05-09 17:36:28 +02:00