Skip to content

Commit f0082f8

Browse files
committed
fix!: make markdown hard wraps configurable, default off
A single newline inside a paragraph rendered as <br>, so prose wrapped at a fixed width came out ragged. It now renders as a space, per CommonMark. Set markdown.hard_wraps: true to restore the old behavior; two trailing spaces or a backslash still force a break. Docs: merge Why Sarde into What Is Sarde and renumber the Start Here pages, document hard_wraps in the configuration reference and Markdown basics, and bring the README back in sync with the codebase.
1 parent 6d291ee commit f0082f8

18 files changed

Lines changed: 361 additions & 128 deletions

File tree

README.md

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919
</p>
2020

2121
<p align="center">
22-
A zero-config static site generator written in Go. Hugo's speed, Docusaurus's defaults, no config file needed.
22+
A static site generator written in Go. Drop in Markdown, get a themed site. Conventions handle the structure, so the config file stays a few lines long.
2323
</p>
2424

2525
## Why Sarde
2626

27-
Most static site generators make you choose: Hugo gives you speed and a single binary but demands configuration and template boilerplate. Docusaurus and Starlight give you great defaults for docs sites but require Node.js and a build toolchain.
27+
Sarde is a single Go binary with no runtime dependencies, and your directory structure is the site structure. Put files in `content/blog/` and you get a date-sorted blog with RSS. A `content/docs/` directory produces sidebar navigation, versioning, and a table of contents. Both layouts are selected by directory name alone, without additional configuration.
2828

29-
Sarde gives you both. It ships as a single Go binary with no runtime dependencies. Your directory structure is your site structure. Put files in `content/blog/` and you get a date-sorted blog with RSS. Put files in `content/docs/` and you get a docs site with sidebar navigation, versioning, and table of contents. No config file needed for either.
30-
31-
When you do need control, everything is overridable through a single `sarde.yaml` file, CLI flags, or environment variables.
29+
Defaults can be overridden through `sarde.yaml`, CLI flags, or environment variables.
3230

3331
<!-- TODO: Add a screenshot of a generated docs site here -->
3432
<!-- <p align="center">
@@ -38,20 +36,21 @@ When you do need control, everything is overridable through a single `sarde.yaml
3836
## Features
3937

4038
**Content**
41-
- Auto-detected collections: directories named `blog`, `posts`, `articles`, `news` get date-sorted feed layouts; `docs`, `guides`, `courses`, `tutorials` get docs layouts with sidebar and ToC
39+
- Auto-detected collections: directory names select date-sorted blogs, docs layouts with sidebar and ToC, lab guides, or slide decks (see the table under [Project structure](#project-structure))
4240
- Frontmatter in YAML, TOML, or JSON
43-
- Title, date, and weight inferred automatically from filenames, headings, and git history
41+
- Title, date, and sidebar order inferred automatically from filenames, headings, and git history
4442
- Page bundles (directory with `index.md` + images) with automatic responsive image generation
4543
- Versioned docs (Docusaurus-style) with URL shadowing for the latest version
4644
- i18n with per-language directories, RTL support, and translation fallback
45+
- Optional `sidebar.yaml` for per-path sidebar overrides, tab overrides, and `collapse_level`
4746

4847
**Markdown**
49-
- 24+ Goldmark extensions: code blocks with syntax highlighting (Kazari + Nuri), KaTeX math, Mermaid diagrams, GitHub-style alerts, callouts, cards, tabs, file trees, image comparison, keyboard shortcuts, spoilers, and more
48+
- 30+ Goldmark extensions: code blocks with syntax highlighting (Kazari + Nuri), KaTeX math, Mermaid diagrams, GitHub-style alerts, callouts, cards, tabs, multi-column layouts, accordions, file trees, timelines, image comparison, keyboard shortcuts, spoilers, and more
5049
- Syntax highlighting via [Kazari](https://github.com/frostybee/kazari) (Expressive Code-style frames, diff markers, line numbers) powered by [Nuri](https://github.com/frostybee/nuri) (TextMate grammars, 400+ languages)
5150

5251
**Asset pipeline**
5352
- CSS/JS bundling via esbuild (Go API, no Node.js)
54-
- Image processing: resize, crop, WebP/AVIF conversion, LQIP blur-up placeholders
53+
- Image processing: resize, crop, WebP conversion, LQIP blur-up placeholders (AVIF is available, but only in builds compiled with `-tags avif`; release binaries skip AVIF variants with a warning)
5554
- Content-hash fingerprinting for cache busting
5655
- HTML/CSS/JS minification
5756

@@ -66,10 +65,25 @@ When you do need control, everything is overridable through a single `sarde.yaml
6665
- `redirects` for redirect stubs (HTML or Netlify `_redirects`)
6766
- `llms_txt` for LLM-friendly site index
6867

68+
**Client-side plugins** (11 available, all opt-in)
69+
70+
Add any of these to `plugins.enabled` to bundle its CSS and JS. Nothing ships to the browser unless it is listed, and each one is injected only on pages that need it.
71+
72+
`scroll-to-top`, `copy-section-link`, `external-links`, `image-lightbox`, `keyboard-nav`, `focus-mode`, `reading-progress`, `search-highlighter`, `text-highlighter`, `reading-position-memory`, `reading-preferences`
73+
74+
**External plugins**
75+
- Install third-party plugins into `plugins/{slug}/` with `sarde plugin install`, from a zip, directory, URL, or GitHub repo
76+
- Plugins are declarative (`plugin.yaml` manifest, assets, templates), so installing one never executes third-party code at build time
77+
- `plugins.disabled` turns off any plugin, built-in or external, without replacing the whole `plugins.enabled` list
78+
- Premium plugins are unlocked by an offline ed25519-signed license file (`sarde license install`). A missing or invalid license warns and skips the plugin; it never fails the build
79+
- The plugin manifest and license file formats are provisional for 1.0 and may change in a 1.x release
80+
6981
**Developer experience**
7082
- Dev server with WebSocket live reload and incremental rebuilds
7183
- Link checking with terminal, JSON, and GitHub Actions annotation output
7284
- Content validation without building (`sarde validate`)
85+
- Fenced-block syntax checking (`sarde check-syntax`)
86+
- Merged configuration inspection with provenance (`sarde effective-config`)
7387
- Obsidian vault importer (converts wikilinks and callouts)
7488
- Deploy command for GitHub Pages, Netlify, Cloudflare Pages, and Vercel
7589

@@ -132,24 +146,31 @@ Output goes to `dist/` by default.
132146

133147
```
134148
my-site/
135-
content/ # Your Markdown files (required)
136-
blog/ # Auto-detected as blog collection
137-
docs/ # Auto-detected as docs collection
138-
_index.md # Homepage content (optional)
139-
public/ # Copied as-is to output
140-
icons/ # Local SVG icons
141-
themes/ # Custom themes (optional)
142-
sarde.yaml # Configuration (optional)
149+
content/ # Your Markdown files (required)
150+
blog/ # Auto-detected as blog collection
151+
docs/ # Auto-detected as docs collection
152+
_index.md # Homepage content (optional)
153+
public/ # Copied as-is to output
154+
icons/ # Local SVG icons
155+
themes/ # Custom themes (optional)
156+
plugins/ # Installed external plugins (optional)
157+
sarde.yaml # Configuration (optional)
158+
sidebar.yaml # Sidebar overrides (optional)
159+
kazari.config.yaml # Code block presentation (optional)
143160
```
144161

145162
Collections are detected by directory name:
146163

147164
| Directory names | Type | Default sort | Layout |
148165
|---|---|---|---|
149166
| `blog`, `posts`, `articles`, `news` | Blog | date descending | Feed with pagination |
150-
| `docs`, `guides`, `courses`, `tutorials` | Docs | weight ascending | Three-column with sidebar + ToC |
167+
| `docs`, `documentation`, `guides`, `reference`, `courses`, `tutorials`, `lessons`, `workshops` | Docs | `sidebar.order` ascending | Three-column with sidebar + ToC |
168+
| `labs` | Labs | `sidebar.order` ascending | Lab guide with progress and objectives |
169+
| `slides`, `presentations`, `decks` | Slides | date descending | Presentation deck with gallery landing |
151170
| Anything else | Generic | title ascending | Default |
152171

172+
These names are a convention, not a requirement. Any directory name works, and an unrecognized name becomes a generic collection. To get docs behavior under a different name, set it explicitly under `collections:` in `sarde.yaml` rather than renaming the directory.
173+
153174
## Configuration
154175

155176
All configuration goes in `sarde.yaml`. Every option has a sensible default; the file is entirely optional. Values are resolved in a 5-layer cascade (last wins):
@@ -208,31 +229,49 @@ i18n:
208229
name: Français
209230

210231
plugins:
232+
# Listing `enabled` replaces the default set, so name every plugin you want.
211233
enabled:
212234
- sitemap
213235
- rss
214236
- search
215237
- seo
216238
- link_validator
239+
- scroll-to-top # client-side plugins are opt-in
240+
# `disabled` turns off individual plugins without replacing the list above.
241+
disabled:
242+
- social_cards
217243
```
218244
219245
See the [default configuration](embedded/defaults/sarde.yaml) for every available option and its default value.
220246
221247
## Commands
222248
223249
```bash
224-
sarde build # Build for production
225-
sarde dev # Dev server with live reload (port 4727)
226-
sarde new site <path> # Scaffold a new project
227-
sarde new course <name> # Create a course directory
228-
sarde new lesson <course> <name> # Add an auto-numbered lesson
229-
sarde check-links # Validate links without building
230-
sarde validate # Validate config and content
231-
sarde deploy # Deploy to configured provider
232-
sarde theme list|add|remove|eject # Manage themes
233-
sarde icons add|list # Download/list Iconify icon sets
234-
sarde import obsidian <vault> # Import an Obsidian vault
235-
sarde version # Print version info
250+
sarde build # Build for production
251+
sarde dev # Dev server with live reload (port 4727)
252+
253+
sarde new site <path> # Scaffold a new project
254+
sarde new <collection> <title> # Add a page to a collection
255+
sarde new course <name> # Create a course directory
256+
sarde new lesson <course> <name> # Add an auto-numbered lesson
257+
258+
sarde check-links # Validate links without building
259+
sarde check-syntax # Check fenced-block syntax
260+
sarde validate # Validate config and content
261+
sarde effective-config # Print merged config with provenance
262+
263+
sarde deploy # Deploy to configured provider
264+
sarde theme list|add|remove|eject # Manage themes
265+
sarde theme info|chromastyles # Inspect a theme, dump Chroma styles
266+
sarde plugin list|install|remove|info # Manage external plugins
267+
sarde license install|list # Manage premium plugin licenses
268+
sarde icons add|list # Download/list Iconify icon sets
269+
sarde i18n add-language|status # Manage languages (also remove-language, scaffold)
270+
sarde doc-version create|delete|update # Manage docs versions
271+
272+
sarde import obsidian <vault> # Import an Obsidian vault
273+
sarde update # Self-update the binary
274+
sarde version # Print version info
236275
```
237276

238277
Global flags: `--config/-c`, `--baseURL`, `--drafts/-D`, `--future`, `--verbose/-v`, `--quiet/-q`
@@ -241,9 +280,9 @@ Global flags: `--config/-c`, `--baseURL`, `--drafts/-D`, `--future`, `--verbose/
241280

242281
Three layers:
243282

244-
1. **Interface**: CLI (Cobra) and [Desktop App](https://github.com/getsarde/sarde-studio) (Tauri+Svelte) both call into a unified ProjectManager API
245-
2. **Engine**: Six-phase pipeline: Initialize, Discover, Parse (parallel), Assemble, Assets, Render (parallel), Write
246-
3. **Plugins**: Four lifecycle hooks run in order: ConfigSetup (serial), ContentLoaded (serial), BeforeRender (serial per page), BuildDone (parallel)
283+
1. **Interface**: the CLI (Cobra) drives everything through ProjectManager, a unified API over the engine rather than direct file access
284+
2. **Engine**: seven-phase pipeline: Initialize, Discover, Parse (parallel), Assemble, Assets, Render (parallel), Write
285+
3. **Plugins**: four lifecycle hooks run in order: ConfigSetup (serial), ContentLoaded (serial), BeforeRender (serial per page), BuildDone (parallel)
247286

248287
The engine is designed around Go interfaces (`ContentDiscoverer`, `FrontmatterParser`, `MarkdownRenderer`, `TemplateEngine`) so each pipeline stage is independently testable.
249288

@@ -272,7 +311,6 @@ On Windows, `build.bat` wraps these commands: `build.bat build`, `build.bat test
272311
## Tech stack
273312

274313
- **Core**: Go, Goldmark, Cobra, Chroma v2, esbuild (Go API), fsnotify, go:embed
275-
- **Desktop app**: Tauri v2 (Rust) + Svelte 5 + CodeMirror 6 ([sarde-studio](https://github.com/getsarde/sarde-studio))
276314
- **Generated sites**: Pure HTML/CSS with ~1KB inline JS, no framework runtime
277315
- **Search**: Orama (offline, embedded in output)
278316
- **Minification**: tdewolff/minify (HTML), esbuild (CSS/JS)

docs/content/docs/extensions/markdown-basics.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ A paragraph is one or more consecutive lines of text, separated by one or more b
2828

2929
Here is a second paragraph. Notice how a blank line separates them. Paragraphs can span multiple lines in the source and still render as a single block of text.
3030

31+
That last point matters when wrapping prose at a fixed width: a single newline inside a paragraph is a soft break and renders as a space, so the text reflows to the reader's screen width. Only a blank line starts a new paragraph.
32+
33+
To force a line break inside a paragraph, end the line with two spaces or a backslash:
34+
35+
```markdown
36+
First line
37+
second line, on its own row.
38+
```
39+
40+
To make every newline break the line instead, set [`markdown.hard_wraps`](/reference/configuration#markdown) to `true`.
41+
3142
---
3243

3344
## Inline Text Formatting

docs/content/docs/reference/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ Outside a git repository, or when git is unavailable, Sarde falls back to `mtime
209209
| `typographer` | bool | `true` | Enable typographic replacements (smart quotes, dashes). |
210210
| `github_alerts` | bool | `true` | Parse GitHub-style alert blocks (`> [!NOTE]`, `> [!TIP]`, etc.). |
211211
| `triple_colon_callouts` | bool | `true` | Parse `:::` container-based callouts/asides. |
212+
| `hard_wraps` | bool | `false` | Render every single newline inside a paragraph as a line break. Off by default, so prose wrapped in the source reflows as one paragraph. Explicit breaks (two trailing spaces, or a trailing backslash) work either way. |
212213

213214
### `markdown.toc`
214215

docs/content/docs/start-here/_index.md

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,14 @@ sidebar:
88
open: "true"
99
---
1010

11-
New to Sarde? Start with these pages to understand what it is, get it
12-
running, and deploy a site.
11+
New to Sarde? Start with these pages to understand what it is, get it running, and deploy a site.
1312

1413
## Orientation
1514

16-
- [What Is Sarde](/start-here/what-is-sarde/) explains what Sarde does
17-
and what kind of sites it builds.
18-
- [Why Sarde](/start-here/why-sarde/) covers the value proposition and
19-
tradeoffs compared to other tools.
20-
- [Core Concepts](/start-here/core-concepts/) introduces the mental model:
21-
content, configuration, themes, and collections.
15+
- [What Is Sarde](/start-here/what-is-sarde/) explains what Sarde does, what a build produces, which kinds of sites it suits, and the tradeoffs that come with it.
16+
- [Core Concepts](/start-here/core-concepts/) introduces the mental model: content and URLs, frontmatter, collections, configuration, and themes.
2217

2318
## Hands-on
2419

25-
- [Getting Started](/start-here/getting-started/) walks through installation,
26-
scaffolding a site, and previewing it locally.
27-
- [Deploying](/start-here/deploying/) covers production builds and deployment
28-
to GitHub Pages, Netlify, Cloudflare Pages, and Vercel.
29-
30-
## Desktop
31-
32-
- [Oi Desktop Quickstart](/start-here/oi-desktop-quickstart/) introduces the
33-
visual editor for creating and previewing Sarde content.
20+
- [Getting Started](/start-here/getting-started/) walks through installation, scaffolding a site, and previewing it locally.
21+
- [Deploying](/start-here/deploying/) covers production builds and deployment to GitHub Pages, Netlify, Cloudflare Pages, and Vercel.

0 commit comments

Comments
 (0)