Skip to content

Commit

Permalink
[IMP] playground: add a new sample
Browse files Browse the repository at this point in the history
  • Loading branch information
jpp-odoo committed Sep 19, 2024
1 parent f8bb868 commit 7fda21e
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/playground/playground.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ const SAMPLES = [
folder: "todo_app",
code: ["js", "xml", "css"],
},
{
description: "Tic-Tac-Toe (with reactivity)",
folder: "tic_tac_toe",
code: ["js", "xml", "css"],
},
{
description: "Responsive app",
folder: "responsive_app",
Expand Down
32 changes: 32 additions & 0 deletions docs/playground/samples/tic_tac_toe/tic_tac_toe.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}

.board-row:after {
clear: both;
content: '';
display: table;
}

.status {
margin-bottom: 10px;
}
.game {
display: flex;
flex-direction: row;
}

.game-info {
margin-left: 20px;
}
105 changes: 105 additions & 0 deletions docs/playground/samples/tic_tac_toe/tic_tac_toe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// This example is an implementation of the Tic-Tac-Toe game, from
// https://react.dev/learn/tutorial-tic-tac-toe. This is an easy application to start learning owl
// with some interesting user interactions.
//
// In this implementation, we use the owl reactivity mechanism.
import { Component, useState, mount } from "@odoo/owl";


class Square extends Component {
static template = "Square";
}

class Board extends Component {
static template = "Board"
static components = { Square };

handleClick(i) {
if (this.calculateWinner(this.props.squares) || this.props.squares[i]) {
return;
}
const nextSquares = this.props.squares.slice();
if (this.props.xIsNext) {
nextSquares[i] = 'X';
} else {
nextSquares[i] = 'O';
}
this.props.onPlay(nextSquares);
}

get status(){
const winner = this.calculateWinner(this.props.squares);
if (winner) {
return 'Winner: ' + winner;
} else {
if (Object.values(this.props.squares).filter((v) => v === null).length > 0)
return 'Next player: ' + (this.props.xIsNext ? 'X' : 'O');
else
return 'Draw';
}
}

calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
}

class Game extends Component {
static template = "Game"
static components = { Board };

setup() {
this.state = useState({
currentMove: 0,
history: [Array(9).fill(null)],
});
}

get currentSquares() {
return this.state.history[this.state.currentMove];
}

get xIsNext() {
return this.state.currentMove % 2 === 0;
}

jumpTo(nextMove) {
this.state.currentMove = nextMove;
}

handlePlay(nextSquares) {
const nextHistory = [...this.state.history.slice(0, this.state.currentMove + 1), nextSquares];
this.state.history = nextHistory;
this.state.currentMove = this.state.history.length - 1;
}

get moves() {
return this.state.history.map((_squares, move) => {
if (move > 0) {
return {id: move, description: 'Go to move #' + move};
} else {
return {id: move, description: 'Go to game start'};
}
});
}

}

// Application setup
mount(Game, document.body, { templates: TEMPLATES, dev: true});
43 changes: 43 additions & 0 deletions docs/playground/samples/tic_tac_toe/tic_tac_toe.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<templates>
<button t-name="Square" class="square" t-on-click="props.onSquareClick">
<t t-esc="props.value"/>
</button>

<t t-name="Board">
<div class="status">
<t t-esc="status"/>
</div>
<div class="board-row">
<Square value="props.squares[0]" onSquareClick="() => this.handleClick(0)" />
<Square value="props.squares[1]" onSquareClick="() => this.handleClick(1)" />
<Square value="props.squares[2]" onSquareClick="() => this.handleClick(2)" />
</div>
<div class="board-row">
<Square value="props.squares[3]" onSquareClick="() => this.handleClick(3)" />
<Square value="props.squares[4]" onSquareClick="() => this.handleClick(4)" />
<Square value="props.squares[5]" onSquareClick="() => this.handleClick(5)" />
</div>
<div class="board-row">
<Square value="props.squares[6]" onSquareClick="() => this.handleClick(6)" />
<Square value="props.squares[7]" onSquareClick="() => this.handleClick(7)" />
<Square value="props.squares[8]" onSquareClick="() => this.handleClick(8)" />
</div>
</t>

<div t-name="Game" class="game">
<div class="game-board">
<Board xIsNext="xIsNext" squares="currentSquares" onPlay.bind="handlePlay" />
</div>
<div class="game-info">
<ol>
<t t-foreach="moves" t-as="move" t-key="move.id">
<li>
<button t-on-click="() => this.jumpTo(move.id)">
<t t-esc="move.description"/>
</button>
</li>
</t>
</ol>
</div>
</div>
</templates>

0 comments on commit 7fda21e

Please sign in to comment.