adding content
This commit is contained in:
parent
ac16903c57
commit
7167ec998f
49
app/(app)/_layout/BottomNav.tsx
Normal file
49
app/(app)/_layout/BottomNav.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import Link from "next/link";
|
||||
import {
|
||||
RiHome6Fill,
|
||||
RiCompass3Fill,
|
||||
RiQuestionAnswerFill,
|
||||
} from "react-icons/ri";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export default function BottomNav() {
|
||||
const navigationItems = [
|
||||
{
|
||||
href: "",
|
||||
name: "home",
|
||||
icon: RiHome6Fill,
|
||||
current: true,
|
||||
},
|
||||
{
|
||||
href: "",
|
||||
name: "explore",
|
||||
icon: RiCompass3Fill,
|
||||
current: false,
|
||||
},
|
||||
{
|
||||
href: "",
|
||||
name: "messages",
|
||||
icon: RiQuestionAnswerFill,
|
||||
current: false,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<footer className="flex-0 flex h-[var(--bottom-nav-height)] sm:hidden">
|
||||
<div className="fixed inset-x-0 bottom-0 flex h-[var(--bottom-nav-height)] flex-1 items-center justify-between border-t px-4">
|
||||
{navigationItems.map((item) => (
|
||||
<Link href={item.href} className="center group group flex-1">
|
||||
<item.icon
|
||||
className={cn(
|
||||
item.current
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground group-hover:text-foreground",
|
||||
"h-6 w-6 shrink-0",
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
29
app/(app)/_layout/Header.tsx
Normal file
29
app/(app)/_layout/Header.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { RiMenu3Line, RiLeafFill } from "react-icons/ri";
|
||||
import { UserMenu } from "./components/UserMenu";
|
||||
import { Search } from "./components/Search";
|
||||
import { Notifications } from "./components/Notifications";
|
||||
import { MobileMenu } from "./components/MobileMenu";
|
||||
export default function Header() {
|
||||
return (
|
||||
<header className="flex h-[var(--header-height)] shrink-0 grow-0 ">
|
||||
<div className="fixed flex h-[var(--header-height)] w-full grow border-b p-5 sm:w-[calc(100vw_-_var(--sidebar-closed-width))] sm:border-b-0 sm:py-0 xl:w-[calc(100vw_-_var(--sidebar-open-width))]">
|
||||
<div className="flex flex-1 items-stretch justify-between gap-x-4 sm:border-b">
|
||||
<div className="center justify-between gap-x-3 text-foreground">
|
||||
<RiLeafFill className="h-6 w-6 sm:hidden" />
|
||||
<div className="font-semibold sm:text-lg">Flockstr</div>
|
||||
</div>
|
||||
<div className="flex grow items-center justify-end">
|
||||
<div className="sm:hidden">
|
||||
<MobileMenu />
|
||||
</div>
|
||||
<div className="hidden items-center gap-x-4 sm:flex">
|
||||
<Search />
|
||||
<Notifications />
|
||||
<UserMenu />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
15
app/(app)/_layout/Keystone.tsx
Normal file
15
app/(app)/_layout/Keystone.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import Link from "next/link";
|
||||
import { RiLeafFill } from "react-icons/ri";
|
||||
|
||||
export default function Keystone() {
|
||||
return (
|
||||
<div className="center hidden sm:flex">
|
||||
<Link
|
||||
href="/"
|
||||
className="center fixed h-[var(--header-height)] w-[var(--sidebar-closed-width)] border-r xl:w-[var(--sidebar-open-width)] xl:justify-start xl:pl-5"
|
||||
>
|
||||
<RiLeafFill className="h-6 w-6" />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
20
app/(app)/_layout/MobileBanner.tsx
Normal file
20
app/(app)/_layout/MobileBanner.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { RiCloseFill, RiLeafFill } from "react-icons/ri";
|
||||
import { Button } from "@/components/ui/button";
|
||||
export default function MobileBanner() {
|
||||
return (
|
||||
<div className="fixed bottom-[var(--bottom-nav-height)] flex w-screen items-center gap-3 border-t bg-card px-3 py-2.5 sm:hidden">
|
||||
<div className="center h-[32px] w-[32px] shrink-0 rounded-[6px] border bg-white shadow">
|
||||
<RiLeafFill className="text-black" />
|
||||
</div>
|
||||
<div className="flex-1 text-sm font-medium text-foreground">
|
||||
Get our PWA
|
||||
</div>
|
||||
<Button size={"sm"} className="rounded-[6px]">
|
||||
Install
|
||||
</Button>
|
||||
<button className="center -mx-1">
|
||||
<RiCloseFill className="h-[18px] w-[18px] text-muted-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
100
app/(app)/_layout/Sidebar.tsx
Normal file
100
app/(app)/_layout/Sidebar.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
import Link from "next/link";
|
||||
import {
|
||||
RiHome6Fill,
|
||||
RiCompassLine,
|
||||
RiCompass3Fill,
|
||||
RiQuestionAnswerLine,
|
||||
RiAddFill,
|
||||
RiSettings4Fill,
|
||||
RiSettings4Line,
|
||||
} from "react-icons/ri";
|
||||
import { HiOutlineLightningBolt } from "react-icons/hi";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export default function Sidebar() {
|
||||
const navigation = [
|
||||
{
|
||||
href: "",
|
||||
name: "home",
|
||||
label: "Home",
|
||||
icon: RiHome6Fill,
|
||||
current: true,
|
||||
},
|
||||
{
|
||||
href: "",
|
||||
name: "explore",
|
||||
label: "Explore",
|
||||
icon: RiCompassLine,
|
||||
current: false,
|
||||
},
|
||||
{
|
||||
href: "",
|
||||
name: "messages",
|
||||
label: "Messages",
|
||||
icon: RiQuestionAnswerLine,
|
||||
current: false,
|
||||
},
|
||||
{
|
||||
href: "",
|
||||
name: "zap",
|
||||
label: "Zap Flockstr",
|
||||
icon: HiOutlineLightningBolt,
|
||||
current: false,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<nav className="z-header- hidden h-[calc(100svh_-_var(--header-height))] w-[var(--sidebar-closed-width)] flex-col sm:flex">
|
||||
<div className="fixed bottom-0 flex h-[calc(100svh_-_var(--header-height))] w-[var(--sidebar-closed-width)] flex-col border-r xl:w-[var(--sidebar-open-width)]">
|
||||
<div className="flex flex-1 flex-col">
|
||||
<div className="flex flex-col items-stretch gap-y-2 p-4">
|
||||
{navigation.map((item) => (
|
||||
<Link
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
"center group relative min-h-[48px] min-w-[48px] rounded-lg hover:bg-muted xl:justify-start xl:gap-x-4 xl:p-2.5",
|
||||
item.current
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
<item.icon
|
||||
className={cn("h-6 w-6 shrink-0")}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span className="hidden text-base xl:flex">{item.label}</span>
|
||||
</Link>
|
||||
))}
|
||||
<div className="center py-2 xl:justify-start">
|
||||
<Button size={"icon"} className="xl:hidden">
|
||||
<RiAddFill className="h-6 w-6" />
|
||||
</Button>
|
||||
<Button size={"lg"} className="hidden xl:flex">
|
||||
<div className="center gap-x-1.5">
|
||||
<RiAddFill className="h-6 w-6" />
|
||||
<span>Add Note</span>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-1 flex-col justify-end p-4">
|
||||
<button
|
||||
className={cn(
|
||||
"center relative min-h-[48px] min-w-[48px] rounded-lg hover:bg-muted xl:justify-start xl:gap-x-4 xl:p-2.5",
|
||||
|
||||
"text-muted-foreground group-hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
<RiSettings4Line
|
||||
className={cn("h-6 w-6 shrink-0")}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span className="hidden text-base xl:flex">Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
56
app/(app)/_layout/components/MobileMenu.tsx
Normal file
56
app/(app)/_layout/components/MobileMenu.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { RiMenu3Line } from "react-icons/ri";
|
||||
|
||||
export function MobileMenu() {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="center text-foregroun hover:text-muted-foreground">
|
||||
<RiMenu3Line className="h-5 w-5" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="z-header+ w-56" align="end" forceMount>
|
||||
<DropdownMenuLabel className="font-normal">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<p className="text-sm font-medium leading-none">shadcn</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
m@example.com
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>New Team</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
Log out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
59
app/(app)/_layout/components/Notifications.tsx
Normal file
59
app/(app)/_layout/components/Notifications.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { RiNotification4Line } from "react-icons/ri";
|
||||
|
||||
export function Notifications() {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="center relative h-8 w-8 rounded-full bg-muted text-foreground"
|
||||
>
|
||||
<RiNotification4Line className="h-[18px] w-[18px] text-foreground" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="z-header+ w-56" align="end" forceMount>
|
||||
<DropdownMenuLabel className="font-normal">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<p className="text-sm font-medium leading-none">shadcn</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
m@example.com
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>New Team</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
Log out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
13
app/(app)/_layout/components/Search.tsx
Normal file
13
app/(app)/_layout/components/Search.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
export function Search() {
|
||||
return (
|
||||
<div>
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search..."
|
||||
className="sm:w-[200px] lg:w-[300px]"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
58
app/(app)/_layout/components/UserMenu.tsx
Normal file
58
app/(app)/_layout/components/UserMenu.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
export function UserMenu() {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage src="/avatars/01.png" alt="@shadcn" />
|
||||
<AvatarFallback>SC</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="z-header+ w-56" align="end" forceMount>
|
||||
<DropdownMenuLabel className="font-normal">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<p className="text-sm font-medium leading-none">shadcn</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
m@example.com
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>New Team</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
Log out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
28
app/(app)/_layout/index.tsx
Normal file
28
app/(app)/_layout/index.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import BottomNav from "./BottomNav";
|
||||
import Header from "./Header";
|
||||
import Keystone from "./Keystone";
|
||||
import MobileBanner from "./MobileBanner";
|
||||
import Sidebar from "./Sidebar";
|
||||
|
||||
export default function AppLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<main className="app-layout absolute inset-0 w-screen">
|
||||
{/* Keystone */}
|
||||
<Keystone />
|
||||
|
||||
{/* Header */}
|
||||
<Header />
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar />
|
||||
<div className="relative z-0 flex shrink-0 grow justify-center overflow-x-hidden">
|
||||
<div className="flex-1 overflow-x-hidden sm:px-5">{children}</div>
|
||||
</div>
|
||||
{/* Mobile Banner */}
|
||||
<MobileBanner />
|
||||
|
||||
{/* BottomNav */}
|
||||
<BottomNav />
|
||||
</main>
|
||||
);
|
||||
}
|
55
app/(app)/app/_sections/HorizontalCarousel.tsx
Normal file
55
app/(app)/app/_sections/HorizontalCarousel.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
import CreatorCard from "@/components/CreatorCard";
|
||||
export default function HorizontalCarousel() {
|
||||
const cards = [
|
||||
{
|
||||
banner:
|
||||
"https://spotlight.tailwindui.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fimage-3.454151b1.jpg&w=640&q=75",
|
||||
picture:
|
||||
"https://images.unsplash.com/photo-1520813792240-56fc4a3765a7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60",
|
||||
displayName: "Mark Cooper",
|
||||
about: "My page is a demo about what i enjoy",
|
||||
},
|
||||
{
|
||||
banner:
|
||||
"https://spotlight.tailwindui.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fimage-4.5c6d0ed6.jpg&w=640&q=75",
|
||||
picture:
|
||||
"https://images.unsplash.com/photo-1566492031773-4f4e44671857?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60",
|
||||
displayName: "Jenny Olsen",
|
||||
about: "More demo stuff to fill the space",
|
||||
},
|
||||
{
|
||||
banner:
|
||||
"https://spotlight.tailwindui.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fimage-2.3c6c01cf.jpg&w=640&q=75",
|
||||
picture:
|
||||
"https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60",
|
||||
displayName: "Kristen Watson",
|
||||
about: "random text that looks fairly nice",
|
||||
},
|
||||
{
|
||||
banner:
|
||||
"https://spotlight.tailwindui.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fimage-1.c5d2141c.jpg&w=640&q=75",
|
||||
picture:
|
||||
"https://spotlight.tailwindui.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Favatar.51a13c67.jpg&w=128&q=75",
|
||||
displayName: "Cody Fisher",
|
||||
about: "So things aren't clearly manual",
|
||||
},
|
||||
{
|
||||
banner:
|
||||
"https://spotlight.tailwindui.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fimage-5.6c6f2784.jpg&w=640&q=75",
|
||||
picture:
|
||||
"https://images.unsplash.com/photo-1532417344469-368f9ae6d187?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60",
|
||||
displayName: "Ester Howard",
|
||||
about: "here again is more ",
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="scrollbar-thumb-rounded-full mr-auto flex min-w-0 max-w-full snap-x snap-mandatory overflow-x-auto pl-5 pr-[50vw] scrollbar-thin sm:pr-[200px]">
|
||||
{cards.map((creator) => (
|
||||
<div className="snap-start pl-5">
|
||||
<CreatorCard key={creator.displayName} {...creator} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
16
app/(app)/app/page.tsx
Normal file
16
app/(app)/app/page.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import HorizontalCarousel from "./_sections/HorizontalCarousel";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="relative pt-10">
|
||||
<div className="relative -mx-5 space-y-6 overflow-x-hidden">
|
||||
<div className="flex items-center justify-between px-5">
|
||||
<h2 className="font-condensed text-3xl font-bold">
|
||||
Explore Creators
|
||||
</h2>
|
||||
</div>
|
||||
<HorizontalCarousel />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
13
app/(app)/layout.tsx
Normal file
13
app/(app)/layout.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import AppLayout from './_layout'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<AppLayout>
|
||||
{children}
|
||||
</AppLayout>
|
||||
);
|
||||
}
|
111
app/(landing)/_layout/Footer.tsx
Normal file
111
app/(landing)/_layout/Footer.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Footer() {
|
||||
const navigation = {
|
||||
main: [
|
||||
{ name: "Home", href: "/" },
|
||||
{ name: "Explore", href: "#" },
|
||||
{ name: "About", href: "#" },
|
||||
{ name: "Contact", href: "#" },
|
||||
],
|
||||
social: [
|
||||
{
|
||||
name: "Facebook",
|
||||
href: "#",
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Instagram",
|
||||
href: "#",
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Twitter",
|
||||
href: "#",
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "GitHub",
|
||||
href: "#",
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "YouTube",
|
||||
href: "#",
|
||||
icon: (props: any) => (
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M19.812 5.418c.861.23 1.538.907 1.768 1.768C21.998 8.746 22 12 22 12s0 3.255-.418 4.814a2.504 2.504 0 0 1-1.768 1.768c-1.56.419-7.814.419-7.814.419s-6.255 0-7.814-.419a2.505 2.505 0 0 1-1.768-1.768C2 15.255 2 12 2 12s0-3.255.417-4.814a2.507 2.507 0 0 1 1.768-1.768C5.744 5 11.998 5 11.998 5s6.255 0 7.814.418ZM15.194 12 10 15V9l5.194 3Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
return (
|
||||
<footer className="bg-white">
|
||||
<div className="mx-auto max-w-7xl overflow-hidden px-6 py-10 sm:py-20 lg:px-8">
|
||||
<nav
|
||||
className="-mb-6 columns-2 sm:flex sm:justify-center sm:space-x-12"
|
||||
aria-label="Footer"
|
||||
>
|
||||
{navigation.main.map((item) => (
|
||||
<div key={item.name} className="pb-6">
|
||||
<Link
|
||||
href={item.href}
|
||||
className="text-sm leading-6 text-gray-600 hover:text-gray-900"
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
{/* <div className="mt-10 flex justify-center space-x-10">
|
||||
{navigation.social.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className="text-gray-400 hover:text-gray-500"
|
||||
>
|
||||
<span className="sr-only">{item.name}</span>
|
||||
<item.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</a>
|
||||
))}
|
||||
</div> */}
|
||||
<p className="mt-10 text-center text-sm leading-5 text-gray-500 sm:mt-6">
|
||||
© {new Date().getFullYear()} Flockstr
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
75
app/(landing)/_layout/Header.tsx
Normal file
75
app/(landing)/_layout/Header.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { RiMenu3Line, RiLeafFill, RiCloseFill } from "react-icons/ri";
|
||||
|
||||
export default function Header() {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const navigation = [
|
||||
{ name: "home", label: "Home", href: "/" },
|
||||
{ name: "explore", label: "Explore", href: "/" },
|
||||
{ name: "about", label: "About", href: "/" },
|
||||
{ name: "contact", label: "Contact", href: "/" },
|
||||
];
|
||||
return (
|
||||
<header
|
||||
className={cn(
|
||||
"flex min-h-[var(--header-height)] shrink-0 grow-0 flex-col overflow-hidden px-6 transition-all",
|
||||
menuOpen ? "max-h-none" : "max-h-[var(--header-height)]",
|
||||
)}
|
||||
>
|
||||
<div className="center hidden min-h-[var(--header-height)] lg:flex">
|
||||
<ul className="font-condensed flex w-full max-w-xl items-center justify-between text-base font-semibold uppercase text-zinc-500 hover:text-zinc-600">
|
||||
{navigation.slice(0, 2).map((item) => (
|
||||
<li className="">
|
||||
<Link key={item.name} href={item.href} className="flex p-1">
|
||||
<div className="center w-full ">{item.label}</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
<Link href="/">
|
||||
<RiLeafFill className="h-8 w-8 text-primary" />
|
||||
</Link>
|
||||
{navigation.slice(2, 4).map((item) => (
|
||||
<li className="">
|
||||
<Link key={item.name} href={item.href} className="flex p-1">
|
||||
<div className="center w-full">{item.label}</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex min-h-[var(--header-height)] flex-1 items-stretch justify-between gap-x-4 lg:hidden">
|
||||
<div className="center justify-between gap-x-3 text-primary">
|
||||
<RiLeafFill className="h-7 w-7" />
|
||||
</div>
|
||||
<div className="flex grow items-center justify-end">
|
||||
<button
|
||||
onClick={() => setMenuOpen((prev) => !prev)}
|
||||
className="center text-foregroun hover:text-muted-foreground"
|
||||
>
|
||||
{menuOpen ? (
|
||||
<RiCloseFill className="h-6 w-6" />
|
||||
) : (
|
||||
<RiMenu3Line className="h-6 w-6" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav className="lg:hidden">
|
||||
<ul className="mb-5 flex w-full flex-col items-stretch border-t">
|
||||
{navigation.map((item) => (
|
||||
<li className="">
|
||||
<Link key={item.name} href={item.href} className="flex p-1">
|
||||
<div className="center w-full rounded-sm bg-zinc-50 py-3 hover:bg-zinc-100">
|
||||
{item.label}
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
}
|
14
app/(landing)/_layout/index.tsx
Normal file
14
app/(landing)/_layout/index.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import Header from "./Header";
|
||||
import Footer from "./Footer";
|
||||
|
||||
export default function AppLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<main className="absolute inset-0 w-screen bg-white">
|
||||
<Header />
|
||||
<div className="relative z-0 flex shrink-0 grow flex-col justify-center">
|
||||
<div className="flex-1">{children}</div>
|
||||
<Footer />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
9
app/(landing)/layout.tsx
Normal file
9
app/(landing)/layout.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import LandingLayout from "./_layout";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return <LandingLayout>{children}</LandingLayout>;
|
||||
}
|
186
app/(landing)/page.tsx
Normal file
186
app/(landing)/page.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<section className="flex w-full flex-col items-center gap-3 px-2">
|
||||
<div className="flex w-full justify-center rounded-[35px] bg-black p-6 pt-20 @container lg:justify-start lg:p-10 lg:py-16">
|
||||
<div className="flex flex-col gap-y-6 text-center lg:max-w-md lg:text-left">
|
||||
<h1 className="font-condensed text-[11cqw] font-semibold leading-[13cqw] text-zinc-100 sm:text-5xl">
|
||||
Your Community, Where ever you are.
|
||||
</h1>
|
||||
<p className="text-sm text-zinc-400 lg:text-base">
|
||||
Nostr allows you to truly own your community with a fully
|
||||
decentralized social graph. Never get locked into a platform
|
||||
again.
|
||||
</p>
|
||||
<div className="center lg:justify-start">
|
||||
<Button size={"lg"}>Get Started</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full flex-col gap-3 lg:flex-row">
|
||||
<div className="flex w-full flex-1 rounded-[35px] bg-zinc-200 p-6 @container">
|
||||
<div className="flex flex-col gap-y-6 text-center">
|
||||
<span className="uppercase tracking-wider text-zinc-400">
|
||||
About nostr
|
||||
</span>
|
||||
<div className="font-condensed space-y-4 font-medium">
|
||||
<p className="text-base text-zinc-800">
|
||||
Nostr is a simple, open protocol for decentralizing how
|
||||
infomration is stored and retreived on the web.
|
||||
</p>
|
||||
<p className="text-base text-zinc-800">
|
||||
Rather that your user data being siloed by the big tech
|
||||
companies whose platforms dominate our culture, nostr
|
||||
distributes data across hundreds of relays that anyone can
|
||||
spin up.
|
||||
</p>
|
||||
<p className="text-base text-zinc-800">
|
||||
This means that no single entity is ever in control of your
|
||||
data. In other words:
|
||||
<span className="mt-3 block text-xl font-bold">
|
||||
No more lock-in, Way more choices.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="center">
|
||||
<Button size={"lg"}>Get Started</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full flex-1 rounded-[35px] bg-primary p-6 @container">
|
||||
<div className="flex flex-col gap-y-6 text-center">
|
||||
<span className="uppercase tracking-wider text-primary-foreground/80">
|
||||
Why Bitcoin?
|
||||
</span>
|
||||
<div className="font-condensed space-y-4 font-medium">
|
||||
<p className="text-base text-zinc-800">
|
||||
Nostr is a simple, open protocol for decentralizing how
|
||||
infomration is stored and retreived on the web.
|
||||
</p>
|
||||
<p className="text-base text-zinc-800">
|
||||
Rather that your user data being siloed by the big tech
|
||||
companies whose platforms dominate our culture, nostr
|
||||
distributes data across hundreds of relays that anyone can
|
||||
spin up.
|
||||
</p>
|
||||
<p className="text-base text-zinc-800">
|
||||
This means that no single entity is ever in control of your
|
||||
data. In other words:
|
||||
<span className="mt-3 block text-xl font-bold">
|
||||
No more lock-in, Way more choices.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="center">
|
||||
<Button size={"lg"} variant={"secondary"}>
|
||||
Explore
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full justify-center rounded-[35px] bg-zinc-500 p-6 pt-10 @container lg:justify-start lg:p-10 lg:py-16 lg:pt-20">
|
||||
<div className="flex flex-col gap-y-6 text-center lg:max-w-md lg:text-left">
|
||||
<h1 className="font-condensed text-[11cqw] font-semibold leading-[13cqw] text-zinc-100 sm:text-5xl">
|
||||
Find out if you're the right fit.
|
||||
</h1>
|
||||
<p className="text-sm text-zinc-200 lg:text-base">
|
||||
Nostr allows you to truly own your community with a fully
|
||||
decentralized social graph. Never get locked into a platform
|
||||
again.
|
||||
</p>
|
||||
<div className="center lg:justify-start">
|
||||
<Button size={"lg"}>Contact Us</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mt-10 w-full">
|
||||
<div className="overflow-hidden pt-32 sm:pt-14">
|
||||
<div className="bg-zinc-800">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="relative pb-16 pt-48 sm:pb-24">
|
||||
<div>
|
||||
<h2
|
||||
id="sale-heading"
|
||||
className="text-4xl font-bold tracking-tight text-white md:text-5xl"
|
||||
>
|
||||
It's about time
|
||||
<br />
|
||||
Let's take a look.
|
||||
</h2>
|
||||
<div className="mt-6 text-base">
|
||||
<Link href="/app" className="font-semibold text-white">
|
||||
Explore Now
|
||||
<span aria-hidden="true"> →</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute -top-32 left-1/2 -translate-x-1/2 transform sm:top-6 sm:translate-x-0">
|
||||
<div className="ml-24 flex min-w-max space-x-6 sm:ml-3 lg:space-x-8">
|
||||
<div className="flex space-x-6 sm:flex-col sm:space-x-0 sm:space-y-6 lg:space-y-8">
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
className="h-64 w-64 rounded-lg object-cover md:h-72 md:w-72"
|
||||
src="https://tailwindui.com/img/ecommerce-images/home-page-03-category-01.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex-shrink-0 sm:mt-0">
|
||||
<img
|
||||
className="h-64 w-64 rounded-lg object-cover md:h-72 md:w-72"
|
||||
src="https://tailwindui.com/img/ecommerce-images/home-page-03-category-02.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex space-x-6 sm:-mt-20 sm:flex-col sm:space-x-0 sm:space-y-6 lg:space-y-8">
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
className="h-64 w-64 rounded-lg object-cover md:h-72 md:w-72"
|
||||
src="https://tailwindui.com/img/ecommerce-images/home-page-03-favorite-01.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex-shrink-0 sm:mt-0">
|
||||
<img
|
||||
className="h-64 w-64 rounded-lg object-cover md:h-72 md:w-72"
|
||||
src="https://tailwindui.com/img/ecommerce-images/home-page-03-favorite-02.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex space-x-6 sm:flex-col sm:space-x-0 sm:space-y-6 lg:space-y-8">
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
className="h-64 w-64 rounded-lg object-cover md:h-72 md:w-72"
|
||||
src="https://tailwindui.com/img/ecommerce-images/home-page-03-category-01.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex-shrink-0 sm:mt-0">
|
||||
<img
|
||||
className="h-64 w-64 rounded-lg object-cover md:h-72 md:w-72"
|
||||
src="https://tailwindui.com/img/ecommerce-images/home-page-03-category-02.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
@ -25,8 +24,12 @@
|
||||
--input: 20 5.9% 90%;
|
||||
--ring: 24.6 95% 53.1%;
|
||||
--radius: 0.75rem;
|
||||
--sidebar-open-width: 300px;
|
||||
--sidebar-closed-width: 80px;
|
||||
--header-height: 72px;
|
||||
--bottom-nav-height: 56px;
|
||||
}
|
||||
|
||||
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 60 9.1% 97.8%;
|
||||
@ -47,10 +50,13 @@
|
||||
--border: 12 6.5% 15.1%;
|
||||
--input: 12 6.5% 15.1%;
|
||||
--ring: 20.5 90.2% 48.2%;
|
||||
--sidebar-open-width: 300px;
|
||||
--sidebar-closed-width: 80px;
|
||||
--header-height: 72px;
|
||||
--bottom-nav-height: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
@ -58,9 +64,18 @@
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
.layout-grid-small-sidebar {
|
||||
grid: var(--header-height) 1fr / var(--sidebar-closed-width) 1fr;
|
||||
}
|
||||
.layout-grid-large-sidebar {
|
||||
grid: var(--header-height) 1fr / var(--sidebar-open-width) 1fr;
|
||||
}
|
||||
.app-layout {
|
||||
@apply sm:layout-grid-small-sidebar xl:layout-grid-large-sidebar flex flex-col sm:grid;
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.center {
|
||||
@apply flex items-center justify-center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
import "./globals.css";
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import { Inter, Inter_Tight } from "next/font/google";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Providers } from "./_providers";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
const interTight = Inter_Tight({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-inter-tight",
|
||||
});
|
||||
const title = "Flockstr";
|
||||
const description = "Own your flock";
|
||||
const image =
|
||||
@ -55,7 +59,11 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning className="">
|
||||
<body
|
||||
className={cn(inter.className, "w-full bg-background scrollbar-none")}
|
||||
className={cn(
|
||||
inter.className,
|
||||
interTight.variable,
|
||||
"w-full bg-background scrollbar-none",
|
||||
)}
|
||||
>
|
||||
<Providers>{children}</Providers>
|
||||
</body>
|
||||
|
113
app/page.tsx
113
app/page.tsx
@ -1,113 +0,0 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
|
||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
||||
Get started by editing
|
||||
<code className="font-mono font-bold">app/page.tsx</code>
|
||||
</p>
|
||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
||||
<a
|
||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{' '}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className="dark:invert"
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
|
||||
<Image
|
||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Docs{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Find in-depth information about Next.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Learn{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Learn about Next.js in an interactive course with quizzes!
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Templates{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Explore the Next.js 13 playground.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Deploy{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
101
components/CreatorCard/index.tsx
Normal file
101
components/CreatorCard/index.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { RiArrowRightLine } from "react-icons/ri";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
|
||||
type CreatorCardProps = {
|
||||
displayName: string;
|
||||
about: string;
|
||||
picture: string;
|
||||
banner: string;
|
||||
};
|
||||
|
||||
export default function CreatorCard({
|
||||
banner,
|
||||
displayName,
|
||||
picture,
|
||||
about,
|
||||
}: CreatorCardProps) {
|
||||
const recentEvents = [
|
||||
{
|
||||
id: "test",
|
||||
title: "How to start building a following on nostr.",
|
||||
summary:
|
||||
"Starting on a new protocol could be intinidating, But there is no reason to fret. I've got it all under control.",
|
||||
},
|
||||
{
|
||||
id: "asg",
|
||||
title: "Jumping through relays",
|
||||
summary: "Getting used to different relays and how to find them",
|
||||
},
|
||||
{
|
||||
id: "ant",
|
||||
title: "Nostrasia is coming",
|
||||
summary: "Time to start preping for Nostraisa.",
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Card className="relative h-[350px] w-[250px] min-w-[250] overflow-hidden">
|
||||
<Image
|
||||
alt="background"
|
||||
src={banner}
|
||||
className="absolute inset-0 object-cover"
|
||||
fill
|
||||
unoptimized
|
||||
/>
|
||||
<div className="absolute inset-0 bg-background/60 backdrop-blur-md transition-all">
|
||||
<div className="group relative flex h-full w-full flex-col items-center justify-end transition-all">
|
||||
<CardHeader className="absolute inset-x-0 top-[59%] transform pt-4 text-center transition-all duration-300 group-hover:top-0 group-hover:ml-[70px] group-hover:text-left">
|
||||
<CardTitle>{displayName}</CardTitle>
|
||||
<CardDescription className="line-clamp-3 group-hover:text-xs">
|
||||
{about}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<Image
|
||||
alt="user"
|
||||
src={picture}
|
||||
className="absolute left-1/2 top-1/2 aspect-square -translate-x-1/2 -translate-y-[70%] transform overflow-hidden rounded-lg object-cover transition-all duration-300 group-hover:left-[45px] group-hover:top-[60px] group-hover:w-[70px]"
|
||||
height={100}
|
||||
width={100}
|
||||
unoptimized
|
||||
/>
|
||||
<Card className="absolute top-full min-h-full w-5/6 overflow-hidden transition-all duration-300 group-hover:top-1/3">
|
||||
<CardHeader className="border-b p-4 pb-3">
|
||||
<CardTitle>Recent work:</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="overflow-hidden px-0">
|
||||
<ul>
|
||||
{recentEvents.map((item) => (
|
||||
<li key={item.id} className="overflow-hidden">
|
||||
<Link
|
||||
href={""}
|
||||
className="flex max-w-fit items-center justify-between overflow-hidden py-1.5 pl-4 pr-2 transition-colors hover:bg-muted hover:text-primary"
|
||||
>
|
||||
<div className="shrink">
|
||||
<h4 className="line-clamp-1 text-sm font-semibold text-card-foreground">
|
||||
{item.title}
|
||||
</h4>
|
||||
<p className="line-clamp-2 text-[10px] leading-4 text-muted-foreground">
|
||||
{item.summary}
|
||||
</p>
|
||||
</div>
|
||||
<div className="center shrink-0 pl-2">
|
||||
<RiArrowRightLine className="h-5 w-5" />
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -54,6 +54,7 @@
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "13.5.4",
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier-plugin-tailwindcss": "^0.5.6",
|
||||
"tailwindcss": "^3",
|
||||
"typescript": "^5",
|
||||
|
@ -52,6 +52,13 @@ module.exports = {
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
condensed: ["var(--font-inter-tight)"],
|
||||
},
|
||||
width: {
|
||||
"sidebar-open": "var(--sidebar-open-width)",
|
||||
"sidebar-closed": "var(--sidebar-closed-width)",
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
|
Loading…
x
Reference in New Issue
Block a user