Fix accessibility and markup bugs across preview pages and docs (#3082)

Co-authored-by: codecalm <codecalm@gmail.com>
This commit is contained in:
Bartosz-Doandcodecalm authored and GitHub committed 2026-09-18 00:16:52 +02:00
1 parent c99a436cc2
commit 364ccf801b
29 files changed
+197 -184

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
---
"@tabler/preview": patch
"@tabler/docs": patch
---
Fixed keyboard access and accessible names across preview pages, `Alert`, `Avatar`, `Rating`, `Tag` and `Wysiwyg` components.
+9 -9
View File
@@ -89,7 +89,7 @@ Add `alert-minor` for a quieter alert. It drops the tinted background and keeps
<div class="alert alert-minor alert-info alert-dismissible" role="alert"> <div class="alert alert-minor alert-info alert-dismissible" role="alert">
<div class="alert-heading">Did you know?</div> <div class="alert-heading">Did you know?</div>
<div class="text-secondary">Here is something that you might like to know.</div> <div class="text-secondary">Here is something that you might like to know.</div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
<div class="alert alert-minor alert-success" role="alert"> <div class="alert alert-minor alert-success" role="alert">
<div class="alert-heading">Everything worked</div> <div class="alert-heading">Everything worked</div>
@@ -102,7 +102,7 @@ Add `alert-minor` for a quieter alert. It drops the tinted background and keeps
Add a close button to let the user dismiss the alert. It stays on the page until they do. Add a close button to let the user dismiss the alert. It stays on the page until they do.
```html ```html
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
``` ```
<Example> <Example>
@@ -222,7 +222,7 @@ Buttons don't inherit the alert's color, so you should set the proper class if y
<a href="#" class="btn btn-success">Okay</a> <a href="#" class="btn btn-success">Okay</a>
<a href="#" class="btn">Cancel</a> <a href="#" class="btn">Cancel</a>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
<div class="alert alert-info alert-dismissible" role="alert"> <div class="alert alert-info alert-dismissible" role="alert">
<h3 class="mb-1">Some Title</h3> <h3 class="mb-1">Some Title</h3>
@@ -231,7 +231,7 @@ Buttons don't inherit the alert's color, so you should set the proper class if y
<a href="#" class="btn btn-info">Okay</a> <a href="#" class="btn btn-info">Okay</a>
<a href="#" class="btn">Cancel</a> <a href="#" class="btn">Cancel</a>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
<div class="alert alert-warning alert-dismissible" role="alert"> <div class="alert alert-warning alert-dismissible" role="alert">
<h3 class="mb-1">Some Title</h3> <h3 class="mb-1">Some Title</h3>
@@ -240,7 +240,7 @@ Buttons don't inherit the alert's color, so you should set the proper class if y
<a href="#" class="btn btn-warning">Okay</a> <a href="#" class="btn btn-warning">Okay</a>
<a href="#" class="btn">Cancel</a> <a href="#" class="btn">Cancel</a>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
<div class="alert alert-danger alert-dismissible" role="alert"> <div class="alert alert-danger alert-dismissible" role="alert">
<h3 class="mb-1">Some Title</h3> <h3 class="mb-1">Some Title</h3>
@@ -249,7 +249,7 @@ Buttons don't inherit the alert's color, so you should set the proper class if y
<a href="#" class="btn btn-danger">Okay</a> <a href="#" class="btn btn-danger">Okay</a>
<a href="#" class="btn">Cancel</a> <a href="#" class="btn">Cancel</a>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
</Example> </Example>
@@ -271,7 +271,7 @@ You can also use other elements, like icons and dismissible buttons, with this t
</div> </div>
<div>Wow! Everything worked!</div> <div>Wow! Everything worked!</div>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
<div class="alert alert-important alert-danger alert-dismissible" role="alert"> <div class="alert alert-important alert-danger alert-dismissible" role="alert">
<div class="d-flex"> <div class="d-flex">
@@ -280,7 +280,7 @@ You can also use other elements, like icons and dismissible buttons, with this t
</div> </div>
<div>Your account has been deleted and can't be restored.</div> <div>Your account has been deleted and can't be restored.</div>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
</Example> </Example>
@@ -318,7 +318,7 @@ You're not limited to the 4 default alert colors. You can use any [base color](/
<div>Be the first to see it!</div> <div>Be the first to see it!</div>
</div> </div>
</div> </div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
</div> </div>
</Example> </Example>
+9 -9
View File
@@ -467,15 +467,15 @@ Add `.btn-animate-icon` to move the icon on hover. The `-rotate`, `-shake`, `-pu
<Example> <Example>
<div class="btn-list"> <div class="btn-list">
<a class="btn btn-animate-icon"> Save <Icon name="arrow-right" class="icon-end" /> </a> <button type="button" class="btn btn-animate-icon"> Save <Icon name="arrow-right" class="icon-end" /> </button>
<a class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="plus" /> Add </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="plus" /> Add </button>
<a class="btn btn-animate-icon btn-animate-icon-shake"> <Icon name="bell" /> Notifications </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-shake"> <Icon name="bell" /> Notifications </button>
<a class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="settings" /> Settings </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="settings" /> Settings </button>
<a class="btn btn-animate-icon btn-animate-icon-pulse"> <Icon name="heart" /> Love </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-pulse"> <Icon name="heart" /> Love </button>
<a class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="x" /> Close </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="x" /> Close </button>
<a class="btn btn-animate-icon btn-animate-icon-tada"> <Icon name="check" /> Confirm </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-tada"> <Icon name="check" /> Confirm </button>
<a class="btn btn-animate-icon"> Next <Icon name="chevron-right" class="icon-end" /> </a> <button type="button" class="btn btn-animate-icon"> Next <Icon name="chevron-right" class="icon-end" /> </button>
<a class="btn btn-animate-icon btn-animate-icon-move-start"> <Icon name="chevron-left" /> Previous </a> <button type="button" class="btn btn-animate-icon btn-animate-icon-move-start"> <Icon name="chevron-left" /> Previous </button>
</div> </div>
</Example> </Example>
+2 -2
View File
@@ -158,8 +158,8 @@ function greetUser(name) {
</CardBody> </CardBody>
<CardFooter> <CardFooter>
<div class="d-flex"> <div class="d-flex">
<a class="btn btn-link">Cancel</a> <button type="button" class="btn btn-link">Cancel</button>
<a class="btn btn-primary ms-auto">Save</a> <button type="button" class="btn btn-primary ms-auto">Save</button>
</div> </div>
</CardFooter> </CardFooter>
</Card> </Card>
+14 -12
View File
@@ -140,18 +140,20 @@ const invoiceStatus = {
<div class="form-selectgroup form-selectgroup-boxes d-flex flex-column"> <div class="form-selectgroup form-selectgroup-boxes d-flex flex-column">
{ {
paymentMethods.map((method) => ( paymentMethods.map((method) => (
<label class="form-selectgroup-item flex-fill"> <div class="form-selectgroup-item flex-fill">
<input type="radio" name="payment-method" value={method.provider} class="form-selectgroup-input" checked={method.isDefault} /> <input type="radio" id={`payment-method-${method.provider}`} name="payment-method" value={method.provider} class="form-selectgroup-input" checked={method.isDefault} />
<div class="form-selectgroup-label d-flex align-items-center p-3"> <div class="form-selectgroup-label d-flex align-items-center p-3">
<div class="me-3"> <label for={`payment-method-${method.provider}`} class="d-flex align-items-center flex-fill mb-0">
<span class="form-selectgroup-check" /> <div class="me-3">
</div> <span class="form-selectgroup-check" />
<Payment payment={method.provider} size="sm" class="me-3" /> </div>
<div class="me-auto"> <Payment payment={method.provider} size="sm" class="me-3" />
<div class="fw-medium">{method.title}</div> <div class="me-auto">
<div class="text-secondary">{method.description}</div> <div class="fw-medium">{method.title}</div>
</div> <div class="text-secondary">{method.description}</div>
{method.isDefault && <Badge text="Default" color="primary" light class="me-2" />} </div>
{method.isDefault && <Badge text="Default" color="primary" light class="me-2" />}
</label>
<div class="dropdown"> <div class="dropdown">
<button type="button" class="btn btn-action btn-sm" data-bs-toggle="dropdown" aria-expanded="false" aria-label={`Actions for ${method.title}`}> <button type="button" class="btn btn-action btn-sm" data-bs-toggle="dropdown" aria-expanded="false" aria-label={`Actions for ${method.title}`}>
<Icon name="dots-vertical" /> <Icon name="dots-vertical" />
@@ -174,7 +176,7 @@ const invoiceStatus = {
</div> </div>
</div> </div>
</div> </div>
</label> </div>
)) ))
} }
</div> </div>
+50 -42
View File
@@ -46,18 +46,18 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<CardTitle>Shapes</CardTitle> <CardTitle>Shapes</CardTitle>
<CardSubtitle>Round the corners with <code>.btn-pill</code>, or square them off with <code>.btn-square</code>.</CardSubtitle> <CardSubtitle>Round the corners with <code>.btn-pill</code>, or square them off with <code>.btn-square</code>.</CardSubtitle>
<ButtonList> <ButtonList>
<a class="btn">Default</a> <button type="button" class="btn">Default</button>
<a class="btn btn-pill">Pill</a> <button type="button" class="btn btn-pill">Pill</button>
<a class="btn btn-square">Square</a> <button type="button" class="btn btn-square">Square</button>
<a class="btn btn-icon"> <button type="button" class="btn btn-icon">
<Icon name="star" /> <Icon name="star" />
</a> </button>
<a class="btn btn-pill btn-icon"> <button type="button" class="btn btn-pill btn-icon">
<Icon name="star" /> <Icon name="star" />
</a> </button>
<a class="btn btn-square btn-icon"> <button type="button" class="btn btn-square btn-icon">
<Icon name="star" /> <Icon name="star" />
</a> </button>
</ButtonList> </ButtonList>
</CardBody> </CardBody>
</Card> </Card>
@@ -105,33 +105,33 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<CardTitle>Animated icon</CardTitle> <CardTitle>Animated icon</CardTitle>
<CardSubtitle>Small hover animations draw attention to the icon.</CardSubtitle> <CardSubtitle>Small hover animations draw attention to the icon.</CardSubtitle>
<ButtonList> <ButtonList>
<a class="btn btn-animate-icon"> <button type="button" class="btn btn-animate-icon">
Save <Icon name="arrow-right" class="icon-end" /> Save <Icon name="arrow-right" class="icon-end" />
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-rotate"> <button type="button" class="btn btn-animate-icon btn-animate-icon-rotate">
<Icon name="plus" /> Add <Icon name="plus" /> Add
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-shake"> <button type="button" class="btn btn-animate-icon btn-animate-icon-shake">
<Icon name="bell" /> Notifications <Icon name="bell" /> Notifications
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-rotate"> <button type="button" class="btn btn-animate-icon btn-animate-icon-rotate">
<Icon name="settings" /> Settings <Icon name="settings" /> Settings
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-pulse"> <button type="button" class="btn btn-animate-icon btn-animate-icon-pulse">
<Icon name="heart" /> Love <Icon name="heart" /> Love
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-rotate"> <button type="button" class="btn btn-animate-icon btn-animate-icon-rotate">
<Icon name="x" /> Close <Icon name="x" /> Close
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-tada"> <button type="button" class="btn btn-animate-icon btn-animate-icon-tada">
<Icon name="check" /> Confirm <Icon name="check" /> Confirm
</a> </button>
<a class="btn btn-animate-icon"> <button type="button" class="btn btn-animate-icon">
Next <Icon name="chevron-right" class="icon-end" /> Next <Icon name="chevron-right" class="icon-end" />
</a> </button>
<a class="btn btn-animate-icon btn-animate-icon-move-start"> <button type="button" class="btn btn-animate-icon btn-animate-icon-move-start">
<Icon name="chevron-left" /> Previous <Icon name="chevron-left" /> Previous
</a> </button>
</ButtonList> </ButtonList>
</CardBody> </CardBody>
</Card> </Card>
@@ -144,9 +144,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
themeColors.map(([name, color]) => ( themeColors.map(([name, color]) => (
<a class={`btn btn-${name}`}> <button type="button" class={`btn btn-${name}`}>
{color.icon && <Icon name={color.icon} />} {color.title} {color.icon && <Icon name={color.icon} />} {color.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -161,9 +161,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
themeColors.map(([name, color]) => ( themeColors.map(([name, color]) => (
<a class={`btn btn-outline btn-${name}`}> <button type="button" class={`btn btn-outline btn-${name}`}>
{color.icon && <Icon name={color.icon} />} {color.title} {color.icon && <Icon name={color.icon} />} {color.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -178,9 +178,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
themeColors.map(([name, color]) => ( themeColors.map(([name, color]) => (
<a class={`btn btn-ghost btn-${name}`}> <button type="button" class={`btn btn-ghost btn-${name}`}>
{color.icon && <Icon name={color.icon} />} {color.title} {color.icon && <Icon name={color.icon} />} {color.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -195,9 +195,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
themeColors.map(([name, color]) => ( themeColors.map(([name, color]) => (
<a class={`btn btn-pill btn-${name}`}> <button type="button" class={`btn btn-pill btn-${name}`}>
{color.icon && <Icon name={color.icon} />} {color.title} {color.icon && <Icon name={color.icon} />} {color.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -212,9 +212,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
themeColors.map(([name, color]) => ( themeColors.map(([name, color]) => (
<a class={`btn btn-square btn-${name}`}> <button type="button" class={`btn btn-square btn-${name}`}>
{color.icon && <Icon name={color.icon} />} {color.title} {color.icon && <Icon name={color.icon} />} {color.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -229,9 +229,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
colors.map(([name, color]) => ( colors.map(([name, color]) => (
<a class={`btn btn-${name}`}> <button type="button" class={`btn btn-${name}`}>
{color.icon && <Icon name={color.icon} />} {color.title} {color.icon && <Icon name={color.icon} />} {color.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -246,9 +246,9 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<ButtonList> <ButtonList>
{ {
socialColors.map(([name, app]) => ( socialColors.map(([name, app]) => (
<a class={`btn btn-${name}`}> <button type="button" class={`btn btn-${name}`}>
{app.icon && <Icon name={app.icon} />} {app.title} {app.icon && <Icon name={app.icon} />} {app.title}
</a> </button>
)) ))
} }
</ButtonList> </ButtonList>
@@ -260,7 +260,15 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
<CardBody> <CardBody>
<CardTitle>Icon buttons</CardTitle> <CardTitle>Icon buttons</CardTitle>
<CardSubtitle>Social brand colors without a label, for compact toolbars.</CardSubtitle> <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> <ButtonList
>{
socialColors.map(([name, app]) => (
<button type="button" class={`btn btn-icon btn-${name}`}>
{app.icon && <Icon name={app.icon} />}
</button>
))
}</ButtonList
>
</CardBody> </CardBody>
</Card> </Card>
</div> </div>
+9 -9
View File
@@ -232,8 +232,8 @@ const operationCurrencies = currencies.slice(0, 20)
<p>Place new order:</p> <p>Place new order:</p>
<div class="input-group mb-3"> <div class="input-group mb-3">
<label class="input-group-text">Amount</label> <label class="input-group-text" for="crypto-amount-value">Amount</label>
<select class="form-select"> <select class="form-select" aria-label="Currency">
{ {
operationCurrencies.map((currency, i) => ( operationCurrencies.map((currency, i) => (
<option value={currency.symbol} selected={i === 0}> <option value={currency.symbol} selected={i === 0}>
@@ -242,19 +242,19 @@ const operationCurrencies = currencies.slice(0, 20)
)) ))
} }
</select> </select>
<input type="text" class="form-control" value="0.25" /> <input type="text" id="crypto-amount-value" class="form-control" value="0.25" />
</div> </div>
<div class="input-group mb-3"> <div class="input-group mb-3">
<label class="input-group-text">Price</label> <label class="input-group-text" for="crypto-order-price">Price</label>
<input type="text" class="form-control" readonly="" value="23,077.05" /> <input type="text" id="crypto-order-price" class="form-control" readonly="" value="23,077.05" />
<label class="input-group-text">$</label> <label class="input-group-text" for="crypto-order-price">$</label>
</div> </div>
<div class="input-group mb-3"> <div class="input-group mb-3">
<label class="input-group-text">Total</label> <label class="input-group-text" for="crypto-order-total">Total</label>
<input type="text" class="form-control" readonly="" value="5,769.27" /> <input type="text" id="crypto-order-total" class="form-control" readonly="" value="5,769.27" />
<label class="input-group-text">$</label> <label class="input-group-text" for="crypto-order-total">$</label>
</div> </div>
<div class="d-grid"> <div class="d-grid">
+1 -1
View File
@@ -57,7 +57,7 @@ const emailEntries = Object.entries(emails)
<div class="row g-0"> <div class="row g-0">
<div class="col-6"> <div class="col-6">
<div class="p-6 bg-surface-secondary rounded-start"> <div class="p-6 bg-surface-secondary rounded-start">
<img src="" class="img-fluid rounded-start" data-email-image /> <img class="img-fluid rounded-start" alt="" data-email-image />
</div> </div>
</div> </div>
<div class="col-6"> <div class="col-6">
+4 -4
View File
@@ -239,7 +239,7 @@ const rows = [
rows.map((row) => ( rows.map((row) => (
<tr> <tr>
<td> <td>
<select class="form-select"> <select class="form-select" aria-label="Source">
{sources.map(([v, l]) => ( {sources.map(([v, l]) => (
<option value={v} selected={v === row.source || undefined}> <option value={v} selected={v === row.source || undefined}>
{l} {l}
@@ -248,10 +248,10 @@ const rows = [
</select> </select>
</td> </td>
<td> <td>
<input type="text" class="form-control" value={row.prop || undefined} /> <input type="text" class="form-control" aria-label="Property" value={row.prop || undefined} />
</td> </td>
<td> <td>
<select class="form-select"> <select class="form-select" aria-label="Comparison">
{comparisons.map(([v, l]) => ( {comparisons.map(([v, l]) => (
<option value={v} selected={v === row.comparison || undefined}> <option value={v} selected={v === row.comparison || undefined}>
{l} {l}
@@ -260,7 +260,7 @@ const rows = [
</select> </select>
</td> </td>
<td> <td>
<input type="text" class="form-control" value={row.target} /> <input type="text" class="form-control" aria-label="Target" value={row.target} />
</td> </td>
</tr> </tr>
)) ))
+1 -3
View File
@@ -2,14 +2,12 @@
import SingleLayout from '@shared/layouts/SingleLayout.astro' import SingleLayout from '@shared/layouts/SingleLayout.astro'
import CardTitle from '@ui/CardTitle.astro' import CardTitle from '@ui/CardTitle.astro'
import Prose from '@ui/Prose.astro' import Prose from '@ui/Prose.astro'
// Card title is empty on purpose.
--- ---
<SingleLayout title="Terms of service" containerSize="narrow"> <SingleLayout title="Terms of service" containerSize="narrow">
<div class="card card-md"> <div class="card card-md">
<div class="card-body"> <div class="card-body">
<CardTitle /> <CardTitle>Terms of service</CardTitle>
<Prose> <Prose>
<p> <p>
We (the folks at Tabler) run a website hosting platform called <a href="https://tabler.io">tabler.io</a> and would love for you to use it. Tabler.io's basic service is free, and we offer paid upgrades for advanced features. Our service is designed to give you as much control and ownership over what goes on your We (the folks at Tabler) run a website hosting platform called <a href="https://tabler.io">tabler.io</a> and would love for you to use it. Tabler.io's basic service is free, and we offer paid upgrades for advanced features. Our service is designed to give you as much control and ownership over what goes on your
+2 -2
View File
@@ -142,11 +142,11 @@ const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[],
<div class={`col-auto${elRight ? ' ms-auto' : ''}`}> <div class={`col-auto${elRight ? ' ms-auto' : ''}`}>
{el === 'switch' ? ( {el === 'switch' ? (
<label class="form-check form-switch m-0"> <label class="form-check form-switch m-0">
<input class="form-check-input position-static" type="checkbox" checked /> <input class="form-check-input position-static" type="checkbox" checked aria-label="Enable" />
</label> </label>
) : el === 'check' ? ( ) : el === 'check' ? (
<label class="form-check m-0"> <label class="form-check m-0">
<input class="form-check-input position-static" type="checkbox" checked /> <input class="form-check-input position-static" type="checkbox" checked aria-label="Select" />
</label> </label>
) : el === 'avatars' ? ( ) : el === 'avatars' ? (
<PeopleAvatarList stacked={true} size="sm" text="+3" /> <PeopleAvatarList stacked={true} size="sm" text="+3" />
+1 -1
View File
@@ -55,7 +55,7 @@ const paneClass = `tab-pane${animation ? ' fade' : ''}`
{ {
dropdown && ( dropdown && (
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Dropdown Dropdown
</a> </a>
<DropdownMenu /> <DropdownMenu />
+1 -1
View File
@@ -59,7 +59,7 @@ const rows = people.slice(offset, offset + limit).map((person, idx) => {
</div> </div>
)} )}
<div class="col-auto"> <div class="col-auto">
<a href="#"> <a href="#" tabindex="-1" aria-hidden="true">
<Avatar person={row.person} /> <Avatar person={row.person} />
</a> </a>
</div> </div>
@@ -41,7 +41,7 @@ const rows = sorted.map((person, idx) => {
<ListGroupItem> <ListGroupItem>
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
<a href="#"> <a href="#" tabindex="-1" aria-hidden="true">
<Avatar person={row.person} /> <Avatar person={row.person} />
</a> </a>
</div> </div>
+1 -1
View File
@@ -36,7 +36,7 @@ import Progress from '@ui/Progress.astro'
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 d-flex justify-content-center"> <div class="col-12 col-sm-6 d-flex justify-content-center">
<a href="./illustrations.html"> <a href="./illustrations.html" aria-label="Illustrations">
<svg xmlns="http://www.w3.org/2000/svg" height="200" fill="none" viewBox="0 0 800 600"> <svg xmlns="http://www.w3.org/2000/svg" height="200" fill="none" viewBox="0 0 800 600">
<style is:inline> <style is:inline>
:where(.theme-dark, [data-theme='dark']) .tblr-illustrations-good-info-a { :where(.theme-dark, [data-theme='dark']) .tblr-illustrations-good-info-a {
+1 -1
View File
@@ -28,7 +28,7 @@ const classes = ['nav', pills ? 'nav-pills' : tabs ? 'nav-tabs' : undefined, cla
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true"> Disabled </a> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true"> Disabled </a>
</li> </li>
<li class="nav-item ms-auto"> <li class="nav-item ms-auto">
<a class="nav-link" href="#"> <a class="nav-link" href="#" aria-label="Settings">
<Icon name="settings" /> <Icon name="settings" />
</a> </a>
</li> </li>
+4 -8
View File
@@ -256,13 +256,11 @@ import Avatar from '@ui/Avatar.astro'
<input type="radio" class="btn-check" name="btn-radio-dropdown" id="btn-radio-dropdown-2" autocomplete="off" /> <input type="radio" class="btn-check" name="btn-radio-dropdown" id="btn-radio-dropdown-2" autocomplete="off" />
<label for="btn-radio-dropdown-2" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Option 2</label> <label for="btn-radio-dropdown-2" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Option 2</label>
<ButtonGroup> <ButtonGroup>
<input type="radio" class="btn-check" name="btn-radio-dropdown" id="btn-radio-dropdown-dropdown" autocomplete="off" /> <button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Other </button>
<label for="btn-radio-dropdown-dropdown" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Other </label>
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class="dropdown-item" href="#"> Action </a> <a class="dropdown-item" href="#"> Action </a>
<a class="dropdown-item" href="#"> Another action </a> <a class="dropdown-item" href="#"> Another action </a>
</div> <div class="dropdown-divider"></div>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="#"> Option 4 </a> <a class="dropdown-item" href="#"> Option 4 </a>
<a class="dropdown-item" href="#"> Option 5 </a> <a class="dropdown-item" href="#"> Option 5 </a>
<a class="dropdown-item" href="#"> Option 6 </a> <a class="dropdown-item" href="#"> Option 6 </a>
@@ -306,13 +304,11 @@ import Avatar from '@ui/Avatar.astro'
<input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-4" autocomplete="off" /> <input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-4" autocomplete="off" />
<label for="btn-radio-vertical-dropdown-4" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 4</label> <label for="btn-radio-vertical-dropdown-4" {...{ type: 'button' } as unknown as astroHTML.JSX.LabelHTMLAttributes} class="btn">Button 4</label>
<ButtonGroup> <ButtonGroup>
<input type="radio" class="btn-check" name="btn-radio-vertical-dropdown" id="btn-radio-vertical-dropdown-dropdown" autocomplete="off" /> <button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Other </button>
<label for="btn-radio-vertical-dropdown-dropdown" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Other </label>
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class="dropdown-item" href="#"> Action </a> <a class="dropdown-item" href="#"> Action </a>
<a class="dropdown-item" href="#"> Another action </a> <a class="dropdown-item" href="#"> Another action </a>
</div> <div class="dropdown-divider"></div>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="#"> Option 4 </a> <a class="dropdown-item" href="#"> Option 4 </a>
<a class="dropdown-item" href="#"> Option 5 </a> <a class="dropdown-item" href="#"> Option 5 </a>
<a class="dropdown-item" href="#"> Option 6 </a> <a class="dropdown-item" href="#"> Option 6 </a>
@@ -7,7 +7,7 @@ import Button from '@ui/Button.astro'
<div class="d-flex"> <div class="d-flex">
<div class="me-3"> <div class="me-3">
<div class="input-icon"> <div class="input-icon">
<input type="text" value="" class="form-control" placeholder="Search…" /> <input type="text" value="" class="form-control" placeholder="Search…" aria-label="Search" />
<span class="input-icon-addon"> <span class="input-icon-addon">
<Icon name="search" /> <Icon name="search" />
@@ -4,7 +4,7 @@ import Button from '@ui/Button.astro'
<!-- BEGIN HEADER ACTIONS --> <!-- BEGIN HEADER ACTIONS -->
<div class="d-flex"> <div class="d-flex">
<input type="search" class="form-control d-inline-block w-9 me-3" placeholder="Search user…" /> <input type="search" class="form-control d-inline-block w-9 me-3" placeholder="Search user…" aria-label="Search user" />
<Button text="New user" color="primary" icon="plus" /> <Button text="New user" color="primary" icon="plus" />
</div> </div>
<!-- END HEADER ACTIONS --> <!-- END HEADER ACTIONS -->
@@ -26,13 +26,13 @@ const sectionClass = ['section', background && `section-${background}`, classNam
<h2 class="section-title text-secondary">Trusted by over 3,000 companies</h2> <h2 class="section-title text-secondary">Trusted by over 3,000 companies</h2>
</div> </div>
<div class="row g-lg-8 align-items-center justify-content-center"> <div class="row g-lg-8 align-items-center justify-content-center">
<div class="col-auto"><a href="#" class="link-secondary"><Baremetrics /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="Baremetrics"><Baremetrics /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Cgi /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="CGI"><Cgi /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Docplanner /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="Docplanner"><Docplanner /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Flow /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="Flow"><Flow /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Fubotv /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="fuboTV"><Fubotv /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><SixFlags /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="Six Flags"><SixFlags /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Vocus /></a></div> <div class="col-auto"><a href="#" class="link-secondary" aria-label="Vocus"><Vocus /></a></div>
</div> </div>
</div> </div>
</section> </section>
@@ -19,13 +19,13 @@ const sectionClass = ['section', className]
</div> </div>
<div class="container-tight"> <div class="container-tight">
<div class="row"> <form class="row" action="./" method="get" novalidate>
<div class="col"> <div class="col">
<input class="w-100 form-control" placeholder="Your Email" type="email" /> <input class="w-100 form-control" name="email" placeholder="Your Email" type="email" />
</div> </div>
<div class="col-auto"> <div class="col-auto">
<button type="submit" class="btn btn-primary"><Icon name="mail" /> Subscribe</button> <button type="submit" class="btn btn-primary"><Icon name="mail" /> Subscribe</button>
</div> </div>
</div> </form>
</div> </div>
</section> </section>
@@ -12,8 +12,8 @@ import InputColor from '../parts/form/InputColor.astro'
<AvatarUpload class="rounded" size="xl" /> <AvatarUpload class="rounded" size="xl" />
</div> </div>
<div class="col"> <div class="col">
<label class="form-label">Name</label> <label class="form-label" for="team-name">Name</label>
<input type="text" class="form-control" /> <input type="text" id="team-name" class="form-control" />
</div> </div>
</div> </div>
+54 -54
View File
@@ -8,16 +8,16 @@
"heightFull": 2370 "heightFull": 2370
}, },
"access-token": { "access-token": {
"descriptionShort": "", "descriptionShort": "Email template about generating an access token",
"descriptionLong": "", "descriptionLong": "Allows to inform the user that a new access token has been created for their account. Shows when the token was generated and from which device or location. Sends directly to the security settings by the button to revoke it if not recognized.",
"width": 1248, "width": 1248,
"height": 1032, "height": 1032,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 1786 "heightFull": 1786
}, },
"account-deleted": { "account-deleted": {
"descriptionShort": "", "descriptionShort": "Email template confirming an account deletion",
"descriptionLong": "", "descriptionLong": "Allows to confirm that a user's account and its data have been permanently deleted. Shows the date the account was removed and a short summary of what happens next. Gives a contact link in case the deletion was not requested.",
"width": 1248, "width": 1248,
"height": 1152, "height": 1152,
"widthFull": 1440, "widthFull": 1440,
@@ -40,16 +40,16 @@
"heightFull": 3260 "heightFull": 3260
}, },
"calendar": { "calendar": {
"descriptionShort": "", "descriptionShort": "Email template with a calendar of events",
"descriptionLong": "", "descriptionLong": "Allows to show a list of upcoming events over the month, each with its date and short description. Highlights the closest event separately. Refers to the full calendar on the website by the button.",
"width": 1248, "width": 1248,
"height": 2744, "height": 2744,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 3498 "heightFull": 3498
}, },
"changelog": { "changelog": {
"descriptionShort": "", "descriptionShort": "Email template with a product changelog",
"descriptionLong": "", "descriptionLong": "Allows to list the latest changes, fixes and new features added to the product. Groups items by category and shows the release date. Sends to the full changelog page by the button.",
"width": 1248, "width": 1248,
"height": 1956, "height": 1956,
"widthFull": 1440, "widthFull": 1440,
@@ -64,8 +64,8 @@
"heightFull": 3528 "heightFull": 3528
}, },
"company-email": { "company-email": {
"descriptionShort": "", "descriptionShort": "Email template for internal company communication",
"descriptionLong": "", "descriptionLong": "Allows to share company news and announcements with employees. Shows the sender's name and department along with the message content. Includes a button to read the full announcement on the intranet.",
"width": 1248, "width": 1248,
"height": 1604, "height": 1604,
"widthFull": 1440, "widthFull": 1440,
@@ -80,8 +80,8 @@
"heightFull": 4440 "heightFull": 4440
}, },
"confirm-email": { "confirm-email": {
"descriptionShort": "", "descriptionShort": "Email template to confirm a new email address",
"descriptionLong": "", "descriptionLong": "Allows to verify that a newly added email address belongs to the user. Shows the address to be confirmed and explains why confirmation is needed. Sends directly to the confirmation page by the button.",
"width": 1248, "width": 1248,
"height": 1484, "height": 1484,
"widthFull": 1440, "widthFull": 1440,
@@ -96,16 +96,16 @@
"heightFull": 5204 "heightFull": 5204
}, },
"deployment-failed": { "deployment-failed": {
"descriptionShort": "", "descriptionShort": "Email template about a failed deployment",
"descriptionLong": "", "descriptionLong": "Allows to notify the team that a deployment did not complete successfully. Shows the project name, the failed step and the time it happened. Sends to the build logs by the button to investigate the cause.",
"width": 1248, "width": 1248,
"height": 1906, "height": 1906,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 2660 "heightFull": 2660
}, },
"domain-configuration": { "domain-configuration": {
"descriptionShort": "", "descriptionShort": "Email template about domain configuration",
"descriptionLong": "", "descriptionLong": "Allows to guide the user through connecting a custom domain. Shows the required DNS records and their current verification status. Sends to the domain settings by the button to finish the setup.",
"width": 1248, "width": 1248,
"height": 1474, "height": 1474,
"widthFull": 1440, "widthFull": 1440,
@@ -168,40 +168,40 @@
"heightFull": 3406 "heightFull": 3406
}, },
"features-3": { "features-3": {
"descriptionShort": "", "descriptionShort": "Email template presenting product features",
"descriptionLong": "", "descriptionLong": "Allows to showcase a set of product features with an icon and short description for each. Groups the features so they are easy to scan. Sends to the features page by the button for more details.",
"width": 1248, "width": 1248,
"height": 1340, "height": 1340,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 2094 "heightFull": 2094
}, },
"footer-1": { "footer-1": {
"descriptionShort": "", "descriptionShort": "Email footer template with social links",
"descriptionLong": "", "descriptionLong": "Shows a simple footer block with the company logo, social media icons and an unsubscribe link. Fits at the bottom of any email template. Keeps the layout compact and consistent with the rest of the message.",
"width": 1248, "width": 1248,
"height": 244, "height": 244,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 998 "heightFull": 998
}, },
"footer-2": { "footer-2": {
"descriptionShort": "", "descriptionShort": "Email footer template with contact details",
"descriptionLong": "", "descriptionLong": "Shows a footer block with the company address, phone number and support email. Includes links to the privacy policy and unsubscribe page. Fits at the bottom of any email template.",
"width": 1248, "width": 1248,
"height": 244, "height": 244,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 964 "heightFull": 964
}, },
"footer-3": { "footer-3": {
"descriptionShort": "", "descriptionShort": "Email footer template with navigation links",
"descriptionLong": "", "descriptionLong": "Shows a footer block with links to the main sections of the website. Includes the company logo and copyright notice. Fits at the bottom of any email template.",
"width": 1248, "width": 1248,
"height": 244, "height": 244,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 1222 "heightFull": 1222
}, },
"footer-4": { "footer-4": {
"descriptionShort": "", "descriptionShort": "Email footer template with app download links",
"descriptionLong": "", "descriptionLong": "Shows a footer block promoting the mobile app with App Store and Google Play buttons. Includes the company logo and an unsubscribe link. Fits at the bottom of any email template.",
"width": 1248, "width": 1248,
"height": 244, "height": 244,
"widthFull": 1440, "widthFull": 1440,
@@ -240,8 +240,8 @@
"heightFull": 2048 "heightFull": 2048
}, },
"invitation-2": { "invitation-2": {
"descriptionShort": "", "descriptionShort": "Email template with an invitation to collaborate",
"descriptionLong": "", "descriptionLong": "Shows who invites the user and to which project or team. Explains what access will be granted once the invitation is accepted. Accepts or declines the invitation by the button at any time.",
"width": 1248, "width": 1248,
"height": 1652, "height": 1652,
"widthFull": 1440, "widthFull": 1440,
@@ -272,8 +272,8 @@
"heightFull": 2484 "heightFull": 2484
}, },
"magic-link": { "magic-link": {
"descriptionShort": "", "descriptionShort": "Email template with a magic link to sign in",
"descriptionLong": "", "descriptionLong": "Allows to sign in without a password by sending a one-time link to the user's email. Shows how long the link stays valid before it expires. Sends directly to the account by the button.",
"width": 1248, "width": 1248,
"height": 1180, "height": 1180,
"widthFull": 1440, "widthFull": 1440,
@@ -296,16 +296,16 @@
"heightFull": 2530 "heightFull": 2530
}, },
"new-app": { "new-app": {
"descriptionShort": "", "descriptionShort": "Email template announcing a new app",
"descriptionLong": "", "descriptionLong": "Allows to introduce a newly released application to users. Shows a short description of what the app does along with a preview image. Sends to the download page by the button.",
"width": 1248, "width": 1248,
"height": 1270, "height": 1270,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 2024 "heightFull": 2024
}, },
"new-photos": { "new-photos": {
"descriptionShort": "", "descriptionShort": "Email template about new photos added",
"descriptionLong": "", "descriptionLong": "Allows to notify the user that new photos have been added to an album or gallery. Shows a preview of the latest photos along with who added them. Sends to the full gallery by the button.",
"width": 1248, "width": 1248,
"height": 1768, "height": 1768,
"widthFull": 1440, "widthFull": 1440,
@@ -320,8 +320,8 @@
"heightFull": 6044 "heightFull": 6044
}, },
"off-deals": { "off-deals": {
"descriptionShort": "", "descriptionShort": "Email template with discounted deals",
"descriptionLong": "", "descriptionLong": "Allows to present a list of products currently on sale with their discounted price. Shows the discount percentage and how long the deal lasts. Sends directly to the store by the button.",
"width": 1248, "width": 1248,
"height": 2508, "height": 2508,
"widthFull": 1440, "widthFull": 1440,
@@ -344,8 +344,8 @@
"heightFull": 4442 "heightFull": 4442
}, },
"otp-code": { "otp-code": {
"descriptionShort": "", "descriptionShort": "Email template with a one-time password code",
"descriptionLong": "", "descriptionLong": "Allows to send a one-time code used to verify the user's identity. Shows how long the code stays valid before it expires. Reminds the user not to share the code with anyone.",
"width": 1248, "width": 1248,
"height": 1908, "height": 1908,
"widthFull": 1440, "widthFull": 1440,
@@ -376,8 +376,8 @@
"heightFull": 3950 "heightFull": 3950
}, },
"post": { "post": {
"descriptionShort": "", "descriptionShort": "Email template about a new post",
"descriptionLong": "", "descriptionLong": "Allows to notify followers when a new post is published. Shows the title, a short excerpt and the cover image of the post. Sends to the full post by the button.",
"width": 1248, "width": 1248,
"height": 1504, "height": 1504,
"widthFull": 1440, "widthFull": 1440,
@@ -424,16 +424,16 @@
"heightFull": 2096 "heightFull": 2096
}, },
"promotions": { "promotions": {
"descriptionShort": "", "descriptionShort": "Email template with a list of promotions",
"descriptionLong": "", "descriptionLong": "Allows to present several ongoing promotions in a single email. Shows each offer with its own image, description and expiry date. Sends directly to the store by the button for each offer.",
"width": 1248, "width": 1248,
"height": 3058, "height": 3058,
"widthFull": 1440, "widthFull": 1440,
"heightFull": 3812 "heightFull": 3812
}, },
"promotions-2": { "promotions-2": {
"descriptionShort": "", "descriptionShort": "Email template with a featured promotion",
"descriptionLong": "", "descriptionLong": "Allows to highlight one main promotion with a large image and short description. Shows the discount and the expiry date of the offer. Sends directly to the store by the button.",
"width": 1248, "width": 1248,
"height": 1626, "height": 1626,
"widthFull": 1440, "widthFull": 1440,
@@ -464,8 +464,8 @@
"heightFull": 3358 "heightFull": 3358
}, },
"review": { "review": {
"descriptionShort": "", "descriptionShort": "Email template asking for a review",
"descriptionLong": "", "descriptionLong": "Allows to ask the user to leave a review after a purchase or an interaction. Shows the product or service along with a star rating widget. Sends to the review form by the button.",
"width": 1248, "width": 1248,
"height": 1340, "height": 1340,
"widthFull": 1440, "widthFull": 1440,
@@ -488,8 +488,8 @@
"heightFull": 2522 "heightFull": 2522
}, },
"security-alert": { "security-alert": {
"descriptionShort": "", "descriptionShort": "Email template with a security alert",
"descriptionLong": "", "descriptionLong": "Allows to warn the user about a suspicious sign-in attempt or account activity. Shows the device, location and time of the activity. Sends directly to the security settings by the button to secure the account.",
"width": 1248, "width": 1248,
"height": 1272, "height": 1272,
"widthFull": 1440, "widthFull": 1440,
@@ -544,8 +544,8 @@
"heightFull": 2750 "heightFull": 2750
}, },
"survey-emoji": { "survey-emoji": {
"descriptionShort": "", "descriptionShort": "Email template with an emoji survey",
"descriptionLong": "", "descriptionLong": "Allows to collect quick feedback using a row of emoji ratings. Shows a short question above the emoji options. Sends the response directly by clicking on an emoji.",
"width": 1248, "width": 1248,
"height": 1834, "height": 1834,
"widthFull": 1440, "widthFull": 1440,
@@ -592,8 +592,8 @@
"heightFull": 3114 "heightFull": 3114
}, },
"uptime-report": { "uptime-report": {
"descriptionShort": "", "descriptionShort": "Email template with an uptime report",
"descriptionLong": "", "descriptionLong": "Allows to summarize the uptime and incidents of a monitored service over a period. Shows the uptime percentage along with a short list of incidents. Sends to the full report by the button.",
"width": 1248, "width": 1248,
"height": 1750, "height": 1750,
"widthFull": 1440, "widthFull": 1440,
@@ -624,8 +624,8 @@
"heightFull": 3680 "heightFull": 3680
}, },
"welcome": { "welcome": {
"descriptionShort": "", "descriptionShort": "Email template welcoming a new user",
"descriptionLong": "", "descriptionLong": "Allows to greet a new user right after they sign up. Shows a short introduction to the product along with the first steps to get started. Sends to the dashboard by the button.",
"width": 1248, "width": 1248,
"height": 1484, "height": 1484,
"widthFull": 1440, "widthFull": 1440,
+1 -1
View File
@@ -130,7 +130,7 @@ const base = '..'
<div class="col-auto"> <div class="col-auto">
<ul class="list-inline list-inline-dots"> <ul class="list-inline list-inline-dots">
<li class="list-inline-item"> <li class="list-inline-item">
<a class="link-secondary" href="/terms-of-service">Terms of service</a> <a class="link-secondary" href="/terms-of-service.html">Terms of service</a>
</li> </li>
<li class="list-inline-item"> <li class="list-inline-item">
<a class="link-secondary" href="#">Privacy policy</a> <a class="link-secondary" href="#">Privacy policy</a>
+1 -1
View File
@@ -66,5 +66,5 @@ const classes = ['alert', variant && `alert-${variant}`, `alert-${color}`, showC
</Fragment> </Fragment>
) )
} }
{showClose && <a class="btn-close" data-bs-dismiss="alert" aria-label="close" />} {showClose && <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close" />}
</div> </div>
+5 -2
View File
@@ -15,6 +15,8 @@ interface Props {
/** person object (photo → src, initials → placeholder); resolve demo ids with personById() from @shared/lib/people */ /** person object (photo → src, initials → placeholder); resolve demo ids with personById() from @shared/lib/people */
person?: Person | undefined person?: Person | undefined
link?: boolean link?: boolean
/** href for the linked avatar (link); defaults to "#" when omitted */
href?: string
size?: AvatarSize | undefined size?: AvatarSize | undefined
class?: string class?: string
/** avatar-{shape} (core/scss/ui/_avatars.scss) */ /** avatar-{shape} (core/scss/ui/_avatars.scss) */
@@ -30,7 +32,7 @@ interface Props {
[key: string]: unknown [key: string]: unknown
} }
const { src: srcProp, placeholder: placeholderProp, person, link: linkProp = false, size, class: className, shape, color, status, statusLabel, brand, icon, base = assetRoot, ...rest } = Astro.props const { src: srcProp, placeholder: placeholderProp, person, link: linkProp = false, href: hrefProp, size, class: className, shape, color, status, statusLabel, brand, icon, base = assetRoot, ...rest } = Astro.props
let src = srcProp let src = srcProp
let placeholder = placeholderProp let placeholder = placeholderProp
@@ -43,10 +45,11 @@ if (person) {
} }
const El = linkProp ? 'a' : 'span' const El = linkProp ? 'a' : 'span'
const linkAttrs = linkProp ? { href: hrefProp ?? '#' } : {}
const classes = ['avatar', size && `avatar-${size}`, className, shape && `avatar-${shape}`, color && `bg-${color}-lt`] const classes = ['avatar', size && `avatar-${size}`, className, shape && `avatar-${shape}`, color && `bg-${color}-lt`]
--- ---
<El class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} {...rest} <El {...linkAttrs} class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} {...rest}
>{status && <span class={`badge bg-${status}`} aria-label={statusLabel ?? status} />}{brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />}{src ? null : placeholder ? placeholder : icon ? <Icon name={icon} /> : <Icon name="user" />}</El >{status && <span class={`badge bg-${status}`} aria-label={statusLabel ?? status} />}{brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />}{src ? null : placeholder ? placeholder : icon ? <Icon name={icon} /> : <Icon name="user" />}</El
> >
+4 -2
View File
@@ -9,9 +9,11 @@ interface Props {
color?: string color?: string
size?: IconSize | undefined size?: IconSize | undefined
value?: number value?: number
/** accessible name for the underlying select; defaults to "Rating" */
label?: string
} }
const { id, icon = 'star', color, size, value } = Astro.props const { id, icon = 'star', color, size, value, label = 'Rating' } = Astro.props
const starClasses = ['icon', 'gl-star-full', color && `text-${color}`, size && `icon-${size}`].filter(Boolean).join(' ') const starClasses = ['icon', 'gl-star-full', color && `text-${color}`, size && `icon-${size}`].filter(Boolean).join(' ')
@@ -21,7 +23,7 @@ const ratingSelector = `#rating-${id}`
const ratingKey = `rating-${id}` const ratingKey = `rating-${id}`
--- ---
<select id={`rating-${id}`}> <select id={`rating-${id}`} aria-label={label}>
<option value="">Select a rating</option> <option value="">Select a rating</option>
<option value="5" selected={value === 5}>Excellent</option> <option value="5" selected={value === 5}>Excellent</option>
<option value="4" selected={value === 4}>Very Good</option> <option value="4" selected={value === 4}>Very Good</option>
+1 -1
View File
@@ -37,7 +37,7 @@ const { text, flag, icon, person, status, legend, checkbox, checked, badge, clas
) : legend ? ( ) : legend ? (
<span class={`legend-dot bg-${legend}`} /> <span class={`legend-dot bg-${legend}`} />
) : checkbox ? ( ) : checkbox ? (
<input type="checkbox" class="form-check-input tag-check" checked={checked} /> <input type="checkbox" class="form-check-input tag-check" checked={checked} aria-label={text} />
) : null ) : null
} }
{text} {text}
+1 -3
View File
@@ -8,9 +8,7 @@ const { id } = Astro.props
const selector = `#hugerte-${id}` const selector = `#hugerte-${id}`
--- ---
<form method="post"> <textarea id={`hugerte-${id}`} set:html={'Hello, <b>Tabler</b>!'} />
<textarea id={`hugerte-${id}`} set:html={'Hello, <b>Tabler</b>!'} />
</form>
<CaptureScript> <CaptureScript>
<!-- BEGIN WYSIWYG --> <!-- BEGIN WYSIWYG -->
<script is:inline define:vars={{ selector }}> <script is:inline define:vars={{ selector }}>