Skip to content

Commit aaa09b4

Browse files
feat: Implement comprehensive help system with contextual icons (#122)
* feat: implement comprehensive help system with contextual icons - Add HelpModal component with navigation sidebar and 7 help sections - Add HelpButton component for main header controls - Add ContextualHelpIcon component for contextual help throughout UI - Add help icons to all major UI sections: - Settings modals (Server Settings, General Settings) - Sync button with update system help - Tab headers (Available, Downloaded, Installed Scripts) - FilterBar and CategorySidebar - Add comprehensive help content covering: - Server Settings: PVE server management, auth types, color coding - General Settings: Save filters, GitHub integration, authentication - Sync Button: Script metadata syncing explanation - Available Scripts: Browsing, filtering, downloading - Downloaded Scripts: Local script management and updates - Installed Scripts: Auto-detection feature (primary focus), manual management - Update System: Automatic/manual update process, release notes - Improve VersionDisplay: remove 'Update Available' text, add 'Release Notes:' label - Make help icons more noticeable with increased size - Fix dark theme compatibility issues in help modal * fix: resolve linting errors in HelpModal component - Remove unused Filter import - Fix unescaped entities by replacing apostrophes and quotes with HTML entities - All linting errors resolved * feat: implement release notes modal system - Add getAllReleases API endpoint to fetch GitHub releases with notes - Create ReleaseNotesModal component with localStorage version tracking - Add sticky Footer component with release notes link - Make version badge clickable to open release notes - Auto-show modal after updates when version changes - Track last seen version in localStorage to prevent repeated shows - Highlight new version in modal when opened after update - Add manual access via footer and version badge clicks * fix: use nullish coalescing operator in ReleaseNotesModal - Replace logical OR (||) with nullish coalescing (??) operator - Fixes ESLint prefer-nullish-coalescing rule violation - Ensures build passes successfully
1 parent 24afce4 commit aaa09b4

File tree

13 files changed

+1050
-97
lines changed

13 files changed

+1050
-97
lines changed

src/app/_components/CategorySidebar.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import { useState } from 'react';
4+
import { ContextualHelpIcon } from './ContextualHelpIcon';
45

56
interface CategorySidebarProps {
67
categories: string[];
@@ -201,9 +202,12 @@ export function CategorySidebar({
201202
{/* Header */}
202203
<div className="flex items-center justify-between p-4 border-b border-border">
203204
{!isCollapsed && (
204-
<div>
205-
<h3 className="text-lg font-semibold text-foreground">Categories</h3>
206-
<p className="text-sm text-muted-foreground">{totalScripts} Total scripts</p>
205+
<div className="flex items-center justify-between w-full">
206+
<div>
207+
<h3 className="text-lg font-semibold text-foreground">Categories</h3>
208+
<p className="text-sm text-muted-foreground">{totalScripts} Total scripts</p>
209+
</div>
210+
<ContextualHelpIcon section="available-scripts" tooltip="Help with categories" />
207211
</div>
208212
)}
209213
<button
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { HelpModal } from './HelpModal';
5+
import { Button } from './ui/button';
6+
import { HelpCircle } from 'lucide-react';
7+
8+
interface ContextualHelpIconProps {
9+
section: string;
10+
className?: string;
11+
size?: 'sm' | 'default';
12+
tooltip?: string;
13+
}
14+
15+
export function ContextualHelpIcon({
16+
section,
17+
className = '',
18+
size = 'sm',
19+
tooltip = 'Help'
20+
}: ContextualHelpIconProps) {
21+
const [isOpen, setIsOpen] = useState(false);
22+
23+
const sizeClasses = size === 'sm'
24+
? 'h-7 w-7 p-1.5'
25+
: 'h-9 w-9 p-2';
26+
27+
return (
28+
<>
29+
<Button
30+
onClick={() => setIsOpen(true)}
31+
variant="ghost"
32+
size="icon"
33+
className={`${sizeClasses} text-muted-foreground hover:text-foreground hover:bg-muted ${className}`}
34+
title={tooltip}
35+
>
36+
<HelpCircle className="w-4 h-4" />
37+
</Button>
38+
39+
<HelpModal
40+
isOpen={isOpen}
41+
onClose={() => setIsOpen(false)}
42+
initialSection={section}
43+
/>
44+
</>
45+
);
46+
}

src/app/_components/FilterBar.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import React, { useState } from "react";
44
import { Button } from "./ui/button";
5+
import { ContextualHelpIcon } from "./ContextualHelpIcon";
56
import { Package, Monitor, Wrench, Server, FileText, Calendar, RefreshCw, Filter } from "lucide-react";
67

78
export interface FilterState {
@@ -104,6 +105,14 @@ export function FilterBar({
104105
</div>
105106
)}
106107

108+
{/* Filter Header */}
109+
{!isLoadingFilters && (
110+
<div className="mb-4 flex items-center justify-between">
111+
<h3 className="text-lg font-medium text-foreground">Filter Scripts</h3>
112+
<ContextualHelpIcon section="available-scripts" tooltip="Help with filtering and searching" />
113+
</div>
114+
)}
115+
107116
{/* Search Bar */}
108117
<div className="mb-4">
109118
<div className="relative max-w-md w-full">

src/app/_components/Footer.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use client';
2+
3+
import { api } from '~/trpc/react';
4+
import { Button } from './ui/button';
5+
import { ExternalLink, FileText } from 'lucide-react';
6+
7+
interface FooterProps {
8+
onOpenReleaseNotes: () => void;
9+
}
10+
11+
export function Footer({ onOpenReleaseNotes }: FooterProps) {
12+
const { data: versionData } = api.version.getCurrentVersion.useQuery();
13+
14+
return (
15+
<footer className="sticky bottom-0 mt-auto border-t border-border bg-muted/30 py-6 backdrop-blur-sm">
16+
<div className="container mx-auto px-4">
17+
<div className="flex flex-col sm:flex-row items-center justify-between gap-4 text-sm text-muted-foreground">
18+
<div className="flex items-center gap-4">
19+
<span>© 2024 PVE Scripts Local</span>
20+
{versionData?.success && versionData.version && (
21+
<Button
22+
variant="ghost"
23+
size="sm"
24+
onClick={onOpenReleaseNotes}
25+
className="h-auto p-1 text-xs hover:text-foreground"
26+
>
27+
v{versionData.version}
28+
</Button>
29+
)}
30+
</div>
31+
32+
<div className="flex items-center gap-4">
33+
<Button
34+
variant="ghost"
35+
size="sm"
36+
onClick={onOpenReleaseNotes}
37+
className="h-auto p-2 text-xs hover:text-foreground"
38+
>
39+
<FileText className="h-3 w-3 mr-1" />
40+
Release Notes
41+
</Button>
42+
43+
<Button
44+
variant="ghost"
45+
size="sm"
46+
asChild
47+
className="h-auto p-2 text-xs hover:text-foreground"
48+
>
49+
<a
50+
href="https://github.com/community-scripts/ProxmoxVE-Local"
51+
target="_blank"
52+
rel="noopener noreferrer"
53+
className="flex items-center gap-1"
54+
>
55+
<ExternalLink className="h-3 w-3" />
56+
GitHub
57+
</a>
58+
</Button>
59+
</div>
60+
</div>
61+
</div>
62+
</footer>
63+
);
64+
}

src/app/_components/GeneralSettingsModal.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
44
import { Button } from './ui/button';
55
import { Input } from './ui/input';
66
import { Toggle } from './ui/toggle';
7+
import { ContextualHelpIcon } from './ContextualHelpIcon';
78

89
interface GeneralSettingsModalProps {
910
isOpen: boolean;
@@ -280,7 +281,10 @@ export function GeneralSettingsModal({ isOpen, onClose }: GeneralSettingsModalPr
280281
<div className="bg-card rounded-lg shadow-xl max-w-4xl w-full max-h-[95vh] sm:max-h-[90vh] overflow-hidden">
281282
{/* Header */}
282283
<div className="flex items-center justify-between p-4 sm:p-6 border-b border-border">
283-
<h2 className="text-xl sm:text-2xl font-bold text-card-foreground">Settings</h2>
284+
<div className="flex items-center gap-2">
285+
<h2 className="text-xl sm:text-2xl font-bold text-card-foreground">Settings</h2>
286+
<ContextualHelpIcon section="general-settings" tooltip="Help with General Settings" />
287+
</div>
284288
<Button
285289
onClick={onClose}
286290
variant="ghost"

src/app/_components/HelpButton.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { HelpModal } from './HelpModal';
5+
import { Button } from './ui/button';
6+
import { HelpCircle } from 'lucide-react';
7+
8+
interface HelpButtonProps {
9+
initialSection?: string;
10+
}
11+
12+
export function HelpButton({ initialSection }: HelpButtonProps) {
13+
const [isOpen, setIsOpen] = useState(false);
14+
15+
return (
16+
<>
17+
<div className="flex flex-col sm:flex-row sm:items-center gap-3">
18+
<div className="text-sm text-muted-foreground font-medium">
19+
Need help?
20+
</div>
21+
<Button
22+
onClick={() => setIsOpen(true)}
23+
variant="outline"
24+
size="default"
25+
className="inline-flex items-center"
26+
title="Open Help"
27+
>
28+
<HelpCircle className="w-5 h-5 mr-2" />
29+
Help
30+
</Button>
31+
</div>
32+
33+
<HelpModal
34+
isOpen={isOpen}
35+
onClose={() => setIsOpen(false)}
36+
initialSection={initialSection}
37+
/>
38+
</>
39+
);
40+
}

0 commit comments

Comments
 (0)