fulldev-ui 0.11.0 → 0.11.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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/public/r/banner-2.json +1 -1
- package/public/r/banner.json +1 -1
- package/public/r/contact-1.json +1 -1
- package/public/r/contact-2.json +1 -1
- package/public/r/contact-3.json +1 -1
- package/public/r/sidebar-1.json +1 -1
- package/public/r/typography.json +1 -1
- package/src/components/blocks/banner-2.astro +7 -4
- package/src/components/blocks/contact-1.astro +2 -1
- package/src/components/blocks/contact-2.astro +2 -1
- package/src/components/blocks/contact-3.astro +2 -1
- package/src/components/blocks/sidebar-1.astro +2 -2
- package/src/components/ui/banner/banner.astro +23 -41
- package/src/components/ui/typography/typography.astro +1 -1
- package/src/styles/global.css +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Fulldev UI
|
|
2
2
|
|
|
3
|
+
## 0.11.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#190](https://github.com/fulldotdev/ui/pull/190) [`a7b9580`](https://github.com/fulldotdev/ui/commit/a7b9580c416a72abb4d09b721d2cba917c806f1b) Thanks [@silveltman](https://github.com/silveltman)! - Fix repeated banner initialization, render informational contact icons without inactive buttons, and improve narrow documentation headers and prose link contrast.
|
|
8
|
+
|
|
3
9
|
## 0.11.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/package.json
CHANGED
package/public/r/banner-2.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
{
|
|
12
12
|
"path": "src/components/blocks/banner-2.astro",
|
|
13
|
-
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Banner, BannerContainer } from \"@/components/ui/banner\"\nimport { Button } from \"@/components/ui/button\"\n\ntype Props = HTMLAttributes<\"aside\"> & {\n title: string\n description: string\n buttons?: {\n label: string\n href: string\n variant?: \"default\" | \"outline\" | \"secondary\" | \"ghost\"\n }[]\n}\n\nconst { class: className, title, description, buttons, ...props } = Astro.props\n---\n\n<Banner\n variant=\"floating\"\n storageKey=\"banner-2\"\n class={cn(\"\", className)}\n {...props}\n>\n <BannerContainer
|
|
13
|
+
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Banner, BannerContainer } from \"@/components/ui/banner\"\nimport { Button } from \"@/components/ui/button\"\n\ntype Props = HTMLAttributes<\"aside\"> & {\n title: string\n description: string\n buttons?: {\n label: string\n href: string\n variant?: \"default\" | \"outline\" | \"secondary\" | \"ghost\"\n }[]\n}\n\nconst { class: className, title, description, buttons, ...props } = Astro.props\n---\n\n<Banner\n variant=\"floating\"\n storageKey=\"banner-2\"\n class={cn(\"@container\", className)}\n {...props}\n>\n <BannerContainer\n class=\"flex-col items-start gap-4 py-1 @2xl:flex-row @2xl:items-center\"\n showClose={false}\n >\n <div\n class=\"flex min-w-0 flex-1 flex-col gap-0.5 @5xl:flex-row @5xl:items-center @5xl:gap-x-4\"\n >\n <p class=\"text-sm font-semibold\">{title}</p>\n <p class=\"text-muted-foreground text-sm\">{description}</p>\n </div>\n {\n buttons?.length && (\n <div class=\"flex flex-wrap items-center gap-2\">\n {buttons.map(({ href, label, ...button }, index) => (\n <Button\n as=\"a\"\n href={href}\n size=\"sm\"\n variant={button.variant ?? (index === 0 ? \"default\" : \"outline\")}\n {...button}\n >\n {label}\n </Button>\n ))}\n </div>\n )\n }\n </BannerContainer>\n</Banner>\n",
|
|
14
14
|
"type": "registry:block"
|
|
15
15
|
}
|
|
16
16
|
],
|
package/public/r/banner.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
{
|
|
15
15
|
"path": "src/components/ui/banner/banner.astro",
|
|
16
|
-
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype Props = HTMLAttributes<\"aside\"> &\n VariantProps<typeof variants> & {\n storageKey?: string\n }\n\nconst variants = cva(\"relative flex items-center py-2\", {\n variants: {\n variant: {\n default: \"bg-foreground text-background w-full\",\n floating:\n \"bg-background mx-auto my-2 w-[calc(100%-2rem)] max-w-[calc(var(--container,1280px)-2rem)] overflow-hidden rounded-lg border shadow-sm\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nconst { class: className, variant, storageKey, ...props } = Astro.props\n---\n\n<aside\n class={cn(variants({ variant }), className)}\n data-slot=\"banner\"\n data-banner-storage-key={storageKey}\n data-variant={variant}\n {...props}\n>\n <slot />\n</aside>\n\n<script
|
|
16
|
+
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype Props = HTMLAttributes<\"aside\"> &\n VariantProps<typeof variants> & {\n storageKey?: string\n }\n\nconst variants = cva(\"relative flex items-center py-2\", {\n variants: {\n variant: {\n default: \"bg-foreground text-background w-full\",\n floating:\n \"bg-background mx-auto my-2 w-[calc(100%-2rem)] max-w-[calc(var(--container,1280px)-2rem)] overflow-hidden rounded-lg border shadow-sm\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nconst { class: className, variant, storageKey, ...props } = Astro.props\n---\n\n<aside\n class={cn(variants({ variant }), className)}\n data-slot=\"banner\"\n data-banner-storage-key={storageKey}\n data-variant={variant}\n {...props}\n>\n <slot />\n</aside>\n\n<script>\n const getStorageToken = (key: string) => `banner:${key}`\n\n const syncBanners = () => {\n document.querySelectorAll(\"[data-slot='banner']\").forEach((banner) => {\n if (!(banner instanceof HTMLElement)) return\n const storageKey = banner.dataset.bannerStorageKey\n if (\n storageKey &&\n sessionStorage.getItem(getStorageToken(storageKey)) === \"hidden\"\n ) {\n banner.hidden = true\n }\n })\n }\n\n syncBanners()\n document.addEventListener(\"astro:page-load\", syncBanners)\n\n document.addEventListener(\"click\", (event) => {\n if (!(event.target instanceof Element)) return\n const closeButton = event.target.closest(\"[data-slot='banner-close']\")\n const banner = closeButton?.closest(\"[data-slot='banner']\")\n if (!(banner instanceof HTMLElement)) return\n banner.hidden = true\n const storageKey = banner.dataset.bannerStorageKey\n if (storageKey)\n sessionStorage.setItem(getStorageToken(storageKey), \"hidden\")\n })\n</script>\n",
|
|
17
17
|
"type": "registry:ui"
|
|
18
18
|
},
|
|
19
19
|
{
|
package/public/r/contact-1.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
{
|
|
20
20
|
"path": "src/components/blocks/contact-1.astro",
|
|
21
|
-
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@/components/ui/field\"\nimport { Form } from \"@/components/ui/form\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n Section,\n SectionContainer,\n SectionDescription,\n SectionTitle,\n} from \"@/components/ui/section\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\ntype Props = HTMLAttributes<\"section\"> & {\n title: string\n description: string\n contactItems: {\n icon: string\n title: string\n description: string\n href?: string\n }[]\n form: {\n id?: string\n action?: string\n method?: \"get\" | \"post\"\n legend: string\n nameLabel: string\n namePlaceholder: string\n emailLabel: string\n emailPlaceholder: string\n messageLabel: string\n messagePlaceholder: string\n messageDescription: string\n actionLabel: string\n }\n}\n\nconst {\n class: className,\n title,\n description,\n contactItems,\n form,\n ...props\n} = Astro.props\nconst formId = form.id ?? `contact-${crypto.randomUUID()}`\n---\n\n<Section class={cn(\"\", className)} {...props}>\n <SectionContainer class=\"items-center gap-6 text-center\">\n <div class=\"flex max-w-2xl flex-col items-center gap-4\">\n <SectionTitle>\n {title}\n </SectionTitle>\n <SectionDescription class=\"max-w-2xl\">\n {description}\n </SectionDescription>\n </div>\n </SectionContainer>\n <SectionContainer>\n <div class=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {\n contactItems.map((item) => (\n <div class=\"flex flex-col gap-3 rounded-xl border p-5\">\n {item.href ? (\n <Button\n as=\"a\"\n href={item.href}\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary\"\n aria-label={item.title}\n >\n <Icon name={item.icon} />\n </Button>\n ) : (\n <Button\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary\"\n aria-
|
|
21
|
+
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@/components/ui/field\"\nimport { Form } from \"@/components/ui/form\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n Section,\n SectionContainer,\n SectionDescription,\n SectionTitle,\n} from \"@/components/ui/section\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\ntype Props = HTMLAttributes<\"section\"> & {\n title: string\n description: string\n contactItems: {\n icon: string\n title: string\n description: string\n href?: string\n }[]\n form: {\n id?: string\n action?: string\n method?: \"get\" | \"post\"\n legend: string\n nameLabel: string\n namePlaceholder: string\n emailLabel: string\n emailPlaceholder: string\n messageLabel: string\n messagePlaceholder: string\n messageDescription: string\n actionLabel: string\n }\n}\n\nconst {\n class: className,\n title,\n description,\n contactItems,\n form,\n ...props\n} = Astro.props\nconst formId = form.id ?? `contact-${crypto.randomUUID()}`\n---\n\n<Section class={cn(\"\", className)} {...props}>\n <SectionContainer class=\"items-center gap-6 text-center\">\n <div class=\"flex max-w-2xl flex-col items-center gap-4\">\n <SectionTitle>\n {title}\n </SectionTitle>\n <SectionDescription class=\"max-w-2xl\">\n {description}\n </SectionDescription>\n </div>\n </SectionContainer>\n <SectionContainer>\n <div class=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {\n contactItems.map((item) => (\n <div class=\"flex flex-col gap-3 rounded-xl border p-5\">\n {item.href ? (\n <Button\n as=\"a\"\n href={item.href}\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary\"\n aria-label={item.title}\n >\n <Icon name={item.icon} />\n </Button>\n ) : (\n <Button\n as=\"span\"\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary\"\n aria-hidden=\"true\"\n >\n <Icon name={item.icon} />\n </Button>\n )}\n <h3 class=\"text-foreground text-sm font-medium\">{item.title}</h3>\n <p class=\"text-muted-foreground text-sm leading-relaxed\">\n {item.description}\n </p>\n </div>\n ))\n }\n </div>\n </SectionContainer>\n <SectionContainer>\n <div class=\"mx-auto w-full max-w-2xl rounded-xl border p-6 sm:p-8\">\n <Form id={formId} action={form.action} method={form.method ?? \"post\"}>\n <FieldSet>\n <FieldLegend class=\"sr-only\">{form.legend}</FieldLegend>\n <FieldGroup>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Field>\n <FieldLabel for={`${formId}-name`}>{form.nameLabel}</FieldLabel>\n <Input\n id={`${formId}-name`}\n name=\"name\"\n autocomplete=\"name\"\n required\n placeholder={form.namePlaceholder}\n />\n </Field>\n <Field>\n <FieldLabel for={`${formId}-email`}\n >{form.emailLabel}</FieldLabel\n >\n <Input\n id={`${formId}-email`}\n name=\"email\"\n autocomplete=\"email\"\n required\n type=\"email\"\n placeholder={form.emailPlaceholder}\n />\n </Field>\n </div>\n <Field>\n <FieldLabel for={`${formId}-message`}\n >{form.messageLabel}</FieldLabel\n >\n <Textarea\n id={`${formId}-message`}\n name=\"message\"\n required\n rows={5}\n placeholder={form.messagePlaceholder}\n />\n <FieldDescription>{form.messageDescription}</FieldDescription>\n </Field>\n <Button type=\"submit\" size=\"lg\" class=\"w-full\"\n >{form.actionLabel}</Button\n >\n </FieldGroup>\n </FieldSet>\n </Form>\n </div>\n </SectionContainer>\n</Section>\n",
|
|
22
22
|
"type": "registry:block"
|
|
23
23
|
}
|
|
24
24
|
],
|
package/public/r/contact-2.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
{
|
|
20
20
|
"path": "src/components/blocks/contact-2.astro",
|
|
21
|
-
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Field,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@/components/ui/field\"\nimport { Form } from \"@/components/ui/form\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n Section,\n SectionContainer,\n SectionTitle,\n} from \"@/components/ui/section\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\ntype Props = HTMLAttributes<\"section\"> & {\n title: string\n description: string\n contactItems: {\n icon: string\n title: string\n description: string\n href?: string\n }[]\n form: {\n id?: string\n action?: string\n method?: \"get\" | \"post\"\n title: string\n legend: string\n nameLabel: string\n namePlaceholder: string\n emailLabel: string\n emailPlaceholder: string\n messageLabel: string\n messagePlaceholder: string\n actionLabel: string\n }\n}\n\nconst {\n class: className,\n title,\n description,\n contactItems,\n form,\n ...props\n} = Astro.props\nconst formId = form.id ?? `contact-${crypto.randomUUID()}`\n---\n\n<Section class={cn(\"\", className)} {...props}>\n <SectionContainer\n class=\"grid gap-10 lg:grid-cols-[minmax(0,1fr)_22rem] lg:items-start\"\n >\n <div class=\"flex flex-col gap-6\">\n <div class=\"flex flex-col gap-4\">\n <SectionTitle>\n {title}\n </SectionTitle>\n <p class=\"text-muted-foreground max-w-xl text-base leading-relaxed\">\n {description}\n </p>\n </div>\n <div class=\"rounded-xl border p-6\">\n <div class=\"mb-6\">\n <h3 class=\"text-lg font-medium\">{form.title}</h3>\n </div>\n <Form id={formId} action={form.action} method={form.method ?? \"post\"}>\n <FieldSet>\n <FieldLegend class=\"sr-only\">{form.legend}</FieldLegend>\n <FieldGroup>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Field>\n <FieldLabel for={`${formId}-name`}\n >{form.nameLabel}</FieldLabel\n >\n <Input\n id={`${formId}-name`}\n name=\"name\"\n autocomplete=\"name\"\n required\n placeholder={form.namePlaceholder}\n />\n </Field>\n <Field>\n <FieldLabel for={`${formId}-email`}\n >{form.emailLabel}</FieldLabel\n >\n <Input\n id={`${formId}-email`}\n name=\"email\"\n autocomplete=\"email\"\n required\n type=\"email\"\n placeholder={form.emailPlaceholder}\n />\n </Field>\n </div>\n <Field>\n <FieldLabel for={`${formId}-message`}\n >{form.messageLabel}</FieldLabel\n >\n <Textarea\n id={`${formId}-message`}\n name=\"message\"\n required\n rows={5}\n placeholder={form.messagePlaceholder}\n />\n </Field>\n <Button type=\"submit\" size=\"lg\" class=\"w-full\"\n >{form.actionLabel}</Button\n >\n </FieldGroup>\n </FieldSet>\n </Form>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-3\">\n {\n contactItems.map((item) => (\n <div class=\"flex gap-4 rounded-xl border p-4\">\n {item.href ? (\n <Button\n as=\"a\"\n href={item.href}\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-label={item.title}\n >\n <Icon name={item.icon} />\n </Button>\n ) : (\n <Button\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-
|
|
21
|
+
"content": "---\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Field,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@/components/ui/field\"\nimport { Form } from \"@/components/ui/form\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n Section,\n SectionContainer,\n SectionTitle,\n} from \"@/components/ui/section\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\ntype Props = HTMLAttributes<\"section\"> & {\n title: string\n description: string\n contactItems: {\n icon: string\n title: string\n description: string\n href?: string\n }[]\n form: {\n id?: string\n action?: string\n method?: \"get\" | \"post\"\n title: string\n legend: string\n nameLabel: string\n namePlaceholder: string\n emailLabel: string\n emailPlaceholder: string\n messageLabel: string\n messagePlaceholder: string\n actionLabel: string\n }\n}\n\nconst {\n class: className,\n title,\n description,\n contactItems,\n form,\n ...props\n} = Astro.props\nconst formId = form.id ?? `contact-${crypto.randomUUID()}`\n---\n\n<Section class={cn(\"\", className)} {...props}>\n <SectionContainer\n class=\"grid gap-10 lg:grid-cols-[minmax(0,1fr)_22rem] lg:items-start\"\n >\n <div class=\"flex flex-col gap-6\">\n <div class=\"flex flex-col gap-4\">\n <SectionTitle>\n {title}\n </SectionTitle>\n <p class=\"text-muted-foreground max-w-xl text-base leading-relaxed\">\n {description}\n </p>\n </div>\n <div class=\"rounded-xl border p-6\">\n <div class=\"mb-6\">\n <h3 class=\"text-lg font-medium\">{form.title}</h3>\n </div>\n <Form id={formId} action={form.action} method={form.method ?? \"post\"}>\n <FieldSet>\n <FieldLegend class=\"sr-only\">{form.legend}</FieldLegend>\n <FieldGroup>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Field>\n <FieldLabel for={`${formId}-name`}\n >{form.nameLabel}</FieldLabel\n >\n <Input\n id={`${formId}-name`}\n name=\"name\"\n autocomplete=\"name\"\n required\n placeholder={form.namePlaceholder}\n />\n </Field>\n <Field>\n <FieldLabel for={`${formId}-email`}\n >{form.emailLabel}</FieldLabel\n >\n <Input\n id={`${formId}-email`}\n name=\"email\"\n autocomplete=\"email\"\n required\n type=\"email\"\n placeholder={form.emailPlaceholder}\n />\n </Field>\n </div>\n <Field>\n <FieldLabel for={`${formId}-message`}\n >{form.messageLabel}</FieldLabel\n >\n <Textarea\n id={`${formId}-message`}\n name=\"message\"\n required\n rows={5}\n placeholder={form.messagePlaceholder}\n />\n </Field>\n <Button type=\"submit\" size=\"lg\" class=\"w-full\"\n >{form.actionLabel}</Button\n >\n </FieldGroup>\n </FieldSet>\n </Form>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-3\">\n {\n contactItems.map((item) => (\n <div class=\"flex gap-4 rounded-xl border p-4\">\n {item.href ? (\n <Button\n as=\"a\"\n href={item.href}\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-label={item.title}\n >\n <Icon name={item.icon} />\n </Button>\n ) : (\n <Button\n as=\"span\"\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-hidden=\"true\"\n >\n <Icon name={item.icon} />\n </Button>\n )}\n <div class=\"flex flex-col gap-1\">\n <p class=\"text-foreground text-sm font-medium\">{item.title}</p>\n <p class=\"text-muted-foreground text-sm leading-relaxed\">\n {item.description}\n </p>\n </div>\n </div>\n ))\n }\n </div>\n </SectionContainer>\n</Section>\n",
|
|
22
22
|
"type": "registry:block"
|
|
23
23
|
}
|
|
24
24
|
],
|
package/public/r/contact-3.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
{
|
|
20
20
|
"path": "src/components/blocks/contact-3.astro",
|
|
21
|
-
"content": "---\nimport type { ImageMetadata } from \"astro\"\nimport { Image } from \"astro:assets\"\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Field,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@/components/ui/field\"\nimport { Form } from \"@/components/ui/form\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n Section,\n SectionContainer,\n SectionTitle,\n} from \"@/components/ui/section\"\nimport { Textarea } from \"@/components/ui/textarea\"\nimport PlaceholderImage from \"@/assets/placeholder.webp\"\n\ntype Props = HTMLAttributes<\"section\"> & {\n title: string\n description: string\n contactItems: {\n icon: string\n title: string\n description: string\n href?: string\n }[]\n form: {\n id?: string\n action?: string\n method?: \"get\" | \"post\"\n legend: string\n nameLabel: string\n namePlaceholder: string\n emailLabel: string\n emailPlaceholder: string\n messageLabel: string\n messagePlaceholder: string\n actionLabel: string\n }\n image?: {\n src: ImageMetadata\n alt: string\n }\n}\n\nconst {\n class: className,\n title,\n description,\n contactItems,\n form,\n image = { src: PlaceholderImage, alt: \"Contact image\" },\n ...props\n} = Astro.props\nconst formId = form.id ?? `contact-${crypto.randomUUID()}`\n---\n\n<Section class={cn(\"\", className)} {...props}>\n <SectionContainer class=\"grid gap-12 lg:grid-cols-2 lg:items-start\">\n <div class=\"flex flex-col gap-8\">\n <div class=\"flex flex-col gap-4\">\n <SectionTitle>\n {title}\n </SectionTitle>\n <p class=\"text-muted-foreground max-w-xl text-base leading-relaxed\">\n {description}\n </p>\n </div>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n {\n contactItems.map((item) => (\n <div class=\"flex gap-4\">\n {item.href ? (\n <Button\n as=\"a\"\n href={item.href}\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-label={item.title}\n >\n <Icon name={item.icon} />\n </Button>\n ) : (\n <Button\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-
|
|
21
|
+
"content": "---\nimport type { ImageMetadata } from \"astro\"\nimport { Image } from \"astro:assets\"\nimport type { HTMLAttributes } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Field,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@/components/ui/field\"\nimport { Form } from \"@/components/ui/form\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n Section,\n SectionContainer,\n SectionTitle,\n} from \"@/components/ui/section\"\nimport { Textarea } from \"@/components/ui/textarea\"\nimport PlaceholderImage from \"@/assets/placeholder.webp\"\n\ntype Props = HTMLAttributes<\"section\"> & {\n title: string\n description: string\n contactItems: {\n icon: string\n title: string\n description: string\n href?: string\n }[]\n form: {\n id?: string\n action?: string\n method?: \"get\" | \"post\"\n legend: string\n nameLabel: string\n namePlaceholder: string\n emailLabel: string\n emailPlaceholder: string\n messageLabel: string\n messagePlaceholder: string\n actionLabel: string\n }\n image?: {\n src: ImageMetadata\n alt: string\n }\n}\n\nconst {\n class: className,\n title,\n description,\n contactItems,\n form,\n image = { src: PlaceholderImage, alt: \"Contact image\" },\n ...props\n} = Astro.props\nconst formId = form.id ?? `contact-${crypto.randomUUID()}`\n---\n\n<Section class={cn(\"\", className)} {...props}>\n <SectionContainer class=\"grid gap-12 lg:grid-cols-2 lg:items-start\">\n <div class=\"flex flex-col gap-8\">\n <div class=\"flex flex-col gap-4\">\n <SectionTitle>\n {title}\n </SectionTitle>\n <p class=\"text-muted-foreground max-w-xl text-base leading-relaxed\">\n {description}\n </p>\n </div>\n <div class=\"grid gap-4 sm:grid-cols-2\">\n {\n contactItems.map((item) => (\n <div class=\"flex gap-4\">\n {item.href ? (\n <Button\n as=\"a\"\n href={item.href}\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-label={item.title}\n >\n <Icon name={item.icon} />\n </Button>\n ) : (\n <Button\n as=\"span\"\n variant=\"secondary\"\n size=\"icon\"\n class=\"text-primary shrink-0\"\n aria-hidden=\"true\"\n >\n <Icon name={item.icon} />\n </Button>\n )}\n <div class=\"flex flex-col gap-1\">\n <p class=\"text-foreground text-sm font-medium\">{item.title}</p>\n <p class=\"text-muted-foreground text-sm leading-relaxed\">\n {item.description}\n </p>\n </div>\n </div>\n ))\n }\n </div>\n <div class=\"rounded-xl border p-6\">\n <Form id={formId} action={form.action} method={form.method ?? \"post\"}>\n <FieldSet>\n <FieldLegend class=\"sr-only\">{form.legend}</FieldLegend>\n <FieldGroup>\n <div class=\"grid gap-4 md:grid-cols-2\">\n <Field>\n <FieldLabel for={`${formId}-name`}\n >{form.nameLabel}</FieldLabel\n >\n <Input\n id={`${formId}-name`}\n name=\"name\"\n autocomplete=\"name\"\n required\n placeholder={form.namePlaceholder}\n />\n </Field>\n <Field>\n <FieldLabel for={`${formId}-email`}\n >{form.emailLabel}</FieldLabel\n >\n <Input\n id={`${formId}-email`}\n name=\"email\"\n autocomplete=\"email\"\n required\n type=\"email\"\n placeholder={form.emailPlaceholder}\n />\n </Field>\n </div>\n <Field>\n <FieldLabel for={`${formId}-message`}\n >{form.messageLabel}</FieldLabel\n >\n <Textarea\n id={`${formId}-message`}\n name=\"message\"\n required\n rows={5}\n placeholder={form.messagePlaceholder}\n />\n </Field>\n <Button type=\"submit\" size=\"lg\" class=\"w-full\"\n >{form.actionLabel}</Button\n >\n </FieldGroup>\n </FieldSet>\n </Form>\n </div>\n </div>\n <Image\n src={image.src}\n alt={image.alt}\n class=\"aspect-[3/4] w-full rounded-xl border object-cover lg:sticky lg:top-24\"\n widths={[640, 960, 1280]}\n sizes=\"(min-width: 1024px) 50vw, 100vw\"\n />\n </SectionContainer>\n</Section>\n",
|
|
22
22
|
"type": "registry:block"
|
|
23
23
|
},
|
|
24
24
|
{
|
package/public/r/sidebar-1.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
{
|
|
25
25
|
"path": "src/components/blocks/sidebar-1.astro",
|
|
26
|
-
"content": "---\nimport ChevronDownIcon from \"@lucide/astro/icons/chevron-down\"\nimport SearchIcon from \"@lucide/astro/icons/search\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandShortcut,\n} from \"@/components/ui/command\"\nimport { Dialog, DialogTrigger } from \"@/components/ui/dialog\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { Header, HeaderContainer, HeaderGroup } from \"@/components/ui/header\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Kbd } from \"@/components/ui/kbd\"\nimport { LogoImage, LogoText } from \"@/components/ui/logo\"\nimport { Separator } from \"@/components/ui/separator\"\nimport {\n Sidebar,\n SidebarContent,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n SidebarTrigger,\n} from \"@/components/ui/sidebar\"\nimport { ThemeToggle } from \"@/components/ui/theme-toggle\"\n\ntype Props = {\n class?: string\n logo: {\n label: string\n href: string\n src?: any\n srcLight?: any\n srcDark?: any\n alt?: string\n }\n search: {\n label: string\n empty: string\n items: {\n label: string\n href: string\n title: string\n path: string\n description: string\n group: string\n }[]\n }\n breadcrumb: {\n items: {\n label: string\n href: string\n }[]\n menu: {\n label: string\n href: string\n }[]\n }\n navigation: {\n label: string\n href: string\n links?: {\n label: string\n href: string\n }[]\n }[]\n githubRepo: string\n}\n\nconst {\n class: className,\n logo,\n search,\n breadcrumb,\n navigation,\n githubRepo,\n}: Props = Astro.props\n\nconst normalizePath = (path: string) => {\n if (path === \"/\") return path\n\n return path.replace(/\\/$/, \"\")\n}\nconst currentPath = normalizePath(Astro.url.pathname)\nconst searchGroups = search.items.reduce<\n { label: string; items: typeof search.items }[]\n>((groups, item) => {\n const group = groups.find((entry) => entry.label === item.group)\n\n if (group) {\n group.items.push(item)\n } else {\n groups.push({ label: item.group, items: [item] })\n }\n\n return groups\n}, [])\n\nlet githubStars = \"Stars\"\n\ntry {\n const response = await fetch(`https://api.github.com/repos/${githubRepo}`)\n const data = await response.json()\n\n if (response.ok && typeof data.stargazers_count === \"number\") {\n githubStars = new Intl.NumberFormat().format(data.stargazers_count)\n }\n} catch {\n // Keep the fallback label when GitHub is unavailable.\n}\n---\n\n<SidebarProvider>\n <Sidebar class={cn(\"\", className)} collapsible=\"offcanvas\" variant=\"inset\">\n <SidebarHeader class=\"flex-col\">\n <SidebarMenuButton size=\"lg\" variant=\"ghost\" href={logo.href}>\n <LogoImage\n src={logo.src}\n srcLight={logo.srcLight}\n srcDark={logo.srcDark}\n alt={logo.alt}\n />\n <LogoText class=\"font-semibold\">{logo.label}</LogoText>\n </SidebarMenuButton>\n <Dialog class=\"w-full\" data-search-dialog>\n <DialogTrigger\n variant=\"outline\"\n size=\"sm\"\n class=\"w-full justify-start shadow-none\"\n aria-keyshortcuts=\"Meta+K Control+K\"\n >\n <SearchIcon data-icon=\"inline-start\" />\n <span class=\"truncate\">{search.label}</span>\n <Kbd\n class=\"bg-background/80 ml-auto h-4 min-w-4 translate-y-0 px-1 text-[10px]\"\n data-search-shortcut\n >\n ⌘ + K\n </Kbd>\n </DialogTrigger>\n\n <CommandDialog title={search.label} description={search.label}>\n <Command\n class=\"[&_[data-slot=command-item][data-selected]]:bg-accent [&_[data-slot=command-item][data-selected]]:text-accent-foreground\"\n >\n <CommandInput placeholder={search.label} />\n <CommandList>\n <CommandEmpty>{search.empty}</CommandEmpty>\n\n {\n searchGroups.map((group) => (\n <CommandGroup heading={group.label}>\n {group.items.map((item) => (\n <CommandItem\n href={item.href}\n value={`${item.group} ${item.label}`}\n label={item.label}\n keywords={[\n item.group,\n item.title,\n item.path,\n item.description,\n ]}\n >\n {item.label}\n <CommandShortcut>{item.href}</CommandShortcut>\n </CommandItem>\n ))}\n </CommandGroup>\n ))\n }\n </CommandList>\n </Command>\n </CommandDialog>\n </Dialog>\n </SidebarHeader>\n <SidebarContent\n class=\"[mask-image:linear-gradient(to_bottom,transparent,black_1rem,black_calc(100%_-_1rem),transparent)] [-webkit-mask-image:linear-gradient(to_bottom,transparent,black_1rem,black_calc(100%_-_1rem),transparent)] group-data-[collapsible=icon]:[mask-image:none] group-data-[collapsible=icon]:[-webkit-mask-image:none]\"\n >\n {\n navigation.map((group) => (\n <SidebarGroup>\n <SidebarGroupLabel>{group.label}</SidebarGroupLabel>\n <SidebarMenu>\n {(group.links ?? [group]).map((item) => (\n <SidebarMenuItem>\n <SidebarMenuButton\n href={item.href}\n isActive={normalizePath(item.href) === currentPath}\n >\n <span>{item.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroup>\n ))\n }\n </SidebarContent>\n </Sidebar>\n <SidebarInset>\n <Header class=\"h-16\">\n <HeaderContainer class=\"max-w-none justify-between\">\n <HeaderGroup>\n <SidebarTrigger />\n <Separator orientation=\"vertical\" class=\"my-auto mr-2 h-4\" />\n <Breadcrumb>\n <BreadcrumbList>\n {\n breadcrumb.items.map((item, index) => {\n const isLast = index === breadcrumb.items.length - 1\n const isHome = item.href === \"/\"\n const hasMenu =\n !isHome &&\n breadcrumb.menu.some(\n (menuItem) =>\n normalizePath(menuItem.href) ===\n normalizePath(item.href)\n )\n\n return (\n <>\n {index > 0 && (\n <BreadcrumbSeparator>/</BreadcrumbSeparator>\n )}\n <BreadcrumbItem>\n {hasMenu ? (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-current={isLast ? \"page\" : undefined}\n class={cn(\n \"hover:text-foreground inline-flex items-center gap-1 transition-colors\",\n isLast && \"text-foreground\"\n )}\n >\n {item.label}\n <ChevronDownIcon\n class=\"size-3.5 opacity-70\"\n aria-hidden=\"true\"\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuGroup>\n {breadcrumb.menu.map((menuItem) => (\n <a\n href={menuItem.href}\n aria-current={\n normalizePath(menuItem.href) ===\n currentPath\n ? \"page\"\n : undefined\n }\n class=\"hover:bg-accent hover:text-accent-foreground aria-[current=page]:text-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none\"\n >\n {menuItem.label}\n </a>\n ))}\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : (\n <BreadcrumbLink href={item.href}>\n {item.label}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </>\n )\n })\n }\n {\n breadcrumb.menu.length > 0 && currentPath === \"/\" && (\n <>\n <BreadcrumbSeparator>/</BreadcrumbSeparator>\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger class=\"hover:text-foreground inline-flex items-center leading-none transition-colors\">\n <BreadcrumbEllipsis />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuGroup>\n {breadcrumb.menu.map((item) => (\n <a\n href={item.href}\n class=\"hover:bg-accent hover:text-accent-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none\"\n >\n {item.label}\n </a>\n ))}\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n </>\n )\n }\n </BreadcrumbList>\n </Breadcrumb>\n </HeaderGroup>\n <HeaderGroup>\n <Button\n as=\"a\"\n href={`https://github.com/${githubRepo}`}\n size=\"sm\"\n variant=\"ghost\"\n target=\"_blank\"\n rel=\"noreferrer\"\n aria-label={`View ${githubRepo} on GitHub`}\n >\n <Icon name=\"github\" />\n <span>{githubStars}</span>\n </Button>\n <ThemeToggle />\n </HeaderGroup>\n </HeaderContainer>\n </Header>\n <slot />\n </SidebarInset>\n</SidebarProvider>\n\n<script>\n const isMac = /Mac|iPhone|iPad|iPod/i.test(\n navigator.platform || navigator.userAgent\n )\n\n document.querySelectorAll(\"[data-search-shortcut]\").forEach((shortcut) => {\n shortcut.textContent = isMac ? \"⌘ + K\" : \"Ctrl + K\"\n })\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key.toLowerCase() !== \"k\") return\n if (event.shiftKey || event.altKey) return\n\n const dialog = document.querySelector(\"[data-search-dialog]\")\n const isSearchShortcut = isMac\n ? event.metaKey && !event.ctrlKey\n : event.ctrlKey && !event.metaKey\n\n if (!dialog || dialog.hasAttribute(\"data-open\") || !isSearchShortcut) return\n\n event.preventDefault()\n dialog.dispatchEvent(\n new CustomEvent(\"dialog:set\", { detail: { open: true } })\n )\n })\n</script>\n",
|
|
26
|
+
"content": "---\nimport ChevronDownIcon from \"@lucide/astro/icons/chevron-down\"\nimport SearchIcon from \"@lucide/astro/icons/search\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandShortcut,\n} from \"@/components/ui/command\"\nimport { Dialog, DialogTrigger } from \"@/components/ui/dialog\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { Header, HeaderContainer, HeaderGroup } from \"@/components/ui/header\"\nimport { Icon } from \"@/components/ui/icon\"\nimport { Kbd } from \"@/components/ui/kbd\"\nimport { LogoImage, LogoText } from \"@/components/ui/logo\"\nimport { Separator } from \"@/components/ui/separator\"\nimport {\n Sidebar,\n SidebarContent,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n SidebarTrigger,\n} from \"@/components/ui/sidebar\"\nimport { ThemeToggle } from \"@/components/ui/theme-toggle\"\n\ntype Props = {\n class?: string\n logo: {\n label: string\n href: string\n src?: any\n srcLight?: any\n srcDark?: any\n alt?: string\n }\n search: {\n label: string\n empty: string\n items: {\n label: string\n href: string\n title: string\n path: string\n description: string\n group: string\n }[]\n }\n breadcrumb: {\n items: {\n label: string\n href: string\n }[]\n menu: {\n label: string\n href: string\n }[]\n }\n navigation: {\n label: string\n href: string\n links?: {\n label: string\n href: string\n }[]\n }[]\n githubRepo: string\n}\n\nconst {\n class: className,\n logo,\n search,\n breadcrumb,\n navigation,\n githubRepo,\n}: Props = Astro.props\n\nconst normalizePath = (path: string) => {\n if (path === \"/\") return path\n\n return path.replace(/\\/$/, \"\")\n}\nconst currentPath = normalizePath(Astro.url.pathname)\nconst searchGroups = search.items.reduce<\n { label: string; items: typeof search.items }[]\n>((groups, item) => {\n const group = groups.find((entry) => entry.label === item.group)\n\n if (group) {\n group.items.push(item)\n } else {\n groups.push({ label: item.group, items: [item] })\n }\n\n return groups\n}, [])\n\nlet githubStars = \"Stars\"\n\ntry {\n const response = await fetch(`https://api.github.com/repos/${githubRepo}`)\n const data = await response.json()\n\n if (response.ok && typeof data.stargazers_count === \"number\") {\n githubStars = new Intl.NumberFormat().format(data.stargazers_count)\n }\n} catch {\n // Keep the fallback label when GitHub is unavailable.\n}\n---\n\n<SidebarProvider>\n <Sidebar class={cn(\"\", className)} collapsible=\"offcanvas\" variant=\"inset\">\n <SidebarHeader class=\"flex-col\">\n <SidebarMenuButton size=\"lg\" variant=\"ghost\" href={logo.href}>\n <LogoImage\n src={logo.src}\n srcLight={logo.srcLight}\n srcDark={logo.srcDark}\n alt={logo.alt}\n />\n <LogoText class=\"font-semibold\">{logo.label}</LogoText>\n </SidebarMenuButton>\n <Dialog class=\"w-full\" data-search-dialog>\n <DialogTrigger\n variant=\"outline\"\n size=\"sm\"\n class=\"w-full justify-start shadow-none\"\n aria-keyshortcuts=\"Meta+K Control+K\"\n >\n <SearchIcon data-icon=\"inline-start\" />\n <span class=\"truncate\">{search.label}</span>\n <Kbd\n class=\"bg-background/80 ml-auto h-4 min-w-4 translate-y-0 px-1 text-[10px]\"\n data-search-shortcut\n >\n ⌘ + K\n </Kbd>\n </DialogTrigger>\n\n <CommandDialog title={search.label} description={search.label}>\n <Command\n class=\"[&_[data-slot=command-item][data-selected]]:bg-accent [&_[data-slot=command-item][data-selected]]:text-accent-foreground\"\n >\n <CommandInput placeholder={search.label} />\n <CommandList>\n <CommandEmpty>{search.empty}</CommandEmpty>\n\n {\n searchGroups.map((group) => (\n <CommandGroup heading={group.label}>\n {group.items.map((item) => (\n <CommandItem\n href={item.href}\n value={`${item.group} ${item.label}`}\n label={item.label}\n keywords={[\n item.group,\n item.title,\n item.path,\n item.description,\n ]}\n >\n {item.label}\n <CommandShortcut>{item.href}</CommandShortcut>\n </CommandItem>\n ))}\n </CommandGroup>\n ))\n }\n </CommandList>\n </Command>\n </CommandDialog>\n </Dialog>\n </SidebarHeader>\n <SidebarContent\n class=\"[mask-image:linear-gradient(to_bottom,transparent,black_1rem,black_calc(100%_-_1rem),transparent)] [-webkit-mask-image:linear-gradient(to_bottom,transparent,black_1rem,black_calc(100%_-_1rem),transparent)] group-data-[collapsible=icon]:[mask-image:none] group-data-[collapsible=icon]:[-webkit-mask-image:none]\"\n >\n {\n navigation.map((group) => (\n <SidebarGroup>\n <SidebarGroupLabel>{group.label}</SidebarGroupLabel>\n <SidebarMenu>\n {(group.links ?? [group]).map((item) => (\n <SidebarMenuItem>\n <SidebarMenuButton\n href={item.href}\n isActive={normalizePath(item.href) === currentPath}\n >\n <span>{item.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroup>\n ))\n }\n </SidebarContent>\n </Sidebar>\n <SidebarInset>\n <Header class=\"h-16\">\n <HeaderContainer class=\"max-w-none justify-between\">\n <HeaderGroup>\n <SidebarTrigger />\n <Separator orientation=\"vertical\" class=\"my-auto mr-2 h-4\" />\n <Breadcrumb>\n <BreadcrumbList>\n {\n breadcrumb.items.map((item, index) => {\n const isLast = index === breadcrumb.items.length - 1\n const isHome = item.href === \"/\"\n const hasMenu =\n !isHome &&\n breadcrumb.menu.some(\n (menuItem) =>\n normalizePath(menuItem.href) ===\n normalizePath(item.href)\n )\n\n return (\n <>\n {index > 0 && (\n <BreadcrumbSeparator>/</BreadcrumbSeparator>\n )}\n <BreadcrumbItem>\n {hasMenu ? (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-current={isLast ? \"page\" : undefined}\n class={cn(\n \"hover:text-foreground inline-flex items-center gap-1 transition-colors\",\n isLast && \"text-foreground\"\n )}\n >\n {item.label}\n <ChevronDownIcon\n class=\"size-3.5 opacity-70\"\n aria-hidden=\"true\"\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuGroup>\n {breadcrumb.menu.map((menuItem) => (\n <a\n href={menuItem.href}\n aria-current={\n normalizePath(menuItem.href) ===\n currentPath\n ? \"page\"\n : undefined\n }\n class=\"hover:bg-accent hover:text-accent-foreground aria-[current=page]:text-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none\"\n >\n {menuItem.label}\n </a>\n ))}\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : (\n <BreadcrumbLink href={item.href}>\n {item.label}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </>\n )\n })\n }\n {\n breadcrumb.menu.length > 0 && currentPath === \"/\" && (\n <>\n <BreadcrumbSeparator>/</BreadcrumbSeparator>\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger class=\"hover:text-foreground inline-flex items-center leading-none transition-colors\">\n <BreadcrumbEllipsis />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuGroup>\n {breadcrumb.menu.map((item) => (\n <a\n href={item.href}\n class=\"hover:bg-accent hover:text-accent-foreground flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none\"\n >\n {item.label}\n </a>\n ))}\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n </>\n )\n }\n </BreadcrumbList>\n </Breadcrumb>\n </HeaderGroup>\n <HeaderGroup class=\"shrink-0\">\n <Button\n as=\"a\"\n href={`https://github.com/${githubRepo}`}\n size=\"sm\"\n variant=\"ghost\"\n target=\"_blank\"\n rel=\"noreferrer\"\n aria-label={`View ${githubRepo} on GitHub`}\n >\n <Icon name=\"github\" />\n <span class=\"hidden sm:inline\">{githubStars}</span>\n </Button>\n <ThemeToggle />\n </HeaderGroup>\n </HeaderContainer>\n </Header>\n <slot />\n </SidebarInset>\n</SidebarProvider>\n\n<script>\n const isMac = /Mac|iPhone|iPad|iPod/i.test(\n navigator.platform || navigator.userAgent\n )\n\n document.querySelectorAll(\"[data-search-shortcut]\").forEach((shortcut) => {\n shortcut.textContent = isMac ? \"⌘ + K\" : \"Ctrl + K\"\n })\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key.toLowerCase() !== \"k\") return\n if (event.shiftKey || event.altKey) return\n\n const dialog = document.querySelector(\"[data-search-dialog]\")\n const isSearchShortcut = isMac\n ? event.metaKey && !event.ctrlKey\n : event.ctrlKey && !event.metaKey\n\n if (!dialog || dialog.hasAttribute(\"data-open\") || !isSearchShortcut) return\n\n event.preventDefault()\n dialog.dispatchEvent(\n new CustomEvent(\"dialog:set\", { detail: { open: true } })\n )\n })\n</script>\n",
|
|
27
27
|
"type": "registry:block"
|
|
28
28
|
}
|
|
29
29
|
],
|
package/public/r/typography.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": "src/components/ui/typography/typography.astro",
|
|
9
|
-
"content": "---\nimport type { HTMLTag, Polymorphic } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype Size = \"sm\" | \"default\" | \"lg\"\ntype Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag; size?: Size }>\n\nconst {\n as: Tag = \"div\",\n class: className,\n size = \"default\",\n ...props\n} = Astro.props\n---\n\n<Tag\n data-slot=\"typography\"\n data-size={size}\n class={cn(\"text-foreground text-base\", className)}\n {...props}\n>\n <slot />\n</Tag>\n\n<style is:global>\n @reference \"@/styles/global.css\";\n\n [data-slot=\"typography\"]\n > :is(\n [data-slot=\"typography-lead\"],\n [data-slot=\"typography-table-container\"],\n div,\n section,\n article,\n aside,\n nav,\n figure,\n details,\n pre,\n small,\n dl,\n img,\n picture,\n video,\n iframe\n ):not(:first-child) {\n @apply mt-6;\n }\n\n [data-slot=\"typography\"] > h1 {\n @apply scroll-m-20 text-4xl font-semibold tracking-tight text-balance;\n }\n\n [data-slot=\"typography\"] > h2 {\n @apply scroll-m-20 text-3xl font-semibold tracking-tight;\n }\n\n [data-slot=\"typography\"] > h2:first-child {\n @apply mt-0;\n }\n\n [data-slot=\"typography\"] > h2:not(:first-child) {\n @apply mt-10;\n }\n\n [data-slot=\"typography\"] > h3 {\n @apply scroll-m-20 text-2xl font-semibold tracking-tight;\n }\n\n [data-slot=\"typography\"] > h3:not(:first-child) {\n @apply mt-8;\n }\n\n [data-slot=\"typography\"] > h4 {\n @apply scroll-m-20 text-xl font-semibold tracking-tight;\n }\n\n [data-slot=\"typography\"] > h4:not(:first-child) {\n @apply mt-8;\n }\n\n [data-slot=\"typography\"]\n > :is(h1, h2, h3, h4)\n + :is(\n [data-slot=\"typography-lead\"],\n [data-slot=\"typography-table-container\"],\n div,\n section,\n article,\n aside,\n nav,\n figure,\n details,\n p,\n blockquote,\n pre,\n ul,\n ol,\n table,\n small,\n dl,\n img,\n picture,\n video,\n iframe\n ) {\n @apply mt-4;\n }\n\n [data-slot=\"typography\"] > p {\n @apply text-base leading-7;\n }\n\n [data-slot=\"typography\"] > p:not(:first-child) {\n @apply mt-6;\n }\n\n [data-slot=\"typography\"]\n > :is(h1, h2, h3, h4)\n + :is(p, [data-slot=\"typography-lead\"]):not(:first-child) {\n @apply mt-4;\n }\n\n [data-slot=\"typography\"] > a:not([data-slot]),\n [data-slot=\"typography\"]\n > :is(p, blockquote, ul, ol, dl, table)\n a:not([data-slot]) {\n @apply text-
|
|
9
|
+
"content": "---\nimport type { HTMLTag, Polymorphic } from \"astro/types\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype Size = \"sm\" | \"default\" | \"lg\"\ntype Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag; size?: Size }>\n\nconst {\n as: Tag = \"div\",\n class: className,\n size = \"default\",\n ...props\n} = Astro.props\n---\n\n<Tag\n data-slot=\"typography\"\n data-size={size}\n class={cn(\"text-foreground text-base\", className)}\n {...props}\n>\n <slot />\n</Tag>\n\n<style is:global>\n @reference \"@/styles/global.css\";\n\n [data-slot=\"typography\"]\n > :is(\n [data-slot=\"typography-lead\"],\n [data-slot=\"typography-table-container\"],\n div,\n section,\n article,\n aside,\n nav,\n figure,\n details,\n pre,\n small,\n dl,\n img,\n picture,\n video,\n iframe\n ):not(:first-child) {\n @apply mt-6;\n }\n\n [data-slot=\"typography\"] > h1 {\n @apply scroll-m-20 text-4xl font-semibold tracking-tight text-balance;\n }\n\n [data-slot=\"typography\"] > h2 {\n @apply scroll-m-20 text-3xl font-semibold tracking-tight;\n }\n\n [data-slot=\"typography\"] > h2:first-child {\n @apply mt-0;\n }\n\n [data-slot=\"typography\"] > h2:not(:first-child) {\n @apply mt-10;\n }\n\n [data-slot=\"typography\"] > h3 {\n @apply scroll-m-20 text-2xl font-semibold tracking-tight;\n }\n\n [data-slot=\"typography\"] > h3:not(:first-child) {\n @apply mt-8;\n }\n\n [data-slot=\"typography\"] > h4 {\n @apply scroll-m-20 text-xl font-semibold tracking-tight;\n }\n\n [data-slot=\"typography\"] > h4:not(:first-child) {\n @apply mt-8;\n }\n\n [data-slot=\"typography\"]\n > :is(h1, h2, h3, h4)\n + :is(\n [data-slot=\"typography-lead\"],\n [data-slot=\"typography-table-container\"],\n div,\n section,\n article,\n aside,\n nav,\n figure,\n details,\n p,\n blockquote,\n pre,\n ul,\n ol,\n table,\n small,\n dl,\n img,\n picture,\n video,\n iframe\n ) {\n @apply mt-4;\n }\n\n [data-slot=\"typography\"] > p {\n @apply text-base leading-7;\n }\n\n [data-slot=\"typography\"] > p:not(:first-child) {\n @apply mt-6;\n }\n\n [data-slot=\"typography\"]\n > :is(h1, h2, h3, h4)\n + :is(p, [data-slot=\"typography-lead\"]):not(:first-child) {\n @apply mt-4;\n }\n\n [data-slot=\"typography\"] > a:not([data-slot]),\n [data-slot=\"typography\"]\n > :is(p, blockquote, ul, ol, dl, table)\n a:not([data-slot]) {\n @apply text-foreground font-medium underline underline-offset-4;\n }\n\n [data-slot=\"typography\"] > blockquote {\n @apply mt-6 border-l-2 pl-6 text-base italic;\n }\n\n [data-slot=\"typography\"] > hr {\n @apply border-border my-8;\n }\n\n [data-slot=\"typography\"] > pre {\n @apply border-border bg-muted/60 overflow-x-auto rounded-xl border p-4 text-sm;\n }\n\n [data-slot=\"typography\"] > .docs-code-block {\n @apply border-border bg-muted/60 relative overflow-hidden rounded-xl border;\n }\n\n [data-slot=\"typography\"] > .docs-code-block > pre,\n [data-slot=\"typography\"] > .docs-code-block > pre.astro-code {\n @apply m-0 rounded-none border-0 !bg-transparent p-4 pr-14 text-sm leading-[var(--text-sm--line-height)];\n font-family: var(--font-mono);\n }\n\n [data-slot=\"typography\"] > .docs-code-block > pre.astro-code code {\n @apply text-sm leading-[var(--text-sm--line-height)] !text-[var(--shiki-light,var(--foreground))];\n }\n\n .dark [data-slot=\"typography\"] > .docs-code-block > pre.astro-code code {\n @apply !text-[var(--shiki-dark,var(--foreground))];\n }\n\n .dark\n [data-slot=\"typography\"]\n > .docs-code-block\n > pre.astro-code\n span[style*=\"--shiki-dark\"] {\n @apply ![font-weight:var(--shiki-dark-font-weight,inherit)] !text-[var(--shiki-dark)] ![font-style:var(--shiki-dark-font-style,inherit)] ![text-decoration:var(--shiki-dark-text-decoration,inherit)];\n }\n\n [data-slot=\"typography\"] > .docs-code-block > .docs-code-copy {\n @apply border-border bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground absolute top-3 right-3 z-10 inline-flex size-8 items-center justify-center rounded-md border shadow-sm transition-colors;\n }\n\n [data-slot=\"typography\"] > .docs-code-block svg {\n @apply size-4;\n }\n\n [data-slot=\"typography\"] > ul,\n [data-slot=\"typography\"] > ol {\n @apply my-6 ml-6 text-base;\n }\n\n [data-slot=\"typography\"] > ul {\n @apply list-disc;\n }\n\n [data-slot=\"typography\"] > ol {\n @apply list-decimal;\n }\n\n [data-slot=\"typography\"] > ul > li,\n [data-slot=\"typography\"] > ol > li {\n @apply mt-2;\n }\n\n [data-slot=\"typography\"] > [data-slot=\"typography-lead\"] {\n @apply text-muted-foreground;\n }\n\n [data-slot=\"typography\"][data-size=\"sm\"] > [data-slot=\"typography-lead\"] {\n @apply text-base;\n }\n\n [data-slot=\"typography\"] > [data-slot=\"typography-lead\"],\n [data-slot=\"typography\"][data-size=\"default\"]\n > [data-slot=\"typography-lead\"] {\n @apply text-lg;\n }\n\n [data-slot=\"typography\"][data-size=\"lg\"] > [data-slot=\"typography-lead\"] {\n @apply text-xl;\n }\n\n [data-slot=\"typography\"] > small {\n @apply block leading-none font-medium;\n }\n\n [data-slot=\"typography\"] > small {\n @apply text-sm;\n }\n\n [data-slot=\"typography\"] > table {\n @apply border-border my-6 block w-full overflow-x-auto rounded-lg border;\n border-collapse: separate;\n border-spacing: 0;\n }\n\n [data-slot=\"typography\"] > table th,\n [data-slot=\"typography\"] > table td {\n @apply border-border border-b px-4 py-2 text-left align-top whitespace-nowrap;\n }\n\n [data-slot=\"typography\"] > table th {\n @apply text-foreground bg-muted/40 font-medium;\n }\n\n [data-slot=\"typography\"] > table tr:last-child td {\n @apply border-b-0;\n }\n\n [data-slot=\"typography\"] > table thead,\n [data-slot=\"typography\"] > table tbody,\n [data-slot=\"typography\"] > table tr {\n @apply w-full;\n }\n\n [data-slot=\"typography\"] > table tr {\n @apply grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)];\n }\n\n [data-slot=\"typography\"] > table tr {\n @apply even:bg-muted/40 m-0 border-t p-0 first:border-t-0;\n }\n\n [data-slot=\"typography\"] > table th {\n @apply border-r px-4 py-2 text-left font-bold last:border-r-0;\n }\n\n [data-slot=\"typography\"] > table th[align=\"center\"] {\n @apply text-center;\n }\n\n [data-slot=\"typography\"] > table th[align=\"right\"] {\n @apply text-right;\n }\n\n [data-slot=\"typography\"] > table td {\n @apply border-r px-4 py-2 text-left last:border-r-0;\n }\n\n [data-slot=\"typography\"] > table td[align=\"center\"] {\n @apply text-center;\n }\n\n [data-slot=\"typography\"] > table td[align=\"right\"] {\n @apply text-right;\n }\n\n [data-slot=\"typography\"] > table tbody tr:last-child td {\n @apply border-b-0;\n }\n\n [data-slot=\"typography\"] :not(pre) > code {\n @apply bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold;\n }\n\n [data-slot=\"typography\"] > table :not(pre) > code {\n @apply rounded-md text-sm leading-5 font-normal;\n }\n\n [data-slot=\"typography\"] > pre.astro-code {\n @apply border-border !bg-muted/60 rounded-xl border p-4 text-sm leading-[var(--text-sm--line-height)];\n }\n\n [data-slot=\"typography\"] > pre.astro-code code {\n @apply !text-inherit;\n }\n\n .dark [data-slot=\"typography\"] > pre.astro-code {\n @apply !text-[var(--shiki-dark,var(--foreground))];\n }\n\n .dark [data-slot=\"typography\"] > pre.astro-code span[style*=\"--shiki-dark\"] {\n @apply ![font-weight:var(--shiki-dark-font-weight,inherit)] !text-[var(--shiki-dark)] ![font-style:var(--shiki-dark-font-style,inherit)] ![text-decoration:var(--shiki-dark-text-decoration,inherit)];\n }\n</style>\n",
|
|
10
10
|
"type": "registry:ui"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
@@ -21,19 +21,22 @@ const { class: className, title, description, buttons, ...props } = Astro.props
|
|
|
21
21
|
<Banner
|
|
22
22
|
variant="floating"
|
|
23
23
|
storageKey="banner-2"
|
|
24
|
-
class={cn("", className)}
|
|
24
|
+
class={cn("@container", className)}
|
|
25
25
|
{...props}
|
|
26
26
|
>
|
|
27
|
-
<BannerContainer
|
|
27
|
+
<BannerContainer
|
|
28
|
+
class="flex-col items-start gap-4 py-1 @2xl:flex-row @2xl:items-center"
|
|
29
|
+
showClose={false}
|
|
30
|
+
>
|
|
28
31
|
<div
|
|
29
|
-
class="flex flex-1 flex-col gap-0.5 @5xl:flex-row @5xl:items-center @5xl:gap-x-4"
|
|
32
|
+
class="flex min-w-0 flex-1 flex-col gap-0.5 @5xl:flex-row @5xl:items-center @5xl:gap-x-4"
|
|
30
33
|
>
|
|
31
34
|
<p class="text-sm font-semibold">{title}</p>
|
|
32
35
|
<p class="text-muted-foreground text-sm">{description}</p>
|
|
33
36
|
</div>
|
|
34
37
|
{
|
|
35
38
|
buttons?.length && (
|
|
36
|
-
<div class="flex
|
|
39
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
37
40
|
{buttons.map(({ href, label, ...button }, index) => (
|
|
38
41
|
<Button
|
|
39
42
|
as="a"
|
|
@@ -87,10 +87,11 @@ const formId = form.id ?? `contact-${crypto.randomUUID()}`
|
|
|
87
87
|
</Button>
|
|
88
88
|
) : (
|
|
89
89
|
<Button
|
|
90
|
+
as="span"
|
|
90
91
|
variant="secondary"
|
|
91
92
|
size="icon"
|
|
92
93
|
class="text-primary"
|
|
93
|
-
aria-
|
|
94
|
+
aria-hidden="true"
|
|
94
95
|
>
|
|
95
96
|
<Icon name={item.icon} />
|
|
96
97
|
</Button>
|
|
@@ -142,10 +142,11 @@ const formId = form.id ?? `contact-${crypto.randomUUID()}`
|
|
|
142
142
|
</Button>
|
|
143
143
|
) : (
|
|
144
144
|
<Button
|
|
145
|
+
as="span"
|
|
145
146
|
variant="secondary"
|
|
146
147
|
size="icon"
|
|
147
148
|
class="text-primary shrink-0"
|
|
148
|
-
aria-
|
|
149
|
+
aria-hidden="true"
|
|
149
150
|
>
|
|
150
151
|
<Icon name={item.icon} />
|
|
151
152
|
</Button>
|
|
@@ -91,10 +91,11 @@ const formId = form.id ?? `contact-${crypto.randomUUID()}`
|
|
|
91
91
|
</Button>
|
|
92
92
|
) : (
|
|
93
93
|
<Button
|
|
94
|
+
as="span"
|
|
94
95
|
variant="secondary"
|
|
95
96
|
size="icon"
|
|
96
97
|
class="text-primary shrink-0"
|
|
97
|
-
aria-
|
|
98
|
+
aria-hidden="true"
|
|
98
99
|
>
|
|
99
100
|
<Icon name={item.icon} />
|
|
100
101
|
</Button>
|
|
@@ -325,7 +325,7 @@ try {
|
|
|
325
325
|
</BreadcrumbList>
|
|
326
326
|
</Breadcrumb>
|
|
327
327
|
</HeaderGroup>
|
|
328
|
-
<HeaderGroup>
|
|
328
|
+
<HeaderGroup class="shrink-0">
|
|
329
329
|
<Button
|
|
330
330
|
as="a"
|
|
331
331
|
href={`https://github.com/${githubRepo}`}
|
|
@@ -336,7 +336,7 @@ try {
|
|
|
336
336
|
aria-label={`View ${githubRepo} on GitHub`}
|
|
337
337
|
>
|
|
338
338
|
<Icon name="github" />
|
|
339
|
-
<span>{githubStars}</span>
|
|
339
|
+
<span class="hidden sm:inline">{githubStars}</span>
|
|
340
340
|
</Button>
|
|
341
341
|
<ThemeToggle />
|
|
342
342
|
</HeaderGroup>
|
|
@@ -35,51 +35,33 @@ const { class: className, variant, storageKey, ...props } = Astro.props
|
|
|
35
35
|
<slot />
|
|
36
36
|
</aside>
|
|
37
37
|
|
|
38
|
-
<script
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
if (!document.documentElement.dataset[initializedKey]) {
|
|
42
|
-
document.documentElement.dataset[initializedKey] = "true"
|
|
43
|
-
|
|
44
|
-
const getStorageToken = (key) => `banner:${key}`
|
|
45
|
-
|
|
46
|
-
const syncBanners = () => {
|
|
47
|
-
document.querySelectorAll("[data-slot='banner']").forEach((banner) => {
|
|
48
|
-
if (!(banner instanceof HTMLElement)) return
|
|
49
|
-
|
|
50
|
-
const storageKey = banner.dataset.bannerStorageKey
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
storageKey &&
|
|
54
|
-
sessionStorage.getItem(getStorageToken(storageKey)) === "hidden"
|
|
55
|
-
) {
|
|
56
|
-
banner.hidden = true
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
syncBanners()
|
|
62
|
-
|
|
63
|
-
document.addEventListener("click", (event) => {
|
|
64
|
-
const target = event.target
|
|
65
|
-
|
|
66
|
-
if (!(target instanceof Element)) return
|
|
67
|
-
|
|
68
|
-
const closeButton = target.closest("[data-slot='banner-close']")
|
|
69
|
-
|
|
70
|
-
if (!(closeButton instanceof HTMLElement)) return
|
|
71
|
-
|
|
72
|
-
const banner = closeButton.closest("[data-slot='banner']")
|
|
38
|
+
<script>
|
|
39
|
+
const getStorageToken = (key: string) => `banner:${key}`
|
|
73
40
|
|
|
41
|
+
const syncBanners = () => {
|
|
42
|
+
document.querySelectorAll("[data-slot='banner']").forEach((banner) => {
|
|
74
43
|
if (!(banner instanceof HTMLElement)) return
|
|
75
|
-
|
|
76
|
-
banner.hidden = true
|
|
77
|
-
|
|
78
44
|
const storageKey = banner.dataset.bannerStorageKey
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
sessionStorage.
|
|
45
|
+
if (
|
|
46
|
+
storageKey &&
|
|
47
|
+
sessionStorage.getItem(getStorageToken(storageKey)) === "hidden"
|
|
48
|
+
) {
|
|
49
|
+
banner.hidden = true
|
|
82
50
|
}
|
|
83
51
|
})
|
|
84
52
|
}
|
|
53
|
+
|
|
54
|
+
syncBanners()
|
|
55
|
+
document.addEventListener("astro:page-load", syncBanners)
|
|
56
|
+
|
|
57
|
+
document.addEventListener("click", (event) => {
|
|
58
|
+
if (!(event.target instanceof Element)) return
|
|
59
|
+
const closeButton = event.target.closest("[data-slot='banner-close']")
|
|
60
|
+
const banner = closeButton?.closest("[data-slot='banner']")
|
|
61
|
+
if (!(banner instanceof HTMLElement)) return
|
|
62
|
+
banner.hidden = true
|
|
63
|
+
const storageKey = banner.dataset.bannerStorageKey
|
|
64
|
+
if (storageKey)
|
|
65
|
+
sessionStorage.setItem(getStorageToken(storageKey), "hidden")
|
|
66
|
+
})
|
|
85
67
|
</script>
|
|
@@ -126,7 +126,7 @@ const {
|
|
|
126
126
|
[data-slot="typography"]
|
|
127
127
|
> :is(p, blockquote, ul, ol, dl, table)
|
|
128
128
|
a:not([data-slot]) {
|
|
129
|
-
@apply text-
|
|
129
|
+
@apply text-foreground font-medium underline underline-offset-4;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
[data-slot="typography"] > blockquote {
|
package/src/styles/global.css
CHANGED
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
--popover: oklch(0.269 0 0);
|
|
69
69
|
--popover-foreground: oklch(0.985 0 0);
|
|
70
70
|
--primary: oklch(0.686 0.2105 41.139);
|
|
71
|
-
--primary-foreground: oklch(
|
|
71
|
+
--primary-foreground: oklch(0.145 0 0);
|
|
72
72
|
--secondary: oklch(0.269 0 0);
|
|
73
73
|
--secondary-foreground: oklch(0.985 0 0);
|
|
74
74
|
--muted: oklch(0.269 0 0);
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
--sidebar: oklch(0.205 0 0);
|
|
89
89
|
--sidebar-foreground: oklch(0.985 0 0);
|
|
90
90
|
--sidebar-primary: oklch(0.686 0.2105 41.139);
|
|
91
|
-
--sidebar-primary-foreground: oklch(
|
|
91
|
+
--sidebar-primary-foreground: oklch(0.145 0 0);
|
|
92
92
|
--sidebar-accent: oklch(0.269 0 0);
|
|
93
93
|
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
94
94
|
--sidebar-border: oklch(0.275 0 0);
|