mirror of
https://github.com/tabler/tabler.git
synced 2026-08-29 13:21:29 +04:00
Narrow component prop types, remove unused props and dead code (#2838)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -4,11 +4,7 @@ import activity from '@data/activity.json'
|
||||
import people from '@data/people.json'
|
||||
import { timeagoLabel } from '@shared/lib/pseudo-random'
|
||||
|
||||
interface Props {
|
||||
limit?: number
|
||||
}
|
||||
|
||||
const { limit = 40 } = Astro.props
|
||||
const limit = 40
|
||||
|
||||
interface Person {
|
||||
full_name?: string
|
||||
|
||||
+8
-21
@@ -1,34 +1,33 @@
|
||||
---
|
||||
import Icon from './Icon.astro'
|
||||
import ButtonList from './ButtonList.astro'
|
||||
|
||||
/** alert-{type} / btn-{type} — matches defaultIcons below */
|
||||
type AlertType = 'success' | 'warning' | 'danger' | 'info'
|
||||
|
||||
interface Props {
|
||||
type?: string
|
||||
icon?: string
|
||||
type?: AlertType
|
||||
important?: boolean
|
||||
minor?: boolean
|
||||
showClose?: boolean
|
||||
avatar?: boolean
|
||||
class?: string
|
||||
title?: string
|
||||
description?: string
|
||||
list?: string[]
|
||||
action?: string
|
||||
link?: string
|
||||
buttons?: boolean
|
||||
}
|
||||
|
||||
const { type = 'success', icon: iconProp, important, minor, showClose, avatar, class: className, title = 'This is a custom alert box!', description, list, action, link, buttons } = Astro.props
|
||||
const { type = 'success', important, minor, showClose, class: className, title = 'This is a custom alert box!', description, list, action, link } = Astro.props
|
||||
|
||||
const defaultIcons: Record<string, string> = {
|
||||
const defaultIcons: Record<AlertType, string> = {
|
||||
success: 'check',
|
||||
warning: 'alert-triangle',
|
||||
danger: 'alert-circle',
|
||||
info: 'info-circle',
|
||||
}
|
||||
const icon = iconProp ?? defaultIcons[type]
|
||||
const icon = defaultIcons[type]
|
||||
|
||||
const classes = ['alert', important ? 'alert-important' : minor ? 'alert-minor' : undefined, `alert-${type}`, showClose && 'alert-dismissible', avatar && 'alert-avatar', className]
|
||||
const classes = ['alert', important ? 'alert-important' : minor ? 'alert-minor' : undefined, `alert-${type}`, showClose && 'alert-dismissible', className]
|
||||
---
|
||||
|
||||
<div class:list={classes} role="alert">
|
||||
@@ -65,17 +64,5 @@ const classes = ['alert', important ? 'alert-important' : minor ? 'alert-minor'
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
{
|
||||
buttons && (
|
||||
<ButtonList>
|
||||
<a href="#" class={`btn btn-${type}`}>
|
||||
Okay
|
||||
</a>
|
||||
<a href="#" class="btn">
|
||||
Cancel
|
||||
</a>
|
||||
</ButtonList>
|
||||
)
|
||||
}
|
||||
{showClose && <a class="btn-close" data-bs-dismiss="alert" aria-label="close" />}
|
||||
</div>
|
||||
|
||||
+10
-11
@@ -9,22 +9,22 @@ interface Person {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** core/scss/_variables.scss `$avatar-sizes` map keys */
|
||||
export type AvatarSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
|
||||
|
||||
interface Props {
|
||||
src?: string
|
||||
placeholder?: string | undefined
|
||||
personId?: number
|
||||
person?: Person | undefined
|
||||
link?: boolean
|
||||
dropdown?: boolean
|
||||
size?: string | undefined
|
||||
size?: AvatarSize | undefined
|
||||
thumb?: boolean
|
||||
class?: string
|
||||
shape?: string
|
||||
color?: string | undefined
|
||||
square?: boolean
|
||||
status?: string
|
||||
statusText?: string
|
||||
statusIcon?: string
|
||||
statusLabel?: string
|
||||
brand?: string
|
||||
icon?: string | undefined
|
||||
@@ -34,7 +34,7 @@ interface Props {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const { src: srcProp, placeholder: placeholderProp, personId, person: personProp, link: linkProp = false, dropdown, size, thumb, class: className, shape, color, square, status, statusText, statusIcon, statusLabel, brand, icon, base = '.', ...rest } = Astro.props
|
||||
const { src: srcProp, placeholder: placeholderProp, personId, person: personProp, link: linkProp = false, size, thumb, class: className, shape, color, square, status, statusLabel, brand, icon, base = '.', ...rest } = Astro.props
|
||||
|
||||
let src = srcProp
|
||||
let placeholder = placeholderProp
|
||||
@@ -47,14 +47,13 @@ if (person) {
|
||||
}
|
||||
}
|
||||
|
||||
const link = linkProp || Boolean(dropdown)
|
||||
const El = link ? 'a' : 'span'
|
||||
const El = linkProp ? 'a' : 'span'
|
||||
|
||||
const classes = ['avatar', size && `avatar-${size}`, thumb && 'avatar-thumb', className, shape && `avatar-${shape}`, color && `bg-${color}-lt`, square && 'avatar-square']
|
||||
---
|
||||
|
||||
<El class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} data-bs-toggle={dropdown ? 'dropdown' : undefined} {...rest}
|
||||
>{status && <span class={`badge bg-${status}`}>{statusText ? statusText : statusIcon ? <Icon name={statusIcon} class="avatar-status-icon" /> : <span class="visually-hidden">{statusLabel ?? status}</span>}</span>}{
|
||||
brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />
|
||||
}{src ? null : placeholder ? placeholder : icon ? <Icon name={icon} class="avatar-icon" /> : <Icon name="user" class="avatar-icon" />}</El
|
||||
<El class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} {...rest}
|
||||
>{status && <span class={`badge bg-${status}`} aria-label={statusLabel ?? status} />}{brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />}{
|
||||
src ? null : placeholder ? placeholder : icon ? <Icon name={icon} class="avatar-icon" /> : <Icon name="user" class="avatar-icon" />
|
||||
}</El
|
||||
>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Pass children to override and render a custom list.
|
||||
// NOTE: when `size` is omitted we pass NO size to Avatar — callers that omit size should not get avatar-N suffix classes.
|
||||
import Avatar from './Avatar.astro'
|
||||
import type { AvatarSize } from './Avatar.astro'
|
||||
import people from '@data/people.json'
|
||||
|
||||
interface Person {
|
||||
@@ -16,7 +17,7 @@ interface Props {
|
||||
offset?: number | undefined
|
||||
stacked?: boolean
|
||||
/** avatar-list-{size} + forwarded to default Avatars */
|
||||
size?: string
|
||||
size?: AvatarSize | undefined
|
||||
class?: string
|
||||
/** placeholder avatar appended after the list */
|
||||
text?: string
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
---
|
||||
import Icon from './Icon.astro'
|
||||
import type { AvatarSize } from './Avatar.astro'
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
size?: string
|
||||
size?: AvatarSize | undefined
|
||||
}
|
||||
|
||||
const { class: className, size } = Astro.props
|
||||
|
||||
@@ -7,16 +7,14 @@ interface Props {
|
||||
/** theme color the pattern ramps up to, e.g. 'primary' */
|
||||
color?: string
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl'
|
||||
/** element to render instead of div */
|
||||
as?: string
|
||||
class?: string
|
||||
/** remaining attributes (style, data-*, …) are forwarded to the element */
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const { pattern, color, size, as: Element = 'div', class: className, ...rest }: Props = Astro.props
|
||||
const { pattern, color, size, class: className, ...rest }: Props = Astro.props
|
||||
---
|
||||
|
||||
<Element class:list={[`bg-pattern-${pattern}`, color && `bg-pattern-${color}`, size && `bg-pattern-${size}`, className]} {...rest}>
|
||||
<div class:list={[`bg-pattern-${pattern}`, color && `bg-pattern-${color}`, size && `bg-pattern-${size}`, className]} {...rest}>
|
||||
<slot />
|
||||
</Element>
|
||||
</div>
|
||||
|
||||
+2
-17
@@ -1,13 +1,5 @@
|
||||
---
|
||||
import Icon from './Icon.astro'
|
||||
import Avatar from './Avatar.astro'
|
||||
import people from '@data/people.json'
|
||||
|
||||
interface Person {
|
||||
full_name?: string
|
||||
photo?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
interface Props {
|
||||
text?: string
|
||||
@@ -18,18 +10,11 @@ interface Props {
|
||||
light?: boolean
|
||||
class?: string
|
||||
icon?: string
|
||||
/** person-id — renders an inline avatar badge for people[personId - 1] */
|
||||
personId?: number
|
||||
/** addon text in a <span class="badge-addon"> */
|
||||
addon?: string
|
||||
addonColor?: string
|
||||
}
|
||||
|
||||
const { text, color, scale, light, class: className, icon, personId, addon, addonColor } = Astro.props
|
||||
|
||||
const person = personId ? (people as Person[])[personId - 1] : undefined
|
||||
const { text, color, scale, light, class: className, icon } = Astro.props
|
||||
|
||||
const classes = ['badge', scale && `badge-${scale}`, color && `bg-${color}${light ? '-lt' : ''} text-${color}${light ? '-lt' : ''}-fg`, className]
|
||||
---
|
||||
|
||||
<span class:list={classes}>{icon && <Icon name={icon} />}{personId && <Avatar personId={personId} />}{text ? text : person?.full_name}{addon && <span class={`badge-addon ${addonColor ? `bg-${addonColor}` : ''}`}>{addon}</span>}</span>
|
||||
<span class:list={classes}>{icon && <Icon name={icon} />}{text}</span>
|
||||
|
||||
+6
-30
@@ -4,6 +4,9 @@
|
||||
// TODO: color=false special case — pass no color prop instead.
|
||||
import Icon from './Icon.astro'
|
||||
|
||||
/** core/scss/ui/_buttons.scss `.btn-{size}` modifier classes — 'md' is the default (no class emitted) */
|
||||
type ButtonSize = 'sm' | 'md' | 'lg' | 'xl'
|
||||
|
||||
interface Props {
|
||||
text?: string
|
||||
href?: string
|
||||
@@ -15,24 +18,13 @@ interface Props {
|
||||
color?: string | undefined
|
||||
outline?: boolean
|
||||
ghost?: boolean
|
||||
/** btn-{height} right after btn */
|
||||
height?: string
|
||||
size?: string
|
||||
size?: ButtonSize | undefined
|
||||
block?: boolean
|
||||
disabled?: boolean
|
||||
square?: boolean
|
||||
loading?: boolean
|
||||
action?: boolean
|
||||
pill?: boolean
|
||||
/** btn-link */
|
||||
link?: boolean
|
||||
class?: string
|
||||
icon?: string
|
||||
iconColor?: string
|
||||
iconEnd?: string
|
||||
iconOnly?: boolean
|
||||
/** animated dots after the text */
|
||||
dots?: boolean
|
||||
/** data-bs-toggle="modal" data-bs-target="#modal-{modalId}" (modal-id param) */
|
||||
modalId?: string
|
||||
/** data-bs-toggle="toast" data-bs-target="#toast-{toastId}" (toast-id param) */
|
||||
@@ -43,33 +35,18 @@ interface Props {
|
||||
dropdown?: boolean
|
||||
}
|
||||
|
||||
const { text = 'Button', href, external, element, type, id, color, outline, ghost, height, size, block, disabled, square, loading, action, pill, link, class: className, icon, iconColor, iconEnd, iconOnly, dots, modalId, toastId, dismiss, dropdown } = Astro.props
|
||||
const { text = 'Button', href, external, element, type, id, color, outline, ghost, size, block, class: className, icon, iconColor, iconEnd, iconOnly, modalId, toastId, dismiss, dropdown } = Astro.props
|
||||
|
||||
// Without a real destination the control is an action, so render <button>; internal hrefs are prefixed with '/'.
|
||||
const Element = element ?? (href ? 'a' : 'button')
|
||||
const resolvedHref = href ? (external ? href : `/${href}`) : '#'
|
||||
|
||||
const classes = [
|
||||
'btn',
|
||||
height && `btn-${height}`,
|
||||
color && `btn-${outline ? 'outline-' : ghost ? 'ghost-' : ''}${color}`,
|
||||
disabled && 'disabled',
|
||||
square && 'btn-square',
|
||||
loading && 'btn-loading',
|
||||
action && 'btn-action',
|
||||
pill && 'btn-pill',
|
||||
size && `btn-${size}`,
|
||||
className,
|
||||
block && 'w-100',
|
||||
link && 'btn-link',
|
||||
iconOnly && 'btn-icon',
|
||||
]
|
||||
const classes = ['btn', color && `btn-${outline ? 'outline-' : ghost ? 'ghost-' : ''}${color}`, size && size !== 'md' && `btn-${size}`, className, block && 'w-100', iconOnly && 'btn-icon']
|
||||
---
|
||||
|
||||
<Element
|
||||
href={Element === 'a' ? resolvedHref : undefined}
|
||||
type={Element === 'button' ? (type ?? 'button') : undefined}
|
||||
disabled={Element === 'button' && disabled ? true : undefined}
|
||||
id={id}
|
||||
class:list={classes}
|
||||
target={external ? '_blank' : undefined}
|
||||
@@ -81,6 +58,5 @@ const classes = [
|
||||
>
|
||||
{icon && <Icon name={icon} color={iconColor} />}
|
||||
{!iconOnly && text}
|
||||
{!iconOnly && dots && <span class="animated-dots" />}
|
||||
{!iconOnly && iconEnd && <Icon name={iconEnd} class="icon-end" />}
|
||||
</Element>
|
||||
|
||||
@@ -4,17 +4,14 @@
|
||||
interface Props {
|
||||
/** use .btn-group-vertical instead of .btn-group */
|
||||
vertical?: boolean
|
||||
/** btn-group-{size}: sm | lg | xl */
|
||||
size?: string
|
||||
class?: string
|
||||
role?: astroHTML.JSX.AriaRole
|
||||
/** remaining attributes (aria-label, …) are forwarded */
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const { vertical, size, class: className, role = 'group', ...rest } = Astro.props
|
||||
const { vertical, class: className, ...rest } = Astro.props
|
||||
---
|
||||
|
||||
<div class:list={[vertical ? 'btn-group-vertical' : 'btn-group', size && `btn-group-${size}`, className]} role={role} {...rest}>
|
||||
<div class:list={[vertical ? 'btn-group-vertical' : 'btn-group', className]} role="group" {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -7,9 +7,11 @@ import type { HTMLTag } from 'astro/types'
|
||||
// literally named `as` and silently falls back to untyped props.
|
||||
type PolymorphicProps = { as?: HTMLTag }
|
||||
|
||||
/** core/scss/ui/_cards.scss `.card-{size}` body padding modifier classes */
|
||||
type CardSize = 'sm' | 'md' | 'lg'
|
||||
|
||||
interface Props extends PolymorphicProps {
|
||||
/** card-{size} body padding: sm | md | lg */
|
||||
size?: string
|
||||
size?: CardSize | undefined
|
||||
class?: string
|
||||
/** remaining attributes (id, action, data-*, …) are forwarded to the element */
|
||||
[key: string]: unknown
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
import Icon from './Icon.astro'
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { icon = 'dots-vertical', class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
const icon = 'dots-vertical'
|
||||
---
|
||||
|
||||
<div class:list={['dropdown', className]}>
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
// Card footer (.card-footer).
|
||||
|
||||
interface Props {
|
||||
/** card-footer-transparent */
|
||||
transparent?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { transparent, class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
---
|
||||
|
||||
<div class:list={['card-footer', transparent && 'card-footer-transparent', className]}>
|
||||
<div class:list={['card-footer', className]}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -9,15 +9,13 @@ type PolymorphicProps = { as?: HTMLTag }
|
||||
|
||||
interface Props extends PolymorphicProps {
|
||||
title?: string
|
||||
/** card-header-light */
|
||||
light?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { title, as: TitleTag = 'h3', light, class: className }: Props = Astro.props
|
||||
const { title, as: TitleTag = 'h3', class: className }: Props = Astro.props
|
||||
---
|
||||
|
||||
<div class:list={['card-header', light && 'card-header-light', className]}>
|
||||
<div class:list={['card-header', className]}>
|
||||
{title && <TitleTag class:list={['card-title']}>{title}</TitleTag>}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import Icon from './Icon.astro'
|
||||
interface Props {
|
||||
icon?: string
|
||||
/** card-stamp-{size}; only 'lg' exists in SCSS (13rem instead of 7rem) */
|
||||
size?: string
|
||||
size?: 'lg' | undefined
|
||||
/** bg-{color} on the icon wrapper; SCSS default is secondary */
|
||||
color?: string
|
||||
/** text-{textColor} on the icon wrapper (e.g. color="white" textColor="primary") */
|
||||
|
||||
@@ -1,67 +1,26 @@
|
||||
---
|
||||
// Self-contained carousel (.carousel). Default slot holds the .carousel-item elements
|
||||
// (the caller marks the first one "active" — see CarouselCard.astro / hero/Side.astro);
|
||||
// indicators/controls are generated from props. A "controls" slot overrides the default
|
||||
// icon-span controls with custom markup (e.g. an <Icon>-based pair).
|
||||
// a "controls" slot renders custom prev/next markup (e.g. an <Icon>-based pair).
|
||||
|
||||
interface Props {
|
||||
id?: string
|
||||
/** slide count, used to generate indicator buttons */
|
||||
slideCount: number
|
||||
fade?: boolean
|
||||
/** data-bs-interval in ms, or false to disable autoplay */
|
||||
interval?: number | false
|
||||
indicators?: boolean
|
||||
indicatorsVariant?: 'dot' | 'thumb'
|
||||
indicatorsVertical?: boolean
|
||||
/** ratio ratio-4x3 on each indicator button, typically paired with indicatorsVariant="thumb" */
|
||||
indicatorsThumbRatio?: boolean
|
||||
/** background-image per slide, used when indicatorsVariant="thumb" */
|
||||
indicatorsImages?: string[]
|
||||
controls?: boolean
|
||||
class?: string
|
||||
/** remaining attributes forwarded to the element */
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const { id, slideCount, fade, interval, indicators, indicatorsVariant, indicatorsVertical, indicatorsThumbRatio, indicatorsImages, controls, class: className, ...rest } = Astro.props
|
||||
const { id, interval, class: className, ...rest } = Astro.props
|
||||
|
||||
const target = id ? `#${id}` : undefined
|
||||
const slideIndexes = Array.from({ length: slideCount }, (_, i) => i)
|
||||
const hasCustomControls = Astro.slots.has('controls')
|
||||
---
|
||||
|
||||
<div id={id} class:list={['carousel', 'slide', fade && 'carousel-fade', className]} data-bs-ride="carousel" data-bs-interval={interval === false ? 'false' : interval} {...rest}>
|
||||
{
|
||||
indicators && (
|
||||
<div class:list={['carousel-indicators', indicatorsVertical && 'carousel-indicators-vertical', indicatorsVariant === 'dot' && 'carousel-indicators-dot', indicatorsVariant === 'thumb' && 'carousel-indicators-thumb']}>
|
||||
{slideIndexes.map((i) => (
|
||||
<button type="button" data-bs-target={target} data-bs-slide-to={i} class:list={[indicatorsThumbRatio && 'ratio ratio-4x3', i === 0 && 'active']} style={indicatorsVariant === 'thumb' && indicatorsImages?.[i] ? `background-image: url(${indicatorsImages[i]})` : undefined} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div id={id} class:list={['carousel', 'slide', className]} data-bs-ride="carousel" data-bs-interval={interval === false ? 'false' : interval} {...rest}>
|
||||
<div class="carousel-inner">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{
|
||||
hasCustomControls ? (
|
||||
<slot name="controls" />
|
||||
) : (
|
||||
controls && (
|
||||
<Fragment>
|
||||
<a class="carousel-control-prev" href={target} role="button" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true" />
|
||||
<span class="visually-hidden">Previous</span>
|
||||
</a>
|
||||
<a class="carousel-control-next" href={target} role="button" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true" />
|
||||
<span class="visually-hidden">Next</span>
|
||||
</a>
|
||||
</Fragment>
|
||||
)
|
||||
)
|
||||
}
|
||||
{hasCustomControls && <slot name="controls" />}
|
||||
</div>
|
||||
|
||||
@@ -5,36 +5,21 @@ interface Props {
|
||||
id?: string | undefined;
|
||||
type?: string;
|
||||
color?: string | undefined;
|
||||
height?: number;
|
||||
small?: boolean;
|
||||
wide?: boolean;
|
||||
data?: string | number;
|
||||
percentage?: string | number;
|
||||
/**
|
||||
* Sparklines are typically decorative, sitting next to a visible stat
|
||||
* number that already conveys the value — so they're hidden from
|
||||
* assistive tech by default. Set to `false` (with `label`) when the
|
||||
* sparkline is the only representation of the data.
|
||||
*/
|
||||
decorative?: boolean;
|
||||
/** Accessible name, used only when `decorative` is explicitly `false`. */
|
||||
label?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
type = 'bar',
|
||||
color = 'primary',
|
||||
height: heightProp,
|
||||
small,
|
||||
wide,
|
||||
data: dataProp,
|
||||
percentage,
|
||||
decorative = true,
|
||||
label,
|
||||
} = Astro.props;
|
||||
|
||||
const height = heightProp ?? (small ? 1.5 : 2.5);
|
||||
const height = small ? 1.5 : 2.5;
|
||||
const heightPx = Math.round(height * 16);
|
||||
|
||||
const data = percentage ?? dataProp;
|
||||
@@ -45,17 +30,12 @@ const chartType = type === 'donut' ? 'radialBar' : type;
|
||||
const classes = [
|
||||
'chart-sparkline',
|
||||
isSquare && 'chart-sparkline-square',
|
||||
wide && 'chart-sparkline-wide',
|
||||
small && 'chart-sparkline-sm',
|
||||
]
|
||||
|
||||
const seriesData = String(data ?? '').split(',').map(Number);
|
||||
const chartKey = `sparkline-${id}`;
|
||||
|
||||
const ariaHidden = decorative ? true : undefined;
|
||||
const ariaRole = decorative ? undefined : 'img';
|
||||
const ariaLabel = decorative ? undefined : (label ?? 'Chart');
|
||||
|
||||
const chartOptions = id
|
||||
? {
|
||||
chart: {
|
||||
@@ -87,7 +67,7 @@ const chartOptions = id
|
||||
: undefined;
|
||||
---
|
||||
|
||||
{id && <div class:list={classes} id={chartKey} role={ariaRole} aria-label={ariaLabel} aria-hidden={ariaHidden} />}
|
||||
{id && <div class:list={classes} id={chartKey} aria-hidden="true" />}
|
||||
{
|
||||
id && (
|
||||
<CaptureScript>
|
||||
|
||||
@@ -5,15 +5,14 @@ import CaptureScript from '../components/CaptureScript.astro'
|
||||
interface Props {
|
||||
value?: string
|
||||
id?: string | number
|
||||
alpha?: boolean
|
||||
format?: string | false
|
||||
swatchesOnly?: boolean
|
||||
class?: string
|
||||
/** Accessible name for the input; falls back to a generic label when the caller doesn't wrap this in a labelled FormGroup */
|
||||
ariaLabel?: string
|
||||
}
|
||||
|
||||
const { value, id = 'default', alpha = false, format = false, swatchesOnly, class: className, ariaLabel } = Astro.props
|
||||
const { value, id = 'default', format = false, class: className, ariaLabel } = Astro.props
|
||||
const alpha = false
|
||||
|
||||
const colors = site.colors as Record<string, { prop: string }>
|
||||
const swatchProps = Object.values(colors).map((color) => color.prop)
|
||||
@@ -25,7 +24,7 @@ const colorpickerSelector = `#colorpicker-${id}`
|
||||
<input type="text" class={`form-control d-block${className ? ` ${className}` : ''}`} id={colorpickerId} value={value} aria-label={ariaLabel ?? 'Color value'} />
|
||||
<CaptureScript>
|
||||
<!-- BEGIN COLORPICKER -->
|
||||
<script is:inline define:vars={{ colorpickerId, colorpickerSelector, alpha, format, swatchesOnly, swatchProps }}>
|
||||
<script is:inline define:vars={{ colorpickerId, colorpickerSelector, alpha, format, swatchProps }}>
|
||||
function initColorpicker() {
|
||||
window.tabler_colorpicker ??= {}
|
||||
|
||||
@@ -40,7 +39,6 @@ const colorpickerSelector = `#colorpicker-${id}`
|
||||
selectInput: false,
|
||||
alpha,
|
||||
...(format ? { format } : {}),
|
||||
...(swatchesOnly ? { swatchesOnly: true } : {}),
|
||||
swatches,
|
||||
})
|
||||
window.tabler_colorpicker[colorpickerId] = colorpickerSelector
|
||||
|
||||
@@ -5,7 +5,6 @@ import CaptureScript from '../components/CaptureScript.astro';
|
||||
interface Props {
|
||||
id?: string;
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
class?: string;
|
||||
/** 'icon' | 'icon-prepend' | undefined (plain) */
|
||||
layout?: string;
|
||||
@@ -15,12 +14,13 @@ interface Props {
|
||||
const {
|
||||
id,
|
||||
value = '2020-06-20',
|
||||
placeholder = 'Select a date',
|
||||
class: className,
|
||||
layout,
|
||||
inline,
|
||||
} = Astro.props;
|
||||
|
||||
const placeholder = 'Select a date';
|
||||
|
||||
const chevronLeft =
|
||||
'<!-- Download SVG icon from http://tabler.io/icons/icon/chevron-left -->\n\t<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false" class="icon"><path d="M15 6l-6 6l6 6" /></svg>';
|
||||
const chevronRight =
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
interface Props {
|
||||
id?: string
|
||||
label?: string
|
||||
value?: string
|
||||
}
|
||||
|
||||
const { id, label = 'Select time range', value = 'Last 7 days' } = Astro.props
|
||||
const { id, label = 'Select time range' } = Astro.props
|
||||
const value = 'Last 7 days'
|
||||
---
|
||||
|
||||
<div class="dropdown">
|
||||
|
||||
@@ -11,12 +11,10 @@ interface Props {
|
||||
arrow?: boolean
|
||||
dark?: boolean
|
||||
class?: string
|
||||
menu?: string[]
|
||||
check?: boolean
|
||||
radio?: boolean
|
||||
people?: boolean
|
||||
flag?: boolean
|
||||
type?: string
|
||||
header?: boolean
|
||||
icons?: boolean
|
||||
badge?: boolean
|
||||
@@ -25,38 +23,17 @@ interface Props {
|
||||
separated?: boolean
|
||||
}
|
||||
|
||||
const { right, show, arrow, dark, class: className, menu, check, radio, people: showPeople, flag: showFlags, type, header, icons, badge, active, disabled, separated } = Astro.props
|
||||
const { right, show, arrow, dark, class: className, check, radio, people: showPeople, flag: showFlags, header, icons, badge, active, disabled, separated } = Astro.props
|
||||
|
||||
const classes = ['dropdown-menu', right && 'dropdown-menu-end', show && 'dropdown-menu-demo', arrow && 'dropdown-menu-arrow', className]
|
||||
|
||||
const menuItems = menu
|
||||
const peopleItems = (people as { id: string; full_name: string }[]).slice(0, 5)
|
||||
const countryItems = (countries as { name: string; flag: string }[]).slice(0, 5)
|
||||
---
|
||||
|
||||
<div class:list={classes} data-bs-theme={dark ? 'dark' : undefined}>
|
||||
{
|
||||
menuItems ? (
|
||||
menuItems.map((item) =>
|
||||
item === '|' ? (
|
||||
<div class="dropdown-divider" />
|
||||
) : item.includes('h:') ? (
|
||||
<h3 class="dropdown-header">{item.split('h:').join('')}</h3>
|
||||
) : item.includes('a:') ? (
|
||||
<button type="button" class="dropdown-item active">
|
||||
{item.split('a:').join('')}
|
||||
</button>
|
||||
) : item.includes('d:') ? (
|
||||
<button type="button" class="dropdown-item text-danger">
|
||||
{item.split('d:').join('')}
|
||||
</button>
|
||||
) : (
|
||||
<button type="button" class="dropdown-item">
|
||||
{item}
|
||||
</button>
|
||||
),
|
||||
)
|
||||
) : check || radio ? (
|
||||
check || radio ? (
|
||||
[1, 2, 3].map((i) => (
|
||||
<label class="dropdown-item">
|
||||
<input class="form-check-input m-0 me-2" type={radio ? 'radio' : 'checkbox'} name={radio ? 'dropdown-menu-radio' : undefined} /> Option {i}
|
||||
@@ -74,7 +51,7 @@ const countryItems = (countries as { name: string; flag: string }[]).slice(0, 5)
|
||||
<Flag flag={country.flag} size="xs" /> {country.name}
|
||||
</button>
|
||||
))
|
||||
) : type === 'text' ? null : (
|
||||
) : (
|
||||
<>
|
||||
{header && <span class="dropdown-header">Dropdown header</span>}
|
||||
<button type="button" class="dropdown-item">
|
||||
|
||||
@@ -6,10 +6,10 @@ interface Props {
|
||||
custom?: boolean
|
||||
text?: string
|
||||
description?: string
|
||||
label?: string
|
||||
}
|
||||
|
||||
const { id = 'default', multiple, custom, text = 'Text', description = 'Description', label = 'Upload file' } = Astro.props
|
||||
const { id = 'default', multiple, custom, text = 'Text', description = 'Description' } = Astro.props
|
||||
const label = 'Upload file'
|
||||
|
||||
const dropzoneId = `dropzone-${id}`
|
||||
const dropzoneSelector = `#dropzone-${id}`
|
||||
|
||||
@@ -6,7 +6,6 @@ import Illustration from './Illustration.astro'
|
||||
interface Props {
|
||||
icon?: string
|
||||
height?: number | string
|
||||
bordered?: boolean
|
||||
class?: string
|
||||
/** illustration file name, e.g. "computer-fix.svg" */
|
||||
illustration?: string | undefined
|
||||
@@ -18,9 +17,9 @@ interface Props {
|
||||
buttonIcon?: string
|
||||
}
|
||||
|
||||
const { icon = 'mood-sad', height = 256, bordered, class: className, illustration, iconText, title = 'No results found', subtitle = "Try adjusting your search or filter to find what you're looking for.", buttonText = 'Search again', buttonIcon = 'search' } = Astro.props
|
||||
const { icon = 'mood-sad', height = 256, class: className, illustration, iconText, title = 'No results found', subtitle = "Try adjusting your search or filter to find what you're looking for.", buttonText = 'Search again', buttonIcon = 'search' } = Astro.props
|
||||
|
||||
const classes = ['empty', bordered && 'empty-bordered', className]
|
||||
const classes = ['empty', className]
|
||||
---
|
||||
|
||||
<div class:list={classes}>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
import type { AvatarSize } from './Avatar.astro'
|
||||
|
||||
interface Props {
|
||||
flag?: string | undefined
|
||||
size?: string
|
||||
/** core/scss/_variables.scss `$flag-sizes` (aliased to `$avatar-sizes`) */
|
||||
size?: AvatarSize | undefined
|
||||
class?: string
|
||||
label?: string | undefined
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
interface Props {
|
||||
text?: string
|
||||
position?: string
|
||||
color?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { text = 'Label', position, color, class: className } = Astro.props
|
||||
const { text = 'Label', position, class: className } = Astro.props
|
||||
|
||||
const classes = ['hr-text', position && `hr-text-${position.toLowerCase()}`, color && `text-${color}`, className]
|
||||
const classes = ['hr-text', position && `hr-text-${position.toLowerCase()}`, className]
|
||||
---
|
||||
|
||||
<div class:list={classes}>{text}</div>
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
---
|
||||
import icons from '@data/icons.json'
|
||||
|
||||
/** core/scss/ui/_icons.scss `.icon-{size}` modifier classes */
|
||||
export type IconSize = 'sm' | 'md' | 'lg'
|
||||
|
||||
interface Props {
|
||||
name: string
|
||||
type?: 'outline' | 'filled'
|
||||
class?: string | undefined
|
||||
color?: string | undefined
|
||||
size?: string
|
||||
size?: IconSize | undefined
|
||||
inline?: boolean
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -4,13 +4,12 @@ import Icon from './Icon.astro'
|
||||
interface Props {
|
||||
pills?: boolean
|
||||
tabs?: boolean
|
||||
header?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { pills, tabs, header, class: className } = Astro.props
|
||||
const { pills, tabs, class: className } = Astro.props
|
||||
|
||||
const classes = ['nav', pills ? 'nav-pills' : tabs ? 'nav-tabs' : undefined, pills && header ? 'card-header-pills' : tabs && header ? 'card-header-tabs' : undefined, className]
|
||||
const classes = ['nav', pills ? 'nav-pills' : tabs ? 'nav-tabs' : undefined, className]
|
||||
---
|
||||
|
||||
<ul class:list={classes}>
|
||||
|
||||
@@ -1,39 +1,33 @@
|
||||
---
|
||||
import Icon from './Icon.astro'
|
||||
import { includeArgCount } from '@shared/lib/include-args'
|
||||
|
||||
interface Props {
|
||||
items?: string[]
|
||||
icons?: string[]
|
||||
disabled?: number[]
|
||||
hover?: string
|
||||
default?: number
|
||||
vertical?: boolean
|
||||
size?: string
|
||||
/** core/scss/ui/_segmented.scss `.nav-{size}` modifier classes */
|
||||
size?: 'sm' | 'lg' | undefined
|
||||
fullWidth?: boolean
|
||||
name?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { items, icons, disabled, hover = '', default: defaultIndex = 1, vertical, size, fullWidth, name, class: className } = Astro.props
|
||||
|
||||
// When `size` is omitted, append `nav-{argCount}` (e.g. nav-1, nav-2). An explicit size uses nav-sm/nav-lg.
|
||||
const includeArgKeys = ['items', 'icons', 'disabled', 'hover', 'default', 'vertical', 'size', 'fullWidth', 'class', 'name'] as const
|
||||
const argCount = includeArgCount(Astro.props as Record<string, unknown>, includeArgKeys)
|
||||
const sizeToken = size ? `nav-${size}` : `nav-${argCount}`
|
||||
const { items, icons, disabled, default: defaultIndex = 1, vertical, size, fullWidth, name, class: className } = Astro.props
|
||||
|
||||
const itemsArr = items ?? []
|
||||
const iconsArr = icons ?? []
|
||||
const count = Math.max(itemsArr.length, iconsArr.length)
|
||||
|
||||
const navClasses = ['nav', 'nav-segmented', vertical && 'nav-segmented-vertical', sizeToken, fullWidth && 'w-100', className]
|
||||
const navClasses = ['nav', 'nav-segmented', vertical && 'nav-segmented-vertical', size && `nav-${size}`, fullWidth && 'w-100', className]
|
||||
|
||||
const rows = Array.from({ length: count }, (_, i) => {
|
||||
const forloopIndex = i + 1
|
||||
const index = String(forloopIndex)
|
||||
const isDisabled = disabled?.includes(forloopIndex) ?? false
|
||||
const isDefault = forloopIndex === defaultIndex
|
||||
const linkClasses = ['nav-link', isDisabled && 'disabled', isDefault && !name && 'active', hover === index && 'hover']
|
||||
const linkClasses = ['nav-link', isDisabled && 'disabled', isDefault && !name && 'active']
|
||||
return { forloopIndex, index, isDisabled, isDefault, linkClasses, icon: iconsArr[i], item: itemsArr[i] }
|
||||
})
|
||||
---
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
// Offcanvas container (.offcanvas). Renders inline at the call site (unlike Modal, which drains to the end of body).
|
||||
|
||||
interface Props {
|
||||
/** offcanvas-{direction}: start | end | top | bottom */
|
||||
direction?: string
|
||||
/** responsive variant offcanvas-{size} (lg | xl | xxl) — replaces the base .offcanvas class */
|
||||
size?: string
|
||||
/** offcanvas-narrow (20rem width) */
|
||||
narrow?: boolean
|
||||
/** core/scss/bootstrap/_offcanvas.scss `.offcanvas-{direction}` modifier classes */
|
||||
direction?: 'start' | 'end' | 'top' | 'bottom' | undefined
|
||||
/** responsive variant offcanvas-{size} ($grid-breakpoints minus xs) — replaces the base .offcanvas class */
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | undefined
|
||||
show?: boolean
|
||||
class?: string
|
||||
/** defaults to "-1" when not provided */
|
||||
@@ -18,11 +16,11 @@ interface Props {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const { direction, size, narrow, show, class: className, tabindex, role, ...rest } = Astro.props
|
||||
const { direction, size, show, class: className, tabindex, role, ...rest } = Astro.props
|
||||
---
|
||||
|
||||
<!-- BEGIN OFFCANVAS -->
|
||||
<div class:list={[size ? `offcanvas-${size}` : 'offcanvas', direction && `offcanvas-${direction}`, narrow && 'offcanvas-narrow', show && 'show', className]} tabindex={tabindex ?? '-1'} role={role ?? 'dialog'} {...rest}>
|
||||
<div class:list={[size ? `offcanvas-${size}` : 'offcanvas', direction && `offcanvas-${direction}`, show && 'show', className]} tabindex={tabindex ?? '-1'} role={role ?? 'dialog'} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
<!-- END OFFCANVAS -->
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
// Offcanvas footer (.offcanvas-footer).
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { class: className } = Astro.props
|
||||
---
|
||||
|
||||
<div class:list={['offcanvas-footer', className]}>
|
||||
<slot />
|
||||
</div>
|
||||
@@ -1,8 +1,11 @@
|
||||
---
|
||||
import type { AvatarSize } from './Avatar.astro'
|
||||
|
||||
interface Props {
|
||||
payment?: string
|
||||
dark?: boolean
|
||||
size?: string
|
||||
/** core/scss/_variables.scss `$payment-sizes` (aliased to `$avatar-sizes`) */
|
||||
size?: AvatarSize | undefined
|
||||
class?: string
|
||||
label?: string | undefined
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ interface Photo {
|
||||
title?: string
|
||||
}
|
||||
|
||||
/** core/scss/_variables.scss `$aspect-ratios` map keys */
|
||||
type PhotoRatio = '1x1' | '2x1' | '1x2' | '3x1' | '1x3' | '4x1' | '1x4' | '4x3' | '3x4' | '16x9' | '9x16' | '21x9' | '9x21'
|
||||
|
||||
interface Props {
|
||||
photo: Photo
|
||||
/** background param — plain <div> with only the background-image (no ratio class) */
|
||||
background?: boolean
|
||||
/** ratio param — img-responsive img-responsive-{ratio} wrapper */
|
||||
ratio?: string
|
||||
ratio?: PhotoRatio | undefined
|
||||
class?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
---
|
||||
/** core/scss/ui/_progress.scss `.progress-{size}` modifier classes */
|
||||
export type ProgressSize = 'sm' | 'lg' | 'xl'
|
||||
|
||||
interface Props {
|
||||
value?: number | string | undefined
|
||||
values?: (string | number)[]
|
||||
color?: string | undefined
|
||||
colors?: string[]
|
||||
size?: string | undefined
|
||||
size?: ProgressSize | undefined
|
||||
class?: string
|
||||
width?: string
|
||||
id?: string
|
||||
@@ -14,11 +16,11 @@ interface Props {
|
||||
showValue?: boolean
|
||||
}
|
||||
|
||||
const { value, values, color, colors: colorsProp, size, class: className, width, id, indeterminate, striped, animated, showValue } = Astro.props
|
||||
const { value, values, color, size, class: className, width, id, indeterminate, striped, animated, showValue } = Astro.props
|
||||
|
||||
const percentage = value !== undefined && value !== null && `${value}` !== '' ? `${value}`.split('%').join('') : '38'
|
||||
|
||||
const colors = colorsProp ?? (color ? [color] : ['blue', 'red', 'green', 'yellow', 'dark'])
|
||||
const colors = color ? [color] : ['blue', 'red', 'green', 'yellow', 'dark']
|
||||
const valueList = values
|
||||
|
||||
const classes = ['progress', size && `progress-${size}`, className]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
import Progress from './Progress.astro'
|
||||
import Flag from './Flag.astro'
|
||||
import { parsePercentage } from '@shared/lib/string-format'
|
||||
|
||||
interface Props {
|
||||
@@ -8,24 +7,16 @@ interface Props {
|
||||
color?: string
|
||||
class?: string
|
||||
text?: string
|
||||
flag?: string
|
||||
showValue?: boolean
|
||||
}
|
||||
|
||||
const { value, color = 'primary-lt', class: className, text, flag, showValue } = Astro.props
|
||||
const { value, color = 'primary-lt', class: className, text, showValue } = Astro.props
|
||||
|
||||
const percentage = parsePercentage(value)
|
||||
---
|
||||
|
||||
<div class={`progressbg${className ? ` ${className}` : ''}`}>
|
||||
<Progress value={percentage} class="progressbg-progress" color={color} />
|
||||
{
|
||||
text && (
|
||||
<div class="progressbg-text">
|
||||
{flag && <Flag flag={flag} class="me-2" size="xs" />}
|
||||
{text}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{text && <div class="progressbg-text">{text}</div>}
|
||||
{showValue && <div class="progressbg-value">{percentage}%</div>}
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
---
|
||||
// Forward `size` only when explicitly provided.
|
||||
import Progress from './Progress.astro'
|
||||
import type { ProgressSize } from './Progress.astro'
|
||||
|
||||
interface Props {
|
||||
label?: string
|
||||
description?: string
|
||||
value?: number | string
|
||||
color?: string
|
||||
size?: string
|
||||
size?: ProgressSize | undefined
|
||||
class?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import CaptureScript from '../components/CaptureScript.astro';
|
||||
interface Props {
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
value?: string | number;
|
||||
id?: string;
|
||||
connect?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { min = 0, max = 100, step = 10, value = 50, id, connect = false, class: className } = Astro.props;
|
||||
const { min = 0, max = 100, value = 50, id, connect = false, class: className } = Astro.props;
|
||||
const step = 10;
|
||||
|
||||
const values = String(value).split(',');
|
||||
const size = values.length;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
---
|
||||
import icons from '@data/icons.json'
|
||||
import CaptureScript from '../components/CaptureScript.astro'
|
||||
import type { IconSize } from './Icon.astro'
|
||||
|
||||
interface Props {
|
||||
id?: string
|
||||
icon?: string
|
||||
color?: string
|
||||
size?: string
|
||||
size?: IconSize | undefined
|
||||
value?: number
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,14 @@ import Icon from './Icon.astro'
|
||||
interface Props {
|
||||
text?: string
|
||||
top?: boolean
|
||||
left?: boolean
|
||||
bottom?: boolean
|
||||
bookmark?: boolean
|
||||
color?: string
|
||||
filled?: boolean
|
||||
}
|
||||
|
||||
const { text, top, left, bottom, bookmark, color, filled } = Astro.props
|
||||
const { text, top, color } = Astro.props
|
||||
|
||||
const classes = ['ribbon', top && 'ribbon-top', left && 'ribbon-start', bottom && 'ribbon-bottom', bookmark && 'ribbon-bookmark', color && `bg-${color}`]
|
||||
const classes = ['ribbon', top && 'ribbon-top', color && `bg-${color}`]
|
||||
---
|
||||
|
||||
<div class:list={classes}>
|
||||
{text ? text : <Icon name="star" type={filled ? 'filled' : 'outline'} />}
|
||||
{text ? text : <Icon name="star" />}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
---
|
||||
// "Less -> More" gradient legend, e.g. for a choropleth map's color scale.
|
||||
interface Props {
|
||||
/** number of swatches */
|
||||
steps?: number
|
||||
/** theme color the swatches ramp up to, e.g. 'primary' */
|
||||
color?: string
|
||||
minLabel?: string
|
||||
maxLabel?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { steps = 10, color = 'primary', minLabel = 'Less', maxLabel = 'More', class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
const steps = 10
|
||||
const color = 'primary'
|
||||
const minLabel = 'Less'
|
||||
const maxLabel = 'More'
|
||||
|
||||
const items = Array.from({ length: steps }, (_, i) => i + 1)
|
||||
---
|
||||
|
||||
@@ -10,29 +10,24 @@ import CaptureScript from '../components/CaptureScript.astro';
|
||||
interface Props {
|
||||
id?: string;
|
||||
key?: string;
|
||||
value?: string;
|
||||
class?: string;
|
||||
state?: string;
|
||||
placeholder?: string;
|
||||
indicator?: string;
|
||||
multiple?: boolean;
|
||||
values?: string[];
|
||||
showSearch?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
id: idProp,
|
||||
key: keyProp,
|
||||
value = '',
|
||||
class: className,
|
||||
state,
|
||||
placeholder,
|
||||
indicator,
|
||||
multiple,
|
||||
values,
|
||||
showSearch,
|
||||
} = Astro.props;
|
||||
|
||||
const value = '';
|
||||
const id = idProp ?? keyProp;
|
||||
const key = keyProp ?? 'people';
|
||||
const data = (selects as Record<string, any>)[key] ?? {};
|
||||
@@ -43,7 +38,7 @@ const selectClass = [
|
||||
state && `is-${state}`,
|
||||
]
|
||||
|
||||
const isMultiple = Boolean(multiple || data.multiple);
|
||||
const isMultiple = Boolean(data.multiple);
|
||||
|
||||
interface Person {
|
||||
id: string;
|
||||
@@ -125,7 +120,7 @@ const selectId = id ? `select-${id}` : undefined;
|
||||
id && (
|
||||
<CaptureScript>
|
||||
<!-- BEGIN SELECT -->
|
||||
<script is:inline define:vars={{ selectId, showSearch }}>
|
||||
<script is:inline define:vars={{ selectId }}>
|
||||
function initSelect() {
|
||||
window.tabler_select ??= {};
|
||||
|
||||
@@ -140,7 +135,6 @@ const selectId = id ? `select-${id}` : undefined;
|
||||
(window.tabler_select[selectId] = new TomSelect(document.getElementById(selectId), {
|
||||
copyClassesToDropdown: false,
|
||||
dropdownParent: 'body',
|
||||
...(showSearch === false ? { controlInput: null } : {}),
|
||||
render: {
|
||||
item: renderOption,
|
||||
option: renderOption,
|
||||
|
||||
+6
-14
@@ -1,23 +1,15 @@
|
||||
---
|
||||
// With explicit `size`: `spinner-{type}-{size}`. Without `size`: `spinner-{type}-{argCount}` (e.g. spinner-border-2).
|
||||
import { includeArgCount } from '@shared/lib/include-args'
|
||||
|
||||
interface Props {
|
||||
element?: 'div' | 'span'
|
||||
type?: string
|
||||
type?: 'border' | 'grow'
|
||||
color?: string
|
||||
size?: string
|
||||
/** core/scss/bootstrap/_spinners.scss `.spinner-{type}-{size}` — only 'sm' exists */
|
||||
size?: 'sm' | undefined
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { element: Element = 'div', type = 'border', color, size, class: className } = Astro.props
|
||||
const { type = 'border', color, size, class: className } = Astro.props
|
||||
|
||||
const includeArgKeys = ['element', 'type', 'color', 'size', 'class'] as const
|
||||
const argCount = includeArgCount(Astro.props as Record<string, unknown>, includeArgKeys)
|
||||
// include['size'] → explicit value, else the arg count meta-property.
|
||||
const sizeValue = size !== undefined ? size : argCount || undefined
|
||||
|
||||
const classes = [`spinner-${type}`, color && `text-${color}`, sizeValue && `spinner-${type}-${sizeValue}`, className]
|
||||
const classes = [`spinner-${type}`, color && `text-${color}`, size && `spinner-${type}-${size}`, className]
|
||||
---
|
||||
|
||||
<Element class:list={classes} role="status" />
|
||||
<div class:list={classes} role="status"></div>
|
||||
|
||||
@@ -4,15 +4,11 @@ interface Props {
|
||||
count?: number | string
|
||||
active?: number | string
|
||||
numbers?: boolean
|
||||
color?: string
|
||||
size?: string
|
||||
showTooltip?: boolean
|
||||
showTitle?: boolean
|
||||
}
|
||||
|
||||
const { count = 4, active = 3, numbers, color, size, showTooltip, showTitle } = Astro.props
|
||||
const { count = 4, active = 3, numbers } = Astro.props
|
||||
|
||||
const classes = ['steps', numbers && 'steps-counter', color && `steps-${color}`, size && `steps-${size}`]
|
||||
const classes = ['steps', numbers && 'steps-counter']
|
||||
|
||||
const activeNum = Number(active)
|
||||
const total = Number(count)
|
||||
@@ -30,8 +26,8 @@ const steps = Array.from({ length: total }, (_, i) => i + 1)
|
||||
const fallbackLabel = `Step ${i}${isCurrent ? ' (current)' : isDone ? ' (completed)' : ''}`
|
||||
return (
|
||||
<li class:list={itemClass}>
|
||||
<Element href={isFuture ? undefined : '#'} aria-current={isCurrent ? 'step' : undefined} data-bs-toggle={showTooltip ? 'tooltip' : undefined} title={showTooltip ? `Step ${i} description` : undefined}>
|
||||
{showTitle ? `Step ${i}` : <span class="visually-hidden">{fallbackLabel}</span>}
|
||||
<Element href={isFuture ? undefined : '#'} aria-current={isCurrent ? 'step' : undefined}>
|
||||
<span class="visually-hidden">{fallbackLabel}</span>
|
||||
</Element>
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -3,27 +3,21 @@ import Icon from './Icon.astro'
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
iconB?: string
|
||||
iconAColor?: string
|
||||
iconBColor?: string
|
||||
iconBClass?: string
|
||||
variant?: string
|
||||
active?: boolean
|
||||
/** accessible name announced alongside the pressed state, e.g. "Favorite" */
|
||||
label?: string
|
||||
}
|
||||
|
||||
const { icon = 'heart', iconB, iconAColor = 'muted', iconBColor = 'red', iconBClass, variant, active, label = 'Favorite' } = Astro.props
|
||||
const { icon = 'heart', iconBColor = 'red', variant } = Astro.props
|
||||
|
||||
const resolvedIconB = iconB ?? icon ?? 'heart'
|
||||
// star/heart force the filled variant; otherwise use the passed class.
|
||||
const resolvedIconBClass = icon === 'star' || icon === 'heart' ? 'icon-filled' : iconBClass
|
||||
const resolvedIconB = icon ?? 'heart'
|
||||
// star/heart force the filled variant; otherwise no extra class.
|
||||
const resolvedIconBClass = icon === 'star' || icon === 'heart' ? 'icon-filled' : undefined
|
||||
|
||||
const buttonClass = ['switch-icon', variant && `switch-icon-${variant}`, active && 'active']
|
||||
const buttonClass = ['switch-icon', variant && `switch-icon-${variant}`]
|
||||
---
|
||||
|
||||
<button type="button" class:list={buttonClass} data-bs-toggle="switch-icon" aria-pressed={active ? 'true' : 'false'} aria-label={label}>
|
||||
<span class={`switch-icon-a text-${iconAColor}`}>
|
||||
<button type="button" class:list={buttonClass} data-bs-toggle="switch-icon" aria-pressed="false" aria-label="Favorite">
|
||||
<span class="switch-icon-a text-muted">
|
||||
<Icon name={icon} />
|
||||
</span>
|
||||
<span class={`switch-icon-b text-${iconBColor}`}>
|
||||
|
||||
@@ -14,17 +14,16 @@ interface Props {
|
||||
avatars?: boolean
|
||||
mobile?: boolean
|
||||
buttons?: boolean
|
||||
nowrap?: boolean
|
||||
}
|
||||
|
||||
const { card, limit = 5, stripped, offset, avatars, mobile, buttons, nowrap } = Astro.props
|
||||
const { card, limit = 5, stripped, offset, avatars, mobile, buttons } = Astro.props
|
||||
|
||||
const roles = ['User', 'Admin', 'Owner']
|
||||
|
||||
const start = offset ?? 0
|
||||
const rows = (people as Record<string, any>[]).slice(start, start + limit)
|
||||
|
||||
const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', card && 'card-table', stripped && 'table-striped', nowrap && 'table-nowrap']
|
||||
const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', card && 'card-table', stripped && 'table-striped']
|
||||
---
|
||||
|
||||
<div class="table-responsive">
|
||||
@@ -38,8 +37,6 @@ const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', car
|
||||
|
||||
<th>Role</th>
|
||||
|
||||
{nowrap && <th />}
|
||||
|
||||
<th class="w-1"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -90,8 +87,6 @@ const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', car
|
||||
{role}
|
||||
</td>
|
||||
|
||||
{nowrap && <td>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi, commodi cupiditate debitis deserunt expedita hic incidunt iste modi molestiae nesciunt non nostrum perferendis perspiciatis placeat praesentium quaerat quo repellendus, voluptates.</td>}
|
||||
|
||||
<td>
|
||||
{buttons ? (
|
||||
<ButtonList class="flex-nowrap">
|
||||
|
||||
+2
-9
@@ -2,7 +2,6 @@
|
||||
import Icon from './Icon.astro'
|
||||
import Flag from './Flag.astro'
|
||||
import Avatar from './Avatar.astro'
|
||||
import Payment from './Payment.astro'
|
||||
import Badge from './Badge.astro'
|
||||
|
||||
interface Person {
|
||||
@@ -16,8 +15,6 @@ interface Props {
|
||||
flag?: string | undefined
|
||||
icon?: string
|
||||
person?: Person
|
||||
personId?: number
|
||||
payment?: string
|
||||
status?: string
|
||||
legend?: string
|
||||
checkbox?: boolean
|
||||
@@ -25,7 +22,7 @@ interface Props {
|
||||
badge?: string | number
|
||||
}
|
||||
|
||||
const { text, flag, icon, person, personId, payment, status, legend, checkbox, checked, badge } = Astro.props
|
||||
const { text, flag, icon, person, status, legend, checkbox, checked, badge } = Astro.props
|
||||
---
|
||||
|
||||
<span class="tag">
|
||||
@@ -33,13 +30,9 @@ const { text, flag, icon, person, personId, payment, status, legend, checkbox, c
|
||||
flag ? (
|
||||
<Flag flag={flag} size="xxs" class="tag-flag" />
|
||||
) : icon ? (
|
||||
<Icon name={icon} size="xxs" class="tag-icon" />
|
||||
<Icon name={icon} size="sm" class="tag-icon" />
|
||||
) : person ? (
|
||||
<Avatar person={person} size="xxs" class="tag-avatar" />
|
||||
) : personId ? (
|
||||
<Avatar personId={personId} size="xxs" class="tag-avatar" />
|
||||
) : payment ? (
|
||||
<Payment payment={payment} size="xxs" class="tag-payment" />
|
||||
) : status ? (
|
||||
<Badge color={status} class="tag-status badge-dot" text="" />
|
||||
) : legend ? (
|
||||
|
||||
+10
-16
@@ -5,16 +5,12 @@ import { requireIndex } from '@shared/lib/array'
|
||||
|
||||
interface Props {
|
||||
toastId?: string
|
||||
/** people index, 0-based (default 2 → Mallory Hulme) */
|
||||
personId?: number
|
||||
show?: boolean
|
||||
hideHeader?: boolean
|
||||
cookies?: boolean
|
||||
date?: string
|
||||
text?: string
|
||||
}
|
||||
|
||||
const { toastId = 'simple', personId = 2, show, hideHeader, cookies, date = '11 mins ago', text = 'Hello, world! This is a toast message.' } = Astro.props
|
||||
const { toastId = 'simple', show, cookies, text = 'Hello, world! This is a toast message.' } = Astro.props
|
||||
|
||||
interface Person {
|
||||
full_name?: string
|
||||
@@ -22,20 +18,18 @@ interface Person {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const person = requireIndex(people as Person[], personId)
|
||||
const date = '11 mins ago'
|
||||
/** people index, 0-based (default 2 → Mallory Hulme) */
|
||||
const person = requireIndex(people as Person[], 2)
|
||||
---
|
||||
|
||||
<div class:list={['toast', show && 'show']} id={`toast-${toastId}`} role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="false">
|
||||
{
|
||||
!hideHeader && (
|
||||
<div class="toast-header">
|
||||
<Avatar person={person} class="me-2" size="xs" />
|
||||
<strong class="me-auto">{person.full_name}</strong>
|
||||
<small>{date}</small>
|
||||
<button type="button" class="ms-2 btn-close" data-bs-dismiss="toast" aria-label="Close" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div class="toast-header">
|
||||
<Avatar person={person} class="me-2" size="xs" />
|
||||
<strong class="me-auto">{person.full_name}</strong>
|
||||
<small>{date}</small>
|
||||
<button type="button" class="ms-2 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{
|
||||
cookies ? (
|
||||
|
||||
@@ -4,20 +4,19 @@ import { capitalize } from '@shared/lib/string-format'
|
||||
interface Props {
|
||||
type?: 'checkbox' | 'radio'
|
||||
checked?: boolean
|
||||
disabled?: boolean
|
||||
/** Switch mode (prop name isSwitch; `switch` is reserved). */
|
||||
switch?: boolean
|
||||
title?: string | false
|
||||
name?: string
|
||||
inline?: boolean
|
||||
size?: string
|
||||
empty?: boolean
|
||||
/** core/scss/ui/forms/_form-check.scss `.form-switch-{size}` — only 'lg' exists */
|
||||
size?: 'lg' | undefined
|
||||
titleOn?: string
|
||||
titleOff?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { type = 'checkbox', checked = false, disabled = false, switch: isSwitch = false, title: titleProp = false, name, inline, size, empty: isEmpty = false, titleOn, titleOff, class: className } = Astro.props
|
||||
const { type = 'checkbox', checked = false, switch: isSwitch = false, title: titleProp = false, name, size, titleOn, titleOff, class: className } = Astro.props
|
||||
const disabled = false
|
||||
|
||||
let title = titleProp
|
||||
if (!title) {
|
||||
@@ -32,9 +31,9 @@ if (!title) {
|
||||
title = t
|
||||
}
|
||||
|
||||
const labelClasses = ['form-check', inline && 'form-check-inline', isSwitch && 'form-switch', isSwitch && size && `form-switch-${size}`, className]
|
||||
const labelClasses = ['form-check', isSwitch && 'form-switch', isSwitch && size && `form-switch-${size}`, className]
|
||||
|
||||
const inputClasses = ['form-check-input', isEmpty && 'position-static']
|
||||
const inputClasses = ['form-check-input']
|
||||
---
|
||||
|
||||
<label class:list={labelClasses}>
|
||||
@@ -46,7 +45,7 @@ const inputClasses = ['form-check-input', isEmpty && 'position-static']
|
||||
<span class="form-check-label form-check-label-off">{titleOff}</span>
|
||||
</Fragment>
|
||||
) : (
|
||||
!isEmpty && <span class="form-check-label">{title}</span>
|
||||
<span class="form-check-label">{title}</span>
|
||||
)
|
||||
}
|
||||
</label>
|
||||
|
||||
@@ -3,25 +3,22 @@ import Icon from '../Icon.astro'
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
iconClass?: string
|
||||
class?: string
|
||||
prepend?: boolean
|
||||
type?: string
|
||||
value?: string
|
||||
light?: boolean
|
||||
rounded?: boolean
|
||||
inputClass?: string
|
||||
ariaLabel?: string
|
||||
readonly?: boolean
|
||||
placeholder?: string
|
||||
loader?: boolean
|
||||
}
|
||||
|
||||
const { icon = 'search', iconClass, class: className, prepend, type = 'text', value = '', light, rounded, inputClass, ariaLabel, readonly, placeholder = 'Search…', loader } = Astro.props
|
||||
const { icon = 'search', class: className, prepend, type = 'text', value = '', rounded, ariaLabel, readonly, placeholder = 'Search…', loader } = Astro.props
|
||||
|
||||
const wrapperClass = ['input-icon', className]
|
||||
const addonClass = ['input-icon-addon', iconClass]
|
||||
const controlClass = ['form-control', light && 'form-control-light', rounded && 'form-control-rounded', inputClass]
|
||||
const addonClass = ['input-icon-addon']
|
||||
const controlClass = ['form-control', rounded && 'form-control-rounded']
|
||||
---
|
||||
|
||||
<div class:list={wrapperClass}>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
// IMask initializes from the data-mask attributes (tabler.js).
|
||||
interface Props {
|
||||
name?: string
|
||||
mask?: string
|
||||
visible?: boolean
|
||||
placeholder?: string
|
||||
reverse?: boolean
|
||||
}
|
||||
|
||||
const { name = 'mask', mask = '00/00/0000', visible, placeholder, reverse } = Astro.props
|
||||
const { mask = '00/00/0000', visible, placeholder, reverse } = Astro.props
|
||||
const name = 'mask'
|
||||
---
|
||||
|
||||
<input type="text" name={`input-${name}`} class="form-control" data-mask={mask} data-mask-visible={visible ? 'true' : undefined} placeholder={placeholder ?? mask} data-mask-reverse={reverse ? 'true' : undefined} autocomplete="off" />
|
||||
|
||||
Reference in New Issue
Block a user