mirror of
https://github.com/bartvdbraak/omnidash.git
synced 2025-04-27 15:31:21 +00:00
refactor: Fix formatting using prettier
This commit is contained in:
parent
d90b2a338f
commit
7ce405fbef
27 changed files with 406 additions and 206 deletions
|
@ -1,7 +1,14 @@
|
|||
import { Logo } from "@/components/logo";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { BarChart, Database, FileKey, Filter, FormInput, Home } from "lucide-react";
|
||||
import {
|
||||
BarChart,
|
||||
Database,
|
||||
FileKey,
|
||||
Filter,
|
||||
FormInput,
|
||||
Home,
|
||||
} from "lucide-react";
|
||||
import { ChannelLink } from "./channelLink";
|
||||
import { TeamSwitcher } from "./TeamSwitcher";
|
||||
import Link from "next/link";
|
||||
|
@ -29,38 +36,64 @@ export const DesktopSidebar: React.FC<Props> = ({ navigation, channels }) => {
|
|||
</Link>
|
||||
<div className="space-y-4">
|
||||
<div className="px-6 py-2">
|
||||
<h2 className="px-2 mb-2 text-lg font-semibold tracking-tight">{/* Events */}</h2>
|
||||
<h2 className="px-2 mb-2 text-lg font-semibold tracking-tight">
|
||||
{/* Events */}
|
||||
</h2>
|
||||
<div className="space-y-1">
|
||||
<Link href="/overview">
|
||||
<Button variant="ghost" size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<Home className="w-4 h-4 mr-2" />
|
||||
Overview
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/keys">
|
||||
<Button variant="ghost" size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<FileKey className="w-4 h-4 mr-2" />
|
||||
API Keys
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/channels">
|
||||
<Button variant="ghost" size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<Database className="w-4 h-4 mr-2" />
|
||||
Channels
|
||||
</Button>
|
||||
</Link>
|
||||
<Button variant="ghost" disabled size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<Filter className="w-4 h-4 mr-2" />
|
||||
Filter
|
||||
</Button>
|
||||
<Button variant="ghost" disabled size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<BarChart className="w-4 h-4 mr-2" />
|
||||
Analytics
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<h2 className="relative px-8 text-lg font-semibold tracking-tight">Channels</h2>
|
||||
<h2 className="relative px-8 text-lg font-semibold tracking-tight">
|
||||
Channels
|
||||
</h2>
|
||||
<ScrollArea className="h-[230px] px-4">
|
||||
<div className="p-2 space-y-1">
|
||||
{channels
|
||||
|
|
|
@ -49,38 +49,64 @@ export const MobileSidebar: React.FC<Props> = ({ channels }) => {
|
|||
</SheetHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="px-6 py-2">
|
||||
<h2 className="px-2 mb-2 text-lg font-semibold tracking-tight">{/* Events */}</h2>
|
||||
<h2 className="px-2 mb-2 text-lg font-semibold tracking-tight">
|
||||
{/* Events */}
|
||||
</h2>
|
||||
<div className="space-y-1">
|
||||
<Link href="/overview">
|
||||
<Button variant="ghost" size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<Home className="w-4 h-4 mr-2" />
|
||||
Overview
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/keys">
|
||||
<Button variant="ghost" size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<FileKey className="w-4 h-4 mr-2" />
|
||||
API Keys
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/channels">
|
||||
<Button variant="ghost" size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<Database className="w-4 h-4 mr-2" />
|
||||
Channels
|
||||
</Button>
|
||||
</Link>
|
||||
<Button variant="ghost" disabled size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<Filter className="w-4 h-4 mr-2" />
|
||||
Filter
|
||||
</Button>
|
||||
<Button variant="ghost" disabled size="sm" className="justify-start w-full">
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled
|
||||
size="sm"
|
||||
className="justify-start w-full"
|
||||
>
|
||||
<BarChart className="w-4 h-4 mr-2" />
|
||||
Analytics
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<h2 className="relative px-8 text-lg font-semibold tracking-tight">Events</h2>
|
||||
<h2 className="relative px-8 text-lg font-semibold tracking-tight">
|
||||
Events
|
||||
</h2>
|
||||
<ScrollArea className="h-[230px] px-4">
|
||||
<div className="p-2 space-y-1">
|
||||
{channels.map((channel) => (
|
||||
|
|
|
@ -12,7 +12,12 @@ import { useRouter } from "next/navigation";
|
|||
import { useState } from "react";
|
||||
import { Loading } from "@/components/loading";
|
||||
|
||||
import { useAuth, useOrganization, useOrganizationList, useUser } from "@clerk/clerk-react";
|
||||
import {
|
||||
useAuth,
|
||||
useOrganization,
|
||||
useOrganizationList,
|
||||
useUser,
|
||||
} from "@clerk/clerk-react";
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
||||
import { AvatarFallback } from "@radix-ui/react-avatar";
|
||||
|
||||
|
@ -51,10 +56,15 @@ export const TeamSwitcher: React.FC<Props> = (): JSX.Element => {
|
|||
<div className="flex items-center justify-start w-full gap-4 ">
|
||||
<Avatar>
|
||||
{user?.profileImageUrl ? (
|
||||
<AvatarImage src={user.profileImageUrl} alt={user.username ?? "Profile picture"} />
|
||||
<AvatarImage
|
||||
src={user.profileImageUrl}
|
||||
alt={user.username ?? "Profile picture"}
|
||||
/>
|
||||
) : null}
|
||||
<AvatarFallback className="flex items-center justify-center w-8 h-8 overflow-hidden border rounded-md bg-zinc-100 border-zinc-500 text-zinc-700">
|
||||
{(currentOrg?.slug ?? user?.username ?? "").slice(0, 2).toUpperCase() ?? "P"}
|
||||
{(currentOrg?.slug ?? user?.username ?? "")
|
||||
.slice(0, 2)
|
||||
.toUpperCase() ?? "P"}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<span>{currentOrg?.name ?? "Personal"}</span>
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export default async function Page(_props: {
|
||||
params: { tenantSlug: string };
|
||||
}) {
|
||||
export default async function Page(_props: { params: { tenantSlug: string } }) {
|
||||
const stats: {
|
||||
label: string;
|
||||
value: string;
|
||||
}[] = [
|
||||
{
|
||||
label: "Total Channels",
|
||||
value: '0',
|
||||
value: "0",
|
||||
},
|
||||
{
|
||||
label: "Total Events (7 days)",
|
||||
value: '0',
|
||||
value: "0",
|
||||
},
|
||||
];
|
||||
return (
|
||||
|
@ -47,7 +44,7 @@ export default async function Page(_props: {
|
|||
"lg:grid-cols-2": stats.length === 2,
|
||||
"lg:grid-cols-3": stats.length === 3,
|
||||
"lg:grid-cols-4": stats.length >= 4,
|
||||
},
|
||||
}
|
||||
)}
|
||||
>
|
||||
{" "}
|
||||
|
@ -55,11 +52,17 @@ export default async function Page(_props: {
|
|||
<div
|
||||
key={stat.label}
|
||||
className={cn(
|
||||
statIdx % 2 === 1 ? "sm:border-l" : statIdx === 2 ? "lg:border-l" : "",
|
||||
"flex items-baseline flex-wrap justify-between gap-y-2 gap-x-4 border-t border-zinc-100/5 px-4 py-10 sm:px-6 lg:border-t-0 xl:px-8",
|
||||
statIdx % 2 === 1
|
||||
? "sm:border-l"
|
||||
: statIdx === 2
|
||||
? "lg:border-l"
|
||||
: "",
|
||||
"flex items-baseline flex-wrap justify-between gap-y-2 gap-x-4 border-t border-zinc-100/5 px-4 py-10 sm:px-6 lg:border-t-0 xl:px-8"
|
||||
)}
|
||||
>
|
||||
<dt className="text-sm font-medium leading-6 text-zinc-500">{stat.label}</dt>
|
||||
<dt className="text-sm font-medium leading-6 text-zinc-500">
|
||||
{stat.label}
|
||||
</dt>
|
||||
{/* <dd
|
||||
className={cn(
|
||||
stat.changeType === 'negative' ? 'text-rose-600' : 'text-zinc-700',
|
||||
|
@ -96,9 +99,7 @@ export default async function Page(_props: {
|
|||
<th>More details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Particles } from "@/components/landing/particles";
|
||||
import { ClerkProvider, SignIn, SignedIn, SignedOut } from "@clerk/nextjs/app-beta";
|
||||
import {
|
||||
ClerkProvider,
|
||||
SignIn,
|
||||
SignedIn,
|
||||
SignedOut,
|
||||
} from "@clerk/nextjs/app-beta";
|
||||
|
||||
export default function AppLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
export default function AppLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ClerkProvider>
|
||||
<SignedIn>{children}</SignedIn>
|
||||
|
|
|
@ -42,7 +42,11 @@ export default function DefaultLayout({
|
|||
className="text-gray-500 hover:text-gray-400"
|
||||
>
|
||||
<span className="sr-only">Github</span>
|
||||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Inter } from 'next/font/google';
|
||||
import { Inter } from "next/font/google";
|
||||
import LocalFont from "next/font/local";
|
||||
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
|
@ -13,7 +13,7 @@ export const metadata: Metadata = {
|
|||
template: "%s | Omnidash",
|
||||
},
|
||||
description: "Open Source Multi-client Ticket Dashboard",
|
||||
metadataBase: new URL('https://omnidash.io'),
|
||||
metadataBase: new URL("https://omnidash.io"),
|
||||
openGraph: {
|
||||
title: "Omnidash",
|
||||
description: "Open Source Multi-client Ticket Dashboard",
|
||||
|
|
|
@ -78,7 +78,10 @@ export const Icons = {
|
|||
),
|
||||
radix: (props: LucideProps) => (
|
||||
<svg viewBox="0 0 25 25" fill="none" {...props}>
|
||||
<path d="M12 25C7.58173 25 4 21.4183 4 17C4 12.5817 7.58173 9 12 9V25Z" fill="currentcolor" />
|
||||
<path
|
||||
d="M12 25C7.58173 25 4 21.4183 4 17C4 12.5817 7.58173 9 12 9V25Z"
|
||||
fill="currentcolor"
|
||||
/>
|
||||
<path d="M12 0H4V8H12V0Z" fill="currentcolor" />
|
||||
<path
|
||||
d="M17 8C19.2091 8 21 6.20914 21 4C21 1.79086 19.2091 0 17 0C14.7909 0 13 1.79086 13 4C13 6.20914 14.7909 8 17 8Z"
|
||||
|
|
|
@ -29,7 +29,9 @@ export const Cta: React.FC = () => {
|
|||
<h2 className="pb-4 text-4xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-zinc-200/60 via-zinc-200 to-zinc-200/60">
|
||||
Simplify your workflows
|
||||
</h2>
|
||||
<p className="mb-8 text-lg text-zinc-400">A consolidated ticket dashboard within 60 seconds.</p>
|
||||
<p className="mb-8 text-lg text-zinc-400">
|
||||
A consolidated ticket dashboard within 60 seconds.
|
||||
</p>
|
||||
<div>
|
||||
<Link
|
||||
className=" justify-center flex sm:inline-flex items-center whitespace-nowrap transition duration-150 ease-in-out font-medium rounded px-4 py-1.5 text-zinc-900 bg-gradient-to-r from-white/80 via-white to-white/80 hover:bg-white group"
|
||||
|
|
|
@ -7,22 +7,26 @@ export const Features: React.FC = () => {
|
|||
{
|
||||
icon: Unplug,
|
||||
name: "Effortless Consolidation",
|
||||
description: "Consolidate all tickets from multiple platforms and clients effortlessly",
|
||||
description:
|
||||
"Consolidate all tickets from multiple platforms and clients effortlessly",
|
||||
},
|
||||
{
|
||||
icon: Eye,
|
||||
name: "Unparalleled Visibility",
|
||||
description: "Gain complete control and visibility over your ticketing operations",
|
||||
description:
|
||||
"Gain complete control and visibility over your ticketing operations",
|
||||
},
|
||||
{
|
||||
icon: Compass,
|
||||
name: "Intuitive Navigation",
|
||||
description: "Seamlessly navigate and find tickets with smart filters and advanced search",
|
||||
description:
|
||||
"Seamlessly navigate and find tickets with smart filters and advanced search",
|
||||
},
|
||||
{
|
||||
icon: Zap,
|
||||
name: "Enhanced Efficiency",
|
||||
description: "Maximize productivity and resource allocation in ticket management",
|
||||
description:
|
||||
"Maximize productivity and resource allocation in ticket management",
|
||||
},
|
||||
];
|
||||
return (
|
||||
|
@ -62,7 +66,9 @@ export const Features: React.FC = () => {
|
|||
Reduce Context Switching
|
||||
</h3>
|
||||
<p className="mb-8 text-lg text-zinc-400">
|
||||
Empower your operations teams with by consolidating all ticket information in one place. Seamlessly filter, sort, and customize ticket views to meet their unique needs.
|
||||
Empower your operations teams with by consolidating all ticket
|
||||
information in one place. Seamlessly filter, sort, and
|
||||
customize ticket views to meet their unique needs.
|
||||
</p>
|
||||
<dl className="max-w-xl grid grid-cols-1 gap-4 lg:max-w-none">
|
||||
{features.map((feature) => (
|
||||
|
|
|
@ -32,9 +32,15 @@ export const Hero: React.FC = () => {
|
|||
className="pb-4 font-extrabold tracking-tight text-transparent text-6xl lg:text-8xl bg-clip-text bg-gradient-to-r from-zinc-200/60 via-zinc-200 to-zinc-200/60"
|
||||
data-aos="fade-down"
|
||||
>
|
||||
<ReactWrapBalancer>One Dashboard, Countless Solutions</ReactWrapBalancer>
|
||||
<ReactWrapBalancer>
|
||||
One Dashboard, Countless Solutions
|
||||
</ReactWrapBalancer>
|
||||
</h1>
|
||||
<p className="mb-8 text-lg text-zinc-300" data-aos="fade-down" data-aos-delay="200">
|
||||
<p
|
||||
className="mb-8 text-lg text-zinc-300"
|
||||
data-aos="fade-down"
|
||||
data-aos-delay="200"
|
||||
>
|
||||
Tame ticket overload and keep your operation teams sane
|
||||
</p>
|
||||
<div
|
||||
|
|
|
@ -126,7 +126,18 @@ export const Particles: React.FC<ParticlesProps> = ({
|
|||
const dx = (Math.random() - 0.5) * 0.2;
|
||||
const dy = (Math.random() - 0.5) * 0.2;
|
||||
const magnetism = 0.1 + Math.random() * 4;
|
||||
return { x, y, translateX, translateY, size, alpha, targetAlpha, dx, dy, magnetism };
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
translateX,
|
||||
translateY,
|
||||
size,
|
||||
alpha,
|
||||
targetAlpha,
|
||||
dx,
|
||||
dy,
|
||||
magnetism,
|
||||
};
|
||||
};
|
||||
|
||||
const rgb = hexToRgb(color);
|
||||
|
@ -149,7 +160,12 @@ export const Particles: React.FC<ParticlesProps> = ({
|
|||
|
||||
const clearContext = () => {
|
||||
if (context.current) {
|
||||
context.current.clearRect(0, 0, canvasSize.current.w, canvasSize.current.h);
|
||||
context.current.clearRect(
|
||||
0,
|
||||
0,
|
||||
canvasSize.current.w,
|
||||
canvasSize.current.h
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -167,9 +183,10 @@ export const Particles: React.FC<ParticlesProps> = ({
|
|||
start1: number,
|
||||
end1: number,
|
||||
start2: number,
|
||||
end2: number,
|
||||
end2: number
|
||||
): number => {
|
||||
const remapped = ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
|
||||
const remapped =
|
||||
((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
|
||||
return remapped > 0 ? remapped : 0;
|
||||
};
|
||||
|
||||
|
@ -184,7 +201,9 @@ export const Particles: React.FC<ParticlesProps> = ({
|
|||
canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
|
||||
];
|
||||
const closestEdge = edge.reduce((a, b) => Math.min(a, b));
|
||||
const remapClosestEdge = parseFloat(remapValue(closestEdge, 0, 20, 0, 1).toFixed(2));
|
||||
const remapClosestEdge = parseFloat(
|
||||
remapValue(closestEdge, 0, 20, 0, 1).toFixed(2)
|
||||
);
|
||||
if (remapClosestEdge > 1) {
|
||||
circle.alpha += 0.02;
|
||||
if (circle.alpha > circle.targetAlpha) {
|
||||
|
@ -196,9 +215,11 @@ export const Particles: React.FC<ParticlesProps> = ({
|
|||
circle.x += circle.dx + vx;
|
||||
circle.y += circle.dy + vy;
|
||||
circle.translateX +=
|
||||
(mouse.current.x / (staticity / circle.magnetism) - circle.translateX) / ease;
|
||||
(mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
|
||||
ease;
|
||||
circle.translateY +=
|
||||
(mouse.current.y / (staticity / circle.magnetism) - circle.translateY) / ease;
|
||||
(mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
|
||||
ease;
|
||||
// circle gets out of the canvas
|
||||
if (
|
||||
circle.x < -circle.size ||
|
||||
|
@ -222,7 +243,7 @@ export const Particles: React.FC<ParticlesProps> = ({
|
|||
translateY: circle.translateY,
|
||||
alpha: circle.alpha,
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,7 +6,10 @@ interface MousePosition {
|
|||
}
|
||||
|
||||
export default function useMousePosition(): MousePosition {
|
||||
const [mousePosition, setMousePosition] = useState<MousePosition>({ x: 0, y: 0 });
|
||||
const [mousePosition, setMousePosition] = useState<MousePosition>({
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
|
|
|
@ -14,13 +14,30 @@ export function Loading({
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="4" cy="12" r="3">
|
||||
<animate id="a" begin="0;b.end-0.25s" attributeName="r" dur={dur} values="3;.2;3" />
|
||||
<animate
|
||||
id="a"
|
||||
begin="0;b.end-0.25s"
|
||||
attributeName="r"
|
||||
dur={dur}
|
||||
values="3;.2;3"
|
||||
/>
|
||||
</circle>
|
||||
<circle cx="12" cy="12" r="3">
|
||||
<animate begin="a.end-0.6s" attributeName="r" dur={dur} values="3;.2;3" />
|
||||
<animate
|
||||
begin="a.end-0.6s"
|
||||
attributeName="r"
|
||||
dur={dur}
|
||||
values="3;.2;3"
|
||||
/>
|
||||
</circle>
|
||||
<circle cx="20" cy="12" r="3">
|
||||
<animate id="b" begin="a.end-0.45s" attributeName="r" dur={dur} values="3;.2;3" />
|
||||
<animate
|
||||
id="b"
|
||||
begin="a.end-0.45s"
|
||||
attributeName="r"
|
||||
dur={dur}
|
||||
values="3;.2;3"
|
||||
/>
|
||||
</circle>
|
||||
</svg>
|
||||
);
|
||||
|
|
|
@ -13,13 +13,12 @@ export const Logo: React.FC<Props> = ({ className }) => {
|
|||
stroke="current"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round">
|
||||
<rect width="7" height="9" x="3" y="3" rx="1"/>
|
||||
<rect width="7" height="5" x="14" y="3" rx="1"/>
|
||||
<rect width="7" height="9" x="14" y="12" rx="1"/>
|
||||
<rect width="7" height="5" x="3" y="16" rx="1"/>
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<rect width="7" height="9" x="3" y="3" rx="1" />
|
||||
<rect width="7" height="5" x="14" y="3" rx="1" />
|
||||
<rect width="7" height="9" x="14" y="12" rx="1" />
|
||||
<rect width="7" height="5" x="3" y="16" rx="1" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ export function MobileNav() {
|
|||
variant="ghost"
|
||||
className="-ml-4 text-base hover:bg-transparent focus:ring-0 focus:ring-offset-0 md:hidden"
|
||||
>
|
||||
<Icons.logo className="w-4 h-4 mr-2" /> <span className="font-bold">Menu</span>
|
||||
<Icons.logo className="w-4 h-4 mr-2" />{" "}
|
||||
<span className="font-bold">Menu</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
|
|
|
@ -4,12 +4,18 @@ type Props = {
|
|||
actions?: React.ReactNode[];
|
||||
};
|
||||
|
||||
export const PageHeader: React.FC<Props> = ({ title, description, actions }) => {
|
||||
export const PageHeader: React.FC<Props> = ({
|
||||
title,
|
||||
description,
|
||||
actions,
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<h2 className="text-2xl font-semibold tracking-tight">{title}</h2>
|
||||
<p className="text-sm text-zinc-500 dark:text-zinc-400">{description}</p>
|
||||
<p className="text-sm text-zinc-500 dark:text-zinc-400">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
<ul className="flex items-center justify-between gap-4">
|
||||
{(actions ?? []).map((action, i) => (
|
||||
|
|
|
@ -11,7 +11,10 @@ const Avatar = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative flex h-8 w-8 shrink-0 overflow-hidden rounded-md ", className)}
|
||||
className={cn(
|
||||
"relative flex h-8 w-8 shrink-0 overflow-hidden rounded-md ",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
@ -37,7 +40,7 @@ const AvatarFallback = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-zinc-100 dark:bg-zinc-700",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
@ -8,11 +8,14 @@ const buttonVariants = cva(
|
|||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-zinc-900 text-white hover:bg-zinc-700 dark:bg-zinc-50 dark:text-zinc-900",
|
||||
destructive: "bg-red-500 text-white hover:bg-red-600 dark:hover:bg-red-600",
|
||||
default:
|
||||
"bg-zinc-900 text-white hover:bg-zinc-700 dark:bg-zinc-50 dark:text-zinc-900",
|
||||
destructive:
|
||||
"bg-red-500 text-white hover:bg-red-600 dark:hover:bg-red-600",
|
||||
outline:
|
||||
"bg-transparent border border-zinc-200 hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-100",
|
||||
subtle: "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100",
|
||||
subtle:
|
||||
"bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100",
|
||||
ghost:
|
||||
"bg-transparent hover:bg-zinc-100 dark:hover:bg-zinc-800 dark:text-zinc-100 dark:hover:text-zinc-100 data-[state=open]:bg-transparent dark:data-[state=open]:bg-transparent",
|
||||
link: "bg-transparent dark:bg-transparent underline-offset-4 hover:underline text-zinc-900 dark:text-zinc-100 hover:bg-transparent dark:hover:bg-transparent",
|
||||
|
@ -28,7 +31,7 @@ const buttonVariants = cva(
|
|||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
|
@ -38,9 +41,13 @@ export interface ButtonProps
|
|||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, ...props }, ref) => {
|
||||
return (
|
||||
<button className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-zinc-100 data-[state=open]:bg-zinc-100 dark:focus:bg-zinc-700 dark:data-[state=open]:bg-zinc-800",
|
||||
inset && "pl-8",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
@ -37,7 +37,8 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|||
<ChevronRight className="w-4 h-4 ml-auto" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
));
|
||||
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
|
@ -47,12 +48,13 @@ const DropdownMenuSubContent = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"animate-in slide-in-from-left-1 z-50 min-w-[8rem] overflow-hidden rounded-md border border-zinc-100 bg-white p-1 text-zinc-700 shadow-md dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName;
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
|
@ -64,7 +66,7 @@ const DropdownMenuContent = React.forwardRef<
|
|||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"animate-in data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border border-zinc-100 bg-white p-1 text-zinc-700 shadow-md dark:border-zinc-800 dark:bg-zinc-800 dark:text-zinc-400",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
@ -83,7 +85,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-zinc-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-zinc-700",
|
||||
inset && "pl-8",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
@ -98,7 +100,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-zinc-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-zinc-700",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
|
@ -111,7 +113,8 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
));
|
||||
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
|
@ -121,7 +124,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-zinc-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-zinc-700",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
@ -146,7 +149,7 @@ const DropdownMenuLabel = React.forwardRef<
|
|||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold text-zinc-900 dark:text-zinc-300",
|
||||
inset && "pl-8",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
@ -165,9 +168,15 @@ const DropdownMenuSeparator = React.forwardRef<
|
|||
));
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||
|
||||
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span className={cn("ml-auto text-xs tracking-widest text-zinc-500", className)} {...props} />
|
||||
<span
|
||||
className={cn("ml-auto text-xs tracking-widest text-zinc-500", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
||||
|
|
|
@ -4,18 +4,20 @@ import { cn } from "@/lib/utils";
|
|||
|
||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-zinc-300 bg-transparent py-2 px-3 text-sm placeholder:text-zinc-400 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-zinc-700 dark:text-zinc-50 focus:ring-zinc-200 dark:focus:ring-zinc-50/50",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-zinc-300 bg-transparent py-2 px-3 text-sm placeholder:text-zinc-400 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-zinc-700 dark:text-zinc-50 focus:ring-zinc-200 dark:focus:ring-zinc-50/50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input };
|
||||
|
|
|
@ -13,7 +13,7 @@ const Label = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
@ -32,9 +32,11 @@ const ScrollBar = React.forwardRef<
|
|||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" && "h-2.5 border-t border-t-transparent p-[1px]",
|
||||
className,
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
|
@ -27,7 +27,12 @@ interface SheetPortalProps
|
|||
extends SheetPrimitive.DialogPortalProps,
|
||||
VariantProps<typeof portalVariants> {}
|
||||
|
||||
const SheetPortal = ({ position, className, children, ...props }: SheetPortalProps) => (
|
||||
const SheetPortal = ({
|
||||
position,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: SheetPortalProps) => (
|
||||
<SheetPrimitive.Portal className={cn(className)} {...props}>
|
||||
<div className={portalVariants({ position })}>{children}</div>
|
||||
</SheetPrimitive.Portal>
|
||||
|
@ -41,7 +46,7 @@ const SheetOverlay = React.forwardRef<
|
|||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-all duration-100",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
|
@ -49,90 +54,93 @@ const SheetOverlay = React.forwardRef<
|
|||
));
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
||||
|
||||
const sheetVariants = cva("fixed z-50 scale-100 gap-4 bg-white p-6 opacity-100 dark:bg-zinc-900", {
|
||||
variants: {
|
||||
position: {
|
||||
top: "animate-in slide-in-from-top w-full duration-300",
|
||||
bottom: "animate-in slide-in-from-bottom w-full duration-300",
|
||||
left: "animate-in slide-in-from-left h-full duration-300",
|
||||
right: "animate-in slide-in-from-right h-full duration-300",
|
||||
const sheetVariants = cva(
|
||||
"fixed z-50 scale-100 gap-4 bg-white p-6 opacity-100 dark:bg-zinc-900",
|
||||
{
|
||||
variants: {
|
||||
position: {
|
||||
top: "animate-in slide-in-from-top w-full duration-300",
|
||||
bottom: "animate-in slide-in-from-bottom w-full duration-300",
|
||||
left: "animate-in slide-in-from-left h-full duration-300",
|
||||
right: "animate-in slide-in-from-right h-full duration-300",
|
||||
},
|
||||
size: {
|
||||
content: "",
|
||||
default: "",
|
||||
sm: "",
|
||||
lg: "",
|
||||
xl: "",
|
||||
full: "",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
content: "",
|
||||
default: "",
|
||||
sm: "",
|
||||
lg: "",
|
||||
xl: "",
|
||||
full: "",
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "content",
|
||||
class: "max-h-screen",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
compoundVariants: [
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "content",
|
||||
class: "max-h-screen",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "default",
|
||||
class: "h-1/3",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "sm",
|
||||
class: "h-1/4",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "lg",
|
||||
class: "h-1/2",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "xl",
|
||||
class: "h-5/6",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "full",
|
||||
class: "h-screen",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "content",
|
||||
class: "max-w-screen",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "default",
|
||||
class: "w-1/3",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "sm",
|
||||
class: "w-1/4",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "lg",
|
||||
class: "w-1/2",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "xl",
|
||||
class: "w-5/6",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "full",
|
||||
class: "w-screen",
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
position: "right",
|
||||
size: "default",
|
||||
class: "h-1/3",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "sm",
|
||||
class: "h-1/4",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "lg",
|
||||
class: "h-1/2",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "xl",
|
||||
class: "h-5/6",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "full",
|
||||
class: "h-screen",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "content",
|
||||
class: "max-w-screen",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "default",
|
||||
class: "w-1/3",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "sm",
|
||||
class: "w-1/4",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "lg",
|
||||
class: "w-1/2",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "xl",
|
||||
class: "w-5/6",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "full",
|
||||
class: "w-screen",
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
position: "right",
|
||||
size: "default",
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export interface DialogContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
|
@ -159,14 +167,29 @@ const SheetContent = React.forwardRef<
|
|||
));
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
||||
|
||||
const SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
|
||||
const SheetHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
SheetHeader.displayName = "SheetHeader";
|
||||
|
||||
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
const SheetFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -178,7 +201,11 @@ const SheetTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-zinc-900", "dark:text-zinc-50", className)}
|
||||
className={cn(
|
||||
"text-lg font-semibold text-zinc-900",
|
||||
"dark:text-zinc-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -15,7 +15,7 @@ const ToastViewport = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:top-auto sm:bottom-0 sm:right-0 sm:flex-col md:max-w-[420px]",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
@ -27,19 +27,22 @@ const toastVariants = cva(
|
|||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-white border-zinc-200 dark:bg-zinc-800 dark:border-zinc-700",
|
||||
destructive: "group destructive bg-red-600 text-white border-red-600 dark:border-red-600",
|
||||
default:
|
||||
"bg-white border-zinc-200 dark:bg-zinc-800 dark:border-zinc-700",
|
||||
destructive:
|
||||
"group destructive bg-red-600 text-white border-red-600 dark:border-red-600",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
|
||||
VariantProps<typeof toastVariants>
|
||||
>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<ToastPrimitives.Root
|
||||
|
@ -59,7 +62,7 @@ const ToastAction = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-transparent px-3 text-sm font-medium transition-colors hover:bg-zinc-100 focus:outline-none focus:ring-2 focus:ring-zinc-400 focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-red-100 group-[.destructive]:hover:border-zinc-50 group-[.destructive]:hover:bg-red-100 group-[.destructive]:hover:text-red-600 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:border-zinc-700 dark:text-zinc-100 dark:hover:bg-zinc-700 dark:hover:text-zinc-100 dark:focus:ring-zinc-400 dark:focus:ring-offset-zinc-900 dark:data-[state=open]:bg-zinc-800",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
@ -74,7 +77,7 @@ const ToastClose = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"absolute top-2 right-2 rounded-md p-1 text-zinc-500 opacity-0 transition-opacity hover:text-zinc-900 focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:hover:text-zinc-50",
|
||||
className,
|
||||
className
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}
|
||||
|
@ -88,7 +91,11 @@ const ToastTitle = React.forwardRef<
|
|||
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Title ref={ref} className={cn("text-sm font-semibold", className)} {...props} />
|
||||
<ToastPrimitives.Title
|
||||
ref={ref}
|
||||
className={cn("text-sm font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName;
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@ export function Toaster() {
|
|||
<Toast key={id} {...props}>
|
||||
<div className="grid gap-1">
|
||||
{title && <ToastTitle>{title}</ToastTitle>}
|
||||
{description && <ToastDescription>{description}</ToastDescription>}
|
||||
{description && (
|
||||
<ToastDescription>{description}</ToastDescription>
|
||||
)}
|
||||
</div>
|
||||
{action}
|
||||
<ToastClose />
|
||||
|
|
|
@ -80,7 +80,9 @@ export const reducer = (state: State, action: Action): State => {
|
|||
case "UPDATE_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)),
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
||||
),
|
||||
};
|
||||
|
||||
case "DISMISS_TOAST":
|
||||
|
@ -104,7 +106,7 @@ export const reducer = (state: State, action: Action): State => {
|
|||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t,
|
||||
: t
|
||||
),
|
||||
};
|
||||
case "REMOVE_TOAST":
|
||||
|
|
Loading…
Reference in a new issue