Private
Public Access
Add a user guide, reachable in-app from Help in the account menu
USER_GUIDE.md at the repo root is the single source of truth -- frontend/public/USER_GUIDE.md symlinks to it so the same file is both readable directly in the repo and served by the app, rendered on a new /help page reusing the existing markdown renderer. Scoped to regular member features (messaging, rooms, attachments, notifications, profile); room admin/site admin features are intentionally left out. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../USER_GUIDE.md
|
||||
@@ -11,6 +11,7 @@ import { ForgotPasswordPage } from './pages/ForgotPasswordPage'
|
||||
import { ResetPasswordPage } from './pages/ResetPasswordPage'
|
||||
import { ChatShellPage } from './pages/ChatShellPage'
|
||||
import { AdminPage } from './pages/AdminPage'
|
||||
import { HelpPage } from './pages/HelpPage'
|
||||
|
||||
function AppRoutes() {
|
||||
const routes = (
|
||||
@@ -43,6 +44,14 @@ function AppRoutes() {
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/help"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<HelpPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Navigate to="/rooms" replace />} />
|
||||
</Routes>
|
||||
)
|
||||
|
||||
@@ -122,6 +122,16 @@ export function TopBar() {
|
||||
>
|
||||
Profile settings
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
role="menuitem"
|
||||
onClick={() => {
|
||||
setMenuOpen(false)
|
||||
navigate('/help')
|
||||
}}
|
||||
>
|
||||
Help
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
role="menuitem"
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
.help-page {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--ds-void);
|
||||
}
|
||||
|
||||
.help-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: var(--sp-6) var(--sp-8);
|
||||
max-width: 760px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.help-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--sp-6);
|
||||
}
|
||||
|
||||
.help-header h1 {
|
||||
font-size: 1.3rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.help-loading {
|
||||
color: var(--ds-muted);
|
||||
}
|
||||
|
||||
.help-content a[href^='#'] {
|
||||
word-break: normal;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import Markdown from 'markdown-to-jsx'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { MARKDOWN_OPTIONS } from '../components/MessageContent'
|
||||
import { TopBar } from '../components/TopBar'
|
||||
import './HelpPage.css'
|
||||
|
||||
// Single source of truth is the repo-root USER_GUIDE.md -- frontend/public/
|
||||
// symlinks to it, so this fetches the same file a developer sees when
|
||||
// browsing the repo, rather than duplicating its content into the bundle.
|
||||
const GUIDE_URL = '/USER_GUIDE.md'
|
||||
|
||||
export function HelpPage() {
|
||||
const [content, setContent] = useState<string | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
fetch(GUIDE_URL)
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error(`Failed to load guide (${res.status})`)
|
||||
return res.text()
|
||||
})
|
||||
.then((text) => {
|
||||
if (!cancelled) setContent(text)
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load guide')
|
||||
})
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="help-page">
|
||||
<TopBar />
|
||||
<div className="help-body">
|
||||
<div className="help-header">
|
||||
<h1>Help</h1>
|
||||
<Link to="/rooms" className="btn-secondary">
|
||||
Back to chat
|
||||
</Link>
|
||||
</div>
|
||||
{error && <p className="admin-error">{error}</p>}
|
||||
{!error && content === null && <p className="help-loading">Loading…</p>}
|
||||
{!error && content !== null && (
|
||||
<div className="message-text help-content">
|
||||
<Markdown options={MARKDOWN_OPTIONS}>{content}</Markdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user