Skip to content

Commit 1a95b84

Browse files
chriscrosstalkclaude
authored andcommitted
feat(docs): polish docs rendering with desert-themed components
Add custom Markdoc renderers for images, links, paragraphs, code blocks, inline code, and horizontal rules. Restyle existing heading, table, and list components to match the desert tactical color palette. Add 8 screenshots to docs with polished image presentation (rounded corners, shadow, captions). Constrain content width for readability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8b8e00d commit 1a95b84

File tree

19 files changed

+184
-34
lines changed

19 files changed

+184
-34
lines changed

admin/app/services/docs_service.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,40 @@ export class DocsService {
155155
td: {
156156
render: 'TableCell',
157157
},
158+
paragraph: {
159+
render: 'Paragraph',
160+
},
161+
image: {
162+
render: 'Image',
163+
attributes: {
164+
src: { type: String, required: true },
165+
alt: { type: String },
166+
title: { type: String },
167+
},
168+
},
169+
link: {
170+
render: 'Link',
171+
attributes: {
172+
href: { type: String, required: true },
173+
title: { type: String },
174+
},
175+
},
176+
fence: {
177+
render: 'CodeBlock',
178+
attributes: {
179+
content: { type: String },
180+
language: { type: String },
181+
},
182+
},
183+
code: {
184+
render: 'InlineCode',
185+
attributes: {
186+
content: { type: String },
187+
},
188+
},
189+
hr: {
190+
render: 'HorizontalRule',
191+
},
158192
},
159193
}
160194
}

admin/docs/getting-started.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@ If this is your first time using N.O.M.A.D., the Easy Setup wizard will help you
1010

1111
**[Launch Easy Setup →](/easy-setup)**
1212

13+
![Easy Setup Wizard — Step 1: Choose your capabilities](/docs/easy-setup-step1.png)
14+
1315
The wizard walks you through four simple steps:
1416
1. **Capabilities** — Choose what to enable: Information Library, AI Assistant, Education Platform, Maps, Data Tools, and Notes
1517
2. **Maps** — Select geographic regions for offline maps
1618
3. **Content** — Choose curated content collections with Essential, Standard, or Comprehensive tiers
19+
20+
![Content tiers — Essential, Standard, and Comprehensive](/docs/easy-setup-tiers.png)
1721
4. **Review** — Confirm your selections and start downloading
1822

1923
Depending on what you selected, downloads may take a while. You can monitor progress in the Settings area, continue using features that are already installed, or leave your server running overnight for large downloads.
@@ -60,6 +64,8 @@ The Education Platform provides complete educational courses that work offline.
6064

6165
### AI Assistant — Built-in Chat
6266

67+
![AI Chat interface](/docs/ai-chat.png)
68+
6369
N.O.M.A.D. includes a built-in AI chat interface powered by Ollama. It runs entirely on your server — no internet needed, no data sent anywhere.
6470

6571
**What can it do:**
@@ -82,6 +88,8 @@ N.O.M.A.D. includes a built-in AI chat interface powered by Ollama. It runs enti
8288

8389
### Knowledge Base — Document-Aware AI
8490

91+
![Knowledge Base upload interface](/docs/knowledge-base.png)
92+
8593
The Knowledge Base lets you upload documents so the AI can reference them when answering your questions. It uses semantic search (RAG via Qdrant) to find relevant information from your uploaded files.
8694

8795
**Supported file types:**
@@ -104,6 +112,8 @@ The Knowledge Base lets you upload documents so the AI can reference them when a
104112

105113
### Maps — Offline Navigation
106114

115+
![Offline maps viewer](/docs/maps.png)
116+
107117
View maps without internet. Download the regions you need before going offline.
108118

109119
**How to use it:**
@@ -135,6 +145,8 @@ As your needs change, you can add more content anytime:
135145

136146
### Wikipedia Selector
137147

148+
![Content Explorer — browse and download Wikipedia packages and curated collections](/docs/content-explorer.png)
149+
138150
N.O.M.A.D. includes a dedicated Wikipedia content management tool for browsing and downloading Wikipedia packages.
139151

140152
**How to use it:**
@@ -146,6 +158,8 @@ N.O.M.A.D. includes a dedicated Wikipedia content management tool for browsing a
146158

147159
### System Benchmark
148160

161+
![System Benchmark with NOMAD Score and Builder Tag](/docs/benchmark.png)
162+
149163
Test your hardware performance and see how your NOMAD build stacks up against the community.
150164

151165
**How to use it:**

admin/docs/home.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Your personal offline knowledge server is ready to use.
88

99
Think of it as having Wikipedia, Khan Academy, an AI assistant, and offline maps all in one place, running on hardware you control.
1010

11+
![Command Center Dashboard](/docs/dashboard.png)
12+
1113
## What Can You Do?
1214

1315
### Browse Offline Knowledge

admin/inertia/components/MarkdocRenderer.tsx

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,81 @@ import Markdoc from '@markdoc/markdoc'
33
import { Heading } from './markdoc/Heading'
44
import { List } from './markdoc/List'
55
import { ListItem } from './markdoc/ListItem'
6+
import { Image } from './markdoc/Image'
67
import { Table, TableHead, TableBody, TableRow, TableHeader, TableCell } from './markdoc/Table'
78

8-
// Custom components for Markdoc tags
9+
// Paragraph component
10+
const Paragraph = ({ children }: { children: React.ReactNode }) => {
11+
return <p className="mb-4 leading-relaxed text-desert-green-darker/85">{children}</p>
12+
}
13+
14+
// Link component
15+
const Link = ({
16+
href,
17+
title,
18+
children,
19+
}: {
20+
href: string
21+
title?: string
22+
children: React.ReactNode
23+
}) => {
24+
const isExternal = href?.startsWith('http')
25+
return (
26+
<a
27+
href={href}
28+
title={title}
29+
className="text-desert-orange font-medium hover:text-desert-orange-dark underline decoration-desert-orange-lighter/50 underline-offset-2 hover:decoration-desert-orange transition-colors"
30+
{...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
31+
>
32+
{children}
33+
</a>
34+
)
35+
}
36+
37+
// Inline code component
38+
const InlineCode = ({ content, children }: { content?: string; children?: React.ReactNode }) => {
39+
return (
40+
<code className="bg-desert-green-lighter/30 text-desert-green-darker border border-desert-green-lighter/50 px-1.5 py-0.5 rounded text-[0.875em] font-mono">
41+
{content || children}
42+
</code>
43+
)
44+
}
45+
46+
// Code block component
47+
const CodeBlock = ({
48+
content,
49+
language,
50+
children,
51+
}: {
52+
content?: string
53+
language?: string
54+
children?: React.ReactNode
55+
}) => {
56+
const code = content || (typeof children === 'string' ? children : '')
57+
return (
58+
<div className="my-6 overflow-hidden rounded-lg border border-desert-green-dark/20">
59+
{language && (
60+
<div className="bg-desert-green-dark px-4 py-1.5 text-xs font-mono text-desert-green-lighter uppercase tracking-wider">
61+
{language}
62+
</div>
63+
)}
64+
<pre className="bg-desert-green-darker overflow-x-auto p-4">
65+
<code className="text-sm font-mono text-desert-green-lighter leading-relaxed whitespace-pre">
66+
{code}
67+
</code>
68+
</pre>
69+
</div>
70+
)
71+
}
72+
73+
// Horizontal rule component
74+
const HorizontalRule = () => {
75+
return (
76+
<hr className="my-10 border-0 h-px bg-gradient-to-r from-transparent via-desert-tan-lighter to-transparent" />
77+
)
78+
}
79+
80+
// Callout component
981
const Callout = ({
1082
type = 'info',
1183
title,
@@ -15,24 +87,29 @@ const Callout = ({
1587
title?: string
1688
children: React.ReactNode
1789
}) => {
18-
const styles = {
19-
info: 'bg-blue-50 border-blue-200 text-blue-800',
20-
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
21-
error: 'bg-red-50 border-red-200 text-red-800',
22-
success: 'bg-green-50 border-green-200 text-green-800',
90+
const styles: Record<string, string> = {
91+
info: 'bg-desert-sand/60 border-desert-olive text-desert-green-darker',
92+
warning: 'bg-desert-orange-lighter/15 border-desert-orange text-desert-green-darker',
93+
error: 'bg-desert-red-lighter/15 border-desert-red text-desert-green-darker',
94+
success: 'bg-desert-olive-lighter/15 border-desert-olive text-desert-green-darker',
2395
}
2496

2597
return (
26-
// @ts-ignore
27-
<div className={`border-l-4 p-4 mb-4 ${styles[type]}`}>
98+
<div className={`border-l-4 rounded-r-lg p-5 mb-6 ${styles[type] || styles.info}`}>
2899
{title && <h4 className="font-semibold mb-2">{title}</h4>}
29-
{children}
100+
<div className="[&>p:last-child]:mb-0">{children}</div>
30101
</div>
31102
)
32103
}
33104

34105
// Component mapping for Markdoc
35106
const components = {
107+
Paragraph,
108+
Image,
109+
Link,
110+
InlineCode,
111+
CodeBlock,
112+
HorizontalRule,
36113
Callout,
37114
Heading,
38115
List,
@@ -50,7 +127,9 @@ interface MarkdocRendererProps {
50127
}
51128

52129
const MarkdocRenderer: React.FC<MarkdocRendererProps> = ({ content }) => {
53-
return <div className="tracking-wide">{Markdoc.renderers.react(content, React, { components })}</div>
130+
return (
131+
<div className="text-base tracking-wide">{Markdoc.renderers.react(content, React, { components })}</div>
132+
)
54133
}
55134

56135
export default MarkdocRenderer

admin/inertia/components/markdoc/Heading.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ export function Heading({
1010
children: React.ReactNode
1111
}) {
1212
const Component = `h${level}` as keyof JSX.IntrinsicElements
13-
const sizes = {
14-
1: 'text-3xl font-bold',
15-
2: 'text-2xl font-semibold',
16-
3: 'text-xl font-semibold',
17-
4: 'text-lg font-semibold',
18-
5: 'text-base font-semibold',
19-
6: 'text-sm font-semibold',
13+
const styles: Record<number, string> = {
14+
1: 'text-3xl font-bold text-desert-green-darker pb-3 mb-6 mt-2 border-b-2 border-desert-orange',
15+
2: 'text-2xl font-bold text-desert-green-dark pb-2 mb-5 mt-10 border-b border-desert-tan-lighter',
16+
3: 'text-xl font-semibold text-desert-green-dark mb-3 mt-8',
17+
4: 'text-lg font-semibold text-desert-green mb-2 mt-6',
18+
5: 'text-base font-semibold text-desert-green mb-2 mt-5',
19+
6: 'text-sm font-semibold text-desert-green mb-2 mt-4',
2020
}
2121

2222
return (
2323
// @ts-ignore
24-
<Component id={id} className={`${sizes[level]} mb-2 mt-6`}>
24+
<Component id={id} className={styles[level]}>
2525
{children}
2626
</Component>
2727
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export function Image({ src, alt, title }: { src: string; alt?: string; title?: string }) {
2+
return (
3+
<figure className="my-8">
4+
<div className="overflow-hidden rounded-lg border border-desert-tan-lighter shadow-md">
5+
<img
6+
src={src}
7+
alt={alt || ''}
8+
title={title}
9+
className="w-full h-auto"
10+
loading="lazy"
11+
/>
12+
</div>
13+
{alt && (
14+
<figcaption className="mt-3 text-center text-sm text-desert-stone italic">
15+
{alt}
16+
</figcaption>
17+
)}
18+
</figure>
19+
)
20+
}

admin/inertia/components/markdoc/List.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export function List({
77
start?: number
88
children: React.ReactNode
99
}) {
10-
const className = ordered
11-
? 'list-decimal list-outside !ml-12 mb-4 space-y-1'
12-
: 'list-disc list-outside !ml-12 mb-4 space-y-1'
10+
const className = ordered
11+
? 'list-decimal list-outside ml-6 mb-5 space-y-2 marker:text-desert-orange marker:font-semibold'
12+
: 'list-disc list-outside ml-6 mb-5 space-y-2 marker:text-desert-orange'
1313
const Tag = ordered ? 'ol' : 'ul'
1414
return (
1515
// @ts-ignore
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
export function ListItem({ children }: { children: React.ReactNode }) {
3-
return <li className="ml-0 !pl-4">{children}</li>
4-
}
2+
return <li className="pl-2 text-desert-green-darker/85 leading-relaxed">{children}</li>
3+
}

admin/inertia/components/markdoc/Table.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
11
export function Table({ children }: { children: React.ReactNode }) {
22
return (
3-
<div className="overflow-x-auto my-6">
4-
<table className="min-w-full divide-y divide-gray-300 border border-gray-300">
3+
<div className="overflow-x-auto my-6 rounded-lg border border-desert-tan-lighter shadow-sm">
4+
<table className="min-w-full divide-y divide-desert-tan-lighter">
55
{children}
66
</table>
77
</div>
88
)
99
}
1010

1111
export function TableHead({ children }: { children: React.ReactNode }) {
12-
return <thead className="bg-gray-50">{children}</thead>
12+
return <thead className="bg-desert-green-dark">{children}</thead>
1313
}
1414

1515
export function TableBody({ children }: { children: React.ReactNode }) {
16-
return <tbody className="divide-y divide-gray-200 bg-white">{children}</tbody>
16+
return <tbody className="divide-y divide-desert-tan-lighter/50 bg-white">{children}</tbody>
1717
}
1818

1919
export function TableRow({ children }: { children: React.ReactNode }) {
20-
return <tr>{children}</tr>
20+
return <tr className="hover:bg-desert-sand/40 transition-colors">{children}</tr>
2121
}
2222

2323
export function TableHeader({ children }: { children: React.ReactNode }) {
2424
return (
25-
<th className="px-6 py-3 text-left text-sm font-semibold text-gray-900 border-r border-gray-300 last:border-r-0">
25+
<th className="px-5 py-3 text-left text-sm font-semibold text-desert-white tracking-wide">
2626
{children}
2727
</th>
2828
)
2929
}
3030

3131
export function TableCell({ children }: { children: React.ReactNode }) {
3232
return (
33-
<td className="px-6 py-4 text-sm text-gray-700 border-r border-gray-200 last:border-r-0">
33+
<td className="px-5 py-3.5 text-sm text-desert-green-darker">
3434
{children}
3535
</td>
3636
)

admin/inertia/layouts/DocsLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default function DocsLayout({ children }: { children: React.ReactNode })
2222
}, [data, isLoading])
2323

2424
return (
25-
<div className="min-h-screen flex flex-row bg-stone-50/90">
25+
<div className="min-h-screen flex flex-row bg-desert-white">
2626
<StyledSidebar title="Documentation" items={items} />
2727
{children}
2828
</div>

0 commit comments

Comments
 (0)