| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- using Spry;
- using Astralis;
- using Inversion;
- using Invercargill.DataStructures;
- /**
- * TodoListDemo - A todo list demo for the Outlets documentation
- *
- * Demonstrates:
- * - Using spry-outlet for dynamic child components
- * - set_outlet_children() to populate outlets
- * - Parent/child component composition
- */
- public class TodoListDemo : Component {
-
- private TodoDemoStore store = inject<TodoDemoStore>();
- private ComponentFactory factory = inject<ComponentFactory>();
- private HttpContext http_context = inject<HttpContext>();
-
- public override string markup { get {
- return """
- <div sid="todo-list" class="demo-todo-list">
- <div class="todo-header">
- <h3>Todo List</h3>
- <span class="todo-count" sid="count"></span>
- </div>
- <form class="todo-form" spry-action=":Add" spry-target="todo-list">
- <input type="text" name="title" placeholder="Add a task..." sid="input"/>
- <button type="submit" class="todo-add-btn">Add</button>
- </form>
- <ul class="todo-items" sid="items">
- <spry-outlet sid="items-outlet"/>
- </ul>
- </div>
- """;
- }}
-
- public override async void prepare() throws Error {
- // Update count
- this["count"].text_content = @"$(store.items.length) items";
-
- // Build list items
- var children = new Series<Renderable>();
- foreach (var item in store.items) {
- var component = factory.create<TodoItemDemo>();
- component.item_id = item.id;
- children.add(component);
- }
- set_outlet_children("items-outlet", children);
- }
-
- public async override void handle_action(string action) throws Error {
- if (action == "Add") {
- var title = http_context.request.query_params.get_any_or_default("title");
- if (title != null && title.strip().length > 0) {
- store.add(title.strip());
- }
- }
- }
- }
- /**
- * TodoItemDemo - Individual todo item component
- */
- public class TodoItemDemo : Component {
-
- private TodoDemoStore store = inject<TodoDemoStore>();
- private HttpContext http_context = inject<HttpContext>();
-
- public int item_id { set; get; }
-
- public override string markup { get {
- return """
- <li sid="item" class="todo-item">
- <span sid="title" class="todo-title"></span>
- <button sid="toggle" spry-action=":Toggle" spry-target="item"
- class="todo-toggle"></button>
- <button sid="delete" spry-action=":Delete" spry-target="item"
- hx-swap="delete" class="todo-delete">×</button>
- </li>
- """;
- }}
-
- public override async void prepare() throws Error {
- var item = store.get_by_id(item_id);
- if (item == null) return;
-
- this["title"].text_content = item.title;
- this["item"].set_attribute("hx-vals", @"{\"id\":$item_id}");
-
- if (item.completed) {
- this["item"].add_class("completed");
- this["toggle"].text_content = "↩";
- } else {
- this["toggle"].text_content = "✓";
- }
- }
-
- public async override void handle_action(string action) throws Error {
- var id_str = http_context.request.query_params.get_any_or_default("id");
- var id = int.parse(id_str);
-
- switch (action) {
- case "Toggle":
- store.toggle(id);
- break;
- case "Delete":
- store.remove(id);
- break;
- }
- }
- }
- /**
- * TodoDemoStore - Singleton store for todo items
- */
- public class TodoDemoStore : Object {
-
- public Series<TodoDemoItem> items { get; set; default = new Series<TodoDemoItem>(); }
- private int _next_id = 1;
-
- public TodoDemoStore() {
- // Add some initial items
- add("Learn Spry components");
- add("Build a web app");
- add("Deploy to production");
- }
-
- public void add(string title) {
- items.add(new TodoDemoItem(_next_id++, title));
- }
-
- public TodoDemoItem? get_by_id(int id) {
- foreach (var item in items) {
- if (item.id == id) return item;
- }
- return null;
- }
-
- public void toggle(int id) {
- var item = get_by_id(id);
- if (item != null) {
- item.completed = !item.completed;
- }
- }
-
- public void remove(int id) {
- // Build a new list without the item
- var new_items = new Series<TodoDemoItem>();
- foreach (var item in items) {
- if (item.id != id) {
- new_items.add(item);
- }
- }
- items = new_items;
- }
- }
- /**
- * TodoDemoItem - Single todo item data
- */
- public class TodoDemoItem : Object {
- public int id { get; construct; }
- public string title { get; construct set; }
- public bool completed { get; set; default = false; }
-
- public TodoDemoItem(int id, string title) {
- Object(id: id, title: title);
- }
- }
|