Skip to content

Commit 964e20b

Browse files
committed
feat: add World Emoji Day noodle implementation
1 parent 4cd712e commit 964e20b

11 files changed

Lines changed: 553 additions & 0 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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+
12+
.sizer > img {
13+
display: none;
14+
}
15+
</style>
16+
17+
<script setup lang="ts">
18+
import { init } from './emoji-thing'
19+
import { onMounted, onUnmounted, useTemplateRef } from 'vue'
20+
import red from './emojisets/red.png'
21+
import blue from './emojisets/blue.png'
22+
import faces from './emojisets/faces.png'
23+
import gold from './emojisets/gold.png'
24+
import hearts from './emojisets/hearts.png'
25+
import green from './emojisets/green.png'
26+
import earth from './emojisets/earth.png'
27+
import cloud from './emojisets/cloud.png'
28+
29+
const EMOJI_SET_SOURCES = {
30+
red,
31+
blue,
32+
hearts,
33+
gold,
34+
faces,
35+
green,
36+
earth,
37+
cloud,
38+
}
39+
40+
let emojiSetImagesPromise: undefined | Promise<Record<string, HTMLImageElement>>
41+
42+
function loadEmojiSetImages() {
43+
if (emojiSetImagesPromise) {
44+
return emojiSetImagesPromise
45+
}
46+
47+
const promises = Object.entries(EMOJI_SET_SOURCES).map(([name, src]) => {
48+
return new Promise(resolve => {
49+
const image = new Image()
50+
image.addEventListener('load', () => {
51+
resolve([name, image])
52+
})
53+
image.src = src
54+
})
55+
})
56+
57+
emojiSetImagesPromise = Promise.all(promises).then(sets => Object.fromEntries(sets))
58+
return emojiSetImagesPromise
59+
}
60+
61+
let running = false
62+
let handle: undefined | ReturnType<typeof init>
63+
let observer: undefined | IntersectionObserver
64+
65+
const sizer = useTemplateRef<HTMLDivElement>('sizer')
66+
67+
onMounted(() => {
68+
observer = new IntersectionObserver(
69+
([entry]) => {
70+
if (!entry) {
71+
return
72+
}
73+
74+
if (entry.isIntersecting) {
75+
running = true
76+
loadEmojiSetImages().then(sets => {
77+
if (!running) {
78+
return
79+
}
80+
if (!handle) {
81+
handle = init(sizer.value, sets)
82+
}
83+
handle.start()
84+
})
85+
} else {
86+
running = false
87+
handle?.pause()
88+
}
89+
},
90+
{
91+
rootMargin: '100px',
92+
},
93+
)
94+
95+
if (sizer.value) {
96+
observer.observe(sizer.value)
97+
}
98+
})
99+
100+
onUnmounted(() => {
101+
handle?.destroy()
102+
handle = undefined
103+
104+
observer?.disconnect()
105+
observer = undefined
106+
107+
running = false
108+
})
109+
</script>

0 commit comments

Comments
 (0)