fix: move docs button to sidebar footer and open in new tab (#184)

* fix(ui): move docs to sidebar footer button with new-tab icon

* sidebar documentation
This commit is contained in:
Shaheer Sarfaraz 2026-02-18 13:36:16 +00:00 committed by GitHub
parent 16fdb425d8
commit 63bf5bdc87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 63 deletions

View File

@ -57,6 +57,11 @@ Ghostwriter is available in `discovered` and `ready` job views.
For details, see [Ghostwriter](/docs/next/features/ghostwriter). For details, see [Ghostwriter](/docs/next/features/ghostwriter).
### Opening documentation from the sidebar
1. Open the sidebar menu.
2. In the footer section under `Version <build>`, click **Documentation**, which opens the locally hosted docs in a new tab.
### Generating PDFs ### Generating PDFs
PDF generation uses: PDF generation uses:

View File

@ -2,7 +2,7 @@
* Shared layout components for consistent page structure. * Shared layout components for consistent page structure.
*/ */
import { type LucideIcon, Menu } from "lucide-react"; import { ExternalLink, type LucideIcon, Menu } from "lucide-react";
import type React from "react"; import type React from "react";
import { useState } from "react"; import { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
@ -60,22 +60,12 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
const setNavOpen = onNavOpenChange ?? setInternalNavOpen; const setNavOpen = onNavOpenChange ?? setInternalNavOpen;
const { version, updateAvailable } = useVersionCheck(); const { version, updateAvailable } = useVersionCheck();
const handleNavClick = ( const handleNavClick = (to: string, activePaths?: string[]) => {
to: string,
activePaths?: string[],
external?: boolean,
) => {
if (isNavActive(location.pathname, to, activePaths)) { if (isNavActive(location.pathname, to, activePaths)) {
setNavOpen(false); setNavOpen(false);
return; return;
} }
setNavOpen(false); setNavOpen(false);
if (external) {
setTimeout(() => {
window.location.href = to;
}, 150);
return;
}
setTimeout(() => navigate(to), 150); setTimeout(() => navigate(to), 150);
}; };
@ -95,46 +85,59 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
<SheetTitle>JobOps</SheetTitle> <SheetTitle>JobOps</SheetTitle>
</SheetHeader> </SheetHeader>
<nav className="mt-6 flex flex-col gap-2"> <nav className="mt-6 flex flex-col gap-2">
{NAV_LINKS.map( {NAV_LINKS.map(({ to, label, icon: NavIcon, activePaths }) => (
({ to, label, icon: NavIcon, activePaths, external }) => ( <button
<button key={to}
key={to} type="button"
type="button" onClick={() => handleNavClick(to, activePaths)}
onClick={() => handleNavClick(to, activePaths, external)} className={cn(
className={cn( "flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground text-left",
"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground text-left", isNavActive(location.pathname, to, activePaths)
isNavActive(location.pathname, to, activePaths) ? "bg-accent text-accent-foreground"
? "bg-accent text-accent-foreground" : "text-muted-foreground",
: "text-muted-foreground", )}
)} >
> <NavIcon className="h-4 w-4" />
<NavIcon className="h-4 w-4" /> {label}
{label} </button>
</button> ))}
),
)}
</nav> </nav>
{showVersionFooter && ( {showVersionFooter && (
<div className="mt-auto pt-6 pb-2"> <div className="mt-auto pt-6 pb-2">
<TooltipProvider> <TooltipProvider>
<a <div className="flex flex-col items-start gap-2">
href="https://github.com/DaKheera47/job-ops/releases" <a
target="_blank" href="https://github.com/DaKheera47/job-ops/releases"
rel="noopener noreferrer" target="_blank"
className="flex items-center gap-2 text-xs text-muted-foreground hover:text-foreground transition-colors" rel="noopener noreferrer"
> className="flex min-w-0 items-center gap-2 text-xs text-muted-foreground transition-colors hover:text-foreground"
<span>Version {version}</span> >
{updateAvailable && ( <span className="truncate">Version {version}</span>
<Tooltip> {updateAvailable && (
<TooltipTrigger asChild> <Tooltip>
<span className="h-2 w-2 rounded-full bg-emerald-500 cursor-pointer" /> <TooltipTrigger asChild>
</TooltipTrigger> <span className="h-2 w-2 shrink-0 cursor-pointer rounded-full bg-emerald-500" />
<TooltipContent> </TooltipTrigger>
<p>Update available</p> <TooltipContent>
</TooltipContent> <p>Update available</p>
</Tooltip> </TooltipContent>
)} </Tooltip>
</a> )}
</a>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => {
setNavOpen(false);
window.open("/docs", "_blank", "noopener,noreferrer");
}}
className="h-7 gap-1.5 px-2 text-xs"
>
<span>Documentation</span>
<ExternalLink className="h-3.5 w-3.5" />
</Button>
</div>
</TooltipProvider> </TooltipProvider>
</div> </div>
)} )}

View File

@ -1,5 +1,4 @@
import { import {
BookOpen,
Columns3, Columns3,
Home, Home,
Inbox, Inbox,
@ -8,26 +7,13 @@ import {
Shield, Shield,
} from "lucide-react"; } from "lucide-react";
declare const __APP_VERSION__: string;
export type NavLink = { export type NavLink = {
to: string; to: string;
label: string; label: string;
icon: typeof Home; icon: typeof Home;
activePaths?: string[]; activePaths?: string[];
external?: boolean;
}; };
const releaseVersion = (() => {
if (typeof __APP_VERSION__ !== "string") return null;
const match = __APP_VERSION__.match(/^v\d+\.\d+\.\d+/);
return match ? match[0] : null;
})();
const docsLabel = releaseVersion
? `Documentation (${releaseVersion})`
: "Documentation";
export const NAV_LINKS: NavLink[] = [ export const NAV_LINKS: NavLink[] = [
{ to: "/overview", label: "Overview", icon: Home }, { to: "/overview", label: "Overview", icon: Home },
{ {
@ -48,7 +34,6 @@ export const NAV_LINKS: NavLink[] = [
activePaths: ["/applications/in-progress"], activePaths: ["/applications/in-progress"],
}, },
{ to: "/tracking-inbox", label: "Tracking Inbox", icon: Inbox }, { to: "/tracking-inbox", label: "Tracking Inbox", icon: Inbox },
{ to: "/docs", label: docsLabel, icon: BookOpen, external: true },
{ to: "/visa-sponsors", label: "Visa Sponsors", icon: Shield }, { to: "/visa-sponsors", label: "Visa Sponsors", icon: Shield },
{ to: "/settings", label: "Settings", icon: Settings }, { to: "/settings", label: "Settings", icon: Settings },
]; ];