Template Gallery Page
v1.0.0Added in 1.8.0
A gallery of ready-made workspace templates: search hero with fanned previews, categories, sort, drawn template cards and a detail dialog.
The hero rises in once on mount over three template cards fanned out below the search (bold: cascaded beside the title); each one opens its template. Typing in the search filters the gallery live (/ focuses it, Escape clears, Enter scrolls to the results) and the popular chips fill it in. On desktop a sticky sidebar picks a category with live counts and a Made by filter (Everyone, Acme, Community); below 1024px the categories become a chip row that scrolls sideways and the Made by filter a segmented control. Popular / Newest / A to Z re-sorts the cards, which glide to their new places; twelve show at first and Show more opens the rest. No match shows an empty state with Clear filters. Every card draws a mini app of what the template is (kanban, roadmap, doc, OKRs, calendar, pipeline, bug table, checklist, automation flow, dashboard, sticky notes, form, habit grid) and is one button: it opens a detail dialog (a bottom sheet below 768px) with a large preview, what's included, the views, the creator and related templates, which swap in place. Use template spins, then confirms Added to your workspace with an Open template link, and the card gets an Added badge. The featured collection rail snaps sideways on phones and Add all adds its four templates. The community band links to submitting a template; the closing band and footer newsletter follow. Reduced motion keeps everything still.
Built with
The sections this page is made of. In the full-screen preview, hold Alt to outline each one on the page.
Add to a project
npx wingo-ui@latest add template-gallery-pagePro item: the CLI needs a Pro account. See plans
Usage
// app/(marketing)/templates/page.tsx
"use client"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { TemplateGalleryPage } from "@/components/templates/template-gallery-page"
export default function TemplatesRoute() {
const router = useRouter()
return (
<TemplateGalleryPage
linkComponent={Link}
ctaTone="brand"
templateHref={(template) => `/app/templates/${template.id}`}
onUseTemplate={async (template) => {
const response = await fetch("/api/templates/copy", { method: "POST", body: JSON.stringify({ id: template.id }) })
if (response.status === 401) router.push(`/sign-up?template=${template.id}`)
if (!response.ok) throw new Error("Could not copy the template")
}}
/>
)
}Props
designdefault"classic""classic" | "bold" | "minimal"The whole page's look. classic: a centered hero over a fanned stack of three template cards, raised cards and a gray collection band; bold: a pill header, a split hero with heavy type on a gradient mesh and a cascade of cards, bigger tiles, an inverted collection panel, an image band and a wordmark footer; minimal: a transparent header, a quiet hero without previews, flat cards with outlined previews, no gray bands, plain closing and a simple footer.
templatesdefault"GALLERY_TEMPLATES"GalleryTemplate[]The gallery: { id, name, description, summary?, category, preview, previewItems?, creator: { name, role?, team? }, uses, plan: free | business, createdAt, includes, views?, keywords? }. preview picks the drawn mini app; previewItems feeds it words.
categoriesdefault"TEMPLATE_CATEGORIES"TemplateCategory[]{ value, label, description? } for the sidebar and the chip row: Product, Engineering, Design, Marketing, HR, Operations, Personal.
collectiondefault"TEMPLATE_COLLECTION"TemplateCollectionThe featured collection: { eyebrow, title, description, steps: { template (id), label, note }[] }.
heroTemplatesdefault"TEMPLATE_GALLERY_HERO"string[]Three template ids drawn in the hero: back left, front, back right.
popularSearchesdefault"TEMPLATE_POPULAR_SEARCHES"string[]The chips under the search; a tap fills the search and scrolls to the results.
labelsdefault"DEFAULT_TEMPLATE_GALLERY_PAGE_LABELS"Partial<TemplateGalleryPageLabels>Every visible string; counts and names go through small functions (results, uses, previewTemplate...).
hrefsdefault"DEFAULT_TEMPLATE_GALLERY_PAGE_HREFS"Partial<TemplateGalleryPageHrefs>{ submit, guidelines, signUp, sales }: the community submit form, its guidelines and the closing band's buttons.
categorystringThe selected category (controlled): "all" or a category value.
defaultCategorydefault"all"stringThe category selected at first (uncontrolled).
onCategoryChange(category: string) => voidRuns when a category is picked.
querystringThe search text (controlled).
defaultQuerydefault""stringThe search text at first (uncontrolled).
onQueryChange(query: string) => voidRuns on every keystroke in the search.
defaultSortdefault"popular""popular" | "newest" | "az"The first order of the cards: most used, most recently published, or by name.
defaultSourcedefault"all""all" | "acme" | "community"The Made by filter at first: everyone, the Acme team only, or community members only.
columnsdefault32 | 3Cards per row from 1280px (two from 640px either way, one on phones).
pageSizedefault12numberCards shown before a Show more button that opens the rest of the matches; a new search, category, filter or sort pages again. 0 shows every match.
ctaVariantdefault"inverted""inverted" | "soft" | "split"The closing band: a solid band, a gray band, or copy beside the buttons on a raised panel. Applies to the classic design.
showPopulardefaulttruebooleanThe popular search chips under the search.
showHeroPreviewsdefaulttruebooleanThe three template cards in the hero (classic and bold).
showSidebardefaulttruebooleanThe sticky category sidebar from 1024px; off, the chip row shows at every width.
showSourceFilterdefaulttruebooleanThe Made by filter: Everyone, Acme, Community.
showSortdefaulttruebooleanThe Popular / Newest / A to Z control.
showCollectiondefaulttruebooleanThe featured collection rail.
showSubmitdefaulttruebooleanThe community band with the top creators, and the sidebar's submit card.
showCtadefaulttruebooleanThe closing call to action.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Accents: the selected category chip, the segmented controls, Business badges, the hero pill, the preview glow and the included checks.
ctaTonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Use template, Add all, Submit a template, the header's Get started and the closing band; brand is the marketing orange.
onUseTemplate(template: GalleryTemplate) => (void | Promise<unknown>)Use template and Add all. A returned promise keeps the button loading; a rejection leaves the template as it was. Without it the button waits 900 ms and confirms.
templateHrefdefault"/app/templates/<id>"(template: GalleryTemplate) => stringWhere Open template goes once the template was added.
onSubscribe(email: string) => (void | Promise<unknown>)The footer newsletter; a rejected promise shows an error.
headerdefaulttruebooleanThe marketing header; off inside a site layout.
footerdefaulttruebooleanThe marketing footer with its newsletter form.
headerPropsPartial<MarketingHeaderProps>Passed to MarketingHeader.
footerPropsPartial<MarketingFooterProps>Passed to MarketingFooter.
ctaPropsPartial<CtaSectionProps>Overrides for the closing CtaSection.
animateIndefaulttruebooleanThe hero and its cards rise in once on mount; false keeps the page still (thumbnails). Reduced motion always does.
localedefault"en-US"stringIntl locale for the use counts (de-DE: 63,9K), publish dates and the A to Z order.
linkComponentdefault"<a>"(props: LinkComponentProps) => ReactNodeThe router link for every link on the page (next/link in an app).
classNamestringClasses for the root.
classNamesPartial<Record<TemplateGalleryPageSlot, string>>Classes for header, hero, title, search, fan, gallery, sidebar, chips, toolbar, grid, card, preview, collection, submit, detail, cta and footer.
Parts
TemplatePreview
componentThe drawn mini app of a template (an app window peeking out of a tinted panel), sized by its container. Takes div props.
templateGalleryTemplateThe template to draw; its preview kind picks the scene and previewItems the words.
labelstringThe spoken label; without it the scene is decorative.
TEMPLATE_GALLERY_SAMPLE
constantAll the sample content in one object: categories, templates, collection, heroTemplates and popularSearches.
GALLERY_TEMPLATES
constantTwenty-four Acme templates across seven categories, from Sprint board to Personal goals.
TEMPLATE_CATEGORIES
constantProduct, Engineering, Design, Marketing, HR, Operations and Personal.
TEMPLATE_COLLECTION
constantShip a launch in 30 days: PRD, roadmap, sprint board and launch checklist.
TEMPLATE_GALLERY_HERO
constantThe three hero template ids.
TEMPLATE_POPULAR_SEARCHES
constantSprint, Roadmap, OKRs, Meeting notes and Hiring.
DEFAULT_TEMPLATE_GALLERY_PAGE_LABELS
constantThe English strings.
DEFAULT_TEMPLATE_GALLERY_PAGE_HREFS
constantThe default link targets.
TEMPLATE_GALLERY_PAGE_DESIGNS
constantThe design names, classic first: ["classic", "bold", "minimal"].
TemplateGalleryPageProps
typeProps of TemplateGalleryPage.
TemplateGalleryPageDesign
type"classic" | "bold" | "minimal".
TemplateGallerySort
type"popular" | "newest" | "az".
TemplateGallerySource
type"all" | "acme" | "community".
TemplatePreviewProps
typeProps of TemplatePreview.
GalleryTemplate
typeOne template of the gallery.
TemplatePreviewKind
typeThe drawn scenes: kanban, roadmap, doc, meeting, okr, calendar, pipeline, bugs, table, checklist, automation, report, retro, form, habits.
TemplateCategory
typeOne category.
TemplateCollection
typeThe featured collection.
TemplateGalleryPageLabels
typeThe strings labels can override.
TemplateGalleryPageHrefs
typeThe link targets hrefs can override.
Examples
Bold design
design="bold": a split hero with heavy type and a cascade of cards, big tiles, an inverted collection panel and a wordmark footer.
Minimal design
design="minimal": a quiet hero without previews, flat cards with outlined previews, no gray bands and a simple footer.
Brand orange, newest first
tone and ctaTone brand with the gallery sorted by Newest: orange chips, Business badges and Use template.
Community engineering templates
defaultCategory engineering and defaultSource community, two columns, without the hero previews.
No results
A search with no match: the empty state with Clear filters.
Dependencies
Files
- components/templates/template-gallery-page.tsx
- components/templates/template-gallery-page-data.ts