Skip to content

Commit 4061599

Browse files
committed
feat: configure noodles infra
1 parent f88bbcb commit 4061599

File tree

7 files changed

+212
-78
lines changed

7 files changed

+212
-78
lines changed

app/components/ColorScheme/Img.vue

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script setup lang="ts">
2+
const props = defineProps<{
3+
lightSrc: string
4+
darkSrc: string
5+
}>()
6+
</script>
7+
8+
<template>
9+
<img
10+
:src="props.darkSrc"
11+
class="color-mode-img"
12+
:style="`--light-src: url('${props.lightSrc}')`"
13+
/>
14+
</template>
15+
16+
<style>
17+
.light .color-mode-img {
18+
content: var(--light-src);
19+
}
20+
</style>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<script setup lang="ts">
2+
import { ACTIVE_NOODLES, PERMANENT_NOODLES, type Noodle } from '../Noodle'
3+
4+
const { env } = useAppConfig().buildInfo
5+
6+
const activeNoodlesData = ACTIVE_NOODLES.map(noodle => ({
7+
key: noodle.key,
8+
date: noodle.date,
9+
timezone: noodle.timezone,
10+
tagline: noodle.tagline,
11+
}))
12+
13+
const permanentNoodlesData = PERMANENT_NOODLES.map(noodle => ({
14+
key: noodle.key,
15+
tagline: noodle.tagline,
16+
}))
17+
18+
onPrehydrate(el => {
19+
const tagline = el.querySelector<HTMLElement>('#intro-header-tagline')
20+
const defaultLogo = el.querySelector<HTMLElement>('#intro-header-noodle-default')
21+
22+
if (!tagline || !defaultLogo) return
23+
24+
let permanentNoodles
25+
try {
26+
permanentNoodles = JSON.parse(el.dataset.permanentNoodles as string) as Noodle[]
27+
} catch {
28+
return
29+
}
30+
const activePermanentNoodle = permanentNoodles?.find(noodle =>
31+
new URLSearchParams(window.location.search).has(noodle.key),
32+
)
33+
34+
if (activePermanentNoodle) {
35+
const permanentNoodleLogo = el.querySelector<HTMLElement>(
36+
`#intro-header-noodle-${activePermanentNoodle.key}`,
37+
)
38+
39+
if (!permanentNoodleLogo) return
40+
41+
permanentNoodleLogo.style.display = 'block'
42+
defaultLogo.style.display = 'none'
43+
if (activePermanentNoodle.tagline === false) {
44+
tagline.style.display = 'none'
45+
}
46+
return
47+
}
48+
49+
let activeNoodles
50+
try {
51+
activeNoodles = JSON.parse(el.dataset.activeNoodles as string) as Noodle[]
52+
} catch {
53+
return
54+
}
55+
56+
const currentActiveNoodles = activeNoodles.filter(noodle => {
57+
const todayDate = new Intl.DateTimeFormat('en-US', {
58+
timeZone: noodle.timezone === 'auto' ? undefined : noodle.timezone,
59+
month: '2-digit',
60+
day: '2-digit',
61+
year: 'numeric',
62+
}).format(new Date())
63+
64+
const noodleDate = new Intl.DateTimeFormat('en-US', {
65+
timeZone: noodle.timezone === 'auto' ? undefined : noodle.timezone,
66+
month: '2-digit',
67+
day: '2-digit',
68+
year: 'numeric',
69+
}).format(new Date())
70+
return todayDate === noodleDate
71+
})
72+
73+
if (!currentActiveNoodles.length) return
74+
75+
const roll = Math.floor(Math.random() * currentActiveNoodles.length)
76+
const selectedNoodle = currentActiveNoodles[roll]
77+
78+
if (!selectedNoodle) return
79+
80+
const noodleLogo = el.querySelector<HTMLElement>(`#intro-header-noodle-${selectedNoodle.key}`)
81+
82+
if (!defaultLogo || !noodleLogo || !tagline) return
83+
84+
defaultLogo.style.display = 'none'
85+
noodleLogo.style.display = 'block'
86+
if (selectedNoodle.tagline === false) {
87+
tagline.style.display = 'none'
88+
}
89+
})
90+
</script>
91+
92+
<template>
93+
<div
94+
:data-active-noodles="JSON.stringify(activeNoodlesData)"
95+
:data-permanent-noodles="JSON.stringify(permanentNoodlesData)"
96+
>
97+
<h1 class="sr-only">
98+
{{ $t('alt_logo') }}
99+
</h1>
100+
<div
101+
id="intro-header-noodle-default"
102+
class="relative mb-6 w-fit mx-auto motion-safe:animate-fade-in motion-safe:animate-fill-both"
103+
aria-hidden="true"
104+
>
105+
<AppLogo id="npmx-index-h1-logo-normal" class="w-42 h-auto sm:w-58 md:w-70" />
106+
<span
107+
id="npmx-index-h1-logo-env"
108+
class="text-sm sm:text-base md:text-lg transform-origin-br font-mono tracking-widest text-accent absolute -bottom-4 -inset-ie-1.5"
109+
>
110+
{{ env === 'release' ? 'alpha' : env }}
111+
</span>
112+
</div>
113+
<component
114+
v-for="noodle in PERMANENT_NOODLES"
115+
:key="noodle.key"
116+
:id="`intro-header-noodle-${noodle.key}`"
117+
class="hidden"
118+
aria-hidden="true"
119+
:is="noodle.logo"
120+
/>
121+
<component
122+
v-for="noodle in ACTIVE_NOODLES"
123+
:key="noodle.key"
124+
:id="`intro-header-noodle-${noodle.key}`"
125+
class="hidden"
126+
aria-hidden="true"
127+
:is="noodle.logo"
128+
/>
129+
<p
130+
id="intro-header-tagline"
131+
class="text-fg-muted text-lg sm:text-xl max-w-xl mb-12 lg:mb-14 motion-safe:animate-slide-up motion-safe:animate-fill-both delay-100"
132+
>
133+
{{ $t('tagline') }}
134+
</p>
135+
</div>
136+
</template>

app/components/LandingLogo.vue

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<template>
2+
<img
3+
width="400"
4+
class="mb-8 motion-safe:animate-fade-in motion-safe:animate-scale-in motion-safe:hover:scale-105 motion-safe:transition w-80 sm:w-100"
5+
src="/extra/npmx-cute.svg"
6+
:alt="$t('alt_logo_kawaii')"
7+
/>
8+
</template>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<template>
2+
<img
3+
width="400"
4+
class="mb-8 motion-safe:animate-fade-in motion-safe:animate-scale-in motion-safe:hover:scale-105 motion-safe:transition w-80 sm:w-100"
5+
src="/extra/npmx-cute-transgender.svg"
6+
:alt="$t('alt_logo_kawaii')"
7+
/>
8+
</template>

app/components/Noodle/index.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import NoodleKawaiiLogo from './Kawaii/Logo.vue'
2+
import NoodleTkawaiiLogo from './Tkawaii/Logo.vue'
3+
4+
export type Noodle = {
5+
// Unique identifier for the noodle
6+
key: string
7+
// Timezone for the noodle (default is auto, i.e. user's timezone)
8+
timezone?: string
9+
// Date for the noodle
10+
date?: string
11+
// Logo for the noodle - could be any component. Relative parent - intro section
12+
logo: Component
13+
// Show npmx tagline or not (default is true)
14+
tagline?: boolean
15+
}
16+
17+
// Archive noodles - might be shown on special page
18+
export const ARCHIVE_NOODLES: Noodle[] = [
19+
{
20+
key: 'tkawaii',
21+
date: '2026-04-08T12:00:00UTC',
22+
timezone: 'auto',
23+
logo: NoodleTkawaiiLogo,
24+
tagline: false,
25+
},
26+
]
27+
28+
// Permanent noodles - always shown on specific query param (e.g. ?kawaii)
29+
export const PERMANENT_NOODLES: Noodle[] = [
30+
{
31+
key: 'kawaii',
32+
logo: NoodleKawaiiLogo,
33+
tagline: false,
34+
},
35+
]
36+
37+
// Active noodles - shown based on date and timezone
38+
export const ACTIVE_NOODLES: Noodle[] = []

app/pages/index.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ defineOgImageComponent('Default', {
2626

2727
<template>
2828
<main>
29-
<section class="container min-h-screen flex flex-col">
29+
<section class="relative container min-h-screen flex flex-col overflow-hidden">
3030
<header
3131
class="flex-1 flex flex-col items-center justify-center text-center pt-20 pb-4 md:pb-8 lg:pb-20"
3232
>
33-
<LandingLogo class="w-42 h-auto sm:w-58 md:w-70" />
33+
<LandingIntroHeader />
3434
<search
3535
class="w-full max-w-2xl motion-safe:animate-slide-up motion-safe:animate-fill-both"
3636
style="animation-delay: 0.2s"

0 commit comments

Comments
 (0)