Skip to content

Commit d12ea73

Browse files
userquindanielroe
andcommitted
chore: merge vacations page
Co-authored-by: Daniel Roe <daniel@roe.dev>
1 parent ea9e429 commit d12ea73

5 files changed

Lines changed: 551 additions & 56 deletions

File tree

app/pages/vacations.vue

Lines changed: 275 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,297 @@
11
<script setup lang="ts">
22
definePageMeta({
33
name: 'vacations',
4-
layout: 'default',
54
})
65
76
useSeoMeta({
8-
title: 'Vacations - npmx',
9-
description: 'The npmx team is taking a well-deserved break after an incredible sprint!',
7+
title: () => `${$t('vacations.title')} - npmx`,
8+
description: () => $t('vacations.meta_description'),
9+
ogTitle: () => `${$t('vacations.title')} - npmx`,
10+
ogDescription: () => $t('vacations.meta_description'),
11+
twitterTitle: () => `${$t('vacations.title')} - npmx`,
12+
twitterDescription: () => $t('vacations.meta_description'),
1013
})
1114
12-
const stats = [
13-
{ label: 'Contributors', value: '150+' },
14-
{ label: 'Commits', value: '1.1k+' },
15-
{ label: 'PRs Merged', value: '944' },
16-
]
15+
defineOgImageComponent('Default', {
16+
title: () => $t('vacations.title'),
17+
description: () => $t('vacations.meta_description'),
18+
})
19+
20+
const router = useRouter()
21+
const canGoBack = useCanGoBack()
22+
23+
// --- Cosy fireplace easter egg ---
24+
const logClicks = ref(0)
25+
const fireVisible = ref(false)
26+
function pokeLog() {
27+
logClicks.value++
28+
if (logClicks.value >= 3) {
29+
fireVisible.value = true
30+
}
31+
}
32+
33+
// Icons that tile across the banner, repeating to fill.
34+
// Classes must be written out statically so UnoCSS can detect them at build time.
35+
const icons = [
36+
'i-carbon:snowflake',
37+
'i-carbon:mountain',
38+
'i-carbon:tree',
39+
'i-carbon:cafe',
40+
'i-carbon:book',
41+
'i-carbon:music',
42+
'i-carbon:snowflake',
43+
'i-carbon:star',
44+
'i-carbon:moon',
45+
] as const
46+
47+
// --- .ics calendar reminder ---
48+
// Pick a random daytime hour (9–17) in the user's local timezone on Feb 22
49+
// so reminders are staggered and people don't all flood in at once.
50+
function downloadIcs() {
51+
const hour = 9 + Math.floor(Math.random() * 9) // 9..17
52+
const start = new Date(2026, 1, 22, hour, 0, 0) // month is 0-indexed
53+
const end = new Date(2026, 1, 22, hour + 1, 0, 0)
54+
55+
// Format as UTC for the .ics file
56+
const fmt = (d: Date) =>
57+
d
58+
.toISOString()
59+
.replace(/[-:]/g, '')
60+
.replace(/\.\d{3}/, '')
61+
62+
const uid = `npmx-vacations-${start.getTime()}@npmx.dev`
63+
64+
const ics = [
65+
'BEGIN:VCALENDAR',
66+
'VERSION:2.0',
67+
'PRODID:-//npmx//vacations//EN',
68+
'BEGIN:VEVENT',
69+
`DTSTART:${fmt(start)}`,
70+
`DTEND:${fmt(end)}`,
71+
`SUMMARY:npmx Discord is back!`,
72+
`DESCRIPTION:The npmx team is back from vacation. Time to rejoin! https://chat.npmx.dev`,
73+
'STATUS:CONFIRMED',
74+
`UID:${uid}`,
75+
'END:VEVENT',
76+
'END:VCALENDAR',
77+
].join('\r\n')
78+
79+
const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })
80+
const url = URL.createObjectURL(blob)
81+
const a = document.createElement('a')
82+
a.href = url
83+
a.download = 'npmx-discord-reminder.ics'
84+
a.click()
85+
URL.revokeObjectURL(url)
86+
}
87+
88+
const stats = {
89+
weeks: '4',
90+
contributors: '160+',
91+
commits: '1.1k+',
92+
pr: '900+',
93+
}
1794
</script>
1895

1996
<template>
20-
<main
21-
class="container flex-1 flex flex-col items-center justify-center py-20 sm:py-32 text-center"
22-
>
23-
<div class="max-w-2xl mx-auto space-y-8">
24-
<!-- Icon / Illustration -->
25-
<div class="relative inline-block">
26-
<div class="absolute inset-0 bg-accent/20 blur-3xl rounded-full" aria-hidden="true" />
27-
<span class="relative text-8xl sm:text-9xl animate-bounce-slow inline-block">🏖️</span>
28-
</div>
29-
30-
<!-- Title -->
31-
<div class="space-y-4">
32-
<h1 class="font-mono text-4xl sm:text-5xl font-bold text-fg">
33-
We are <span class="text-accent">recharging</span>
34-
</h1>
35-
<p class="text-lg sm:text-xl text-fg-muted max-w-lg mx-auto leading-relaxed">
36-
After 3 weeks of intense coding, 150+ contributors, and over 1,100 commits, the npmx team
37-
is taking a short break.
38-
</p>
39-
</div>
97+
<main class="container flex-1 py-12 sm:py-16 overflow-x-hidden max-w-full">
98+
<article class="max-w-2xl mx-auto">
99+
<header class="mb-12">
100+
<div class="max-w-2xl mx-auto py-8 bg-none flex justify-center">
101+
<!-- Icon / Illustration -->
102+
<div class="relative inline-block">
103+
<div class="absolute inset-0 bg-accent/20 blur-3xl rounded-full" aria-hidden="true" />
104+
<span class="relative text-8xl sm:text-9xl animate-bounce-slow inline-block">🏖️</span>
105+
</div>
106+
</div>
107+
<div class="flex items-baseline justify-between gap-4 mb-4">
108+
<h1 class="font-mono text-3xl sm:text-4xl font-medium">
109+
{{ $t('vacations.heading') }}
110+
</h1>
111+
<button
112+
type="button"
113+
class="cursor-pointer inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
114+
@click="router.back()"
115+
v-if="canGoBack"
116+
>
117+
<span class="i-carbon:arrow-left rtl-flip w-4 h-4" aria-hidden="true" />
118+
<span class="sr-only sm:not-sr-only">{{ $t('nav.back') }}</span>
119+
</button>
120+
</div>
121+
<i18n-t
122+
keypath="vacations.subtitle"
123+
tag="p"
124+
scope="global"
125+
class="text-fg-muted text-lg sm:text-xl"
126+
>
127+
<template #weeks>
128+
{{ $t('vacations.stats.subtitle.weeks', [stats.weeks]) }}
129+
</template>
130+
<template #contributors>
131+
{{ $t('vacations.stats.subtitle.contributors', [stats.contributors]) }}
132+
</template>
133+
<template #commits>
134+
{{ $t('vacations.stats.subtitle.commits', [stats.commits]) }}
135+
</template>
136+
<template #npmx>
137+
<strong>npmx</strong>
138+
</template>
139+
</i18n-t>
140+
</header>
40141

41-
<!-- Stats Grid -->
42-
<div class="grid grid-cols-3 gap-4 sm:gap-8 py-8 border-y border-border/50">
43-
<div v-for="stat in stats" :key="stat.label" class="space-y-1">
44-
<div class="font-mono text-2xl sm:text-3xl font-bold text-fg">{{ stat.value }}</div>
142+
<div
143+
class="grid grid-cols-3 justify-center gap-4 sm:gap-8 mb-8 py-8 border-y border-border/50"
144+
>
145+
<div class="space-y-1 text-center">
146+
<div class="font-mono text-2xl sm:text-3xl font-bold text-fg">
147+
{{ stats.contributors }}
148+
</div>
149+
<div class="text-xs sm:text-sm text-fg-subtle uppercase tracking-wider">
150+
{{ $t('vacations.stats.contributors') }}
151+
</div>
152+
</div>
153+
<div class="space-y-1 text-center">
154+
<div class="font-mono text-2xl sm:text-3xl font-bold text-fg">{{ stats.commits }}</div>
155+
<div class="text-xs sm:text-sm text-fg-subtle uppercase tracking-wider">
156+
{{ $t('vacations.stats.commits') }}
157+
</div>
158+
</div>
159+
<div class="space-y-1 text-center">
160+
<div class="font-mono text-2xl sm:text-3xl font-bold text-fg">{{ stats.pr }}</div>
45161
<div class="text-xs sm:text-sm text-fg-subtle uppercase tracking-wider">
46-
{{ stat.label }}
162+
{{ $t('vacations.stats.pr') }}
47163
</div>
48164
</div>
49165
</div>
50166

51-
<!-- Message -->
52-
<div class="space-y-6">
53-
<p class="text-fg-muted">
54-
We'll be back soon to continue building the best package explorer for the community.
55-
<br class="hidden sm:block" />
56-
Thank you for being part of this incredible journey!
57-
</p>
58-
59-
<div class="flex items-center justify-center gap-4">
60-
<ButtonBase to="/" variant="primary" size="medium" classicon="i-carbon:home">
61-
Back to Home
62-
</ButtonBase>
63-
<ButtonBase
64-
href="https://github.com/npmx-dev/npmx.dev"
65-
target="_blank"
66-
rel="noopener noreferrer"
67-
variant="secondary"
68-
size="medium"
69-
classicon="i-carbon:logo-github"
70-
>
71-
Star on GitHub
72-
</ButtonBase>
167+
<!-- Icon banner — a single row of cosy icons, clipped to fill width -->
168+
<div
169+
class="relative mb-12 px-4 border border-border rounded-lg bg-bg-subtle overflow-hidden select-none"
170+
:aria-label="$t('vacations.illustration_alt')"
171+
role="img"
172+
>
173+
<div class="flex items-center gap-4 sm:gap-5 py-3 sm:py-4 w-max">
174+
<template v-for="n in 4" :key="`set-${n}`">
175+
<!-- Campsite icon — click it 3x to light the fire -->
176+
<button
177+
type="button"
178+
class="relative shrink-0 cursor-pointer rounded transition-transform duration-200 hover:scale-110 focus-visible:outline-accent/70 w-5 h-5 sm:w-6 sm:h-6"
179+
:aria-label="$t('vacations.poke_log')"
180+
@click="pokeLog"
181+
>
182+
<span
183+
class="absolute inset-0 i-carbon:fire w-5 h-5 sm:w-6 sm:h-6 text-orange-400 transition-opacity duration-400"
184+
:class="fireVisible ? 'opacity-100' : 'opacity-0'"
185+
/>
186+
<span
187+
class="absolute inset-0 i-carbon:campsite w-5 h-5 sm:w-6 sm:h-6 transition-colors duration-400"
188+
:class="fireVisible ? 'text-amber-700' : ''"
189+
/>
190+
</button>
191+
<span
192+
v-for="(icon, i) in icons"
193+
:key="`${n}-${i}`"
194+
class="shrink-0 w-5 h-5 sm:w-6 sm:h-6 opacity-40"
195+
:class="icon"
196+
/>
197+
</template>
73198
</div>
74199
</div>
75-
</div>
200+
201+
<section class="prose prose-invert max-w-none space-y-8">
202+
<div>
203+
<p class="text-fg-muted leading-relaxed mb-4">
204+
<i18n-t keypath="vacations.intro.p1" tag="span" scope="global">
205+
<template #some>
206+
<span class="line-through decoration-fg">{{ $t('vacations.intro.some') }}</span>
207+
{{ ' ' }}
208+
<strong class="text-fg">{{ $t('vacations.intro.all') }}</strong>
209+
</template>
210+
</i18n-t>
211+
</p>
212+
<p class="text-fg-muted leading-relaxed">
213+
{{ $t('vacations.intro.p2') }}
214+
</p>
215+
</div>
216+
217+
<!-- What's happening -->
218+
<div>
219+
<h2 class="text-lg text-fg-subtle uppercase tracking-wider mb-4">
220+
{{ $t('vacations.what.title') }}
221+
</h2>
222+
<p class="text-fg-muted leading-relaxed mb-4">
223+
<i18n-t keypath="vacations.what.p1" tag="span" scope="global">
224+
<template #dates>
225+
<strong class="text-fg">{{ $t('vacations.what.dates') }}</strong>
226+
</template>
227+
</i18n-t>
228+
</p>
229+
<ul class="space-y-3 text-fg-muted list-none p-0">
230+
<li class="flex items-start gap-3">
231+
<span class="text-fg-subtle shrink-0 mt-1">&mdash;</span>
232+
<span>
233+
<i18n-t keypath="vacations.what.discord" tag="span" scope="global">
234+
<template #garden>
235+
<code class="font-mono text-fg text-sm">{{ $t('vacations.what.garden') }}</code>
236+
</template>
237+
</i18n-t>
238+
</span>
239+
</li>
240+
<li class="flex items-start gap-3">
241+
<span class="text-fg-subtle shrink-0 mt-1">&mdash;</span>
242+
<span>{{ $t('vacations.what.site') }}</span>
243+
</li>
244+
<li class="flex items-start gap-3">
245+
<span class="text-fg-subtle shrink-0 mt-1">&mdash;</span>
246+
<span>{{ $t('vacations.what.repo') }}</span>
247+
</li>
248+
</ul>
249+
</div>
250+
251+
<!-- In the meantime -->
252+
<div>
253+
<h2 class="text-lg text-fg-subtle uppercase tracking-wider mb-4">
254+
{{ $t('vacations.meantime.title') }}
255+
</h2>
256+
<p class="text-fg-muted leading-relaxed mb-4">
257+
<i18n-t keypath="vacations.meantime.p1" tag="span" scope="global">
258+
<template #repo>
259+
<LinkBase to="https://repo.npmx.dev">
260+
{{ $t('vacations.meantime.repo_link') }}
261+
</LinkBase>
262+
</template>
263+
</i18n-t>
264+
</p>
265+
<p class="text-fg-muted leading-relaxed">
266+
{{ $t('vacations.meantime.p2') }}
267+
</p>
268+
</div>
269+
270+
<!-- See you soon -->
271+
<div>
272+
<h2 class="text-lg text-fg-subtle uppercase tracking-wider mb-4">
273+
{{ $t('vacations.return.title') }}
274+
</h2>
275+
<p class="text-fg-muted leading-relaxed mb-4">
276+
{{ $t('vacations.return.p1') }}
277+
</p>
278+
<p class="text-fg-muted leading-relaxed mb-6">
279+
<i18n-t keypath="vacations.return.p2" tag="span" scope="global">
280+
<template #social>
281+
<LinkBase to="https://social.npmx.dev">
282+
{{ $t('vacations.return.social_link') }}
283+
</LinkBase>
284+
</template>
285+
</i18n-t>
286+
</p>
287+
288+
<!-- Add to calendar button -->
289+
<ButtonBase classicon="i-carbon:calendar" @click="downloadIcs">
290+
{{ $t('vacations.return.add_to_calendar') }}
291+
</ButtonBase>
292+
</div>
293+
</section>
294+
</article>
76295
</main>
77296
</template>
78297

0 commit comments

Comments
 (0)