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:
parent
16fdb425d8
commit
63bf5bdc87
@ -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:
|
||||||
|
|||||||
@ -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,12 +85,11 @@ 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, external)}
|
onClick={() => handleNavClick(to, activePaths)}
|
||||||
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)
|
||||||
@ -111,23 +100,23 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
|
|||||||
<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>
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
<a
|
<a
|
||||||
href="https://github.com/DaKheera47/job-ops/releases"
|
href="https://github.com/DaKheera47/job-ops/releases"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="flex items-center gap-2 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
className="flex min-w-0 items-center gap-2 text-xs text-muted-foreground transition-colors hover:text-foreground"
|
||||||
>
|
>
|
||||||
<span>Version {version}</span>
|
<span className="truncate">Version {version}</span>
|
||||||
{updateAvailable && (
|
{updateAvailable && (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<span className="h-2 w-2 rounded-full bg-emerald-500 cursor-pointer" />
|
<span className="h-2 w-2 shrink-0 cursor-pointer rounded-full bg-emerald-500" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Update available</p>
|
<p>Update available</p>
|
||||||
@ -135,6 +124,20 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
|
|||||||
</Tooltip>
|
</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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -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 },
|
||||||
];
|
];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user