diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js
new file mode 100644
index 00000000000..70b1749aab5
--- /dev/null
+++ b/awesome_owl/static/src/card/card.js
@@ -0,0 +1,17 @@
+import { Component, useState } from "@odoo/owl"
+
+export class Card extends Component {
+ static template = "awesome_owl.card"
+ static props = {
+ title: String,
+ slots: Object,
+ }
+
+ setup() {
+ this.isOpened = useState({ value: true });
+ }
+
+ toggle() {
+ this.isOpened.value = !this.isOpened.value;
+ }
+}
diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml
new file mode 100644
index 00000000000..faf4e7d4ffa
--- /dev/null
+++ b/awesome_owl/static/src/card/card.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js
new file mode 100644
index 00000000000..c427b2f224d
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.js
@@ -0,0 +1,17 @@
+import { Component, useState } from "@odoo/owl";
+
+export class Counter extends Component {
+ static template = "awesome_owl.counter"
+ static props = {
+ onChange: { type: Function, optional: true }
+ }
+
+ setup() {
+ this.state = useState({ value: 0 });
+ }
+
+ increment() {
+ this.state.value++;
+ this.props?.onChange();
+ }
+}
diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml
new file mode 100644
index 00000000000..c1f3ccb092f
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+ Counter:
+
+
+
+
+
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js
index 657fb8b07bb..fe79bc526b9 100644
--- a/awesome_owl/static/src/playground.js
+++ b/awesome_owl/static/src/playground.js
@@ -1,7 +1,21 @@
/** @odoo-module **/
-import { Component } from "@odoo/owl";
+import { Component, useState, markup } from "@odoo/owl";
+import { Counter } from "./counter/counter";
+import { Card } from "./card/card";
+import { TodoList } from "./todo_list/todo_list";
export class Playground extends Component {
static template = "awesome_owl.playground";
+ static components = { Counter, Card, TodoList };
+
+ setup() {
+ this.normal_string = "
some content
";
+ this.markup_string = markup("some content
");
+ this.sum = useState({ value: 2 });
+ }
+
+ incrementSum() {
+ this.sum.value++;
+ }
}
diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml
index 4fb905d59f9..c4520307226 100644
--- a/awesome_owl/static/src/playground.xml
+++ b/awesome_owl/static/src/playground.xml
@@ -4,6 +4,21 @@
hello world
+
+
+
+ The sum is:
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/todo_list/todo_item.js b/awesome_owl/static/src/todo_list/todo_item.js
new file mode 100644
index 00000000000..14afdb63cfa
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_item.js
@@ -0,0 +1,9 @@
+import { Component } from "@odoo/owl"
+import { Todo } from "./todo_model";
+
+export class TodoItem extends Component {
+ static template = "awesome_owl.todo_item";
+ static props = {
+ todo: Todo,
+ }
+}
diff --git a/awesome_owl/static/src/todo_list/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item.xml
new file mode 100644
index 00000000000..5140bb33f5b
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_item.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ .
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js
new file mode 100644
index 00000000000..703c952c610
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_list.js
@@ -0,0 +1,22 @@
+import { Component, useRef, useState, onMounted } from "@odoo/owl";
+import { TodoItem } from "./todo_item";
+import { useAutofocus } from "../utils";
+import { TodoModel } from "./todo_model";
+
+export class TodoList extends Component {
+ static template = "awesome_owl.todo_list";
+ static components = { TodoItem };
+
+ setup() {
+ this.model = useState(new TodoModel());
+ useAutofocus("todo_input");
+ }
+
+ addTodo(ev) {
+ if (ev.keyCode !== 13 || ev.target.value == "") {
+ return;
+ }
+ this.model.add(ev.target.value);
+ ev.target.value = "";
+ }
+}
diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml
new file mode 100644
index 00000000000..54795505d09
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_list.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/todo_list/todo_model.js b/awesome_owl/static/src/todo_list/todo_model.js
new file mode 100644
index 00000000000..7c9426c8136
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_model.js
@@ -0,0 +1,34 @@
+export class Todo {
+ static nextId = 1;
+
+ constructor(model, description) {
+ this._model = model;
+ this.id = Todo.nextId++;
+ this.description = description;
+ this.isCompleted = false;
+ }
+
+ toggle() {
+ this.isCompleted = !this.isCompleted;
+ }
+
+ delete() {
+ this._model.delete(this.id);
+ }
+}
+
+export class TodoModel {
+ constructor() {
+ this.todoList = [];
+ }
+
+ add(description) {
+ this.todoList.push(new Todo(this, description));
+ }
+
+ delete(id) {
+ const index = this.todoList.findIndex((todo) => todo.id === id);
+ if (index == -1) return;
+ this.todoList.splice(index, 1);
+ }
+}
diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js
new file mode 100644
index 00000000000..4e62da7c3c2
--- /dev/null
+++ b/awesome_owl/static/src/utils.js
@@ -0,0 +1,8 @@
+import { useRef, onMounted } from "@odoo/owl";
+
+export function useAutofocus(refName) {
+ const ref = useRef(refName);
+ onMounted(() => {
+ ref.el.focus();
+ })
+}