- Section « Design System – Canevas » : liste des canevas (intégrés +
personnels, GET /board/api/page-templates) puis page de détail avec
« Créer une page à partir du canevas », « Insérer dans le document ouvert »
(désactivé sans document ouvert) et « Enregistrer le document ouvert comme
canevas ».
- GET /board/api/page-templates/{id}/blocks (nouvelle route) : blocs d'un
canevas — intégré via template_id=0&key=, sinon id ; 404 clé/id inconnu.
Insertion côté front via ensureBlockIds() global + concat dans E.blocks
+ autoSave/render.
- Canevas « Design System » ajouté aux builtins (callout tokens, TOC, toggles
composants, grille, checklist revue UI, citation).
- Fix : le front du panneau appelait /api/page-templates (404 silencieux) —
le router est sous prefix=/board → /board/api/page-templates.
- Piège : pour /use la clé builtin se passe DANS LE BODY (body.key), pas en
query string — test garde-fou ajouté.
- Tests : tests/test_v753_canvases.py (5) + test_v751 adapté. Suite complète
1285 verts (-n auto), ruff 0, eslint 0 problème. OpenAPI 516 chemins.
132 lines
4.9 KiB
Python
132 lines
4.9 KiB
Python
"""FlowDeck — Built-in page (block) templates (v5.12.0).
|
|
|
|
Global page templates used by the « + New page » picker. Built-ins live here
|
|
(code, versioned); user templates live in the ``page_global_templates``
|
|
table. Block shapes match the editor's storage format (see
|
|
``app/routers/board.py::save_page_blocks``) — ids are assigned client-side.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
|
|
def _b(btype: str, content: str = "", **extra) -> dict:
|
|
out = {"type": btype, "content": content}
|
|
out.update(extra)
|
|
return out
|
|
|
|
|
|
BUILTIN_TEMPLATES: dict[str, dict] = {
|
|
"empty": {
|
|
"name": "Empty",
|
|
"icon": "📄",
|
|
"description": "A blank page.",
|
|
"blocks": [_b("paragraph")],
|
|
},
|
|
"meeting_notes": {
|
|
"name": "Meeting notes",
|
|
"icon": "🗒️",
|
|
"description": "Attendees, agenda, notes, action items.",
|
|
"blocks": [
|
|
_b("heading_1", "Meeting notes"),
|
|
_b("callout", "Date: · Time: · Attendees: ", icon="📅"),
|
|
_b("heading_2", "Agenda"),
|
|
_b("bulleted_list", "Topic 1"),
|
|
_b("bulleted_list", "Topic 2"),
|
|
_b("heading_2", "Notes"),
|
|
_b("paragraph"),
|
|
_b("heading_2", "Decisions"),
|
|
_b("bulleted_list"),
|
|
_b("heading_2", "Action items"),
|
|
_b("to_do", "Owner — due date", checked=False),
|
|
_b("to_do", "", checked=False),
|
|
],
|
|
},
|
|
"weekly_report": {
|
|
"name": "Weekly report",
|
|
"icon": "📊",
|
|
"description": "Wins, in progress, blockers, next week.",
|
|
"blocks": [
|
|
_b("heading_1", "Week of [[fddate:2026-01-05]]"),
|
|
_b("heading_2", "🎉 Wins"),
|
|
_b("bulleted_list"),
|
|
_b("heading_2", "🚧 In progress"),
|
|
_b("bulleted_list"),
|
|
_b("heading_2", "⛔ Blockers"),
|
|
_b("bulleted_list"),
|
|
_b("heading_2", "🗓️ Next week"),
|
|
_b("to_do", "", checked=False),
|
|
],
|
|
},
|
|
"todo_list": {
|
|
"name": "To-do list",
|
|
"icon": "✅",
|
|
"description": "A simple checklist.",
|
|
"blocks": [
|
|
_b("heading_1", "To-do"),
|
|
_b("to_do", "", checked=False),
|
|
_b("to_do", "", checked=False),
|
|
_b("to_do", "", checked=False),
|
|
],
|
|
},
|
|
"project_doc": {
|
|
"name": "Project doc",
|
|
"icon": "🚀",
|
|
"description": "Goals, status, team, links.",
|
|
"blocks": [
|
|
_b("heading_1", "Project title"),
|
|
_b("callout", "One-line description of the project.", icon="💡"),
|
|
_b("heading_2", "Goals"),
|
|
_b("numbered_list"),
|
|
_b("heading_2", "Status"),
|
|
_b("toggle", "This week", expanded=True, children=[_b("paragraph")]),
|
|
_b("heading_2", "Team"),
|
|
_b("bulleted_list"),
|
|
_b("heading_2", "Resources"),
|
|
_b("bulleted_list"),
|
|
],
|
|
},
|
|
"design_system": {
|
|
"name": "Design System",
|
|
"icon": "🎨",
|
|
"description": "Tokens, composants et grille — canevas de référence UI.",
|
|
"blocks": [
|
|
_b("heading_1", "Design System"),
|
|
_b("callout",
|
|
"Tokens : couleur, espacement, typographie, rayon, ombres "
|
|
"(static/css/design-tokens.css).",
|
|
icon="🎨"),
|
|
_b("table_of_contents"),
|
|
_b("heading_2", "Composants"),
|
|
_b("toggle", "Boutons & actions", expanded=False,
|
|
children=[_b("paragraph", "Primaire · secondaire · danger — états idle, hover, focus, disabled.")]),
|
|
_b("toggle", "Cartes & panneaux", expanded=False,
|
|
children=[_b("paragraph", "Élévation, rayon, bordure, padding, zones de clic.")]),
|
|
_b("toggle", "Formulaires", expanded=False,
|
|
children=[_b("paragraph", "Champs, labels, hints, erreurs, focus visible.")]),
|
|
_b("heading_2", "Grille & espacement"),
|
|
_b("bulleted_list", "Base 4 px — pas d'espacement hors échelle."),
|
|
_b("bulleted_list", "Colonnes : 12 / 8 / 4 selon le point de rupture."),
|
|
_b("heading_2", "Revue UI"),
|
|
_b("to_do", "Contraste AA vérifié", checked=False),
|
|
_b("to_do", "États hover / focus / disabled", checked=False),
|
|
_b("to_do", "Responsive mobile", checked=False),
|
|
_b("quote", "Une décision de design vaut mieux qu'une justification après coup."),
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def template_list() -> list[dict]:
|
|
"""Public shape of the built-in templates for the picker UI."""
|
|
return [
|
|
{"key": key, "name": t["name"], "icon": t["icon"],
|
|
"description": t["description"], "builtin": True}
|
|
for key, t in BUILTIN_TEMPLATES.items()
|
|
]
|
|
|
|
|
|
def blocks_json_for(key: str) -> str | None:
|
|
t = BUILTIN_TEMPLATES.get(key)
|
|
return json.dumps(t["blocks"]) if t else None
|