All checks were successful
Build and Deploy Nuxt / build (push) Successful in 58s
177 lines
4.5 KiB
Vue
177 lines
4.5 KiB
Vue
<script setup>
|
||
const props = defineProps(['content']);
|
||
|
||
import { parse } from '~/services/widgets/DiceParser';
|
||
import { AddSound } from '~/services/Sound';
|
||
|
||
const container = ref(null);
|
||
const resultText = ref("");
|
||
const steps = ref(null);
|
||
const stepsHtml = ref("");
|
||
|
||
const rollDice = () => {
|
||
const result = parse(props.content);
|
||
resultText.value = result.total;
|
||
stepsHtml.value = result.steps.map(renderStep).join('');
|
||
};
|
||
|
||
const renderStep = (s) => {
|
||
if (s.type === 'op') {
|
||
const label = s.op === '*' ? '×' : s.op === '/' ? '÷' : s.op;
|
||
return `<span class="step-op">${label}</span>`;
|
||
}
|
||
|
||
if (s.type === 'const') {
|
||
return `<span class="step-const">${s.value}</span>`;
|
||
}
|
||
|
||
if (s.type === 'dice') {
|
||
const { entry } = s;
|
||
const { rawRolls, kept, sides, mod, value } = entry;
|
||
|
||
const keptCopy = [...kept];
|
||
const tagged = rawRolls.map(v => {
|
||
const i = keptCopy.indexOf(v);
|
||
if (i !== -1) { keptCopy.splice(i, 1); return { v, kept: true }; }
|
||
return { v, kept: false };
|
||
});
|
||
|
||
let html = '';
|
||
|
||
tagged.forEach(({ v, kept }) => {
|
||
const isMax = v === sides, isMin = v === 1;
|
||
const cls = !kept ? 'roll-val dropped'
|
||
: isMax ? 'roll-val max-val'
|
||
: isMin ? 'roll-val min-val'
|
||
: 'roll-val kept';
|
||
html += `<span class="${cls}">${v}</span>`;
|
||
});
|
||
|
||
if (kept.length < rawRolls.length || kept.length > 1) {
|
||
html += `<span class="step-sum">=${value}</span>`;
|
||
}
|
||
|
||
return html;
|
||
}
|
||
|
||
return '';
|
||
};
|
||
|
||
onMounted(() => {
|
||
AddSound(container.value);
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<div class="roll-widget" ref="container">
|
||
<div class="roll-widget-body">
|
||
<span class="result-text">{{ resultText || '-' }}</span>
|
||
<button class="btn-primary roll-btn sound-click" @click="rollDice">
|
||
<span class="dice-content">
|
||
<!-- Dice icon (SVG) -->
|
||
<img class="icon" src="/icons/iconoir/regular/dice-three.svg" draggable="false">
|
||
</span>
|
||
</button>
|
||
</div>
|
||
<div class="roll-widget-results">
|
||
<span class="formula">{{ "[" + props.content + "]" }}</span>
|
||
<div class="steps" v-html="stepsHtml"></div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.steps {
|
||
margin-left: 8px;
|
||
height: 22px;
|
||
> {
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
.steps :deep(.roll-val){
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 18px;
|
||
padding: 1px 2px;
|
||
border-radius: 3px;
|
||
margin: 2px;
|
||
font-size: 12px;
|
||
border: 1px solid;
|
||
}
|
||
.steps :deep(.roll-val.kept){
|
||
background: rgba(93,184,122,0.12);
|
||
border-color: #4a8c5c;
|
||
color: #a8d4b4;
|
||
}
|
||
|
||
.steps :deep(.roll-val.dropped) {
|
||
background: transparent;
|
||
border-color: var(--color-border);
|
||
color: var(--color-text-tertiary);
|
||
text-decoration: line-through;
|
||
}
|
||
|
||
.steps :deep(.roll-val.max-val) {
|
||
background: rgba(93,184,122,0.2);
|
||
border-color: #5db87a;
|
||
color: #5db87a;
|
||
}
|
||
|
||
.steps :deep(.roll-val.min-val) {
|
||
background: rgba(201,95,95,0.12);
|
||
border-color: #c95f5f;
|
||
color: #c95f5f;
|
||
}
|
||
|
||
.steps :deep(.step-op) { color: var(--color-text-secondary); padding: 0 4px; font-size: 13px; }
|
||
.steps :deep(.step-const) { font-size: 13px; color: var(--color-text-primary); padding: 0 2px; }
|
||
.steps :deep(.step-dice-label) { font-size: 11px; color: var(--color-text-tertiary); margin-right: 2px; }
|
||
.steps :deep(.step-sum) { font-size: 11px; color: var(--color-text-tertiary); margin-left: 2px; }
|
||
.steps :deep(.dice-mod) { font-style: normal; margin-left: 2px; }
|
||
|
||
.result-text {
|
||
font-size: 24px;
|
||
vertical-align: center;
|
||
}
|
||
|
||
.roll-widget-body {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.result-text {
|
||
margin-left: 12px;
|
||
}
|
||
|
||
.formula {
|
||
margin-left: 12px;
|
||
font-family: ui-monospace, monospace;
|
||
font-size: 12px;
|
||
color: var(--color-gray);
|
||
}
|
||
|
||
.roll-widget-results {
|
||
display: flex;
|
||
align-items: center;
|
||
padding-bottom: 10px;
|
||
}
|
||
|
||
.roll-widget {
|
||
width: 100%;
|
||
background-color: var(--color-background-light);
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-bottom: 8px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.roll-btn {
|
||
padding: 8px;
|
||
margin-right: 4px;
|
||
}
|
||
|
||
</style> |