aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDhravya <[email protected]>2024-05-25 23:38:48 -0500
committerDhravya <[email protected]>2024-05-25 23:38:48 -0500
commitc12ecfc4316a6f37d2d07c57e4dfefa231783c0d (patch)
treec04612a8db2b06060e1e1087ef298fa124aa71e4
parentfix global file stuff (diff)
downloadsupermemory-c12ecfc4316a6f37d2d07c57e4dfefa231783c0d.tar.xz
supermemory-c12ecfc4316a6f37d2d07c57e4dfefa231783c0d.zip
brought all the APIs back
-rw-r--r--apps/web/app/api/chat/route.ts73
-rw-r--r--apps/web/app/api/getCount/route.ts47
-rw-r--r--apps/web/app/api/me/route.ts47
-rw-r--r--apps/web/app/api/spaces/route.ts29
-rw-r--r--apps/web/app/api/store/route.ts121
-rw-r--r--apps/web/app/helpers/lib/get-metadata.ts40
-rw-r--r--apps/web/app/upload/uploaded-files-card.tsx8
-rw-r--r--apps/web/env.d.ts3
-rw-r--r--apps/web/package.json2
-rw-r--r--apps/web/tsconfig.json5
-rw-r--r--package.json2
-rw-r--r--packages/shared-types/index.ts10
-rw-r--r--packages/shared-types/package.json14
-rw-r--r--packages/ui/hooks/use-upload-file.tsx73
-rw-r--r--packages/ui/src/hooks/use-callback-ref.ts (renamed from packages/ui/hooks/use-callback-ref.ts)0
-rw-r--r--packages/ui/src/hooks/use-controllable-state.ts (renamed from packages/ui/hooks/use-controllable-state.ts)2
-rw-r--r--packages/ui/src/icons/add.svg3
-rw-r--r--packages/ui/src/icons/arrowright.svg3
-rw-r--r--packages/ui/src/icons/chat.svg3
-rw-r--r--packages/ui/src/icons/explore.svg3
-rw-r--r--packages/ui/src/icons/history.svg3
-rw-r--r--packages/ui/src/icons/index.ts17
-rw-r--r--packages/ui/src/icons/memories.svg3
-rw-r--r--packages/ui/src/icons/select.svg4
-rw-r--r--packages/ui/src/shadcn/divider.tsx7
-rw-r--r--packages/ui/src/shadcn/form.tsx2
-rw-r--r--packages/ui/src/ui.d.ts4
27 files changed, 430 insertions, 98 deletions
diff --git a/apps/web/app/api/chat/route.ts b/apps/web/app/api/chat/route.ts
new file mode 100644
index 00000000..34099848
--- /dev/null
+++ b/apps/web/app/api/chat/route.ts
@@ -0,0 +1,73 @@
+import { type NextRequest } from "next/server";
+import { ChatHistory } from "@repo/shared-types";
+import { ensureAuth } from "../ensureAuth";
+
+export const runtime = "edge";
+
+export async function POST(req: NextRequest) {
+ const session = await ensureAuth(req);
+
+ if (!session) {
+ return new Response("Unauthorized", { status: 401 });
+ }
+
+ if (!process.env.BACKEND_SECURITY_KEY) {
+ return new Response("Missing BACKEND_SECURITY_KEY", { status: 500 });
+ }
+
+ const query = new URL(req.url).searchParams.get("q");
+ const spaces = new URL(req.url).searchParams.get("spaces");
+
+ const sourcesOnly =
+ new URL(req.url).searchParams.get("sourcesOnly") ?? "false";
+
+ const chatHistory = (await req.json()) as {
+ chatHistory: ChatHistory[];
+ };
+
+ console.log("CHathistory", chatHistory);
+
+ if (!query) {
+ return new Response(JSON.stringify({ message: "Invalid query" }), {
+ status: 400,
+ });
+ }
+
+ try {
+ const resp = await fetch(
+ `https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}&spaces=${spaces}`,
+ {
+ headers: {
+ "X-Custom-Auth-Key": process.env.BACKEND_SECURITY_KEY!,
+ },
+ method: "POST",
+ body: JSON.stringify({
+ chatHistory: chatHistory.chatHistory ?? [],
+ }),
+ },
+ );
+
+ console.log("sourcesOnly", sourcesOnly);
+
+ if (sourcesOnly == "true") {
+ const data = await resp.json();
+ console.log("data", data);
+ return new Response(JSON.stringify(data), { status: 200 });
+ }
+
+ if (resp.status !== 200 || !resp.ok) {
+ const errorData = await resp.json();
+ console.log(errorData);
+ return new Response(
+ JSON.stringify({ message: "Error in CF function", error: errorData }),
+ { status: resp.status },
+ );
+ }
+
+ // Stream the response back to the client
+ const { readable, writable } = new TransformStream();
+ resp && resp.body!.pipeTo(writable);
+
+ return new Response(readable, { status: 200 });
+ } catch {}
+}
diff --git a/apps/web/app/api/getCount/route.ts b/apps/web/app/api/getCount/route.ts
new file mode 100644
index 00000000..f760c145
--- /dev/null
+++ b/apps/web/app/api/getCount/route.ts
@@ -0,0 +1,47 @@
+import { db } from "@/app/helpers/server/db";
+import { and, eq, ne, sql } from "drizzle-orm";
+import { sessions, storedContent, users } from "@/app/helpers/server/db/schema";
+import { type NextRequest, NextResponse } from "next/server";
+import { ensureAuth } from "../ensureAuth";
+
+export const runtime = "edge";
+
+export async function GET(req: NextRequest) {
+ const session = await ensureAuth(req);
+
+ if (!session) {
+ return new Response("Unauthorized", { status: 401 });
+ }
+
+ const tweetsCount = await db
+ .select({
+ count: sql<number>`count(*)`.mapWith(Number),
+ })
+ .from(storedContent)
+ .where(
+ and(
+ eq(storedContent.user, session.user.id),
+ eq(storedContent.type, "twitter-bookmark"),
+ ),
+ );
+
+ const pageCount = await db
+ .select({
+ count: sql<number>`count(*)`.mapWith(Number),
+ })
+ .from(storedContent)
+ .where(
+ and(
+ eq(storedContent.user, session.user.id),
+ ne(storedContent.type, "twitter-bookmark"),
+ ),
+ );
+
+ return NextResponse.json({
+ tweetsCount: tweetsCount[0]!.count,
+ tweetsLimit: 1000,
+ pageCount: pageCount[0]!.count,
+ pageLimit: 100,
+ user: session.user.email,
+ });
+}
diff --git a/apps/web/app/api/me/route.ts b/apps/web/app/api/me/route.ts
new file mode 100644
index 00000000..20b6aece
--- /dev/null
+++ b/apps/web/app/api/me/route.ts
@@ -0,0 +1,47 @@
+import { db } from "@/app/helpers/server/db";
+import { eq } from "drizzle-orm";
+import { sessions, users } from "@/app/helpers/server/db/schema";
+import { type NextRequest, NextResponse } from "next/server";
+
+export const runtime = "edge";
+
+export async function GET(req: NextRequest) {
+ const token =
+ req.cookies.get("next-auth.session-token")?.value ??
+ req.cookies.get("__Secure-authjs.session-token")?.value ??
+ req.cookies.get("authjs.session-token")?.value ??
+ req.headers.get("Authorization")?.replace("Bearer ", "");
+
+ const session = await db
+ .select()
+ .from(sessions)
+ .where(eq(sessions.sessionToken, token!));
+
+ if (!session || session.length === 0) {
+ return new Response(
+ JSON.stringify({ message: "Invalid Key, session not found." }),
+ { status: 404 },
+ );
+ }
+
+ const user = await db
+ .select()
+ .from(users)
+ .where(eq(users.id, session[0]!.userId))
+ .limit(1);
+
+ if (!user || user.length === 0) {
+ return NextResponse.json(
+ { message: "Invalid Key, session not found." },
+ { status: 404 },
+ );
+ }
+
+ return new Response(
+ JSON.stringify({
+ message: "OK",
+ data: { session: session[0], user: user[0] },
+ }),
+ { status: 200 },
+ );
+}
diff --git a/apps/web/app/api/spaces/route.ts b/apps/web/app/api/spaces/route.ts
new file mode 100644
index 00000000..c46b02fc
--- /dev/null
+++ b/apps/web/app/api/spaces/route.ts
@@ -0,0 +1,29 @@
+import { db } from "@/app/helpers/server/db";
+import { sessions, space, users } from "@/app/helpers/server/db/schema";
+import { eq } from "drizzle-orm";
+import { NextRequest, NextResponse } from "next/server";
+import { ensureAuth } from "../ensureAuth";
+
+export const runtime = "edge";
+
+export async function GET(req: NextRequest) {
+ const session = await ensureAuth(req);
+
+ if (!session) {
+ return new Response("Unauthorized", { status: 401 });
+ }
+
+ const spaces = await db
+ .select()
+ .from(space)
+ .where(eq(space.user, session.user.id))
+ .all();
+
+ return NextResponse.json(
+ {
+ message: "OK",
+ data: spaces,
+ },
+ { status: 200 },
+ );
+}
diff --git a/apps/web/app/api/store/route.ts b/apps/web/app/api/store/route.ts
new file mode 100644
index 00000000..f96f90cf
--- /dev/null
+++ b/apps/web/app/api/store/route.ts
@@ -0,0 +1,121 @@
+import { db } from "@/app/helpers/server/db";
+import { and, eq, sql, inArray } from "drizzle-orm";
+import {
+ contentToSpace,
+ sessions,
+ storedContent,
+ users,
+ space,
+} from "@/app/helpers/server/db/schema";
+import { type NextRequest, NextResponse } from "next/server";
+import { getMetaData } from "@/app/helpers/lib/get-metadata";
+import { ensureAuth } from "../ensureAuth";
+
+export const runtime = "edge";
+
+export async function POST(req: NextRequest) {
+ const session = await ensureAuth(req);
+
+ if (!session) {
+ return new Response("Unauthorized", { status: 401 });
+ }
+
+ const data = (await req.json()) as {
+ pageContent: string;
+ url: string;
+ spaces?: string[];
+ };
+
+ const metadata = await getMetaData(data.url);
+ let storeToSpaces = data.spaces;
+
+ if (!storeToSpaces) {
+ storeToSpaces = [];
+ }
+
+ const count = await db
+ .select({
+ count: sql<number>`count(*)`.mapWith(Number),
+ })
+ .from(storedContent)
+ .where(
+ and(
+ eq(storedContent.user, session.user.id),
+ eq(storedContent.type, "page"),
+ ),
+ );
+
+ if (count[0]!.count > 100) {
+ return NextResponse.json(
+ { message: "Error", error: "Limit exceeded" },
+ { status: 499 },
+ );
+ }
+
+ const rep = await db
+ .insert(storedContent)
+ .values({
+ content: data.pageContent,
+ title: metadata.title,
+ description: metadata.description,
+ url: data.url,
+ baseUrl: metadata.baseUrl,
+ image: metadata.image,
+ savedAt: new Date(),
+ user: session.user.id,
+ })
+ .returning({ id: storedContent.id });
+
+ const id = rep[0]?.id;
+
+ if (!id) {
+ return NextResponse.json(
+ { message: "Error", error: "Error in CF function" },
+ { status: 500 },
+ );
+ }
+
+ if (storeToSpaces.length > 0) {
+ const spaceData = await db
+ .select()
+ .from(space)
+ .where(
+ and(
+ inArray(space.name, storeToSpaces ?? []),
+ eq(space.user, session.user.id),
+ ),
+ )
+ .all();
+
+ await Promise.all([
+ spaceData.forEach(async (space) => {
+ await db
+ .insert(contentToSpace)
+ .values({ contentId: id, spaceId: space.id });
+ }),
+ ]);
+ }
+
+ const res = (await Promise.race([
+ fetch("https://cf-ai-backend.dhravya.workers.dev/add", {
+ method: "POST",
+ headers: {
+ "X-Custom-Auth-Key": process.env.BACKEND_SECURITY_KEY,
+ },
+ body: JSON.stringify({ ...data, user: session.user.email }),
+ }),
+ new Promise((_, reject) =>
+ setTimeout(() => reject(new Error("Request timed out")), 40000),
+ ),
+ ])) as Response;
+
+ if (res.status !== 200) {
+ console.log(res.status, res.statusText);
+ return NextResponse.json(
+ { message: "Error", error: "Error in CF function" },
+ { status: 500 },
+ );
+ }
+
+ return NextResponse.json({ message: "OK", data: "Success" }, { status: 200 });
+}
diff --git a/apps/web/app/helpers/lib/get-metadata.ts b/apps/web/app/helpers/lib/get-metadata.ts
new file mode 100644
index 00000000..4609e49b
--- /dev/null
+++ b/apps/web/app/helpers/lib/get-metadata.ts
@@ -0,0 +1,40 @@
+"use server";
+import * as cheerio from "cheerio";
+
+// TODO: THIS SHOULD PROBABLY ALSO FETCH THE OG-IMAGE
+export async function getMetaData(url: string) {
+ const response = await fetch(url);
+ const html = await response.text();
+
+ const $ = cheerio.load(html);
+
+ // Extract the base URL
+ const baseUrl = new URL(url).origin;
+
+ // Extract title
+ const title = $("title").text().trim();
+
+ const description = $("meta[name=description]").attr("content") ?? "";
+
+ const _favicon =
+ $("link[rel=icon]").attr("href") ?? "https://supermemory.dhr.wtf/web.svg";
+
+ let favicon =
+ _favicon.trim().length > 0
+ ? _favicon.trim()
+ : "https://supermemory.dhr.wtf/web.svg";
+ if (favicon.startsWith("/")) {
+ favicon = baseUrl + favicon;
+ } else if (favicon.startsWith("./")) {
+ favicon = baseUrl + favicon.slice(1);
+ }
+
+ // Prepare the metadata object
+ const metadata = {
+ title,
+ description,
+ image: favicon,
+ baseUrl,
+ };
+ return metadata;
+}
diff --git a/apps/web/app/upload/uploaded-files-card.tsx b/apps/web/app/upload/uploaded-files-card.tsx
index fc9b7d5b..869663b5 100644
--- a/apps/web/app/upload/uploaded-files-card.tsx
+++ b/apps/web/app/upload/uploaded-files-card.tsx
@@ -1,5 +1,5 @@
import Image from "next/image";
-import type { UploadedFile } from "@repo/shared-types";
+// import type { UploadedFile } from '@repo/shared-types';
import {
Card,
@@ -7,11 +7,11 @@ import {
CardDescription,
CardHeader,
CardTitle,
-} from "@repo/ui/src/card";
-import { ScrollArea, ScrollBar } from "@repo/ui/src/scroll-area";
+} from "@repo/ui/src/shadcn/card";
+import { ScrollArea, ScrollBar } from "@repo/ui/src/shadcn/scroll-area";
interface UploadedFilesCardProps {
- uploadedFiles: UploadedFile[];
+ uploadedFiles: any[];
}
import { ImageIcon } from "@radix-ui/react-icons";
diff --git a/apps/web/env.d.ts b/apps/web/env.d.ts
index d74dcdf3..161177a1 100644
--- a/apps/web/env.d.ts
+++ b/apps/web/env.d.ts
@@ -1,4 +1,4 @@
-// Generated by Wrangler on Sat May 25 2024 17:07:13 GMT-0500 (Central Daylight Time)
+// Generated by Wrangler on Sat May 25 2024 23:32:58 GMT-0500 (Central Daylight Time)
// by running `wrangler types --env-interface CloudflareEnv env.d.ts`
interface CloudflareEnv {
@@ -9,6 +9,7 @@ interface CloudflareEnv {
R2_ACCESS_ID: string;
R2_SECRET_KEY: string;
R2_BUCKET_NAME: string;
+ BACKEND_SECURITY_KEY: string;
STORAGE: R2Bucket;
DATABASE: D1Database;
}
diff --git a/apps/web/package.json b/apps/web/package.json
index 70ad3b46..adca3031 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -1,5 +1,5 @@
{
- "name": "web",
+ "name": "@repo/web",
"version": "1.0.0",
"private": true,
"scripts": {
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json
index e5590d6b..ee2fb650 100644
--- a/apps/web/tsconfig.json
+++ b/apps/web/tsconfig.json
@@ -5,7 +5,10 @@
{
"name": "next"
}
- ]
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
},
"include": [
"cf-env.d.ts",
diff --git a/package.json b/package.json
index 32f0b528..d169b935 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"@repo/shared-types": "*",
"@repo/tailwind-config": "*",
"@repo/typescript-config": "*",
+ "@repo/ui": "*",
"@tailwindcss/typography": "^0.5.13",
"autoprefixer": "^10.4.19",
"drizzle-kit": "^0.21.2",
@@ -58,6 +59,7 @@
"@radix-ui/react-toast": "^1.1.5",
"@types/readline-sync": "^1.4.8",
"ai": "^3.1.14",
+ "cheerio": "^1.0.0-rc.12",
"compromise": "^14.13.0",
"drizzle-orm": "^0.30.10",
"framer-motion": "^11.2.6",
diff --git a/packages/shared-types/index.ts b/packages/shared-types/index.ts
index 0ccc2ef7..bf4a56da 100644
--- a/packages/shared-types/index.ts
+++ b/packages/shared-types/index.ts
@@ -1,3 +1,7 @@
-import { type ClientUploadedFileData } from "uploadthing/types";
-
-export interface UploadedFile<T = unknown> extends ClientUploadedFileData<T> {}
+export type ChatHistory = {
+ question: string;
+ answer: {
+ parts: { text: string }[];
+ sources: { isNote: boolean; source: string }[];
+ };
+};
diff --git a/packages/shared-types/package.json b/packages/shared-types/package.json
index f4eaa5bd..18e6049e 100644
--- a/packages/shared-types/package.json
+++ b/packages/shared-types/package.json
@@ -1,15 +1,3 @@
{
- "name": "@repo/shared-types",
- "version": "0.0.0",
- "private": true,
- "type": "module",
- "license": "MIT",
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@repo/eslint-config": "*",
- "@repo/typescript-config": "*",
- "@repo/tailwind-config": "*"
- }
+ "name": "@repo/shared-types"
}
diff --git a/packages/ui/hooks/use-upload-file.tsx b/packages/ui/hooks/use-upload-file.tsx
deleted file mode 100644
index c81d735b..00000000
--- a/packages/ui/hooks/use-upload-file.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { UploadedFile } from "@repo/shared-types";
-import { useState } from "react";
-
-export function useUploadFile<T>(key: string, options?: T) {
- const [isUploading, setIsUploading] = useState(false);
- const [uploadedFiles, setUploadedFiles] = useState<UploadedFile[]>([]);
-
- const uploadFiles = async (image: File[]) => {
- setIsUploading(true);
- await Promise.all(
- image.map(async (file) => {
- const fileName =
- file.name.split(".")[0]! + Date.now() + "." + file.name.split(".")[1];
-
- const formData = new FormData();
- formData.append("data", file);
-
- const response = await fetch(`/api/upload_image?filename=${fileName}`, {
- method: "PUT",
- body: formData,
- });
-
- if (response.status !== 200) {
- throw new Error(response.statusText);
- }
-
- const resp = (await response.json()) as { url: string };
- const url = resp.url;
-
- const response2 = await fetch(url, {
- method: "PUT",
- body: file,
- headers: {
- "Content-Type": file.type,
- },
- });
-
- if (response2.status !== 200) {
- throw new Error(response2.statusText);
- }
-
- // For showing on the client
- const uri = URL.createObjectURL(file);
-
- setUploadedFiles((prev) => [
- ...prev,
- {
- name: fileName,
- url: uri,
- size: file.size,
- type: file.type,
- customId: null,
- key: fileName,
- serverData: null,
- },
- ]);
-
- return {
- url,
- filename: fileName,
- };
- }),
- );
-
- setIsUploading(false);
- };
-
- return {
- uploadFiles,
- uploadedFiles,
- isUploading,
- };
-}
diff --git a/packages/ui/hooks/use-callback-ref.ts b/packages/ui/src/hooks/use-callback-ref.ts
index e3133618..e3133618 100644
--- a/packages/ui/hooks/use-callback-ref.ts
+++ b/packages/ui/src/hooks/use-callback-ref.ts
diff --git a/packages/ui/hooks/use-controllable-state.ts b/packages/ui/src/hooks/use-controllable-state.ts
index 5ffc90f6..7cf20f89 100644
--- a/packages/ui/hooks/use-controllable-state.ts
+++ b/packages/ui/src/hooks/use-controllable-state.ts
@@ -1,6 +1,6 @@
import * as React from "react";
-import { useCallbackRef } from "@repo/ui/hooks/use-callback-ref";
+import { useCallbackRef } from "@repo/ui/src/hooks/use-callback-ref.js";
/**
* @see https://github.com/radix-ui/primitives/blob/main/packages/react/use-controllable-state/src/useControllableState.tsx
diff --git a/packages/ui/src/icons/add.svg b/packages/ui/src/icons/add.svg
new file mode 100644
index 00000000..1c6d87f6
--- /dev/null
+++ b/packages/ui/src/icons/add.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 4.25V16.75M16.25 10.5H3.75" stroke="#C2C7CB" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/icons/arrowright.svg b/packages/ui/src/icons/arrowright.svg
new file mode 100644
index 00000000..d794b094
--- /dev/null
+++ b/packages/ui/src/icons/arrowright.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.25 16.25L17.5 10M17.5 10L11.25 3.75M17.5 10H2.5" stroke="#369DFD" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/icons/chat.svg b/packages/ui/src/icons/chat.svg
new file mode 100644
index 00000000..7fe96c16
--- /dev/null
+++ b/packages/ui/src/icons/chat.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.1875 10C7.1875 10.0829 7.15458 10.1624 7.09597 10.221C7.03737 10.2796 6.95788 10.3125 6.875 10.3125C6.79212 10.3125 6.71263 10.2796 6.65403 10.221C6.59542 10.1624 6.5625 10.0829 6.5625 10C6.5625 9.91712 6.59542 9.83763 6.65403 9.77903C6.71263 9.72042 6.79212 9.6875 6.875 9.6875C6.95788 9.6875 7.03737 9.72042 7.09597 9.77903C7.15458 9.83763 7.1875 9.91712 7.1875 10ZM7.1875 10H6.875M10.3125 10C10.3125 10.0829 10.2796 10.1624 10.221 10.221C10.1624 10.2796 10.0829 10.3125 10 10.3125C9.91712 10.3125 9.83763 10.2796 9.77903 10.221C9.72042 10.1624 9.6875 10.0829 9.6875 10C9.6875 9.91712 9.72042 9.83763 9.77903 9.77903C9.83763 9.72042 9.91712 9.6875 10 9.6875C10.0829 9.6875 10.1624 9.72042 10.221 9.77903C10.2796 9.83763 10.3125 9.91712 10.3125 10ZM10.3125 10H10M13.4375 10C13.4375 10.0829 13.4046 10.1624 13.346 10.221C13.2874 10.2796 13.2079 10.3125 13.125 10.3125C13.0421 10.3125 12.9626 10.2796 12.904 10.221C12.8454 10.1624 12.8125 10.0829 12.8125 10C12.8125 9.91712 12.8454 9.83763 12.904 9.77903C12.9626 9.72042 13.0421 9.6875 13.125 9.6875C13.2079 9.6875 13.2874 9.72042 13.346 9.77903C13.4046 9.83763 13.4375 9.91712 13.4375 10ZM13.4375 10H13.125M17.5 10C17.5 13.7967 14.1417 16.875 10 16.875C9.28099 16.8759 8.56503 16.7814 7.87083 16.5942C6.8923 17.2824 5.6986 17.5951 4.50833 17.475C4.376 17.4622 4.24422 17.4442 4.11333 17.4208C4.52406 16.9368 4.80456 16.356 4.92833 15.7333C5.00333 15.3525 4.8175 14.9825 4.53917 14.7117C3.275 13.4817 2.5 11.8242 2.5 10C2.5 6.20333 5.85833 3.125 10 3.125C14.1417 3.125 17.5 6.20333 17.5 10Z" stroke="#989EA4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/icons/explore.svg b/packages/ui/src/icons/explore.svg
new file mode 100644
index 00000000..d6332612
--- /dev/null
+++ b/packages/ui/src/icons/explore.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6.5 17.5L14 14L17.5 6.5L10 10L6.5 17.5ZM12 13C11.7167 13 11.4793 12.904 11.288 12.712C11.0967 12.52 11.0007 12.2827 11 12C10.9993 11.7173 11.0953 11.48 11.288 11.288C11.4807 11.096 11.718 11 12 11C12.282 11 12.5197 11.096 12.713 11.288C12.9063 11.48 13.002 11.7173 13 12C12.998 12.2827 12.902 12.5203 12.712 12.713C12.522 12.9057 12.2847 13.0013 12 13ZM12 22C10.6167 22 9.31667 21.7373 8.1 21.212C6.88334 20.6867 5.825 19.9743 4.925 19.075C4.025 18.1757 3.31267 17.1173 2.788 15.9C2.26333 14.6827 2.00067 13.3827 2 12C1.99933 10.6173 2.262 9.31733 2.788 8.1C3.314 6.88267 4.02633 5.82433 4.925 4.925C5.82367 4.02567 6.882 3.31333 8.1 2.788C9.318 2.26267 10.618 2 12 2C13.382 2 14.682 2.26267 15.9 2.788C17.118 3.31333 18.1763 4.02567 19.075 4.925C19.9737 5.82433 20.6863 6.88267 21.213 8.1C21.7397 9.31733 22.002 10.6173 22 12C21.998 13.3827 21.7353 14.6827 21.212 15.9C20.6887 17.1173 19.9763 18.1757 19.075 19.075C18.1737 19.9743 17.1153 20.687 15.9 21.213C14.6847 21.739 13.3847 22.0013 12 22Z" fill="#6A737D"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/icons/history.svg b/packages/ui/src/icons/history.svg
new file mode 100644
index 00000000..7766c75d
--- /dev/null
+++ b/packages/ui/src/icons/history.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2.25C6.615 2.25 2.25 6.615 2.25 12C2.25 17.385 6.615 21.75 12 21.75C17.385 21.75 21.75 17.385 21.75 12C21.75 6.615 17.385 2.25 12 2.25ZM12.75 6C12.75 5.80109 12.671 5.61032 12.5303 5.46967C12.3897 5.32902 12.1989 5.25 12 5.25C11.8011 5.25 11.6103 5.32902 11.4697 5.46967C11.329 5.61032 11.25 5.80109 11.25 6V12C11.25 12.414 11.586 12.75 12 12.75H16.5C16.6989 12.75 16.8897 12.671 17.0303 12.5303C17.171 12.3897 17.25 12.1989 17.25 12C17.25 11.8011 17.171 11.6103 17.0303 11.4697C16.8897 11.329 16.6989 11.25 16.5 11.25H12.75V6Z" fill="#6A737D"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts
new file mode 100644
index 00000000..6c528aba
--- /dev/null
+++ b/packages/ui/src/icons/index.ts
@@ -0,0 +1,17 @@
+import AddIcon from "./add.svg";
+import ChatIcon from "./chat.svg";
+import HistoryIcon from "./history.svg";
+import ExploreIcon from "./explore.svg";
+import MemoriesIcon from "./memories.svg";
+import ArrowRightIcon from "./arrowRight.svg";
+import SelectIcon from "./select.svg";
+
+export {
+ AddIcon,
+ ChatIcon,
+ HistoryIcon,
+ ExploreIcon,
+ MemoriesIcon,
+ ArrowRightIcon,
+ SelectIcon,
+};
diff --git a/packages/ui/src/icons/memories.svg b/packages/ui/src/icons/memories.svg
new file mode 100644
index 00000000..27784aac
--- /dev/null
+++ b/packages/ui/src/icons/memories.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.566 4.657C5.95195 4.55235 6.35011 4.49955 6.75 4.5H17.25C17.66 4.5 18.056 4.555 18.433 4.657C18.1837 4.15898 17.8006 3.7402 17.3268 3.44754C16.8529 3.15489 16.3069 2.99993 15.75 3H8.25C7.69288 2.99974 7.1467 3.15462 6.67265 3.44728C6.1986 3.73994 5.8154 4.15883 5.566 4.657ZM2.25 12C2.25 11.2044 2.56607 10.4413 3.12868 9.87868C3.69129 9.31607 4.45435 9 5.25 9H18.75C19.5456 9 20.3087 9.31607 20.8713 9.87868C21.4339 10.4413 21.75 11.2044 21.75 12V18C21.75 18.7956 21.4339 19.5587 20.8713 20.1213C20.3087 20.6839 19.5456 21 18.75 21H5.25C4.45435 21 3.69129 20.6839 3.12868 20.1213C2.56607 19.5587 2.25 18.7956 2.25 18V12ZM5.25 7.5C4.84 7.5 4.444 7.555 4.066 7.657C4.3154 7.15883 4.6986 6.73994 5.17265 6.44728C5.6467 6.15462 6.19288 5.99974 6.75 6H17.25C17.8069 5.99993 18.3529 6.15489 18.8268 6.44754C19.3006 6.7402 19.6837 7.15898 19.933 7.657C19.5474 7.55244 19.1496 7.49964 18.75 7.5H5.25Z" fill="#6A737D"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/icons/select.svg b/packages/ui/src/icons/select.svg
new file mode 100644
index 00000000..0b019c01
--- /dev/null
+++ b/packages/ui/src/icons/select.svg
@@ -0,0 +1,4 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.25 11.25L9 15L12.75 11.25" stroke="#858B92" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M5.25 6.75L9 3L12.75 6.75" stroke="#858B92" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg> \ No newline at end of file
diff --git a/packages/ui/src/shadcn/divider.tsx b/packages/ui/src/shadcn/divider.tsx
new file mode 100644
index 00000000..34439866
--- /dev/null
+++ b/packages/ui/src/shadcn/divider.tsx
@@ -0,0 +1,7 @@
+import { cn } from "@repo/ui/lib/utils";
+
+function Divider({ className }: { className?: string }) {
+ return <div className={cn("bg-[#2D343A] h-[1px] w-full", className)}></div>;
+}
+
+export default Divider;
diff --git a/packages/ui/src/shadcn/form.tsx b/packages/ui/src/shadcn/form.tsx
index 9de2d23e..452a6e30 100644
--- a/packages/ui/src/shadcn/form.tsx
+++ b/packages/ui/src/shadcn/form.tsx
@@ -11,7 +11,7 @@ import {
} from "react-hook-form";
import { cn } from "@repo/ui/lib/utils";
-import { Label } from "@repo/ui/shadcn/label";
+import { Label } from "@repo/ui/src/shadcn/label";
const Form = FormProvider;
diff --git a/packages/ui/src/ui.d.ts b/packages/ui/src/ui.d.ts
new file mode 100644
index 00000000..1a3dd3c2
--- /dev/null
+++ b/packages/ui/src/ui.d.ts
@@ -0,0 +1,4 @@
+declare module "*.svg" {
+ const content: any;
+ export default content;
+}