about summary refs log tree commit diff
path: root/bskyogcard/src
diff options
context:
space:
mode:
authordevin ivy <devinivy@gmail.com>2024-06-27 13:02:29 -0400
committerGitHub <noreply@github.com>2024-06-27 13:02:29 -0400
commit49396451ec8c877aebd27299a98c1b9e5b1e6cd4 (patch)
treec424c554a431c9594896a09bf422c737c2341e62 /bskyogcard/src
parentf6b138f709bcf52248e3f0c5a1ef67abe96bef9c (diff)
downloadvoidsky-49396451ec8c877aebd27299a98c1b9e5b1e6cd4.tar.zst
bskyogcard: support emoji, more languages, long starter pack names (#4668)
Diffstat (limited to 'bskyogcard/src')
-rw-r--r--bskyogcard/src/assets/fonts/Inter-Bold.ttf (renamed from bskyogcard/src/assets/Inter-Bold.ttf)bin316584 -> 316584 bytes
-rw-r--r--bskyogcard/src/components/StarterPack.tsx5
-rw-r--r--bskyogcard/src/context.ts20
-rw-r--r--bskyogcard/src/logger.ts1
-rw-r--r--bskyogcard/src/routes/starter-pack.tsx6
-rw-r--r--bskyogcard/src/util.ts37
6 files changed, 59 insertions, 10 deletions
diff --git a/bskyogcard/src/assets/Inter-Bold.ttf b/bskyogcard/src/assets/fonts/Inter-Bold.ttf
index fe23eeb9c..fe23eeb9c 100644
--- a/bskyogcard/src/assets/Inter-Bold.ttf
+++ b/bskyogcard/src/assets/fonts/Inter-Bold.ttf
Binary files differdiff --git a/bskyogcard/src/components/StarterPack.tsx b/bskyogcard/src/components/StarterPack.tsx
index f73442190..29bb8f32a 100644
--- a/bskyogcard/src/components/StarterPack.tsx
+++ b/bskyogcard/src/components/StarterPack.tsx
@@ -43,6 +43,7 @@ export function StarterPack(props: {
   } else {
     imagesAcross.push(...imagesExceptCreator.slice(0, 7))
   }
+  const isLongTitle = record ? record.name.length > 30 : false
   return (
     <div
       style={{
@@ -130,7 +131,9 @@ export function StarterPack(props: {
         <div
           style={{
             padding: '75px 30px 0px',
-            fontSize: 65,
+            fontSize: isLongTitle ? 55 : 65,
+            display: 'flex',
+            textAlign: 'center',
           }}>
           {record?.name || 'Starter Pack'}
         </div>
diff --git a/bskyogcard/src/context.ts b/bskyogcard/src/context.ts
index f92651caf..0c972c94d 100644
--- a/bskyogcard/src/context.ts
+++ b/bskyogcard/src/context.ts
@@ -1,8 +1,8 @@
-import {readFileSync} from 'node:fs'
+import {readdirSync, readFileSync} from 'node:fs'
+import * as path from 'node:path'
+import {fileURLToPath} from 'node:url'
 
 import {AtpAgent} from '@atproto/api'
-import * as path from 'path'
-import {fileURLToPath} from 'url'
 
 import {Config} from './config.js'
 
@@ -28,12 +28,14 @@ export class AppContext {
 
   static async fromConfig(cfg: Config, overrides?: Partial<AppContextOptions>) {
     const appviewAgent = new AtpAgent({service: cfg.service.appviewUrl})
-    const fonts = [
-      {
-        name: 'Inter',
-        data: readFileSync(path.join(__DIRNAME, 'assets', 'Inter-Bold.ttf')),
-      },
-    ]
+    const fontDirectory = path.join(__DIRNAME, 'assets', 'fonts')
+    const fontFiles = readdirSync(fontDirectory)
+    const fonts = fontFiles.map(file => {
+      return {
+        name: path.basename(file, path.extname(file)),
+        data: readFileSync(path.join(fontDirectory, file)),
+      }
+    })
     return new AppContext({
       cfg,
       appviewAgent,
diff --git a/bskyogcard/src/logger.ts b/bskyogcard/src/logger.ts
index 04b5d9046..320206513 100644
--- a/bskyogcard/src/logger.ts
+++ b/bskyogcard/src/logger.ts
@@ -1,3 +1,4 @@
 import {subsystemLogger} from '@atproto/common'
 
 export const httpLogger = subsystemLogger('bskyogcard')
+export const renderLogger = subsystemLogger('bskyogcard:render')
diff --git a/bskyogcard/src/routes/starter-pack.tsx b/bskyogcard/src/routes/starter-pack.tsx
index cb3a55327..06cd6977c 100644
--- a/bskyogcard/src/routes/starter-pack.tsx
+++ b/bskyogcard/src/routes/starter-pack.tsx
@@ -13,6 +13,7 @@ import {
 } from '../components/StarterPack.js'
 import {AppContext} from '../context.js'
 import {httpLogger} from '../logger.js'
+import {loadEmojiAsSvg} from '../util.js'
 import {handler, originVerifyMiddleware} from './util.js'
 
 export default function (ctx: AppContext, app: Express) {
@@ -65,6 +66,11 @@ export default function (ctx: AppContext, app: Express) {
           fonts: ctx.fonts,
           height: STARTERPACK_HEIGHT,
           width: STARTERPACK_WIDTH,
+          loadAdditionalAsset: async (code, text) => {
+            if (code === 'emoji') {
+              return await loadEmojiAsSvg(text)
+            }
+          },
         },
       )
       const output = await resvg.renderAsync(svg)
diff --git a/bskyogcard/src/util.ts b/bskyogcard/src/util.ts
new file mode 100644
index 000000000..2b86ded06
--- /dev/null
+++ b/bskyogcard/src/util.ts
@@ -0,0 +1,37 @@
+import twemoji from 'twemoji'
+
+import {renderLogger} from './logger.js'
+
+const U200D = String.fromCharCode(0x200d)
+const UFE0F_REGEXP = /\uFE0F/g
+
+export async function loadEmojiAsSvg(chars: string) {
+  const cached = emojiCache.get(chars)
+  if (cached) return cached
+  const iconCode = twemoji.convert.toCodePoint(
+    chars.indexOf(U200D) < 0 ? chars.replace(UFE0F_REGEXP, '') : chars,
+  )
+  const res = await fetch(getEmojiUrl(iconCode))
+  const body = await res.arrayBuffer()
+  if (!res.ok) {
+    renderLogger.warn(
+      {status: res.status, err: Buffer.from(body).toString()},
+      'could not fetch emoji',
+    )
+    return
+  }
+  const svg =
+    'data:image/svg+xml;base64,' + Buffer.from(body).toString('base64')
+  emojiCache.set(chars, svg)
+  return svg
+}
+
+const emojiCache = new Map<string, string>()
+
+function getEmojiUrl(code: string) {
+  return (
+    'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/' +
+    code.toLowerCase() +
+    '.svg'
+  )
+}