atagen

malice

public
Star0
Watch0
294426c7f88fd4348a61b8a8590233237a1e52c0
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/src/lib/emoji.ts

544a170ead2catagen2026-10-20 11:47 UTC1
export interface EmojiEntry {
544a170ead2catagen2026-10-20 11:47 UTC2
  emoji: string;
544a170ead2catagen2026-10-20 11:47 UTC3
  label: string;
544a170ead2catagen2026-10-20 11:47 UTC4
  tags: string[];
544a170ead2catagen2026-10-20 11:47 UTC5
  shortcodes: string[];
544a170ead2catagen2026-10-20 11:47 UTC6
}
544a170ead2catagen2026-10-20 11:47 UTC7
544a170ead2catagen2026-10-20 11:47 UTC8
export interface EmojiGroup {
544a170ead2catagen2026-10-20 11:47 UTC9
  name: string;
544a170ead2catagen2026-10-20 11:47 UTC10
  emojis: EmojiEntry[];
544a170ead2catagen2026-10-20 11:47 UTC11
}
544a170ead2catagen2026-10-20 11:47 UTC12
544a170ead2catagen2026-10-20 11:47 UTC13
interface RawEmoji {
544a170ead2catagen2026-10-20 11:47 UTC14
  hexcode: string;
544a170ead2catagen2026-10-20 11:47 UTC15
  unicode: string;
544a170ead2catagen2026-10-20 11:47 UTC16
  label: string;
544a170ead2catagen2026-10-20 11:47 UTC17
  group?: number;
544a170ead2catagen2026-10-20 11:47 UTC18
  order?: number;
544a170ead2catagen2026-10-20 11:47 UTC19
  tags?: string[];
544a170ead2catagen2026-10-20 11:47 UTC20
}
544a170ead2catagen2026-10-20 11:47 UTC21
544a170ead2catagen2026-10-20 11:47 UTC22
const GROUP_NAMES: Record<number, string> = {
544a170ead2catagen2026-10-20 11:47 UTC23
  0: 'Smileys & emotion',
544a170ead2catagen2026-10-20 11:47 UTC24
  1: 'People & body',
544a170ead2catagen2026-10-20 11:47 UTC25
  3: 'Animals & nature',
544a170ead2catagen2026-10-20 11:47 UTC26
  4: 'Food & drink',
544a170ead2catagen2026-10-20 11:47 UTC27
  5: 'Travel & places',
544a170ead2catagen2026-10-20 11:47 UTC28
  6: 'Activities',
544a170ead2catagen2026-10-20 11:47 UTC29
  7: 'Objects',
544a170ead2catagen2026-10-20 11:47 UTC30
  8: 'Symbols',
544a170ead2catagen2026-10-20 11:47 UTC31
  9: 'Flags'
544a170ead2catagen2026-10-20 11:47 UTC32
};
544a170ead2catagen2026-10-20 11:47 UTC33
544a170ead2catagen2026-10-20 11:47 UTC34
let loading: Promise<EmojiGroup[]> | null = null;
544a170ead2catagen2026-10-20 11:47 UTC35
544a170ead2catagen2026-10-20 11:47 UTC36
export function loadEmoji(): Promise<EmojiGroup[]> {
544a170ead2catagen2026-10-20 11:47 UTC37
  loading ??= (async () => {
544a170ead2catagen2026-10-20 11:47 UTC38
    const [compact, codes] = await Promise.all([
544a170ead2catagen2026-10-20 11:47 UTC39
      import('emojibase-data/en/compact.json'),
544a170ead2catagen2026-10-20 11:47 UTC40
      import('emojibase-data/en/shortcodes/emojibase.json')
544a170ead2catagen2026-10-20 11:47 UTC41
    ]);
544a170ead2catagen2026-10-20 11:47 UTC42
    const shortcodes = codes.default as Record<string, string | string[]>;
544a170ead2catagen2026-10-20 11:47 UTC43
    const byGroup = new Map<number, EmojiEntry[]>();
544a170ead2catagen2026-10-20 11:47 UTC44
    for (const raw of compact.default as RawEmoji[]) {
544a170ead2catagen2026-10-20 11:47 UTC45
      if (raw.group === undefined || !(raw.group in GROUP_NAMES)) continue;
544a170ead2catagen2026-10-20 11:47 UTC46
      const code = shortcodes[raw.hexcode];
544a170ead2catagen2026-10-20 11:47 UTC47
      const entry: EmojiEntry = {
544a170ead2catagen2026-10-20 11:47 UTC48
        emoji: raw.unicode,
544a170ead2catagen2026-10-20 11:47 UTC49
        label: raw.label,
544a170ead2catagen2026-10-20 11:47 UTC50
        tags: raw.tags ?? [],
544a170ead2catagen2026-10-20 11:47 UTC51
        shortcodes: code === undefined ? [] : Array.isArray(code) ? code : [code]
544a170ead2catagen2026-10-20 11:47 UTC52
      };
544a170ead2catagen2026-10-20 11:47 UTC53
      const list = byGroup.get(raw.group) ?? [];
544a170ead2catagen2026-10-20 11:47 UTC54
      list.push(entry);
544a170ead2catagen2026-10-20 11:47 UTC55
      byGroup.set(raw.group, list);
544a170ead2catagen2026-10-20 11:47 UTC56
    }
544a170ead2catagen2026-10-20 11:47 UTC57
    return Object.entries(GROUP_NAMES).flatMap(([id, name]) => {
544a170ead2catagen2026-10-20 11:47 UTC58
      const emojis = byGroup.get(Number(id));
544a170ead2catagen2026-10-20 11:47 UTC59
      return emojis ? [{ name, emojis }] : [];
544a170ead2catagen2026-10-20 11:47 UTC60
    });
544a170ead2catagen2026-10-20 11:47 UTC61
  })().catch((e) => {
544a170ead2catagen2026-10-20 11:47 UTC62
    loading = null;
544a170ead2catagen2026-10-20 11:47 UTC63
    throw e;
544a170ead2catagen2026-10-20 11:47 UTC64
  });
544a170ead2catagen2026-10-20 11:47 UTC65
  return loading;
544a170ead2catagen2026-10-20 11:47 UTC66
}
544a170ead2catagen2026-10-20 11:47 UTC67
544a170ead2catagen2026-10-20 11:47 UTC68
export function matchesEmoji(entry: EmojiEntry, query: string): boolean {
544a170ead2catagen2026-10-20 11:47 UTC69
  const q = query.trim().toLowerCase().replace(/^:|:$/g, '');
544a170ead2catagen2026-10-20 11:47 UTC70
  if (!q) return true;
544a170ead2catagen2026-10-20 11:47 UTC71
  return (
544a170ead2catagen2026-10-20 11:47 UTC72
    entry.label.toLowerCase().includes(q) ||
544a170ead2catagen2026-10-20 11:47 UTC73
    entry.tags.some((t) => t.toLowerCase().includes(q)) ||
544a170ead2catagen2026-10-20 11:47 UTC74
    entry.shortcodes.some((s) => s.toLowerCase().includes(q))
544a170ead2catagen2026-10-20 11:47 UTC75
  );
544a170ead2catagen2026-10-20 11:47 UTC76
}
544a170ead2catagen2026-10-20 11:47 UTC77
544a170ead2catagen2026-10-20 11:47 UTC78
export function searchEmoji(groups: EmojiGroup[], query: string): EmojiGroup[] {
544a170ead2catagen2026-10-20 11:47 UTC79
  return groups
544a170ead2catagen2026-10-20 11:47 UTC80
    .map((g) => ({ name: g.name, emojis: g.emojis.filter((e) => matchesEmoji(e, query)) }))
544a170ead2catagen2026-10-20 11:47 UTC81
    .filter((g) => g.emojis.length > 0);
544a170ead2catagen2026-10-20 11:47 UTC82
}