@adaptive-sm/astro-ui 0.1.1 → 0.2.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/README.md CHANGED
@@ -3,6 +3,7 @@
3
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
4
 
5
5
  Quick link
6
+
6
7
  - code - https://github.com/adaptive-shield-matrix/astro-ui
7
8
  - npm - https://www.npmjs.com/package/@adaptive-sm/astro-ui
8
9
  - component demo - https://adaptive-astro-ui.pages.dev/
@@ -27,20 +28,38 @@ This tells Tailwind to include classes from the library's `.astro`, `.ts`, and o
27
28
 
28
29
  ## Option configuration: import alias
29
30
 
31
+ ### Typescript
32
+
33
+ In your `tsconfig.json`, set up the `~` alias to point to the library:
34
+
35
+ ```json
36
+ {
37
+ "compilerOptions": {
38
+ "baseUrl": ".",
39
+ "paths": {
40
+ "@/*": ["src/*"],
41
+ "~/*": ["node_modules/@adaptive-sm/astro-ui/lib/*"]
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### Astro
48
+
30
49
  In your `astro.config.mjs`, set up the `~` alias to point to the library:
31
50
 
32
51
  ```js
33
- import { defineConfig } from 'astro/config';
52
+ import { defineConfig } from "astro/config"
34
53
 
35
54
  export default defineConfig({
36
55
  vite: {
37
56
  resolve: {
38
57
  alias: {
39
- '~': new URL('./node_modules/@adaptive-sm/astro-ui/lib', import.meta.url).pathname,
58
+ "~": new URL("./node_modules/@adaptive-sm/astro-ui/lib", import.meta.url).pathname,
40
59
  },
41
60
  },
42
61
  },
43
- });
62
+ })
44
63
  ```
45
64
 
46
65
  ## Usage
@@ -62,7 +81,7 @@ Import and use components directly in your Astro files. For example:
62
81
 
63
82
  ```astro
64
83
  ---
65
- import { Button } from '~/button/Button.astro';
84
+ import { Button } from "~/button/Button.astro"
66
85
  ---
67
86
 
68
87
  <Button variant="primary">Click me</Button>
@@ -72,19 +91,17 @@ import { Button } from '~/button/Button.astro';
72
91
 
73
92
  ```astro
74
93
  ---
75
- import { CardWrapper } from '~/card/CardWrapper.astro';
94
+ import { CardWrapper } from "~/card/CardWrapper.astro"
76
95
  ---
77
96
 
78
- <CardWrapper>
79
- Card content here.
80
- </CardWrapper>
97
+ <CardWrapper> Card content here. </CardWrapper>
81
98
  ```
82
99
 
83
100
  ### Image Component
84
101
 
85
102
  ```astro
86
103
  ---
87
- import { Img } from '~/img/Img.astro';
104
+ import { Img } from "~/img/Img.astro"
88
105
  ---
89
106
 
90
107
  <Img src="/path/to/image.jpg" alt="Description" />
@@ -95,19 +112,24 @@ Refer to individual component documentation in the source code for props and var
95
112
  ## Components
96
113
 
97
114
  ### Buttons
115
+
98
116
  - [Button.astro](lib/button/Button.astro)
99
117
  - Button variants and animations via CVAs in `buttonCva.ts`, `buttonIconCva.ts`
100
118
 
101
119
  ### Cards
120
+
102
121
  - [CardWrapper.astro](lib/card/CardWrapper.astro)
103
122
 
104
123
  ### Details
124
+
105
125
  - [Details.astro](lib/details/Details.astro)
106
126
 
107
127
  ### Forms
128
+
108
129
  - [Fieldset.astro](lib/form/Fieldset.astro)
109
130
 
110
131
  ### Icons
132
+
111
133
  - [Icon1.astro](lib/icon/Icon1.astro) (replaces SVG icons)
112
134
 
113
135
  usage:
@@ -117,6 +139,7 @@ usage:
117
139
  - Passed on as `path` prop
118
140
 
119
141
  ### Images
142
+
120
143
  - [Img.astro](lib/img/Img.astro)
121
144
 
122
145
  A small wrapper setting loading lazy and decoding to async.
@@ -128,35 +151,44 @@ usage:
128
151
  Generate types using `lib/generate_image_list/generateImageList.ts`
129
152
 
130
153
  ### Layouts
154
+
131
155
  - [MinimalLayout.astro](lib/layouts/MinimalLayout.astro)
132
156
  - [MarkdownWrapper.astro](lib/layouts/MarkdownWrapper.astro)
133
157
 
134
158
  ### Navigation bar
159
+
135
160
  - [ThemeToggle.astro](lib/layouts/parts/ThemeToggle.astro)
136
161
 
137
162
  ### Links
163
+
138
164
  - [LinkText.astro](lib/link/LinkText.astro)
139
165
  - [LinkButton.astro](lib/link/LinkButton.astro)
140
166
 
141
167
  ### Lists
168
+
142
169
  - [BlackBulletPoints.astro](lib/list/BlackBulletPoints.astro)
143
170
  - [CheckPoints.astro](lib/list/CheckPoints.astro)
144
171
  - [NumberedList.astro](lib/list/NumberedList.astro)
145
172
 
146
173
  ### Modals
174
+
147
175
  - [ModalButton.astro](lib/modal/ModalButton.astro)
148
176
 
149
177
  ### Pages
178
+
150
179
  - [PageCentered.astro](lib/page/PageCentered.astro)
151
180
  - [PageCenteredCard.astro](lib/page/PageCenteredCard.astro)
152
181
 
153
182
  ### Popovers
183
+
154
184
  - [Popover1.astro](lib/popover/Popover1.astro)
155
185
 
156
186
  ### Selects
187
+
157
188
  - [Select.astro](lib/select/Select.astro)
158
189
 
159
190
  ### Table
191
+
160
192
  - [Table.astro](lib/table/Table.astro)
161
193
 
162
194
  ## Demos
@@ -201,3 +233,11 @@ Follow the coding rules in `.roo/rules-code/` for style and best practices.
201
233
  ## License
202
234
 
203
235
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
236
+
237
+ ## Acknowledgments
238
+
239
+ - Built on top of [Astro](https://astro.build).
240
+ - Styled with [Tailwind CSS](https://tailwindcss.com/).
241
+ - Icons from [MDI](https://pictogrammers.com/library/mdi/).
242
+
243
+ For more information, visit the [GitHub repository](https://github.com/adaptive-shield-matrix/astro-ui).
@@ -94,19 +94,19 @@ const variantClasses = {
94
94
  // filled colors
95
95
  //
96
96
  filledYellow: classArr(
97
- "text-white dark:text-yellow-100 ", // text
97
+ "text-white", // text
98
98
  "bg-yellow-500 dark:bg-yellow-800 ", // bg
99
99
  "hover:bg-yellow-700 dark:hover:bg-yellow-600", // bg hover
100
100
  "focus:ring-yellow-400 dark:focus:ring-yellow-400", // focus
101
101
  ),
102
102
  filledAmber: classArr(
103
- "text-white dark:text-amber-100 ", // text
103
+ "text-white", // text
104
104
  "bg-amber-500 dark:bg-amber-800 ", // bg
105
105
  "hover:bg-amber-700 dark:hover:bg-amber-600", // bg hover
106
106
  "focus:ring-amber-400 dark:focus:ring-amber-400", // focus
107
107
  ),
108
108
  filledOrange: classArr(
109
- "text-white dark:text-orange-100 ", // text
109
+ "text-white", // text
110
110
  "bg-orange-500 dark:bg-orange-800 ", // bg
111
111
  "hover:bg-orange-700 dark:hover:bg-orange-600", // bg hover
112
112
  "focus:ring-orange-400 dark:focus:ring-orange-400", // focus
@@ -128,7 +128,7 @@ const variantClasses = {
128
128
  "focus:ring-sky-400 dark:focus:ring-sky-400", // focus
129
129
  ),
130
130
  filledIndigo: classArr(
131
- "text-white dark:text-indigo-100 ", // text
131
+ "text-white", // text
132
132
  "bg-indigo-500 dark:bg-indigo-800 ", // bg
133
133
  "hover:bg-indigo-700 dark:hover:bg-indigo-600", // bg hover
134
134
  "focus:ring-indigo-400 dark:focus:ring-indigo-400", // focus
@@ -11,11 +11,10 @@ interface Props {
11
11
  class?: string
12
12
  summaryClass?: string
13
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
14
+ const p = Astro.props
15
+ const icon = p.icon
16
+ const title = p.title
17
+ const subtitle = p.subtitle
19
18
  const hasSummary = Astro.slots.has("summary")
20
19
  ---
21
20
 
@@ -26,14 +25,15 @@ const hasSummary = Astro.slots.has("summary")
26
25
  "rounded-lg border border-gray-200",
27
26
  "shadow-sm",
28
27
  "overflow-hidden",
29
- props.class,
28
+ p.class,
30
29
  )}
31
30
  >
32
31
  <summary
33
32
  class={classArr(
34
33
  "flex flex-col sm:flex-row items-center justify-between gap-4",
35
- "p-6",
34
+ "p-4 sm:p-6",
36
35
  "cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors",
36
+ p.summaryClass,
37
37
  )}
38
38
  >
39
39
  {
@@ -2,18 +2,20 @@
2
2
  import { classesTextLink } from "~/link/classesTextLink"
3
3
  import { classArr } from "~/utils/ui/classArr"
4
4
  import { type DemoListType } from "./DemoListType"
5
+ import { classMerge } from "~/utils/ui/classMerge"
5
6
 
6
7
  interface Props {
7
8
  demos: DemoListType
9
+ urlPrefix?: string
8
10
  class?: string
9
11
  }
10
- const props = Astro.props
12
+ const p = Astro.props
11
13
 
12
14
  // Extract categories and their demo pages
13
- const categories = Object.entries(props.demos)
15
+ const categories = Object.entries(p.demos)
14
16
  ---
15
17
 
16
- <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
18
+ <div class={classMerge("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mt-4", p.class)}>
17
19
  {
18
20
  categories.map(([category, pages]) => (
19
21
  <section class="bg-white dark:bg-zinc-700 rounded-lg shadow-md p-4 border border-gray-200 dark:border-zinc-600">
@@ -21,7 +23,7 @@ const categories = Object.entries(props.demos)
21
23
  <ul class="list-disc pl-4 space-y-1">
22
24
  {pages.map((page) => (
23
25
  <li class={classArr(classesTextLink)}>
24
- <a href={`/demos/${category}/${page}`}>{page.replace(/_/g, " ").replaceAll("demo ", "")}</a>
26
+ <a href={`${p.urlPrefix ?? ""}/${category}/${page}`}>{page.replace(/_/g, " ").replaceAll("demo ", "")}</a>
25
27
  </li>
26
28
  ))}
27
29
  </ul>
@@ -6,6 +6,28 @@ import { runCmdAsync } from "~/utils/bun/runCmdAsync"
6
6
 
7
7
  const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".avif", ".tiff", ".svg"])
8
8
 
9
+ function getMimeType(ext: string): string {
10
+ switch (ext) {
11
+ case ".jpg":
12
+ case ".jpeg":
13
+ return "image/jpeg"
14
+ case ".png":
15
+ return "image/png"
16
+ case ".gif":
17
+ return "image/gif"
18
+ case ".webp":
19
+ return "image/webp"
20
+ case ".avif":
21
+ return "image/avif"
22
+ case ".tiff":
23
+ return "image/tiff"
24
+ case ".svg":
25
+ return "image/svg+xml"
26
+ default:
27
+ return "application/octet-stream"
28
+ }
29
+ }
30
+
9
31
  export async function generateImageList(
10
32
  imageDirectory: string,
11
33
  existingImages: Record<string, ImageType>,
@@ -55,12 +77,14 @@ async function processImageFiles(
55
77
 
56
78
  const prevAlt = existingImages[key]?.alt
57
79
  const alt = prevAlt || fileName.replace(/[-_]/g, " ")
80
+ const mimeType = getMimeType(ext)
58
81
 
59
82
  imageMap[key] = {
60
83
  path: relativePath,
61
84
  width: dimensions.width,
62
85
  height: dimensions.height,
63
86
  alt,
87
+ mimeType,
64
88
  }
65
89
  } catch (error) {
66
90
  console.error(`Error processing ${filePath}:`, error)
@@ -0,0 +1,80 @@
1
+ ---
2
+ import Icon1 from "~/icon/Icon1.astro"
3
+ import { classArr } from "~/utils/ui/classArr"
4
+ import { mdiLink } from "@mdi/js"
5
+ import type { GridFeatureType } from "./GridFeatureType"
6
+ import { classMerge } from "~/utils/ui/classMerge"
7
+
8
+ interface Props {
9
+ id: string
10
+ title: string
11
+ subtitle1: string
12
+ subtitle2?: string
13
+ features: GridFeatureType[]
14
+ class?: string
15
+ gridClass?: string
16
+ cardClass?: string
17
+ }
18
+ const p = Astro.props
19
+ ---
20
+
21
+ <section id={p.id} class={classMerge("w-full", "py-25 px-4", p.class)}>
22
+ <div class={classArr("max-w-7xl mx-auto", "text-center mb-8")}>
23
+ <h2 class={classArr("text-3xl sm:text-4xl font-bold", "mb-4", "group flex items-center justify-center")}>
24
+ <span>{p.title}</span>
25
+ <button
26
+ onclick={`copyLink('${p.id}')`}
27
+ class="opacity-0 group-hover:opacity-100 ml-2 p-1 rounded hidden sm:flex"
28
+ title="Copy link to this section"
29
+ >
30
+ <Icon1 path={mdiLink} class="size-4" />
31
+ </button>
32
+ </h2>
33
+ <p class="text-xl text-muted-foreground mx-auto">
34
+ {p.subtitle1}
35
+ </p>
36
+ {p.subtitle2 && <p class="text-xl text-muted-foreground mx-auto mt-1">{p.subtitle2}</p>}
37
+ </div>
38
+
39
+ <div class={classMerge("grid md:grid-cols-2 lg:grid-cols-3 gap-8", "max-w-7xl mx-auto", p.gridClass)}>
40
+ {
41
+ p.features.map((feature, index) => (
42
+ <div
43
+ class={classMerge(
44
+ "bg-white dark:bg-gray-800", // bg
45
+ "rounded-lg p-6", // padding
46
+ // "border", // border
47
+ "shadow-sm hover:shadow-lg transition-shadow", // shadow
48
+ p.cardClass,
49
+ )}
50
+ >
51
+ <div class="flex items-center gap-3 mb-4">
52
+ <Icon1 path={feature.icon} class="size-8" />
53
+ <h3 class="text-xl font-semibold">{feature.title}</h3>
54
+ </div>
55
+ <p class="text-muted-foreground">{feature.description}</p>
56
+ </div>
57
+ ))
58
+ }
59
+ </div>
60
+ </section>
61
+
62
+ <script>
63
+ declare global {
64
+ interface Window {
65
+ copyLink?: (id: string) => void
66
+ }
67
+ }
68
+ window.copyLink = function (id: string) {
69
+ const url = window.location.href.split("#")[0] + "#" + id
70
+ navigator.clipboard
71
+ .writeText(url)
72
+ .then(() => {
73
+ // Optional: show a toast or feedback
74
+ console.log("Link copied:", url)
75
+ })
76
+ .catch((err) => {
77
+ console.error("Failed to copy link:", err)
78
+ })
79
+ }
80
+ </script>
@@ -0,0 +1,5 @@
1
+ export type GridFeatureType = {
2
+ icon: string
3
+ title: string
4
+ description: string
5
+ }
@@ -15,7 +15,7 @@ const ariaHidden = props.ariaHidden ?? !props.title
15
15
  <svg
16
16
  viewBox={"0 0 24 24"}
17
17
  aria-hidden={ariaHidden}
18
- class={classMerge("size-6 align-middle dark:fill-white", props.class)}
18
+ class={classMerge("size-6 flex-shrink-0 align-middle dark:fill-white", props.class)}
19
19
  >
20
20
  <path d={props.path}></path>
21
21
  </svg>
@@ -3,4 +3,5 @@ export type ImageType = {
3
3
  height: number
4
4
  width: number
5
5
  alt: string
6
+ mimeType?: string
6
7
  }
package/lib/img/Img.astro CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- import { classesImgZoomInOnHover } from "./classesImgZoomInOnHover"
2
+ import { classesImgZoomInOnHover10 } from "./classesImgZoomInOnHover10"
3
3
  import { classMerge } from "~/utils/ui/classMerge"
4
4
 
5
5
  interface Props {
@@ -19,7 +19,7 @@ const p = Astro.props
19
19
  <img
20
20
  src={p.src}
21
21
  alt={p.alt}
22
- class={classMerge(p.zoomIn && classesImgZoomInOnHover, p.class)}
22
+ class={classMerge(p.zoomIn && classesImgZoomInOnHover10, p.class)}
23
23
  loading={p.loadingLazy ?? true ? "lazy" : undefined}
24
24
  decoding={p.decodeAsync ?? true ? "async" : undefined}
25
25
  width={p.size ?? p.width}
@@ -2,15 +2,18 @@
2
2
  import { classArr } from "~/utils/ui/classArr"
3
3
  import type { ImageType } from "./ImageType"
4
4
  import Img from "./Img.astro"
5
- import { classInvertDiagram } from "~/img/classInvertDiagram"
5
+ import { classInvertBlack } from "~/img/classInvertBlack"
6
6
 
7
7
  interface Props {
8
8
  img: ImageType
9
9
  zoomIn?: boolean
10
+ invertColorsInDarkMode?: boolean
10
11
  class?: string
11
12
  }
12
- const props = Astro.props
13
- const isSvg = props.img.path.endsWith(".svg")
13
+ const p = Astro.props
14
+ const isSvg = p.img.path.endsWith(".svg")
15
+ // const invert = isSvg && p.invertColorsInDarkMode
16
+ const invert = p.invertColorsInDarkMode
14
17
 
15
18
  function imageUrl(p: string) {
16
19
  return "/media-b2/" + p
@@ -18,9 +21,9 @@ function imageUrl(p: string) {
18
21
  ---
19
22
 
20
23
  <Img
21
- src={imageUrl(props.img.path)}
22
- alt={props.img.alt}
23
- class={classArr(isSvg ? classInvertDiagram : "", props.class)}
24
- width={isSvg ? null : props.img.width}
25
- height={isSvg ? null : props.img.height}
24
+ src={imageUrl(p.img.path)}
25
+ alt={p.img.alt}
26
+ class={classArr(invert ? classInvertBlack : "", p.class)}
27
+ width={isSvg ? null : p.img.width}
28
+ height={isSvg ? null : p.img.height}
26
29
  />
@@ -0,0 +1 @@
1
+ export const classInvertBlack = "invert-black"
@@ -0,0 +1 @@
1
+ export const classesImgZoomInOnHover10 = "transform transition-transform duration-200 hover:scale-110"
@@ -0,0 +1 @@
1
+ export const classesImgZoomInOnHover5 = "transform transition-transform duration-200 hover:scale-105"
@@ -29,7 +29,7 @@ interface Props {
29
29
  const p = Astro.props
30
30
  const title = p.title ?? "Toggle theme"
31
31
  const textLight = p.textLight ?? "Light"
32
- const textDark = p.textLight ?? "Dark"
32
+ const textDark = p.textDark ?? "Dark"
33
33
  ---
34
34
 
35
35
  <Button
@@ -1,6 +1,6 @@
1
- export type ClassesBg = keyof typeof classesBg
1
+ export type ClassesBg = keyof typeof classesBg100
2
2
 
3
- export const classesBg = {
3
+ export const classesBg100 = {
4
4
  white: "bg-white dark:bg-black",
5
5
  orange: "bg-orange-100 dark:bg-yellow-900",
6
6
  red: "bg-red-100 dark:bg-red-900",
@@ -0,0 +1,27 @@
1
+ export type ClassesBg = keyof typeof classesBg50
2
+
3
+ export const classesBg50 = {
4
+ white: "bg-white dark:bg-black",
5
+ orange: "bg-orange-50 dark:bg-yellow-950",
6
+ red: "bg-red-50 dark:bg-red-950",
7
+ amber: "bg-amber-50 dark:bg-amber-950",
8
+ yellow: "bg-yellow-50 dark:bg-yellow-950",
9
+ lime: "bg-lime-50 dark:bg-lime-950",
10
+ green: "bg-green-50 dark:bg-green-950",
11
+ emerald: "bg-emerald-50 dark:bg-emerald-950",
12
+ teal: "bg-teal-50 dark:bg-teal-950",
13
+ cyan: "bg-cyan-50 dark:bg-cyan-950",
14
+ sky: "bg-sky-50 dark:bg-sky-950",
15
+ blue: "bg-blue-50 dark:bg-blue-950",
16
+ indigo: "bg-indigo-50 dark:bg-indigo-950",
17
+ violet: "bg-violet-50 dark:bg-violet-950",
18
+ purple: "bg-purple-50 dark:bg-purple-950",
19
+ fuchsia: "bg-fuchsia-50 dark:bg-fuchsia-950",
20
+ pink: "bg-pink-50 dark:bg-pink-950",
21
+ rose: "bg-rose-50 dark:bg-rose-950",
22
+ slate: "bg-slate-50 dark:bg-slate-950",
23
+ gray: "bg-gray-50 dark:bg-gray-950",
24
+ zinc: "bg-zinc-50 dark:bg-zinc-950",
25
+ neutral: "bg-neutral-50 dark:bg-neutral-950",
26
+ stone: "bg-stone-50 dark:bg-stone-950",
27
+ } as const
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptive-sm/astro-ui",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "scripts": {
5
5
  "astro": "astro",
6
6
  "dev": "nice -5 astro dev",
@@ -9,11 +9,12 @@
9
9
  "deploy": "bun run build && bun run upload && bun run tag",
10
10
  "upload": "bun run wrangler pages deploy ./dist --project-name=adaptive-astro-ui --commit-dirty",
11
11
  "tag": "git branch -f deployed",
12
- "generateDemoList": "bun run ./src/pages/demos/generateDemoList.cli.ts",
12
+ "release": "bash ./ops/release.sh",
13
+ "generateDemoList": "bun run ./lib/generate_demo_list/generateDemoList.ts",
13
14
  "generateImageList": "bun run ./src/pages/images/generateImageList.cli.ts",
14
15
  "generateAiRulesLib": "bash ./lib/generate_ai_rules/generate_agent_rules_1_lib.bash",
15
16
  "update": "nice -15 bun x npm-check-updates -u && bun i",
16
- "update:commit": "bun x npm-check-updates -u && bun i && git add package.json && bun run tsc && git commit -m \"update dependencies\" && git push",
17
+ "update:commit": "bun x npm-check-updates -u && bun i && git add package.json && bun run tsc && git commit -m \"chore(deps): update dependencies\" && git push",
17
18
  "clean": "rm -rf ./dist",
18
19
  "reset": "rm -rf ./node_modules"
19
20
  },
@@ -66,5 +67,8 @@
66
67
  "web-development",
67
68
  "frontend",
68
69
  "typescript"
69
- ]
70
+ ],
71
+ "repository": {
72
+ "url": "git+https://github.com/adaptive-shield-matrix/astro-ui.git"
73
+ }
70
74
  }
@@ -1 +0,0 @@
1
- export const classInvertDiagram = "invert-diagram"
@@ -1 +0,0 @@
1
- export const classesImgZoomInOnHover = "transform transition-transform duration-200 -translate-x-3 hover:scale-110"