Compare commits

..
2 Commits
Author SHA1 Message Date
bvandeusen 324059b2bd Merge pull request 'Discover request surface — taste-aware, rotating, snoozable, tag-targeted (milestone #268)' (#116) from dev into main
test-web / test (push) Successful in 1m5s
test-go / test (push) Successful in 1m30s
android / Build + lint + test (push) Successful in 5m1s
test-go / integration (push) Successful in 5m29s
release / Build signed APK (tag releases only) (push) Successful in 4m21s
release / Build + push container image (push) Successful in 17s
2026-08-03 08:38:24 -04:00
bvandeusen 1138d75a45 Merge pull request 'Playlist-track atomic replace + ci-requirements true-up' (#115) from dev into main
release / Build signed APK (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m33s
android / Build + lint + test (push) Successful in 4m30s
2026-08-01 12:23:37 -04:00
20 changed files with 2 additions and 155 deletions
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Adaptive icon (API 26+). Before this the app shipped legacy bitmaps only,
so modern launchers letterboxed the square instead of masking it to the
device's icon shape. The foreground PNGs are drawn on a 108dp canvas with
the mark inside the 66dp safe zone, so no mask can clip it. -->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Obsidian. The adaptive icon's plate; chosen over the raised-surface
iron because the accent note only clears the 3:1 graphics contrast
threshold against this darker value (3.04:1 vs 2.70:1). -->
<color name="ic_launcher_background">#14171A</color>
</resources>
+1 -13
View File
@@ -2,19 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<!-- <link rel="icon" href="%sveltekit.assets%/favicon.png" />
SVG first: it flips the M with the viewer's colour scheme, which the PNG
can't. The PNG is the fallback for browsers without SVG-favicon support
and is plated for the same reason apple-touch-icon is — see brand/.
Ordering matters: browsers take the last icon they understand, so the
PNG must come FIRST or it wins over the SVG in Chrome.
-->
<link rel="icon" href="%sveltekit.assets%/favicon.png" sizes="32x32" />
<link rel="icon" href="%sveltekit.assets%/brand/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" />
<!-- Obsidian: matches --fs-surface-page so mobile browser chrome doesn't
seam against the app's own background. -->
<meta name="theme-color" content="#14171A" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Minstrel</title> <title>Minstrel</title>
<script> <script>
@@ -1,57 +0,0 @@
<script lang="ts">
// The Minstrel mark: a Didone M whose right leg is an eighth note.
//
// Inlined rather than <img src="mark.svg"> on purpose — an <img> cannot
// inherit currentColor, and inheriting it is the whole point: the letter
// takes the surrounding text colour, so it reads on both the dark and light
// palettes without a second asset. Parchment-on-parchment is invisible,
// which is exactly the bug a fixed fill would reintroduce.
//
// The note keeps the accent in both modes — one of the places the design
// system sanctions the accent (the wordmark).
//
// ⚠ These paths are duplicated in web/static/brand/favicon.svg and
// web/static/brand/mark.svg, which need literal colours instead of
// currentColor (a favicon has no cascade to inherit from). Change the
// silhouette here, change it there.
//
// aria-hidden: every current use sits directly beside the words "Minstrel",
// so labelling it would make a screen reader announce the name twice. A
// STANDALONE use would need its own label.
let { size = 20, class: klass = '' }: { size?: number; class?: string } = $props();
</script>
<svg
viewBox="202 251 902 723"
width={size * 902 / 723}
height={size}
class={klass}
aria-hidden="true"
focusable="false"
>
<g transform="translate(0,1254) scale(0.1,-0.1)" fill-rule="evenodd">
<path fill="currentColor" d="M2252 9878 l3 -152 109 -22 c342 -72 492 -184 538 -405 16 -74 24
-4823 9 -5024 -20 -266 -73 -375 -236 -484 -116 -77 -332 -150 -543 -181 -114
-18 -107 -6 -110 -165 -1 -76 2 -143 7 -148 9 -9 2607 -11 2623 -1 14 9 10
280 -4 291 -7 5 -49 15 -93 22 -380 60 -638 193 -720 374 -63 136 -59 -12 -61
2247 -3 1999 -2 2054 15 2015 116 -253 646 -1520 1183 -2825 71 -173 216 -524
322 -780 206 -494 266 -640 370 -895 97 -237 68 -210 226 -210 l135 0 23 50
c13 27 95 212 182 410 134 307 747 1685 1015 2285 92 205 726 1599 910 2000
65 140 126 274 137 297 22 50 52 71 74 52 12 -10 14 -266 14 -1864 l0 -1852
-82 -7 c-347 -29 -716 -203 -973 -460 -710 -712 -343 -1645 650 -1649 453 -2
892 184 1206 510 193 202 295 397 351 676 l23 112 0 2357 c0 1297 0 2358 1
2358 12 0 142 -49 179 -67 342 -173 607 -545 715 -1004 85 -361 66 -801 -51
-1215 -43 -151 -40 -173 18 -174 53 0 284 377 396 650 243 590 303 1238 163
1754 -178 652 -643 1100 -1294 1248 -93 21 -122 22 -716 25 -707 4 -649 12
-696 -90 -15 -34 -78 -172 -140 -307 -593 -1297 -1123 -2469 -1717 -3800 -210
-472 -193 -437 -204 -418 -11 19 -173 423 -630 1568 -214 536 -394 986 -400
1000 -6 14 -76 187 -156 385 -80 198 -182 452 -228 565 -46 113 -140 346 -209
518 -205 507 -225 554 -244 568 -14 11 -209 13 -1055 14 l-1038 0 3 -152z"/>
<path fill="#4A6B5C" d="M8830 7450 l0 -2582 -32 6 c-517 106 -1064 -47 -1442 -405 -598 -566
-501 -1354 196 -1598 489 -170 1134 -19 1548 363 234 217 350 418 423 736 l22
95 3 2373 c2 1961 5 2372 16 2372 27 0 132 -41 205 -81 315 -169 569 -524 675
-944 50 -198 60 -285 60 -525 0 -288 -27 -487 -105 -756 -34 -120 -35 -130
-11 -143 33 -18 64 11 154 144 227 334 402 795 469 1235 37 238 34 646 -4 843
-149 761 -637 1271 -1353 1418 -98 20 -147 23 -466 27 l-358 4 0 -2582z"/>
</g>
</svg>
+1 -6
View File
@@ -5,7 +5,6 @@
import { user, logout } from '$lib/auth/store.svelte'; import { user, logout } from '$lib/auth/store.svelte';
import { player } from '$lib/player/store.svelte'; import { player } from '$lib/player/store.svelte';
import { appName } from '$lib/branding'; import { appName } from '$lib/branding';
import MinstrelMark from './MinstrelMark.svelte';
import PlayerBar from './PlayerBar.svelte'; import PlayerBar from './PlayerBar.svelte';
import SearchInput from './SearchInput.svelte'; import SearchInput from './SearchInput.svelte';
@@ -67,11 +66,7 @@
whenever search or the user menu grew, so the nav drifted off whenever search or the user menu grew, so the nav drifted off
window-center. Grid pins each column to a fixed lane. --> window-center. Grid pins each column to a fixed lane. -->
<header class="grid grid-cols-3 items-center border-b border-border bg-surface px-3 md:px-4 py-2 gap-3 md:gap-6"> <header class="grid grid-cols-3 items-center border-b border-border bg-surface px-3 md:px-4 py-2 gap-3 md:gap-6">
<a <a href="/" class="font-semibold text-sm md:text-base whitespace-nowrap justify-self-start">
href="/"
class="flex items-center gap-2 font-semibold text-sm md:text-base whitespace-nowrap justify-self-start"
>
<MinstrelMark size={20} class="shrink-0" />
{appName()} {appName()}
</a> </a>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

-35
View File
@@ -1,35 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="157 116 992 992">
<!-- Minstrel mark. The M flips with the viewer's scheme because a favicon
sits on browser chrome we don't control: parchment would vanish on a
light tab strip, obsidian on a dark one. The note keeps the accent in
both — teal holds against either. -->
<style>
.m { fill: #E8E4D8; }
@media (prefers-color-scheme: light) { .m { fill: #14171A; } }
</style>
<g transform="translate(0,1254) scale(0.1,-0.1)" fill-rule="evenodd">
<path class="m" d="M2252 9878 l3 -152 109 -22 c342 -72 492 -184 538 -405 16 -74 24
-4823 9 -5024 -20 -266 -73 -375 -236 -484 -116 -77 -332 -150 -543 -181 -114
-18 -107 -6 -110 -165 -1 -76 2 -143 7 -148 9 -9 2607 -11 2623 -1 14 9 10
280 -4 291 -7 5 -49 15 -93 22 -380 60 -638 193 -720 374 -63 136 -59 -12 -61
2247 -3 1999 -2 2054 15 2015 116 -253 646 -1520 1183 -2825 71 -173 216 -524
322 -780 206 -494 266 -640 370 -895 97 -237 68 -210 226 -210 l135 0 23 50
c13 27 95 212 182 410 134 307 747 1685 1015 2285 92 205 726 1599 910 2000
65 140 126 274 137 297 22 50 52 71 74 52 12 -10 14 -266 14 -1864 l0 -1852
-82 -7 c-347 -29 -716 -203 -973 -460 -710 -712 -343 -1645 650 -1649 453 -2
892 184 1206 510 193 202 295 397 351 676 l23 112 0 2357 c0 1297 0 2358 1
2358 12 0 142 -49 179 -67 342 -173 607 -545 715 -1004 85 -361 66 -801 -51
-1215 -43 -151 -40 -173 18 -174 53 0 284 377 396 650 243 590 303 1238 163
1754 -178 652 -643 1100 -1294 1248 -93 21 -122 22 -716 25 -707 4 -649 12
-696 -90 -15 -34 -78 -172 -140 -307 -593 -1297 -1123 -2469 -1717 -3800 -210
-472 -193 -437 -204 -418 -11 19 -173 423 -630 1568 -214 536 -394 986 -400
1000 -6 14 -76 187 -156 385 -80 198 -182 452 -228 565 -46 113 -140 346 -209
518 -205 507 -225 554 -244 568 -14 11 -209 13 -1055 14 l-1038 0 3 -152z"/>
<path fill="#4A6B5C" d="M8830 7450 l0 -2582 -32 6 c-517 106 -1064 -47 -1442 -405 -598 -566
-501 -1354 196 -1598 489 -170 1134 -19 1548 363 234 217 350 418 423 736 l22
95 3 2373 c2 1961 5 2372 16 2372 27 0 132 -41 205 -81 315 -169 569 -524 675
-944 50 -198 60 -285 60 -525 0 -288 -27 -487 -105 -756 -34 -120 -35 -130
-11 -143 33 -18 64 11 154 144 227 334 402 795 469 1235 37 238 34 646 -4 843
-149 761 -637 1271 -1353 1418 -98 20 -147 23 -466 27 l-358 4 0 -2582z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

-27
View File
@@ -1,27 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="202 251 902 723">
<g transform="translate(0,1254) scale(0.1,-0.1)" fill-rule="evenodd">
<path fill="currentColor" d="M2252 9878 l3 -152 109 -22 c342 -72 492 -184 538 -405 16 -74 24
-4823 9 -5024 -20 -266 -73 -375 -236 -484 -116 -77 -332 -150 -543 -181 -114
-18 -107 -6 -110 -165 -1 -76 2 -143 7 -148 9 -9 2607 -11 2623 -1 14 9 10
280 -4 291 -7 5 -49 15 -93 22 -380 60 -638 193 -720 374 -63 136 -59 -12 -61
2247 -3 1999 -2 2054 15 2015 116 -253 646 -1520 1183 -2825 71 -173 216 -524
322 -780 206 -494 266 -640 370 -895 97 -237 68 -210 226 -210 l135 0 23 50
c13 27 95 212 182 410 134 307 747 1685 1015 2285 92 205 726 1599 910 2000
65 140 126 274 137 297 22 50 52 71 74 52 12 -10 14 -266 14 -1864 l0 -1852
-82 -7 c-347 -29 -716 -203 -973 -460 -710 -712 -343 -1645 650 -1649 453 -2
892 184 1206 510 193 202 295 397 351 676 l23 112 0 2357 c0 1297 0 2358 1
2358 12 0 142 -49 179 -67 342 -173 607 -545 715 -1004 85 -361 66 -801 -51
-1215 -43 -151 -40 -173 18 -174 53 0 284 377 396 650 243 590 303 1238 163
1754 -178 652 -643 1100 -1294 1248 -93 21 -122 22 -716 25 -707 4 -649 12
-696 -90 -15 -34 -78 -172 -140 -307 -593 -1297 -1123 -2469 -1717 -3800 -210
-472 -193 -437 -204 -418 -11 19 -173 423 -630 1568 -214 536 -394 986 -400
1000 -6 14 -76 187 -156 385 -80 198 -182 452 -228 565 -46 113 -140 346 -209
518 -205 507 -225 554 -244 568 -14 11 -209 13 -1055 14 l-1038 0 3 -152z"/>
<path fill="#4A6B5C" d="M8830 7450 l0 -2582 -32 6 c-517 106 -1064 -47 -1442 -405 -598 -566
-501 -1354 196 -1598 489 -170 1134 -19 1548 363 234 217 350 418 423 736 l22
95 3 2373 c2 1961 5 2372 16 2372 27 0 132 -41 205 -81 315 -169 569 -524 675
-944 50 -198 60 -285 60 -525 0 -288 -27 -487 -105 -756 -34 -120 -35 -130
-11 -143 33 -18 64 11 154 144 227 334 402 795 469 1235 37 238 34 646 -4 843
-149 761 -637 1271 -1353 1418 -98 20 -147 23 -466 27 l-358 4 0 -2582z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 70 B