Create new site design

This commit is contained in:
Ategon 2025-01-17 05:19:57 -05:00
parent e908237d84
commit a3870224fa
29 changed files with 718 additions and 616 deletions

BIN
public/images/d2jam.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

3
src/app/about/page.tsx Normal file
View file

@ -0,0 +1,3 @@
export default function AboutPage() {
return <p>About page coming soon</p>;
}

3
src/app/games/page.tsx Normal file
View file

@ -0,0 +1,3 @@
export default function GamesPage() {
return <p>Games page coming soon</p>;
}

View file

@ -4,6 +4,8 @@ import "./globals.css";
import Navbar from "../components/navbar";
import Providers from "./providers";
import { ToastContainer } from "react-toastify";
import { Spacer } from "@nextui-org/react";
import Footer from "@/components/footer";
const inter = Inter({ subsets: ["latin"] });
@ -22,9 +24,13 @@ export default function RootLayout({
<body className={inter.className}>
<Providers>
<div className="dark">
<div className="bg-zinc-100 dark:bg-zinc-950 min-h-screen">
<div className="bg-gradient-to-br from-[#181818] to-[#222] min-h-screen flex flex-col">
<Navbar />
<div className="max-w-8xl mx-auto">{children}</div>
<Spacer y={5} />
<div className="max-w-8xl mx-auto flex-grow w-full">
{children}
</div>
<Footer />
<ToastContainer />
</div>
</div>

View file

@ -48,6 +48,7 @@ export default function UserPage() {
body: JSON.stringify({ username: username, password: password }),
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
}
);
@ -57,7 +58,15 @@ export default function UserPage() {
return;
}
const { token, user } = await response.json();
const { user } = await response.json();
const token = response.headers.get("Authorization");
console.log(response.headers);
if (!token) {
toast.error("Failed to retreive access token");
setPassword("");
return;
}
document.cookie = `token=${token}`;
document.cookie = `user=${user.slug}`;

View file

@ -1,46 +1,16 @@
import { Image } from "@nextui-org/image";
import { Button } from "@nextui-org/button";
import { SiDiscord } from "@icons-pack/react-simple-icons";
import { Link } from "@nextui-org/react";
import Posts from "@/components/posts";
import Timers from "@/components/timers";
import JamHeader from "@/components/jam-header";
export default async function Home() {
return (
<div className="w-full">
<div className="fixed left-0 top-0 w-full h-full z-0">
<Image
src="/images/bg.jpg"
alt="Home background"
className="object-cover w-full h-full"
radius="none"
loading="eager"
removeWrapper
/>
<div className="absolute left-0 top-0 w-full h-full bg-gradient-to-r from-black/50 to-transparent z-10" />
<div className="flex justify-between flex-wrap">
<div className="md:w-2/3">
<JamHeader />
<Posts />
</div>
<div className="z-10 relative flex w-full flex-wrap">
<div>
<div className="flex flex-col gap-4 py-4 sm:py-8 md:py-12 pl-16">
<h1 className="text-3xl sm:text-4xl md:text-5xl">Dare2Jam</h1>
<p className="text-lg sm:text-xl">April 4th - 7th</p>
<div className="flex gap-2">
<Link href="https://discord.gg/rfmKzM6ASw" target="_blank">
<Button
variant="bordered"
className="border-white/50 text-white"
startContent={<SiDiscord />}
>
Join the Discord
</Button>
</Link>
</div>
</div>
<Posts />
</div>
<div className="w-1/3 flex justify-end py-4 sm:py-8 md:py-12 flex-grow">
<Timers />
</div>
<div>
<Timers />
</div>
</div>
);

View file

@ -28,6 +28,7 @@ export default function UserPage() {
: `http://localhost:3005/api/v1/self?username=${getCookie("user")}`,
{
headers: { authorization: `Bearer ${getCookie("token")}` },
credentials: "include",
}
);

View file

@ -1,9 +1,7 @@
"use client";
import { Button, Form, Input } from "@nextui-org/react";
import { redirect } from "next/navigation";
import { useState } from "react";
import { toast } from "react-toastify";
export default function UserPage() {
const [username, setUsername] = useState("");
@ -83,13 +81,13 @@ export default function UserPage() {
return;
}
const { token, user } = await response.json();
document.cookie = `token=${token}`;
document.cookie = `user=${user.slug}`;
// const { token, user } = await response.json();
// document.cookie = `token=${token}`;
// document.cookie = `user=${user.slug}`;
toast.success("Successfully signed up");
// toast.success("Successfully signed up");
redirect("/");
// redirect("/");
}}
>
<Input

View file

@ -1,9 +1,34 @@
import User from "../../../components/user";
"use client";
import { UserType } from "@/types/UserType";
import { useParams } from "next/navigation";
import { useEffect, useState } from "react";
export default function UserPage() {
const [user, setUser] = useState<UserType>();
const { slug } = useParams();
useEffect(() => {
const fetchUser = async () => {
const response = await fetch(
process.env.NEXT_PUBLIC_MODE === "PROD"
? `https://d2jam.com/api/v1/user?slug=${slug}`
: `http://localhost:3005/api/v1/user?slug=${slug}`
);
setUser(await response.json());
};
fetchUser();
}, [slug]);
return (
<div>
<User />
{user && (
<div>
<p>{user.name}</p>
</div>
)}
</div>
);
return <div></div>;
}

View file

@ -1,8 +0,0 @@
"use client";
export default function Announcements() {
return (
<div></div>
);
}

View file

@ -0,0 +1,20 @@
import IconLink from "../link-components/IconLink";
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
export default function Footer() {
return (
<div className="p-8 bg-[#222] mt-8 border-t-2 border-white/15">
<div className="flex justify-between">
<div></div>
<div className="flex gap-3">
<IconLink icon={<SiGithub />} href="https://github.com/Dare2Jam" />
<IconLink
icon={<SiForgejo />}
href="https://git.edikoyo.com/Ategon/Jamjar"
/>
<IconLink icon={<SiDiscord />} href="https://discord.d2jam.com" />
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,15 @@
import { Calendar } from "lucide-react";
export default function JamHeader() {
return (
<div className="bg-[#124a88] flex rounded-2xl overflow-hidden">
<div className="bg-[#1892b3] p-4 px-6 flex items-center gap-2 font-bold">
<Calendar />
<p>Dare2Jam 1</p>
</div>
<div className="p-4 px-6 font-bold">
<p>April 4th - 7th</p>
</div>
</div>
);
}

View file

@ -0,0 +1,25 @@
import { Button } from "@nextui-org/react";
import { ReactNode } from "react";
interface ButtonActionProps {
icon?: ReactNode;
onPress: () => void;
name: string;
}
export default function ButtonAction({
icon,
onPress,
name,
}: ButtonActionProps) {
return (
<Button
endContent={icon}
className="text-white border-white/50 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
onPress={onPress}
>
{name}
</Button>
);
}

View file

@ -0,0 +1,25 @@
import { Button, Link } from "@nextui-org/react";
import { ReactNode } from "react";
interface ButtonLinkProps {
icon?: ReactNode;
href: string;
name: string;
}
export default function ButtonLink({ icon, href, name }: ButtonLinkProps) {
return (
<Link
href={href}
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-110 ease-in-out"
>
<Button
endContent={icon}
className="text-white border-white/50 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
{name}
</Button>
</Link>
);
}

View file

@ -0,0 +1,18 @@
import { Link } from "@nextui-org/react";
import { ReactNode } from "react";
interface IconLinkProps {
icon: ReactNode;
href: string;
}
export default function IconLink({ icon, href }: IconLinkProps) {
return (
<Link
href={href}
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125"
>
{icon}
</Link>
);
}

View file

@ -0,0 +1,17 @@
import { Link as BaseLink } from "@nextui-org/react";
interface LinkProps {
name: string;
href: string;
}
export default function Link({ name, href }: LinkProps) {
return (
<BaseLink
href={href}
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-110"
>
{name}
</BaseLink>
);
}

View file

@ -0,0 +1,111 @@
"use client";
import {
Image,
Link,
NavbarBrand,
Navbar as NavbarBase,
NavbarContent,
} from "@nextui-org/react";
import NavbarButtonLink from "./NavbarButtonLink";
import { LogInIcon, NotebookPen } from "lucide-react";
import NextImage from "next/image";
import { useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import { getCookie, hasCookie } from "@/helpers/cookie";
import { getCurrentJam } from "@/helpers/jam";
import { JamType } from "@/types/JamType";
import { UserType } from "@/types/UserType";
import MobileNavbarUser from "./MobileNavbarUser";
export default function MobileNavbar() {
const pathname = usePathname();
const [jam, setJam] = useState<JamType | null>();
const [isInJam, setIsInJam] = useState<boolean>();
const [user, setUser] = useState<UserType>();
useEffect(() => {
loadUser();
async function loadUser() {
const currentJam = await getCurrentJam();
setJam(currentJam);
if (!hasCookie("token")) {
setUser(undefined);
return;
}
const response = await fetch(
process.env.NEXT_PUBLIC_MODE === "PROD"
? `https://d2jam.com/api/v1/self?username=${getCookie("user")}`
: `http://localhost:3005/api/v1/self?username=${getCookie("user")}`,
{
headers: { authorization: `Bearer ${getCookie("token")}` },
credentials: "include",
}
);
const user = await response.json();
if (
currentJam &&
user.jams.filter((jam: JamType) => jam.id == currentJam.id).length > 0
) {
setIsInJam(true);
} else {
setIsInJam(false);
}
if (response.status == 200) {
setUser(user);
} else {
setUser(undefined);
}
}
}, [pathname]);
return (
<NavbarBase maxWidth="2xl" className="bg-[#222] p-1" isBordered height={80}>
{/* Left side navbar items */}
<NavbarContent justify="start" className="gap-10">
<NavbarBrand className="flex-grow-0">
<Link
href="/"
className="duration-500 ease-in-out transition-all transform hover:scale-110"
>
<Image
as={NextImage}
src="/images/d2jam.png"
className="min-w-[70px]"
alt="Dare2Jam logo"
width={70}
height={59.7}
/>
</Link>
</NavbarBrand>
</NavbarContent>
{/* Right side navbar items */}
<NavbarContent justify="end" className="gap-4">
{!user && (
<NavbarButtonLink icon={<LogInIcon />} name="Log In" href="/login" />
)}
{!user && (
<NavbarButtonLink
icon={<NotebookPen />}
name="Sign Up"
href="/signup"
/>
)}
{user && (
<MobileNavbarUser
user={user}
isInJam={isInJam}
setIsInJam={setIsInJam}
jam={jam}
/>
)}
</NavbarContent>
</NavbarBase>
);
}

View file

@ -0,0 +1,102 @@
import {
Avatar,
Dropdown,
DropdownItem,
DropdownMenu,
DropdownTrigger,
NavbarItem,
} from "@nextui-org/react";
import { UserType } from "@/types/UserType";
import { getCurrentJam, joinJam } from "@/helpers/jam";
import { JamType } from "@/types/JamType";
import { Dispatch, SetStateAction } from "react";
import { toast } from "react-toastify";
interface NavbarUserProps {
user: UserType;
jam?: JamType | null;
setIsInJam: Dispatch<SetStateAction<boolean | undefined>>;
isInJam?: boolean;
}
export default function MobileNavbarUser({
user,
jam,
setIsInJam,
isInJam,
}: NavbarUserProps) {
return (
<NavbarItem>
<Dropdown>
<DropdownTrigger>
<Avatar src={user.profilePicture} className="cursor-pointer" />
</DropdownTrigger>
<DropdownMenu>
{jam && isInJam ? (
<DropdownItem
key="create-game"
href="/create-game"
className="text-black"
>
Create Game
</DropdownItem>
) : null}
{jam && !isInJam ? (
<DropdownItem
key="join-event"
className="text-black"
onPress={async () => {
try {
const currentJam = await getCurrentJam();
if (!currentJam) {
toast.error("There is no jam to join");
return;
}
if (await joinJam(currentJam.id)) {
setIsInJam(true);
}
} catch (error) {
console.error("Error during join process:", error);
}
}}
>
Join Event
</DropdownItem>
) : null}
<DropdownItem
key="create-post"
href="/create-post"
className="text-black"
>
Create Post
</DropdownItem>
<DropdownItem
key="profile"
className="text-black"
href={`/u/${user.slug}`}
>
Profile
</DropdownItem>
<DropdownItem
showDivider
key="settings"
className="text-black"
href="/settings"
>
Settings
</DropdownItem>
<DropdownItem
key="logout"
color="danger"
className="text-danger"
href="/logout"
>
Logout
</DropdownItem>
</DropdownMenu>
</Dropdown>
</NavbarItem>
);
}

View file

@ -0,0 +1,21 @@
import { NavbarItem } from "@nextui-org/react";
import { ReactNode } from "react";
import ButtonAction from "../link-components/ButtonAction";
interface NavbarButtonActionProps {
icon?: ReactNode;
onPress: () => void;
name: string;
}
export default function NavbarButtonAction({
icon,
onPress,
name,
}: NavbarButtonActionProps) {
return (
<NavbarItem>
<ButtonAction icon={icon} onPress={onPress} name={name} />
</NavbarItem>
);
}

View file

@ -0,0 +1,21 @@
import { NavbarItem } from "@nextui-org/react";
import { ReactNode } from "react";
import ButtonLink from "../link-components/ButtonLink";
interface NavbarButtonLinkProps {
icon?: ReactNode;
href: string;
name: string;
}
export default function NavbarButtonLink({
icon,
href,
name,
}: NavbarButtonLinkProps) {
return (
<NavbarItem>
<ButtonLink icon={icon} href={href} name={name} />
</NavbarItem>
);
}

View file

@ -0,0 +1,16 @@
import { NavbarItem } from "@nextui-org/react";
import { ReactNode } from "react";
import IconLink from "../link-components/IconLink";
interface NavbarIconLinkProps {
icon: ReactNode;
href: string;
}
export default function NavbarIconLink({ icon, href }: NavbarIconLinkProps) {
return (
<NavbarItem>
<IconLink icon={icon} href={href} />
</NavbarItem>
);
}

View file

@ -0,0 +1,15 @@
import { NavbarItem } from "@nextui-org/react";
import Link from "../link-components/Link";
interface NavbarLinkProps {
name: string;
href: string;
}
export default function NavbarLink({ name, href }: NavbarLinkProps) {
return (
<NavbarItem>
<Link name={name} href={href} />
</NavbarItem>
);
}

View file

@ -0,0 +1,9 @@
import { Input, NavbarItem } from "@nextui-org/react";
export default function NavbarSearchbar() {
return (
<NavbarItem>
<Input placeholder="Search" />
</NavbarItem>
);
}

View file

@ -0,0 +1,152 @@
"use client";
import {
Image,
Link,
NavbarBrand,
Navbar as NavbarBase,
NavbarContent,
Divider,
} from "@nextui-org/react";
import NavbarLink from "./NavbarLink";
import NavbarSearchbar from "./NavbarSearchbar";
import NavbarButtonLink from "./NavbarButtonLink";
import {
CalendarPlus,
Gamepad2,
LogInIcon,
NotebookPen,
SquarePen,
} from "lucide-react";
import NextImage from "next/image";
import { useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import { getCookie, hasCookie } from "@/helpers/cookie";
import { getCurrentJam, joinJam } from "@/helpers/jam";
import { JamType } from "@/types/JamType";
import { UserType } from "@/types/UserType";
import NavbarUser from "./PCNavbarUser";
import NavbarButtonAction from "./NavbarButtonAction";
import { toast } from "react-toastify";
export default function PCNavbar() {
const pathname = usePathname();
const [jam, setJam] = useState<JamType | null>();
const [isInJam, setIsInJam] = useState<boolean>();
const [user, setUser] = useState<UserType>();
useEffect(() => {
loadUser();
async function loadUser() {
const currentJam = await getCurrentJam();
setJam(currentJam);
if (!hasCookie("token")) {
setUser(undefined);
return;
}
const response = await fetch(
process.env.NEXT_PUBLIC_MODE === "PROD"
? `https://d2jam.com/api/v1/self?username=${getCookie("user")}`
: `http://localhost:3005/api/v1/self?username=${getCookie("user")}`,
{
headers: { authorization: `Bearer ${getCookie("token")}` },
credentials: "include",
}
);
const user = await response.json();
if (
currentJam &&
user.jams.filter((jam: JamType) => jam.id == currentJam.id).length > 0
) {
setIsInJam(true);
} else {
setIsInJam(false);
}
if (response.status == 200) {
setUser(user);
} else {
setUser(undefined);
}
}
}, [pathname]);
return (
<NavbarBase maxWidth="2xl" className="bg-[#222] p-1" isBordered height={80}>
{/* Left side navbar items */}
<NavbarContent justify="start" className="gap-10">
<NavbarBrand className="flex-grow-0">
<Link
href="/"
className="duration-500 ease-in-out transition-all transform hover:scale-110"
>
<Image
as={NextImage}
src="/images/d2jam.png"
className="min-w-[70px]"
alt="Dare2Jam logo"
width={70}
height={59.7}
/>
</Link>
</NavbarBrand>
<NavbarLink href="/about" name="About" />
<NavbarLink href="/games" name="Games" />
</NavbarContent>
{/* Right side navbar items */}
<NavbarContent justify="end" className="gap-4">
<NavbarSearchbar />
{user && <Divider orientation="vertical" className="h-1/2" />}
{user && jam && isInJam && (
<NavbarButtonLink
icon={<Gamepad2 />}
name="Create Game"
href="/create-game"
/>
)}
{user && jam && !isInJam && (
<NavbarButtonAction
icon={<CalendarPlus />}
name="Join jam"
onPress={async () => {
const currentJam = await getCurrentJam();
if (!currentJam) {
toast.error("There is no jam to join");
return;
}
if (await joinJam(currentJam.id)) {
setIsInJam(true);
}
}}
/>
)}
{user && (
<NavbarButtonLink
icon={<SquarePen />}
name="Create Post"
href="/create-post"
/>
)}
<Divider orientation="vertical" className="h-1/2" />
{!user && (
<NavbarButtonLink icon={<LogInIcon />} name="Log In" href="/login" />
)}
{!user && (
<NavbarButtonLink
icon={<NotebookPen />}
name="Sign Up"
href="/signup"
/>
)}
{user && <NavbarUser user={user} />}
</NavbarContent>
</NavbarBase>
);
}

View file

@ -0,0 +1,50 @@
import {
Avatar,
Dropdown,
DropdownItem,
DropdownMenu,
DropdownTrigger,
NavbarItem,
} from "@nextui-org/react";
import { UserType } from "@/types/UserType";
interface NavbarUserProps {
user: UserType;
}
export default function PCNavbarUser({ user }: NavbarUserProps) {
return (
<NavbarItem>
<Dropdown>
<DropdownTrigger>
<Avatar src={user.profilePicture} className="cursor-pointer" />
</DropdownTrigger>
<DropdownMenu>
<DropdownItem
key="profile"
className="text-black"
href={`/u/${user.slug}`}
>
Profile
</DropdownItem>
<DropdownItem
showDivider
key="settings"
className="text-black"
href="/settings"
>
Settings
</DropdownItem>
<DropdownItem
key="logout"
color="danger"
className="text-danger"
href="/logout"
>
Logout
</DropdownItem>
</DropdownMenu>
</Dropdown>
</NavbarItem>
);
}

View file

@ -1,531 +1,20 @@
"use client";
import {
Navbar as NavbarBase,
NavbarBrand,
NavbarContent,
NavbarItem,
} from "@nextui-org/navbar";
import { Link } from "@nextui-org/link";
import { Divider } from "@nextui-org/divider";
import {
Avatar,
Button,
Dropdown,
DropdownItem,
DropdownMenu,
DropdownTrigger,
Image,
Tooltip,
} from "@nextui-org/react";
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
import {
CalendarPlus,
Gamepad2,
LogInIcon,
Menu,
NotebookPen,
SquarePen,
} from "lucide-react";
import { useEffect, useState } from "react";
import { hasCookie, getCookie } from "@/helpers/cookie";
import { usePathname } from "next/navigation";
import { UserType } from "@/types/UserType";
import { getCurrentJam, joinJam } from "@/helpers/jam";
import { toast } from "react-toastify";
import { JamType } from "@/types/JamType";
import PCNavbar from "./PCNavbar";
import MobileNavbar from "./MobileNavbar";
export default function Navbar() {
const [user, setUser] = useState<UserType>();
const pathname = usePathname();
const [isMobile, setIsMobile] = useState(false);
const [jam, setJam] = useState<JamType | null>();
const [isInJam, setIsInJam] = useState<boolean>();
useEffect(() => {
loadUser();
async function loadUser() {
const currentJam = await getCurrentJam();
setJam(currentJam);
if (!hasCookie("token")) {
setUser(undefined);
return;
}
const response = await fetch(
process.env.NEXT_PUBLIC_MODE === "PROD"
? `https://d2jam.com/api/v1/self?username=${getCookie("user")}`
: `http://localhost:3005/api/v1/self?username=${getCookie("user")}`,
{
headers: { authorization: `Bearer ${getCookie("token")}` },
}
);
const user = await response.json();
if (
currentJam &&
user.jams.filter((jam: JamType) => jam.id == currentJam.id).length > 0
) {
setIsInJam(true);
} else {
setIsInJam(false);
}
if (response.status == 200) {
setUser(user);
} else {
setUser(undefined);
}
}
}, [pathname]);
const [isMobile, setIsMobile] = useState<boolean>(false);
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth <= 768); // Adjust breakpoint as needed
setIsMobile(window.innerWidth <= 768);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return (
<NavbarBase
shouldHideOnScroll
maxWidth="2xl"
className="bg-transparent p-1"
>
<NavbarBrand>
<Link
href="/"
className="duration-500 ease-in-out transition-all transform hover:scale-110"
>
<Image src="/images/dare2jam.png" alt="Dare2Jam logo" width={80} />
</Link>
</NavbarBrand>
<NavbarContent justify="end">
{isMobile ? (
user ? (
<Dropdown>
<DropdownTrigger>
<Avatar src={user.profilePicture} />
</DropdownTrigger>
<DropdownMenu className="text-black">
{jam && isInJam ? (
<DropdownItem key="create-game" href="/create-game">
Create Game
</DropdownItem>
) : null}
{jam && !isInJam ? (
<DropdownItem
key="join-event"
onPress={async () => {
try {
const currentJam = await getCurrentJam();
if (!currentJam) {
toast.error("There is no jam to join");
return;
}
if (await joinJam(currentJam.id)) {
setIsInJam(true);
}
} catch (error) {
console.error("Error during join process:", error);
}
}}
>
Join Event
</DropdownItem>
) : null}
<DropdownItem key="create-post" href="/create-post">
Create Post
</DropdownItem>
<DropdownItem
key="profile"
className="text-black"
href={`/u/${user.slug}`}
>
Profile
</DropdownItem>
<DropdownItem
showDivider
key="settings"
className="text-black"
href="/settings"
>
Settings
</DropdownItem>
<DropdownItem
key="github"
href="https://github.com/Ategon/Jamjar"
>
GitHub
</DropdownItem>
<DropdownItem
key="forgejo"
href="https://git.edikoyo.com/Ategon/Jamjar"
>
Forgejo
</DropdownItem>
<DropdownItem
key="discord"
href="https://discord.gg/rfmKzM6ASw"
>
Discord
</DropdownItem>
<DropdownItem key="logout" color="danger" href="/logout">
Logout
</DropdownItem>
</DropdownMenu>
</Dropdown>
) : (
<Dropdown>
<DropdownTrigger>
<Menu />
</DropdownTrigger>
<DropdownMenu className="text-black">
<DropdownItem
key="github"
href="https://github.com/Ategon/Jamjar"
>
GitHub
</DropdownItem>
<DropdownItem
key="forgejo"
href="https://git.edikoyo.com/Ategon/Jamjar"
>
Forgejo
</DropdownItem>
<DropdownItem
key="discord"
href="https://discord.gg/rfmKzM6ASw"
>
Discord
</DropdownItem>
<DropdownItem key="login" href="/login">
Log In
</DropdownItem>
<DropdownItem key="signup" href="/signup">
Sign Up
</DropdownItem>
</DropdownMenu>
</Dropdown>
)
) : (
<div className="flex gap-3 items-center">
{user && jam && isInJam && (
<NavbarItem>
<Link href="/create-game">
<Button
endContent={<Gamepad2 />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Create Game
</Button>
</Link>
</NavbarItem>
)}
{user && jam && !isInJam && (
<NavbarItem>
<Button
endContent={<CalendarPlus />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
onPress={async () => {
const currentJam = await getCurrentJam();
if (!currentJam) {
toast.error("There is no jam to join");
return;
}
if (await joinJam(currentJam.id)) {
setIsInJam(true);
}
}}
>
Join Jam
</Button>
</NavbarItem>
)}
{user && (
<NavbarItem className="flex items-center">
<Link href="/create-post">
<Button
endContent={<SquarePen />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Create Post
</Button>
</Link>
</NavbarItem>
)}
<NavbarItem>
<Tooltip
delay={1000}
content={
<div className="px-1 py-2 text-black text-center">
<div className="text-small font-bold">GitHub</div>
<div className="text-tiny">Source Code</div>
</div>
}
>
<Link
href="https://github.com/Dare2Jam/"
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125 hover:text-red-100"
isExternal
>
<SiGithub title="" />
</Link>
</Tooltip>
</NavbarItem>
<NavbarItem>
<Tooltip
delay={1000}
content={
<div className="px-1 py-2 text-black text-center">
<div className="text-small font-bold">Forgejo</div>
<div className="text-tiny">Source Code</div>
</div>
}
>
<Link
href="https://git.edikoyo.com/Ategon/Jamjar"
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125 hover:text-red-100"
isExternal
>
<SiForgejo title="" />
</Link>
</Tooltip>
</NavbarItem>
<NavbarItem>
<Link
href="https://discord.gg/rfmKzM6ASw"
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125 hover:text-indigo-100"
isExternal
>
<SiDiscord />
</Link>
</NavbarItem>
<Divider orientation="vertical" className="h-1/2" />
{!user ? (
<div className="flex gap-3 items-center">
<NavbarItem>
<Link href="/login">
<Button
endContent={<LogInIcon />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Log In
</Button>
</Link>
</NavbarItem>
<NavbarItem>
<Link href="/signup">
<Button
endContent={<NotebookPen />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Sign up
</Button>
</Link>
</NavbarItem>
</div>
) : (
<Dropdown>
<DropdownTrigger>
<Avatar src={user.profilePicture} />
</DropdownTrigger>
<DropdownMenu>
<DropdownItem
key="profile"
className="text-black"
href={`/u/${user.slug}`}
>
Profile
</DropdownItem>
<DropdownItem
showDivider
key="settings"
className="text-black"
href="/settings"
>
Settings
</DropdownItem>
<DropdownItem
key="logout"
color="danger"
className="text-danger"
href="/logout"
>
Logout
</DropdownItem>
</DropdownMenu>
</Dropdown>
)}
</div>
)}
</NavbarContent>
</NavbarBase>
);
return isMobile ? <MobileNavbar /> : <PCNavbar />;
}
/*
{isMobile ? (
// Mobile view
user ? (
<Dropdown>
<DropdownTrigger>
<Avatar src={user.profilePicture} />
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="create-post" href="/create-post">
Create Post
</DropdownItem>
<DropdownItem key="logout" color="danger" href="/logout">
Logout
</DropdownItem>
</DropdownMenu>
</Dropdown>
) : (
<Dropdown>
<DropdownTrigger>
<Button auto flat className="text-white">
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem key="github" href="https://github.com/Ategon/Jamjar" isExternal>
GitHub
</DropdownItem>
<DropdownItem key="forgejo" href="https://git.edikoyo.com/Ategon/Jamjar" isExternal>
Forgejo
</DropdownItem>
<DropdownItem key="discord" href="https://discord.gg/rfmKzM6ASw" isExternal>
Discord
</DropdownItem>
<DropdownItem key="login" href="/login">
Log In
</DropdownItem>
<DropdownItem key="signup" href="/signup">
Sign Up
</DropdownItem>
</DropdownMenu>
</Dropdown>
)
) : (
user && (
<NavbarItem>
<Link href="/create-post">
<Button
endContent={<SquarePen />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Create Post
</Button>
</Link>
<Spacer x={32} />
</NavbarItem>
)
<NavbarItem>
<Tooltip
delay={1000}
content={
<div className="px-1 py-2 text-black text-center">
<div className="text-small font-bold">GitHub</div>
<div className="text-tiny">Source Code</div>
</div>
}
>
<Link
href="https://github.com/Dare2Jam/"
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125 hover:text-red-100"
isExternal
>
<SiGithub title="" />
</Link>
</Tooltip>
</NavbarItem>
<NavbarItem>
<Tooltip
delay={1000}
content={
<div className="px-1 py-2 text-black text-center">
<div className="text-small font-bold">Forgejo</div>
<div className="text-tiny">Source Code</div>
</div>
}
>
<Link
href="https://git.edikoyo.com/Ategon/Jamjar"
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125 hover:text-red-100"
isExternal
>
<SiForgejo title="" />
</Link>
</Tooltip>
</NavbarItem>
<NavbarItem>
<Link
href="https://discord.gg/rfmKzM6ASw"
className="text-white flex justify-center duration-500 ease-in-out transition-all transform hover:scale-125 hover:text-indigo-100"
isExternal
>
<SiDiscord />
</Link>
</NavbarItem>
<Divider orientation="vertical" className="h-1/2" />
{!user ? (
<div className="flex gap-3 items-center">
<NavbarItem>
<Link href="/login">
<Button
endContent={<LogInIcon />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Log In
</Button>
</Link>
</NavbarItem>
<NavbarItem>
<Link href="/signup">
<Button
endContent={<NotebookPen />}
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
variant="bordered"
>
Sign up
</Button>
</Link>
</NavbarItem>
</div>
) : (
<Dropdown>
<DropdownTrigger>
<Avatar src={user.profilePicture} />
</DropdownTrigger>
<DropdownMenu>
<DropdownItem
key="logout"
color="danger"
className="text-danger"
href="/logout"
>
Logout
</DropdownItem>
</DropdownMenu>
</Dropdown>
)}
)
</NavbarContent> */

View file

@ -1,12 +1,13 @@
import { Avatar, Card, CardBody, Spacer } from "@nextui-org/react";
import { Avatar, Button, Card, CardBody, Spacer } from "@nextui-org/react";
import { formatDistance } from "date-fns";
import Link from "next/link";
import { PostType } from "@/types/PostType";
import { Heart, MessageCircle } from "lucide-react";
export default function PostCard({ post }: { post: PostType }) {
return (
<Card className="bg-opacity-60">
<CardBody>
<CardBody className="p-5">
<p className="text-2xl">{post.title}</p>
<div className="flex items-center gap-3 text-xs text-default-500 pt-1">
@ -35,14 +36,14 @@ export default function PostCard({ post }: { post: PostType }) {
<Spacer y={4} />
{/* <div className="flex gap-3">
<Button size="sm">
<div className="flex gap-3">
<Button size="sm" variant="bordered">
<Heart size={16} /> {post.likers.length}
</Button>
<Button size="sm">
<Button size="sm" variant="bordered">
<MessageCircle size={16} /> {0}
</Button>
</div> */}
</div>
</CardBody>
</Card>
);

View file

@ -3,6 +3,7 @@
import { useEffect, useState } from "react";
import PostCard from "./PostCard";
import { PostType } from "@/types/PostType";
import { Button } from "@nextui-org/react";
export default function Posts() {
const [posts, setPosts] = useState<PostType[]>();
@ -21,13 +22,30 @@ export default function Posts() {
}, []);
return (
<div className="flex flex-col gap-3 p-4">
{posts &&
posts.map((post) => (
<div key={post.id}>
<PostCard post={post} />
</div>
))}
<div>
<div className="flex justify-between p-4 pb-0">
<div className="flex gap-2">
<Button size="sm" className="text-xs" variant="faded">
Newest
</Button>
<Button size="sm" className="text-xs" variant="faded">
All Tags
</Button>
</div>
<div>
<Button size="sm" className="text-xs" variant="faded">
Cozy
</Button>
</div>
</div>
<div className="flex flex-col gap-3 p-4">
{posts &&
posts.map((post) => (
<div key={post.id}>
<PostCard post={post} />
</div>
))}
</div>
</div>
);
return <div></div>;

View file

@ -1,30 +0,0 @@
"use client";
// import { useEffect, useState } from "react";
// import { useParams } from "next/navigation";
export default function User() {
// const [user, setUser] = useState();
// const { slug } = useParams();
// useEffect(() => {
// const fetchUser = async () => {
// const response = await fetch(`http://localhost:3005/api/v1/user?slug=${slug}`)
// setUser(await response.json());
// }
// fetchUser();
// }, [])
// return (
// <div>
// {user && (
// <div>
// <p>{user.name}</p>
// <p>{user.bio}</p>
// </div>
// )}
// </div>
// );
return <div></div>;
}