forked from BRETT/BRETT
51 lines
1.7 KiB
TypeScript
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 }
|
|
}
|