Hintergründe: 15 kuratierte Bilder statt Testfotos

Elf universelle Hintergründe von grafisch bis fotografisch (Tinte, Goldstaub,
Horizont, Kohle, Leinen, Nebel, Dämmerung, Nachthimmel, Tusche, Papier,
Aquarell) plus vier v2-Fassungen zur Abstimmung, alle 2048² JPEG mit
320er Vorschauen (7 MB statt 48 MB). Auswahl, Reihenfolge und Helligkeit
stehen in src/config/backgrounds.js; der Picker zeigt Name und aktuelle
Wahl, das Logo folgt der Bildhelligkeit, Presets zeigen auf die neuen
Bilder, alte Pfade werden beim Laden auf den Nachfolger umgeschrieben.
Der Service Worker cacht nur die Vorschauen vor.

Werkzeuge zum Neu-Rendern (SVG-Builder, Gemini-Prompts) liegen in
dev/tools/backgrounds, die Sichtungs-Renders bleiben lokal (gitignore).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-25 09:31:09 +00:00
parent 10251e4f41
commit 522deffa1a
66 changed files with 556 additions and 38 deletions

View file

@ -38,3 +38,10 @@ describe('brand — logo variant follows the LifeWave background', () => {
expect(logoVariantForBackground({ bgEdge: 'transparent', isDark: true })).toBe('negative')
})
})
describe('brand — bundled photos carry their own tone', () => {
it('lets a light photo win over a dark theme and the other way round', () => {
expect(logoVariantForBackground({ backgroundImage: '/images/backgrounds/papier.jpg', imageTone: 'light', isDark: true })).toBe('positive')
expect(logoVariantForBackground({ backgroundImage: '/images/backgrounds/tinte.jpg', imageTone: 'dark', isDark: false })).toBe('negative')
})
})

View file

@ -233,7 +233,7 @@ describe('events store — media types and the voice note (remote user)', () =>
await flush(3)
await eventsStore.deleteGhostVoiceNote('v1')
await flush(2)
await waitFor(() => api.callsTo(MEDIA_DELETE).length === 1, { label: 'DELETE sent' })
const deletes = api.callsTo(MEDIA_DELETE)
expect(deletes).toHaveLength(1)

View file

@ -23,6 +23,7 @@ vi.mock('src/services/apiClient', () => ({
import { BRAND_PRESET_ID, WAVE_PRESETS, findWavePreset, isBuiltInPresetId, presetPreviewStyle } from 'src/config/wavePresets'
import { FLOATING_LINES_DEFAULTS, useSettingsStore } from 'stores/settings'
import { relativeLuminance } from 'src/utils/brand'
import { BACKGROUND_IMAGES, normalizeBackgroundImage } from 'src/config/backgrounds'
// Vitest runs from the frontend directory.
const publicDir = resolve(process.cwd(), 'public')
@ -186,3 +187,30 @@ describe('settings store — accent colour defaults', () => {
expect(useSettingsStore().accentColor).toBe('grey')
})
})
describe('backgrounds — bundled set and legacy paths', () => {
it('ships every configured background with its thumbnail', () => {
expect(BACKGROUND_IMAGES.length).toBeGreaterThanOrEqual(10)
expect(new Set(BACKGROUND_IMAGES.map(image => image.id)).size).toBe(BACKGROUND_IMAGES.length)
for (const image of BACKGROUND_IMAGES) {
expect(existsSync(`${publicDir}${image.src}`), `${image.id} missing`).toBe(true)
expect(existsSync(`${publicDir}${image.thumb}`), `${image.id} thumb missing`).toBe(true)
expect(['dark', 'light']).toContain(image.tone)
}
})
it('rewrites a stored path from the retired test set and keeps everything else', () => {
expect(normalizeBackgroundImage('/images/bg-image-1.jpg')).toBe('/images/backgrounds/nachthimmel.jpg')
expect(normalizeBackgroundImage('/images/backgrounds/kohle.jpg')).toBe('/images/backgrounds/kohle.jpg')
expect(normalizeBackgroundImage('/settings/media/background?v=1')).toBe('/settings/media/background?v=1')
expect(normalizeBackgroundImage('')).toBe('')
expect(normalizeBackgroundImage(undefined)).toBe('')
})
it('the settings store applies the rewrite when loading', () => {
setActivePinia(createPinia())
api = createApiRouter()
localStorage.setItem('thatsme-settings:guest', JSON.stringify({ floatingLines: { backgroundImage: '/images/bg-image-3.jpg' } }))
expect(useSettingsStore().floatingLines.backgroundImage).toBe('/images/backgrounds/nebel.jpg')
})
})