mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-12 23:01:07 +00:00
fixed new chat button showing up on all pages
This commit is contained in:
parent
3754b2c2c8
commit
9272d87e5f
14 changed files with 188 additions and 54 deletions
|
|
@ -375,10 +375,6 @@ app.post(
|
|||
// SLICED to 5 to avoid too many queries
|
||||
for (const space of spaces.slice(0, 5)) {
|
||||
if (space && space.length >= 1) {
|
||||
console.log(
|
||||
"this is the key being used",
|
||||
`space-${query.user}-${space}`,
|
||||
);
|
||||
// it's possible for space list to be [undefined] so we only add space filter conditionally
|
||||
filter[`space-${query.user}-${space}`] = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import Logo from "@/public/logo.svg";
|
||||
import { signIn } from "@/server/auth";
|
||||
import { auth, signIn } from "@/server/auth";
|
||||
import { Google } from "@repo/ui/components/icons";
|
||||
import gradientStyle from "./_components/TextGradient/gradient.module.css";
|
||||
import { cn } from "@repo/ui/lib/utils";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
async function Signin() {
|
||||
const user = await auth();
|
||||
|
||||
if (user) {
|
||||
await redirect("/home");
|
||||
}
|
||||
return (
|
||||
<div className="flex relative font-geistSans overflow-hidden items-center justify-between min-h-screen">
|
||||
<div className="relative w-full lg:w-1/2 flex items-center min-h-screen bg-page-gradient p-8 border-r-[1px] border-white/5">
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ function ChatWindow({
|
|||
mini
|
||||
className="w-full shadow-md"
|
||||
initialQuery={""}
|
||||
initialSpaces={[]}
|
||||
initialSpaces={spaces}
|
||||
handleSubmit={async (q, spaces) => {
|
||||
setChatHistory((prevChatHistory) => {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import Logo from "../../public/logo.svg";
|
||||
import { AddIcon, ChatIcon } from "@repo/ui/icons";
|
||||
import Logo from "../../../public/logo.svg";
|
||||
|
||||
import { db } from "@/server/db";
|
||||
import { getChatHistory } from "../actions/fetchers";
|
||||
import { getChatHistory } from "../../actions/fetchers";
|
||||
import NewChatButton from "./newChatButton";
|
||||
|
||||
async function Header() {
|
||||
const chatThreads = await getChatHistory();
|
||||
|
|
@ -26,10 +25,7 @@ async function Header() {
|
|||
</Link>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<button className="flex duration-200 items-center text-[#7D8994] hover:bg-[#1F2429] text-[13px] gap-2 px-3 py-2 rounded-xl">
|
||||
<Image src={ChatIcon} alt="Chat icon" className="w-5" />
|
||||
Start new chat
|
||||
</button>
|
||||
<NewChatButton />
|
||||
|
||||
<div className="relative group">
|
||||
<button className="flex duration-200 items-center text-[#7D8994] hover:bg-[#1F2429] text-[13px] gap-2 px-3 py-2 rounded-xl">
|
||||
27
apps/web/app/(dash)/header/newChatButton.tsx
Normal file
27
apps/web/app/(dash)/header/newChatButton.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
"use client";
|
||||
|
||||
import { ChatIcon } from "@repo/ui/icons";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import React from "react";
|
||||
|
||||
function NewChatButton() {
|
||||
const path = usePathname();
|
||||
|
||||
if (path.startsWith("/chat")) {
|
||||
return (
|
||||
<Link
|
||||
href="/home"
|
||||
className="flex duration-200 items-center text-[#7D8994] hover:bg-[#1F2429] text-[13px] gap-2 px-3 py-2 rounded-xl"
|
||||
>
|
||||
<Image src={ChatIcon} alt="Chat icon" className="w-5" />
|
||||
Start new chat
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default NewChatButton;
|
||||
|
|
@ -74,6 +74,7 @@ function Page({
|
|||
);
|
||||
}}
|
||||
initialSpaces={spaces}
|
||||
setInitialSpaces={setSpaces}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import { useRouter } from "next/navigation";
|
|||
import { getSpaces } from "@/app/actions/fetchers";
|
||||
import Combobox from "@repo/ui/shadcn/combobox";
|
||||
import { MinusIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { createSpace } from "@/app/actions/doers";
|
||||
|
||||
function QueryInput({
|
||||
initialQuery = "",
|
||||
|
|
@ -16,6 +18,7 @@ function QueryInput({
|
|||
className,
|
||||
mini = false,
|
||||
handleSubmit,
|
||||
setInitialSpaces,
|
||||
}: {
|
||||
initialQuery?: string;
|
||||
initialSpaces?: {
|
||||
|
|
@ -26,6 +29,9 @@ function QueryInput({
|
|||
className?: string;
|
||||
mini?: boolean;
|
||||
handleSubmit: (q: string, spaces: { id: number; name: string }[]) => void;
|
||||
setInitialSpaces?: React.Dispatch<
|
||||
React.SetStateAction<{ id: number; name: string }[]>
|
||||
>;
|
||||
}) {
|
||||
const [q, setQ] = useState(initialQuery);
|
||||
|
||||
|
|
@ -104,6 +110,7 @@ function QueryInput({
|
|||
<div className="flex justify-between items-center gap-6 h-auto bg-secondary rounded-b-3xl border-2 border-border">
|
||||
<Combobox
|
||||
options={options}
|
||||
className="rounded-bl-3xl bg-[#3C464D] w-44"
|
||||
onSelect={(v) =>
|
||||
setSelectedSpaces((prev) => {
|
||||
if (v === "") {
|
||||
|
|
@ -112,8 +119,33 @@ function QueryInput({
|
|||
return [...prev, parseInt(v)];
|
||||
})
|
||||
}
|
||||
onSubmit={() => {}}
|
||||
placeholder="Filter spaces..."
|
||||
onSubmit={async (spaceName) => {
|
||||
const space = options.find((x) => x.label === spaceName);
|
||||
toast.info("Creating space...");
|
||||
|
||||
if (space) {
|
||||
toast.error("A space with that name already exists.");
|
||||
}
|
||||
|
||||
const creationTask = await createSpace(spaceName);
|
||||
if (creationTask.success && creationTask.data) {
|
||||
toast.success("Space created " + creationTask.data);
|
||||
setInitialSpaces?.((prev) => [
|
||||
...prev,
|
||||
{
|
||||
name: spaceName,
|
||||
id: creationTask.data!,
|
||||
},
|
||||
]);
|
||||
setSelectedSpaces((prev) => [...prev, creationTask.data!]);
|
||||
} else {
|
||||
toast.error(
|
||||
"Space creation failed: " + creationTask.error ??
|
||||
"Unknown error",
|
||||
);
|
||||
}
|
||||
}}
|
||||
placeholder="Chat with a space..."
|
||||
/>
|
||||
|
||||
<div className="flex flex-row gap-0.5 h-full">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Header from "./header";
|
||||
import Header from "./header/header";
|
||||
import Menu from "./menu";
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "../../server/auth";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Image from "next/image";
|
|||
import Link from "next/link";
|
||||
import { MemoriesIcon, ExploreIcon, CanvasIcon, AddIcon } from "@repo/ui/icons";
|
||||
import { Button } from "@repo/ui/shadcn/button";
|
||||
import { PlusCircleIcon } from "lucide-react";
|
||||
import { MinusIcon, PlusCircleIcon } from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
|
@ -34,8 +34,9 @@ import {
|
|||
TooltipTrigger,
|
||||
} from "@repo/ui/shadcn/tooltip";
|
||||
import { InformationCircleIcon } from "@heroicons/react/24/outline";
|
||||
import { createMemory } from "../actions/doers";
|
||||
import { createMemory, createSpace } from "../actions/doers";
|
||||
import { Input } from "@repo/ui/shadcn/input";
|
||||
import ComboboxWithCreate from "@repo/ui/shadcn/combobox";
|
||||
|
||||
function Menu() {
|
||||
const [spaces, setSpaces] = useState<Space[]>([]);
|
||||
|
|
@ -77,7 +78,7 @@ function Menu() {
|
|||
];
|
||||
|
||||
const [content, setContent] = useState("");
|
||||
const [selectedSpace, setSelectedSpace] = useState<string | null>(null);
|
||||
const [selectedSpaces, setSelectedSpaces] = useState<number[]>([]);
|
||||
|
||||
const autoDetectedType = useMemo(() => {
|
||||
if (content.length === 0) {
|
||||
|
|
@ -97,6 +98,15 @@ function Menu() {
|
|||
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
|
||||
const options = useMemo(
|
||||
() =>
|
||||
spaces.map((x) => ({
|
||||
label: x.name,
|
||||
value: x.id.toString(),
|
||||
})),
|
||||
[spaces],
|
||||
);
|
||||
|
||||
const handleSubmit = async (content?: string, space?: string) => {
|
||||
setDialogOpen(false);
|
||||
|
||||
|
|
@ -212,7 +222,7 @@ function Menu() {
|
|||
className="text-[#858B92] flex items-center gap-1 duration-200 transform transition-transform"
|
||||
htmlFor="space"
|
||||
>
|
||||
Space
|
||||
Spaces
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
|
|
@ -227,26 +237,81 @@ function Menu() {
|
|||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</Label>
|
||||
<Select
|
||||
onValueChange={(value) => setSelectedSpace(value)}
|
||||
value={selectedSpace ?? "none"}
|
||||
defaultValue="none"
|
||||
name="space"
|
||||
>
|
||||
<SelectTrigger className="mt-2">
|
||||
<SelectValue placeholder="None" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-secondary text-white">
|
||||
<SelectItem defaultChecked value="none">
|
||||
None
|
||||
</SelectItem>
|
||||
{spaces.map((space) => (
|
||||
<SelectItem key={space.id} value={space.id.toString()}>
|
||||
{space.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<ComboboxWithCreate
|
||||
options={spaces.map((x) => ({
|
||||
label: x.name,
|
||||
value: x.id.toString(),
|
||||
}))}
|
||||
onSelect={(v) =>
|
||||
setSelectedSpaces((prev) => {
|
||||
if (v === "") {
|
||||
return [];
|
||||
}
|
||||
return [...prev, parseInt(v)];
|
||||
})
|
||||
}
|
||||
onSubmit={async (spaceName) => {
|
||||
const space = options.find((x) => x.label === spaceName);
|
||||
toast.info("Creating space...");
|
||||
|
||||
if (space) {
|
||||
toast.error("A space with that name already exists.");
|
||||
}
|
||||
|
||||
const creationTask = await createSpace(spaceName);
|
||||
if (creationTask.success && creationTask.data) {
|
||||
toast.success("Space created " + creationTask.data);
|
||||
setSpaces?.((prev) => [
|
||||
...prev,
|
||||
{
|
||||
name: spaceName,
|
||||
id: creationTask.data!,
|
||||
},
|
||||
]);
|
||||
setSelectedSpaces((prev) => [
|
||||
...prev,
|
||||
creationTask.data!,
|
||||
]);
|
||||
} else {
|
||||
toast.error(
|
||||
"Space creation failed: " + creationTask.error ??
|
||||
"Unknown error",
|
||||
);
|
||||
}
|
||||
}}
|
||||
placeholder="Save or create space by typing."
|
||||
className="bg-[#2B3237] h-min rounded-md mt-2 mb-4"
|
||||
/>
|
||||
|
||||
<div>
|
||||
{selectedSpaces.length > 0 && (
|
||||
<div className="flex flex-row flex-wrap gap-0.5 h-min">
|
||||
{selectedSpaces.map((x, idx) => (
|
||||
<button
|
||||
key={x}
|
||||
onClick={() =>
|
||||
setSelectedSpaces((prev) =>
|
||||
prev.filter((y) => y !== x),
|
||||
)
|
||||
}
|
||||
className={`relative group p-2 py-3 bg-[#3C464D] max-w-32 ${
|
||||
idx === selectedSpaces.length - 1
|
||||
? "rounded-br-xl"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<p className="line-clamp-1">
|
||||
{spaces.find((y) => y.id === x)?.name}
|
||||
</p>
|
||||
<div className="absolute h-full right-0 top-0 p-1 opacity-0 group-hover:opacity-100 items-center">
|
||||
<MinusIcon className="w-6 h-6 rounded-full bg-secondary" />
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,16 +9,15 @@ import { auth } from "@/server/auth";
|
|||
import Services from "./Features/index";
|
||||
import { Showcases } from "./Showcase";
|
||||
import BackgroundPlus from "./GridPatterns/PlusGrid";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
export default async function Home() {
|
||||
const user = await auth();
|
||||
|
||||
console.log(user);
|
||||
|
||||
if (user) {
|
||||
// await redirect("/home")
|
||||
await redirect("/home");
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export const createSpace = async (
|
|||
.values({ name: input, user: data.user.id });
|
||||
|
||||
revalidatePath("/home");
|
||||
return { success: true, data: 1 };
|
||||
return { success: true, data: resp.meta.last_row_id };
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (
|
||||
|
|
|
|||
13
apps/web/middleware.ts
Normal file
13
apps/web/middleware.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// middleware.js
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
requestHeaders.set("x-pathname", request.nextUrl.pathname);
|
||||
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: requestHeaders,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -21,10 +21,11 @@ interface Option {
|
|||
interface ComboboxWithCreateProps {
|
||||
options: Option[];
|
||||
onSelect: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
onSubmit: (newName: string) => void;
|
||||
placeholder?: string;
|
||||
emptyMessage?: string;
|
||||
createNewMessage?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const ComboboxWithCreate: React.FC<ComboboxWithCreateProps> = ({
|
||||
|
|
@ -34,9 +35,8 @@ const ComboboxWithCreate: React.FC<ComboboxWithCreateProps> = ({
|
|||
placeholder = "Select an option",
|
||||
emptyMessage = "No option found.",
|
||||
createNewMessage = "Create",
|
||||
className,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [value, setValue] = useState("");
|
||||
const [options, setOptions] = useState<Option[]>(initialOptions);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ const ComboboxWithCreate: React.FC<ComboboxWithCreateProps> = ({
|
|||
}, [initialOptions]);
|
||||
|
||||
return (
|
||||
<Command className="w-40 group">
|
||||
<Command className={cn("group", className)}>
|
||||
<CommandInput
|
||||
onChangeCapture={(e) => setInputValue(e.currentTarget.value)}
|
||||
placeholder={placeholder}
|
||||
|
|
@ -53,7 +53,9 @@ const ComboboxWithCreate: React.FC<ComboboxWithCreateProps> = ({
|
|||
/>
|
||||
<CommandList className="z-10 translate-y-12 translate-x-5 opacity-0 absolute group-focus-within:opacity-100 bg-secondary p-2 rounded-b-xl max-w-64">
|
||||
<CommandEmpty>
|
||||
{createNewMessage} "{inputValue}"
|
||||
<Button onClick={async () => onSubmit(inputValue)} variant="link">
|
||||
{createNewMessage} "{inputValue}"
|
||||
</Button>
|
||||
</CommandEmpty>
|
||||
<CommandGroup
|
||||
className="hidden group-focus-within:block"
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ const Command = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-bl-3xl bg-[#3C464D]",
|
||||
className,
|
||||
)}
|
||||
className={cn("flex h-full w-full flex-col overflow-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue