diff --git a/src/assets/base.css b/src/assets/base.css index 41a9ed5..8a3b008 100644 --- a/src/assets/base.css +++ b/src/assets/base.css @@ -8,7 +8,7 @@ body { } #app { - @apply flex justify-around items-center w-screen min-h-screen; + @apply flex justify-around items-center w-screen h-screen overflow-hidden; } button, input { diff --git a/src/composables/useRaffle.ts b/src/composables/useRaffle.ts index f98f929..56b5553 100644 --- a/src/composables/useRaffle.ts +++ b/src/composables/useRaffle.ts @@ -15,6 +15,7 @@ export default function useRaffle() { title: '', date: new Date().toLocaleDateString('de'), participants: [], + description: '', }) const newParticipant = ref('') diff --git a/src/pages/Home.vue b/src/pages/Home.vue index b8f4b46..cdca904 100644 --- a/src/pages/Home.vue +++ b/src/pages/Home.vue @@ -17,12 +17,12 @@ const { } = useRaffle() const showNewRaffleForm = $ref(false) +const router = useRouter() function startRaffle() { if (!readyToRaffle) return raffleStore.value.push(newRaffle.value) - const router = useRouter() router.push(`/raffle/${newRaffle.value.id}`) } </script> @@ -47,12 +47,19 @@ function startRaffle() { <div class="text-xl" v-if="showNewRaffleForm"> <input - class="w-full mb-16" + class="w-full mb-8" placeholder="Amazing Raffle Title" :class="{ 'border-transparent': newRaffle.title.length }" v-model="newRaffle.title" /> + <input + class="w-full mb-16" + placeholder="Some description" + :class="{ 'border-transparent': newRaffle.title.length }" + v-model="newRaffle.description" + /> + <section> <ul> <li class="flex justify-between items-center mb-1" v-for="(p, i) in newRaffle.participants"> diff --git a/src/pages/Raffle.vue b/src/pages/Raffle.vue index e377a8b..a6980ea 100644 --- a/src/pages/Raffle.vue +++ b/src/pages/Raffle.vue @@ -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 participants = $computed(() => { - return raffle ? raffle.participants : [] -}) - -const amount = $computed(() => participants.length) -let aligned = $ref(false) // used for animation - -function degrees(index: number) { - if (!aligned) return 0 - return (360 / amount) * index -} +const raffle = $computed(() => raffleStore.value.find(r => r.id === raffleId)) useHead({ title: raffle ? raffle.title : 'Lets Go' }) -onMounted(() => { - setTimeout(() => { - aligned = true - }, 100) +const items = $computed(() => { + return raffle ? raffle.participants : [] }) + +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 roll() { + if (rollRot) rollRot = 0 + else { + const winner = Math.round(Math.random() * items.length) + rollRot = 3600 + sliceRot * winner + } +} </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%); +.pie { + position: absolute; + right: -12rem; + transform: rotate(v-bind(pieRot)) scale(3); + transition: transform 30s cubic-bezier(.38,.16,.67,.89); } -.aligned { - transform: translateX(0); +.label { + position: absolute; + top: calc(50% - .5em); + left: 0; + width: 50%; + height: 1em; + padding-left: 1em; + line-height: 1em; + transform-origin: center right; } .slice { - --w: 50vw; - --h: calc(6.283185307179586 * var(--w) / v-bind(amount)); 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; -} -.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; -} - -.slice > div { - 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> diff --git a/src/types.d.ts b/src/types.d.ts index 4e02333..2cd0d59 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -4,6 +4,7 @@ declare global { title: string date: string participants: string[] + description: string } }