From 6b14b8ab19c70fac5016556073b242179b793ceb Mon Sep 17 00:00:00 2001 From: at-susie Date: Mon, 28 Sep 2026 11:02:02 +0200 Subject: [PATCH 1/3] chore: Add heros --- pages/common/heroshot.tsx | 60 ++++++++++ pages/heroshot/overview.page.tsx | 190 +++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 pages/common/heroshot.tsx create mode 100644 pages/heroshot/overview.page.tsx diff --git a/pages/common/heroshot.tsx b/pages/common/heroshot.tsx new file mode 100644 index 0000000000..2d50b2e819 --- /dev/null +++ b/pages/common/heroshot.tsx @@ -0,0 +1,60 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React from 'react'; + +import { + colorBackgroundContainerContent, + colorBorderDividerDefault, + colorTextBodySecondary, + fontSizeBodyS, +} from '~design-tokens'; + +// Thumbnail size used by the components overview pages of the documentation website. +export const HEROSHOT_WIDTH = 346; +export const HEROSHOT_HEIGHT = 170; + +interface HeroshotProps { + /** Caption rendered above the frame, outside of the captured area. */ + label?: string; + /** Vertical placement of the content inside the frame. Use `start` when the composition grows downwards (for example an open dropdown). */ + align?: 'center' | 'start'; + /** Inset between the frame edges and the content. Set to 0 for compositions that bleed to the edges. */ + padding?: number; + /** Stretches the content to the full frame width. Use for block components such as alert or container. */ + stretch?: boolean; + children: React.ReactNode; +} + +/** + * Renders its children inside a frame that matches the documentation website thumbnail size exactly. + * The dashed guide is drawn with an outline so it sits outside of the 346x170 box and is not captured + * when the frame is cropped to its bounding box. + */ +export function Heroshot({ label, align = 'center', padding = 16, stretch = false, children }: HeroshotProps) { + return ( +
+ {label ? ( +
+ {label} — {HEROSHOT_WIDTH}×{HEROSHOT_HEIGHT} +
+ ) : null} +
+ {children} +
+
+ ); +} diff --git a/pages/heroshot/overview.page.tsx b/pages/heroshot/overview.page.tsx new file mode 100644 index 0000000000..a52bf9af8f --- /dev/null +++ b/pages/heroshot/overview.page.tsx @@ -0,0 +1,190 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React, { useState } from 'react'; + +import { Alert, Autosuggest, Box, Button, ButtonGroup, FormField, Link, SpaceBetween } from '~components'; +import Dropdown from '~components/dropdown/internal'; +import Option from '~components/internal/components/option'; +import OptionsList from '~components/internal/components/options-list'; +import SelectableItem from '~components/internal/components/selectable-item'; + +import { i18nStrings as alertI18nStrings } from '../alert/common'; +import { SimplePage } from '../app/templates'; +import { Heroshot } from '../common/heroshot'; + +export default function HeroshotOverviewPage() { + return ( + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + The change applies after the next restart. Learn more + + + + + + + + + + + + + Retry} + > + The request timed out after 30 seconds. + + +
+ +
+ + + + + + + + + + + + + +
+
+ ); +} + +function Section({ title, children }: { title: string; children: React.ReactNode }) { + return ( + + {title} + + {children} + + + ); +} + +const autosuggestOptions = [ + { value: 'us-east-1' }, + { value: 'us-east-2' }, + { value: 'us-west-1' }, + { value: 'eu-west-1' }, +]; + +const enteredTextLabel = (value: string) => `Use: ${value}`; + +/** + * The public Autosuggest only opens its dropdown while the input is focused, which a heroshot + * can't rely on. This reproduces the open state statically from the same internal building + * blocks the real dropdown uses, so it stays open without focus or interaction. + */ +function OpenAutosuggest() { + // Narrow enough that the entered-text row plus the matches fit the frame without being clipped. + const highlightText = 'us-e'; + const matches = autosuggestOptions.filter(option => option.value.startsWith(highlightText)); + + return ( + {}} + onMouseDown={() => {}} + trigger={} + content={ + + + {enteredTextLabel(highlightText)} + + {matches.map(option => ( + + + ))} + + } + /> + ); +} + +function ClosedAutosuggest({ value: initialValue }: { value: string }) { + const [value, setValue] = useState(initialValue); + + return ( + setValue(event.detail.value)} + options={autosuggestOptions} + ariaLabel="Region" + placeholder="Choose a region" + enteredTextLabel={enteredTextLabel} + empty="No matches found" + /> + ); +} From 80d61ffecf633c929189bf2278936f148d6739a5 Mon Sep 17 00:00:00 2001 From: at-susie Date: Wed, 7 Oct 2026 10:06:13 +0200 Subject: [PATCH 2/3] chore: Add more components to the hero thumbnails --- pages/common/heroshot.tsx | 58 +- pages/heroshot/overview.page.tsx | 928 +++++++++++++++++++++++++++---- pages/utils/iframe-wrapper.tsx | 34 +- 3 files changed, 914 insertions(+), 106 deletions(-) diff --git a/pages/common/heroshot.tsx b/pages/common/heroshot.tsx index 2d50b2e819..97c0e1c37e 100644 --- a/pages/common/heroshot.tsx +++ b/pages/common/heroshot.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { - colorBackgroundContainerContent, + colorBackgroundLayoutMain, colorBorderDividerDefault, colorTextBodySecondary, fontSizeBodyS, @@ -16,12 +16,21 @@ export const HEROSHOT_HEIGHT = 170; interface HeroshotProps { /** Caption rendered above the frame, outside of the captured area. */ label?: string; - /** Vertical placement of the content inside the frame. Use `start` when the composition grows downwards (for example an open dropdown). */ + /** + * Vertical placement of the content inside the frame. Content is centered by default; use `start` + * only when it is taller than the frame, so the crop keeps the top instead of cutting both ends. + */ align?: 'center' | 'start'; /** Inset between the frame edges and the content. Set to 0 for compositions that bleed to the edges. */ padding?: number; /** Stretches the content to the full frame width. Use for block components such as alert or container. */ stretch?: boolean; + /** + * Lays the content out at this pixel size and scales it down to fit the frame. Use for page-level + * layouts (app layout, wizard) that only read as themselves at a full viewport width. Pick a size + * with the same 346:170 aspect ratio to avoid letterboxing. + */ + contentSize?: { width: number; height: number }; children: React.ReactNode; } @@ -29,14 +38,47 @@ interface HeroshotProps { * Renders its children inside a frame that matches the documentation website thumbnail size exactly. * The dashed guide is drawn with an outline so it sits outside of the 346x170 box and is not captured * when the frame is cropped to its bounding box. + * + * Animations are stopped by the `disableAnimations` screenshot area the page renders, so the frames + * capture the same pixels every time. */ -export function Heroshot({ label, align = 'center', padding = 16, stretch = false, children }: HeroshotProps) { +export function Heroshot({ + label, + align = 'center', + padding = 16, + stretch = false, + contentSize, + children, +}: HeroshotProps) { + // Scaled content is laid out at its own size and shrunk to fit, so it ignores the flex alignment below. + const scaled = contentSize ? ( +
+
+ {children} +
+
+ ) : null; + return (
{label ? ( -
- {label} — {HEROSHOT_WIDTH}×{HEROSHOT_HEIGHT} -
+
{label}
) : null}
- {children} + {scaled ?? children}
); diff --git a/pages/heroshot/overview.page.tsx b/pages/heroshot/overview.page.tsx index a52bf9af8f..92cc279faa 100644 --- a/pages/heroshot/overview.page.tsx +++ b/pages/heroshot/overview.page.tsx @@ -1,132 +1,877 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import React, { useState } from 'react'; +import React from 'react'; -import { Alert, Autosuggest, Box, Button, ButtonGroup, FormField, Link, SpaceBetween } from '~components'; +import { + ActionCard, + Alert, + AnchorNavigation, + AppLayout, + AppLayoutToolbar, + AreaChart, + AttributeEditor, + Autosuggest, + Badge, + BarChart, + Box, + BreadcrumbGroup, + Button, + ButtonDropdown, + ButtonGroup, + Calendar, + Cards, + Checkbox, + ColumnLayout, + Container, + ContentLayout, + CopyToClipboard, + DateInput, + DatePicker, + DateRangePicker, + Dialog, + Divider, + ExpandableSection, + FileDropzone, + FileInput, + FileTokenGroup, + FileUpload, + Flashbar, + Form, + FormField, + Grid, + Header, + HelpPanel, + Icon, + Input, + ItemCard, + KeyValuePairs, + LineChart, + Link, + List, + MixedLineBarChart, + Multiselect, + Pagination, + PieChart, + ProgressBar, + PromptInput, + PropertyFilter, + RadioButton, + RadioGroup, + SegmentedControl, + Select, + SideNavigation, + Skeleton, + Slider, + SpaceBetween, + Spinner, + StatusIndicator, + Steps, + Table, + Tabs, + TagEditor, + Textarea, + TextContent, + TextFilter, + Tiles, + TimeInput, + Toggle, + ToggleButton, + Token, + TokenGroup, + TopNavigation, + TreeView, +} from '~components'; import Dropdown from '~components/dropdown/internal'; import Option from '~components/internal/components/option'; import OptionsList from '~components/internal/components/options-list'; import SelectableItem from '~components/internal/components/selectable-item'; -import { i18nStrings as alertI18nStrings } from '../alert/common'; import { SimplePage } from '../app/templates'; import { Heroshot } from '../common/heroshot'; +import { IframeWrapper } from '../utils/iframe-wrapper'; export default function HeroshotOverviewPage() { return ( - -
- + + {/* The frames have a fixed size, so the gallery wraps them instead of stacking 70+ rows. */} +
+ + } + href="#" + /> + + + + + The change applies after the next restart. Learn more + + + + + + + + + + + + + + + + + + + + + }, + { label: 'Value', control: item => }, + ]} + /> + + + + + + + + + Default + Blue + Green + Red + + + + + + + + + + Instance details + + Review the configuration before you launch the instance. + + + + + + + + + - - - - - + + + Actions + + + + + + + + + + + + + item.id }} + cardDefinition={{ + header: item => item.id, + sections: [{ id: 'type', header: 'Type', content: item => item.type }], + }} + /> + + + + + + Enable monitoring + + + Enable termination protection + - - - - - + + + + Instance type +
t3.medium
- - - + + Region +
us-east-1
+
+
+ + + Instance details}> + + + + + + Instances}> + Content + + + + + + + + + + + + + + + + + + + + + + ({ valid: true })} + onChange={noop} + /> + + + + + + + +
+ } + > + This action cannot be undone. + +
+ + + + Instance settings + + Network settings - - - - + + + + + + + Drop files to upload + + + + + Choose file + + + + + `Remove file ${index + 1}` }} + /> + + + + + + + + + + + + + +
Create instance} + actions={ + + + + + } + > + + + + + +
+
+ + + + + + + + + + Main + Side + + + + +
Launch instance} + > + Instances +
+
+ + + Instances}> +

An instance is a virtual server in the cloud.

+
+
+ + + + + + + + + + + + + + + + Compare types} + /> + + + + Running }, + { label: 'Launched', value: 'Oct 6, 2026' }, + ]} + /> + + + + + + + + + Secondary link + + Primary link + + + External link + + + + + + ({ id: item.id, content: item.id, secondaryContent: item.type })} + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +