04191193c2
Add a standalone bilingual /coming-soon page (branded, dark, email signup via mailto:info@dezky.eu, fires a waitlist-signup Umami event, noindex) plus a global middleware that redirects every route to the locale-correct holding page while NUXT_PUBLIC_COMING_SOON=true. - Env-gated (default off, so dev and the live site are unaffected); flip the env in Coolify to show/hide the holding page with no code change. - Preview the real site behind the gate via ?preview=<previewToken> (NUXT_PUBLIC_PREVIEW_TOKEN), which sets a 7-day cookie. - Locale-preserving redirects (/da/* -> /da/coming-soon), no loops.
80 lines
4.4 KiB
Vue
80 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
// Gated "coming soon" holding page. Shown for every route while
|
|
// NUXT_PUBLIC_COMING_SOON=true (see middleware/coming-soon.global.ts). Interim
|
|
// signup composes an email to info@dezky.eu — swap for a real list later.
|
|
import { ref } from 'vue'
|
|
import { C } from '~/utils/landingTokens'
|
|
import { useCopy, useLang, track } from '~/composables/useLanding'
|
|
|
|
definePageMeta({ layout: false })
|
|
|
|
const copy = useCopy()
|
|
const lang = useLang()
|
|
const c = computed(() => copy.value.waitlist)
|
|
const switchLocalePath = useSwitchLocalePath()
|
|
|
|
const email = ref('')
|
|
function submit() {
|
|
const subject = lang.value === 'da' ? 'Skriv mig op til dezky' : 'Add me to the dezky waitlist'
|
|
const body = lang.value === 'da'
|
|
? `Skriv mig op til ventelisten: ${email.value}`
|
|
: `Please add me to the waitlist: ${email.value}`
|
|
track('waitlist-signup')
|
|
window.location.href = `mailto:info@dezky.eu?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`
|
|
}
|
|
|
|
function segStyle(code: 'en' | 'da') {
|
|
const active = lang.value === code
|
|
return {
|
|
padding: '5px 9px', border: 'none', cursor: 'pointer', borderRadius: '3px',
|
|
fontFamily: '\'JetBrains Mono\', monospace', fontSize: '11px', letterSpacing: '0.08em',
|
|
background: active ? C.bone : 'transparent',
|
|
color: active ? C.carbon : 'rgba(244,243,238,0.6)',
|
|
fontWeight: active ? 700 : 500,
|
|
}
|
|
}
|
|
|
|
useHead({
|
|
title: () => (lang.value === 'da' ? 'dezky — snart klar' : 'dezky — coming soon'),
|
|
meta: [{ name: 'robots', content: 'noindex, nofollow' }],
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div :style="{ minHeight: '100vh', background: C.carbon, color: C.bone, display: 'flex', flexDirection: 'column', padding: 'clamp(24px, 5vw, 56px)' }">
|
|
<!-- Top bar: wordmark + language switcher -->
|
|
<div :style="{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }">
|
|
<div :style="{ display: 'flex', alignItems: 'center', gap: '12px' }">
|
|
<BrandNodeMark :size="32" :fg="C.signal" :accent="C.carbon" />
|
|
<span :style="{ fontFamily: '\'JetBrains Mono\', monospace', fontWeight: 600, fontSize: '16px', letterSpacing: '-0.02em' }">dezky</span>
|
|
</div>
|
|
<div :style="{ display: 'inline-flex', alignItems: 'center', gap: '2px', border: '1px solid rgba(244,243,238,0.2)', borderRadius: '5px', padding: '2px' }">
|
|
<NuxtLink :to="switchLocalePath('en')" :style="segStyle('en')">EN</NuxtLink>
|
|
<NuxtLink :to="switchLocalePath('da')" :style="segStyle('da')">DA</NuxtLink>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Center -->
|
|
<div :style="{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', maxWidth: '620px' }">
|
|
<div :style="{ fontFamily: '\'JetBrains Mono\', monospace', fontSize: '12px', letterSpacing: '0.18em', textTransform: 'uppercase', color: C.signal }">{{ c.eyebrow }}</div>
|
|
<h1 :style="{ fontFamily: '\'Inter Tight\', sans-serif', fontWeight: 600, fontSize: 'clamp(40px, 8vw, 84px)', letterSpacing: '-0.04em', lineHeight: 0.98, margin: '20px 0 0', textWrap: 'balance' }">{{ c.heading }}</h1>
|
|
<p :style="{ fontFamily: '\'Inter\', sans-serif', fontSize: 'clamp(16px, 2.4vw, 19px)', lineHeight: 1.55, color: 'rgba(244,243,238,0.72)', margin: '28px 0 0', textWrap: 'pretty' }">{{ c.body }}</p>
|
|
|
|
<form @submit.prevent="submit" :style="{ display: 'flex', gap: '12px', marginTop: '40px', flexWrap: 'wrap', maxWidth: '480px' }">
|
|
<input
|
|
v-model="email" type="email" required :placeholder="c.emailPh"
|
|
:style="{ flex: 1, minWidth: '220px', padding: '15px 18px', borderRadius: '4px', border: '1px solid rgba(244,243,238,0.2)', background: 'rgba(244,243,238,0.05)', color: C.bone, fontFamily: '\'Inter\', sans-serif', fontSize: '15px', boxSizing: 'border-box' }"
|
|
>
|
|
<button
|
|
type="submit"
|
|
:style="{ background: C.signal, color: C.carbon, border: 'none', padding: '15px 26px', fontFamily: '\'Inter\', sans-serif', fontSize: '15px', fontWeight: 600, borderRadius: '4px', cursor: 'pointer', whiteSpace: 'nowrap' }"
|
|
>{{ c.submit }} →</button>
|
|
</form>
|
|
<p :style="{ fontFamily: '\'Inter\', sans-serif', fontSize: '13px', color: 'rgba(244,243,238,0.45)', margin: '16px 0 0' }">{{ c.note }}</p>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div :style="{ fontFamily: '\'JetBrains Mono\', monospace', fontSize: '11px', color: 'rgba(244,243,238,0.4)' }">dezky.eu · info@dezky.eu</div>
|
|
</div>
|
|
</template>
|