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