Add Help page with full User Guide
Covers: overview, sheets, AI commands, brief extraction, export CSV, export templates, admin (clients, dropdowns, users), and login/emergency access. Admin-only sections are hidden for regular users. Accessible via sidebar "Help" link at /help. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6c93915768
commit
8f57c657fa
3 changed files with 440 additions and 0 deletions
|
|
@ -15,6 +15,7 @@ import AdminUsersPage from './pages/admin/AdminUsersPage'
|
|||
import AdminDropdownsPage from './pages/admin/AdminDropdownsPage'
|
||||
import AdminClientsPage from './pages/admin/AdminClientsPage'
|
||||
import LoginPage from './pages/LoginPage'
|
||||
import HelpPage from './pages/HelpPage'
|
||||
|
||||
function AuthGate({ children }: { children: React.ReactNode }) {
|
||||
const { instance, inProgress, accounts } = useMsal()
|
||||
|
|
@ -109,6 +110,7 @@ export default function App() {
|
|||
<Route path="/admin/users" element={<AdminRoute><AdminUsersPage /></AdminRoute>} />
|
||||
<Route path="/admin/dropdowns" element={<AdminRoute><AdminDropdownsPage /></AdminRoute>} />
|
||||
<Route path="/admin/clients" element={<AdminRoute><AdminClientsPage /></AdminRoute>} />
|
||||
<Route path="/help" element={<HelpPage />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</AppShell>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@ const IconPlus = () => (
|
|||
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
|
||||
</svg>
|
||||
)
|
||||
const IconHelp = () => (
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default function Sidebar() {
|
||||
const navigate = useNavigate()
|
||||
|
|
@ -125,6 +132,18 @@ export default function Sidebar() {
|
|||
<IconUpload />
|
||||
Upload Brief
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => navigate('/help')}
|
||||
className="w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm text-left transition-colors"
|
||||
style={{
|
||||
background: location.pathname === '/help' ? 'var(--accent-dim)' : 'transparent',
|
||||
color: location.pathname === '/help' ? 'var(--accent)' : 'var(--text-secondary)',
|
||||
}}
|
||||
>
|
||||
<IconHelp />
|
||||
Help
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* ── Divider ── */}
|
||||
|
|
|
|||
419
frontend/src/pages/HelpPage.tsx
Normal file
419
frontend/src/pages/HelpPage.tsx
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useAuthStore } from '../stores/useAuthStore'
|
||||
|
||||
// ── Section types ──────────────────────────────────────────────────────────────
|
||||
|
||||
interface Section {
|
||||
id: string
|
||||
icon: string
|
||||
title: string
|
||||
adminOnly?: boolean
|
||||
content: React.ReactNode
|
||||
}
|
||||
|
||||
// ── Reusable helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
const H2 = ({ children }: { children: React.ReactNode }) => (
|
||||
<h2 style={{ color: 'var(--text-primary)', fontSize: 16, fontWeight: 700, marginBottom: 12, marginTop: 0 }}>{children}</h2>
|
||||
)
|
||||
const H3 = ({ children }: { children: React.ReactNode }) => (
|
||||
<h3 style={{ color: 'var(--accent)', fontSize: 13, fontWeight: 600, marginBottom: 8, marginTop: 20 }}>{children}</h3>
|
||||
)
|
||||
const P = ({ children }: { children: React.ReactNode }) => (
|
||||
<p style={{ color: 'var(--text-secondary)', fontSize: 13, lineHeight: 1.7, marginBottom: 10 }}>{children}</p>
|
||||
)
|
||||
const Li = ({ children }: { children: React.ReactNode }) => (
|
||||
<li style={{ color: 'var(--text-secondary)', fontSize: 13, lineHeight: 1.7, marginBottom: 4 }}>{children}</li>
|
||||
)
|
||||
const Code = ({ children }: { children: React.ReactNode }) => (
|
||||
<code style={{
|
||||
background: 'rgba(255,196,7,0.12)', color: 'var(--accent)',
|
||||
padding: '1px 6px', borderRadius: 4, fontSize: 12, fontFamily: 'monospace',
|
||||
}}>{children}</code>
|
||||
)
|
||||
const Tip = ({ children }: { children: React.ReactNode }) => (
|
||||
<div style={{
|
||||
background: 'rgba(255,196,7,0.07)', border: '1px solid rgba(255,196,7,0.2)',
|
||||
borderRadius: 8, padding: '10px 14px', marginBottom: 12,
|
||||
}}>
|
||||
<span style={{ color: 'var(--accent)', fontWeight: 600, fontSize: 12 }}>Tip: </span>
|
||||
<span style={{ color: 'var(--text-secondary)', fontSize: 13 }}>{children}</span>
|
||||
</div>
|
||||
)
|
||||
const Steps = ({ items }: { items: string[] }) => (
|
||||
<ol style={{ paddingLeft: 20, margin: '8px 0 12px' }}>
|
||||
{items.map((item, i) => (
|
||||
<li key={i} style={{ color: 'var(--text-secondary)', fontSize: 13, lineHeight: 1.7, marginBottom: 6 }}
|
||||
dangerouslySetInnerHTML={{ __html: item }} />
|
||||
))}
|
||||
</ol>
|
||||
)
|
||||
|
||||
// ── Sections ───────────────────────────────────────────────────────────────────
|
||||
|
||||
const SECTIONS: Section[] = [
|
||||
{
|
||||
id: 'overview',
|
||||
icon: '📋',
|
||||
title: 'Overview',
|
||||
content: (
|
||||
<>
|
||||
<H2>What is AC Helper?</H2>
|
||||
<P>
|
||||
AC Helper is an Activation Calendar management tool for Oliver Agency.
|
||||
It lets you create and manage deliverable sheets, extract deliverables from briefs using AI,
|
||||
and export them in a format tailored to each client.
|
||||
</P>
|
||||
<H3>Core concepts</H3>
|
||||
<ul style={{ paddingLeft: 20, margin: '0 0 12px' }}>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Sheet</strong> — a spreadsheet of deliverables (rows). Each row is one ad/asset.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Brief extraction</strong> — upload a client brief (PDF, PPTX, DOCX, XLSX) and AI reads it and populates a sheet automatically.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>AI command</strong> — type a plain-English instruction to add or modify rows in the sheet.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Client</strong> — each client can have its own Category/Media hierarchy and CSV export format.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Export template</strong> — define which columns appear in the exported CSV and what they're called.</Li>
|
||||
</ul>
|
||||
<H3>Navigation</H3>
|
||||
<ul style={{ paddingLeft: 20, margin: '0 0 12px' }}>
|
||||
<Li>The <strong style={{ color: 'var(--text-primary)' }}>sidebar</strong> (left) lists all your sheets. Click any sheet to open it.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Dashboard</strong> — quick access to recent sheets and extractions.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Upload Brief</strong> — start a new AI extraction.</Li>
|
||||
<Li>Admins see <strong style={{ color: 'var(--text-primary)' }}>Users / Clients / Dropdowns</strong> links at the bottom of the sidebar.</Li>
|
||||
</ul>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'sheets',
|
||||
icon: '📄',
|
||||
title: 'Sheets',
|
||||
content: (
|
||||
<>
|
||||
<H2>Working with Sheets</H2>
|
||||
<H3>Create a new sheet</H3>
|
||||
<Steps items={[
|
||||
'Click the <strong>+</strong> button next to "Sheets" in the sidebar, or click <strong>New Sheet</strong> on the Dashboard.',
|
||||
'A blank sheet opens immediately. The name defaults to today\'s date — you can rename it.',
|
||||
]} />
|
||||
|
||||
<H3>Rename, duplicate, delete</H3>
|
||||
<P>Right-click any sheet in the sidebar to open the context menu with Rename, Duplicate and Delete options.</P>
|
||||
|
||||
<H3>Sheet columns</H3>
|
||||
<ul style={{ paddingLeft: 20, margin: '0 0 12px' }}>
|
||||
<Li><Code>Title</Code> — deliverable name / description</Li>
|
||||
<Li><Code>Status</Code> — Booked / To-do / In Progress / Done</Li>
|
||||
<Li><Code>Category</Code> — task type (e.g. Social (Static), OOH Print). Dropdown — values depend on the selected client.</Li>
|
||||
<Li><Code>Media</Code> — media channel. Dependent on Category.</Li>
|
||||
<Li><Code>Sub-media</Code> — sub-channel</Li>
|
||||
<Li><Code>Format</Code> — size/spec (e.g. 1080x1080)</Li>
|
||||
<Li><Code>Supply date</Code> / <Code>Live date</Code> — key dates</Li>
|
||||
<Li><Code>Language</Code> / <Code>Country</Code> — market</Li>
|
||||
<Li><Code>Quantity</Code> — number of units</Li>
|
||||
</ul>
|
||||
|
||||
<H3>Editing cells</H3>
|
||||
<P>Click any cell to edit. Category and Media are dropdowns — the available values come from the selected client's hierarchy (or the global list if no client is set).</P>
|
||||
<Tip>Changes are auto-saved a few seconds after you stop typing. The "Saving…" indicator appears in the header.</Tip>
|
||||
|
||||
<H3>Assign a client to a sheet</H3>
|
||||
<P>In the sheet header, select a client from the <strong>Client</strong> dropdown. This loads that client's Category/Media hierarchy and their export template.</P>
|
||||
|
||||
<H3>Clear sheet</H3>
|
||||
<P>Click <strong>Clear</strong> in the sheet header to remove all rows and reset the AI activity log.</P>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'ai',
|
||||
icon: '🤖',
|
||||
title: 'AI Commands',
|
||||
content: (
|
||||
<>
|
||||
<H2>AI Commands</H2>
|
||||
<P>
|
||||
The command bar at the bottom of every sheet lets you add or modify deliverables using plain English.
|
||||
The AI understands the client's Category/Media hierarchy and will only use valid values.
|
||||
</P>
|
||||
|
||||
<H3>Example commands</H3>
|
||||
<ul style={{ paddingLeft: 20, margin: '0 0 12px' }}>
|
||||
<Li><Code>Add 5 social media banners for UK</Code></Li>
|
||||
<Li><Code>Add 3 email newsletters for DE, FR, ES</Code></Li>
|
||||
<Li><Code>Create 10 OOH Print A4 deliverables for Germany</Code></Li>
|
||||
<Li><Code>Add 2 TVC 30s adaptations for France, supply 15 May, live 1 June</Code></Li>
|
||||
<Li><Code>Change all UK rows to "In Progress"</Code></Li>
|
||||
</ul>
|
||||
|
||||
<H3>YOLO mode</H3>
|
||||
<P>
|
||||
Toggle the <strong>YOLO</strong> switch to stop the AI from asking clarifying questions.
|
||||
It will make its best guess and apply changes immediately. Useful when you're in a hurry.
|
||||
</P>
|
||||
|
||||
<H3>Voice input</H3>
|
||||
<P>
|
||||
Click the <strong>microphone button</strong> to start dictating. Click again to stop.
|
||||
The transcript appears in the command field in real-time — edit it if needed, then press Enter or click Send.
|
||||
</P>
|
||||
<Tip>Voice works best in Chrome / Edge. Make sure microphone permission is granted for this site.</Tip>
|
||||
|
||||
<H3>Quick starters</H3>
|
||||
<P>Below the command bar there are pre-filled example commands. Click one to load it into the input, then customise and send.</P>
|
||||
|
||||
<H3>Activity log</H3>
|
||||
<P>Every AI action is recorded in the activity log (visible below the sheet). It shows what the AI did, which rows were affected, and any messages from the AI.</P>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'brief',
|
||||
icon: '📁',
|
||||
title: 'Brief Extraction',
|
||||
content: (
|
||||
<>
|
||||
<H2>Extracting Deliverables from a Brief</H2>
|
||||
<P>
|
||||
The AI can read a client brief document and automatically populate a sheet with the deliverables it finds.
|
||||
Supported formats: <Code>.pdf</Code>, <Code>.pptx</Code>, <Code>.docx</Code>, <Code>.xlsx</Code>, <Code>.ppt</Code>, <Code>.doc</Code>, <Code>.xls</Code>
|
||||
</P>
|
||||
|
||||
<H3>Step-by-step</H3>
|
||||
<Steps items={[
|
||||
'Click <strong>Upload Brief</strong> in the sidebar or on the Dashboard.',
|
||||
'(Optional) Select a <strong>Client</strong> from the dropdown — this helps the AI use the right categories.',
|
||||
'Drag & drop your file(s) or click to browse. You can upload multiple files at once.',
|
||||
'The extraction runs in the background. You\'ll see a progress card appear.',
|
||||
'When complete, click <strong>Review</strong> to inspect the extracted deliverables.',
|
||||
'On the review page, adjust rows if needed, then click <strong>Import to Sheet</strong> to add them to an existing sheet or create a new one.',
|
||||
]} />
|
||||
|
||||
<Tip>You can upload multiple briefs at once. Each one becomes a separate extraction job.</Tip>
|
||||
|
||||
<H3>Review page</H3>
|
||||
<P>
|
||||
The review page shows all extracted rows in a table. You can edit any cell before importing.
|
||||
Use <strong>Append</strong> to add rows to an existing sheet, or <strong>Replace</strong> to overwrite it.
|
||||
</P>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'export',
|
||||
icon: '⬇️',
|
||||
title: 'Export CSV',
|
||||
content: (
|
||||
<>
|
||||
<H2>Exporting to CSV</H2>
|
||||
<P>
|
||||
Click <strong>Export CSV</strong> in the sheet header to download the current sheet as a CSV file.
|
||||
The column names and order depend on the active export template.
|
||||
</P>
|
||||
|
||||
<H3>Export template priority</H3>
|
||||
<P>The system uses the first template it finds, in this order:</P>
|
||||
<ol style={{ paddingLeft: 20, margin: '0 0 12px' }}>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Client template</strong> — set by admin for the selected client</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Your personal template</strong> — set by you using the ⚙ button</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Global template</strong> — set by admin in the Dropdowns admin page</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>Built-in default</strong> — standard AC columns</Li>
|
||||
</ol>
|
||||
|
||||
<H3>Set your personal export template</H3>
|
||||
<Steps items={[
|
||||
'Click the <strong>⚙</strong> button next to "Export CSV" in the sheet header.',
|
||||
'A panel opens. Drag & drop a sample <Code>.csv</Code> file — it only needs the header row.',
|
||||
'The system detects your column names and suggests which internal field each one maps to.',
|
||||
'Adjust the mapping if needed using the dropdowns.',
|
||||
'Click <strong>Save template</strong>. From now on every export will use your column names.',
|
||||
]} />
|
||||
|
||||
<Tip>To reset to the default format, open the ⚙ panel and click <strong>Remove</strong>.</Tip>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'admin-clients',
|
||||
icon: '🏢',
|
||||
title: 'Admin: Clients',
|
||||
adminOnly: true,
|
||||
content: (
|
||||
<>
|
||||
<H2>Managing Clients</H2>
|
||||
<P>Go to <strong>Clients</strong> in the sidebar (admin only). Each client can have its own Category/Media hierarchy and CSV export template.</P>
|
||||
|
||||
<H3>Create a client</H3>
|
||||
<Steps items={[
|
||||
'Type the client name in the <strong>Add Client</strong> field and press Enter or click Create.',
|
||||
'The client now appears in the list and in the Client dropdown on every sheet.',
|
||||
]} />
|
||||
|
||||
<H3>Upload a custom Category/Media hierarchy</H3>
|
||||
<P>
|
||||
By default, sheets use the global dropdown hierarchy. You can override this per client with an <Code>.xlsx</Code> file.
|
||||
</P>
|
||||
<Steps items={[
|
||||
'In the client card, drag & drop an <Code>.xlsx</Code> file onto the dropdown zone (or click to browse).',
|
||||
'The system reads the file headers and shows you the detected column mapping.',
|
||||
'<strong>Confirm mapping</strong>: verify which column is "Category name", which is "Status", which is "Media types".',
|
||||
'A full preview of parsed categories appears. Click <strong>Apply</strong> to save.',
|
||||
'The client card shows a <strong>Custom hierarchy</strong> badge.',
|
||||
]} />
|
||||
<Tip>Expected Excel format: Column A = Category name, Column E = Status (Active/Archived), Column G = Media types (comma-separated). The mapping step lets you correct this if your file differs.</Tip>
|
||||
|
||||
<H3>Upload a custom export CSV template</H3>
|
||||
<Steps items={[
|
||||
'In the client card, scroll to the <strong>Export CSV template</strong> section.',
|
||||
'Drop a sample <Code>.csv</Code> file. Only the header row matters.',
|
||||
'Map each of your column names to the internal field it should contain.',
|
||||
'Click <strong>Save template</strong>.',
|
||||
]} />
|
||||
|
||||
<H3>Reset to global</H3>
|
||||
<P>Click <strong>Reset to global</strong> on a client card to remove the custom hierarchy and revert to the global dropdown list.</P>
|
||||
|
||||
<H3>Delete a client</H3>
|
||||
<P>Click <strong>Delete</strong> on a client card. This also removes their custom dropdown and export template files.</P>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'admin-dropdowns',
|
||||
icon: '🗂️',
|
||||
title: 'Admin: Dropdowns',
|
||||
adminOnly: true,
|
||||
content: (
|
||||
<>
|
||||
<H2>Global Dropdown Data</H2>
|
||||
<P>
|
||||
Go to <strong>Dropdowns</strong> in the sidebar. This page manages the <em>global</em> Category/Media hierarchy
|
||||
used by sheets that have no client assigned (or whose client has no custom file).
|
||||
</P>
|
||||
|
||||
<H3>Upload a new hierarchy</H3>
|
||||
<Steps items={[
|
||||
'Drag & drop an <Code>.xlsx</Code> file onto the upload zone.',
|
||||
'Confirm the detected column mapping (Category name / Status / Media types).',
|
||||
'Review the full list of parsed categories.',
|
||||
'Click <strong>Apply Changes</strong> to replace the global data.',
|
||||
]} />
|
||||
|
||||
<P>The current global data is always shown at the bottom of the page.</P>
|
||||
<Tip>Uploading a new file replaces the entire global list. Clients with custom hierarchies are not affected.</Tip>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'admin-users',
|
||||
icon: '👥',
|
||||
title: 'Admin: Users',
|
||||
adminOnly: true,
|
||||
content: (
|
||||
<>
|
||||
<H2>User Management</H2>
|
||||
<P>Go to <strong>Users</strong> in the sidebar. Every user who has signed in appears here.</P>
|
||||
|
||||
<H3>Roles</H3>
|
||||
<ul style={{ paddingLeft: 20, margin: '0 0 12px' }}>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>user</strong> — can create and manage their own sheets, upload briefs, export CSV.</Li>
|
||||
<Li><strong style={{ color: 'var(--text-primary)' }}>admin</strong> — everything above, plus access to the admin panel (Users, Clients, Dropdowns).</Li>
|
||||
</ul>
|
||||
|
||||
<H3>Change a user's role</H3>
|
||||
<P>Click the role badge next to a user and select <strong>admin</strong> or <strong>user</strong> from the dropdown.</P>
|
||||
|
||||
<H3>Deactivate a user</H3>
|
||||
<P>Toggle the <strong>Active</strong> switch off to prevent a user from logging in. Their data is preserved.</P>
|
||||
|
||||
<H3>Admin bootstrap</H3>
|
||||
<P>
|
||||
The emails <Code>daveporter@oliver.agency</Code> and <Code>vadymsamoilenko@oliver.agency</Code> automatically
|
||||
receive admin role on first login and cannot be downgraded through the UI.
|
||||
</P>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'login',
|
||||
icon: '🔐',
|
||||
title: 'Login & Access',
|
||||
content: (
|
||||
<>
|
||||
<H2>Signing In</H2>
|
||||
|
||||
<H3>Standard login (Microsoft SSO)</H3>
|
||||
<P>Click <strong>Sign in with Microsoft</strong> on the login page. You'll be redirected to Microsoft for authentication. Use your Oliver Agency account.</P>
|
||||
|
||||
<H3>Emergency access</H3>
|
||||
<P>
|
||||
If Microsoft SSO / 2FA is unavailable, use the emergency bypass:
|
||||
</P>
|
||||
<Steps items={[
|
||||
'On the login page, click the small <strong>Emergency access</strong> link at the bottom.',
|
||||
'Enter the emergency token (ask an admin).',
|
||||
'Click <strong>Sign in</strong>.',
|
||||
]} />
|
||||
<P>The emergency token is configured in the server <Code>.env</Code> file as <Code>EMERGENCY_TOKEN=…</Code>. If not set, emergency access is disabled.</P>
|
||||
|
||||
<H3>Signing out</H3>
|
||||
<P>There is no explicit sign-out button — closing the browser tab ends the session. The Microsoft SSO token expires and you'll be asked to sign in again on your next visit.</P>
|
||||
</>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
// ── Page ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
export default function HelpPage() {
|
||||
const navigate = useNavigate()
|
||||
const user = useAuthStore(s => s.user)
|
||||
const isAdmin = user?.role === 'admin'
|
||||
const [activeId, setActiveId] = useState('overview')
|
||||
|
||||
const visible = SECTIONS.filter(s => !s.adminOnly || isAdmin)
|
||||
const active = visible.find(s => s.id === activeId) ?? visible[0]
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-0" style={{ maxWidth: 1100, margin: '0 auto', width: '100%' }}>
|
||||
{/* Left nav */}
|
||||
<div
|
||||
className="flex-shrink-0 py-2 pr-4"
|
||||
style={{ width: 200, borderRight: '1px solid var(--border)', overflowY: 'auto' }}
|
||||
>
|
||||
<div className="text-xs font-bold uppercase tracking-widest mb-4 px-2" style={{ color: 'var(--text-muted)' }}>
|
||||
User Guide
|
||||
</div>
|
||||
<nav className="space-y-0.5">
|
||||
{visible.map(section => (
|
||||
<button
|
||||
key={section.id}
|
||||
onClick={() => setActiveId(section.id)}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-left transition-colors"
|
||||
style={{
|
||||
background: activeId === section.id ? 'var(--accent-dim)' : 'transparent',
|
||||
color: activeId === section.id ? 'var(--accent)' : 'var(--text-secondary)',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 14 }}>{section.icon}</span>
|
||||
<span className="text-xs font-medium">{section.title}</span>
|
||||
{section.adminOnly && (
|
||||
<span className="ml-auto text-xs px-1 rounded" style={{ background: 'rgba(255,196,7,0.15)', color: 'var(--accent)', fontSize: 9 }}>
|
||||
Admin
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 overflow-y-auto px-8 py-6">
|
||||
<div style={{ maxWidth: 680 }}>
|
||||
{active.content}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue