feat: restructure as pnpm monorepo with Tauri desktop shell

- Migrate to packages/web + packages/desktop workspace layout via git mv
- Add Tauri v2 desktop shell with @tauri-apps/plugin-http for CORS bypass
- Configure Turborepo with package-level dependsOn build graph
- Add semantic-release with exec plugin for GHA output and disabled PR comments
- Fix http:default capability scope to allow all HTTP/HTTPS origins
- Add Vite Tauri integration (clearScreen, TAURI_DEV_HOST, target, envPrefix)
- Add semantic-release.yml and release.yml GitHub Actions workflows
- Fix all Biome lint errors (noArrayIndexKey, noNonNullAssertion, button types)
This commit is contained in:
Offending Commit
2026-04-24 16:52:40 -05:00
parent 9a74182f97
commit 92c4dfd3dd
152 changed files with 14088 additions and 4774 deletions

View File

@@ -0,0 +1,29 @@
import { cn } from "@/lib/utils";
import { type VariantProps, cva } from "class-variance-authority";
import type { HTMLAttributes } from "react";
const badgeVariants = cva(
"inline-flex items-center gap-1 rounded-md border px-2 py-0.5 text-xs font-medium transition-colors",
{
variants: {
variant: {
default: "border-transparent bg-primary/15 text-primary",
secondary: "border-transparent bg-secondary text-muted-foreground",
outline: "border-border text-muted-foreground",
destructive: "border-transparent bg-red-500/15 text-red-400",
success: "border-transparent bg-emerald-500/15 text-emerald-400",
warning: "border-transparent bg-amber-500/15 text-amber-400",
blue: "border-transparent bg-sky-500/15 text-sky-400",
},
},
defaultVariants: { variant: "default" },
},
);
interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {}
export function Badge({ className, variant, ...props }: BadgeProps) {
return <span className={cn(badgeVariants({ variant }), className)} {...props} />;
}
export { badgeVariants };

View File

@@ -0,0 +1,66 @@
import { cn } from "@/lib/utils";
import { Slot } from "@radix-ui/react-slot";
import { type VariantProps, cva } from "class-variance-authority";
import { forwardRef } from "react";
const buttonVariants = cva(
[
"inline-flex items-center justify-center gap-1.5 rounded-lg font-medium transition-all",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-1)]",
"disabled:opacity-50 disabled:pointer-events-none",
],
{
variants: {
variant: {
primary: ["text-white", "[background:var(--accent)]", "focus-visible:ring-[var(--accent)]"],
accent: [
"[background:var(--accent-dim)] [color:var(--accent-text)]",
"[border:1px_solid_var(--accent-border)]",
"focus-visible:ring-[var(--accent)]",
],
surface: [
"[background:var(--surface)] [color:var(--text-2)]",
"[border:1px_solid_var(--border)]",
"focus-visible:ring-[var(--border)]",
],
ghost: [
"[color:var(--text-3)]",
"hover:[background:var(--surface)]",
"focus-visible:ring-[var(--border)]",
],
destructive: [
"bg-[rgba(239,68,68,0.08)] text-[#f87171]",
"border border-[rgba(239,68,68,0.2)]",
"focus-visible:ring-[#f87171]",
],
},
size: {
default: "px-4 py-2 text-sm",
sm: "px-3 py-1.5 text-xs",
icon: "p-1.5 text-sm",
},
},
defaultVariants: {
variant: "accent",
size: "default",
},
},
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp ref={ref} className={cn(buttonVariants({ variant, size }), className)} {...props} />
);
},
);
Button.displayName = "Button";
export { buttonVariants };

View File

@@ -0,0 +1,25 @@
import { cn } from "@/lib/utils";
import type { HTMLAttributes } from "react";
export function Card({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("rounded-xl border border-border bg-card text-card-foreground", className)}
{...props}
/>
);
}
export function CardHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
return <div className={cn("flex flex-col gap-1 px-5 py-4", className)} {...props} />;
}
export function CardTitle({ className, ...props }: HTMLAttributes<HTMLHeadingElement>) {
return (
<h3 className={cn("text-sm font-semibold leading-none tracking-tight", className)} {...props} />
);
}
export function CardContent({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
return <div className={cn("px-5 pb-5", className)} {...props} />;
}

View File

@@ -0,0 +1,9 @@
"use client";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
const Collapsible = CollapsiblePrimitive.Root;
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
export { Collapsible, CollapsibleTrigger, CollapsibleContent };

View File

@@ -0,0 +1,105 @@
import { cn } from "@/lib/utils";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import { forwardRef } from "react";
export const Dialog = DialogPrimitive.Root;
export const DialogTrigger = DialogPrimitive.Trigger;
export const DialogPortal = DialogPrimitive.Portal;
export const DialogClose = DialogPrimitive.Close;
export const DialogOverlay = forwardRef<
React.ComponentRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 backdrop-blur-sm",
"bg-black/60",
"data-[state=open]:animate-in data-[state=closed]:animate-out",
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
export const DialogContent = forwardRef<
React.ComponentRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-1/2 top-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2",
"rounded-2xl p-6 shadow-2xl",
"[background:var(--bg-2)] [border:1px_solid_var(--border-2)]",
"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-[state=closed]:slide-out-to-top-[2%] data-[state=open]:slide-in-from-top-[2%]",
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close
className={cn(
"absolute right-4 top-4 rounded-lg p-1 transition-colors",
"[color:var(--text-4)] hover:[color:var(--text-2)]",
"focus:outline-none focus:ring-2 focus:ring-[var(--accent)] focus:ring-offset-2 focus:ring-offset-[var(--bg-2)]",
)}
>
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
export function DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"flex flex-col gap-1.5 pb-4 mb-4 [border-bottom:1px_solid_var(--border)]",
className,
)}
{...props}
/>
);
}
export function DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div className={cn("flex justify-end gap-2 pt-4 mt-4", className)} {...props} />;
}
export const DialogTitle = forwardRef<
React.ComponentRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn("text-sm font-semibold", className)}
style={{ color: "var(--text-1)" }}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;
export const DialogDescription = forwardRef<
React.ComponentRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm", className)}
style={{ color: "var(--text-3)" }}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

View File

@@ -0,0 +1,42 @@
import { cn } from "@/lib/utils";
import { forwardRef } from "react";
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
export const Input = forwardRef<HTMLInputElement, InputProps>(({ className, ...props }, ref) => (
<input
ref={ref}
className={cn(
"flex w-full rounded-lg px-3 py-2 text-sm transition-all outline-none",
"[background:var(--surface)] [color:var(--text-1)]",
"[border:1px_solid_var(--border-2)]",
"placeholder:[color:var(--text-4)]",
"focus:[border-color:var(--accent)]",
"disabled:opacity-50 disabled:cursor-not-allowed",
className,
)}
{...props}
/>
));
Input.displayName = "Input";
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => (
<textarea
ref={ref}
className={cn(
"flex w-full rounded-lg px-3 py-2 text-sm transition-all outline-none resize-none",
"[background:var(--surface)] [color:var(--text-1)]",
"[border:1px_solid_var(--border-2)]",
"placeholder:[color:var(--text-4)]",
"focus:[border-color:var(--accent)]",
"disabled:opacity-50 disabled:cursor-not-allowed",
className,
)}
{...props}
/>
),
);
Textarea.displayName = "Textarea";

View File

@@ -0,0 +1,20 @@
import { cn } from "@/lib/utils";
import * as LabelPrimitive from "@radix-ui/react-label";
import { forwardRef } from "react";
export const Label = forwardRef<
React.ComponentRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(
"block text-xs font-medium leading-none",
"peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
className,
)}
style={{ color: "var(--text-2)" }}
{...props}
/>
));
Label.displayName = LabelPrimitive.Root.displayName;

View File

@@ -0,0 +1,21 @@
import { cn } from "@/lib/utils";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { forwardRef } from "react";
export const Separator = forwardRef<
React.ComponentRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 [background:var(--border)]",
orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
className,
)}
{...props}
/>
));
Separator.displayName = SeparatorPrimitive.Root.displayName;

View File

@@ -0,0 +1,76 @@
import { cn } from "@/lib/utils";
import { forwardRef } from "react";
export const Table = forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
({ className, ...props }, ref) => (
<div className="w-full overflow-x-auto">
<table ref={ref} className={cn("w-full text-xs caption-bottom", className)} {...props} />
</div>
),
);
Table.displayName = "Table";
export const TableHeader = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead
ref={ref}
className={cn("[&_tr]:border-b [&_tr]:[border-color:var(--border)]", className)}
{...props}
/>
));
TableHeader.displayName = "TableHeader";
export const TableBody = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody ref={ref} className={cn("[&_tr:last-child]:border-0", className)} {...props} />
));
TableBody.displayName = "TableBody";
export const TableRow = forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b transition-colors [border-color:var(--border)]",
"hover:[background:var(--surface)]",
"data-[state=selected]:[background:var(--surface)]",
className,
)}
{...props}
/>
),
);
TableRow.displayName = "TableRow";
export const TableHead = forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-9 px-4 text-left align-middle font-medium [background:var(--bg-3)]",
"[color:var(--text-3)]",
"[&:has([role=checkbox])]:pr-0",
className,
)}
{...props}
/>
));
TableHead.displayName = "TableHead";
export const TableCell = forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("px-4 py-2.5 align-middle [&:has([role=checkbox])]:pr-0", className)}
{...props}
/>
));
TableCell.displayName = "TableCell";

View File

@@ -0,0 +1,31 @@
import { cn } from "@/lib/utils";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
export const TooltipProvider = TooltipPrimitive.Provider;
export const Tooltip = TooltipPrimitive.Root;
export const TooltipTrigger = TooltipPrimitive.Trigger;
export function TooltipContent({
className,
sideOffset = 4,
...props
}: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>) {
return (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-lg px-2.5 py-1.5 text-xs font-medium",
"[background:var(--bg-3)] [color:var(--text-1)]",
"[border:1px_solid_var(--border)]",
"shadow-md",
"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=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</TooltipPrimitive.Portal>
);
}

View File

@@ -0,0 +1,110 @@
import { cn } from "@/lib/utils";
type AsChild<T extends React.ElementType> = {
as?: T;
className?: string;
children?: React.ReactNode;
};
type Props<T extends React.ElementType> = AsChild<T> &
Omit<React.ComponentPropsWithoutRef<T>, keyof AsChild<T>>;
export function PageTitle<T extends React.ElementType = "h1">({
as,
className,
children,
...rest
}: Props<T>) {
const Tag = (as ?? "h1") as React.ElementType;
return (
<Tag
className={cn("text-xl font-semibold tracking-tight", className)}
style={{ color: "var(--text-1)" }}
{...rest}
>
{children}
</Tag>
);
}
export function SectionHeading<T extends React.ElementType = "h2">({
as,
className,
children,
...rest
}: Props<T>) {
const Tag = (as ?? "h2") as React.ElementType;
return (
<Tag
className={cn("text-sm font-medium mb-3", className)}
style={{ color: "var(--text-1)" }}
{...rest}
>
{children}
</Tag>
);
}
export function Body<T extends React.ElementType = "p">({
as,
className,
children,
...rest
}: Props<T>) {
const Tag = (as ?? "p") as React.ElementType;
return (
<Tag
className={cn("text-sm leading-relaxed", className)}
style={{ color: "var(--text-2)" }}
{...rest}
>
{children}
</Tag>
);
}
export function Muted<T extends React.ElementType = "p">({
as,
className,
children,
...rest
}: Props<T>) {
const Tag = (as ?? "p") as React.ElementType;
return (
<Tag className={cn("text-sm", className)} style={{ color: "var(--text-3)" }} {...rest}>
{children}
</Tag>
);
}
export function Caption<T extends React.ElementType = "span">({
as,
className,
children,
...rest
}: Props<T>) {
const Tag = (as ?? "span") as React.ElementType;
return (
<Tag className={cn("text-xs", className)} style={{ color: "var(--text-4)" }} {...rest}>
{children}
</Tag>
);
}
export function MonoCaption<T extends React.ElementType = "span">({
as,
className,
children,
...rest
}: Props<T>) {
const Tag = (as ?? "span") as React.ElementType;
return (
<Tag
className={cn("text-xs font-mono", className)}
style={{ color: "var(--text-4)" }}
{...rest}
>
{children}
</Tag>
);
}