Breadcrumb && Link added new Components

This commit is contained in:
2025-09-29 18:36:15 +05:30
parent b7446fcd57
commit 3882fdb7ae
5 changed files with 230 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
---
import { Icon } from "astro-icon/components";
interface BreadcrumbItem {
name: string;
icon?: string;
url?: string;
}
const { items, separator = "/" } = Astro.props as {
items: BreadcrumbItem[];
separator?: string;
};
---
<nav
aria-label="Breadcrumb"
class="wr:flex wr:items-center wr:gap-2 wr:text-sm wr:text-gray-600"
>
{
items.map((item, index) => (
<span class="wr:flex wr:items-center wr:gap-3">
{index !== 0 && (
<span class="wr:text-gray-400">{separator}</span>
)}
{index === items.length - 1 || !item.url ? (
<span class="wr:flex wr:items-center wr:gap-2 wr:font-medium wr:text-gray-900 wr:dark:text-white">
{item.icon && (
<Icon name={item.icon} class={`wr:size-4`} />
)}
{item.name}
</span>
) : (
<a
href={item.url}
class="wr:flex wr:items-center wr:gap-2 wr:text-gray-800 wr:dark:text-gray-200 wr:hover:underline wr:hover:text-blue-600 wr:hover:dark:text-blue-400"
>
{item.icon && (
<Icon name={item.icon} class={`wr:size-4`} />
)}
{item.name}
</a>
)}
</span>
))
}
</nav>
+140
View File
@@ -0,0 +1,140 @@
---
import type { HTMLAttributes } from "astro/types";
import { cn } from "../utils/cn";
import { Icon } from "astro-icon/components";
type Variant = "solid" | "outline" | "ghost" | "soft" | "link";
type Color =
| "primary"
| "secondary"
| "tertiary"
| "accent"
| "info"
| "success"
| "warning"
| "danger"
| "neutral";
type Size = "sm" | "md" | "lg" | "icon";
interface Props extends HTMLAttributes<"a"> {
variant?: Variant;
color?: Color;
size?: Size;
pill?: boolean;
icon?: string;
}
const {
variant = "solid",
color = "primary",
size = "md",
pill = false,
icon = "",
class: className,
href = "#",
...rest
}: Props = Astro.props;
const base =
"wr:inline-flex wr:items-center wr:justify-center wr:gap-2 wr:font-medium wr:transition-colors " +
"wr:focus-visible:outline-none wr:focus-visible:ring-2 wr:focus-visible:ring-offset-2 " +
"wr:disabled:opacity-50 wr:disabled:pointer-events-none";
const sizeClass: Record<Size, string> = {
sm: "wr:h-8 wr:px-3 wr:text-sm",
md: "wr:h-10 wr:px-4 wr:text-sm",
lg: "wr:h-11 wr:px-5 wr:text-base",
icon: "wr:h-10 wr:w-10 wr:p-0",
};
const radius = pill ? "wr:rounded-full" : "wr:rounded-md";
const styles: Record<Color, Record<Variant, string>> = {
primary: {
solid: "wr:bg-primary wr:text-primary-foreground wr:hover:bg-primary/90 wr:border wr:border-transparent wr:focus-visible:ring-primary/40",
outline:
"wr:border wr:border-primary wr:text-primary wr:hover:bg-primary/10 wr:focus-visible:ring-primary/40",
ghost: "wr:text-primary wr:hover:bg-primary/10 wr:border wr:border-transparent wr:focus-visible:ring-primary/30",
soft: "wr:bg-primary/15 wr:text-primary wr:hover:bg-primary/20 wr:border wr:border-transparent wr:focus-visible:ring-primary/30",
link: "wr:text-primary wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-primary/40",
},
secondary: {
solid: "wr:bg-secondary wr:text-secondary-foreground wr:hover:bg-secondary/90 wr:border wr:border-transparent wr:focus-visible:ring-secondary/40",
outline:
"wr:border wr:border-secondary wr:text-secondary wr:hover:bg-secondary/10 wr:focus-visible:ring-secondary/40",
ghost: "wr:text-secondary wr:hover:bg-secondary/10 wr:border wr:border-transparent wr:focus-visible:ring-secondary/30",
soft: "wr:bg-secondary/15 wr:text-secondary wr:hover:bg-secondary/20 wr:border wr:border-transparent wr:focus-visible:ring-secondary/30",
link: "wr:text-secondary wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-secondary/40",
},
tertiary: {
solid: "wr:bg-tertiary wr:text-tertiary-foreground wr:hover:bg-tertiary/90 wr:border wr:border-transparent wr:focus-visible:ring-tertiary/40",
outline:
"wr:border wr:border-tertiary wr:text-tertiary wr:hover:bg-tertiary/10 wr:focus-visible:ring-tertiary/40",
ghost: "wr:text-tertiary wr:hover:bg-tertiary/10 wr:border wr:border-transparent wr:focus-visible:ring-tertiary/30",
soft: "wr:bg-tertiary/15 wr:text-tertiary wr:hover:bg-tertiary/20 wr:border wr:border-transparent wr:focus-visible:ring-tertiary/30",
link: "wr:text-tertiary wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-tertiary/40",
},
accent: {
solid: "wr:bg-accent wr:text-accent-foreground wr:hover:bg-accent/90 wr:border wr:border-transparent wr:focus-visible:ring-accent/40",
outline:
"wr:border wr:border-accent wr:text-accent wr:hover:bg-accent/10 wr:focus-visible:ring-accent/40",
ghost: "wr:text-accent wr:hover:bg-accent/10 wr:border wr:border-transparent wr:focus-visible:ring-accent/30",
soft: "wr:bg-accent/15 wr:text-accent wr:hover:bg-accent/20 wr:border wr:border-transparent wr:focus-visible:ring-accent/30",
link: "wr:text-accent wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-accent/40",
},
info: {
solid: "wr:bg-info wr:text-info-foreground wr:hover:bg-info/90 wr:border wr:border-transparent wr:focus-visible:ring-info/40",
outline:
"wr:border wr:border-info wr:text-info wr:hover:bg-info/10 wr:focus-visible:ring-info/40",
ghost: "wr:text-info wr:hover:bg-info/10 wr:border wr:border-transparent wr:focus-visible:ring-info/30",
soft: "wr:bg-info/15 wr:text-info wr:hover:bg-info/20 wr:border wr:border-transparent wr:focus-visible:ring-info/30",
link: "wr:text-info wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-info/40",
},
success: {
solid: "wr:bg-success wr:text-success-foreground wr:hover:bg-success/90 wr:border wr:border-transparent wr:focus-visible:ring-success/40",
outline:
"wr:border wr:border-success wr:text-success wr:hover:bg-success/10 wr:focus-visible:ring-success/40",
ghost: "wr:text-success wr:hover:bg-success/10 wr:border wr:border-transparent wr:focus-visible:ring-success/30",
soft: "wr:bg-success/15 wr:text-success wr:hover:bg-success/20 wr:border wr:border-transparent wr:focus-visible:ring-success/30",
link: "wr:text-success wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-success/40",
},
warning: {
solid: "wr:bg-warning wr:text-warning-foreground wr:hover:bg-warning/90 wr:border wr:border-transparent wr:focus-visible:ring-warning/40",
outline:
"wr:border wr:border-warning wr:text-warning wr:hover:bg-warning/10 wr:focus-visible:ring-warning/40",
ghost: "wr:text-warning wr:hover:bg-warning/10 wr:border wr:border-transparent wr:focus-visible:ring-warning/30",
soft: "wr:bg-warning/14 wr:text-warning wr:hover:bg-warning/20 wr:border wr:border-transparent wr:focus-visible:ring-warning/30",
link: "wr:text-warning wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-warning/40",
},
danger: {
solid: "wr:bg-danger wr:text-danger-foreground wr:hover:bg-danger/90 wr:border wr:border-transparent wr:focus-visible:ring-danger/40",
outline:
"wr:border wr:border-danger wr:text-danger wr:hover:bg-danger/10 wr:focus-visible:ring-danger/40",
ghost: "wr:text-danger wr:hover:bg-danger/10 wr:border wr:border-transparent wr:focus-visible:ring-danger/30",
soft: "wr:bg-danger/15 wr:text-danger wr:hover:bg-danger/20 wr:border wr:border-transparent wr:focus-visible:ring-danger/30",
link: "wr:text-danger wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-danger/40",
},
neutral: {
solid: "wr:bg-neutral wr:text-neutral-foreground wr:hover:bg-neutral/90 wr:border wr:border-transparent wr:focus-visible:ring-neutral/40",
outline:
"wr:border wr:border-neutral wr:text-neutral wr:hover:bg-neutral/10 wr:focus-visible:ring-neutral/40",
ghost: "wr:text-neutral wr:hover:bg-neutral/10 wr:border wr:border-transparent wr:focus-visible:ring-neutral/30",
soft: "wr:bg-neutral/15 wr:text-neutral wr:hover:bg-neutral/20 wr:border wr:border-transparent wr:focus-visible:ring-neutral/30",
link: "wr:text-neutral wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-neutral/40",
},
};
const variantColor = styles[color][variant];
const sizeKls = variant === "link" ? "" : sizeClass[size];
const iconSize =
size === "sm" ? "wr:size-4" : size === "lg" ? "wr:size-5" : "wr:size-5";
---
<a
href={href}
class={cn(base, radius, sizeKls, variantColor, className)}
{...rest}
>
{icon && <Icon name={icon} class={cn(iconSize, "wr:shrink-0")} />}
<slot />
</a>