M src/assets/base.css => src/assets/base.css +2 -2
@@ 3,12 3,12 @@
@tailwind utilities;
body {
- @apply min-h-screen bg-slate-900 text-slate-100 leading-relaxed;
+ @apply min-h-screen m-0 p-0 bg-slate-900 text-slate-100 leading-relaxed;
transition: color 0.3s, background-color 0.2s;
}
#app {
- @apply flex justify-around items-center w-screen min-h-screen m-0 p-4;
+ @apply flex justify-around items-center w-screen min-h-screen;
}
button, input {
M src/composables/useRaffle.ts => src/composables/useRaffle.ts +1 -0
@@ 11,6 11,7 @@ export default function useRaffle() {
const raffleStore = useStorage<Raffle[]>('', EMPTY_STORE)
const newRaffle = ref<Raffle>({
+ id: genId(),
title: '',
date: new Date().toLocaleDateString('de'),
participants: [],
M src/pages/Home.vue => src/pages/Home.vue +16 -1
@@ 1,5 1,6 @@
<script setup lang="ts">
import { useHead } from '@vueuse/head'
+import { useRouter } from 'vue-router'
import useRaffle from '../composables/useRaffle'
useHead({
@@ 19,13 20,27 @@ const showNewRaffleForm = $ref(false)
function startRaffle() {
if (!readyToRaffle) return
- //
+
+ raffleStore.value.push(newRaffle.value)
+ const router = useRouter()
+ router.push(`/raffle/${newRaffle.value.id}`)
}
</script>
<template>
<header>
<h1 class="text-4xl">Raffle Me That!</h1>
+
+ <div class="mt-8" v-if="raffleStore.length">
+ <strong>Select Existing:</strong>
+ <ul>
+ <li v-for="raffle in raffleStore">
+ <router-link :to="`/raffle/${raffle.id}`">
+ {{ raffle.title }}
+ </router-link>
+ </li>
+ </ul>
+ </div>
</header>
<main>
M src/pages/Raffle.vue => src/pages/Raffle.vue +107 -2
@@ 1,6 1,111 @@
<script setup lang="ts">
+import { onMounted } from 'vue'
import { useHead } from '@vueuse/head'
-useHead({
- title: 'Lets go!',
+import { useStorage } from '@vueuse/core'
+import { useRoute } from 'vue-router'
+
+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
+}
+
+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>
+</template>
+
+<style scoped>
+.shifted {
+ transform: translateX(-100%);
+}
+.aligned {
+ transform: translateX(0);
+}
+.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%;
+ height: 100%;
+}
+</style>
M src/types.d.ts => src/types.d.ts +1 -0
@@ 1,5 1,6 @@
declare global {
type Raffle = {
+ id: string
title: string
date: string
participants: string[]