Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add emoji support #63

Merged
merged 5 commits into from Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 9 additions & 9 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions src/social-card/highlight-card/highlight-card.service.ts
Expand Up @@ -14,6 +14,7 @@ import highlightCardTemplate from "../templates/highlight-card.template";
import { DbUserHighlight } from "../../github/entities/db-user-highlight.entity";
import { DbReaction } from "../../github/entities/db-reaction.entity";
import { RequiresUpdateMeta } from "../user-card/user-card.service";
import { getIconCode, loadEmoji } from "../../utils/twemoji";

interface HighlightCardData {
login: string;
Expand Down Expand Up @@ -122,6 +123,16 @@ export class HighlightCardService {
},
],
tailwindConfig,
loadAdditionalAsset: async (code: string, segment: string) => {
if (code === "emoji") {
// if segment is an emoji
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return (`data:image/svg+xml;base64,${btoa(await loadEmoji( "twemoji", getIconCode(segment)))}`);
}

// if segment is normal text
return (code);
},
});

const resvg = new Resvg(svg, { background: "rgba(238, 235, 230, .9)" });
Expand Down
3 changes: 2 additions & 1 deletion src/social-card/templates/highlight-card.template.ts
@@ -1,6 +1,7 @@
import cardFooter from "./shared/card-footer";
import cardStyleSetup from "./shared/card-style-setup";


const highlightCardTemplate = (
avatarUrl: string,
body: string,
Expand All @@ -15,7 +16,7 @@ const highlightCardTemplate = (
<div tw="flex-row justify-between" style="gap: 16px;">
<div tw="w-906px flex-col flex-nowrap" style="gap: -10px;">
<h1 tw="text-72px leading-72px text-black tracking-tight" style="width: 926px; font-weight: 500;">
OpenSauced Highlight
OpenSauced Highlight
a0m0rajab marked this conversation as resolved.
Show resolved Hide resolved
</h1>
<p tw="font-normal text-48px text-light-slate-11 tracking-tight">
${body.length > 108 ? `${body.slice(0, 108)}...` : body}
Expand Down
76 changes: 76 additions & 0 deletions src/utils/twemoji.ts
@@ -0,0 +1,76 @@
/**
* modified version of https://unpkg.com/[email protected]/dist/twemoji.esm.js.
*/

/* ! Copyright Twitter Inc. and other contributors. Licensed under MIT */

// this file added in: https://github.com/open-sauced/opengraph/issues/50

const U200D = String.fromCharCode(8205);
const UFE0Fg = /\uFE0F/g;

export function getIconCode (char: string) {
return toCodePoint(!char.includes(U200D) ? char.replace(UFE0Fg, "") : char);
}

function toCodePoint (unicodeSurrogates: string) {
const r = [];
let c = 0;
let i = 0;
let p = 0;

// eslint-disable-next-line no-loops/no-loops
while (i < unicodeSurrogates.length) {
c = unicodeSurrogates.charCodeAt(i++);
if (p) {
r.push((65536 + ((p - 55296) << 10) + (c - 56320)).toString(16));
p = 0;
} else if (55296 <= c && c <= 56319) {
p = c;
} else {
r.push(c.toString(16));
}
}
return r.join("-");
}

export const apis = {
twemoji: (code: string) =>
`https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/${
code.toLowerCase()
}.svg`,
openmoji: "https://cdn.jsdelivr.net/npm/@svgmoji/[email protected]/svg/",
blobmoji: "https://cdn.jsdelivr.net/npm/@svgmoji/[email protected]/svg/",
noto: "https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/",
fluent: (code: string) =>
`https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${
code.toLowerCase()
}_color.svg`,
fluentFlat: (code: string) =>
`https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${
code.toLowerCase()
}_flat.svg`,
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const emojiCache: Record<string, Promise<string>> = {};

export async function loadEmoji (type: keyof typeof apis, code: string) {
const key = `${type}:${code}`;

if (key in emojiCache) {
return emojiCache[key];
}

if (!type || !apis[type]) {

Check warning on line 65 in src/utils/twemoji.ts

View workflow job for this annotation

GitHub Actions / test / Code standards

Unnecessary conditional, value is always falsy
type = "twemoji";
}

const api = apis[type];

if (typeof api === "function") {
return (emojiCache[key] = fetch(api(code)).then(async r => r.text()));
}
return (emojiCache[key] = fetch(`${api}${code.toUpperCase()}.svg`).then(async r =>
r.text()));
}
2 changes: 1 addition & 1 deletion test/local-dev/HighlightCards.ts
Expand Up @@ -4,7 +4,7 @@ import { existsSync } from "node:fs";
import { mkdir, writeFile } from "fs/promises";
import { HighlightCardService } from "../../src/social-card/highlight-card/highlight-card.service";

const testHighlights = [124, 120, 116, 115];
const testHighlights = [124, 120, 116, 115, 161];

const folderPath = "dist/local-dev";

Expand Down