Objective
Create a simple one-page static website with a non-technical editor UI at /admin/ using Decap CMS. Content is stored as Markdown (content/home.md) and rendered into HTML via Eleventy (11ty) at build time. Host on Netlify with auto-deploys from Git.
What to create (file tree) / ├─ package.json ├─ .eleventy.js ├─ netlify.toml ├─ README.md ├─ /admin/ │ ├─ index.html │ └─ config.yml ├─ /assets/ # CMS-uploaded images/files (in repo) ├─ /content/ │ └─ home.md # Single editable page (frontmatter + body) └─ /_includes/ └─ /layouts/ └─ home.njk # Template for the one-page site
Netlify will publish from ./_site (Eleventy’s default output).
Commands to support
npm install
npm run dev → local preview at http://localhost:8080 (11ty serve)
npm run build → static build to ./_site
Files — create with exact contents package.json { "name": "decap-onepage-netlify", "version": "1.0.0", "private": true, "scripts": { "dev": "npx @11ty/eleventy --serve", "build": "npx @11ty/eleventy" }, "devDependencies": { "@11ty/eleventy": "^2.0.0" } }
.eleventy.js module.exports = function(eleventyConfig) { // Copy CMS admin and assets straight through to _site eleventyConfig.addPassthroughCopy({ "admin": "admin" }); eleventyConfig.addPassthroughCopy({ "assets": "assets" });
// Set input/output return { dir: { input: ".", includes: "_includes", data: "_data", output: "_site" }, markdownTemplateEngine: "njk", htmlTemplateEngine: "njk", templateFormats: ["md", "njk", "html"] }; };
netlify.toml [build] command = "npm run build" publish = "_site"
[[redirects]] from = "/admin" to = "/admin/" status = 301
admin/index.html <!doctype html>
<title>Content Admin</title> <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>admin/config.yml
If you’ll use Netlify Identity + Git Gateway, keep backend: git-gateway and enable both in the Netlify dashboard (Site → Identity → Enable; then Enable Git Gateway). If you prefer GitHub OAuth, change to backend: github and set repo: your-user/your-repo.
backend: name: git-gateway # or "github" branch: main
media_folder: "assets" # stored in repo public_folder: "/assets" # how site references them
publish_mode: editorial_workflow # allow drafts/review (optional)
collections:
- label: "Homepage"
name: "homepage"
delete: false
files:
- label: "Home Content"
name: "home"
file: "content/home.md"
fields:
-
{ label: "Title", name: "title", widget: "string" }
-
{ label: "Tagline", name: "tagline", widget: "string" }
-
{ label: "Hero Image", name: "hero_image", widget: "image", required: false }
-
label: "Sections" name: "sections" widget: "list" types:
- label: "Feature Grid"
name: "feature_grid"
widget: "object"
fields:
- { label: "Heading", name: "heading", widget: "string" }
- label: "Items"
name: "items"
widget: "list"
fields:
- { label: "Title", name: "title", widget: "string" }
- { label: "Description", name: "description", widget: "text" }
- { label: "Icon", name: "icon", widget: "image", required: false }
- label: "Testimonial"
name: "testimonial"
widget: "object"
fields:
- { label: "Quote", name: "quote", widget: "text" }
- { label: "Author", name: "author", widget: "string" }
- label: "Call to Action"
name: "cta"
widget: "object"
fields:
- { label: "Heading", name: "heading", widget: "string" }
- { label: "Button Text", name: "button_text", widget: "string" }
- { label: "Button Link", name: "button_href", widget: "string" }
- label: "Feature Grid"
name: "feature_grid"
widget: "object"
fields:
-
label: "SEO" name: "seo" widget: "object" fields:
- { label: "Meta Title", name: "meta_title", widget: "string" }
- { label: "Meta Description", name: "meta_description", widget: "text" }
- { label: "Social Image", name: "social_image", widget: "image", required: false }
-
{ label: "Body", name: "body", widget: "markdown" }
-
- label: "Home Content"
name: "home"
file: "content/home.md"
fields:
layout: layouts/home.njk title: "Site Title" tagline: "One clear sentence about what this is" hero_image: "/assets/hero.jpg"
sections:
-
type: "feature_grid" heading: "What we do" items:
- title: "Feature A" description: "Short blurb explaining A." icon: "/assets/icon-a.svg"
- title: "Feature B" description: "Short blurb explaining B." icon: "/assets/icon-b.svg"
-
type: "testimonial" quote: "This product changed our workflows." author: "Alex C., Ops Lead"
-
type: "cta" heading: "Ready to talk?" button_text: "Contact us" button_href: "mailto:hello@example.com"
seo: meta_title: "Company — Clear Tagline" meta_description: "Short, keyword-rich description for search and link unfurls." social_image: "/assets/social-card.jpg"
Welcome to our site. This paragraph is the main body content shown near the top. You can edit everything on this page from the admin panel.
/_includes/layouts/home.njk <!doctype html>
<title>{{ seo.meta_title or title }}</title> {% if seo.meta_description %} {% endif %} {% if seo.social_image %} {% endif %} <style> :root { --max: 980px; } html,body { margin:0; padding:0; } body { font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; line-height:1.6; color:#111; } header, main, footer { padding: 24px; } .wrap { max-width: var(--max); margin: 0 auto; } header.hero { padding-top: 56px; padding-bottom: 32px; text-align: center; } header.hero img { max-width: 100%; height: auto; border-radius: 16px; } h1 { font-size: clamp(28px, 4vw, 44px); margin: 16px 0 8px; } .tagline { color:#444; font-size: clamp(16px, 2.2vw, 20px); margin-bottom: 20px; } section { margin: 40px 0; } .grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } .card { border: 1px solid #eee; border-radius: 16px; padding: 16px; box-shadow: 0 1px 2px rgba(0,0,0,.04); } .card h3 { margin: 0 0 8px; font-size: 18px; } .testimonial { font-style: italic; background: #fafafa; border-radius: 16px; padding: 20px; border: 1px solid #eee; } .cta { text-align: center; background: #0f62fe0d; border: 1px solid #cfe0ff; border-radius: 16px; padding: 24px; } .btn { display:inline-block; padding:12px 18px; border-radius: 999px; border: 1px solid #0f62fe; text-decoration:none; } .btn:hover { background:#0f62fe; color:#fff; } footer { color:#666; font-size:14px; border-top:1px solid #eee; } .body { margin-top: 16px; } img.icon { width: 32px; height: 32px; vertical-align: middle; margin-right: 8px; } </style>{{ tagline }}
{% endif %} {% if content %}<main>
<div class="wrap">
{% if sections and sections.length %}
{% for s in sections %}
{% if s.type == "feature_grid" %}
<section>
{% if s.heading %}<h2>{{ s.heading }}</h2>{% endif %}
<div class="grid">
{% for it in s.items or [] %}
<div class="card">
<h3>
{% if it.icon %}<img class="icon" src="{{ it.icon }}" alt="">{% endif %}
{{ it.title }}
</h3>
<p>{{ it.description }}</p>
</div>
{% endfor %}
</div>
</section>
{% elif s.type == "testimonial" %}
<section>
<div class="testimonial">
<p>“{{ s.quote }}”</p>
<p><strong>— {{ s.author }}</strong></p>
</div>
</section>
{% elif s.type == "cta" %}
<section>
<div class="cta">
<h2>{{ s.heading }}</h2>
{% if s.button_text and s.button_href %}
<p><a class="btn" href="{{ s.button_href }}">{{ s.button_text }}</a></p>
{% endif %}
</div>
</section>
{% endif %}
{% endfor %}
{% endif %}
</div>
</main>
<footer>
<div class="wrap">
<p>© {{ (new Date()).getFullYear() }} {{ title }}</p>
</div>
</footer>
README.md
- Edit at
/admin/(Decap CMS) - Content lives in
content/home.md( Markdown + frontmatter ) - Built by Eleventy → static HTML → deployed on Netlify
npm install
npm run dev
# open the served URL (usually http://localhost:8080)
Local CMS login requires either GitHub backend or running with Netlify Identity in production. For local content editing without auth, you can edit content/home.md directly.
Build
npm run build
# output in ./_site
Deploy to Netlify
Push this repo to GitHub/GitLab/Bitbucket.
In Netlify, New site from Git, pick your repo.
Build command: npm run build
Publish directory: _site
Deploy.
Enable Editor Login
Option A: Netlify Identity + Git Gateway (no GitHub app needed)
Netlify → Site → Identity → Enable Identity.
Click Invite Users (use your editors’ emails).
Netlify → Identity → Git Gateway → Enable Git Gateway.
Visit https://<yoursite>.netlify.app/admin/ to log in.
Option B: GitHub Backend
In admin/config.yml, set:
backend:
name: github
repo: your-user/your-repo
branch: main
Create a GitHub OAuth app and set callback in Netlify (Site settings → Build & deploy → Environment → add required vars). Follow Decap GitHub backend docs.
Editors log in at /admin/.
Editing Content
Go to /admin/ → “Homepage” → “Home Content”
Change fields or upload images
Save → Publish
Netlify runs a new build; site updates after deploy completes
Notes
Images uploaded via the CMS are stored in /assets/ and deployed with the site.
You can rename sections or add types in admin/config.yml and map them in the layout template.
---
## How to run (for Claude to execute)
1. **Initialize project**
- Create all files above with the exact contents.
- Run `npm install`.
2. **Local preview**
- `npm run dev`
- Open the served URL (usually `http://localhost:8080`).
3. **First deploy**
- Commit and push to your Git host.
- Create a new Netlify site from this repo.
- Build command: `npm run build`, Publish dir: `_site`.
- Deploy.
4. **Enable login**
- **Recommended:** Netlify Identity + Git Gateway.
- Invite editors; they log in at `/admin/`.
5. **Handoff**
- Share the site URL and `/admin/` with editors.
- Keep `README.md` as your non-technical handoff doc.
---
## Done When
- `/` renders the one-page site from `content/home.md`.
- `/admin/` loads Decap CMS and allows editing + publishing.
- Publishing triggers Netlify builds and updates the live site.
---
**That’s the full, end-to-end setup.** If you want me to swap Eleventy for Astro or plain HTML + simple build, say the word and I’ll output a variant CLAUDE.md tailored to that stack.
::contentReference[oaicite:0]{index=0}