feat: install DaisyUI and add perfs

This commit is contained in:
Julien Calixte
2025-08-06 19:14:30 +02:00
parent 6bf6031940
commit 35432ff44c
5 changed files with 160 additions and 42 deletions

6
5s.css
View File

@@ -1,5 +1,9 @@
@import 'tailwindcss'; @import 'tailwindcss';
@plugin "daisyui"; @plugin "@tailwindcss/typography";
@plugin "daisyui" {
themes: light --default, dark --prefersdark;
}
*:not(td):not(th) { *:not(td):not(th) {
border-radius: 0.5rem; border-radius: 0.5rem;

View File

@@ -30,6 +30,7 @@
}, },
"devDependencies": { "devDependencies": {
"@faker-js/faker": "^9.4.0", "@faker-js/faker": "^9.4.0",
"@tailwindcss/typography": "^0.5.16",
"@types/hex-color-regex": "^1.1.3", "@types/hex-color-regex": "^1.1.3",
"@types/node": "^22.10.2", "@types/node": "^22.10.2",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",

52
pnpm-lock.yaml generated
View File

@@ -48,6 +48,9 @@ importers:
'@faker-js/faker': '@faker-js/faker':
specifier: ^9.4.0 specifier: ^9.4.0
version: 9.4.0 version: 9.4.0
'@tailwindcss/typography':
specifier: ^0.5.16
version: 0.5.16(tailwindcss@4.1.11)
'@types/hex-color-regex': '@types/hex-color-regex':
specifier: ^1.1.3 specifier: ^1.1.3
version: 1.1.3 version: 1.1.3
@@ -762,6 +765,11 @@ packages:
resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
'@tailwindcss/typography@0.5.16':
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
'@tailwindcss/vite@4.1.11': '@tailwindcss/vite@4.1.11':
resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==} resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==}
peerDependencies: peerDependencies:
@@ -899,6 +907,11 @@ packages:
comlink@4.4.2: comlink@4.4.2:
resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==} resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==}
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -1100,6 +1113,15 @@ packages:
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
loupe@3.1.3: loupe@3.1.3:
resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
@@ -1163,6 +1185,10 @@ packages:
typescript: typescript:
optional: true optional: true
postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
postcss@8.5.1: postcss@8.5.1:
resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@@ -1251,6 +1277,9 @@ packages:
undici-types@6.20.0: undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
vite-node@2.1.9: vite-node@2.1.9:
resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
@@ -1812,6 +1841,14 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11
'@tailwindcss/oxide-win32-x64-msvc': 4.1.11 '@tailwindcss/oxide-win32-x64-msvc': 4.1.11
'@tailwindcss/typography@0.5.16(tailwindcss@4.1.11)':
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 4.1.11
'@tailwindcss/vite@4.1.11(vite@6.0.9(@types/node@22.10.2)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.85.0))': '@tailwindcss/vite@4.1.11(vite@6.0.9(@types/node@22.10.2)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.85.0))':
dependencies: dependencies:
'@tailwindcss/node': 4.1.11 '@tailwindcss/node': 4.1.11
@@ -2001,6 +2038,8 @@ snapshots:
comlink@4.4.2: {} comlink@4.4.2: {}
cssesc@3.0.0: {}
csstype@3.1.3: {} csstype@3.1.3: {}
d3-array@2.12.1: d3-array@2.12.1:
@@ -2203,6 +2242,12 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-arm64-msvc: 1.30.1
lightningcss-win32-x64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1
lodash.castarray@4.4.0: {}
lodash.isplainobject@4.0.6: {}
lodash.merge@4.6.2: {}
loupe@3.1.3: {} loupe@3.1.3: {}
magic-string@0.30.12: magic-string@0.30.12:
@@ -2255,6 +2300,11 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@vue/composition-api' - '@vue/composition-api'
postcss-selector-parser@6.0.10:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss@8.5.1: postcss@8.5.1:
dependencies: dependencies:
nanoid: 3.3.8 nanoid: 3.3.8
@@ -2371,6 +2421,8 @@ snapshots:
undici-types@6.20.0: {} undici-types@6.20.0: {}
util-deprecate@1.0.2: {}
vite-node@2.1.9(@types/node@22.10.2)(lightningcss@1.30.1)(sass@1.85.0): vite-node@2.1.9(@types/node@22.10.2)(lightningcss@1.30.1)(sass@1.85.0):
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14

View File

@@ -10,14 +10,17 @@ const duration = ref<string | null>(null)
setInterval(() => { setInterval(() => {
duration.value = boardGameStore.start duration.value = boardGameStore.start
? toDuration(new Date(boardGameStore.start)) ? toDuration(
new Date(boardGameStore.start),
boardGameStore.end ? new Date(boardGameStore.end) : new Date()
)
: null : null
}, 1000) }, 1000)
const submit = () => { const submit = () => {
const tool = toValue(userInput) const lastInput = toValue(userInput)
boardGameStore.craftWithTool(tool) boardGameStore.craftWithTool(lastInput)
userInput.value = '' userInput.value = ''
} }
@@ -43,7 +46,7 @@ const submit = () => {
</table> </table>
</aside> </aside>
<div class="main"> <div class="main prose">
<h2>Workshop</h2> <h2>Workshop</h2>
<button <button
v-if="!boardGameStore.currentBoardGame" v-if="!boardGameStore.currentBoardGame"
@@ -57,13 +60,56 @@ const submit = () => {
<input type="text" v-model="userInput" autofocus /> <input type="text" v-model="userInput" autofocus />
</form> </form>
<h3> <div class="card bg-base-100 w-96 shadow-sm">
<div class="card-body">
<h2 class="card-title">
{{ boardGameStore.currentBoardGame.name }} {{ boardGameStore.currentBoardGame.name }}
</h3> </h2>
<div v-if="boardGameStore.currentTask"> <ul>
<h4>current task</h4> <li
<p>{{ boardGameStore.currentTask.name }}</p> v-for="(part, partIndex) in boardGameStore.currentBoardGame
with tools: .parts"
:key="part.name"
>
<span
:class="{
crafted: boardGameStore.currentPartIndex
? partIndex <= boardGameStore.currentPartIndex
: false
}"
>
{{ part.name }}
</span>
<template v-if="partIndex === boardGameStore.currentPartIndex">
<div class="inline-grid *:[grid-area:1/1]">
<div class="status status-primary animate-ping"></div>
<div class="status status-primary"></div>
</div>
<ol>
<li
v-for="(task, taskIndex) in boardGameStore.currentPart
?.tasks"
:key="task.name"
>
<span
:class="{
crafted: boardGameStore.currentTaskIndex
? taskIndex < boardGameStore.currentTaskIndex
: false
}"
>{{ task.name }}</span
>
<template
v-if="
taskIndex === boardGameStore.currentTaskIndex &&
boardGameStore.currentTask
"
>
<div class="inline-grid *:[grid-area:1/1]">
<div class="status status-primary animate-ping"></div>
<div class="status status-primary"></div>
</div>
<ul> <ul>
<li <li
v-for="tool in boardGameStore.currentTask.tools" v-for="tool in boardGameStore.currentTask.tools"
@@ -77,30 +123,34 @@ const submit = () => {
{{ tool.name }} {{ tool.name }}
</li> </li>
</ul> </ul>
</template>
</li>
</ol>
</template>
</li>
</ul>
</div>
</div> </div>
<hr />
<ul>
<li
v-for="part in boardGameStore.currentBoardGame.parts"
:key="part.name"
>
{{ part.name }}
<ul>
<li v-for="task in part.tasks" :key="task.name">
{{ task.name }} ({{
task.tools.map((tool) => tool.name).join(', ')
}})
</li>
</ul>
</li>
</ul>
</div> </div>
</div> </div>
<aside v-if="duration"> <aside
class="prose"
v-if="duration !== null || boardGameStore.perfs.length > 0"
>
<h2>Performance</h2> <h2>Performance</h2>
<p>{{ duration }}</p> <p>{{ duration }}</p>
<template v-if="boardGameStore.perfs.length > 0">
<h3>Last performances</h3>
<ul>
<li v-for="perf in boardGameStore.perfs">
{{ toDuration(new Date(perf[0]), new Date(perf[1])) }}
</li>
</ul>
</template>
</aside> </aside>
</div> </div>
</template> </template>
@@ -127,6 +177,11 @@ const submit = () => {
} }
} }
form {
text-align: center;
}
.crafted,
.used-tool { .used-tool {
color: green; color: green;
} }

View File

@@ -11,6 +11,7 @@ type State = {
usedTools: string[] usedTools: string[]
start: string | null start: string | null
end: string | null end: string | null
perfs: Array<[string, string]>
} }
export const useBoardGameStore = defineStore('board-game', { export const useBoardGameStore = defineStore('board-game', {
@@ -21,15 +22,18 @@ export const useBoardGameStore = defineStore('board-game', {
currentTaskIndex: null, currentTaskIndex: null,
usedTools: [], usedTools: [],
start: null, start: null,
end: null end: null,
perfs: []
}), }),
actions: { actions: {
initGame() { initGame() {
this.boardGames = [boardGames[0], boardGames[1]] // this.boardGames = [boardGames[0], boardGames[1]]
this.boardGames = [boardGames[0]]
this.currentBoardGameIndex = 0 this.currentBoardGameIndex = 0
this.currentPartIndex = 0 this.currentPartIndex = 0
this.currentTaskIndex = 0 this.currentTaskIndex = 0
this.start = new Date().toISOString() this.start = new Date().toISOString()
this.end = null
}, },
craftWithTool(tool: string) { craftWithTool(tool: string) {
if (!this.currentTask) { if (!this.currentTask) {
@@ -49,6 +53,7 @@ export const useBoardGameStore = defineStore('board-game', {
}, },
increment() { increment() {
if ( if (
!this.start ||
!this.currentTask || !this.currentTask ||
!this.currentPart || !this.currentPart ||
!this.currentBoardGame || !this.currentBoardGame ||
@@ -81,6 +86,7 @@ export const useBoardGameStore = defineStore('board-game', {
// All board games complete // All board games complete
this.end = new Date().toISOString() this.end = new Date().toISOString()
this.perfs = [...this.perfs, [this.start, this.end]]
this.currentBoardGameIndex = null this.currentBoardGameIndex = null
this.currentPartIndex = null this.currentPartIndex = null
this.currentTaskIndex = null this.currentTaskIndex = null