your personal website on atproto - mirror blento.app
at switch-grid-layout 73 lines 2.6 kB view raw
1import { COLUMNS } from '$lib'; 2import { CardDefinitionsByType } from '$lib/cards'; 3import { clamp } from '$lib/helper'; 4import { fixAllCollisions, findValidPosition } from './algorithms'; 5import type { Item } from '$lib/types'; 6 7/** 8 * Returns true when mirroring should still happen (i.e. user hasn't edited both layouts). 9 * editedOn: 0/undefined = never, 1 = desktop only, 2 = mobile only, 3 = both 10 */ 11export function shouldMirror(editedOn: number | undefined): boolean { 12 return (editedOn ?? 0) !== 3; 13} 14 15/** Snap a value to the nearest even integer (min 2). */ 16function snapEven(v: number): number { 17 return Math.max(2, Math.round(v / 2) * 2); 18} 19 20/** 21 * Compute the other layout's size for a single item, preserving aspect ratio. 22 * Clamps to the card definition's minW/maxW/minH/maxH if defined. 23 * Mutates the item in-place. 24 */ 25export function mirrorItemSize(item: Item, fromMobile: boolean): void { 26 const def = CardDefinitionsByType[item.cardType]; 27 28 if (fromMobile) { 29 // Mobile → Desktop: halve both dimensions, then clamp to card def constraints 30 // (constraints are in desktop units) 31 item.w = clamp(snapEven(item.mobileW / 2), def?.minW ?? 2, def?.maxW ?? COLUMNS); 32 item.h = clamp(Math.round(item.mobileH / 2), def?.minH ?? 1, def?.maxH ?? Infinity); 33 } else { 34 // Desktop → Mobile: double both dimensions 35 // (don't apply card def constraints — they're in desktop units) 36 item.mobileW = Math.min(item.w * 2, COLUMNS); 37 item.mobileH = Math.max(item.h * 2, 2); 38 } 39} 40 41/** 42 * Mirror the full layout from one view to the other. 43 * Copies sizes proportionally and maps positions, then resolves collisions. 44 * Mutates items in-place. 45 */ 46export function mirrorLayout(items: Item[], fromMobile: boolean): void { 47 // Mirror sizes first 48 for (const item of items) { 49 mirrorItemSize(item, fromMobile); 50 } 51 52 if (fromMobile) { 53 // Mobile → Desktop: reflow items to use the full grid width. 54 // Sort by mobile position so items are placed in reading order. 55 const sorted = items.toSorted((a, b) => a.mobileY - b.mobileY || a.mobileX - b.mobileX); 56 57 // Place each item into the first available spot on the desktop grid 58 const placed: Item[] = []; 59 for (const item of sorted) { 60 item.x = 0; 61 item.y = 0; 62 findValidPosition(item, placed, false); 63 placed.push(item); 64 } 65 } else { 66 // Desktop → Mobile: proportional positions 67 for (const item of items) { 68 item.mobileX = clamp(Math.floor((item.x * 2) / 2) * 2, 0, COLUMNS - item.mobileW); 69 item.mobileY = Math.max(0, Math.round(item.y * 2)); 70 } 71 fixAllCollisions(items, true); 72 } 73}