Skip to content
Source
Sign inSign up
Open History to see the last commit

previewViewport.ts

174 lines4.2 KB

1import type {
2 PreviewAutomationResizeInput,
3 PreviewViewportPresetId,
4 PreviewViewportSetting,
5} from "@t3tools/contracts";
6import { PREVIEW_VIEWPORT_PRESET_IDS } from "@t3tools/contracts";
7​
8export interface PreviewViewportPreset {
9 readonly id: PreviewViewportPresetId;
10 readonly label: string;
11 readonly category: "Desktop" | "Tablet" | "Phone";
12 readonly detail: string;
13 readonly width: number;
14 readonly height: number;
16​
17type PreviewViewportPresetDefinition = Omit<PreviewViewportPreset, "id">;
18​
19// Chromium EmulatedDevices.ts CSS viewport sizes in Chrome DevTools default-device order.
20const PREVIEW_VIEWPORT_PRESET_DEFINITIONS = {
21 "iphone-se": {
22 label: "iPhone SE",
23 category: "Phone",
24 detail: "375 × 667",
25 width: 375,
26 height: 667,
27 },
28 "iphone-xr": {
29 label: "iPhone XR",
30 category: "Phone",
31 detail: "414 × 896",
32 width: 414,
33 height: 896,
34 },
35 "iphone-12-pro": {
36 label: "iPhone 12 Pro",
37 category: "Phone",
38 detail: "390 × 844",
39 width: 390,
40 height: 844,
41 },
42 "iphone-14-pro-max": {
43 label: "iPhone 14 Pro Max",
44 category: "Phone",
45 detail: "430 × 932",
46 width: 430,
47 height: 932,
48 },
49 "pixel-7": {
50 label: "Pixel 7",
51 category: "Phone",
52 detail: "412 × 915",
53 width: 412,
54 height: 915,
55 },
56 "samsung-galaxy-s8-plus": {
57 label: "Samsung Galaxy S8+",
58 category: "Phone",
59 detail: "360 × 740",
60 width: 360,
61 height: 740,
62 },
63 "samsung-galaxy-s20-ultra": {
64 label: "Samsung Galaxy S20 Ultra",
65 category: "Phone",
66 detail: "412 × 915",
67 width: 412,
68 height: 915,
69 },
70 "ipad-mini": {
71 label: "iPad Mini",
72 category: "Tablet",
73 detail: "768 × 1024",
74 width: 768,
75 height: 1024,
76 },
77 "ipad-air": {
78 label: "iPad Air",
79 category: "Tablet",
80 detail: "820 × 1180",
81 width: 820,
82 height: 1180,
83 },
84 "ipad-pro": {
85 label: "iPad Pro",
86 category: "Tablet",
87 detail: "1024 × 1366",
88 width: 1024,
89 height: 1366,
90 },
91 "surface-pro-7": {
92 label: "Surface Pro 7",
93 category: "Tablet",
94 detail: "912 × 1368",
95 width: 912,
96 height: 1368,
97 },
98 "surface-duo": {
99 label: "Surface Duo",
100 category: "Phone",
101 detail: "540 × 720",
102 width: 540,
103 height: 720,
104 },
105 "galaxy-z-fold-5": {
106 label: "Galaxy Z Fold 5",
107 category: "Phone",
108 detail: "344 × 882",
109 width: 344,
110 height: 882,
111 },
112 "asus-zenbook-fold": {
113 label: "Asus Zenbook Fold",
114 category: "Tablet",
115 detail: "853 × 1280",
116 width: 853,
117 height: 1280,
118 },
119 "samsung-galaxy-a51-71": {
120 label: "Samsung Galaxy A51/71",
121 category: "Phone",
122 detail: "412 × 914",
123 width: 412,
124 height: 914,
125 },
126 "nest-hub": {
127 label: "Nest Hub",
128 category: "Tablet",
129 detail: "1024 × 600",
130 width: 1024,
131 height: 600,
132 },
133 "nest-hub-max": {
134 label: "Nest Hub Max",
135 category: "Tablet",
136 detail: "1280 × 800",
137 width: 1280,
138 height: 800,
139 },
140} as const satisfies Record<PreviewViewportPresetId, PreviewViewportPresetDefinition>;
141​
142export const PREVIEW_VIEWPORT_PRESETS: ReadonlyArray<PreviewViewportPreset> =
143 PREVIEW_VIEWPORT_PRESET_IDS.map((id) => ({
144 id,
145 ...PREVIEW_VIEWPORT_PRESET_DEFINITIONS[id],
146 }));
147​
148export function resolvePreviewViewport(
149 input: PreviewAutomationResizeInput,
150): PreviewViewportSetting {
151 if (input.mode === "fill") return { _tag: "fill" };
152 if (input.mode === "preset" && input.preset !== undefined) {
153 const preset = PREVIEW_VIEWPORT_PRESETS.find((candidate) => candidate.id === input.preset);
154 if (!preset) throw new Error(`Unknown preview viewport preset: ${input.preset}`);
155 const landscape = input.orientation === "landscape";
156 const portrait = input.orientation === "portrait";
157 const nativePortrait = preset.height >= preset.width;
158 const shouldSwap = (landscape && nativePortrait) || (portrait && !nativePortrait);
159 return {
160 _tag: "preset",
161 width: shouldSwap ? preset.height : preset.width,
162 height: shouldSwap ? preset.width : preset.height,
163 presetId: preset.id,
164 };
165 }
166 if (input.width === undefined || input.height === undefined) {
167 throw new Error("Custom preview viewport requires width and height");
168 }
169 return {
170 _tag: "freeform",
171 width: input.width,
172 height: input.height,
173 };