~koehr/raffle-me-that

b8f9b918d401d855b4ad74115d68b522422e5b4c — Norman Köhring 1 year, 9 months ago fda9a2a main
fixes the wheel
5 files changed, 82 insertions(+), 85 deletions(-)

M src/assets/base.css
M src/composables/useRaffle.ts
M src/pages/Home.vue
M src/pages/Raffle.vue
M src/types.d.ts
M src/assets/base.css => src/assets/base.css +1 -1
@@ 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 {

M src/composables/useRaffle.ts => src/composables/useRaffle.ts +1 -0
@@ 15,6 15,7 @@ export default function useRaffle() {
    title: '',
    date: new Date().toLocaleDateString('de'),
    participants: [],
    description: '',
  })

  const newParticipant = ref('')

M src/pages/Home.vue => src/pages/Home.vue +9 -2
@@ 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">

M src/pages/Raffle.vue => src/pages/Raffle.vue +70 -82
@@ 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>

M src/types.d.ts => src/types.d.ts +1 -0
@@ 4,6 4,7 @@ declare global {
    title: string
    date: string
    participants: string[]
    description: string
  }
}