UNPKG

@voilajsx/uikit

Version:

Cross-platform React components with beautiful themes and OKLCH color science

322 lines (321 loc) 11.5 kB
import { jsx, jsxs, Fragment } from "react/jsx-runtime"; import { createContext, forwardRef, useContext } from "react"; import { cva } from "class-variance-authority"; import { cn } from "./utils.js"; import { Button } from "./button.js"; import { Separator } from "./separator.js"; const FooterContext = createContext({}); const footerVariants = cva( "w-full border-t transition-all duration-200", { variants: { variant: { default: [ "bg-background border-border", "text-foreground" ], muted: [ "bg-muted/30 border-border/50", "text-foreground" ], dark: [ "bg-secondary border-border", "text-secondary-foreground" ] } }, defaultVariants: { variant: "default" } } ); const containerVariants = cva( "mx-auto", { variants: { size: { sm: "max-w-2xl py-4 px-4", md: "max-w-4xl py-5 px-4 sm:px-6", lg: "max-w-6xl py-6 px-4 sm:px-6 lg:px-8", xl: "max-w-7xl py-6 px-4 sm:px-6 lg:px-8", full: "max-w-full py-8 px-4 sm:px-6 lg:px-8" } }, defaultVariants: { size: "xl" } } ); const Footer = forwardRef(({ className, variant = "default", size = "xl", children, ...props }, ref) => { return /* @__PURE__ */ jsx(FooterContext.Provider, { value: { variant, size }, children: /* @__PURE__ */ jsx( "footer", { ref, className: cn(footerVariants({ variant }), className), ...props, children: /* @__PURE__ */ jsx("div", { className: cn(containerVariants({ size })), children }) } ) }); }); Footer.displayName = "Footer"; const FooterBasic = forwardRef(({ className, logo, links = [], social, copyright, ...props }, ref) => { const { variant } = useContext(FooterContext); const getLinkStyles = () => { switch (variant) { case "muted": return "text-muted-foreground hover:text-foreground"; case "dark": return "text-secondary-foreground/70 hover:text-secondary-foreground"; default: return "text-muted-foreground hover:text-foreground"; } }; return /* @__PURE__ */ jsxs( "div", { ref, className: cn("space-y-4", className), ...props, children: [ /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-4", children: [ logo && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: logo }), links.length > 0 && /* @__PURE__ */ jsx("nav", { className: "flex flex-wrap items-center justify-center gap-6", children: links.map((link, index) => /* @__PURE__ */ jsx( "button", { onClick: link.onClick, className: cn( "text-sm transition-colors cursor-pointer", getLinkStyles(), link.className ), children: link.label }, link.key || index )) }), social && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: social }) ] }), copyright && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Separator, {}), /* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx("p", { className: cn( "text-sm", variant === "dark" ? "text-secondary-foreground/60" : "text-muted-foreground" ), children: copyright }) }) ] }) ] } ); }); FooterBasic.displayName = "FooterBasic"; const FooterAdvanced = forwardRef(({ className, brand, columns = [], newsletter, social, legal, copyright, ...props }, ref) => { const { variant } = useContext(FooterContext); const getTextStyles = () => { switch (variant) { case "muted": return { heading: "text-foreground", text: "text-muted-foreground", link: "text-muted-foreground hover:text-foreground" }; case "dark": return { heading: "text-secondary-foreground", text: "text-secondary-foreground/70", link: "text-secondary-foreground/70 hover:text-secondary-foreground" }; default: return { heading: "text-foreground", text: "text-muted-foreground", link: "text-muted-foreground hover:text-foreground" }; } }; const styles = getTextStyles(); const getTotalColumnsCount = () => { let count = 0; if (brand) count += 1; if (columns.length > 0) count += Math.min(columns.length, 4); if (newsletter) count += 1; return Math.min(count, 5); }; const totalColumns = getTotalColumnsCount(); const getMainGridClass = () => { if (totalColumns <= 1) return "lg:grid-cols-1"; if (totalColumns === 2) return "lg:grid-cols-2"; if (totalColumns === 3) return "lg:grid-cols-3"; if (totalColumns === 4) return "lg:grid-cols-4"; return "lg:grid-cols-5"; }; return /* @__PURE__ */ jsxs( "div", { ref, className: cn("space-y-8", className), ...props, children: [ /* @__PURE__ */ jsxs("div", { children: [ /* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6", children: [ brand && /* @__PURE__ */ jsx("div", { className: "space-y-4", children: brand }), columns.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-6", children: columns.slice(0, 4).map((column, index) => /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ jsx("h4", { className: cn("text-sm font-semibold", styles.heading), children: column.title }), /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: column.links?.map((link, linkIndex) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx( "button", { onClick: link.onClick, className: cn( "text-sm transition-colors cursor-pointer block", styles.link, link.className ), children: link.label } ) }, link.key || linkIndex)) }) ] }, column.key || index)) }), newsletter && /* @__PURE__ */ jsx("div", { className: "space-y-4", children: newsletter }) ] }), /* @__PURE__ */ jsx("div", { className: "hidden lg:block", children: /* @__PURE__ */ jsxs("div", { className: cn("grid gap-8", getMainGridClass()), children: [ brand && /* @__PURE__ */ jsx("div", { className: "space-y-4", children: brand }), columns.slice(0, 4).map((column, index) => /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ jsx("h4", { className: cn("text-sm font-semibold", styles.heading), children: column.title }), /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: column.links?.map((link, linkIndex) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx( "button", { onClick: link.onClick, className: cn( "text-sm transition-colors cursor-pointer block", styles.link, link.className ), children: link.label } ) }, link.key || linkIndex)) }) ] }, column.key || index)), newsletter && /* @__PURE__ */ jsx("div", { className: "space-y-4", children: newsletter }) ] }) }) ] }), columns.length > 4 && /* @__PURE__ */ jsx("div", { className: "grid gap-8 grid-cols-1 sm:grid-cols-2 lg:grid-cols-5", children: columns.slice(4).map((column, index) => /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ jsx("h4", { className: cn("text-sm font-semibold", styles.heading), children: column.title }), /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: column.links?.map((link, linkIndex) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx( "button", { onClick: link.onClick, className: cn( "text-sm transition-colors cursor-pointer block", styles.link, link.className ), children: link.label } ) }, link.key || linkIndex)) }) ] }, column.key || index + 4)) }), /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [ /* @__PURE__ */ jsx(Separator, {}), /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-4", children: [ copyright && /* @__PURE__ */ jsx("p", { className: cn("text-sm", styles.text), children: copyright }), legal && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: legal }), social && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: social }) ] }) ] }) ] } ); }); FooterAdvanced.displayName = "FooterAdvanced"; const FooterBrand = forwardRef(({ className, logo, description, contact, ...props }, ref) => { const { variant } = useContext(FooterContext); const textClass = variant === "dark" ? "text-secondary-foreground/70" : "text-muted-foreground"; return /* @__PURE__ */ jsxs( "div", { ref, className: cn("space-y-4", className), ...props, children: [ logo && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: logo }), description && /* @__PURE__ */ jsx("p", { className: cn("text-sm leading-relaxed", textClass), children: description }), contact && /* @__PURE__ */ jsx("div", { className: cn("text-sm", textClass), children: contact }) ] } ); }); FooterBrand.displayName = "FooterBrand"; const FooterSocial = forwardRef(({ className, links = [], ...props }, ref) => { const { variant } = useContext(FooterContext); const getButtonStyles = () => { switch (variant) { case "muted": return "text-muted-foreground hover:text-foreground hover:bg-background/50"; case "dark": return "text-secondary-foreground/70 hover:text-secondary-foreground hover:bg-secondary-foreground/10"; default: return "text-muted-foreground hover:text-foreground hover:bg-muted"; } }; return /* @__PURE__ */ jsx( "div", { ref, className: cn("flex items-center gap-1", className), ...props, children: links.map((link, index) => /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "icon", className: cn("h-8 w-8", getButtonStyles(), link.className), onClick: link.onClick, title: link.label, children: link.icon && /* @__PURE__ */ jsx(link.icon, { className: "h-4 w-4" }) }, link.key || index )) } ); }); FooterSocial.displayName = "FooterSocial"; Footer.Basic = FooterBasic; Footer.Advanced = FooterAdvanced; Footer.Brand = FooterBrand; Footer.Social = FooterSocial; export { Footer, FooterAdvanced, FooterBasic, FooterBrand, FooterSocial, containerVariants, footerVariants }; //# sourceMappingURL=footer.js.map