Unify shared/ui props, split demo components, add SCSS-driven tokens (#2872)

This commit is contained in:
Paweł Kuna
2026-08-14 01:16:54 +02:00
committed by GitHub
parent f11ece4b94
commit 87047250c0
210 changed files with 1885 additions and 948 deletions
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env node
// Generates shared/lib/tokens.ts from the core SCSS maps, so the TS
// unions used by components can never drift from the stylesheet source of
// truth. Values are read through the real Sass compiler (after every merge and
// !default), not by parsing the source text.
// Run: pnpm run generate-tokens — (re)write the file
// pnpm run generate-tokens:check — fail when the committed file is stale
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
import { join, dirname, relative } from 'node:path'
import { fileURLToPath } from 'node:url'
import { compileString } from 'sass'
import { format, resolveConfig } from 'prettier'
const __dirname = dirname(fileURLToPath(import.meta.url))
const repoRoot = join(__dirname, '..')
const scssDir = join(repoRoot, 'core', 'scss')
const outFile = join(repoRoot, 'shared', 'lib', 'tokens.ts')
const mode = process.argv[2] === 'check' ? 'check' : 'generate'
// One entry per generated const/type; `source` is the Sass member the keys come
// from — `kind: 'map'` reads map.keys(), `kind: 'list'` reads the list itself.
const TOKENS = [
{ name: 'themeColors', type: 'ThemeColor', module: 'v', variable: '$theme-colors', kind: 'map', source: 'core/scss/_variables.scss' },
{ name: 'socialColors', type: 'SocialColor', module: 'v', variable: '$social-colors', kind: 'map', source: 'core/scss/_variables.scss' },
{ name: 'avatarSizes', type: 'AvatarSize', module: 'v', variable: '$avatar-sizes', kind: 'map', source: 'core/scss/_variables.scss' },
{ name: 'aspectRatios', type: 'AspectRatio', module: 'v', variable: '$aspect-ratios', kind: 'map', source: 'core/scss/_variables.scss' },
{ name: 'breakpoints', type: 'Breakpoint', module: 's', variable: '$grid-breakpoints', kind: 'map', source: 'core/scss/_settings.scss' },
{ name: 'breadcrumbVariants', type: 'BreadcrumbVariant', module: 'v', variable: '$breadcrumb-variants', kind: 'map', source: 'core/scss/_variables.scss' },
{ name: 'formValidationStates', type: 'FormValidationState', module: 'v', variable: '$form-validation-states', kind: 'map', source: 'core/scss/_variables.scss' },
{ name: 'paymentProviders', type: 'PaymentProvider', module: 'v', variable: '$payment-providers', kind: 'list', source: 'core/scss/_variables.scss' },
{ name: 'flagCountries', type: 'FlagCountry', module: 'v', variable: '$flag-countries', kind: 'list', source: 'core/scss/_variables.scss' },
{ name: 'patternSizes', type: 'PatternSize', module: 'p', variable: '$sizes', kind: 'map', source: 'core/scss/ui/_patterns.scss' },
] as const
const entry = `
@use 'sass:map';
@use 'variables' as v;
@use 'settings' as s;
@use 'ui/patterns' as p;
${TOKENS.map((t) => `@debug 'TOKEN ${t.name}=#{${t.kind === 'map' ? `map.keys(${t.module}.${t.variable})` : `${t.module}.${t.variable}`}}';`).join('\n')}
`
const keysByName = new Map<string, string[]>()
compileString(entry, {
loadPaths: [scssDir],
logger: {
debug(message) {
const match = message.match(/^TOKEN (\w+)=(.*)$/)
if (match?.[1] && match[2] !== undefined) {
keysByName.set(
match[1],
match[2].split(',').map((key) => key.trim()),
)
}
},
warn() {
/* deprecations from core scss are handled by the css build, not here */
},
},
})
let output = `// Generated from the core SCSS maps by .build/generate-tokens.ts — DO NOT EDIT.
// Regenerate with: pnpm run generate-tokens
`
for (const token of TOKENS) {
const keys = keysByName.get(token.name)
if (!keys || keys.length === 0) {
console.error(`✖ No keys extracted for ${token.variable} (${token.name}) — check the sass entry.`)
process.exit(1)
}
output += `
/** Keys of \`${token.variable}\` (${token.source}). */
export const ${token.name} = [${keys.map((key) => `'${key}'`).join(', ')}] as const
export type ${token.type} = (typeof ${token.name})[number]
`
}
// Wrapped in main() because the root package is CJS (no top-level await).
const main = async () => {
// Format with the repo prettier config so the generated file passes lint-prettier.
const prettierConfig = await resolveConfig(outFile)
const formatted = await format(output, { ...prettierConfig, filepath: outFile })
if (mode === 'check') {
const current = existsSync(outFile) ? readFileSync(outFile, 'utf8') : ''
if (current !== formatted) {
console.error(`${relative(repoRoot, outFile)} is stale — run "pnpm run generate-tokens" and commit the result.`)
process.exit(1)
}
console.log(`${relative(repoRoot, outFile)} is up to date.`)
} else {
writeFileSync(outFile, formatted)
console.log(`✓ Generated ${relative(repoRoot, outFile)} (${TOKENS.map((t) => t.name).join(', ')}).`)
}
}
main()
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env node
// Renders every preview page from a running dev server and compares the HTML
// against a stored baseline, so internal refactors can prove they don't change
// the rendered output at all. Volatile content (the "Generated <date>" footer)
// is normalized away before comparing.
// Run: pnpm run html-diff:baseline — capture baseline snapshots (before refactoring)
// pnpm run html-diff — re-render and diff against the baseline
// The dev server defaults to http://localhost:3000; override with HTML_DIFF_BASE.
import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from 'node:fs'
import { join, dirname, relative } from 'node:path'
import { fileURLToPath } from 'node:url'
import { sync } from 'glob'
const __dirname = dirname(fileURLToPath(import.meta.url))
const repoRoot = join(__dirname, '..')
const pagesDir = join(repoRoot, 'preview', 'pages')
const snapshotDir = join(repoRoot, '.cache', 'html-diff')
const baseUrl = process.env.HTML_DIFF_BASE ?? 'http://localhost:3000'
const mode = process.argv[2] === 'baseline' ? 'baseline' : 'check'
// ---------------------------------------------------------------------------
// Route table: every preview page url, keyed by its snapshot file name.
// ---------------------------------------------------------------------------
const routes = new Map<string, string>()
for (const file of sync(join(pagesDir, '**', '*.astro'))) {
if (file.includes('[')) continue // dynamic routes have no single url
const url =
'/' +
relative(pagesDir, file)
.replace(/\/?index\.astro$/, '')
.replace(/\.astro$/, '')
routes.set((url === '/' ? 'index' : url.slice(1)).replaceAll('/', '_') + '.html', url)
}
// The footer stamps the render time into every page — meaningless for diffing.
const normalize = (html: string) => html.replace(/Generated \d{4}[^<]*/g, 'Generated')
const fetchPage = async (url: string): Promise<string> => {
const response = await fetch(baseUrl + url)
if (!response.ok) throw new Error(`${response.status} ${baseUrl + url}`)
return normalize(await response.text())
}
// Render with a small worker pool — the dev server compiles pages on demand.
// Wrapped in main() because the root package is CJS (no top-level await).
const CONCURRENCY = 8
const main = async () => {
const entries = [...routes.entries()]
const failures: string[] = []
const pages = new Map<string, string>()
let cursor = 0
await Promise.all(
Array.from({ length: CONCURRENCY }, async () => {
while (cursor < entries.length) {
const entry = entries[cursor++]
if (!entry) break
const [name, url] = entry
try {
pages.set(name, await fetchPage(url))
} catch (error) {
failures.push(`${url}${error instanceof Error ? error.message : error}`)
}
}
}),
)
if (failures.length > 0) {
console.error(`${failures.length} page(s) failed to render (is the dev server running at ${baseUrl}?):`)
for (const failure of failures) console.error(` ${failure}`)
process.exit(1)
}
if (mode === 'baseline') {
rmSync(snapshotDir, { recursive: true, force: true })
mkdirSync(snapshotDir, { recursive: true })
for (const [name, html] of pages) writeFileSync(join(snapshotDir, name), html)
console.log(`✓ Baseline captured: ${pages.size} pages → ${relative(repoRoot, snapshotDir)}`)
return
}
if (!existsSync(snapshotDir)) {
console.error(`✖ No baseline found in ${relative(repoRoot, snapshotDir)} — run "pnpm run html-diff:baseline" first.`)
process.exit(1)
}
// Compare against the baseline; report the first differing line per page.
let differing = 0
for (const [name, html] of pages) {
const baselineFile = join(snapshotDir, name)
if (!existsSync(baselineFile)) {
console.error(`± ${name}: new page (no baseline snapshot)`)
differing++
continue
}
const baseline = readFileSync(baselineFile, 'utf8')
if (baseline === html) continue
differing++
// Classify: inter-tag whitespace reshuffles are usually visually inert
// (flex containers, select internals) — but review inline contexts manually.
const squash = (s: string) => s.replace(/>\s+</g, '><').replace(/\s+/g, ' ')
if (squash(baseline) === squash(html)) {
console.error(`± ${name}: WHITESPACE-ONLY difference (identical after normalization — verify inline contexts)`)
continue
}
const baselineLines = baseline.split('\n')
const currentLines = html.split('\n')
// findIndex misses the case where one side is a strict prefix of the other
// (lines appended/removed at the end) — point at the first extra line then.
let line = baselineLines.findIndex((l, i) => l !== currentLines[i])
if (line === -1) line = Math.min(baselineLines.length, currentLines.length)
console.error(`± ${name}: differs at line ${line + 1}`)
console.error(` - ${(baselineLines[line] ?? '<missing>').trim().slice(0, 160)}`)
console.error(` + ${(currentLines[line] ?? '<missing>').trim().slice(0, 160)}`)
}
for (const name of sync(join(snapshotDir, '*.html'))) {
const snapshotName = relative(snapshotDir, name)
if (!pages.has(snapshotName)) {
console.error(`± ${snapshotName}: page removed (baseline snapshot has no live page)`)
differing++
}
}
if (differing > 0) {
console.error(`${differing} of ${pages.size} pages differ from the baseline.`)
process.exit(1)
}
console.log(`✓ All ${pages.size} pages are byte-identical to the baseline.`)
}
main()
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/preview": patch
---
Fixed root-absolute `Button` hrefs in demos, so error-page links work in the downloadable package.
+6
View File
@@ -0,0 +1,6 @@
---
"@tabler/preview": patch
"@tabler/docs": patch
---
Updated preview and docs examples to the unified demo component props: `variant`, `color`, `size`, `ariaLabel`.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/preview": patch
---
Fixed icon-only demo buttons rendering a generic `aria-label="Button"` instead of a real label.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/preview": patch
---
Updated the marketing CTA `Learn more` button to the `.btn-ghost` style.
+3
View File
@@ -35,3 +35,6 @@ jobs:
- name: Run JS tests
run: pnpm --filter @tabler/core test:js
- name: Run shared lib tests
run: pnpm --filter @tabler/shared test
+1 -1
View File
@@ -34,7 +34,7 @@ node_modules/
.turbo
package-lock.json
demo/
/core/demo/
dist/
packages-zip/
.env
+16 -8
View File
@@ -36,14 +36,22 @@ Do not edit `dist/` folders — they are generated by the build.
## Useful commands
| Command | What it does |
| -------------------- | ----------------------------------------------------- |
| `pnpm run dev` | Start preview and docs dev servers with live reload |
| `pnpm run build` | Production build of all packages |
| `pnpm run lint` | Markdown, Prettier and SCSS variable checks |
| `pnpm run lint:fix` | Auto-fix lint issues where possible |
| `pnpm run test` | Run the test suites |
| `pnpm run check` | Lint plus TypeScript type checks |
| Command | What it does |
| ----------------------------- | ------------------------------------------------------------ |
| `pnpm run dev` | Start preview and docs dev servers with live reload |
| `pnpm run build` | Production build of all packages |
| `pnpm run lint` | Markdown, Prettier, SCSS variable and generated-token checks |
| `pnpm run lint:fix` | Auto-fix lint issues where possible |
| `pnpm run test` | Run the test suites |
| `pnpm run check` | Lint plus TypeScript type checks |
| `pnpm run html-diff:baseline` | Snapshot all rendered preview pages (needs the dev server) |
| `pnpm run html-diff` | Byte-compare rendered preview pages against the snapshot |
| `pnpm run generate-tokens` | Regenerate `shared/lib/tokens.ts` from the core SCSS maps |
Two of these help with refactors:
- **`html-diff`** proves a refactor does not change the rendered demo HTML: run `html-diff:baseline` before your change, refactor, then `html-diff` — it reports the first differing line per page and marks whitespace-only differences.
- **`generate-tokens`** keeps the TS unions in `shared/lib/tokens.ts` in sync with the SCSS maps (colors, sizes, breakpoints, payment providers, flags). Edit the SCSS map, regenerate, commit both — a stale file fails `pnpm run lint`.
## Before you open a pull request
+3 -3
View File
@@ -17,7 +17,7 @@ Combine `alert` class with one of the following: `alert-success`, `alert-info`,
Alert classes affect the color of all the text inside an alert. Use another class, e.g. `text-secondary` to change the color of the alert's content.
<Example>
<Alert type="success" title="Wow! Everything worked!" description="Your account has been saved!" /> <Alert type="info" title="Did you know?" description="Here is something that you might like to know." /> <Alert type="warning" title="Uh oh, something went wrong" description="Sorry! There was a problem with your request." /> <Alert type="danger" title={"I'm so sorry&hellip;"} description="Your account has been deleted and can't be restored." />
<Alert color="success" title="Wow! Everything worked!" description="Your account has been saved!" /> <Alert color="info" title="Did you know?" description="Here is something that you might like to know." /> <Alert color="warning" title="Uh oh, something went wrong" description="Sorry! There was a problem with your request." /> <Alert color="danger" title={"I'm so sorry&hellip;"} description="Your account has been deleted and can't be restored." />
</Example>
## Alert links
@@ -25,7 +25,7 @@ Alert classes affect the color of all the text inside an alert. Use another clas
Add a link to your alert message to redirect users to the details they need to complete or additional information they should read. Use `alert-link` class to style the link and match the text color.
<Example>
<Alert type="danger" title="This is a danger alert" link="check it out" />
<Alert color="danger" title="This is a danger alert" link="check it out" />
</Example>
## Dismissible alerts
@@ -37,7 +37,7 @@ Add the `x` close button to make an alert modal dismissible. Thanks to that, you
```
<Example>
<Alert type="danger" title="This is a danger alert" showClose />
<Alert color="danger" title="This is a danger alert" showClose />
</Example>
## Alerts with icons
+2 -2
View File
@@ -74,7 +74,7 @@ You can use [icons](/ui/components/icon) in badges to make them more visually ap
You can also use an icon on the right side of the badge. The example below demonstrates how to use icons on the right side of badges.
<Example centered>
<BadgeList><Badge text="Star" icon-end="arrow-right" /> <Badge text="Heart" icon-end="arrow-right" /> <Badge text="Check" icon-end="arrow-right" /> <Badge text="X" icon-end="arrow-right" /> <Badge text="Plus" icon-end="arrow-right" /> <Badge text="Minus" icon-end="arrow-right" /></BadgeList>
<BadgeList><Badge text="Star" iconEnd="arrow-right" /> <Badge text="Heart" iconEnd="arrow-right" /> <Badge text="Check" iconEnd="arrow-right" /> <Badge text="X" iconEnd="arrow-right" /> <Badge text="Plus" iconEnd="arrow-right" /> <Badge text="Minus" iconEnd="arrow-right" /></BadgeList>
</Example>
## Links
@@ -108,7 +108,7 @@ You can use the `.badge-blink` class to create a blinking effect. This class wil
Use `.badge-sm` or `.badge-lg` to change badge size according to your needs. The default size is `.badge` and it is used in the examples above.
<Example centered vertical>
<BadgeList> <Badge color="primary" scale="sm" text="New" class="badge-sm" /> <Badge color="primary" scale="sm" text="1" class="badge-pill" /> </BadgeList> <BadgeList> <Badge color="primary" text="New" class="badge-sm" /> <Badge color="primary" text="1" class="badge-pill" /> </BadgeList> <BadgeList> <Badge color="primary" scale="lg" text="New" class="badge-sm" /> <Badge color="primary" scale="lg" text="1" class="badge-pill" /> </BadgeList>
<BadgeList> <Badge color="primary" size="sm" text="New" class="badge-sm" /> <Badge color="primary" size="sm" text="1" class="badge-pill" /> </BadgeList> <BadgeList> <Badge color="primary" text="New" class="badge-sm" /> <Badge color="primary" text="1" class="badge-pill" /> </BadgeList> <BadgeList> <Badge color="primary" size="lg" text="New" class="badge-sm" /> <Badge color="primary" size="lg" text="1" class="badge-pill" /> </BadgeList>
</Example>
+1 -1
View File
@@ -34,7 +34,7 @@ This example shows how to use different breadcrumb styles.
You can use [icons](/ui/components/icon) in breadcrumbs to make them more visually appealing. The example below demonstrates how to use icons in breadcrumbs.
<Example vertical separated>
<Breadcrumb pages={['Home', 'Library', 'Data']} home-icon />
<Breadcrumb pages={['Home', 'Library', 'Data']} homeIcon />
</Example>
## Muted breadcrumbs
+7 -7
View File
@@ -7,7 +7,7 @@ related: [/ui/components/countup, /ui/components/trending]
---
import Example from '@components/Example.astro'
import Chart from '@ui/Chart.astro'
import Chart from '@shared/components/demo/Chart.astro'
import CodeDocs from '@components/CodeDocs.astro';
To be able to use the charts in your application you will need to install the apexcharts dependency with `npm install apexcharts`.
@@ -21,7 +21,7 @@ Line charts are an essential tool for visualizing data trends over time. They ar
<Example>
<div class="card">
<div class="card-body">
<Chart chartId="demo-line" legend height={15} />
<Chart chartId="demo-line" label="Line chart example" height={15} />
</div>
</div>
</Example>
@@ -33,7 +33,7 @@ Area charts are ideal for representing cumulative data over time. They add visua
<Example>
<div class="card">
<div class="card-body">
<Chart chartId="demo-area" height={15} />
<Chart chartId="demo-area" label="Area chart example" height={15} />
</div>
</div>
</Example>
@@ -45,7 +45,7 @@ Bar charts are highly effective for comparing data across different categories.
<Example>
<div class="card">
<div class="card-body">
<Chart chartId="demo-bar" height={15} />
<Chart chartId="demo-bar" label="Bar chart example" height={15} />
</div>
</div>
</Example>
@@ -57,7 +57,7 @@ Pie charts are a simple and effective way to visualize proportions and ratios. T
<Example>
<div class="card">
<div class="card-body">
<Chart chartId="demo-pie" height={15} />
<Chart chartId="demo-pie" label="Pie chart example" height={15} />
</div>
</div>
</Example>
@@ -69,7 +69,7 @@ Heatmaps provide a graphical representation of data where individual values are
<Example>
<div class="card">
<div class="card-body">
<Chart chartId="demo-heatmap" height={15} />
<Chart chartId="demo-heatmap" label="Heatmap chart example" height={15} />
</div>
</div>
</Example>
@@ -81,7 +81,7 @@ For more complex data visualizations, you can create advanced charts with multip
<Example>
<div class="card">
<div class="card-body">
<Chart chartId="social-referrals" height={15} />
<Chart chartId="social-referrals" label="Social referrals chart" height={15} />
</div>
</div>
</Example>
+2 -2
View File
@@ -28,7 +28,7 @@ Results can be seen in the example below.
To use filled icons, you need to copy the SVG code of the selected filled Icon from the [Tabler Icons website](https://tabler.io/icons) and paste it into your HTML file.
<Example>
<Icon name="heart" type="filled" /> <Icon name="bell-ringing" type="filled" /> <Icon name="cherry" type="filled" /> <Icon name="circle-key" type="filled" />
<Icon name="heart" filled /> <Icon name="bell-ringing" filled /> <Icon name="cherry" filled /> <Icon name="circle-key" filled />
</Example>
## Icon colors
@@ -44,7 +44,7 @@ To change the color of the icon, you need to add the `text-*` class to the paren
Look at the example below to see how the color of the icon changes.
<Example>
<span class="text-red"> <Icon name="heart" type="filled" /> </span> <span class="text-yellow"> <Icon name="star" type="filled" /> </span> <span class="text-blue"> <Icon name="circle" /> </span> <span class="text-green"> <Icon name="square-rounded" /> </span>
<span class="text-red"> <Icon name="heart" filled /> </span> <span class="text-yellow"> <Icon name="star" filled /> </span> <span class="text-blue"> <Icon name="circle" /> </span> <span class="text-green"> <Icon name="square-rounded" /> </span>
</Example>
## Icon animations
+6 -6
View File
@@ -13,7 +13,7 @@ import CodeDocs from '@components/CodeDocs.astro';
Use slightly customized pagination with previous and next icon links:
<Example centered vertical>
<Pagination />
<Pagination count={5} activeItem={3} />
</Example>
## With first and last links
@@ -21,7 +21,7 @@ Use slightly customized pagination with previous and next icon links:
When you have a lot of pages, you can use first and last links to quickly navigate to the beginning or end of the pagination.
<Example centered vertical>
<Pagination firstLast />
<Pagination count={5} activeItem={3} firstLast />
</Example>
## Offset
@@ -29,7 +29,7 @@ When you have a lot of pages, you can use first and last links to quickly naviga
If the count of pages is too large, you can use offset to show only a few pages at a time.
<Example centered vertical>
<Pagination offset={3} count={20} />
<Pagination offset={3} count={20} activeItem={3} />
</Example>
## Button with text
@@ -37,7 +37,7 @@ If the count of pages is too large, you can use offset to show only a few pages
When you want to use pagination with text, you can use text buttons. This will give you a more traditional look and feel, which is great for applications where you want to keep the focus on the content rather than the navigation.
<Example centered vertical>
<Pagination text />
<Pagination count={5} activeItem={3} text />
</Example>
## Outline version
@@ -45,7 +45,7 @@ When you want to use pagination with text, you can use text buttons. This will g
If you want to use an outline version of the pagination, you can use the `.pagination-outline` class. This will give you a more subtle look and feel, which is great for applications where you want to keep the focus on the content rather than the navigation.
<Example centered vertical>
<Pagination class="pagination-outline" />
<Pagination count={5} activeItem={3} class="pagination-outline" />
</Example>
## Circle version
@@ -53,7 +53,7 @@ If you want to use an outline version of the pagination, you can use the `.pagin
If you want to use a circle version of the pagination, you can use the `.pagination-circle` class. This will give you a more subtle look and feel, which is great for applications where you want to keep the focus on the content rather than the navigation. This can also be combined with the `.pagination-outline` class for a more prominent look.
<Example centered vertical separated>
<Pagination class="pagination-circle" /> <Pagination class="pagination-circle pagination-outline" />
<Pagination count={5} activeItem={3} class="pagination-circle" /> <Pagination count={5} activeItem={3} class="pagination-circle pagination-outline" />
</Example>
## SCSS variables
+2 -2
View File
@@ -112,7 +112,7 @@ page, the progress bar could gradually fill up, creating a sense of momentum and
Thanks to this you can create a nice looking statistics section:
<Example columnFullWidth>
<ProgressBg value="65" text="Poland" showValue true /> <ProgressBg value="35" text="Germany" showValue true /> <ProgressBg value="28" text="United States" showValue true /> <ProgressBg value="20" text="United Kingdom" showValue true /> <ProgressBg value="15" text="France" showValue true />
<ProgressBg value={65} text="Poland" showValue /> <ProgressBg value={35} text="Germany" showValue /> <ProgressBg value={28} text="United States" showValue /> <ProgressBg value={20} text="United Kingdom" showValue /> <ProgressBg value={15} text="France" showValue />
</Example>
## Progress background colors
@@ -120,7 +120,7 @@ Thanks to this you can create a nice looking statistics section:
You can combine progress background with contextual light colors to better separate categories.
<Example columnFullWidth>
<ProgressBg value="75" text="Success" color="success-lt" showValue true /> <ProgressBg value="60" text="Warning" color="warning-lt" showValue true /> <ProgressBg value="40" text="Danger" color="danger-lt" showValue true /> <ProgressBg value="90" text="Info" color="info-lt" showValue true />
<ProgressBg value={75} text="Success" color="success" showValue /> <ProgressBg value={60} text="Warning" color="warning" showValue /> <ProgressBg value={40} text="Danger" color="danger" showValue /> <ProgressBg value={90} text="Info" color="info" showValue />
</Example>
## SCSS variables
+5 -5
View File
@@ -13,7 +13,7 @@ Use `.stars` as the container and `.star` for each icon.
This creates an inline star row with spacing and base color.
<Example centered>
<div class="stars"> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star"><Icon name="star" type="filled" /></span> </div>
<div class="stars"> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star"><Icon name="star" filled /></span> </div>
</Example>
## Variants
@@ -24,7 +24,7 @@ Use `.stars` for read-only values in lists and cards.
Color only the active stars and keep the rest in default color.
<Example>
<div class="space-y"> <div class="d-flex justify-content-between align-items-center"> <span>Product quality</span> <div class="stars"> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> </div> </div> <div class="d-flex justify-content-between align-items-center"> <span>Delivery speed</span> <div class="stars"> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star"><Icon name="star" type="filled" /></span> <span class="star"><Icon name="star" type="filled" /></span> </div> </div> </div>
<div class="space-y"> <div class="d-flex justify-content-between align-items-center"> <span>Product quality</span> <div class="stars"> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> </div> </div> <div class="d-flex justify-content-between align-items-center"> <span>Delivery speed</span> <div class="stars"> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star"><Icon name="star" filled /></span> <span class="star"><Icon name="star" filled /></span> </div> </div> </div>
</Example>
### Data-star-rating states
@@ -33,7 +33,7 @@ The vendor styles also target `[data-star-rating]`.
Use `.gl-active` and `.gl-star-full` to control active and inactive star color.
<Example centered>
<div data-star-rating class="d-flex gap-1" style="--tblr-icon-size: 1.25rem;"> <span class="gl-active"><Icon name="star" type="filled" class="gl-star-full" /></span> <span class="gl-active"><Icon name="star" type="filled" class="gl-star-full" /></span> <span class="gl-active"><Icon name="star" type="filled" class="gl-star-full" /></span> <span><Icon name="star" type="filled" class="gl-star-full" /></span> <span><Icon name="star" type="filled" class="gl-star-full" /></span> </div>
<div data-star-rating class="d-flex gap-1" style="--tblr-icon-size: 1.25rem;"> <span class="gl-active"><Icon name="star" filled class="gl-star-full" /></span> <span class="gl-active"><Icon name="star" filled class="gl-star-full" /></span> <span class="gl-active"><Icon name="star" filled class="gl-star-full" /></span> <span><Icon name="star" filled class="gl-star-full" /></span> <span><Icon name="star" filled class="gl-star-full" /></span> </div>
</Example>
### Custom rating colors
@@ -42,7 +42,7 @@ Use CSS custom properties from vendor styles to change star colors.
You can set active and inactive colors per instance.
<Example centered>
<div data-star-rating class="d-flex gap-1" style="--gl-star-color: var(--tblr-red); --gl-star-color-inactive: var(--tblr-border-color); --tblr-icon-size: 1.25rem;"> <span class="gl-active"><Icon name="heart" type="filled" class="gl-star-full" /></span> <span class="gl-active"><Icon name="heart" type="filled" class="gl-star-full" /></span> <span class="gl-active"><Icon name="heart" type="filled" class="gl-star-full" /></span> <span><Icon name="heart" type="filled" class="gl-star-full" /></span> <span><Icon name="heart" type="filled" class="gl-star-full" /></span> </div>
<div data-star-rating class="d-flex gap-1" style="--gl-star-color: var(--tblr-red); --gl-star-color-inactive: var(--tblr-border-color); --tblr-icon-size: 1.25rem;"> <span class="gl-active"><Icon name="heart" filled class="gl-star-full" /></span> <span class="gl-active"><Icon name="heart" filled class="gl-star-full" /></span> <span class="gl-active"><Icon name="heart" filled class="gl-star-full" /></span> <span><Icon name="heart" filled class="gl-star-full" /></span> <span><Icon name="heart" filled class="gl-star-full" /></span> </div>
</Example>
## Examples
@@ -53,7 +53,7 @@ Combine stars with text to show score and vote count.
This pattern works for cards, reviews, and product lists.
<Example centered>
<div class="d-flex align-items-center gap-2"> <div class="stars"> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star text-yellow"><Icon name="star" type="filled" /></span> <span class="star"><Icon name="star" type="filled" /></span> </div> <span class="text-secondary">4.0 (128 reviews)</span> </div>
<div class="d-flex align-items-center gap-2"> <div class="stars"> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star text-yellow"><Icon name="star" filled /></span> <span class="star"><Icon name="star" filled /></span> </div> <span class="text-secondary">4.0 (128 reviews)</span> </div>
</Example>
## Accessibility
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -35,7 +35,7 @@ Use `.tag-icon` for a leading icon inside a tag. The icon uses compact size and
Use `.tag-avatar`, `.tag-flag`, or `.tag-payment` to add media at the start of the tag. These classes keep spacing aligned with tag content.
<Example centered>
<TagList> <span class="tag"> <span class="avatar avatar-xs tag-avatar">AP</span> Alex P. <a href="#" class="btn-close" aria-label="Remove Alex tag"></a> </span> <span class="tag"> <Flag flag="us" size="xxs" class="tag-flag" />United States <a href="#" class="btn-close" aria-label="Remove country tag"></a> </span> <span class="tag"> <Payment provider="visa" size="xxs" class="tag-payment" />Visa <a href="#" class="btn-close" aria-label="Remove payment tag"></a> </span> </TagList>
<TagList> <span class="tag"> <span class="avatar avatar-xs tag-avatar">AP</span> Alex P. <a href="#" class="btn-close" aria-label="Remove Alex tag"></a> </span> <span class="tag"> <Flag flag="us" size="xxs" class="tag-flag" />United States <a href="#" class="btn-close" aria-label="Remove country tag"></a> </span> <span class="tag"> <Payment payment="visa" size="xxs" class="tag-payment" />Visa <a href="#" class="btn-close" aria-label="Remove payment tag"></a> </span> </TagList>
</Example>
### With badge
+1 -1
View File
@@ -5,7 +5,7 @@ description: Visualize events in chronological order with a timeline. Add icons,
related: [/ui/components/step]
---
import Example from '@components/Example.astro';
import Timeline from '@ui/Timeline.astro';
import Timeline from '@shared/components/demo/Timeline.astro';
## Timeline
+1 -1
View File
@@ -7,7 +7,7 @@ related: [/ui/components/map]
---
import Example from '@components/Example.astro'
import MapVector from '@ui/MapVector.astro'
import MapVector from '@shared/components/demo/MapVector.astro'
import { Code } from 'astro:components'
import { site } from '@shared/lib/site.ts'
+1 -1
View File
@@ -16,5 +16,5 @@ import Wysiwyg from '@ui/Wysiwyg.astro'
Initialize HugeRTE on any element (or elements) on the web page by passing an object containing a selector value to `hugerte.init()`. The selector value can be any valid CSS selector.
<Example>
<Wysiwyg />
<Wysiwyg id="example" />
</Example>
+2 -1
View File
@@ -3,6 +3,7 @@
// Standalone layout with its own <head>; does NOT use BaseLayout.astro.
// Development uses the unminified assets; production additionally emits the SEO metadata.
import { site } from '@shared/lib/site';
import { isExternal } from '@shared/lib/url';
import libs from '@tabler/core/libs.json';
import docs from '@data/docs.json';
import Icon from '@ui/Icon.astro';
@@ -120,7 +121,7 @@ const editFilePath =
type Lib = { npm?: string; js?: string[]; css?: string[] };
const libEntries = Object.entries(libs as Record<string, Lib>);
const libUrl = (lib: Lib, file: string) =>
file.startsWith('http://') || file.startsWith('https://')
isExternal(file)
? file
: `/dist/libs/${lib.npm}/${file}`;
const docsLibCss = libEntries
+5 -1
View File
@@ -14,8 +14,12 @@
"version": "changeset version",
"publish": "changeset publish",
"reformat-md": "tsx .build/reformat-mdx.ts",
"html-diff": "tsx .build/html-diff.ts check",
"html-diff:baseline": "tsx .build/html-diff.ts baseline",
"generate-tokens": "tsx .build/generate-tokens.ts",
"generate-tokens:check": "tsx .build/generate-tokens.ts check",
"check-docs-links": "tsx .build/check-docs-links.ts",
"lint": "pnpm run lint-md && pnpm run check-docs-links && pnpm run lint-prettier && pnpm run lint-scss-vars",
"lint": "pnpm run lint-md && pnpm run check-docs-links && pnpm run lint-prettier && pnpm run lint-scss-vars && pnpm run generate-tokens:check",
"lint:fix": "(pnpm run lint-md-fix || true) && (pnpm run lint:scss:fix || true) && (pnpm run format-prettier || true)",
"lint:scss": "pnpm --filter @tabler/core lint:scss",
"lint:scss:fix": "pnpm --filter @tabler/core lint:scss:fix",
+3 -3
View File
@@ -1,6 +1,6 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Accordion from '@ui/Accordion.astro'
import Accordion from '@components/demo/Accordion.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import CardTitle from '@ui/CardTitle.astro'
@@ -17,7 +17,7 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Default</CardTitle>
<CardSubtitle>The base accordion — one panel open at a time.</CardSubtitle>
<Accordion />
<Accordion id="default" />
</CardBody>
</Card>
</div>
@@ -53,7 +53,7 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Inverted with plus icon</CardTitle>
<CardSubtitle>Combine <code>inverted</code> with a custom <code>toggleIcon</code>.</CardSubtitle>
<Accordion id="inverted-plus" type={['inverted', 'plus']} toggleIcon="plus" />
<Accordion id="inverted-plus" type={['inverted']} toggleIcon="plus" />
</CardBody>
</Card>
</div>
+1 -1
View File
@@ -2,7 +2,7 @@
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import ActivityPart from '@ui/ActivityPart.astro'
import ActivityPart from '@components/demo/ActivityPart.astro'
---
<DefaultLayout title="Activity" pageMenu="extra.activity">
+24 -24
View File
@@ -17,10 +17,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Basic</CardTitle>
<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!" />
<Alert type="info" title="Just a quick note!" />
<Alert color="danger" title="An error occurred!" />
<Alert color="warning" title="Some information is missing!" />
<Alert color="success" title="Completed successfully!" />
<Alert color="info" title="Just a quick note!" />
</CardBody>
</Card>
</div>
@@ -29,10 +29,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>With action</CardTitle>
<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!" />
<Alert showClose action="Link" type="info" title="Just a quick note!" />
<Alert showClose action="Link" color="danger" title="An error occurred!" />
<Alert showClose action="Link" color="warning" title="Some information is missing!" />
<Alert showClose action="Link" color="success" title="Completed successfully!" />
<Alert showClose action="Link" color="info" title="Just a quick note!" />
</CardBody>
</Card>
</div>
@@ -41,10 +41,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Dismissible</CardTitle>
<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!" />
<Alert showClose type="info" title="Just a quick note!" />
<Alert showClose color="danger" title="An error occurred!" />
<Alert showClose color="warning" title="Some information is missing!" />
<Alert showClose color="success" title="Completed successfully!" />
<Alert showClose color="info" title="Just a quick note!" />
</CardBody>
</Card>
</div>
@@ -53,10 +53,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>With a description</CardTitle>
<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." />
<Alert showClose type="info" title="Just a quick note!" description="This is a custom alert box with a description." />
<Alert showClose color="danger" title="Password does not meet requirements:" list={['Minimum 8 characters', 'Include a special character']} />
<Alert showClose color="warning" title="Some information is missing!" description="This is a custom alert box with a description." />
<Alert showClose color="success" title="Completed successfully!" description="This is a custom alert box with a description." />
<Alert showClose color="info" title="Just a quick note!" description="This is a custom alert box with a description." />
</CardBody>
</Card>
</div>
@@ -65,10 +65,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Important</CardTitle>
<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." />
<Alert showClose important type="info" description="This is a custom alert box with a description." />
<Alert showClose variant="important" color="danger" title="Password does not meet requirements:" list={['Minimum 8 characters', 'Include a special character']} />
<Alert showClose variant="important" color="success" title="This is a custom alert box!" description="This is a custom alert box with a description." />
<Alert showClose variant="important" color="warning" title="This is a custom alert box!" description="This is a custom alert box with a description." />
<Alert showClose variant="important" color="info" title="This is a custom alert box!" description="This is a custom alert box with a description." />
</CardBody>
</Card>
</div>
@@ -77,10 +77,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Minor</CardTitle>
<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." />
<Alert showClose minor type="info" description="This is a custom alert box with a description." />
<Alert showClose variant="minor" color="danger" title="Password does not meet requirements:" list={['Minimum 8 characters', 'Include a special character']} />
<Alert showClose variant="minor" color="success" title="This is a custom alert box!" description="This is a custom alert box with a description." />
<Alert showClose variant="minor" color="warning" title="This is a custom alert box!" description="This is a custom alert box with a description." />
<Alert showClose variant="minor" color="info" title="This is a custom alert box!" description="This is a custom alert box with a description." />
</CardBody>
</Card>
</div>
+40 -40
View File
@@ -14,22 +14,22 @@ import Alert from '@ui/Alert.astro'
import Badge from '@ui/Badge.astro'
import BadgeList from '@ui/BadgeList.astro'
import Progress from '@ui/Progress.astro'
import Select from '@ui/Select.astro'
import DataSelect from '@components/demo/DataSelect.astro'
import Check from '@ui/form/Check.astro'
import FormGroup from '@ui/FormGroup.astro'
import Nav from '@ui/Nav.astro'
import Nav from '@components/demo/Nav.astro'
import Breadcrumb from '@ui/Breadcrumb.astro'
import Pagination from '@ui/Pagination.astro'
import Avatar from '@ui/Avatar.astro'
import AvatarList from '@ui/AvatarList.astro'
import Icon from '@ui/Icon.astro'
import Dropdown from '@ui/Dropdown.astro'
import Accordion from '@ui/Accordion.astro'
import Dropdown from '@components/demo/Dropdown.astro'
import Accordion from '@components/demo/Accordion.astro'
import Spinner from '@ui/Spinner.astro'
import Rating from '@ui/Rating.astro'
import Steps from '@ui/Steps.astro'
import StatusDot from '@ui/StatusDot.astro'
import Toast from '@ui/Toast.astro'
import Toast from '@components/demo/Toast.astro'
import InputIcon from '@ui/form/InputIcon.astro'
import InputGroup from '@ui/InputGroup.astro'
import Range from '@ui/Range.astro'
@@ -38,7 +38,7 @@ import TagList from '@ui/TagList.astro'
import Ribbon from '@ui/Ribbon.astro'
import Flag from '@ui/Flag.astro'
import Payment from '@ui/Payment.astro'
import Timeline from '@ui/Timeline.astro'
import Timeline from '@components/demo/Timeline.astro'
import Empty from '@ui/Empty.astro'
import NavSegmented from '@ui/NavSegmented.astro'
import ListGroup from '@ui/ListGroup.astro'
@@ -130,9 +130,9 @@ function greetUser(name) {
<h4>Icon Buttons</h4>
<ButtonList class="mb-3 align-items-start">
<Button icon="heart" iconOnly />
<Button icon="star" iconOnly />
<Button icon="check" iconOnly />
<Button icon="heart" iconOnly text="Heart" />
<Button icon="star" iconOnly text="Star" />
<Button icon="check" iconOnly text="Check" />
</ButtonList>
</div>
</div>
@@ -170,10 +170,10 @@ function greetUser(name) {
<Card>
<CardHeader title="Alerts" />
<CardBody>
<Alert type="info" title="This is a primary alert with an icon." />
<Alert type="success" title="This is a success alert message." />
<Alert type="warning" title="This is a warning alert message." />
<Alert type="danger" title="This is a danger alert message." />
<Alert color="info" title="This is a primary alert with an icon." />
<Alert color="success" title="This is a success alert message." />
<Alert color="warning" title="This is a warning alert message." />
<Alert color="danger" title="This is a danger alert message." />
</CardBody>
</Card>
</div>
@@ -208,16 +208,16 @@ function greetUser(name) {
<CardBody>
<div class="space-y">
<div>
<Progress value="25" />
<Progress value={25} />
</div>
<div>
<Progress value="50" color="success" />
<Progress value={50} color="success" />
</div>
<div>
<Progress value="75" color="warning" />
<Progress value={75} color="warning" />
</div>
<div>
<Progress value="90" color="danger" showValue />
<Progress value={90} color="danger" showValue />
</div>
</div>
</CardBody>
@@ -241,7 +241,7 @@ function greetUser(name) {
<input type="password" class="form-control" id="all-elements-password-input" placeholder="Enter password" />
</FormGroup>
<FormGroup label="Select Dropdown" for="select-demo-select">
<Select id="demo-select" values={['Option 1', 'Option 2', 'Option 3']} />
<DataSelect id="demo-select" values={['Option 1', 'Option 2', 'Option 3']} />
</FormGroup>
</div>
<div class="col-md-6">
@@ -289,10 +289,10 @@ function greetUser(name) {
<div class="col-md-6">
<h4>Pagination</h4>
{/* activeItem="2" is a string — strict equality never matches integer index, so no page is active */}
<Pagination count={5} activeItem="2" class="mb-4" />
<Pagination count={5} activeItem={2} class="mb-4" />
<h4>Pagination with Text</h4>
<Pagination count={3} text />
<Pagination count={3} activeItem={3} text />
</div>
</div>
</CardBody>
@@ -471,10 +471,10 @@ function greetUser(name) {
<h4>Steps</h4>
<div class="mb-3">
<Steps count={4} active="2" />
<Steps count={4} active={2} />
</div>
<div class="mb-3">
<Steps count={4} active="3" numbers />
<Steps count={4} active={3} numbers />
</div>
</div>
</div>
@@ -489,10 +489,10 @@ function greetUser(name) {
<CardBody>
<h4>Status Dots</h4>
<div class="mb-3">
<StatusDot color="success" label="Success" />
<StatusDot color="warning" label="Warning" />
<StatusDot color="danger" label="Danger" />
<StatusDot color="info" animated label="Info" />
<StatusDot color="success" ariaLabel="Success" />
<StatusDot color="warning" ariaLabel="Warning" />
<StatusDot color="danger" ariaLabel="Danger" />
<StatusDot color="info" animated ariaLabel="Info" />
</div>
<h4>Toast Notifications</h4>
@@ -526,7 +526,7 @@ function greetUser(name) {
<h4>Range Slider</h4>
<div class="mb-3">
<Range id="demo-range" min={0} max={100} value="50" />
<Range id="demo-range" min={0} max={100} value={50} />
</div>
</CardBody>
</Card>
@@ -563,16 +563,16 @@ function greetUser(name) {
<h4>Flags</h4>
<div class="mb-3">
<div class="d-flex flex-wrap gap-2">
<Flag flag="us" label={countryNames.us} />
<Flag flag="gb" label={countryNames.gb} />
<Flag flag="de" label={countryNames.de} />
<Flag flag="fr" label={countryNames.fr} />
<Flag flag="pl" label={countryNames.pl} />
<Flag flag="es" label={countryNames.es} />
<Flag flag="it" label={countryNames.it} />
<Flag flag="nl" label={countryNames.nl} />
<Flag flag="ca" label={countryNames.ca} />
<Flag flag="au" label={countryNames.au} />
<Flag flag="us" ariaLabel={countryNames.us} />
<Flag flag="gb" ariaLabel={countryNames.gb} />
<Flag flag="de" ariaLabel={countryNames.de} />
<Flag flag="fr" ariaLabel={countryNames.fr} />
<Flag flag="pl" ariaLabel={countryNames.pl} />
<Flag flag="es" ariaLabel={countryNames.es} />
<Flag flag="it" ariaLabel={countryNames.it} />
<Flag flag="nl" ariaLabel={countryNames.nl} />
<Flag flag="ca" ariaLabel={countryNames.ca} />
<Flag flag="au" ariaLabel={countryNames.au} />
</div>
</div>
@@ -582,8 +582,8 @@ function greetUser(name) {
{
PAYMENT_IDS.map((payment) => (
<>
<Payment payment={payment} label={paymentNames[payment]} class="hide-theme-dark" />
<Payment payment={payment} label={paymentNames[payment]} dark class="hide-theme-light" />
<Payment payment={payment} ariaLabel={paymentNames[payment]} class="hide-theme-dark" />
<Payment payment={payment} ariaLabel={paymentNames[payment]} dark class="hide-theme-light" />
</>
))
}
@@ -608,7 +608,7 @@ function greetUser(name) {
<Card>
<CardHeader title="Empty State" />
<CardBody>
<Empty title="No data found" subtitle="Try adjusting your search or filter to find what you're looking for." illustration="boy-girl.svg" buttonText="Add new item" buttonIcon="plus" />
<Empty title="No data found" description="Try adjusting your search or filter to find what you're looking for." illustration="boy-girl.svg" buttonText="Add new item" buttonIcon="plus" />
</CardBody>
</Card>
</div>
+4 -4
View File
@@ -1,4 +1,5 @@
---
import { people, personById } from '@shared/lib/people'
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Avatar from '@ui/Avatar.astro'
import AvatarUpload from '@ui/AvatarUpload.astro'
@@ -7,7 +8,6 @@ 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 people from '@data/people.json'
import { site } from '@shared/lib/site'
import { firstLetters } from '@shared/lib/string-format'
import DocsLink from '@ui/DocsLink.astro'
@@ -78,7 +78,7 @@ const brands = ['netflix', 'amazon', 'messenger', 'figma', 'twitch']
<CardTitle>Avatar placeholder</CardTitle>
<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)} />)}
{people8.map((person) => <Avatar placeholder={firstLetters(person.full_name ?? '')} />)}
</div>
</CardBody>
</Card>
@@ -162,7 +162,7 @@ const brands = ['netflix', 'amazon', 'messenger', 'figma', 'twitch']
<CardBody>
<CardTitle>Avatar statuses</CardTitle>
<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} />)}
{statusColors.map((color, i) => <Avatar person={personById(i + 1)} class="rounded-circle" status={color} />)}
</CardBody>
</Card>
</div>
@@ -171,7 +171,7 @@ const brands = ['netflix', 'amazon', 'messenger', 'figma', 'twitch']
<CardBody>
<CardTitle>Avatar brands</CardTitle>
<CardSubtitle>Show a recognizable brand icon instead of a person.</CardSubtitle>
{brands.map((brand, i) => <Avatar personId={i + 1} brand={brand} />)}
{brands.map((brand, i) => <Avatar person={personById(i + 1)} brand={brand} />)}
</CardBody>
</Card>
</div>
+3 -3
View File
@@ -9,7 +9,7 @@ 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 DropdownMenu from '@components/demo/DropdownMenu.astro'
import site from '@data/site.json'
import { ucFirst } from '@shared/lib/string-format'
import DocsLink from '@ui/DocsLink.astro'
@@ -54,7 +54,7 @@ const sizes = ['sm', 'md', 'lg']
<Icon name="arrow-right" />
</span>
<span class={`badge badge-icononly${size !== 'md' ? ` badge-${size}` : ''}`}>
<Icon name="star" type="filled" />
<Icon name="star" filled />
</span>
</BadgeList>
))
@@ -208,7 +208,7 @@ const sizes = ['sm', 'md', 'lg']
colors.map((color) => (
<span class={`badge bg-${color} text-${color}-fg`}>
{' '}
<Icon name="star" type="filled" /> {ucFirst(color)}{' '}
<Icon name="star" filled /> {ucFirst(color)}{' '}
</span>
))
}
+1 -1
View File
@@ -6,5 +6,5 @@ import Empty from '@ui/Empty.astro'
<DefaultLayout title="Blank page" pageHeader={false} pageMenu="base.blank" containerCentered>
<h1 class="visually-hidden">Blank page</h1>
<Empty buttonText="Add your first client" buttonIcon="plus" illustration="computer-fix.svg" />
<Empty title="No results found" description="Try adjusting your search or filter to find what you're looking for." buttonText="Add your first client" buttonIcon="plus" illustration="computer-fix.svg" />
</DefaultLayout>
+1 -1
View File
@@ -90,7 +90,7 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
sizes.map((size) => (
<ButtonList>
<Button size={size} text="Button" />
<Button size={size} icon="star" iconOnly />
<Button size={size} icon="star" iconOnly text="Icon only" />
<Button size={size} icon="star" text="Button" />
<Button size={size} iconEnd="star" text="Button" />
</ButtonList>
+1 -1
View File
@@ -9,7 +9,7 @@ import CardTitle from '@ui/CardTitle.astro'
import Button from '@ui/Button.astro'
import Avatar from '@ui/Avatar.astro'
import Icon from '@ui/Icon.astro'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
import DocsLink from '@ui/DocsLink.astro'
+1 -1
View File
@@ -10,7 +10,7 @@ import YouWin from '@shared/components/cards/YouWin.astro'
import Weather from '@shared/components/cards/Weather.astro'
import ProfileContact from '@shared/components/cards/ProfileContact.astro'
import SmallStats from '@shared/components/cards/SmallStats.astro'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
import DocsLink from '@ui/DocsLink.astro'
---
+1 -1
View File
@@ -2,7 +2,7 @@
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Activity from '@shared/components/parts/charts/Activity.astro'
import SocialReferrals from '@shared/components/cards/charts/SocialReferrals.astro'
import Chart from '@ui/Chart.astro'
import Chart from '@components/demo/Chart.astro'
import Card from '@ui/Card.astro'
import CardHeader from '@ui/CardHeader.astro'
import CardBody from '@ui/CardBody.astro'
+3 -9
View File
@@ -1,24 +1,18 @@
---
// Front matter page-container-class: "flex-fill d-flex flex-column" → containerClass prop.
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import { people } from '@shared/lib/people'
import Icon from '@ui/Icon.astro'
import Avatar from '@ui/Avatar.astro'
import Chat from '@ui/Chat.astro'
import people from '@data/people.json'
import Chat from '@components/demo/Chat.astro'
import chats from '@data/chats.json'
interface Person {
full_name?: string
photo?: string
[key: string]: unknown
}
interface Message {
message?: string
[key: string]: unknown
}
const sidebarPeople = (people as Person[]).slice(0, 10)
const sidebarPeople = people.slice(0, 10)
const messages = chats as Message[]
---
+1 -1
View File
@@ -22,7 +22,7 @@ const colors = Object.values(site.colors) as { hex: string; title: string }[]
colors.map((color, index) => (
<div class="col-2">
<div>
<Colorpicker value={color.hex} id={index + 1} format="hex" ariaLabel={`${color.title} color value`} />
<Colorpicker value={color.hex} id={`${index + 1}`} format="hex" ariaLabel={`${color.title} color value`} />
</div>
</div>
))
+4 -4
View File
@@ -35,7 +35,7 @@ const gradientColors = [...Object.keys(site.colors), 'inverted', 'white', 'trans
<div class="col-12">
<div class="row align-items-center">
<div class="col-auto">
<Avatar square class={`bg-${name} text-${name}-fg`} placeholder={color.abbr} />
<Avatar shape="square" class={`bg-${name} text-${name}-fg`} placeholder={color.abbr} />
</div>
<div class="col">
{color.title}
@@ -61,7 +61,7 @@ const gradientColors = [...Object.keys(site.colors), 'inverted', 'white', 'trans
<div class="col-12">
<div class="row align-items-center">
<div class="col-auto">
<Avatar square class={`bg-${name}-lt text-${name}-lt-fg`} placeholder={color.abbr} />
<Avatar shape="square" class={`bg-${name}-lt text-${name}-lt-fg`} placeholder={color.abbr} />
</div>
<div class="col">
{color.title}
@@ -87,7 +87,7 @@ const gradientColors = [...Object.keys(site.colors), 'inverted', 'white', 'trans
<div class="col-12">
<div class="row align-items-center">
<div class="col-auto">
<Avatar square class={`bg-${name} text-${name}-fg`} placeholder={color.abbr} />
<Avatar shape="square" class={`bg-${name} text-${name}-fg`} placeholder={color.abbr} />
</div>
<div class="col">
{color.title}
@@ -113,7 +113,7 @@ const gradientColors = [...Object.keys(site.colors), 'inverted', 'white', 'trans
<div class="col-12">
<div class="row align-items-center">
<div class="col-auto">
<Avatar square class={`bg-${name} text-${name}-fg`} icon={color.icon} />
<Avatar shape="square" class={`bg-${name} text-${name}-fg`} icon={color.icon} />
</div>
<div class="col">
{color.title}
+3 -3
View File
@@ -8,7 +8,7 @@ import Card from '@ui/Card.astro'
import CardHeader from '@ui/CardHeader.astro'
import CardBody from '@ui/CardBody.astro'
import NavSegmented from '@ui/NavSegmented.astro'
import Chart from '@ui/Chart.astro'
import Chart from '@components/demo/Chart.astro'
import SwitchIcon from '@ui/SwitchIcon.astro'
import cryptoCurrencies from '@data/crypto-currencies.json'
import cryptoMarkets from '@data/crypto-markets.json'
@@ -174,7 +174,7 @@ const operationCurrencies = currencies.slice(0, 20)
<thead>
<tr>
<th>
<SwitchIcon icon="star" iconBColor="yellow" variant="slide-up" />
<SwitchIcon icon="star" activeColor="yellow" variant="slide-up" />
</th>
<th>Coin</th>
<th>Price</th>
@@ -187,7 +187,7 @@ const operationCurrencies = currencies.slice(0, 20)
markets.map((market) => (
<tr>
<td>
<SwitchIcon icon="star" iconBColor="yellow" variant="slide-up" />
<SwitchIcon icon="star" activeColor="yellow" variant="slide-up" />
</td>
<td>{market.coin}</td>
<td class="">{market.price}</td>
+2 -2
View File
@@ -1,7 +1,7 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import DropdownMenu from '@ui/DropdownMenu.astro'
import DropdownMenuAll from '@ui/DropdownMenuAll.astro'
import DropdownMenu from '@components/demo/DropdownMenu.astro'
import DropdownMenuAll from '@components/demo/DropdownMenuAll.astro'
import DocsLink from '@ui/DocsLink.astro'
---
+4 -4
View File
@@ -17,7 +17,7 @@ import mails from '@data/mails.json'
<Card>
<div class="row g-0">
<div class="col-xxl-3 email-border border-end">
<Offcanvas size="xxl" direction="start" class="h-100 file-offcanvas" tabindex="-1" id="emailSidebaroffcanvas">
<Offcanvas responsive="xxl" direction="start" class="h-100 file-offcanvas" tabindex="-1" id="emailSidebaroffcanvas">
<div class="card-body h-100">
<div>
<Button icon="pencil" text="Compose" color="primary" class="d-none d-sm-block" modalId="new-email" />
@@ -81,9 +81,9 @@ import mails from '@data/mails.json'
</div>
<ButtonGroup>
<Button icon="archive" iconOnly />
<Button icon="alert-octagon" iconOnly />
<Button icon="trash" iconOnly />
<Button icon="archive" iconOnly text="Archive" />
<Button icon="alert-octagon" iconOnly text="Report spam" />
<Button icon="trash" iconOnly text="Delete" />
</ButtonGroup>
<ButtonGroup>
+1 -1
View File
@@ -18,7 +18,7 @@ import CardBody from '@ui/CardBody.astro'
import CardFooter from '@ui/CardFooter.astro'
import CardTitle from '@ui/CardTitle.astro'
import FormGroup from '@ui/FormGroup.astro'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
import DocsLink from '@ui/DocsLink.astro'
+2 -2
View File
@@ -179,7 +179,7 @@ const countries = flags as { name: string }[]
</div>
</FormGroup>
<FormGroup label="Date of Birth" for="datepicker-birth-date" class="">
<div><Datepicker layout="icon" id="birth-date" /></div>
<div><Datepicker layout="icon" id="birth-date" value="2020-06-20" /></div>
</FormGroup>
</div>
<FormGroup label="Category" for="example-form-category" class="">
@@ -234,6 +234,6 @@ const countries = flags as { name: string }[]
</div>
</div>
<div class="col"><Payment label="Visa" /></div>
<div class="col"><Payment payment="visa" ariaLabel="Visa" /></div>
</div>
</DefaultLayout>
+1 -1
View File
@@ -14,7 +14,7 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Full calendar</CardTitle>
<CardSubtitle>Drag to create an event, click one to edit it — populated here with sample events.</CardSubtitle>
<Fullcalendar sampleEvents />
<Fullcalendar id="default" sampleEvents />
</CardBody>
</Card>
</DefaultLayout>
+2 -2
View File
@@ -3,7 +3,7 @@ import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import GalleryPhoto from '@shared/components/cards/GalleryPhoto.astro'
import Pagination from '@ui/Pagination.astro'
import photos from '@data/photos.json'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
import HeaderActionsPhotos from '@shared/components/layout/HeaderActionsPhotos.astro'
@@ -24,6 +24,6 @@ const galleryPhotos = photos.filter((photo) => photo.horizontal).slice(0, 15)
</div>
<div class="d-flex mt-5">
<Pagination class="ms-auto" />
<Pagination count={5} activeItem={3} class="ms-auto" />
</div>
</DefaultLayout>
+2 -1
View File
@@ -1,4 +1,5 @@
---
import { illustrationSvg } from '@shared/lib/svg'
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Icon from '@ui/Icon.astro'
import CardStamp from '@ui/CardStamp.astro'
@@ -19,7 +20,7 @@ const autodarkEntries = Object.entries(autodark)
// Last autodark entry (loop overwrites each pass).
const firstIllustration = autodarkEntries.length ? requireIndex(autodarkEntries, autodarkEntries.length - 1)[1] : ''
const withClass = (svg: string) => svg.replaceAll('<svg ', '<svg class="w-100 h-auto" ')
const withClass = (svg: string) => illustrationSvg(svg, { classes: 'w-100 h-auto' })
const colors = siteData.colors as Record<string, { hex: string; class: string; prop: string }>
const skinColors = siteData.skinColors as Record<string, { hex: string; class: string }>
+1 -1
View File
@@ -1,7 +1,7 @@
---
// Gallery uses horizontal photos only.
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Photo from '@ui/Photo.astro'
import Photo from '@components/demo/Photo.astro'
import photos from '@data/photos.json'
import DocsLink from '@ui/DocsLink.astro'
+1 -1
View File
@@ -1,6 +1,6 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import MapVector from '@ui/MapVector.astro'
import MapVector from '@components/demo/MapVector.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import CardTitle from '@ui/CardTitle.astro'
+1 -1
View File
@@ -1,7 +1,7 @@
---
// Card maps span full-width column with no card-body; non-card maps get card-body with title.
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Map from '@ui/Map.astro'
import Map from '@components/demo/Map.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import maps from '@data/maps.json'
+2 -2
View File
@@ -17,8 +17,8 @@ import DocsLink from '@ui/DocsLink.astro'
<CardBody>
<CardTitle>Numbered</CardTitle>
<CardSubtitle>Page numbers, with or without <code>text</code> Prev/Next labels.</CardSubtitle>
<Pagination />
<Pagination text />
<Pagination count={5} activeItem={3} />
<Pagination count={5} activeItem={3} text />
</CardBody>
</Card>
</div>
+2 -1
View File
@@ -1,5 +1,6 @@
---
// tabler-payments is not in core/libs.json — only imask emits a script tag.
import { personById } from '@shared/lib/people'
import PayLayout from '@shared/layouts/PayLayout.astro'
import Avatar from '@ui/Avatar.astro'
import Payment from '@ui/Payment.astro'
@@ -20,7 +21,7 @@ import Icon from '@ui/Icon.astro'
<div class="card rounded-top-0 border-top-0">
<div class="card-body pt-0">
<div class="mb-3 text-center">
<Avatar personId={1} size="xl" class="avatar-cover rounded-circle mb-3" />
<Avatar person={personById(1)} size="xl" class="avatar-cover rounded-circle mb-3" />
<div class="mb-4">
<h2 class="h2">Front-End Learning</h2>
<div class="text-secondary">Learn to build web apps with HTML & CSS. Get started quickly with included templates.</div>
+3 -2
View File
@@ -1,5 +1,6 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import type { PaymentProvider } from '@shared/lib/tokens'
import Payment from '@ui/Payment.astro'
import Card from '@ui/Card.astro'
import CardHeader from '@ui/CardHeader.astro'
@@ -31,7 +32,7 @@ const providers = payments as { name: string; logo: string }[]
<div class="col">
<div class="row">
<div class="col-auto">
<Payment payment={provider.logo} />
<Payment payment={provider.logo as PaymentProvider} />
</div>
<div class="col">
<strong class="d-block">{provider.name}</strong>
@@ -62,7 +63,7 @@ const providers = payments as { name: string; logo: string }[]
<div class="col">
<div class="row">
<div class="col-auto">
<Payment payment={provider.logo} dark={true} />
<Payment payment={provider.logo as PaymentProvider} dark={true} />
</div>
<div class="col">
<strong class="d-block">{provider.name}</strong>
+1 -1
View File
@@ -1,6 +1,6 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Photo from '@ui/Photo.astro'
import Photo from '@components/demo/Photo.astro'
import photosData from '@data/photos.json'
import { requireIndex } from '@shared/lib/array'
+2 -1
View File
@@ -6,6 +6,7 @@ import Button from '@ui/Button.astro'
import Badge from '@ui/Badge.astro'
import Avatar from '@ui/Avatar.astro'
import AvatarList from '@ui/AvatarList.astro'
import PeopleAvatarList from '@components/demo/PeopleAvatarList.astro'
import Pagination from '@ui/Pagination.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
@@ -169,7 +170,7 @@ import CardBody from '@ui/CardBody.astro'
<p class="fs-sm text-secondary mb-0">Last post 1 day ago</p>
<hr />
<div class="d-flex align-items-center justify-content-between">
<AvatarList stacked={true} size="xs" offset={3} limit={3} />
<PeopleAvatarList stacked={true} size="xs" offset={3} limit={3} />
<div class="text-end">
<Badge text="62 posts" class="bg-light text-body" />
</div>
+1 -1
View File
@@ -138,7 +138,7 @@ import CardTitle from '@ui/CardTitle.astro'
<Datepicker id="playground-weekday" value="2024-01-15" />
</FormGroup>
<FormGroup label="With pre-selected dates" for="datepicker-playground-preselected">
<Datepicker id="playground-preselected" />
<Datepicker id="playground-preselected" value="2020-06-20" />
</FormGroup>
</div>
<div class="col-12">
+1 -1
View File
@@ -3,7 +3,7 @@ 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 Timeline from '@ui/Timeline.astro'
import Timeline from '@components/demo/Timeline.astro'
import UserInfo from '@shared/components/cards/UserInfo.astro'
---
+42 -42
View File
@@ -22,10 +22,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Default</CardTitle>
<CardSubtitle>Track completion with a simple bar from empty to full.</CardSubtitle>
<div class="space-y">
<Progress value="0" />
<Progress value="20" />
<Progress value="40" />
<Progress value="100" />
<Progress value={0} />
<Progress value={20} />
<Progress value={40} />
<Progress value={100} />
</div>
</CardBody>
</Card>
@@ -36,9 +36,9 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>With value</CardTitle>
<CardSubtitle>Show the exact percentage inside a larger bar with <code>showValue</code>.</CardSubtitle>
<div class="space-y">
<Progress value="10" showValue size="lg" />
<Progress value="20" showValue size="lg" />
<Progress value="90" showValue size="lg" />
<Progress value={10} showValue size="lg" />
<Progress value={20} showValue size="lg" />
<Progress value={90} showValue size="lg" />
</div>
</CardBody>
</Card>
@@ -49,10 +49,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Colors</CardTitle>
<CardSubtitle>Match the bar color to the context with any theme color.</CardSubtitle>
<div class="space-y">
<Progress color="blue" value="20" />
<Progress color="green" value="40" />
<Progress color="yellow" value="60" />
<Progress color="red" value="80" />
<Progress color="blue" value={20} />
<Progress color="green" value={40} />
<Progress color="yellow" value={60} />
<Progress color="red" value={80} />
</div>
</CardBody>
</Card>
@@ -63,10 +63,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Sizes</CardTitle>
<CardSubtitle>Scale a bar from <code>sm</code> to <code>xl</code>.</CardSubtitle>
<div class="space-y">
<Progress value="20" size="sm" />
<Progress value="40" />
<Progress value="60" size="lg" />
<Progress value="80" size="xl" />
<Progress value={20} size="sm" />
<Progress value={40} />
<Progress value={60} size="lg" />
<Progress value={80} size="xl" />
</div>
</CardBody>
</Card>
@@ -88,8 +88,8 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Multiple values</CardTitle>
<CardSubtitle>Stack several segments in one bar to compare parts of a whole.</CardSubtitle>
<div class="space-y">
<Progress values={[20, 30, 10]} />
<Progress values={[10, 20, 30, 40]} class="progress-separated" />
<Progress values={[20, 30, 10]} colors={['blue', 'red', 'green']} />
<Progress values={[10, 20, 30, 40]} colors={['blue', 'red', 'green', 'yellow']} class="progress-separated" />
</div>
</CardBody>
</Card>
@@ -100,10 +100,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Striped</CardTitle>
<CardSubtitle>Add diagonal stripes with <code>striped</code> for a textured look.</CardSubtitle>
<div class="space-y">
<Progress color="blue" value="20" striped />
<Progress color="green" value="40" striped />
<Progress color="yellow" value="60" striped />
<Progress color="red" value="80" striped />
<Progress color="blue" value={20} striped />
<Progress color="green" value={40} striped />
<Progress color="yellow" value={60} striped />
<Progress color="red" value={80} striped />
</div>
</CardBody>
</Card>
@@ -114,10 +114,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Animated</CardTitle>
<CardSubtitle>Combine <code>striped</code> with <code>animated</code> to keep the stripes moving.</CardSubtitle>
<div class="space-y">
<Progress value="20" striped animated />
<Progress value="40" color="green" striped animated />
<Progress value="60" color="yellow" striped animated />
<Progress value="80" color="red" striped animated />
<Progress value={20} striped animated />
<Progress value={40} color="green" striped animated />
<Progress value={60} color="yellow" striped animated />
<Progress value={80} color="red" striped animated />
</div>
</CardBody>
</Card>
@@ -129,7 +129,7 @@ import DocsLink from '@ui/DocsLink.astro'
<CardSubtitle>Update the bar's width at runtime and watch it react.</CardSubtitle>
<div class="row align-items-center g-0">
<div class="col">
<Progress value="0" id="progress-animated" />
<Progress value={0} id="progress-animated" />
</div>
<div class="col-2 text-end" id="progress-animated-value">0%</div>
</div>
@@ -201,10 +201,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle> Progress Background </CardTitle>
<CardSubtitle>Fill a row's background as the progress indicator itself.</CardSubtitle>
<div class="space-y">
<ProgressBg value="85" text="Poland" showValue />
<ProgressBg value="65" text="Germany" showValue />
<ProgressBg value="45" text="United States" showValue />
<ProgressBg value="25" text="France" showValue />
<ProgressBg value={85} text="Poland" showValue />
<ProgressBg value={65} text="Germany" showValue />
<ProgressBg value={45} text="United States" showValue />
<ProgressBg value={25} text="France" showValue />
</div>
</CardBody>
</Card>
@@ -215,10 +215,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle> Progress Background Colors </CardTitle>
<CardSubtitle>Pair a light background fill with a matching accent color.</CardSubtitle>
<div class="space-y">
<ProgressBg value="75" text="Success" color="success-lt" showValue />
<ProgressBg value="60" text="Warning" color="warning-lt" showValue />
<ProgressBg value="40" text="Danger" color="danger-lt" showValue />
<ProgressBg value="90" text="Info" color="info-lt" showValue />
<ProgressBg value={75} text="Success" color="success" showValue />
<ProgressBg value={60} text="Warning" color="warning" showValue />
<ProgressBg value={40} text="Danger" color="danger" showValue />
<ProgressBg value={90} text="Info" color="info" showValue />
</div>
</CardBody>
</Card>
@@ -229,10 +229,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle> Progress Description </CardTitle>
<CardSubtitle>Pair a label and percentage with the bar for more context.</CardSubtitle>
<div class="space-y">
<ProgressDescription label="Project completion" value="85" color="green" />
<ProgressDescription label="Storage usage" description="2.4GB of 5GB" value="48" color="blue" />
<ProgressDescription label="Download progress" value="75" color="yellow" />
<ProgressDescription label="Skills assessment" description="HTML/CSS" value="92" color="red" />
<ProgressDescription label="Project completion" value={85} color="green" />
<ProgressDescription label="Storage usage" description="2.4GB of 5GB" value={48} color="blue" />
<ProgressDescription label="Download progress" value={75} color="yellow" />
<ProgressDescription label="Skills assessment" description="HTML/CSS" value={92} color="red" />
</div>
</CardBody>
</Card>
@@ -243,10 +243,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle> Progress Description Sizes </CardTitle>
<CardSubtitle>Scale the labeled progress bar from <code>sm</code> to <code>xl</code>.</CardSubtitle>
<div class="space-y">
<ProgressDescription label="Small progress" value="60" size="sm" color="blue" />
<ProgressDescription label="Default progress" value="70" color="green" />
<ProgressDescription label="Large progress" value="80" size="lg" color="orange" />
<ProgressDescription label="Extra large" value="90" size="xl" color="purple" />
<ProgressDescription label="Small progress" value={60} size="sm" color="blue" />
<ProgressDescription label="Default progress" value={70} color="green" />
<ProgressDescription label="Large progress" value={80} size="lg" color="orange" />
<ProgressDescription label="Extra large" value={90} size="xl" color="purple" />
</div>
</CardBody>
</Card>
+1 -1
View File
@@ -1,6 +1,6 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import { slugifyWord as slug } from '@shared/lib/string-format'
import { slugify as slug } from '@shared/lib/string-format'
const articles: [string, string[]][] = [
[
+1 -1
View File
@@ -3,7 +3,7 @@ import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import NavAside from '@shared/components/parts/NavAside.astro'
import GalleryPhoto from '@shared/components/cards/GalleryPhoto.astro'
import photos from '@data/photos.json'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
const resultPhotos = photos.filter((photo) => photo.horizontal).slice(0, 18)
+4 -4
View File
@@ -97,8 +97,8 @@ import DocsLink from '@ui/DocsLink.astro'
<Card>
<CardBody>
<CardTitle>Full width</CardTitle>
<CardSubtitle>Add <code>fullWidth</code> to stretch the control across its container.</CardSubtitle>
<NavSegmented items={['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']} fullWidth={true} />
<CardSubtitle>Add <code>block</code> to stretch the control across its container.</CardSubtitle>
<NavSegmented items={['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']} block={true} />
</CardBody>
</Card>
</div>
@@ -108,8 +108,8 @@ import DocsLink from '@ui/DocsLink.astro'
<CardTitle>Full width, stacked</CardTitle>
<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>
<div><NavSegmented items={['Overview', 'Analytics', 'Reports', 'Notifications']} block={true} /></div>
<div><NavSegmented items={['Account', 'Password']} block={true} /></div>
</div>
</CardBody>
</Card>
+3 -3
View File
@@ -1,4 +1,5 @@
---
import { people, personById } from '@shared/lib/people'
import CardSubtitle from '@ui/CardSubtitle.astro'
import SettingsLayout from '@shared/layouts/SettingsLayout.astro'
import Avatar from '@ui/Avatar.astro'
@@ -7,7 +8,6 @@ import ButtonList from '@ui/ButtonList.astro'
import Check from '@ui/form/Check.astro'
import FormGroup from '@ui/FormGroup.astro'
import CardTitle from '@ui/CardTitle.astro'
import people from '@data/people.json'
import { requireIndex } from '@shared/lib/array'
const person = requireIndex(people, 0)
@@ -20,9 +20,9 @@ const person = requireIndex(people, 0)
<CardTitle>Profile Details</CardTitle>
<div class="row align-items-center">
<div class="col-auto"><Avatar size="xl" personId={1} /></div>
<div class="col-auto"><Avatar size="xl" person={personById(1)} /></div>
<div class="col-auto"><Button text="Change avatar" /></div>
<div class="col-auto"><Button text="Delete avatar" color="danger" ghost /></div>
<div class="col-auto"><Button text="Delete avatar" color="danger" variant="ghost" /></div>
</div>
<CardTitle class="mt-4">Business Profile</CardTitle>
+1 -1
View File
@@ -3,7 +3,7 @@
import BaseLayout from '@shared/layouts/BaseLayout.astro'
import Logo from '@shared/components/navbar/Logo.astro'
import SignInForm from '@shared/components/cards/SignInForm.astro'
import Photo from '@ui/Photo.astro'
import Photo from '@components/demo/Photo.astro'
import photos from '@data/photos.json'
import { requireIndex } from '@shared/lib/array'
---
+1 -1
View File
@@ -74,7 +74,7 @@ document.querySelector("#signature-advanced-png").addEventListener("click", func
<input type="text" class="form-control" id="signature-last-name" name="last_name" />
</FormGroup>
<FormGroup label="Signature" required associate={false}>
<Signature clear extraJs={simpleJs} />
<Signature id="default" clear extraJs={simpleJs} />
</FormGroup>
</form>
<div class="text-secondary fs-5">I agree that the signature and initials will be the electronic representation of my signature and initials for all purposes when I (or my agent) use them on documents, including legally binding contracts - just the same as a pen-and-paper signature or initial.</div>
+5 -5
View File
@@ -1,9 +1,9 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Table from '@ui/Table.astro'
import Table from '@components/demo/Table.astro'
import Progressbg from '@shared/components/cards/tables/Progressbg.astro'
import Invoices from '@shared/components/cards/Invoices.astro'
import AdvancedTable from '@ui/AdvancedTable.astro'
import AdvancedTable from '@components/demo/AdvancedTable.astro'
import Card from '@ui/Card.astro'
import CardHeader from '@ui/CardHeader.astro'
import CardTitle from '@ui/CardTitle.astro'
@@ -35,10 +35,10 @@ import DocsLink from '@ui/DocsLink.astro'
<CardHeader>
<div>
<CardTitle>Striped rows</CardTitle>
<CardSubtitle>Alternate row shading with <code>stripped</code> to make wide tables easier to scan.</CardSubtitle>
<CardSubtitle>Alternate row shading with <code>striped</code> to make wide tables easier to scan.</CardSubtitle>
</div>
</CardHeader>
<Table card={true} stripped={true} offset={5} />
<Table card={true} striped={true} offset={5} />
</Card>
</div>
@@ -71,7 +71,7 @@ import DocsLink from '@ui/DocsLink.astro'
</div>
<div class="col-12">
<AdvancedTable />
<AdvancedTable id="advanced-table" />
</div>
</div>
</DefaultLayout>
+4 -4
View File
@@ -1,4 +1,6 @@
---
import { range } from '@shared/lib/array'
import type { FlagCountry } from '@shared/lib/tokens'
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Tag from '@ui/Tag.astro'
import TagList from '@ui/TagList.astro'
@@ -6,15 +8,13 @@ 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 people from '@data/people.json'
import { people } from '@shared/lib/people'
import flags from '@data/flags.json'
import siteData from '@data/site.json'
import DocsLink from '@ui/DocsLink.astro'
const tagIcons = ['bold', 'italic', 'underline', 'copy', 'scissors', 'file-plus', 'file-minus', 'ghost', 'star', 'script', 'photo', 'dog', 'piano']
const range = (a: number, b: number) => Array.from({ length: b - a + 1 }, (_, i) => a + i)
const flags9 = flags.slice(0, 9) as { name: string; flag: string }[]
const people8 = people.slice(0, 8)
@@ -44,7 +44,7 @@ const colors = Object.values(siteData.colors) as { class: string; title: string
<CardTitle>Tags with flag</CardTitle>
<CardSubtitle>Pair a tag with a country flag.</CardSubtitle>
<TagList>
{flags9.map((country) => <Tag text={country.name} flag={country.flag} />)}
{flags9.map((country) => <Tag text={country.name} flag={country.flag as FlagCountry} />)}
</TagList>
</CardBody>
</Card>
+3 -10
View File
@@ -1,4 +1,5 @@
---
import { people, personById } from '@shared/lib/people'
import CardActions from '@ui/CardActions.astro'
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Button from '@ui/Button.astro'
@@ -9,17 +10,9 @@ import Modal from '@shared/components/modals/Modal.astro'
import CaptureModal from '@shared/components/CaptureModal.astro'
import FormGroup from '@ui/FormGroup.astro'
import tasks from '@data/tasks.json'
import people from '@data/people.json'
import { requireIndex } from '@shared/lib/array'
import CardTitle from '@ui/CardTitle.astro'
interface Person {
id?: string
full_name?: string
photo?: string
[key: string]: unknown
}
interface Task {
'name'?: string
'assigned_to'?: number
@@ -35,7 +28,7 @@ interface Column {
}
const columns = (tasks as { columns: Column[] }).columns
const peopleList = people as Person[]
const peopleList = people
// Assignable people for the add-task modal.
const selectedPeople = [5, 6, 2, 3].map((id) => requireIndex(peopleList, id - 1))
@@ -79,7 +72,7 @@ const selectedPeople = [5, 6, 2, 3].map((id) => requireIndex(peopleList, id - 1)
<td>
{task.assigned_to && person ? (
<div class="d-flex align-items-center">
<Avatar personId={task.assigned_to} size="xs" class="me-2" />
<Avatar person={personById(task.assigned_to)} size="xs" class="me-2" />
<span>{person.full_name}</span>
</div>
) : (
+1 -1
View File
@@ -4,7 +4,7 @@ import Button from '@ui/Button.astro'
import ButtonList from '@ui/ButtonList.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import Toast from '@ui/Toast.astro'
import Toast from '@components/demo/Toast.astro'
import DocsLink from '@ui/DocsLink.astro'
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
import Subheader from '@ui/Subheader.astro'
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Chart from '@ui/Chart.astro'
import Chart from '@components/demo/Chart.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import CardTitle from '@ui/CardTitle.astro'
+3 -10
View File
@@ -2,22 +2,15 @@
// progress and online_counter assigned per person but never rendered — omitted.
// rounded=true on avatar has no effect — Avatar has no `rounded` prop.
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import { people } from '@shared/lib/people'
import Avatar from '@ui/Avatar.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import Icon from '@ui/Icon.astro'
import Pagination from '@ui/Pagination.astro'
import people from '@data/people.json'
import HeaderActionsUsers from '@shared/components/layout/HeaderActionsUsers.astro'
interface Person {
full_name?: string
job_title?: string
photo?: string
[key: string]: unknown
}
const users = (people as Person[]).slice(0, 18)
const users = people.slice(0, 18)
---
<DefaultLayout title="Users list" pageHeader="Users" description="1-18 of 413 people" pageMenu="extra.users">
@@ -54,6 +47,6 @@ const users = (people as Person[]).slice(0, 18)
</div>
<div class="d-flex mt-4">
<Pagination class="ms-auto" />
<Pagination count={5} activeItem={3} class="ms-auto" />
</div>
</DefaultLayout>
+4 -4
View File
@@ -5,9 +5,9 @@ import Alert from '@ui/Alert.astro'
<ScreenshotLayout title="Alert" columns={2}>
<div class="space-y">
<Alert type="success" title="Well done!" description="You successfully read this important alert message." />
<Alert type="warning" title="Warning!" description="Better check yourself, you're not looking too good." />
<Alert type="danger" title="Oh snap!" description="Change a few things up and try submitting again." showClose />
<Alert type="info" title="Heads up!" description="This alert needs your attention, but it's not super important." />
<Alert color="success" title="Well done!" description="You successfully read this important alert message." />
<Alert color="warning" title="Warning!" description="Better check yourself, you're not looking too good." />
<Alert color="danger" title="Oh snap!" description="Change a few things up and try submitting again." showClose />
<Alert color="info" title="Heads up!" description="This alert needs your attention, but it's not super important." />
</div>
</ScreenshotLayout>
+1 -1
View File
@@ -6,7 +6,7 @@ import ChartRadial from '@ui/ChartRadial.astro'
<ScreenshotLayout title="Task progress" columns={1} pageLibs={['apexcharts']}>
<div class="card">
<div class="card-body">
<ChartRadial title="Task progress" value={72} />
<ChartRadial id="task-progress" title="Task progress" value={72} />
</div>
</div>
</ScreenshotLayout>
+1 -1
View File
@@ -1,6 +1,6 @@
---
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
import Chat from '@ui/Chat.astro'
import Chat from '@components/demo/Chat.astro'
---
<ScreenshotLayout title="Chat" columns={2}>
+1 -1
View File
@@ -4,5 +4,5 @@ import Empty from '@ui/Empty.astro'
---
<ScreenshotLayout title="Empty state" columns={2}>
<Empty illustration="not-found.svg" />
<Empty illustration="not-found.svg" title="No results found" description="Try adjusting your search or filter to find what you're looking for." buttonText="Search again" buttonIcon="search" />
</ScreenshotLayout>
+2 -2
View File
@@ -2,9 +2,9 @@
// MapVectorCard.astro has no room for a header legend/stats row, so the card
// is hand-built here (same shape as MapVectorCard.astro) instead of reusing it.
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
import MapVector from '@ui/MapVector.astro'
import MapVector from '@components/demo/MapVector.astro'
import Subheader from '@ui/Subheader.astro'
import ScaleLegend from '@ui/ScaleLegend.astro'
import ScaleLegend from '@components/demo/ScaleLegend.astro'
---
<ScreenshotLayout title="Map" columns={2} pageLibs={['jsvectormap']} cssPlugins={['flags']}>
+2 -1
View File
@@ -1,5 +1,6 @@
---
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
import type { PaymentProvider } from '@shared/lib/tokens'
import Payment from '@ui/Payment.astro'
import allPayments from '@data/payments.json'
@@ -13,7 +14,7 @@ const payments = popularLogos.map((logo) => allPayments.find((item) => item.logo
{
payments.map((item) => (
<span title={item.name}>
<Payment payment={item.logo} dark={true} />
<Payment payment={item.logo as PaymentProvider} dark={true} />
</span>
))
}
+1 -1
View File
@@ -1,6 +1,6 @@
---
// shared by index.astro and layout-vertical.astro.
import Chart from '@ui/Chart.astro'
import Chart from '@shared/components/demo/Chart.astro'
import CardTitle from '@ui/CardTitle.astro'
import MapVectorCard from './cards/MapVectorCard.astro'
import Welcome from './cards/Welcome.astro'
+1 -1
View File
@@ -1,5 +1,5 @@
---
import ActivityPart from '@ui/ActivityPart.astro'
import ActivityPart from '@shared/components/demo/ActivityPart.astro'
---
<div class="card" style="height: 28rem">
+1 -1
View File
@@ -2,7 +2,7 @@
import Button from '@ui/Button.astro'
import Avatar from '@ui/Avatar.astro'
import CardTitle from '@ui/CardTitle.astro'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
const person = requireIndex(people, 0)
+4 -4
View File
@@ -1,7 +1,7 @@
---
import { staticPath } from '@shared/lib/assets';
import Icon from '@ui/Icon.astro';
import AvatarList from '@ui/AvatarList.astro';
import PeopleAvatarList from '@shared/components/demo/PeopleAvatarList.astro';
import Empty from '@ui/Empty.astro';
import Progress from '@ui/Progress.astro';
import photos from '@data/photos.json';
@@ -66,7 +66,7 @@ const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[],
<div class:list={classes}>
{
empty ? (
<Empty illustration="not-found" height={160} />
<Empty illustration="not-found" height={160} title="No results found" description="Try adjusting your search or filter to find what you're looking for." buttonText="Search again" buttonIcon="search" />
) : (
<Fragment>
{imgTop && (
@@ -149,7 +149,7 @@ const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[],
<input class="form-check-input position-static" type="checkbox" checked />
</label>
) : el === 'avatars' ? (
<AvatarList stacked={true} size="sm" text="+3" />
<PeopleAvatarList stacked={true} size="sm" text="+3" />
) : el === 'more' ? (
<a href="#">More information</a>
) : null}
@@ -186,7 +186,7 @@ const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[],
</Fragment>
)}
{progress && <Progress class="progress-sm card-progress" />}
{progress && <Progress value={38} class="progress-sm card-progress" />}
</Fragment>
)
}
@@ -1,5 +1,6 @@
---
import Chart from '@ui/Chart.astro'
import { personById } from '@shared/lib/people'
import Chart from '@shared/components/demo/Chart.astro'
import ChartSparkline from '@ui/ChartSparkline.astro'
import Icon from '@ui/Icon.astro'
import Avatar from '@ui/Avatar.astro'
@@ -49,7 +50,7 @@ const rows = (commits as Commit[]).slice(0, 5)
rows.map((commit, index) => (
<tr>
<td class="w-1">
<Avatar personId={index + 1} size="sm" />
<Avatar person={personById(index + 1)} size="sm" />
</td>
<td class="td-truncate">
<div class="text-truncate">{commit.description}</div>
+2 -2
View File
@@ -1,5 +1,5 @@
---
import AvatarList from '@ui/AvatarList.astro'
import PeopleAvatarList from '@shared/components/demo/PeopleAvatarList.astro'
import Button from '@ui/Button.astro'
import CardTitle from '@ui/CardTitle.astro'
---
@@ -7,7 +7,7 @@ import CardTitle from '@ui/CardTitle.astro'
<div class="card card-lg card-dashed card-transparent">
<div class="card-body text-center">
<div class="mb-3">
<AvatarList stacked={true} />
<PeopleAvatarList stacked={true} />
</div>
<CardTitle>No Team Members</CardTitle>
<p class="text-secondary">Invite your team to<br />collaborate on this project.</p>
+1 -1
View File
@@ -30,7 +30,7 @@ const entries = Object.entries(icons as Record<string, { svg?: Record<string, st
([iconName, icon]) =>
icon.svg?.[type] && (
<a href={`https://tabler.io/icons/icon/${iconName}`} target="_blank" rel="noopener" class="demo-icons-list-item" title={iconName} data-bs-toggle="tooltip" data-bs-placement="top">
<Icon name={iconName} type={type} />
<Icon name={iconName} filled={type === 'filled'} />
</a>
),
)
+4 -3
View File
@@ -1,8 +1,9 @@
---
import Icon from '@ui/Icon.astro'
import type { FlagCountry } from '@shared/lib/tokens'
import Flag from '@ui/Flag.astro'
import CardTitle from '@ui/CardTitle.astro'
import DropdownMenu from '@ui/DropdownMenu.astro'
import DropdownMenu from '@shared/components/demo/DropdownMenu.astro'
import Pagination from '@ui/Pagination.astro'
import invoices from '@data/invoices.json'
import countries from '@data/countries.json'
@@ -64,7 +65,7 @@ const countryNames = Object.fromEntries((countries as { code: string; name: stri
</a>
</td>
<td>
<Flag flag={invoice.country} size="xs" class="me-2" label={countryNames[invoice.country] ?? invoice.country.toUpperCase()} />
<Flag flag={invoice.country as FlagCountry} size="xs" class="me-2" ariaLabel={countryNames[invoice.country] ?? invoice.country.toUpperCase()} />
{invoice.client}
</td>
<td>{invoice['vat-no']}</td>
@@ -94,7 +95,7 @@ const countryNames = Object.fromEntries((countries as { code: string; name: stri
<p class="m-0 text-secondary">Showing <strong>1 to 8</strong> of <strong>16 entries</strong></p>
</div>
<div class="col-auto">
<Pagination class="m-0 ms-auto" />
<Pagination count={5} activeItem={3} class="m-0 ms-auto" />
</div>
</div>
</div>
+1 -1
View File
@@ -1,5 +1,5 @@
---
import MapVector from '@ui/MapVector.astro'
import MapVector from '@shared/components/demo/MapVector.astro'
import CardTitle from '@ui/CardTitle.astro'
interface Props {
@@ -34,7 +34,7 @@ import { formatNumber } from '@shared/lib/string-format'
<td class="text-secondary">{formatNumber(url.unique)}</td>
<td class="text-secondary">{url.bounce}</td>
<td class="text-end w-1">
<ChartSparkline type="line" data={url.data} id={`bounce-rate-${index + 1}`} small={true} color="primary" />
<ChartSparkline type="line" data={url.data} id={`bounce-rate-${index + 1}`} size="sm" color="primary" />
</td>
</tr>
))
+2 -2
View File
@@ -21,10 +21,10 @@ const color = 'yellow'
<div class={`card card-gradient card-gradient-${color}`}>
<div class="card-body text-center py-6">
<div class="position-absolute top-0 end-0 p-1">
<div class="btn btn-action"><Icon name="star" color="yellow" type="filled" /></div>
<div class="btn btn-action"><Icon name="star" color="yellow" filled /></div>
</div>
<div>
<Avatar size="2xl" person={person} shape="rounded-circle" />
<Avatar size="2xl" person={person} shape="rounded" />
</div>
<div class="h1 mt-4 mb-1">{person.full_name}</div>
<div class="text-secondary">{person.job_title}</div>
+3 -3
View File
@@ -1,6 +1,6 @@
---
import Progress from '@ui/Progress.astro'
import AvatarList from '@ui/AvatarList.astro'
import PeopleAvatarList from '@shared/components/demo/PeopleAvatarList.astro'
import Icon from '@ui/Icon.astro'
import CardTitle from '@ui/CardTitle.astro'
@@ -11,7 +11,7 @@ interface Props {
limit?: number
percentageColor?: string
due?: string
value?: number | string
value?: number
}
const { title = 'Task Title', badge, offset = 40, limit = 7, percentageColor = 'green', due = '2 days', value = 20 } = Astro.props
@@ -32,7 +32,7 @@ const { title = 'Task Title', badge, offset = 40, limit = 7, percentageColor = '
}
</CardTitle>
<AvatarList offset={offset} limit={limit} stacked class="mb-3" />
<PeopleAvatarList offset={offset} limit={limit} stacked class="mb-3" />
<div class="card-meta d-flex justify-content-between">
<div class="d-flex align-items-center">
+3 -3
View File
@@ -1,6 +1,6 @@
---
import Avatar from '@ui/Avatar.astro'
import AvatarList from '@ui/AvatarList.astro'
import PeopleAvatarList from '@shared/components/demo/PeopleAvatarList.astro'
import Progress from '@ui/Progress.astro'
interface Props {
@@ -22,8 +22,8 @@ const stage = 'Waiting'
<span class={`badge bg-${stageColor}-lt`}>{stage}</span>
</p>
<div>
<AvatarList stacked />
<PeopleAvatarList stacked />
</div>
</div>
<Progress class="card-progress" />
<Progress value={38} class="card-progress" />
</div>
+4 -2
View File
@@ -1,6 +1,8 @@
---
// Covers: icon / person-id / chart-data (left/right) / small-icon /
// description-value / trending / button branches.
import { personById } from '@shared/lib/people'
import type { SparklineType } from '@ui/ChartSparkline.astro'
import Icon from '@ui/Icon.astro'
import Avatar from '@ui/Avatar.astro'
import ChartSparkline from '@ui/ChartSparkline.astro'
@@ -14,7 +16,7 @@ interface Props {
class?: string
id?: string
personId?: number
chartType?: string
chartType?: SparklineType
chartPosition?: string
chartData?: string | number
smallIcon?: string
@@ -40,7 +42,7 @@ const avatarClass = [color ? `bg-${color}${lt ? '-lt' : ' text-white'}` : '', 'a
</div>
) : personId ? (
<div class="col-auto">
<Avatar personId={personId} />
<Avatar person={personById(personId)} />
</div>
) : chartData && chartPosition === 'left' ? (
<div class="col-auto">
+1 -1
View File
@@ -206,7 +206,7 @@ const { rtl = false } = Astro.props
<p class="h3 fw-normal">Sponsor Tabler and help us make a difference!</p>
<div class="mt-4">
<button class="btn w-100 pe-none" type="button" dir="ltr">
<Icon name="heart" type="filled" color="pink" class={rtl ? 'icon-end' : undefined} />
<Icon name="heart" filled color="pink" class={rtl ? 'icon-end' : undefined} />
Become a Sponsor
</button>
</div>
+2 -9
View File
@@ -1,23 +1,16 @@
---
import Avatar from '@ui/Avatar.astro'
import { people } from '@shared/lib/people'
import CardDropdown from '@ui/CardDropdown.astro'
import people from '@data/people.json'
import { requireIndex } from '@shared/lib/array'
import CardTitle from '@ui/CardTitle.astro'
interface Person {
full_name?: string
company?: string
photo?: string
[key: string]: unknown
}
interface Props {
personId?: number
}
const { personId = 0 } = Astro.props
const person = requireIndex(people as Person[], personId)
const person = requireIndex(people, personId)
---
<div class="card">
+1 -1
View File
@@ -1,6 +1,6 @@
---
import Icon from '@ui/Icon.astro'
import DropdownMenu from '@ui/DropdownMenu.astro'
import DropdownMenu from '@shared/components/demo/DropdownMenu.astro'
interface Props {
id: string
+2 -1
View File
@@ -1,4 +1,5 @@
---
import { personById } from '@shared/lib/people'
import Icon from '@ui/Icon.astro'
import Avatar from '@ui/Avatar.astro'
import CardTitle from '@ui/CardTitle.astro'
@@ -42,7 +43,7 @@ import { formatLongDate } from '@shared/lib/date-format'
</a>
</td>
<td>
<Avatar size="sm" personId={index} />
<Avatar size="sm" person={personById(index)} />
</td>
</tr>
)
@@ -1,4 +1,5 @@
---
import { personById } from '@shared/lib/people'
import CardSubtitle from '@ui/CardSubtitle.astro'
import Avatar from '@ui/Avatar.astro'
import ListGroup from '@ui/ListGroup.astro'
@@ -25,7 +26,7 @@ const leaderboard = crmDashboard.leaderboard
<div class="row align-items-center g-3">
<div class="col-auto fw-bold me-3">{index + 1}</div>
<div class="col-auto">
<Avatar personId={index + 1} color={item.avatar_color} size="sm" />
<Avatar person={personById(index + 1)} color={item.avatar_color} size="sm" />
</div>
<div class="col">
<div class="fw-medium">{item.name}</div>
+2 -9
View File
@@ -1,23 +1,16 @@
---
// person = people[person-id] (no -1: the object is passed straight to Avatar).
import Avatar from '@ui/Avatar.astro'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
interface Person {
full_name?: string
job_title?: string
photo?: string
[key: string]: unknown
}
interface Props {
personId?: number
right?: boolean
}
const { personId = 0, right } = Astro.props
const person = requireIndex(people as Person[], personId)
const person = requireIndex(people, personId)
---
<a class="card card-link" href="#">
+2 -9
View File
@@ -1,19 +1,12 @@
---
// person = people[person-id]; the cover photo is photos[person-id].file.
import { staticPath } from '@shared/lib/assets'
import { people } from '@shared/lib/people'
import Avatar from '@ui/Avatar.astro'
import people from '@data/people.json'
import photos from '@data/photos.json'
import { requireIndex } from '@shared/lib/array'
import CardTitle from '@ui/CardTitle.astro'
interface Person {
full_name?: string
job_title?: string
photo?: string
[key: string]: unknown
}
interface Photo {
file?: string
[key: string]: unknown
@@ -25,7 +18,7 @@ interface Props {
}
const { personId = 0, blurred } = Astro.props
const person = requireIndex(people as Person[], personId)
const person = requireIndex(people, personId)
const photo = requireIndex(photos as Photo[], personId)
---
+2 -9
View File
@@ -1,22 +1,15 @@
---
import Avatar from '@ui/Avatar.astro'
import people from '@data/people.json'
import { people } from '@shared/lib/people'
import { requireIndex } from '@shared/lib/array'
import CardTitle from '@ui/CardTitle.astro'
interface Person {
full_name?: string
job_title?: string
photo?: string
[key: string]: unknown
}
interface Props {
personId?: number
}
const { personId = 0 } = Astro.props
const person = requireIndex(people as Person[], personId)
const person = requireIndex(people, personId)
---
<div class="card">
+4 -14
View File
@@ -1,23 +1,13 @@
---
// person = people[person-id - 1] (default person-id = 25 → people[24]).
import Icon from '@ui/Icon.astro'
import type { FlagCountry } from '@shared/lib/tokens'
import { people } from '@shared/lib/people'
import Flag from '@ui/Flag.astro'
import people from '@data/people.json'
import { requireIndex } from '@shared/lib/array'
import CardTitle from '@ui/CardTitle.astro'
interface Person {
university?: string
company?: string
city?: string
country?: string
country_code?: string
birth_date?: string
time_zone?: string
[key: string]: unknown
}
const person = requireIndex(people as Person[], 24)
const person = requireIndex(people, 24)
---
<div class="card">
@@ -37,7 +27,7 @@ const person = requireIndex(people as Person[], 24)
</div>
<div class="mb-2">
<Icon name="map-pin" class="me-2 text-secondary" />
From: <strong><Flag size="xs" flag={person.country_code} /> {person.country}</strong>
From: <strong><Flag size="xs" flag={(person.country_code ?? '') as FlagCountry} /> {person.country}</strong>
</div>
<div class="mb-2">
<Icon name="calendar" class="me-2 text-secondary" />
+2 -9
View File
@@ -1,20 +1,13 @@
---
import Avatar from '@ui/Avatar.astro'
import { people } from '@shared/lib/people'
import Icon from '@ui/Icon.astro'
import ListGroup from '@ui/ListGroup.astro'
import ListGroupItem from '@ui/ListGroupItem.astro'
import CardTitle from '@ui/CardTitle.astro'
import people from '@data/people.json'
import commits from '@data/commits.json'
import { randomNumber } from '@shared/lib/pseudo-random'
interface Person {
full_name?: string
photo?: string
last_name?: string
[key: string]: unknown
}
interface Props {
offset?: number
hoverable?: boolean
@@ -38,7 +31,7 @@ const limit = 8
const colors = ['green', 'red', 'yellow', 'x', 'x']
const commitList = commits as { description: string }[]
const rows = (people as Person[]).slice(offset, offset + limit).map((person, idx) => {
const rows = people.slice(offset, offset + limit).map((person, idx) => {
const index = idx + 1 // forloop.index (1-based)
const color = colors[randomNumber(index + 5, 0, colors.length - 1)]
const checked = checkedIds?.includes(index) ?? false
+2 -8
View File
@@ -1,16 +1,10 @@
---
import Avatar from '@ui/Avatar.astro'
import { people } from '@shared/lib/people'
import CardTitle from '@ui/CardTitle.astro'
import people from '@data/people.json'
import { randomNumber, timeagoLabel } from '@shared/lib/pseudo-random'
import { requireIndex } from '@shared/lib/array'
interface Person {
full_name?: string
photo?: string
[key: string]: unknown
}
interface Props {
class?: string
}
@@ -24,7 +18,7 @@ const title = 'Top users'
const colors = ['green', 'red', 'yellow', 'x', 'x'] as const
const statusLabels: Record<(typeof colors)[number], string> = { green: 'Online', red: 'Busy', yellow: 'Away', x: 'Offline' }
const rows = (people as Person[]).slice(offset, offset + limit).map((person, idx) => {
const rows = people.slice(offset, offset + limit).map((person, idx) => {
const index = idx + 1 // forloop.index (1-based)
const status = requireIndex(colors, randomNumber(index + 5, 0, colors.length - 1))
return {

Some files were not shown because too many files have changed in this diff Show More