mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-24 03:16:40 +00:00
Use Joypixels instead of native emojis (#176)
* fist test * Use a font * Cleanup * Use right fallbacks for fonts * Lint * Cleanup and comment * Add visual test
This commit is contained in:
@@ -0,0 +1 @@
|
||||
index.ts
|
||||
@@ -0,0 +1,26 @@
|
||||
import fs from 'fs';
|
||||
import emojisRaws from 'emoji-assets/emoji.json';
|
||||
|
||||
interface EmojiData {
|
||||
code_points: {
|
||||
base: string;
|
||||
fully_qualified: string;
|
||||
};
|
||||
}
|
||||
|
||||
const emojis = emojisRaws as Record<string, EmojiData>;
|
||||
const output: Record<string, string> = {};
|
||||
|
||||
Object.entries(emojis).forEach(([key, value]) => {
|
||||
const emoji = value.code_points?.fully_qualified;
|
||||
if (emoji && key !== emoji) {
|
||||
output[key] = emoji;
|
||||
} else if (!emoji) {
|
||||
console.log('No emoji for', key);
|
||||
}
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
'index.ts',
|
||||
`export const emojiCodepoints: Record<string, string> = ${JSON.stringify(output, null, 4)};`,
|
||||
);
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@gitbook/emoji-codepoints",
|
||||
"description": "Optimized mapping of codepoints to the fully qualified emoji codepoints",
|
||||
"private": true,
|
||||
"main": "./index.ts",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"emoji-assets": "^8.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "bun ./build.ts"
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import assertNever from 'assert-never';
|
||||
import colors from 'tailwindcss/colors';
|
||||
|
||||
import { emojiFontClassName } from '@/components/primitives';
|
||||
import { fonts, ibmPlexMono } from '@/fonts';
|
||||
import { getSpaceLanguage } from '@/intl/server';
|
||||
import { getSpaceContent } from '@/lib/api';
|
||||
@@ -103,6 +104,7 @@ export default async function SpaceRootLayout(props: {
|
||||
</head>
|
||||
<body
|
||||
className={tcls(
|
||||
emojiFontClassName,
|
||||
`${fonts[customization.styling.font].className}`,
|
||||
`${ibmPlexMono.variable}`,
|
||||
'bg-light',
|
||||
|
||||
@@ -15,9 +15,7 @@ export async function BlockContentRef(props: BlockProps<DocumentBlockContentRef>
|
||||
|
||||
return (
|
||||
<Card
|
||||
leadingIcon={
|
||||
resolved.emoji ? <Emoji code={resolved.emoji} style={['text-xl']} /> : null
|
||||
}
|
||||
leadingIcon={resolved.emoji ? <Emoji code={resolved.emoji} /> : null}
|
||||
href={resolved.href}
|
||||
preTitle={kind}
|
||||
title={resolved.text}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { ClassValue, tcls } from '@/lib/tailwind';
|
||||
|
||||
/**
|
||||
* Render an emoji by its UTF-8 codepoint.
|
||||
*/
|
||||
export async function Emoji(props: { code: string; style?: ClassValue }) {
|
||||
const { code, style } = props;
|
||||
|
||||
const emojiCodepointDecimal = parseInt(code, 16);
|
||||
const emoji = String.fromCodePoint(emojiCodepointDecimal);
|
||||
|
||||
return <span className={tcls(style)}>{emoji}</span>;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { emojiCodepoints } from '@gitbook/emoji-codepoints';
|
||||
import localFont from 'next/font/local';
|
||||
|
||||
import { ClassValue, tcls } from '@/lib/tailwind';
|
||||
|
||||
import './emoji.css';
|
||||
|
||||
/* Load the 3 variants of the font as CSS variables and let the emoji.css decide on the best one to use */
|
||||
|
||||
const svgFont = localFont({
|
||||
src: './svg.woff2',
|
||||
preload: false,
|
||||
variable: '--font-emojis-svg',
|
||||
});
|
||||
|
||||
const sbixFont = localFont({
|
||||
src: './sbix.woff2',
|
||||
preload: false,
|
||||
variable: '--font-emojis-sbix',
|
||||
});
|
||||
|
||||
const cbdtFont = localFont({
|
||||
src: './cbdt.woff2',
|
||||
preload: false,
|
||||
variable: '--font-emojis-cbdt',
|
||||
});
|
||||
|
||||
/**
|
||||
* Class name to set on the <html> tag to use the emoji font.
|
||||
*/
|
||||
export const emojiFontClassName = [svgFont.variable, sbixFont.variable, cbdtFont.variable].join(
|
||||
' ',
|
||||
);
|
||||
|
||||
/**
|
||||
* Render an emoji by its codepoint.
|
||||
* It renders the UTF-8 character and use the emojione font to display it (fallbacking to default browser font).
|
||||
*/
|
||||
export async function Emoji(props: { code: string; style?: ClassValue }) {
|
||||
const { code, style } = props;
|
||||
|
||||
const fullCode = emojiCodepoints[code] ?? code;
|
||||
const fallback = getEmojiForCodepoint(fullCode);
|
||||
|
||||
return <span className={'emoji ' + tcls(style)}>{fallback}</span>;
|
||||
}
|
||||
|
||||
function getEmojiForCodepoint(unicode: string): string {
|
||||
if (!unicode) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const codePoints = unicode.split('-').map((elt) => parseInt(elt, 16));
|
||||
return String.fromCodePoint(...codePoints);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,24 @@
|
||||
[class*='emoji'] {
|
||||
font-family: var(--font-emojis-cbdt);
|
||||
}
|
||||
|
||||
/* Safari Only CSS here */
|
||||
_::-webkit-full-page-media,
|
||||
_:future,
|
||||
:root [class*='emoji'] {
|
||||
font-family: var(--font-emojis-sbix);
|
||||
}
|
||||
|
||||
/* Chrome Only CSS here */
|
||||
@media screen and (-webkit-min-device-pixel-ratio: 0) {
|
||||
.emoji {
|
||||
font-family: var(--font-emojis-svg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Firefox Only CSS here */
|
||||
@-moz-document url-prefix() {
|
||||
.emoji {
|
||||
font-family: var(--font-emojis-svg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './Emoji';
|
||||
Binary file not shown.
Binary file not shown.
@@ -213,6 +213,10 @@ const testCases: TestsCase[] = [
|
||||
name: 'Marks',
|
||||
url: 'blocks/marks',
|
||||
},
|
||||
{
|
||||
name: 'Emojis',
|
||||
url: 'blocks/emojis',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user