Skip to content

Commit 7601dfa

Browse files
committed
feat: implement theme support for the Wold Emoji Day noodle
1 parent 1d3ee47 commit 7601dfa

5 files changed

Lines changed: 115 additions & 93 deletions

File tree

Lines changed: 14 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,37 @@
11
<template>
2-
<div ref="sizer" class="sizer w-full sm:w-[540px] md:w-[640px] lg:w-[900px]"></div>
2+
<div class="relative flex">
3+
<ThemedLogo v-if="colorMode.value === 'dark'" :emojiSets="darkTheme" />
4+
<ThemedLogo v-else :emojiSets="lightTheme" />
5+
</div>
36
</template>
47

5-
<style>
6-
.sizer {
7-
position: relative;
8-
height: auto;
9-
aspect-ratio: 900/360;
10-
}
11-
</style>
12-
138
<script setup lang="ts">
14-
import { init } from './emoji-thing'
15-
import { onMounted, onUnmounted, useTemplateRef } from 'vue'
9+
import ThemedLogo from './ThemedLogo.vue'
1610
import red from './emojisets/red.png'
1711
import blue from './emojisets/blue.png'
1812
import faces from './emojisets/faces.png'
1913
import gold from './emojisets/gold.png'
2014
import hearts from './emojisets/hearts.png'
2115
import green from './emojisets/green.png'
2216
import earth from './emojisets/earth.png'
23-
import cloud from './emojisets/cloud.png'
17+
import light from './emojisets/themed-light.png'
18+
import dark from './emojisets/themed-dark.png'
2419
25-
const EMOJI_SET_SOURCES = {
20+
const colorMode = useColorMode()
21+
22+
const lightTheme = {
2623
red,
2724
blue,
2825
hearts,
2926
gold,
3027
faces,
3128
green,
3229
earth,
33-
cloud,
30+
themed: light,
3431
}
3532
36-
let emojiSetImagesPromise: undefined | Promise<Record<string, HTMLImageElement>>
37-
38-
function loadEmojiSetImages() {
39-
if (emojiSetImagesPromise) {
40-
return emojiSetImagesPromise
41-
}
42-
43-
const promise = Promise.all(
44-
Object.entries(EMOJI_SET_SOURCES).map(([name, src]) => {
45-
return new Promise<[string, HTMLImageElement]>((resolve, reject) => {
46-
const image = new Image()
47-
image.addEventListener('load', () => {
48-
resolve([name, image])
49-
})
50-
image.addEventListener('error', () => {
51-
if (promise === emojiSetImagesPromise) {
52-
emojiSetImagesPromise = undefined
53-
}
54-
reject(new Error(`could not load image ${JSON.stringify(src)}`))
55-
})
56-
image.src = src
57-
})
58-
}),
59-
).then(sets => Object.fromEntries(sets))
60-
61-
emojiSetImagesPromise = promise
62-
return emojiSetImagesPromise
33+
const darkTheme = {
34+
...lightTheme,
35+
themed: dark,
6336
}
64-
65-
let running = false
66-
let handle: undefined | ReturnType<typeof init>
67-
let observer: undefined | IntersectionObserver
68-
69-
const sizerRef = useTemplateRef<HTMLDivElement>('sizer')
70-
71-
onMounted(() => {
72-
const sizer = sizerRef.value
73-
if (!sizer) {
74-
return
75-
}
76-
77-
observer = new IntersectionObserver(
78-
([entry]) => {
79-
if (!entry) {
80-
return
81-
}
82-
83-
if (entry.isIntersecting) {
84-
running = true
85-
loadEmojiSetImages().then(sets => {
86-
if (!running) {
87-
return
88-
}
89-
if (!handle) {
90-
handle = init(sizer, sets)
91-
}
92-
handle.start()
93-
})
94-
} else {
95-
running = false
96-
handle?.pause()
97-
}
98-
},
99-
{
100-
rootMargin: '100px',
101-
},
102-
)
103-
observer.observe(sizer)
104-
})
105-
106-
onUnmounted(() => {
107-
handle?.destroy()
108-
handle = undefined
109-
110-
observer?.disconnect()
111-
observer = undefined
112-
113-
running = false
114-
})
11537
</script>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<template>
2+
<div ref="sizer" class="sizer w-full sm:w-[540px] md:w-[640px] lg:w-[900px]"></div>
3+
</template>
4+
5+
<style>
6+
.sizer {
7+
position: relative;
8+
height: auto;
9+
aspect-ratio: 900/360;
10+
}
11+
</style>
12+
13+
<script setup lang="ts">
14+
import { init } from './emoji-thing'
15+
import { onMounted, onUnmounted, useTemplateRef } from 'vue'
16+
17+
const props = defineProps<{
18+
emojiSets: Record<string, string>
19+
}>()
20+
21+
let emojiSetImagesPromise: undefined | Promise<Record<string, HTMLImageElement>>
22+
23+
function loadEmojiSetImages() {
24+
if (emojiSetImagesPromise) {
25+
return emojiSetImagesPromise
26+
}
27+
28+
const promise = Promise.all(
29+
Object.entries(props.emojiSets).map(([name, src]) => {
30+
return new Promise<[string, HTMLImageElement]>((resolve, reject) => {
31+
const image = new Image()
32+
image.addEventListener('load', () => {
33+
resolve([name, image])
34+
})
35+
image.addEventListener('error', () => {
36+
if (promise === emojiSetImagesPromise) {
37+
emojiSetImagesPromise = undefined
38+
}
39+
reject(new Error(`could not load image ${JSON.stringify(src)}`))
40+
})
41+
image.src = src
42+
})
43+
}),
44+
).then(sets => Object.fromEntries(sets))
45+
46+
emojiSetImagesPromise = promise
47+
return emojiSetImagesPromise
48+
}
49+
50+
let running = false
51+
let handle: undefined | ReturnType<typeof init>
52+
let observer: undefined | IntersectionObserver
53+
54+
const sizerRef = useTemplateRef<HTMLDivElement>('sizer')
55+
56+
onMounted(() => {
57+
const sizer = sizerRef.value
58+
if (!sizer) {
59+
return
60+
}
61+
62+
observer = new IntersectionObserver(
63+
([entry]) => {
64+
if (!entry) {
65+
return
66+
}
67+
68+
if (entry.isIntersecting) {
69+
running = true
70+
loadEmojiSetImages().then(sets => {
71+
if (!running) {
72+
return
73+
}
74+
if (!handle) {
75+
handle = init(sizer, sets)
76+
}
77+
handle.start()
78+
})
79+
} else {
80+
running = false
81+
handle?.pause()
82+
}
83+
},
84+
{
85+
rootMargin: '100px',
86+
},
87+
)
88+
observer.observe(sizer)
89+
})
90+
91+
onUnmounted(() => {
92+
handle?.destroy()
93+
handle = undefined
94+
95+
observer?.disconnect()
96+
observer = undefined
97+
98+
running = false
99+
})
100+
</script>

app/components/Noodle/EmojiDay/emoji-thing.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const GLYPH_CONFIG = [
8080
path: polyline(569, 130, 592, 123, 613, 136, 628, 168, 628, 257),
8181
},
8282
{
83-
emojiSet: 'cloud',
83+
emojiSet: 'themed',
8484
emojiCount: 24,
8585
path: polyline(628, 155, 649, 129, 673, 123, 695, 136, 710, 168, 710, 257),
8686
},
File renamed without changes.
15.1 KB
Loading

0 commit comments

Comments
 (0)