@adaptive-sm/astro-ui 0.1.1 → 0.3.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.
Files changed (101) hide show
  1. package/README.md +52 -12
  2. package/lib/badge/Badge.astro +27 -0
  3. package/lib/badge/classesBadge.ts +67 -0
  4. package/lib/button/Button.astro +17 -27
  5. package/lib/button/buttonCva.ts +6 -6
  6. package/lib/button/buttonIconCva.ts +2 -2
  7. package/lib/button/classesButtonClickAnimation.ts +1 -1
  8. package/lib/button/classesButtonClickAnimationPush.ts +1 -1
  9. package/lib/button/classesButtonClickAnimationSquish.ts +1 -1
  10. package/lib/card/CardWrapper.astro +6 -5
  11. package/lib/card/classesBorderWrapper.ts +1 -0
  12. package/lib/card/classesCardWrapper.ts +21 -9
  13. package/lib/card/classesShadow.ts +5 -0
  14. package/lib/details/Details.astro +20 -15
  15. package/lib/dev/TailwindIndicator.astro +2 -2
  16. package/lib/form/Fieldset.astro +8 -5
  17. package/lib/generate_demo_list/DemoList.astro +8 -6
  18. package/lib/generate_demo_list/generateDemoList.ts +2 -2
  19. package/lib/generate_image_list/generateImageList.ts +27 -3
  20. package/lib/grid/FeatureGridSection.astro +73 -0
  21. package/lib/grid/GridFeatureType.ts +5 -0
  22. package/lib/grid/classesGridCols.ts +27 -2
  23. package/lib/header/PageHeader.astro +25 -0
  24. package/lib/header/SectionHeader.astro +37 -0
  25. package/lib/icon/Icon.astro +26 -0
  26. package/lib/icons/iconGithub.ts +4 -0
  27. package/lib/icons/iconGoogle.ts +4 -0
  28. package/lib/icons/iconLinkedin.ts +2 -0
  29. package/lib/icons/iconNpm.ts +2 -0
  30. package/lib/icons/iconTelegram.ts +2 -0
  31. package/lib/icons/iconTrello.ts +2 -0
  32. package/lib/icons/iconXcom.ts +1 -0
  33. package/lib/img/ImageType.ts +1 -0
  34. package/lib/img/Img.astro +10 -7
  35. package/lib/img/TypedImg.astro +15 -13
  36. package/lib/img/TypedImgB2.astro +23 -0
  37. package/lib/img/classInvertBlack.ts +1 -0
  38. package/lib/img/classesImgZoomInOnHover10.ts +1 -0
  39. package/lib/img/classesImgZoomInOnHover5.ts +1 -0
  40. package/lib/layouts/MarkdownPageWrapper.astro +19 -0
  41. package/lib/layouts/MinimalLayout.astro +23 -16
  42. package/lib/layouts/parts/ThemeToggle.astro +10 -10
  43. package/lib/link/LinkButton.astro +18 -19
  44. package/lib/link/LinkText.astro +10 -7
  45. package/lib/link/classesTextLink.ts +1 -1
  46. package/lib/list/BlackBulletPoint.astro +1 -1
  47. package/lib/list/BlackBulletPoints.astro +7 -7
  48. package/lib/list/CheckPoint.astro +3 -3
  49. package/lib/list/CheckPoints.astro +3 -3
  50. package/lib/list/NumberedList.astro +1 -1
  51. package/lib/list/Ps.astro +8 -5
  52. package/lib/list/TextOrLink.astro +3 -9
  53. package/lib/md/MarkdownDiv.astro +18 -0
  54. package/lib/modal/Modal.astro +4 -4
  55. package/lib/modal/ModalButton.astro +24 -11
  56. package/lib/page/PageCentered.astro +5 -3
  57. package/lib/page/PageCenteredCard.astro +7 -5
  58. package/lib/page/{classesBg.ts → classesBg100.ts} +2 -2
  59. package/lib/page/classesBg50.ts +27 -0
  60. package/lib/page/classesPageCentered.ts +1 -1
  61. package/lib/popover/Popover1.astro +4 -4
  62. package/lib/select/Select.astro +14 -10
  63. package/lib/table/Table.astro +2 -2
  64. package/lib/table/TableD.astro +2 -2
  65. package/lib/table/TableM.astro +2 -2
  66. package/lib/table/TableMEntry.astro +2 -2
  67. package/lib/table/tableVisibilityClasses.ts +3 -3
  68. package/lib/utils/HasId.ts +3 -0
  69. package/lib/utils/HasSubtitle.ts +4 -0
  70. package/lib/utils/HasTitle.ts +4 -0
  71. package/lib/utils/MayHaveButtonVariant.ts +5 -0
  72. package/lib/utils/MayHaveClass.ts +3 -0
  73. package/lib/utils/MayHaveIcon.ts +4 -0
  74. package/lib/utils/MayHaveId.ts +3 -0
  75. package/lib/utils/MayHaveInnerClass.ts +3 -0
  76. package/lib/utils/MayHaveSubtitle.ts +4 -0
  77. package/lib/utils/MayHaveTitle.ts +4 -0
  78. package/package.json +19 -14
  79. package/lib/icon/Icon1.astro +0 -21
  80. package/lib/img/classInvertDiagram.ts +0 -1
  81. package/lib/img/classesImgZoomInOnHover.ts +0 -1
  82. package/lib/layouts/MarkdownWrapper.astro +0 -17
  83. package/lib/utils/bun/BunCmd.ts +0 -7
  84. package/lib/utils/bun/cryAndTryAgainLater.ts +0 -6
  85. package/lib/utils/bun/logBunCmd.ts +0 -1
  86. package/lib/utils/bun/runCmdAsync.ts +0 -44
  87. package/lib/utils/bun/runCmdLocally.ts +0 -13
  88. package/lib/utils/obj/objectKeys.ts +0 -21
  89. package/lib/utils/ran/generateId12.ts +0 -7
  90. package/lib/utils/ran/generateId3.ts +0 -7
  91. package/lib/utils/ran/generateId4.ts +0 -7
  92. package/lib/utils/ran/generateId5.ts +0 -7
  93. package/lib/utils/ran/generateId6.ts +0 -7
  94. package/lib/utils/ran/generateId7.ts +0 -7
  95. package/lib/utils/ran/generateReadableId.ts +0 -35
  96. package/lib/utils/ran/urlAlphabet32.ts +0 -8
  97. /package/lib/{layouts/parts → md}/markdown.css +0 -0
  98. /package/lib/utils/{ui/classArr.ts → classArr.ts} +0 -0
  99. /package/lib/utils/{ui/classMerge.ts → classMerge.ts} +0 -0
  100. /package/lib/utils/{ui/isDevEnv.ts → isDevEnv.ts} +0 -0
  101. /package/lib/utils/{ui/tailwindBreakpoint.ts → tailwindBreakpoint.ts} +0 -0
@@ -1,11 +1,33 @@
1
1
  import imageSize from "image-size"
2
2
  import { promises as fs } from "node:fs"
3
3
  import path from "node:path"
4
- import type { ImageType } from "~/img/ImageType"
5
- import { runCmdAsync } from "~/utils/bun/runCmdAsync"
4
+ import type { ImageType } from "~ui/img/ImageType"
5
+ 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>,
@@ -20,7 +42,7 @@ export async function generateImageList(
20
42
 
21
43
  async function writeGeneratedImagesFile(imageMap: Record<string, ImageType>, outputPath: string): Promise<void> {
22
44
  const outputContent = `
23
- import type { ImageType } from "~/img/ImageType"
45
+ import type { ImageType } from "~ui/img/ImageType"
24
46
  // Auto-generated, manual changes will be lost
25
47
  export const imageList = ${JSON.stringify(imageMap, null, 2)} as const satisfies Record<string, ImageType>;
26
48
  `
@@ -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,73 @@
1
+ ---
2
+ import Icon from "~ui/icon/Icon.astro"
3
+ import { classArr } from "~ui/utils/classArr"
4
+ import { mdiLink } from "@mdi/js"
5
+ import type { GridFeatureType } from "./GridFeatureType"
6
+ import { classMerge } from "~ui/utils/classMerge"
7
+ import type { HTMLAttributes } from "astro/types"
8
+ import type { CssProperties } from "node_modules/astro/dist/assets/fonts/definitions"
9
+ import { classesShadowMdLg } from "~ui/card/classesShadow"
10
+
11
+ interface Props {
12
+ id: string
13
+ title: string
14
+ titleClass?: string
15
+ subtitle1: string
16
+ subtitle1Class?: string
17
+ subtitle2?: string
18
+ subtitle2Class?: string
19
+ features: GridFeatureType[]
20
+ class?: string
21
+ headerClass?: string
22
+ gridClass?: string
23
+ cardClass?: string
24
+ restProps?: HTMLAttributes<"section">
25
+ style?: CssProperties
26
+ }
27
+ const p = Astro.props
28
+ ---
29
+
30
+ <section id={p.id} class={classMerge("w-full", "py-25 px-4", p.class)} style={p.style} {...p.restProps}>
31
+ <div class={classArr("max-w-7xl mx-auto", "text-center mb-8", p.headerClass)}>
32
+ <h2 class={classArr("text-3xl sm:text-4xl font-bold", "mb-4", "group flex items-center justify-center")}>
33
+ <span>{p.title}</span>
34
+ <a
35
+ href={"#" + p.id}
36
+ class="opacity-0 group-hover:opacity-100 p-1 rounded hidden sm:flex"
37
+ title="Link to this section"
38
+ >
39
+ <Icon path={mdiLink} class="size-6 fill-gray-500 dark:fill-gray-500" />
40
+ </a>
41
+ </h2>
42
+ <p class={classMerge("text-xl text-muted-foreground mx-auto", p.subtitle1Class)}>
43
+ {p.subtitle1}
44
+ </p>
45
+ {
46
+ p.subtitle2 && (
47
+ <p class={classMerge("text-xl text-muted-foreground mx-auto mt-1", p.subtitle2Class)}>{p.subtitle2}</p>
48
+ )
49
+ }
50
+ </div>
51
+
52
+ <div class={classMerge("grid md:grid-cols-2 lg:grid-cols-3 gap-8", "max-w-7xl mx-auto", p.gridClass)}>
53
+ {
54
+ p.features.map((feature, index) => (
55
+ <div
56
+ class={classMerge(
57
+ "bg-white dark:bg-gray-800", // bg
58
+ "rounded-lg p-6", // padding
59
+ // "border", // border
60
+ classesShadowMdLg,
61
+ p.cardClass,
62
+ )}
63
+ >
64
+ <div class="flex items-center gap-3 mb-4">
65
+ <Icon path={feature.icon} class="size-8" />
66
+ <h3 class="text-xl font-semibold">{feature.title}</h3>
67
+ </div>
68
+ <p class="text-muted-foreground">{feature.description}</p>
69
+ </div>
70
+ ))
71
+ }
72
+ </div>
73
+ </section>
@@ -0,0 +1,5 @@
1
+ export type GridFeatureType = {
2
+ icon: string
3
+ title: string
4
+ description: string
5
+ }
@@ -1,14 +1,33 @@
1
- import { classArr } from "~/utils/ui/classArr"
1
+ import { classArr } from "~ui/utils/classArr"
2
2
 
3
3
  export const classesGridCols2ContentFr = "grid grid-cols-[max-content_1fr]"
4
4
  export const classesGridCols3MaxMinFr = "grid grid-cols-[max-content_min-content_1fr]"
5
5
 
6
+ export const classesGridCols2sm = classArr("grid grid-cols-1", "sm:grid-cols-2")
7
+
8
+ export const classesGridCols2md = classArr("grid grid-cols-1", "md:grid-cols-2")
9
+
10
+ /**
11
+ * 1280/2 = 640 px = 35.5 rem / col
12
+ */
13
+ export const classesGridCols2lg = classArr("grid grid-cols-1", "lg:grid-cols-2")
14
+
6
15
  /**
7
16
  * ~600 px (37rem, ~60ch) / col
8
17
  */
9
18
  export const classesGridCols2xl = classArr("grid grid-cols-1", "xl:grid-cols-2")
10
19
  export const classesGridCols2xl3 = classArr(classesGridCols2xl, "2xl:grid-cols-4", "3xl:grid-cols-6")
11
20
 
21
+ /**
22
+ * 1024/3 = 341 px = 19rem / col
23
+ * xl: 1280/340 = 3.75
24
+ * lg: 1024/340 = 3
25
+ * md: 768/340 = 2.26
26
+ * sm: 640/340 = 1.8
27
+ * xs: 400/340 = 1.17
28
+ */
29
+ export const classesGridCols3lg = classArr("grid grid-cols-1", "md:grid-cols-2", "lg:grid-cols-3")
30
+
12
31
  /**
13
32
  * ~400 px (25rem, ~40ch) / col
14
33
  */
@@ -36,7 +55,13 @@ export const classesGridCols4xl3 = classArr(classesGridCols4xl, "2xl:grid-cols-8
36
55
  * sm: 640/256 = 2.5
37
56
  * xs: 400/256 = 1.56
38
57
  */
39
- export const classesGridCols5xl = classArr("grid grid-cols-1", "sm:grid-cols-2", "md:grid-cols-3", "lg:grid-cols-4", "xl:grid-cols-5")
58
+ export const classesGridCols5xl = classArr(
59
+ "grid grid-cols-1",
60
+ "sm:grid-cols-2",
61
+ "md:grid-cols-3",
62
+ "lg:grid-cols-4",
63
+ "xl:grid-cols-5",
64
+ )
40
65
  export const classesGridCols5xl3 = classArr(classesGridCols5xl, "2xl:grid-cols-10", "3xl:grid-cols-15")
41
66
 
42
67
  /**
@@ -0,0 +1,25 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { classMerge } from "~ui/utils/classMerge"
4
+
5
+ interface Props {
6
+ title: string
7
+ subtitle?: string
8
+ titleClass?: string
9
+ subtitleClass?: string
10
+ innerClass?: string
11
+ class?: string
12
+ restProps?: HTMLAttributes<"header">
13
+ }
14
+
15
+ const p = Astro.props
16
+ ---
17
+
18
+ <header class={p.class}>
19
+ <div class={classMerge("flex flex-wrap justify-between items-center gap-4", p.innerClass)} {...p.restProps}>
20
+ <h1 class={classMerge("text-2xl font-semibold", p.titleClass)}>{p.title}</h1>
21
+ <slot />
22
+ </div>
23
+ {p.subtitle && <p class={classMerge("text-lg", p.subtitleClass)}>{p.subtitle}</p>}
24
+ <slot name="subtitle" />
25
+ </header>
@@ -0,0 +1,37 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { buttonVariant } from "~ui/button/buttonCva"
4
+ import LinkButton from "~ui/link/LinkButton.astro"
5
+ import type { MayHaveClass } from "~ui/utils/MayHaveClass"
6
+ import { classMerge } from "~ui/utils/classMerge"
7
+
8
+ interface Props extends MayHaveClass {
9
+ icon: string
10
+ href?: string
11
+ title: string
12
+ titleClass?: string
13
+ subtitle?: string
14
+ subtitleClass?: string
15
+ innerClass?: string
16
+ class?: string
17
+ restProps?: HTMLAttributes<"header">
18
+ }
19
+
20
+ const p = Astro.props
21
+ ---
22
+
23
+ <div class={classMerge("flex flex-wrap items-center justify-between gap-4", p.class)} {...p.restProps}>
24
+ <h2 class={classMerge("text-2xl font-semibold", p.titleClass)}>
25
+ {
26
+ p.href ? (
27
+ <LinkButton href={p.href} icon={p.icon} variant={buttonVariant.link} class="pl-0">
28
+ {p.title}
29
+ </LinkButton>
30
+ ) : (
31
+ p.title
32
+ )
33
+ }
34
+ </h2>
35
+ {p.subtitle && <p class={classMerge("text-lg", p.subtitleClass)}>{p.subtitle}</p>}
36
+ <slot />
37
+ </div>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { classMerge } from "~ui/utils/classMerge"
4
+
5
+ interface Props {
6
+ id?: string
7
+ pathId?: string
8
+ path: string
9
+ class?: string
10
+ title?: string
11
+ ariaHidden?: boolean
12
+ restProps?: HTMLAttributes<"svg">
13
+ }
14
+ const p = Astro.props
15
+ const ariaHidden = p.ariaHidden ?? !p.title
16
+ ---
17
+
18
+ <svg
19
+ id={p.id}
20
+ viewBox={"0 0 24 24"}
21
+ aria-hidden={ariaHidden}
22
+ class={classMerge("size-6 flex-shrink-0 align-middle dark:fill-white", p.class)}
23
+ {...p.restProps}
24
+ >
25
+ <path id={p.pathId} d={p.path}></path>
26
+ </svg>
@@ -0,0 +1,4 @@
1
+ /**
2
+ * https://authjs.dev/img/providers/github.svg
3
+ */
4
+ export const iconGithub = "M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z"
@@ -0,0 +1,4 @@
1
+ /**
2
+ * https://authjs.dev/img/providers/google.svg
3
+ */
4
+ export const iconGoogle = "M21.35,11.1H12.18V13.83H18.69C18.36,17.64 15.19,19.27 12.19,19.27C8.36,19.27 5,16.25 5,12C5,7.9 8.2,4.73 12.2,4.73C15.29,4.73 17.1,6.7 17.1,6.7L19,4.72C19,4.72 16.56,2 12.1,2C6.42,2 2.03,6.8 2.03,12C2.03,17.05 6.16,22 12.25,22C17.6,22 21.5,18.33 21.5,12.91C21.5,11.76 21.35,11.1 21.35,11.1V11.1Z"
@@ -0,0 +1,2 @@
1
+ export const iconLinkedin =
2
+ "m3 4.29c0-.712.592-1.29 1.32-1.29h15.4c.73 0 1.32.577 1.32 1.29v15.4c0 .712-.592 1.29-1.32 1.29h-15.4c-.73 0-1.32-.577-1.32-1.29zm5.56 13.8v-8.13h-2.7v8.13zm-1.35-9.24c.942 0 1.53-.623 1.53-1.4-.0169-.798-.585-1.4-1.51-1.4-.925 0-1.53.608-1.53 1.4 0 .781.586 1.4 1.49 1.4zm5.52 9.24v-4.54c0-.243.018-.486.09-.659.195-.485.639-.988 1.39-.988.978 0 1.37.745 1.37 1.84v4.35h2.7v-4.66c0-2.5-1.33-3.66-3.11-3.66-1.43 0-2.08.788-2.44 1.34v.0281h-.018l.018-.0281v-1.15h-2.7c.0337.763 0 8.13 0 8.13z"
@@ -0,0 +1,2 @@
1
+ export const iconNpm =
2
+ "M4,10V14H6V11H7V14H8V10H4M9,10V15H11V14H13V10H9M12,11V13H11V11H12M14,10V14H16V11H17V14H18V11H19V14H20V10H14M3,9H21V15H12V16H8V15H3V9Z"
@@ -0,0 +1,2 @@
1
+ export const iconTelegram =
2
+ "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"
@@ -0,0 +1,2 @@
1
+ export const iconTrello =
2
+ "m18.9 3h-13.7c-1.18.00289-2.14.959-2.14 2.14v13.7c.00289 1.18.959 2.14 2.14 2.14h13.7c1.18-.0029 2.14-.959 2.14-2.14v-13.7c-.0029-1.18-.959-2.14-2.14-2.14zm-8.11 13c0 .19-.0753.371-.209.506-.134.134-.316.209-.505.209h-3c-.395 0-.715-.32-.716-.715v-8.93c0-.19.0754-.372.21-.506s.316-.209.506-.209h3c.395.00041.714.32.715.715zm6.92-4.1c7e-4.189-.0746.371-.209.504s-.316.208-.506.206h-3c-.189.0011-.371-.0732-.505-.206-.134-.133-.21-.315-.21-.504v-4.83c1e-4-.395.32-.715.715-.715h3c.395.00041.714.32.715.715z"
@@ -0,0 +1 @@
1
+ export const iconXcom = "m13.9 10.4 7.45-8.65h-1.76l-6.46 7.51-5.16-7.51h-5.96l7.81 11.4-7.81 9.08h1.76l6.83-7.94 5.45 7.94h5.96zm-2.42 2.81-7.09-10.1h2.71l12.5 17.8h-2.71z"
@@ -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,6 +1,7 @@
1
1
  ---
2
- import { classesImgZoomInOnHover } from "./classesImgZoomInOnHover"
3
- import { classMerge } from "~/utils/ui/classMerge"
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { classesImgZoomInOnHover10 } from "./classesImgZoomInOnHover10"
4
+ import { classMerge } from "~ui/utils/classMerge"
4
5
 
5
6
  interface Props {
6
7
  alt: string
@@ -10,8 +11,9 @@ interface Props {
10
11
  size?: number
11
12
  width?: number | null | undefined
12
13
  height?: number | null | undefined
13
- loadingLazy?:boolean
14
- decodeAsync?:boolean
14
+ loadingLazy?: boolean
15
+ decodeAsync?: boolean
16
+ restProps?: HTMLAttributes<"img">
15
17
  }
16
18
  const p = Astro.props
17
19
  ---
@@ -19,9 +21,10 @@ const p = Astro.props
19
21
  <img
20
22
  src={p.src}
21
23
  alt={p.alt}
22
- class={classMerge(p.zoomIn && classesImgZoomInOnHover, p.class)}
23
- loading={p.loadingLazy ?? true ? "lazy" : undefined}
24
- decoding={p.decodeAsync ?? true ? "async" : undefined}
24
+ class={classMerge(p.zoomIn && classesImgZoomInOnHover10, p.class)}
25
+ loading={(p.loadingLazy ?? true) ? "lazy" : undefined}
26
+ decoding={(p.decodeAsync ?? true) ? "async" : undefined}
25
27
  width={p.size ?? p.width}
26
28
  height={p.size ?? p.height}
29
+ {...p.restProps}
27
30
  />
@@ -1,26 +1,28 @@
1
1
  ---
2
- import { classArr } from "~/utils/ui/classArr"
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { classInvertBlack } from "~ui/img/classInvertBlack"
4
+ import { classArr } from "~ui/utils/classArr"
3
5
  import type { ImageType } from "./ImageType"
4
6
  import Img from "./Img.astro"
5
- import { classInvertDiagram } from "~/img/classInvertDiagram"
6
7
 
7
8
  interface Props {
8
9
  img: ImageType
9
10
  zoomIn?: boolean
11
+ invertColorsInDarkMode?: boolean
10
12
  class?: string
13
+ srcPrefix?: string
14
+ restProps?: HTMLAttributes<"img">
11
15
  }
12
- const props = Astro.props
13
- const isSvg = props.img.path.endsWith(".svg")
14
-
15
- function imageUrl(p: string) {
16
- return "/media-b2/" + p
17
- }
16
+ const p = Astro.props
17
+ const isSvg = p.img.path.endsWith(".svg")
18
+ const imageUrl = (p.srcPrefix ? p.srcPrefix : "") + p.img.path
18
19
  ---
19
20
 
20
21
  <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}
22
+ src={imageUrl}
23
+ alt={p.img.alt}
24
+ class={classArr(p.invertColorsInDarkMode ? classInvertBlack : "", p.class)}
25
+ width={isSvg ? null : p.img.width}
26
+ height={isSvg ? null : p.img.height}
27
+ restProps={p.restProps}
26
28
  />
@@ -0,0 +1,23 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import type { ImageType } from "./ImageType"
4
+ import TypedImg from "~ui/img/TypedImg.astro"
5
+
6
+ interface Props {
7
+ img: ImageType
8
+ zoomIn?: boolean
9
+ invertColorsInDarkMode?: boolean
10
+ class?: string
11
+ restProps?: HTMLAttributes<"img">
12
+ }
13
+ const p = Astro.props
14
+ ---
15
+
16
+ <TypedImg
17
+ img={p.img}
18
+ srcPrefix="/media-b2/"
19
+ zoomIn={p.zoomIn}
20
+ invertColorsInDarkMode={p.invertColorsInDarkMode}
21
+ class={p.class}
22
+ restProps={p.restProps}
23
+ />
@@ -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"
@@ -0,0 +1,19 @@
1
+ ---
2
+ import { classMerge } from "~ui/utils/classMerge"
3
+ import { classesCardWrapperPage } from "~ui/card/classesCardWrapper"
4
+ import MarkdownDiv from "~ui/md/MarkdownDiv.astro"
5
+ import PageCentered from "~ui/page/PageCentered.astro"
6
+
7
+ interface Props {
8
+ class?: string
9
+ innerClass?: string
10
+ }
11
+
12
+ const p = Astro.props
13
+ ---
14
+
15
+ <PageCentered class={classMerge("max-w-5xl my-12", p.class)}>
16
+ <MarkdownDiv class={classMerge(classesCardWrapperPage, p.innerClass)}>
17
+ <slot />
18
+ </MarkdownDiv>
19
+ </PageCentered>
@@ -1,20 +1,23 @@
1
1
  ---
2
- import { classArr } from "../utils/ui/classArr"
3
- import { objectKeys } from "~/utils/obj/objectKeys"
4
- import TailwindIndicator from "~/dev/TailwindIndicator.astro"
2
+ import TailwindIndicator from "~ui/dev/TailwindIndicator.astro"
3
+
4
+ import { classMerge } from "~ui/utils/classMerge"
5
+ import { classArr } from "../utils/classArr"
5
6
 
6
7
  export interface Props {
8
+ lang?: string
7
9
  title: string
8
10
  description?: string
9
11
  meta?: Record<string, string>
10
12
  class?: string
13
+ bodyClass?: string
11
14
  }
12
15
 
13
- const props = Astro.props
16
+ const p = Astro.props
14
17
  ---
15
18
 
16
19
  <!doctype html>
17
- <html lang="en">
20
+ <html lang={p.lang ?? "en"}>
18
21
  <head>
19
22
  <!-- Base -->
20
23
  <meta charset="UTF-8" />
@@ -22,8 +25,8 @@ const props = Astro.props
22
25
  <meta name="generator" content={Astro.generator} />
23
26
 
24
27
  <!-- Site -->
25
- <title>{props.title}</title>
26
- {props.description && <meta name="description" content={props.description} />}
28
+ <title>{p.title}</title>
29
+ {p.description && <meta name="description" content={p.description} />}
27
30
 
28
31
  <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
29
32
 
@@ -38,25 +41,29 @@ const props = Astro.props
38
41
  <meta name="googlebot" content="index, follow" />
39
42
 
40
43
  {
41
- props.meta && (
44
+ p.meta && (
42
45
  <Fragment>
43
- {objectKeys(props.meta).map((k) => (
44
- <meta property={k} content={props.meta![k]} />
46
+ {Object.entries(p.meta).map(([k, v]) => (
47
+ <meta property={k} content={v} />
45
48
  ))}
46
49
  </Fragment>
47
50
  )
48
51
  }
52
+ <slot name="head" />
49
53
  </head>
50
- <body class="min-h-dvh w-full font-sans antialiased bg-background text-foreground">
54
+ <body
55
+ class={classMerge(
56
+ "min-h-dvh w-full", // full screen
57
+ "font-sans antialiased text-foreground", // text
58
+ p.bodyClass,
59
+ )}
60
+ >
51
61
  <slot name="navbar" />
52
62
  <main
53
63
  id="main"
54
64
  class={classArr(
55
- "relative min-h-dvh",
56
- "w-full",
57
- "flex flex-col items-center",
58
- props.class,
59
- //
65
+ "relative min-h-dvh w-full", // full screen
66
+ p.class,
60
67
  )}
61
68
  >
62
69
  <slot />
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  import { mdiMoonWaxingCrescent, mdiWhiteBalanceSunny } from "@mdi/js"
3
- import { buttonVariant, type ButtonVariant } from "~/button/buttonCva"
4
- import Button from "~/button/Button.astro"
5
- import Icon1 from "~/icon/Icon1.astro"
6
- import { classArr } from "~/utils/ui/classArr"
7
- import { astroElementId } from "~/layouts/parts/astroElementId"
3
+ import { buttonVariant, type ButtonVariant } from "~ui/button/buttonCva"
4
+ import Button from "~ui/button/Button.astro"
5
+ import Icon from "~ui/icon/Icon.astro"
6
+ import { classArr } from "~ui/utils/classArr"
7
+ import { astroElementId } from "~ui/layouts/parts/astroElementId"
8
8
 
9
9
  /*
10
10
  * have to use "is:inline" script to run/apply theme before page render -> white flash on page reload otherwise
@@ -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
@@ -40,10 +40,10 @@ const textDark = p.textLight ?? "Dark"
40
40
  class={classArr(p.class)}
41
41
  contentClass={classArr("flex flex-row gap-1")}
42
42
  >
43
- <Icon1 path={mdiWhiteBalanceSunny} class={classArr("size-6 dark:hidden mr-2", p.iconClass, p.iconLightClass)} />
44
- <Icon1 path={mdiMoonWaxingCrescent} class={classArr("hidden size-6 dark:block mr-2", p.iconClass, p.iconDarkClass)} />
45
- <p id="theme-toggle-text-light" class={classArr("dark:hidden", p.textClass, p.textLightClass)}>{textLight}</p>
46
- <p id="theme-toggle-text-dark" class={classArr("hidden dark:block", p.textClass, p.textDarkClass)}>{textDark}</p>
43
+ <Icon path={mdiWhiteBalanceSunny} class={classArr("size-6 dark:hidden mr-2", p.iconClass, p.iconLightClass)} />
44
+ <Icon path={mdiMoonWaxingCrescent} class={classArr("hidden size-6 dark:block mr-2", p.iconClass, p.iconDarkClass)} />
45
+ <span id="theme-toggle-text-light" class={classArr("dark:hidden", p.textClass, p.textLightClass)}>{textLight}</span>
46
+ <span id="theme-toggle-text-dark" class={classArr("hidden dark:block", p.textClass, p.textDarkClass)}>{textDark}</span>
47
47
  </Button>
48
48
 
49
49
  <script is:inline>
@@ -1,8 +1,9 @@
1
1
  ---
2
- import { buttonCva2, buttonVariant, 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"
2
+ import type { HTMLAttributes } from "astro/types"
3
+ import { buttonCva2, buttonVariant, type ButtonSize, type ButtonVariant } from "~ui/button/buttonCva"
4
+ import { buttonIconCva } from "~ui/button/buttonIconCva"
5
+ import { classesButtonClickAnimation } from "~ui/button/classesButtonClickAnimation"
6
+ import Icon from "~ui/icon/Icon.astro"
6
7
 
7
8
  interface Props {
8
9
  title?: string
@@ -16,32 +17,30 @@ interface Props {
16
17
  class?: string
17
18
  id?: string
18
19
  clickAnimation?: boolean
20
+ restProps?: HTMLAttributes<"a">
19
21
  }
20
- const props = Astro.props
22
+ const p = Astro.props
21
23
  const hasChildren = Astro.slots.has("default")
22
24
  const classes = buttonCva2(
23
- props.variant ?? buttonVariant.link,
24
- props.size,
25
- props.clickAnimation ?? classesButtonClickAnimation,
26
- props.class,
25
+ p.variant ?? buttonVariant.link,
26
+ p.size,
27
+ p.clickAnimation ?? classesButtonClickAnimation,
28
+ p.class,
27
29
  )
28
30
  ---
29
31
 
30
- <a href={props.href} class={classes} target={props.newTab ? "_blank" : undefined} id={props.id} title={props.title}>
32
+ <a href={p.href} class={classes} target={p.newTab ? "_blank" : undefined} id={p.id} title={p.title} {...p.restProps}>
31
33
  {
32
- props.icon && (
33
- <Icon1
34
- path={props.icon}
35
- class={buttonIconCva(props.variant ?? "link", (props.title || hasChildren) && "mr-2", props.iconClass)}
36
- />
34
+ p.icon && (
35
+ <Icon path={p.icon} class={buttonIconCva(p.variant ?? "link", (p.title || hasChildren) && "mr-2", p.iconClass)} />
37
36
  )
38
37
  }
39
38
  <slot />
40
39
  {
41
- props.iconRight && (
42
- <Icon1
43
- path={props.iconRight}
44
- class={buttonIconCva(props.variant ?? "link", (props.title || hasChildren) && "ml-2", props.iconClass)}
40
+ p.iconRight && (
41
+ <Icon
42
+ path={p.iconRight}
43
+ class={buttonIconCva(p.variant ?? "link", (p.title || hasChildren) && "ml-2", p.iconClass)}
45
44
  />
46
45
  )
47
46
  }