Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3d26fef
[ADD] counter: create counter component
Mohamed-Dallash Sep 23, 2025
1efd503
[IMP] playground: add two counters to the playground
Mohamed-Dallash Sep 23, 2025
bc8df7e
[IMP] counter: update styling of counter component
Mohamed-Dallash Sep 23, 2025
38f3bfb
[ADD] card: create card component
Mohamed-Dallash Sep 23, 2025
c032556
[IMP] card: update card component to use t-out
Mohamed-Dallash Sep 23, 2025
3ef6e22
[IMP] playground: update data displayed on cards and try markup
Mohamed-Dallash Sep 23, 2025
af70968
[IMP] card: add props validation to card component
Mohamed-Dallash Sep 23, 2025
9657d39
[IMP] counter: add onChange callback to counters
Mohamed-Dallash Sep 23, 2025
6da5f5f
[IMP] playground: add a sum and increment it using the counters
Mohamed-Dallash Sep 23, 2025
8161e3f
[ADD] todo_list: add todo item and todo list components
Mohamed-Dallash Sep 23, 2025
bc5e35d
[IMP] todo_list: add styling to completed todo items
Mohamed-Dallash Sep 23, 2025
ea02bb0
[IMP] todo_list: remove hard coded list and allow user to add todo items
Mohamed-Dallash Sep 23, 2025
fd87e8c
[IMP] todo_list: automatically focus on the todo list input when load…
Mohamed-Dallash Sep 23, 2025
205a7b4
[IMP] todo_list: allow toggling of todos
Mohamed-Dallash Sep 23, 2025
99d8ecf
[IMP] todo_list: low deletion of todo list items
Mohamed-Dallash Sep 23, 2025
3c2782a
[IMP] card: allow generic data inside cards using slots
Mohamed-Dallash Sep 23, 2025
3af4e61
[IMP] card: allow toggling of cards' content
Mohamed-Dallash Sep 23, 2025
423ede6
[IMP] playground: add newlines to files that didn't have them at the…
Mohamed-Dallash Sep 26, 2025
6131331
[IMP] todo_list: fix a potential bug with toggling and deleting todos
Mohamed-Dallash Sep 26, 2025
8f6e5ed
[IMP] todo_list: add models for todo and use them instead of hard cod…
Mohamed-Dallash Sep 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions awesome_owl/static/src/card/card.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
18 changes: 18 additions & 0 deletions awesome_owl/static/src/card/card.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.card">
<div class="card d-inline-block m-2" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">
<t t-out="props.title"/>
<button class="btn btn-primary" t-on-click="toggle">toggle</button>
</h5>
<p class="card-text" t-if="isOpened.value">
<t t-slot="default"/>
</p>
</div>
</div>
</t>

</templates>
17 changes: 17 additions & 0 deletions awesome_owl/static/src/counter/counter.js
Original file line number Diff line number Diff line change
@@ -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();
}
}
11 changes: 11 additions & 0 deletions awesome_owl/static/src/counter/counter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.counter">
<div class="m-2 p-2 border d-inline-block">
<span class="me-2">Counter: <t t-esc="state.value"/></span>
<button class="btn btn-primary" t-on-click="increment">Increment</button>
</div>
</t>

</templates>
16 changes: 15 additions & 1 deletion awesome_owl/static/src/playground.js
Original file line number Diff line number Diff line change
@@ -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 = "<div class='text-primary'>some content</div>";
this.markup_string = markup("<div class='text-primary'>some content</div>");
this.sum = useState({ value: 2 });
}

incrementSum() {
this.sum.value++;
}
}
15 changes: 15 additions & 0 deletions awesome_owl/static/src/playground.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@
<t t-name="awesome_owl.playground">
<div class="p-3">
hello world
<Counter onChange.bind="incrementSum"/>
<Counter onChange.bind="incrementSum"/>
</div>
<p>The sum is: <t t-esc="this.sum.value"/></p>
<div>
<Card title="'Card 1'">
<t t-out="normal_string"/>
</Card>
<Card title="'Card 2'">
<t t-out="markup_string"/>
<Counter/>
</Card>
</div>
<div>
<TodoList/>
</div>
</t>

Expand Down
9 changes: 9 additions & 0 deletions awesome_owl/static/src/todo_list/todo_item.js
Original file line number Diff line number Diff line change
@@ -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,
}
}
13 changes: 13 additions & 0 deletions awesome_owl/static/src/todo_list/todo_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.todo_item">
<div t-att-class="{'text-muted text-decoration-line-through':props.todo.isCompleted}">
<input type="checkbox" t-att-checked="props.todo.isCompleted" t-on-change="() => props.todo.toggle()"/>
<t t-esc="props.todo.id"/>.
<t t-esc="props.todo.description"/>
<span class="fa fa-remove text-danger" t-on-click="() => props.todo.delete()"/>
</div>
</t>

</templates>
22 changes: 22 additions & 0 deletions awesome_owl/static/src/todo_list/todo_list.js
Original file line number Diff line number Diff line change
@@ -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 = "";
}
}
15 changes: 15 additions & 0 deletions awesome_owl/static/src/todo_list/todo_list.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_owl.todo_list">
<div>
<input placeholder="Enter a new task" t-on-keyup="addTodo" t-ref="todo_input"/>
</div>
<div>
<t t-foreach="model.todoList" t-as="todo" t-key="todo.id">
<TodoItem todo="todo" />
</t>
</div>
</t>

</templates>
34 changes: 34 additions & 0 deletions awesome_owl/static/src/todo_list/todo_model.js
Original file line number Diff line number Diff line change
@@ -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);
}
}
8 changes: 8 additions & 0 deletions awesome_owl/static/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useRef, onMounted } from "@odoo/owl";

export function useAutofocus(refName) {
const ref = useRef(refName);
onMounted(() => {
ref.el.focus();
})
}