diff --git a/docs/APPS.md b/docs/APPS.md index c698d316b..c3b1f7005 100644 --- a/docs/APPS.md +++ b/docs/APPS.md @@ -88,7 +88,8 @@ See `solstone/apps/__init__.py` for discovery logic and route injection. ### 1. `workspace.html` - Main Content -The workspace template is included inside the app container (`app.html`). +The workspace fragment is served verbatim and mounted into the static shell +(`convey/static/shell.html`) at `/app/{name}/`. **Available Template Context:** - `app` - Current app name (auto-injected from URL) @@ -148,14 +149,12 @@ Override default icon, label, and other app settings. - `date_nav` - Show date navigation bar (default: false) - `app_bar` - Show the universal chat bar (default: true) - `allow_future_dates` - Allow clicking future dates in month picker (default: false) -- `spa` - Transitional opt-in for the static shell and `/workspace` fragment route (default: false) **When to disable facets:** Set `"facets": false` for apps that don't use facet-based organization (e.g., system settings, dev tools). -**Static shell default:** New apps should use `"spa": true` with a -construct-free `workspace.html`: no `{{`, `{%`, or `{#` Jinja constructs. -SPA apps serve `convey/static/shell.html` at `/app/{name}/` and their workspace -bytes at `/app/{name}/workspace`. +**Static shell:** Every app serves `convey/static/shell.html` at `/app/{name}/` +and its `workspace.html` bytes at `/app/{name}/workspace`. Keep +`workspace.html` construct-free — no `{{`, `{%`, or `{#`. **Examples:** Browse `solstone/apps/*/app.json` for reference configurations. @@ -634,7 +633,7 @@ See [talent/journal/SKILL.md](../talent/journal/SKILL.md), [CORTEX.md](CORTEX.md ### Global Variables -Defined in `solstone/convey/templates/app.html`: +Set up by the shell runtime (`solstone/convey/static/app.js`): - `window.facetsData` - Array of facet objects `[{name, title, color, emoji}, ...]` - `window.selectedFacet` - Current facet name or null (see Facet Selection below) - `window.appFacetCounts` - Badge counts for current app `{"work": 5, "personal": 3}` (set via route's `facet_counts`) @@ -766,12 +765,10 @@ See `solstone/apps/entities/routes.py` POST handlers - Shows request parsing, va See `solstone/apps/entities/routes.py` - Loads data per-facet when selected, or all facets when null. ### Facet Pill Badges -Pass `facet_counts` dict to `render_template()` to show initial badge counts on facet pills: -```python -facet_counts = {"work": 5, "personal": 3} -return render_template("app.html", facet_counts=facet_counts) +Use the shell runtime to show or update facet pill counts: +```javascript +AppServices.badges.facet.set(facetName, count); ``` -For client-side updates, use `AppServices.badges.facet.set(facetName, count)`. Apps with per-facet counts should compute them from already-loaded data before rendering, or update them client-side as data changes. @@ -836,7 +833,7 @@ Browse `solstone/apps/*/` directories for reference implementations. Apps range - **`solstone/apps/__init__.py`** - App discovery and registry implementation - **`solstone/convey/apps.py`** - Context processors and vendor library helper -- **`solstone/convey/templates/app.html`** - Main app container template +- **`solstone/convey/static/shell.html`** - Static SPA shell served for every app - **`solstone/convey/static/app.js`** - AppServices framework - **`solstone/convey/static/websocket.js`** - WebSocket event system - [../AGENTS.md](../AGENTS.md) - Project development guidelines and standards diff --git a/docs/CONVEY-FRONTEND.md b/docs/CONVEY-FRONTEND.md index ae9b6ec83..26f2e15e9 100644 --- a/docs/CONVEY-FRONTEND.md +++ b/docs/CONVEY-FRONTEND.md @@ -11,11 +11,9 @@ server. ## Architecture: static shell + per-app workspaces -- **One static shell** (`convey/static/shell.html`) is served for every - `/app/{name}` route. The client derives the current app from - `location.pathname` and boots from `GET /api/shell`. During the transitional - conversion, apps opt into this path with `"spa": true` in `app.json`; - unflagged apps continue through the legacy Jinja shell. +- **One static shell** (`convey/static/shell.html`) is served unconditionally for + every `/app/{name}` route. The client derives the current app from + `location.pathname` and boots from `GET /api/shell`. - **Per-app workspace fragments** stay one file per app (`apps/{name}/workspace.html`): markup + ` - {% endif %} - {% endif %} - -{% set body_classes = [] %} -{% if app_registry.apps[app].app_bar %}{% set _ = body_classes.append('has-app-bar') %}{% endif %} -{% if app_registry.apps[app].date_nav_enabled() and day %}{% set _ = body_classes.append('has-date-nav') %}{% endif %} - - - - - - - - -{% include "menu_bar.html" %} - - - - - -{% if app_registry.apps[app].date_nav_enabled() and day %} - {% include "date_nav.html" %} -{% endif %} - - -{% include "status_pane.html" %} -{% include "diagnostic_console.html" %} - - -
- - - - -{% if app_registry.apps[app].app_bar %} - {% include "chat_bar.html" %} -{% endif %} - - -
- {% block workspace_content %} -

{{ app_registry.apps[app].label }}

- {% include app_registry.apps[app].get_workspace_template() %} - {% endblock %} -
- - - - -{% for app_name, app_instance in app_registry.apps.items() %} - {% set background_tpl = app_instance.get_background_template() %} - {% if background_tpl %} - - - {% endif %} -{% endfor %} - - - - - - diff --git a/solstone/convey/templates/chat_bar.html b/solstone/convey/templates/chat_bar.html deleted file mode 100644 index 2ba95e545..000000000 --- a/solstone/convey/templates/chat_bar.html +++ /dev/null @@ -1,61 +0,0 @@ -
- - - - -
- - - -
-
-
- - -
- -
- diff --git a/solstone/convey/templates/date_nav.html b/solstone/convey/templates/date_nav.html deleted file mode 100644 index de0b59cb9..000000000 --- a/solstone/convey/templates/date_nav.html +++ /dev/null @@ -1,127 +0,0 @@ -{# Date Nav - renders below facet bar when app has date_nav enabled #} -{# Both day and app are auto-extracted from URL by context processor #} -{% if day %} -
-
- -
- -
- - -
-
-
- - - -{% endif %} diff --git a/solstone/convey/templates/diagnostic_console.html b/solstone/convey/templates/diagnostic_console.html deleted file mode 100644 index 65276a101..000000000 --- a/solstone/convey/templates/diagnostic_console.html +++ /dev/null @@ -1,24 +0,0 @@ - diff --git a/solstone/convey/templates/menu_bar.html b/solstone/convey/templates/menu_bar.html deleted file mode 100644 index b9114e622..000000000 --- a/solstone/convey/templates/menu_bar.html +++ /dev/null @@ -1,26 +0,0 @@ - - diff --git a/solstone/convey/templates/status_pane.html b/solstone/convey/templates/status_pane.html deleted file mode 100644 index c7e92b479..000000000 --- a/solstone/convey/templates/status_pane.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - diff --git a/solstone/convey/tests/test_static_cache.py b/solstone/convey/tests/test_static_cache.py index 38f483342..c06b7667b 100644 --- a/solstone/convey/tests/test_static_cache.py +++ b/solstone/convey/tests/test_static_cache.py @@ -1,9 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-only # Copyright (c) 2026 sol pbc -import re from datetime import timedelta -from pathlib import Path def test_send_file_max_age_default_configured(convey_env): @@ -20,13 +18,3 @@ def test_static_asset_carries_max_age_and_etag(convey_env): assert resp.status_code == 200 assert "max-age=300" in resp.headers["Cache-Control"] assert resp.headers.get("ETag") - - -def test_head_scripts_all_deferred(): - app_html = Path(__file__).resolve().parents[1] / "templates" / "app.html" - text = app_html.read_text(encoding="utf-8") - - script_tags = re.findall(r"