-
Notifications
You must be signed in to change notification settings - Fork 0
docs: progressive complexity guide and feature documentation #221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5fb7dbb
0cd9393
61dea3d
9e1f85c
1240e0f
25cd02e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,8 +14,8 @@ Tinkerdown replaces typical app scaffolding with a single markdown file — data | |
|
|
||
| - **One file = one app.** Data connections, layout, and interactions all live in one place. No build step, no node_modules, no boilerplate. | ||
| - **AI gets it right.** A single declarative file with no component tree or state management means less surface area for LLMs to misconfigure. | ||
| - **8 data sources out of the box.** SQLite, PostgreSQL, REST APIs, JSON, CSV, shell commands, markdown, and WASM. Point at existing infrastructure and get a working UI. | ||
| - **Start simple, add power as needed.** Plain markdown tables become editable grids. Add YAML frontmatter for databases, or drop to HTML + Go templates for full control. | ||
| - **9 data sources out of the box.** SQLite, PostgreSQL, REST APIs, JSON, CSV, shell commands, markdown, WASM, and computed/derived sources. Point at existing infrastructure and get a working UI. | ||
| - **Progressive complexity.** Write standard markdown — task lists become interactive, tables auto-bind to data sources. Need more control? Add HTML attributes. Need full custom layouts? Drop to Go templates. Each step builds on the last without rewriting. See the [Progressive Complexity Guide](docs/guides/progressive-complexity.md). | ||
| - **Git-native and self-hosted.** Plain text in a repo. Version history, search, collaboration, offline access, no subscriptions. | ||
| - **Made for disposable software.** The admin panel for this sprint. The tracker for that hiring round. Software you'd never scaffold a React project for, but that's useful for days or weeks. | ||
|
|
||
|
|
@@ -36,35 +36,43 @@ tinkerdown serve | |
|
|
||
| ## What You Can Build | ||
|
|
||
| Write a single markdown file with frontmatter configuration: | ||
| Write a markdown file with a YAML source definition and a standard markdown table. Tinkerdown infers that the "Tasks" heading matches the "tasks" source and auto-generates an interactive table with add, edit, and delete: | ||
|
|
||
| ```markdown | ||
| --- | ||
| title: Task Manager | ||
| sources: | ||
| tasks: | ||
| type: sqlite | ||
| path: ./tasks.db | ||
| query: SELECT * FROM tasks | ||
| db: ./tasks.db | ||
| table: tasks | ||
| readonly: false | ||
|
Comment on lines
44
to
+49
|
||
| --- | ||
|
|
||
| # Task Manager | ||
|
|
||
| <table lvt-source="tasks" lvt-columns="title,status,due_date" lvt-actions="Complete,Delete"> | ||
| </table> | ||
|
|
||
| <form lvt-submit="AddTask"> | ||
| <input name="title" placeholder="New task" required> | ||
| <button type="submit">Add</button> | ||
| </form> | ||
| ## Tasks | ||
| | Title | Status | Due Date | | ||
| |-------|--------|----------| | ||
| ``` | ||
|
|
||
| Run `tinkerdown serve` and get a fully interactive app with database persistence. | ||
| Run `tinkerdown serve` and get a fully interactive app with database persistence — no HTML needed: | ||
|
|
||
| <p align="center"> | ||
| <img src="docs/assets/auto-table-demo.png" alt="Screenshot showing an auto-generated expense tracker with data table, edit/delete buttons per row, and an add form — all from a markdown table and YAML source definition" width="720"> | ||
| </p> | ||
|
|
||
| **Need more control?** Use HTML attributes for explicit binding: | ||
|
|
||
| ```html | ||
| <table lvt-source="tasks" lvt-columns="title,status" lvt-datatable lvt-actions="Complete,Delete"> | ||
| </table> | ||
| ``` | ||
|
|
||
| ## Key Features | ||
|
|
||
| - **Single-file apps**: Everything in one markdown file with frontmatter | ||
| - **8 data sources**: SQLite, JSON, CSV, REST APIs, PostgreSQL, exec scripts, markdown, WASM | ||
| - **9 data sources**: SQLite, JSON, CSV, REST APIs, PostgreSQL, exec scripts, markdown, WASM, computed | ||
| - **Auto-rendering**: Tables, selects, and lists generated from data | ||
|
Comment on lines
74
to
76
|
||
| - **Real-time updates**: WebSocket-powered reactivity | ||
| - **Zero config**: `tinkerdown serve` just works | ||
|
|
@@ -102,6 +110,7 @@ sources: | |
| | `exec` | Shell commands | [lvt-source-exec-test](examples/lvt-source-exec-test) | | ||
| | `markdown` | Markdown files | [markdown-data-todo](examples/markdown-data-todo) | | ||
| | `wasm` | WASM modules | [lvt-source-wasm-test](examples/lvt-source-wasm-test) | | ||
| | `computed` | Derived/aggregated data | [computed-source](examples/computed-source) | | ||
|
|
||
| ## Auto-Rendering | ||
|
|
||
|
|
@@ -189,6 +198,7 @@ See [AI Generation Guide](docs/guides/ai-generation.md) for tips on using Claude | |
| - [Project Structure](docs/getting-started/project-structure.md) | ||
|
|
||
| **Guides:** | ||
| - [Progressive Complexity](docs/guides/progressive-complexity.md) | ||
| - [Data Sources](docs/guides/data-sources.md) | ||
| - [Auto-Rendering](docs/guides/auto-rendering.md) | ||
| - [Go Templates](docs/guides/go-templates.md) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,7 @@ sources: | |
| | [csv](../sources/csv.md) | CSV files | Spreadsheet data, imports | | ||
| | [markdown](../sources/markdown.md) | Markdown files | Content management | | ||
| | [wasm](../sources/wasm.md) | WebAssembly modules | Custom sources | | ||
| | [computed](../sources/computed.md) | Derived/aggregated data | Dashboards, summaries | | ||
|
Comment on lines
36
to
+39
|
||
|
|
||
| ## Frontmatter Configuration (Recommended) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| # Progressive Complexity | ||
|
|
||
| Tinkerdown lets you build increasingly complex apps by graduating through natural complexity tiers. Each tier builds on the previous one — nothing needs rewriting. Start with pure markdown and add capabilities as your needs grow. | ||
|
|
||
| ## Tier 0: Pure Markdown | ||
|
|
||
| Write standard markdown. Task lists become interactive automatically — checkboxes toggle, new items can be added, changes persist to the file. | ||
|
|
||
| ```markdown | ||
| # Shopping List | ||
| - [ ] Milk | ||
| - [x] Bread | ||
| - [ ] Eggs | ||
| ``` | ||
|
|
||
| No YAML, no HTML, no configuration. Just markdown. | ||
|
|
||
| **What you get:** Interactive checkboxes, add-item form, file persistence. | ||
|
|
||
| **Examples:** [auto-tasks](../../examples/auto-tasks/) | ||
|
|
||
| --- | ||
|
|
||
| ## Tier 1: Markdown + YAML Sources | ||
|
|
||
| Define data sources in YAML frontmatter and write standard markdown tables. Tinkerdown matches heading names to source names and auto-generates the appropriate UI. | ||
|
|
||
| ```yaml | ||
| --- | ||
| sources: | ||
| expenses: | ||
| type: sqlite | ||
| db: ./expenses.db | ||
| table: expenses | ||
| readonly: false | ||
| --- | ||
|
|
||
| # Expense Tracker | ||
|
|
||
| ## Expenses | ||
| | Description | Category | Amount | | ||
| |-------------|----------|--------| | ||
| ``` | ||
|
|
||
| The heading "Expenses" matches the source named "expenses". Since the source is writable (`readonly: false`), Tinkerdown generates a full CRUD interface: data table with edit and delete buttons, plus an add form. Amount gets a number input because schema introspection detects it as a numeric column. | ||
|
|
||
| For read-only sources (REST APIs, JSON files), the table auto-populates with a refresh button and no CRUD controls. | ||
|
|
||
| ### Computed Sources | ||
|
|
||
| Derive aggregated data from other sources without writing code: | ||
|
|
||
| ```yaml | ||
| --- | ||
| sources: | ||
| expenses: | ||
| type: sqlite | ||
| db: ./expenses.db | ||
| table: expenses | ||
| by_category: | ||
| type: computed | ||
| from: expenses | ||
| group_by: category | ||
| aggregate: | ||
| total: sum(amount) | ||
| count: count() | ||
| --- | ||
|
|
||
| ## By Category | ||
| | Category | Total | Count | | ||
| |----------|-------|-------| | ||
| ``` | ||
|
|
||
| Supported aggregation functions: `sum()`, `count()`, `avg()`, `min()`, `max()`. Computed sources auto-refresh when the parent source changes. Note: a computed source cannot reference another computed source as its parent — only real data sources (SQLite, REST, etc.). | ||
|
|
||
| ### How Source Matching Works | ||
|
|
||
| Tinkerdown matches markdown table headings to source names using smart matching: | ||
|
|
||
| 1. **Exact match:** Heading "Expenses" (slug: `expenses`) matches source `expenses` | ||
| 2. **Underscore normalization:** Heading "By Category" (slug: `by-category`) also matches source `by_category` | ||
| 3. **Word containment:** Heading "My Monthly Expenses" matches source `expenses` (the slug `my-monthly-expenses` contains `expenses` at a word boundary) | ||
| 4. **No match:** The table renders as a normal static markdown table | ||
|
|
||
| Exact and underscore-normalized matches take precedence over word containment. If containment is ambiguous (heading matches multiple sources), Tinkerdown skips with a warning. Use `auto_bind: false` on a source to exclude it from matching — useful for generic names like `data` or `items`: | ||
|
|
||
| ```yaml | ||
| sources: | ||
| status: | ||
| type: rest | ||
| from: https://api.example.com/status | ||
| auto_bind: false # don't auto-match to heading "Status" | ||
| ``` | ||
|
|
||
| **What you get:** Auto-populated tables, CRUD for writable sources, schema-aware form inputs, computed aggregations. | ||
|
|
||
| **Examples:** [auto-table-sqlite](../../examples/auto-table-sqlite/), [auto-table-rest](../../examples/auto-table-rest/), [computed-source](../../examples/computed-source/) | ||
|
|
||
| --- | ||
|
|
||
| ## Tier 2: HTML + lvt-* Attributes | ||
|
|
||
| When auto-inference can't give you what you need — custom layouts, explicit action buttons, confirmation dialogs, datatable features, cross-source selects — use HTML elements with `lvt-*` attributes. | ||
|
|
||
| ```html | ||
| <table lvt-source="tasks" lvt-columns="title,status" lvt-datatable lvt-actions="Complete,Delete"> | ||
| </table> | ||
|
|
||
| <form lvt-submit="Add" lvt-reset-on:success> | ||
| <input name="title" placeholder="New task" required> | ||
| <select name="priority" lvt-source="priorities" lvt-value="id" lvt-label="name"></select> | ||
| <button type="submit">Add</button> | ||
| </form> | ||
|
|
||
| <button lvt-click="ClearDone" lvt-confirm="Delete all completed tasks?">Clear Done</button> | ||
| ``` | ||
|
|
||
| The escape from Tier 1 to Tier 2 is clean: if the auto-generated UI isn't right, replace the markdown table with explicit HTML. The auto-generated template can serve as a starting point. | ||
|
|
||
| **What you get:** Explicit data binding, custom forms, action buttons with confirmation, datatable with sorting/pagination, cross-source selects. | ||
|
|
||
| **References:** [Auto-Rendering Guide](auto-rendering.md), [lvt-* Attributes Reference](../reference/lvt-attributes.md) | ||
|
|
||
| --- | ||
|
|
||
| ## Tier 3: Go Templates | ||
|
|
||
| For full control over rendering, use Go template syntax inside `lvt` code blocks: | ||
|
|
||
| ````markdown | ||
| ```lvt | ||
| <div lvt-source="expenses"> | ||
| {{if .Error}} | ||
| <div class="error">{{.Error}}</div> | ||
| {{else}} | ||
| {{range .Data}} | ||
| <div class="card"> | ||
| <h3>{{.Description}}</h3> | ||
| <span class="badge">{{.Category}}</span> | ||
| <span class="amount">${{.Amount}}</span> | ||
| <button lvt-click="Delete" lvt-data-id="{{.Id}}">Remove</button> | ||
| </div> | ||
| {{end}} | ||
| {{end}} | ||
| </div> | ||
| ``` | ||
| ```` | ||
|
|
||
| Go templates give you conditionals, loops, custom HTML structure, and access to the full state object (`.Data`, `.Error`, `.Errors`). | ||
|
|
||
| **What you get:** Conditional rendering, custom HTML layouts, multiple data iterations, error handling. | ||
|
|
||
| **References:** [Go Templates Guide](go-templates.md) | ||
|
|
||
| --- | ||
|
|
||
| ## Tier 4: Custom Data Sources | ||
|
|
||
| For data that doesn't fit built-in source types, write a custom source in TinyGo compiled to WASM. The module exports a `fetch` function that returns JSON data: | ||
|
|
||
| ```yaml | ||
| sources: | ||
| custom: | ||
| type: wasm | ||
| path: ./sources/custom.wasm | ||
| ``` | ||
|
|
||
| Use `tinkerdown new myapp --template wasm-source` to scaffold a working WASM source project with build scripts and a test app. | ||
|
|
||
| **What you get:** Arbitrary data fetching logic, compiled to WASM, runs server-side. | ||
|
|
||
| **References:** [WASM Source Docs](../sources/wasm.md) | ||
|
|
||
| --- | ||
|
|
||
| ## When to Graduate | ||
|
|
||
| | If you need... | Use | | ||
| |----------------|-----| | ||
| | Interactive task lists | Tier 0 — just write markdown checkboxes | | ||
| | Data tables from databases/APIs | Tier 1 — markdown tables + YAML sources | | ||
| | Aggregated dashboards | Tier 1 — computed sources | | ||
| | Custom form layouts | Tier 2 — HTML + lvt-* attributes | | ||
| | Conditional rendering | Tier 3 — Go templates | | ||
| | Custom data fetching | Tier 4 — WASM sources | | ||
|
|
||
| The key principle: **start at the lowest tier that works.** Each tier adds complexity but also capability. If you're writing HTML when a markdown table would suffice, you're working harder than you need to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The README claims “9 data sources out of the box” but the codebase also supports a
graphqlsource type (and the docs include it). Either include GraphQL in the list and update the count, or adjust the wording to avoid an incorrect/fragile count.