1 Commits

Author SHA1 Message Date
Renovate Bot
2b07eb3b22 Update dependency eslint to v9 2024-10-07 00:07:21 +00:00
21 changed files with 54 additions and 963 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -1,6 +1,6 @@
---
title: 'Hello'
published: '2024-10-06'
published: '10-06-2024'
summary: 'petentium usu tota noluisse errem elaboraret auctor.'
---

View File

@ -1,6 +1,6 @@
---
title: 'Hey'
published: '2024-10-06'
published: '10-06-2024'
summary: 'petentium usu tota noluisse errem elaboraret auctor.'
---

View File

@ -1,6 +1,6 @@
---
title: 'Hi'
published: '2024-10-06'
published: '10-06-2024'
summary: 'petentium usu tota noluisse errem elaboraret auctor.'
---

View File

@ -1,293 +1,8 @@
---
title: '🚀 Introduction'
published: '2024-10-06'
published: '10-06-2024'
summary: 'petentium usu tota noluisse errem elaboraret auctor.'
---
# Get started with Pulse App!
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# an mel dissentiunt ponderum eius dicant adhuc,
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# vim an explicari eirmod pro singulis scripta iaculis fermentum.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# eruditi propriae vulputate elit venenatis reprehendunt delectus.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# dicunt antiopam ultricies nisl egestas voluptatibus harum,
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# viverra senserit cursus theophrastus elaboraret iudicabit ligula.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# posidonium dicat eum nostra auctor quaeque harum
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# doctus primis disputationi atqui magnis himenaeos fastidii
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# ligula cras prodesset litora ridens docendi euripidis
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# efficitur detraxit detraxit fames appareat mutat elit
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# donec nominavi qui dolorum adversarium eum eleifend
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
# nunc contentiones numquam pharetra his vero solum
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.
petentium usu tota noluisse errem elaboraret auctor.

View File

@ -20,13 +20,11 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "1.0.0",
"framer-motion": "^11.11.1",
"lucide-react": "^0.447.0",
"luxon": "^3.5.0",
"next": "^15.0.0-canary.179",
"next-themes": "^0.3.0",
"react": "^19.0.0-rc-1460d67c-20241003",
@ -37,14 +35,13 @@
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@types/luxon": "^3.4.2",
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^9.0.0",
"eslint-config-next": "14.2.8",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"
"eslint": "^9.0.0",
"eslint-config-next": "14.2.8"
}
}

View File

@ -76,7 +76,7 @@ const DocsPage = async ({
</Breadcrumb>
{/* Content */}
<div className="flex gap-5 justify-between">
<div className="flex justify-between">
<div className="flex flex-col">
<CustomMDX source={page.content} />
</div>

View File

@ -4,8 +4,6 @@ import { ReactElement, ReactNode } from "react";
import { ThemeProvider } from "@/components/theme-provider";
import Navbar from "@/components/navbar/navbar";
import Sidebar from "@/components/sidebar/sidebar";
import Footer from "@/components/footer";
import { TooltipProvider } from "@/components/ui/tooltip";
/**
* The metadata for this app.
@ -50,18 +48,15 @@ const RootLayout = ({
}}
>
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
<TooltipProvider delayDuration={100}>
<div className="px-7 max-w-[90rem] mx-auto min-h-screen flex flex-col">
<Navbar />
<div className="pt-[4.5rem] w-full h-full flex flex-grow gap-5">
<div className="relative hidden xs:flex">
<div className="relative hidden xs:flex pr-40 sm:pr-52">
<Sidebar />
</div>
{children}
</div>
</div>
<Footer />
</TooltipProvider>
</ThemeProvider>
</body>
</html>

View File

@ -1,12 +1,10 @@
"use client";
import { ReactElement, useEffect, useState } from "react";
import { ReactElement } from "react";
import { usePathname } from "next/navigation";
import Link from "next/link";
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
import { Separator } from "@/components/ui/separator";
import { DateTime } from "luxon";
import SimpleTooltip from "@/components/simple-tooltip";
const DocsFooter = ({
pages,
@ -16,72 +14,35 @@ const DocsFooter = ({
const path: string = usePathname();
const current: number = pages.findIndex(
(page: DocsContentMetadata) =>
(path === "/" && page.slug === "intro") || path === `/${page.slug}`
(page: DocsContentMetadata) => `/${page.slug}` === path
);
const previous: DocsContentMetadata | undefined =
current > 0 ? pages[current - 1] : undefined;
const next: DocsContentMetadata | undefined =
current < pages.length - 1 ? pages[current + 1] : undefined;
const [publicationDate, setPublicationDate] = useState<string | null>(
DateTime.fromISO(pages[current]?.published).toRelative()
);
useEffect(() => {
const interval = setInterval(() => {
setPublicationDate(
DateTime.fromISO(pages[current]?.published).toRelative()
);
}, 1000);
return () => clearInterval(interval);
}, [current, pages]);
return (
<footer className="xs:mx-5 sm:mx-10 my-2 flex flex-col select-none transition-all transform-gpu">
{/* Publish Date */}
<div className="ml-auto pt-4">
<SimpleTooltip
content={DateTime.fromISO(
pages[current]?.published
).toLocaleString(DateTime.DATETIME_MED)}
>
<span className="text-sm opacity-75">
Published {publicationDate}
</span>
</SimpleTooltip>
</div>
{/* Pages */}
<Separator className="my-4" />
<footer className="xs:mx-5 sm:mx-10 my-5 flex flex-col select-none transition-all transform-gpu">
<Separator className="mb-4" />
<div className="flex justify-between">
{/* Previous */}
{previous && (
<Link
className="flex gap-2 items-end hover:opacity-75 transition-all transform-gpu group"
className="flex gap-2 items-center hover:opacity-75 transition-all transform-gpu group"
href={`/${previous.slug}` || "#"}
draggable={false}
>
<ChevronLeftIcon className="pb-1 w-4 h-4 group-hover:-translate-x-0.5 transition-all transform-gpu" />
<div className="flex flex-col">
<h1 className="text-sm opacity-75">Previous</h1>
<p>{previous.title}</p>
</div>
<ChevronLeftIcon className="w-4 h-4 group-hover:-translate-x-0.5 transition-all transform-gpu" />
{previous.title}
</Link>
)}
{/* Next */}
{next && (
<Link
className="ml-auto flex gap-2 items-end hover:opacity-75 transition-all transform-gpu group"
className="ml-auto flex gap-2 items-center hover:opacity-75 transition-all transform-gpu group"
href={`/${next.slug}` || "#"}
draggable={false}
>
<div className="flex flex-col">
<h1 className="text-sm opacity-75">Next</h1>
<p>{next.title}</p>
</div>
<ChevronRightIcon className="pb-1 w-4 h-4 group-hover:translate-x-0.5 transition-all transform-gpu" />
{next.title}
<ChevronRightIcon className="w-4 h-4 group-hover:translate-x-0.5 transition-all transform-gpu" />
</Link>
)}
</div>

View File

@ -1,195 +0,0 @@
"use client";
import { ReactElement, ReactNode } from "react";
import AnimatedGridPattern from "@/components/ui/animated-grid-pattern";
import Link from "next/link";
import Image from "next/image";
import {
ArrowTopRightOnSquareIcon,
EnvelopeIcon,
} from "@heroicons/react/24/outline";
import { cn } from "@/lib/utils";
const links = {
Resources: [
{
name: "Support",
href: "https://support.pulseapp.cc",
},
{
name: "Jobs",
href: "https://jobs.pulseapp.cc",
},
{
name: "Developers",
shortName: "Devs",
href: "https://dev.pulseapp.cc",
external: true,
},
{
name: "System Status",
shortName: "Status",
href: "https://status.pulseapp.cc",
external: true,
},
],
Legal: [
{
name: "Terms & Conditions",
shortName: "Terms",
href: "/legal/terms",
},
{
name: "Privacy Policy",
shortName: "Privacy",
href: "/legal/privacy",
},
],
};
const Footer = (): ReactElement => (
<footer className="mt-3 relative h-[19.5rem] md:h-[17rem] flex justify-center border-t border-zinc-700/75 overflow-hidden select-none">
<div className="w-full md:max-w-[65rem]">
<div className="px-5 py-5 md:py-10 w-full flex flex-col md:flex-row items-center justify-around md:items-start gap-7">
{/* Top */}
<div className="flex flex-col gap-2.5 items-center md:items-start">
<Branding />
{/* Socials */}
<div className="pl-1 flex gap-2.5 items-center z-50">
<SocialLink
name="GitHub"
logo="github.svg"
href="https://github.com/PulseAppCC"
/>
<SocialLink
name="Discord"
logo="discord.svg"
href="https://discord.pulseapp.cc"
/>
<SocialLink
name="Email"
logo={
<EnvelopeIcon className="opacity-95 w-6 h-6" />
}
href="mailto:support@pulseapp.cc"
/>
</div>
</div>
{/* Links */}
<div className="flex gap-7 md:gap-12 transition-all transform-gpu">
{Object.entries(links).map(([title, links]) => (
<LinkCategory key={title} title={title}>
{links.map((link) => (
<FooterLink key={link.name} {...link} />
))}
</LinkCategory>
))}
</div>
</div>
{/* Copyright */}
<p className="absolute inset-x-0 bottom-3.5 flex text-sm text-center justify-center opacity-60">
Copyright &copy; {new Date().getFullYear()} Pulse App. All
rights reserved.
</p>
</div>
{/* Background */}
<AnimatedGridPattern
className="inset-x-0 skew-y-12 [mask-image:radial-gradient(500px_circle_at_center,white,transparent)]"
numSquares={30}
maxOpacity={0.1}
duration={3}
repeatDelay={1}
/>
</footer>
);
const Branding = () => (
<Link
className="flex gap-3 items-center hover:opacity-75 transition-all transform-gpu"
href="https://pulseapp.cc"
draggable={false}
>
<Image
src="/media/logo.png"
alt="Pulse App Logo"
width={40}
height={40}
draggable={false}
/>
<h1 className="text-xl font-bold">Pulse App</h1>
</Link>
);
const SocialLink = ({
name,
logo,
href,
}: {
name: string;
logo: string | ReactElement;
href: string;
}) => (
<Link
className="hover:opacity-75 transition-all transform-gpu"
href={href}
target="_blank"
draggable={false}
>
{typeof logo === "string" ? (
<Image
src={`/media/${logo}`}
alt={`${name}'s Logo`}
width={20}
height={20}
draggable={false}
/>
) : (
logo
)}
</Link>
);
const LinkCategory = ({
title,
children,
}: {
title: string;
children: ReactNode;
}): ReactElement => (
<div className="flex flex-col gap-0.5">
<h1 className="text-lg font-semibold">{title}</h1>
{children}
</div>
);
const FooterLink = ({
name,
shortName,
href,
}: {
name: string;
shortName?: string | undefined;
href: string;
}): ReactElement => {
const external: boolean = !href.startsWith("/");
return (
<Link
className="flex gap-2 items-center hover:opacity-75 transition-all transform-gpu"
href={href}
target={external ? "_blank" : undefined}
draggable={false}
>
<span className={cn("hidden sm:flex", !shortName && "flex")}>
{name}
</span>
{shortName && <span className="flex sm:hidden">{shortName}</span>}
{external && <ArrowTopRightOnSquareIcon className="w-3.5 h-3.5" />}
</Link>
);
};
export default Footer;

View File

@ -8,32 +8,32 @@ import remarkGfm from "remark-gfm";
*/
const components = {
h1: ({ children }: { children: ReactNode }): ReactElement => (
<Heading as="h1" size={1} className="text-4xl">
<Heading size={1} className="text-4xl">
{children}
</Heading>
),
h2: ({ children }: { children: ReactNode }): ReactElement => (
<Heading as="h2" size={2} className="text-3xl">
<Heading size={2} className="text-3xl">
{children}
</Heading>
),
h3: ({ children }: { children: ReactNode }): ReactElement => (
<Heading as="h3" size={3} className="text-2xl">
<Heading size={3} className="text-2xl">
{children}
</Heading>
),
h4: ({ children }: { children: ReactNode }): ReactElement => (
<Heading as="h4" size={4} className="text-xl">
<Heading size={4} className="text-xl">
{children}
</Heading>
),
h5: ({ children }: { children: ReactNode }): ReactElement => (
<Heading as="h5" size={5} className="text-lg">
<Heading size={5} className="text-lg">
{children}
</Heading>
),
h6: ({ children }: { children: ReactNode }): ReactElement => (
<Heading as="h6" size={6} className="text-md">
<Heading size={5} className="text-md">
{children}
</Heading>
),
@ -89,31 +89,15 @@ export const CustomMDX = (props: any): ReactElement => (
* @return the heading jsx
*/
const Heading = ({
as: Component,
className,
size,
children,
}: {
as: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
className: string;
size: number;
children: ReactNode;
}): ReactElement => {
const id: string | undefined =
typeof children === "string" ? slugify(children) : undefined;
return (
<Component
id={id}
className={cn("pt-2.5 font-bold", size >= 2 && "pt-7", className)}
>
}): ReactElement => (
<h1 className={cn("pt-2.5 font-bold", size >= 2 && "pt-7", className)}>
{children}
</Component>
);
};
const slugify = (text: string): string =>
text
.toLowerCase()
.replace(/[^\w\s-]/g, "")
.replace(/[\s_-]+/g, "-")
.trim();
</h1>
);

View File

@ -1,6 +1,7 @@
import { ReactElement } from "react";
import Link from "next/link";
import Image from "next/image";
import { cn } from "@/lib/utils";
import QuickSearchDialog from "@/components/navbar/search-dialog";
import { getDocsContent } from "@/lib/mdx";
import Sidebar from "@/components/sidebar/sidebar";
@ -8,12 +9,12 @@ import Sidebar from "@/components/sidebar/sidebar";
const Navbar = (): ReactElement => {
const pages: DocsContentMetadata[] = getDocsContent();
return (
<nav className="fixed left-0 inset-x-0 bg-white/[0.007] backdrop-saturate-100 backdrop-blur-xl border-b z-50">
<nav className="fixed left-0 inset-x-0 bg-white/[0.007] backdrop-saturate-100 backdrop-blur-xl border-b">
<div className="px-7 max-w-[90rem] mx-auto py-4 flex justify-between items-center">
{/* Branding */}
<Link
className="flex gap-1 items-end hover:opacity-75 transition-all transform-gpu select-none"
href="/"
href="/public"
draggable={false}
>
<h1 className="text-lg font-semibold">docs.</h1>
@ -30,7 +31,7 @@ const Navbar = (): ReactElement => {
<div className="flex gap-5 sm:gap-7 items-center transition-all transform-gpu">
{/* Search */}
<div className="hidden xs:flex">
<QuickSearchDialog pages={pages} bindKeybind />
<QuickSearchDialog pages={pages} />
</div>
{/* Social */}

View File

@ -21,19 +21,14 @@ import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.share
*/
const QuickSearchDialog = ({
pages,
bindKeybind = false,
}: {
pages: DocsContentMetadata[];
bindKeybind?: boolean;
}): ReactElement => {
const [open, setOpen] = useState<boolean>(false);
const router: AppRouterInstance = useRouter();
// Listen for CTRL + K keybinds to open this dialog
useEffect(() => {
if (!bindKeybind) {
return;
}
const handleKeyDown = (event: KeyboardEvent): void => {
if ((event.ctrlKey || event.metaKey) && event.key === "k") {
event.preventDefault();
@ -42,7 +37,7 @@ const QuickSearchDialog = ({
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [bindKeybind]);
}, []);
// Render the contents
return (

View File

@ -1,17 +1,8 @@
"use client";
import { ReactElement, useEffect, useRef, useState } from "react";
import {
ArrowLongRightIcon,
ArrowLongUpIcon,
Bars3CenterLeftIcon,
} from "@heroicons/react/24/outline";
import { ReactElement, useEffect, useState } from "react";
import { Bars3CenterLeftIcon } from "@heroicons/react/24/outline";
import Link from "next/link";
import { cn } from "@/lib/utils";
import { truncateText } from "@/lib/string";
import { motion, useInView } from "framer-motion";
import { Separator } from "@/components/ui/separator";
import { Button } from "@/components/ui/button";
type Header = {
id: string;
@ -21,13 +12,6 @@ type Header = {
const OnThisPage = ({ page }: { page: DocsContentMetadata }): ReactElement => {
const [headers, setHeaders] = useState<Header[]>([]);
const [activeHeader, setActiveHeader] = useState<string | undefined>(
undefined
);
const observerRef = useRef<IntersectionObserver | undefined>(undefined);
const ref = useRef<HTMLDivElement>(null);
const inView = useInView(ref);
useEffect(() => {
// Regular expression to match markdown headers
@ -49,139 +33,27 @@ const OnThisPage = ({ page }: { page: DocsContentMetadata }): ReactElement => {
setHeaders(extractedHeaders);
}, [page.content]);
useEffect(() => {
// Cleanup existing observer
if (observerRef.current) {
observerRef.current.disconnect();
}
const observer = new IntersectionObserver(
(entries: IntersectionObserverEntry[]) => {
entries.forEach((entry: IntersectionObserverEntry) => {
if (entry.isIntersecting) {
setActiveHeader(entry.target.id);
}
});
},
{ rootMargin: "0px 0px -80% 0px", threshold: 0.1 }
);
observerRef.current = observer;
// Observe all header elements
headers.forEach((header: Header) => {
const element: HTMLElement | null = document.getElementById(
header.id
);
if (element) {
observer.observe(element);
}
});
return () => observer.disconnect();
}, [headers]);
return (
<motion.div
ref={ref}
className="sticky top-[5.5rem] w-44 max-h-[calc(100vh-3.5rem)] flex flex-col gap-2 text-sm select-none"
initial={{ opacity: 0 }}
animate={{ opacity: inView ? 1 : 0 }}
transition={{ duration: 0.2 }}
>
<div className="flex flex-col gap-2 text-sm">
{/* Title */}
<div className="flex gap-2.5 items-center">
<div className="flex gap-2.5 items-center select-none">
<Bars3CenterLeftIcon className="w-5 h-5" />
<h1>On This Page</h1>
</div>
{/* Headers */}
<ul className="relative">
<ul>
{headers.map((header: Header) => (
<li
key={header.id}
className={cn(
"hover:opacity-80 transition-all transform-gpu relative",
activeHeader === header.id
? "font-semibold text-primary"
: "opacity-65"
)}
style={{ paddingLeft: `${(header.level - 1) * 16}px` }}
className="opacity-65 hover:opacity-80 transition-all transform-gpu"
style={{ marginLeft: `${(header.level - 1) * 16}px` }}
>
{/* Indentation */}
{header.level > 1 && (
<div
className="absolute left-0 top-0 bottom-0 border-l border-muted"
style={{
left: `${(header.level - 2) * 16 + 4}px`,
}}
/>
)}
{/* Header */}
<Link
href={`#${header.id}`}
draggable={false}
className="block py-1"
>
{truncateText(header.text, 24)}
</Link>
<Link href={`#${header.id}`}>{header.text}</Link>
</li>
))}
</ul>
{/* Footer */}
<div>
<Separator className="mt-1 mb-3.5" />
<Footer page={page} />
</div>
</motion.div>
);
};
const Footer = ({ page }: { page: DocsContentMetadata }): ReactElement => {
const [hasScrolled, setHasScrolled] = useState<boolean>(false);
useEffect(() => {
const handleScroll = () => setHasScrolled(window.scrollY > 400);
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return (
<footer className="flex flex-col opacity-75">
{/* Edit on Git */}
<Link
className="flex gap-1.5 items-center text-xs hover:opacity-75 transition-all transform-gpu group"
href={`https://git.rainnny.club/PulseApp/docs/src/branch/master/docs/${page.slug}.md`}
target="_blank"
draggable={false}
>
<span>Edit this page on GitHub</span>
<ArrowLongRightIcon className="w-4 h-4 group-hover:translate-x-0.5 transition-all transform-gpu" />
</Link>
{/* Scroll to Top */}
<div
className={cn(
"transition-opacity transform-gpu",
hasScrolled
? "opacity-100"
: "opacity-0 pointer-events-none"
)}
>
<Button
className="p-0 justify-start flex gap-1.5 items-center text-xs hover:bg-transparent hover:opacity-75 transition-all transform-gpu group"
variant="ghost"
onClick={() =>
window.scrollTo({ top: 0, behavior: "smooth" })
}
>
<span>Scroll to Top</span>
<ArrowLongUpIcon className="w-4 h-4 group-hover:translate-x-0.5 transition-all transform-gpu" />
</Button>
</div>
</footer>
);
};
export default OnThisPage;

View File

@ -101,10 +101,11 @@ const CategoryItem = ({
animate="open"
exit="collapsed"
variants={{
open: { opacity: 1, height: "auto" },
open: { opacity: 1, height: "auto", y: 0 },
collapsed: {
opacity: 0,
height: 0,
y: -20,
},
}}
transition={{

View File

@ -22,7 +22,7 @@ const Sidebar = (): ReactElement => (
</div>
{/* Desktop */}
<div className="hidden xs:flex sticky top-[4.3rem] max-h-[calc(100vh-3.5rem)] overflow-y-auto min-w-32 w-40 lg:w-52 py-5 flex-col justify-between transition-all transform-gpu">
<div className="hidden fixed top-[4.3rem] inset-y-0 min-w-32 w-40 sm:w-52 py-3 xs:flex flex-col justify-between transition-all transform-gpu">
<SidebarContent />
</div>
</>

View File

@ -1,47 +0,0 @@
import { ReactElement, ReactNode } from "react";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { SIDE_OPTIONS } from "@radix-ui/react-popper";
/**
* The props for a simple tooltip.
*/
type SimpleTooltipProps = {
/**
* The content to display in the tooltip.
*/
content: string | ReactElement;
/**
* The side to display the tooltip on.
*/
side?: (typeof SIDE_OPTIONS)[number];
/**
* The children to render in this tooltip.
*/
children: ReactNode;
};
/**
* A simple tooltip, this is wrapping the
* shadcn tooltip to make it easier to use.
*
* @return the tooltip jsx
*/
const SimpleTooltip = ({
content,
side,
children,
}: SimpleTooltipProps): ReactElement => (
<Tooltip>
<TooltipTrigger asChild>{children}</TooltipTrigger>
<TooltipContent className="bg-muted text-white" side={side}>
{content}
</TooltipContent>
</Tooltip>
);
export default SimpleTooltip;

View File

@ -1,150 +0,0 @@
"use client";
import { useEffect, useId, useRef, useState } from "react";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
interface GridPatternProps {
width?: number;
height?: number;
x?: number;
y?: number;
strokeDasharray?: any;
numSquares?: number;
className?: string;
maxOpacity?: number;
duration?: number;
repeatDelay?: number;
}
export function GridPattern({
width = 40,
height = 40,
x = -1,
y = -1,
strokeDasharray = 0,
numSquares = 50,
className,
maxOpacity = 0.5,
duration = 4,
repeatDelay = 0.5,
...props
}: GridPatternProps) {
const id = useId();
const containerRef = useRef(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const [squares, setSquares] = useState(() => generateSquares(numSquares));
function getPos() {
return [
Math.floor((Math.random() * dimensions.width) / width),
Math.floor((Math.random() * dimensions.height) / height),
];
}
// Adjust the generateSquares function to return objects with an id, x, and y
function generateSquares(count: number) {
return Array.from({ length: count }, (_, i) => ({
id: i,
pos: getPos(),
}));
}
// Function to update a single square's position
const updateSquarePosition = (id: number) => {
setSquares((currentSquares) =>
currentSquares.map((sq) =>
sq.id === id
? {
...sq,
pos: getPos(),
}
: sq
)
);
};
// Update squares to animate in
useEffect(() => {
if (dimensions.width && dimensions.height) {
setSquares(generateSquares(numSquares));
}
}, [dimensions, numSquares, generateSquares]);
// Resize observer to update container dimensions
useEffect(() => {
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
setDimensions({
width: entry.contentRect.width,
height: entry.contentRect.height,
});
}
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => {
if (containerRef.current) {
resizeObserver.unobserve(containerRef.current);
}
};
}, [containerRef]);
return (
<svg
ref={containerRef}
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/30 stroke-gray-400/30",
className
)}
{...props}
>
<defs>
<pattern
id={id}
width={width}
height={height}
patternUnits="userSpaceOnUse"
x={x}
y={y}
>
<path
d={`M.5 ${height}V.5H${width}`}
fill="none"
strokeDasharray={strokeDasharray}
/>
</pattern>
</defs>
<rect width="100%" height="100%" fill={`url(#${id})`} />
<svg x={x} y={y} className="overflow-visible">
{squares.map(({ pos: [x, y], id }, index) => (
<motion.rect
initial={{ opacity: 0 }}
animate={{ opacity: maxOpacity }}
transition={{
duration,
repeat: 1,
delay: index * 0.1,
repeatType: "reverse",
}}
onAnimationComplete={() => updateSquarePosition(id)}
key={`${x}-${y}-${index}`}
width={width - 1}
height={height - 1}
x={x * width + 1}
y={y * height + 1}
fill="currentColor"
strokeWidth="0"
/>
))}
</svg>
</svg>
);
}
export default GridPattern;

View File

@ -31,7 +31,7 @@ const SheetOverlay = React.forwardRef<
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-&lsqb;state=open&rsqb;:duration-&lsqb;450ms&rsqb; data-[state=open]:animate-in data-[state=closed]:animate-out",
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-[450ms] data-[state=open]:animate-in data-[state=closed]:animate-out",
{
variants: {
side: {

View File

@ -1,30 +0,0 @@
"use client";
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-105 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View File

@ -8,11 +8,3 @@
export const capitalizeWords = (str: string | undefined): string | undefined =>
str &&
str.toLowerCase().replace(/\b\w/g, (char: string) => char.toUpperCase());
export const truncateText = (
text: string | undefined,
maxLength: number
): string | undefined =>
text && text.length > maxLength
? text.slice(0, maxLength - 3).trim() + "..."
: text;