Compare commits

..

16 Commits

Author SHA1 Message Date
[dyad]
4970d0117f [dyad] Applied Geist font globally - wrote 1 file(s) 2026-01-30 10:15:41 +01:00
[dyad]
1659519f0a [dyad] Switched font to Geist - wrote 3 file(s), added geist package(s) 2026-01-30 10:13:20 +01:00
[dyad]
000a8455b3 [dyad] Re-enabled Pocket ID login - wrote 1 file(s) 2026-01-30 10:08:20 +01:00
[dyad]
35685ebe1e [dyad] Fixed crash on clip options menu - wrote 1 file(s) 2026-01-30 10:04:54 +01:00
[dyad]
094b1aafc0 [dyad] Removed custom auth provider to fix build - wrote 1 file(s) 2026-01-30 09:59:24 +01:00
[dyad]
af82499397 [dyad] Installed missing Supabase package - wrote 2 file(s), added @supabase/supabase-js package(s) 2026-01-30 09:57:00 +01:00
[dyad]
9f97bf6fd0 [dyad] Fixed TypeScript errors in auth listeners - wrote 3 file(s) 2026-01-30 09:54:40 +01:00
[dyad]
41e368dce5 [dyad] Replaced incompatible font to fix build error - wrote 3 file(s) 2026-01-30 09:52:38 +01:00
[dyad]
3a459b73a1 [dyad] Fixed Next.js configuration file format - wrote 1 file(s), renamed 1 file(s) 2026-01-30 09:47:27 +01:00
[dyad]
7d9f7b7fbf Update 1 file 2026-01-30 09:45:45 +01:00
[dyad]
f05bc7d830 [dyad] Downgraded packages to fix build error - wrote 2 file(s) 2026-01-30 09:44:28 +01:00
[dyad]
f71e70de27 [dyad] Attempting to fix build error with a more complete type definition - wrote 1 file(s) 2026-01-30 09:42:48 +01:00
[dyad]
97d3ea9e42 [dyad] Fixed persistent TypeScript build error - wrote 1 file(s) 2026-01-30 09:39:38 +01:00
[dyad]
6960025d71 [dyad] Fixed TypeScript error on clip page - wrote 1 file(s) 2026-01-30 09:36:28 +01:00
[dyad]
beae5d0811 [dyad] Fixed build error by syncing dependencies - wrote 1 file(s) 2026-01-30 09:34:59 +01:00
[dyad]
9941c6e244 [dyad] Fixed dependency versions causing build failure - wrote 1 file(s) 2026-01-30 09:33:04 +01:00
10 changed files with 788 additions and 1066 deletions

View File

@@ -1,6 +1,5 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config) => {
if (process.env.NODE_ENV === "development") {
config.module.rules.push({

View File

@@ -11,63 +11,65 @@
"dependencies": {
"@ffmpeg/ffmpeg": "^0.12.15",
"@ffmpeg/util": "^0.12.2",
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-aspect-ratio": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-context-menu": "^2.2.1",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-menubar": "^1.1.1",
"@radix-ui/react-navigation-menu": "^1.2.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@hookform/resolvers": "^5.0.1",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-alert-dialog": "^1.1.14",
"@radix-ui/react-aspect-ratio": "^1.1.7",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-collapsible": "^1.1.11",
"@radix-ui/react-context-menu": "^2.2.15",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-hover-card": "^1.1.14",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-menubar": "^1.1.15",
"@radix-ui/react-navigation-menu": "^1.2.13",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-radio-group": "^1.3.7",
"@radix-ui/react-scroll-area": "^1.2.9",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slider": "^1.3.5",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-toggle": "^1.1.9",
"@radix-ui/react-toggle-group": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.7",
"@supabase/auth-ui-react": "^0.4.7",
"@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",
"cmdk": "^1.0.0",
"cmdk": "^1.1.1",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.1.6",
"input-otp": "^1.2.5",
"lucide-react": "^0.408.0",
"next": "15.3.8-canary.5",
"next-themes": "^0.3.0",
"react": "^19.0.0-rc.0",
"embla-carousel-react": "^8.6.0",
"geist": "^1.5.1",
"input-otp": "^1.4.2",
"lucide-react": "^0.511.0",
"next": "14.2.3",
"next-themes": "^0.4.6",
"react": "^18.2.0",
"react-day-picker": "^8.10.1",
"react-dom": "^19.0.0-rc.0",
"react-hook-form": "^7.52.1",
"react-resizable-panels": "^2.0.20",
"recharts": "^2.12.7",
"sonner": "^1.5.0",
"tailwind-merge": "^2.4.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.56.4",
"react-resizable-panels": "^3.0.2",
"recharts": "^2.15.3",
"sonner": "^2.0.3",
"tailwind-merge": "^3.3.0",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.1",
"zod": "^3.23.8"
"vaul": "^1.1.2",
"zod": "^3.25.28"
},
"devDependencies": {
"@dyad-sh/nextjs-webpack-component-tagger": "^0.8.0",
"@types/node": "^20.14.10",
"@types/react": "^19.0.0-rc.0",
"@types/react-dom": "^19.0.0-rc.0",
"postcss": "^8.4.39",
"tailwindcss": "^3.4.4",
"typescript": "^5.5.3"
"@types/node": "^20",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
}

1639
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,9 +5,7 @@ import { Button } from "@/components/ui/button";
import { ArrowLeft } from "lucide-react";
type ClipPageProps = {
params: {
id: string;
};
params: { id: string };
};
export default async function ClipPage({ params }: ClipPageProps) {

View File

@@ -1,18 +1,8 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { GeistSans } from "geist/font/sans";
import "./globals.css";
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 = {
metadataBase: new URL("https://clips.linxweiler.xyz"),
title: "Video Clip Cutter",
@@ -25,9 +15,9 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en" className="dark">
<html lang="en" className={`${GeistSans.variable} dark`}>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
className="antialiased"
>
<Header />
{children}

View File

@@ -7,12 +7,13 @@ import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/ui/button";
import { KeyRound } from "lucide-react";
import type { AuthChangeEvent, Session, Provider } from "@supabase/supabase-js";
export default function LoginPage() {
const router = useRouter();
useEffect(() => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event: AuthChangeEvent, session: Session | null) => {
if (session) {
router.push('/');
}
@@ -23,7 +24,7 @@ export default function LoginPage() {
const handleOidcSignIn = async () => {
await supabase.auth.signInWithOAuth({
provider: 'pocket_id',
provider: 'pocket_id' as Provider,
});
};
@@ -40,7 +41,7 @@ export default function LoginPage() {
providers={[]}
theme="dark"
view="sign_in"
showLinks={false}
showLinks={true}
/>
<div className="relative">
<div className="absolute inset-0 flex items-center">

View File

@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation';
import { supabase } from '@/integrations/supabase/client';
import { VideoEditor } from "@/components/video-editor";
import { Loader2 } from 'lucide-react';
import type { AuthChangeEvent, Session } from '@supabase/supabase-js';
export default function Home() {
const router = useRouter();
@@ -22,7 +23,7 @@ export default function Home() {
checkSession();
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((event: AuthChangeEvent, _session: Session | null) => {
if (event === 'SIGNED_OUT') {
router.push('/login');
}
@@ -40,7 +41,7 @@ export default function Home() {
}
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">
<VideoEditor />
</main>

View File

@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react';
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 { LogOut, User } from 'lucide-react';
import { useRouter } from 'next/navigation';
@@ -21,7 +21,7 @@ export function Header() {
const router = useRouter();
useEffect(() => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event: AuthChangeEvent, session: Session | null) => {
setUser(session?.user ?? null);
});

View File

@@ -6,8 +6,8 @@ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/componen
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, DialogClose } from '@/components/ui/dialog';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogClose } from '@/components/ui/dialog';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
import { supabase } from '@/integrations/supabase/client';
import { toast } from 'sonner';
import { Toaster } from '@/components/ui/sonner';
@@ -25,6 +25,7 @@ type UserClipsProps = {
export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProps) {
const [clipToEdit, setClipToEdit] = useState<Clip | null>(null);
const [clipToDelete, setClipToDelete] = useState<Clip | null>(null);
const [newTitle, setNewTitle] = useState('');
const [isSaving, setIsSaving] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
@@ -74,6 +75,7 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
onClipDeleted(clip.id);
toast.success('Clip deleted successfully!');
setClipToDelete(null);
} catch (error) {
toast.error('Failed to delete clip.');
console.error(error);
@@ -112,18 +114,17 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DialogTrigger asChild onClick={() => handleEditClick(clip)}>
<DropdownMenuItem>
<Edit className="mr-2 h-4 w-4" />
<span>Edit Title</span>
</DropdownMenuItem>
</DialogTrigger>
<AlertDialogTrigger asChild>
<DropdownMenuItem className="text-destructive focus:text-destructive">
<Trash2 className="mr-2 h-4 w-4" />
<span>Delete</span>
</DropdownMenuItem>
</AlertDialogTrigger>
<DropdownMenuItem onSelect={() => handleEditClick(clip)}>
<Edit className="mr-2 h-4 w-4" />
<span>Edit Title</span>
</DropdownMenuItem>
<DropdownMenuItem
className="text-destructive focus:text-destructive"
onSelect={() => setClipToDelete(clip)}
>
<Trash2 className="mr-2 h-4 w-4" />
<span>Delete</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</CardTitle>
@@ -154,25 +155,6 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
{hasCopied === clip.short_id ? 'Copied!' : 'Copy Link'}
</Button>
</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>
))}
</div>
@@ -209,6 +191,25 @@ export function UserClips({ clips, onClipDeleted, onClipUpdated }: UserClipsProp
</DialogFooter>
</DialogContent>
</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>
</>
);
}

View File

@@ -9,6 +9,9 @@ export default {
],
theme: {
extend: {
fontFamily: {
sans: ["var(--font-geist-sans)"],
},
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',