Skip to content

Commit ed72177

Browse files
feat: noodles (#2421)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 7505f1a commit ed72177

File tree

13 files changed

+283
-81
lines changed

13 files changed

+283
-81
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: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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 =
65+
noodle.date &&
66+
new Intl.DateTimeFormat('en-US', {
67+
timeZone: noodle.timezone === 'auto' ? undefined : noodle.timezone,
68+
month: '2-digit',
69+
day: '2-digit',
70+
year: 'numeric',
71+
}).format(new Date(noodle.date))
72+
return todayDate === noodleDate
73+
})
74+
75+
if (!currentActiveNoodles.length) return
76+
77+
const roll = Math.floor(Math.random() * currentActiveNoodles.length)
78+
const selectedNoodle = currentActiveNoodles[roll]
79+
80+
if (!selectedNoodle) return
81+
82+
const noodleLogo = el.querySelector<HTMLElement>(`#intro-header-noodle-${selectedNoodle.key}`)
83+
84+
if (!defaultLogo || !noodleLogo || !tagline) return
85+
86+
defaultLogo.style.display = 'none'
87+
noodleLogo.style.display = 'block'
88+
if (selectedNoodle.tagline === false) {
89+
tagline.style.display = 'none'
90+
}
91+
})
92+
</script>
93+
94+
<template>
95+
<div
96+
:data-active-noodles="JSON.stringify(activeNoodlesData)"
97+
:data-permanent-noodles="JSON.stringify(permanentNoodlesData)"
98+
>
99+
<h1 class="sr-only">
100+
{{ $t('alt_logo') }}
101+
</h1>
102+
<div
103+
id="intro-header-noodle-default"
104+
class="relative mb-6 w-fit mx-auto motion-safe:animate-fade-in motion-safe:animate-fill-both"
105+
aria-hidden="true"
106+
>
107+
<AppLogo id="npmx-index-h1-logo-normal" class="w-42 h-auto sm:w-58 md:w-70" />
108+
<span
109+
id="npmx-index-h1-logo-env"
110+
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"
111+
>
112+
{{ env === 'release' ? 'alpha' : env }}
113+
</span>
114+
</div>
115+
<component
116+
v-for="noodle in PERMANENT_NOODLES"
117+
:key="noodle.key"
118+
:id="`intro-header-noodle-${noodle.key}`"
119+
class="hidden"
120+
aria-hidden="true"
121+
:is="noodle.logo"
122+
/>
123+
<component
124+
v-for="noodle in ACTIVE_NOODLES"
125+
:key="noodle.key"
126+
:id="`intro-header-noodle-${noodle.key}`"
127+
class="hidden"
128+
aria-hidden="true"
129+
:is="noodle.logo"
130+
/>
131+
<p
132+
id="intro-header-tagline"
133+
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"
134+
>
135+
{{ $t('tagline') }}
136+
</p>
137+
</div>
138+
</template>

app/components/LandingLogo.vue

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<template>
2+
<div>
3+
<ColorSchemeImg
4+
width="400"
5+
class="mb-8 motion-safe:animate-fade-in motion-safe:animate-scale-in w-80 sm:w-100"
6+
dark-src="/extra/npmx-dark-artemis.svg"
7+
light-src="/extra/npmx-light-artemis.svg"
8+
alt=""
9+
/>
10+
<ColorSchemeImg
11+
width="1440"
12+
height="455"
13+
class="absolute bottom-0 inset-is-0 w-full h-auto mix-blend-lighten light:mix-blend-darken motion-safe:animate-fade-in"
14+
dark-src="/extra/moon-dark.png"
15+
light-src="/extra/moon-light.png"
16+
alt=""
17+
/>
18+
</div>
19+
</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.svg"
6+
:alt="$t('alt_logo_kawaii')"
7+
/>
8+
</template>

app/components/Noodle/index.ts

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

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"

public/extra/moon-dark.png

553 KB
Loading

public/extra/moon-light.png

567 KB
Loading

public/extra/npmx-dark-artemis.svg

Lines changed: 20 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)