mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
WIP
This commit is contained in:
parent
58403986d7
commit
fa76b75c12
@ -120,3 +120,16 @@ body {
|
||||
text-align: center;
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
#grid {
|
||||
transition: background-color 0.5s ease;
|
||||
}
|
||||
|
||||
.flash-animation {
|
||||
animation: flashRed 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes flashRed {
|
||||
0% { background-color: #e55; }
|
||||
100% { background-color: white; }
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ pub const Channel = struct {
|
||||
game.evaluate();
|
||||
|
||||
if (game.victor != null) {
|
||||
try channel.publish(.{ .err = "Game is already over." });
|
||||
try channel.invoke(.game_over, .{});
|
||||
return;
|
||||
} else {
|
||||
try movePlayer(channel, &game, cells, cell);
|
||||
|
@ -5,13 +5,23 @@
|
||||
stateChangedCallbacks: [],
|
||||
messageCallbacks: [],
|
||||
invokeCallbacks: {},
|
||||
elementMap: {},
|
||||
transformerMap: {},
|
||||
transformers: {},
|
||||
onStateChanged: function(callback) { this.stateChangedCallbacks.push(callback); },
|
||||
onMessage: function(callback) { this.messageCallbacks.push(callback); },
|
||||
receive: function(event, callback) {
|
||||
if (Object.hasOwn(this.invokeCallbacks, event)) {
|
||||
this.invokeCallbacks[event].push(callback);
|
||||
transform: function(ref, callback) {
|
||||
if (Object.hasOwn(this.transformers, ref)) {
|
||||
this.transformers[ref].push(callback);
|
||||
} else {
|
||||
this.invokeCallbacks[event] = [callback];
|
||||
this.transformers[ref] = [callback];
|
||||
}
|
||||
},
|
||||
receive: function(ref, callback) {
|
||||
if (Object.hasOwn(this.invokeCallbacks, ref)) {
|
||||
this.invokeCallbacks[ref].push(callback);
|
||||
} else {
|
||||
this.invokeCallbacks[ref] = [callback];
|
||||
}
|
||||
},
|
||||
publish: function(data) {
|
||||
@ -21,11 +31,22 @@
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
(() => {
|
||||
|
||||
@if (context.request) |request|
|
||||
const transform = (value, state, element) => {
|
||||
const id = element.getAttribute('jetzig-id');
|
||||
const key = id && channel.transformerMap[id];
|
||||
const transformers = key && channel.transformers[key];
|
||||
if (transformers) {
|
||||
return transformers.reduce((acc, val) => val(acc), value);
|
||||
} else {
|
||||
return value === undefined || value == null ? '' : `${value}`
|
||||
}
|
||||
};
|
||||
|
||||
@if (request.headers.get("host")) |host|
|
||||
<script>
|
||||
channel.websocket = new WebSocket('ws://{{host}}{{request.path.base_path}}');
|
||||
channel.websocket.addEventListener("message", (event) => {
|
||||
const state_tag = "__jetzig_channel_state__:";
|
||||
@ -34,6 +55,10 @@
|
||||
|
||||
if (event.data.startsWith(state_tag)) {
|
||||
const state = JSON.parse(event.data.slice(state_tag.length));
|
||||
Object.entries(channel.elementMap).forEach(([ref, elements]) => {
|
||||
const value = reduceState(ref, state);
|
||||
elements.forEach(element => element.innerHTML = transform(value, state, element));
|
||||
});
|
||||
channel.stateChangedCallbacks.forEach((callback) => {
|
||||
callback(state);
|
||||
});
|
||||
@ -74,23 +99,54 @@
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const reduceState = (ref, state) => {
|
||||
if (!ref.startsWith('$.')) throw new Error(`Unexpected ref format: ${ref}`);
|
||||
const args = ref.split('.');
|
||||
args.shift();
|
||||
const isNumeric = (string) => [...string].every(char => '0123456789'.includes(char));
|
||||
const isObject = (object) => object && typeof object === 'object';
|
||||
return args.reduce((acc, arg) => {
|
||||
if (isNumeric(arg)) {
|
||||
if (acc && Array.isArray(acc) && acc.length > arg) return acc[parseInt(arg)];
|
||||
return null;
|
||||
} else {
|
||||
if (acc && isObject(acc)) return acc[arg];
|
||||
return null;
|
||||
}
|
||||
}, state);
|
||||
};
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('[jetzig-connect]').forEach(element => {
|
||||
const ref = element.getAttribute('jetzig-connect');
|
||||
if (!channel.elementMap[ref]) channel.elementMap[ref] = [];
|
||||
const id = `jetzig-${crypto.randomUUID()}`;
|
||||
element.setAttribute('jetzig-id', id);
|
||||
channel.elementMap[ref].push(element);
|
||||
channel.transformerMap[id] = element.getAttribute('jetzig-transform');
|
||||
});
|
||||
});
|
||||
|
||||
@// channel.websocket.addEventListener("open", (event) => {
|
||||
@// // TODO
|
||||
@// channel.publish("websockets", {});
|
||||
@// });
|
||||
</script>
|
||||
@end
|
||||
@end
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div id="results-wrapper">
|
||||
<span class="trophy">🏆</span>
|
||||
<div id="results">
|
||||
<div>Player</div>
|
||||
<div id="player-wins"></div>
|
||||
<div id="player-wins" jetzig-connect="$.results.player"></div>
|
||||
<div>CPU</div>
|
||||
<div id="cpu-wins"></div>
|
||||
<div id="cpu-wins" jetzig-connect="$.results.cpu"></div>
|
||||
<div>Tie</div>
|
||||
<div id="ties"></div>
|
||||
<div id="ties" jetzig-connect="$.results.tie"></div>
|
||||
</div>
|
||||
<span class="trophy">🏆</span>
|
||||
</div>
|
||||
@ -98,15 +154,9 @@
|
||||
<div id="party-container"></div>
|
||||
|
||||
<div class="board" id="board">
|
||||
<div class="cell" jetzig-connect="$.cells.0" id="tic-tac-toe-cell-0" data-cell="0"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.1" id="tic-tac-toe-cell-1" data-cell="1"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.2" id="tic-tac-toe-cell-2" data-cell="2"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.3" id="tic-tac-toe-cell-3" data-cell="3"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.4" id="tic-tac-toe-cell-4" data-cell="4"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.5" id="tic-tac-toe-cell-5" data-cell="5"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.6" id="tic-tac-toe-cell-6" data-cell="6"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.7" id="tic-tac-toe-cell-7" data-cell="7"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.8" id="tic-tac-toe-cell-8" data-cell="8"></div>
|
||||
@for (0..9) |index| {
|
||||
<div class="cell" jetzig-connect="$.cells.{{index}}" jetzig-transform="cell" id="tic-tac-toe-cell-{{index}}" data-cell="{{index}}"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<button id="reset-button">Reset Game</button>
|
||||
@ -118,19 +168,10 @@
|
||||
|
||||
<script>
|
||||
channel.onStateChanged(state => {
|
||||
document.querySelector("#player-wins").innerText = state.results.player;
|
||||
document.querySelector("#cpu-wins").innerText = state.results.cpu;
|
||||
document.querySelector("#ties").innerText = state.results.tie;
|
||||
|
||||
if (!state.victor) {
|
||||
const elem = document.querySelector("#victor");
|
||||
elem.style.visibility = 'hidden';
|
||||
const element = document.querySelector("#victor");
|
||||
element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
Object.entries(state.cells).forEach(([cell, state]) => {
|
||||
const element = document.querySelector(`#tic-tac-toe-cell-${cell}`);
|
||||
element.innerHTML = { player: "✈️", cpu: "🦎" }[state] || "";
|
||||
});
|
||||
});
|
||||
|
||||
channel.onMessage(message => {
|
||||
@ -140,25 +181,35 @@
|
||||
});
|
||||
|
||||
channel.receive("victor", (data) => {
|
||||
console.log(data);
|
||||
const elem = document.querySelector("#victor");
|
||||
const element = document.querySelector("#victor");
|
||||
const emoji = {
|
||||
player: "✈️",
|
||||
cpu: "🦎",
|
||||
tie: "🤝"
|
||||
}[data.params.type] || "";
|
||||
elem.innerHTML = `🏆 ${emoji} 🏆`;
|
||||
elem.style.visibility = 'visible';
|
||||
element.innerHTML = `🏆 ${emoji} 🏆`;
|
||||
element.style.visibility = 'visible';
|
||||
triggerPartyAnimation();
|
||||
});
|
||||
|
||||
channel.receive("game_over", (data) => {
|
||||
const element = document.querySelector("#board");
|
||||
element.classList.remove('flash-animation');
|
||||
void element.offsetWidth;
|
||||
element.classList.add('flash-animation');
|
||||
});
|
||||
|
||||
channel.transform("cell", (value) => (
|
||||
{ player: "✈️", cpu: "🦎" }[value] || ""
|
||||
));
|
||||
document.querySelectorAll("#board div.cell").forEach(element => {
|
||||
element.addEventListener("click", () => {
|
||||
channel.actions.move(parseInt(element.dataset.cell));
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector("#reset-button").addEventListener("click", () => {
|
||||
channel.actions.reset();
|
||||
});
|
||||
|
||||
document.querySelectorAll("#board div.cell").forEach(element => {
|
||||
element.addEventListener("click", () => {
|
||||
channel.actions.move(parseInt(element.dataset.cell));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user