Simple Game
Reward: Cost:
Code
The following example assumes that you have imported the component and set up the theme.
<wcp-template id="mine-cell">31 collapsed lines
<template> <div class="cell" template-repeat="random:index"> <wcp-ui-state> <wcp-store type="boolean" name="$opened" value="false"></wcp-store> <wcp-store type="string" name="$type" value='[[ random[index] < 0.2 ? "trap" : random[index] < 0.7 ? "gold" : "empty" ]]' ></wcp-store>
<button class="cell-button" bind-attr='aria-label:($opened ? $type : "unknown") + " cell in row " + [[ Math.floor(index / 6) + 1 ]] + " column " + [[ (index % 6 ) + 1 ]]' bind-attr-toggle="disabled:$opened || $lost" bind-class="$opened ? $type : ''" bind-event='click: $opened(!$opened), ( $type === "trap" ? $health($health - 1) : $type === "gold" ? $gold($gold + $reward) : null )' bind-text='$opened ? ($type === "trap" ? "💣" : $type === "gold" ? "🪙" : ".") : "?"' > ? </button> </wcp-ui-state> </div> </template></wcp-template>
<wcp-ui-state> <wcp-store type="number" name="$gold" value="0"></wcp-store> <wcp-store type="number" name="$health" value="5"></wcp-store> <wcp-store type="number" name="$target" value="25"></wcp-store>
<wcp-store type="number" name="$shovelCost" value="5"></wcp-store> <wcp-store type="number" name="$reward" value="2"></wcp-store>
<wcp-store derive="$gold >= $target" name="$won"></wcp-store> <wcp-store derive="$health <= 0" name="$lost"></wcp-store>
<div class="mine-game">54 collapsed lines
<div class="topbar"> <div> Gold: <strong class="gold" bind-text="$gold"></strong> / <span class="gold" bind-text="$target"></span> </div>
<div> Health: <strong bind-text="$health"></strong> </div> </div>
<div class="shop"> <button bind-attr-toggle="disabled:$gold < $shovelCost || $lost" bind-event="click:$gold($gold - $shovelCost), $reward($reward + 1), $shovelCost($shovelCost + 5)" > Upgrade Shovel </button>
<span> Reward: <strong class="gold" bind-text="$reward"></strong> </span>
<span> Cost: <strong class="gold" bind-text="$shovelCost"></strong> </span> </div>
<div class="board"> <wcp-template prop-random:js="Array(6 * 6).fill().map(Math.random)" use="mine-cell"></wcp-template> </div>
<div class="status"> <div class="win" style="display: none" bind-show="$won">You reached the gold target.</div> <div class="lose" style="display: none" bind-show="$lost && !$won">You ran out of health.</div> <br /> <button class="restart-button" bind-event="click: $gold(0), $health(5), $target(25), $shovelCost(5), $reward(2) " > Restart </button> </div> </div></wcp-ui-state>
<script>17 collapsed lines
// @ts-check
document.addEventListener("DOMContentLoaded", () => { /** @type {HTMLButtonElement | null} */ const restartButton = document.querySelector(".restart-button");
/** @type {HTMLDivElement | null} */ const board = document.querySelector(".board");
restartButton?.addEventListener("click", () => { const newTemplate = document.createElement("wcp-template"); newTemplate.setAttribute("prop-random:js", "Array(6 * 6).fill().map(Math.random)"); newTemplate.setAttribute("use", "mine-cell");
board?.replaceChildren(newTemplate); }); });</script>
<style>96 collapsed lines
.mine-game { display: flex; flex-direction: column; gap: 1rem; max-inline-size: 32rem; margin: auto; color: var(--sb-color-text); }
.gold { color: light-dark(#ba9e00, gold); }
.topbar, .shop { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }
.board { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.5rem; }
.cell { display: flex; }
.cell-button { flex: 1; aspect-ratio: 1; font-size: var(--sb-text-lg); font-weight: 700; color: var(--sb-color-text); cursor: pointer; background: var(--sb-color-gray-6); border: 1px solid var(--sb-color-gray-4); border-radius: 8px;
&:disabled { cursor: default; }
&:hover:not(:disabled) { border-color: var(--sb-color-accent); }
&.gold { background: var(--sb-color-accent-low); border-color: var(--sb-color-accent); }
&.trap { background: var(--sb-caution-background); border-color: var(--sb-caution-border); }
&.empty { background: var(--sb-color-gray-7); } }
.shop button, .restart-button { padding: 0.6rem 1rem; color: #fff; cursor: pointer; background: var(--sb-color-accent); border: 0; border-radius: 8px;
&:disabled { filter: grayscale(); } }
.win, .lose { padding: 0.75rem; border-radius: 8px; }
.win { color: var(--sb-tip-text); background: var(--sb-tip-background); border: 1px solid var(--sb-tip-border); }
.lose { color: var(--sb-caution-text); background: var(--sb-caution-background); border: 1px solid var(--sb-caution-border); }</style>