Compare commits
16 Commits
07116d7909
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4970d0117f | ||
|
|
1659519f0a | ||
|
|
000a8455b3 | ||
|
|
35685ebe1e | ||
|
|
094b1aafc0 | ||
|
|
af82499397 | ||
|
|
9f97bf6fd0 | ||
|
|
41e368dce5 | ||
|
|
3a459b73a1 | ||
|
|
7d9f7b7fbf | ||
|
|
f05bc7d830 | ||
|
|
f71e70de27 | ||
|
|
97d3ea9e42 | ||
|
|
6960025d71 | ||
|
|
beae5d0811 | ||
|
|
9941c6e244 |
@@ -1,6 +1,5 @@
|
|||||||
import type { NextConfig } from "next";
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
const nextConfig: NextConfig = {
|
|
||||||
webpack: (config) => {
|
webpack: (config) => {
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
@@ -14,4 +13,4 @@ const nextConfig: NextConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
100
package.json
100
package.json
@@ -11,63 +11,65 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ffmpeg/ffmpeg": "^0.12.15",
|
"@ffmpeg/ffmpeg": "^0.12.15",
|
||||||
"@ffmpeg/util": "^0.12.2",
|
"@ffmpeg/util": "^0.12.2",
|
||||||
"@hookform/resolvers": "^3.9.0",
|
"@hookform/resolvers": "^5.0.1",
|
||||||
"@radix-ui/react-accordion": "^1.2.0",
|
"@radix-ui/react-accordion": "^1.2.11",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.1",
|
"@radix-ui/react-alert-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-aspect-ratio": "^1.1.0",
|
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||||
"@radix-ui/react-avatar": "^1.1.0",
|
"@radix-ui/react-avatar": "^1.1.10",
|
||||||
"@radix-ui/react-checkbox": "^1.1.1",
|
"@radix-ui/react-checkbox": "^1.3.2",
|
||||||
"@radix-ui/react-collapsible": "^1.1.0",
|
"@radix-ui/react-collapsible": "^1.1.11",
|
||||||
"@radix-ui/react-context-menu": "^2.2.1",
|
"@radix-ui/react-context-menu": "^2.2.15",
|
||||||
"@radix-ui/react-dialog": "^1.1.1",
|
"@radix-ui/react-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||||
"@radix-ui/react-hover-card": "^1.1.1",
|
"@radix-ui/react-hover-card": "^1.1.14",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-menubar": "^1.1.1",
|
"@radix-ui/react-menubar": "^1.1.15",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.0",
|
"@radix-ui/react-navigation-menu": "^1.2.13",
|
||||||
"@radix-ui/react-popover": "^1.1.1",
|
"@radix-ui/react-popover": "^1.1.14",
|
||||||
"@radix-ui/react-progress": "^1.1.0",
|
"@radix-ui/react-progress": "^1.1.7",
|
||||||
"@radix-ui/react-radio-group": "^1.2.0",
|
"@radix-ui/react-radio-group": "^1.3.7",
|
||||||
"@radix-ui/react-scroll-area": "^1.1.0",
|
"@radix-ui/react-scroll-area": "^1.2.9",
|
||||||
"@radix-ui/react-select": "^2.1.1",
|
"@radix-ui/react-select": "^2.2.5",
|
||||||
"@radix-ui/react-separator": "^1.1.0",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
"@radix-ui/react-slider": "^1.2.0",
|
"@radix-ui/react-slider": "^1.3.5",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
"@radix-ui/react-switch": "^1.1.0",
|
"@radix-ui/react-switch": "^1.2.5",
|
||||||
"@radix-ui/react-tabs": "^1.1.0",
|
"@radix-ui/react-tabs": "^1.1.12",
|
||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.9",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
"@radix-ui/react-toggle-group": "^1.1.10",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.2.7",
|
||||||
"@supabase/auth-ui-react": "^0.4.7",
|
"@supabase/auth-ui-react": "^0.4.7",
|
||||||
"@supabase/auth-ui-shared": "^0.1.8",
|
"@supabase/auth-ui-shared": "^0.1.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"@supabase/supabase-js": "^2.93.3",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.1.1",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"embla-carousel-react": "^8.1.6",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"input-otp": "^1.2.5",
|
"geist": "^1.5.1",
|
||||||
"lucide-react": "^0.408.0",
|
"input-otp": "^1.4.2",
|
||||||
"next": "15.3.8-canary.5",
|
"lucide-react": "^0.511.0",
|
||||||
"next-themes": "^0.3.0",
|
"next": "14.2.3",
|
||||||
"react": "^19.0.0-rc.0",
|
"next-themes": "^0.4.6",
|
||||||
|
"react": "^18.2.0",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^19.0.0-rc.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.52.1",
|
"react-hook-form": "^7.56.4",
|
||||||
"react-resizable-panels": "^2.0.20",
|
"react-resizable-panels": "^3.0.2",
|
||||||
"recharts": "^2.12.7",
|
"recharts": "^2.15.3",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^2.0.3",
|
||||||
"tailwind-merge": "^2.4.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^0.9.1",
|
"vaul": "^1.1.2",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.25.28"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@dyad-sh/nextjs-webpack-component-tagger": "^0.8.0",
|
"@dyad-sh/nextjs-webpack-component-tagger": "^0.8.0",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19.0.0-rc.0",
|
"@types/react": "^18.2.0",
|
||||||
"@types/react-dom": "^19.0.0-rc.0",
|
"@types/react-dom": "^18.2.0",
|
||||||
"postcss": "^8.4.39",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.4",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5.5.3"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1639
pnpm-lock.yaml
generated
1639
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { ArrowLeft } from "lucide-react";
|
import { ArrowLeft } from "lucide-react";
|
||||||
|
|
||||||
type ClipPageProps = {
|
type ClipPageProps = {
|
||||||
params: {
|
params: { id: string };
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function ClipPage({ params }: ClipPageProps) {
|
export default async function ClipPage({ params }: ClipPageProps) {
|
||||||
|
|||||||
@@ -1,18 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { GeistSans } from "geist/font/sans";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { Header } from "@/components/header";
|
import { Header } from "@/components/header";
|
||||||
|
|
||||||
const geistSans = Geist({
|
|
||||||
variable: "--font-geist-sans",
|
|
||||||
subsets: ["latin"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const geistMono = Geist_Mono({
|
|
||||||
variable: "--font-geist-mono",
|
|
||||||
subsets: ["latin"],
|
|
||||||
});
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
metadataBase: new URL("https://clips.linxweiler.xyz"),
|
metadataBase: new URL("https://clips.linxweiler.xyz"),
|
||||||
title: "Video Clip Cutter",
|
title: "Video Clip Cutter",
|
||||||
@@ -25,9 +15,9 @@ export default function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" className="dark">
|
<html lang="en" className={`${GeistSans.variable} dark`}>
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className="antialiased"
|
||||||
>
|
>
|
||||||
<Header />
|
<Header />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import { useEffect } from "react";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { KeyRound } from "lucide-react";
|
import { KeyRound } from "lucide-react";
|
||||||
|
import type { AuthChangeEvent, Session, Provider } from "@supabase/supabase-js";
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
|
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event: AuthChangeEvent, session: Session | null) => {
|
||||||
if (session) {
|
if (session) {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
}
|
}
|
||||||
@@ -23,7 +24,7 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
const handleOidcSignIn = async () => {
|
const handleOidcSignIn = async () => {
|
||||||
await supabase.auth.signInWithOAuth({
|
await supabase.auth.signInWithOAuth({
|
||||||
provider: 'pocket_id',
|
provider: 'pocket_id' as Provider,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ export default function LoginPage() {
|
|||||||
providers={[]}
|
providers={[]}
|
||||||
theme="dark"
|
theme="dark"
|
||||||
view="sign_in"
|
view="sign_in"
|
||||||
showLinks={false}
|
showLinks={true}
|
||||||
/>
|
/>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute inset-0 flex items-center">
|
<div className="absolute inset-0 flex items-center">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { VideoEditor } from "@/components/video-editor";
|
import { VideoEditor } from "@/components/video-editor";
|
||||||
import { Loader2 } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
|
import type { AuthChangeEvent, Session } from '@supabase/supabase-js';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -22,7 +23,7 @@ export default function Home() {
|
|||||||
|
|
||||||
checkSession();
|
checkSession();
|
||||||
|
|
||||||
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
|
const { data: { subscription } } = supabase.auth.onAuthStateChange((event: AuthChangeEvent, _session: Session | null) => {
|
||||||
if (event === 'SIGNED_OUT') {
|
if (event === 'SIGNED_OUT') {
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,7 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center min-h-screen bg-background p-4 sm:p-6 md:p-8 font-[family-name:var(--font-geist-sans)]">
|
<div className="flex flex-col items-center justify-center min-h-screen bg-background p-4 sm:p-6 md:p-8">
|
||||||
<main className="w-full max-w-4xl">
|
<main className="w-full max-w-4xl">
|
||||||
<VideoEditor />
|
<VideoEditor />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { User as SupabaseUser } from '@supabase/supabase-js';
|
import { User as SupabaseUser, AuthChangeEvent, Session } from '@supabase/supabase-js';
|
||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
import { LogOut, User } from 'lucide-react';
|
import { LogOut, User } from 'lucide-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -21,7 +21,7 @@ export function Header() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
|
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event: AuthChangeEvent, session: Session | null) => {
|
||||||
setUser(session?.user ?? null);
|
setUser(session?.user ?? null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/componen
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, DialogClose } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogClose } from '@/components/ui/dialog';
|
||||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { Toaster } from '@/components/ui/sonner';
|
import { Toaster } from '@/components/ui/sonner';
|
||||||
@@ -25,6 +25,7 @@ type UserClipsProps = {
|
|||||||
|
|
||||||
export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProps) {
|
export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProps) {
|
||||||
const [clipToEdit, setClipToEdit] = useState<Clip | null>(null);
|
const [clipToEdit, setClipToEdit] = useState<Clip | null>(null);
|
||||||
|
const [clipToDelete, setClipToDelete] = useState<Clip | null>(null);
|
||||||
const [newTitle, setNewTitle] = useState('');
|
const [newTitle, setNewTitle] = useState('');
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
@@ -74,6 +75,7 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
|
|||||||
|
|
||||||
onClipDeleted(clip.id);
|
onClipDeleted(clip.id);
|
||||||
toast.success('Clip deleted successfully!');
|
toast.success('Clip deleted successfully!');
|
||||||
|
setClipToDelete(null);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('Failed to delete clip.');
|
toast.error('Failed to delete clip.');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -112,18 +114,17 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
|
|||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DialogTrigger asChild onClick={() => handleEditClick(clip)}>
|
<DropdownMenuItem onSelect={() => handleEditClick(clip)}>
|
||||||
<DropdownMenuItem>
|
<Edit className="mr-2 h-4 w-4" />
|
||||||
<Edit className="mr-2 h-4 w-4" />
|
<span>Edit Title</span>
|
||||||
<span>Edit Title</span>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuItem>
|
<DropdownMenuItem
|
||||||
</DialogTrigger>
|
className="text-destructive focus:text-destructive"
|
||||||
<AlertDialogTrigger asChild>
|
onSelect={() => setClipToDelete(clip)}
|
||||||
<DropdownMenuItem className="text-destructive focus:text-destructive">
|
>
|
||||||
<Trash2 className="mr-2 h-4 w-4" />
|
<Trash2 className="mr-2 h-4 w-4" />
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</AlertDialogTrigger>
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
@@ -154,25 +155,6 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
|
|||||||
{hasCopied === clip.short_id ? 'Copied!' : 'Copy Link'}
|
{hasCopied === clip.short_id ? 'Copied!' : 'Copy Link'}
|
||||||
</Button>
|
</Button>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
|
|
||||||
{/* Delete Confirmation Dialog */}
|
|
||||||
<AlertDialog>
|
|
||||||
<AlertDialogContent>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
This action cannot be undone. This will permanently delete your clip and its thumbnail from our servers.
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
|
|
||||||
<AlertDialogAction onClick={() => handleDeleteClip(clip)} disabled={isDeleting} className="bg-destructive hover:bg-destructive/90">
|
|
||||||
{isDeleting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
|
||||||
Delete
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -209,6 +191,25 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
|
|||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
{/* Delete Confirmation Dialog */}
|
||||||
|
<AlertDialog open={!!clipToDelete} onOpenChange={(isOpen) => !isOpen && setClipToDelete(null)}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
This action cannot be undone. This will permanently delete your clip and its thumbnail from our servers.
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={() => clipToDelete && handleDeleteClip(clipToDelete)} disabled={isDeleting} className="bg-destructive hover:bg-destructive/90">
|
||||||
|
{isDeleting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||||
|
Delete
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,9 @@ export default {
|
|||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ["var(--font-geist-sans)"],
|
||||||
|
},
|
||||||
colors: {
|
colors: {
|
||||||
background: 'hsl(var(--background))',
|
background: 'hsl(var(--background))',
|
||||||
foreground: 'hsl(var(--foreground))',
|
foreground: 'hsl(var(--foreground))',
|
||||||
@@ -91,4 +94,4 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [require("tailwindcss-animate")],
|
plugins: [require("tailwindcss-animate")],
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
Reference in New Issue
Block a user