aboutsummaryrefslogtreecommitdiffstats
path: root/web/app
diff options
context:
space:
mode:
Diffstat (limited to 'web/app')
-rw-r--r--web/app/api/auth/[...nextauth]/route.tsx3
-rw-r--r--web/app/api/v1/links/[linkId]/route.ts32
-rw-r--r--web/app/api/v1/links/route.ts49
-rw-r--r--web/app/dashboard/bookmarks/components/AddLink.tsx67
-rw-r--r--web/app/dashboard/bookmarks/components/LinkCard.tsx96
-rw-r--r--web/app/dashboard/bookmarks/components/LinksGrid.tsx21
-rw-r--r--web/app/dashboard/bookmarks/page.tsx20
-rw-r--r--web/app/dashboard/components/Sidebar.tsx56
-rw-r--r--web/app/dashboard/layout.tsx15
-rw-r--r--web/app/favicon.icobin25931 -> 0 bytes
-rw-r--r--web/app/globals.css76
-rw-r--r--web/app/layout.tsx27
-rw-r--r--web/app/page.tsx19
13 files changed, 0 insertions, 481 deletions
diff --git a/web/app/api/auth/[...nextauth]/route.tsx b/web/app/api/auth/[...nextauth]/route.tsx
deleted file mode 100644
index e722926b..00000000
--- a/web/app/api/auth/[...nextauth]/route.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { authHandler } from "@/lib/auth";
-
-export { authHandler as GET, authHandler as POST };
diff --git a/web/app/api/v1/links/[linkId]/route.ts b/web/app/api/v1/links/[linkId]/route.ts
deleted file mode 100644
index 39449d6d..00000000
--- a/web/app/api/v1/links/[linkId]/route.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { authOptions } from "@/lib/auth";
-import { unbookmarkLink } from "@/lib/services/links";
-import { Prisma } from "@remember/db";
-
-import { getServerSession } from "next-auth";
-import { NextRequest } from "next/server";
-
-export async function DELETE(
- _request: NextRequest,
- { params }: { params: { linkId: string } },
-) {
- // TODO: We probably should be using an API key here instead of the session;
- const session = await getServerSession(authOptions);
- if (!session) {
- return new Response(null, { status: 401 });
- }
-
- try {
- await unbookmarkLink(params.linkId, session.user.id);
- } catch (e: unknown) {
- if (
- e instanceof Prisma.PrismaClientKnownRequestError &&
- e.code === "P2025" // RecordNotFound
- ) {
- return new Response(null, { status: 404 });
- } else {
- throw e;
- }
- }
-
- return new Response(null, { status: 201 });
-}
diff --git a/web/app/api/v1/links/route.ts b/web/app/api/v1/links/route.ts
deleted file mode 100644
index 87541634..00000000
--- a/web/app/api/v1/links/route.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { authOptions } from "@/lib/auth";
-import { bookmarkLink, getLinks } from "@/lib/services/links";
-
-import {
- zNewBookmarkedLinkRequestSchema,
- ZGetLinksResponse,
- ZBookmarkedLink,
-} from "@/lib/types/api/links";
-import { getServerSession } from "next-auth";
-import { NextRequest, NextResponse } from "next/server";
-
-export async function POST(request: NextRequest) {
- // TODO: We probably should be using an API key here instead of the session;
- const session = await getServerSession(authOptions);
- if (!session) {
- return new Response(null, { status: 401 });
- }
-
- const linkRequest = zNewBookmarkedLinkRequestSchema.safeParse(
- await request.json(),
- );
-
- if (!linkRequest.success) {
- return NextResponse.json(
- {
- error: linkRequest.error.toString(),
- },
- { status: 400 },
- );
- }
-
- const link = await bookmarkLink(linkRequest.data.url, session.user.id);
-
- let response: ZBookmarkedLink = { ...link };
- return NextResponse.json(response, { status: 201 });
-}
-
-export async function GET() {
- // TODO: We probably should be using an API key here instead of the session;
- const session = await getServerSession(authOptions);
- if (!session) {
- return new Response(null, { status: 401 });
- }
-
- const links = await getLinks(session.user.id);
-
- let response: ZGetLinksResponse = { links };
- return NextResponse.json(response);
-}
diff --git a/web/app/dashboard/bookmarks/components/AddLink.tsx b/web/app/dashboard/bookmarks/components/AddLink.tsx
deleted file mode 100644
index fb77786c..00000000
--- a/web/app/dashboard/bookmarks/components/AddLink.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-"use client";
-
-import { Button } from "@/components/ui/button";
-import { Form, FormControl, FormField, FormItem } from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import APIClient from "@/lib/api";
-import { Plus } from "lucide-react";
-import { useRouter } from "next/navigation";
-import { useForm, SubmitErrorHandler } from "react-hook-form";
-import { z } from "zod";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { toast } from "@/components/ui/use-toast";
-
-const formSchema = z.object({
- url: z.string().url({ message: "The link must be a valid URL" }),
-});
-
-export default function AddLink() {
- const router = useRouter();
-
- const form = useForm<z.infer<typeof formSchema>>({
- resolver: zodResolver(formSchema),
- });
-
- async function onSubmit(value: z.infer<typeof formSchema>) {
- const [_resp, error] = await APIClient.bookmarkLink(value.url);
- if (error) {
- toast({ description: error.message, variant: "destructive" });
- return;
- }
- router.refresh();
- }
-
- const onError: SubmitErrorHandler<z.infer<typeof formSchema>> = (errors) => {
- toast({
- description: Object.values(errors)
- .map((v) => v.message)
- .join("\n"),
- variant: "destructive",
- });
- };
-
- return (
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit, onError)}>
- <div className="py-4 container flex w-full items-center space-x-2">
- <FormField
- control={form.control}
- name="url"
- render={({ field }) => {
- return (
- <FormItem className="flex-1">
- <FormControl>
- <Input type="text" placeholder="Link" {...field} />
- </FormControl>
- </FormItem>
- );
- }}
- />
- <Button type="submit">
- <Plus />
- </Button>
- </div>
- </form>
- </Form>
- );
-}
diff --git a/web/app/dashboard/bookmarks/components/LinkCard.tsx b/web/app/dashboard/bookmarks/components/LinkCard.tsx
deleted file mode 100644
index da59d9da..00000000
--- a/web/app/dashboard/bookmarks/components/LinkCard.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-"use client";
-
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-import {
- ImageCard,
- ImageCardBody,
- ImageCardFooter,
- ImageCardTitle,
-} from "@/components/ui/imageCard";
-import { useToast } from "@/components/ui/use-toast";
-import APIClient from "@/lib/api";
-import { ZBookmarkedLink } from "@/lib/types/api/links";
-import { MoreHorizontal, Trash2 } from "lucide-react";
-import Link from "next/link";
-import { useRouter } from "next/navigation";
-
-export function LinkOptions({ linkId }: { linkId: string }) {
- const { toast } = useToast();
- const router = useRouter();
-
- const unbookmarkLink = async () => {
- let [_, error] = await APIClient.unbookmarkLink(linkId);
-
- if (error) {
- toast({
- variant: "destructive",
- title: "Something went wrong",
- description: "There was a problem with your request.",
- });
- } else {
- toast({
- description: "The link has been deleted!",
- });
- }
-
- router.refresh();
- };
- return (
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button variant="ghost">
- <MoreHorizontal />
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent className="w-fit">
- <DropdownMenuItem className="text-destructive" onClick={unbookmarkLink}>
- <Trash2 className="mr-2 h-4 w-4" />
- <span>Delete</span>
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
- );
-}
-
-export default function LinkCard({ link }: { link: ZBookmarkedLink }) {
- const parsedUrl = new URL(link.url);
-
- return (
- <ImageCard
- className={
- "bg-gray-50 duration-300 ease-in border border-grey-100 hover:transition-all hover:border-blue-300"
- }
- image={link.details?.imageUrl ?? undefined}
- >
- <ImageCardTitle>
- <Link className="line-clamp-3" href={link.url}>
- {link.details?.title ?? parsedUrl.host}
- </Link>
- </ImageCardTitle>
- <ImageCardBody className="py-2 overflow-clip">
- {link.tags.map((t) => (
- <Badge variant="default" className="bg-gray-300 text-gray-500" key={t.id}>
- #{t.name}
- </Badge>
- ))}
- </ImageCardBody>
- <ImageCardFooter>
- <div className="flex justify-between text-gray-500">
- <div className="my-auto">
- <Link className="line-clamp-1 hover:text-black" href={link.url}>
- {parsedUrl.host}
- </Link>
- </div>
- <LinkOptions linkId={link.id} />
- </div>
- </ImageCardFooter>
- </ImageCard>
- );
-}
diff --git a/web/app/dashboard/bookmarks/components/LinksGrid.tsx b/web/app/dashboard/bookmarks/components/LinksGrid.tsx
deleted file mode 100644
index 66f0d766..00000000
--- a/web/app/dashboard/bookmarks/components/LinksGrid.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { getServerSession } from "next-auth";
-import { redirect } from "next/navigation";
-import { authOptions } from "@/lib/auth";
-import { getLinks } from "@/lib/services/links";
-import LinkCard from "./LinkCard";
-
-export default async function LinksGrid() {
- const session = await getServerSession(authOptions);
- if (!session) {
- redirect("/");
- }
- const links = await getLinks(session.user.id);
-
- return (
- <div className="container grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
- {links.map((l) => (
- <LinkCard key={l.id} link={l} />
- ))}
- </div>
- );
-}
diff --git a/web/app/dashboard/bookmarks/page.tsx b/web/app/dashboard/bookmarks/page.tsx
deleted file mode 100644
index b4158893..00000000
--- a/web/app/dashboard/bookmarks/page.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import AddLink from "./components/AddLink";
-import LinksGrid from "./components/LinksGrid";
-import type { Metadata } from "next";
-
-export const metadata: Metadata = {
- title: "Remember - Bookmarks",
-};
-
-export default async function Bookmarks() {
- return (
- <div className="flex flex-col">
- <div>
- <AddLink />
- </div>
- <div>
- <LinksGrid />
- </div>
- </div>
- );
-}
diff --git a/web/app/dashboard/components/Sidebar.tsx b/web/app/dashboard/components/Sidebar.tsx
deleted file mode 100644
index 0ed87daf..00000000
--- a/web/app/dashboard/components/Sidebar.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Button } from "@/components/ui/button";
-import { authOptions } from "@/lib/auth";
-import { Archive, MoreHorizontal, Star, Tag, Home, Brain} from "lucide-react";
-import { getServerSession } from "next-auth";
-import Link from "next/link";
-import { redirect } from "next/navigation";
-
-function SidebarItem({
- name,
- logo,
- path,
-}: {
- name: string;
- logo: React.ReactNode;
- path: string;
-}) {
- return (
- <li className="rounded-lg px-3 py-2 hover:bg-slate-100">
- <Link href={path} className="flex w-full space-x-2">
- {logo}
- <span className="my-auto"> {name} </span>
- </Link>
- </li>
- );
-}
-
-export default async function Sidebar() {
- const session = await getServerSession(authOptions);
- if (!session) {
- redirect("/");
- }
-
- return (
- <aside className="flex flex-col h-full w-60 border-r p-4">
- <div className="flex px-1 mb-5 items-center rounded-lg text-slate-900">
- <Brain />
- <span className="ml-2 text-base font-semibold">Remember</span>
- </div>
- <hr />
- <div>
- <ul className="space-y-2 mt-5 text-sm font-medium">
- <SidebarItem logo={<Home />} name="Home" path="#" />
- <SidebarItem logo={<Star />} name="Favourites" path="#" />
- <SidebarItem logo={<Archive />} name="Archived" path="#" />
- <SidebarItem logo={<Tag />} name="Tags" path="#" />
- </ul>
- </div>
- <div className="mt-auto flex justify-between">
- <div className="my-auto"> {session.user.name} </div>
- <Button variant="ghost" className="h-10 w-30">
- <MoreHorizontal />
- </Button>
- </div>
- </aside>
- );
-}
diff --git a/web/app/dashboard/layout.tsx b/web/app/dashboard/layout.tsx
deleted file mode 100644
index 9b21271e..00000000
--- a/web/app/dashboard/layout.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import Bookmarks from "@/app/dashboard/bookmarks/page";
-import Sidebar from "@/app/dashboard/components/Sidebar";
-
-export default async function Dashboard() {
- return (
- <div className="flex w-screen h-screen">
- <div className="flex-none">
- <Sidebar />
- </div>
- <div className="flex-1 bg-gray-100">
- <Bookmarks />
- </div>
- </div>
- );
-}
diff --git a/web/app/favicon.ico b/web/app/favicon.ico
deleted file mode 100644
index 718d6fea..00000000
--- a/web/app/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/web/app/globals.css b/web/app/globals.css
deleted file mode 100644
index 8abdb15c..00000000
--- a/web/app/globals.css
+++ /dev/null
@@ -1,76 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-@layer base {
- :root {
- --background: 0 0% 100%;
- --foreground: 222.2 84% 4.9%;
-
- --card: 0 0% 100%;
- --card-foreground: 222.2 84% 4.9%;
-
- --popover: 0 0% 100%;
- --popover-foreground: 222.2 84% 4.9%;
-
- --primary: 222.2 47.4% 11.2%;
- --primary-foreground: 210 40% 98%;
-
- --secondary: 210 40% 96.1%;
- --secondary-foreground: 222.2 47.4% 11.2%;
-
- --muted: 210 40% 96.1%;
- --muted-foreground: 215.4 16.3% 46.9%;
-
- --accent: 210 40% 96.1%;
- --accent-foreground: 222.2 47.4% 11.2%;
-
- --destructive: 0 84.2% 60.2%;
- --destructive-foreground: 210 40% 98%;
-
- --border: 214.3 31.8% 91.4%;
- --input: 214.3 31.8% 91.4%;
- --ring: 222.2 84% 4.9%;
-
- --radius: 0.5rem;
- }
-
- .dark {
- --background: 222.2 84% 4.9%;
- --foreground: 210 40% 98%;
-
- --card: 222.2 84% 4.9%;
- --card-foreground: 210 40% 98%;
-
- --popover: 222.2 84% 4.9%;
- --popover-foreground: 210 40% 98%;
-
- --primary: 210 40% 98%;
- --primary-foreground: 222.2 47.4% 11.2%;
-
- --secondary: 217.2 32.6% 17.5%;
- --secondary-foreground: 210 40% 98%;
-
- --muted: 217.2 32.6% 17.5%;
- --muted-foreground: 215 20.2% 65.1%;
-
- --accent: 217.2 32.6% 17.5%;
- --accent-foreground: 210 40% 98%;
-
- --destructive: 0 62.8% 30.6%;
- --destructive-foreground: 210 40% 98%;
-
- --border: 217.2 32.6% 17.5%;
- --input: 217.2 32.6% 17.5%;
- --ring: 212.7 26.8% 83.9%;
- }
-}
-
-@layer base {
- * {
- @apply border-border;
- }
- body {
- @apply bg-background text-foreground;
- }
-}
diff --git a/web/app/layout.tsx b/web/app/layout.tsx
deleted file mode 100644
index a2d34046..00000000
--- a/web/app/layout.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { Metadata } from "next";
-import { Inter } from "next/font/google";
-import "./globals.css";
-import React from "react";
-import { Toaster } from "@/components/ui/toaster";
-
-const inter = Inter({ subsets: ["latin"] });
-
-export const metadata: Metadata = {
- title: "Remember",
- description: "Your AI powered second brain",
-};
-
-export default function RootLayout({
- children,
-}: Readonly<{
- children: React.ReactNode;
-}>) {
- return (
- <html lang="en">
- <body className={inter.className}>
- {children}
- <Toaster />
- </body>
- </html>
- );
-}
diff --git a/web/app/page.tsx b/web/app/page.tsx
deleted file mode 100644
index ffc128a5..00000000
--- a/web/app/page.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { LoginButton } from "@/components/auth/login";
-import { LogoutButton } from "@/components/auth/logout";
-import Link from "next/link";
-
-export default function Home() {
- return (
- <main className="flex min-h-screen flex-col items-center justify-between p-24">
- <div>
- <LoginButton />
- <br />
- <br />
- <LogoutButton />
- <br />
- <br />
- <Link href="/bookmarks">Bookmarks</Link>
- </div>
- </main>
- );
-}