Deleted a ton of old components, started tidying things up

This commit is contained in:
Matt Aitken
2023-05-09 18:50:46 +01:00
parent 1f1cf0cb74
commit 60309677fe
71 changed files with 674 additions and 1463 deletions
+22
View File
@@ -1,5 +1,26 @@
import type { StorybookConfig } from "@storybook/react-webpack5";
import path from "path";
const root = path.resolve(__dirname, "../app/");
console.log("storybook root", root);
const config: StorybookConfig = {
webpackFinal: async (config) => {
return {
...config,
resolve: {
...config.resolve,
alias: {
...(config.resolve?.alias ?? {}),
"~/": root,
},
extensions: [
...(config.resolve?.extensions ?? []),
...[".ts", ".tsx", ".js", ".jsx", ".mdx"],
],
},
};
},
stories: [
"../app/**/stories/*.mdx",
"../app/**/stories/*.stories.@(js|jsx|ts|tsx)",
@@ -26,5 +47,6 @@ const config: StorybookConfig = {
docs: {
autodocs: "tag",
},
staticDirs: [path.resolve("public"), path.resolve("app/styles")],
};
export default config;
@@ -10,7 +10,7 @@ import type { TemplateListItem } from "~/presenters/templateListPresenter.server
import { ApiLogoIcon } from "./code/ApiLogoIcon";
import { Panel } from "./layout/Panel";
import { Body } from "./primitives/text/Body";
import { Header1, Header3 } from "./primitives/text/Headers";
import { Header1, Header3 } from "./primitives/Headers";
export function LoginPromoPanel({ template }: { template?: TemplateListItem }) {
return (
@@ -1,59 +0,0 @@
type Props = Omit<
React.DetailedHTMLProps<
React.ImgHTMLAttributes<HTMLImageElement>,
HTMLImageElement
>,
"src" | "alt"
> & {
integration?: { icon: string; name: string };
size?: Size;
};
type Size =
| "extra-small"
| "small"
| "regular"
| "large"
| "extra-large"
| "custom";
export function ApiLogoIcon({
className,
integration,
size = "extra-large",
...props
}: Props) {
if (!integration) {
return null;
}
return (
<img
className={`
rounded bg-slate-850
${getSizeClassName(size)}
${className}
`}
src={integration.icon}
alt={integration.name}
{...props}
/>
);
}
function getSizeClassName(size: Size) {
switch (size) {
case "extra-small":
return "h-6 w-6 p-2";
case "small":
return "h-8 w-8 p-2";
case "large":
return "h-16 w-16 p-2";
case "extra-large":
return "h-20 w-20 p-2";
case "custom":
return "";
case "regular":
default:
return "h-10 w-10 p-2";
}
}
@@ -22,6 +22,7 @@ type CodeBlockProps = {
className?: string;
};
//todo change to use CodeHike
export default function CodeBlock({
code,
language = "typescript",
@@ -1,79 +0,0 @@
import { javascript } from "@codemirror/lang-javascript";
import type { ViewUpdate } from "@codemirror/view";
import type {
ReactCodeMirrorProps,
UseCodeMirror,
} from "@uiw/react-codemirror";
import { useCodeMirror } from "@uiw/react-codemirror";
import classNames from "classnames";
import { useRef, useEffect } from "react";
import { getEditorSetup } from "./codeMirrorSetup";
import { darkTheme } from "./codeMirrorTheme";
export interface CodeEditorProps extends Omit<ReactCodeMirrorProps, "onBlur"> {
content: string;
language?: "typescript" | "shell";
showLineNumbers?: boolean;
showHighlights?: boolean;
readOnly?: boolean;
onChange?: (value: string) => void;
onUpdate?: (update: ViewUpdate) => void;
onBlur?: (code: string) => void;
}
type CodeEditorDefaultProps = Partial<CodeEditorProps>;
const defaultProps: CodeEditorDefaultProps = {
language: "typescript",
showLineNumbers: true,
showHighlights: true,
readOnly: true,
basicSetup: false,
};
export function CodeEditor(opts: CodeEditorProps) {
const { content, readOnly, onChange, onUpdate, onBlur } = {
...defaultProps,
...opts,
};
const extensions = getEditorSetup(opts.showLineNumbers, opts.showHighlights);
if (opts.language === "typescript") {
extensions.push(javascript({ typescript: true }));
}
const editor = useRef<HTMLDivElement>(null);
const settings: Omit<UseCodeMirror, "onBlur"> = {
...opts,
container: editor.current,
extensions,
editable: !readOnly,
contentEditable: !readOnly,
value: content,
autoFocus: false,
theme: darkTheme(),
indentWithTab: false,
basicSetup: false,
onChange,
onUpdate,
};
const { setContainer } = useCodeMirror(settings);
useEffect(() => {
if (editor.current) {
setContainer(editor.current);
}
}, [setContainer]);
return (
<div
className={classNames("no-scrollbar overflow-y-auto", opts.className)}
ref={editor}
onBlur={() => {
if (!onBlur) return;
onBlur(editor.current?.textContent ?? "");
}}
/>
);
}
@@ -13,7 +13,7 @@ import {
SheetTitle,
SheetTrigger,
} from "../primitives/Sheet";
import { Header3 } from "../primitives/text/Headers";
import { Header3 } from "../primitives/Headers";
import { Input } from "../primitives/Input";
import { Badge } from "../primitives/Badge";
@@ -1,15 +0,0 @@
import type { ServiceMetadata } from "@trigger.dev/integration-sdk";
export function IntegrationIcon({
integration,
}: {
integration: ServiceMetadata;
}) {
return (
<img
src={integration.icon}
alt={integration.name}
className="h-5 w-5 shadow-lg transition group-hover:opacity-80"
/>
);
}
@@ -1,68 +0,0 @@
import { Link } from "@remix-run/react";
import classNames from "classnames";
import invariant from "tiny-invariant";
import type { ConnectionSlot } from "~/hooks/useConnectionSlots";
import { useCurrentOrganization } from "~/hooks/useOrganizations";
import { ApiLogoIcon } from "../code/ApiLogoIcon";
import { List } from "../layout/List";
import { Header3 } from "../primitives/text/Headers";
import { SubTitle } from "../primitives/text/SubTitle";
import { ConnectionSelector } from "./ConnectionSelector";
export function WorkflowConnections({
className,
connectionSlots,
}: {
className?: string;
connectionSlots: (ConnectionSlot & { type: "source" | "service" })[];
}) {
const organization = useCurrentOrganization();
invariant(organization, "Organization not found");
return (
<div className={classNames(className)}>
<SubTitle>API Connections</SubTitle>
<List>
{connectionSlots.map((slot) => (
<li
key={slot.id}
className={classNames(
slot.connection === null
? "!border !border-rose-600 bg-rose-500/10"
: "",
"flex w-full items-center gap-4 px-4 py-4 first:rounded-t-md last:rounded-b-md"
)}
>
<ApiLogoIcon integration={slot.integration} size="regular" />
<div className="flex w-full items-center justify-between">
<Header3 size="small" className="truncate text-slate-300">
{slot.integration?.name}
</Header3>
<ConnectionSelector
type={slot.type}
sourceServiceId={slot.id}
organizationId={organization.id}
integration={slot.integration}
connections={slot.possibleConnections}
selectedConnectionId={slot.connection?.id}
className="mr-1"
popoverAlign="right"
/>
</div>
</li>
))}
<li className="p-4 pl-5 text-sm text-slate-500">
You will be able to authenticate APIs on demand when your workflow
runs. You can also{" "}
<Link
to={`/orgs/${organization.slug}/integrations`}
className="text-slate-500 underline decoration-slate-500 underline-offset-4 transition hover:text-slate-400"
>
connect them now
</Link>
.
</li>
</List>
</div>
);
}
@@ -1,60 +0,0 @@
import classNames from "classnames";
export function AppLayoutThreeCol({ children }: { children: React.ReactNode }) {
return (
<div className="grid h-full w-full grid-cols-[3.5rem_auto]">{children}</div>
);
}
export function AppLayoutTwoCol({ children }: { children: React.ReactNode }) {
return (
<div className="grid h-full w-full grid-cols-[16rem_auto] overflow-hidden">
{children}
</div>
);
}
export function AppBody({
children,
className = "bg-slate-850",
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<div
className={classNames(
"grid h-full grid-rows-[3.6rem_auto] overflow-hidden",
className
)}
>
{children}
</div>
);
}
export function PublicAppLayout({ children }: { children: React.ReactNode }) {
return (
<div className="grid h-full w-full grid-rows-[4rem_auto] overflow-y-auto">
{children}
</div>
);
}
export function LoggedInAppLayout({ children }: { children: React.ReactNode }) {
return (
<div className="grid h-full w-full grid-rows-[3.6rem_auto] overflow-hidden">
{children}
</div>
);
}
export function PublicAppBody({
children,
className = "bg-slate-850",
}: {
children: React.ReactNode;
className?: string;
}) {
return <div className={classNames("", className)}>{children}</div>;
}
@@ -1,17 +0,0 @@
import classNames from "classnames";
const baseClasses = "px-4 py-4 md:px-8 md:py-6 lg:px-12 lg:py-10";
export function Container({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<div className={classNames("overflow-y-auto", baseClasses, className)}>
{children}
</div>
);
}
@@ -1,49 +0,0 @@
const linkStyle =
"text-xs font-medium text-slate-400 whitespace-nowrap bg-transparent text-slate-500 transition hover:text-indigo-500";
export function Footer() {
return (
<div className="flex w-full flex-col items-center justify-between border-t border-slate-800 bg-slate-950 py-4 pl-2 pr-3 sm:flex-row sm:py-4">
<div className="flex gap-2 pb-4 text-xs text-slate-500 sm:pb-0">
<p>&copy; {new Date().getFullYear()} Trigger.dev </p>
<span className="text-slate-600">|</span>{" "}
<a
className="transition hover:text-indigo-500"
href="https://trigger.dev/legal/terms"
>
Terms
</a>{" "}
<span className="text-slate-600">|</span>{" "}
<a
className="transition hover:text-indigo-500"
href="https://trigger.dev/legal/privacy"
>
Privacy
</a>
</div>
<div className="flex gap-3">
<a
target="_blank"
rel="noopener noreferrer"
href="https://discord.gg/kA47vcd8P6"
className={linkStyle}
>
Discord
</a>
<a
target="_blank"
rel="noopener noreferrer"
href="https://twitter.com/triggerdotdev"
className={linkStyle}
>
Twitter
</a>
<a href="mailto:hello@trigger.dev" className={linkStyle}>
Get in touch
</a>
</div>
</div>
);
}
@@ -1,20 +0,0 @@
export type PanelProps = {
children: React.ReactNode;
className?: string;
};
export function Panel({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<div
className={`bg-slate-800 w-full shadow-md rounded-md p-3 ${className}`}
>
{children}
</div>
);
}
@@ -1,76 +0,0 @@
import { ArrowRightIcon } from "@heroicons/react/24/outline";
import type { ReactNode } from "react";
import { dateDifference, formatDateTime } from "~/utils";
import { Body } from "../primitives/text/Body";
const workflowNodeFlexClasses = "flex gap-1 items-baseline";
const workflowNodeUppercaseClasses = "uppercase text-slate-400";
export function PanelHeader({
icon,
title,
startedAt,
finishedAt,
integration,
runId,
name,
}: {
icon: ReactNode;
title: string;
startedAt?: Date | null;
finishedAt?: Date | null;
integration?: string;
runId?: string;
name?: string;
}) {
return (
<div className="flex mb-4 pb-3 justify-between items-center border-b border-slate-850">
<div className="flex gap-1 items-center">
{icon}
<Body size="small" className="uppercase text-slate-400 font-semibold">
{title}
</Body>
{name && (
<div className="flex gap-3 items-center ml-2">
<span className="block h-5 border-l border-slate-850"></span>
<Body size="small" className="text-slate-400">
{name}
</Body>
</div>
)}
</div>
<ul className="flex justify-end items-center gap-4">
<div className={workflowNodeFlexClasses}>
{startedAt && (
<Body size="small">{formatDateTime(startedAt, "long")}</Body>
)}
{startedAt &&
finishedAt &&
dateDifference(startedAt, finishedAt) > 1000 && (
<>
<Body
size="extra-small"
className={workflowNodeUppercaseClasses}
>
<ArrowRightIcon className="h-3 w-3" />
</Body>
<Body size="small">{formatDateTime(finishedAt, "long")}</Body>
</>
)}
</div>
{integration && (
<li className="flex gap-2 items-center">
<Body size="small">{integration}</Body>
</li>
)}
{runId && (
<li className="flex gap-2 items-center">
<Body size="small">{runId}</Body>
</li>
)}
</ul>
</div>
);
}
@@ -1,96 +0,0 @@
import { InformationCircleIcon } from "@heroicons/react/24/solid";
import { Spinner } from "../primitives/Spinner";
import { Body } from "../primitives/text/Body";
export type PanelInfoProps = {
children: React.ReactNode;
className?: string;
};
export function PanelInfo({
children,
className,
message,
}: {
children?: React.ReactNode;
className?: string;
message?: string;
}) {
return (
<IconPanel
className={className}
message={message}
icon={
<InformationCircleIcon className="h-6 w-6 min-w-[24px] text-blue-500" />
}
>
{children}
</IconPanel>
);
}
export function PanelWarning({
children,
className,
message,
}: {
children?: React.ReactNode;
className?: string;
message?: string;
}) {
return (
<IconPanel
className={className}
message={message}
icon={
<InformationCircleIcon className="h-6 w-6 min-w-[24px] text-yellow-500" />
}
>
{children}
</IconPanel>
);
}
export function PanelLoading({
children,
className,
message,
}: {
children?: React.ReactNode;
className?: string;
message?: string;
}) {
return (
<IconPanel
className={className}
message={message}
icon={<Spinner className="h-6 w-6 min-w-[24px]" />}
>
{children}
</IconPanel>
);
}
export function IconPanel({
children,
className,
message,
icon,
}: {
children?: React.ReactNode;
className?: string;
message?: string;
icon: React.ReactNode;
}) {
return (
<div
className={`flex w-full gap-4 rounded-md border border-slate-600 bg-slate-400/10 py-3 pl-3 pr-4 shadow-md backdrop-blur-sm ${className}`}
>
<div className="flex items-center justify-start gap-2.5">
{icon}
<Body className="text-slate-300">{message}</Body>
</div>
{children}
</div>
);
}
@@ -1,29 +0,0 @@
import { ExclamationTriangleIcon } from "@heroicons/react/24/solid";
import { Body } from "../primitives/text/Body";
export type PanelWarningProps = {
children: React.ReactNode;
className?: string;
};
export function PanelWarning({
children,
className,
message,
}: {
children?: React.ReactNode;
className?: string;
message: string;
}) {
return (
<div
className={`flex w-full items-center rounded-md border border-amber-500 bg-amber-400/10 p-3 shadow-md ${className}`}
>
<div className="flex items-center gap-2.5">
<ExclamationTriangleIcon className="h-6 w-6 min-w-[24px] text-amber-500" />
<Body className="">{message}</Body>
</div>
{children}
</div>
);
}
@@ -1,7 +1,7 @@
import { Popover, Transition } from "@headlessui/react";
import {
ChevronUpDownIcon,
ArrowsRightLeftIcon,
ChevronUpDownIcon,
} from "@heroicons/react/24/outline";
import {
CheckIcon,
@@ -13,13 +13,13 @@ import classNames from "classnames";
import { Fragment } from "react";
import { useCurrentOrganization } from "~/hooks/useOrganizations";
import { useCurrentWorkflow, useWorkflows } from "~/hooks/useWorkflows";
import { BreadcrumbDivider } from "../layout/Header";
import { PrimaryLink } from "../primitives/Buttons";
import { MobileNavIcon, MobileNavLink } from "../primitives/NavLink";
import { BreadcrumbDivider } from "./NavBar";
const dimmedClassNames = "text-slate-500";
export function WorkflowMenu() {
//todo change to jobs
//todo change to use popover
export function JobsMenu() {
const workflows = useWorkflows();
const currentWorkflow = useCurrentWorkflow();
const currentOrganization = useCurrentOrganization();
@@ -4,43 +4,35 @@ import {
ChatBubbleLeftRightIcon,
} from "@heroicons/react/24/outline";
import { Fragment } from "react";
import { ProjectMenu } from "~/features/ee/projects/components/ProjectMenu";
import { Logo } from "../Logo";
import { OrganizationMenu } from "../navigation/OrganizationMenu";
import { WorkflowMenu } from "../navigation/WorkflowMenu";
import {
PrimaryA,
PrimaryButton,
SecondaryA,
SecondaryButton,
SecondaryLink,
} from "../primitives/Buttons";
import { MobileNavIcon } from "../primitives/NavLink";
import { ProjectsMenu } from "./ProjectsMenu";
import { JobsMenu } from "./JobsMenu";
import { Button, LinkButton } from "../primitives";
type HeaderProps = {
children?: React.ReactNode;
context: "workflows" | "projects";
};
export function Header({ children, context }: HeaderProps) {
export function NavBar() {
return (
<div className="z-50 flex h-[3.6rem] w-full items-center gap-2 border-b border-slate-800 bg-slate-950 py-1 pl-2 pr-2.5">
<div className="hidden items-center lg:flex">
<OrganizationMenu />
{context === "workflows" ? <WorkflowMenu /> : <ProjectMenu />}
<ProjectsMenu />
<JobsMenu />
</div>
<Logo className="ml-1 w-36 lg:hidden" />
<div className="flex flex-1 justify-center">{children}</div>
<MobileDropdownMenu />
<div className="hidden items-center gap-2 sm:flex">
<SecondaryA href="https://docs.trigger.dev" target="_blank">
<ArrowTopRightOnSquareIcon className="-ml-1 h-4 w-4" />
Documentation
</SecondaryA>
<SecondaryButton data-attr="posthog-feedback-button">
<ChatBubbleLeftRightIcon className="-ml-1 h-4 w-4" />
Send us feedback
</SecondaryButton>
<LinkButton
to="https://docs.trigger.dev"
text="Documentation"
size="medium"
theme="secondary"
LeadingIcon={ArrowTopRightOnSquareIcon}
/>
<Button
text="Send us feedback"
size="medium"
theme="secondary"
data-attr="posthog-feedback-button"
LeadingIcon={ChatBubbleLeftRightIcon}
/>
</div>
</div>
);
@@ -126,3 +118,30 @@ function MobileDropdownMenu() {
</Popover>
);
}
function MobileNavIcon({ open }: { open: boolean }) {
return (
<svg
aria-hidden="true"
className="h-3.5 w-3.5 overflow-visible stroke-slate-300"
fill="none"
strokeWidth={2}
strokeLinecap="round"
>
<path
d="M0 1H14M0 7H14M0 13H14"
className={classnames(
"origin-center transition",
open && "scale-90 opacity-0"
)}
/>
<path
d="M2 2L12 12M12 2L2 12"
className={classnames(
"origin-center transition",
!open && "scale-90 opacity-0"
)}
/>
</svg>
);
}
@@ -1,6 +1,5 @@
import { Popover, Transition } from "@headlessui/react";
import {
BookmarkIcon,
BuildingOffice2Icon,
ChevronUpDownIcon,
UserIcon,
@@ -14,12 +13,13 @@ import {
useIsNewOrganizationPage,
useOrganizations,
} from "~/hooks/useOrganizations";
import { BreadcrumbDivider } from "../layout/Header";
const actionClassNames = "text-white";
const dimmedClassNames = "text-slate-500";
export function OrganizationMenu() {
//todo change to projects
//todo change to use popover
export function ProjectsMenu() {
const organizations = useOrganizations();
const currentOrganization = useCurrentOrganization();
const isNewPage = useIsNewOrganizationPage();
@@ -23,8 +23,9 @@ import { useOptionalUser } from "~/hooks/useUser";
import { LogoIcon } from "../LogoIcon";
import { MenuTitleToolTip } from "../primitives/MenuTitleToolTip";
import { Body } from "../primitives/text/Body";
import { Header1 } from "../primitives/text/Headers";
import { Header1 } from "../primitives/Headers";
//todo change to the new collapsible side menu
export function SideMenuContainer({ children }: { children: React.ReactNode }) {
return (
<div className="grid h-full grid-cols-[16rem_auto] overflow-hidden">
@@ -1,32 +0,0 @@
import { Link } from "@remix-run/react";
import { TertiaryLink } from "../primitives/Buttons";
import { SubTitle } from "../primitives/text/SubTitle";
import { StepNumber } from "./StepNumber";
export function BackToStep1() {
return (
<>
<SubTitle className="flex items-center">
<StepNumber complete />
<Link to=".." className="transition hover:text-slate-300">
I'll host the workflow myself
</Link>
</SubTitle>
<TertiaryLink to="..">Change answer</TertiaryLink>
</>
);
}
export function BackToStep2({ text }: { text: string }) {
return (
<>
<SubTitle className="flex items-center">
<StepNumber complete />
<Link to="../step2" className="transition hover:text-slate-300">
{text}
</Link>
</SubTitle>
<TertiaryLink to="../step2">Change answer</TertiaryLink>
</>
);
}
@@ -1,7 +0,0 @@
export const onboarding = {
buttonStyles:
"relative flex flex-col cursor-pointer items-center justify-start hover:bg-slate-700 px-4 shadow gap-4 rounded bg-slate-700/50 py-8 border border-slate-700 transition",
labelStyles:
"absolute top-0 right-0 uppercase text-xs text-slate-900 px-2 py-1 font-semibold rounded-bl rounded-tr",
maxWidth: "flex flex-col max-w-4xl",
};
+136 -275
View File
@@ -1,290 +1,151 @@
import type { LinkProps } from "@remix-run/react";
import { Link } from "@remix-run/react";
import classnames from "classnames";
import React from "react";
import { cn } from "~/utils/cn";
type Size = "regular" | "large";
const sizes = {
small: "h-[24px] px-2 text-xs",
medium: "h-[32px] px-2.5 text-sm",
large: "h-[40px] px-3 text-base",
};
const commonClasses =
"inline-flex items-center justify-center max-w-max rounded transition whitespace-nowrap";
export const primaryClasses = classnames(
commonClasses,
"px-4 py-2 bg-indigo-700 text-white hover:bg-indigo-600 focus-visible:ring-indigo-800 gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-slate-700 disabled:text-slate-400"
);
export const secondaryClasses = classnames(
commonClasses,
"px-4 py-2 bg-transparent ring-1 ring-slate-700 ring-inset text-white hover:bg-white/5 hover:border-slate-700 focus-visible:ring-slate-300 gap-2"
);
export const tertiaryClasses = classnames(
commonClasses,
"text-slate-300/70 hover:text-white gap-1"
);
export const dangerClasses = classnames(
commonClasses,
"px-4 py-2 bg-rose-700 text-white hover:bg-rose-600 focus-visible:ring-rose-800 gap-2"
);
export const toxicClasses = classnames(
commonClasses,
"hover:cursor-pointer px-3 py-1 transition bg-gradient-to-r from-acid-500 to-toxic-500 text-slate-1000 !text-base font-bold hover:from-acid-600 hover:to-toxic-600 focus-visible:ring-slate-300"
);
const themes = {
primary:
"text-slate-900 bg-gradient-primary overflow-hidden hover:opacity-90",
secondary:
"text-slate-200 bg-gradient-secondary transition duration-500 hover:opacity-90",
secondaryOutline:
"text-indigo-400 hover:text-indigo-300 border border-indigo-500 focus:ring-indigo-400 py-1/2 hover:border-indigo-400",
};
function getSizeClassName(size: Size) {
switch (size) {
case "large":
return "text-lg";
case "regular":
default:
return "text-sm";
const btnVariants = {
$all: "text-center font-semibold font-sans justify-center items-center shrink-0 transition-all duration-300 leading-tight rounded select-none group-focus:outline-none group-disabled:opacity-75 group-disabled:pointer-events-none",
size: sizes,
theme: themes,
};
const iconVariants = {
size: {
// ExtraSmall: "h-3",
small: "h-4",
medium: "h-4",
large: "h-5",
// ExtraLarge: "h-6",
},
theme: {
primary: "text-slate-900",
secondary: "text-slate-200",
secondaryOutline: "text-indigo-400",
},
};
type ButtonContentPropsType = {
text?: string | React.ReactNode;
LeadingIcon?: React.ComponentType<any>;
TrailingIcon?: React.ComponentType<any>;
fullWidth?: boolean;
className?: string;
size: keyof typeof sizes;
theme: keyof typeof themes;
};
function ButtonContent(props: ButtonContentPropsType) {
const { text, LeadingIcon, TrailingIcon, fullWidth, className } = props;
// Based on the size prop, we'll use the corresponding variant classnames
const btnClassName = `${btnVariants.$all} ${btnVariants.size[props.size]} ${
btnVariants.theme[props.theme]
}`;
const iconClassName = `${iconVariants.size[props.size]} ${
iconVariants.theme[props.theme]
}`;
return (
<div
className={cn(
className,
fullWidth ? "flex" : "inline-flex",
btnClassName
)}
>
<div className="flex w-full items-center gap-x-1">
{LeadingIcon && (
<LeadingIcon
className={cn(iconClassName, "shrink-0 justify-start")}
/>
)}
{text && <span className="mx-auto self-center truncate">{text}</span>}
{TrailingIcon && (
<TrailingIcon className={cn(iconClassName, "shrink-0 justify-end")} />
)}
</div>
</div>
);
}
type ButtonPropsType = Pick<
JSX.IntrinsicElements["button"],
"type" | "disabled" | "onClick" | "name" | "value"
> &
React.ComponentProps<typeof ButtonContent>;
export const Button = ({
type,
disabled,
onClick,
...props
}: ButtonPropsType) => {
return (
<button
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
type={type}
disabled={disabled}
onClick={onClick}
name={props.name}
value={props.value}
>
<ButtonContent {...props} />
</button>
);
};
type LinkPropsType = Pick<LinkProps, "to"> &
React.ComponentProps<typeof ButtonContent>;
export const LinkButton = ({ to, ...props }: LinkPropsType) => {
if (to.toString().startsWith("http")) {
return (
<ExtLink
href={to.toString()}
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
>
<ButtonContent {...props} />
</ExtLink>
);
} else {
return (
<Link
to={to}
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
>
<ButtonContent {...props} />
</Link>
);
}
}
type ButtonProps = React.DetailedHTMLProps<
React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
> & {
size?: Size;
};
type LinkProps = Parameters<typeof Link>[0] & {
size?: Size;
type ExtLinkProps = JSX.IntrinsicElements["a"] & {
children: React.ReactNode;
className?: string;
href: string;
};
type AProps = React.DetailedHTMLProps<
React.AnchorHTMLAttributes<HTMLAnchorElement>,
HTMLAnchorElement
> & {
size?: Size;
};
export function PrimaryButton({
children,
size = "regular",
className,
...props
}: ButtonProps) {
return (
<button
className={classnames(primaryClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</button>
);
}
export function SecondaryButton({
children,
size = "regular",
className,
...props
}: ButtonProps) {
return (
<button
className={classnames(
secondaryClasses,
getSizeClassName(size),
className
)}
{...props}
>
{children}
</button>
);
}
export function TertiaryButton({
children,
size = "regular",
className,
...props
}: ButtonProps) {
return (
<button
className={classnames(tertiaryClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</button>
);
}
export function DangerButton({
children,
size = "regular",
className,
...props
}: ButtonProps) {
return (
<button
className={classnames(dangerClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</button>
);
}
export function PrimaryLink({
children,
size = "regular",
className,
to,
...props
}: LinkProps) {
return (
<Link
to={to}
className={classnames(primaryClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</Link>
);
}
export function SecondaryLink({
children,
className,
size = "regular",
to,
...props
}: LinkProps) {
return (
<Link
to={to}
className={classnames(
secondaryClasses,
getSizeClassName(size),
className
)}
{...props}
>
{children}
</Link>
);
}
export function TertiaryLink({
children,
className,
size = "regular",
to,
...props
}: LinkProps) {
return (
<Link
to={to}
className={classnames(tertiaryClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</Link>
);
}
export function DangerLink({
children,
className,
size = "regular",
to,
...props
}: LinkProps) {
return (
<Link
to={to}
className={classnames(dangerClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</Link>
);
}
export function ToxicLink({
children,
className,
size = "regular",
to,
...props
}: LinkProps) {
return (
<Link
to={to}
className={classnames(toxicClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</Link>
);
}
export function PrimaryA({
children,
className,
size = "regular",
href,
...props
}: AProps) {
function ExtLink({ className, href, children, ...props }: ExtLinkProps) {
return (
<a
className={cn(className)}
target="_blank"
rel="noopener noreferrer"
href={href}
className={classnames(primaryClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</a>
);
}
export function SecondaryA({
children,
className,
size = "regular",
href,
...props
}: AProps) {
return (
<a
href={href}
className={classnames(
secondaryClasses,
getSizeClassName(size),
className
)}
{...props}
>
{children}
</a>
);
}
export function TertiaryA({
children,
className,
size = "regular",
href,
...props
}: AProps) {
return (
<a
href={href}
className={classnames(tertiaryClasses, getSizeClassName(size), className)}
{...props}
>
{children}
</a>
);
}
export function ToxicA({
children,
className,
size = "regular",
href,
...props
}: AProps) {
return (
<a
href={href}
className={classnames(toxicClasses, getSizeClassName(size), className)}
{...props}
>
{children}
@@ -5,6 +5,7 @@ type DialogProps = Parameters<typeof HeadlessDialog>[0] & {
children: React.ReactNode;
};
//todo change to use ShadCn
function Dialog({ onClose, children, ...props }: DialogProps) {
return (
<Transition {...props}>
@@ -1,5 +1,6 @@
import type { z } from "zod";
//todo use a new Input Field Error component
export function FormError({
errors,
path,
@@ -20,7 +21,7 @@ export function FormError({
}
return (
<div className="mt-2 text-sm text-red-600 col-span-full">
<div className="col-span-full mt-2 text-sm text-red-600">
{relevantErrors.map((error, index) => (
<p key={index}>{error.message}</p>
))}
@@ -0,0 +1,127 @@
import { cn } from "~/utils/cn";
const header1Variants = {
"small/bold": "font-title font-bold text-3xl pb-4",
"base/bold": "font-title font-bold text-4xl pb-4",
"large/bold": "font-title font-bold sm:text-5xl sm:pb-8 text-4xl pb-6",
};
const header2Variants = {
"small/bold": "font-title font-bold text-2xl pb-4",
"base/bold": "font-title font-bold text-3xl pb-4",
"large/bold": "font-title font-bold text-4xl pb-6",
};
const header3Variants = {
"small/semibold": "font-title font-semibold text-xl pb-2",
"base/semibold": "font-title font-semibold text-2xl pb-2",
"large/semibold": "font-title font-semibold text-3xl pb-4",
};
const header4Variants = {
"small/semibold": "font-title font-semibold text-lg pb-2",
"base/semibold": "font-title font-semibold text-xl pb-2",
"large/semibold": "font-title font-semibold text-2xl pb-4",
};
type HeaderProps = {
className?: string;
children: React.ReactNode;
textCenter?: boolean;
};
type Header1Props = HeaderProps & {
variant: keyof typeof header1Variants;
};
type Header2Props = HeaderProps & {
variant: keyof typeof header2Variants;
};
type Header3Props = HeaderProps & {
variant: keyof typeof header3Variants;
};
type Header4Props = HeaderProps & {
variant: keyof typeof header4Variants;
};
export function Header1({
variant,
textCenter,
className,
children,
}: Header1Props) {
return (
<h1
className={cn(
"text-slate-200",
header1Variants[variant],
textCenter ? "text-center" : "",
className
)}
>
{children}
</h1>
);
}
export function Header2({
variant,
textCenter,
className,
children,
}: Header2Props) {
return (
<h2
className={cn(
"text-slate-200",
textCenter ? "text-center" : "",
header2Variants[variant],
className
)}
>
{children}
</h2>
);
}
export function Header3({
variant,
textCenter,
className,
children,
}: Header3Props) {
return (
<h3
className={cn(
"text-slate-200",
textCenter ? "text-center" : "",
header3Variants[variant],
className
)}
>
{children}
</h3>
);
}
export function Header4({
variant,
textCenter,
className,
children,
}: Header4Props) {
return (
<h4
className={cn(
"text-slate-200",
textCenter ? "text-center" : "",
header4Variants[variant],
className
)}
>
{children}
</h4>
);
}
@@ -1,25 +0,0 @@
export function PlugIcon({
className,
fill,
}: {
className?: string;
fill?: string;
}) {
return (
<svg
width="418"
height="418"
viewBox="0 0 418 418"
xmlns="http://www.w3.org/2000/svg"
className={className}
fill={fill}
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M411.662 6.12075C419.821 14.2794 419.821 27.5054 411.662 35.6637L390.942 56.3841C422.842 102.22 418.355 165.702 377.482 206.57L357.947 226.104C341.701 242.351 315.354 242.351 299.106 226.104L191.677 118.675C175.43 102.428 175.43 76.0848 191.677 59.8335L211.211 40.3029C252.084 -0.570291 315.56 -5.05725 361.397 26.8393L382.117 6.11896C390.276 -2.03965 403.502 -2.03965 411.66 6.11896L411.662 6.12075ZM347.939 69.8441C318.34 40.2456 270.35 40.2456 240.751 69.8441L221.342 89.2565L328.53 196.444L347.942 177.031C377.541 147.433 377.541 99.4426 347.942 69.8441H347.939ZM172.391 142.848C180.549 151.007 180.549 164.233 172.391 172.391L135.889 208.893L208.893 281.897L245.395 245.396C253.553 237.237 266.78 237.237 274.938 245.396C283.093 253.554 283.093 266.78 274.938 274.939L235.736 314.14C241.164 328.891 237.953 346.103 226.105 357.952L206.575 377.482C165.701 418.356 102.216 422.846 56.3797 390.946L35.6593 411.666C27.5007 419.821 14.2747 419.821 6.11634 411.666C-2.03878 403.508 -2.03878 390.282 6.11634 382.123L26.8367 361.403C-5.05987 315.567 -0.57291 252.085 40.3003 211.217L59.8309 191.683C71.6785 179.835 88.8913 176.629 103.642 182.056L142.848 142.85C151.003 134.695 164.229 134.695 172.387 142.85L172.391 142.848ZM89.2557 221.343L69.8468 240.756C40.2483 270.354 40.2483 318.345 69.8468 347.943C99.4426 377.545 147.432 377.545 177.034 347.943L196.447 328.534L89.2557 221.343Z"
fill={fill}
/>
</svg>
);
}
+21 -29
View File
@@ -1,32 +1,24 @@
import classNames from "classnames";
import * as React from "react";
import { cn } from "~/utils/cn";
const roundedStyles = {
roundedLeft: "rounded-l -mr-1",
roundedRight: "rounded-r -ml-1",
roundedFull: "rounded",
};
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
type InputProps = JSX.IntrinsicElements["input"] & {
roundedEdges?: "roundedLeft" | "roundedRight" | "roundedFull";
};
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
}
);
Input.displayName = "Input";
export function Input({
children,
className,
roundedEdges = "roundedFull",
...props
}: InputProps) {
const classes = classNames(roundedStyles[roundedEdges], className);
return (
<input
{...props}
className={classNames(
`flex grow py-2 pl-4 pr-1 text-slate-200 rounded border-none bg-black/20 group-focus:border-indigo-500 placeholder:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500`,
classes
)}
>
{children}
</input>
);
}
export { Input };
@@ -1,24 +1,13 @@
import classNames from "classnames";
import { cn } from "~/utils/cn";
type InputGroupProps = {
layout?: "vertical" | "horizontal";
children: React.ReactNode;
className?: string;
};
export function InputGroup({
layout = "vertical",
children,
className,
}: InputGroupProps) {
export function InputGroup({ children, className }: InputGroupProps) {
return (
<div
className={classNames(
"mb-2 grid gap-1",
{ className },
layout === "horizontal" ? "grid-cols-2" : "grid-cols-1"
)}
>
<div className={cn("grid w-full max-w-sm items-center gap-1.5", className)}>
{children}
</div>
);
@@ -0,0 +1,3 @@
export function InputHint({ children }: { children: React.ReactNode }) {
return <p className="slate-400 text-xs">{children}</p>;
}
+24 -13
View File
@@ -1,15 +1,26 @@
import classNames from "classnames";
"use client";
type LabelProps = React.DetailedHTMLProps<
React.LabelHTMLAttributes<HTMLLabelElement>,
HTMLLabelElement
>;
import * as LabelPrimitive from "@radix-ui/react-label";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import * as React from "react";
import { cn } from "~/utils/cn";
export function Label(props: LabelProps) {
return (
<label
className={classNames("text-sm text-slate-500", props.className)}
{...props}
/>
);
}
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
);
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
));
Label.displayName = LabelPrimitive.Root.displayName;
export { Label };
@@ -1,72 +0,0 @@
import { Listbox } from "@headlessui/react";
import { ChevronUpDownIcon } from "@heroicons/react/24/outline";
import classNames from "classnames";
type LabelProps = Parameters<typeof Listbox.Label>[0];
const labelClassName = "block text-sm font-medium text-gray-700";
function Label(props: LabelProps) {
return (
<Listbox className={classNames(labelClassName, props.className)} {...props}>
{props.children}
</Listbox>
);
}
type ButtonProps = Parameters<typeof Listbox.Button>[0] & {
children: React.ReactNode;
};
const buttonClassName =
"relative w-full rounded bg-slate-700 py-2 pl-4 pr-10 text-slate-300 text-sm text-left shadow-md hover:cursor-pointer hover:bg-slate-600/80 transition";
function Button({ children, ...props }: ButtonProps) {
return (
<Listbox.Button
className={classNames(buttonClassName, props.className)}
{...props}
>
<span className="block truncate">{children}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
);
}
type OptionsProps = Parameters<typeof Listbox.Options>[0];
const optionsClassName =
"absolute z-10 mt-1 max-h-96 w-full overflow-auto rounded p-1 bg-slate-700 text-base shadow-lg";
function Options(props: OptionsProps) {
return (
<Listbox.Options
className={classNames(optionsClassName, props.className)}
{...props}
>
{props.children}
</Listbox.Options>
);
}
type OptionProps = Parameters<typeof Listbox.Option>[0];
const optionClassName = "relative cursor-default select-none py-2 pl-3 pr-7";
const activeOptionClassName =
"bg-slate-800 rounded hover:cursor-pointer font-bold";
const inactiveOptionClassName = "text-slate-300";
function Option(props: OptionProps) {
return (
<Listbox.Option
className={({ active }: { active: boolean }) =>
classNames(
active ? activeOptionClassName : inactiveOptionClassName,
optionClassName,
props.className
)
}
{...props}
/>
);
}
export const StyledListBox = { Label, Button, Options, Option };
@@ -1,19 +0,0 @@
import React, { memo } from "react";
export type TooltipProps = {
children: React.ReactNode;
text: string;
};
export const MenuTitleToolTip: React.FC<TooltipProps> = memo((props) => {
return (
<span className="group relative flex">
<span className="pointer-events-none absolute top-0.5 left-12 flex translate-x-0 items-center justify-center whitespace-nowrap rounded bg-slate-700 px-3 py-2 text-sm text-slate-300 opacity-0 shadow transition before:absolute before:-left-2 before:top-full before:-translate-y-[22px] before:border-4 before:border-transparent before:border-r-slate-700 before:shadow before:content-[''] group-hover:opacity-100">
{props.text}
</span>
{props.children}
</span>
);
});
MenuTitleToolTip.displayName = "Menu Title";
@@ -1,77 +0,0 @@
import { Link } from "@remix-run/react";
import classnames from "classnames";
type NavLinkProps = Parameters<typeof Link>[0];
export function NavLink({
to,
children,
target,
className,
onClick,
...props
}: NavLinkProps) {
return (
<Link
to={to}
{...props}
onClick={onClick}
target={target}
className={classnames(
"hover:text-toxic-500 inline-block whitespace-nowrap py-1 text-sm text-slate-200 transition md:px-2",
{ className }
)}
>
{children}
</Link>
);
}
export function MobileNavLink({
to,
children,
className,
onClick,
...props
}: NavLinkProps) {
return (
<Link
to={to}
{...props}
onClick={onClick}
className={classnames(
"hover:text-toxic-500 text-s block w-full whitespace-nowrap rounded-lg bg-slate-900 p-2 text-center text-sm text-slate-50 transition",
{ className }
)}
>
{children}
</Link>
);
}
export function MobileNavIcon({ open }: { open: boolean }) {
return (
<svg
aria-hidden="true"
className="h-3.5 w-3.5 overflow-visible stroke-slate-300"
fill="none"
strokeWidth={2}
strokeLinecap="round"
>
<path
d="M0 1H14M0 7H14M0 13H14"
className={classnames(
"origin-center transition",
open && "scale-90 opacity-0"
)}
/>
<path
d="M2 2L12 12M12 2L2 12"
className={classnames(
"origin-center transition",
!open && "scale-90 opacity-0"
)}
/>
</svg>
);
}
+116 -14
View File
@@ -1,17 +1,119 @@
import classNames from "classnames";
"use client";
type SelectProps = React.DetailedHTMLProps<
React.SelectHTMLAttributes<HTMLSelectElement>,
HTMLSelectElement
>;
import * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select";
import { Check, ChevronDown } from "lucide-react";
import { cn } from "~/utils/cn";
const defaultClasses =
"block rounded bg-slate-700 text-slate-200 shadow-md border-none py-2 pl-4 pr-9 text-sm hover:cursor-pointer hover:bg-slate-700/50 focus:border-none focus:outline-none focus:ring-0 transition";
const Select = SelectPrimitive.Root;
export function Select({ children, className, ...props }: SelectProps) {
return (
<select className={classNames(defaultClasses, className)} {...props}>
{children}
</select>
);
}
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-80",
position === "popper" && "translate-y-1",
className
)}
position={position}
{...props}
>
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
));
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...props}
/>
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50 relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
};
@@ -1,14 +1,12 @@
export * from "./Buttons";
export * from "./Dialog";
export * from "./FormError";
export * from "./IconPlug";
export * from "./Input";
export * from "./InputGroup";
export * from "./Label";
export * from "./ListBox";
export * from "./MenuTitleToolTip";
export * from "./NavLink";
export * from "./InputHint";
export * from "./PrettyDuration";
export * from "./Select";
export * from "./Sheet";
export * from "./Spinner";
export * from "./Tabs";
@@ -1,24 +1,23 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import { Button } from "../Buttons";
import { DangerButton } from "../primitives/Buttons";
const meta: Meta<typeof DangerButton> = {
title: "Primitives/DangerButton",
component: DangerButton,
const meta: Meta<typeof Button> = {
title: "Primitives/Button",
component: Button,
decorators: [withDesign],
};
export default meta;
type Story = StoryObj<typeof DangerButton>;
type Story = StoryObj<typeof Button>;
export const Basic: Story = {
args: {
children: "Danger Button",
text: "Action text",
},
render: (args) => <DangerButton {...args} />,
render: (args) => <Button {...args} />,
};
Basic.parameters = {
@@ -1,7 +1,7 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import { StyledDialog } from "../primitives/Dialog";
import { StyledDialog } from "../Dialog";
const meta: Meta<typeof StyledDialog> = {
title: "Primitives/Dialog",
@@ -1,7 +1,13 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import { Select } from "../primitives/Select";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../Select";
const meta: Meta<typeof Select> = {
title: "Primitives/Select",
@@ -19,9 +25,14 @@ export const Basic: Story = {
},
render: (args) => (
<Select>
<option>Option One</option>
<option>Option Two </option>
<option>Option Three</option>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
<SelectItem value="system">System</SelectItem>
</SelectContent>
</Select>
),
};
@@ -1,30 +0,0 @@
export type BodyProps = {
children: React.ReactNode;
size?: Size;
className?: string;
};
type Size = "regular" | "small" | "extra-small";
const baseClasses = "font-sans";
const overrideClasses = "text-slate-300";
export function Body({
children,
className = overrideClasses,
size = "regular",
}: BodyProps) {
let sizeClass = "text-base";
switch (size) {
case "small":
sizeClass = "text-sm";
break;
case "extra-small":
sizeClass = "text-xs";
break;
}
return (
<p className={`${baseClasses} ${sizeClass} ${className}`}>{children}</p>
);
}
@@ -1,82 +0,0 @@
export type TitleProps = {
children: React.ReactNode;
size?: Size;
className?: string;
};
type Size =
| "extra-extra-small"
| "extra-small"
| "small"
| "regular"
| "large"
| "extra-large";
const baseClasses = "font-sans";
const overrideClasses = "text-slate-200";
export function Header1({
children,
className = overrideClasses,
size = "extra-large",
}: TitleProps) {
return (
<h1 className={`${baseClasses} ${getSizeClassName(size)} ${className}`}>
{children}
</h1>
);
}
export function Header2({
children,
className = overrideClasses,
size = "large",
}: TitleProps) {
return (
<h2 className={`${baseClasses} ${getSizeClassName(size)} ${className}`}>
{children}
</h2>
);
}
export function Header3({
children,
className = overrideClasses,
size = "regular",
}: TitleProps) {
return (
<h3 className={`${baseClasses} ${getSizeClassName(size)} ${className}`}>
{children}
</h3>
);
}
export function Header4({
children,
className = overrideClasses,
size = "small",
}: TitleProps) {
return (
<h4 className={`${baseClasses} ${getSizeClassName(size)} ${className}`}>
{children}
</h4>
);
}
function getSizeClassName(size: Size) {
switch (size) {
case "extra-extra-small":
return "text-sm";
case "extra-small":
return "text-base";
case "small":
return "text-lg";
case "large":
return "text-2xl";
case "extra-large":
return "text-3xl";
case "regular":
default:
return "text-xl";
}
}
@@ -1,15 +0,0 @@
import { Header2 } from "./Headers";
export function SubTitle({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<Header2 size="small" className={`mb-2 text-slate-400 ${className}`}>
{children}
</Header2>
);
}
@@ -1,16 +0,0 @@
import classNames from "classnames";
import { Header1 } from "./Headers";
export function Title({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
<Header1 size="extra-large" className={classNames("mb-6 text-slate-200")}>
{children}
</Header1>
);
}
@@ -1,28 +0,0 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import { PrimaryButton } from "../primitives/Buttons";
const meta: Meta<typeof PrimaryButton> = {
title: "Primitives/PrimaryButton",
component: PrimaryButton,
decorators: [withDesign],
};
export default meta;
type Story = StoryObj<typeof PrimaryButton>;
export const Basic: Story = {
args: {
children: "Primary Button",
},
render: (args) => <PrimaryButton {...args} />,
};
Basic.parameters = {
design: {
type: "figma",
url: "https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File",
},
};
@@ -1,28 +0,0 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import { SecondaryButton } from "../primitives/Buttons";
const meta: Meta<typeof SecondaryButton> = {
title: "Primitives/SecondaryButton",
component: SecondaryButton,
decorators: [withDesign],
};
export default meta;
type Story = StoryObj<typeof SecondaryButton>;
export const Basic: Story = {
args: {
children: "Secondary Button",
},
render: (args) => <SecondaryButton {...args} />,
};
Basic.parameters = {
design: {
type: "figma",
url: "https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File",
},
};
@@ -1,28 +0,0 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import { TertiaryButton } from "../primitives/Buttons";
const meta: Meta<typeof TertiaryButton> = {
title: "Primitives/TertiaryButton",
component: TertiaryButton,
decorators: [withDesign],
};
export default meta;
type Story = StoryObj<typeof TertiaryButton>;
export const Basic: Story = {
args: {
children: "Tertiary Button",
},
render: (args) => <TertiaryButton {...args} />,
};
Basic.parameters = {
design: {
type: "figma",
url: "https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File",
},
};
@@ -2,7 +2,7 @@ import classNames from "classnames";
import type { TemplateListItem } from "~/presenters/templateListPresenter.server";
import { ApiLogoIcon } from "../code/ApiLogoIcon";
import { Body } from "../primitives/text/Body";
import { Header1 } from "../primitives/text/Headers";
import { Header1 } from "../primitives/Headers";
export function TemplateCard({
template,
@@ -6,7 +6,7 @@ import { ApiLogoIcon } from "../code/ApiLogoIcon";
import { CopyTextPanel } from "../CopyTextButton";
import { SecondaryA } from "../primitives/Buttons";
import { Body } from "../primitives/text/Body";
import { Header1 } from "../primitives/text/Headers";
import { Header1 } from "../primitives/Headers";
export function TemplateOverview({
template,
@@ -5,7 +5,7 @@ import { Fragment, useState } from "react";
import type { TemplateListItem } from "~/presenters/templateListPresenter.server";
import { CopyTextPanel } from "../CopyTextButton";
import { StyledDialog } from "../primitives/Dialog";
import { Header1 } from "../primitives/text/Headers";
import { Header1 } from "../primitives/Headers";
import { TemplateOverview } from "./TemplateOverview";
export function TemplatesGrid({
@@ -8,7 +8,7 @@ import type {
WebhookEventTrigger,
} from "@trigger.dev/internal";
import { Body } from "../primitives/text/Body";
import { Header2 } from "../primitives/text/Headers";
import { Header2 } from "../primitives/Headers";
import cronstrue from "cronstrue";
export function TriggerBody({ trigger }: { trigger: TriggerMetadata }) {
@@ -1,4 +1,4 @@
export function StepNumber({
export function TutorialStep({
stepNumber,
drawLine,
active = false,
@@ -7,7 +7,7 @@ import { PlusIcon } from "@heroicons/react/24/solid";
import { Link } from "@remix-run/react";
import { Fragment } from "react";
import invariant from "tiny-invariant";
import { BreadcrumbDivider } from "~/components/layout/Header";
import { BreadcrumbDivider } from "~/components/navigation/NavBar";
import { useCurrentOrganization } from "~/hooks/useOrganizations";
const dimmedClassNames = "text-slate-500";
@@ -4,7 +4,7 @@ import type { UseDataFunctionReturn } from "remix-typedjson";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import invariant from "tiny-invariant";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import {
ProjectSideMenu,
SideMenuContainer,
@@ -3,7 +3,7 @@ import type { LoaderArgs } from "@remix-run/server-runtime";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { z } from "zod";
import { SecondaryLink } from "~/components/primitives/Buttons";
import { Header1 } from "~/components/primitives/text/Headers";
import { Header1 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { DeploymentBuildLogsPresenter } from "~/features/ee/projects/presenters/deploymentBuildLogsPresenter.server";
import { LogOutput } from "../../../../components/LogOutput";
@@ -14,7 +14,7 @@ import {
import { PrettyDuration } from "~/components/primitives/PrettyDuration";
import { Spinner } from "~/components/primitives/Spinner";
import { Body } from "~/components/primitives/text/Body";
import { Header1 } from "~/components/primitives/text/Headers";
import { Header1 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { deploymentStatusTitle } from "~/features/ee/projects/components/deploymentStatus";
import { DeploymentPresenter } from "~/features/ee/projects/presenters/deploymentPresenter.server";
@@ -8,7 +8,7 @@ import { PanelWarning } from "~/components/layout/PanelInfo";
import { TertiaryLink } from "~/components/primitives/Buttons";
import { Spinner } from "~/components/primitives/Spinner";
import { Body } from "~/components/primitives/text/Body";
import { Header1, Header4 } from "~/components/primitives/text/Headers";
import { Header1, Header4 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { useCurrentProject } from "../$projectP";
import { LogOutput } from "../../../components/LogOutput";
@@ -13,7 +13,7 @@ import { InputGroup } from "~/components/primitives/InputGroup";
import { Label } from "~/components/primitives/Label";
import { Select } from "~/components/primitives/Select";
import { Body } from "~/components/primitives/text/Body";
import { Header1 } from "~/components/primitives/text/Headers";
import { Header1 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { useLiveEnvironment } from "~/hooks/useEnvironments";
import {
@@ -1,10 +1,10 @@
import { CloudIcon } from "@heroicons/react/24/outline";
import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { OrganizationsSideMenu } from "~/components/navigation/SideMenu";
import { Body } from "~/components/primitives/text/Body";
import { Header1 } from "~/components/primitives/text/Headers";
import { Header1 } from "~/components/primitives/Headers";
export default function ComingSoonPage() {
return (
@@ -21,14 +21,14 @@ import { OctoKitty } from "~/components/GitHubLoginButton";
import { IntlDate } from "~/components/IntlDate";
import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { List } from "~/components/layout/List";
import { Panel } from "~/components/layout/Panel";
import { OrganizationsSideMenu } from "~/components/navigation/SideMenu";
import { PrimaryLink } from "~/components/primitives/Buttons";
import { Spinner } from "~/components/primitives/Spinner";
import { Body } from "~/components/primitives/text/Body";
import { Header2 } from "~/components/primitives/text/Headers";
import { Header2 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { Title } from "~/components/primitives/text/Title";
import { requireUser } from "~/services/session.server";
@@ -30,7 +30,7 @@ import invariant from "tiny-invariant";
import { OctoKitty } from "~/components/GitHubLoginButton";
import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { List } from "~/components/layout/List";
import { Panel } from "~/components/layout/Panel";
import { PanelWarning } from "~/components/layout/PanelWarning";
@@ -43,7 +43,7 @@ import {
import { StyledDialog } from "~/components/primitives/Dialog";
import { Spinner } from "~/components/primitives/Spinner";
import { Body } from "~/components/primitives/text/Body";
import { Header4 } from "~/components/primitives/text/Headers";
import { Header4 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { Title } from "~/components/primitives/text/Title";
import { Tooltip } from "~/components/primitives/Tooltip";
+2 -2
View File
@@ -7,10 +7,10 @@ import {
import { Link } from "@remix-run/react";
import classNames from "classnames";
import { AppBody } from "~/components/layout/AppLayout";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { MenuTitleToolTip } from "~/components/primitives/MenuTitleToolTip";
import { Body } from "~/components/primitives/text/Body";
import { Header4 } from "~/components/primitives/text/Headers";
import { Header4 } from "~/components/primitives/Headers";
import type { MatchedOrganization } from "~/hooks/useOrganizations";
import { useOrganizations } from "~/hooks/useOrganizations";
import { useOptionalUser } from "~/hooks/useUser";
@@ -5,7 +5,7 @@ import invariant from "tiny-invariant";
import { CopyTextPanel } from "~/components/CopyTextButton";
import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { Panel } from "~/components/layout/Panel";
import { OrganizationsSideMenu } from "~/components/navigation/SideMenu";
import { TertiaryButton } from "~/components/primitives/Buttons";
@@ -1,6 +1,6 @@
import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { OrganizationsSideMenu } from "~/components/navigation/SideMenu";
import { Title } from "~/components/primitives/text/Title";
import { useDevEnvironment } from "~/hooks/useEnvironments";
@@ -7,7 +7,7 @@ import { NamedIcon, NamedIconInBox } from "~/components/Icon";
import { ConnectButton } from "~/components/integrations/ConnectButton";
import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout";
import { Container } from "~/components/layout/Container";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { List } from "~/components/layout/List";
import { OrganizationsSideMenu } from "~/components/navigation/SideMenu";
import { Badge } from "~/components/primitives/Badge";
@@ -21,7 +21,7 @@ import {
PopoverTrigger,
} from "~/components/primitives/Popover";
import { Body } from "~/components/primitives/text/Body";
import { Header3 } from "~/components/primitives/text/Headers";
import { Header3 } from "~/components/primitives/Headers";
import { SubTitle } from "~/components/primitives/text/SubTitle";
import { Title } from "~/components/primitives/text/Title";
import { useCurrentOrganization } from "~/hooks/useOrganizations";
@@ -1,12 +1,12 @@
import { UserGroupIcon } from "@heroicons/react/24/outline";
import { Container } from "~/components/layout/Container";
import { Body } from "~/components/primitives/text/Body";
import { Header1 } from "~/components/primitives/text/Headers";
import { Header1 } from "~/components/primitives/Headers";
export default function Members() {
return (
<Container>
<main className="w-full h-full flex items-center justify-center">
<div className="flex flex-col items-center gap-y-3.5 min-w-[400px] bg-slate-800 shadow-md border border-slate-800 rounded-md p-10">
<main className="flex h-full w-full items-center justify-center">
<div className="flex min-w-[400px] flex-col items-center gap-y-3.5 rounded-md border border-slate-800 bg-slate-800 p-10 shadow-md">
<UserGroupIcon className="h-10 w-10 text-indigo-500" />
<Header1 size="large" className="">
Manage team members
+2 -2
View File
@@ -3,9 +3,9 @@ import type { ActionFunction } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, useActionData } from "@remix-run/react";
import * as React from "react";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { PrimaryButton, SecondaryLink } from "~/components/primitives/Buttons";
import { Header1 } from "~/components/primitives/text/Headers";
import { Header1 } from "~/components/primitives/Headers";
import { createOrganization } from "~/models/organization.server";
import { requireUserId } from "~/services/session.server";
+1 -1
View File
@@ -7,7 +7,7 @@ import {
PublicAppBody,
PublicAppLayout,
} from "~/components/layout/AppLayout";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
import { MarketingHeader } from "~/components/layout/MarketingHeader";
import { getOrganizations } from "~/models/organization.server";
import { getImpersonationId } from "~/services/impersonation.server";
@@ -1,5 +1,5 @@
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { Header2 } from "~/components/primitives/text/Headers";
import { Header2 } from "~/components/primitives/Headers";
import { TemplatesGrid } from "~/components/templates/TemplatesGrid";
import { TemplateListPresenter } from "~/presenters/templateListPresenter.server";
+1 -1
View File
@@ -1,6 +1,6 @@
import { BookOpenIcon } from "@heroicons/react/24/solid";
import { Link, Outlet } from "@remix-run/react";
import { Header } from "~/components/layout/Header";
import { Header } from "~/components/navigation/NavBar";
const pages = [
{
+2 -1
View File
@@ -67,7 +67,9 @@
"@octokit/webhooks-methods": "^3.0.2",
"@prisma/client": "^4.13.0",
"@radix-ui/react-dialog": "^1.0.3",
"@radix-ui/react-label": "^2.0.1",
"@radix-ui/react-popover": "^1.0.5",
"@radix-ui/react-select": "^1.2.1",
"@react-email/head": "^0.0.2",
"@remix-run/express": "v1.11.0",
"@remix-run/node": "v1.11.0",
@@ -81,7 +83,6 @@
"@uiw/react-codemirror": "^4.13.2",
"bcryptjs": "^2.4.3",
"class-variance-authority": "^0.5.2",
"classnames": "^2.3.1",
"clsx": "^1.2.1",
"compression": "^1.7.4",
"cron-parser": "^4.7.1",
+101 -2
View File
@@ -68,7 +68,9 @@ importers:
'@octokit/webhooks-types': ^6.10.0
'@prisma/client': ^4.13.0
'@radix-ui/react-dialog': ^1.0.3
'@radix-ui/react-label': ^2.0.1
'@radix-ui/react-popover': ^1.0.5
'@radix-ui/react-select': ^1.2.1
'@react-email/head': ^0.0.2
'@remix-run/dev': v1.11.0
'@remix-run/eslint-config': v1.11.0
@@ -130,7 +132,6 @@ importers:
bcryptjs: ^2.4.3
c8: ^7.11.3
class-variance-authority: ^0.5.2
classnames: ^2.3.1
cli-ux: ^6.0.9
clsx: ^1.2.1
compression: ^1.7.4
@@ -249,7 +250,9 @@ importers:
'@octokit/webhooks-methods': 3.0.2
'@prisma/client': 4.13.0_prisma@4.13.0
'@radix-ui/react-dialog': 1.0.3_ib3m5ricvtkl2cll7qpr2f6lvq
'@radix-ui/react-label': 2.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-popover': 1.0.5_ib3m5ricvtkl2cll7qpr2f6lvq
'@radix-ui/react-select': 1.2.1_ib3m5ricvtkl2cll7qpr2f6lvq
'@react-email/head': 0.0.2
'@remix-run/express': 1.11.0_cwk4saenierp7pa7l5cpbeswge
'@remix-run/node': 1.11.0_biqbaboplfbrettd7655fr4n2y
@@ -263,7 +266,6 @@ importers:
'@uiw/react-codemirror': 4.19.5_aguurb4bmecpxzejz52amioxne
bcryptjs: 2.4.3
class-variance-authority: 0.5.2_typescript@4.9.4
classnames: 2.3.2
clsx: 1.2.1
compression: 1.7.4
cron-parser: 4.7.1
@@ -6481,6 +6483,12 @@ packages:
resolution: {integrity: sha512-HrniowHRZXHuGT9XRgoXEaP2gJLXM5RMoItaY2PkjvuZ+iHc0Zjbm/302MB8YsPdWozAPHHn+jpFEcEn71OgPw==}
requiresBuild: true
/@radix-ui/number/1.0.0:
resolution: {integrity: sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==}
dependencies:
'@babel/runtime': 7.20.7
dev: false
/@radix-ui/primitive/1.0.0:
resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==}
dependencies:
@@ -6499,6 +6507,21 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-collection/1.0.2_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.7
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
'@radix-ui/react-context': 1.0.0_react@18.2.0
'@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-slot': 1.0.1_react@18.2.0
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-compose-refs/1.0.0_react@18.2.0:
resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==}
peerDependencies:
@@ -6544,6 +6567,15 @@ packages:
- '@types/react'
dev: false
/@radix-ui/react-direction/1.0.0_react@18.2.0:
resolution: {integrity: sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.7
react: 18.2.0
dev: false
/@radix-ui/react-dismissable-layer/1.0.3_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==}
peerDependencies:
@@ -6593,6 +6625,18 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-label/2.0.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-qcfbS3B8hTYmEO44RNcXB6pegkxRsJIbdxTMu0PEX0Luv5O2DvTIwwVYxQfUwLpM88EL84QRPLOLgwUSApMsLQ==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.7
'@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-popover/1.0.5_ib3m5ricvtkl2cll7qpr2f6lvq:
resolution: {integrity: sha512-GRHZ8yD12MrN2NLobHPE8Rb5uHTxd9x372DE9PPNnBjpczAQHcZ5ne0KXG4xpf+RDdXSzdLv9ym6mYJCDTaUZg==}
peerDependencies:
@@ -6681,6 +6725,40 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-select/1.2.1_ib3m5ricvtkl2cll7qpr2f6lvq:
resolution: {integrity: sha512-GULRMITaOHNj79BZvQs3iZO0+f2IgI8g5HDhMi7Bnc13t7IlG86NFtOCfTLme4PNZdEtU+no+oGgcl6IFiphpQ==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.7
'@radix-ui/number': 1.0.0
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-collection': 1.0.2_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
'@radix-ui/react-context': 1.0.0_react@18.2.0
'@radix-ui/react-direction': 1.0.0_react@18.2.0
'@radix-ui/react-dismissable-layer': 1.0.3_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-focus-guards': 1.0.0_react@18.2.0
'@radix-ui/react-focus-scope': 1.0.2_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-id': 1.0.0_react@18.2.0
'@radix-ui/react-popper': 1.1.1_ib3m5ricvtkl2cll7qpr2f6lvq
'@radix-ui/react-portal': 1.0.2_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-slot': 1.0.1_react@18.2.0
'@radix-ui/react-use-callback-ref': 1.0.0_react@18.2.0
'@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0
'@radix-ui/react-use-layout-effect': 1.0.0_react@18.2.0
'@radix-ui/react-use-previous': 1.0.0_react@18.2.0
'@radix-ui/react-visually-hidden': 1.0.2_biqbaboplfbrettd7655fr4n2y
aria-hidden: 1.2.3
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-remove-scroll: 2.5.5_kzbn2opkn2327fwg5yzwzya5o4
transitivePeerDependencies:
- '@types/react'
dev: false
/@radix-ui/react-slot/1.0.0_react@18.2.0:
resolution: {integrity: sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==}
peerDependencies:
@@ -6739,6 +6817,15 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-use-previous/1.0.0_react@18.2.0:
resolution: {integrity: sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.7
react: 18.2.0
dev: false
/@radix-ui/react-use-rect/1.0.0_react@18.2.0:
resolution: {integrity: sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==}
peerDependencies:
@@ -6759,6 +6846,18 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-visually-hidden/1.0.2_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-qirnJxtYn73HEk1rXL12/mXnu2rwsNHDID10th2JGtdK25T9wX+mxRmGt7iPSahw512GbZOc0syZX1nLQGoEOg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.7
'@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/rect/1.0.0:
resolution: {integrity: sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==}
dependencies: