diff --git a/vault/app/snippets/page.tsx b/vault/app/snippets/page.tsx new file mode 100644 index 0000000..b012fc4 --- /dev/null +++ b/vault/app/snippets/page.tsx @@ -0,0 +1,114 @@ +"use client"; + +import { useEffect, useState, useMemo } from "react"; +import { useRouter } from "next/navigation"; +import { motion, LayoutGroup } from "framer-motion"; +import { Plus } from "lucide-react"; +import Link from "next/link"; +import { SnippetCard } from "@/components/snippet-card"; +import { SearchBar } from "@/components/search-bar"; +import { ViewToggle } from "@/components/view-toggle"; +import { EmptyState } from "@/components/empty-state"; +import { Button } from "@/components/ui/button"; +import { api } from "@/lib/api-client"; +import { Snippet } from "@/lib/types"; + +const containerVariants = { + hidden: {}, + visible: { transition: { staggerChildren: 0.06 } }, +}; + +export default function SnippetsPage() { + const router = useRouter(); + const [snippets, setSnippets] = useState([]); + const [search, setSearch] = useState(""); + const [view, setView] = useState<"grid" | "list">("grid"); + const [loading, setLoading] = useState(true); + const [authRequired, setAuthRequired] = useState(false); + + useEffect(() => { + api.listSnippets() + .then(({ snippets }) => { + setSnippets(snippets); + setAuthRequired(false); + }) + .catch(() => { + setAuthRequired(true); + router.push("/login"); + }) + .finally(() => setLoading(false)); + }, [router]); + + const filtered = useMemo(() => { + if (!search.trim()) return snippets; + const q = search.toLowerCase(); + return snippets.filter( + (s) => + s.title.toLowerCase().includes(q) || + s.language.toLowerCase().includes(q) || + s.tags.some((t) => t.toLowerCase().includes(q)) || + s.code.toLowerCase().includes(q) + ); + }, [snippets, search]); + + return ( +
+
+
+

Snippets

+

+ {snippets.length} snippet{snippets.length !== 1 ? "s" : ""} saved +

+
+ + + +
+ +
+
+ +
+ +
+ + {loading ? ( +
+ {[0, 1, 2].map((item) => ( +
+ ))} +
+ ) : authRequired ? ( + + ) : filtered.length === 0 ? ( + + ) : ( + + + {filtered.map((snippet, i) => ( + + ))} + + + )} +
+ ); +}