Spaces:
Running
Running
| <template> | |
| <div class="mcts-move-navigation"> | |
| <div class="nav-buttons"> | |
| <button @click="mctsStore.firstMove()" :disabled="isFirst" class="nav-btn">⏮ First</button> | |
| <button @click="mctsStore.prevMove()" :disabled="isFirst" class="nav-btn">◀ Prev</button> | |
| <button @click="mctsStore.nextMove()" :disabled="isLast" class="nav-btn">Next ▶</button> | |
| <button @click="mctsStore.lastMove()" :disabled="isLast" class="nav-btn">Last ⏭</button> | |
| </div> | |
| <div class="move-slider"> | |
| <input | |
| type="range" | |
| :min="0" | |
| :max="maxMove" | |
| :value="currentMove" | |
| @input="onSliderChange" | |
| class="slider" | |
| /> | |
| <span class="move-label">Move {{ currentMove + 1 }} / {{ maxMove + 1 }}</span> | |
| </div> | |
| <div class="move-info"> | |
| <span>Player: <strong>{{ currentPlayer }}</strong></span> | |
| </div> | |
| </div> | |
| </template> | |
| <script setup lang="ts"> | |
| import { computed } from "vue"; | |
| import { useMCTSStore } from "@/stores/mctsStore"; | |
| const mctsStore = useMCTSStore(); | |
| const currentMove = computed(() => mctsStore.currentMoveIndex); | |
| const maxMove = computed(() => mctsStore.maxMoveIndex); | |
| const isFirst = computed(() => currentMove.value === 0); | |
| const isLast = computed(() => currentMove.value === maxMove.value); | |
| const currentPlayer = computed(() => { | |
| const moveData = mctsStore.currentMoveData; | |
| return moveData ? moveData.player : "-"; | |
| }); | |
| function onSliderChange(event: Event) { | |
| const target = event.target as HTMLInputElement; | |
| mctsStore.setCurrentMoveIndex(parseInt(target.value, 10)); | |
| } | |
| </script> | |
| <style scoped lang="scss"> | |
| .mcts-move-navigation { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| } | |
| .nav-buttons { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 8px; | |
| } | |
| .nav-btn { | |
| padding: 8px 12px; | |
| background-color: #3a3a3a; | |
| border: 1px solid #505050; | |
| border-radius: 4px; | |
| color: #e0e0e0; | |
| font-size: 12px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| &:hover:not(:disabled) { | |
| background-color: #4a4a4a; | |
| border-color: #4a90e2; | |
| } | |
| &:active:not(:disabled) { | |
| background-color: #2a2a2a; | |
| } | |
| &:disabled { | |
| opacity: 0.4; | |
| cursor: not-allowed; | |
| } | |
| } | |
| .move-slider { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .slider { | |
| width: 100%; | |
| height: 6px; | |
| border-radius: 3px; | |
| background-color: #3a3a3a; | |
| outline: none; | |
| -webkit-appearance: none; | |
| &::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| appearance: none; | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 50%; | |
| background-color: #4a90e2; | |
| cursor: pointer; | |
| &:hover { | |
| background-color: #357abd; | |
| } | |
| } | |
| &::-moz-range-thumb { | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 50%; | |
| background-color: #4a90e2; | |
| cursor: pointer; | |
| border: none; | |
| &:hover { | |
| background-color: #357abd; | |
| } | |
| } | |
| } | |
| .move-label { | |
| font-size: 13px; | |
| color: #c0c0c0; | |
| text-align: center; | |
| } | |
| .move-info { | |
| padding: 8px; | |
| background-color: #1a1a1a; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| color: #a0a0a0; | |
| strong { | |
| color: #e0e0e0; | |
| text-transform: capitalize; | |
| } | |
| } | |
| </style> | |