From 6056009b60a2b8aa722ca1a0dd6792b4d46e769e Mon Sep 17 00:00:00 2001 From: codecalm Date: Tue, 6 Oct 2026 18:31:30 +0200 Subject: [PATCH] Add docs and demo pages for Pricing and Shape --- core/scss/ui/_shape.scss | 2 + docs/content/ui/components/pricing.mdx | 127 +++++++++++++++++++ docs/content/ui/components/shape.mdx | 107 ++++++++++++++++ preview/pages/pricing.astro | 49 +++++++- preview/pages/shape.astro | 162 +++++++++++++++++++++++++ screenshots/pages/pricing.astro | 51 ++++++++ screenshots/pages/shape.astro | 36 ++++++ shared/data/docs.json | 8 ++ shared/data/menu.json | 5 + 9 files changed, 546 insertions(+), 1 deletion(-) create mode 100644 docs/content/ui/components/pricing.mdx create mode 100644 docs/content/ui/components/shape.mdx create mode 100644 preview/pages/shape.astro create mode 100644 screenshots/pages/pricing.astro create mode 100644 screenshots/pages/shape.astro diff --git a/core/scss/ui/_shape.scss b/core/scss/ui/_shape.scss index b09854eff..6d7e94141 100644 --- a/core/scss/ui/_shape.scss +++ b/core/scss/ui/_shape.scss @@ -3,9 +3,11 @@ @use '../config' as *; .shape { + // scss-docs-start shape-css-vars --shape-size: #{$avatar-size}; --shape-icon-size: #{$avatar-icon-size}; --shape-border-radius: 35%; + // scss-docs-end shape-css-vars display: inline-flex; align-items: center; justify-content: center; diff --git a/docs/content/ui/components/pricing.mdx b/docs/content/ui/components/pricing.mdx new file mode 100644 index 000000000..15abb7e90 --- /dev/null +++ b/docs/content/ui/components/pricing.mdx @@ -0,0 +1,127 @@ +--- +title: Pricing +summary: A row of plan cards with a price, a feature list and a button, where one card can be marked as featured. +description: Show your plans side by side with the pricing component. Each card has a title, a price, a feature list and a button. Mark one card as featured to raise it above the others. +related: [/ui/components/card, /ui/components/badge] +source: core/scss/ui/_pricing.scss +added-in: '1.7.0' +classnames: + component: + - class: pricing + desc: Container that lays the cards out in a column, and in a row from the md breakpoint up + part: + - class: pricing-card + desc: One plan, with a border, a shadow and centered text + - class: pricing-title + desc: Plan name, sized like an h2 + - class: pricing-label + desc: Label centered on the top edge of the card, for a badge such as "Popular" + - class: pricing-price + desc: Price row, large and bold + - class: pricing-price-currency + desc: Currency sign in front of the amount, smaller than the amount + - class: pricing-price-description + desc: Text next to the amount, such as the billing period + - class: pricing-features + desc: Plain list of features, aligned to the start + - class: pricing-btn + desc: Button wrapper, pushed to the bottom of the card + modifier: + - class: featured + desc: Raises the card, adds a primary border and puts it first on small screens; set on pricing-card +--- +import Example from '@components/Example.astro'; +import Icon from '@ui/Icon.astro'; + +## Default markup + +Put the plans in a `.pricing` container, one `.pricing-card` per plan. Each card holds a `.pricing-title`, a `.pricing-price`, a `.pricing-features` list and a `.pricing-btn`. On small screens the cards stack. From the `md` breakpoint up they sit in a row and share their borders, so the group reads as one table. + +Add `.featured` to the main plan. The card gets a primary border and a shadow, and on wide screens it is a bit taller than its neighbors, so it stands out. On small screens it moves to the top of the stack. A `.pricing-label` with a [badge](/ui/components/badge) sits on the top edge of the card. + + +
+
+

Free

+
+ $0 +
+
per user
+
per month
+
+
+
    +
  • Up to 3 users
  • +
  • Basic components
  • +
  • Community support
  • +
+ +
+ +
+

Enterprise

+
+ $99 +
+
per user
+
per month
+
+
+
    +
  • Unlimited users
  • +
  • All components
  • +
  • Dedicated support
  • +
+ +
+
+
+ +## Price + +The `.pricing-price` row holds the amount. Put the currency sign in a `.pricing-price-currency` in front of it, and the billing period in a `.pricing-price-description` after it. The description is smaller and uses the secondary text color, so the amount stays the strongest part of the card. + + +
+ $49 +
+
per user
+
per month
+
+
+
+ +## Features + +`.pricing-features` is a plain list with no bullets, aligned to the start of the card. Put an icon in front of each item to show what the plan includes. Use a margin utility such as `.my-4` to space the list from the price and the button. + + + + + +## Accessibility + +- Use a heading for `.pricing-title`, with the level that fits the page, so users of a screen reader can jump between plans. +- Say in the button text or in an `aria-label` which plan the button belongs to when several buttons share the same text. +- Do not rely on the border color alone to mark the featured plan. The `.pricing-label` badge names it in text. diff --git a/docs/content/ui/components/shape.mdx b/docs/content/ui/components/shape.mdx new file mode 100644 index 000000000..c7b254973 --- /dev/null +++ b/docs/content/ui/components/shape.mdx @@ -0,0 +1,107 @@ +--- +title: Shape +summary: A tinted, rounded square that holds one icon, for feature lists and other places where an icon needs a background. +description: Put an icon on a soft, tinted background with the shape component. Pick a size and a color, or set the corner radius with a CSS variable. +related: [/ui/components/avatar, /ui/components/icon] +source: core/scss/ui/_shape.scss +css-vars: shape +added-in: '1.7.0' +classnames: + component: + - class: shape + desc: Container element, an inline rounded square in the primary color + color: + - class: shape-{color} + desc: Any palette color, for example shape-red or shape-teal + size: + - class: shape-{size} + desc: Avatar sizes from shape-xxs to shape-2xl +--- +import Example from '@components/Example.astro'; +import Icon from '@ui/Icon.astro'; + +## Default markup + +A shape is a `.shape` element with one icon inside. It is a square with soft corners, filled with a light tint of the primary color. The icon takes the stronger primary color. The square is the same size as an [avatar](/ui/components/avatar), so the two line up in a list. + + + + + +## Sizes + +Add `.shape-{size}` to change the size. The sizes are the avatar sizes, from `xxs` to `2xl`. The icon grows with the square. + + +
+ + + + + + + +
+
+ +## Colors + +Add `.shape-{color}` to use another palette color. The square takes the light tint of the color and the icon takes the full color. + + +
+ + + + + + + + + + + + +
+
+ +## Corner radius + +The corners are rounded by `35%` of the size. Set `--tblr-shape-border-radius` on the shape to change this: `50%` makes a circle, `0` makes a sharp square. + + +
+ + + +
+
+ +## In a feature list + +Shapes mark the items of a feature list. Put one above or next to each heading, with the same size and color on every item. + + +
+
+ +

Mobile-optimized

+

Every page works on any screen size.

+
+
+ +

Tested email clients

+

Checked in more than 90 email clients.

+
+
+ +

Minimal design

+

Clean layouts based on Bootstrap.

+
+
+
+ +## Accessibility + +- A shape is decoration. The icon inside renders with `aria-hidden="true"`, so the shape adds nothing to the accessibility tree. +- Put the meaning in the text next to the shape, not in the icon or the color. diff --git a/preview/pages/pricing.astro b/preview/pages/pricing.astro index 29b94e7e8..44f67574a 100644 --- a/preview/pages/pricing.astro +++ b/preview/pages/pricing.astro @@ -1,10 +1,20 @@ --- import DefaultLayout from '@shared/layouts/DefaultLayout.astro' +import DocsLink from '@ui/DocsLink.astro' +import Icon from '@ui/Icon.astro' import PricingCard from '@shared/components/cards/PricingCard.astro' import PricingCardEnterprise from '@shared/components/cards/PricingCardEnterprise.astro' + +const plans = [ + { title: 'Free', price: '0', features: ['Up to 3 users', 'Basic components', 'Community support'], button: 'Get started', buttonClass: 'btn' }, + { title: 'Premium', price: '49', featured: true, label: 'Popular', features: ['Up to 10 users', 'All components', 'Figma UI kit', 'Priority support'], button: 'Get started', buttonClass: 'btn btn-primary' }, + { title: 'Enterprise', price: '99', features: ['Unlimited users', 'All components', 'Dedicated support'], button: 'Contact us', buttonClass: 'btn' }, +] --- - + + +
@@ -21,5 +31,42 @@ import PricingCardEnterprise from '@shared/components/cards/PricingCardEnterpris
+
+
+ { + plans.map((plan) => ( +
+ {plan.label && ( +
+ {plan.label} +
+ )} +

{plan.title}

+
+ $ + {plan.price} +
+
per user
+
per month
+
+
+
    + {plan.features.map((feature) => ( +
  • + + {feature} +
  • + ))} +
+ +
+ )) + } +
+
diff --git a/preview/pages/shape.astro b/preview/pages/shape.astro new file mode 100644 index 000000000..cda315af2 --- /dev/null +++ b/preview/pages/shape.astro @@ -0,0 +1,162 @@ +--- +import DefaultLayout from '@shared/layouts/DefaultLayout.astro' +import Card from '@ui/Card.astro' +import CardBody from '@ui/CardBody.astro' +import CardTitle from '@ui/CardTitle.astro' +import CardSubtitle from '@ui/CardSubtitle.astro' +import DocsLink from '@ui/DocsLink.astro' +import Icon from '@ui/Icon.astro' +import { avatarSizes, extraColors } from '@shared/lib/tokens' + +const icons = ['devices', 'mailbox', 'palette', 'tools', 'brand-bootstrap', 'paint', 'rocket', 'shield-check'] + +const radii = [ + { label: 'Square', value: '0' }, + { label: 'Default', value: undefined }, + { label: 'Circle', value: '50%' }, +] + +const features = [ + { icon: 'devices', title: 'Mobile-optimized', text: 'Every page works on any screen size, from a phone to a wide monitor.' }, + { icon: 'mailbox', title: 'Tested email clients', text: 'Checked in more than 90 email clients and devices.' }, + { icon: 'palette', title: 'Minimal design', text: 'Clean layouts based on Bootstrap and Material Design principles.' }, +] + +const featureList = [ + { icon: 'tools', color: 'blue', title: 'Easy to customize', text: 'Change colors, fonts and spacing with Sass or CSS variables.' }, + { icon: 'brand-bootstrap', color: 'purple', title: 'Built on Bootstrap', text: 'Every Bootstrap component works out of the box.' }, + { icon: 'paint', color: 'green', title: 'Dark mode', text: 'One attribute switches the whole interface to a dark theme.' }, +] +--- + + + + +
+
+ + + Sizes + Add .shape-{size}, from xxs to 2xl, the same sizes as an avatar. +
+ { + avatarSizes.map((size) => ( + + + + )) + } +
+
+
+
+ +
+ + + Colors + Add .shape-{color} to use another palette color. +
+ + { + extraColors.map((color) => ( + + + + )) + } +
+
+
+
+ +
+ + + With icons + Put one .icon inside the shape; it is sized with the square. +
+ { + icons.map((icon) => ( + + + + )) + } +
+
+
+
+ +
+ + + Corner radius + Set --tblr-shape-border-radius to change the corners; the default is 35%. +
+ { + radii.map((item) => ( +
+ + + +
{item.label}
+
+ )) + } +
+
+
+
+ +
+ + + Feature list + A shape above each heading, with the same size and color on every item. +
+ { + features.map((feature) => ( +
+ + + +

{feature.title}

+

{feature.text}

+
+ )) + } +
+
+
+
+ +
+ + + Feature list, inline + A colored shape next to each heading, in a .row with an auto column. +
+ { + featureList.map((feature) => ( +
+
+
+ + + +
+
+

{feature.title}

+

{feature.text}

+
+
+
+ )) + } +
+
+
+
+
+
diff --git a/screenshots/pages/pricing.astro b/screenshots/pages/pricing.astro new file mode 100644 index 000000000..f927b2c8c --- /dev/null +++ b/screenshots/pages/pricing.astro @@ -0,0 +1,51 @@ +--- +// Pricing component: three plan cards joined into one table, the middle one +// featured with a primary border and a "Popular" badge on its top edge. Same +// plans as the docs page, so the picture matches the example. +import ScreenshotLayout from '../layouts/ScreenshotLayout.astro' +import Icon from '@ui/Icon.astro' + +const plans = [ + { title: 'Free', price: '0', features: ['Up to 3 users', 'Basic components', 'Community support'], button: 'Get started', buttonClass: 'btn' }, + { title: 'Premium', price: '49', featured: true, label: 'Popular', features: ['Up to 10 users', 'All components', 'Figma UI kit', 'Priority support'], button: 'Get started', buttonClass: 'btn btn-primary' }, + { title: 'Enterprise', price: '99', features: ['Unlimited users', 'All components', 'Dedicated support'], button: 'Contact us', buttonClass: 'btn' }, +] +--- + + +
+ { + plans.map((plan) => ( +
+ {plan.label && ( +
+ {plan.label} +
+ )} +

{plan.title}

+
+ $ + {plan.price} +
+
per user
+
per month
+
+
+
    + {plan.features.map((feature) => ( +
  • + + {feature} +
  • + ))} +
+ +
+ )) + } +
+
diff --git a/screenshots/pages/shape.astro b/screenshots/pages/shape.astro new file mode 100644 index 000000000..621508cd4 --- /dev/null +++ b/screenshots/pages/shape.astro @@ -0,0 +1,36 @@ +--- +// Shape component: a three-item feature list, each item with a colored shape +// above its heading, the way the marketing pages use it. Three colors so the +// tint and the icon color read as a pair; medium size so the icons are legible +// at picture size. +import ScreenshotLayout from '../layouts/ScreenshotLayout.astro' +import Card from '@ui/Card.astro' +import CardBody from '@ui/CardBody.astro' +import Icon from '@ui/Icon.astro' + +const features = [ + { icon: 'devices', color: 'blue', title: 'Mobile-optimized', text: 'Every page works on any screen size, from a phone to a wide monitor.' }, + { icon: 'mailbox', color: 'purple', title: 'Tested email clients', text: 'Checked in more than 90 email clients and devices.' }, + { icon: 'palette', color: 'green', title: 'Minimal design', text: 'Clean layouts based on Bootstrap and Material Design principles.' }, +] +--- + + + + +
+ { + features.map((feature) => ( +
+ + + +

{feature.title}

+

{feature.text}

+
+ )) + } +
+
+
+
diff --git a/shared/data/docs.json b/shared/data/docs.json index c42bfaf71..4de1011c5 100644 --- a/shared/data/docs.json +++ b/shared/data/docs.json @@ -274,6 +274,10 @@ "title": "Popover", "url": "/ui/components/popover" }, + { + "title": "Pricing", + "url": "/ui/components/pricing" + }, { "title": "Progress bar", "url": "/ui/components/progress" @@ -290,6 +294,10 @@ "title": "Segmented control", "url": "/ui/components/segmented-control" }, + { + "title": "Shape", + "url": "/ui/components/shape" + }, { "title": "Signal", "url": "/ui/components/signal" diff --git a/shared/data/menu.json b/shared/data/menu.json index 82ada0513..c81693429 100644 --- a/shared/data/menu.json +++ b/shared/data/menu.json @@ -236,6 +236,11 @@ "title": "Scroll spy", "url": "scroll-spy.html" }, + "shape": { + "title": "Shape", + "url": "shape.html", + "badge": "New" + }, "signal": { "title": "Signal", "url": "signal.html"