Files
2026-10-03 20:07:49 +02:00

51 lines
1.7 KiB
TypeScript

export type GridMode = 'bento' | 'uniform'
export function useGridMode() {
const cookie = useCookie<GridMode>('grid-mode', {
default: () => 'bento',
maxAge: 60 * 60 * 24 * 365,
sameSite: 'lax',
})
// useState ist über alle Komponenten geteilt — die Cookie-Ref ist es nicht zuverlässig
const mode = useState<GridMode>('grid-mode', () => cookie.value)
const uniform = computed(() => mode.value === 'uniform')
const animating = ref(false)
async function toggle() {
const next: GridMode = uniform.value ? 'bento' : 'uniform'
if (!import.meta.client || animating.value) {
mode.value = next
cookie.value = next
return
}
// FLIP: alte Positionen messen, solange das DOM noch den alten Zustand zeigt
const tiles = Array.from(document.querySelectorAll<HTMLElement>('.upload-tile'))
const oldRects = tiles.map(el => el.getBoundingClientRect())
animating.value = true
mode.value = next
cookie.value = next
await nextTick()
tiles.forEach((el, i) => {
const oldR = oldRects[i]
const newR = el.getBoundingClientRect()
const dx = oldR.left - newR.left
const dy = oldR.top - newR.top
const sx = newR.width ? oldR.width / newR.width : 1
const sy = newR.height ? oldR.height / newR.height : 1
if (!dx && !dy && sx === 1 && sy === 1) return
el.animate(
[
{ transformOrigin: 'top left', transform: `translate(${dx}px, ${dy}px) scale(${sx}, ${sy})` },
{ transformOrigin: 'top left', transform: 'none' },
],
{ duration: 400, easing: 'cubic-bezier(0.2, 0, 0, 1)' },
)
})
setTimeout(() => {
animating.value = false
}, 400)
}
return { mode, uniform, toggle }
}