Publishing posts
How the content of jonasheinle.de is laid out, and how a new blog post or a post about a book gets on it. Running and building the app: getting-started.md.
Why Markdown and not a CMS
I wanted to publish new content (blog posts, thoughts about books, ...) fast, and without a CMS:
- The content is pure Markdown, so the technology can change at any time; many CMS tie the content tightly to their technology. You do not depend on my repo either: you can always switch.
- A native Linux UI would make the effort put into a CMS web blog more or less useless. This project is a large reusable part that builds native UIs too (with a Rust backend, for example).
- I want a unique look and feel, so I want full control over the application, which some drag-and-drop solutions make difficult.
- I want to learn front-end development and its challenges; just using WordPress does not get you there.
- My own WebDavClient keeps the content (.md files, images, videos, .csv, etc.) private while the source code stays open source. To keep your data private too, see my build pipeline file.
If you like the lightweight Markdown approach, my DocumANTation project converts Markdown to an A4 PDF or to presentation slides.
Content
All source code is open source, free to use and ready to go. The website data is separate from its view (MVC best practice): this repo has only the dummy entries, not my blog posts, which are my intellectual property.
The assets directory holds every file the app includes (fonts and the shared images come from
the ANThology package):
- data (.zip, .csv, ...)
- documents (for example .md for blog posts)
- and the settings directory, with the options for your own needs:
- global user settings: customize the blog for you: every user-related option (like email, name, image, etc.).
- All entries in
user_skills_de.json,user_skills_en.jsonanduser_skills_fr.json(one per language, named in the global user settings) show in the corresponding section.
- app settings: the app name and title. The footer can be disabled; the
supportedLocalesfield takes these values:["de"]: build a web app in pure German["en"]: build a web app in pure English["de","en"]or["en","de"]: switch between English and German["de","en","fr"](the committed setting): switch between German, English and French
Publish a new blog post
- Open
assets/settings/blog_settings.json. - Append an entry like this one:
{
"routingName":"/aiBlog2",
"shortDescriptionEN":"AI playground 2",
"shortDescriptionDE":"AI Spielwiese 2",
"filePath":"assets/documents/blog/aiBlogPageEn.md",
"imageDir":"assets/images/aiBlog",
"githubRepo":"MachineLearningAlgorithms",
"fileTitle": "AIBlog.pdf",
"fileAdditionalInfo": "PDF version",
"fileBaseDir": "assets/documents/blog/",
"lastModified":"03.04.2024",
"landingPageAlignment":"left",
"landingPageEntryImagePath": "assets/images/ML_CV.jpeg",
"landingPageEntryImageCaptioning": "image source: https://pyimagesearch.com/2023/03/30/machine-learning-computer-vision/",
"docsDesc": [
{
"baseDir":"assets/documents/cv/",
"title":"CV_Jonas_Heinle_english.pdf",
"additionalInfo": "~3.7MB English"
},
{
"baseDir": "assets/documents/cv/",
"title": "CV_Jonas_Heinle_german.pdf",
"additionalInfo": "~3.7MB German"
},
{
"baseDir": "assets/data/",
"title": "WorleyNoiseTextures.zip",
"additionalInfo": "Use it for you own projects."
}
]
},
- Every file an entry names must be bundled with the app. Flutter bundles only the files directly
in a directory listed under
flutter: assets:inpubspec.yaml, and the example'sassets/documents/blog/andassets/images/aiBlog/are no longer listed (they moved into ANThology on 2026-09-07). List your directory there, or name apackages/anthology/...asset as the committedblog_settings.jsondoes. The same holds for the entry below.
Publish a post about a book
- Open
assets/settings/my_two_cents_settings.json. - Add an entry like this one:
{
"routingName":"/books/fuenfGeheimnisse",
"filePath":"assets/documents/books/fuenfGeheimnisse.md",
"imageDir":"assets/images/aiBlog",
"mediaTitle":"Die fünf Geheimnisse, die Sie entdecken sollten, bevor Sie sterben",
"fileBaseDir": "assets/documents/books/",
"docsDesc": [
{
"baseDir":"assets/documents/cv/",
"title":"CV_Jonas_Heinle_english.pdf",
"additionalInfo": "~3.7MB English"
},
{
"baseDir": "assets/documents/cv/",
"title": "CV_Jonas_Heinle_german.pdf",
"additionalInfo": "~3.7MB German"
},
{
"baseDir": "assets/data/",
"title": "WorleyNoiseTextures.zip",
"additionalInfo": "Use it for you own projects."
}
]
},
- The
mediaTitlemust also appear inassets/data/Buecherliste_gelesen.csv.
Localization
Localized messages are generated from the .arb files in lib/l10n; flutter gen-l10n
regenerates the Dart after an edit (AGENTS.md § 4).
To support more languages, see Internationalizing Flutter apps.