import { mkdir, exists, readdir, copyFile } from "node:fs/promises" import * as path from 'path' const emojiDir = './emoji' if(!await exists(emojiDir)) await mkdir(emojiDir) const cssDir = './css' if(!await exists(cssDir)) await mkdir(cssDir) const fluentDir = './sources/fluentui-emoji/assets' const fluentList = await readdir(fluentDir) const animatedDir = `./sources/Animated-Fluent-Emojis/Emojis` const animatedCatList = await readdir(animatedDir) const animatedList:Map = new Map() for(let c in animatedCatList) { const category = animatedCatList[c] const catDir = `${animatedDir}/${category}` const catFiles = await readdir(catDir) catFiles.forEach((filename) => { let key = path.parse(filename).name.toLowerCase()//.replace(/[\(\)'’“”]/g, '') animatedList.set(key, `${catDir}/${filename}`) }) } const rootURL = process.env.ROOT_URL || "https://flumoji.pages.dev/emoji/" const cssRules = { animated: [] as string[], threeD: [] as string[], color: [] as string[], flat: [] as string[], highContrast: [] as string[] } await Promise.all(fluentList.map(async (folder) => { let thisEmojiIn = `${fluentDir}/${folder}` const metadataFile = Bun.file(`${thisEmojiIn}/metadata.json`) const metadata = await metadataFile.json() const thisEmojiOut = `${emojiDir}/${metadata.glyph}` if(!await exists(thisEmojiOut)) await mkdir(thisEmojiOut) if(!await exists(`${thisEmojiOut}/metadata.json`)) await Bun.write(`${thisEmojiOut}/metadata.json`, metadataFile) if(metadata.unicodeSkintones) thisEmojiIn = `${thisEmojiIn}/Default` const in3d = `${thisEmojiIn}/3D` const inColor = `${thisEmojiIn}/Color` const inFlat = `${thisEmojiIn}/Flat` const inHighContrast = `${thisEmojiIn}/High Contrast` // we have to search for the appropriate animated folder let title = metadata.tts.toLowerCase().replace(/[:]/g, '') // if(metadata.unicodeSkintones) title += ' Light Skin Tone' let imgAnimPath = animatedList.get(title) const img3DPath = `${in3d}/${(await readdir(in3d))[0]}` const imgColorPath = `${inColor}/${(await readdir(inColor))[0]}` const imgFlatPath = `${inFlat}/${(await readdir(inFlat))[0]}` const imgHighContrastPath = `${inHighContrast}/${(await readdir(inHighContrast))[0]}` if(!imgAnimPath){ // hard-coded matches: switch(title){ case 'keycap 0': imgAnimPath = animatedList.get("keycap digit zero"); break; case 'keycap 1': imgAnimPath = animatedList.get("keycap digit one"); break; case 'keycap 2': imgAnimPath = animatedList.get("keycap digit two"); break; case 'keycap 3': imgAnimPath = animatedList.get("keycap digit three"); break; case 'keycap 4': imgAnimPath = animatedList.get("keycap digit four"); break; case 'keycap 5': imgAnimPath = animatedList.get("keycap digit five"); break; case 'keycap 6': imgAnimPath = animatedList.get("keycap digit six"); break; case 'keycap 7': imgAnimPath = animatedList.get("keycap digit seven"); break; case 'keycap 8': imgAnimPath = animatedList.get("keycap digit eight"); break; case 'keycap 9': imgAnimPath = animatedList.get("keycap digit nine"); break; case 'keycap #': imgAnimPath = animatedList.get("keycap number sign"); break; case 'keycap *': imgAnimPath = animatedList.get("keycap asterisk"); break; case 'pouting face': imgAnimPath = animatedList.get("enraged face"); break; default: console.warn(`could not find animated ${metadata.glyph} ${title}. Defaulting to 3D version: ${img3DPath}`) } } const imgAnim = Bun.file(imgAnimPath || img3DPath) const img3d = Bun.file(img3DPath) const imgColor = Bun.file(imgColorPath) const imgFlat = Bun.file(imgFlatPath) const imgHighContrast = Bun.file(imgHighContrastPath) if(!await exists(`${thisEmojiOut}/animated.png`)) await Bun.write(`${thisEmojiOut}/animated.png`, imgAnim) if(!await exists(`${thisEmojiOut}/3d.png`)) await Bun.write(`${thisEmojiOut}/3d.png`, img3d) if(!await exists(`${thisEmojiOut}/color.svg`)) await Bun.write(`${thisEmojiOut}/color.svg`, imgColor) if(!await exists(`${thisEmojiOut}/flat.svg`)) await Bun.write(`${thisEmojiOut}/flat.svg`, imgFlat) if(!await exists(`${thisEmojiOut}/high-contrast.svg`)) await Bun.write(`${thisEmojiOut}/high-contrast.svg`, imgHighContrast) const cssRule = `[alt|="${metadata.glyph}"]{ content: url(${rootURL}${metadata.glyph}/{file}); }` cssRules.animated.push(cssRule.replace("{file}", "animated.png")) cssRules.threeD.push(cssRule.replace("{file}", "3d.png")) cssRules.color.push(cssRule.replace("{file}", "color.svg")) cssRules.flat.push(cssRule.replace("{file}", "flat.svg")) cssRules.highContrast.push(cssRule.replace("{file}", "high-contrast.svg")) })) const cssAnim = Bun.file(path.join(cssDir, 'animated.css')) const css3d = Bun.file(path.join(cssDir, '3d.css')) const cssColor = Bun.file(path.join(cssDir, 'color.css')) const cssFlat = Bun.file(path.join(cssDir, 'flat.css')) const cssHighContrast = Bun.file(path.join(cssDir, 'high-contrast.css')) await Bun.write(cssAnim, cssRules.animated.join('\n')) await Bun.write(css3d, cssRules.threeD.join('\n')) await Bun.write(cssColor, cssRules.color.join('\n')) await Bun.write(cssFlat, cssRules.flat.join('\n')) await Bun.write(cssHighContrast, cssRules.highContrast.join('\n'))