Skip to content

Commit 81390af

Browse files
committed
feat(labels): expands GitHub emoji shortcodes to Unicode
1 parent 30f1194 commit 81390af

File tree

4 files changed

+48
-1
lines changed

4 files changed

+48
-1
lines changed

src/app/components/dashboard/ItemRow.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { For, JSX, Show } from "solid-js";
22
import { isSafeGitHubUrl } from "../../lib/url";
33
import { relativeTime, labelTextColor, formatCount } from "../../lib/format";
4+
import { expandEmoji } from "../../lib/emoji";
45

56
export interface ItemRowProps {
67
repo: string;
@@ -78,7 +79,7 @@ export default function ItemRow(props: ItemRowProps) {
7879
class="inline-flex items-center rounded-full text-xs px-2 py-0.5 font-medium bg-[var(--lb)] text-[var(--lf)]"
7980
style={{ "--lb": bg, "--lf": fg }}
8081
>
81-
{label.name}
82+
{expandEmoji(label.name)}
8283
</span>
8384
);
8485
}}

src/app/lib/emoji.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Vendored from gemoji 8.1.0 — static shortcode→Unicode map (42KB, ~15KB gzipped).
2+
// Regenerate: node -e "const {gemoji}=require('gemoji');const m={};for(const e of gemoji)for(const n of e.names)m[n]=e.emoji;process.stdout.write(JSON.stringify(m))" > src/app/lib/github-emoji-map.json
3+
import emojiMap from "./github-emoji-map.json";
4+
5+
const SHORTCODE_RE = /:([a-z0-9_+-]+):/g;
6+
7+
const map = emojiMap as Record<string, string>;
8+
9+
/** Replace GitHub `:shortcode:` patterns with Unicode emoji. Unknown codes are left as-is. */
10+
export function expandEmoji(text: string): string {
11+
if (!text.includes(":")) return text;
12+
return text.replace(SHORTCODE_RE, (match, name: string) => map[name] ?? match);
13+
}

src/app/lib/github-emoji-map.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/lib/emoji.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { describe, it, expect } from "vitest";
2+
import { expandEmoji } from "../../src/app/lib/emoji";
3+
4+
describe("expandEmoji", () => {
5+
it("expands known shortcodes to Unicode", () => {
6+
expect(expandEmoji(":microbe: bug")).toBe("🦠 bug");
7+
expect(expandEmoji(":sponge: formatter")).toBe("🧽 formatter");
8+
expect(expandEmoji(":rocket:")).toBe("🚀");
9+
});
10+
11+
it("handles multiple shortcodes in one string", () => {
12+
expect(expandEmoji(":bug: :fire: critical")).toBe("🐛 🔥 critical");
13+
});
14+
15+
it("leaves unknown shortcodes as-is", () => {
16+
expect(expandEmoji(":not_a_real_emoji:")).toBe(":not_a_real_emoji:");
17+
});
18+
19+
it("returns plain text unchanged", () => {
20+
expect(expandEmoji("no emoji here")).toBe("no emoji here");
21+
expect(expandEmoji("")).toBe("");
22+
});
23+
24+
it("handles mixed known and unknown shortcodes", () => {
25+
expect(expandEmoji(":rocket: :fakecode: go")).toBe("🚀 :fakecode: go");
26+
});
27+
28+
it("does not expand partial colon patterns", () => {
29+
expect(expandEmoji("time: 3:00")).toBe("time: 3:00");
30+
expect(expandEmoji("key:value")).toBe("key:value");
31+
});
32+
});

0 commit comments

Comments
 (0)