137 lines
10 KiB
TypeScript
137 lines
10 KiB
TypeScript
import { computed, onBeforeUnmount, ref, type ComputedRef, type Ref } from 'vue'
|
|
|
|
import type { HomeDisplayCategory, HomePreviewPhase } from './homeLandingTypes'
|
|
|
|
export function useHomePhasePresentation(params: {
|
|
previewPhase: Ref<HomePreviewPhase>
|
|
displayCategories: ComputedRef<HomeDisplayCategory[]>
|
|
candidateCount: ComputedRef<number>
|
|
publicStreamUrl: ComputedRef<string>
|
|
showDate: ComputedRef<string>
|
|
showStartsAt: ComputedRef<string>
|
|
currentYear: ComputedRef<string>
|
|
formatRange: (key: 'nomination' | 'voting' | 'preparation') => string
|
|
formatShowDate: () => string
|
|
}) {
|
|
const {
|
|
previewPhase,
|
|
displayCategories,
|
|
candidateCount,
|
|
publicStreamUrl,
|
|
showDate,
|
|
showStartsAt,
|
|
currentYear,
|
|
formatRange,
|
|
formatShowDate,
|
|
} = params
|
|
|
|
const nominationPhase = computed(() => previewPhase.value === 'nomination')
|
|
const votingPhase = computed(() => previewPhase.value === 'voting')
|
|
const preparationPhase = computed(() => previewPhase.value === 'preparation')
|
|
const showPhase = computed(() => previewPhase.value === 'show')
|
|
const completedPhase = computed(() => previewPhase.value === 'completed')
|
|
const currentTimestamp = ref(Date.now())
|
|
const ticker = setInterval(() => {
|
|
currentTimestamp.value = Date.now()
|
|
}, 1000)
|
|
onBeforeUnmount(() => clearInterval(ticker))
|
|
const showCountdown = computed(() => true)
|
|
const showStartMs = computed(() => parseShowStartMs(showDate.value, showStartsAt.value))
|
|
const streamLive = computed(() => showPhase.value && !Number.isNaN(showStartMs.value) && currentTimestamp.value >= showStartMs.value)
|
|
const streamLocked = computed(() => !streamLive.value)
|
|
const phaseCardTitle = computed(() => completedPhase.value ? 'Award-Jahr abgeschlossen' : nominationPhase.value ? 'Community Nominierung' : votingPhase.value ? 'Community Voting' : preparationPhase.value ? 'Aufbereitung bis zur Show' : 'Award Show Live')
|
|
const phaseCardDescription = computed(() => completedPhase.value ? 'Die grosse Award-Show ist beendet. Das Jahr ist abgeschlossen und alle Teilnahme-Aktionen sind gesperrt.' : nominationPhase.value ? 'Die Nominierungsphase läuft gerade. Reiche deine Favoriten und Highlight-Clips ein.' : votingPhase.value ? 'Die Nominierungsphase ist abgeschlossen.\nJetzt liegt es an dir: Stimme für deine Favoriten!' : preparationPhase.value ? 'Das Voting ist abgeschlossen. Das Team bereitet Clips, Ablauf und Gewinner-Momente für die Show vor.' : 'Die Award-Show läuft jetzt live. Zeit für Bühne, Gewinner:innen und ganz viel Glitzer.')
|
|
const phaseCardRange = computed(() => completedPhase.value ? `Finale abgeschlossen · ${formatShowDate()}` : nominationPhase.value ? `Nominierungszeitraum · ${formatRange('nomination')}` : votingPhase.value ? `Voting-Zeitraum · ${formatRange('voting')}` : preparationPhase.value ? `Aufbereitungszeit · ${formatRange('preparation')}` : `Live · ${formatShowDate()} · ${formatTimeLabel(showStartsAt.value)} Uhr`)
|
|
const phaseStatusLabel = computed(() => completedPhase.value ? 'ABGESCHLOSSEN' : streamLive.value ? 'LIVE' : showPhase.value ? 'STARTET BALD' : preparationPhase.value ? 'IN AUFBEREITUNG' : 'AKTIV')
|
|
const phaseStatusStyle = computed(() => completedPhase.value ? 'display:inline-flex;align-items:center;gap:5px;padding:4px 11px;border-radius:999px;background:#f1ecfb;color:#8b6cdb;font-size:11px;font-weight:700;letter-spacing:.5px;' : showPhase.value ? 'display:inline-flex;align-items:center;gap:5px;padding:4px 11px;border-radius:999px;background:#ffe5ec;color:#ec3b5a;font-size:11px;font-weight:700;letter-spacing:.5px;' : preparationPhase.value ? 'display:inline-flex;align-items:center;gap:5px;padding:4px 11px;border-radius:999px;background:#fff1d6;color:#b7791f;font-size:11px;font-weight:700;letter-spacing:.5px;' : 'display:inline-flex;align-items:center;gap:5px;padding:4px 11px;border-radius:999px;background:#e3f7ec;color:#1f9d5a;font-size:11px;font-weight:700;letter-spacing:.5px;')
|
|
const phasePrimaryLabel = computed(() => completedPhase.value ? '✦ Award beendet' : nominationPhase.value ? '✦ Nominieren & Clip' : votingPhase.value ? '★ Jetzt voten' : preparationPhase.value ? '✦ Show wird vorbereitet' : '● Zum Live-Stream')
|
|
const phasePrimaryDisabled = computed(() => preparationPhase.value || completedPhase.value)
|
|
const phasePrimaryActionStyle = computed(() => phasePrimaryDisabled.value
|
|
? 'display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:15px 18px;border-radius:13px;background:#eee7f8;color:#9b8abf;border:none;text-decoration:none;font-family:\'Outfit\',sans-serif;font-weight:600;font-size:15px;box-shadow:none;cursor:not-allowed;'
|
|
: 'display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:15px 18px;border-radius:13px;background:linear-gradient(135deg,#8b6cdb,#7355c8);color:#fff;border:none;text-decoration:none;font-family:\'Outfit\',sans-serif;font-weight:600;font-size:15px;box-shadow:0 10px 22px rgba(124,86,196,.32);cursor:pointer;')
|
|
const streamEyebrow = computed(() => 'Das grosse Finale')
|
|
const streamTitle = computed(() => 'Award-Show Countdown')
|
|
const streamMeta = computed(() => `Finale am ${formatShowDate()} · ${formatTimeLabel(showStartsAt.value)} Uhr`)
|
|
const streamLockedLabel = computed(() => completedPhase.value ? 'Award abgeschlossen' : 'Stream noch gesperrt')
|
|
const streamLockedTitle = computed(() => completedPhase.value ? 'Die Award-Show ist beendet' : 'Verfügbar, sobald die Show startet')
|
|
const statOneValue = computed(() => completedPhase.value ? 'DONE' : streamLive.value ? 'LIVE' : String(candidateCount.value))
|
|
const statOneLabel = computed(() => completedPhase.value ? 'Jahr-Status' : showPhase.value ? 'Show-Status' : 'Kandidat:innen')
|
|
const statTwoValue = computed(() => String(displayCategories.value.length))
|
|
const statThreeValue = computed(() => currentYear.value || '—')
|
|
const statThreeLabel = computed(() => 'Award-Jahr')
|
|
const categoryIntroText = computed(() => {
|
|
const count = displayCategories.value.length
|
|
const countLabel = count === 1 ? 'Eine Kategorie' : `${count || 'Alle'} Kategorien`
|
|
return `${countLabel}, eine Show, eine Szene. Stimm für deine Lieblings-VTuber ab und sei live dabei, wenn die Gewinner feststehen.`
|
|
})
|
|
const timelineLineStyle = computed(() => nominationPhase.value
|
|
? 'position:absolute;top:27px;left:10%;right:10%;height:3px;background:linear-gradient(90deg,#e2d6f4 0%,#e2d6f4 100%);border-radius:3px;z-index:0;'
|
|
: votingPhase.value
|
|
? 'position:absolute;top:27px;left:10%;right:10%;height:3px;background:linear-gradient(90deg,#8b6cdb 0%,#8b6cdb 33.33%,#e2d6f4 33.33%,#e2d6f4 100%);border-radius:3px;z-index:0;'
|
|
: preparationPhase.value
|
|
? 'position:absolute;top:27px;left:10%;right:10%;height:3px;background:linear-gradient(90deg,#8b6cdb 0%,#8b6cdb 66.66%,#e2d6f4 66.66%,#e2d6f4 100%);border-radius:3px;z-index:0;'
|
|
: 'position:absolute;top:27px;left:10%;right:10%;height:3px;background:linear-gradient(90deg,#8b6cdb 0%,#8b6cdb 100%,#e2d6f4 100%,#e2d6f4 100%);border-radius:3px;z-index:0;')
|
|
const sectionTitle = computed(() => completedPhase.value ? 'Das Award-Jahr ist abgeschlossen ✦' : nominationPhase.value ? 'Jetzt Highlights und Favoriten einreichen ✦' : votingPhase.value ? 'Meine Favoriten unterstützen ⭐' : preparationPhase.value ? 'Die Show wird vorbereitet ✦' : 'Die Gewinner werden jetzt live gekürt ✦')
|
|
const sectionText = computed(() => completedPhase.value ? 'Danke an alle, die nominiert, abgestimmt und live mitgefiebert haben. Die nächsten Aktionen sind gesperrt, bis ein neues Award-Jahr startet.' : nominationPhase.value ? 'Reiche deine Lieblingsmomente ein und hilf mit, die stärksten Clips und spannendsten Namen in die Show zu bringen.' : votingPhase.value ? 'Jede Stimme erzählt eine Geschichte. Unterstütze die Creator, die dich zum Lachen, Staunen und Mitfiebern bringen.' : preparationPhase.value ? 'Die Community hat abgestimmt. Jetzt bereitet das Team Clips, Ablauf und Show-Momente für die Award-Nacht vor.' : 'Die Bühne ist offen. Schau live zu, wie die Stars der Szene ausgezeichnet werden und die besten Momente gezeigt werden.')
|
|
const sectionActionLabel = computed(() => completedPhase.value ? 'Award-Jahr abgeschlossen' : nominationPhase.value ? 'Nominieren & Clip einreichen' : votingPhase.value ? 'Mit Twitch anmelden & voten' : preparationPhase.value ? 'Aufbereitung läuft' : 'Zum Live-Stream')
|
|
const sectionActionHref = computed(() => showPhase.value ? publicStreamUrl.value : '#')
|
|
const sectionActionDisabled = computed(() => preparationPhase.value || completedPhase.value)
|
|
const sectionActionStyle = computed(() => sectionActionDisabled.value
|
|
? 'display:inline-flex;align-items:center;gap:11px;padding:17px 38px;border-radius:14px;background:rgba(255,255,255,.72);color:#9b8abf;text-decoration:none;font-family:\'Outfit\',sans-serif;font-weight:700;font-size:18px;box-shadow:none;cursor:not-allowed;border:none;'
|
|
: nominationPhase.value
|
|
? 'display:inline-flex;align-items:center;gap:11px;padding:17px 38px;border-radius:14px;background:#fff;color:#e855a5;text-decoration:none;font-family:\'Outfit\',sans-serif;font-weight:700;font-size:18px;box-shadow:0 14px 34px rgba(0,0,0,.22);'
|
|
: 'display:inline-flex;align-items:center;gap:11px;padding:17px 38px;border-radius:14px;background:#fff;color:#7a3fd0;text-decoration:none;font-family:\'Outfit\',sans-serif;font-weight:700;font-size:18px;box-shadow:0 14px 34px rgba(0,0,0,.22);')
|
|
|
|
return {
|
|
nominationPhase,
|
|
votingPhase,
|
|
preparationPhase,
|
|
showPhase,
|
|
completedPhase,
|
|
showCountdown,
|
|
streamLive,
|
|
streamLocked,
|
|
phaseCardTitle,
|
|
phaseCardDescription,
|
|
phaseCardRange,
|
|
phaseStatusLabel,
|
|
phaseStatusStyle,
|
|
phasePrimaryLabel,
|
|
phasePrimaryDisabled,
|
|
phasePrimaryActionStyle,
|
|
streamEyebrow,
|
|
streamTitle,
|
|
streamMeta,
|
|
streamLockedLabel,
|
|
streamLockedTitle,
|
|
statOneValue,
|
|
statOneLabel,
|
|
statTwoValue,
|
|
statThreeValue,
|
|
statThreeLabel,
|
|
categoryIntroText,
|
|
timelineLineStyle,
|
|
sectionTitle,
|
|
sectionText,
|
|
sectionActionLabel,
|
|
sectionActionHref,
|
|
sectionActionDisabled,
|
|
sectionActionStyle,
|
|
}
|
|
}
|
|
|
|
function parseShowStartMs(showDate: string, showStartsAt: string) {
|
|
if (!showDate) return Number.NaN
|
|
const time = normalizeTime(showStartsAt)
|
|
return new Date(`${showDate}T${time}`).getTime()
|
|
}
|
|
|
|
function normalizeTime(value: string) {
|
|
if (!value) return '20:00:00'
|
|
return value.length === 5 ? `${value}:00` : value
|
|
}
|
|
|
|
function formatTimeLabel(value: string) {
|
|
return normalizeTime(value).slice(0, 5)
|
|
}
|