Repository navigation
Releases
v1.0.0
More than one kind of article: news, notices, events, each in its own directory, in one editor.
This changes config.json; see Upgrading from 0.x.
collectionsin config.json. A list of the site's kinds of article, each with its owndir,
url,label,imageFieldandpreviewpage, and anamefor the address bar (by default the
last part ofdir). With more than one, the sidebar's label becomes a menu that switches between
them: the list, the cover field, the Preview button and View on site all follow the one picked.
Switching away from unsaved changes asks first. The repository, images, blocks, saving,
publishing, deployment and action buttons are the same for all of them.- The address bar says which collection as well as which article (
?c=notices&id=…), since an
id is only unique within its own directory. A reload or a link comes back to both; a link from
before 1.0 (?id=…) opens in the first collection, and one naming a collection there no longer
is opens the first one. - Breaking:
collectionis nowcollections, andpreview.urlis each entry'spreview. An
old config.json is not silently half-used: the editor says what each of the two became and how
to write it, and so doesnpx simple-git-cms installwhen the config.json it leaves in place is
an old one. npm run devserves every collection's directory, and only those.- The automatic summary follows the body. A summary the editor generated used to be taken for
one written by hand the next time the article was opened, and stayed as it was however the body
changed. Now it shows as automatic and is taken from the body again on every save; one written
by hand is kept. Summaries generated by earlier versions are recognised too. - Cleaner automatic summaries. HTML tags and components (
<aside>,<YouTube />), code
blocks and tables are left out, the text inside a tag is kept,snake_casekeeps its
underscore, and an English word is not cut in half at the end. - Alt text for images. The caption form has a second field for alt text. Left empty, the
caption is used, instead of the empty alt that told screen readers to skip the image.
rehype-figuresdoes the same on the site for captioned images that have no alt text, which
covers articles saved before this.
v0.9.0
Article history: every earlier version of an article, to look through and to bring back.
- History. A History button next to Preview lists every commit that changed the open article,
newest first, with when, who and the commit message. Clicking one shows the article as that
commit left it — title, date, tags, cover and body, drawn the way the site would draw it — and
Preview on the site shows it in the site's own layout. Looking changes nothing in the editor
and writes nothing. The version is drawn in a sandbox where nothing in it can run.
Works against GitHub (no new permission: Contents: Read already covers it) and on the local dev
server (git log/git show). - Restore a version. In the history, Restore this version puts it in the editor as unsaved
changes; saving is the usual save, and its commit message says which version it came from
(Update article: … (restored from <when>, <sha>)). Whether the article is published stays as it
is now, and a save someone else made meanwhile is still a conflict. Restoring the latest version
with unsaved changes on top is going back to what is saved. With unsaved changes in the editor,
it first says they will be replaced and by which version; afterwards the notice offers Undo for
ten seconds, and until then the browser's copy of the unsaved work is still the work that was
replaced, so a reload in that time offers it back.
v0.8.0
Buttons that start GitHub Actions workflows, so a site can keep the editor on its test copy only;
and a sidebar that can be made wider.
actionsin config.json. Each entry is a sidebar button: alabel, aworkflowwith a
workflow_dispatchtrigger, and optionally therefto run on (the content branch by default),
fixedinputs, theconfirmtext, and aurlto link once it succeeds. A click confirms —
warning about unsaved changes in the open article — starts the workflow, and the line under the
button follows the run to the end. The typical use: the editor lives on a test site built from
main, and a button publishesmainto the live site, which is built without the editor. The
GitHub App needs Actions: Read and write for them; withoutactions, nothing changes and
Read-only is still enough. See Action buttons.- Resizable sidebar. Drag the sidebar's right edge to make the article list wider or narrower
(or focus it and use the arrow keys); the width is kept in the browser, and a double-click puts
it back. Phones keep the drawer as it was.
v0.7.0
The sign-in relay can live under a site's own path.
PUBLIC_URLfor the relay. Set it to where the browser reaches the relay — e.g.
https://example.com/cms-auth— and the relay answers under that path, sends sign-in back to
…/cms-auth/callback, and keeps its cookies to that path. So the relay can run on the site's own
server without a domain of its own, and a reverse proxy that hands it plainhttpno longer
puts the wrong address in the callback. Without it, nothing changes. See
auth/README.md.
v0.6.0
The editor is on npm.
- On npm.
npm install --save-dev simple-git-cms, thennpx simple-git-cms install public/editor: the editor comes already built, and upgrading isnpm updateand installing
again. The preview client and the rehype plugin are imported from the package
(simple-git-cms/preview-client,simple-git-cms/rehype-figures) instead of copied in. After
this first one, releases are published from GitHub Actions, with a provenance statement linking
each to the commit it was built from.
v0.5.0
Articles imported from another system now come back exactly as they went in, and the preview is
sent the cover image and the rest of the frontmatter.
- Lists keep their spacing. A list with a blank line between its items — the way turndown and
so most imported articles write them — was saved as a tight one, which the site draws closer
together. It stays loose now, and keeps the spaces after its markers (-), so it goes back
byte for byte. A rule keeps its spelling too (* * *). - Extra blank lines are no longer an empty paragraph. Three blank lines in a row were read as a
blank line of their own and saved as , adding space to the page that was never there.
They are one blank line now, which is all the site ever made of them. - The preview is sent the cover image and the rest of the frontmatter:
article.image, as an
address the page can load even before it is uploaded, andarticle.fields. A preview page
written for 0.4.0 ignores them and works as before.
v0.4.0
The release that made the editor usable for a real article rather than a plain one: tables,
attachments, cover images, site-defined blocks, and a firm answer to what happens to HTML the
editor doesn't understand. Everything an article file contains now survives a round trip
byte for byte.
Writing
- Tables, created in the editor and written to the file as clean GFM — padded to the column
width, CJK counted as two cells wide, no in empty cells. A table typed by hand is
reformatted once and then left alone. - HTML tables, for the cases GFM cannot hold: merged cells, and a switch between the two
spellings. Only whereconfig.jsonasks for it, so an ordinary table keeps an ordinary toolbar. - Attachments: a PDF or any other file goes up as it is, under its own name, and is linked
from the body. Same path as images, so saving, conflicts and draft recovery were unchanged. - Cover image, uploaded, cropped, replaced or removed from the article's own panel — and it
can reuse a picture already in the body instead of uploading a second copy. - Code blocks and inline code, with the escaping rules stopping at the backtick.
- Pasted markup is treated as markup rather than as text.
HTML in an article
- Nothing unrecognised is dropped any more. A
<div>, a comment or a component the site
expands itself becomes an editable source box and is written back exactly as it was found. - Blocks the site defines itself: name a tag in
config.jsonand the editor edits it as a
small form — a card of fields, a table, or its own source. An element is claimed by its tag,
the attributes it must carry, and optionally what one of them starts with, so one kind of
<iframe>can be a video block without every iframe becoming one. Attributes the definition
never mentioned are kept and editable, folded away. - The file's own spelling is kept:
<iframe></iframe>is not rewritten as<iframe />, and
bare attributes such asallowfullscreenare not dropped. - A tag that is never closed is marked where it stands — in the box or in the sentence — and
saving says which tag and on which line before it goes out. One unclosed<div>wraps the rest
of the page it lands on, and Markdown cannot see that on its own. - Elements written across a blank line — a notice with two paragraphs in it — are read back as
the one element they are.
Around the editor
- The list loads in two steps: which files there are, then their text in batches, newest
first, so it appears without waiting for the last article. The text is cached in the browser
under git's own hash of it, so opening the editor again downloads only what changed. - Nothing in progress is lost: unsaved work, images included, is kept as you type and offered
back after a crash, a closed tab or a reload. - A reload comes back to the article that was open, and its address can be shared.
- Boxes can be left with the keyboard: Enter steps in, Escape steps out, Backspace takes an
empty one away, and dragging one moves that one thing and nothing else. - Dark mode, a favicon, and tags are no longer required.
Configuration, security, project
config.jsonis checked at startup and says everything that is wrong with it at once,
against a schema that editors can use for completion.- A Content-Security-Policy for the editor, with CI keeping the policy in the README and the
policy the tests run under from drifting apart. - Browser tests: the built editor driven in a real Chrome against an in-memory GitHub, so the
interface that gets clicked is the one that makes the commit. app.jssplit into modules by responsibility, ESLint added, and the cropper loaded on demand
(first load 207KB → 194KB gzipped).- A site of its own at simple-git-cms.azq1994.com, with a demo that runs the real editor
against a service worker standing in for GitHub, and three site templates the preview can switch
between. - Node 22 or newer to build and test the editor; CI runs the oldest supported line and the
newest (22 and 26). Node 20 reached its end of life in April 2026.