Translate the whole site to English: English routes with 301 redirects from the Dutch paths, English UI, docs, seeds and captions, one-time live content migration
This commit is contained in:
@@ -3,22 +3,22 @@
|
||||
{% block docs_content %}
|
||||
<h1>API: {{ group.title }}</h1>
|
||||
<p>{{ group.description }}</p>
|
||||
<p class="muted">Elke HTML-route geeft JSON terug met <code>Accept: application/json</code>. Authenticatie: sessiecookie, <code>X-API-KEY</code>, <code>Authorization: Bearer</code> of <code>Basic</code>.</p>
|
||||
<p class="muted">Every HTML route returns JSON with <code>Accept: application/json</code>. Authentication: session cookie, <code>X-API-KEY</code>, <code>Authorization: Bearer</code> or <code>Basic</code>.</p>
|
||||
{% for item in endpoints %}
|
||||
<section class="endpoint" data-endpoint data-method="{{ item.method }}" data-path="{{ item.path }}" data-auth="{{ item.auth }}" data-negotiation="{{ item.negotiation }}" data-destructive="{{ '1' if item.destructive else '0' }}">
|
||||
<div class="signature"><span class="method">{{ item.method }}</span><code>{{ item.path }}</code><span class="auth">{{ item.min_role }}</span></div>
|
||||
<strong>{{ item.title }}</strong>
|
||||
{% if item.description %}<p>{{ item.description }}</p>{% endif %}
|
||||
{% if item.fields %}
|
||||
<table class="admin-table"><thead><tr><th>Veld</th><th>Type</th><th>Plek</th><th>Verplicht</th></tr></thead><tbody>
|
||||
{% for f in item.fields %}<tr><td><code>{{ f.name }}</code>{% if f.enum %}<div class="allowed">Toegestaan: {{ f.enum | join(', ') }}</div>{% endif %}</td><td>{{ f.type }}</td><td>{{ f.location }}</td><td>{{ 'ja' if f.required else 'nee' }}</td></tr>{% endfor %}
|
||||
<table class="admin-table"><thead><tr><th>Field</th><th>Type</th><th>Location</th><th>Required</th></tr></thead><tbody>
|
||||
{% for f in item.fields %}<tr><td><code>{{ f.name }}</code>{% if f.enum %}<div class="allowed">Allowed: {{ f.enum | join(', ') }}</div>{% endif %}</td><td>{{ f.type }}</td><td>{{ f.location }}</td><td>{{ 'yes' if f.required else 'no' }}</td></tr>{% endfor %}
|
||||
</tbody></table>
|
||||
{% endif %}
|
||||
<div class="tabs" data-tabs>
|
||||
<button type="button" class="active" data-tab="curl">cURL</button>
|
||||
<button type="button" data-tab="js">JS</button>
|
||||
<button type="button" data-tab="python">Python</button>
|
||||
<button type="button" data-tab="expected">Verwacht</button>
|
||||
<button type="button" data-tab="expected">Expected</button>
|
||||
{% if item.interactive %}<button type="button" data-tab="live">Live</button>{% endif %}
|
||||
</div>
|
||||
<pre data-panel="curl">{{ item.curl }}</pre>
|
||||
@@ -26,7 +26,7 @@
|
||||
console.log(await response.json());</pre>
|
||||
<pre data-panel="python" hidden>import httpx
|
||||
print(httpx.request("{{ item.method }}", BASE + "{{ item.path }}", headers={"Accept": "application/json", "X-API-KEY": API_KEY}).json())</pre>
|
||||
<pre data-panel="expected" hidden>{{ item.sample | tojson(indent=2) if item.sample is not none else 'Geen voorbeeld' }}</pre>
|
||||
<pre data-panel="expected" hidden>{{ item.sample | tojson(indent=2) if item.sample is not none else 'No example' }}</pre>
|
||||
{% if item.interactive %}
|
||||
<div data-panel="live" hidden class="tester">
|
||||
{% for f in item.fields %}
|
||||
@@ -35,8 +35,8 @@ print(httpx.request("{{ item.method }}", BASE + "{{ item.path }}", headers={"Acc
|
||||
{% else %}<input type="text" data-param="{{ f.name }}" data-location="{{ f.location }}" value="{{ f.example or '' }}">{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="actions"><button class="button small" type="button" data-send {% if item.auth != 'public' and not viewer %}disabled title="Log in om te versturen"{% endif %}>Verstuur</button></div>
|
||||
<pre data-response>Nog niet verstuurd.</pre>
|
||||
<div class="actions"><button class="button small" type="button" data-send {% if item.auth != 'public' and not viewer %}disabled title="Log in to send"{% endif %}>Send</button></div>
|
||||
<pre data-response>Not sent yet.</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
@@ -45,7 +45,7 @@ print(httpx.request("{{ item.method }}", BASE + "{{ item.path }}", headers={"Acc
|
||||
<h2>Live services</h2>
|
||||
{% for service in services %}
|
||||
<section class="endpoint"><strong>{{ service.title }}</strong> <code>{{ service.name }}</code><p>{{ service.description }}</p>
|
||||
<p class="muted">Velden: {% for f in service.fields %}<code>{{ f.key }}</code> ({{ f.type }}){% if not loop.last %}, {% endif %}{% endfor %}</p></section>
|
||||
<p class="muted">Fields: {% for f in service.fields %}<code>{{ f.key }}</code> ({{ f.type }}){% if not loop.last %}, {% endif %}{% endfor %}</p></section>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
<ul>{% for page in pages %}<li><a href="/docs/{{ page.slug }}" class="{{ nav_active(request, '/docs/' ~ page.slug, exact=True) }}">{{ page.title }}</a></li>{% endfor %}</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if section == 'Bouwen met de API' %}
|
||||
{% if section == 'Building with the API' %}
|
||||
<div>
|
||||
<h4>API-groepen</h4>
|
||||
<h4>API groups</h4>
|
||||
<ul>{% for group in api_groups %}<li><a href="/docs/api/{{ group.slug }}" class="{{ nav_active(request, '/docs/api/' ~ group.slug, exact=True) }}">{{ group.title }}</a></li>{% endfor %}</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div>
|
||||
<h4>Downloads</h4>
|
||||
<ul><li><a href="/docs/download.md">download.md</a></li><li><a href="/docs/download.html">download.html</a></li><li><a href="/voorwaarden">Voorwaarden</a></li><li><a href="/privacy">Privacy</a></li><li><a href="/swagger">OpenAPI</a></li></ul>
|
||||
<ul><li><a href="/docs/download.md">download.md</a></li><li><a href="/docs/download.html">download.html</a></li><li><a href="/terms">Terms</a></li><li><a href="/privacy">Privacy</a></li><li><a href="/swagger">OpenAPI</a></li></ul>
|
||||
</div>
|
||||
</aside>
|
||||
<article class="docs-content prose">
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Admin and services
|
||||
|
||||
*Admin, Services* lists every background service. Each service has an overview, configuration and logs. Start, stop, run now and clear logs are database writes the service picks up within a second.
|
||||
|
||||
| Service | Purpose |
|
||||
|---------|---------|
|
||||
| presence | publishes the online set |
|
||||
| housekeeping | clears expired sessions, prunes the audit log |
|
||||
| backup | works through the backup queue and schedules automatic backups |
|
||||
|
||||
## Intro
|
||||
|
||||
The intro at the top of the home page lives in the `site_intro` setting (markdown, line breaks are kept). Edit it under *Settings*; the first paragraph is set large.
|
||||
|
||||
## Maintenance mode
|
||||
|
||||
Set `maintenance_mode` to `1` under *Settings*. Administrators keep seeing everything.
|
||||
@@ -1,24 +1,28 @@
|
||||
# API en authenticatie
|
||||
# API and authentication
|
||||
|
||||
Elke route heeft vier gezichten: HTML, JSON, documentatie en (waar geselecteerd) een assistent-tool. Vraag JSON met `Accept: application/json`.
|
||||
Every route has four faces: HTML, JSON, documentation and (where selected) an assistant tool. Ask for JSON with `Accept: application/json`.
|
||||
|
||||
## Authenticatie
|
||||
## Authentication
|
||||
|
||||
Volgorde van resolutie:
|
||||
Resolution order:
|
||||
|
||||
1. `session` cookie (64 hex tekens) na inloggen op `/auth/login`.
|
||||
2. `X-API-KEY` header met je API-sleutel.
|
||||
3. `Authorization: Bearer <sleutel>`.
|
||||
4. `Authorization: Basic` met naam of e-mail en wachtwoord.
|
||||
1. `session` cookie (64 hex characters) after logging in at `/auth/login`.
|
||||
2. `X-API-KEY` header with your API key.
|
||||
3. `Authorization: Bearer <key>`.
|
||||
4. `Authorization: Basic` with name or email and password.
|
||||
|
||||
Er is geen JWT en geen OAuth.
|
||||
There is no JWT and no OAuth.
|
||||
|
||||
## Voorbeeld
|
||||
## Example
|
||||
|
||||
```bash
|
||||
curl -H 'Accept: application/json' https://molodetz.nl/rol
|
||||
curl -H 'Accept: application/json' https://molodetz.nl/roll
|
||||
```
|
||||
|
||||
## Fouten
|
||||
## Errors
|
||||
|
||||
Fouten hebben de vorm `{"error": {"status": 404, "message": "..."}}`. Validatiefouten geven `422` met `{"error": "validation", "fields": [...], "messages": [...]}`.
|
||||
Errors have the shape `{"error": {"status": 404, "message": "..."}}`. Validation errors return `422` with `{"error": "validation", "fields": [...], "messages": [...]}`.
|
||||
|
||||
## Old paths
|
||||
|
||||
The Dutch paths from before (`/rol`, `/standaard`, `/mensen`, `/binnen`, `/voorwaarden`) answer with a 301 to their English replacement. Query strings are kept.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Architecture
|
||||
|
||||
FastAPI with Jinja2, rendered on the server. SQLite through `dataset`, synchronous and deliberately without a threadpool. Sessions with PBKDF2-SHA256 passwords.
|
||||
|
||||
## Layers
|
||||
|
||||
- `molodetz/database/`: one file per subject, always import from the package root.
|
||||
- `molodetz/routers/`: mirrors the URL path.
|
||||
- `molodetz/services/`: background services under one supervisor with a file lock.
|
||||
- `molodetz/templates/`: one Jinja environment in `templating.py`.
|
||||
|
||||
## Deleting
|
||||
|
||||
Everything is soft deleted with `deleted_at` and `deleted_by`. Only cleanup jobs delete for real.
|
||||
|
||||
## Static files
|
||||
|
||||
Assets go through `static_url()`, which versions them under `/static/v<version>/`. Those are immutably cacheable for a year.
|
||||
@@ -1,18 +0,0 @@
|
||||
# Architectuur
|
||||
|
||||
FastAPI met Jinja2, server-side gerenderd. SQLite via `dataset`, synchroon en bewust zonder threadpool. Sessies met PBKDF2-SHA256 wachtwoorden.
|
||||
|
||||
## Lagen
|
||||
|
||||
- `molodetz/database/`: één bestand per onderwerp, importeer altijd vanaf de package-root.
|
||||
- `molodetz/routers/`: spiegelt het URL-pad.
|
||||
- `molodetz/services/`: achtergrondservices onder één supervisor met een bestandsslot.
|
||||
- `molodetz/templates/`: één Jinja-omgeving in `templating.py`.
|
||||
|
||||
## Verwijderen
|
||||
|
||||
Alles wordt zacht verwijderd met `deleted_at` en `deleted_by`. Alleen opruimtaken verwijderen hard.
|
||||
|
||||
## Statische bestanden
|
||||
|
||||
Assets lopen via `static_url()`, wat ze versioneert onder `/static/v<versie>/`. Die zijn een jaar onveranderlijk cachebaar.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Back-ups en onderhoud
|
||||
# Backups and maintenance
|
||||
|
||||
Doelen: `database`, `uploads`, `keys`, `full`. Archieven worden gecomprimeerd met zstd of brotli en staan onder `data/backups/`. Alleen de primaire beheerder kan downloaden.
|
||||
Targets: `database`, `uploads`, `keys`, `full`. Archives are compressed with zstd or brotli and live under `data/backups/`. Only the primary administrator can download them.
|
||||
|
||||
## CLI
|
||||
|
||||
@@ -11,4 +11,4 @@ molodetz backups prune --keep 14 --dry-run
|
||||
molodetz system prune --dry-run
|
||||
```
|
||||
|
||||
Het onderhoudsscript `bin/maintenance.sh` draait alle prunes en toont schijfgebruik voor en na.
|
||||
The maintenance script `bin/maintenance.sh` runs every prune and shows disk usage before and after.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Beheer en services
|
||||
|
||||
Onder *Beheer, Services* staan alle achtergrondservices. Elke service heeft een overzicht, configuratie en logs. Starten, stoppen, nu draaien en logs wissen zijn databaseschrijfacties waar de service binnen een seconde op reageert.
|
||||
|
||||
| Service | Doel |
|
||||
|---------|------|
|
||||
| presence | publiceert de online-set |
|
||||
| housekeeping | ruimt verlopen sessies op, snoeit het auditlog |
|
||||
| backup | verwerkt de back-upwachtrij en plant automatische back-ups |
|
||||
|
||||
## Onderhoudsmodus
|
||||
|
||||
De intro bovenaan de homepage staat in de instelling `site_intro` (markdown, regelovergangen blijven staan). Bewerk hem onder *Instellingen*; de eerste alinea wordt groot gezet.
|
||||
|
||||
Zet `maintenance_mode` op `1` onder *Instellingen*. Beheerders blijven alles zien.
|
||||
@@ -1,5 +0,0 @@
|
||||
# Binnenkomen
|
||||
|
||||
Het formulier op [/binnen](/binnen) slaat een aanmelding op: naam, contact, optioneel een link naar je werk en een bericht. Beheerders krijgen een melding en zien de aanmelding onder *Beheer, Aanmeldingen*.
|
||||
|
||||
Er is geen automatische toegang. retoor leest elke aanmelding en neemt zelf contact op.
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-avatar
|
||||
|
||||
Toont een deterministische SVG-avatar plus presence-stip. Attribuut `seed`, `size`, `uid`.
|
||||
Shows a deterministic SVG avatar plus a presence dot. Attributes `seed`, `size`, `uid`.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-chat
|
||||
|
||||
Eenvoudige log met invoerregel. Geeft een `dp-chat-send` event.
|
||||
Simple log with an input line. Emits a `dp-chat-send` event.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-code
|
||||
|
||||
Markeert een codeblok met highlight.js en voegt een Kopieer-knop toe.
|
||||
Highlights a code block with highlight.js and adds a Copy button.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-content
|
||||
|
||||
Rendert live markdown aan de clientkant via marked, daarna DOMPurify. Alleen voor live inhoud, zoals het editorvoorbeeld.
|
||||
Renders live markdown on the client through marked, then DOMPurify. Only for live content, such as the editor preview.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-context-menu
|
||||
|
||||
Klein contextmenu met knoppen, gepositioneerd bij de cursor.
|
||||
Small context menu with buttons, positioned at the cursor.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-dialog
|
||||
|
||||
Bevestigingsdialoog. Formulieren met `data-confirm` lopen hierlangs.
|
||||
Confirmation dialog. Forms with `data-confirm` go through it.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-lightbox
|
||||
|
||||
Volledig scherm voor afbeeldingen met `data-lightbox`. Escape of klik sluit.
|
||||
Full screen view for images with `data-lightbox`. Escape or a click closes it.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-title
|
||||
|
||||
Inline-variant van dp-content voor titels.
|
||||
Inline variant of dp-content for titles.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-toast
|
||||
|
||||
Host voor korte meldingen. Gebruik `Toast.flash(el, bericht)` of `app.toast(bericht)`.
|
||||
Host for short notices. Use `Toast.flash(el, message)` or `app.toast(message)`.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# dp-upload
|
||||
|
||||
Sleepvlak voor bestanden. Geeft een `dp-files` event met de gekozen bestanden.
|
||||
Drop zone for files. Emits a `dp-files` event with the chosen files.
|
||||
|
||||
Light DOM, geen shadow DOM. Registreert zichzelf met `customElements.define`.
|
||||
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Frontend en componenten
|
||||
# Frontend and components
|
||||
|
||||
ES6-modules, één klasse per bestand, geen framework en geen bundler. `Application.js` maakt alle singletons aan en zet `window.app`.
|
||||
ES6 modules, one class per file, no framework and no bundler. `Application.js` creates all singletons and sets `window.app`.
|
||||
|
||||
Componenten zijn custom elements met het voorvoegsel `dp-`, zonder shadow DOM. Zie de componentpagina's in de zijbalk.
|
||||
Components are custom elements with the `dp-` prefix, without shadow DOM. See the component pages in the sidebar.
|
||||
|
||||
Clientrendering met marked en DOMPurify is alleen voor live inhoud: het voorbeeld in de editor. Gepubliceerde berichten worden op de server gerenderd.
|
||||
Client rendering with marked and DOMPurify is only for live content: the preview in the editor. Published posts are rendered on the server.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Joining
|
||||
|
||||
The form at [/join](/join) stores a join request: name, contact, an optional link to your work and a message. Administrators get a notification and see the request under *Admin, Join requests*.
|
||||
|
||||
There is no automatic access. retoor reads every request and gets in touch himself.
|
||||
@@ -1,6 +0,0 @@
|
||||
# Voorwaarden en privacy
|
||||
|
||||
- [Voorwaarden](/voorwaarden)
|
||||
- [Privacy](/privacy)
|
||||
|
||||
Molodetz heeft geen advertenties, geen tracking over apps heen, geen betalingen en geen sociale login.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Terms and privacy
|
||||
|
||||
- [Terms](/terms)
|
||||
- [Privacy](/privacy)
|
||||
|
||||
Molodetz has no ads, no cross-app tracking, no payments and no social login.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Schrijven op de rol
|
||||
|
||||
Berichten zijn markdown en staan in SQLite. Alleen beheerders schrijven. Een bericht heeft een titel, een onderwerp (`rol` of `standaard`), een status (`draft` of `published`) en optioneel de markering *placeholder*.
|
||||
|
||||
## Markdown
|
||||
|
||||
De server rendert met GFM: tabellen, doorhalen, harde regeleinden. HTML in de tekst wordt ge-escaped. Links mogen alleen `http`, `https`, `mailto` en `tel` zijn. Emoji schrijf je als `:shortcode:`, bijvoorbeeld `:fire:`.
|
||||
|
||||
Een losse afbeeldings-URL wordt een afbeelding, `@naam` wordt een link naar het profiel.
|
||||
|
||||
## Placeholders
|
||||
|
||||
De eerste notities zijn overgenomen uit de oude Molodetz-pagina en dragen het label *Placeholder*. retoor vervangt ze door eigen verhalen. Haal het vinkje weg bij het bewerken zodra een bericht echt is.
|
||||
|
||||
## Slugs
|
||||
|
||||
Een slug is permanent: titel plus de laatste twaalf tekens van de uid. Bewerken verandert de slug niet.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Welcome to Molodetz
|
||||
|
||||
Molodetz is a quiet blog roll. Notes about the work, finishing it, and judgement. This documentation describes how the site works, how to use the API and how admin keeps the whole thing running.
|
||||
|
||||
## What is here
|
||||
|
||||
- **Roll**: short notes, newest first.
|
||||
- **Standard**: what Molodetz stands for.
|
||||
- **Flyers** and **Memes**: two galleries.
|
||||
- **People**: who writes here.
|
||||
- **Join**: the form to write along.
|
||||
|
||||
## Where to start
|
||||
|
||||
Read [Writing on the roll](/docs/writing) for the content, [API and authentication](/docs/api) for integrations, and [Architecture](/docs/architecture) if you want to know how it is built.
|
||||
@@ -1,15 +0,0 @@
|
||||
# Welkom bij Molodetz
|
||||
|
||||
Molodetz is een rustige blogrol. Notities over het werk, het afmaken en het oordeel. Deze documentatie beschrijft hoe de site werkt, hoe je de API gebruikt en hoe beheer de boel draaiende houdt.
|
||||
|
||||
## Wat er is
|
||||
|
||||
- **Rol**: korte notities, nieuwste eerst.
|
||||
- **Standaard**: waar Molodetz op staat.
|
||||
- **Flyers** en **Memes**: twee galerijen.
|
||||
- **Mensen**: wie er schrijft.
|
||||
- **Binnen**: het formulier om mee te schrijven.
|
||||
|
||||
## Waar te beginnen
|
||||
|
||||
Lees [Schrijven op de rol](/docs/schrijven) voor de inhoud, [API en authenticatie](/docs/api) voor integraties, en [Architectuur](/docs/architectuur) als je wilt weten hoe het gebouwd is.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Writing on the roll
|
||||
|
||||
Posts are markdown and live in SQLite. Only administrators write. A post has a title, a topic (`roll` or `standard`), a status (`draft` or `published`) and an optional *placeholder* marker.
|
||||
|
||||
## Markdown
|
||||
|
||||
The server renders GFM: tables, strikethrough, hard line breaks. HTML in the text is escaped. Links may only be `http`, `https`, `mailto` and `tel`. Write emoji as `:shortcode:`, for example `:fire:`.
|
||||
|
||||
A bare image URL becomes an image, `@name` becomes a link to the profile.
|
||||
|
||||
## Placeholders
|
||||
|
||||
The first notes were carried over from the old Molodetz page and carry the *Placeholder* label. retoor replaces them with his own stories. Untick the box while editing once a post is real.
|
||||
|
||||
## Slugs
|
||||
|
||||
A slug is the title plus the last twelve characters of the uid. Editing does not change the slug. If a title is ever rewritten in the database, the old slug still resolves through its uid tail and redirects with 301 to the canonical one.
|
||||
@@ -1,14 +1,14 @@
|
||||
<!-- retoor <retoor@molodetz.nl> -->
|
||||
{% extends "docs/base_docs.html" %}
|
||||
{% block docs_content %}
|
||||
<h1>Zoeken</h1>
|
||||
{% if query %}<p class="muted">{{ results | length }} resultaten voor <strong>{{ query }}</strong></p>{% endif %}
|
||||
<h1>Search</h1>
|
||||
{% if query %}<p class="muted">{{ results | length }} results for <strong>{{ query }}</strong></p>{% endif %}
|
||||
{% for hit in results %}
|
||||
<div class="search-hit">
|
||||
<a href="{{ hit.url }}">{{ hit.title }}</a> <span class="muted">{{ hit.score }}</span>
|
||||
<p>{{ hit.snippet | e | replace('[[', '<mark>') | replace(']]', '</mark>') | safe }}</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if query %}<p class="empty">Niets gevonden.</p>{% endif %}
|
||||
{% if query %}<p class="empty">Nothing found.</p>{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user