diff --git a/docs/conf.py b/docs/conf.py index 22728e3..2af7207 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,6 +15,7 @@ "sphinx.ext.viewcode", "sphinx.ext.intersphinx", "sphinx_copybutton", + "myst_parser", ] templates_path = ["_templates"] @@ -41,3 +42,12 @@ copybutton_prompt_text = r">>> |\.\.\. |\$ " copybutton_prompt_is_regexp = True + +myst_enable_extensions = [ + "colon_fence", + "deflist", + "fieldlist", + "substitution", + "tasklist", +] +myst_heading_anchors = 3 diff --git a/docs/how_it_works.md b/docs/how_it_works.md new file mode 100644 index 0000000..09c0f66 --- /dev/null +++ b/docs/how_it_works.md @@ -0,0 +1,101 @@ +# How It Works + +## Current + +The default mode is the current, modern `httk-web` workflow. + +### Directory layout + +A site source directory is expected to contain: + +- `content/`: page sources (`.md`, `.rst`, `.html`) +- `templates/`: Jinja2 templates (for example `default.html.j2` and `base_default.html.j2`) +- `static/`: static files copied as-is in publish mode +- `functions/`: optional Python modules exposing `execute(...)` + +### Runtime flow + +1. Route resolution maps a URL path to a content page or static file. +2. Content rendering extracts metadata and body HTML. +3. Function injection evaluates `*-function` metadata entries when query/post constraints are satisfied. +4. Template rendering produces final HTML through Jinja2. +5. ASGI serving returns responses, or static publishing writes `.html` output files. + +### Public API + +The main API surface is: + +- `httk.web.create_asgi_app(...)` +- `httk.web.serve(...)` +- `httk.web.publish(...)` + +### Example usage + +Serve dynamically: + +```python +from httk.web import serve +serve("src", port=8080) +``` + +Publish statically: + +```python +from httk.web import publish +publish("src", "public", "http://127.0.0.1/") +``` + +To control link style in published output: + +```python +publish("src", "public", "http://127.0.0.1/", use_urls_without_ext=False) # -> about.html +publish("src", "public", "http://127.0.0.1/", use_urls_without_ext=True) # -> about +``` + +### Examples + +Modern examples live under `examples/modern`: + +- `minimal` +- `rst_site` +- `blog` +- `search_app` + +For a ready-made starter repository, see {doc}`site_template_repository`. + +## Legacy + +`httk-web` also supports a compatibility mode for legacy site structures and templates. + +### Enable compatibility mode + +Use `compatibility_mode=True` in API calls: + +```python +from httk.web import serve +serve("src", compatibility_mode=True) +``` + +### Compatibility behaviors + +When compatibility mode is enabled, `httk-web` additionally supports: + +- `.httkweb` content and `.httkweb.html` template resolution +- legacy formatter constructs used by old templates (for example repeat/call/if forms) +- loading global metadata from `config.*` (or another name via `config_name`) +- running `functions/init.py` at engine startup +- `_functions/` directory fallback when `functions/` is not present + +### Examples + +Migrated legacy examples are available under `examples/legacy`: + +- `static_simple` +- `hello_world_app` +- `rst_templator` +- `blog` +- `search_app` + +For legacy examples that use optional old `httk` subsystems, availability depends on those dependencies. + +See also: {doc}`migration_legacy_to_jinja2`. diff --git a/docs/how_it_works.rst b/docs/how_it_works.rst deleted file mode 100644 index a9cc2b4..0000000 --- a/docs/how_it_works.rst +++ /dev/null @@ -1,101 +0,0 @@ -How It Works -============ - -Current -------- - -The default mode is the current, modern ``httk-web`` workflow. - -Directory layout -^^^^^^^^^^^^^^^^ - -A site source directory is expected to contain: - -- ``content/``: page sources (``.md``, ``.rst``, ``.html``) -- ``templates/``: Jinja2 templates (for example ``default.html.j2`` and ``base_default.html.j2``) -- ``static/``: static files copied as-is in publish mode -- ``functions/``: optional Python modules exposing ``execute(...)`` - -Runtime flow -^^^^^^^^^^^^ - -1. Route resolution maps a URL path to a content page or static file. -2. Content rendering extracts metadata and body HTML. -3. Function injection evaluates ``*-function`` metadata entries when query/post constraints are satisfied. -4. Template rendering produces final HTML through Jinja2. -5. ASGI serving returns responses, or static publishing writes ``.html`` output files. - -Public API -^^^^^^^^^^ - -The main API surface is: - -- ``httk.web.create_asgi_app(...)`` -- ``httk.web.serve(...)`` -- ``httk.web.publish(...)`` - -Example usage -^^^^^^^^^^^^^ - -Serve dynamically: - -.. code-block:: python - - from httk.web import serve - serve("src", port=8080) - -Publish statically: - -.. code-block:: python - - from httk.web import publish - publish("src", "public", "http://127.0.0.1/") - -Examples -^^^^^^^^ - -Modern examples live under ``examples/modern``: - -- ``minimal`` -- ``rst_site`` -- ``blog`` -- ``search_app`` - -Legacy ------- - -``httk-web`` also supports a compatibility mode for legacy site structures and templates. - -Enable compatibility mode -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Use ``compatibility_mode=True`` in API calls: - -.. code-block:: python - - from httk.web import serve - serve("src", compatibility_mode=True) - -Compatibility behaviors -^^^^^^^^^^^^^^^^^^^^^^^ - -When compatibility mode is enabled, ``httk-web`` additionally supports: - -- ``.httkweb`` content and ``.httkweb.html`` template resolution -- legacy formatter constructs used by old templates (for example repeat/call/if forms) -- loading global metadata from ``config.*`` (or another name via ``config_name``) -- running ``functions/init.py`` at engine startup -- ``_functions/`` directory fallback when ``functions/`` is not present - -Examples -^^^^^^^^ - -Migrated legacy examples are available under ``examples/legacy``: - -- ``static_simple`` -- ``hello_world_app`` -- ``rst_templator`` -- ``blog`` -- ``search_app`` - -For legacy examples that use optional old ``httk`` subsystems, availability depends on those dependencies. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..a6e2d13 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,22 @@ +# *httk-web* + +*httk-web* is a [*httk v2*](https://github.com/httk/httk2) module providing web serving and static publishing functionality. + +```{admonition} Quick links +:class: tip + +- {doc}`how_it_works` +- {doc}`migration_legacy_to_jinja2` +- {doc}`site_template_repository` +- {doc}`reference` +``` + +```{toctree} +:maxdepth: 2 +:caption: Documentation + +how_it_works +migration_legacy_to_jinja2 +site_template_repository +reference +``` diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index d95dd69..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,17 +0,0 @@ -httk-web -======== - -*httk-web* is a [*httk v2*](https://github.com/httk/httk2) module providing web serving and static publishing functionality. - -Quick links ------------ - -- :doc:`how_it_works` -- :doc:`reference` - -.. toctree:: - :maxdepth: 2 - :caption: Documentation - - how_it_works - reference diff --git a/docs/migration_legacy_to_jinja2.md b/docs/migration_legacy_to_jinja2.md new file mode 100644 index 0000000..bfdefbe --- /dev/null +++ b/docs/migration_legacy_to_jinja2.md @@ -0,0 +1,172 @@ +# Migration: Legacy Templates to Jinja2 + +This guide maps common legacy template patterns to their modern Jinja2 equivalents. + +## Overview + +Legacy projects typically use `.httkweb.html` templates with formatter-style constructs such as `{name:repeat::...}`, `{func:call:...}`, and conditional specifiers. Modern projects should use `.html.j2` (or `.jinja`/`.j2`) with standard Jinja2 syntax. + +## Template file naming + +### Legacy + +- `default.httkweb.html` +- `base_default.httkweb.html` +- function fragments like `search_result.httkweb.html` + +### Modern + +- `default.html.j2` +- `base_default.html.j2` +- function fragments like `search_result.html.j2` + +## Variable access + +Legacy: + +```text +{title} +{page.relurl} +``` + +Modern: + +```jinja +{{ title }} +{{ page.relurl }} +``` + +## Escaping behavior + +Legacy templates often rely on formatter-level quote/unquoted controls. +In Jinja2, use autoescaping defaults and explicit `|safe` only when needed. + +Legacy: + +```text +{content} +{content:unquoted} +``` + +Modern: + +```jinja +{{ content }} +{{ content|safe }} +``` + +## Loops + +Legacy `repeat`: + +```text +{menuitems:repeat:: +
  • {{item}}
  • +} +``` + +Modern Jinja2: + +```jinja +{% for item in menuitems %} +
  • {{ item }}
  • +{% endfor %} +``` + +## Conditionals + +Legacy conditionals are encoded in format specs (for example `if` / `if-not`). +Use Jinja2 control blocks directly. + +Legacy: + +```text +{error_404_reason:if::Reason: {error_404_reason}} +``` + +Modern: + +```jinja +{% if error_404_reason %} +Reason: {{ error_404_reason }} +{% endif %} +``` + +## Function-style calls + +Legacy `call` often appears around helper access: + +```text +{{pages:call:{{item}}:title}} +``` + +Modern: + +```jinja +{{ pages(item, 'title') }} +``` + +## Indexing and attribute access + +Legacy: + +```text +{{item[id]}} +{{item[formula]}} +``` + +Modern: + +```jinja +{{ item['id'] }} +{{ item['formula'] }} +``` + +## Function fragments (metadata) + +Legacy metadata often points to fragment names without modern suffixes. +Modern projects should use clear names and Jinja templates. + +Legacy metadata: + +```yaml +results-function: search:q:search_result +``` + +Modern metadata (same key format, modern template files): + +```yaml +results-function: search:q:search_result +``` + +and template file: + +```text +templates/search_result.html.j2 +``` + +## Metadata key casing and structure + +Prefer lowercase keys in modern projects: + +- `template` instead of `Template` +- `base_template` instead of `Base_template` +- `title` instead of `Title` + +Both styles may work in compatibility contexts, but lowercase metadata avoids surprises and keeps templates predictable. + +## Migration checklist + +1. Rename templates to `.html.j2`. +2. Replace legacy formatter expressions with Jinja2 syntax. +3. Keep helper usage explicit: `pages(...)`, `first_value(...)`, `listdir(...)`. +4. Normalize metadata keys to lowercase. +5. Run your site with `compatibility_mode=False` and verify output. + +## Tip + +If needed, migrate page-by-page: + +- Keep legacy project operational in compatibility mode. +- Port one template at a time to Jinja2. +- Switch the site to current mode once templates and metadata are fully modernized. diff --git a/docs/reference.rst b/docs/reference.md similarity index 53% rename from docs/reference.rst rename to docs/reference.md index aac4154..3c995da 100644 --- a/docs/reference.rst +++ b/docs/reference.md @@ -1,18 +1,22 @@ -Reference -========= +:orphan: +# Reference -Public API ----------- +This section documents the supported public API. +## Public API + +```{eval-rst} .. automodule:: httk.web.api :members: :undoc-members: :show-inheritance: +``` -Convenience Exports -------------------- +## Convenience Exports +```{eval-rst} .. automodule:: httk.web :members: :undoc-members: :show-inheritance: +``` diff --git a/docs/site_template_repository.md b/docs/site_template_repository.md new file mode 100644 index 0000000..dad98b8 --- /dev/null +++ b/docs/site_template_repository.md @@ -0,0 +1,47 @@ +# Site Template Repository + +A ready-to-use template repository for new `httk.web` sites is available at: + +- https://github.com/httk/example_website_httk + +## Create a new site on GitHub + +1. Open the template repository URL in your browser. +2. Click **Use this template** (top-right on GitHub). +3. Choose **Create a new repository**. +4. Set repository name/visibility and create it. + +## Clone and run locally + +After creating your repository, clone it and run: + +```bash +git clone https://github.com//.git +cd +python -m pip install -e . +make serve +``` + +## Edit site content + +The main content is under `src/content`: + +- Edit existing pages like `src/content/index.md` and `src/content/contact.md`. +- Add new pages by creating `.md` files in `src/content`. +- Blog posts are in `src/content/blogposts`. + +Then regenerate/publish: + +```bash +make generate +``` + +This writes output to `public/`. + +If you need `.html` links for a static host, pass `use_urls_without_ext=False` +to `httk.web.publish(...)` in your publish script. + +## GitHub Pages publishing + +The template repository includes a GitHub Actions workflow for Pages publishing. +After enabling GitHub Pages for the repository, pushes to `main` will build and publish the site automatically. diff --git a/examples/legacy/blog/src/content/index.md b/examples/legacy/blog/src/content/index.md index 702570e..ee48dd5 100644 --- a/examples/legacy/blog/src/content/index.md +++ b/examples/legacy/blog/src/content/index.md @@ -21,7 +21,7 @@ Subheading Here is some nice math: -\(\int (x+y) dx\) +$\int (x+y)\,dx$ And a code segment: diff --git a/examples/legacy/blog/src/templates/base_default.httkweb.html b/examples/legacy/blog/src/templates/base_default.httkweb.html index a8f839b..d347bc0 100644 --- a/examples/legacy/blog/src/templates/base_default.httkweb.html +++ b/examples/legacy/blog/src/templates/base_default.httkweb.html @@ -31,9 +31,19 @@ + " in rendered + + def test_create_asgi_app_compatibility_mode_prefers_httkweb_templates(tmp_path: Path) -> None: src = tmp_path / "src" (src / "content").mkdir(parents=True)