Use CardSubtitle and a new PageTitle component in demo pages (#2866)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-08-12 23:56:30 +02:00
1 parent 5363668dc2
commit cc298a6c46
31 files changed
+189 -122

No files matched your search

@@ -0,0 +1,5 @@
---
"@tabler/preview": minor
---
Added a `PageTitle` component and used it with `CardSubtitle` in place of raw `.page-title` and `.card-subtitle` markup.
+9 -7
View File
@@ -4,15 +4,17 @@ import Accordion from '@ui/Accordion.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 Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
---
<DefaultLayout title="Accordion" pageMenu="base.accordion" description="Accordions show and hide sections of content, one panel at a time, inside a card.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Accordion</h1>
<PageTitle>Accordion</PageTitle>
<a href={accordionDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -23,7 +25,7 @@ const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
<Card>
<CardBody>
<CardTitle>Default</CardTitle>
<div class="card-subtitle">The base accordion — one panel open at a time.</div>
<CardSubtitle>The base accordion — one panel open at a time.</CardSubtitle>
<Accordion />
</CardBody>
</Card>
@@ -32,7 +34,7 @@ const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
<Card>
<CardBody>
<CardTitle>Flush</CardTitle>
<div class="card-subtitle">Add <code>flush</code> to remove the card border and rounded corners.</div>
<CardSubtitle>Add <code>flush</code> to remove the card border and rounded corners.</CardSubtitle>
</CardBody>
<Accordion type={['flush']} id="flush" />
</Card>
@@ -41,7 +43,7 @@ const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
<Card>
<CardBody>
<CardTitle>Tabs</CardTitle>
<div class="card-subtitle">Add <code>tabs</code> for a tab-like header instead of the default style.</div>
<CardSubtitle>Add <code>tabs</code> for a tab-like header instead of the default style.</CardSubtitle>
<Accordion type={['tabs']} id="tabs" />
</CardBody>
</Card>
@@ -50,7 +52,7 @@ const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
<Card>
<CardBody>
<CardTitle>Inverted</CardTitle>
<div class="card-subtitle">Add <code>inverted</code> to flip the toggle icon to the start of the header.</div>
<CardSubtitle>Add <code>inverted</code> to flip the toggle icon to the start of the header.</CardSubtitle>
<Accordion type={['inverted']} id="inverted" />
</CardBody>
</Card>
@@ -59,7 +61,7 @@ const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
<Card>
<CardBody>
<CardTitle>Inverted with plus icon</CardTitle>
<div class="card-subtitle">Combine <code>inverted</code> with a custom <code>toggleIcon</code>.</div>
<CardSubtitle>Combine <code>inverted</code> with a custom <code>toggleIcon</code>.</CardSubtitle>
<Accordion id="inverted-plus" type={['inverted', 'plus']} toggleIcon="plus" />
</CardBody>
</Card>
@@ -68,7 +70,7 @@ const accordionDocsUrl = getDocsUrl('/ui/components/accordion')
<Card>
<CardBody>
<CardTitle>With icons</CardTitle>
<div class="card-subtitle">Add <code>showIcon</code> to show an icon next to each panel's title.</div>
<CardSubtitle>Add <code>showIcon</code> to show an icon next to each panel's title.</CardSubtitle>
<Accordion id="icons" showIcon />
</CardBody>
</Card>
+9 -7
View File
@@ -4,15 +4,17 @@ import Alert from '@ui/Alert.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 Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const alertDocsUrl = getDocsUrl('/ui/components/alert')
---
<DefaultLayout title="Alerts" pageMenu="base.alerts" description="Alert messages inform users about the status of an action, in success, info, warning, or danger states.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Alerts</h1>
<PageTitle>Alerts</PageTitle>
<a href={alertDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -23,7 +25,7 @@ const alertDocsUrl = getDocsUrl('/ui/components/alert')
<Card>
<CardBody>
<CardTitle as="h2">Basic</CardTitle>
<div class="card-subtitle">A title and a color are enough to show the status of an action.</div>
<CardSubtitle>A title and a color are enough to show the status of an action.</CardSubtitle>
<Alert type="danger" title="An error occurred!" />
<Alert type="warning" title="Some information is missing!" />
<Alert type="success" title="Completed successfully!" />
@@ -35,7 +37,7 @@ const alertDocsUrl = getDocsUrl('/ui/components/alert')
<Card>
<CardBody>
<CardTitle as="h2">With action</CardTitle>
<div class="card-subtitle">Add a link with the <code>action</code> prop to give users something to do next.</div>
<CardSubtitle>Add a link with the <code>action</code> prop to give users something to do next.</CardSubtitle>
<Alert showClose action="Link" type="danger" title="An error occurred!" />
<Alert showClose action="Link" type="warning" title="Some information is missing!" />
<Alert showClose action="Link" type="success" title="Completed successfully!" />
@@ -47,7 +49,7 @@ const alertDocsUrl = getDocsUrl('/ui/components/alert')
<Card>
<CardBody>
<CardTitle as="h2">Dismissible</CardTitle>
<div class="card-subtitle">Add <code>showClose</code> to let users close the alert.</div>
<CardSubtitle>Add <code>showClose</code> to let users close the alert.</CardSubtitle>
<Alert showClose type="danger" title="An error occurred!" />
<Alert showClose type="warning" title="Some information is missing!" />
<Alert showClose type="success" title="Completed successfully!" />
@@ -59,7 +61,7 @@ const alertDocsUrl = getDocsUrl('/ui/components/alert')
<Card>
<CardBody>
<CardTitle as="h2">With a description</CardTitle>
<div class="card-subtitle">Add a <code>description</code> or a <code>list</code> when the title alone isn't enough context.</div>
<CardSubtitle>Add a <code>description</code> or a <code>list</code> when the title alone isn't enough context.</CardSubtitle>
<Alert showClose type="danger" title="Password does not meet requirements:" list={['Minimum 8 characters', 'Include a special character']} />
<Alert showClose type="warning" title="Some information is missing!" description="This is a custom alert box with a description." />
<Alert showClose type="success" title="Completed successfully!" description="This is a custom alert box with a description." />
@@ -71,7 +73,7 @@ const alertDocsUrl = getDocsUrl('/ui/components/alert')
<Card>
<CardBody>
<CardTitle as="h2">Important</CardTitle>
<div class="card-subtitle">Add <code>important</code> for a bolder style that stands out from the rest of the page.</div>
<CardSubtitle>Add <code>important</code> for a bolder style that stands out from the rest of the page.</CardSubtitle>
<Alert showClose important type="danger" title="Password does not meet requirements:" list={['Minimum 8 characters', 'Include a special character']} />
<Alert showClose important type="success" description="This is a custom alert box with a description." />
<Alert showClose important type="warning" description="This is a custom alert box with a description." />
@@ -83,7 +85,7 @@ const alertDocsUrl = getDocsUrl('/ui/components/alert')
<Card>
<CardBody>
<CardTitle as="h2">Minor</CardTitle>
<div class="card-subtitle">Add <code>minor</code> for a quieter style that fits inline with other content.</div>
<CardSubtitle>Add <code>minor</code> for a quieter style that fits inline with other content.</CardSubtitle>
<Alert showClose minor type="danger" title="Password does not meet requirements:" list={['Minimum 8 characters', 'Include a special character']} />
<Alert showClose minor type="success" description="This is a custom alert box with a description." />
<Alert showClose minor type="warning" description="This is a custom alert box with a description." />
+14 -12
View File
@@ -6,10 +6,12 @@ import AvatarList from '@ui/AvatarList.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 Icon from '@ui/Icon.astro'
import people from '@data/people.json'
import { site } from '@shared/lib/site'
import { firstLetters, getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const iconIcons = ['user', 'settings', 'car', 'balloon', 'users', 'users-group', 'apps', 'ghost']
@@ -29,7 +31,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<DefaultLayout title="Avatars" pageMenu="base.avatars" description="Avatars display a photo, icon, or initials to represent a person, brand, or status.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Avatars</h1>
<PageTitle>Avatars</PageTitle>
<a href={avatarDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -40,7 +42,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Default avatar</CardTitle>
<div class="card-subtitle">The base <code>.avatar</code> element — a placeholder box for a photo, icon, or initials.</div>
<CardSubtitle>The base <code>.avatar</code> element — a placeholder box for a photo, icon, or initials.</CardSubtitle>
<Avatar />
</CardBody>
</Card>
@@ -49,7 +51,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar with icon</CardTitle>
<div class="card-subtitle">Use an icon instead of a photo with the <code>icon</code> prop.</div>
<CardSubtitle>Use an icon instead of a photo with the <code>icon</code> prop.</CardSubtitle>
<div class="avatar-list">
{iconIcons.map((icon) => <Avatar icon={icon} />)}
</div>
@@ -60,7 +62,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar icon colors</CardTitle>
<div class="card-subtitle">Combine an icon avatar with any theme color.</div>
<CardSubtitle>Combine an icon avatar with any theme color.</CardSubtitle>
<div class="avatar-list">
{colors.map((color) => <Avatar icon="user" color={color} />)}
</div>
@@ -71,7 +73,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Simple avatar</CardTitle>
<div class="card-subtitle">Pass a <code>person</code> object to render their photo.</div>
<CardSubtitle>Pass a <code>person</code> object to render their photo.</CardSubtitle>
<div class="avatar-list">
{people8.map((person) => <Avatar person={person} />)}
</div>
@@ -82,7 +84,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar placeholder</CardTitle>
<div class="card-subtitle">Fall back to initials with the <code>placeholder</code> prop when there's no photo.</div>
<CardSubtitle>Fall back to initials with the <code>placeholder</code> prop when there's no photo.</CardSubtitle>
<div class="avatar-list">
{people8.map((person) => <Avatar placeholder={firstLetters(person.full_name)} />)}
</div>
@@ -93,7 +95,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar shapes</CardTitle>
<div class="card-subtitle">Square by default — add <code>.rounded-circle</code> or <code>.rounded-0</code> to change the shape.</div>
<CardSubtitle>Square by default — add <code>.rounded-circle</code> or <code>.rounded-0</code> to change the shape.</CardSubtitle>
<div class="avatar-list">
<Avatar />
<Avatar class="rounded-circle" />
@@ -106,7 +108,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar sizes</CardTitle>
<div class="card-subtitle">Six sizes from <code>xxs</code> to <code>xl</code>, for both photos and placeholders.</div>
<CardSubtitle>Six sizes from <code>xxs</code> to <code>xl</code>, for both photos and placeholders.</CardSubtitle>
<div class="row">
<div class="col-6">
<div class="avatar-list">
@@ -126,7 +128,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar lists</CardTitle>
<div class="card-subtitle">Stack avatars with <code>&lt;AvatarList&gt;</code> to show a group at a glance.</div>
<CardSubtitle>Stack avatars with <code>&lt;AvatarList&gt;</code> to show a group at a glance.</CardSubtitle>
<div class="row g-3">
{
listSizes.map((size) => (
@@ -158,7 +160,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar upload</CardTitle>
<div class="card-subtitle">An upload control styled as an avatar, for profile photo pickers.</div>
<CardSubtitle>An upload control styled as an avatar, for profile photo pickers.</CardSubtitle>
{uploadSizes.map((size) => <AvatarUpload size={size} />)}
</CardBody>
</Card>
@@ -167,7 +169,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar statuses</CardTitle>
<div class="card-subtitle">Add a <code>status</code> dot to show online, away, or busy state.</div>
<CardSubtitle>Add a <code>status</code> dot to show online, away, or busy state.</CardSubtitle>
{statusColors.map((color, i) => <Avatar personId={i + 1} class="rounded-circle" status={color} />)}
</CardBody>
</Card>
@@ -176,7 +178,7 @@ const avatarDocsUrl = getDocsUrl('/ui/components/avatar')
<Card>
<CardBody>
<CardTitle as="h2">Avatar brands</CardTitle>
<div class="card-subtitle">Show a recognizable brand icon instead of a person.</div>
<CardSubtitle>Show a recognizable brand icon instead of a person.</CardSubtitle>
{brands.map((brand, i) => <Avatar personId={i + 1} brand={brand} />)}
</CardBody>
</Card>
+14 -12
View File
@@ -8,9 +8,11 @@ import ButtonList from '@ui/ButtonList.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 DropdownMenu from '@ui/DropdownMenu.astro'
import site from '@data/site.json'
import { ucFirst, getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const colors = ['default', ...Object.keys(site.colors), 'dark', 'light']
const sizes = ['sm', 'md', 'lg']
@@ -20,7 +22,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<DefaultLayout title="Badges" pageMenu="base.badges" description="Badges highlight a count, status, or short label attached to text, buttons, or menu items.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Badges</h1>
<PageTitle>Badges</PageTitle>
<a href={badgeDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -31,7 +33,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>In headings</CardTitle>
<div class="card-subtitle">A badge scales with the heading level it sits next to.</div>
<CardSubtitle>A badge scales with the heading level it sits next to.</CardSubtitle>
<h1>Example heading <span class="badge">New</span></h1>
<h2>Example heading <span class="badge">New</span></h2>
<h3>Example heading <span class="badge">New</span></h3>
@@ -45,7 +47,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Sizes</CardTitle>
<div class="card-subtitle">Three sizes, with an optional icon before or after the label.</div>
<CardSubtitle>Three sizes, with an optional icon before or after the label.</CardSubtitle>
<div class="space-y">
{
sizes.map((size) => (
@@ -72,7 +74,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Positioned</CardTitle>
<div class="card-subtitle">Attach a count or a dot to a button with <code>.badge-notification</code>.</div>
<CardSubtitle>Attach a count or a dot to a button with <code>.badge-notification</code>.</CardSubtitle>
<ButtonList>
<button type="button" class="btn">Notifications <span class="badge text-bg-secondary ms-2">4</span></button>
@@ -111,7 +113,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>In a dropdown</CardTitle>
<div class="card-subtitle">A badge inside a dropdown item.</div>
<CardSubtitle>A badge inside a dropdown item.</CardSubtitle>
<DropdownMenu show badge arrow />
</CardBody>
</Card>
@@ -120,7 +122,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>On buttons</CardTitle>
<div class="card-subtitle">Pair any badge color with a button label.</div>
<CardSubtitle>Pair any badge color with a button label.</CardSubtitle>
<ButtonList>
{
colors.map((color, index) => (
@@ -137,7 +139,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Notification dot</CardTitle>
<div class="card-subtitle">A pill-shaped counter positioned on the corner of a button.</div>
<CardSubtitle>A pill-shaped counter positioned on the corner of a button.</CardSubtitle>
<ButtonList>
{
colors.map((color, index) => (
@@ -154,7 +156,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Blinking notification</CardTitle>
<div class="card-subtitle">Add <code>.badge-blink</code> to draw attention to unread activity.</div>
<CardSubtitle>Add <code>.badge-blink</code> to draw attention to unread activity.</CardSubtitle>
<ButtonList>
{
colors.map((color) => (
@@ -174,7 +176,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Basic</CardTitle>
<div class="card-subtitle">Fill a badge with a theme or extended color.</div>
<CardSubtitle>Fill a badge with a theme or extended color.</CardSubtitle>
<BadgeList>
{colors.map((color) => <span class={`badge bg-${color} text-${color}-fg`}>{ucFirst(color)}</span>)}
</BadgeList>
@@ -185,7 +187,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Light</CardTitle>
<div class="card-subtitle">A tinted background for a softer, secondary badge.</div>
<CardSubtitle>A tinted background for a softer, secondary badge.</CardSubtitle>
<BadgeList>
{colors.map((color) => <span class={`badge bg-${color}-lt`}>{ucFirst(color)}</span>)}
</BadgeList>
@@ -196,7 +198,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>Outline</CardTitle>
<div class="card-subtitle">A colored border with a transparent background.</div>
<CardSubtitle>A colored border with a transparent background.</CardSubtitle>
<BadgeList>
{colors.map((color) => <span class={`badge badge-outline text-${color}`}>{ucFirst(color)}</span>)}
</BadgeList>
@@ -207,7 +209,7 @@ const badgeDocsUrl = getDocsUrl('/ui/components/badge')
<Card>
<CardBody>
<CardTitle>With icons</CardTitle>
<div class="card-subtitle">Add an icon before the label to reinforce its meaning.</div>
<CardSubtitle>Add an icon before the label to reinforce its meaning.</CardSubtitle>
<BadgeList>
{
colors.map((color) => (
+16 -14
View File
@@ -6,8 +6,10 @@ import ButtonList from '@ui/ButtonList.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 site from '@data/site.json'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
type ColorEntry = [string, { title: string; icon?: string }]
@@ -25,7 +27,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<DefaultLayout title="Buttons" pageMenu="base.buttons" description="Buttons are used to trigger actions in a user interface.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Buttons</h1>
<PageTitle>Buttons</PageTitle>
<a href={buttonDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -36,7 +38,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Basic</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Add an icon to the left, the right, or drop the label for an icon-only button.</div>
<CardSubtitle>Add an icon to the left, the right, or drop the label for an icon-only button.</CardSubtitle>
<ButtonList>
<Button text="Button" />
<Button icon="star" text="With icon" />
@@ -51,7 +53,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Shapes</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Round the corners with <code>.btn-pill</code>, or square them off with <code>.btn-square</code>.</div>
<CardSubtitle>Round the corners with <code>.btn-pill</code>, or square them off with <code>.btn-square</code>.</CardSubtitle>
<ButtonList>
<a class="btn">Default</a>
<a class="btn btn-pill">Pill</a>
@@ -73,7 +75,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Action buttons</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Compact, icon-only buttons for card headers and toolbars.</div>
<CardSubtitle>Compact, icon-only buttons for card headers and toolbars.</CardSubtitle>
<div class="btn-actions">
{
actions.map((action) => (
@@ -90,7 +92,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Sizes</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Scale a button from <code>sm</code> to <code>xl</code> without changing its icon layout.</div>
<CardSubtitle>Scale a button from <code>sm</code> to <code>xl</code> without changing its icon layout.</CardSubtitle>
<div class="space-y">
{
sizes.map((size) => (
@@ -110,7 +112,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Animated icon</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Small hover animations draw attention to the icon.</div>
<CardSubtitle>Small hover animations draw attention to the icon.</CardSubtitle>
<ButtonList>
<a class="btn btn-animate-icon">
Save <Icon name="arrow-right" class="icon-end" />
@@ -147,7 +149,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Standard</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Fill a button with a theme color to mark its purpose.</div>
<CardSubtitle>Fill a button with a theme color to mark its purpose.</CardSubtitle>
<ButtonList>
{
themeColors.map(([name, color]) => (
@@ -164,7 +166,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Outline</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Keep the border colored and the background transparent for a subtler action.</div>
<CardSubtitle>Keep the border colored and the background transparent for a subtler action.</CardSubtitle>
<ButtonList>
{
themeColors.map(([name, color]) => (
@@ -181,7 +183,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Ghost</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Drop the border too — color appears only on hover.</div>
<CardSubtitle>Drop the border too — color appears only on hover.</CardSubtitle>
<ButtonList>
{
themeColors.map(([name, color]) => (
@@ -198,7 +200,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Pill</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Combine <code>.btn-pill</code> with a theme color.</div>
<CardSubtitle>Combine <code>.btn-pill</code> with a theme color.</CardSubtitle>
<ButtonList>
{
themeColors.map(([name, color]) => (
@@ -215,7 +217,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Square</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Combine <code>.btn-square</code> with a theme color.</div>
<CardSubtitle>Combine <code>.btn-square</code> with a theme color.</CardSubtitle>
<ButtonList>
{
themeColors.map(([name, color]) => (
@@ -232,7 +234,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Extra colors</CardTitle>
<div class="text-secondary mb-3 card-subtitle">The full Tabler palette, beyond the eight theme colors.</div>
<CardSubtitle>The full Tabler palette, beyond the eight theme colors.</CardSubtitle>
<ButtonList>
{
colors.map(([name, color]) => (
@@ -249,7 +251,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Social colors</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Brand colors for linking out to social networks.</div>
<CardSubtitle>Brand colors for linking out to social networks.</CardSubtitle>
<ButtonList>
{
socialColors.map(([name, app]) => (
@@ -266,7 +268,7 @@ const buttonDocsUrl = getDocsUrl('/ui/components/button')
<Card>
<CardBody>
<CardTitle>Icon buttons</CardTitle>
<div class="text-secondary mb-3 card-subtitle">Social brand colors without a label, for compact toolbars.</div>
<CardSubtitle>Social brand colors without a label, for compact toolbars.</CardSubtitle>
<ButtonList>{socialColors.map(([name, app]) => <a class={`btn btn-icon btn-${name}`}>{app.icon && <Icon name={app.icon} />}</a>)}</ButtonList>
</CardBody>
</Card>
+2 -1
View File
@@ -3,13 +3,14 @@ import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import CarouselCard from '@shared/components/cards/CarouselCard.astro'
import Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const carouselDocsUrl = getDocsUrl('/ui/components/carousel')
---
<DefaultLayout title="Carousel" pageMenu="base.carousel" description="A carousel cycles through a set of slides, with optional indicators and controls.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Carousel</h1>
<PageTitle>Carousel</PageTitle>
<a href={carouselDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+9 -7
View File
@@ -6,9 +6,11 @@ import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import Avatar from '@ui/Avatar.astro'
import CardTitle from '@ui/CardTitle.astro'
import CardSubtitle from '@ui/CardSubtitle.astro'
import Icon from '@ui/Icon.astro'
import site from '@data/site.json'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
type ColorEntry = [string, { title: string; hex: string; abbr?: string; icon?: string }]
@@ -24,7 +26,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<DefaultLayout title="Colors" pageMenu="base.colors" description="The full color palette, with hex values, and a gradient builder.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Colors</h1>
<PageTitle>Colors</PageTitle>
<a href={colorsDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -35,7 +37,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<Card>
<CardBody>
<CardTitle>Colors</CardTitle>
<div class="card-subtitle">The extended color palette, with hex values.</div>
<CardSubtitle>The extended color palette, with hex values.</CardSubtitle>
<div class="row g-3">
{
colors.map(([name, color]) => (
@@ -61,7 +63,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<Card>
<CardBody>
<CardTitle>Light colors</CardTitle>
<div class="card-subtitle">A tinted, low-contrast version of each color.</div>
<CardSubtitle>A tinted, low-contrast version of each color.</CardSubtitle>
<div class="row g-3">
{
lightColors.map(([name, color]) => (
@@ -87,7 +89,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<Card>
<CardBody>
<CardTitle>Gray colors</CardTitle>
<div class="card-subtitle">The neutral gray scale used for text, borders, and backgrounds.</div>
<CardSubtitle>The neutral gray scale used for text, borders, and backgrounds.</CardSubtitle>
<div class="row g-3">
{
grayColors.map(([name, color]) => (
@@ -113,7 +115,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<Card>
<CardBody>
<CardTitle>Social colors</CardTitle>
<div class="card-subtitle">Brand colors for social networks.</div>
<CardSubtitle>Brand colors for social networks.</CardSubtitle>
<div class="row g-3">
{
socialColors.map(([name, color]) => (
@@ -141,7 +143,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<Card>
<CardBody>
<CardTitle>Gradient</CardTitle>
<div class="card-subtitle">Build a gradient from any two colors and preview it live.</div>
<CardSubtitle>Build a gradient from any two colors and preview it live.</CardSubtitle>
<form action="">
<div class="row g-4">
<div class="col">
@@ -198,7 +200,7 @@ const colorsDocsUrl = getDocsUrl('/ui/base/colors')
<Card>
<CardBody>
<CardTitle>Gradient colors</CardTitle>
<div class="card-subtitle">Every color faded to transparent, fading in from the left or the right.</div>
<CardSubtitle>Every color faded to transparent, fading in from the left or the right.</CardSubtitle>
<div class="row">
<div class="col">
<div class="space-y">
+2 -1
View File
@@ -6,13 +6,14 @@ import CardBody from '@ui/CardBody.astro'
import Icon from '@ui/Icon.astro'
import Datagrid from '@shared/components/parts/Datagrid.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const datagridDocsUrl = getDocsUrl('/ui/components/datagrid')
---
<DefaultLayout title="Data grid" pageMenu="base.datagrid" description="A data grid lays out label/value pairs in a compact, aligned grid.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Data grid</h1>
<PageTitle>Data grid</PageTitle>
<a href={datagridDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -4,13 +4,14 @@ import DropdownMenu from '@ui/DropdownMenu.astro'
import DropdownMenuAll from '@ui/DropdownMenuAll.astro'
import Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const dropdownDocsUrl = getDocsUrl('/ui/components/dropdown')
---
<DefaultLayout title="Dropdowns" pageMenu="base.dropdowns" description="Dropdown menus for actions, filters, and selections, always shown open here for reference.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Dropdowns</h1>
<PageTitle>Dropdowns</PageTitle>
<a href={dropdownDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+3 -2
View File
@@ -10,6 +10,7 @@ import freeIllustrations from '@data/free-illustrations.json'
import illustrationsList from '@data/illustrations.json'
import siteData from '@data/site.json'
import { requireIndex } from '@shared/lib/array'
import PageTitle from '@ui/PageTitle.astro'
const autodark = (freeIllustrations as { autodark: Record<string, string> }).autodark
const autodarkEntries = Object.entries(autodark)
@@ -114,9 +115,9 @@ const illustrationsData = Object.fromEntries(autodarkEntries.map(([key, svg]) =>
</div>
</div>
<h2 class="page-title my-5">
<PageTitle as="h2" class="my-5">
{moreCount} more SVG Illustrations
</h2>
</PageTitle>
<div class="row row-cards">
<div class="col-lg-4">
+2 -1
View File
@@ -9,13 +9,14 @@ import UsersListHeaders from '@shared/components/cards/UsersListHeaders.astro'
import ListGroup from '@ui/ListGroup.astro'
import ListGroupItem from '@ui/ListGroupItem.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const listGroupDocsUrl = getDocsUrl('/ui/components/list-group')
---
<DefaultLayout title="Lists" pageMenu="base.lists" description="Lists of users, contacts, and links — built from list-group items or a plain card body.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Lists</h1>
<PageTitle>Lists</PageTitle>
<a href={listGroupDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -24,6 +24,7 @@ import ConfirmDeleteModalContent from '@shared/components/modals/ConfirmDeleteMo
import ChangePasswordModalContent from '@shared/components/modals/ChangePasswordModalContent.astro'
import AddTaskModalContent from '@shared/components/modals/AddTaskModalContent.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const cardClass = 'position-relative rounded d-block bg-surface-backdrop py-6 w-auto h-auto z-0'
@@ -32,7 +33,7 @@ const modalDocsUrl = getDocsUrl('/ui/components/modal')
<DefaultLayout title="Modals" pageMenu="base.modals" pageLibs={['signature_pad', 'hugerte', 'litepicker', 'tom-select']} description="Modals interrupt the page to ask for input, confirmation, or a focused action.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Modals</h1>
<PageTitle>Modals</PageTitle>
<a href={modalDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -6,13 +6,14 @@ import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Navbar from '@shared/components/navbar/Navbar.astro'
import Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const navbarDocsUrl = getDocsUrl('/ui/layout/navbars')
---
<DefaultLayout title="Navigation" pageMenu="base.navigation" description="Navbar variants — condensed, dark, colored, and with different logo and search layouts.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Navigation</h1>
<PageTitle>Navigation</PageTitle>
<a href={navbarDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -8,6 +8,7 @@ import Icon from '@ui/Icon.astro'
import Offcanvas from '@ui/Offcanvas.astro'
import OffcanvasHeader from '@ui/OffcanvasHeader.astro'
import OffcanvasBody from '@ui/OffcanvasBody.astro'
import PageTitle from '@ui/PageTitle.astro'
const directions = ['start', 'end', 'top', 'bottom'] as const
@@ -16,7 +17,7 @@ const offcanvasDocsUrl = getDocsUrl('/ui/components/offcanvas')
<DefaultLayout title="Offcanvas" pageMenu="base.offcanvas" description="An offcanvas panel slides in from an edge of the screen for navigation or supplementary content.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Offcanvas</h1>
<PageTitle>Offcanvas</PageTitle>
<a href={offcanvasDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -6,6 +6,7 @@ import ProgressSteps from '@ui/ProgressSteps.astro'
import Button from '@ui/Button.astro'
import ButtonList from '@ui/ButtonList.astro'
import FormGroup from '@ui/FormGroup.astro'
import PageTitle from '@ui/PageTitle.astro'
---
<BaseLayout title="Onboarding">
@@ -28,7 +29,7 @@ import FormGroup from '@ui/FormGroup.astro'
<main class="py-5" id="content">
<div class="container container-tight">
<div class="page-header">
<h1 class="page-title">Let's set up your account</h1>
<PageTitle>Let's set up your account</PageTitle>
</div>
<div class="card mt-5">
<div class="card-body space-y-4">
+5 -3
View File
@@ -4,15 +4,17 @@ import Pagination from '@ui/Pagination.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 Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const paginationDocsUrl = getDocsUrl('/ui/components/pagination')
---
<DefaultLayout title="Pagination" pageMenu="base.pagination" description="Pagination splits a long list of results into pages, with Prev/Next controls.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Pagination</h1>
<PageTitle>Pagination</PageTitle>
<a href={paginationDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -23,7 +25,7 @@ const paginationDocsUrl = getDocsUrl('/ui/components/pagination')
<Card>
<CardBody>
<CardTitle>Numbered</CardTitle>
<div class="card-subtitle">Page numbers, with or without <code>text</code> Prev/Next labels.</div>
<CardSubtitle>Page numbers, with or without <code>text</code> Prev/Next labels.</CardSubtitle>
<Pagination />
<Pagination text />
</CardBody>
@@ -33,7 +35,7 @@ const paginationDocsUrl = getDocsUrl('/ui/components/pagination')
<Card>
<CardBody>
<CardTitle>With descriptions</CardTitle>
<div class="card-subtitle">Add <code>prevDescription</code>/<code>nextDescription</code> to name the adjacent page.</div>
<CardSubtitle>Add <code>prevDescription</code>/<code>nextDescription</code> to name the adjacent page.</CardSubtitle>
<Pagination count={0} prevDescription="Getting started" nextDescription="Breadcrumbs" />
</CardBody>
</Card>
+2 -1
View File
@@ -7,6 +7,7 @@ import Icon from '@ui/Icon.astro'
import BackgroundPattern from '@ui/BackgroundPattern.astro'
import site from '@data/site.json'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const patternColors = Object.keys(site.colors)
const patternSizes = ['sm', 'md', 'lg', 'xl'] as const
@@ -18,7 +19,7 @@ const patternsDocsUrl = getDocsUrl('/ui/utilities/background-patterns')
<DefaultLayout title="Patterns" pageMenu="base.patterns" description="Background patterns you can apply to any element with a utility class.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Patterns</h1>
<PageTitle>Patterns</PageTitle>
<a href={patternsDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -8,6 +8,7 @@ import PlaceholderCard4 from '@shared/components/cards/placeholder/Card4.astro'
import PlaceholderCard5 from '@shared/components/cards/placeholder/Card5.astro'
import PlaceholderCard6 from '@shared/components/cards/placeholder/Card6.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const cols = [1, 2, 3, 4]
@@ -16,7 +17,7 @@ const placeholderDocsUrl = getDocsUrl('/ui/components/placeholder')
<DefaultLayout title="Placeholder" pageMenu="base.placeholder" description="Placeholders mimic the shape of content that hasn't loaded yet.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Placeholder</h1>
<PageTitle>Placeholder</PageTitle>
<a href={placeholderDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+2 -1
View File
@@ -4,13 +4,14 @@ import Prose from '@ui/Prose.astro'
import Icon from '@ui/Icon.astro'
import Avatar from '@ui/Avatar.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const proseDocsUrl = getDocsUrl('/ui/base/prose')
---
<DefaultLayout title="Prose" pageMenu="base.prose" description="Wrap long-form content in .prose to style headings, paragraphs, lists, and tables without adding classes to every element.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Prose</h1>
<PageTitle>Prose</PageTitle>
<a href={proseDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+15 -13
View File
@@ -4,15 +4,17 @@ import NavSegmented from '@ui/NavSegmented.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 Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
---
<DefaultLayout title="Segmented control" pageMenu="base.segmented-control" description="A segmented control lets users pick one option from a small, always-visible set.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Segmented control</h1>
<PageTitle>Segmented control</PageTitle>
<a href={segmentedControlDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -23,7 +25,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Basic</CardTitle>
<div class="card-subtitle">A list of <code>items</code> is enough for a plain control.</div>
<CardSubtitle>A list of <code>items</code> is enough for a plain control.</CardSubtitle>
<NavSegmented items={['1', '2', '3', '4']} />
</CardBody>
</Card>
@@ -32,7 +34,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Any content</CardTitle>
<div class="card-subtitle">Items can be any short text, including emoji.</div>
<CardSubtitle>Items can be any short text, including emoji.</CardSubtitle>
<NavSegmented items={['👦', '👦🏿', '👦🏾', '👦🏽', '👦🏼', '👦🏻']} />
</CardBody>
</Card>
@@ -41,7 +43,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Icons only</CardTitle>
<div class="card-subtitle">Pass <code>icons</code> without <code>items</code> for an icon-only control.</div>
<CardSubtitle>Pass <code>icons</code> without <code>items</code> for an icon-only control.</CardSubtitle>
<NavSegmented icons={['home', 'star', 'clock', 'ghost', 'bold', 'italic', 'underline']} />
</CardBody>
</Card>
@@ -50,7 +52,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>With icons</CardTitle>
<div class="card-subtitle">Combine <code>items</code> and <code>icons</code> to label each option.</div>
<CardSubtitle>Combine <code>items</code> and <code>icons</code> to label each option.</CardSubtitle>
<NavSegmented items={['List', 'Kanban', 'Calendar', 'Files']} icons={['list', 'layout', 'calendar', 'files']} />
</CardBody>
</Card>
@@ -59,7 +61,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Vertical</CardTitle>
<div class="card-subtitle">Add <code>vertical</code> to stack the options in a column.</div>
<CardSubtitle>Add <code>vertical</code> to stack the options in a column.</CardSubtitle>
<NavSegmented items={['List', 'Kanban', 'Calendar', 'Files']} icons={['list', 'layout', 'calendar', 'files']} vertical />
</CardBody>
</Card>
@@ -68,7 +70,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Vertical with disabled items</CardTitle>
<div class="card-subtitle">Pass indexes to <code>disabled</code> to make specific options unselectable.</div>
<CardSubtitle>Pass indexes to <code>disabled</code> to make specific options unselectable.</CardSubtitle>
<NavSegmented icons={['home', 'star', 'clock', 'ghost', 'bold', 'italic', 'underline']} vertical disabled={[3]} />
</CardBody>
</Card>
@@ -77,7 +79,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Disabled items</CardTitle>
<div class="card-subtitle">Disabled options stay visible but can't be selected.</div>
<CardSubtitle>Disabled options stay visible but can't be selected.</CardSubtitle>
<NavSegmented items={['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']} disabled={[4, 5]} />
</CardBody>
</Card>
@@ -86,7 +88,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Vertical, no icons</CardTitle>
<div class="card-subtitle">A vertical control also works with text-only items.</div>
<CardSubtitle>A vertical control also works with text-only items.</CardSubtitle>
<NavSegmented items={['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']} vertical={true} />
</CardBody>
</Card>
@@ -95,7 +97,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Independent group</CardTitle>
<div class="card-subtitle">Set a unique <code>name</code> so this control doesn't share selection state with others using the same items.</div>
<CardSubtitle>Set a unique <code>name</code> so this control doesn't share selection state with others using the same items.</CardSubtitle>
<NavSegmented items={['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']} name="checkbox" />
</CardBody>
</Card>
@@ -104,7 +106,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Full width</CardTitle>
<div class="card-subtitle">Add <code>fullWidth</code> to stretch the control across its container.</div>
<CardSubtitle>Add <code>fullWidth</code> to stretch the control across its container.</CardSubtitle>
<NavSegmented items={['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']} fullWidth={true} />
</CardBody>
</Card>
@@ -113,7 +115,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Full width, stacked</CardTitle>
<div class="card-subtitle">Multiple full-width controls, one above the other.</div>
<CardSubtitle>Multiple full-width controls, one above the other.</CardSubtitle>
<div class="space-y">
<div><NavSegmented items={['Overview', 'Analytics', 'Reports', 'Notifications']} fullWidth={true} /></div>
<div><NavSegmented items={['Account', 'Password']} fullWidth={true} /></div>
@@ -125,7 +127,7 @@ const segmentedControlDocsUrl = getDocsUrl('/ui/components/segmented-control')
<Card>
<CardBody>
<CardTitle>Sizes</CardTitle>
<div class="card-subtitle">Set <code>size</code> to <code>sm</code> or <code>lg</code> — with text, icons, or both.</div>
<CardSubtitle>Set <code>size</code> to <code>sm</code> or <code>lg</code> — with text, icons, or both.</CardSubtitle>
<div class="space-y">
<div><NavSegmented items={['List', 'Kanban', 'Calendar', 'Files']} disabled={[3, 5]} size="sm" /></div>
<div><NavSegmented items={['List', 'Kanban', 'Calendar', 'Files']} disabled={[3, 5]} /></div>
+5 -3
View File
@@ -6,10 +6,12 @@ import Trending from '@ui/Trending.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 Icon from '@ui/Icon.astro'
import socialTiles from '@data/social-tiles.json'
import socials from '@data/socials.json'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
interface SocialTile {
icon: string
@@ -32,7 +34,7 @@ const socialDocsUrl = getDocsUrl('/ui/plugins/social-icons')
<DefaultLayout title="Social icons" pageMenu="base.social" description="Branded icons and helpers for linking out to, or signing in with, social networks.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Social icons</h1>
<PageTitle>Social icons</PageTitle>
<a href={socialDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -69,7 +71,7 @@ const socialDocsUrl = getDocsUrl('/ui/plugins/social-icons')
<Card>
<CardBody>
<CardTitle>Sign in with social media</CardTitle>
<div class="card-subtitle">A button per provider, for a social sign-in screen.</div>
<CardSubtitle>A button per provider, for a social sign-in screen.</CardSubtitle>
<ButtonList>
{
socialList.map((social) => (
@@ -88,7 +90,7 @@ const socialDocsUrl = getDocsUrl('/ui/plugins/social-icons')
<Card>
<CardBody>
<CardTitle>List of all social media icons</CardTitle>
<div class="card-subtitle">Every brand icon shipped with the social icons plugin.</div>
<CardSubtitle>Every brand icon shipped with the social icons plugin.</CardSubtitle>
</CardBody>
<CardBody class="p-0">
<div class="demo-icons-list-wrap">
+7 -5
View File
@@ -4,15 +4,17 @@ import Rating from '@ui/Rating.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 Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const starsRatingDocsUrl = getDocsUrl('/ui/components/star-rating')
---
<DefaultLayout title="Star Ratings" pageMenu="base.stars-rating" pageLibs={['tabler-flags', 'star-rating.js']} description="An interactive star rating built on the star-rating.js widget, backed by a hidden select for accessibility and forms.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Star Ratings</h1>
<PageTitle>Star Ratings</PageTitle>
<a href={starsRatingDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -23,7 +25,7 @@ const starsRatingDocsUrl = getDocsUrl('/ui/components/star-rating')
<Card>
<CardBody>
<CardTitle>Basic</CardTitle>
<div class="card-subtitle">Click a star to set the value.</div>
<CardSubtitle>Click a star to set the value.</CardSubtitle>
<Rating id="basic" value={4} />
</CardBody>
</Card>
@@ -32,7 +34,7 @@ const starsRatingDocsUrl = getDocsUrl('/ui/components/star-rating')
<Card>
<CardBody>
<CardTitle>Icons</CardTitle>
<div class="card-subtitle">Swap the star for any icon with the <code>icon</code> prop.</div>
<CardSubtitle>Swap the star for any icon with the <code>icon</code> prop.</CardSubtitle>
<div class="space-y">
<Rating id="icon-star" value={4} />
<Rating id="icon-heart" icon="heart" value={4} color="red" />
@@ -46,7 +48,7 @@ const starsRatingDocsUrl = getDocsUrl('/ui/components/star-rating')
<Card>
<CardBody>
<CardTitle>Sizes</CardTitle>
<div class="card-subtitle">Match the rating to surrounding text with <code>size</code>.</div>
<CardSubtitle>Match the rating to surrounding text with <code>size</code>.</CardSubtitle>
<div class="space-y">
<Rating id="size-sm" value={3} size="sm" />
<Rating id="size-md" value={3} size="md" />
@@ -59,7 +61,7 @@ const starsRatingDocsUrl = getDocsUrl('/ui/components/star-rating')
<Card>
<CardBody>
<CardTitle>Colors</CardTitle>
<div class="card-subtitle">Set <code>color</code> to any theme or extended color to match the rest of the page.</div>
<CardSubtitle>Set <code>color</code> to any theme or extended color to match the rest of the page.</CardSubtitle>
<div class="space-y">
<Rating id="color-default" value={3} />
<Rating id="color-primary" color="primary" value={3} />
+11 -9
View File
@@ -3,15 +3,17 @@ 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 Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const stepDocsUrl = getDocsUrl('/ui/components/step')
---
<DefaultLayout title="Steps" pageMenu="base.steps" description="Steps show progress through a numbered or labeled sequence, as a horizontal bar, breadcrumb, or vertical timeline.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Steps</h1>
<PageTitle>Steps</PageTitle>
<a href={stepDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -22,7 +24,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Horizontal</CardTitle>
<div class="card-subtitle">Numbered steps for a linear process, with the current step highlighted.</div>
<CardSubtitle>Numbered steps for a linear process, with the current step highlighted.</CardSubtitle>
<ul class="steps steps-green my-4">
<li class="step-item">1</li>
<li class="step-item active">2</li>
@@ -35,7 +37,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Horizontal counter</CardTitle>
<div class="card-subtitle">The same steps without numbers, for a more minimal look.</div>
<CardSubtitle>The same steps without numbers, for a more minimal look.</CardSubtitle>
<ul class="steps steps-green steps-counter my-4">
<li class="step-item"></li>
<li class="step-item active"></li>
@@ -48,7 +50,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>With labels</CardTitle>
<div class="card-subtitle">Give each step a title instead of a number.</div>
<CardSubtitle>Give each step a title instead of a number.</CardSubtitle>
<ul class="steps steps-green steps-counter my-4">
<li class="step-item">Cart</li>
<li class="step-item active">Billing Information</li>
@@ -61,7 +63,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Breadcrumb arrows</CardTitle>
<div class="card-subtitle">Chevron-style steps, useful for wizards and checkouts.</div>
<CardSubtitle>Chevron-style steps, useful for wizards and checkouts.</CardSubtitle>
<ol class="breadcrumb breadcrumb-arrows">
<li class="breadcrumb-item"><a href="#">Step one</a></li>
<li class="breadcrumb-item active"><a href="#">Step two</a></li>
@@ -75,7 +77,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Breadcrumb numbered</CardTitle>
<div class="card-subtitle">Number each step and mute the ones not yet reached.</div>
<CardSubtitle>Number each step and mute the ones not yet reached.</CardSubtitle>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">1. Step one</a></li>
<li class="breadcrumb-item"><a href="#">2. Step two</a></li>
@@ -90,7 +92,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Breadcrumb muted</CardTitle>
<div class="card-subtitle">A quieter style for steps that shouldn't compete with the rest of the page.</div>
<CardSubtitle>A quieter style for steps that shouldn't compete with the rest of the page.</CardSubtitle>
<ol class="breadcrumb breadcrumb-muted">
<li class="breadcrumb-item"><a href="#">1. Step one</a></li>
<li class="breadcrumb-item"><a href="#">2. Step two</a></li>
@@ -108,7 +110,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Vertical</CardTitle>
<div class="card-subtitle">A title and description per step, for a detailed timeline.</div>
<CardSubtitle>A title and description per step, for a detailed timeline.</CardSubtitle>
<ul class="steps steps-vertical">
<li class="step-item">
<div class="h4 m-0">Order received</div>
@@ -134,7 +136,7 @@ const stepDocsUrl = getDocsUrl('/ui/components/step')
<Card>
<CardBody>
<CardTitle>Vertical counter</CardTitle>
<div class="card-subtitle">Numbered steps in a vertical list, without descriptions.</div>
<CardSubtitle>Numbered steps in a vertical list, without descriptions.</CardSubtitle>
<ul class="steps steps-counter steps-vertical">
<li class="step-item">Step one</li>
<li class="step-item">Step two</li>
+2 -1
View File
@@ -3,13 +3,14 @@ import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import TabsCard from '@shared/components/cards/TabsCard.astro'
import Icon from '@ui/Icon.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const tabsDocsUrl = getDocsUrl('/ui/layout/navs-tabs')
---
<DefaultLayout title="Tabs" pageMenu="base.tabs" description="Tabs switch between related panels of content inside a card.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Tabs</h1>
<PageTitle>Tabs</PageTitle>
<a href={tabsDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+11 -9
View File
@@ -5,11 +5,13 @@ import TagList from '@ui/TagList.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 Icon from '@ui/Icon.astro'
import people from '@data/people.json'
import flags from '@data/flags.json'
import siteData from '@data/site.json'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const tagIcons = ['bold', 'italic', 'underline', 'copy', 'scissors', 'file-plus', 'file-minus', 'ghost', 'star', 'script', 'photo', 'dog', 'piano']
@@ -26,7 +28,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<DefaultLayout title="Tags" pageMenu="base.tags" description="Tags are compact labels for filters, categories, and keywords.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Tags</h1>
<PageTitle>Tags</PageTitle>
<a href={tagDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -37,7 +39,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Default tags</CardTitle>
<div class="card-subtitle">The base tag, for a plain label.</div>
<CardSubtitle>The base tag, for a plain label.</CardSubtitle>
<TagList>
{range(1, 14).map((i) => <Tag text={`Label ${i}`} />)}
</TagList>
@@ -49,7 +51,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Tags with flag</CardTitle>
<div class="card-subtitle">Pair a tag with a country flag.</div>
<CardSubtitle>Pair a tag with a country flag.</CardSubtitle>
<TagList>
{flags9.map((country) => <Tag text={country.name} flag={country.flag} />)}
</TagList>
@@ -61,7 +63,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Tags with icon</CardTitle>
<div class="card-subtitle">Add an icon before the label.</div>
<CardSubtitle>Add an icon before the label.</CardSubtitle>
<TagList>
{tagIcons.map((icon) => <Tag text={icon} icon={icon} />)}
</TagList>
@@ -73,7 +75,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Tags with avatar</CardTitle>
<div class="card-subtitle">Add a person's avatar before the label.</div>
<CardSubtitle>Add a person's avatar before the label.</CardSubtitle>
<TagList>
{people8.map((person) => <Tag text={person.full_name} person={person} />)}
</TagList>
@@ -85,7 +87,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Tags with status</CardTitle>
<div class="card-subtitle">Add a small status dot in any theme or extended color.</div>
<CardSubtitle>Add a small status dot in any theme or extended color.</CardSubtitle>
<TagList>
{colors.map((color) => <Tag text={color.title} status={color.class} />)}
</TagList>
@@ -97,7 +99,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Tags with legend</CardTitle>
<div class="card-subtitle">Add a colored legend square instead of a dot.</div>
<CardSubtitle>Add a colored legend square instead of a dot.</CardSubtitle>
<TagList>
{colors.map((color) => <Tag text={color.title} legend={color.class} />)}
</TagList>
@@ -109,7 +111,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Selectable tags</CardTitle>
<div class="card-subtitle">Add <code>checkbox</code> to let users toggle a tag on and off.</div>
<CardSubtitle>Add <code>checkbox</code> to let users toggle a tag on and off.</CardSubtitle>
<TagList>
{range(1, 6).map((i) => <Tag text={`Label ${i}`} checkbox={true} />)}
{range(7, 12).map((i) => <Tag text={`Label ${i}`} checkbox={true} checked={true} />)}
@@ -122,7 +124,7 @@ const tagDocsUrl = getDocsUrl('/ui/components/tag')
<Card>
<CardBody>
<CardTitle>Tags with badge</CardTitle>
<div class="card-subtitle">Add a <code>badge</code> count to the end of the tag.</div>
<CardSubtitle>Add a <code>badge</code> count to the end of the tag.</CardSubtitle>
<TagList>
{range(1, 12).map((i) => <Tag text="Label" badge={i} />)}
</TagList>
+2 -1
View File
@@ -7,13 +7,14 @@ import CardBody from '@ui/CardBody.astro'
import Icon from '@ui/Icon.astro'
import Toast from '@ui/Toast.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
const toastDocsUrl = getDocsUrl('/ui/components/toast')
---
<DefaultLayout title="Toasts" pageMenu="base.toasts" description="Toasts show a brief, dismissible notification in the corner of the screen.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Toasts</h1>
<PageTitle>Toasts</PageTitle>
<a href={toastDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
+5 -3
View File
@@ -3,9 +3,11 @@ 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 Icon from '@ui/Icon.astro'
import StatusMonitoring from '@shared/components/cards/StatusMonitoring.astro'
import { getDocsUrl } from '@shared/lib/string-format'
import PageTitle from '@ui/PageTitle.astro'
interface TrackingItem {
status?: 'success' | 'warning' | 'danger'
@@ -51,7 +53,7 @@ const trackingDocsUrl = getDocsUrl('/ui/components/tracking')
<DefaultLayout title="Tracking" pageMenu="base.tracking" description="Tracking blocks show an uptime or activity history as a row of colored bars.">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="page-title">Tracking</h1>
<PageTitle>Tracking</PageTitle>
<a href={trackingDocsUrl} target="_blank" rel="noopener" class="link-secondary">
Docs <Icon name="external-link" class="icon-sm" />
</a>
@@ -62,7 +64,7 @@ const trackingDocsUrl = getDocsUrl('/ui/components/tracking')
<Card>
<CardBody>
<CardTitle>Basic example</CardTitle>
<div class="card-subtitle">Hover a block to see its status.</div>
<CardSubtitle>Hover a block to see its status.</CardSubtitle>
<div class="tracking">
{uptime.map((item) => <div class:list={['tracking-block', item.status && `bg-${item.status}`]} data-bs-toggle="tooltip" data-bs-placement="top" title={item.label} />)}
</div>
@@ -78,7 +80,7 @@ const trackingDocsUrl = getDocsUrl('/ui/components/tracking')
<Card>
<CardBody>
<CardTitle>Squares variant</CardTitle>
<div class="card-subtitle">Add <code>.tracking-squares</code> for square, evenly spaced blocks.</div>
<CardSubtitle>Add <code>.tracking-squares</code> for square, evenly spaced blocks.</CardSubtitle>
<div class="tracking tracking-squares">
{uptime.map((item) => <div class:list={['tracking-block', item.status && `bg-${item.status}`]} data-bs-toggle="tooltip" data-bs-placement="top" title={item.label} />)}
</div>
+2 -1
View File
@@ -2,6 +2,7 @@
// TODO: no standalone StatusIndicator component yet.
import Button from '@ui/Button.astro'
import ButtonList from '@ui/ButtonList.astro'
import PageTitle from '@ui/PageTitle.astro'
---
<!-- BEGIN HEADER UPTIME -->
@@ -17,7 +18,7 @@ import ButtonList from '@ui/ButtonList.astro'
</div>
<div class="col">
<h1 class="page-title">tabler.io/icons</h1>
<PageTitle>tabler.io/icons</PageTitle>
<div class="text-secondary">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item"><span class="text-green">Up</span></li>
+3 -2
View File
@@ -11,6 +11,7 @@ import HeaderActionsAddJob from './HeaderActionsAddJob.astro';
import HeaderActionsUsers from './HeaderActionsUsers.astro';
import HeaderProfile from './HeaderProfile.astro';
import HeaderUptime from './HeaderUptime.astro';
import PageTitle from '@ui/PageTitle.astro';
interface Props {
/** page-header — the page title; without it the whole block is not rendered */
@@ -46,9 +47,9 @@ const { title, pretitle, description, actions, class: className, file, textWhite
<div class="page-pretitle">{pretitle}</div>
</Fragment>
)}
<h1 class="page-title">
<PageTitle>
{title}
</h1>
</PageTitle>
{description && <div class="text-secondary mt-1">{description}</div>}
</div>
+20
View File
@@ -0,0 +1,20 @@
---
import type { HTMLTag } from 'astro/types'
// Page heading (.page-title), used at the top of a page or inside a .page-header.
// `as` must stay out of the Props body: Astro's frontmatter scanner bails on a member
// literally named `as` and silently falls back to untyped props.
type PolymorphicProps = { as?: HTMLTag }
interface Props extends PolymorphicProps {
class?: string
id?: string
}
const { as: Tag = 'h1', class: className, id }: Props = Astro.props
---
<Tag class:list={['page-title', className]} {...id ? { id } : {}}>
<slot />
</Tag>