feat(refactor): fontLoader (#148)

This commit is contained in:
vMohammad 2025-02-12 22:18:51 +03:00 committed by GitHub
parent 76c540bd73
commit a0d0823def
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -13,6 +13,7 @@ import { Margins } from "@utils/margins";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { Card, Forms, React, TextInput } from "@webpack/common"; import { Card, Forms, React, TextInput } from "@webpack/common";
interface GoogleFontMetadata { interface GoogleFontMetadata {
family: string; family: string;
displayName: string; displayName: string;
@ -27,7 +28,15 @@ interface GoogleFontMetadata {
}>; }>;
}>; }>;
} }
const userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome / 128.0.0.0 Safari / 537.36";
const createGoogleFontUrl = (family: string, options = "") =>
`https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}${options}&display=swap`;
const loadFontStyle = (url: string) => {
document.head.insertAdjacentHTML("beforeend", `<link rel="stylesheet" href="${url}">`);
return document.createElement("style");
};
async function searchGoogleFonts(query: string) { async function searchGoogleFonts(query: string) {
try { try {
const response = await fetch("https://fonts.google.com/$rpc/fonts.fe.catalog.actions.metadata.MetadataService/FontSearch", { const response = await fetch("https://fonts.google.com/$rpc/fonts.fe.catalog.actions.metadata.MetadataService/FontSearch", {
@ -36,14 +45,12 @@ async function searchGoogleFonts(query: string) {
"content-type": "application/json+protobuf", "content-type": "application/json+protobuf",
"x-user-agent": "grpc-web-javascript/0.1" "x-user-agent": "grpc-web-javascript/0.1"
}, },
// the nulls are optional filters
body: JSON.stringify([[query, null, null, null, null, null, 1], [5], null, 16]) body: JSON.stringify([[query, null, null, null, null, null, 1], [5], null, 16])
}); });
const data = await response.json(); const data = await response.json();
if (!data?.[1]) return []; if (!data?.[1]) return [];
// god please help me return data[1].map(([_, fontData]: [string, any[]]) => ({
const fonts = data[1].map(([_, fontData]: [string, any[]]) => ({
family: fontData[0], family: fontData[0],
displayName: fontData[1], displayName: fontData[1],
authors: fontData[2], authors: fontData[2],
@ -54,81 +61,52 @@ async function searchGoogleFonts(query: string) {
})) }))
})) }))
})); }));
return fonts;
// LETS GO IT FUCKING WORKSSSSSSSSSSSS
} catch (err) { } catch (err) {
console.error("Failed to fetch fonts:", err); console.error("Failed to fetch fonts:", err);
return []; return [];
} }
} }
async function preloadFont(family: string) { const preloadFont = (family: string) =>
// https://developers.google.com/fonts/docs/css2 loadFontStyle(createGoogleFontUrl(family, "&text=The quick brown fox jumps over the lazy dog"));
const url = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}&text=The quick brown fox jumps over the lazy dog&display=swap`;
const css = await fetch(url, {
headers: {
"User-Agent": userAgent
}
}).then(r => r.text());
const style = document.createElement("style"); let styleElement: HTMLStyleElement | null = null;
style.textContent = css;
document.head.appendChild(style);
return style;
}
async function applyFont(fontFamily: string) { const applyFont = async (fontFamily: string) => {
if (!fontFamily) { if (!fontFamily) {
if (styleElement) { styleElement?.remove();
styleElement.remove(); styleElement = null;
styleElement = null;
}
return; return;
} }
try { try {
const response = await fetch(
`https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontFamily)}:wght@300;400;500;600;700&display=swap`,
{
headers: {
"User-Agent": userAgent
}
}
);
const css = await response.text();
if (!styleElement) { if (!styleElement) {
styleElement = document.createElement("style"); styleElement = document.createElement("style");
document.head.appendChild(styleElement); document.head.appendChild(styleElement);
} }
loadFontStyle(createGoogleFontUrl(fontFamily, ":wght@300;400;500;600;700"));
styleElement.textContent = ` styleElement.textContent = `
${css} * {
* { --font-primary: '${fontFamily}', sans-serif !important;
--font-primary: '${fontFamily}', sans-serif !important; --font-display: '${fontFamily}', sans-serif !important;
--font-display: '${fontFamily}', sans-serif !important; --font-headline: '${fontFamily}', sans-serif !important;
--font-headline: '${fontFamily}', sans-serif !important; --font-code: '${fontFamily}', monospace !important;
--font-code: '${fontFamily}', monospace !important; }
} `;
`;
} catch (err) { } catch (err) {
console.error("Failed to load font:", err); console.error("Failed to load font:", err);
} }
} };
function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) => void; }) { function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) => void; }) {
const [query, setQuery] = React.useState(""); const [query, setQuery] = React.useState("");
const [results, setResults] = React.useState<GoogleFontMetadata[]>([]); const [results, setResults] = React.useState<GoogleFontMetadata[]>([]);
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
const previewStyles = React.useRef<HTMLStyleElement[]>([]); const previewStyles = React.useRef<HTMLStyleElement[]>([]);
React.useEffect(() => () => {
React.useEffect(() => { previewStyles.current.forEach(style => style.remove());
return () => {
previewStyles.current.forEach(style => style.remove());
};
}, []); }, []);
const debouncedSearch = debounce(async (value: string) => { const debouncedSearch = debounce(async (value: string) => {
@ -138,22 +116,18 @@ function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) =
setLoading(false); setLoading(false);
return; return;
} }
const fonts = await searchGoogleFonts(value); const fonts = await searchGoogleFonts(value);
previewStyles.current.forEach(style => style.remove()); previewStyles.current.forEach(style => style.remove());
previewStyles.current = []; previewStyles.current = await Promise.all(fonts.map(f => preloadFont(f.family)));
const styles = await Promise.all(fonts.map(f => preloadFont(f.family)));
previewStyles.current = styles;
setResults(fonts); setResults(fonts);
setLoading(false); setLoading(false);
}, 300); }, 300);
const handleSearch = React.useCallback((value: string) => { const handleSearch = (e: string) => {
setQuery(value); setQuery(e);
debouncedSearch(value); debouncedSearch(e);
}, []); };
return ( return (
<Forms.FormSection> <Forms.FormSection>
@ -193,8 +167,6 @@ function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) =
); );
} }
let styleElement: HTMLStyleElement | null = null;
const settings = definePluginSettings({ const settings = definePluginSettings({
selectedFont: { selectedFont: {
type: OptionType.STRING, type: OptionType.STRING,