package gallery import ( "fmt" "html/template" ) // The preview heights: how tall each example's own document is, so the // box the widget draws it in has its height before the frame arrives, // scripts or no scripts, and a wrong number is a test failure rather // than a jump on screen. Measured, not guessed: the two height drives // in heights_browser_test.go read every frame's content off a real // engine and name the number to write here; FIESTA_SWEEP=full prints // the whole table. Keyed /, /row for a // grouped widget, and demo for the demo application. // // A box holds what a reader opens in it as well as what is there at // rest: a menu, the enhanced select's list, the date and time fields' // calendar or clock. The drives open each in turn in a box made tall // enough that a menu's dvh cap is not the frame, and the number here is // the larger of the two readings, so a box sized for the closed state // is a short box. Rastrillo reserves the same room by hand. The one // exception is a frame in previewRestHeights, whose open menus need far // more than its page: there the box rests at the closed reading and // view.js grows it to this one while a menu is open. // // Seeded once by the widget task to prove the measurement; calibrated // once the shell, the frame padding, the stage and the demo were all // in, which is when the drives started failing a short box; and swept // again over all twelve locales once the samples were translated, which // is where previewMobileLocaleHeights comes from: the languages whose // samples wrap taller than English's on a phone. // previewHeight is what an example gets when the table has nothing to // say about it. const previewHeight = 220 // previewHeights is each key's Desktop height, in CSS pixels at its // class's virtual width: the tallest of its content at rest and with // each thing in it open, over the twelve locales, with slack. var previewHeights = map[string]int{ "actor/a-person": 80, "actor/an-agent-acting-for-a-person": 80, "api-tokens/four-tokens-two-of-them-live": 990, "api-tokens/just-created-the-secret-shown-once": 1120, "api-tokens/no-tokens-yet": 670, "back-nav/back-to-a-record": 100, "badge/row": 100, "box/default": 220, "bulk-bar/three-rows-selected": 210, "button/default": 270, "callout/info": 140, "callout/negative": 160, "callout/negative-announced-as-an-alert": 160, "callout/positive": 160, "callout/warning": 160, "choice-field/pick-any": 280, "choice-field/pick-one": 280, "confirm-form/destructive": 170, "confirm-form/ordinary-default-cancel-wording": 170, "demo": 760, "detail-list/four-facts-one-machine-ish": 230, "dropdown/a-filter-menu-with-one-choice-applied": 200, "dropdown/menu-idiom": 210, "empty-state/sentence-only": 160, "empty-state/with-a-post-call-to-action": 240, "error-page/403-forbidden": 350, "error-page/404-not-found": 350, "error-page/422-unprocessable": 330, "error-page/500-server-error": 400, "error-page/503-unavailable": 350, "error-page/anything-else-the-generic-pair": 330, "field-check/disabled": 160, "field-check/off": 160, "field-check/on": 160, "field-date/bounded": 430, "field-date/enhanced-input-type-tomorrow-or-in-3-weeks": 430, "field-date/plain-the-bare-native-input": 190, "field-date/required-with-an-error": 430, "field-daterange/date-and-time-seeded": 460, "field-daterange/dates-only-with-an-error-on-the-end": 460, "field-datetime/bounded": 430, "field-datetime/enhanced-input-type-tomorrow-or-in-3-weeks": 430, "field-datetime/plain-the-bare-native-input": 190, "field-datetime/required-with-an-error": 430, "field-money/bare": 190, "field-money/with-a-hint": 210, "field-money/with-an-error": 210, "field-select/hand-written-with-optgroups": 400, "field-select/required-with-an-error": 210, "field-select/three-options-a-native-select": 180, "field-select/twelve-options-plain-the-enhancement-opted-out": 180, "field-select/twelve-options-the-filterable-combobox": 400, "field-text/bare": 190, "field-text/required": 190, "field-text/the-headline-field": 190, "field-text/with-a-hint": 210, "field-text/with-an-error": 210, "field-textarea/bare": 230, "field-textarea/required": 230, "field-textarea/with-a-hint": 260, "field-textarea/with-an-error": 260, "field-time/bounded": 440, "field-time/enhanced-input-type-half-seven-or-noon": 440, "field-time/plain-the-bare-native-input": 190, "field-time/required-with-an-error": 440, "field-url/bare": 190, "field-url/with-a-hint": 210, "field-url/with-an-error": 210, "field/bare": 190, "field/required": 190, "field/short": 190, "field/the-headline-field": 190, "field/with-a-hint": 190, "field/with-an-error": 210, "field/with-help-under-the-control": 210, "form-error/a-rejected-submission": 100, "form-foot/idle-the-button-before-anything-happens": 180, "form-foot/save-and-cancel": 180, "form-foot/submit-only": 180, "form-foot/working-what-busy-js-writes-on-the-way-out": 180, "form-layout/default": 380, "format-abbr/default": 170, "format-addresses/default": 220, "format-dates/default": 150, "format-durations/default": 150, "format-filesizes/default": 150, "format-identifiers/default": 170, "format-money/default": 210, "format-numbers/default": 140, "format-output/default": 230, "format-people/default": 120, "format-ratios/default": 280, "help/default": 100, "job-status/failed": 80, "job-status/finished": 80, "job-status/running": 90, "layout-column/default": 920, "layout-console-page/default": 680, "layout-console/default": 680, "layout-sidebar-page/default": 560, "layout-sidebar/default": 560, "layout-stage/default": 460, "layout-topbar/default": 660, "list-bar-search/empty-accessible-name-from-the-catalog": 120, "list-bar-search/with-a-query": 120, "list-bar-search/with-a-query-on-page-4": 120, "list-bar/search-with-a-filter-dropdown": 210, "list-grid/default": 280, "list-row-action/a-short-status-beside-the-name": 120, "list-row-action/lead-marker-status-and-an-action": 120, "list-row-action/name-and-meta-line-only": 120, "list-search-submit/default-label": 130, "locale-menu/twelve-languages-current-highlighted": 440, "media-grid/screenshots-a-logo-and-a-banner": 720, "media-grid/select-mode-one-tile-selected": 400, "meter/row": 100, "modal/default": 250, "notice/a-saved-message": 120, "page-header/title-only": 120, "page-header/title-subhead-and-a-primary-action": 150, "pagination/first-page-default-accessible-name": 120, "pagination/middle-of-a-long-list": 120, "person/large-the-show-header-size": 100, "person/name-and-email": 90, "person/no-initial": 90, "row-menu/links-a-form-and-a-destructive-item": 210, "row-menu/links-only-for-a-list-inside-a-selection-form": 180, "scheme-menu/standalone": 210, "scheme-menu/three-choices-dark-current": 210, "seg-tabs/buttons-that-switch-in-place": 110, "seg-tabs/two-sections": 110, "side-nav/four-sections-the-first-open": 210, "selbox/default": 90, "shell-sidebar/default": 260, "shell-topbar/default": 210, "signin/a-passkey": 470, "signin/after-the-link-is-sent": 390, "signin/after-the-link-is-sent-in-another-browser": 390, "signin/an-address-that-does-not-look-right": 390, "signin/asking-for-an-address": 420, "signin/coming-back-with-an-email-link": 390, "signin/coming-back-with-keymail": 390, "signin/email-and-password": 390, "signin/google-apple-and-the-rest": 310, "signin/on-the-way-to-keymail": 390, "signin/when-keymail-could-not-confirm-it": 410, "signin/when-keymail-was-offered-and-a-link-went-out": 390, "snippet/a-line-to-copy": 110, "stat-band/default": 190, "stat-band/two-to-a-line-on-a-phone": 200, "stat/a-shortened-number": 140, "stat/a-smaller-number": 140, "stat/the-big-number": 190, "stat/when-going-down-is-good": 180, "stat/when-going-up-is-bad": 180, "stat/when-you-cannot-say": 180, "status-pill/row": 100, "tblock/default": 270, } // previewMobileHeights overrides the 1.25× factor for the examples // whose Mobile layout is taller than the factor allows: one that // reflows onto a different axis at 390px, and, since Mobile lays out // at the stage's own width below 390px, one whose text wraps taller at // the narrowest phone frame, a 320px viewport. Seeded from the sweep at // 1500px with Mobile chosen and at a 320px viewport, over the twelve // locales, whose samples are all English until they are translated. var previewMobileHeights = map[string]int{ "api-tokens/four-tokens-two-of-them-live": 1850, "api-tokens/just-created-the-secret-shown-once": 2080, "badge/row": 252, "button/default": 410, "callout/negative": 240, "callout/warning": 240, "format-abbr/default": 220, "format-numbers/default": 220, "layout-column/default": 1330, "layout-console-page/default": 1130, "layout-sidebar-page/default": 1000, "layout-stage/default": 640, "layout-topbar/default": 1070, "list-bar/search-with-a-filter-dropdown": 310, "list-row-action/a-short-status-beside-the-name": 300, "list-row-action/lead-marker-status-and-an-action": 240, "media-grid/screenshots-a-logo-and-a-banner": 1590, "media-grid/select-mode-one-tile-selected": 850, "meter/row": 370, "page-header/title-subhead-and-a-primary-action": 220, "pagination/middle-of-a-long-list": 180, "side-nav/four-sections-the-first-open": 300, "signin/a-passkey": 730, "signin/after-the-link-is-sent": 600, "signin/after-the-link-is-sent-in-another-browser": 570, "signin/an-address-that-does-not-look-right": 610, "signin/asking-for-an-address": 660, "signin/coming-back-with-an-email-link": 560, "signin/coming-back-with-keymail": 580, "signin/on-the-way-to-keymail": 550, "signin/when-keymail-could-not-confirm-it": 660, "signin/when-keymail-was-offered-and-a-link-went-out": 660, "snippet/a-line-to-copy": 180, "stat-band/default": 460, "stat-band/two-to-a-line-on-a-phone": 310, "status-pill/row": 180, } // previewMobileLocaleHeights is a language's own Mobile height for a // frame whose content wraps taller in that language than // previewMobileHeights allows, read for that language's pages only. var previewMobileLocaleHeights = map[string]map[string]int{ "ar": { "api-tokens/four-tokens-two-of-them-live": 1880, "list-row-action/a-short-status-beside-the-name": 320, "stat-band/two-to-a-line-on-a-phone": 330, }, "bn": { "form-layout/default": 510, }, "es": { "api-tokens/four-tokens-two-of-them-live": 1880, "api-tokens/just-created-the-secret-shown-once": 2110, "box/default": 310, "callout/info": 210, "callout/negative-announced-as-an-alert": 240, "empty-state/with-a-post-call-to-action": 350, "error-page/403-forbidden": 470, "error-page/404-not-found": 440, "error-page/422-unprocessable": 470, "error-page/500-server-error": 520, "form-layout/default": 570, "format-abbr/default": 250, "list-row-action/a-short-status-beside-the-name": 410, "signin/after-the-link-is-sent-in-another-browser": 620, "signin/on-the-way-to-keymail": 580, "signin/when-keymail-could-not-confirm-it": 700, "signin/when-keymail-was-offered-and-a-link-went-out": 710, }, "ga": { "api-tokens/four-tokens-two-of-them-live": 2040, "api-tokens/just-created-the-secret-shown-once": 2290, "box/default": 320, "button/default": 450, "callout/positive": 240, "empty-state/with-a-post-call-to-action": 350, "error-page/403-forbidden": 500, "error-page/404-not-found": 450, "error-page/422-unprocessable": 440, "error-page/500-server-error": 520, "form-layout/default": 510, "format-abbr/default": 270, "format-addresses/default": 320, "layout-column/default": 1390, "layout-console-page/default": 1240, "layout-topbar/default": 1180, "list-row-action/lead-marker-status-and-an-action": 310, "modal/default": 350, "side-nav/four-sections-the-first-open": 320, "signin/after-the-link-is-sent": 630, "signin/after-the-link-is-sent-in-another-browser": 630, "signin/google-apple-and-the-rest": 430, "signin/on-the-way-to-keymail": 590, "signin/when-keymail-could-not-confirm-it": 730, "signin/when-keymail-was-offered-and-a-link-went-out": 720, "snippet/a-line-to-copy": 200, "stat-band/two-to-a-line-on-a-phone": 330, }, "hi": { "list-row-action/a-short-status-beside-the-name": 350, }, "ja": { "api-tokens/four-tokens-two-of-them-live": 1900, "api-tokens/just-created-the-secret-shown-once": 2130, "callout/negative-announced-as-an-alert": 240, "error-page/403-forbidden": 470, "error-page/500-server-error": 520, "form-layout/default": 530, "format-abbr/default": 250, "list-row-action/a-short-status-beside-the-name": 530, }, "pt-PT": { "api-tokens/four-tokens-two-of-them-live": 1900, "api-tokens/just-created-the-secret-shown-once": 2130, "button/default": 450, "callout/positive": 240, "callout/warning": 290, "empty-state/with-a-post-call-to-action": 350, "error-page/404-not-found": 440, "error-page/500-server-error": 520, "form-layout/default": 570, "format-abbr/default": 250, "list-row-action/a-short-status-beside-the-name": 390, "signin/after-the-link-is-sent": 630, "signin/after-the-link-is-sent-in-another-browser": 630, "signin/on-the-way-to-keymail": 590, "signin/when-keymail-could-not-confirm-it": 730, "signin/when-keymail-was-offered-and-a-link-went-out": 690, "tblock/default": 360, }, "ru": { "api-tokens/four-tokens-two-of-them-live": 2020, "api-tokens/just-created-the-secret-shown-once": 2270, "button/default": 450, "callout/info": 210, "callout/positive": 240, "callout/warning": 290, "error-page/403-forbidden": 520, "error-page/404-not-found": 440, "error-page/422-unprocessable": 500, "error-page/500-server-error": 550, "form-layout/default": 510, "format-abbr/default": 270, "format-addresses/default": 350, "job-status/failed": 130, "layout-column/default": 1400, "layout-console-page/default": 1200, "layout-topbar/default": 1140, "list-row-action/a-short-status-beside-the-name": 330, "list-row-action/lead-marker-status-and-an-action": 290, "modal/default": 350, "seg-tabs/buttons-that-switch-in-place": 170, "seg-tabs/two-sections": 170, "side-nav/four-sections-the-first-open": 320, "signin/after-the-link-is-sent": 640, "signin/after-the-link-is-sent-in-another-browser": 640, "signin/on-the-way-to-keymail": 590, "signin/when-keymail-could-not-confirm-it": 700, "signin/when-keymail-was-offered-and-a-link-went-out": 730, "snippet/a-line-to-copy": 220, "stat-band/two-to-a-line-on-a-phone": 330, "status-pill/row": 310, }, "vi": { "api-tokens/four-tokens-two-of-them-live": 1990, "api-tokens/just-created-the-secret-shown-once": 2230, "callout/info": 210, "error-page/403-forbidden": 440, "job-status/failed": 130, "list-row-action/a-short-status-beside-the-name": 420, "signin/after-the-link-is-sent-in-another-browser": 600, "signin/when-keymail-was-offered-and-a-link-went-out": 690, }, } // previewReserved is the room a box is given beyond what any sweep // measures, written by hand with its reason, and never printed by a // sweep: a floor under the measured table. The modal's is Rastrillo's // 620px: a modal wants a window to be modal over, and its panel is // sized from the window (85vh, at most 640px), so a box that only just // holds the panel shows a modal in a letterbox rather than one over a // page. The drives still read the panel for clipping at whatever the // box comes to. var previewReserved = map[string]int{ "modal/default": 620, } // restHeights is a box's Desktop and Mobile heights while nothing in // its frame is open. type restHeights struct{ Desktop, Mobile int } // previewRestHeights is for a frame whose open menu needs far more room // than its page: the column's footer menus open downward under the // page, so a box sized for them open is mostly empty at rest. The main // tables keep the open height; view.js shows these while no menu in // the frame is open and the open height while one is. With scripts // off the box keeps the open height, since nothing could grow it. var previewRestHeights = map[string]restHeights{ "layout-column/default": {Desktop: 650, Mobile: 1110}, } // heightOf is one key's Desktop height: the measured table's, or the // default, raised to its reservation where it has one. func heightOf(key string) int { h, ok := previewHeights[key] if !ok { h = previewHeight } if r := previewReserved[key]; r > h { h = r } return h } // previewStyle writes one widget's two virtual heights. Mobile is a // quarter taller than Desktop unless the tables say otherwise: one // factor rather than a second table, since a component this small has // one column either way, and the exceptions are the ones whose whole // shape is a row that becomes a column. func previewStyle(locale, key string) template.CSS { h, m := previewHeightsFor(locale, key) css := fmt.Sprintf("--ds-h: %dpx; --ds-hm: %dpx", h, m) if r, ok := previewRestHeights[key]; ok { css += fmt.Sprintf("; --ds-hr: %dpx; --ds-hmr: %dpx", r.Desktop, r.Mobile) } return template.CSS(css) } // previewHeightsFor is one widget's Desktop and Mobile heights in // locale, as previewStyle writes them. func previewHeightsFor(locale, key string) (desktop, mobile int) { h := heightOf(key) m, ok := previewMobileHeights[key] if !ok { m = h * 5 / 4 } if l, ok := previewMobileLocaleHeights[locale][key]; ok && l > m { m = l } return h, m }