FontLoader: Overhaul

This commit is contained in:
thororen 2026-09-26 21:49:09 -04:00
parent 4b2c093346
commit 359503153e
No known key found for this signature in database
2 changed files with 54 additions and 50 deletions

View file

@ -6,12 +6,16 @@
import "./styles.css";
import { definePluginSettings, migratePluginSetting } from "@api/Settings";
import { isPluginEnabled } from "@api/PluginManager";
import { definePluginSettings } from "@api/Settings";
import { managedStyleRootNode } from "@api/Styles";
import { Button } from "@components/Button";
import { Card } from "@components/Card";
import { HeadingSecondary, HeadingTertiary } from "@components/Heading";
import { Paragraph } from "@components/Paragraph";
import { debounce } from "@shared/debounce";
import { EquicordDevs } from "@utils/constants";
import { createAndAppendStyle } from "@utils/css";
import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
@ -32,13 +36,8 @@ interface GoogleFontMetadata {
}>;
}
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");
};
const fontImport = (family: string, weights: string) =>
`@import url("https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:wght@${weights}&display=swap");`;
async function searchGoogleFonts(query: string) {
try {
@ -70,47 +69,35 @@ async function searchGoogleFonts(query: string) {
}
}
const preloadFont = (family: string) =>
loadFontStyle(createGoogleFontUrl(family, ":wght@400;700"));
let fontStyle: HTMLStyleElement | null = null;
let styleElement: HTMLStyleElement | null = null;
const applyFont = async (fontFamily: string) => {
function applyFont(fontFamily: string) {
if (!fontFamily) {
styleElement?.remove();
styleElement = null;
fontStyle?.remove();
fontStyle = null;
return;
}
try {
if (!styleElement) {
styleElement = document.createElement("style");
document.head.appendChild(styleElement);
fontStyle ??= createAndAppendStyle("vc-fontloader", managedStyleRootNode);
fontStyle.textContent = `
${fontImport(fontFamily, "300;400;500;600;700")}
* {
--font-primary: '${fontFamily}', sans-serif !important;
--font-display: '${fontFamily}', sans-serif !important;
--font-headline: '${fontFamily}', sans-serif !important;
${settings.store.applyOnCodeBlocks ? `--font-code: '${fontFamily}', monospace !important;` : ""}
}
loadFontStyle(createGoogleFontUrl(fontFamily, ":wght@300;400;500;600;700"));
styleElement.textContent = `
* {
--font-primary: '${fontFamily}', sans-serif !important;
--font-display: '${fontFamily}', sans-serif !important;
--font-headline: '${fontFamily}', sans-serif !important;
${settings.store.applyOnCodeBlocks ? "--font-code: '${fontFamily}', monospace !important;" : ""}
}
`;
} catch (err) {
console.error("Failed to load font:", err);
}
};
`;
}
function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) => void; }) {
const [query, setQuery] = React.useState("");
const [results, setResults] = React.useState<GoogleFontMetadata[]>([]);
const [loading, setLoading] = React.useState(false);
const previewStyles = React.useRef<HTMLStyleElement[]>([]);
const previewStyle = React.useRef<HTMLStyleElement | null>(null);
const { selectedFont } = settings.use(["selectedFont"]);
React.useEffect(() => () => {
previewStyles.current.forEach(style => style.remove());
}, []);
React.useEffect(() => () => previewStyle.current?.remove(), []);
const debouncedSearch = debounce(async (value: string) => {
setLoading(true);
@ -121,8 +108,8 @@ function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) =
}
const fonts = await searchGoogleFonts(value);
previewStyles.current.forEach(style => style.remove());
previewStyles.current = await Promise.all(fonts.map(f => preloadFont(f.family)));
previewStyle.current ??= createAndAppendStyle("vc-fontloader-previews", managedStyleRootNode);
previewStyle.current.textContent = fonts.map(f => fontImport(f.family, "400;700")).join("\n");
setResults(fonts);
setLoading(false);
}, 300);
@ -137,6 +124,22 @@ function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) =
<HeadingSecondary>Search Google Fonts</HeadingSecondary>
<Paragraph className={Margins.bottom8}>Click on any font to apply it.</Paragraph>
{selectedFont && (
<div className={classes(Margins.bottom8, "eq-googlefonts-current")}>
<Paragraph>Current font: <strong>{selectedFont}</strong></Paragraph>
<Button
variant="secondary"
size="small"
onClick={() => {
settings.store.selectedFont = "";
applyFont("");
}}
>
Reset Font
</Button>
</div>
)}
<TextInput
value={query}
onChange={e => handleSearch(e)}
@ -169,7 +172,6 @@ function GoogleFontSearch({ onSelect }: { onSelect: (font: GoogleFontMetadata) =
);
}
migratePluginSetting("FontLoader", "applyOnCodeBlocks", "applyOnClodeBlocks");
const settings = definePluginSettings({
selectedFont: {
type: OptionType.STRING,
@ -184,7 +186,7 @@ const settings = definePluginSettings({
<GoogleFontSearch
onSelect={font => {
settings.store.selectedFont = font.family;
applyFont(font.family);
if (isPluginEnabled("FontLoader")) applyFont(font.family);
}}
/>
)
@ -203,17 +205,11 @@ export default definePlugin({
authors: [EquicordDevs.vmohammad],
settings,
async start() {
const savedFont = settings.store.selectedFont;
if (savedFont) {
await applyFont(savedFont);
}
start() {
applyFont(settings.store.selectedFont);
},
stop() {
if (styleElement) {
styleElement.remove();
styleElement = null;
}
applyFont("");
}
});

View file

@ -1,6 +1,14 @@
.eq-googlefonts-current {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.eq-googlefonts-results {
max-height: 400px;
overflow-y: auto;
scrollbar-width: none;
}
.eq-googlefonts-card {