From e1db7bd878c434c1da68bad75c6ec7c71acc0802 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:17:15 +0330 Subject: [PATCH] Import source: vault/app/s/[id]/page Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- vault/app/s/[id]/page.tsx | 141 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 vault/app/s/[id]/page.tsx diff --git a/vault/app/s/[id]/page.tsx b/vault/app/s/[id]/page.tsx new file mode 100644 index 0000000..e1063df --- /dev/null +++ b/vault/app/s/[id]/page.tsx @@ -0,0 +1,141 @@ +"use client"; + +import { useEffect, useState, useCallback } from "react"; +import { useParams } from "next/navigation"; +import { motion } from "framer-motion"; +import { Lock, Link as LinkIcon, Clock, FileText } from "lucide-react"; +import Link from "next/link"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { CodeViewer } from "@/components/code-viewer"; +import { PasswordGate } from "@/components/password-gate"; +import { api } from "@/lib/api-client"; +import { Snippet } from "@/lib/types"; +import { formatExpiry } from "@/lib/expiry-format"; +import { cn } from "@/lib/utils"; + +export default function SharedSnippetPage() { + const params = useParams(); + const id = params.id as string; + const [snippet, setSnippet] = useState(null); + const [loading, setLoading] = useState(true); + const [locked, setLocked] = useState(false); + const [error, setError] = useState(""); + + useEffect(() => { + api.getSharedSnippet(id) + .then(({ snippet, locked }) => { + setSnippet(snippet); + setLocked(locked); + }) + .catch(() => setSnippet(null)) + .finally(() => setLoading(false)); + }, [id]); + + const handleUnlock = useCallback(async (password: string) => { + setError(""); + try { + const { snippet } = await api.unlockSharedSnippet(id, password); + setSnippet(snippet); + setLocked(false); + } catch (error) { + setError(error instanceof Error ? error.message : "Incorrect password"); + } + }, [id]); + + if (loading) { + return ( +
+
+
+
+
+
+ ); + } + + if (!snippet) { + return ( +
+

Snippet not found

+

This snippet may have expired or been deleted.

+
+ ); + } + + if (locked) { + return ( +
+ +
+ ); + } + + const expiryLabel = formatExpiry(snippet.expiresAt); + const rawUrl = typeof window !== "undefined" ? `${window.location.origin}/raw/${id}` : `/raw/${id}`; + + return ( +
+ +
+

{snippet.title}

+ + {snippet.privacy === "password" ? ( + <> Protected + ) : ( + <> Secret + )} + +
+ +
+ + {snippet.language} + + + {new Date(snippet.createdAt).toLocaleDateString()} + + {expiryLabel && ( + + + {expiryLabel} + + )} + {snippet.privacy !== "password" && ( + + + + )} +
+ + + +
+ + + +
+
+
+ ); +}