|
|
|
@ -1,5 +1,4 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { onMounted } from 'vue'
|
|
|
|
|
import { useHead } from '@vueuse/head'
|
|
|
|
|
import { useStorage } from '@vueuse/core'
|
|
|
|
|
import { useRoute } from 'vue-router'
|
|
|
|
@ -8,104 +7,93 @@ const route = useRoute()
|
|
|
|
|
const raffleId = route.params.id as string
|
|
|
|
|
|
|
|
|
|
const raffleStore = useStorage<Raffle[]>('', [])
|
|
|
|
|
const raffle = raffleStore.value.find(r => r.id === raffleId)
|
|
|
|
|
const raffle = $computed(() => raffleStore.value.find(r => r.id === raffleId))
|
|
|
|
|
|
|
|
|
|
const participants = $computed(() => {
|
|
|
|
|
useHead({ title: raffle ? raffle.title : 'Lets Go' })
|
|
|
|
|
|
|
|
|
|
const items = $computed(() => {
|
|
|
|
|
return raffle ? raffle.participants : []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const amount = $computed(() => participants.length)
|
|
|
|
|
let aligned = $ref(false) // used for animation
|
|
|
|
|
let rollRot = $ref(0)
|
|
|
|
|
const sliceRot = 360 / items.length
|
|
|
|
|
const sliceSkew = sliceRot + 90
|
|
|
|
|
const labelShift = 90 - sliceRot / 2
|
|
|
|
|
const pieRot = $computed(() => `${(-90 + sliceRot / 2) + rollRot}deg`)
|
|
|
|
|
|
|
|
|
|
function degrees(index: number) {
|
|
|
|
|
if (!aligned) return 0
|
|
|
|
|
return (360 / amount) * index
|
|
|
|
|
function roll() {
|
|
|
|
|
if (rollRot) rollRot = 0
|
|
|
|
|
else {
|
|
|
|
|
const winner = Math.round(Math.random() * items.length)
|
|
|
|
|
rollRot = 3600 + sliceRot * winner
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useHead({ title: raffle ? raffle.title : 'Lets Go' })
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
aligned = true
|
|
|
|
|
}, 100)
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="relative w-screen h-screen overflow-hidden flex justify-end items-center">
|
|
|
|
|
<ol class="absolute top-0 -left-1/2 w-screen h-screen transition-transform duration-500 ease-in" :class="aligned ? 'aligned' : 'shifted'">
|
|
|
|
|
<li v-for="(participant, i) in participants"
|
|
|
|
|
class="slice"
|
|
|
|
|
:style="`
|
|
|
|
|
transform: rotate(${degrees(i)}deg);
|
|
|
|
|
`"
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
{{ participant }}bcdef ghijklmn
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
<div class="absolute top-1/2 left-1/2 w-32 h-32 -ml-16 -mt-16 rounded-full bg-black"></div>
|
|
|
|
|
</ol>
|
|
|
|
|
<div class="w-full h-full">
|
|
|
|
|
<div class="flex flex-col justify-between items-center w-1/2 h-full">
|
|
|
|
|
<header>
|
|
|
|
|
<h1 class="my-8 text-2xl">{{ raffle.title }}</h1>
|
|
|
|
|
</header>
|
|
|
|
|
<button @click="roll" class="text-4xl">{{ rollRot === 0 ? 'Roll!' : 'Reset' }}</button>
|
|
|
|
|
<footer>
|
|
|
|
|
<p class="my-4">Some raffle description</p>
|
|
|
|
|
</footer>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<ol
|
|
|
|
|
class="pie w-96 h-96 border-2 border-black rounded-full bg-white/10 overflow-hidden transition-transform"
|
|
|
|
|
:style="`transition-duration: ${rollRot ? 30 : 1}s`"
|
|
|
|
|
>
|
|
|
|
|
<li v-for="item,i in items"
|
|
|
|
|
class="slice"
|
|
|
|
|
:style="`transform: rotate(${sliceRot * i}deg) skewY(${sliceSkew}deg)`"
|
|
|
|
|
>
|
|
|
|
|
</li>
|
|
|
|
|
<li v-for="item,i in items"
|
|
|
|
|
class="label"
|
|
|
|
|
:style="`transform: rotate(${sliceRot * i + labelShift}deg)`"
|
|
|
|
|
>
|
|
|
|
|
{{ item }}
|
|
|
|
|
</li>
|
|
|
|
|
</ol>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.shifted {
|
|
|
|
|
transform: translateX(-100%);
|
|
|
|
|
}
|
|
|
|
|
.aligned {
|
|
|
|
|
transform: translateX(0);
|
|
|
|
|
}
|
|
|
|
|
.slice {
|
|
|
|
|
--w: 50vw;
|
|
|
|
|
--h: calc(6.283185307179586 * var(--w) / v-bind(amount));
|
|
|
|
|
.pie {
|
|
|
|
|
position: absolute;
|
|
|
|
|
width: var(--w);
|
|
|
|
|
height: var(--h);
|
|
|
|
|
left: 50%;
|
|
|
|
|
top: 28%;
|
|
|
|
|
padding: 0;
|
|
|
|
|
text-align: right;
|
|
|
|
|
transform-origin: left center;
|
|
|
|
|
transition: transform 1s ease-out .4s;
|
|
|
|
|
color: white;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-size: 2em;
|
|
|
|
|
}
|
|
|
|
|
.slice:nth-child(even) {
|
|
|
|
|
color: black;
|
|
|
|
|
right: -12rem;
|
|
|
|
|
transform: rotate(v-bind(pieRot)) scale(3);
|
|
|
|
|
transition: transform 30s cubic-bezier(.38,.16,.67,.89);
|
|
|
|
|
}
|
|
|
|
|
.slice::before, .slice::after {
|
|
|
|
|
content: '';
|
|
|
|
|
display: block;
|
|
|
|
|
width: 0;
|
|
|
|
|
height: 0;
|
|
|
|
|
border-style: solid;
|
|
|
|
|
}
|
|
|
|
|
.slice::before {
|
|
|
|
|
margin-bottom: -1px;
|
|
|
|
|
border-width: 0 0 calc(var(--h) / 2) calc(var(--w) * .97);
|
|
|
|
|
border-color: transparent transparent #0074D9 transparent;
|
|
|
|
|
}
|
|
|
|
|
.slice:nth-child(even)::before {
|
|
|
|
|
border-color: transparent transparent #2ECC40 transparent;
|
|
|
|
|
}
|
|
|
|
|
.slice::after {
|
|
|
|
|
border-width: 0 calc(var(--w) * .97) calc(var(--h) / 2) 0;
|
|
|
|
|
border-color: transparent #0074D9 transparent transparent;
|
|
|
|
|
}
|
|
|
|
|
.slice:nth-child(even)::after {
|
|
|
|
|
border-color: transparent #2ECC40 transparent transparent;
|
|
|
|
|
.label {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: calc(50% - .5em);
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 50%;
|
|
|
|
|
height: 1em;
|
|
|
|
|
padding-left: 1em;
|
|
|
|
|
line-height: 1em;
|
|
|
|
|
transform-origin: center right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.slice > div {
|
|
|
|
|
.slice {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
align-items: center;
|
|
|
|
|
width: 85%;
|
|
|
|
|
top: -50%;
|
|
|
|
|
right: -50%;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
transform-origin: 0% 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
border: 1px solid black;
|
|
|
|
|
}
|
|
|
|
|
.slice:nth-child(n) { background-color: #555; }
|
|
|
|
|
.slice:nth-child(2n) { background-color: #55A; }
|
|
|
|
|
.slice:nth-child(3n) { background-color: #A55; }
|
|
|
|
|
.slice:nth-child(4n) { background-color: #AA5; }
|
|
|
|
|
.slice:nth-child(5n) { background-color: #A5A; }
|
|
|
|
|
.slice:nth-child(6n) { background-color: #5AA; }
|
|
|
|
|
.slice:nth-child(7n) { background-color: #999; }
|
|
|
|
|
</style>
|
|
|
|
|