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 {
|
||||
children: React.ReactNode;
|
||||
className?: string
|
||||
}
|
||||
const DottedGridBackground = ({ children }: DottedGridBackgroundProps) => {
|
||||
const DottedGridBackground = ({ children, className }: DottedGridBackgroundProps) => {
|
||||
return (
|
||||
<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}
|
||||
</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;
|
||||
@@ -1,26 +1,23 @@
|
||||
import { type NextPage } from "next";
|
||||
import {type NextPage} from "next";
|
||||
import Head from "next/head";
|
||||
import DottedGridBackground from "../components/DottedGridBackground";
|
||||
import Badge from "../components/Badge";
|
||||
import Input from "../ui/input";
|
||||
import {useState} from "react";
|
||||
import DefaultLayout from "../layout/default";
|
||||
|
||||
const Home: NextPage = () => {
|
||||
const input = useState("")
|
||||
|
||||
return (
|
||||
<>
|
||||
<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>
|
||||
<DefaultLayout>
|
||||
<div id="title" className="flex gap-4 items-center">
|
||||
<div className="font-bold text-4xl text-[#C0C0C0]">AgentGPT</div>
|
||||
<Badge>Beta 🚀</Badge>
|
||||
|
||||
</div>
|
||||
</DottedGridBackground>
|
||||
</main>
|
||||
</>
|
||||
<Input model={input}/>
|
||||
</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