diff --git a/awesome_owl/__init__.py b/awesome_owl/__init__.py
index 457bae27e11..b0f26a9a602 100644
--- a/awesome_owl/__init__.py
+++ b/awesome_owl/__init__.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
-from . import controllers
\ No newline at end of file
+from . import controllers
diff --git a/awesome_owl/controllers/__init__.py b/awesome_owl/controllers/__init__.py
index 457bae27e11..b0f26a9a602 100644
--- a/awesome_owl/controllers/__init__.py
+++ b/awesome_owl/controllers/__init__.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
-from . import controllers
\ No newline at end of file
+from . import controllers
diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js
new file mode 100644
index 00000000000..711c29c0918
--- /dev/null
+++ b/awesome_owl/static/src/card/card.js
@@ -0,0 +1,25 @@
+import {Component, useState} from "@odoo/owl"
+
+
+export class Card extends Component {
+ static template = "awesome_owl.card";
+
+ static props = {
+ title: String,
+ slots: {type: Object, optional: true},
+ };
+
+ setup() {
+ const {title} = this.props;
+ this.title = title;
+ this.state = useState({isOpened: true})
+ }
+
+ get isOpened() {
+ return this.state.isOpened;
+ }
+
+ toggle() {
+ this.state.isOpened = !this.isOpened;
+ }
+}
diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml
new file mode 100644
index 00000000000..95ee77a660b
--- /dev/null
+++ b/awesome_owl/static/src/card/card.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js
new file mode 100644
index 00000000000..ba5a550d3b2
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.js
@@ -0,0 +1,18 @@
+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..8bf995ba3c5
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ Counter:
+
+
+
+
diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js
index 1af6c827e0b..9a131ef4f0d 100644
--- a/awesome_owl/static/src/main.js
+++ b/awesome_owl/static/src/main.js
@@ -2,6 +2,7 @@ import { whenReady } from "@odoo/owl";
import { mountComponent } from "@web/env";
import { Playground } from "./playground";
+
const config = {
dev: true,
name: "Owl Tutorial",
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js
index 657fb8b07bb..3aa35c68758 100644
--- a/awesome_owl/static/src/playground.js
+++ b/awesome_owl/static/src/playground.js
@@ -1,7 +1,20 @@
-/** @odoo-module **/
+import { Card } from "./card/card"
+import { Component, useState } from "@odoo/owl";
+import { Counter } from "./counter/counter";
+import { TodoList } from "./todo_list/todo_list";
-import { Component } from "@odoo/owl";
export class Playground extends Component {
static template = "awesome_owl.playground";
+
+ static components = { Counter, Card, TodoList };
+
+ setup() {
+ this.state = useState({ sum: 0 });
+ this.incrementSum = this.incrementSum.bind(this);
+ }
+
+ incrementSum() {
+ this.state.sum++;
+ }
}
diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml
index 4fb905d59f9..68fea7baa62 100644
--- a/awesome_owl/static/src/playground.xml
+++ b/awesome_owl/static/src/playground.xml
@@ -1,10 +1,17 @@
-
+
-
- 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..29496144141
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_item.js
@@ -0,0 +1,26 @@
+import { Component } from "@odoo/owl"
+
+
+export class TodoItem extends Component {
+ static template = "awesome_owl.todo.item";
+
+ static props = {
+ id: Number,
+ description: String,
+ isCompleted: Boolean,
+ toggleState: Function,
+ deleteTodo: Function,
+ }
+
+ get id() {
+ return this.props.id;
+ }
+
+ get description() {
+ return this.props.description;
+ }
+
+ get isCompleted() {
+ return this.props.isCompleted;
+ }
+}
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..6c9c6fed585
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_item.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+ .
+
+
+
+
+
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..e02440d7142
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_list.js
@@ -0,0 +1,50 @@
+import { Component, useState } from "@odoo/owl"
+import { TodoItem } from "./todo_item";
+import { useAutofocus } from "../utils";
+
+
+export class TodoList extends Component {
+ static template = "awesome_owl.todo.list";
+
+ static components = { TodoItem };
+
+ static idGen = 0;
+
+ static get id() {
+ return this.idGen++;
+ }
+
+ setup() {
+ this.todos = useState([]);
+ useAutofocus('todo_input');
+ this.toggleTodo = this.toggleTodo.bind(this);
+ this.deleteTodo = this.deleteTodo.bind(this);
+ }
+
+ addTodo(event) {
+ if (event.keyCode === 13 && event.target.value) {
+ this.todos.push(
+ {
+ id: this.constructor.id,
+ description: event.target.value,
+ isCompleted: false
+ }
+ );
+ event.target.value = '';
+ }
+ }
+
+ toggleTodo(id) {
+ const idx = this.todos.findIndex((elem) => elem.id === id);
+ if (idx !== -1) {
+ this.todos[idx].isCompleted = !this.todos[idx].isCompleted;
+ }
+ }
+
+ deleteTodo(id) {
+ const idx = this.todos.findIndex((elem) => elem.id === id);
+ if (idx !== -1) {
+ this.todos.splice(idx, 1);
+ }
+ }
+}
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..aae7e639406
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_list.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js
new file mode 100644
index 00000000000..88b545b216b
--- /dev/null
+++ b/awesome_owl/static/src/utils.js
@@ -0,0 +1,9 @@
+import { onMounted, useRef } from "@odoo/owl";
+
+
+export function useAutofocus(name) {
+ const ref = useRef(name);
+ onMounted(() => {
+ ref.el.focus();
+ });
+}