mirror of
https://github.com/tabler/tabler.git
synced 2026-08-28 12:56:24 +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:
@@ -1,16 +1,15 @@
|
||||
---
|
||||
interface Props {
|
||||
width?: number
|
||||
height?: number
|
||||
ratio?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { width = 400, height = 200, ratio, class: className } = Astro.props
|
||||
const width = 400
|
||||
const { height = 200, class: className } = Astro.props
|
||||
---
|
||||
|
||||
<div class={`card-body${className ? ` ${className}` : ''}`}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-100 border rounded" preserveAspectRatio={ratio ? 'xMidYMid meet' : 'none'} width={width} height={height} viewBox={`0 0 ${width} ${height}`} fill="transparent" stroke="var(--tblr-border-color, #b8cef1)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-100 border rounded" preserveAspectRatio="none" width={width} height={height} viewBox={`0 0 ${width} ${height}`} fill="transparent" stroke="var(--tblr-border-color, #b8cef1)">
|
||||
<line x1="0" y1="0" x2={width} y2={height}></line>
|
||||
<line x1="0" y1={height} x2={width} y2="0"></line>
|
||||
</svg>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
---
|
||||
import CardSubtitle from '@ui/CardSubtitle.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
import AvatarList from '@ui/AvatarList.astro';
|
||||
import Empty from '@ui/Empty.astro';
|
||||
@@ -8,9 +7,6 @@ import photos from '@data/photos.json';
|
||||
import { requireIndex } from '@shared/lib/array';
|
||||
|
||||
interface Props {
|
||||
link?: boolean;
|
||||
active?: boolean;
|
||||
inactive?: boolean;
|
||||
class?: string;
|
||||
empty?: boolean;
|
||||
imgTop?: boolean;
|
||||
@@ -18,17 +14,9 @@ interface Props {
|
||||
statusTop?: string;
|
||||
statusBottom?: string;
|
||||
statusStart?: string;
|
||||
header?: boolean;
|
||||
headerTitle?: string;
|
||||
headerTabs?: boolean;
|
||||
headerPills?: boolean;
|
||||
alert?: string;
|
||||
alertType?: string;
|
||||
title?: string;
|
||||
subtitle?: boolean;
|
||||
body?: string;
|
||||
button?: boolean;
|
||||
footer?: boolean;
|
||||
footerButton?: boolean;
|
||||
footerButtons?: boolean;
|
||||
/** a right-angle-bracket prefix pushes the element (and every following one) to the right — `right` is never reset */
|
||||
@@ -37,9 +25,6 @@ interface Props {
|
||||
}
|
||||
|
||||
const {
|
||||
link = false,
|
||||
active,
|
||||
inactive,
|
||||
class: className,
|
||||
empty,
|
||||
imgTop,
|
||||
@@ -47,31 +32,16 @@ const {
|
||||
statusTop,
|
||||
statusBottom,
|
||||
statusStart,
|
||||
header,
|
||||
headerTitle,
|
||||
headerTabs,
|
||||
headerPills,
|
||||
alert,
|
||||
alertType = 'success',
|
||||
title,
|
||||
subtitle,
|
||||
body,
|
||||
button,
|
||||
footer,
|
||||
footerButton,
|
||||
footerButtons,
|
||||
footerElements,
|
||||
progress,
|
||||
}: Props = Astro.props;
|
||||
|
||||
const Element = link ? 'a' : 'div';
|
||||
|
||||
const classes = [
|
||||
'card',
|
||||
active && 'card-active',
|
||||
inactive && 'card-inactive',
|
||||
className,
|
||||
]
|
||||
const classes = ['card', className]
|
||||
|
||||
// footer-elements parsing — `right` is never reset once set across iterations.
|
||||
let right = false;
|
||||
@@ -84,14 +54,14 @@ const footerEls = (footerElements ?? []).map((element: string) => {
|
||||
return { el, right };
|
||||
});
|
||||
|
||||
const hasHeader = header || headerTitle || headerTabs || headerPills;
|
||||
const hasFooter = footer || footerButton || footerButtons || footerElements;
|
||||
const hasHeader = headerTabs || headerPills;
|
||||
const hasFooter = footerButton || footerButtons || footerElements;
|
||||
|
||||
const imgTopPhoto = requireIndex(photos as { file: string; title: string }[], 7);
|
||||
const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[], 11);
|
||||
---
|
||||
|
||||
<Element href={link ? '#' : undefined} class:list={classes}>
|
||||
<div class:list={classes}>
|
||||
{
|
||||
empty ? (
|
||||
<Empty illustration="not-found" height={160} />
|
||||
@@ -142,32 +112,18 @@ const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[],
|
||||
</li>
|
||||
</ul>
|
||||
) : (
|
||||
<h3 class="card-title" set:html={headerTitle ?? 'Header title'} />
|
||||
<h3 class="card-title">Header title</h3>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{alert && <div class={`card-alert alert alert-${alertType} mb-0`} set:html={alert} />}
|
||||
<div class="card-body">
|
||||
{title && <h3 class="card-title" set:html={title} />}
|
||||
{subtitle && <CardSubtitle as="div">Card subtitle</CardSubtitle>}
|
||||
|
||||
{body ? (
|
||||
<p class="text-secondary" set:html={body} />
|
||||
) : (
|
||||
<p class="text-secondary">
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque
|
||||
minima neque pariatur perferendis sed suscipit velit vitae voluptatem.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{button && (
|
||||
<div class="card-text">
|
||||
<a href="#" class="btn btn-primary">
|
||||
Go somewhere
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<p class="text-secondary">
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque
|
||||
minima neque pariatur perferendis sed suscipit velit vitae voluptatem.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{hasFooter && (
|
||||
@@ -228,4 +184,4 @@ const imgBottomPhoto = requireIndex(photos as { file: string; title: string }[],
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
</Element>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
---
|
||||
// Tabs/content blocks are HTML strings (different order when `bottom`).
|
||||
interface Props {
|
||||
/** tabs-count — present but unused */
|
||||
count?: number
|
||||
id?: string
|
||||
bottom?: boolean
|
||||
borderless?: boolean
|
||||
}
|
||||
|
||||
const { id = 'top', bottom, borderless } = Astro.props
|
||||
const { id = 'top', bottom } = Astro.props
|
||||
|
||||
const tabs = ['Activity', 'Profile', 'Settings']
|
||||
|
||||
@@ -37,7 +34,7 @@ ${tabs
|
||||
---
|
||||
|
||||
<!-- Cards with tabs component -->
|
||||
<div class={`card-tabs${borderless ? ' border-0' : ''}`}>
|
||||
<div class="card-tabs">
|
||||
{
|
||||
bottom ? (
|
||||
<Fragment>
|
||||
|
||||
@@ -14,12 +14,12 @@ interface Props {
|
||||
controls?: boolean
|
||||
captions?: boolean
|
||||
offset?: number
|
||||
limit?: number
|
||||
fade?: boolean
|
||||
}
|
||||
|
||||
const { id: idProp, title = 'Carousel', indicators, indicatorsThumb, indicatorsThumbRatio, indicatorsDot, indicatorsVertical, controls, captions, offset = 0, limit = 5, fade } = Astro.props
|
||||
const { id: idProp, title = 'Carousel', indicators, indicatorsThumb, indicatorsThumbRatio, indicatorsDot, indicatorsVertical, controls, captions, offset = 0, fade } = Astro.props
|
||||
|
||||
const limit = 5
|
||||
const carouselId = idProp ?? 'carousel'
|
||||
const filteredPhotos = (photos as { file: string; title?: string; horizontal?: boolean }[]).filter((p) => p.horizontal)
|
||||
const slides = filteredPhotos.slice(offset, offset + limit)
|
||||
|
||||
@@ -3,10 +3,10 @@ import MapVector from '@ui/MapVector.astro'
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
map?: string
|
||||
}
|
||||
|
||||
const { title, map = 'world' } = Astro.props
|
||||
const { title } = Astro.props
|
||||
const map = 'world'
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
|
||||
@@ -12,10 +12,10 @@ interface Person {
|
||||
|
||||
interface Props {
|
||||
person: Person
|
||||
color?: string
|
||||
}
|
||||
|
||||
const { person, color = 'yellow' } = Astro.props
|
||||
const { person } = Astro.props
|
||||
const color = 'yellow'
|
||||
---
|
||||
|
||||
<div class={`card card-gradient card-gradient-${color}`}>
|
||||
|
||||
@@ -9,17 +9,16 @@ interface Props {
|
||||
badge?: string
|
||||
offset?: number
|
||||
limit?: number
|
||||
percentage?: number | string
|
||||
percentageColor?: string
|
||||
due?: string
|
||||
value?: number | string
|
||||
}
|
||||
|
||||
const { title = 'Task Title', badge, offset = 40, limit = 7, percentage, percentageColor = 'green', due = '2 days', value = 20 } = Astro.props
|
||||
const { title = 'Task Title', badge, offset = 40, limit = 7, percentageColor = 'green', due = '2 days', value = 20 } = Astro.props
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
<Progress value={percentage ?? value} class="card-progress" color={percentageColor} />
|
||||
<Progress value={value} class="card-progress" color={percentageColor} />
|
||||
<div class="card-body">
|
||||
<CardTitle>
|
||||
<a href="#">{title}</a>
|
||||
|
||||
@@ -4,31 +4,26 @@ import AvatarList from '@ui/AvatarList.astro'
|
||||
import Progress from '@ui/Progress.astro'
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
date?: string
|
||||
stageColor?: string
|
||||
stage?: string
|
||||
projectColor?: string
|
||||
percentage?: number | string
|
||||
percentageColor?: string
|
||||
avatarOffset?: number
|
||||
avatarLimit?: number
|
||||
}
|
||||
|
||||
const { title = 'New website', date = '28 Aug 2019', stageColor = 'green', stage = 'Waiting', projectColor, percentage, percentageColor, avatarOffset, avatarLimit } = Astro.props
|
||||
const { stageColor = 'green' } = Astro.props
|
||||
const title = 'New website'
|
||||
const date = '28 Aug 2019'
|
||||
const stage = 'Waiting'
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body p-4 py-5 text-center">
|
||||
<Avatar size="xl" placeholder="W" class="mb-4" color={projectColor} />
|
||||
<Avatar size="xl" placeholder="W" class="mb-4" />
|
||||
<h3 class="mb-0">{title}</h3>
|
||||
<p class="text-secondary">Due to: {date}</p>
|
||||
<p class="mb-3">
|
||||
<span class={`badge bg-${stageColor}-lt`}>{stage}</span>
|
||||
</p>
|
||||
<div>
|
||||
<AvatarList stacked offset={avatarOffset} limit={avatarLimit} />
|
||||
<AvatarList stacked />
|
||||
</div>
|
||||
</div>
|
||||
<Progress class="card-progress" value={percentage} color={percentageColor} />
|
||||
<Progress class="card-progress" />
|
||||
</div>
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
import Icon from '@ui/Icon.astro'
|
||||
import Avatar from '@ui/Avatar.astro'
|
||||
import ChartSparkline from '@ui/ChartSparkline.astro'
|
||||
import Trending from '@ui/Trending.astro'
|
||||
import Button from '@ui/Button.astro'
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
@@ -19,16 +17,12 @@ interface Props {
|
||||
chartType?: string
|
||||
chartPosition?: string
|
||||
chartData?: string | number
|
||||
chartLabel?: string
|
||||
chartLabelIcon?: string
|
||||
smallIcon?: string
|
||||
descriptionValue?: string
|
||||
descriptionValueColor?: string
|
||||
trending?: number
|
||||
button?: string
|
||||
}
|
||||
|
||||
const { icon, color, lt, title, description, class: className, id, personId, chartType = 'line', chartPosition = 'right', chartData, smallIcon, descriptionValue, descriptionValueColor, trending, button } = Astro.props
|
||||
const { icon, color, lt, title, description, class: className, id, personId, chartType = 'line', chartPosition = 'right', chartData, smallIcon, descriptionValue, descriptionValueColor } = Astro.props
|
||||
|
||||
const chartColor = color ?? 'primary'
|
||||
const avatarClass = [color ? `bg-${color}${lt ? '-lt' : ' text-white'}` : '', 'avatar', 'avatar-square']
|
||||
@@ -73,22 +67,6 @@ const avatarClass = [color ? `bg-${color}${lt ? '-lt' : ' text-white'}` : '', 'a
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
trending && (
|
||||
<div class="col-auto">
|
||||
<Trending value={trending} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
button && (
|
||||
<div class="col-auto">
|
||||
<Button text={button} size="sm" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,6 @@ import DropdownMenu from '@ui/DropdownMenu.astro'
|
||||
interface Props {
|
||||
id: string
|
||||
icons?: boolean
|
||||
/** hide-text param; not used by current call sites */
|
||||
hideText?: boolean
|
||||
reverse?: boolean
|
||||
justified?: boolean
|
||||
activity?: boolean
|
||||
@@ -16,9 +14,8 @@ interface Props {
|
||||
animation?: boolean
|
||||
}
|
||||
|
||||
const { id, icons, hideText, reverse = false, justified, activity, disabled, dropdown, settings, animation } = Astro.props
|
||||
const { id, icons, reverse = false, justified, activity, disabled, dropdown, settings, animation } = Astro.props
|
||||
|
||||
const iconClass = hideText ? undefined : 'me-2'
|
||||
const navClass = `nav nav-tabs card-header-tabs${reverse ? ' flex-row-reverse' : ''}${justified ? ' nav-fill' : ''}`
|
||||
const paneClass = `tab-pane${animation ? ' fade' : ''}`
|
||||
---
|
||||
@@ -27,18 +24,18 @@ const paneClass = `tab-pane${animation ? ' fade' : ''}`
|
||||
<div class="card-header">
|
||||
<ul class={navClass} role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href={`#tabs-home-${id}`} id={`tabs-home-${id}-tab`} class="nav-link active" data-bs-toggle="tab" data-bs-target={`#tabs-home-${id}`} role="tab" aria-controls={`tabs-home-${id}`} aria-selected="true">{icons && <Icon name="home" class={iconClass} />}{!hideText && 'Home'}</a>
|
||||
<a href={`#tabs-home-${id}`} id={`tabs-home-${id}-tab`} class="nav-link active" data-bs-toggle="tab" data-bs-target={`#tabs-home-${id}`} role="tab" aria-controls={`tabs-home-${id}`} aria-selected="true">{icons && <Icon name="home" class="me-2" />}Home</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href={`#tabs-profile-${id}`} id={`tabs-profile-${id}-tab`} class="nav-link" data-bs-toggle="tab" data-bs-target={`#tabs-profile-${id}`} role="tab" aria-controls={`tabs-profile-${id}`} aria-selected="false">{icons && <Icon name="user" class={iconClass} />}{!hideText && 'Profile'}</a>
|
||||
<a href={`#tabs-profile-${id}`} id={`tabs-profile-${id}-tab`} class="nav-link" data-bs-toggle="tab" data-bs-target={`#tabs-profile-${id}`} role="tab" aria-controls={`tabs-profile-${id}`} aria-selected="false">{icons && <Icon name="user" class="me-2" />}Profile</a>
|
||||
</li>
|
||||
|
||||
{
|
||||
activity && (
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href={`#tabs-activity-${id}`} id={`tabs-activity-${id}-tab`} class="nav-link" data-bs-toggle="tab" data-bs-target={`#tabs-activity-${id}`} role="tab" aria-controls={`tabs-activity-${id}`} aria-selected="false">
|
||||
{icons && <Icon name="activity" class={iconClass} />}
|
||||
{!hideText && 'Activity'}
|
||||
{icons && <Icon name="activity" class="me-2" />}
|
||||
Activity
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
@@ -48,8 +45,8 @@ const paneClass = `tab-pane${animation ? ' fade' : ''}`
|
||||
disabled && (
|
||||
<li class="nav-item" role="presentation">
|
||||
<a href="#" class="nav-link disabled" data-bs-toggle="tab" role="tab" aria-selected="false" aria-disabled="true" tabindex="-1">
|
||||
{icons && <Icon name="x" class={iconClass} />}
|
||||
{!hideText && 'Disabled'}
|
||||
{icons && <Icon name="x" class="me-2" />}
|
||||
Disabled
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -16,18 +16,12 @@ interface Person {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
personId?: number
|
||||
}
|
||||
|
||||
const { title = 'Basic info', personId = 25 } = Astro.props
|
||||
const person = requireIndex(people as Person[], personId - 1)
|
||||
const person = requireIndex(people as Person[], 24)
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">{title}</h3>
|
||||
<h3 class="card-title">Basic info</h3>
|
||||
<div class="mb-2">
|
||||
<Icon name="book" class="me-2 text-secondary" />
|
||||
Went to: <strong>{person.university}</strong>
|
||||
|
||||
@@ -16,7 +16,6 @@ interface Person {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
limit?: number
|
||||
offset?: number
|
||||
hoverable?: boolean
|
||||
checkbox?: boolean
|
||||
@@ -32,7 +31,9 @@ interface Props {
|
||||
hover?: boolean
|
||||
}
|
||||
|
||||
const { limit = 8, offset = 0, hoverable = false, checkbox, checkedIds, title = 'Last commits', class: className } = Astro.props
|
||||
const { offset = 0, hoverable = false, checkbox, checkedIds, title = 'Last commits', class: className } = Astro.props
|
||||
|
||||
const limit = 8
|
||||
|
||||
const colors = ['green', 'red', 'yellow', 'x', 'x']
|
||||
const commitList = commits as { description: string }[]
|
||||
|
||||
@@ -12,13 +12,14 @@ interface Person {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
limit?: number
|
||||
offset?: number
|
||||
title?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { limit = 10, offset = 0, title = 'Top users', class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
|
||||
const limit = 10
|
||||
const offset = 0
|
||||
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' }
|
||||
|
||||
@@ -15,11 +15,7 @@ interface Person {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
}
|
||||
|
||||
const { title = 'People' } = Astro.props
|
||||
const title = 'People'
|
||||
|
||||
const commitList = commits as { description: string }[]
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Layout front-matter flags are plain props here.
|
||||
// TODO: layout-navbar-overlap && layout-navbar-dark → extra text-white class
|
||||
// on .page-header — both unset on the homepage.
|
||||
import Icon from '@ui/Icon.astro';
|
||||
import HeaderActionsButtons from './HeaderActionsButtons.astro';
|
||||
import HeaderActionsPrint from './HeaderActionsPrint.astro';
|
||||
import HeaderActionsPhotos from './HeaderActionsPhotos.astro';
|
||||
@@ -24,15 +23,13 @@ interface Props {
|
||||
actions?: string | undefined;
|
||||
/** page-header-class */
|
||||
class?: string;
|
||||
/** page-header-icon */
|
||||
icon?: string;
|
||||
/** page-header-file — name of an include from layout/headers/, e.g. "profile" */
|
||||
file?: string | undefined;
|
||||
/** layout-navbar-overlap && layout-navbar-dark → text-white on .page-header */
|
||||
textWhite?: boolean | undefined;
|
||||
}
|
||||
|
||||
const { title, pretitle, description, actions, class: className, icon, file, textWhite } = Astro.props;
|
||||
const { title, pretitle, description, actions, class: className, file, textWhite } = Astro.props;
|
||||
---
|
||||
|
||||
{file === 'profile' && <HeaderProfile />}
|
||||
@@ -50,7 +47,6 @@ const { title, pretitle, description, actions, class: className, icon, file, tex
|
||||
</Fragment>
|
||||
)}
|
||||
<h1 class="page-title">
|
||||
{icon && <Icon name={icon} />}
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const typedId = 'typed'
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="hero-img-side">
|
||||
<Carousel id="carousel-controls" slideCount={3} interval={4000}>
|
||||
<Carousel id="carousel-controls" interval={4000}>
|
||||
<div class="carousel-item active">
|
||||
<Illustration image="boy-with-key.svg" class="d-block mx-auto" height="350" />
|
||||
</div>
|
||||
|
||||
@@ -3,13 +3,12 @@ import Button from '@ui/Button.astro'
|
||||
import ButtonList from '@ui/ButtonList.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { background, class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
const sectionClass = ['section', className]
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
---
|
||||
import SectionDivider from '../SectionDivider.astro'
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
divider?: string
|
||||
}
|
||||
|
||||
const { background, class: className, divider } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
const sectionClass = ['section', className]
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
<SectionDivider divider={divider} />
|
||||
<div class="container">
|
||||
<div class="row items-center text-center g-lg-10">
|
||||
<div class="col-md-6 col-lg">
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
---
|
||||
import SectionDivider from '../SectionDivider.astro'
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
divider?: string
|
||||
}
|
||||
|
||||
const { background, class: className, divider } = Astro.props
|
||||
const { background, class: className } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
<SectionDivider divider={divider} />
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Everything you need to deploy your app</h2>
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
---
|
||||
import SectionDivider from '../SectionDivider.astro'
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
divider?: string
|
||||
}
|
||||
|
||||
const { background, class: className, divider } = Astro.props
|
||||
const { background, class: className } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
<SectionDivider divider={divider} />
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Everything you need to deploy your app</h2>
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { background, class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
const sectionClass = ['section', className]
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
---
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
}
|
||||
|
||||
const { background } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`]
|
||||
const sectionClass = ['section']
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { background, class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
const sectionClass = ['section', className]
|
||||
---
|
||||
|
||||
<section class:list={sectionClass}>
|
||||
|
||||
@@ -13,15 +13,14 @@ interface Person {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
background?: string
|
||||
class?: string
|
||||
limit?: number
|
||||
hideHeader?: boolean
|
||||
}
|
||||
|
||||
const { background, class: className, limit = 99, hideHeader } = Astro.props
|
||||
const { class: className, limit = 99, hideHeader } = Astro.props
|
||||
|
||||
const sectionClass = ['section', background && `section-${background}`, className]
|
||||
const sectionClass = ['section', className]
|
||||
|
||||
// Slice testimonials and split into 3 columns.
|
||||
const list = (testimonials as string[]).slice(0, limit)
|
||||
|
||||
@@ -3,24 +3,21 @@
|
||||
// end of <body> (see PageModals). For inline gallery demos use ModalInline.
|
||||
interface Props {
|
||||
modalId?: string
|
||||
size?: string
|
||||
/** core/scss/bootstrap/_modal.scss + ui/_modals.scss `.modal-{size}` modifier classes */
|
||||
size?: 'sm' | 'lg' | 'xl' | 'fullscreen' | 'full-width' | undefined
|
||||
top?: boolean
|
||||
scrollable?: boolean
|
||||
class?: string
|
||||
show?: boolean
|
||||
style?: string
|
||||
/** id of the title element the root references via aria-labelledby; defaults to `modal-${modalId}-title` */
|
||||
titleId?: string
|
||||
}
|
||||
|
||||
const { modalId = 'simple', size, top, scrollable, class: className, show, style, titleId = `modal-${modalId}-title` } = Astro.props
|
||||
const { modalId = 'simple', size, top, class: className } = Astro.props
|
||||
const titleId = `modal-${modalId}-title`
|
||||
|
||||
const modalClass = ['modal modal-blur fade', className, show && 'show'].filter(Boolean).join(' ')
|
||||
const dialogClass = ['modal-dialog', size && `modal-${size}`, !top && 'modal-dialog-centered', scrollable && 'modal-dialog-scrollable'].filter(Boolean).join(' ')
|
||||
const modalClass = ['modal modal-blur fade', className].filter(Boolean).join(' ')
|
||||
const dialogClass = ['modal-dialog', size && `modal-${size}`, !top && 'modal-dialog-centered'].filter(Boolean).join(' ')
|
||||
---
|
||||
|
||||
<!-- BEGIN MODAL -->
|
||||
<div class={modalClass} style={style} id={`modal-${modalId}`} tabindex="-1" role="dialog" aria-modal="true" aria-labelledby={titleId} aria-hidden={show ? undefined : 'true'}>
|
||||
<div class={modalClass} id={`modal-${modalId}`} tabindex="-1" role="dialog" aria-modal="true" aria-labelledby={titleId} aria-hidden="true">
|
||||
<div class={dialogClass}>
|
||||
<div class="modal-content">
|
||||
<slot />
|
||||
|
||||
@@ -3,20 +3,19 @@
|
||||
// modals gallery page where each modal is shown inline with `inline show`.
|
||||
interface Props {
|
||||
modalId?: string
|
||||
size?: string
|
||||
top?: boolean
|
||||
/** core/scss/bootstrap/_modal.scss + ui/_modals.scss `.modal-{size}` modifier classes */
|
||||
size?: 'sm' | 'lg' | 'xl' | 'fullscreen' | 'full-width' | undefined
|
||||
scrollable?: boolean
|
||||
class?: string
|
||||
show?: boolean
|
||||
style?: string
|
||||
/** id of the title element the root references via aria-labelledby; defaults to `modal-${modalId}-title` */
|
||||
titleId?: string
|
||||
}
|
||||
|
||||
const { modalId = 'simple', size, top, scrollable, class: className, show, style, titleId = `modal-${modalId}-title` } = Astro.props
|
||||
const { modalId = 'simple', size, scrollable, class: className, show, style } = Astro.props
|
||||
const titleId = `modal-${modalId}-title`
|
||||
|
||||
const modalClass = ['modal modal-blur fade', className, show && 'show'].filter(Boolean).join(' ')
|
||||
const dialogClass = ['modal-dialog', size && `modal-${size}`, !top && 'modal-dialog-centered', scrollable && 'modal-dialog-scrollable'].filter(Boolean).join(' ')
|
||||
const dialogClass = ['modal-dialog', size && `modal-${size}`, 'modal-dialog-centered', scrollable && 'modal-dialog-scrollable'].filter(Boolean).join(' ')
|
||||
---
|
||||
|
||||
<!-- BEGIN MODAL -->
|
||||
|
||||
@@ -17,7 +17,6 @@ interface Props {
|
||||
hideSearch?: boolean;
|
||||
/** equivalent of the page-menu front matter (active menu entry), e.g. "dashboards.default" */
|
||||
pageMenu?: string | undefined;
|
||||
breakpoint?: string;
|
||||
condensed?: boolean | undefined;
|
||||
dark?: boolean | undefined;
|
||||
transparent?: boolean;
|
||||
@@ -48,7 +47,6 @@ interface Props {
|
||||
const {
|
||||
hideSearch = false,
|
||||
pageMenu,
|
||||
breakpoint = 'md',
|
||||
condensed = false,
|
||||
dark = false,
|
||||
transparent = false,
|
||||
@@ -67,6 +65,8 @@ const {
|
||||
class: className,
|
||||
} = Astro.props;
|
||||
|
||||
const breakpoint = 'md';
|
||||
|
||||
const headerClass = [
|
||||
`navbar navbar-expand-${breakpoint}`,
|
||||
transparent ? 'navbar-transparent' : background && `bg-${background}`,
|
||||
|
||||
@@ -5,16 +5,15 @@ import InputIcon from '@ui/form/InputIcon.astro'
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
rounded?: boolean
|
||||
}
|
||||
|
||||
const { class: className, rounded = false } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
---
|
||||
|
||||
<!-- BEGIN NAVBAR SEARCH -->
|
||||
<div class={className}>
|
||||
<form action="./" method="get" autocomplete="off" novalidate role="search">
|
||||
<InputIcon prepend rounded={rounded} ariaLabel="Search in website" />
|
||||
<InputIcon prepend ariaLabel="Search in website" />
|
||||
</form>
|
||||
</div>
|
||||
<!-- END NAVBAR SEARCH -->
|
||||
|
||||
@@ -7,9 +7,12 @@ import NavbarSideApps from './NavbarSideApps.astro'
|
||||
import NavbarSideLanguage from './NavbarSideLanguage.astro'
|
||||
import NavbarSideUser from './NavbarSideUser.astro'
|
||||
|
||||
/** Bootstrap responsive breakpoint used for `d-{breakpoint}-flex` — $grid-breakpoints minus xs */
|
||||
export type Breakpoint = 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
breakpoint?: string
|
||||
breakpoint?: Breakpoint | undefined
|
||||
condensed?: boolean
|
||||
personId?: number | undefined
|
||||
hideUsername?: boolean
|
||||
|
||||
@@ -3,10 +3,11 @@ import NavbarToggler from './NavbarToggler.astro'
|
||||
import Logo from './Logo.astro'
|
||||
import NavbarSide from './NavbarSide.astro'
|
||||
import NavbarMenu from './NavbarMenu.astro'
|
||||
import type { Breakpoint } from './NavbarSide.astro'
|
||||
|
||||
interface Props {
|
||||
dark?: boolean | undefined
|
||||
breakpoint?: string
|
||||
breakpoint?: Breakpoint | undefined
|
||||
/** layout-sidebar-end — navbar-end class */
|
||||
end?: boolean | undefined
|
||||
/** layout-navbar-transparent — navbar-transparent class */
|
||||
|
||||
@@ -12,11 +12,11 @@ interface Column {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data?: { columns: Column[] }
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { data = tasksData as unknown as { columns: Column[] }, class: className } = Astro.props
|
||||
const { class: className } = Astro.props
|
||||
const data = tasksData as unknown as { columns: Column[] }
|
||||
---
|
||||
|
||||
<div class={`row${className ? ` ${className}` : ''}`}>
|
||||
|
||||
@@ -2,13 +2,6 @@
|
||||
import CardTitle from '@ui/CardTitle.astro'
|
||||
import Chart from '@ui/Chart.astro'
|
||||
import DropdownDays from '@ui/DropdownDays.astro'
|
||||
|
||||
interface Props {
|
||||
/** hide-breakpoint — when set, the stats column drops the -md breakpoint */
|
||||
hideBreakpoint?: boolean
|
||||
}
|
||||
|
||||
const { hideBreakpoint } = Astro.props
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
@@ -24,7 +17,7 @@ const { hideBreakpoint } = Astro.props
|
||||
<div class="col">
|
||||
<Chart chartId="active-users-2" label="Active users" />
|
||||
</div>
|
||||
<div class={`col${hideBreakpoint ? '' : '-md'}-auto`}>
|
||||
<div class="col-md-auto">
|
||||
<div class="divide-y divide-y-fill">
|
||||
<div class="px-3">
|
||||
<div class="text-secondary">
|
||||
|
||||
@@ -43,18 +43,6 @@ export function extractMarkedSnippet(source: string, marker: string, name: strin
|
||||
.trim()
|
||||
}
|
||||
|
||||
/** Escape text for use in HTML attributes (e.g. data-clipboard-text). */
|
||||
export function escapeAttribute(text: string): string {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\r\n/g, ' ')
|
||||
.replace(/[\r\n]/g, ' ')
|
||||
}
|
||||
|
||||
/** Replace href="#" with javascript:void(0) in example markup. */
|
||||
export function removeHref(content: string): string {
|
||||
return content.replace(/href="#"/g, 'href="javascript:void(0)"')
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { includeArgCount } from './include-args'
|
||||
|
||||
describe('includeArgCount', () => {
|
||||
const keys = ['a', 'b', 'c'] as const
|
||||
|
||||
it('counts only the keys present with a defined value', () => {
|
||||
expect(includeArgCount({ a: 1, b: undefined, c: 'x' }, keys)).toBe(2)
|
||||
})
|
||||
|
||||
it('returns 0 when no keys are present', () => {
|
||||
expect(includeArgCount({}, keys)).toBe(0)
|
||||
})
|
||||
|
||||
it('counts falsy-but-defined values (0, "", false) as present', () => {
|
||||
expect(includeArgCount({ a: 0, b: '', c: false }, keys)).toBe(3)
|
||||
})
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Returns how many of the given prop keys are explicitly set (not undefined).
|
||||
* Some components use this count as a class suffix when `size` (or similar) is
|
||||
* omitted, e.g. `spinner-border-2` or `nav-2`.
|
||||
*/
|
||||
export function includeArgCount(props: Record<string, unknown>, keys: readonly string[]): number {
|
||||
return keys.filter((k) => props[k] !== undefined).length
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { capitalize, firstLetters, formatNumber, millisecondsToMinutes, parseCurrency, parsePercentage, pathSlug, roundTo, slugifyWord, sortBy, splitDropTrailingEmpty, ucFirst } from './string-format'
|
||||
import { capitalize, firstLetters, formatNumber, millisecondsToMinutes, parseCurrency, parsePercentage, pathSlug, roundTo, slugifyWord, sortBy, ucFirst } from './string-format'
|
||||
import { requireIndex } from './array'
|
||||
|
||||
describe('capitalize', () => {
|
||||
@@ -34,16 +34,6 @@ describe('formatNumber', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('splitDropTrailingEmpty', () => {
|
||||
it('drops trailing empty strings', () => {
|
||||
expect(splitDropTrailingEmpty('Tabler,Pages,', ',')).toEqual(['Tabler', 'Pages'])
|
||||
})
|
||||
|
||||
it('keeps internal empty segments', () => {
|
||||
expect(splitDropTrailingEmpty('a,,b', ',')).toEqual(['a', '', 'b'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('slugifyWord', () => {
|
||||
it('lowercases the input', () => {
|
||||
expect(slugifyWord('Settings')).toBe('settings')
|
||||
|
||||
@@ -23,13 +23,6 @@ export function formatNumber(value: number): string {
|
||||
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
}
|
||||
|
||||
/** Splits a string on `sep`, dropping trailing empty segments (e.g. "a,b," -> ["a", "b"]). */
|
||||
export function splitDropTrailingEmpty(str: string, sep: string): string[] {
|
||||
const items = str.split(sep)
|
||||
while (items.length > 0 && items[items.length - 1] === '') items.pop()
|
||||
return items
|
||||
}
|
||||
|
||||
/** Lowercases a single-word string for use as an anchor slug. */
|
||||
export function slugifyWord(text: string): string {
|
||||
return text.toLowerCase()
|
||||
|
||||
@@ -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