A configurable CMS built with Svelte and inspired by Decap CMS and Sveltia CMS.
I created this project because I wanted a CMS with a rich-text markdown widget, more intuitive custom preview configuration, and a configurable backend.
[!NOTE] When using the local backend, certain filesystem interactions may perform slowly on Firefox.
For maximum compatibility, use a Chrome-based browser.
npm i snow-cms
[my-site]/cmsapp.cms-config in your project at the same level as the previously created cms path.[my-site]/cms-configconfig.yml and any relevant css, html template, and js files.An example of a basic project with the expected structure would look something like this:
index.html
cms/ // The path to access the CMS. (Path name can be anything)
|-- index.html // Page that loads 'cms.js'
|-- snow.js // JS module that imports the CMS. (File name can be anything)
cms-config/ // The path containing CMS config files. (Must be named 'cms-config')
|-- config.yml // CMS config file
|-- preview-template.html // Layout template to apply to page previews in the editor
|-- preview-styles.css // Styles to apply to page previews in the editor
|-- cms-actions.js // Additional behavior to hook into editor actions. (Optional)
[!NOTE] This example assumes the use of a build system that allows importing css in js. But you should adapt importing of the css and js to your project's build system.
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- The module that loads the CMS -->
<script type="module" src="snow.js"></script>
</head>
<body>
<!-- The root element used to load the CMS -->
<slot id="app"></slot>
</body>
</html>
// Import the CMS css and js
import 'snow-cms/dist/index.css';
import 'snow-cms/dist/index';
See Config for information on configuration as well as dev-site/cms-config for example config files.
npm install -g pnpm
pnpm install
pnpm run dev
Then navigate to http://localhost:5173/ in your browser to view the dev site.
pnpm run build
Built files will be output to the dist/ directory.
Contains the source files to build the CMS.
Contains files for running the development server.
Development server site's photos by Pixabay and Simon Berger from Pexels.
See dev-site/cms-config for example config files.
[!NOTE] The GitHub backend requires a GitHub App to authenticate through and a server-side handler to exchange the access token.
The GitHub app should be configured with
Callback URLandSetup URLset to the url of the CMS.The server-side handler should exchange the received auth code for a user access token. Using one of the Oauth App middlewares makes this easy to set up.
Widgets share the following configuration options:
label: The input label displayed in the editor interface.name: The name of the input.default: The input's default value.required: Whether the input is required. (Defaults to true.)[!IMPORTANT] Each collection must have widgets configured for the names
title,date,draft, andbody.
widget: 'boolean'{
label: 'Draft',
name: 'draft',
widget: 'boolean',
required: false
}
[!NOTE] If the Boolean Widget's
requiredoption is set totrueor isn't specified, the input's value must betruefor editor data to submit.
widget: 'number'step: The amount the value increments / decrements by. (Defaults to 1.)min: The minimum value allowed.max: The maximum value allowed.{
label: 'Cookies',
name: 'cookies',
widget: 'number',
step: 5
}
widget: 'datetime'type: 'datetime-local|date|time' Which input to display.datetime_format: How the datetime should be displayed.date_format: How the date should be displayed.time_format: How the time should be displayed.{
label: 'Publish Date',
name: 'date',
widget: 'datetime',
type: 'datetime-local',
datetime_format: 'MM.DD.YYYY HH:mm'
}
[!NOTE] The corresponding
formatoption should be set depending on thetype.
widget: 'string|text' Which input to display. Use string for single-line or text for multiline.{
label: 'Title',
name: 'title',
widget: 'string'
}
widget: 'markdown'{
label: 'Body',
name: 'body',
widget: 'markdown'
}
widget: 'hidden'type: 'boolean|number|text|datetime-local|date|time' The type of the input's value.default: The value of the hidden input.{
name: 'hiddenValue',
widget: 'hidden',
type: 'text',
default: 'secret box'
}