- // ==UserScript==
- // @name Font Customizer
- // @namespace http://tampermonkey.net/
- // @version 1.1
- // @description Customize fonts for any website through the Tampermonkey menu
- // @author Cursor, claude-3.7, and me(qooo).
- // @license MIT
- // @match *://*/*
- // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik05LjkzIDEzLjVoNC4xNEwxMiA3Ljk4ek0yMCAySDRjLTEuMSAwLTIgLjktMiAydjE2YzAgMS4xLjkgMiAyIDJoMTZjMS4xIDAgMi0uOSAyLTJWNGMwLTEuMS0uOS0yLTItMm0tNC4wNSAxNi41bC0xLjE0LTNIOS4xN2wtMS4xMiAzSDUuOTZsNS4xMS0xM2gxLjg2bDUuMTEgMTN6Ii8+PC9zdmc+
- // @grant GM_registerMenuCommand
- // @grant GM_unregisterMenuCommand
- // @grant GM_addStyle
- // @grant GM_xmlhttpRequest
- // @grant GM_setValue
- // @grant GM_getValue
- // @connect fonts.googleapis.com
- // @connect fonts.gstatic.com
- // ==/UserScript==
-
- (function () {
- "use strict";
-
- // Storage keys
- const STORAGE_KEY_PREFIX = "fontCustomizer_";
- const ENABLED_SUFFIX = "_enabled";
- const FONT_SUFFIX = "_font";
- const FONT_LIST_KEY = "fontCustomizer_globalFonts";
-
- // Common web fonts from Google Fonts
- const WEB_FONTS = [
- {
- name: "Roboto",
- family: "Roboto, sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap",
- },
- {
- name: "Open Sans",
- family: "'Open Sans', sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap",
- },
- {
- name: "Lato",
- family: "Lato, sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap",
- },
- {
- name: "Montserrat",
- family: "Montserrat, sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap",
- },
- {
- name: "Poppins",
- family: "Poppins, sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap",
- },
- {
- name: "Source Sans Pro",
- family: "'Source Sans Pro', sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;600;700&display=swap",
- },
- {
- name: "Ubuntu",
- family: "Ubuntu, sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&display=swap",
- },
- {
- name: "Nunito",
- family: "Nunito, sans-serif",
- url: "https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700&display=swap",
- },
- {
- name: "Playfair Display",
- family: "'Playfair Display', serif",
- url: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&display=swap",
- },
- {
- name: "Merriweather",
- family: "Merriweather, serif",
- url: "https://fonts.googleapis.com/css2?family=Merriweather:wght@300;400;700&display=swap",
- },
- ];
-
- // Load a web font
- function loadWebFont(fontUrl) {
- GM_xmlhttpRequest({
- method: "GET",
- url: fontUrl,
- onload: function (response) {
- const style = document.createElement("style");
- style.textContent = response.responseText;
- document.head.appendChild(style);
- },
- });
- }
-
- // Get saved fonts or initialize with empty array
- function getSavedFonts() {
- return GM_getValue(FONT_LIST_KEY, []);
- }
-
- // Save a font to the list if it doesn't exist already
- function saveFontToList(font) {
- const fonts = getSavedFonts();
- if (!fonts.includes(font)) {
- fonts.push(font);
- GM_setValue(FONT_LIST_KEY, fonts);
- }
- }
-
- // Remove a font from the saved list
- function removeFontFromList(font) {
- const fonts = getSavedFonts();
- const index = fonts.indexOf(font);
- if (index !== -1) {
- fonts.splice(index, 1);
- GM_setValue(FONT_LIST_KEY, fonts);
- }
- }
-
- // Get current hostname
- const hostname = window.location.hostname;
-
- // Storage helper functions
- function getStorageKey(suffix) {
- return STORAGE_KEY_PREFIX + hostname + suffix;
- }
-
- function isEnabledForSite() {
- return localStorage.getItem(getStorageKey(ENABLED_SUFFIX)) === "true";
- }
-
- function setEnabledForSite(enabled) {
- localStorage.setItem(getStorageKey(ENABLED_SUFFIX), enabled.toString());
- }
-
- function getFontForSite() {
- return localStorage.getItem(getStorageKey(FONT_SUFFIX)) || "";
- }
-
- function setFontForSite(font) {
- localStorage.setItem(getStorageKey(FONT_SUFFIX), font);
- }
-
- // Apply font to the website
- function applyFont() {
- if (isEnabledForSite()) {
- const font = getFontForSite();
- GM_addStyle(`
- * {
- font-family: ${font} !important;
- }
- `);
- }
- }
-
- // Remove applied font styles
- function removeAppliedFont() {
- const styleId = "font-customizer-styles";
- const existingStyle = document.getElementById(styleId);
- if (existingStyle) {
- existingStyle.remove();
- }
- applyStyles();
- }
-
- // Apply all necessary styles
- function applyStyles() {
- if (isEnabledForSite()) {
- const font = getFontForSite();
- const styleElement = document.createElement("style");
- styleElement.id = "font-customizer-styles";
- styleElement.textContent = `
- * {
- font-family: ${font} !important;
- }
- `;
- document.head.appendChild(styleElement);
- }
- }
-
- // Menu command IDs
- let toggleCommandId = null;
- let fontCommandId = null;
-
- // Register menu commands
- function registerMenuCommands() {
- if (toggleCommandId !== null) {
- GM_unregisterMenuCommand(toggleCommandId);
- }
- if (fontCommandId !== null) {
- GM_unregisterMenuCommand(fontCommandId);
- }
-
- const enabled = isEnabledForSite();
- const toggleText = enabled
- ? "🟢 Enabled on the site"
- : "🔴 Disabled on the site";
-
- toggleCommandId = GM_registerMenuCommand(toggleText, function () {
- const newEnabledState = !enabled;
- setEnabledForSite(newEnabledState);
-
- if (newEnabledState) {
- applyStyles();
- } else {
- removeAppliedFont();
- }
-
- registerMenuCommands();
- });
-
- const currentFont = getFontForSite();
- // Truncate the font name if it's too long (more than x characters)
- const truncatedFont =
- currentFont && currentFont.length > 10
- ? currentFont.substring(0, 10) + "..."
- : currentFont || "None";
-
- fontCommandId = GM_registerMenuCommand(
- `✨ Select Font (Current: ${truncatedFont})`,
- showFontSelector
- );
- }
-
- // Create and show font selector popup
- function showFontSelector() {
- // Remove existing popup if any
- const existingPopup = document.getElementById("font-customizer-popup");
- if (existingPopup) {
- existingPopup.remove();
- }
-
- // Create popup container
- const popup = document.createElement("div");
- popup.id = "font-customizer-popup";
-
- // Add styles for the popup
- GM_addStyle(`
- #font-customizer-popup {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background-color: var(--popup-bg, #ffffff);
- color: var(--popup-text, #000000);
- border: 1px solid var(--popup-border, #cccccc);
- border-radius: 12px;
- padding: 24px;
- z-index: 9999;
- min-width: 380px;
- width: 400px;
- height: fit-content;
- overflow-y: auto;
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
- animation: popup-fade-in 0.2s ease-out;
- }
-
- @keyframes popup-fade-in {
- from { opacity: 0; transform: translate(-50%, -48%); }
- to { opacity: 1; transform: translate(-50%, -50%); }
- }
-
- #font-customizer-popup h2 {
- margin-top: 0;
- margin-bottom: 20px;
- font-size: 20px;
- font-weight: 600;
- text-align: center;
- color: var(--popup-title, inherit);
- }
-
- #font-customizer-popup .font-input-container {
- margin-bottom: 16px;
- }
-
- #font-customizer-popup .font-input {
- width: 100%;
- padding: 12px;
- border: 1px solid var(--popup-border, #cccccc);
- border-radius: 8px;
- box-sizing: border-box;
- font-size: 14px;
- transition: border-color 0.2s;
- margin-bottom: 8px;
- }
-
- #font-customizer-popup .font-input:focus {
- border-color: var(--popup-button, #4a86e8);
- outline: none;
- box-shadow: 0 0 0 2px rgba(74, 134, 232, 0.2);
- }
-
- #font-customizer-popup .add-font-button {
- display: block;
- width: 100%;
- padding: 8px 16px;
- background-color: var(--popup-button, #4a86e8);
- color: white;
- border: none;
- border-radius: 8px;
- cursor: pointer;
- font-weight: 600;
- font-size: 14px;
- transition: background-color 0.2s, transform 0.1s;
- }
-
- #font-customizer-popup .add-font-button:hover {
- background-color: var(--popup-button-hover, #3b78e7);
- }
-
- #font-customizer-popup .add-font-button:active {
- transform: scale(0.98);
- }
-
- #font-customizer-popup .section-title {
- font-size: 16px;
- font-weight: 600;
- margin: 16px 0 8px 0;
- color: var(--popup-title, inherit);
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
-
- #font-customizer-popup .section-title .title-with-info {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- #font-customizer-popup .toggle-section{
- cursor: pointer;
- border: 1px solid var(--popup-border, #cccccc);
- border-radius: 8px;
- padding: 4px 8px;
- font-size: 12px;
- font-weight: 600;
- color: var(--popup-text-secondary);
- }
- #font-customizer-popup .toggle-section:hover {
- background-color: var(--popup-hover, #f5f5f5);
- }
-
- #font-customizer-popup .info-icon {
- cursor: help;
- color: var(--popup-text-secondary);
- font-size: 14px;
- position: relative;
- }
-
- #font-customizer-popup .info-tooltip {
- visibility: hidden;
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- bottom: calc(100% + 8px);
- color: var(--popup-tooltip-text);
- padding: 8px 12px;
- background-color: var(--popup-tooltip-bg);
- border-radius: 6px;
- font-size: 12px;
- font-weight: normal;
- white-space: normal;
- text-wrap: wrap;
- z-index: 10000;
- opacity: 0;
- transition: opacity 0.2s, visibility 0.2s;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- width: 250px;
- line-height: 1.4;
- }
-
- #font-customizer-popup .info-tooltip::after {
- content: '';
- position: absolute;
- top: 100%;
- left: 50%;
- transform: translateX(-50%);
- border-width: 5px;
- border-style: solid;
- border-color: var(--popup-tooltip-bg) transparent transparent transparent;
- }
-
- #font-customizer-popup .info-icon:hover .info-tooltip {
- visibility: visible;
- opacity: 1;
- }
-
- #font-customizer-popup .no-fonts-message {
- color: var(--popup-text-secondary, #666666);
- font-style: italic;
- text-align: center;
- padding: 16px 0;
- }
-
- #font-customizer-popup ul {
- list-style: none;
- padding: 0;
- margin: 0 0 16px 0;
- max-height: 200px;
- overflow-y: auto;
- border-radius: 8px;
- border: 1px solid var(--popup-border, #eaeaea);
- }
-
- #font-customizer-popup ul:empty {
- display: none;
- }
-
- #font-customizer-popup ul::-webkit-scrollbar {
- width: 8px;
- }
-
- #font-customizer-popup ul::-webkit-scrollbar-track {
- background: var(--popup-scrollbar-track, #f1f1f1);
- border-radius: 0 8px 8px 0;
- }
-
- #font-customizer-popup ul::-webkit-scrollbar-thumb {
- background: var(--popup-scrollbar-thumb, #c1c1c1);
- border-radius: 4px;
- }
-
- #font-customizer-popup ul::-webkit-scrollbar-thumb:hover {
- background: var(--popup-scrollbar-thumb-hover, #a1a1a1);
- }
-
- #font-customizer-popup li {
- padding: 10px 16px;
- cursor: pointer;
- transition: all 0.15s ease;
- border-bottom: 1px solid var(--popup-border, #eaeaea);
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
-
- #font-customizer-popup li:last-child {
- border-bottom: none;
- }
-
- #font-customizer-popup li:hover {
- background-color: var(--popup-hover, #f5f5f5);
- }
-
- #font-customizer-popup li.selected {
- background-color: var(--popup-selected, #e8f0fe);
- font-weight: 500;
- }
-
- #font-customizer-popup li.selected .font-name::before {
- content: "✓";
- margin-right: 8px;
- color: var(--popup-check, #4a86e8);
- font-weight: bold;
- }
-
- #font-customizer-popup li:not(.selected) .font-name {
- padding-left: 24px;
- }
-
- #font-customizer-popup .font-actions {
- display: flex;
- opacity: 0;
- transition: opacity 0.2s;
- }
-
- #font-customizer-popup li:hover .font-actions {
- opacity: 1;
- }
-
- #font-customizer-popup .delete-font {
- color: var(--popup-delete, #e53935);
- cursor: pointer;
- font-size: 16px;
- padding: 4px;
- border-radius: 4px;
- transition: background-color 0.2s;
- }
-
- #font-customizer-popup .delete-font:hover {
- background-color: var(--popup-delete-hover, rgba(229, 57, 53, 0.1));
- }
-
- #font-customizer-popup .close-button {
- display: block;
- width: 100%;
- margin: 16px auto 0;
- padding: 12px 16px;
- background-color: var(--popup-button-secondary, #757575);
- color: white;
- border: none;
- border-radius: 8px;
- cursor: pointer;
- font-weight: 600;
- font-size: 15px;
- transition: background-color 0.2s, transform 0.1s;
- }
-
- #font-customizer-popup .close-button:hover {
- background-color: var(--popup-button-secondary-hover, #616161);
- }
-
- #font-customizer-popup .close-button:active {
- transform: scale(0.98);
- }
-
- #font-customizer-popup .web-font-item {
- font-family: inherit;
- }
-
- #font-customizer-popup .web-font-item .font-name {
- font-family: inherit;
- }
-
- /* Dark mode detection and styles */
- @media (prefers-color-scheme: dark) {
- #font-customizer-popup {
- --popup-bg: #222222;
- --popup-text: #ffffff;
- --popup-text-secondary: #aaaaaa;
- --popup-title: #ffffff;
- --popup-border: #444444;
- --popup-hover: #333333;
- --popup-selected: #2c3e50;
- --popup-check: #64b5f6;
- --popup-button: #4a86e8;
- --popup-button-hover: #3b78e7;
- --popup-button-secondary: #616161;
- --popup-button-secondary-hover: #757575;
- --popup-delete: #f44336;
- --popup-delete-hover: rgba(244, 67, 54, 0.2);
- --popup-scrollbar-track: #333333;
- --popup-scrollbar-thumb: #555555;
- --popup-scrollbar-thumb-hover: #666666;
- --popup-tooltip-bg: #4a4a4a;
- --popup-tooltip-text: #ffffff;
- }
- }
-
- /* Light mode styles */
- @media (prefers-color-scheme: light) {
- #font-customizer-popup {
- --popup-bg: #ffffff;
- --popup-text: #333333;
- --popup-text-secondary: #666666;
- --popup-title: #222222;
- --popup-border: #eaeaea;
- --popup-hover: #f5f5f5;
- --popup-selected: #e8f0fe;
- --popup-check: #4a86e8;
- --popup-button: #4a86e8;
- --popup-button-hover: #3b78e7;
- --popup-button-secondary: #757575;
- --popup-button-secondary-hover: #616161;
- --popup-delete: #e53935;
- --popup-delete-hover: rgba(229, 57, 53, 0.1);
- --popup-scrollbar-track: #f1f1f1;
- --popup-scrollbar-thumb: #c1c1c1;
- --popup-scrollbar-thumb-hover: #a1a1a1;
- --popup-tooltip-bg: #ffffff;
- --popup-tooltip-text: #333333;
- }
- }
-
- /* Overlay to prevent clicking outside */
- #font-customizer-overlay {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0, 0, 0, 0.5);
- z-index: 9998;
- animation: overlay-fade-in 0.2s ease-out;
- }
-
- @keyframes overlay-fade-in {
- from { opacity: 0; }
- to { opacity: 1; }
- }
- `);
-
- // Create overlay to prevent clicking outside
- const overlay = document.createElement("div");
- overlay.id = "font-customizer-overlay";
- document.body.appendChild(overlay);
-
- // Add click event to overlay to close popup
- overlay.addEventListener("click", closePopup);
-
- // Create popup content
- popup.innerHTML = `
- <h2>Font Customizer</h2>
- <div class="font-input-container">
- <input type="text" id="new-font-input" class="font-input" placeholder="Enter font name (e.g., Arial, sans-serif)">
- <button id="add-font-button" class="add-font-button">Add & Apply Font</button>
- </div>
- <div class="section-title">
- <div class="title-with-info">
- <span>Your Saved Fonts</span>
- <span class="info-icon">ℹ️
- <span class="info-tooltip">Custom fonts will only work if they are installed on your system. Use exact font names for best results.</span>
- </span>
- </div>
- <span class="toggle-section" id="toggle-saved">Hide</span>
- </div>
- <ul id="saved-fonts-list"></ul>
- <div id="no-saved-fonts" class="no-fonts-message">No saved fonts or Hiden yet. Add one above!</div>
- <div class="section-title">
- <div class="title-with-info">
- <span>Web Fonts</span>
- <span class="info-icon">ℹ️
- <span class="info-tooltip">These fonts will be loaded from Google Fonts when selected. They work on any system but require internet connection.</span>
- </span>
- </div>
- <span class="toggle-section" id="toggle-web">Show</span>
- </div>
- <ul id="web-fonts-list" style="display: none;"></ul>
- <button class="close-button" id="close-popup">Close</button>
- `;
-
- document.body.appendChild(popup);
-
- // Get current font and saved fonts
- const currentFont = getFontForSite();
- const savedFonts = getSavedFonts();
-
- // Populate saved fonts list
- const savedFontsList = document.getElementById("saved-fonts-list");
- const noSavedFonts = document.getElementById("no-saved-fonts");
-
- // Show/hide no fonts message
- if (savedFonts.length === 0) {
- noSavedFonts.style.display = "block";
- } else {
- noSavedFonts.style.display = "none";
- }
-
- // Add saved fonts to the list
- savedFonts.forEach((font) => {
- addFontToList(font, savedFontsList, true);
- });
-
- // Add web fonts to the list
- const webFontsList = document.getElementById("web-fonts-list");
- WEB_FONTS.forEach((font) => {
- addFontToList(font.name, webFontsList, false, font);
- });
-
- // Toggle sections
- document
- .getElementById("toggle-saved")
- .addEventListener("click", function () {
- const savedList = document.getElementById("saved-fonts-list");
- const noSaved = document.getElementById("no-saved-fonts");
- const isHidden = savedList.style.display === "none";
-
- savedList.style.display = isHidden ? "block" : "none";
- noSaved.style.display =
- isHidden && getSavedFonts().length === 0 ? "block" : "none";
- this.textContent = isHidden ? "Hide" : "Show";
- });
-
- document
- .getElementById("toggle-web")
- .addEventListener("click", function () {
- const webList = document.getElementById("web-fonts-list");
- const isHidden = webList.style.display === "none";
-
- webList.style.display = isHidden ? "block" : "none";
- this.textContent = isHidden ? "Hide" : "Show";
- });
-
- // Handle new font input
- const newFontInput = document.getElementById("new-font-input");
- const addFontButton = document.getElementById("add-font-button");
-
- // Focus the input field
- newFontInput.focus();
-
- // Add font when button is clicked
- addFontButton.addEventListener("click", addNewFont);
-
- // Add font when Enter is pressed
- newFontInput.addEventListener("keydown", (e) => {
- if (e.key === "Enter") {
- addNewFont();
- }
- });
-
- // Function to add a font to the list
- function addFontToList(font, listElement, isSaved = false, webFont = null) {
- const li = document.createElement("li");
- if (webFont) {
- li.classList.add("web-font-item");
- li.style.fontFamily = webFont.family;
- }
-
- li.innerHTML = `
- <span class="font-name">${font}</span>
- ${
- isSaved
- ? `
- <div class="font-actions">
- <span class="delete-font" title="Remove font">🗑️</span>
- </div>
- `
- : ""
- }
- `;
-
- if (font === currentFont) {
- li.classList.add("selected");
- }
-
- // Select font when clicked
- li.addEventListener("click", (e) => {
- if (e.target.classList.contains("delete-font")) {
- return;
- }
-
- // Remove selected class from all items
- document
- .querySelectorAll("#font-customizer-popup li")
- .forEach((item) => {
- item.classList.remove("selected");
- });
-
- // Add selected class to clicked item
- li.classList.add("selected");
-
- // Set the selected font
- if (webFont) {
- setFontForSite(webFont.family);
- loadWebFont(webFont.url);
- } else {
- setFontForSite(font);
- }
-
- // Apply the font if enabled
- if (isEnabledForSite()) {
- removeAppliedFont();
- applyStyles();
- }
-
- // Update menu commands
- registerMenuCommands();
- });
-
- // Delete font when delete button is clicked (only for saved fonts)
- if (isSaved) {
- const deleteButton = li.querySelector(".delete-font");
- deleteButton.addEventListener("click", (e) => {
- e.stopPropagation();
-
- removeFontFromList(font);
- li.remove();
-
- if (font === currentFont) {
- const remainingFonts = getSavedFonts();
- if (remainingFonts.length > 0) {
- setFontForSite(remainingFonts[0]);
- const firstFont = document.querySelector("#saved-fonts-list li");
- if (firstFont) {
- firstFont.classList.add("selected");
- }
- } else {
- setFontForSite("");
- }
-
- if (isEnabledForSite()) {
- removeAppliedFont();
- applyStyles();
- }
-
- registerMenuCommands();
- }
-
- if (savedFontsList.children.length === 0) {
- noSavedFonts.style.display = "block";
- }
- });
- }
-
- listElement.appendChild(li);
- }
-
- // Function to add a new font
- function addNewFont() {
- const fontName = newFontInput.value.trim();
- if (fontName) {
- saveFontToList(fontName);
- newFontInput.value = "";
- noSavedFonts.style.display = "none";
- addFontToList(fontName, savedFontsList, true);
- setFontForSite(fontName);
-
- document
- .querySelectorAll("#font-customizer-popup li")
- .forEach((item) => {
- item.classList.remove("selected");
- });
-
- const newFontElement = Array.from(
- document.querySelectorAll("#saved-fonts-list li")
- ).find((li) => li.querySelector(".font-name").textContent === fontName);
- if (newFontElement) {
- newFontElement.classList.add("selected");
- }
-
- if (isEnabledForSite()) {
- removeAppliedFont();
- applyStyles();
- }
-
- registerMenuCommands();
- }
- }
-
- // Function to close the popup
- function closePopup() {
- const popup = document.getElementById("font-customizer-popup");
- const overlay = document.getElementById("font-customizer-overlay");
- if (popup) popup.remove();
- if (overlay) overlay.remove();
- }
-
- // Close button functionality
- document
- .getElementById("close-popup")
- .addEventListener("click", closePopup);
-
- // Prevent closing when clicking on the popup itself
- popup.addEventListener("click", (e) => {
- e.stopPropagation();
- });
-
- // Allow Escape key to close the popup
- document.addEventListener("keydown", function handleEscape(e) {
- if (e.key === "Escape") {
- closePopup();
- document.removeEventListener("keydown", handleEscape);
- }
- });
- }
-
- // Initialize
- function init() {
- registerMenuCommands();
- applyStyles();
-
- const observer = new MutationObserver(function (mutations) {
- if (!isEnabledForSite()) return;
-
- const styleElement = document.getElementById("font-customizer-styles");
- if (!styleElement) {
- applyStyles();
- }
- });
-
- observer.observe(document.documentElement, {
- childList: true,
- subtree: true,
- });
- }
-
- // Run the script
- init();
- })();