adding content

This commit is contained in:
zmeyer44 2023-10-13 19:02:59 -04:00
parent ac16903c57
commit 7167ec998f
25 changed files with 1044 additions and 119 deletions

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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
View 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
View File

@ -0,0 +1,13 @@
import AppLayout from './_layout'
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<AppLayout>
{children}
</AppLayout>
);
}

View 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">
&copy; {new Date().getFullYear()} Flockstr
</p>
</div>
</footer>
);
}

View 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>
);
}

View 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
View 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
View 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"> &rarr;</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>
);
}

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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&nbsp;
<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">
-&gt;
</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">
-&gt;
</span>
</h2>
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
Learn about Next.js in an interactive course with&nbsp;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">
-&gt;
</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">
-&gt;
</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>
)
}

BIN
bun.lockb

Binary file not shown.

View 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>
);
}

View File

@ -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",

View File

@ -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)",