@usace/groundwork 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +18 -0
- package/.github/workflows/deploy-docs.yml +59 -0
- package/.github/workflows/publish.yml +19 -0
- package/README.md +5 -0
- package/index.html +13 -0
- package/lib/catalyst/alert.jsx +110 -0
- package/lib/catalyst/avatar.jsx +64 -0
- package/lib/catalyst/badge.jsx +72 -0
- package/lib/catalyst/checkbox.jsx +160 -0
- package/lib/catalyst/dialog.jsx +101 -0
- package/lib/catalyst/dropdown.jsx +202 -0
- package/lib/catalyst/fieldset.jsx +87 -0
- package/lib/catalyst/input.jsx +78 -0
- package/lib/catalyst/listbox.jsx +195 -0
- package/lib/catalyst/pagination.jsx +75 -0
- package/lib/catalyst/radio.jsx +144 -0
- package/lib/catalyst/select.jsx +78 -0
- package/lib/catalyst/switch.jsx +203 -0
- package/lib/catalyst/textarea.jsx +59 -0
- package/lib/components/breadcrumbs.jsx +46 -0
- package/lib/components/button.jsx +219 -0
- package/lib/components/display/headings.jsx +39 -0
- package/lib/components/display/text.jsx +48 -0
- package/lib/components/hero.jsx +51 -0
- package/lib/components/layout/container.jsx +13 -0
- package/lib/components/layout/usace-box.jsx +26 -0
- package/lib/components/link.jsx +18 -0
- package/lib/components/table.jsx +146 -0
- package/lib/composite/footer/essayons.jsx +12 -0
- package/lib/composite/footer/footer-links.jsx +33 -0
- package/lib/composite/footer/index.jsx +148 -0
- package/lib/composite/footer/logo-banner.jsx +55 -0
- package/lib/composite/footer/social-links.jsx +60 -0
- package/lib/composite/header/index.jsx +83 -0
- package/lib/composite/header/navbar-links.jsx +113 -0
- package/lib/composite/header/usa-banner/USABanner.jsx +114 -0
- package/lib/composite/header/usa-banner/usa-banner.css +220 -0
- package/lib/composite/site-wrapper/index.jsx +52 -0
- package/lib/index.jsx +19 -0
- package/package.json +39 -0
- package/postcss.config.js +6 -0
- package/public/Magnifying_glass_icon.svg +5 -0
- package/public/armystar-logo-rb.svg +4 -0
- package/public/cwbi-logo.png +0 -0
- package/public/essayonscrest.png +0 -0
- package/public/icon-dot-gov.svg +1 -0
- package/public/icon-https.svg +1 -0
- package/public/nww-lucky-peak-dam.jpg +0 -0
- package/public/rsgis-logo.png +0 -0
- package/public/us_flag_small.png +0 -0
- package/public/usace-logo-color.svg +1 -0
- package/src/App.jsx +38 -0
- package/src/app-bundles/index.js +4 -0
- package/src/app-bundles/route-bundle.js +36 -0
- package/src/app-components/code-example.jsx +17 -0
- package/src/app-components/copy-button.jsx +32 -0
- package/src/app-components/props-table.jsx +43 -0
- package/src/app-components/sub-site-banner.jsx +15 -0
- package/src/app-pages/documentation/_docs-page.jsx +31 -0
- package/src/app-pages/documentation/_docs-sidebar.jsx +111 -0
- package/src/app-pages/documentation/_template.jsx +55 -0
- package/src/app-pages/documentation/app-shell/index.jsx +39 -0
- package/src/app-pages/documentation/app-shell/site-wrapper.jsx +190 -0
- package/src/app-pages/documentation/buttons/index.jsx +170 -0
- package/src/app-pages/documentation/index.jsx +57 -0
- package/src/app-pages/documentation/layout/container.jsx +68 -0
- package/src/app-pages/documentation/layout/index.jsx +52 -0
- package/src/app-pages/documentation/layout/usace-box.jsx +76 -0
- package/src/app-pages/documentation/navigation/breadcrumbs.jsx +119 -0
- package/src/app-pages/documentation/navigation/index.jsx +31 -0
- package/src/app-pages/documentation/types/index.jsx +31 -0
- package/src/app-pages/documentation/types/link.jsx +72 -0
- package/src/app-pages/home.jsx +71 -0
- package/src/index.css +3 -0
- package/src/main.jsx +18 -0
- package/tailwind.config.js +31 -0
- package/vite.config.js +46 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Field as HeadlessField, Radio as HeadlessRadio, RadioGroup as HeadlessRadioGroup } from '@headlessui/react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
|
|
4
|
+
export function RadioGroup({ className, ...props }) {
|
|
5
|
+
return (
|
|
6
|
+
<HeadlessRadioGroup
|
|
7
|
+
data-slot="control"
|
|
8
|
+
{...props}
|
|
9
|
+
className={clsx(
|
|
10
|
+
className,
|
|
11
|
+
|
|
12
|
+
// Basic groups
|
|
13
|
+
'space-y-3 [&_[data-slot=label]]:font-normal',
|
|
14
|
+
|
|
15
|
+
// With descriptions
|
|
16
|
+
'has-[[data-slot=description]]:space-y-6 [&_[data-slot=label]]:has-[[data-slot=description]]:font-medium'
|
|
17
|
+
)}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function RadioField({ className, ...props }) {
|
|
23
|
+
return (
|
|
24
|
+
<HeadlessField
|
|
25
|
+
data-slot="field"
|
|
26
|
+
{...props}
|
|
27
|
+
className={clsx(
|
|
28
|
+
className,
|
|
29
|
+
|
|
30
|
+
// Base layout
|
|
31
|
+
'grid grid-cols-[1.125rem_1fr] items-center gap-x-4 gap-y-1 sm:grid-cols-[1rem_1fr]',
|
|
32
|
+
|
|
33
|
+
// Control layout
|
|
34
|
+
'[&>[data-slot=control]]:col-start-1 [&>[data-slot=control]]:row-start-1 [&>[data-slot=control]]:justify-self-center',
|
|
35
|
+
|
|
36
|
+
// Label layout
|
|
37
|
+
'[&>[data-slot=label]]:col-start-2 [&>[data-slot=label]]:row-start-1 [&>[data-slot=label]]:justify-self-start',
|
|
38
|
+
|
|
39
|
+
// Description layout
|
|
40
|
+
'[&>[data-slot=description]]:col-start-2 [&>[data-slot=description]]:row-start-2',
|
|
41
|
+
|
|
42
|
+
// With description
|
|
43
|
+
'[&_[data-slot=label]]:has-[[data-slot=description]]:font-medium'
|
|
44
|
+
)}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const base = [
|
|
50
|
+
// Basic layout
|
|
51
|
+
'relative isolate flex size-[1.1875rem] shrink-0 rounded-full sm:size-[1.0625rem]',
|
|
52
|
+
|
|
53
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
54
|
+
'before:absolute before:inset-0 before:-z-10 before:rounded-full before:bg-white before:shadow',
|
|
55
|
+
|
|
56
|
+
// Background color when checked
|
|
57
|
+
'before:group-data-[checked]:bg-[--radio-checked-bg]',
|
|
58
|
+
|
|
59
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
60
|
+
'dark:before:hidden',
|
|
61
|
+
|
|
62
|
+
// Background color applied to control in dark mode
|
|
63
|
+
'dark:bg-white/5 dark:group-data-[checked]:bg-[--radio-checked-bg]',
|
|
64
|
+
|
|
65
|
+
// Border
|
|
66
|
+
'border border-zinc-950/15 group-data-[checked]:border-transparent group-data-[checked]:group-data-[hover]:border-transparent group-data-[hover]:border-zinc-950/30 group-data-[checked]:bg-[--radio-checked-border]',
|
|
67
|
+
'dark:border-white/15 dark:group-data-[checked]:border-white/5 dark:group-data-[checked]:group-data-[hover]:border-white/5 dark:group-data-[hover]:border-white/30',
|
|
68
|
+
|
|
69
|
+
// Inner highlight shadow
|
|
70
|
+
'after:absolute after:inset-0 after:rounded-full after:shadow-[inset_0_1px_theme(colors.white/15%)]',
|
|
71
|
+
'dark:after:-inset-px dark:after:hidden dark:after:rounded-full dark:group-data-[checked]:after:block',
|
|
72
|
+
|
|
73
|
+
// Indicator color (light mode)
|
|
74
|
+
'[--radio-indicator:transparent] group-data-[checked]:[--radio-indicator:var(--radio-checked-indicator)] group-data-[checked]:group-data-[hover]:[--radio-indicator:var(--radio-checked-indicator)] group-data-[hover]:[--radio-indicator:theme(colors.zinc.900/10%)]',
|
|
75
|
+
|
|
76
|
+
// Indicator color (dark mode)
|
|
77
|
+
'dark:group-data-[checked]:group-data-[hover]:[--radio-indicator:var(--radio-checked-indicator)] dark:group-data-[hover]:[--radio-indicator:theme(colors.zinc.700)]',
|
|
78
|
+
|
|
79
|
+
// Focus ring
|
|
80
|
+
'group-data-[focus]:outline group-data-[focus]:outline-2 group-data-[focus]:outline-offset-2 group-data-[focus]:outline-blue-500',
|
|
81
|
+
|
|
82
|
+
// Disabled state
|
|
83
|
+
'group-data-[disabled]:opacity-50',
|
|
84
|
+
'group-data-[disabled]:border-zinc-950/25 group-data-[disabled]:bg-zinc-950/5 group-data-[disabled]:[--radio-checked-indicator:theme(colors.zinc.950/50%)] group-data-[disabled]:before:bg-transparent',
|
|
85
|
+
'dark:group-data-[disabled]:border-white/20 dark:group-data-[disabled]:bg-white/[2.5%] dark:group-data-[disabled]:[--radio-checked-indicator:theme(colors.white/50%)] dark:group-data-[disabled]:group-data-[checked]:after:hidden',
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
const colors = {
|
|
89
|
+
'dark/zinc': [
|
|
90
|
+
'[--radio-checked-bg:theme(colors.zinc.900)] [--radio-checked-border:theme(colors.zinc.950/90%)] [--radio-checked-indicator:theme(colors.white)]',
|
|
91
|
+
'dark:[--radio-checked-bg:theme(colors.zinc.600)]',
|
|
92
|
+
],
|
|
93
|
+
'dark/white': [
|
|
94
|
+
'[--radio-checked-bg:theme(colors.zinc.900)] [--radio-checked-border:theme(colors.zinc.950/90%)] [--radio-checked-indicator:theme(colors.white)]',
|
|
95
|
+
'dark:[--radio-checked-bg:theme(colors.white)] dark:[--radio-checked-border:theme(colors.zinc.950/15%)] dark:[--radio-checked-indicator:theme(colors.zinc.900)]',
|
|
96
|
+
],
|
|
97
|
+
white:
|
|
98
|
+
'[--radio-checked-bg:theme(colors.white)] [--radio-checked-border:theme(colors.zinc.950/15%)] [--radio-checked-indicator:theme(colors.zinc.900)]',
|
|
99
|
+
dark: '[--radio-checked-bg:theme(colors.zinc.900)] [--radio-checked-border:theme(colors.zinc.950/90%)] [--radio-checked-indicator:theme(colors.white)]',
|
|
100
|
+
zinc: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.zinc.600)] [--radio-checked-border:theme(colors.zinc.700/90%)]',
|
|
101
|
+
red: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.red.600)] [--radio-checked-border:theme(colors.red.700/90%)]',
|
|
102
|
+
orange:
|
|
103
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.orange.500)] [--radio-checked-border:theme(colors.orange.600/90%)]',
|
|
104
|
+
amber:
|
|
105
|
+
'[--radio-checked-bg:theme(colors.amber.400)] [--radio-checked-border:theme(colors.amber.500/80%)] [--radio-checked-indicator:theme(colors.amber.950)]',
|
|
106
|
+
yellow:
|
|
107
|
+
'[--radio-checked-bg:theme(colors.yellow.300)] [--radio-checked-border:theme(colors.yellow.400/80%)] [--radio-checked-indicator:theme(colors.yellow.950)]',
|
|
108
|
+
lime: '[--radio-checked-bg:theme(colors.lime.300)] [--radio-checked-border:theme(colors.lime.400/80%)] [--radio-checked-indicator:theme(colors.lime.950)]',
|
|
109
|
+
green:
|
|
110
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.green.600)] [--radio-checked-border:theme(colors.green.700/90%)]',
|
|
111
|
+
emerald:
|
|
112
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.emerald.600)] [--radio-checked-border:theme(colors.emerald.700/90%)]',
|
|
113
|
+
teal: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.teal.600)] [--radio-checked-border:theme(colors.teal.700/90%)]',
|
|
114
|
+
cyan: '[--radio-checked-bg:theme(colors.cyan.300)] [--radio-checked-border:theme(colors.cyan.400/80%)] [--radio-checked-indicator:theme(colors.cyan.950)]',
|
|
115
|
+
sky: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.sky.500)] [--radio-checked-border:theme(colors.sky.600/80%)]',
|
|
116
|
+
blue: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.blue.600)] [--radio-checked-border:theme(colors.blue.700/90%)]',
|
|
117
|
+
indigo:
|
|
118
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.indigo.500)] [--radio-checked-border:theme(colors.indigo.600/90%)]',
|
|
119
|
+
violet:
|
|
120
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.violet.500)] [--radio-checked-border:theme(colors.violet.600/90%)]',
|
|
121
|
+
purple:
|
|
122
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.purple.500)] [--radio-checked-border:theme(colors.purple.600/90%)]',
|
|
123
|
+
fuchsia:
|
|
124
|
+
'[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.fuchsia.500)] [--radio-checked-border:theme(colors.fuchsia.600/90%)]',
|
|
125
|
+
pink: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.pink.500)] [--radio-checked-border:theme(colors.pink.600/90%)]',
|
|
126
|
+
rose: '[--radio-checked-indicator:theme(colors.white)] [--radio-checked-bg:theme(colors.rose.500)] [--radio-checked-border:theme(colors.rose.600/90%)]',
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function Radio({ color = 'dark/zinc', className, ...props }) {
|
|
130
|
+
return (
|
|
131
|
+
<HeadlessRadio data-slot="control" {...props} className={clsx(className, 'group inline-flex focus:outline-none')}>
|
|
132
|
+
<span className={clsx([base, colors[color]])}>
|
|
133
|
+
<span
|
|
134
|
+
className={clsx(
|
|
135
|
+
'size-full rounded-full border-[4.5px] border-transparent bg-[--radio-indicator] bg-clip-padding',
|
|
136
|
+
|
|
137
|
+
// Forced colors mode
|
|
138
|
+
'forced-colors:border-[Canvas] forced-colors:group-data-[checked]:border-[Highlight]'
|
|
139
|
+
)}
|
|
140
|
+
/>
|
|
141
|
+
</span>
|
|
142
|
+
</HeadlessRadio>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Select as HeadlessSelect } from '@headlessui/react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { forwardRef } from 'react'
|
|
4
|
+
|
|
5
|
+
export const Select = forwardRef(function Select({ className, multiple, ...props }, ref) {
|
|
6
|
+
return (
|
|
7
|
+
<span
|
|
8
|
+
data-slot="control"
|
|
9
|
+
className={clsx([
|
|
10
|
+
className,
|
|
11
|
+
|
|
12
|
+
// Basic layout
|
|
13
|
+
'group relative block w-full',
|
|
14
|
+
|
|
15
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
16
|
+
'before:absolute before:inset-px before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-white before:shadow',
|
|
17
|
+
|
|
18
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
19
|
+
'dark:before:hidden',
|
|
20
|
+
|
|
21
|
+
// Focus ring
|
|
22
|
+
'after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-inset after:ring-transparent sm:after:has-[[data-focus]]:ring-2 sm:after:has-[[data-focus]]:ring-blue-500',
|
|
23
|
+
|
|
24
|
+
// Disabled state
|
|
25
|
+
'has-[[data-disabled]]:opacity-50 before:has-[[data-disabled]]:bg-zinc-950/5 before:has-[[data-disabled]]:shadow-none',
|
|
26
|
+
])}
|
|
27
|
+
>
|
|
28
|
+
<HeadlessSelect
|
|
29
|
+
ref={ref}
|
|
30
|
+
multiple={multiple}
|
|
31
|
+
{...props}
|
|
32
|
+
className={clsx([
|
|
33
|
+
// Basic layout
|
|
34
|
+
'relative block w-full appearance-none rounded-lg py-[calc(theme(spacing[2.5])-1px)] sm:py-[calc(theme(spacing[1.5])-1px)]',
|
|
35
|
+
|
|
36
|
+
// Horizontal padding
|
|
37
|
+
multiple
|
|
38
|
+
? 'px-[calc(theme(spacing[3.5])-1px)] sm:px-[calc(theme(spacing.3)-1px)]'
|
|
39
|
+
: 'pl-[calc(theme(spacing[3.5])-1px)] pr-[calc(theme(spacing.10)-1px)] sm:pl-[calc(theme(spacing.3)-1px)] sm:pr-[calc(theme(spacing.9)-1px)]',
|
|
40
|
+
|
|
41
|
+
// Options (multi-select)
|
|
42
|
+
'[&_optgroup]:font-semibold',
|
|
43
|
+
|
|
44
|
+
// Typography
|
|
45
|
+
'text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white dark:*:text-white',
|
|
46
|
+
|
|
47
|
+
// Border
|
|
48
|
+
'border border-zinc-950/10 data-[hover]:border-zinc-950/20 dark:border-white/10 dark:data-[hover]:border-white/20',
|
|
49
|
+
|
|
50
|
+
// Background color
|
|
51
|
+
'bg-transparent dark:bg-white/5 dark:*:bg-zinc-800',
|
|
52
|
+
|
|
53
|
+
// Hide default focus styles
|
|
54
|
+
'focus:outline-none',
|
|
55
|
+
|
|
56
|
+
// Invalid state
|
|
57
|
+
'data-[invalid]:border-red-500 data-[invalid]:data-[hover]:border-red-500 data-[invalid]:dark:border-red-600 data-[invalid]:data-[hover]:dark:border-red-600',
|
|
58
|
+
|
|
59
|
+
// Disabled state
|
|
60
|
+
'data-[disabled]:border-zinc-950/20 data-[disabled]:opacity-100 dark:data-[hover]:data-[disabled]:border-white/15 data-[disabled]:dark:border-white/15 data-[disabled]:dark:bg-white/[2.5%]',
|
|
61
|
+
])}
|
|
62
|
+
/>
|
|
63
|
+
{!multiple && (
|
|
64
|
+
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
|
65
|
+
<svg
|
|
66
|
+
className="size-5 stroke-zinc-500 group-has-[[data-disabled]]:stroke-zinc-600 sm:size-4 dark:stroke-zinc-400 forced-colors:stroke-[CanvasText]"
|
|
67
|
+
viewBox="0 0 16 16"
|
|
68
|
+
aria-hidden="true"
|
|
69
|
+
fill="none"
|
|
70
|
+
>
|
|
71
|
+
<path d="M5.75 10.75L8 13L10.25 10.75" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
|
|
72
|
+
<path d="M10.25 5.25L8 3L5.75 5.25" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
|
|
73
|
+
</svg>
|
|
74
|
+
</span>
|
|
75
|
+
)}
|
|
76
|
+
</span>
|
|
77
|
+
)
|
|
78
|
+
})
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Field as HeadlessField, Switch as HeadlessSwitch } from '@headlessui/react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
|
|
4
|
+
export function SwitchGroup({ className, ...props }) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
data-slot="control"
|
|
8
|
+
{...props}
|
|
9
|
+
className={clsx(
|
|
10
|
+
className,
|
|
11
|
+
|
|
12
|
+
// Basic groups
|
|
13
|
+
'space-y-3 [&_[data-slot=label]]:font-normal',
|
|
14
|
+
|
|
15
|
+
// With descriptions
|
|
16
|
+
'has-[[data-slot=description]]:space-y-6 [&_[data-slot=label]]:has-[[data-slot=description]]:font-medium'
|
|
17
|
+
)}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function SwitchField({ className, ...props }) {
|
|
23
|
+
return (
|
|
24
|
+
<HeadlessField
|
|
25
|
+
data-slot="field"
|
|
26
|
+
{...props}
|
|
27
|
+
className={clsx(
|
|
28
|
+
className,
|
|
29
|
+
|
|
30
|
+
// Base layout
|
|
31
|
+
'grid grid-cols-[1fr_auto] items-center gap-x-8 gap-y-1 sm:grid-cols-[1fr_auto]',
|
|
32
|
+
|
|
33
|
+
// Control layout
|
|
34
|
+
'[&>[data-slot=control]]:col-start-2 [&>[data-slot=control]]:self-center',
|
|
35
|
+
|
|
36
|
+
// Label layout
|
|
37
|
+
'[&>[data-slot=label]]:col-start-1 [&>[data-slot=label]]:row-start-1 [&>[data-slot=label]]:justify-self-start',
|
|
38
|
+
|
|
39
|
+
// Description layout
|
|
40
|
+
'[&>[data-slot=description]]:col-start-1 [&>[data-slot=description]]:row-start-2',
|
|
41
|
+
|
|
42
|
+
// With description
|
|
43
|
+
'[&_[data-slot=label]]:has-[[data-slot=description]]:font-medium'
|
|
44
|
+
)}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const colors = {
|
|
50
|
+
'dark/zinc': [
|
|
51
|
+
'[--switch-bg-ring:theme(colors.zinc.950/90%)] [--switch-bg:theme(colors.zinc.900)] dark:[--switch-bg-ring:transparent] dark:[--switch-bg:theme(colors.white/25%)]',
|
|
52
|
+
'[--switch-ring:theme(colors.zinc.950/90%)] [--switch-shadow:theme(colors.black/10%)] [--switch:white] dark:[--switch-ring:theme(colors.zinc.700/90%)]',
|
|
53
|
+
],
|
|
54
|
+
'dark/white': [
|
|
55
|
+
'[--switch-bg-ring:theme(colors.zinc.950/90%)] [--switch-bg:theme(colors.zinc.900)] dark:[--switch-bg-ring:transparent] dark:[--switch-bg:theme(colors.white)]',
|
|
56
|
+
'[--switch-ring:theme(colors.zinc.950/90%)] [--switch-shadow:theme(colors.black/10%)] [--switch:white] dark:[--switch-ring:transparent] dark:[--switch:theme(colors.zinc.900)]',
|
|
57
|
+
],
|
|
58
|
+
dark: [
|
|
59
|
+
'[--switch-bg-ring:theme(colors.zinc.950/90%)] [--switch-bg:theme(colors.zinc.900)] dark:[--switch-bg-ring:theme(colors.white/15%)]',
|
|
60
|
+
'[--switch-ring:theme(colors.zinc.950/90%)] [--switch-shadow:theme(colors.black/10%)] [--switch:white]',
|
|
61
|
+
],
|
|
62
|
+
zinc: [
|
|
63
|
+
'[--switch-bg-ring:theme(colors.zinc.700/90%)] [--switch-bg:theme(colors.zinc.600)] dark:[--switch-bg-ring:transparent]',
|
|
64
|
+
'[--switch-shadow:theme(colors.black/10%)] [--switch:white] [--switch-ring:theme(colors.zinc.700/90%)]',
|
|
65
|
+
],
|
|
66
|
+
white: [
|
|
67
|
+
'[--switch-bg-ring:theme(colors.black/15%)] [--switch-bg:white] dark:[--switch-bg-ring:transparent]',
|
|
68
|
+
'[--switch-shadow:theme(colors.black/10%)] [--switch-ring:transparent] [--switch:theme(colors.zinc.950)]',
|
|
69
|
+
],
|
|
70
|
+
red: [
|
|
71
|
+
'[--switch-bg-ring:theme(colors.red.700/90%)] [--switch-bg:theme(colors.red.600)] dark:[--switch-bg-ring:transparent]',
|
|
72
|
+
'[--switch:white] [--switch-ring:theme(colors.red.700/90%)] [--switch-shadow:theme(colors.red.900/20%)]',
|
|
73
|
+
],
|
|
74
|
+
orange: [
|
|
75
|
+
'[--switch-bg-ring:theme(colors.orange.600/90%)] [--switch-bg:theme(colors.orange.500)] dark:[--switch-bg-ring:transparent]',
|
|
76
|
+
'[--switch:white] [--switch-ring:theme(colors.orange.600/90%)] [--switch-shadow:theme(colors.orange.900/20%)]',
|
|
77
|
+
],
|
|
78
|
+
amber: [
|
|
79
|
+
'[--switch-bg-ring:theme(colors.amber.500/80%)] [--switch-bg:theme(colors.amber.400)] dark:[--switch-bg-ring:transparent]',
|
|
80
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:theme(colors.amber.950)]',
|
|
81
|
+
],
|
|
82
|
+
yellow: [
|
|
83
|
+
'[--switch-bg-ring:theme(colors.yellow.400/80%)] [--switch-bg:theme(colors.yellow.300)] dark:[--switch-bg-ring:transparent]',
|
|
84
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:theme(colors.yellow.950)]',
|
|
85
|
+
],
|
|
86
|
+
lime: [
|
|
87
|
+
'[--switch-bg-ring:theme(colors.lime.400/80%)] [--switch-bg:theme(colors.lime.300)] dark:[--switch-bg-ring:transparent]',
|
|
88
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:theme(colors.lime.950)]',
|
|
89
|
+
],
|
|
90
|
+
green: [
|
|
91
|
+
'[--switch-bg-ring:theme(colors.green.700/90%)] [--switch-bg:theme(colors.green.600)] dark:[--switch-bg-ring:transparent]',
|
|
92
|
+
'[--switch:white] [--switch-ring:theme(colors.green.700/90%)] [--switch-shadow:theme(colors.green.900/20%)]',
|
|
93
|
+
],
|
|
94
|
+
emerald: [
|
|
95
|
+
'[--switch-bg-ring:theme(colors.emerald.600/90%)] [--switch-bg:theme(colors.emerald.500)] dark:[--switch-bg-ring:transparent]',
|
|
96
|
+
'[--switch:white] [--switch-ring:theme(colors.emerald.600/90%)] [--switch-shadow:theme(colors.emerald.900/20%)]',
|
|
97
|
+
],
|
|
98
|
+
teal: [
|
|
99
|
+
'[--switch-bg-ring:theme(colors.teal.700/90%)] [--switch-bg:theme(colors.teal.600)] dark:[--switch-bg-ring:transparent]',
|
|
100
|
+
'[--switch:white] [--switch-ring:theme(colors.teal.700/90%)] [--switch-shadow:theme(colors.teal.900/20%)]',
|
|
101
|
+
],
|
|
102
|
+
cyan: [
|
|
103
|
+
'[--switch-bg-ring:theme(colors.cyan.400/80%)] [--switch-bg:theme(colors.cyan.300)] dark:[--switch-bg-ring:transparent]',
|
|
104
|
+
'[--switch-ring:transparent] [--switch-shadow:transparent] [--switch:theme(colors.cyan.950)]',
|
|
105
|
+
],
|
|
106
|
+
sky: [
|
|
107
|
+
'[--switch-bg-ring:theme(colors.sky.600/80%)] [--switch-bg:theme(colors.sky.500)] dark:[--switch-bg-ring:transparent]',
|
|
108
|
+
'[--switch:white] [--switch-ring:theme(colors.sky.600/80%)] [--switch-shadow:theme(colors.sky.900/20%)]',
|
|
109
|
+
],
|
|
110
|
+
blue: [
|
|
111
|
+
'[--switch-bg-ring:theme(colors.blue.700/90%)] [--switch-bg:theme(colors.blue.600)] dark:[--switch-bg-ring:transparent]',
|
|
112
|
+
'[--switch:white] [--switch-ring:theme(colors.blue.700/90%)] [--switch-shadow:theme(colors.blue.900/20%)]',
|
|
113
|
+
],
|
|
114
|
+
indigo: [
|
|
115
|
+
'[--switch-bg-ring:theme(colors.indigo.600/90%)] [--switch-bg:theme(colors.indigo.500)] dark:[--switch-bg-ring:transparent]',
|
|
116
|
+
'[--switch:white] [--switch-ring:theme(colors.indigo.600/90%)] [--switch-shadow:theme(colors.indigo.900/20%)]',
|
|
117
|
+
],
|
|
118
|
+
violet: [
|
|
119
|
+
'[--switch-bg-ring:theme(colors.violet.600/90%)] [--switch-bg:theme(colors.violet.500)] dark:[--switch-bg-ring:transparent]',
|
|
120
|
+
'[--switch:white] [--switch-ring:theme(colors.violet.600/90%)] [--switch-shadow:theme(colors.violet.900/20%)]',
|
|
121
|
+
],
|
|
122
|
+
purple: [
|
|
123
|
+
'[--switch-bg-ring:theme(colors.purple.600/90%)] [--switch-bg:theme(colors.purple.500)] dark:[--switch-bg-ring:transparent]',
|
|
124
|
+
'[--switch:white] [--switch-ring:theme(colors.purple.600/90%)] [--switch-shadow:theme(colors.purple.900/20%)]',
|
|
125
|
+
],
|
|
126
|
+
fuchsia: [
|
|
127
|
+
'[--switch-bg-ring:theme(colors.fuchsia.600/90%)] [--switch-bg:theme(colors.fuchsia.500)] dark:[--switch-bg-ring:transparent]',
|
|
128
|
+
'[--switch:white] [--switch-ring:theme(colors.fuchsia.600/90%)] [--switch-shadow:theme(colors.fuchsia.900/20%)]',
|
|
129
|
+
],
|
|
130
|
+
pink: [
|
|
131
|
+
'[--switch-bg-ring:theme(colors.pink.600/90%)] [--switch-bg:theme(colors.pink.500)] dark:[--switch-bg-ring:transparent]',
|
|
132
|
+
'[--switch:white] [--switch-ring:theme(colors.pink.600/90%)] [--switch-shadow:theme(colors.pink.900/20%)]',
|
|
133
|
+
],
|
|
134
|
+
rose: [
|
|
135
|
+
'[--switch-bg-ring:theme(colors.rose.600/90%)] [--switch-bg:theme(colors.rose.500)] dark:[--switch-bg-ring:transparent]',
|
|
136
|
+
'[--switch:white] [--switch-ring:theme(colors.rose.600/90%)] [--switch-shadow:theme(colors.rose.900/20%)]',
|
|
137
|
+
],
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function Switch({ color = 'dark/zinc', className, children, ...props }) {
|
|
141
|
+
return (
|
|
142
|
+
<HeadlessSwitch
|
|
143
|
+
data-slot="control"
|
|
144
|
+
className={clsx(
|
|
145
|
+
className,
|
|
146
|
+
|
|
147
|
+
// Base styles
|
|
148
|
+
'group relative isolate inline-flex h-6 w-10 cursor-default rounded-full p-[3px] sm:h-5 sm:w-8',
|
|
149
|
+
|
|
150
|
+
// Transitions
|
|
151
|
+
'transition duration-0 ease-in-out data-[changing]:duration-200',
|
|
152
|
+
|
|
153
|
+
// Outline and background color in forced-colors mode so switch is still visible
|
|
154
|
+
'forced-colors:outline forced-colors:[--switch-bg:Highlight] dark:forced-colors:[--switch-bg:Highlight]',
|
|
155
|
+
|
|
156
|
+
// Unchecked
|
|
157
|
+
'bg-zinc-200 ring-1 ring-inset ring-black/5 dark:bg-white/5 dark:ring-white/15',
|
|
158
|
+
|
|
159
|
+
// Checked
|
|
160
|
+
'data-[checked]:bg-[--switch-bg] data-[checked]:ring-[--switch-bg-ring] dark:data-[checked]:bg-[--switch-bg] dark:data-[checked]:ring-[--switch-bg-ring]',
|
|
161
|
+
|
|
162
|
+
// Focus
|
|
163
|
+
'focus:outline-none data-[focus]:outline data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-blue-500',
|
|
164
|
+
|
|
165
|
+
// Hover
|
|
166
|
+
'data-[hover]:data-[checked]:ring-[--switch-bg-ring] data-[hover]:ring-black/15',
|
|
167
|
+
'dark:data-[hover]:data-[checked]:ring-[--switch-bg-ring] dark:data-[hover]:ring-white/25',
|
|
168
|
+
|
|
169
|
+
// Disabled
|
|
170
|
+
'data-[disabled]:bg-zinc-200 data-[disabled]:data-[checked]:bg-zinc-200 data-[disabled]:opacity-50 data-[disabled]:data-[checked]:ring-black/5',
|
|
171
|
+
'dark:data-[disabled]:bg-white/15 dark:data-[disabled]:data-[checked]:bg-white/15 dark:data-[disabled]:data-[checked]:ring-white/15',
|
|
172
|
+
|
|
173
|
+
// Color specific styles
|
|
174
|
+
colors[color]
|
|
175
|
+
)}
|
|
176
|
+
{...props}
|
|
177
|
+
>
|
|
178
|
+
<span
|
|
179
|
+
aria-hidden="true"
|
|
180
|
+
className={clsx(
|
|
181
|
+
// Basic layout
|
|
182
|
+
'pointer-events-none relative inline-block size-[1.125rem] rounded-full sm:size-3.5',
|
|
183
|
+
|
|
184
|
+
// Transition
|
|
185
|
+
'translate-x-0 transition duration-200 ease-in-out',
|
|
186
|
+
|
|
187
|
+
// Invisible border so the switch is still visible in forced-colors mode
|
|
188
|
+
'border border-transparent',
|
|
189
|
+
|
|
190
|
+
// Unchecked
|
|
191
|
+
'bg-white shadow ring-1 ring-black/5',
|
|
192
|
+
|
|
193
|
+
// Checked
|
|
194
|
+
'group-data-[checked]:bg-[--switch] group-data-[checked]:shadow-[--switch-shadow] group-data-[checked]:ring-[--switch-ring]',
|
|
195
|
+
'group-data-[checked]:translate-x-4 sm:group-data-[checked]:translate-x-3',
|
|
196
|
+
|
|
197
|
+
// Disabled
|
|
198
|
+
'group-data-[disabled]:group-data-[checked]:bg-white group-data-[disabled]:group-data-[checked]:shadow group-data-[disabled]:group-data-[checked]:ring-black/5'
|
|
199
|
+
)}
|
|
200
|
+
/>
|
|
201
|
+
</HeadlessSwitch>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Textarea as HeadlessTextarea } from '@headlessui/react'
|
|
2
|
+
import { clsx } from 'clsx'
|
|
3
|
+
import { forwardRef } from 'react'
|
|
4
|
+
|
|
5
|
+
export const Textarea = forwardRef(function Textarea({ className, resizable = true, ...props }, ref) {
|
|
6
|
+
return (
|
|
7
|
+
<span
|
|
8
|
+
data-slot="control"
|
|
9
|
+
className={clsx([
|
|
10
|
+
className,
|
|
11
|
+
|
|
12
|
+
// Basic layout
|
|
13
|
+
'relative block w-full',
|
|
14
|
+
|
|
15
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
16
|
+
'before:absolute before:inset-px before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-white before:shadow',
|
|
17
|
+
|
|
18
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
19
|
+
'dark:before:hidden',
|
|
20
|
+
|
|
21
|
+
// Focus ring
|
|
22
|
+
'after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-inset after:ring-transparent sm:after:focus-within:ring-2 sm:after:focus-within:ring-blue-500',
|
|
23
|
+
|
|
24
|
+
// Disabled state
|
|
25
|
+
'has-[[data-disabled]]:opacity-50 before:has-[[data-disabled]]:bg-zinc-950/5 before:has-[[data-disabled]]:shadow-none',
|
|
26
|
+
])}
|
|
27
|
+
>
|
|
28
|
+
<HeadlessTextarea
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={clsx([
|
|
31
|
+
// Basic layout
|
|
32
|
+
'relative block h-full w-full appearance-none rounded-lg px-[calc(theme(spacing[3.5])-1px)] py-[calc(theme(spacing[2.5])-1px)] sm:px-[calc(theme(spacing.3)-1px)] sm:py-[calc(theme(spacing[1.5])-1px)]',
|
|
33
|
+
|
|
34
|
+
// Typography
|
|
35
|
+
'text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white',
|
|
36
|
+
|
|
37
|
+
// Border
|
|
38
|
+
'border border-zinc-950/10 data-[hover]:border-zinc-950/20 dark:border-white/10 dark:data-[hover]:border-white/20',
|
|
39
|
+
|
|
40
|
+
// Background color
|
|
41
|
+
'bg-transparent dark:bg-white/5',
|
|
42
|
+
|
|
43
|
+
// Hide default focus styles
|
|
44
|
+
'focus:outline-none',
|
|
45
|
+
|
|
46
|
+
// Invalid state
|
|
47
|
+
'data-[invalid]:border-red-500 data-[invalid]:data-[hover]:border-red-500 data-[invalid]:dark:border-red-600 data-[invalid]:data-[hover]:dark:border-red-600',
|
|
48
|
+
|
|
49
|
+
// Disabled state
|
|
50
|
+
'disabled:border-zinc-950/20 disabled:dark:border-white/15 disabled:dark:bg-white/[2.5%] dark:data-[hover]:disabled:border-white/15',
|
|
51
|
+
|
|
52
|
+
// Resizable
|
|
53
|
+
resizable ? 'resize-y' : 'resize-none',
|
|
54
|
+
])}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
</span>
|
|
58
|
+
)
|
|
59
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { MdHome } from "react-icons/md";
|
|
3
|
+
import { VscChevronRight } from "react-icons/vsc";
|
|
4
|
+
|
|
5
|
+
function BreadcrumbItem({ className, href, text }) {
|
|
6
|
+
const cls = clsx(
|
|
7
|
+
"text-gray-300 hover:text-gray-500 last:text-gray-900",
|
|
8
|
+
className
|
|
9
|
+
);
|
|
10
|
+
return (
|
|
11
|
+
<li className={cls}>
|
|
12
|
+
<div className="flex items-center">
|
|
13
|
+
<VscChevronRight
|
|
14
|
+
size={18}
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
color="rgb(156 163 175)"
|
|
17
|
+
/>
|
|
18
|
+
<a href={href} className="ml-2 hover:underline">
|
|
19
|
+
{text}
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
</li>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function Breadcrumbs({ className, children }) {
|
|
27
|
+
const cls = clsx("flex items-center justify-between py-4", className);
|
|
28
|
+
return (
|
|
29
|
+
<nav className={cls}>
|
|
30
|
+
<ol className="flex items-center space-x-2">
|
|
31
|
+
<li>
|
|
32
|
+
<div>
|
|
33
|
+
<a href="/" className="text-gray-300 hover:text-gray-500">
|
|
34
|
+
<MdHome size={22} />
|
|
35
|
+
<span className="sr-only">Home</span>
|
|
36
|
+
</a>
|
|
37
|
+
</div>
|
|
38
|
+
</li>
|
|
39
|
+
{children}
|
|
40
|
+
</ol>
|
|
41
|
+
</nav>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default Breadcrumbs;
|
|
46
|
+
export { Breadcrumbs, BreadcrumbItem };
|