breadcrumb and better mobile support
Some checks failed
Deploy / deploy (ubuntu-latest, 2.44.0) (push) Failing after 23s

Took 27 minutes
This commit is contained in:
Braydon 2024-10-06 17:10:39 -04:00
parent 8298e33f44
commit 28bb9c61ac
15 changed files with 417 additions and 343 deletions

1
.gitattributes vendored
View File

@ -1 +0,0 @@
*.lockb binary diff=lockb

BIN
bun.lockb

Binary file not shown.

View File

@ -5,4 +5,5 @@ summary: 'petentium usu tota noluisse errem elaboraret auctor.'
--- ---
# Get started with Pulse App! # Get started with Pulse App!
petentium usu tota noluisse errem elaboraret auctor. petentium usu tota noluisse errem elaboraret auctor.

View File

@ -2,6 +2,14 @@ import { ReactElement } from "react";
import { getDocsContent } from "@/lib/mdx"; import { getDocsContent } from "@/lib/mdx";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { CustomMDX } from "@/components/mdx"; import { CustomMDX } from "@/components/mdx";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { capitalizeWords } from "@/lib/string";
/** /**
* The page to render the documentation markdown content. * The page to render the documentation markdown content.
@ -25,9 +33,39 @@ const DocsPage = async ({
if (!content) { if (!content) {
notFound(); notFound();
} }
const splitSlug: string[] = content.slug?.split("/") || [];
return ( return (
<main> <main className="flex flex-col">
{/* Breadcrumb */}
<Breadcrumb className="pt-4 select-none">
<BreadcrumbList>
{splitSlug.map(
(part: string, index: number): ReactElement => {
const slug: string = splitSlug
.slice(1, index + 1)
.join("/");
return (
<div className="flex items-center" key={part}>
<BreadcrumbItem>
<BreadcrumbLink
href={slug}
draggable={false}
>
{capitalizeWords(part)}
</BreadcrumbLink>
</BreadcrumbItem>
{index < splitSlug.length - 1 && (
<BreadcrumbSeparator className="pl-1.5" />
)}
</div>
);
}
)}
</BreadcrumbList>
</Breadcrumb>
{/* Content */}
<CustomMDX source={content.content} /> <CustomMDX source={content.content} />
</main> </main>
); );

View File

@ -72,9 +72,32 @@ body {
@layer base { @layer base {
* { * {
@apply border-border; @apply border-border;
/* Scrollbar (Firefox) */
scrollbar-color: hsl(var(--accent)) hsl(var(--background));
scrollbar-width: thin;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} }
/* Scrollbar (Chrome & Safari) */
@layer base {
::-webkit-scrollbar {
@apply w-1.5;
}
::-webkit-scrollbar-track {
@apply bg-inherit;
}
::-webkit-scrollbar-thumb {
@apply bg-accent rounded-3xl;
}
::-webkit-scrollbar-thumb:hover {
@apply bg-opacity-80;
}
}

View File

@ -2,7 +2,6 @@ import { ReactElement } from "react";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Input } from "@/components/ui/input";
import QuickSearchDialog from "@/components/navbar/search-dialog"; import QuickSearchDialog from "@/components/navbar/search-dialog";
import { getDocsContent } from "@/lib/mdx"; import { getDocsContent } from "@/lib/mdx";
@ -33,9 +32,7 @@ const Navbar = (): ReactElement => {
{/* Right */} {/* Right */}
<div className="flex gap-5 sm:gap-7 items-center transition-all transform-gpu"> <div className="flex gap-5 sm:gap-7 items-center transition-all transform-gpu">
{/* Search */} {/* Search */}
<div className="hidden xs:flex">
<QuickSearchDialog pages={pages} /> <QuickSearchDialog pages={pages} />
</div>
{/* Social */} {/* Social */}
<div className="flex gap-5 items-center"> <div className="flex gap-5 items-center">

View File

@ -13,6 +13,7 @@ import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime"; import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
import { Button } from "@/components/ui/button";
/** /**
* The dialog for quickly searching the docs. * The dialog for quickly searching the docs.
@ -44,9 +45,11 @@ const QuickSearchDialog = ({
<> <>
{/* Button to open */} {/* Button to open */}
<div <div
className="hover:opacity-85 transition-all transform-gpu" className="cursor-pointer hover:opacity-85 transition-all transform-gpu select-none"
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
> >
{/* Bigger Screens */}
<div className="hidden xs:flex">
<div className="absolute top-2.5 left-3 z-10"> <div className="absolute top-2.5 left-3 z-10">
<MagnifyingGlassIcon className="w-[1.15rem] h-[1.15rem]" /> <MagnifyingGlassIcon className="w-[1.15rem] h-[1.15rem]" />
</div> </div>
@ -66,13 +69,22 @@ const QuickSearchDialog = ({
</div> </div>
</div> </div>
{/* Smaller Screens */}
<Button className="p-2 flex xs:hidden" variant="outline">
<MagnifyingGlassIcon className="w-5 h-5" />
</Button>
</div>
{/* Dialog */} {/* Dialog */}
<CommandDialog open={open} onOpenChange={setOpen}> <CommandDialog open={open} onOpenChange={setOpen}>
{/* Input */} {/* Input */}
<CommandInput placeholder="Start typing to get started..." /> <CommandInput
className="select-none"
placeholder="Start typing to get started..."
/>
{/* Results */} {/* Results */}
<CommandList> <CommandList className="select-none">
<CommandEmpty className="text-center text-red-500"> <CommandEmpty className="text-center text-red-500">
No results were found. No results were found.
</CommandEmpty> </CommandEmpty>
@ -85,7 +97,7 @@ const QuickSearchDialog = ({
): ReactElement => ( ): ReactElement => (
<CommandItem <CommandItem
key={index} key={index}
className="flex flex-col gap-1 items-start" className="flex flex-col gap-1 items-start cursor-pointer"
onSelect={() => { onSelect={() => {
setOpen(false); setOpen(false);
router.push(`/${result.slug}`); router.push(`/${result.slug}`);

View File

@ -8,7 +8,6 @@ import {
} from "@/components/ui/collapsible"; } from "@/components/ui/collapsible";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import Link from "next/link"; import Link from "next/link";
import { ChevronRight } from "lucide-react";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
@ -52,7 +51,7 @@ const CategoryItem = ({
const hasChildren = Object.keys(node.children).length > 0; const hasChildren = Object.keys(node.children).length > 0;
return ( return (
<div className={`relative ${depth > 0 ? "ml-4" : ""}`}> <div className={`relative ${depth > 0 ? "ml-4" : ""} select-none`}>
{/* Indentation */} {/* Indentation */}
{depth > 0 && ( {depth > 0 && (
<div <div

View File

@ -24,7 +24,7 @@ const ThemeSwitcher = (): ReactElement => {
return mounted ? ( return mounted ? (
<Button <Button
className="p-1.5 flex gap-7 items-center hover:opacity-85" className="p-1.5 flex gap-7 justify-start items-center hover:opacity-85 select-none"
variant="ghost" variant="ghost"
onClick={() => setTheme(isLight ? "dark" : "light")} onClick={() => setTheme(isLight ? "dark" : "light")}
> >
@ -38,7 +38,7 @@ const ThemeSwitcher = (): ReactElement => {
}} }}
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
> >
<Sun className="w-[1.2rem] h-[1.2rem]" /> <Sun className="w-[1.1rem] h-[1.1rem]" />
</motion.div> </motion.div>
<motion.div <motion.div
className="absolute" className="absolute"
@ -49,10 +49,10 @@ const ThemeSwitcher = (): ReactElement => {
}} }}
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
> >
<MoonStar className="w-[1.2rem] h-[1.2rem]" /> <MoonStar className="w-[1.1rem] h-[1.1rem]" />
</motion.div> </motion.div>
</div> </div>
<span className="font-semibold">{capitalizeWords(theme)}</span> <span>{capitalizeWords(theme)}</span>
</Button> </Button>
) : ( ) : (
<></> <></>

View File

@ -1,8 +1,8 @@
import * as React from "react" import * as React from "react";
import { Slot } from "@radix-ui/react-slot" import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
@ -32,26 +32,26 @@ const buttonVariants = cva(
size: "default", size: "default",
}, },
} }
) );
export interface ButtonProps export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>, extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> { VariantProps<typeof buttonVariants> {
asChild?: boolean asChild?: boolean;
} }
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => { ({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button" const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
className={cn(buttonVariants({ variant, size, className }))} className={cn(buttonVariants({ variant, size, className }))}
ref={ref} ref={ref}
{...props} {...props}
/> />
) );
} }
) );
Button.displayName = "Button" Button.displayName = "Button";
export { Button, buttonVariants } export { Button, buttonVariants };

View File

@ -1,11 +1,11 @@
"use client" "use client";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
const Collapsible = CollapsiblePrimitive.Root const Collapsible = CollapsiblePrimitive.Root;
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
export { Collapsible, CollapsibleTrigger, CollapsibleContent } export { Collapsible, CollapsibleTrigger, CollapsibleContent };

View File

@ -1,12 +1,12 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import { type DialogProps } from "@radix-ui/react-dialog" import { type DialogProps } from "@radix-ui/react-dialog";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons" import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { Command as CommandPrimitive } from "cmdk" import { Command as CommandPrimitive } from "cmdk";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
import { Dialog, DialogContent } from "@/components/ui/dialog" import { Dialog, DialogContent } from "@/components/ui/dialog";
const Command = React.forwardRef< const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>, React.ElementRef<typeof CommandPrimitive>,
@ -20,8 +20,8 @@ const Command = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
Command.displayName = CommandPrimitive.displayName Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {} interface CommandDialogProps extends DialogProps {}
@ -34,8 +34,8 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
</Command> </Command>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
) );
} };
const CommandInput = React.forwardRef< const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>, React.ElementRef<typeof CommandPrimitive.Input>,
@ -52,9 +52,9 @@ const CommandInput = React.forwardRef<
{...props} {...props}
/> />
</div> </div>
)) ));
CommandInput.displayName = CommandPrimitive.Input.displayName CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef< const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>, React.ElementRef<typeof CommandPrimitive.List>,
@ -62,12 +62,15 @@ const CommandList = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<CommandPrimitive.List <CommandPrimitive.List
ref={ref} ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)} className={cn(
"max-h-[300px] overflow-y-auto overflow-x-hidden",
className
)}
{...props} {...props}
/> />
)) ));
CommandList.displayName = CommandPrimitive.List.displayName CommandList.displayName = CommandPrimitive.List.displayName;
const CommandEmpty = React.forwardRef< const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>, React.ElementRef<typeof CommandPrimitive.Empty>,
@ -78,9 +81,9 @@ const CommandEmpty = React.forwardRef<
className="py-6 text-center text-sm" className="py-6 text-center text-sm"
{...props} {...props}
/> />
)) ));
CommandEmpty.displayName = CommandPrimitive.Empty.displayName CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
const CommandGroup = React.forwardRef< const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>, React.ElementRef<typeof CommandPrimitive.Group>,
@ -94,9 +97,9 @@ const CommandGroup = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
CommandGroup.displayName = CommandPrimitive.Group.displayName CommandGroup.displayName = CommandPrimitive.Group.displayName;
const CommandSeparator = React.forwardRef< const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>, React.ElementRef<typeof CommandPrimitive.Separator>,
@ -107,8 +110,8 @@ const CommandSeparator = React.forwardRef<
className={cn("-mx-1 h-px bg-border", className)} className={cn("-mx-1 h-px bg-border", className)}
{...props} {...props}
/> />
)) ));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
const CommandItem = React.forwardRef< const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>, React.ElementRef<typeof CommandPrimitive.Item>,
@ -122,9 +125,9 @@ const CommandItem = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
CommandItem.displayName = CommandPrimitive.Item.displayName CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({ const CommandShortcut = ({
className, className,
@ -138,9 +141,9 @@ const CommandShortcut = ({
)} )}
{...props} {...props}
/> />
) );
} };
CommandShortcut.displayName = "CommandShortcut" CommandShortcut.displayName = "CommandShortcut";
export { export {
Command, Command,
@ -152,4 +155,4 @@ export {
CommandItem, CommandItem,
CommandShortcut, CommandShortcut,
CommandSeparator, CommandSeparator,
} };

View File

@ -1,18 +1,18 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog" import * as DialogPrimitive from "@radix-ui/react-dialog";
import { Cross2Icon } from "@radix-ui/react-icons" import { Cross2Icon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const Dialog = DialogPrimitive.Root const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close const DialogClose = DialogPrimitive.Close;
const DialogOverlay = React.forwardRef< const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>, React.ElementRef<typeof DialogPrimitive.Overlay>,
@ -26,8 +26,8 @@ const DialogOverlay = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef< const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>, React.ElementRef<typeof DialogPrimitive.Content>,
@ -50,8 +50,8 @@ const DialogContent = React.forwardRef<
</DialogPrimitive.Close> </DialogPrimitive.Close>
</DialogPrimitive.Content> </DialogPrimitive.Content>
</DialogPortal> </DialogPortal>
)) ));
DialogContent.displayName = DialogPrimitive.Content.displayName DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({ const DialogHeader = ({
className, className,
@ -64,8 +64,8 @@ const DialogHeader = ({
)} )}
{...props} {...props}
/> />
) );
DialogHeader.displayName = "DialogHeader" DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({ const DialogFooter = ({
className, className,
@ -78,8 +78,8 @@ const DialogFooter = ({
)} )}
{...props} {...props}
/> />
) );
DialogFooter.displayName = "DialogFooter" DialogFooter.displayName = "DialogFooter";
const DialogTitle = React.forwardRef< const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>, React.ElementRef<typeof DialogPrimitive.Title>,
@ -93,8 +93,8 @@ const DialogTitle = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
DialogTitle.displayName = DialogPrimitive.Title.displayName DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef< const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>, React.ElementRef<typeof DialogPrimitive.Description>,
@ -105,8 +105,8 @@ const DialogDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)} className={cn("text-sm text-muted-foreground", className)}
{...props} {...props}
/> />
)) ));
DialogDescription.displayName = DialogPrimitive.Description.displayName DialogDescription.displayName = DialogPrimitive.Description.displayName;
export { export {
Dialog, Dialog,
@ -119,4 +119,4 @@ export {
DialogFooter, DialogFooter,
DialogTitle, DialogTitle,
DialogDescription, DialogDescription,
} };

View File

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
export interface InputProps export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {} extends React.InputHTMLAttributes<HTMLInputElement> {}
@ -17,9 +17,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
ref={ref} ref={ref}
{...props} {...props}
/> />
) );
} }
) );
Input.displayName = "Input" Input.displayName = "Input";
export { Input } export { Input };

View File

@ -1,9 +1,9 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator" import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const Separator = React.forwardRef< const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>, React.ElementRef<typeof SeparatorPrimitive.Root>,
@ -19,13 +19,15 @@ const Separator = React.forwardRef<
orientation={orientation} orientation={orientation}
className={cn( className={cn(
"shrink-0 bg-border", "shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", orientation === "horizontal"
? "h-[1px] w-full"
: "h-full w-[1px]",
className className
)} )}
{...props} {...props}
/> />
) )
) );
Separator.displayName = SeparatorPrimitive.Root.displayName Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator } export { Separator };