feat: sync active design to URL for refresh/share

Switching designs now reflects the active design id in the URL
(?design=<id>). A page refresh or shared link reopens that design;
an absent or unknown id falls back to the default design.

ha-relevant: no
This commit is contained in:
Pouzor
2026-07-09 16:29:04 +02:00
parent 15b000d555
commit 1aecb0a4d9
3 changed files with 80 additions and 2 deletions
@@ -0,0 +1,44 @@
import { describe, it, expect, beforeEach } from 'vitest'
import { getDesignIdFromUrl, setDesignIdInUrl } from '@/utils/designUrl'
describe('designUrl', () => {
beforeEach(() => {
window.history.replaceState(null, '', '/')
})
it('returns null when no design param is present', () => {
expect(getDesignIdFromUrl()).toBeNull()
})
it('reads the design id from the URL', () => {
window.history.replaceState(null, '', '/?design=abc-123')
expect(getDesignIdFromUrl()).toBe('abc-123')
})
it('writes the design id into the URL without adding history', () => {
const before = window.history.length
setDesignIdInUrl('design-42')
expect(getDesignIdFromUrl()).toBe('design-42')
expect(window.history.length).toBe(before)
})
it('drops the param when passed null', () => {
setDesignIdInUrl('design-42')
setDesignIdInUrl(null)
expect(getDesignIdFromUrl()).toBeNull()
expect(window.location.search).toBe('')
})
it('preserves other query params when updating design', () => {
window.history.replaceState(null, '', '/?key=secret')
setDesignIdInUrl('design-42')
const params = new URLSearchParams(window.location.search)
expect(params.get('key')).toBe('secret')
expect(params.get('design')).toBe('design-42')
})
it('round-trips: written id is read back', () => {
setDesignIdInUrl('xyz')
expect(getDesignIdFromUrl()).toBe('xyz')
})
})
+22
View File
@@ -0,0 +1,22 @@
// Sync the active design id with the browser URL (`?design=<id>`), so the
// current design survives a page refresh and can be shared/opened via URL.
// When no `design` param is present, callers fall back to the default design.
const DESIGN_PARAM = 'design'
/** Read the design id from the current URL, or null when absent. */
export function getDesignIdFromUrl(): string | null {
if (typeof window === 'undefined') return null
return new URLSearchParams(window.location.search).get(DESIGN_PARAM)
}
/**
* Reflect the active design id into the URL without adding a history entry
* (replaceState). Pass null to drop the param (back to the default design).
*/
export function setDesignIdInUrl(id: string | null): void {
if (typeof window === 'undefined') return
const url = new URL(window.location.href)
if (id) url.searchParams.set(DESIGN_PARAM, id)
else url.searchParams.delete(DESIGN_PARAM)
window.history.replaceState(window.history.state, '', url)
}