@ugurdemirel/landcraft 0.1.4 → 0.1.9

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 (112) hide show
  1. package/dist/styles.css +12 -0
  2. package/package.json +14 -7
  3. package/src/components/Badge.tsx +0 -68
  4. package/src/components/Blog/BlogCard.tsx +0 -12
  5. package/src/components/Blog/BlogSection.tsx +0 -95
  6. package/src/components/Blog/index.ts +0 -8
  7. package/src/components/Blog/parts.tsx +0 -38
  8. package/src/components/Blog/types.ts +0 -42
  9. package/src/components/Blog/variants/Card.tsx +0 -62
  10. package/src/components/Blog/variants/Row.tsx +0 -41
  11. package/src/components/Button.tsx +0 -113
  12. package/src/components/CTA/CTA.tsx +0 -12
  13. package/src/components/CTA/index.ts +0 -2
  14. package/src/components/CTA/parts.tsx +0 -26
  15. package/src/components/CTA/types.ts +0 -12
  16. package/src/components/CTA/variants/Inverse.tsx +0 -50
  17. package/src/components/CTA/variants/Panel.tsx +0 -60
  18. package/src/components/CTA/variants/Surface.tsx +0 -34
  19. package/src/components/Card.tsx +0 -80
  20. package/src/components/Container.tsx +0 -86
  21. package/src/components/FAQ/FAQ.tsx +0 -48
  22. package/src/components/FAQ/index.ts +0 -2
  23. package/src/components/FAQ/parts.tsx +0 -74
  24. package/src/components/FAQ/types.ts +0 -18
  25. package/src/components/FAQ/variants/Accordion.tsx +0 -46
  26. package/src/components/FAQ/variants/Cards.tsx +0 -40
  27. package/src/components/FAQ/variants/Split.tsx +0 -44
  28. package/src/components/Features/FeatureCard.tsx +0 -44
  29. package/src/components/Features/FeatureGrid.tsx +0 -14
  30. package/src/components/Features/index.ts +0 -3
  31. package/src/components/Features/parts.ts +0 -15
  32. package/src/components/Features/types.ts +0 -25
  33. package/src/components/Features/variants/Bento.tsx +0 -32
  34. package/src/components/Features/variants/Columns.tsx +0 -21
  35. package/src/components/Features/variants/EditorialRows.tsx +0 -38
  36. package/src/components/Footer/Footer.tsx +0 -11
  37. package/src/components/Footer/index.ts +0 -2
  38. package/src/components/Footer/parts.tsx +0 -101
  39. package/src/components/Footer/types.ts +0 -32
  40. package/src/components/Footer/variants/Classic.tsx +0 -59
  41. package/src/components/Footer/variants/Editorial.tsx +0 -47
  42. package/src/components/Footer/variants/Minimal.tsx +0 -33
  43. package/src/components/Hero/Hero.tsx +0 -12
  44. package/src/components/Hero/index.ts +0 -2
  45. package/src/components/Hero/parts.tsx +0 -29
  46. package/src/components/Hero/types.ts +0 -20
  47. package/src/components/Hero/variants/Centered.tsx +0 -54
  48. package/src/components/Hero/variants/Split.tsx +0 -53
  49. package/src/components/Hero/variants/Statement.tsx +0 -60
  50. package/src/components/LanguageSwitcher/LanguageSwitcher.tsx +0 -37
  51. package/src/components/LanguageSwitcher/index.ts +0 -6
  52. package/src/components/LanguageSwitcher/parts.tsx +0 -144
  53. package/src/components/LanguageSwitcher/types.ts +0 -40
  54. package/src/components/LanguageSwitcher/useLanguageSwitcher.ts +0 -23
  55. package/src/components/LanguageSwitcher/variants/Dropdown.tsx +0 -88
  56. package/src/components/LanguageSwitcher/variants/Modal.tsx +0 -56
  57. package/src/components/LogoCloud/LogoCloud.tsx +0 -14
  58. package/src/components/LogoCloud/index.ts +0 -2
  59. package/src/components/LogoCloud/parts.tsx +0 -32
  60. package/src/components/LogoCloud/types.ts +0 -16
  61. package/src/components/LogoCloud/variants/Marquee.tsx +0 -30
  62. package/src/components/LogoCloud/variants/Quiet.tsx +0 -26
  63. package/src/components/LogoCloud/variants/Strip.tsx +0 -25
  64. package/src/components/MegaMenu/MegaMenu.tsx +0 -454
  65. package/src/components/MegaMenu/index.ts +0 -9
  66. package/src/components/MegaMenu/types.ts +0 -56
  67. package/src/components/Modal.tsx +0 -125
  68. package/src/components/Navbar/Navbar.tsx +0 -185
  69. package/src/components/Navbar/index.ts +0 -2
  70. package/src/components/Navbar/types.ts +0 -30
  71. package/src/components/Newsletter/Newsletter.tsx +0 -12
  72. package/src/components/Newsletter/index.ts +0 -2
  73. package/src/components/Newsletter/parts.tsx +0 -23
  74. package/src/components/Newsletter/types.ts +0 -12
  75. package/src/components/Newsletter/useNewsletterForm.ts +0 -27
  76. package/src/components/Newsletter/variants/Card.tsx +0 -62
  77. package/src/components/Newsletter/variants/Inline.tsx +0 -54
  78. package/src/components/Newsletter/variants/Underline.tsx +0 -52
  79. package/src/components/Pricing/Pricing.tsx +0 -37
  80. package/src/components/Pricing/index.ts +0 -2
  81. package/src/components/Pricing/parts.tsx +0 -132
  82. package/src/components/Pricing/types.ts +0 -28
  83. package/src/components/Pricing/variants/Bento.tsx +0 -72
  84. package/src/components/Pricing/variants/Cards.tsx +0 -79
  85. package/src/components/Pricing/variants/Compact.tsx +0 -69
  86. package/src/components/Prose.tsx +0 -55
  87. package/src/components/Section.tsx +0 -106
  88. package/src/components/Slot.tsx +0 -78
  89. package/src/components/Stats/Stats.tsx +0 -16
  90. package/src/components/Stats/index.ts +0 -2
  91. package/src/components/Stats/parts.tsx +0 -29
  92. package/src/components/Stats/types.ts +0 -23
  93. package/src/components/Stats/variants/Cells.tsx +0 -34
  94. package/src/components/Stats/variants/Editorial.tsx +0 -41
  95. package/src/components/Stats/variants/Hairline.tsx +0 -31
  96. package/src/components/Stats/variants/Ticker.tsx +0 -36
  97. package/src/components/Testimonials/TestimonialCard.tsx +0 -61
  98. package/src/components/Testimonials/Testimonials.tsx +0 -14
  99. package/src/components/Testimonials/index.ts +0 -3
  100. package/src/components/Testimonials/parts.ts +0 -7
  101. package/src/components/Testimonials/types.ts +0 -24
  102. package/src/components/Testimonials/variants/Carousel.tsx +0 -94
  103. package/src/components/Testimonials/variants/Grid.tsx +0 -19
  104. package/src/components/Testimonials/variants/Marquee.tsx +0 -28
  105. package/src/icons.tsx +0 -290
  106. package/src/index.ts +0 -120
  107. package/src/styles/index.css +0 -18
  108. package/src/utils/cn.ts +0 -6
  109. package/src/utils/contrast.ts +0 -107
  110. package/src/utils/iso2Flag.ts +0 -26
  111. package/src/utils/useTokenForeground.ts +0 -39
  112. /package/{src/styles → dist}/theme.css +0 -0
@@ -1,50 +0,0 @@
1
- "use client";
2
- import { forwardRef } from "react";
3
- import { cn } from "../../../utils/cn";
4
- import { Container } from "../../Container";
5
- import { useTokenForeground } from "../../../utils/useTokenForeground";
6
- import { CTAActions } from "../parts";
7
- import type { CTAProps } from "../types";
8
-
9
- /** inverse — ink panel with a wide left-aligned split. */
10
- export const CTAInverse = forwardRef<HTMLElement, CTAProps>(
11
- ({ className, title, description, action, secondaryAction, align = "left", id, ...props }, ref) => {
12
- const fg = useTokenForeground("--color-secondary");
13
-
14
- return (
15
- <section ref={ref} id={id} className={cn("w-full py-6 pb-20", className)} {...props}>
16
- <Container>
17
- <div
18
- className="relative overflow-hidden rounded-[1.75rem] px-7 py-16 sm:px-16 sm:py-20"
19
- style={{
20
- backgroundColor: "rgb(var(--color-secondary))",
21
- color: fg,
22
- }}
23
- >
24
- <div aria-hidden className="pointer-events-none absolute inset-0 grain opacity-[0.09] mix-blend-overlay" />
25
- <div
26
- className={cn(
27
- "relative flex flex-col items-start gap-10",
28
- align === "center" && "items-center text-center",
29
- "lg:flex-row lg:items-end lg:justify-between",
30
- )}
31
- >
32
- <div className={cn("max-w-3xl", align === "center" && "mx-auto")}>
33
- <h2 className="font-display text-balance text-4xl font-semibold leading-[1.02] tracking-[-0.03em] sm:text-6xl">
34
- {title}
35
- </h2>
36
- {description ? (
37
- <p className={cn("mt-5 max-w-xl text-pretty text-base leading-7 sm:text-lg", align === "center" && "mx-auto")}>
38
- {description}
39
- </p>
40
- ) : null}
41
- </div>
42
- <CTAActions action={action} secondaryAction={secondaryAction} align={align} />
43
- </div>
44
- </div>
45
- </Container>
46
- </section>
47
- );
48
- },
49
- );
50
- CTAInverse.displayName = "CTAInverse";
@@ -1,60 +0,0 @@
1
- "use client";
2
- import { forwardRef } from "react";
3
- import { cn } from "../../../utils/cn";
4
- import { Container } from "../../Container";
5
- import { useTokenForeground } from "../../../utils/useTokenForeground";
6
- import { CTAActions } from "../parts";
7
- import type { CTAProps } from "../types";
8
-
9
- /** panel — brand gradient panel, rounded corners. */
10
- export const CTAPanel = forwardRef<HTMLElement, CTAProps>(
11
- ({ className, title, description, action, secondaryAction, align = "left", id, ...props }, ref) => {
12
- const fg = useTokenForeground("--color-primary");
13
-
14
- return (
15
- <section ref={ref} id={id} className={cn("w-full py-6 pb-20", className)} {...props}>
16
- <Container>
17
- <div
18
- className="relative overflow-hidden rounded-[1.75rem] px-7 py-14 sm:px-14 sm:py-20"
19
- style={{
20
- background:
21
- "radial-gradient(120% 160% at 0% 0%, rgb(var(--color-primary)), rgb(var(--color-primary-hover)) 55%, rgb(var(--color-primary) / 0.85))",
22
- color: fg,
23
- }}
24
- >
25
- <div aria-hidden className="pointer-events-none absolute inset-0 grain opacity-[0.07] mix-blend-overlay" />
26
- <div
27
- aria-hidden
28
- className="pointer-events-none absolute -right-24 -top-24 h-72 w-72 rounded-full"
29
- style={{ background: "rgb(var(--color-accent))", opacity: 0.35, filter: "blur(60px)" }}
30
- />
31
- <div
32
- className={cn(
33
- "relative flex flex-col gap-9",
34
- align === "center" ? "items-center text-center" : "items-start",
35
- )}
36
- >
37
- <div className={cn("max-w-2xl", align === "center" && "mx-auto")}>
38
- <h2 className="font-display text-balance text-3xl font-semibold leading-[1.06] tracking-[-0.02em] sm:text-5xl">
39
- {title}
40
- </h2>
41
- {description ? (
42
- <p
43
- className={cn(
44
- "mt-4 text-pretty text-base leading-7 sm:text-lg",
45
- align === "center" && "mx-auto max-w-xl",
46
- )}
47
- >
48
- {description}
49
- </p>
50
- ) : null}
51
- </div>
52
- <CTAActions action={action} secondaryAction={secondaryAction} align={align} />
53
- </div>
54
- </div>
55
- </Container>
56
- </section>
57
- );
58
- },
59
- );
60
- CTAPanel.displayName = "CTAPanel";
@@ -1,34 +0,0 @@
1
- import { forwardRef } from "react";
2
- import { cn } from "../../../utils/cn";
3
- import { Container } from "../../Container";
4
- import { CTAActions } from "../parts";
5
- import type { CTAProps } from "../types";
6
-
7
- /** surface — quiet paper band: hairline rule, big display type, actions right. */
8
- export const CTASurface = forwardRef<HTMLElement, CTAProps>(
9
- ({ className, title, description, action, secondaryAction, align = "left", id, ...props }, ref) => (
10
- <section ref={ref} id={id} className={cn("w-full", className)} {...props}>
11
- <Container className="py-20 sm:py-24">
12
- <div
13
- className={cn(
14
- "flex flex-col gap-10 border-t border-border pt-14 sm:flex-row sm:items-end sm:justify-between sm:pt-16",
15
- align === "center" && "items-center text-center sm:flex-col sm:items-center",
16
- )}
17
- >
18
- <div className={cn("max-w-3xl", align === "center" && "mx-auto")}>
19
- <h2 className="font-display text-4xl font-semibold leading-[1.03] tracking-[-0.03em] text-balance text-foreground sm:text-6xl">
20
- {title}
21
- </h2>
22
- {description ? (
23
- <p className={cn("mt-5 max-w-xl text-pretty text-base leading-7 text-muted-foreground sm:text-lg", align === "center" && "mx-auto")}>
24
- {description}
25
- </p>
26
- ) : null}
27
- </div>
28
- <CTAActions action={action} secondaryAction={secondaryAction} align={align} />
29
- </div>
30
- </Container>
31
- </section>
32
- ),
33
- );
34
- CTASurface.displayName = "CTASurface";
@@ -1,80 +0,0 @@
1
- import { forwardRef, type HTMLAttributes, type ReactNode } from "react";
2
- import { cn } from "../utils/cn";
3
-
4
- export type CardVariant = "outlined" | "elevated" | "inset";
5
-
6
- export interface CardProps extends HTMLAttributes<HTMLDivElement> {
7
- variant?: CardVariant;
8
- /** Softens the whole card with hover lift + border tint. */
9
- interactive?: boolean;
10
- }
11
-
12
- const variants: Record<CardVariant, string> = {
13
- outlined: "border border-border bg-surface",
14
- elevated: "border border-border bg-surface shadow-soft",
15
- inset: "bg-surface-strong",
16
- };
17
-
18
- export const Card = forwardRef<HTMLDivElement, CardProps>(
19
- ({ className, variant = "outlined", interactive = false, ...props }, ref) => (
20
- <div
21
- ref={ref}
22
- className={cn(
23
- "rounded-xl transition-[border-color,box-shadow,transform] duration-200",
24
- variants[variant],
25
- interactive &&
26
- "cursor-pointer hover:-translate-y-0.5 hover:border-foreground/20 hover:shadow-raised",
27
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
28
- className,
29
- )}
30
- {...props}
31
- />
32
- ),
33
- );
34
- Card.displayName = "Card";
35
-
36
- export interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {
37
- icon?: ReactNode;
38
- }
39
-
40
- export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
41
- ({ className, icon, children, ...props }, ref) => (
42
- <div ref={ref} className={cn("flex flex-col gap-2 p-6 pb-0", className)} {...props}>
43
- {icon ? <div className="mb-1.5">{icon}</div> : null}
44
- {children}
45
- </div>
46
- ),
47
- );
48
- CardHeader.displayName = "CardHeader";
49
-
50
- export const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement>>(
51
- ({ className, ...props }, ref) => (
52
- <h3
53
- ref={ref}
54
- className={cn("font-display text-lg font-semibold tracking-tight text-foreground", className)}
55
- {...props}
56
- />
57
- ),
58
- );
59
- CardTitle.displayName = "CardTitle";
60
-
61
- export const CardDescription = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(
62
- ({ className, ...props }, ref) => (
63
- <p ref={ref} className={cn("text-sm leading-6 text-muted-foreground", className)} {...props} />
64
- ),
65
- );
66
- CardDescription.displayName = "CardDescription";
67
-
68
- export const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
69
- ({ className, ...props }, ref) => (
70
- <div ref={ref} className={cn("p-6 pt-5", className)} {...props} />
71
- ),
72
- );
73
- CardContent.displayName = "CardContent";
74
-
75
- export const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
76
- ({ className, ...props }, ref) => (
77
- <div ref={ref} className={cn("flex items-center gap-3 border-t border-border/70 p-6 pt-5", className)} {...props} />
78
- ),
79
- );
80
- CardFooter.displayName = "CardFooter";
@@ -1,86 +0,0 @@
1
- import { forwardRef, type ElementType, type HTMLAttributes } from "react";
2
- import { cn } from "../utils/cn";
3
-
4
- export type ContainerSize = "sm" | "md" | "lg" | "xl" | "full";
5
-
6
- export interface ContainerProps extends HTMLAttributes<HTMLElement> {
7
- /** Render as a specific element (section, header, …). */
8
- as?: ElementType;
9
- /**
10
- * Maximum content width:
11
- * `sm` → prose · `md` → reading · `lg` → plans/splits ·
12
- * `xl` → default marketing page · `full` → edge-to-edge.
13
- */
14
- size?: ContainerSize;
15
- /** Responsive gutters (px-5 / sm:px-8). Disable for flush content. */
16
- gutters?: boolean;
17
- }
18
-
19
- const sizes: Record<Exclude<ContainerSize, "full">, string> = {
20
- sm: "max-w-xl",
21
- md: "max-w-3xl",
22
- lg: "max-w-5xl",
23
- xl: "max-w-6xl",
24
- };
25
-
26
- /**
27
- * Shared layout wrapper — the single source of the container + gutter rules
28
- * used across Section, Footer, CTA, templates…
29
- */
30
- export const Container = forwardRef<HTMLElement, ContainerProps>(
31
- ({ className, as, size = "xl", gutters = true, ...props }, ref) => {
32
- const Tag = (as ?? "div") as ElementType;
33
- return (
34
- <Tag
35
- ref={ref as never}
36
- className={cn(
37
- "mx-auto w-full",
38
- size !== "full" && sizes[size],
39
- gutters && "px-5 sm:px-8",
40
- className,
41
- )}
42
- {...props}
43
- />
44
- );
45
- },
46
- );
47
- Container.displayName = "Container";
48
-
49
- export type StackGap = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20;
50
-
51
- const gaps: Record<StackGap, string> = {
52
- 0: "gap-0",
53
- 1: "gap-1",
54
- 2: "gap-2",
55
- 3: "gap-3",
56
- 4: "gap-4",
57
- 5: "gap-5",
58
- 6: "gap-6",
59
- 8: "gap-8",
60
- 10: "gap-10",
61
- 12: "gap-12",
62
- 16: "gap-16",
63
- 20: "gap-20",
64
- };
65
-
66
- export interface StackProps extends HTMLAttributes<HTMLDivElement> {
67
- gap?: StackGap;
68
- horizontal?: boolean;
69
- }
70
-
71
- /** Vertical (or horizontal) rhythm helper using flex gaps. */
72
- export const Stack = forwardRef<HTMLDivElement, StackProps>(
73
- ({ className, gap = 4, horizontal = false, ...props }, ref) => (
74
- <div
75
- ref={ref}
76
- className={cn(
77
- "flex",
78
- horizontal ? "flex-row flex-wrap items-center" : "flex-col",
79
- gaps[gap],
80
- className,
81
- )}
82
- {...props}
83
- />
84
- ),
85
- );
86
- Stack.displayName = "Stack";
@@ -1,48 +0,0 @@
1
- import type { FAQProps } from "./types";
2
- import { FaqCards } from "./variants/Cards";
3
- import { FaqAccordion } from "./variants/Accordion";
4
- import { FaqSplit } from "./variants/Split";
5
-
6
- export const FAQ = ({
7
- className,
8
- items,
9
- option = "accordion",
10
- allowMultiple = false,
11
- defaultOpen = [],
12
- eyebrow,
13
- title,
14
- description,
15
- ...props
16
- }: FAQProps) => {
17
- if (option === "cards") {
18
- return <FaqCards className={className} items={items} eyebrow={eyebrow} {...props} />;
19
- }
20
-
21
- if (option === "split") {
22
- return (
23
- <FaqSplit
24
- className={className}
25
- items={items}
26
- allowMultiple={allowMultiple}
27
- defaultOpen={defaultOpen}
28
- eyebrow={eyebrow}
29
- title={title}
30
- description={description}
31
- {...props}
32
- />
33
- );
34
- }
35
-
36
- // accordion
37
- return (
38
- <div className="mx-auto w-full max-w-3xl">
39
- <FaqAccordion
40
- className={className}
41
- items={items}
42
- allowMultiple={allowMultiple}
43
- defaultOpen={defaultOpen}
44
- />
45
- </div>
46
- );
47
- };
48
- FAQ.displayName = "FAQ";
@@ -1,2 +0,0 @@
1
- export { FAQ } from "./FAQ";
2
- export type { FAQProps, FAQOption, FaqItem } from "./types";
@@ -1,74 +0,0 @@
1
- "use client";
2
- import { useState } from "react";
3
- import { cn } from "../../utils/cn";
4
- import { Plus } from "../../icons";
5
- import type { FaqItem } from "./types";
6
-
7
- export function useFaqState(allowMultiple: boolean, defaultOpen: number[]) {
8
- const [openSet, setOpenSet] = useState<Set<number>>(
9
- () => new Set(allowMultiple ? defaultOpen : defaultOpen.slice(0, 1)),
10
- );
11
-
12
- const toggle = (index: number) => {
13
- setOpenSet((prev) => {
14
- const next = new Set(prev);
15
- if (next.has(index)) {
16
- next.delete(index);
17
- } else {
18
- if (!allowMultiple) next.clear();
19
- next.add(index);
20
- }
21
- return next;
22
- });
23
- };
24
-
25
- return { openSet, toggle, isOpen: (i: number) => openSet.has(i) };
26
- }
27
-
28
- export function FaqItemRow({
29
- item,
30
- open,
31
- onToggle,
32
- style,
33
- }: {
34
- item: FaqItem;
35
- open: boolean;
36
- onToggle: () => void;
37
- style: "boxed" | "bare";
38
- }) {
39
- return (
40
- <div>
41
- <h3>
42
- <button
43
- type="button"
44
- aria-expanded={open}
45
- onClick={onToggle}
46
- className={
47
- style === "boxed"
48
- ? "flex w-full cursor-pointer items-center justify-between gap-4 px-6 py-5 text-left text-[15px] font-medium text-foreground transition-colors duration-150 hover:bg-surface-strong/60 focus-visible:outline-none"
49
- : "flex w-full cursor-pointer items-center justify-between gap-4 py-5 text-left text-base font-semibold text-foreground transition-colors duration-150 focus-visible:outline-none"
50
- }
51
- >
52
- {item.question}
53
- <Plus
54
- className={cn(
55
- "h-4.5 w-4.5 shrink-0 text-foreground/45 transition-transform duration-200 sm:h-5 sm:w-5",
56
- open && "rotate-45 text-primary",
57
- )}
58
- />
59
- </button>
60
- </h3>
61
- {open ? (
62
- <p className={style === "boxed" ? "px-6 pb-6 text-sm leading-7 text-muted-foreground" : "pb-6 text-sm leading-7 text-muted-foreground"}>
63
- {item.answer}
64
- </p>
65
- ) : null}
66
- </div>
67
- );
68
- }
69
-
70
- export function FaqEyebrow({ label }: { label: string }) {
71
- return (
72
- <p className="text-xs font-semibold uppercase tracking-[0.18em] text-primary">{label}</p>
73
- );
74
- }
@@ -1,18 +0,0 @@
1
- import type { HTMLAttributes, ReactNode } from "react";
2
-
3
- export type FAQOption = "accordion" | "split" | "cards";
4
-
5
- export interface FaqItem {
6
- question: string;
7
- answer: string;
8
- }
9
-
10
- export interface FAQProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
11
- items: FaqItem[];
12
- option?: FAQOption;
13
- allowMultiple?: boolean;
14
- defaultOpen?: number[];
15
- eyebrow?: ReactNode;
16
- title?: ReactNode;
17
- description?: ReactNode;
18
- }
@@ -1,46 +0,0 @@
1
- "use client";
2
- import { cn } from "../../../utils/cn";
3
- import { useFaqState, FaqItemRow } from "../parts";
4
- import type { FAQProps } from "../types";
5
-
6
- interface AccordionProps extends FAQProps {
7
- allowMultiple?: boolean;
8
- defaultOpen?: number[];
9
- bare?: boolean;
10
- }
11
-
12
- export const FaqAccordion = ({
13
- className,
14
- items,
15
- allowMultiple = false,
16
- defaultOpen = [],
17
- bare = false,
18
- option,
19
- title,
20
- eyebrow,
21
- description,
22
- ...props
23
- }: AccordionProps) => {
24
- const { isOpen, toggle } = useFaqState(allowMultiple, defaultOpen);
25
-
26
- return (
27
- <div
28
- className={cn(
29
- !bare && "divide-y divide-border rounded-2xl border border-border bg-surface",
30
- className,
31
- )}
32
- {...props}
33
- >
34
- {items.map((item, index) => (
35
- <FaqItemRow
36
- key={item.question}
37
- item={item}
38
- open={isOpen(index)}
39
- onToggle={() => toggle(index)}
40
- style={bare ? "bare" : "boxed"}
41
- />
42
- ))}
43
- </div>
44
- );
45
- };
46
- FaqAccordion.displayName = "FaqAccordion";
@@ -1,40 +0,0 @@
1
- import { cn } from "../../../utils/cn";
2
- import { FaqEyebrow } from "../parts";
3
- import type { FAQProps } from "../types";
4
-
5
- interface CardsProps extends FAQProps {}
6
-
7
- export const FaqCards = ({
8
- className,
9
- items,
10
- eyebrow,
11
- title,
12
- description,
13
- option,
14
- ...props
15
- }: CardsProps) => (
16
- <div className={cn("w-full", className)} {...props}>
17
- {eyebrow ? <div className="mb-10"><FaqEyebrow label={String(eyebrow)} /></div> : null}
18
- <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
19
- {items.map((item, i) => (
20
- <div
21
- key={item.question}
22
- className="flex flex-col rounded-xl border border-border bg-surface p-7"
23
- >
24
- <div className="flex items-baseline gap-4">
25
- <span className="font-display text-sm font-semibold tabular-nums text-foreground/35">
26
- {String(i + 1).padStart(2, "0")}
27
- </span>
28
- <h3 className="font-display text-lg font-semibold tracking-tight text-foreground">
29
- {item.question}
30
- </h3>
31
- </div>
32
- <p className="mt-4 border-t border-border pt-4 text-sm leading-6 text-muted-foreground">
33
- {item.answer}
34
- </p>
35
- </div>
36
- ))}
37
- </div>
38
- </div>
39
- );
40
- FaqCards.displayName = "FaqCards";
@@ -1,44 +0,0 @@
1
- import { cn } from "../../../utils/cn";
2
- import { FaqEyebrow } from "../parts";
3
- import { FaqAccordion } from "./Accordion";
4
- import type { FAQProps } from "../types";
5
-
6
- interface SplitProps extends FAQProps {
7
- allowMultiple?: boolean;
8
- defaultOpen?: number[];
9
- }
10
-
11
- export const FaqSplit = ({
12
- className,
13
- items,
14
- allowMultiple = false,
15
- defaultOpen = [],
16
- eyebrow,
17
- title,
18
- description,
19
- option,
20
- ...props
21
- }: SplitProps) => (
22
- <div className={cn("grid w-full gap-10 lg:grid-cols-[0.9fr_1.1fr] lg:gap-20", className)} {...props}>
23
- <div className="lg:sticky lg:top-24 lg:self-start">
24
- {eyebrow ? <FaqEyebrow label={String(eyebrow)} /> : null}
25
- {title ? (
26
- <h2 className="mt-4 font-display text-3xl font-semibold leading-[1.08] tracking-tight text-foreground sm:text-4xl">
27
- {title}
28
- </h2>
29
- ) : null}
30
- {description ? (
31
- <p className="mt-4 text-pretty text-base leading-7 text-muted-foreground">{description}</p>
32
- ) : null}
33
- </div>
34
- <div className="divide-y divide-border">
35
- <FaqAccordion
36
- items={items}
37
- allowMultiple={allowMultiple}
38
- defaultOpen={defaultOpen}
39
- bare
40
- />
41
- </div>
42
- </div>
43
- );
44
- FaqSplit.displayName = "FaqSplit";
@@ -1,44 +0,0 @@
1
- import { forwardRef } from "react";
2
- import { cn } from "../../utils/cn";
3
- import { getContrastText } from "../../utils/contrast";
4
- import type { FeatureCardProps } from "./types";
5
-
6
- export const FeatureCard = forwardRef<HTMLDivElement, FeatureCardProps>(
7
- ({ className, icon, title, description, accent, large = false, ...props }, ref) => {
8
- const chipStyle = accent
9
- ? { backgroundColor: accent, color: getContrastText(accent, "#111111", "#ffffff") }
10
- : undefined;
11
-
12
- return (
13
- <div
14
- ref={ref}
15
- className={cn(
16
- "group relative flex h-full flex-col rounded-xl border border-border bg-surface p-7 transition-colors duration-200 hover:border-foreground/15",
17
- className,
18
- )}
19
- {...props}
20
- >
21
- {icon ? (
22
- <div
23
- className={cn(
24
- "mb-5 inline-flex h-10 w-10 items-center justify-center rounded-lg text-[1.05rem]",
25
- !accent && "bg-primary-soft text-primary",
26
- )}
27
- style={chipStyle}
28
- >
29
- {icon}
30
- </div>
31
- ) : null}
32
- <h3 className={cn("font-display font-semibold tracking-tight text-foreground", large ? "text-2xl" : "text-lg")}>
33
- {title}
34
- </h3>
35
- {description ? (
36
- <p className={cn("mt-2.5 text-pretty leading-relaxed text-muted-foreground", large ? "text-[15px]" : "text-sm")}>
37
- {description}
38
- </p>
39
- ) : null}
40
- </div>
41
- );
42
- },
43
- );
44
- FeatureCard.displayName = "FeatureCard";
@@ -1,14 +0,0 @@
1
- import { forwardRef } from "react";
2
- import type { FeatureGridProps } from "./types";
3
- import { FeatureColumns } from "./variants/Columns";
4
- import { FeatureBento } from "./variants/Bento";
5
- import { FeatureEditorialRows } from "./variants/EditorialRows";
6
-
7
- export const FeatureGrid = forwardRef<HTMLDivElement, FeatureGridProps>(
8
- ({ option = "columns", columns = 3, ...props }, ref) => {
9
- if (option === "editorialRows") return <FeatureEditorialRows ref={ref} {...props} />;
10
- if (option === "bento") return <FeatureBento ref={ref} {...props} />;
11
- return <FeatureColumns ref={ref} columns={columns} {...props} />;
12
- },
13
- );
14
- FeatureGrid.displayName = "FeatureGrid";
@@ -1,3 +0,0 @@
1
- export { FeatureCard } from "./FeatureCard";
2
- export { FeatureGrid } from "./FeatureGrid";
3
- export type { FeatureItem, FeatureCardProps, FeatureGridProps, FeatureGridOption } from "./types";
@@ -1,15 +0,0 @@
1
- export const gridCols: Record<2 | 3 | 4, string> = {
2
- 2: "sm:grid-cols-2",
3
- 3: "sm:grid-cols-2 lg:grid-cols-3",
4
- 4: "sm:grid-cols-2 lg:grid-cols-4",
5
- };
6
-
7
- /** Asymmetric bento layout for up to 6 features. */
8
- export const bentoSpans: string[] = [
9
- "sm:col-span-2 lg:row-span-2",
10
- "",
11
- "",
12
- "lg:col-span-2",
13
- "",
14
- "lg:col-span-2",
15
- ];