| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- using Spry;
- using Inversion;
- /**
- * ComponentsOverviewPage - Introduction to Spry Components
- *
- * This page provides a comprehensive overview of what Spry components are,
- * their lifecycle, key methods, and basic usage patterns.
- */
- public class ComponentsOverviewPage : PageComponent {
-
- public const string ROUTE = "/components/overview";
-
- private ComponentFactory factory = inject<ComponentFactory>();
-
- public override string markup { get {
- return """
- <div sid="page" class="doc-content">
- <h1>Components Overview</h1>
-
- <section class="doc-section">
- <h2>What are Spry Components?</h2>
- <p>
- Spry components are the building blocks of your web application. They combine
- HTML templates with behavior logic in a single, cohesive Vala class. Each component
- is self-contained with its own markup, state management, and action handling.
- </p>
- <p>
- Unlike traditional web frameworks where templates and logic are separated,
- Spry components embrace a component-based architecture where everything related
- to a UI element lives in one place.
- </p>
- </section>
-
- <section class="doc-section">
- <h2>Component Lifecycle</h2>
- <p>
- Understanding the component lifecycle is crucial for building effective Spry applications.
- The template DOM is <strong>fresh on every request</strong>, meaning state is not
- persisted between requests.
- </p>
-
- <div class="lifecycle-diagram">
- <div class="lifecycle-step">
- <div class="step-number">1</div>
- <div class="step-content">
- <h4>Component Creation</h4>
- <p>Component is instantiated via ComponentFactory</p>
- </div>
- </div>
- <div class="lifecycle-arrow">↓</div>
- <div class="lifecycle-step">
- <div class="step-number">2</div>
- <div class="step-content">
- <h4>prepare_once()</h4>
- <p>One-time initialization (called only before first prepare)</p>
- </div>
- </div>
- <div class="lifecycle-arrow">↓</div>
- <div class="lifecycle-step">
- <div class="step-number">3</div>
- <div class="step-content">
- <h4>prepare()</h4>
- <p>Fetch data from stores, populate template elements</p>
- </div>
- </div>
- <div class="lifecycle-arrow">↓</div>
- <div class="lifecycle-step">
- <div class="step-number">4</div>
- <div class="step-content">
- <h4>handle_action()</h4>
- <p>Handle user interactions (if action triggered)</p>
- </div>
- </div>
- <div class="lifecycle-arrow">↓</div>
- <div class="lifecycle-step">
- <div class="step-number">5</div>
- <div class="step-content">
- <h4>Serialization</h4>
- <p>Template is rendered to HTML and sent to client</p>
- </div>
- </div>
- </div>
- </section>
-
- <section class="doc-section">
- <h2>Key Methods</h2>
- <p>
- Every component inherits from the base <code>Component</code> class and can
- override these key methods:
- </p>
-
- <table class="doc-table">
- <thead>
- <tr>
- <th>Method</th>
- <th>Description</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><code>markup</code></td>
- <td>Property returning the HTML template string with Spry attributes</td>
- </tr>
- <tr>
- <td><code>prepare()</code></td>
- <td>Called before serialization. Fetch data and populate template here.</td>
- </tr>
- <tr>
- <td><code>prepare_once()</code></td>
- <td>Called only once before the first prepare(). For one-time initialization.</td>
- </tr>
- <tr>
- <td><code>handle_action()</code></td>
- <td>Called when HTMX triggers an action. Modify state here.</td>
- </tr>
- <tr>
- <td><code>continuation()</code></td>
- <td>For real-time updates via Server-Sent Events (SSE).</td>
- </tr>
- </tbody>
- </table>
- </section>
-
- <section class="doc-section">
- <h2>Basic Component Example</h2>
- <p>
- Here's a simple counter component demonstrating the core concepts:
- </p>
-
- <spry-component name="CodeBlockComponent" sid="example-code"/>
- </section>
-
- <section class="doc-section">
- <h2>Important: Template State is Not Persisted</h2>
- <div class="warning-box">
- <p>
- <strong>⚠️ Critical Concept:</strong> The template DOM is fresh on every request.
- Any state set via setters (like <code>title</code>, <code>completed</code>) is
- NOT available in <code>handle_action()</code>.
- </p>
- <p>
- Always use <code>prepare()</code> to fetch data from stores and set up the template.
- Use <code>hx-vals</code> to pass data between requests.
- </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 Spry's special HTML attributes</p>
- </a>
- <a href="/components/actions" class="nav-card">
- <h3>Actions →</h3>
- <p>Handle user interactions with actions</p>
- </a>
- <a href="/components/outlets" class="nav-card">
- <h3>Outlets →</h3>
- <p>Compose components with outlets</p>
- </a>
- </div>
- </section>
- </div>
- """;
- }}
-
- public override async void prepare() throws Error {
- var code = get_component_child<CodeBlockComponent>("example-code");
- code.language = "Vala";
- code.code = "using Spry;\n\n" +
- "public class CounterComponent : Component {\n" +
- " private CounterStore store = inject<CounterStore>();\n\n" +
- " public override string markup { get {\n" +
- " return \"\"\"\n" +
- " <div sid=\"counter\" class=\"counter\">\n" +
- " <span sid=\"count\"></span>\n" +
- " <button sid=\"inc\" spry-action=\":Increment\"\n" +
- " spry-target=\"counter\">+</button>\n" +
- " <button sid=\"dec\" spry-action=\":Decrement\"\n" +
- " spry-target=\"counter\">-</button>\n" +
- " </div>\n" +
- " \"\"\";\n" +
- " }}\n\n" +
- " public override void prepare() throws Error {\n" +
- " this[\"count\"].text_content = store.count.to_string();\n" +
- " }\n\n" +
- " public async override void handle_action(string action) throws Error {\n" +
- " switch (action) {\n" +
- " case \"Increment\":\n" +
- " store.count++;\n" +
- " break;\n" +
- " case \"Decrement\":\n" +
- " store.count--;\n" +
- " break;\n" +
- " }\n" +
- " // prepare() is called automatically after handle_action()\n" +
- " }\n" +
- "}";
- }
- }
|