mirror of
https://github.com/aljazceru/AgentGPT.git
synced 2025-12-17 05:54:20 +01:00
🎨 Add header
This commit is contained in:
1
public/logo-white.svg
Normal file
1
public/logo-white.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 205 KiB |
@@ -2,11 +2,12 @@ import React from "react";
|
|||||||
|
|
||||||
interface DottedGridBackgroundProps {
|
interface DottedGridBackgroundProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
className?: string
|
||||||
}
|
}
|
||||||
const DottedGridBackground = ({ children }: DottedGridBackgroundProps) => {
|
const DottedGridBackground = ({ children, className }: DottedGridBackgroundProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col justify-center items-center bg-gradient-to-b from-gray-100 to-transparent w-screen h-screen background"
|
className={`${className ? className + " " : ""} background`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
92
src/components/Header.tsx
Normal file
92
src/components/Header.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// import { AnimatePresence, motion } from "framer-motion";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import {
|
||||||
|
FaAngleDown,
|
||||||
|
FaGithub,
|
||||||
|
FaHome,
|
||||||
|
FaLink,
|
||||||
|
FaSignOutAlt,
|
||||||
|
} from "react-icons/fa";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
// import { Dropdown, DropdownItem } from "@/ui/dropdown";
|
||||||
|
// import Loader from "@/ui/loader";
|
||||||
|
//
|
||||||
|
// import { useAuth } from "@/hooks/useAuth";
|
||||||
|
|
||||||
|
const Header: React.FC = () => {
|
||||||
|
// const { signOut, session, status } = useAuth();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// const authenticated = status == "authenticated" && (
|
||||||
|
// <Dropdown
|
||||||
|
// title={session?.user?.name || ""}
|
||||||
|
// icon={<FaAngleDown className="h-5 text-inherit" />}
|
||||||
|
// loader={false}
|
||||||
|
// >
|
||||||
|
// <h1 className="border-white/5 border-b-2 font-bold px-3 pb-1 text-md">
|
||||||
|
// {session?.user?.name}
|
||||||
|
// </h1>
|
||||||
|
//
|
||||||
|
// <DropdownItem
|
||||||
|
// icon={<FaSignOutAlt className="h-4 text-inherit text-white" />}
|
||||||
|
// onClick={signOut}
|
||||||
|
// >
|
||||||
|
// Sign Out
|
||||||
|
// </DropdownItem>
|
||||||
|
// {router.route != "/" && (
|
||||||
|
// <DropdownItem icon={<FaHome className="h-4 text-inherit" />}>
|
||||||
|
// <Link href="/">Home</Link>
|
||||||
|
// </DropdownItem>
|
||||||
|
// )}
|
||||||
|
// <DropdownItem icon={<FaLink className="h-4 text-inherit" />}>
|
||||||
|
// <a
|
||||||
|
// href="https://github.com/awtkns/confetti/issues/new"
|
||||||
|
// target="_blank"
|
||||||
|
// rel="noreferrer"
|
||||||
|
// >
|
||||||
|
// Report a bug
|
||||||
|
// </a>
|
||||||
|
// </DropdownItem>
|
||||||
|
// </Dropdown>
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const loading = status == "loading" && <Loader />;
|
||||||
|
//
|
||||||
|
// const unauthenticated =
|
||||||
|
// status == "unauthenticated" && router.route != "/auth" ? (
|
||||||
|
// <Link href="/auth">Sign In</Link>
|
||||||
|
// ) : (
|
||||||
|
// <Link href="/">Home</Link>
|
||||||
|
// );
|
||||||
|
|
||||||
|
const github = (
|
||||||
|
<a
|
||||||
|
href="https://github.com/reworkd/AgentGPT"
|
||||||
|
className="right-0 ml-0 block block text-white hover:text-yellow-500"
|
||||||
|
>
|
||||||
|
<span className="sr-only">Confetti on GitHub</span>
|
||||||
|
<FaGithub size="25" />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header className="z-50 w-full p-2 relative flex flex-row items-center justify-between align-middle">
|
||||||
|
<Image src="logo-white.svg" alt="yes" width={30} height={0} />
|
||||||
|
{/*<AnimatePresence>*/}
|
||||||
|
{/* <motion.div*/}
|
||||||
|
{/* initial={{ opacity: 0 }}*/}
|
||||||
|
{/* animate={{ opacity: 1 }}*/}
|
||||||
|
{/* transition={{ duration: 1, type: "spring" }}*/}
|
||||||
|
{/* className="ml-auto pr-4 text-lg text-white hover:text-yellow-500"*/}
|
||||||
|
{/* >*/}
|
||||||
|
{/* {authenticated || loading || unauthenticated}*/}
|
||||||
|
{/* </motion.div>*/}
|
||||||
|
{/*</AnimatePresence>*/}
|
||||||
|
{github}
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
33
src/layout/default.tsx
Normal file
33
src/layout/default.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// import Footer from "../components/Footer";
|
||||||
|
// import Header from "../components/Header";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import Head from "next/head";
|
||||||
|
import DottedGridBackground from "../components/DottedGridBackground";
|
||||||
|
import Header from "../components/Header";
|
||||||
|
|
||||||
|
interface LayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultLayout = (props: LayoutProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex min-h-screen flex-col min-h-screen bg-gradient-to-b from-[#2B2B2B] to-[#1F1F1F]"
|
||||||
|
>
|
||||||
|
<Head>
|
||||||
|
<title>Agent-GPT</title>
|
||||||
|
<meta name="description" content="Agent-GPT b Reworkd.ai"/>
|
||||||
|
<link rel="icon" href="/favicon.ico"/>
|
||||||
|
</Head>
|
||||||
|
<DottedGridBackground>
|
||||||
|
<Header />
|
||||||
|
<main className="flex flex-col justify-center items-center w-screen h-screen ">
|
||||||
|
{props.children}
|
||||||
|
</main>
|
||||||
|
</DottedGridBackground>
|
||||||
|
{/*<Footer />*/}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DefaultLayout;
|
||||||
@@ -2,25 +2,22 @@ import { type NextPage } from "next";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import DottedGridBackground from "../components/DottedGridBackground";
|
import DottedGridBackground from "../components/DottedGridBackground";
|
||||||
import Badge from "../components/Badge";
|
import Badge from "../components/Badge";
|
||||||
|
import Input from "../ui/input";
|
||||||
|
import {useState} from "react";
|
||||||
|
import DefaultLayout from "../layout/default";
|
||||||
|
|
||||||
const Home: NextPage = () => {
|
const Home: NextPage = () => {
|
||||||
|
const input = useState("")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DefaultLayout>
|
||||||
<Head>
|
|
||||||
<title>Agent-GPT</title>
|
|
||||||
<meta name="description" content="Agent-GPT b Reworkd.ai" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
</Head>
|
|
||||||
<main className="min-h-screen bg-gradient-to-b from-[#2B2B2B] to-[#1F1F1F]">
|
|
||||||
<DottedGridBackground>
|
|
||||||
<div id="title" className="flex gap-4 items-center">
|
<div id="title" className="flex gap-4 items-center">
|
||||||
<div className="font-bold text-4xl text-[#C0C0C0]">AgentGPT</div>
|
<div className="font-bold text-4xl text-[#C0C0C0]">AgentGPT</div>
|
||||||
<Badge>Beta 🚀</Badge>
|
<Badge>Beta 🚀</Badge>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</DottedGridBackground>
|
<Input model={input}/>
|
||||||
</main>
|
</DefaultLayout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
55
src/ui/button.tsx
Normal file
55
src/ui/button.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import type { ForwardedRef } from "react";
|
||||||
|
import { forwardRef, useState } from "react";
|
||||||
|
|
||||||
|
import Loader from "./loader";
|
||||||
|
|
||||||
|
export interface ButtonProps {
|
||||||
|
type?: "button" | "submit" | "reset";
|
||||||
|
className?: string;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
loader?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => Promise<void> | void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = forwardRef(
|
||||||
|
(props: ButtonProps, ref: ForwardedRef<HTMLButtonElement>) => {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
if (props.loader == true) setLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Promise.resolve(props.onClick?.(e)).then();
|
||||||
|
} catch (e) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
ref={ref}
|
||||||
|
type={props.type}
|
||||||
|
disabled={loading || props.disabled}
|
||||||
|
onClick={onClick}
|
||||||
|
className={
|
||||||
|
"text-white transition hover:text-yellow-500 " + props.className
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{loading ? (
|
||||||
|
<Loader />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{props.icon ? <div className="mr-2">{props.icon}</div> : null}
|
||||||
|
{props.children}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Button.displayName = "Button";
|
||||||
|
export default Button;
|
||||||
50
src/ui/dropdown.tsx
Normal file
50
src/ui/dropdown.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { Menu, Transition } from "@headlessui/react";
|
||||||
|
import { Fragment } from "react";
|
||||||
|
|
||||||
|
import type { ButtonProps } from "./button";
|
||||||
|
import Button from "./button";
|
||||||
|
|
||||||
|
interface DropdownProps extends ButtonProps {
|
||||||
|
title?: string | undefined;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Dropdown = (props: DropdownProps) => {
|
||||||
|
return (
|
||||||
|
<Menu as="div" className="right-0 ml-auto">
|
||||||
|
<Menu.Button as={Button} className={props.className} icon={props.icon}>
|
||||||
|
<span className="hidden md:flex">{props.title}</span>
|
||||||
|
</Menu.Button>
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
enter="transition ease-out duration-100"
|
||||||
|
enterFrom="transform opacity-0 scale-95"
|
||||||
|
enterTo="transform opacity-100 scale-100"
|
||||||
|
leave="transition ease-in duration-75"
|
||||||
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
|
leaveTo="transform opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Menu.Items className="absolute right-2 z-40 mt-2 w-56 origin-top-right divide-y rounded-lg bg-slate-900 p-1 shadow-sm focus:outline-none">
|
||||||
|
<div className="py-1">{props.children}</div>
|
||||||
|
</Menu.Items>
|
||||||
|
</Transition>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DropdownItem = (props: DropdownProps) => {
|
||||||
|
return (
|
||||||
|
<Menu.Item>
|
||||||
|
<div
|
||||||
|
className={`block cursor-pointer justify-between rounded px-3 py-2 text-sm text-white duration-200 hover:text-yellow-500
|
||||||
|
${props.className}`}
|
||||||
|
onClick={props.onClick}
|
||||||
|
>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{props.icon && <div className="mr-3">{props.icon}</div>}
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Menu.Item>
|
||||||
|
);
|
||||||
|
};
|
||||||
61
src/ui/input.tsx
Normal file
61
src/ui/input.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// import Loader from "@/motions/loader";
|
||||||
|
import type {
|
||||||
|
Dispatch,
|
||||||
|
ForwardedRef,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
KeyboardEventHandler,
|
||||||
|
SetStateAction,
|
||||||
|
} from "react";
|
||||||
|
import { forwardRef } from "react";
|
||||||
|
|
||||||
|
const SHARED_STYLE = "rounded-full ";
|
||||||
|
const STYLE =
|
||||||
|
SHARED_STYLE +
|
||||||
|
" border-gray-300 focus:border-yellow-500 focus:ring-yellow-500 ";
|
||||||
|
const ERROR_STYLE =
|
||||||
|
SHARED_STYLE + " border-red-500 focus:border-red-500 focus:ring-red-500 ";
|
||||||
|
|
||||||
|
export interface InputProps<T> extends InputHTMLAttributes<HTMLInputElement> {
|
||||||
|
model: [T, Dispatch<SetStateAction<T>>];
|
||||||
|
error?: [boolean, Dispatch<SetStateAction<boolean>>];
|
||||||
|
enterPressed?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Input = forwardRef(
|
||||||
|
(props: InputProps<string>, ref: ForwardedRef<HTMLInputElement>) => {
|
||||||
|
const { model, error, enterPressed, onKeyDown, className, ...otherProps } =
|
||||||
|
props;
|
||||||
|
const [isError, setIsError] = error || [false, () => undefined];
|
||||||
|
|
||||||
|
const keyDown: KeyboardEventHandler<HTMLInputElement> = (e) => {
|
||||||
|
try {
|
||||||
|
if (e.key === "Enter" && enterPressed) {
|
||||||
|
e.preventDefault();
|
||||||
|
enterPressed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onKeyDown) onKeyDown(e);
|
||||||
|
} catch (e) {
|
||||||
|
setIsError(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ref}
|
||||||
|
onKeyDown={keyDown}
|
||||||
|
value={model[0]}
|
||||||
|
onChange={(e) => {
|
||||||
|
model[1](e.target.value);
|
||||||
|
setIsError(false);
|
||||||
|
}}
|
||||||
|
className={(isError ? ERROR_STYLE : STYLE) + className}
|
||||||
|
{...otherProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Input.displayName = "input";
|
||||||
|
export default Input;
|
||||||
23
src/ui/loader.tsx
Normal file
23
src/ui/loader.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Ring } from "@uiball/loaders";
|
||||||
|
|
||||||
|
interface LoaderProps {
|
||||||
|
className?: string;
|
||||||
|
size?: number;
|
||||||
|
speed?: number;
|
||||||
|
lineWeight?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Loader: React.FC<LoaderProps> = ({
|
||||||
|
className,
|
||||||
|
size = 16,
|
||||||
|
speed = 2,
|
||||||
|
lineWeight = 7,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<Ring size={size} speed={speed} color="white" lineWeight={lineWeight} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Loader;
|
||||||
20
src/ui/popin.tsx
Normal file
20
src/ui/popin.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { motion } from "framer-motion";
|
||||||
|
import type { PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
interface MotionProps extends PropsWithChildren {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PopIn = (props: MotionProps) => (
|
||||||
|
<motion.div
|
||||||
|
initial={{ scale: 0 }}
|
||||||
|
animate={{ scale: 1 }}
|
||||||
|
transition={{ duration: 0.5, type: "spring" }}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
|
||||||
|
PopIn.displayName = "PopIn";
|
||||||
|
export default PopIn;
|
||||||
77
src/ui/toast.tsx
Normal file
77
src/ui/toast.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import * as ToastPrimitive from "@radix-ui/react-toast";
|
||||||
|
import cx from "classnames";
|
||||||
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
model: [boolean, Dispatch<SetStateAction<boolean>>];
|
||||||
|
onAction?: () => void;
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Toast = (props: Props) => {
|
||||||
|
const [open, setOpen] = props.model;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToastPrimitive.Provider swipeDirection={"right"}>
|
||||||
|
<ToastPrimitive.Root
|
||||||
|
open={open}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
className={cx(
|
||||||
|
"fixed inset-x-4 bottom-4 z-50 w-auto rounded-2xl shadow-lg md:right-4 md:left-auto md:w-full md:max-w-sm",
|
||||||
|
"bg-slate-900",
|
||||||
|
"radix-state-open:animate-toast-slide-in-bottom md:radix-state-open:animate-toast-slide-in-right",
|
||||||
|
"radix-state-closed:animate-toast-hide",
|
||||||
|
"radix-swipe-direction-right:radix-swipe-end:animate-toast-swipe-out-x",
|
||||||
|
"radix-swipe-direction-right:translate-x-radix-toast-swipe-move-x",
|
||||||
|
"radix-swipe-direction-down:radix-swipe-end:animate-toast-swipe-out-y",
|
||||||
|
"radix-swipe-direction-down:translate-y-radix-toast-swipe-move-y",
|
||||||
|
"radix-swipe-cancel:translate-x-0 radix-swipe-cancel:duration-200 radix-swipe-cancel:ease-[ease]",
|
||||||
|
"focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex">
|
||||||
|
<div className="flex w-0 flex-1 items-center py-4 pl-5">
|
||||||
|
<div className="radix w-full">
|
||||||
|
<ToastPrimitive.Title className="text-lg font-medium text-white">
|
||||||
|
{props.title}
|
||||||
|
</ToastPrimitive.Title>
|
||||||
|
{props.description && (
|
||||||
|
<ToastPrimitive.Description className="dark:text-gray-10 text-md mt-1 rounded-md bg-slate-800/50 p-1 text-white">
|
||||||
|
<pre className="overflow-hidden text-ellipsis">
|
||||||
|
{props.description}
|
||||||
|
</pre>
|
||||||
|
</ToastPrimitive.Description>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mx-4 flex items-center justify-center py-4">
|
||||||
|
<div className="flex flex-col ">
|
||||||
|
{props.onAction && (
|
||||||
|
<ToastPrimitive.Action
|
||||||
|
altText="copy"
|
||||||
|
className="text-md flex w-full items-center justify-center rounded-2xl border border-transparent px-3 py-2 font-medium text-yellow-500 hover:bg-white/20 "
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (props.onAction) props.onAction();
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</ToastPrimitive.Action>
|
||||||
|
)}
|
||||||
|
<ToastPrimitive.Close className="text-md flex w-full items-center justify-center rounded-2xl border border-transparent px-3 py-2 font-medium text-white hover:bg-white/20 ">
|
||||||
|
Close
|
||||||
|
</ToastPrimitive.Close>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ToastPrimitive.Root>
|
||||||
|
|
||||||
|
<ToastPrimitive.Viewport />
|
||||||
|
</ToastPrimitive.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Toast;
|
||||||
Reference in New Issue
Block a user