Use Case: CMS Content Editor

Build a headless CMS content editing interface using the File Manager and Code Editor as embedded widgets. Create content pages with frontmatter metadata, preview rendered HTML, and organize content in a structured directory.

Live Demo

<iframe id="cms-demo" src="/online/webapp/file-manager" width="100%" height="650" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('cms-demo', 'cmsSocket');
window._cmsSeq = function (cmds, done) {

var s = window._ws('cmsSocket');
if (!s) return;
var i = 0;
var next = function () {
    if (i >= cmds.length) { if (done) done(); return; }
    var cmd = cmds[i++];
    var args = cmd.concat([function () { setTimeout(next, 5); }]);
    s.fire.apply(s, ['webapp::instance::request'].concat(args));
};
next();

};
window._cmsAppCode = function (renderFnStr) {

return 'module.exports = function () {\n' +
    'var app = new ApplicationPrototype();\n' +
    'var node = document.createElement("div");\n' +
    'var win = null;\n' +
    'var ready = new Application.Promise();\n' +
    'app.bind("node", function () { return node; }, "");\n' +
    'app.bind("window", function () { return win; }, "");\n' +
    'app.bind("ready", function () { return ready; });\n' +
    'app.bind("handleWindow", function (w) {\n' +
    '    win = w;\n' +
    '    w.emit("api-request::attached", []);\n' +
    '    w.on("api-request::ready", function (cb) { cb(ready); });\n' +
    '});\n' +
    'app.bind("render", function (cb) {\n' +
    '    (' + renderFnStr + ')(app, win, node, cb);\n' +
    '});\n' +
    'app.bind("destroy", function () {});\n' +
    'app.bind("init", function () {\n' +
    '    app.render(function (err) {\n' +
    '        if (err) return ready.reject(err);\n' +
    '        ready.resolve(app);\n' +
    '    });\n' +
    '    return app;\n' +
    '});\n' +
    'return app;\n' +
'};';

};
window._cmsSetup = function () {

// Page Preview app - renders frontmatter + markdown content as a styled page
var previewAppCode = window._cmsAppCode((function (app, win, node, cb) {
    win.title('Page Preview'); win.icon('paper/icons/apps/internet-web-browser');
    win.height(500); win.width(700);
    var args = app.window().env().args || [];
    if (!args[0]) { cb(); return; }
    node.innerHTML = '

Rendering page...

'; Application.require('/files/api/modules/fs.js').then(function (fsModule) { fsModule().read(args[0], null, true).response('text').then(function (text) { var frontmatter = {}; var content = text; var fmMatch = text.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); if (fmMatch) { fmMatch[1].split('\n').forEach(function (line) { var parts = line.split(':'); if (parts.length >= 2) frontmatter[parts[0].trim()] = parts.slice(1).join(':').trim(); }); content = fmMatch[2]; } var html = content .replace(/^### (.+)$/gm, '

$1

') .replace(/^## (.+)$/gm, '

$1

') .replace(/^# (.+)$/gm, '

$1

') .replace(/\*\*(.+?)\*\*/g, '$1') .replace(/\*(.+?)\*/g, '$1') .replace(/`([^`]+)`/g, '$1') .replace(/^- (.+)$/gm, '
  • $1
  • ') .replace(/\n\n/g, '

    ') .replace(/\n/g, '
    '); var page = '

    '; if (frontmatter.title) { page += '
    '; page += '

    ' + frontmatter.title + '

    '; if (frontmatter.description) page += '

    ' + frontmatter.description + '

    '; if (frontmatter.author || frontmatter.date) page += '
    ' + (frontmatter.author || '') + (frontmatter.author && frontmatter.date ? ' · ' : '') + (frontmatter.date || '') + '
    '; page += '
    '; } page += '

    ' + html + '

    '; if (frontmatter.tags) page += '
    Tags: ' + frontmatter.tags.split(',').map(function(t){return ''+t.trim()+''}).join(' ') + '
    '; page += '
    '; node.innerHTML = page; }); }); cb(); }).toString());
    // Content pages
    var homePage = [
        '---',
        'title: Welcome to Our Platform',
        'description: The fastest way to build modern web applications',
        'author: SGApps Team',
        'date: 2026-04-03',
        'tags: home, landing, featured',
        'status: published',
        '---',
        '',
        '## Build Something Amazing',
        '',
        'Our platform provides everything you need to create, deploy, and scale modern web applications.',
        '',
        '## Key Features',
        '',
        '- **Fast Development** — Go from idea to prototype in minutes',
        '- **Cloud Native** — Deploys automatically to our global CDN',
        '- **API First** — RESTful APIs generated from your schema',
        '- **Real-time** — Built-in WebSocket support for live features',
        '',
        '## Getting Started',
        '',
        'Create your first project with `npx create-app my-project` and start building immediately.',
        '',
        'Check out our documentation for tutorials, API reference, and best practices.'
    ].join('\n');
    var aboutPage = [
        '---',
        'title: About Us',
        'description: Learn about our team and mission',
        'author: SGApps Team',
        'date: 2026-03-15',
        'tags: about, team, company',
        'status: published',
        '---',
        '',
        '## Our Mission',
        '',
        'We believe that building web applications should be **accessible to everyone**. Our tools remove complexity so you can focus on what matters — your users.',
        '',
        '## The Team',
        '',
        'Founded in 2020, we are a small team of developers and designers passionate about developer experience.',
        '',
        '- *Engineering* — Building the platform core',
        '- *Design* — Crafting intuitive interfaces',
        '- *Community* — Supporting our users'
    ].join('\n');
    var blogPost = [
        '---',
        'title: Introducing Archive Support',
        'description: View and edit ZIP, TAR, and 7Z archives directly in the browser',
        'author: Sergiu Gordienco',
        'date: 2026-04-01',
        'tags: feature, archive, release',
        'status: draft',
        '---',
        '',
        '## What is New',
        '',
        'We are excited to announce **full archive support** in the File Manager. You can now open, browse, and edit ZIP, TAR, TAR.GZ, and 7Z archives directly in the browser.',
        '',
        '## How It Works',
        '',
        'When you double-click an archive file, the Archive Viewer:',
        '',
        '- Extracts all files to **browser memory** (no server upload)',
        '- Shows them in the familiar File Manager interface',
        '- Lets you **edit, add, and delete** files',
        '- Rebuilds the archive with one click',
        '',
        '## Supported Formats',
        '',
        '- ZIP (read + write)',
        '- TAR (read + write)',
        '- TAR.GZ (read + write)',
        '- 7Z (read + write)',
        '- RAR (read only)',
        '',
        '## Try It Now',
        '',
        'Open any archive file in the File Manager or use the Archive Viewer webapp at `/online/webapp/archive-viewer`.'
    ].join('\n');
    var siteConfig = JSON.stringify({
        site: { name: "My Platform", url: "https://example.com", language: "en" },
        navigation: [
            { label: "Home", path: "/", page: "pages/home.md" },
            { label: "About", path: "/about", page: "pages/about.md" },
            { label: "Blog", path: "/blog", page: "blog/" }
        ],
        theme: { primary: "#4a6cf7", font: "Inter, sans-serif" },
        build: { output: "dist/", minify: true }
    }, null, 2);
    window._cmsSeq([
        ['gui:specialPaths:clear'],
        ['fs:mkdirp', 'input://apps/'],
        ['fs:mkdirp', 'input://cms/pages/'],
        ['fs:mkdirp', 'input://cms/blog/'],
        ['fs:mkdirp', 'input://cms/assets/'],
        ['fs:write', 'input://apps/page-preview.js', previewAppCode],
        ['fs:write', 'input://cms/site.json', siteConfig],
        ['fs:write', 'input://cms/pages/home.md', homePage],
        ['fs:write', 'input://cms/pages/about.md', aboutPage],
        ['fs:write', 'input://cms/blog/2026-04-01-archive-support.md', blogPost],
        ['apps:register', {
            'page-preview': { path: 'input://apps/page-preview.js', name: 'Page Preview', icon: 'paper/icons/apps/internet-web-browser', comment: 'Preview content pages with frontmatter', mimetypes: ['text/markdown', 'text/x-markdown'], args: ['%U'] }
        }],
        ['gui:specialPaths:add', { path: 'input://cms/', name: 'CMS Content', icon: 'breeze/icons/places/64/folder-documents', paths: [{ rule: 'pages\\/', name: 'Pages' }, { rule: 'blog\\/', name: 'Blog Posts' }, { rule: 'assets\\/', name: 'Assets' }], bookmark: { category: 'cms', name: 'CMS Content', icon: 'breeze/icons/places/64/folder-documents' } }],
        ['gui:sidebar:toggle', true],
        ['fs:cwd', 'input://cms/']
    ], function () {
        alert('CMS workspace ready!\n\nTry:\n- Double-click home.md or about.md to preview the page\n- Double-click the blog post to see it as a draft\n- Double-click site.json to view config (opens in Code Editor)\n- Check the breadcrumbs: CMS Content > Pages, Blog Posts');
    });

    };</script>
    <button onclick="window._cmsSetup()" style="padding:10px 20px;font-size:15px;cursor:pointer">Setup CMS Content Editor</button>


    What This Demo Does

    Creates a headless CMS structure with a custom Page Preview app that understands frontmatter metadata:

    input://cms/
      site.json              ← opens with JSON Viewer (if registered) or Code Editor
      pages/
        home.md              ← opens with Page Preview (renders frontmatter header + markdown)
        about.md             ← opens with Page Preview
      blog/
        2026-04-01-*.md      ← opens with Page Preview (shows "draft" status)
      assets/                ← for images, CSS, etc.

    The Page Preview App

    Parses YAML-like frontmatter between --- delimiters:

    ---
    title: Page Title
    description: A brief description
    author: Author Name
    date: 2026-04-03
    tags: tag1, tag2, tag3
    status: published
    ---
    
    ## Content starts here
    
    Regular **markdown** content...

    The preview renders:

    Content Workflow

    1. Browse — navigate the pages/ and blog/ directories
    2. Preview — double-click a .md file to see the rendered page
    3. Edit — right-click → "Edit" to open in Code Editor, modify the markdown
    4. Create — right-click → "New Document" to add a new page
    5. Organize — drag files between pages/ and blog/ folders

    Building a CMS Widget

    // Setup the CMS workspace
    socket.fire("webapp::instance::request", "fs:mkdirp", "input://cms/pages/");
    socket.fire("webapp::instance::request", "fs:mkdirp", "input://cms/blog/");
    
    // Write content pages
    socket.fire("webapp::instance::request", "fs:write",
        "input://cms/pages/home.md",
        "---\ntitle: Home\n---\n\n## Welcome\n\nYour content here."
    );
    
    // Register the page preview app
    socket.fire("webapp::instance::request", "apps:register", {
        "page-preview": {
            path: "input://apps/page-preview.js",
            name: "Page Preview",
            mimetypes: ["text/markdown"],
            args: ["%U"]
        }
    });
    
    // Configure sidebar navigation
    socket.fire("webapp::instance::request", "gui:specialPaths:add", {
        path: "input://cms/",
        name: "Content",
        paths: [
            { rule: "pages\\/", name: "Pages" },
            { rule: "blog\\/", name: "Blog" }
        ],
        bookmark: { category: "cms", name: "Content", icon: "breeze/icons/places/64/folder-documents" }
    });

    Combining with Other Use Cases

    This CMS demo works alongside the other use cases:

    sgapps.io