mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 02:10:12 -06:00
Compare commits
1 Commits
add-saas-d
...
shubham/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b37b1dcb8f |
@@ -1,6 +1,6 @@
|
||||
import { Sidebar } from "./Sidebar";
|
||||
import Sidebar from "./Sidebar";
|
||||
|
||||
export const LayoutApp = ({ children }: { children: React.ReactNode }) => {
|
||||
export default function LayoutApp({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="min-h-full">
|
||||
{/* Static sidebar for desktop */}
|
||||
@@ -10,4 +10,4 @@ export const LayoutApp = ({ children }: { children: React.ReactNode }) => {
|
||||
<div className="flex flex-1 flex-col lg:pl-64">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const secondaryNavigation = [
|
||||
{ name: "Privacy", href: "#", icon: ShieldCheckIcon },
|
||||
];
|
||||
|
||||
export const Sidebar = () => {
|
||||
export default function Sidebar({}) {
|
||||
return (
|
||||
<div className="flex flex-grow flex-col overflow-y-auto bg-cyan-700 pb-4 pt-5">
|
||||
<nav
|
||||
@@ -63,4 +63,4 @@ export const Sidebar = () => {
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
||||
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return <div className={classNames(badgeVariants({ variant }), className)} {...props} />;
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants };
|
||||
@@ -1,91 +0,0 @@
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Breadcrumb = React.forwardRef<
|
||||
HTMLElement,
|
||||
React.ComponentPropsWithoutRef<"nav"> & {
|
||||
separator?: React.ReactNode;
|
||||
}
|
||||
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />);
|
||||
Breadcrumb.displayName = "Breadcrumb";
|
||||
|
||||
const BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWithoutRef<"ol">>(
|
||||
({ className, ...props }, ref) => (
|
||||
<ol
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"text-muted-foreground flex flex-wrap items-center gap-1.5 break-words text-sm sm:gap-2.5",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
BreadcrumbList.displayName = "BreadcrumbList";
|
||||
|
||||
const BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentPropsWithoutRef<"li">>(
|
||||
({ className, ...props }, ref) => (
|
||||
<li ref={ref} className={classNames("inline-flex items-center gap-1.5", className)} {...props} />
|
||||
)
|
||||
);
|
||||
BreadcrumbItem.displayName = "BreadcrumbItem";
|
||||
|
||||
const BreadcrumbLink = React.forwardRef<
|
||||
HTMLAnchorElement,
|
||||
React.ComponentPropsWithoutRef<"a"> & {
|
||||
asChild?: boolean;
|
||||
}
|
||||
>(({ asChild, className, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "a";
|
||||
|
||||
return (
|
||||
<Comp ref={ref} className={classNames("hover:text-foreground transition-colors", className)} {...props} />
|
||||
);
|
||||
});
|
||||
BreadcrumbLink.displayName = "BreadcrumbLink";
|
||||
|
||||
const BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWithoutRef<"span">>(
|
||||
({ className, ...props }, ref) => (
|
||||
<span
|
||||
ref={ref}
|
||||
role="link"
|
||||
aria-disabled="true"
|
||||
aria-current="page"
|
||||
className={classNames("text-foreground font-normal", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
BreadcrumbPage.displayName = "BreadcrumbPage";
|
||||
|
||||
const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<"li">) => (
|
||||
<li role="presentation" aria-hidden="true" className={classNames("[&>svg]:size-3.5", className)} {...props}>
|
||||
{children ?? <ChevronRight />}
|
||||
</li>
|
||||
);
|
||||
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
|
||||
|
||||
const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<"span">) => (
|
||||
<span
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={classNames("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...props}>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">More</span>
|
||||
</span>
|
||||
);
|
||||
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
|
||||
|
||||
export {
|
||||
Breadcrumb,
|
||||
BreadcrumbEllipsis,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return <Comp className={classNames(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
|
||||
}
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants };
|
||||
@@ -1,53 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={classNames("bg-card text-card-foreground rounded-lg border shadow-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
Card.displayName = "Card";
|
||||
|
||||
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={classNames("flex flex-col space-y-1.5 p-6", className)} {...props} />
|
||||
)
|
||||
);
|
||||
CardHeader.displayName = "CardHeader";
|
||||
|
||||
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<h3
|
||||
ref={ref}
|
||||
className={classNames("text-2xl font-semibold leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
CardTitle.displayName = "CardTitle";
|
||||
|
||||
const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<p ref={ref} className={classNames("text-muted-foreground text-sm", className)} {...props} />
|
||||
)
|
||||
);
|
||||
CardDescription.displayName = "CardDescription";
|
||||
|
||||
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => <div ref={ref} className={classNames("p-6 pt-0", className)} {...props} />
|
||||
);
|
||||
CardContent.displayName = "CardContent";
|
||||
|
||||
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={classNames("flex items-center p-6 pt-0", className)} {...props} />
|
||||
)
|
||||
);
|
||||
CardFooter.displayName = "CardFooter";
|
||||
|
||||
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
||||
@@ -1,182 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
));
|
||||
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={classNames(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
));
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
));
|
||||
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
));
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean;
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={classNames("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={classNames("bg-muted -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||
|
||||
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return <span className={classNames("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />;
|
||||
};
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={classNames(
|
||||
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input };
|
||||
@@ -1,89 +0,0 @@
|
||||
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
import { ButtonProps, buttonVariants } from "./button";
|
||||
|
||||
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
||||
<nav
|
||||
role="navigation"
|
||||
aria-label="pagination"
|
||||
className={classNames("mx-auto flex w-full justify-center", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
Pagination.displayName = "Pagination";
|
||||
|
||||
const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<"ul">>(
|
||||
({ className, ...props }, ref) => (
|
||||
<ul ref={ref} className={classNames("flex flex-row items-center gap-1", className)} {...props} />
|
||||
)
|
||||
);
|
||||
PaginationContent.displayName = "PaginationContent";
|
||||
|
||||
const PaginationItem = React.forwardRef<HTMLLIElement, React.ComponentProps<"li">>(
|
||||
({ className, ...props }, ref) => <li ref={ref} className={classNames("", className)} {...props} />
|
||||
);
|
||||
PaginationItem.displayName = "PaginationItem";
|
||||
|
||||
type PaginationLinkProps = {
|
||||
isActive?: boolean;
|
||||
} & Pick<ButtonProps, "size"> &
|
||||
React.ComponentProps<"a">;
|
||||
|
||||
const PaginationLink = ({ className, isActive, size = "icon", ...props }: PaginationLinkProps) => (
|
||||
<a
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
className={classNames(
|
||||
buttonVariants({
|
||||
variant: isActive ? "outline" : "ghost",
|
||||
size,
|
||||
}),
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
PaginationLink.displayName = "PaginationLink";
|
||||
|
||||
const PaginationPrevious = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => (
|
||||
<PaginationLink
|
||||
aria-label="Go to previous page"
|
||||
size="default"
|
||||
className={classNames("gap-1 pl-2.5", className)}
|
||||
{...props}>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
<span>Previous</span>
|
||||
</PaginationLink>
|
||||
);
|
||||
PaginationPrevious.displayName = "PaginationPrevious";
|
||||
|
||||
const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => (
|
||||
<PaginationLink
|
||||
aria-label="Go to next page"
|
||||
size="default"
|
||||
className={classNames("gap-1 pr-2.5", className)}
|
||||
{...props}>
|
||||
<span>Next</span>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</PaginationLink>
|
||||
);
|
||||
PaginationNext.displayName = "PaginationNext";
|
||||
|
||||
const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<"span">) => (
|
||||
<span aria-hidden className={classNames("flex h-9 w-9 items-center justify-center", className)} {...props}>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">More pages</span>
|
||||
</span>
|
||||
);
|
||||
PaginationEllipsis.displayName = "PaginationEllipsis";
|
||||
|
||||
export {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationEllipsis,
|
||||
PaginationItem,
|
||||
PaginationLink,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Progress = React.forwardRef<
|
||||
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
|
||||
>(({ className, value, ...props }, ref) => (
|
||||
<ProgressPrimitive.Root
|
||||
ref={ref}
|
||||
className={classNames("bg-secondary relative h-4 w-full overflow-hidden rounded-full", className)}
|
||||
{...props}>
|
||||
<ProgressPrimitive.Indicator
|
||||
className="bg-primary h-full w-full flex-1 transition-all"
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
));
|
||||
Progress.displayName = ProgressPrimitive.Root.displayName;
|
||||
|
||||
export { Progress };
|
||||
@@ -1,26 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Separator = React.forwardRef<
|
||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
||||
>(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
|
||||
<SeparatorPrimitive.Root
|
||||
ref={ref}
|
||||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={classNames(
|
||||
"bg-border shrink-0",
|
||||
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
||||
|
||||
export { Separator };
|
||||
@@ -1,120 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
||||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import { X } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Sheet = SheetPrimitive.Root;
|
||||
|
||||
const SheetTrigger = SheetPrimitive.Trigger;
|
||||
|
||||
const SheetClose = SheetPrimitive.Close;
|
||||
|
||||
const SheetPortal = SheetPrimitive.Portal;
|
||||
|
||||
const SheetOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={classNames(
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
));
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
||||
|
||||
const sheetVariants = cva(
|
||||
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
||||
bottom:
|
||||
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
||||
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
||||
right:
|
||||
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
side: "right",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
interface SheetContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> {}
|
||||
|
||||
const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, SheetContentProps>(
|
||||
({ side = "right", className, children, ...props }, ref) => (
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content ref={ref} className={classNames(sheetVariants({ side }), className)} {...props}>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
)
|
||||
);
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
||||
|
||||
const SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={classNames("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
|
||||
);
|
||||
SheetHeader.displayName = "SheetHeader";
|
||||
|
||||
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={classNames("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
SheetFooter.displayName = "SheetFooter";
|
||||
|
||||
const SheetTitle = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={classNames("text-foreground text-lg font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
||||
|
||||
const SheetDescription = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={classNames("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetOverlay,
|
||||
SheetPortal,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table ref={ref} className={classNames("w-full caption-bottom text-sm", className)} {...props} />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
Table.displayName = "Table";
|
||||
|
||||
const TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={classNames("[&_tr]:border-b", className)} {...props} />
|
||||
)
|
||||
);
|
||||
TableHeader.displayName = "TableHeader";
|
||||
|
||||
const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<tbody ref={ref} className={classNames("[&_tr:last-child]:border-0", className)} {...props} />
|
||||
)
|
||||
);
|
||||
TableBody.displayName = "TableBody";
|
||||
|
||||
const TableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={classNames("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
TableFooter.displayName = "TableFooter";
|
||||
|
||||
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
TableRow.displayName = "TableRow";
|
||||
|
||||
const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<HTMLTableCellElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"text-muted-foreground h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
TableHead.displayName = "TableHead";
|
||||
|
||||
const TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<td
|
||||
ref={ref}
|
||||
className={classNames("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
TableCell.displayName = "TableCell";
|
||||
|
||||
const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<caption ref={ref} className={classNames("text-muted-foreground mt-4 text-sm", className)} {...props} />
|
||||
)
|
||||
);
|
||||
TableCaption.displayName = "TableCaption";
|
||||
|
||||
export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
|
||||
@@ -1,55 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const Tabs = TabsPrimitive.Root;
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"bg-muted text-muted-foreground inline-flex h-10 items-center justify-center rounded-md p-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||
|
||||
const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"ring-offset-background focus-visible:ring-ring data-[state=active]:bg-background data-[state=active]:text-foreground inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||
|
||||
const TabsContent = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"ring-offset-background focus-visible:ring-ring mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||
|
||||
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
||||
@@ -1,30 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
import * as React from "react";
|
||||
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider;
|
||||
|
||||
const Tooltip = TooltipPrimitive.Root;
|
||||
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger;
|
||||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={classNames(
|
||||
"bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md border px-3 py-1.5 text-sm shadow-md",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
||||
@@ -1,3 +1,3 @@
|
||||
export const classNames = (...classes: any) => {
|
||||
export function classNames(...classes: any) {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,21 +13,13 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
"@radix-ui/react-progress": "^1.0.3",
|
||||
"@radix-ui/react-separator": "^1.0.3",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-tooltip": "^1.0.7",
|
||||
"classnames": "^2.5.1",
|
||||
"lucide-react": "^0.378.0",
|
||||
"next": "14.2.3",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/tsconfig": "workspace:*",
|
||||
"eslint-config-formbricks": "workspace:*"
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
"@formbricks/tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import Head from "next/head";
|
||||
|
||||
import "../styles/globals.css";
|
||||
|
||||
const App = ({ Component, pageProps }: AppProps) => {
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -18,6 +18,4 @@ const App = ({ Component, pageProps }: AppProps) => {
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Head, Html, Main, NextScript } from "next/document";
|
||||
|
||||
const Document = () => {
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en" className="h-full bg-slate-50">
|
||||
<Head />
|
||||
@@ -10,6 +10,4 @@ const Document = () => {
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
};
|
||||
|
||||
export default Document;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
declare const window: any;
|
||||
|
||||
const AppPage = ({}) => {
|
||||
export default function AppPage({}) {
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -36,11 +36,7 @@ const AppPage = ({}) => {
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
|
||||
const userInitAttributes = {
|
||||
language: "de",
|
||||
"Init Attribute 1": "eight",
|
||||
"Init Attribute 2": "two",
|
||||
};
|
||||
const userInitAttributes = { language: "de", "Init Attribute 1": "eight", "Init Attribute 2": "two" };
|
||||
|
||||
formbricks.init({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
@@ -238,6 +234,4 @@ const AppPage = ({}) => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppPage;
|
||||
}
|
||||
|
||||
@@ -1,663 +0,0 @@
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Copy,
|
||||
CreditCard,
|
||||
File,
|
||||
Home,
|
||||
LineChart,
|
||||
ListFilter,
|
||||
MoreVertical,
|
||||
Package,
|
||||
Package2,
|
||||
PanelLeft,
|
||||
Search,
|
||||
Settings,
|
||||
ShoppingCart,
|
||||
Truck,
|
||||
Users2,
|
||||
} from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import formbricks from "@formbricks/js/app";
|
||||
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "../../components/ui/breadcrumb";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../../components/ui/card";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "../../components/ui/dropdown-menu";
|
||||
import { Input } from "../../components/ui/input";
|
||||
import { Pagination, PaginationContent, PaginationItem } from "../../components/ui/pagination";
|
||||
import { Progress } from "../../components/ui/progress";
|
||||
import { Separator } from "../../components/ui/separator";
|
||||
import { Sheet, SheetContent, SheetTrigger } from "../../components/ui/sheet";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../components/ui/table";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../components/ui/tooltip";
|
||||
|
||||
declare const window: any;
|
||||
|
||||
const SaaSPage = ({}) => {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
// enable Formbricks debug mode by adding formbricksDebug=true GET parameter
|
||||
const addFormbricksDebugParam = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (!urlParams.has("formbricksDebug")) {
|
||||
urlParams.set("formbricksDebug", "true");
|
||||
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
}
|
||||
};
|
||||
|
||||
addFormbricksDebugParam();
|
||||
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const userId = "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING";
|
||||
const userInitAttributes = {
|
||||
language: "de",
|
||||
"Init Attribute 1": "eight",
|
||||
"Init Attribute 2": "two",
|
||||
};
|
||||
|
||||
formbricks.init({
|
||||
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
|
||||
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
|
||||
userId,
|
||||
attributes: userInitAttributes,
|
||||
});
|
||||
}
|
||||
|
||||
// Connect next.js router to Formbricks
|
||||
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
|
||||
const handleRouteChange = formbricks?.registerRouteChange;
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
router.events.off("routeChangeComplete", handleRouteChange);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="bg-muted/40 flex min-h-screen w-full flex-col">
|
||||
<TooltipProvider delayDuration={10}>
|
||||
<aside className="bg-background fixed inset-y-0 left-0 z-10 hidden w-14 flex-col border-r sm:flex">
|
||||
<nav className="flex flex-col items-center gap-4 px-2 sm:py-5">
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-primary text-primary-foreground group flex h-9 w-9 shrink-0 items-center justify-center gap-2 rounded-full text-lg font-semibold md:h-8 md:w-8 md:text-base">
|
||||
<Package2 className="h-4 w-4 transition-all group-hover:scale-110" />
|
||||
<span className="sr-only">Acme Inc</span>
|
||||
</Link>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex h-9 w-9 items-center justify-center rounded-lg transition-colors md:h-8 md:w-8">
|
||||
<Home className="h-5 w-5" />
|
||||
<span className="sr-only">Dashboard</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Dashboard</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-accent text-accent-foreground hover:text-foreground flex h-9 w-9 items-center justify-center rounded-lg transition-colors md:h-8 md:w-8">
|
||||
<ShoppingCart className="h-5 w-5" />
|
||||
<span className="sr-only">Orders</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Orders</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex h-9 w-9 items-center justify-center rounded-lg transition-colors md:h-8 md:w-8">
|
||||
<Package className="h-5 w-5" />
|
||||
<span className="sr-only">Products</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Products</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex h-9 w-9 items-center justify-center rounded-lg transition-colors md:h-8 md:w-8">
|
||||
<Users2 className="h-5 w-5" />
|
||||
<span className="sr-only">Customers</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Customers</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex h-9 w-9 items-center justify-center rounded-lg transition-colors md:h-8 md:w-8">
|
||||
<LineChart className="h-5 w-5" />
|
||||
<span className="sr-only">Analytics</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Analytics</TooltipContent>
|
||||
</Tooltip>
|
||||
</nav>
|
||||
<nav className="mt-auto flex flex-col items-center gap-4 px-2 sm:py-5">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex h-9 w-9 items-center justify-center rounded-lg transition-colors md:h-8 md:w-8">
|
||||
<Settings className="h-5 w-5" />
|
||||
<span className="sr-only">Settings</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Settings</TooltipContent>
|
||||
</Tooltip>
|
||||
</nav>
|
||||
</aside>
|
||||
<div className="flex flex-col sm:gap-4 sm:py-4 sm:pl-14">
|
||||
<header className="bg-background sticky top-0 z-30 flex h-14 items-center gap-4 border-b px-4 sm:static sm:h-auto sm:border-0 sm:bg-transparent sm:px-6">
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button size="icon" variant="outline" className="sm:hidden">
|
||||
<PanelLeft className="h-5 w-5" />
|
||||
<span className="sr-only">Toggle Menu</span>
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="sm:max-w-xs">
|
||||
<nav className="grid gap-6 text-lg font-medium">
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-primary text-primary-foreground group flex h-10 w-10 shrink-0 items-center justify-center gap-2 rounded-full text-lg font-semibold md:text-base">
|
||||
<Package2 className="h-5 w-5 transition-all group-hover:scale-110" />
|
||||
<span className="sr-only">Acme Inc</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex items-center gap-4 px-2.5">
|
||||
<Home className="h-5 w-5" />
|
||||
Dashboard
|
||||
</Link>
|
||||
<Link href="#" className="text-foreground flex items-center gap-4 px-2.5">
|
||||
<ShoppingCart className="h-5 w-5" />
|
||||
Orders
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex items-center gap-4 px-2.5">
|
||||
<Package className="h-5 w-5" />
|
||||
Products
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex items-center gap-4 px-2.5">
|
||||
<Users2 className="h-5 w-5" />
|
||||
Customers
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="text-muted-foreground hover:text-foreground flex items-center gap-4 px-2.5">
|
||||
<LineChart className="h-5 w-5" />
|
||||
Settings
|
||||
</Link>
|
||||
</nav>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
<Breadcrumb className="hidden md:flex">
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink asChild>
|
||||
<Link href="#">Dashboard</Link>
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink asChild>
|
||||
<Link href="#">Orders</Link>
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Recent Orders</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
<div className="relative ml-auto flex-1 md:grow-0">
|
||||
<Search className="text-muted-foreground absolute left-2.5 top-2.5 h-4 w-4" />
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search..."
|
||||
className="bg-background w-full rounded-lg pl-8 md:w-[200px] lg:w-[336px]"
|
||||
/>
|
||||
</div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon" className="overflow-hidden rounded-full">
|
||||
<Image
|
||||
src="/user-avatar.png"
|
||||
width={36}
|
||||
height={36}
|
||||
alt="Avatar"
|
||||
className="overflow-hidden rounded-full"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
<DropdownMenuItem>Support</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Logout</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</header>
|
||||
<main className="grid flex-1 items-start gap-4 p-4 sm:px-6 sm:py-0 md:gap-8 lg:grid-cols-3 xl:grid-cols-3">
|
||||
<div className="grid auto-rows-max items-start gap-4 md:gap-8 lg:col-span-2">
|
||||
<div className="grid gap-4 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-2 xl:grid-cols-4">
|
||||
<Card className="sm:col-span-2" x-chunk="dashboard-05-chunk-0">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle>Your Orders</CardTitle>
|
||||
<CardDescription className="max-w-lg text-balance leading-relaxed">
|
||||
Introducing Our Dynamic Orders Dashboard for Seamless Management and Insightful
|
||||
Analysis.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<Button>Create New Order</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<Card x-chunk="dashboard-05-chunk-1">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription>This Week</CardDescription>
|
||||
<CardTitle className="text-4xl">$1,329</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-muted-foreground text-xs">+25% from last week</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Progress value={25} aria-label="25% increase" />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<Card x-chunk="dashboard-05-chunk-2">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription>This Month</CardDescription>
|
||||
<CardTitle className="text-4xl">$5,329</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-muted-foreground text-xs">+10% from last month</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Progress value={12} aria-label="12% increase" />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
<Tabs defaultValue="week">
|
||||
<div className="flex items-center">
|
||||
<TabsList>
|
||||
<TabsTrigger value="week">Week</TabsTrigger>
|
||||
<TabsTrigger value="month">Month</TabsTrigger>
|
||||
<TabsTrigger value="year">Year</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="h-7 gap-1 text-sm">
|
||||
<ListFilter className="h-3.5 w-3.5" />
|
||||
<span className="sr-only sm:not-sr-only">Filter</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Filter by</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuCheckboxItem checked>Fulfilled</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem>Declined</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem>Refunded</DropdownMenuCheckboxItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Button size="sm" variant="outline" className="h-7 gap-1 text-sm">
|
||||
<File className="h-3.5 w-3.5" />
|
||||
<span className="sr-only sm:not-sr-only">Export</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<TabsContent value="week">
|
||||
<Card x-chunk="dashboard-05-chunk-3">
|
||||
<CardHeader className="px-7">
|
||||
<CardTitle>Orders</CardTitle>
|
||||
<CardDescription>Recent orders from your store.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Customer</TableHead>
|
||||
<TableHead className="hidden sm:table-cell">Type</TableHead>
|
||||
<TableHead className="hidden sm:table-cell">Status</TableHead>
|
||||
<TableHead className="hidden md:table-cell">Date</TableHead>
|
||||
<TableHead className="text-right">Amount</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow className="bg-accent">
|
||||
<TableCell>
|
||||
<div className="font-medium">Liam Johnson</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
liam@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Sale</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
Fulfilled
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-23</TableCell>
|
||||
<TableCell className="text-right">$250.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Olivia Smith</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
olivia@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Refund</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="outline">
|
||||
Declined
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-24</TableCell>
|
||||
<TableCell className="text-right">$150.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Noah Williams</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
noah@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Subscription</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
Fulfilled
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-25</TableCell>
|
||||
<TableCell className="text-right">$350.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Emma Brown</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
emma@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Sale</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
Fulfilled
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-26</TableCell>
|
||||
<TableCell className="text-right">$450.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Liam Johnson</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
liam@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Sale</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
Fulfilled
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-23</TableCell>
|
||||
<TableCell className="text-right">$250.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Liam Johnson</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
liam@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Sale</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
Fulfilled
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-23</TableCell>
|
||||
<TableCell className="text-right">$250.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Olivia Smith</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
olivia@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Refund</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="outline">
|
||||
Declined
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-24</TableCell>
|
||||
<TableCell className="text-right">$150.00</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<div className="font-medium">Emma Brown</div>
|
||||
<div className="text-muted-foreground hidden text-sm md:inline">
|
||||
emma@example.com
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">Sale</TableCell>
|
||||
<TableCell className="hidden sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
Fulfilled
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="hidden md:table-cell">2023-06-26</TableCell>
|
||||
<TableCell className="text-right">$450.00</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
<div>
|
||||
<Card className="overflow-hidden" x-chunk="dashboard-05-chunk-4">
|
||||
<CardHeader className="bg-muted/50 flex flex-row items-start">
|
||||
<div className="grid gap-0.5">
|
||||
<CardTitle className="group flex items-center gap-2 text-lg">
|
||||
Order Oe31b70H
|
||||
<Button
|
||||
size="icon"
|
||||
variant="outline"
|
||||
className="h-6 w-6 opacity-0 transition-opacity group-hover:opacity-100">
|
||||
<Copy className="h-3 w-3" />
|
||||
<span className="sr-only">Copy Order ID</span>
|
||||
</Button>
|
||||
</CardTitle>
|
||||
<CardDescription>Date: November 23, 2023</CardDescription>
|
||||
</div>
|
||||
<div className="ml-auto flex items-center gap-1">
|
||||
<Button size="sm" variant="outline" className="h-8 gap-1">
|
||||
<Truck className="h-3.5 w-3.5" />
|
||||
<span className="lg:sr-only xl:not-sr-only xl:whitespace-nowrap">Track Order</span>
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="icon" variant="outline" className="h-8 w-8">
|
||||
<MoreVertical className="h-3.5 w-3.5" />
|
||||
<span className="sr-only">More</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Export</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Trash</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="p-6 text-sm">
|
||||
<div className="grid gap-3">
|
||||
<div className="font-semibold">Order Details</div>
|
||||
<ul className="grid gap-3">
|
||||
<li className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">
|
||||
Glimmer Lamps x <span>2</span>
|
||||
</span>
|
||||
<span>$250.00</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">
|
||||
Aqua Filters x <span>1</span>
|
||||
</span>
|
||||
<span>$49.00</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Separator className="my-2" />
|
||||
<ul className="grid gap-3">
|
||||
<li className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Subtotal</span>
|
||||
<span>$299.00</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Shipping</span>
|
||||
<span>$5.00</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Tax</span>
|
||||
<span>$25.00</span>
|
||||
</li>
|
||||
<li className="flex items-center justify-between font-semibold">
|
||||
<span className="text-muted-foreground">Total</span>
|
||||
<span>$329.00</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid gap-3">
|
||||
<div className="font-semibold">Shipping Information</div>
|
||||
<address className="text-muted-foreground grid gap-0.5 not-italic">
|
||||
<span>Liam Johnson</span>
|
||||
<span>1234 Main St.</span>
|
||||
<span>Anytown, CA 12345</span>
|
||||
</address>
|
||||
</div>
|
||||
<div className="grid auto-rows-max gap-3">
|
||||
<div className="font-semibold">Billing Information</div>
|
||||
<div className="text-muted-foreground">Same as shipping address</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<div className="grid gap-3">
|
||||
<div className="font-semibold">Customer Information</div>
|
||||
<dl className="grid gap-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<dt className="text-muted-foreground">Customer</dt>
|
||||
<dd>Liam Johnson</dd>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<dt className="text-muted-foreground">Email</dt>
|
||||
<dd>
|
||||
<a href="mailto:">liam@acme.com</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<dt className="text-muted-foreground">Phone</dt>
|
||||
<dd>
|
||||
<a href="tel:">+1 234 567 890</a>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<div className="grid gap-3">
|
||||
<div className="font-semibold">Payment Information</div>
|
||||
<dl className="grid gap-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<dt className="text-muted-foreground flex items-center gap-1">
|
||||
<CreditCard className="h-4 w-4" />
|
||||
Visa
|
||||
</dt>
|
||||
<dd>**** **** **** 4532</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="bg-muted/50 flex flex-row items-center border-t px-6 py-3">
|
||||
<div className="text-muted-foreground text-xs">
|
||||
Updated <time dateTime="2023-11-23">November 23, 2023</time>
|
||||
</div>
|
||||
<Pagination className="ml-auto mr-0 w-auto">
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<Button size="icon" variant="outline" className="h-6 w-6">
|
||||
<ChevronLeft className="h-3.5 w-3.5" />
|
||||
<span className="sr-only">Previous Order</span>
|
||||
</Button>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<Button size="icon" variant="outline" className="h-6 w-6">
|
||||
<ChevronRight className="h-3.5 w-3.5" />
|
||||
<span className="sr-only">Next Order</span>
|
||||
</Button>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SaaSPage;
|
||||
@@ -9,7 +9,7 @@ import fbsetup from "../../public/fb-setup.png";
|
||||
|
||||
declare const window: any;
|
||||
|
||||
const AppPage = ({}) => {
|
||||
export default function AppPage({}) {
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -139,6 +139,4 @@ const AppPage = ({}) => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppPage;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
@@ -33,7 +33,7 @@ const libraries = [
|
||||
},
|
||||
];
|
||||
|
||||
export const Libraries = () => {
|
||||
export function Libraries() {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-slate-900/5 sm:grid-cols-2 xl:max-w-none xl:grid-cols-3 dark:border-white/5">
|
||||
@@ -57,4 +57,4 @@ export const Libraries = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -80,11 +80,6 @@ formbricks.init({
|
||||
|
||||
You can use the setAttribute function to set any custom attribute for the user (e.g. name, plan, etc.):
|
||||
|
||||
<Note>
|
||||
Please note that the number of different attribute classes (e.g., "Plan," "First Name," etc.) is currently
|
||||
limited to 150 attributes per environment.
|
||||
</Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Setting Custom Attributes">
|
||||
|
||||
@@ -120,4 +115,4 @@ formbricks.logout();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Col>
|
||||
@@ -135,7 +135,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/Popover"
|
||||
|
||||
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
|
||||
|
||||
export const DocsFeedback = () => {
|
||||
export default function DocsFeedback() {
|
||||
const router = useRouter();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [sharedFeedback, setSharedFeedback] = useState(false);
|
||||
@@ -199,7 +199,7 @@ export const DocsFeedback = () => {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@formbricks/ui/Accordion";
|
||||
|
||||
import { FaqJsonLdComponent } from "./FAQPageJsonLd";
|
||||
import FaqJsonLdComponent from "./FAQPageJsonLd";
|
||||
|
||||
const FAQ_DATA = [
|
||||
{
|
||||
@@ -62,7 +62,7 @@ export const faqJsonLdData = FAQ_DATA.map((faq) => ({
|
||||
acceptedAnswerText: faq.answer(),
|
||||
}));
|
||||
|
||||
export const FAQ = () => {
|
||||
export default function FAQ() {
|
||||
return (
|
||||
<>
|
||||
<FaqJsonLdComponent data={faqJsonLdData} />
|
||||
@@ -76,4 +76,4 @@ export const FAQ = () => {
|
||||
</Accordion>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
import { FAQPageJsonLd } from "next-seo";
|
||||
|
||||
export const FaqJsonLdComponent = ({ data }) => {
|
||||
export default function FaqJsonLdComponent({ data }) {
|
||||
const faqEntities = data.map(({ question, answer }) => ({
|
||||
questionName: question,
|
||||
acceptedAnswerText: answer,
|
||||
}));
|
||||
|
||||
return <FAQPageJsonLd mainEntity={faqEntities} />;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const gettingStarted = [
|
||||
},
|
||||
];
|
||||
|
||||
export const GettingStarted = () => {
|
||||
export function GettingStarted() {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<Heading level={2} id="getting-started">
|
||||
@@ -47,4 +47,4 @@ export const GettingStarted = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export const metadata: Metadata = {
|
||||
|
||||
const jost = Jost({ subsets: ["latin"] });
|
||||
|
||||
const RootLayout = async ({ children }: { children: React.ReactNode }) => {
|
||||
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
let pages = await glob("**/*.mdx", { cwd: "src/app" });
|
||||
let allSectionsEntries = (await Promise.all(
|
||||
pages.map(async (filename) => [
|
||||
@@ -36,6 +36,4 @@ const RootLayout = async ({ children }: { children: React.ReactNode }) => {
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
};
|
||||
|
||||
export default RootLayout;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button } from "@/components/Button";
|
||||
import { HeroPattern } from "@/components/HeroPattern";
|
||||
|
||||
const NotFound = () => {
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<>
|
||||
<HeroPattern />
|
||||
@@ -17,6 +17,4 @@ const NotFound = () => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFound;
|
||||
}
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
import { ThemeProvider, useTheme } from "next-themes";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const ThemeWatcher = () => {
|
||||
function ThemeWatcher() {
|
||||
let { resolvedTheme, setTheme } = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
let media = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
const onMediaChange = () => {
|
||||
function onMediaChange() {
|
||||
let systemTheme = media.matches ? "dark" : "light";
|
||||
if (resolvedTheme === systemTheme) {
|
||||
setTheme("system");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onMediaChange();
|
||||
media.addEventListener("change", onMediaChange);
|
||||
@@ -25,13 +25,13 @@ const ThemeWatcher = () => {
|
||||
}, [resolvedTheme, setTheme]);
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
export const Providers = ({ children }: { children: React.ReactNode }) => {
|
||||
export function Providers({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ThemeProvider attribute="class" disableTransitionOnChange>
|
||||
<ThemeWatcher />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,12 +17,6 @@ Formbricks v2.0 comes with huge features such as Multi-Language Surveys and Adva
|
||||
the upgrade. Follow the below steps thoroughly to upgrade your Formbricks instance to v2.0.
|
||||
</Note>
|
||||
|
||||
and
|
||||
|
||||
<Note>
|
||||
If you've used the Formbricks Enterprise Edition with a free beta license key, your instance will be downgraded to the Community Edition 2.0. You find all license details on the [license page.](/self-hosting/license/)
|
||||
</Note>
|
||||
|
||||
### Steps to Migrate
|
||||
|
||||
This guide is for users who are self-hosting Formbricks using our one-click setup. If you are using a different setup, you might adjust the commands accordingly.
|
||||
|
||||
@@ -33,7 +33,7 @@ const libraries = [
|
||||
},
|
||||
];
|
||||
|
||||
export const Libraries = () => {
|
||||
export function Libraries() {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-slate-900/5 sm:grid-cols-2 xl:max-w-none xl:grid-cols-3 dark:border-white/5">
|
||||
@@ -57,4 +57,4 @@ export const Libraries = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import clsx from "clsx";
|
||||
import Link from "next/link";
|
||||
|
||||
const ArrowIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function ArrowIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -12,7 +12,7 @@ const ArrowIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const variantStyles = {
|
||||
primary:
|
||||
@@ -34,7 +34,7 @@ type ButtonProps = {
|
||||
| (React.ComponentPropsWithoutRef<"button"> & { href?: undefined })
|
||||
);
|
||||
|
||||
export const Button = ({ variant = "primary", className, children, arrow, ...props }: ButtonProps) => {
|
||||
export function Button({ variant = "primary", className, children, arrow, ...props }: ButtonProps) {
|
||||
className = clsx(
|
||||
"inline-flex gap-0.5 justify-center items-center overflow-hidden font-medium transition text-center",
|
||||
variantStyles[variant],
|
||||
@@ -74,4 +74,4 @@ export const Button = ({ variant = "primary", className, children, arrow, ...pro
|
||||
{inner}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const languageNames: Record<string, string> = {
|
||||
go: "Go",
|
||||
};
|
||||
|
||||
const getPanelTitle = ({ title, language }: { title?: string; language?: string }) => {
|
||||
function getPanelTitle({ title, language }: { title?: string; language?: string }) {
|
||||
if (title) {
|
||||
return title;
|
||||
}
|
||||
@@ -25,9 +25,9 @@ const getPanelTitle = ({ title, language }: { title?: string; language?: string
|
||||
return languageNames[language];
|
||||
}
|
||||
return "Code";
|
||||
};
|
||||
}
|
||||
|
||||
const ClipboardIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function ClipboardIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -41,9 +41,9 @@ const ClipboardIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const CopyButton = ({ code }: { code: string }) => {
|
||||
function CopyButton({ code }: { code: string }) {
|
||||
let [copyCount, setCopyCount] = useState(0);
|
||||
let copied = copyCount > 0;
|
||||
|
||||
@@ -89,9 +89,9 @@ const CopyButton = ({ code }: { code: string }) => {
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const CodePanelHeader = ({ tag, label }: { tag?: string; label?: string }) => {
|
||||
function CodePanelHeader({ tag, label }: { tag?: string; label?: string }) {
|
||||
if (!tag && !label) {
|
||||
return null;
|
||||
}
|
||||
@@ -107,9 +107,9 @@ const CodePanelHeader = ({ tag, label }: { tag?: string; label?: string }) => {
|
||||
{label && <span className="font-mono text-xs text-slate-400">{label}</span>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const CodePanel = ({
|
||||
function CodePanel({
|
||||
children,
|
||||
tag,
|
||||
label,
|
||||
@@ -119,7 +119,7 @@ const CodePanel = ({
|
||||
tag?: string;
|
||||
label?: string;
|
||||
code?: string;
|
||||
}) => {
|
||||
}) {
|
||||
let child = Children.only(children);
|
||||
|
||||
if (isValidElement(child)) {
|
||||
@@ -141,9 +141,9 @@ const CodePanel = ({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const CodeGroupHeader = ({
|
||||
function CodeGroupHeader({
|
||||
title,
|
||||
children,
|
||||
selectedIndex,
|
||||
@@ -151,7 +151,7 @@ const CodeGroupHeader = ({
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
selectedIndex: number;
|
||||
}) => {
|
||||
}) {
|
||||
let hasTabs = Children.count(children) >= 1;
|
||||
|
||||
if (!title && !hasTabs) {
|
||||
@@ -178,9 +178,9 @@ const CodeGroupHeader = ({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const CodeGroupPanels = ({ children, ...props }: React.ComponentPropsWithoutRef<typeof CodePanel>) => {
|
||||
function CodeGroupPanels({ children, ...props }: React.ComponentPropsWithoutRef<typeof CodePanel>) {
|
||||
let hasTabs = Children.count(children) >= 1;
|
||||
|
||||
if (hasTabs) {
|
||||
@@ -196,9 +196,9 @@ const CodeGroupPanels = ({ children, ...props }: React.ComponentPropsWithoutRef<
|
||||
}
|
||||
|
||||
return <CodePanel {...props}>{children}</CodePanel>;
|
||||
};
|
||||
}
|
||||
|
||||
const usePreventLayoutShift = () => {
|
||||
function usePreventLayoutShift() {
|
||||
let positionRef = useRef<HTMLElement>(null);
|
||||
let rafRef = useRef<number>();
|
||||
|
||||
@@ -227,7 +227,7 @@ const usePreventLayoutShift = () => {
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const usePreferredLanguageStore = create<{
|
||||
preferredLanguages: Array<string>;
|
||||
@@ -243,7 +243,7 @@ const usePreferredLanguageStore = create<{
|
||||
})),
|
||||
}));
|
||||
|
||||
const useTabGroupProps = (availableLanguages: Array<string>) => {
|
||||
function useTabGroupProps(availableLanguages: Array<string>) {
|
||||
let { preferredLanguages, addPreferredLanguage } = usePreferredLanguageStore();
|
||||
let [selectedIndex, setSelectedIndex] = useState(0);
|
||||
let activeLanguage = [...availableLanguages].sort(
|
||||
@@ -265,15 +265,15 @@ const useTabGroupProps = (availableLanguages: Array<string>) => {
|
||||
preventLayoutShift(() => addPreferredLanguage(availableLanguages[newSelectedIndex]));
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const CodeGroupContext = createContext(false);
|
||||
|
||||
export const CodeGroup = ({
|
||||
export function CodeGroup({
|
||||
children,
|
||||
title,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<typeof CodeGroupPanels> & { title: string }) => {
|
||||
}: React.ComponentPropsWithoutRef<typeof CodeGroupPanels> & { title: string }) {
|
||||
let languages =
|
||||
Children.map(children, (child) => getPanelTitle(isValidElement(child) ? child.props : {})) ?? [];
|
||||
let tabGroupProps = useTabGroupProps(languages);
|
||||
@@ -303,9 +303,9 @@ export const CodeGroup = ({
|
||||
)}
|
||||
</CodeGroupContext.Provider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Code = ({ children, ...props }: React.ComponentPropsWithoutRef<"code">) => {
|
||||
export function Code({ children, ...props }: React.ComponentPropsWithoutRef<"code">) {
|
||||
let isGrouped = useContext(CodeGroupContext);
|
||||
|
||||
if (isGrouped) {
|
||||
@@ -316,9 +316,9 @@ export const Code = ({ children, ...props }: React.ComponentPropsWithoutRef<"cod
|
||||
}
|
||||
|
||||
return <code {...props}>{children}</code>;
|
||||
};
|
||||
}
|
||||
|
||||
export const Pre = ({ children, ...props }: React.ComponentPropsWithoutRef<typeof CodeGroup>) => {
|
||||
export function Pre({ children, ...props }: React.ComponentPropsWithoutRef<typeof CodeGroup>) {
|
||||
let isGrouped = useContext(CodeGroupContext);
|
||||
|
||||
if (isGrouped) {
|
||||
@@ -326,4 +326,4 @@ export const Pre = ({ children, ...props }: React.ComponentPropsWithoutRef<typeo
|
||||
}
|
||||
|
||||
return <CodeGroup {...props}>{children}</CodeGroup>;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { Fragment, forwardRef, useState } from "react";
|
||||
|
||||
const CheckIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function CheckIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<circle cx="10" cy="10" r="10" strokeWidth="0" />
|
||||
@@ -16,9 +16,9 @@ const CheckIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const FeedbackButton = (props: Omit<React.ComponentPropsWithoutRef<"button">, "type" | "className">) => {
|
||||
function FeedbackButton(props: Omit<React.ComponentPropsWithoutRef<"button">, "type" | "className">) {
|
||||
return (
|
||||
<button
|
||||
type="submit"
|
||||
@@ -26,12 +26,12 @@ const FeedbackButton = (props: Omit<React.ComponentPropsWithoutRef<"button">, "t
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const FeedbackForm = forwardRef<
|
||||
React.ElementRef<"form">,
|
||||
Pick<React.ComponentPropsWithoutRef<"form">, "onSubmit">
|
||||
>(({ onSubmit }, ref) => {
|
||||
>(function FeedbackForm({ onSubmit }, ref) {
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
@@ -47,9 +47,7 @@ const FeedbackForm = forwardRef<
|
||||
);
|
||||
});
|
||||
|
||||
FeedbackForm.displayName = "FeedbackForm";
|
||||
|
||||
const FeedbackThanks = forwardRef<React.ElementRef<"div">>((_props, ref) => {
|
||||
const FeedbackThanks = forwardRef<React.ElementRef<"div">>(function FeedbackThanks(_props, ref) {
|
||||
return (
|
||||
<div ref={ref} className="absolute inset-0 flex justify-center md:justify-start">
|
||||
<div className="flex items-center gap-3 rounded-full bg-teal-50/50 py-1 pl-1.5 pr-3 text-sm text-teal-900 ring-1 ring-inset ring-teal-500/20 dark:bg-teal-500/5 dark:text-teal-200 dark:ring-teal-500/30">
|
||||
@@ -60,19 +58,17 @@ const FeedbackThanks = forwardRef<React.ElementRef<"div">>((_props, ref) => {
|
||||
);
|
||||
});
|
||||
|
||||
FeedbackThanks.displayName = "FeedbackThanks";
|
||||
|
||||
export const Feedback = () => {
|
||||
export function Feedback() {
|
||||
let [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
|
||||
// event.nativeEvent.submitter.dataset.response
|
||||
// => "yes" or "no"
|
||||
|
||||
setSubmitted(true);
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative h-8">
|
||||
@@ -94,4 +90,4 @@ export const Feedback = () => {
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { DiscordIcon } from "./icons/DiscordIcon";
|
||||
import { GithubIcon } from "./icons/GithubIcon";
|
||||
import { TwitterIcon } from "./icons/TwitterIcon";
|
||||
|
||||
const PageLink = ({
|
||||
function PageLink({
|
||||
label,
|
||||
page,
|
||||
previous = false,
|
||||
@@ -17,7 +17,7 @@ const PageLink = ({
|
||||
label: string;
|
||||
page: { href: string; title: string };
|
||||
previous?: boolean;
|
||||
}) => {
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
@@ -36,9 +36,9 @@ const PageLink = ({
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const PageNavigation = () => {
|
||||
function PageNavigation() {
|
||||
let pathname = usePathname();
|
||||
let allPages = navigation.flatMap((group) => {
|
||||
return group.links.flatMap((link) => {
|
||||
@@ -72,9 +72,9 @@ const PageNavigation = () => {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const SocialLink = ({
|
||||
function SocialLink({
|
||||
href,
|
||||
icon: Icon,
|
||||
children,
|
||||
@@ -82,16 +82,16 @@ const SocialLink = ({
|
||||
href: string;
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
}) {
|
||||
return (
|
||||
<Link href={href} className="group">
|
||||
<span className="sr-only">{children}</span>
|
||||
<Icon className="h-5 w-5 fill-slate-700 transition group-hover:fill-slate-900 dark:group-hover:fill-slate-500" />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const SmallPrint = () => {
|
||||
function SmallPrint() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
@@ -112,13 +112,13 @@ const SmallPrint = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Footer = () => {
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="mx-auto w-full max-w-2xl space-y-10 pb-16 lg:max-w-5xl">
|
||||
<PageNavigation />
|
||||
<SmallPrint />
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useId } from "react";
|
||||
|
||||
export const GridPattern = ({
|
||||
export function GridPattern({
|
||||
width,
|
||||
height,
|
||||
x,
|
||||
@@ -13,7 +13,7 @@ export const GridPattern = ({
|
||||
x: string | number;
|
||||
y: string | number;
|
||||
squares: Array<[x: number, y: number]>;
|
||||
}) => {
|
||||
}) {
|
||||
let patternId = useId();
|
||||
|
||||
return (
|
||||
@@ -40,4 +40,4 @@ export const GridPattern = ({
|
||||
)}
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ const guides = [
|
||||
},
|
||||
];
|
||||
|
||||
export const Guides = () => {
|
||||
export function Guides() {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<Heading level={2} id="guides">
|
||||
@@ -45,4 +45,4 @@ export const Guides = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Button } from "./Button";
|
||||
import { MobileNavigation, useIsInsideMobileNavigation, useMobileNavigationStore } from "./MobileNavigation";
|
||||
import { ThemeToggle } from "./ThemeToggle";
|
||||
|
||||
const TopLevelNavItem = ({ href, children }: { href: string; children: React.ReactNode }) => {
|
||||
function TopLevelNavItem({ href, children }: { href: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
@@ -21,9 +21,12 @@ const TopLevelNavItem = ({ href, children }: { href: string; children: React.Rea
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Header = forwardRef<React.ElementRef<"div">, { className?: string }>(({ className }, ref) => {
|
||||
export const Header = forwardRef<React.ElementRef<"div">, { className?: string }>(function Header(
|
||||
{ className },
|
||||
ref
|
||||
) {
|
||||
let { isOpen: mobileNavIsOpen } = useMobileNavigationStore();
|
||||
let isInsideMobileNavigation = useIsInsideMobileNavigation();
|
||||
|
||||
@@ -88,5 +91,3 @@ export const Header = forwardRef<React.ElementRef<"div">, { className?: string }
|
||||
</motion.div>
|
||||
);
|
||||
});
|
||||
|
||||
Header.displayName = "Header";
|
||||
|
||||
@@ -7,15 +7,15 @@ import { useInView } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
const AnchorIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function AnchorIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" fill="none" strokeLinecap="round" aria-hidden="true" {...props}>
|
||||
<path d="m6.5 11.5-.964-.964a3.535 3.535 0 1 1 5-5l.964.964m2 2 .964.964a3.536 3.536 0 0 1-5 5L8.5 13.5m0-5 3 3" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const Eyebrow = ({ tag, label }: { tag?: string; label?: string }) => {
|
||||
function Eyebrow({ tag, label }: { tag?: string; label?: string }) {
|
||||
if (!tag && !label) {
|
||||
return null;
|
||||
}
|
||||
@@ -27,9 +27,9 @@ const Eyebrow = ({ tag, label }: { tag?: string; label?: string }) => {
|
||||
{label && <span className="font-mono text-xs text-zinc-400">{label}</span>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const Anchor = ({ id, inView, children }: { id: string; inView: boolean; children: React.ReactNode }) => {
|
||||
function Anchor({ id, inView, children }: { id: string; inView: boolean; children: React.ReactNode }) {
|
||||
return (
|
||||
<Link href={`#${id}`} className="group text-inherit no-underline hover:text-inherit">
|
||||
{inView && (
|
||||
@@ -42,9 +42,9 @@ const Anchor = ({ id, inView, children }: { id: string; inView: boolean; childre
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Heading = <Level extends 2 | 3>({
|
||||
export function Heading<Level extends 2 | 3>({
|
||||
children,
|
||||
tag,
|
||||
label,
|
||||
@@ -57,7 +57,7 @@ export const Heading = <Level extends 2 | 3>({
|
||||
label?: string;
|
||||
level?: Level;
|
||||
anchor?: boolean;
|
||||
}) => {
|
||||
}) {
|
||||
level = level ?? (2 as Level);
|
||||
let Component = `h${level}` as "h2" | "h3";
|
||||
let ref = useRef<HTMLHeadingElement>(null);
|
||||
@@ -88,4 +88,4 @@ export const Heading = <Level extends 2 | 3>({
|
||||
</Component>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GridPattern } from "./GridPattern";
|
||||
|
||||
export const HeroPattern = () => {
|
||||
export function HeroPattern() {
|
||||
return (
|
||||
<div className="absolute inset-0 -z-10 mx-0 max-w-none overflow-hidden">
|
||||
<div className="absolute left-1/2 top-0 ml-[-38rem] h-[25rem] w-[81.25rem] dark:[mask-image:linear-gradient(white,transparent)]">
|
||||
@@ -28,4 +28,4 @@ export const HeroPattern = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ import { Footer } from "./Footer";
|
||||
import { Header } from "./Header";
|
||||
import { type Section, SectionProvider } from "./SectionProvider";
|
||||
|
||||
export const Layout = ({
|
||||
export function Layout({
|
||||
children,
|
||||
allSections,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
allSections: Record<string, Array<Section>>;
|
||||
}) => {
|
||||
}) {
|
||||
let pathname = usePathname();
|
||||
|
||||
return (
|
||||
@@ -42,4 +42,4 @@ export const Layout = ({
|
||||
</div>
|
||||
</SectionProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import logoDark from "@/images/logo/logo-dark.svg";
|
||||
import logoLight from "@/images/logo/logo-light.svg";
|
||||
import Image from "next/image";
|
||||
|
||||
export const Logo = ({ className }: { className?: string }) => {
|
||||
export function Logo({ className }: { className?: string }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="block dark:hidden">
|
||||
@@ -13,4 +13,4 @@ export const Logo = ({ className }: { className?: string }) => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Image, { ImageProps } from "next/image";
|
||||
import React from "react";
|
||||
|
||||
export const MdxImage = (props: ImageProps) => {
|
||||
export function MdxImage(props: ImageProps) {
|
||||
return <Image {...props} alt={props.alt} />;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,25 +8,25 @@ import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { Fragment, Suspense, createContext, useContext, useEffect, useRef } from "react";
|
||||
import { create } from "zustand";
|
||||
|
||||
const MenuIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function MenuIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 10 9" fill="none" strokeLinecap="round" aria-hidden="true" {...props}>
|
||||
<path d="M.5 1h9M.5 8h9M.5 4.5h9" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const XIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function XIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 10 9" fill="none" strokeLinecap="round" aria-hidden="true" {...props}>
|
||||
<path d="m1.5 1 7 7M8.5 1l-7 7" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const IsInsideMobileNavigationContext = createContext(false);
|
||||
|
||||
const MobileNavigationDialog = ({ isOpen, close }: { isOpen: boolean; close: () => void }) => {
|
||||
function MobileNavigationDialog({ isOpen, close }: { isOpen: boolean; close: () => void }) {
|
||||
let pathname = usePathname();
|
||||
let searchParams = useSearchParams();
|
||||
let initialPathname = useRef(pathname).current;
|
||||
@@ -38,7 +38,7 @@ const MobileNavigationDialog = ({ isOpen, close }: { isOpen: boolean; close: ()
|
||||
}
|
||||
}, [pathname, searchParams, close, initialPathname, initialSearchParams]);
|
||||
|
||||
const onClickDialog = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
function onClickDialog(event: React.MouseEvent<HTMLDivElement>) {
|
||||
if (!(event.target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ const MobileNavigationDialog = ({ isOpen, close }: { isOpen: boolean; close: ()
|
||||
) {
|
||||
close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={Fragment}>
|
||||
@@ -97,11 +97,11 @@ const MobileNavigationDialog = ({ isOpen, close }: { isOpen: boolean; close: ()
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const useIsInsideMobileNavigation = () => {
|
||||
export function useIsInsideMobileNavigation() {
|
||||
return useContext(IsInsideMobileNavigationContext);
|
||||
};
|
||||
}
|
||||
|
||||
export const useMobileNavigationStore = create<{
|
||||
isOpen: boolean;
|
||||
@@ -115,7 +115,7 @@ export const useMobileNavigationStore = create<{
|
||||
toggle: () => set((state) => ({ isOpen: !state.isOpen })),
|
||||
}));
|
||||
|
||||
export const MobileNavigation = () => {
|
||||
export function MobileNavigation() {
|
||||
let isInsideMobileNavigation = useIsInsideMobileNavigation();
|
||||
let { isOpen, toggle, close } = useMobileNavigationStore();
|
||||
let ToggleIcon = isOpen ? XIcon : MenuIcon;
|
||||
@@ -136,4 +136,4 @@ export const MobileNavigation = () => {
|
||||
)}
|
||||
</IsInsideMobileNavigationContext.Provider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ export interface NavGroup {
|
||||
links: Array<LinkWithHref | LinkWithChildren>;
|
||||
}
|
||||
|
||||
const useInitialValue = <T,>(value: T, condition = true) => {
|
||||
function useInitialValue<T>(value: T, condition = true) {
|
||||
let initialValue = useRef(value).current;
|
||||
return condition ? initialValue : value;
|
||||
};
|
||||
}
|
||||
|
||||
const NavLink = ({
|
||||
function NavLink({
|
||||
href,
|
||||
children,
|
||||
active = false,
|
||||
@@ -50,7 +50,7 @@ const NavLink = ({
|
||||
children: React.ReactNode;
|
||||
active: boolean;
|
||||
isAnchorLink?: boolean;
|
||||
}) => {
|
||||
}) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
@@ -65,9 +65,9 @@ const NavLink = ({
|
||||
<span className="flex w-full truncate">{children}</span>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const VisibleSectionHighlight = ({ group, pathname }: { group: NavGroup; pathname: string }) => {
|
||||
function VisibleSectionHighlight({ group, pathname }: { group: NavGroup; pathname: string }) {
|
||||
let [sections, visibleSections] = useInitialValue(
|
||||
[useSectionStore((s) => s.sections), useSectionStore((s) => s.visibleSections)],
|
||||
useIsInsideMobileNavigation()
|
||||
@@ -99,9 +99,9 @@ const VisibleSectionHighlight = ({ group, pathname }: { group: NavGroup; pathnam
|
||||
style={{ height, top }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const ActivePageMarker = ({ group, pathname }: { group: NavGroup; pathname: string }) => {
|
||||
function ActivePageMarker({ group, pathname }: { group: NavGroup; pathname: string }) {
|
||||
let itemHeight = remToPx(2);
|
||||
let offset = remToPx(0.25);
|
||||
let activePageIndex = group.links.findIndex(
|
||||
@@ -122,9 +122,9 @@ const ActivePageMarker = ({ group, pathname }: { group: NavGroup; pathname: stri
|
||||
style={{ top }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const NavigationGroup = ({
|
||||
function NavigationGroup({
|
||||
group,
|
||||
className,
|
||||
activeGroup,
|
||||
@@ -138,7 +138,7 @@ const NavigationGroup = ({
|
||||
setActiveGroup: (group: NavGroup | null) => void;
|
||||
openGroups: string[];
|
||||
setOpenGroups: (groups: string[]) => void;
|
||||
}) => {
|
||||
}) {
|
||||
const isInsideMobileNavigation = useIsInsideMobileNavigation();
|
||||
const pathname = usePathname();
|
||||
const isActiveGroup = activeGroup?.title === group.title;
|
||||
@@ -219,9 +219,9 @@ const NavigationGroup = ({
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Navigation = (props: React.ComponentPropsWithoutRef<"nav">) => {
|
||||
export function Navigation(props: React.ComponentPropsWithoutRef<"nav">) {
|
||||
const [activeGroup, setActiveGroup] = useState<NavGroup | null>(navigation[0]);
|
||||
const [openGroups, setOpenGroups] = useState<string[]>([]);
|
||||
|
||||
@@ -251,4 +251,4 @@ export const Navigation = (props: React.ComponentPropsWithoutRef<"nav">) => {
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import clsx from "clsx";
|
||||
|
||||
export const Prose = <T extends React.ElementType = "div">({
|
||||
export function Prose<T extends React.ElementType = "div">({
|
||||
as,
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<T>, "as" | "className"> & {
|
||||
as?: T;
|
||||
className?: string;
|
||||
}) => {
|
||||
}) {
|
||||
let Component = as ?? "div";
|
||||
|
||||
return (
|
||||
@@ -21,4 +21,4 @@ export const Prose = <T extends React.ElementType = "div">({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,22 +72,22 @@ const resources: Array<Resource> = [
|
||||
},
|
||||
];
|
||||
|
||||
const ResourceIcon = ({ icon: Icon }: { icon: Resource["icon"] }) => {
|
||||
function ResourceIcon({ icon: Icon }: { icon: Resource["icon"] }) {
|
||||
return (
|
||||
<div className="dark:bg-white/7.5 flex h-7 w-7 items-center justify-center rounded-full bg-zinc-900/5 ring-1 ring-zinc-900/25 backdrop-blur-[2px] transition duration-300 group-hover:bg-white/50 group-hover:ring-zinc-900/25 dark:ring-white/15 dark:group-hover:bg-teal-300/10 dark:group-hover:ring-teal-400">
|
||||
<Icon className="h-5 w-5 fill-zinc-700/10 stroke-zinc-700 transition-colors duration-300 group-hover:stroke-zinc-900 dark:fill-white/10 dark:stroke-zinc-400 dark:group-hover:fill-teal-300/10 dark:group-hover:stroke-teal-400" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const ResourcePattern = ({
|
||||
function ResourcePattern({
|
||||
mouseX,
|
||||
mouseY,
|
||||
...gridProps
|
||||
}: Resource["pattern"] & {
|
||||
mouseX: MotionValue<number>;
|
||||
mouseY: MotionValue<number>;
|
||||
}) => {
|
||||
}) {
|
||||
let maskImage = useMotionTemplate`radial-gradient(180px at ${mouseX}px ${mouseY}px, white, transparent)`;
|
||||
let style = { maskImage, WebkitMaskImage: maskImage };
|
||||
|
||||
@@ -119,17 +119,17 @@ const ResourcePattern = ({
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const Resource = ({ resource }: { resource: Resource }) => {
|
||||
function Resource({ resource }: { resource: Resource }) {
|
||||
let mouseX = useMotionValue(0);
|
||||
let mouseY = useMotionValue(0);
|
||||
|
||||
const onMouseMove = ({ currentTarget, clientX, clientY }: React.MouseEvent<HTMLDivElement>) => {
|
||||
function onMouseMove({ currentTarget, clientX, clientY }: React.MouseEvent<HTMLDivElement>) {
|
||||
let { left, top } = currentTarget.getBoundingClientRect();
|
||||
mouseX.set(clientX - left);
|
||||
mouseY.set(clientY - top);
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -150,9 +150,9 @@ const Resource = ({ resource }: { resource: Resource }) => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Resources = () => {
|
||||
export function Resources() {
|
||||
return (
|
||||
<div className="my-16 xl:max-w-none">
|
||||
<Heading level={2} id="resources">
|
||||
@@ -165,4 +165,4 @@ export const Resources = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// ResponsiveVideo.js
|
||||
export const ResponsiveVideo = ({ src, title }) => {
|
||||
export function ResponsiveVideo({ src, title }) {
|
||||
return (
|
||||
<div className="relative w-full overflow-hidden pt-[56.25%]">
|
||||
<iframe
|
||||
@@ -12,4 +12,4 @@ export const ResponsiveVideo = ({ src, title }) => {
|
||||
allowFullScreen></iframe>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,19 +16,19 @@ interface HitProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const Hit = ({ hit, children }: HitProps) => {
|
||||
function Hit({ hit, children }: HitProps) {
|
||||
return <Link href={hit.url}>{children}</Link>;
|
||||
};
|
||||
}
|
||||
|
||||
const SearchIcon = (props: any) => {
|
||||
function SearchIcon(props: any) {
|
||||
return (
|
||||
<svg aria-hidden="true" viewBox="0 0 20 20" {...props}>
|
||||
<path d="M16.293 17.707a1 1 0 0 0 1.414-1.414l-1.414 1.414ZM9 14a5 5 0 0 1-5-5H2a7 7 0 0 0 7 7v-2ZM4 9a5 5 0 0 1 5-5V2a7 7 0 0 0-7 7h2Zm5-5a5 5 0 0 1 5 5h2a7 7 0 0 0-7-7v2Zm8.707 12.293-3.757-3.757-1.414 1.414 3.757 3.757 1.414-1.414ZM14 9a4.98 4.98 0 0 1-1.464 3.536l1.414 1.414A6.98 6.98 0 0 0 16 9h-2Zm-1.464 3.536A4.98 4.98 0 0 1 9 14v2a6.98 6.98 0 0 0 4.95-2.05l-1.414-1.414Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Search = () => {
|
||||
export function Search() {
|
||||
let { resolvedTheme } = useTheme();
|
||||
let isLightMode = resolvedTheme === "light";
|
||||
|
||||
@@ -132,4 +132,4 @@ export const Search = () => {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ interface SectionState {
|
||||
}) => void;
|
||||
}
|
||||
|
||||
const createSectionStore = (sections: Array<Section>) => {
|
||||
function createSectionStore(sections: Array<Section>) {
|
||||
return createStore<SectionState>()((set) => ({
|
||||
sections,
|
||||
visibleSections: [],
|
||||
@@ -49,14 +49,14 @@ const createSectionStore = (sections: Array<Section>) => {
|
||||
};
|
||||
}),
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
const useVisibleSections = (sectionStore: StoreApi<SectionState>) => {
|
||||
function useVisibleSections(sectionStore: StoreApi<SectionState>) {
|
||||
let setVisibleSections = useStore(sectionStore, (s) => s.setVisibleSections);
|
||||
let sections = useStore(sectionStore, (s) => s.sections);
|
||||
|
||||
useEffect(() => {
|
||||
const checkVisibleSections = () => {
|
||||
function checkVisibleSections() {
|
||||
let { innerHeight, scrollY } = window;
|
||||
let newVisibleSections: string[] = [];
|
||||
|
||||
@@ -90,7 +90,7 @@ const useVisibleSections = (sectionStore: StoreApi<SectionState>) => {
|
||||
}
|
||||
|
||||
setVisibleSections(newVisibleSections);
|
||||
};
|
||||
}
|
||||
|
||||
let raf = window.requestAnimationFrame(() => checkVisibleSections());
|
||||
window.addEventListener("scroll", checkVisibleSections, { passive: true });
|
||||
@@ -102,19 +102,19 @@ const useVisibleSections = (sectionStore: StoreApi<SectionState>) => {
|
||||
window.removeEventListener("resize", checkVisibleSections);
|
||||
};
|
||||
}, [setVisibleSections, sections]);
|
||||
};
|
||||
}
|
||||
|
||||
const SectionStoreContext = createContext<StoreApi<SectionState> | null>(null);
|
||||
|
||||
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
||||
|
||||
export const SectionProvider = ({
|
||||
export function SectionProvider({
|
||||
sections,
|
||||
children,
|
||||
}: {
|
||||
sections: Array<Section>;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
}) {
|
||||
let [sectionStore] = useState(() => createSectionStore(sections));
|
||||
|
||||
useVisibleSections(sectionStore);
|
||||
@@ -124,9 +124,9 @@ export const SectionProvider = ({
|
||||
}, [sectionStore, sections]);
|
||||
|
||||
return <SectionStoreContext.Provider value={sectionStore}>{children}</SectionStoreContext.Provider>;
|
||||
};
|
||||
}
|
||||
|
||||
export const useSectionStore = <T,>(selector: (state: SectionState) => T) => {
|
||||
const store = useContext(SectionStoreContext);
|
||||
export function useSectionStore<T>(selector: (state: SectionState) => T) {
|
||||
let store = useContext(SectionStoreContext);
|
||||
return useStore(store!, selector);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ const valueColorMap = {
|
||||
DELETE: "rose",
|
||||
} as Record<string, keyof typeof colorStyles>;
|
||||
|
||||
export const Tag = ({
|
||||
export function Tag({
|
||||
children,
|
||||
variant = "medium",
|
||||
color = valueColorMap[children] ?? "teal",
|
||||
@@ -47,7 +47,7 @@ export const Tag = ({
|
||||
children: keyof typeof valueColorMap & (string | {});
|
||||
variant?: keyof typeof variantStyles;
|
||||
color?: keyof typeof colorStyles;
|
||||
}) => {
|
||||
}) {
|
||||
return (
|
||||
<span
|
||||
className={clsx(
|
||||
@@ -58,4 +58,4 @@ export const Tag = ({
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
|
||||
export const TellaVideo = ({ tellaVideoIdentifier }: { tellaVideoIdentifier: string }) => {
|
||||
export function TellaVideo({ tellaVideoIdentifier }: { tellaVideoIdentifier: string }) {
|
||||
return (
|
||||
<div>
|
||||
<iframe
|
||||
@@ -15,4 +15,4 @@ export const TellaVideo = ({ tellaVideoIdentifier }: { tellaVideoIdentifier: str
|
||||
title="Tella Video Help"></iframe>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useTheme } from "next-themes";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const SunIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function SunIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" {...props}>
|
||||
<path d="M12.5 10a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0Z" />
|
||||
@@ -11,17 +11,17 @@ const SunIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const MoonIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function MoonIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" {...props}>
|
||||
<path d="M15.224 11.724a5.5 5.5 0 0 1-6.949-6.949 5.5 5.5 0 1 0 6.949 6.949Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const ThemeToggle = () => {
|
||||
export function ThemeToggle() {
|
||||
let { resolvedTheme, setTheme } = useTheme();
|
||||
let otherTheme = resolvedTheme === "dark" ? "light" : "dark";
|
||||
let [mounted, setMounted] = useState(false);
|
||||
@@ -40,4 +40,4 @@ export const ThemeToggle = () => {
|
||||
<MoonIcon className="hidden h-5 w-5 stroke-white dark:block" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const BellIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function BellIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -14,4 +14,4 @@ export const BellIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const BoltIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function BoltIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -8,4 +8,4 @@ export const BoltIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const BookIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function BookIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -10,4 +10,4 @@ export const BookIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m17.5 2.5-7.5 3v12l7.5-3v-12Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const CalendarIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function CalendarIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -15,4 +15,4 @@ export const CalendarIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<path fill="none" strokeLinecap="round" strokeLinejoin="round" d="M5.5 5.5v-3M14.5 5.5v-3" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const CartIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function CartIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -12,4 +12,4 @@ export const CartIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const ChatBubbleIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function ChatBubbleIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -9,4 +9,4 @@ export const ChatBubbleIcon = (props: React.ComponentPropsWithoutRef<"svg">) =>
|
||||
<path fill="none" strokeLinecap="round" strokeLinejoin="round" d="M7.5 8.5h5M8.5 11.5h3" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export const CheckIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function CheckIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10 1.5a8.5 8.5 0 1 1 0 17 8.5 8.5 0 0 1 0-17Z" />
|
||||
<path fill="none" strokeLinecap="round" strokeLinejoin="round" d="m7.5 10.5 2 2c1-3.5 3-5 3-5" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const ChevronRightLeftIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function ChevronRightLeftIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -14,4 +14,4 @@ export const ChevronRightLeftIcon = (props: React.ComponentPropsWithoutRef<"svg"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const ClipboardIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function ClipboardIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -14,4 +14,4 @@ export const ClipboardIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const CogIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function CogIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -16,4 +16,4 @@ export const CogIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<circle cx="10" cy="10" r="2.5" fill="none" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const CopyIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function CopyIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -14,4 +14,4 @@ export const CopyIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const DocumentIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function DocumentIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -9,4 +9,4 @@ export const DocumentIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<path fill="none" strokeLinecap="round" strokeLinejoin="round" d="m11.5 2.5 5 5" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const EnvelopeIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function EnvelopeIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -14,4 +14,4 @@ export const EnvelopeIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const FaceSmileIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function FaceSmileIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10 1.5a8.5 8.5 0 1 1 0 17 8.5 8.5 0 0 1 0-17Z" />
|
||||
@@ -10,4 +10,4 @@ export const FaceSmileIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const FolderIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function FolderIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -16,4 +16,4 @@ export const FolderIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const LinkIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function LinkIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -9,4 +9,4 @@ export const LinkIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const ListIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function ListIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -9,4 +9,4 @@ export const ListIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<path fill="none" strokeLinecap="round" strokeLinejoin="round" d="M6.5 6.5h7M6.5 13.5h7M6.5 10h7" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const MagnifyingGlassIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function MagnifyingGlassIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path strokeWidth="0" d="M2.5 8.5a6 6 0 1 1 12 0 6 6 0 0 1-12 0Z" />
|
||||
@@ -10,4 +10,4 @@ export const MagnifyingGlassIcon = (props: React.ComponentPropsWithoutRef<"svg">
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const MapPinIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function MapPinIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -16,4 +16,4 @@ export const MapPinIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<circle cx="10" cy="8" r="1.5" fill="none" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const PackageIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function PackageIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path strokeWidth="0" d="m10 9.5-7.5-4v9l7.5 4v-9ZM10 9.5l7.5-4v9l-7.5 4v-9Z" />
|
||||
@@ -10,4 +10,4 @@ export const PackageIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const PaperAirplaneIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function PaperAirplaneIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -10,4 +10,4 @@ export const PaperAirplaneIcon = (props: React.ComponentPropsWithoutRef<"svg">)
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M11 19L8 12L17 3L11 19Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const PaperClipIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function PaperClipIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -9,4 +9,4 @@ export const PaperClipIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const ShapesIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function ShapesIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -14,4 +14,4 @@ export const ShapesIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const ShirtIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function ShirtIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -8,4 +8,4 @@ export const ShirtIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const SquaresPlusIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function SquaresPlusIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -9,4 +9,4 @@ export const SquaresPlusIcon = (props: React.ComponentPropsWithoutRef<"svg">) =>
|
||||
<path fill="none" strokeLinecap="round" strokeLinejoin="round" d="M14.5 11.5v6M17.5 14.5h-6" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const TagIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function TagIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -16,4 +16,4 @@ export const TagIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<circle cx="7" cy="7" r="1.5" fill="none" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const UserIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function UserIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -21,4 +21,4 @@ export const UserIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const UsersIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
export function UsersIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path
|
||||
@@ -21,4 +21,4 @@ export const UsersIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13 2a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const a = Link;
|
||||
export { Button } from "@/components/Button";
|
||||
export { CodeGroup, Code as code, Pre as pre } from "@/components/Code";
|
||||
|
||||
export const wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
export function wrapper({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<article className="flex h-full flex-col pb-10 pt-16">
|
||||
<Prose className="flex-auto font-normal">{children}</Prose>
|
||||
@@ -17,13 +17,13 @@ export const wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
</footer>
|
||||
</article>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const h2 = (props: Omit<React.ComponentPropsWithoutRef<typeof Heading>, "level">) => {
|
||||
export const h2 = function H2(props: Omit<React.ComponentPropsWithoutRef<typeof Heading>, "level">) {
|
||||
return <Heading level={2} {...props} />;
|
||||
};
|
||||
|
||||
const InfoIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
function InfoIcon(props: React.ComponentPropsWithoutRef<"svg">) {
|
||||
return (
|
||||
<svg viewBox="0 0 16 16" aria-hidden="true" {...props}>
|
||||
<circle cx="8" cy="8" r="8" strokeWidth="0" />
|
||||
@@ -37,34 +37,34 @@ const InfoIcon = (props: React.ComponentPropsWithoutRef<"svg">) => {
|
||||
<circle cx="8" cy="4" r=".5" fill="none" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Note = ({ children }: { children: React.ReactNode }) => {
|
||||
export function Note({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="my-6 flex gap-2.5 rounded-2xl border border-teal-500/20 bg-teal-50/50 p-4 leading-6 text-teal-900 dark:border-teal-500/30 dark:bg-teal-500/5 dark:text-teal-200 dark:[--tw-prose-links-hover:theme(colors.teal.300)] dark:[--tw-prose-links:theme(colors.white)]">
|
||||
<InfoIcon className="mt-1 h-4 w-4 flex-none fill-teal-500 stroke-white dark:fill-teal-200/20 dark:stroke-teal-200" />
|
||||
<div className="[&>:first-child]:mt-0 [&>:last-child]:mb-0">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Row = ({ children }: { children: React.ReactNode }) => {
|
||||
export function Row({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="grid grid-cols-1 items-start gap-x-16 gap-y-10 xl:max-w-none xl:grid-cols-2">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Col = ({ children, sticky = false }: { children: React.ReactNode; sticky?: boolean }) => {
|
||||
export function Col({ children, sticky = false }: { children: React.ReactNode; sticky?: boolean }) {
|
||||
return (
|
||||
<div className={clsx("[&>:first-child]:mt-0 [&>:last-child]:mb-0", sticky && "xl:sticky xl:top-24")}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Properties = ({ children }: { children: React.ReactNode }) => {
|
||||
export function Properties({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="my-6">
|
||||
<ul
|
||||
@@ -74,9 +74,9 @@ export const Properties = ({ children }: { children: React.ReactNode }) => {
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Property = ({
|
||||
export function Property({
|
||||
name,
|
||||
children,
|
||||
type,
|
||||
@@ -84,7 +84,7 @@ export const Property = ({
|
||||
name: string;
|
||||
children: React.ReactNode;
|
||||
type?: string;
|
||||
}) => {
|
||||
}) {
|
||||
return (
|
||||
<li className="m-0 px-0 py-4 first:pt-0 last:pb-0">
|
||||
<dl className="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
|
||||
@@ -103,4 +103,4 @@ export const Property = ({
|
||||
</dl>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export const remToPx = (remValue: number) => {
|
||||
export function remToPx(remValue: number) {
|
||||
let rootFontSize =
|
||||
typeof window === "undefined"
|
||||
? 16
|
||||
: parseFloat(window.getComputedStyle(document.documentElement).fontSize);
|
||||
|
||||
return remValue * rootFontSize;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as mdxComponents from "@/components/mdx";
|
||||
import { type MDXComponents } from "mdx/types";
|
||||
|
||||
export const useMDXComponents = (components: MDXComponents) => {
|
||||
export function useMDXComponents(components: MDXComponents) {
|
||||
return {
|
||||
...components,
|
||||
...mdxComponents,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,35 +1,42 @@
|
||||
import { slugifyWithCounter } from "@sindresorhus/slugify";
|
||||
import * as acorn from "acorn";
|
||||
import { toString } from "mdast-util-to-string";
|
||||
import { mdxAnnotations } from "mdx-annotations";
|
||||
import { getHighlighter, renderToHtml } from "shiki";
|
||||
import { visit } from "unist-util-visit";
|
||||
import { slugifyWithCounter } from '@sindresorhus/slugify'
|
||||
import * as acorn from 'acorn'
|
||||
import { toString } from 'mdast-util-to-string'
|
||||
import { mdxAnnotations } from 'mdx-annotations'
|
||||
import { getHighlighter, renderToHtml } from 'shiki'
|
||||
import { visit } from 'unist-util-visit'
|
||||
|
||||
const rehypeParseCodeBlocks = () => {
|
||||
function rehypeParseCodeBlocks() {
|
||||
return (tree) => {
|
||||
visit(tree, "element", (node, _nodeIndex, parentNode) => {
|
||||
if (node.tagName === "code" && node.properties.className) {
|
||||
parentNode.properties.language = node.properties.className[0]?.replace(/^language-/, "");
|
||||
visit(tree, 'element', (node, _nodeIndex, parentNode) => {
|
||||
if (node.tagName === 'code' && node.properties.className) {
|
||||
parentNode.properties.language = node.properties.className[0]?.replace(
|
||||
/^language-/,
|
||||
'',
|
||||
)
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let highlighter;
|
||||
let highlighter
|
||||
|
||||
const rehypeShiki = () => {
|
||||
function rehypeShiki() {
|
||||
return async (tree) => {
|
||||
highlighter = highlighter ?? (await getHighlighter({ theme: "css-variables" }));
|
||||
highlighter =
|
||||
highlighter ?? (await getHighlighter({ theme: 'css-variables' }))
|
||||
|
||||
visit(tree, "element", (node) => {
|
||||
if (node.tagName === "pre" && node.children[0]?.tagName === "code") {
|
||||
let codeNode = node.children[0];
|
||||
let textNode = codeNode.children[0];
|
||||
visit(tree, 'element', (node) => {
|
||||
if (node.tagName === 'pre' && node.children[0]?.tagName === 'code') {
|
||||
let codeNode = node.children[0]
|
||||
let textNode = codeNode.children[0]
|
||||
|
||||
node.properties.code = textNode.value;
|
||||
node.properties.code = textNode.value
|
||||
|
||||
if (node.properties.language) {
|
||||
let tokens = highlighter.codeToThemedTokens(textNode.value, node.properties.language);
|
||||
let tokens = highlighter.codeToThemedTokens(
|
||||
textNode.value,
|
||||
node.properties.language,
|
||||
)
|
||||
|
||||
textNode.value = renderToHtml(tokens, {
|
||||
elements: {
|
||||
@@ -37,68 +44,71 @@ const rehypeShiki = () => {
|
||||
code: ({ children }) => children,
|
||||
line: ({ children }) => `<span>${children}</span>`,
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const rehypeSlugify = () => {
|
||||
function rehypeSlugify() {
|
||||
return (tree) => {
|
||||
let slugify = slugifyWithCounter();
|
||||
visit(tree, "element", (node) => {
|
||||
if (node.tagName === "h2" && !node.properties.id) {
|
||||
node.properties.id = slugify(toString(node));
|
||||
let slugify = slugifyWithCounter()
|
||||
visit(tree, 'element', (node) => {
|
||||
if (node.tagName === 'h2' && !node.properties.id) {
|
||||
node.properties.id = slugify(toString(node))
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const rehypeAddMDXExports = (getExports) => {
|
||||
function rehypeAddMDXExports(getExports) {
|
||||
return (tree) => {
|
||||
let exports = Object.entries(getExports(tree));
|
||||
let exports = Object.entries(getExports(tree))
|
||||
|
||||
for (let [name, value] of exports) {
|
||||
for (let node of tree.children) {
|
||||
if (node.type === "mdxjsEsm" && new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value)) {
|
||||
return;
|
||||
if (
|
||||
node.type === 'mdxjsEsm' &&
|
||||
new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value)
|
||||
) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let exportStr = `export const ${name} = ${value}`;
|
||||
let exportStr = `export const ${name} = ${value}`
|
||||
|
||||
tree.children.push({
|
||||
type: "mdxjsEsm",
|
||||
type: 'mdxjsEsm',
|
||||
value: exportStr,
|
||||
data: {
|
||||
estree: acorn.parse(exportStr, {
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
}),
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const getSections = (node) => {
|
||||
let sections = [];
|
||||
function getSections(node) {
|
||||
let sections = []
|
||||
|
||||
for (let child of node.children ?? []) {
|
||||
if (child.type === "element" && child.tagName === "h2") {
|
||||
if (child.type === 'element' && child.tagName === 'h2') {
|
||||
sections.push(`{
|
||||
title: ${JSON.stringify(toString(child))},
|
||||
id: ${JSON.stringify(child.properties.id)},
|
||||
...${child.properties.annotation}
|
||||
}`);
|
||||
}`)
|
||||
} else if (child.children) {
|
||||
sections.push(...getSections(child));
|
||||
sections.push(...getSections(child))
|
||||
}
|
||||
}
|
||||
|
||||
return sections;
|
||||
};
|
||||
return sections
|
||||
}
|
||||
|
||||
export const rehypePlugins = [
|
||||
mdxAnnotations.rehype,
|
||||
@@ -111,4 +121,4 @@ export const rehypePlugins = [
|
||||
sections: `[${getSections(tree).join()}]`,
|
||||
}),
|
||||
],
|
||||
];
|
||||
]
|
||||
|
||||
@@ -1,36 +1,51 @@
|
||||
import { slugifyWithCounter } from "@sindresorhus/slugify";
|
||||
import glob from "fast-glob";
|
||||
import * as fs from "fs";
|
||||
import { toString } from "mdast-util-to-string";
|
||||
import * as path from "path";
|
||||
import { remark } from "remark";
|
||||
import remarkMdx from "remark-mdx";
|
||||
import { createLoader } from "simple-functional-loader";
|
||||
import { filter } from "unist-util-filter";
|
||||
import { SKIP, visit } from "unist-util-visit";
|
||||
import * as url from "url";
|
||||
import { slugifyWithCounter } from '@sindresorhus/slugify'
|
||||
import glob from 'fast-glob'
|
||||
import * as fs from 'fs'
|
||||
import { toString } from 'mdast-util-to-string'
|
||||
import * as path from 'path'
|
||||
import { remark } from 'remark'
|
||||
import remarkMdx from 'remark-mdx'
|
||||
import { createLoader } from 'simple-functional-loader'
|
||||
import { filter } from 'unist-util-filter'
|
||||
import { SKIP, visit } from 'unist-util-visit'
|
||||
import * as url from 'url'
|
||||
|
||||
const extractSections = () => {
|
||||
const __filename = url.fileURLToPath(import.meta.url)
|
||||
const processor = remark().use(remarkMdx).use(extractSections)
|
||||
const slugify = slugifyWithCounter()
|
||||
|
||||
function isObjectExpression(node) {
|
||||
return (
|
||||
node.type === 'mdxTextExpression' &&
|
||||
node.data?.estree?.body?.[0]?.expression?.type === 'ObjectExpression'
|
||||
)
|
||||
}
|
||||
|
||||
function excludeObjectExpressions(tree) {
|
||||
return filter(tree, (node) => !isObjectExpression(node))
|
||||
}
|
||||
|
||||
function extractSections() {
|
||||
return (tree, { sections }) => {
|
||||
slugify.reset();
|
||||
slugify.reset()
|
||||
|
||||
visit(tree, (node) => {
|
||||
if (node.type === "heading" || node.type === "paragraph") {
|
||||
let content = toString(excludeObjectExpressions(node));
|
||||
if (node.type === "heading" && node.depth <= 2) {
|
||||
let hash = node.depth === 1 ? null : slugify(content);
|
||||
sections.push([content, hash, []]);
|
||||
if (node.type === 'heading' || node.type === 'paragraph') {
|
||||
let content = toString(excludeObjectExpressions(node))
|
||||
if (node.type === 'heading' && node.depth <= 2) {
|
||||
let hash = node.depth === 1 ? null : slugify(content)
|
||||
sections.push([content, hash, []])
|
||||
} else {
|
||||
sections.at(-1)?.[2].push(content);
|
||||
sections.at(-1)?.[2].push(content)
|
||||
}
|
||||
return SKIP;
|
||||
return SKIP
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const Search = (nextConfig = {}) => {
|
||||
let cache = new Map();
|
||||
export default function Search(nextConfig = {}) {
|
||||
let cache = new Map()
|
||||
|
||||
return Object.assign({}, nextConfig, {
|
||||
webpack(config, options) {
|
||||
@@ -38,26 +53,26 @@ export const Search = (nextConfig = {}) => {
|
||||
test: __filename,
|
||||
use: [
|
||||
createLoader(function () {
|
||||
let appDir = path.resolve("./src/app");
|
||||
this.addContextDependency(appDir);
|
||||
let appDir = path.resolve('./src/app')
|
||||
this.addContextDependency(appDir)
|
||||
|
||||
let files = glob.sync("**/*.mdx", { cwd: appDir });
|
||||
let files = glob.sync('**/*.mdx', { cwd: appDir })
|
||||
let data = files.map((file) => {
|
||||
let url = "/" + file.replace(/(^|\/)page\.mdx$/, "");
|
||||
let mdx = fs.readFileSync(path.join(appDir, file), "utf8");
|
||||
let url = '/' + file.replace(/(^|\/)page\.mdx$/, '')
|
||||
let mdx = fs.readFileSync(path.join(appDir, file), 'utf8')
|
||||
|
||||
let sections = [];
|
||||
let sections = []
|
||||
|
||||
if (cache.get(file)?.[0] === mdx) {
|
||||
sections = cache.get(file)[1];
|
||||
sections = cache.get(file)[1]
|
||||
} else {
|
||||
let vfile = { value: mdx, sections };
|
||||
processor.runSync(processor.parse(vfile), vfile);
|
||||
cache.set(file, [mdx, sections]);
|
||||
let vfile = { value: mdx, sections }
|
||||
processor.runSync(processor.parse(vfile), vfile)
|
||||
cache.set(file, [mdx, sections])
|
||||
}
|
||||
|
||||
return { url, sections };
|
||||
});
|
||||
return { url, sections }
|
||||
})
|
||||
|
||||
// When this file is imported within the application
|
||||
// the following module is loaded:
|
||||
@@ -91,7 +106,7 @@ export const Search = (nextConfig = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const search = (query, options = {}) => {
|
||||
export function search(query, options = {}) {
|
||||
let result = sectionIndex.search(query, {
|
||||
...options,
|
||||
enrich: true,
|
||||
@@ -105,30 +120,16 @@ export const Search = (nextConfig = {}) => {
|
||||
pageTitle: item.doc.pageTitle,
|
||||
}))
|
||||
}
|
||||
`;
|
||||
`
|
||||
}),
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
if (typeof nextConfig.webpack === "function") {
|
||||
return nextConfig.webpack(config, options);
|
||||
if (typeof nextConfig.webpack === 'function') {
|
||||
return nextConfig.webpack(config, options)
|
||||
}
|
||||
|
||||
return config;
|
||||
return config
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const processor = remark().use(remarkMdx).use(extractSections);
|
||||
const slugify = slugifyWithCounter();
|
||||
|
||||
const isObjectExpression = (node) => {
|
||||
return (
|
||||
node.type === "mdxTextExpression" && node.data?.estree?.body?.[0]?.expression?.type === "ObjectExpression"
|
||||
);
|
||||
};
|
||||
|
||||
const excludeObjectExpressions = (tree) => {
|
||||
return filter(tree, (node) => !isObjectExpression(node));
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import nextMDX from "@next/mdx";
|
||||
import { recmaPlugins } from "./mdx/recma.mjs";
|
||||
import { rehypePlugins } from "./mdx/rehype.mjs";
|
||||
import { remarkPlugins } from "./mdx/remark.mjs";
|
||||
import { Search as withSearch } from "./mdx/search.mjs";
|
||||
import withSearch from "./mdx/search.mjs";
|
||||
|
||||
const withMDX = nextMDX({
|
||||
options: {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { MetadataRoute } from "next";
|
||||
|
||||
const robots = (): MetadataRoute.Robots => {
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default robots;
|
||||
}
|
||||
|
||||
2
apps/docs/types.d.ts
vendored
2
apps/docs/types.d.ts
vendored
@@ -7,5 +7,5 @@ declare module "@/mdx/search.mjs" {
|
||||
pageTitle?: string;
|
||||
};
|
||||
|
||||
export const search: (query: string, options?: SearchOptions) => Array<Result>;
|
||||
export function search(query: string, options?: SearchOptions): Array<Result>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type PluginUtils } from "tailwindcss/types/config";
|
||||
|
||||
const typographyStyles = ({ theme }: PluginUtils) => {
|
||||
export default function typographyStyles({ theme }: PluginUtils) {
|
||||
return {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
@@ -367,6 +367,4 @@ const typographyStyles = ({ theme }: PluginUtils) => {
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default typographyStyles;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,10 @@ import { dirname, join } from "path";
|
||||
* This function is used to resolve the absolute path of a package.
|
||||
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
|
||||
*/
|
||||
const getAbsolutePath = (value: string): any => {
|
||||
function getAbsolutePath(value: string): any {
|
||||
return dirname(require.resolve(join(value, "package.json")));
|
||||
};
|
||||
|
||||
export const config: StorybookConfig = {
|
||||
}
|
||||
const config: StorybookConfig = {
|
||||
stories: ["../../../packages/ui/**/stories.@(js|jsx|mjs|ts|tsx)"],
|
||||
addons: [
|
||||
getAbsolutePath("@storybook/addon-links"),
|
||||
@@ -25,3 +24,4 @@ export const config: StorybookConfig = {
|
||||
autodocs: "tag",
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Preview } from "@storybook/react";
|
||||
|
||||
import "../src/index.css";
|
||||
|
||||
export const preview: Preview = {
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
@@ -13,3 +13,5 @@ export const preview: Preview = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from "react";
|
||||
|
||||
import "./App.css";
|
||||
|
||||
export const App = () => {
|
||||
function App() {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
return (
|
||||
@@ -23,4 +23,6 @@ export const App = () => {
|
||||
<p className="read-the-docs">Click on the Vite and React logos to learn more</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FormbricksClient } from "@/app/(app)/components/FormbricksClient";
|
||||
import { PosthogIdentify } from "@/app/(app)/environments/[environmentId]/components/PosthogIdentify";
|
||||
import FormbricksClient from "@/app/(app)/components/FormbricksClient";
|
||||
import PosthogIdentify from "@/app/(app)/environments/[environmentId]/components/PosthogIdentify";
|
||||
import { ResponseFilterProvider } from "@/app/(app)/environments/[environmentId]/components/ResponseFilterContext";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { redirect } from "next/navigation";
|
||||
@@ -10,9 +10,9 @@ import { getEnvironment } from "@formbricks/lib/environment/service";
|
||||
import { getTeamByEnvironmentId } from "@formbricks/lib/team/service";
|
||||
import { AuthorizationError } from "@formbricks/types/errors";
|
||||
import { DevEnvironmentBanner } from "@formbricks/ui/DevEnvironmentBanner";
|
||||
import { ToasterClient } from "@formbricks/ui/ToasterClient";
|
||||
import ToasterClient from "@formbricks/ui/ToasterClient";
|
||||
|
||||
const EnvLayout = async ({ children, params }) => {
|
||||
export default async function EnvLayout({ children, params }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || !session.user) {
|
||||
return redirect(`/auth/login`);
|
||||
@@ -54,6 +54,4 @@ const EnvLayout = async ({ children, params }) => {
|
||||
</ResponseFilterProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EnvLayout;
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ import { TProduct } from "@formbricks/types/product";
|
||||
import { TBaseFilters, TSegmentUpdateInput, ZSegmentFilters } from "@formbricks/types/segment";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
|
||||
export const surveyMutateAction = async (survey: TSurvey): Promise<TSurvey> => {
|
||||
export async function surveyMutateAction(survey: TSurvey): Promise<TSurvey> {
|
||||
return await updateSurvey(survey);
|
||||
};
|
||||
}
|
||||
|
||||
export const updateSurveyAction = async (survey: TSurvey): Promise<TSurvey> => {
|
||||
export async function updateSurveyAction(survey: TSurvey): Promise<TSurvey> {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
@@ -45,7 +45,7 @@ export const updateSurveyAction = async (survey: TSurvey): Promise<TSurvey> => {
|
||||
if (!hasCreateOrUpdateAccess) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await updateSurvey(survey);
|
||||
};
|
||||
}
|
||||
|
||||
export const deleteSurveyAction = async (surveyId: string) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
@@ -190,7 +190,7 @@ export const resetBasicSegmentFiltersAction = async (surveyId: string) => {
|
||||
return await resetSegmentInSurvey(surveyId);
|
||||
};
|
||||
|
||||
export const getImagesFromUnsplashAction = async (searchQuery: string, page: number = 1) => {
|
||||
export async function getImagesFromUnsplashAction(searchQuery: string, page: number = 1) {
|
||||
if (!UNSPLASH_ACCESS_KEY) {
|
||||
throw new Error("Unsplash access key is not set");
|
||||
}
|
||||
@@ -231,9 +231,9 @@ export const getImagesFromUnsplashAction = async (searchQuery: string, page: num
|
||||
} catch (error) {
|
||||
throw new Error("Error getting images from Unsplash");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const triggerDownloadUnsplashImageAction = async (downloadUrl: string) => {
|
||||
export async function triggerDownloadUnsplashImageAction(downloadUrl: string) {
|
||||
try {
|
||||
const response = await fetch(`${downloadUrl}/?client_id=${UNSPLASH_ACCESS_KEY}`, {
|
||||
method: "GET",
|
||||
@@ -249,9 +249,9 @@ export const triggerDownloadUnsplashImageAction = async (downloadUrl: string) =>
|
||||
} catch (error) {
|
||||
throw new Error("Error downloading image from Unsplash");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const createActionClassAction = async (action: TActionClassInput) => {
|
||||
export async function createActionClassAction(action: TActionClassInput) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
@@ -259,4 +259,4 @@ export const createActionClassAction = async (action: TActionClassInput) => {
|
||||
if (!isAuthorized) throw new AuthorizationError("Not authorized");
|
||||
|
||||
return await createActionClass(action.environmentId, action);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ interface AddQuestionButtonProps {
|
||||
product: TProduct;
|
||||
}
|
||||
|
||||
export const AddQuestionButton = ({ addQuestion, product }: AddQuestionButtonProps) => {
|
||||
export default function AddQuestionButton({ addQuestion, product }: AddQuestionButtonProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -59,4 +59,4 @@ export const AddQuestionButton = ({ addQuestion, product }: AddQuestionButtonPro
|
||||
</Collapsible.CollapsibleContent>
|
||||
</Collapsible.Root>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys";
|
||||
|
||||
import { LogicEditor } from "./LogicEditor";
|
||||
import { UpdateQuestionId } from "./UpdateQuestionId";
|
||||
import LogicEditor from "./LogicEditor";
|
||||
import UpdateQuestionId from "./UpdateQuestionId";
|
||||
|
||||
interface AdvancedSettingsProps {
|
||||
question: TSurveyQuestion;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user