Add useful components for ui
This commit is contained in:
7
src/components/ui/Background.astro
Normal file
7
src/components/ui/Background.astro
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
const { isDark = false } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class:list={["absolute inset-0", { "bg-dark dark:bg-transparent": isDark }]}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
38
src/components/ui/CTA.astro
Normal file
38
src/components/ui/CTA.astro
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import type { CallToAction } from "~/types";
|
||||||
|
|
||||||
|
const { callToAction } = Astro.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
targetBlank,
|
||||||
|
text = "",
|
||||||
|
icon = "",
|
||||||
|
href = "",
|
||||||
|
} = callToAction as CallToAction;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="flex w-auto">
|
||||||
|
{
|
||||||
|
targetBlank ? (
|
||||||
|
<a
|
||||||
|
class="inline-flex items-center justify-center"
|
||||||
|
href={href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
{icon && (
|
||||||
|
<Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:ml-1 rtl:-mr-1.5" />
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<a class="inline-flex items-center justify-center" href={href}>
|
||||||
|
{text}
|
||||||
|
{icon && (
|
||||||
|
<Icon name={icon} class="w-5 h-5 ml-1 -mr-1.5 rtl:ml-1 rtl:-mr-1.5" />
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
48
src/components/ui/Headline.astro
Normal file
48
src/components/ui/Headline.astro
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
import type { Headline } from "~/types";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
const {
|
||||||
|
title = await Astro.slots.render("title"),
|
||||||
|
subtitle = await Astro.slots.render("subtitle"),
|
||||||
|
tagline,
|
||||||
|
classes = {},
|
||||||
|
} = Astro.props as Headline;
|
||||||
|
|
||||||
|
const {
|
||||||
|
container: containerClass = "max-w-3xl",
|
||||||
|
title: titleClass = "text-3xl md:text-4xl ",
|
||||||
|
subtitle: subtitleClass = "text-xl",
|
||||||
|
} = classes;
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
(title || subtitle || tagline) && (
|
||||||
|
<div
|
||||||
|
class={twMerge("mb-8 md:mx-auto md:mb-12 text-center", containerClass)}
|
||||||
|
>
|
||||||
|
{tagline && (
|
||||||
|
<p
|
||||||
|
class="text-base text-secondary dark:text-blue-200 font-bold tracking-wide uppercase"
|
||||||
|
set:html={tagline}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{title && (
|
||||||
|
<h2
|
||||||
|
class={twMerge(
|
||||||
|
"font-bold leading-tighter tracking-tighter font-heading text-heading text-3xl",
|
||||||
|
titleClass
|
||||||
|
)}
|
||||||
|
set:html={title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{subtitle && (
|
||||||
|
<p
|
||||||
|
class={twMerge("mt-4 text-muted", subtitleClass)}
|
||||||
|
set:html={subtitle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
100
src/components/ui/ItemGrid.astro
Normal file
100
src/components/ui/ItemGrid.astro
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import type { ItemGrid } from "~/types";
|
||||||
|
import CTA from "./CTA.astro";
|
||||||
|
|
||||||
|
const {
|
||||||
|
items = [],
|
||||||
|
columns,
|
||||||
|
defaultIcon = "",
|
||||||
|
classes = {},
|
||||||
|
} = Astro.props as ItemGrid;
|
||||||
|
|
||||||
|
const {
|
||||||
|
container: containerClass = "",
|
||||||
|
// container: containerClass = "md:grid-cols-2",
|
||||||
|
panel: panelClass = "",
|
||||||
|
title: titleClass = "",
|
||||||
|
description: descriptionClass = "",
|
||||||
|
icon: defaultIconClass = "text-primary",
|
||||||
|
} = classes;
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
items && (
|
||||||
|
<div
|
||||||
|
class={twMerge(
|
||||||
|
`grid mx-auto gap-8 gap-y-12 ${
|
||||||
|
columns === 4
|
||||||
|
? "lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2"
|
||||||
|
: columns === 3
|
||||||
|
? "lg:grid-cols-3 sm:grid-cols-2"
|
||||||
|
: columns === 2
|
||||||
|
? "sm:grid-cols-2 "
|
||||||
|
: ""
|
||||||
|
}`,
|
||||||
|
containerClass
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{items.map(
|
||||||
|
({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
icon,
|
||||||
|
callToAction,
|
||||||
|
classes: itemClasses = {},
|
||||||
|
}) => (
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class={twMerge(
|
||||||
|
"flex flex-row max-w-md",
|
||||||
|
panelClass,
|
||||||
|
itemClasses?.panel
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
{(icon || defaultIcon) && (
|
||||||
|
<Icon
|
||||||
|
name={icon || defaultIcon}
|
||||||
|
class={twMerge(
|
||||||
|
"w-7 h-7 mr-2 rtl:mr-0 rtl:ml-2",
|
||||||
|
defaultIconClass,
|
||||||
|
itemClasses?.icon
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class={twMerge(
|
||||||
|
"text-xl font-bold",
|
||||||
|
titleClass,
|
||||||
|
itemClasses?.title
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
{description && (
|
||||||
|
<p
|
||||||
|
class={twMerge(
|
||||||
|
`${title ? "mt-3" : ""} text-muted`,
|
||||||
|
descriptionClass,
|
||||||
|
itemClasses?.description
|
||||||
|
)}
|
||||||
|
set:html={description}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{callToAction && (
|
||||||
|
<div class="mt-2 text-primary cursor-pointer">
|
||||||
|
<CTA callToAction={callToAction} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
94
src/components/ui/ItemGrid2.astro
Normal file
94
src/components/ui/ItemGrid2.astro
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import type { ItemGrid } from "~/types";
|
||||||
|
import CTA from "./CTA.astro";
|
||||||
|
|
||||||
|
const {
|
||||||
|
items = [],
|
||||||
|
columns,
|
||||||
|
defaultIcon = "",
|
||||||
|
classes = {},
|
||||||
|
} = Astro.props as ItemGrid;
|
||||||
|
|
||||||
|
const {
|
||||||
|
container: containerClass = "",
|
||||||
|
// container: containerClass = "sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
||||||
|
panel: panelClass = "",
|
||||||
|
title: titleClass = "",
|
||||||
|
description: descriptionClass = "",
|
||||||
|
icon: defaultIconClass = "text-primary",
|
||||||
|
} = classes;
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
items && (
|
||||||
|
<div
|
||||||
|
class={twMerge(
|
||||||
|
`grid gap-8 gap-x-12 sm:gap-y-8 ${
|
||||||
|
columns === 4
|
||||||
|
? "lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2"
|
||||||
|
: columns === 3
|
||||||
|
? "lg:grid-cols-3 sm:grid-cols-2"
|
||||||
|
: columns === 2
|
||||||
|
? "sm:grid-cols-2 "
|
||||||
|
: ""
|
||||||
|
}`,
|
||||||
|
containerClass
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{items.map(
|
||||||
|
({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
icon,
|
||||||
|
callToAction,
|
||||||
|
classes: itemClasses = {},
|
||||||
|
}) => (
|
||||||
|
<div
|
||||||
|
class={twMerge(
|
||||||
|
"relative flex flex-col",
|
||||||
|
panelClass,
|
||||||
|
itemClasses?.panel
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{(icon || defaultIcon) && (
|
||||||
|
<Icon
|
||||||
|
name={icon || defaultIcon}
|
||||||
|
class={twMerge(
|
||||||
|
"mb-2 w-10 h-10",
|
||||||
|
defaultIconClass,
|
||||||
|
itemClasses?.icon
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
class={twMerge(
|
||||||
|
"text-xl font-bold",
|
||||||
|
titleClass,
|
||||||
|
itemClasses?.title
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
{description && (
|
||||||
|
<p
|
||||||
|
class={twMerge(
|
||||||
|
"text-muted mt-2",
|
||||||
|
descriptionClass,
|
||||||
|
itemClasses?.description
|
||||||
|
)}
|
||||||
|
set:html={description}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{callToAction && (
|
||||||
|
<div class="mt-2 text-primary cursor-pointer">
|
||||||
|
<CTA callToAction={callToAction} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
82
src/components/ui/Timeline.astro
Normal file
82
src/components/ui/Timeline.astro
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon/components";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import type { Item } from "~/types";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
items?: Array<Item>;
|
||||||
|
defaultIcon?: string;
|
||||||
|
classes?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { items = [], classes = {}, defaultIcon } = Astro.props as Props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
container: containerClass = "",
|
||||||
|
panel: panelClass = "",
|
||||||
|
title: titleClass = "",
|
||||||
|
description: descriptionClass = "",
|
||||||
|
icon: defaultIconClass = "text-primary dark:text-slate-200 border-primary dark:border-blue-700",
|
||||||
|
} = classes;
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
items && items.length && (
|
||||||
|
<div class={containerClass}>
|
||||||
|
{items.map(
|
||||||
|
(
|
||||||
|
{ title, description, icon, classes: itemClasses = {} },
|
||||||
|
index = 0
|
||||||
|
) => (
|
||||||
|
<div class={twMerge("flex", panelClass, itemClasses?.panel)}>
|
||||||
|
<div class="flex flex-col items-center mr-4">
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
{(icon || defaultIcon) && (
|
||||||
|
<Icon
|
||||||
|
name={icon || defaultIcon}
|
||||||
|
class={twMerge(
|
||||||
|
"w-10 h-10 p-2 rounded-full border-2",
|
||||||
|
defaultIconClass,
|
||||||
|
itemClasses?.icon
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{index !== items.length - 1 && (
|
||||||
|
<div class="w-px h-full bg-black/10 dark:bg-slate-400/50" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class={`max-w-md pt-1 ${
|
||||||
|
index !== items.length - 1 ? "pb-8" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{title && (
|
||||||
|
<p
|
||||||
|
class={twMerge(
|
||||||
|
"text-xl font-bold",
|
||||||
|
titleClass,
|
||||||
|
itemClasses?.title
|
||||||
|
)}
|
||||||
|
set:html={title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{description && (
|
||||||
|
<p
|
||||||
|
class={twMerge(
|
||||||
|
"text-muted mt-2",
|
||||||
|
descriptionClass,
|
||||||
|
itemClasses?.description
|
||||||
|
)}
|
||||||
|
set:html={description}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
24
src/components/ui/WidgetWrapper.astro
Normal file
24
src/components/ui/WidgetWrapper.astro
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import Background from "./Background.astro";
|
||||||
|
|
||||||
|
const { id, isDark = false, containerClass = "", bg, as = "section" } = Astro.props;
|
||||||
|
|
||||||
|
const WrapperTag = as;
|
||||||
|
---
|
||||||
|
|
||||||
|
<WrapperTag class="relative not-prose" {...id ? { id } : {}}>
|
||||||
|
<div class="absolute inset-0 pointer-events-none -z-[1]" aria-hidden="true">
|
||||||
|
<slot name="bg">
|
||||||
|
{bg ? <Fragment set:html={bg} /> : <Background isDark={isDark} />}
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class:list={[
|
||||||
|
twMerge("relative mx-auto max-w-7xl px-4 md:px-6 py-12 md:py-16 lg:py-20 text-default", containerClass),
|
||||||
|
{ dark: isDark },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</WrapperTag>
|
Reference in New Issue
Block a user