Planter Content

This repository contains the blog posts, documentation, series, newsletters, and other content for planter.garden. Content is Markdown with YAML frontmatter; the website is statically generated from it by the Jaspr site in the main planter repo.

Structure

planter_content/
├── blog/           # Growing guide posts (one folder or .md file per post)
├── docs/           # Documentation, organized by section folder
├── series/         # Series landing pages
├── author/         # Author bio pages
├── newsletters/    # Newsletter archive
├── eula.md         # Legal pages
├── privacy.md
└── .github/
    └── workflows/
        └── trigger-jaspr-build.yml  # Triggers the website rebuild on push

How publishing works

Push to main and the website rebuilds itself — no other steps:

  1. A push triggers a content-only build of the website (the Flutter app part is cached, only the static site is rebuilt).
  2. planter.garden is live with your changes in about 5 minutes.
  3. preview.planter.garden rebuilds at the same time and additionally shows all draft: true content — send authors there to review drafts in full site context.

You can also skip this repo entirely and use the CMS at planter.garden/admin — it edits this repository through the GitHub API and publishes the same way.

Local development, from zero

Run the real website locally against your working copy of the content, so you can preview docs/blog changes before pushing.

1. Prerequisites

  • git, with SSH access to the PlanterApp GitHub org (the site build depends on the private planter_core package via SSH). Test with: ssh -T git@github.com
  • Flutter SDK (the site's Dart packages require it — plain Dart isn't enough): https://docs.flutter.dev/get-started/install, then confirm flutter --version works.

2. Clone both repos side by side

The site expects planter_content to be a sibling of the planter repo:

cd ~/development   # or wherever you keep repos
git clone git@github.com:PlanterApp/planter.git          # skip if you have it
git clone git@github.com:PlanterApp/planter_content.git
cd planter/web_jaspr
rm -rf content                      # remove any existing checkout
ln -s ../../planter_content content

(../../planter_content resolves from inside web_jaspr/, which is why the repos must be siblings.)

4. Install the Jaspr CLI

dart pub global activate jaspr_cli

Make sure ~/.pub-cache/bin is on your PATH (the activate command prints a warning with instructions if it isn't).

5. One-time package setup

The site depends on the shared planter_models package, which needs its code generated once (and again whenever its models change):

cd planter/packages/planter_models
dart pub get
dart run build_runner build --delete-conflicting-outputs

6. Run the dev server

cd planter/web_jaspr
dart pub get
jaspr serve

The first build takes a few minutes (later ones are incremental). Then open:

  • http://localhost:8080/docs — documentation
  • http://localhost:8080/blog — growing guide
  • Plant pages use a data snapshot checked into web_jaspr/data/ — possibly stale, but fine for content work.

7. The editing loop

  1. Edit Markdown in your planter_content checkout.
  2. Reload the page — the dev server re-reads content per request.
  3. If a change stubbornly doesn't appear (file watching through the symlink is imperfect), restart jaspr serve.
  4. draft: true content is always visible in local dev, exactly like on the preview site.
  5. When it looks right: commit, push to main (or open a PR for review), and it's live in ~5 minutes.

Content format

Blog post (blog/<slug>/index.md)

---
title: "Post Title"
description: "Brief description for SEO"
date: 2026-01-15T09:00:00.000Z
author: Full Name
tags: ["Compost", "Soil Health"]
series: ["Herbs"]
plants: ["Basil", "Mint"]      # links the post to plant pages + app feeds
cover:
  image: "https://ucarecdn.com/<uuid>/"
  alt: "Image description"
draft: true                     # remove (or set false) to publish
---

Content goes here...

Referencing a series that doesn't have a landing page yet? Publishing through the CMS creates one automatically; when editing here directly, add series/<slug>/index.md yourself (copy an existing one).

Doc page (docs/<section>/<slug>/index.md)

---
title: "How do I do the thing?"
description: "Shown in search results and section overviews"
weight: 210        # sort order within the section (lower = higher)
toc: true          # show the on-page table of contents
---

The folder structure is the site structure: docs/plants/add-plants/index.md is served at /docs/plants/add-plants. Each section folder has an index.md (the section overview) whose title and weight drive the sidebar navigation.

Components available in Markdown

<Notice type="tip">Markdown works **inside** notices.</Notice>   # tip | info | warning | note
<YouTube id="VIDEO_ID" />
<Mdi name="sort" label="Sort icon" />        # inline Material Design Icon
<Caption text="Source: ..." />               # small muted caption (e.g. under tables)
<Search />                                   # docs search box (docs pages only)
![Alt text](https://ucarecdn.com/<uuid>/ "Optional caption")

Images should be hosted on UploadCare (the CMS uploads there automatically); portrait screenshots are automatically constrained so they don't dominate the page.

Contributing

  1. Branch (or edit main directly for trivial fixes — pushes to main deploy).
  2. Add or edit content; preview locally or rely on draft: true + the preview site.
  3. PR for anything that wants review; merge publishes it.