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:
2026-08-18 13:58:05 -06:00
co-authored by Claude Sonnet 5
parent 344eb7ebf1
commit aadf620014
6 changed files with 270 additions and 0 deletions
+159
View File
@@ -0,0 +1,159 @@
# DS Chat — User Guide
A quick reference for everyday use: sending messages, organizing rooms,
attachments, notifications, and personalizing your account.
## Contents
- [Getting started](#getting-started)
- [Rooms](#rooms)
- [Sending messages](#sending-messages)
- [Formatting](#formatting)
- [Mentions and room links](#mentions-and-room-links)
- [Attachments](#attachments)
- [Reactions](#reactions)
- [Editing a message](#editing-a-message)
- [Presence and notifications](#presence-and-notifications)
- [Your profile](#your-profile)
- [Room details](#room-details)
- [Staying up to date](#staying-up-to-date)
## Getting started
DS Chat is invite-only — there's no public sign-up page. You'll either be
given an account directly, or you'll receive an email invite with a
link. Opening that link lets you pick a username and password; once
you submit it, you're signed in automatically.
If you forget your password, use **Forgot password?** on the login
screen. You'll get an email with a reset link that's valid for 15
minutes.
## Rooms
Rooms are where conversations happen — similar to channels in other chat
apps. The sidebar on the left lists every room you belong to, with a
search box at the top to filter by name.
- **Create a room**: click the **+** button above the room list. Give it a
name and, optionally, a description. You become that room's owner.
- **Browse rooms**: click **Browse rooms** to see every *open* room on the
site and join any of them directly.
- **Private rooms**: a room marked private (shown with a lock icon) isn't
listed in Browse rooms — you can only get in by being added by an
owner or admin of that room.
- **Unread indicators**: a room with new activity shows a dot next to its
name — a plain dot for unread messages, a highlighted dot if you were
specifically @mentioned.
## Sending messages
Type in the message box at the bottom of a room and press **Enter** to
send. Use **Shift+Enter** to add a line break without sending.
## Formatting
Messages support Markdown:
- `**bold**`, `*italic*`, `~~strikethrough~~`
- `` `inline code` `` and fenced code blocks (three backticks)
- `> blockquotes`
- `-` or `1.` for bulleted/numbered lists
- `[link text](https://example.com)` — or just paste a bare URL and it
becomes clickable automatically
- `#`, `##`, `###` for headings
Pasting a link on its own often also generates a preview card underneath
your message, pulled from that page's title/description/image, when the
page provides one.
Emoji: click the 🙂 button in the composer to open the emoji picker, or
type a shortcode like `:tada:` and it's converted automatically once you
send. The picker remembers your recently-used emoji and has a search box.
## Mentions and room links
Type `@` followed by a few letters of someone's username to open an
autocomplete of that room's members — pick one (or press Enter/Tab) to
insert a mention. Mentioning someone highlights the message for them and
marks the room specially in their sidebar, even if they're not currently
looking at it.
Type `#` followed by a few letters of a room name to do the same for
rooms you belong to — it inserts a clickable link that takes anyone who
can see the message (and is a member of that room) straight to it.
## Attachments
Click the paperclip icon to attach a file, or just drag a file onto the
message box and drop it. Images show as an inline thumbnail — click one
to view it full-size. Other files show as a small card with the
filename and size; `.txt`, `.md`, and `.pdf` files open in a preview
without leaving the room, everything else downloads when clicked.
There's a server-configured maximum file size — if a file is too large,
you'll see an error before it uploads.
## Reactions
Hover over a message and click the 🙂 icon in its action row to react
with an emoji. Reactions from everyone appear as small pills under the
message with a count; click an existing pill to add or remove your own
reaction to it. Hovering a pill shows who reacted.
## Editing a message
You can edit any message you sent: hover it and click **Edit**, make your
changes, then press **Enter** to save or **Escape** to cancel. Clicking
away also saves. Edited messages are marked *(edited)*.
## Presence and notifications
Everyone's avatar shows a small status dot — green for online, grey for
offline — based on whether they currently have the app open. If you'd
rather not broadcast that you're active, open your account menu (click
your avatar, top right) and choose **Appear offline**.
The same menu has a notifications toggle:
- In a regular browser, turning it on asks your browser for permission
and subscribes you to push notifications for messages in rooms you're
not actively looking at.
- In DS Chat Desktop, the same toggle controls native desktop
notifications instead — no browser permission prompt needed. You'll
get a notification whenever the app is minimized *or* simply not the
focused window, even if it's still open somewhere on screen.
## Your profile
Open your account menu and choose **Profile settings** to:
- Upload or remove a profile photo
- Set a display name (shown instead of your username throughout the app)
- Pick a theme — Dark, Light, Midnight, Sunset, or build your own custom
color scheme (create one, then customize each color; changes preview
live)
- Change your password
## Room details
Click the info icon in a room's header to open its details panel, where
you can:
- See who else is in the room and their role (member/admin/owner)
- Browse and re-download every file and image ever shared in the room,
without scrolling back through history
- Leave the room — unless you're the owner, in which case ownership has
to be transferred to someone else first
Room admins and owners see additional management options here that
aren't covered in this guide.
## Staying up to date
If your connection drops, a banner lets you know you're offline and
working from cached data — sending is disabled until you're back online.
When a new version of DS Chat has been deployed, a banner offers a
**Reload** button to pick it up immediately, instead of waiting for your
next natural page refresh.
+1
View File
@@ -0,0 +1 @@
../../USER_GUIDE.md
+9
View File
@@ -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>
)
+10
View File
@@ -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"
+36
View File
@@ -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;
}
+55
View File
@@ -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>
)
}