rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1package gallery
2
3import (
4 "fmt"
5 "html/template"
6)
7
8// The preview heights: how tall each example's own document is, so the
9// box the widget draws it in has its height before the frame arrives,
10// scripts or no scripts, and a wrong number is a test failure rather
11// than a jump on screen. Measured, not guessed: the two height drives
12// in heights_browser_test.go read every frame's content off a real
13// engine and name the number to write here; FIESTA_SWEEP=full prints
14// the whole table. Keyed <example>/<state>, <example>/row for a
15// grouped widget, and demo for the demo application.
16//
17// A box holds what a reader opens in it as well as what is there at
18// rest: a menu, the enhanced select's list, the date and time fields'
19// calendar or clock. The drives open each in turn in a box made tall
20// enough that a menu's dvh cap is not the frame, and the number here is
21// the larger of the two readings, so a box sized for the closed state
22// is a short box. Rastrillo reserves the same room by hand. The one
23// exception is a frame in previewRestHeights, whose open menus need far
24// more than its page: there the box rests at the closed reading and
25// view.js grows it to this one while a menu is open.
26//
27// Seeded once by the widget task to prove the measurement; calibrated
28// once the shell, the frame padding, the stage and the demo were all
29// in, which is when the drives started failing a short box; and swept
30// again over all twelve locales once the samples were translated, which
31// is where previewMobileLocaleHeights comes from: the languages whose
32// samples wrap taller than English's on a phone.
33
34// previewHeight is what an example gets when the table has nothing to
35// say about it.
36const previewHeight = 220
37
38// previewHeights is each key's Desktop height, in CSS pixels at its
39// class's virtual width: the tallest of its content at rest and with
40// each thing in it open, over the twelve locales, with slack.
41var previewHeights = map[string]int{
42 "actor/a-person": 80,
43 "actor/an-agent-acting-for-a-person": 80,
44 "api-tokens/four-tokens-two-of-them-live": 990,
45 "api-tokens/just-created-the-secret-shown-once": 1120,
46 "api-tokens/no-tokens-yet": 670,
47 "back-nav/back-to-a-record": 100,
48 "badge/row": 100,
49 "box/default": 220,
50 "bulk-bar/three-rows-selected": 210,
51 "button/default": 270,
52 "callout/info": 140,
53 "callout/negative": 160,
54 "callout/negative-announced-as-an-alert": 160,
55 "callout/positive": 160,
56 "callout/warning": 160,
57 "choice-field/pick-any": 280,
58 "choice-field/pick-one": 280,
59 "confirm-form/destructive": 170,
60 "confirm-form/ordinary-default-cancel-wording": 170,
61 "demo": 760,
62 "detail-list/four-facts-one-machine-ish": 230,
63 "dropdown/a-filter-menu-with-one-choice-applied": 200,
64 "dropdown/menu-idiom": 210,
65 "empty-state/sentence-only": 160,
66 "empty-state/with-a-post-call-to-action": 240,
67 "error-page/403-forbidden": 350,
68 "error-page/404-not-found": 350,
69 "error-page/422-unprocessable": 330,
70 "error-page/500-server-error": 400,
71 "error-page/503-unavailable": 350,
72 "error-page/anything-else-the-generic-pair": 330,
73 "field-check/disabled": 160,
74 "field-check/off": 160,
75 "field-check/on": 160,
76 "field-date/bounded": 430,
77 "field-date/enhanced-input-type-tomorrow-or-in-3-weeks": 430,
78 "field-date/plain-the-bare-native-input": 190,
79 "field-date/required-with-an-error": 430,
80 "field-daterange/date-and-time-seeded": 460,
81 "field-daterange/dates-only-with-an-error-on-the-end": 460,
82 "field-datetime/bounded": 430,
83 "field-datetime/enhanced-input-type-tomorrow-or-in-3-weeks": 430,
84 "field-datetime/plain-the-bare-native-input": 190,
85 "field-datetime/required-with-an-error": 430,
86 "field-money/bare": 190,
87 "field-money/with-a-hint": 210,
88 "field-money/with-an-error": 210,
89 "field-select/hand-written-with-optgroups": 400,
90 "field-select/required-with-an-error": 210,
91 "field-select/three-options-a-native-select": 180,
92 "field-select/twelve-options-plain-the-enhancement-opted-out": 180,
93 "field-select/twelve-options-the-filterable-combobox": 400,
94 "field-text/bare": 190,
95 "field-text/required": 190,
96 "field-text/the-headline-field": 190,
97 "field-text/with-a-hint": 210,
98 "field-text/with-an-error": 210,
99 "field-textarea/bare": 230,
100 "field-textarea/required": 230,
101 "field-textarea/with-a-hint": 260,
102 "field-textarea/with-an-error": 260,
103 "field-time/bounded": 440,
104 "field-time/enhanced-input-type-half-seven-or-noon": 440,
105 "field-time/plain-the-bare-native-input": 190,
106 "field-time/required-with-an-error": 440,
107 "field-url/bare": 190,
108 "field-url/with-a-hint": 210,
109 "field-url/with-an-error": 210,
110 "field/bare": 190,
111 "field/required": 190,
112 "field/short": 190,
113 "field/the-headline-field": 190,
114 "field/with-a-hint": 190,
115 "field/with-an-error": 210,
116 "field/with-help-under-the-control": 210,
117 "form-error/a-rejected-submission": 100,
118 "form-foot/idle-the-button-before-anything-happens": 180,
119 "form-foot/save-and-cancel": 180,
120 "form-foot/submit-only": 180,
121 "form-foot/working-what-busy-js-writes-on-the-way-out": 180,
122 "form-layout/default": 380,
123 "format-abbr/default": 170,
124 "format-addresses/default": 220,
125 "format-dates/default": 150,
126 "format-durations/default": 150,
127 "format-filesizes/default": 150,
128 "format-identifiers/default": 170,
129 "format-money/default": 210,
130 "format-numbers/default": 140,
131 "format-output/default": 230,
132 "format-people/default": 120,
133 "format-ratios/default": 280,
134 "help/default": 100,
135 "job-status/failed": 80,
136 "job-status/finished": 80,
137 "job-status/running": 90,
138 "layout-column/default": 920,
139 "layout-console-page/default": 680,
140 "layout-console/default": 680,
141 "layout-sidebar-page/default": 560,
142 "layout-sidebar/default": 560,
143 "layout-stage/default": 460,
144 "layout-topbar/default": 660,
145 "list-bar-search/empty-accessible-name-from-the-catalog": 120,
146 "list-bar-search/with-a-query": 120,
147 "list-bar-search/with-a-query-on-page-4": 120,
148 "list-bar/search-with-a-filter-dropdown": 210,
149 "list-grid/default": 280,
150 "list-row-action/a-short-status-beside-the-name": 120,
151 "list-row-action/lead-marker-status-and-an-action": 120,
152 "list-row-action/name-and-meta-line-only": 120,
153 "list-search-submit/default-label": 130,
154 "locale-menu/twelve-languages-current-highlighted": 440,
155 "media-grid/screenshots-a-logo-and-a-banner": 720,
156 "media-grid/select-mode-one-tile-selected": 400,
157 "meter/row": 100,
158 "modal/default": 250,
159 "notice/a-saved-message": 120,
160 "page-header/title-only": 120,
161 "page-header/title-subhead-and-a-primary-action": 150,
162 "pagination/first-page-default-accessible-name": 120,
163 "pagination/middle-of-a-long-list": 120,
164 "person/large-the-show-header-size": 100,
165 "person/name-and-email": 90,
166 "person/no-initial": 90,
167 "row-menu/links-a-form-and-a-destructive-item": 210,
168 "row-menu/links-only-for-a-list-inside-a-selection-form": 180,
169 "scheme-menu/standalone": 210,
170 "scheme-menu/three-choices-dark-current": 210,
171 "seg-tabs/buttons-that-switch-in-place": 110,
172 "seg-tabs/two-sections": 110,
173 "side-nav/four-sections-the-first-open": 210,
174 "selbox/default": 90,
175 "shell-sidebar/default": 260,
176 "shell-topbar/default": 210,
177 "signin/a-passkey": 470,
178 "signin/after-the-link-is-sent": 390,
179 "signin/after-the-link-is-sent-in-another-browser": 390,
180 "signin/an-address-that-does-not-look-right": 390,
181 "signin/asking-for-an-address": 420,
182 "signin/coming-back-with-an-email-link": 390,
183 "signin/coming-back-with-keymail": 390,
184 "signin/email-and-password": 390,
185 "signin/google-apple-and-the-rest": 310,
186 "signin/on-the-way-to-keymail": 390,
187 "signin/when-keymail-could-not-confirm-it": 410,
188 "signin/when-keymail-was-offered-and-a-link-went-out": 390,
189 "snippet/a-line-to-copy": 110,
190 "stat-band/default": 190,
191 "stat-band/two-to-a-line-on-a-phone": 200,
192 "stat/a-shortened-number": 140,
193 "stat/a-smaller-number": 140,
194 "stat/the-big-number": 190,
195 "stat/when-going-down-is-good": 180,
196 "stat/when-going-up-is-bad": 180,
197 "stat/when-you-cannot-say": 180,
198 "status-pill/row": 100,
199 "tblock/default": 270,
200}
201
202// previewMobileHeights overrides the 1.25× factor for the examples
203// whose Mobile layout is taller than the factor allows: one that
204// reflows onto a different axis at 390px, and, since Mobile lays out
205// at the stage's own width below 390px, one whose text wraps taller at
206// the narrowest phone frame, a 320px viewport. Seeded from the sweep at
207// 1500px with Mobile chosen and at a 320px viewport, over the twelve
208// locales, whose samples are all English until they are translated.
209var previewMobileHeights = map[string]int{
210 "api-tokens/four-tokens-two-of-them-live": 1850,
211 "api-tokens/just-created-the-secret-shown-once": 2080,
212 "badge/row": 252,
213 "button/default": 410,
214 "callout/negative": 240,
215 "callout/warning": 240,
216 "format-abbr/default": 220,
217 "format-numbers/default": 220,
218 "layout-column/default": 1330,
219 "layout-console-page/default": 1130,
220 "layout-sidebar-page/default": 1000,
221 "layout-stage/default": 640,
222 "layout-topbar/default": 1070,
223 "list-bar/search-with-a-filter-dropdown": 310,
224 "list-row-action/a-short-status-beside-the-name": 300,
225 "list-row-action/lead-marker-status-and-an-action": 240,
226 "media-grid/screenshots-a-logo-and-a-banner": 1590,
227 "media-grid/select-mode-one-tile-selected": 850,
228 "meter/row": 370,
229 "page-header/title-subhead-and-a-primary-action": 220,
230 "pagination/middle-of-a-long-list": 180,
231 "side-nav/four-sections-the-first-open": 300,
232 "signin/a-passkey": 730,
233 "signin/after-the-link-is-sent": 600,
234 "signin/after-the-link-is-sent-in-another-browser": 570,
235 "signin/an-address-that-does-not-look-right": 610,
236 "signin/asking-for-an-address": 660,
237 "signin/coming-back-with-an-email-link": 560,
238 "signin/coming-back-with-keymail": 580,
239 "signin/on-the-way-to-keymail": 550,
240 "signin/when-keymail-could-not-confirm-it": 660,
241 "signin/when-keymail-was-offered-and-a-link-went-out": 660,
242 "snippet/a-line-to-copy": 180,
243 "stat-band/default": 460,
244 "stat-band/two-to-a-line-on-a-phone": 310,
245 "status-pill/row": 180,
246}
247
248// previewMobileLocaleHeights is a language's own Mobile height for a
249// frame whose content wraps taller in that language than
250// previewMobileHeights allows, read for that language's pages only.
251var previewMobileLocaleHeights = map[string]map[string]int{
252 "ar": {
253 "api-tokens/four-tokens-two-of-them-live": 1880,
254 "list-row-action/a-short-status-beside-the-name": 320,
255 "stat-band/two-to-a-line-on-a-phone": 330,
256 },
257 "bn": {
258 "form-layout/default": 510,
259 },
260 "es": {
261 "api-tokens/four-tokens-two-of-them-live": 1880,
262 "api-tokens/just-created-the-secret-shown-once": 2110,
263 "box/default": 310,
264 "callout/info": 210,
265 "callout/negative-announced-as-an-alert": 240,
266 "empty-state/with-a-post-call-to-action": 350,
267 "error-page/403-forbidden": 470,
268 "error-page/404-not-found": 440,
269 "error-page/422-unprocessable": 470,
270 "error-page/500-server-error": 520,
271 "form-layout/default": 570,
272 "format-abbr/default": 250,
273 "list-row-action/a-short-status-beside-the-name": 410,
274 "signin/after-the-link-is-sent-in-another-browser": 620,
275 "signin/on-the-way-to-keymail": 580,
276 "signin/when-keymail-could-not-confirm-it": 700,
277 "signin/when-keymail-was-offered-and-a-link-went-out": 710,
278 },
279 "ga": {
280 "api-tokens/four-tokens-two-of-them-live": 2040,
281 "api-tokens/just-created-the-secret-shown-once": 2290,
282 "box/default": 320,
283 "button/default": 450,
284 "callout/positive": 240,
285 "empty-state/with-a-post-call-to-action": 350,
286 "error-page/403-forbidden": 500,
287 "error-page/404-not-found": 450,
288 "error-page/422-unprocessable": 440,
289 "error-page/500-server-error": 520,
290 "form-layout/default": 510,
291 "format-abbr/default": 270,
292 "format-addresses/default": 320,
293 "layout-column/default": 1390,
294 "layout-console-page/default": 1240,
295 "layout-topbar/default": 1180,
296 "list-row-action/lead-marker-status-and-an-action": 310,
297 "modal/default": 350,
298 "side-nav/four-sections-the-first-open": 320,
299 "signin/after-the-link-is-sent": 630,
300 "signin/after-the-link-is-sent-in-another-browser": 630,
301 "signin/google-apple-and-the-rest": 430,
302 "signin/on-the-way-to-keymail": 590,
303 "signin/when-keymail-could-not-confirm-it": 730,
304 "signin/when-keymail-was-offered-and-a-link-went-out": 720,
305 "snippet/a-line-to-copy": 200,
306 "stat-band/two-to-a-line-on-a-phone": 330,
307 },
308 "hi": {
309 "list-row-action/a-short-status-beside-the-name": 350,
310 },
311 "ja": {
312 "api-tokens/four-tokens-two-of-them-live": 1900,
313 "api-tokens/just-created-the-secret-shown-once": 2130,
314 "callout/negative-announced-as-an-alert": 240,
315 "error-page/403-forbidden": 470,
316 "error-page/500-server-error": 520,
317 "form-layout/default": 530,
318 "format-abbr/default": 250,
319 "list-row-action/a-short-status-beside-the-name": 530,
320 },
321 "pt-PT": {
322 "api-tokens/four-tokens-two-of-them-live": 1900,
323 "api-tokens/just-created-the-secret-shown-once": 2130,
324 "button/default": 450,
325 "callout/positive": 240,
326 "callout/warning": 290,
327 "empty-state/with-a-post-call-to-action": 350,
328 "error-page/404-not-found": 440,
329 "error-page/500-server-error": 520,
330 "form-layout/default": 570,
331 "format-abbr/default": 250,
332 "list-row-action/a-short-status-beside-the-name": 390,
333 "signin/after-the-link-is-sent": 630,
334 "signin/after-the-link-is-sent-in-another-browser": 630,
335 "signin/on-the-way-to-keymail": 590,
336 "signin/when-keymail-could-not-confirm-it": 730,
337 "signin/when-keymail-was-offered-and-a-link-went-out": 690,
338 "tblock/default": 360,
339 },
340 "ru": {
341 "api-tokens/four-tokens-two-of-them-live": 2020,
342 "api-tokens/just-created-the-secret-shown-once": 2270,
343 "button/default": 450,
344 "callout/info": 210,
345 "callout/positive": 240,
346 "callout/warning": 290,
347 "error-page/403-forbidden": 520,
348 "error-page/404-not-found": 440,
349 "error-page/422-unprocessable": 500,
350 "error-page/500-server-error": 550,
351 "form-layout/default": 510,
352 "format-abbr/default": 270,
353 "format-addresses/default": 350,
354 "job-status/failed": 130,
355 "layout-column/default": 1400,
356 "layout-console-page/default": 1200,
357 "layout-topbar/default": 1140,
358 "list-row-action/a-short-status-beside-the-name": 330,
359 "list-row-action/lead-marker-status-and-an-action": 290,
360 "modal/default": 350,
361 "seg-tabs/buttons-that-switch-in-place": 170,
362 "seg-tabs/two-sections": 170,
363 "side-nav/four-sections-the-first-open": 320,
364 "signin/after-the-link-is-sent": 640,
365 "signin/after-the-link-is-sent-in-another-browser": 640,
366 "signin/on-the-way-to-keymail": 590,
367 "signin/when-keymail-could-not-confirm-it": 700,
368 "signin/when-keymail-was-offered-and-a-link-went-out": 730,
369 "snippet/a-line-to-copy": 220,
370 "stat-band/two-to-a-line-on-a-phone": 330,
371 "status-pill/row": 310,
372 },
373 "vi": {
374 "api-tokens/four-tokens-two-of-them-live": 1990,
375 "api-tokens/just-created-the-secret-shown-once": 2230,
376 "callout/info": 210,
377 "error-page/403-forbidden": 440,
378 "job-status/failed": 130,
379 "list-row-action/a-short-status-beside-the-name": 420,
380 "signin/after-the-link-is-sent-in-another-browser": 600,
381 "signin/when-keymail-was-offered-and-a-link-went-out": 690,
382 },
383}
384
385// previewReserved is the room a box is given beyond what any sweep
386// measures, written by hand with its reason, and never printed by a
387// sweep: a floor under the measured table. The modal's is Rastrillo's
388// 620px: a modal wants a window to be modal over, and its panel is
389// sized from the window (85vh, at most 640px), so a box that only just
390// holds the panel shows a modal in a letterbox rather than one over a
391// page. The drives still read the panel for clipping at whatever the
392// box comes to.
393var previewReserved = map[string]int{
394 "modal/default": 620,
395}
396
397// restHeights is a box's Desktop and Mobile heights while nothing in
398// its frame is open.
399type restHeights struct{ Desktop, Mobile int }
400
401// previewRestHeights is for a frame whose open menu needs far more room
402// than its page: the column's footer menus open downward under the
403// page, so a box sized for them open is mostly empty at rest. The main
404// tables keep the open height; view.js shows these while no menu in
405// the frame is open and the open height while one is. With scripts
406// off the box keeps the open height, since nothing could grow it.
407var previewRestHeights = map[string]restHeights{
408 "layout-column/default": {Desktop: 650, Mobile: 1110},
409}
410
411// heightOf is one key's Desktop height: the measured table's, or the
412// default, raised to its reservation where it has one.
413func heightOf(key string) int {
414 h, ok := previewHeights[key]
415 if !ok {
416 h = previewHeight
417 }
418 if r := previewReserved[key]; r > h {
419 h = r
420 }
421 return h
422}
423
424// previewStyle writes one widget's two virtual heights. Mobile is a
425// quarter taller than Desktop unless the tables say otherwise: one
426// factor rather than a second table, since a component this small has
427// one column either way, and the exceptions are the ones whose whole
428// shape is a row that becomes a column.
429func previewStyle(locale, key string) template.CSS {
430 h, m := previewHeightsFor(locale, key)
431 css := fmt.Sprintf("--ds-h: %dpx; --ds-hm: %dpx", h, m)
432 if r, ok := previewRestHeights[key]; ok {
433 css += fmt.Sprintf("; --ds-hr: %dpx; --ds-hmr: %dpx", r.Desktop, r.Mobile)
434 }
435 return template.CSS(css)
436}
437
438// previewHeightsFor is one widget's Desktop and Mobile heights in
439// locale, as previewStyle writes them.
440func previewHeightsFor(locale, key string) (desktop, mobile int) {
441 h := heightOf(key)
442 m, ok := previewMobileHeights[key]
443 if !ok {
444 m = h * 5 / 4
445 }
446 if l, ok := previewMobileLocaleHeights[locale][key]; ok && l > m {
447 m = l
448 }
449 return h, m
450}
451