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:
29
packages/web/src/components/ui/badge.tsx
Normal file
29
packages/web/src/components/ui/badge.tsx
Normal 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 };
|
||||
66
packages/web/src/components/ui/button.tsx
Normal file
66
packages/web/src/components/ui/button.tsx
Normal 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 };
|
||||
25
packages/web/src/components/ui/card.tsx
Normal file
25
packages/web/src/components/ui/card.tsx
Normal 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} />;
|
||||
}
|
||||
9
packages/web/src/components/ui/collapsible.tsx
Normal file
9
packages/web/src/components/ui/collapsible.tsx
Normal 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 };
|
||||
105
packages/web/src/components/ui/dialog.tsx
Normal file
105
packages/web/src/components/ui/dialog.tsx
Normal 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;
|
||||
42
packages/web/src/components/ui/input.tsx
Normal file
42
packages/web/src/components/ui/input.tsx
Normal 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";
|
||||
20
packages/web/src/components/ui/label.tsx
Normal file
20
packages/web/src/components/ui/label.tsx
Normal 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;
|
||||
21
packages/web/src/components/ui/separator.tsx
Normal file
21
packages/web/src/components/ui/separator.tsx
Normal 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;
|
||||
76
packages/web/src/components/ui/table.tsx
Normal file
76
packages/web/src/components/ui/table.tsx
Normal 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";
|
||||
31
packages/web/src/components/ui/tooltip.tsx
Normal file
31
packages/web/src/components/ui/tooltip.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
110
packages/web/src/components/ui/typography.tsx
Normal file
110
packages/web/src/components/ui/typography.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user