| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- using Spry;
- using Inversion;
- /**
- * ComponentsMkconstPage - Documentation for the spry-mkconst tool
- *
- * This page explains how to use spry-mkconst to convert HTML files
- * to Vala string constants that can be referenced in component markup properties.
- */
- public class ComponentsMkconstPage : PageComponent {
-
- public override string title { get { return "spry-mkconst Tool - Spry"; } }
-
- public const string ROUTE = "/components/spry-mkconst";
-
- private ComponentFactory factory = inject<ComponentFactory>();
-
- public override string markup { get {
- return """
- <div sid="page" class="doc-content">
- <h1>spry-mkconst Tool</h1>
-
- <section class="doc-section">
- <h2>What is spry-mkconst?</h2>
- <p>
- <code>spry-mkconst</code> is a command-line tool that converts file contents
- (typically HTML templates) into Vala string constants. This allows you to:
- </p>
- <ul>
- <li>Keep HTML templates in separate files for easier editing</li>
- <li>Maintain valid Vala syntax that the Vala language server can recognize</li>
- <li>Reference generated constants from your component's <code>markup</code> property</li>
- </ul>
- <p>
- Unlike the previous <code>spry-mkcomponent</code> approach which modified Vala files,
- <code>spry-mkconst</code> generates separate constant declarations, keeping your
- original Vala files intact and recognizable by IDEs and language servers.
- </p>
- </section>
-
- <section class="doc-section">
- <h2>Command-Line Usage</h2>
-
- <spry-component name="CodeBlockComponent" sid="usage-code"/>
-
- <h3>Options</h3>
- <table class="doc-table">
- <thead>
- <tr>
- <th>Option</th>
- <th>Description</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>-o, --output FILE</code></td>
- <td>Output file path (default: stdout)</td>
- </tr>
- <tr>
- <td><code>--ns NAMESPACE</code></td>
- <td>Wrap const in a namespace</td>
- </tr>
- <tr>
- <td><code>-n, --name NAME</code></td>
- <td>Override const name (default: derived from filename)</td>
- </tr>
- <tr>
- <td><code>-v, --version</code></td>
- <td>Show version information</td>
- </tr>
- <tr>
- <td><code>--help</code></td>
- <td>Show help message</td>
- </tr>
- </tbody>
- </table>
- </section>
-
- <section class="doc-section">
- <h2>How It Works</h2>
- <p>
- The tool takes a single input file and generates a Vala const declaration:
- </p>
-
- <spry-component name="CodeBlockComponent" sid="workflow-diagram"/>
-
- <div class="info-box">
- <p>
- <strong>💡 Key Concept:</strong> The const name is automatically derived from the
- filename using CAPITAL_SNAKE_CASE. For example, <code>UserContentComponent.vala.html</code>
- becomes <code>USER_CONTENT_COMPONENT_VALA_HTML</code>.
- </p>
- </div>
- </section>
-
- <section class="doc-section">
- <h2>Example Transformation</h2>
- <p>
- Here's a complete example showing how the tool works:
- </p>
-
- <h3>Input HTML File (<code>UserContentComponent.vala.html</code>)</h3>
- <spry-component name="CodeBlockComponent" sid="input-html"/>
-
- <h3>Generated Output (stdout or file)</h3>
- <spry-component name="CodeBlockComponent" sid="output-const"/>
-
- <h3>Your Vala Component (unchanged, valid Vala)</h3>
- <spry-component name="CodeBlockComponent" sid="vala-component"/>
-
- <p>
- The key advantage is that your Vala file remains valid, parseable Vala code.
- The Vala language server can still recognize it, provide autocomplete, and
- show errors. The generated constant is referenced via <code>return USER_CONTENT_COMPONENT_VALA_HTML;</code>
- </p>
- </section>
-
- <section class="doc-section">
- <h2>Integrating with Meson</h2>
- <p>
- The recommended way to use spry-mkconst is with meson's build system.
- You generate a separate Vala file containing the const declarations,
- then include it in your build.
- </p>
-
- <h3>Basic meson.build Setup</h3>
- <spry-component name="CodeBlockComponent" sid="meson-basic"/>
-
- <h3>With Namespace</h3>
- <spry-component name="CodeBlockComponent" sid="meson-namespace"/>
-
- <h3>Complete Example</h3>
- <spry-component name="CodeBlockComponent" sid="meson-complete"/>
-
- <div class="info-box">
- <p>
- <strong>💡 Tip:</strong> The generated file should be included in your
- executable's sources. Meson will run spry-mkconst automatically before
- compilation.
- </p>
- </div>
- </section>
-
- <section class="doc-section">
- <h2>HTML Template Guidelines</h2>
- <p>
- When creating HTML templates for use with spry-mkconst, follow these guidelines:
- </p>
-
- <ul>
- <li>
- <strong>Use <code>sid</code> attributes</strong> - Add <code>sid="name"</code>
- to elements you need to access from Vala code via <code>this["name"]</code>
- </li>
- <li>
- <strong>Name templates consistently</strong> - Use <code>ComponentName.vala.html</code>
- for clear association with the component
- </li>
- <li>
- <strong>Use HTMX attributes</strong> - Add <code>hx-*</code> attributes for
- interactivity without writing JavaScript
- </li>
- <li>
- <strong>Avoid complex logic</strong> - Keep templates focused on structure;
- use Vala for conditional rendering
- </li>
- </ul>
-
- <spry-component name="CodeBlockComponent" sid="html-guidelines"/>
- </section>
-
- <section class="doc-section">
- <h2>Why spry-mkconst vs spry-mkcomponent?</h2>
- <p>
- The previous <code>spry-mkcomponent</code> tool modified Vala source files by
- injecting HTML into the markup getter. This had a significant drawback:
- the Vala language server couldn't recognize the modified files as valid Vala
- during development.
- </p>
-
- <p>
- <code>spry-mkconst</code> solves this by:
- </p>
-
- <ul>
- <li>Keeping your Vala files as valid, parseable Vala code</li>
- <li>Generating constants in a separate file that's included at build time</li>
- <li>Allowing the language server to provide full IDE support</li>
- <li>Using <code>public override string markup { get { return CONSTANT_NAME; } }</code>
- which is valid Vala syntax</li>
- </ul>
- </section>
-
- <section class="doc-section">
- <h2>Workflow Integration</h2>
- <p>
- A typical development workflow with spry-mkconst looks like this:
- </p>
-
- <ol>
- <li><strong>Create</strong> your HTML template file (e.g., <code>MyComponent.vala.html</code>)</li>
- <li><strong>Write</strong> your Vala component referencing the generated constant name</li>
- <li><strong>Configure</strong> meson to generate the const file</li>
- <li><strong>Build</strong> your project - meson runs spry-mkconst automatically</li>
- <li><strong>Iterate</strong> - Edit the HTML file; changes are picked up on rebuild</li>
- </ol>
-
- <p>
- During development, you can run the tool manually to see the generated output:
- </p>
-
- <spry-component name="CodeBlockComponent" sid="manual-run"/>
- </section>
-
- <section class="doc-section">
- <h2>When to Use spry-mkconst</h2>
-
- <h3>✅ Good Use Cases</h3>
- <ul>
- <li>Components with substantial HTML markup</li>
- <li>When you need Vala language server support (autocomplete, errors)</li>
- <li>Teams where designers work on HTML separately from developers</li>
- <li>Keeping Vala files focused on logic</li>
- </ul>
-
- <h3>❌ When to Skip It</h3>
- <ul>
- <li>Simple components with minimal markup (inline is fine)</li>
- <li>Quick prototypes where separation isn't beneficial</li>
- <li>Components with dynamically generated markup</li>
- </ul>
-
- <div class="info-box">
- <p>
- <strong>💡 Remember:</strong> You can always inline markup directly in your
- Vala files using triple-quoted strings. spry-mkconst is opt-in - use it
- when the separation provides value for your project.
- </p>
- </div>
- </section>
-
- <section class="doc-section">
- <h2>Next Steps</h2>
- <div class="nav-cards">
- <a href="/components/template-syntax" class="nav-card">
- <h3>← Template Syntax</h3>
- <p>Learn about component template syntax</p>
- </a>
- <a href="/components/actions" class="nav-card">
- <h3>Actions →</h3>
- <p>Handle user interactions in components</p>
- </a>
- </div>
- </section>
- </div>
- """;
- }}
-
- public override async void prepare() throws Error {
- var usage_code = get_component_child<CodeBlockComponent>("usage-code");
- usage_code.language = "Bash";
- usage_code.code = "spry-mkconst [OPTIONS] <INPUT_FILE>\n\n" +
- "# Examples:\n" +
- "spry-mkconst Templates/UserContent.html\n" +
- "spry-mkconst -o generated/constants.vala Templates/UserContent.html\n" +
- "spry-mkconst --ns MyApp.Templates Templates/UserContent.html\n" +
- "spry-mkconst -n CUSTOM_NAME Templates/UserContent.html";
-
- var workflow_diagram = get_component_child<CodeBlockComponent>("workflow-diagram");
- workflow_diagram.language = "Text";
- workflow_diagram.code = "┌─────────────────────────────────────┐\n" +
- "│ UserContentComponent.vala.html │\n" +
- "│ (HTML template) │\n" +
- "└─────────────┬───────────────────────┘\n" +
- " │\n" +
- " ▼\n" +
- " ┌───────────────┐\n" +
- " │ spry-mkconst │\n" +
- " └───────┬───────┘\n" +
- " │\n" +
- " ▼\n" +
- "┌─────────────────────────────────────────────────┐\n" +
- "│ const string USER_CONTENT_COMPONENT_VALA_HTML │\n" +
- "│ = \"\"\"<html>...</html>\"\"\"; │\n" +
- "└─────────────────────────────────────────────────┘";
-
- var input_html = get_component_child<CodeBlockComponent>("input-html");
- input_html.language = "HTML";
- input_html.code = "<p>You said: <strong sid=\"message\"></strong> <em>(via <span sid=\"action\"></span>)</em></p>";
-
- var output_const = get_component_child<CodeBlockComponent>("output-const");
- output_const.language = "Vala";
- output_const.code = "const string USER_CONTENT_COMPONENT_VALA_HTML = \"\"\"\n" +
- "<p>You said: <strong sid=\"message\"></strong> <em>(via <span sid=\"action\"></span>)</em></p>\n" +
- "\"\"\";";
-
- var vala_component = get_component_child<CodeBlockComponent>("vala-component");
- vala_component.language = "Vala";
- vala_component.code = "// This file is valid Vala - the language server recognizes it!\n" +
- "class UserContentComponent : Component {\n" +
- " public override string markup { get { return USER_CONTENT_COMPONENT_VALA_HTML; } }\n\n" +
- " public async override void handle_action(string action) throws Error {\n" +
- " this[\"message\"].text_content = \"Hello, World!\";\n" +
- " }\n" +
- "}";
-
- var meson_basic = get_component_child<CodeBlockComponent>("meson-basic");
- meson_basic.language = "Meson";
- meson_basic.code = "# Find the tool\n" +
- "spry_mkconst = find_program('spry-mkconst')\n\n" +
- "# Generate constants from HTML templates\n" +
- "markup_constants = custom_target('markup-constants',\n" +
- " input: 'Templates/UserContentComponent.vala.html',\n" +
- " output: 'UserContentConstants.vala',\n" +
- " command: [spry_mkconst, '@INPUT@', '-o', '@OUTPUT@']\n" +
- ")\n\n" +
- "# Include in your executable\n" +
- "executable('myapp',\n" +
- " sources: ['Main.vala', 'UserContentComponent.vala', markup_constants],\n" +
- " dependencies: [spry_dep]\n" +
- ")";
-
- var meson_namespace = get_component_child<CodeBlockComponent>("meson-namespace");
- meson_namespace.language = "Meson";
- meson_namespace.code = "# Generate constants with namespace\n" +
- "spry_mkconst = find_program('spry-mkconst')\n\n" +
- "markup_constants = custom_target('markup-constants',\n" +
- " input: 'Templates/UserContentComponent.vala.html',\n" +
- " output: 'UserContentConstants.vala',\n" +
- " command: [spry_mkconst, '@INPUT@', '-o', '@OUTPUT@',\n" +
- " '--ns', 'MyApp.Markup']\n" +
- ")\n\n" +
- "# In your Vala file, use:\n" +
- "# public override string markup { get { return MyApp.Markup.USER_CONTENT_COMPONENT_VALA_HTML; } }";
-
- var meson_complete = get_component_child<CodeBlockComponent>("meson-complete");
- meson_complete.language = "Meson";
- meson_complete.code = "# Find the spry-mkconst tool\n" +
- "spry_mkconst = find_program('spry-mkconst')\n\n" +
- "# Collect all HTML template files\n" +
- "template_files = files(\n" +
- " 'Templates/HeaderComponent.vala.html',\n" +
- " 'Templates/FooterComponent.vala.html',\n" +
- " 'Templates/UserContentComponent.vala.html',\n" +
- ")\n\n" +
- "# Generate a single constants file from all templates\n" +
- "# Note: You can also generate separate files per template\n" +
- "markup_constants = custom_target('markup-constants',\n" +
- " input: template_files,\n" +
- " output: 'MarkupConstants.vala',\n" +
- " command: [spry_mkconst, '@INPUT@', '-o', '@OUTPUT@', '--ns', 'Markup']\n" +
- ")\n\n" +
- "# Component source files (reference the constants)\n" +
- "component_sources = files(\n" +
- " 'Components/HeaderComponent.vala',\n" +
- " 'Components/FooterComponent.vala',\n" +
- " 'Components/UserContentComponent.vala',\n" +
- ")\n\n" +
- "# Build executable\n" +
- "executable('myapp',\n" +
- " sources: ['Main.vala', component_sources, markup_constants],\n" +
- " dependencies: [spry_dep],\n" +
- ")";
-
- var html_guidelines = get_component_child<CodeBlockComponent>("html-guidelines");
- html_guidelines.language = "HTML";
- html_guidelines.code = "<!-- Good: Use sid attributes for elements you need to access -->\n" +
- "<div class=\"user-card\">\n" +
- " <h2 sid=\"username\"></h2>\n" +
- " <p sid=\"email\"></p>\n" +
- " <button sid=\"delete-btn\" hx-post=\"/delete\" hx-target=\"closest .user-card\">\n" +
- " Delete\n" +
- " </button>\n" +
- "</div>\n\n" +
- "<!-- Good: Keep it simple and focused on structure -->\n" +
- "<form sid=\"login-form\" hx-post=\"/login\">\n" +
- " <input type=\"text\" name=\"username\" sid=\"username-input\"/>\n" +
- " <input type=\"password\" name=\"password\" sid=\"password-input\"/>\n" +
- " <button type=\"submit\">Login</button>\n" +
- "</form>";
-
- var manual_run = get_component_child<CodeBlockComponent>("manual-run");
- manual_run.language = "Bash";
- manual_run.code = "# Run manually to see generated output\n" +
- "spry-mkconst Templates/MyComponent.vala.html\n\n" +
- "# Save to a file\n" +
- "spry-mkconst Templates/MyComponent.vala.html -o generated/MyComponentMarkup.vala\n\n" +
- "# View the result\n" +
- "cat generated/MyComponentMarkup.vala\n\n" +
- "# Generate with namespace\n" +
- "spry-mkconst Templates/MyComponent.vala.html --ns MyApp.Templates";
- }
- }
|