@adaptive-sm/astro-ui 0.1.0
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/LICENSE +22 -0
- package/README.md +183 -0
- package/lib/button/Button.astro +58 -0
- package/lib/button/buttonCva.ts +196 -0
- package/lib/button/buttonIconCva.ts +52 -0
- package/lib/button/classesButtonClickAnimation.ts +8 -0
- package/lib/button/classesButtonClickAnimationPush.ts +6 -0
- package/lib/button/classesButtonClickAnimationSquish.ts +6 -0
- package/lib/button/classesButtonDisabled.ts +1 -0
- package/lib/card/CardWrapper.astro +15 -0
- package/lib/card/classesCardWrapper.ts +16 -0
- package/lib/details/Details.astro +57 -0
- package/lib/dev/TailwindIndicator.astro +28 -0
- package/lib/form/Fieldset.astro +21 -0
- package/lib/form/classesFieldset.ts +1 -0
- package/lib/generate_ai_rules/generate_agent_rules.bash +9 -0
- package/lib/generate_ai_rules/generate_agent_rules_1_lib.bash +33 -0
- package/lib/generate_ai_rules/generate_agent_rules_2_copy.bash +14 -0
- package/lib/generate_ai_rules/generate_agent_rules_3_combine.bash +31 -0
- package/lib/generate_demo_list/DemoList.astro +31 -0
- package/lib/generate_demo_list/DemoListType.ts +1 -0
- package/lib/generate_demo_list/generateDemoList.ts +55 -0
- package/lib/generate_image_list/generateImageList.ts +101 -0
- package/lib/grid/classesGridCols.ts +86 -0
- package/lib/icon/Icon1.astro +21 -0
- package/lib/img/ImageType.ts +6 -0
- package/lib/img/Img.astro +27 -0
- package/lib/img/TypedImg.astro +26 -0
- package/lib/img/classInvertDiagram.ts +1 -0
- package/lib/img/classesImgZoomInOnHover.ts +1 -0
- package/lib/layouts/MarkdownWrapper.astro +17 -0
- package/lib/layouts/MinimalLayout.astro +67 -0
- package/lib/layouts/parts/ThemeToggle.astro +137 -0
- package/lib/layouts/parts/astroElementId.ts +7 -0
- package/lib/layouts/parts/markdown.css +93 -0
- package/lib/link/LinkButton.astro +48 -0
- package/lib/link/LinkText.astro +23 -0
- package/lib/link/classesTextLink.ts +13 -0
- package/lib/list/BlackBulletPoint.astro +16 -0
- package/lib/list/BlackBulletPoints.astro +23 -0
- package/lib/list/CheckPoint.astro +20 -0
- package/lib/list/CheckPoints.astro +23 -0
- package/lib/list/NumberedList.astro +14 -0
- package/lib/list/Ps.astro +12 -0
- package/lib/list/TextOrLink.astro +19 -0
- package/lib/modal/Modal.astro +54 -0
- package/lib/modal/Modal.module.css +19 -0
- package/lib/modal/ModalButton.astro +41 -0
- package/lib/modal/modal.ts +137 -0
- package/lib/page/PageCentered.astro +14 -0
- package/lib/page/PageCenteredCard.astro +17 -0
- package/lib/page/classesBg.ts +27 -0
- package/lib/page/classesPageCentered.ts +6 -0
- package/lib/popover/Popover1.astro +45 -0
- package/lib/popover/setupPopoverListeners.ts +22 -0
- package/lib/select/Select.astro +45 -0
- package/lib/table/DesktopTableClassses.ts +6 -0
- package/lib/table/MobileTableClassses.ts +7 -0
- package/lib/table/Table.astro +41 -0
- package/lib/table/TableColumnDef.ts +10 -0
- package/lib/table/TableD.astro +55 -0
- package/lib/table/TableM.astro +22 -0
- package/lib/table/TableMEntry.astro +27 -0
- package/lib/table/sharedTableRowClasses.ts +1 -0
- package/lib/table/tableVisibilityClasses.ts +28 -0
- package/lib/text/classesTextGray.ts +1 -0
- package/lib/text/classesTextHeader.ts +1 -0
- package/lib/utils/bun/BunCmd.ts +7 -0
- package/lib/utils/bun/cryAndTryAgainLater.ts +6 -0
- package/lib/utils/bun/logBunCmd.ts +1 -0
- package/lib/utils/bun/runCmdAsync.ts +44 -0
- package/lib/utils/bun/runCmdLocally.ts +13 -0
- package/lib/utils/obj/objectKeys.ts +21 -0
- package/lib/utils/ran/generateId12.ts +7 -0
- package/lib/utils/ran/generateId3.ts +7 -0
- package/lib/utils/ran/generateId4.ts +7 -0
- package/lib/utils/ran/generateId5.ts +7 -0
- package/lib/utils/ran/generateId6.ts +7 -0
- package/lib/utils/ran/generateId7.ts +7 -0
- package/lib/utils/ran/generateReadableId.ts +35 -0
- package/lib/utils/ran/urlAlphabet32.ts +8 -0
- package/lib/utils/ui/classArr.ts +3 -0
- package/lib/utils/ui/classMerge.ts +10 -0
- package/lib/utils/ui/isDevEnv.ts +7 -0
- package/lib/utils/ui/tailwindBreakpoint.ts +83 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025 Adaptive Shield Matrix
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Adaptive Astro UI
|
|
2
|
+
|
|
3
|
+
A library of reusable UI components for Astro projects. Built with TypeScript, Tailwind CSS, and Astro in static output mode. Components are designed to be accessible, customizable, and easy to integrate.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the package using Bun:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @adaptive-sm/astro-ui
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Recommended configuration
|
|
14
|
+
|
|
15
|
+
In your `astro.config.mjs`, set up the `~` alias to point to the library:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import { defineConfig } from 'astro/config';
|
|
19
|
+
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
vite: {
|
|
22
|
+
resolve: {
|
|
23
|
+
alias: {
|
|
24
|
+
'~': new URL('./node_modules/@adaptive-sm/astro-ui/lib', import.meta.url).pathname,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Tailwind CSS Configuration
|
|
32
|
+
|
|
33
|
+
To ensure Tailwind scans the library's source files for classes (since components are published as source without a build step), add the following `@source` directive to your project's `src/layouts/global.css` (or equivalent global stylesheet):
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
@source '/node_modules/@adaptive-sm/astro-ui/lib/**/*.{astro,html,md,mdx,ts,tsx}';
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This tells Tailwind to include classes from the library's `.astro`, `.ts`, and other relevant files in the purge process, preventing unused classes from being purged during the build. Without it, Tailwind might not detect classes used in imported components, leading to missing styles.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
## No Build Step Required
|
|
44
|
+
|
|
45
|
+
This library ships source `.astro` and `.ts` files directly—no pre-build needed. Benefits include:
|
|
46
|
+
|
|
47
|
+
- **Smaller size**: No bundled or compiled files.
|
|
48
|
+
- **Full compatibility**: Your Astro project compiles components using its own Astro, Vite, and Tailwind setup.
|
|
49
|
+
- **Better DX**: Preserves TypeScript types and IntelliSense.
|
|
50
|
+
- **Easier updates**: Consumers get changes immediately, with no build artifacts to manage.
|
|
51
|
+
|
|
52
|
+
Just set up your alias - Astro handles the rest automatically.
|
|
53
|
+
|
|
54
|
+
Import and use components directly in your Astro files. For example:
|
|
55
|
+
|
|
56
|
+
### Button Component
|
|
57
|
+
|
|
58
|
+
```astro
|
|
59
|
+
---
|
|
60
|
+
import { Button } from '~/button/Button.astro';
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<Button variant="primary">Click me</Button>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Card Component
|
|
67
|
+
|
|
68
|
+
```astro
|
|
69
|
+
---
|
|
70
|
+
import { CardWrapper } from '~/card/CardWrapper.astro';
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
<CardWrapper>
|
|
74
|
+
Card content here.
|
|
75
|
+
</CardWrapper>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Image Component
|
|
79
|
+
|
|
80
|
+
```astro
|
|
81
|
+
---
|
|
82
|
+
import { Img } from '~/img/Img.astro';
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
<Img src="/path/to/image.jpg" alt="Description" />
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Refer to individual component documentation in the source code for props and variants.
|
|
89
|
+
|
|
90
|
+
## Components
|
|
91
|
+
|
|
92
|
+
### Buttons
|
|
93
|
+
- [Button.astro](lib/button/Button.astro)
|
|
94
|
+
- Button variants and animations via CVAs in `buttonCva.ts`, `buttonIconCva.ts`
|
|
95
|
+
|
|
96
|
+
### Cards
|
|
97
|
+
- [CardWrapper.astro](lib/card/CardWrapper.astro)
|
|
98
|
+
|
|
99
|
+
### Details
|
|
100
|
+
- [Details.astro](lib/details/Details.astro)
|
|
101
|
+
|
|
102
|
+
### Forms
|
|
103
|
+
- [Fieldset.astro](lib/form/Fieldset.astro)
|
|
104
|
+
|
|
105
|
+
### Icons
|
|
106
|
+
- [Icon1.astro](lib/icon/Icon1.astro) (replaces SVG icons)
|
|
107
|
+
|
|
108
|
+
### Images
|
|
109
|
+
- [Img.astro](lib/img/Img.astro)
|
|
110
|
+
- [TypedImg.astro](lib/img/TypedImg.astro)
|
|
111
|
+
|
|
112
|
+
### Layouts
|
|
113
|
+
- [MinimalLayout.astro](lib/layouts/MinimalLayout.astro)
|
|
114
|
+
- [MarkdownWrapper.astro](lib/layouts/MarkdownWrapper.astro)
|
|
115
|
+
- [ThemeToggle.astro](lib/layouts/parts/ThemeToggle.astro)
|
|
116
|
+
|
|
117
|
+
### Links
|
|
118
|
+
- [LinkText.astro](lib/link/LinkText.astro)
|
|
119
|
+
- [LinkButton.astro](lib/link/LinkButton.astro)
|
|
120
|
+
|
|
121
|
+
### Lists
|
|
122
|
+
- [BlackBulletPoints.astro](lib/list/BlackBulletPoints.astro)
|
|
123
|
+
- [CheckPoints.astro](lib/list/CheckPoints.astro)
|
|
124
|
+
- [NumberedList.astro](lib/list/NumberedList.astro)
|
|
125
|
+
|
|
126
|
+
### Modals
|
|
127
|
+
- [ModalButton.astro](lib/modal/ModalButton.astro)
|
|
128
|
+
|
|
129
|
+
### Pages
|
|
130
|
+
- [PageCentered.astro](lib/page/PageCentered.astro)
|
|
131
|
+
- [PageCenteredCard.astro](lib/page/PageCenteredCard.astro)
|
|
132
|
+
|
|
133
|
+
### Popovers
|
|
134
|
+
- [Popover1.astro](lib/popover/Popover1.astro)
|
|
135
|
+
|
|
136
|
+
### Selects
|
|
137
|
+
- [Select.astro](lib/select/Select.astro)
|
|
138
|
+
|
|
139
|
+
### Table
|
|
140
|
+
- [Table.astro](lib/table/Table.astro)
|
|
141
|
+
|
|
142
|
+
## Demos
|
|
143
|
+
|
|
144
|
+
Explore component demos at:
|
|
145
|
+
[https://adaptive-astro-ui.pages.dev/](https://adaptive-astro-ui.pages.dev/)
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
### Building the Library
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
bun run build
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Running Demos
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
bun run dev
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Linting and Formatting
|
|
162
|
+
|
|
163
|
+
Uses Biome for linting and formatting:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
bun run biome check .
|
|
167
|
+
bun run biome format --write .
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Contributing
|
|
171
|
+
|
|
172
|
+
1. Fork the repository.
|
|
173
|
+
2. Create a feature branch.
|
|
174
|
+
3. Add or update components in `lib/`.
|
|
175
|
+
4. Update demos in `src/pages/demos/`.
|
|
176
|
+
5. Ensure tests pass and run `bun run build`.
|
|
177
|
+
6. Submit a pull request.
|
|
178
|
+
|
|
179
|
+
Follow the coding rules in `.roo/rules-code/` for style and best practices.
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { buttonCva2, type ButtonSize, type ButtonVariant } from "~/button/buttonCva"
|
|
3
|
+
import { buttonIconCva } from "~/button/buttonIconCva"
|
|
4
|
+
import { classesButtonClickAnimation } from "~/button/classesButtonClickAnimation"
|
|
5
|
+
import Icon1 from "~/icon/Icon1.astro"
|
|
6
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
id?: string
|
|
10
|
+
textId?: string
|
|
11
|
+
contentId?: string
|
|
12
|
+
contentClass?: string
|
|
13
|
+
title?: string
|
|
14
|
+
text?: string
|
|
15
|
+
variant: ButtonVariant
|
|
16
|
+
size?: ButtonSize
|
|
17
|
+
icon?: string
|
|
18
|
+
iconRight?: string
|
|
19
|
+
iconClass?: string
|
|
20
|
+
class?: string
|
|
21
|
+
onclick?: any
|
|
22
|
+
}
|
|
23
|
+
const props = Astro.props
|
|
24
|
+
|
|
25
|
+
const classes = buttonCva2(props.variant, props.size, classesButtonClickAnimation, props.class)
|
|
26
|
+
const hasChildren = Astro.slots.has("default")
|
|
27
|
+
const hasContent = hasChildren || props.text
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<button id={props.id} title={props.title} class={classes} onclick={props.onclick}>
|
|
31
|
+
{
|
|
32
|
+
props.icon && (
|
|
33
|
+
<Icon1
|
|
34
|
+
path={props.icon}
|
|
35
|
+
class={classMerge(hasContent && "mr-2", buttonIconCva(props.variant, props.iconClass))}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
{
|
|
40
|
+
props.text && (
|
|
41
|
+
<span id={props.contentId} class={props.contentClass}>
|
|
42
|
+
{props.text}
|
|
43
|
+
</span>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
{
|
|
47
|
+
hasContent && (
|
|
48
|
+
<span id={props.contentId} class={props.contentClass}>
|
|
49
|
+
<slot />
|
|
50
|
+
</span>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
{
|
|
54
|
+
props.iconRight && (
|
|
55
|
+
<Icon1 path={props.iconRight} class={buttonIconCva(props.variant, hasContent && "ml-2", props.iconClass)} />
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
</button>
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { classArr } from "~/utils/ui/classArr"
|
|
2
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
3
|
+
import { classesButtonClickAnimation } from "./classesButtonClickAnimation"
|
|
4
|
+
import { classesButtonDisabled } from "./classesButtonDisabled"
|
|
5
|
+
|
|
6
|
+
export type ButtonVariant = keyof typeof buttonVariant
|
|
7
|
+
export const buttonVariant = {
|
|
8
|
+
// transparent bg
|
|
9
|
+
outline: "outline",
|
|
10
|
+
ghost: "ghost",
|
|
11
|
+
link: "link",
|
|
12
|
+
// filled black/white/gray
|
|
13
|
+
filled: "filled",
|
|
14
|
+
subtle: "subtle",
|
|
15
|
+
contrast: "contrast",
|
|
16
|
+
// filled colors
|
|
17
|
+
filledYellow: "filledYellow",
|
|
18
|
+
filledAmber: "filledAmber",
|
|
19
|
+
filledOrange: "filledOrange",
|
|
20
|
+
filledRed: "filledRed",
|
|
21
|
+
filledGreen: "filledGreen",
|
|
22
|
+
filledSky: "filledSky",
|
|
23
|
+
filledIndigo: "filledIndigo",
|
|
24
|
+
// outlined colors
|
|
25
|
+
outlineRed: "outlineRed",
|
|
26
|
+
} as const
|
|
27
|
+
|
|
28
|
+
export type ButtonSize = keyof typeof buttonSize
|
|
29
|
+
export const buttonSize = {
|
|
30
|
+
none: "none",
|
|
31
|
+
minimal: "minimal",
|
|
32
|
+
sm: "sm",
|
|
33
|
+
default: "default",
|
|
34
|
+
lg: "lg",
|
|
35
|
+
} as const
|
|
36
|
+
|
|
37
|
+
export type ButtonCvaProps = {
|
|
38
|
+
variant?: ButtonVariant
|
|
39
|
+
size?: ButtonSize
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const baseClasses = classArr(
|
|
43
|
+
"inline-flex", // layout
|
|
44
|
+
"font-medium", // text
|
|
45
|
+
"items-center justify-center", // layout children
|
|
46
|
+
"rounded-md ring-offset-background", // rounded, rings
|
|
47
|
+
"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", // focus
|
|
48
|
+
"transition-colors", // animation
|
|
49
|
+
"group",
|
|
50
|
+
"cursor-pointer",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const variantClasses = {
|
|
54
|
+
//
|
|
55
|
+
// transparent bg
|
|
56
|
+
//
|
|
57
|
+
outline: classArr(
|
|
58
|
+
"bg-transparent dark:bg-transparent",
|
|
59
|
+
"dark:text-slate-100", // text
|
|
60
|
+
"hover:bg-slate-100", // bg hover
|
|
61
|
+
"border border-slate-200 dark:border-slate-700 dark:hover:bg-slate-900", // border
|
|
62
|
+
),
|
|
63
|
+
ghost: classArr(
|
|
64
|
+
"dark:text-slate-100 dark:hover:text-slate-100", // text
|
|
65
|
+
"bg-transparent dark:bg-transparent", // bg
|
|
66
|
+
"data-[state=open]:bg-transparent dark:data-[state=open]:bg-transparent", // bg data
|
|
67
|
+
"hover:bg-slate-100 dark:hover:bg-slate-800", // bg hover
|
|
68
|
+
),
|
|
69
|
+
link: classArr(
|
|
70
|
+
"text-slate-900 dark:text-slate-100", // text
|
|
71
|
+
"underline-offset-4 hover:underline ", // underline
|
|
72
|
+
"bg-transparent dark:bg-transparent", // bg
|
|
73
|
+
"hover:bg-transparent dark:hover:bg-transparent", // bg hover
|
|
74
|
+
),
|
|
75
|
+
//
|
|
76
|
+
// filled grayscale
|
|
77
|
+
//
|
|
78
|
+
filled: classArr(
|
|
79
|
+
"dark:text-slate-100", // text
|
|
80
|
+
"bg-white dark:bg-black", // bg
|
|
81
|
+
"hover:bg-slate-50 dark:hover:bg-slate-900", // bg hover
|
|
82
|
+
),
|
|
83
|
+
subtle: classArr(
|
|
84
|
+
"text-slate-900 dark:text-slate-100", // text
|
|
85
|
+
"bg-slate-100 dark:bg-slate-700", // bg
|
|
86
|
+
"hover:bg-slate-200 dark:hover:bg-slate-600", // bg hover
|
|
87
|
+
),
|
|
88
|
+
contrast: classArr(
|
|
89
|
+
"text-white dark:text-slate-900 dark:hover:text-slate-900", // text
|
|
90
|
+
"bg-slate-900 dark:bg-slate-50", // bg
|
|
91
|
+
"hover:bg-slate-700 dark:hover:bg-slate-300", // bg hover
|
|
92
|
+
),
|
|
93
|
+
//
|
|
94
|
+
// filled colors
|
|
95
|
+
//
|
|
96
|
+
filledYellow: classArr(
|
|
97
|
+
"text-white dark:text-yellow-100 ", // text
|
|
98
|
+
"bg-yellow-500 dark:bg-yellow-800 ", // bg
|
|
99
|
+
"hover:bg-yellow-700 dark:hover:bg-yellow-600", // bg hover
|
|
100
|
+
"focus:ring-yellow-400 dark:focus:ring-yellow-400", // focus
|
|
101
|
+
),
|
|
102
|
+
filledAmber: classArr(
|
|
103
|
+
"text-white dark:text-amber-100 ", // text
|
|
104
|
+
"bg-amber-500 dark:bg-amber-800 ", // bg
|
|
105
|
+
"hover:bg-amber-700 dark:hover:bg-amber-600", // bg hover
|
|
106
|
+
"focus:ring-amber-400 dark:focus:ring-amber-400", // focus
|
|
107
|
+
),
|
|
108
|
+
filledOrange: classArr(
|
|
109
|
+
"text-white dark:text-orange-100 ", // text
|
|
110
|
+
"bg-orange-500 dark:bg-orange-800 ", // bg
|
|
111
|
+
"hover:bg-orange-700 dark:hover:bg-orange-600", // bg hover
|
|
112
|
+
"focus:ring-orange-400 dark:focus:ring-orange-400", // focus
|
|
113
|
+
),
|
|
114
|
+
filledRed: classArr(
|
|
115
|
+
"text-white", // text
|
|
116
|
+
"bg-red-500 dark:bg-red-700", // bg
|
|
117
|
+
"hover:bg-red-600 dark:hover:bg-red-600", // bg hover
|
|
118
|
+
"focus:ring-red-400 dark:focus:ring-red-400", // focus
|
|
119
|
+
),
|
|
120
|
+
filledGreen: classArr(
|
|
121
|
+
"text-white", // text
|
|
122
|
+
"bg-green-500 hover:bg-green-700 dark:hover:bg-green-700", // bg
|
|
123
|
+
"focus:ring-green-400 dark:focus:ring-green-400", // focus
|
|
124
|
+
),
|
|
125
|
+
filledSky: classArr(
|
|
126
|
+
"text-white", // text
|
|
127
|
+
"bg-sky-500 hover:bg-sky-700 dark:hover:bg-sky-700", // bg
|
|
128
|
+
"focus:ring-sky-400 dark:focus:ring-sky-400", // focus
|
|
129
|
+
),
|
|
130
|
+
filledIndigo: classArr(
|
|
131
|
+
"text-white dark:text-indigo-100 ", // text
|
|
132
|
+
"bg-indigo-500 dark:bg-indigo-800 ", // bg
|
|
133
|
+
"hover:bg-indigo-700 dark:hover:bg-indigo-600", // bg hover
|
|
134
|
+
"focus:ring-indigo-400 dark:focus:ring-indigo-400", // focus
|
|
135
|
+
),
|
|
136
|
+
//
|
|
137
|
+
// outline toast colors
|
|
138
|
+
//
|
|
139
|
+
outlineRed: classArr(
|
|
140
|
+
"text-red-500 dark:text-red-500", // text
|
|
141
|
+
"border border-red-200 dark:border-red-700", // border
|
|
142
|
+
"bg-transparent", // bg
|
|
143
|
+
"hover:bg-red-100 dark:hover:bg-red-950", // bg hover
|
|
144
|
+
"focus:ring-red-400 dark:focus:ring-red-400", // focus
|
|
145
|
+
),
|
|
146
|
+
} as const satisfies Record<ButtonVariant, string>
|
|
147
|
+
|
|
148
|
+
const sizeClasses = {
|
|
149
|
+
none: "",
|
|
150
|
+
minimal: "rounded-none",
|
|
151
|
+
sm: "px-3",
|
|
152
|
+
default: "py-2 px-3",
|
|
153
|
+
lg: "px-8 py-4 text-lg",
|
|
154
|
+
} as const satisfies Record<ButtonSize, string>
|
|
155
|
+
|
|
156
|
+
const defaultSize = buttonSize.default
|
|
157
|
+
|
|
158
|
+
export function buttonCva1(variant: ButtonVariant, ...customClasses: (string | boolean | undefined | null | 0)[]) {
|
|
159
|
+
return buttonCva2(variant, null, ...customClasses)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function buttonCva2(
|
|
163
|
+
variant: ButtonVariant,
|
|
164
|
+
size: ButtonSize | null = defaultSize,
|
|
165
|
+
...customClasses: (string | boolean | undefined | null | 0)[]
|
|
166
|
+
) {
|
|
167
|
+
const v = variant
|
|
168
|
+
const s = size ?? defaultSize
|
|
169
|
+
return classMerge(baseClasses, variantClasses[v], sizeClasses[s], combinedClasses(v, s), customClasses)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function combinedClasses(variant: ButtonVariant, size: ButtonSize) {
|
|
173
|
+
const variantGroup1 =
|
|
174
|
+
variant === buttonVariant.outline || variant === buttonVariant.filledYellow || variant === buttonVariant.outlineRed
|
|
175
|
+
if (variantGroup1 && size === buttonSize.lg) {
|
|
176
|
+
return "border-2"
|
|
177
|
+
}
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function buttonCvaIconOnly(
|
|
182
|
+
variant: ButtonVariant,
|
|
183
|
+
isLoading: boolean | undefined,
|
|
184
|
+
isDisabled: boolean | undefined,
|
|
185
|
+
...customClasses: (string | boolean | undefined | null | 0)[]
|
|
186
|
+
) {
|
|
187
|
+
const classes = buttonCva2(
|
|
188
|
+
variant,
|
|
189
|
+
buttonSize.none,
|
|
190
|
+
classesButtonClickAnimation,
|
|
191
|
+
"rounded-full p-2.5",
|
|
192
|
+
(isDisabled || isLoading) && classesButtonDisabled,
|
|
193
|
+
...customClasses,
|
|
194
|
+
)
|
|
195
|
+
return classes
|
|
196
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { classArr } from "~/utils/ui/classArr"
|
|
2
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
3
|
+
import { type ButtonVariant } from "./buttonCva"
|
|
4
|
+
|
|
5
|
+
const classesTextFillBlack = "text-black fill-black"
|
|
6
|
+
const classesTextFillWhite = "text-white fill-white"
|
|
7
|
+
|
|
8
|
+
const classesBlackWhite = classArr(
|
|
9
|
+
classesTextFillBlack,
|
|
10
|
+
"dark:text-white", // dark text
|
|
11
|
+
"dark:fill-white", // dark fill
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
const classesWhiteWhite = classArr(
|
|
15
|
+
classesTextFillWhite,
|
|
16
|
+
"dark:text-white", // dark text
|
|
17
|
+
"dark:fill-white", // dark fill
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const baseClasses = classArr(
|
|
21
|
+
"size-6", // size
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const buttonIconClasses = {
|
|
25
|
+
// transparent bg
|
|
26
|
+
outline: classesBlackWhite,
|
|
27
|
+
ghost: classesBlackWhite,
|
|
28
|
+
link: classesBlackWhite,
|
|
29
|
+
// filled grayscale
|
|
30
|
+
filled: classesBlackWhite,
|
|
31
|
+
subtle: classesBlackWhite,
|
|
32
|
+
contrast: classArr(classesTextFillWhite, "dark:text-black dark:fill-black"),
|
|
33
|
+
// filled colors
|
|
34
|
+
filledYellow: classArr(classesTextFillWhite, "dark:text-yellow-100 dark:fill-yellow-100"),
|
|
35
|
+
filledOrange: classArr(classesTextFillWhite, "dark:text-orange-100 dark:fill-orange-100"),
|
|
36
|
+
filledAmber: classArr(classesTextFillWhite, "dark:text-amber-100 dark:fill-amber-100"),
|
|
37
|
+
filledRed: classArr(classesTextFillWhite, "dark:text-red-100 dark:fill-red-100"),
|
|
38
|
+
|
|
39
|
+
filledGreen: classesWhiteWhite,
|
|
40
|
+
filledIndigo: classArr(classesTextFillWhite, "dark:text-indigo-100 dark:fill-indigo-100"),
|
|
41
|
+
// outlineRed: classesWhiteWhite,
|
|
42
|
+
filledSky: classesWhiteWhite,
|
|
43
|
+
// outlined colors
|
|
44
|
+
outlineRed: classArr("text-red-500 fill-red-500 dark:text-red-700 dark:fill-red-700"),
|
|
45
|
+
} as const satisfies Record<ButtonVariant, string>
|
|
46
|
+
|
|
47
|
+
export function buttonIconCva(
|
|
48
|
+
variant: ButtonVariant,
|
|
49
|
+
...customClasses: (string | boolean | undefined | null | 0 | 0n)[]
|
|
50
|
+
) {
|
|
51
|
+
return classMerge(baseClasses, buttonIconClasses[variant], customClasses)
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const classesButtonDisabled = "cursor-not-allowed opacity-70"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { classesCardWrapperP4 } from "~/card/classesCardWrapper"
|
|
3
|
+
import { classArr } from "~/utils/ui/classArr"
|
|
4
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
id?:string
|
|
8
|
+
class?: string
|
|
9
|
+
}
|
|
10
|
+
const p = Astro.props
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<div id={p.id} class={classMerge(classesCardWrapperP4, p.class)}>
|
|
14
|
+
<slot />
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { classArr } from "~/utils/ui/classArr"
|
|
2
|
+
|
|
3
|
+
export const classesCardWrapper = classArr(
|
|
4
|
+
"rounded-lg shadow-lg", // card shadows/padding
|
|
5
|
+
"bg-white dark:bg-gray-900", // bg
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
export const classesCardWrapperP4 = classArr(classesCardWrapper, "p-4 lg:p-8")
|
|
9
|
+
export const classesCardWrapperP8 = classArr(classesCardWrapper, "p-4 sm:p-8")
|
|
10
|
+
|
|
11
|
+
export const classesCardWrapperPage = classArr(
|
|
12
|
+
"rounded-xl shadow-xl", // rounded border + shadow
|
|
13
|
+
"p-4 sm:p-8 md:p-12", // padding
|
|
14
|
+
// "sm:mx-auto", // center
|
|
15
|
+
"bg-white dark:bg-gray-900", // bg
|
|
16
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Icon1 from "~/icon/Icon1.astro"
|
|
3
|
+
import { classArr } from "~/utils/ui/classArr"
|
|
4
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
5
|
+
import { mdiChevronDown } from "@mdi/js"
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
icon?: string
|
|
9
|
+
title?: string
|
|
10
|
+
subtitle?: string
|
|
11
|
+
class?: string
|
|
12
|
+
summaryClass?: string
|
|
13
|
+
}
|
|
14
|
+
const props = Astro.props
|
|
15
|
+
const icon = props.icon
|
|
16
|
+
const title = props.title
|
|
17
|
+
const subtitle = props.subtitle
|
|
18
|
+
const summaryClass = props.summaryClass
|
|
19
|
+
const hasSummary = Astro.slots.has("summary")
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<details
|
|
23
|
+
class={classMerge(
|
|
24
|
+
"group",
|
|
25
|
+
"bg-white dark:bg-gray-800",
|
|
26
|
+
"rounded-lg border border-gray-200",
|
|
27
|
+
"shadow-sm",
|
|
28
|
+
"overflow-hidden",
|
|
29
|
+
props.class,
|
|
30
|
+
)}
|
|
31
|
+
>
|
|
32
|
+
<summary
|
|
33
|
+
class={classArr(
|
|
34
|
+
"flex flex-col sm:flex-row items-center justify-between gap-4",
|
|
35
|
+
"p-6",
|
|
36
|
+
"cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors",
|
|
37
|
+
)}
|
|
38
|
+
>
|
|
39
|
+
{
|
|
40
|
+
!hasSummary && title && (
|
|
41
|
+
<>
|
|
42
|
+
{icon && <Icon1 path={icon} class="size-7 mt-1" />}
|
|
43
|
+
<div class="flex-1">
|
|
44
|
+
<h3 class={"text-xl font-semibold"}>{title}</h3>
|
|
45
|
+
{subtitle && <p class={"text-muted-foreground mt-1"}>{subtitle}</p>}
|
|
46
|
+
</div>
|
|
47
|
+
</>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
<slot name="summary" />
|
|
51
|
+
<Icon1
|
|
52
|
+
path={mdiChevronDown}
|
|
53
|
+
class={classArr("size-7", "text-gray-400 dark:text-gray-600", "transition-transform group-open:rotate-180")}
|
|
54
|
+
/>
|
|
55
|
+
</summary>
|
|
56
|
+
<slot />
|
|
57
|
+
</details>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
3
|
+
import { isDevEnv } from "~/utils/ui/isDevEnv"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
{
|
|
7
|
+
isDevEnv() && (
|
|
8
|
+
<div
|
|
9
|
+
id={"tailwindIndicator"}
|
|
10
|
+
class={classMerge(
|
|
11
|
+
"fixed bottom-1 left-1 z-50", // position
|
|
12
|
+
"flex size-6 items-center justify-center", // size
|
|
13
|
+
"rounded-full p-3", // size
|
|
14
|
+
"font-mono font-bold text-sm", // font
|
|
15
|
+
"bg-zinc-100 dark:bg-zinc-900", // bg
|
|
16
|
+
"select-none print:hidden",
|
|
17
|
+
)}
|
|
18
|
+
>
|
|
19
|
+
<div class="block sm:hidden">xs</div>
|
|
20
|
+
<div class="hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden 3xl:hidden">sm</div>
|
|
21
|
+
<div class="hidden md:block lg:hidden xl:hidden 2xl:hidden 3xl:hidden">md</div>
|
|
22
|
+
<div class="hidden lg:block xl:hidden 2xl:hidden 3xl:hidden">lg</div>
|
|
23
|
+
<div class="hidden xl:block 2xl:hidden 3xl:hidden">xl</div>
|
|
24
|
+
<div class="hidden 2xl:block 3xl:hidden">2xl</div>
|
|
25
|
+
<div class="hidden 3xl:block">3xl</div>
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { classesFieldset } from "./classesFieldset"
|
|
3
|
+
import { classMerge } from "~/utils/ui/classMerge"
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
title: string
|
|
7
|
+
titleClass?: string
|
|
8
|
+
subtitles?: string | string[]
|
|
9
|
+
subtitleClass?: string
|
|
10
|
+
class?: string
|
|
11
|
+
}
|
|
12
|
+
const props = Astro.props
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<fieldset class={classMerge(classesFieldset, props.class)}>
|
|
16
|
+
<legend class={classMerge("px-1", props.titleClass)}>
|
|
17
|
+
{props.title}
|
|
18
|
+
<!--{props.subtitles && <PopoverI title={props.title} points={props.subtitles} />}-->
|
|
19
|
+
</legend>
|
|
20
|
+
<slot />
|
|
21
|
+
</fieldset>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const classesFieldset = "rounded-lg border border-solid border-gray-300 dark:border-gray-700 p-3"
|