298 lines
8.8 KiB
JavaScript
298 lines
8.8 KiB
JavaScript
// fonts.jsx - Centralized Font Management System
|
|
|
|
// =============================================================================
|
|
// FONT IMPORTS - All Fontsource imports in one place
|
|
// =============================================================================
|
|
|
|
// Montserrat - Modern sans-serif, great for UI text
|
|
import '@fontsource/montserrat/400-italic.css'; // Italic
|
|
import '@fontsource/montserrat/400.css'; // Normal
|
|
import '@fontsource/montserrat/700-italic.css'; // Bold Italic
|
|
import '@fontsource/montserrat/700.css'; // Bold
|
|
|
|
// Bungee - Display font for headers and watermarks
|
|
import '@fontsource/bungee/400.css';
|
|
|
|
// Optional: Add more fonts here as needed
|
|
// import '@fontsource/inter/400.css';
|
|
// import '@fontsource/roboto/400.css';
|
|
|
|
// NOTE: Make sure to install these packages:
|
|
// npm install @fontsource/montserrat @fontsource/bungee
|
|
|
|
// =============================================================================
|
|
// FONT CONFIGURATION - Single source of truth for all font data
|
|
// =============================================================================
|
|
|
|
const FONTS = {
|
|
montserrat: {
|
|
name: 'Montserrat',
|
|
family: 'Montserrat',
|
|
category: 'sans-serif',
|
|
weights: [400, 700],
|
|
styles: ['normal', 'italic'],
|
|
description: 'Modern geometric sans-serif',
|
|
preview: 'The quick brown fox jumps over the lazy dog',
|
|
},
|
|
bungee: {
|
|
name: 'Bungee',
|
|
family: 'Bungee',
|
|
category: 'display',
|
|
weights: [400],
|
|
styles: ['normal'],
|
|
description: 'Decorative display font',
|
|
preview: 'memefa.st',
|
|
},
|
|
arial: {
|
|
name: 'Arial',
|
|
family: 'Arial',
|
|
category: 'system',
|
|
weights: [400, 700],
|
|
styles: ['normal', 'italic'],
|
|
description: 'System fallback font',
|
|
preview: 'System default font',
|
|
},
|
|
};
|
|
|
|
// =============================================================================
|
|
// FONT UTILITIES - Helper functions for font operations
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Get available fonts as array for UI components
|
|
* @returns {Array} Array of font objects for dropdowns/selectors
|
|
*/
|
|
const getAvailableFonts = () => {
|
|
return Object.values(FONTS).map((font) => ({
|
|
name: font.name,
|
|
value: font.family,
|
|
category: font.category,
|
|
description: font.description,
|
|
preview: font.preview,
|
|
}));
|
|
};
|
|
|
|
/**
|
|
* Get font family name by key
|
|
* @param {string} fontKey - Key from FONTS object
|
|
* @returns {string} Font family name
|
|
*/
|
|
const getFontFamily = (fontKey) => {
|
|
return FONTS[fontKey]?.family || FONTS.montserrat.family;
|
|
};
|
|
|
|
/**
|
|
* Get CSS font-style value based on element properties
|
|
* @param {Object} element - Text element with font properties
|
|
* @returns {string} CSS font-style value
|
|
*/
|
|
const getFontStyle = (element) => {
|
|
const isBold = element.fontWeight === 'bold' || element.fontWeight === 700;
|
|
const isItalic = element.fontStyle === 'italic';
|
|
|
|
if (isBold && isItalic) {
|
|
return 'bold italic';
|
|
} else if (isBold) {
|
|
return 'bold';
|
|
} else if (isItalic) {
|
|
return 'italic';
|
|
} else {
|
|
return 'normal';
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get numeric font weight
|
|
* @param {string|number} fontWeight - Font weight value
|
|
* @returns {number} Numeric font weight
|
|
*/
|
|
const getFontWeight = (fontWeight) => {
|
|
if (fontWeight === 'bold') return 700;
|
|
if (typeof fontWeight === 'number') return fontWeight;
|
|
return 400; // default normal
|
|
};
|
|
|
|
/**
|
|
* Validate if font supports specific weight/style combination
|
|
* @param {string} fontFamily - Font family name
|
|
* @param {string|number} fontWeight - Font weight
|
|
* @param {string} fontStyle - Font style
|
|
* @returns {boolean} Whether combination is supported
|
|
*/
|
|
const isFontCombinationSupported = (fontFamily, fontWeight, fontStyle) => {
|
|
const font = Object.values(FONTS).find((f) => f.family === fontFamily);
|
|
if (!font) return false;
|
|
|
|
const numericWeight = getFontWeight(fontWeight);
|
|
const hasWeight = font.weights.includes(numericWeight);
|
|
const hasStyle = font.styles.includes(fontStyle || 'normal');
|
|
|
|
return hasWeight && hasStyle;
|
|
};
|
|
|
|
/**
|
|
* Get fallback font if current combination isn't supported
|
|
* @param {string} fontFamily - Desired font family
|
|
* @param {string|number} fontWeight - Desired font weight
|
|
* @param {string} fontStyle - Desired font style
|
|
* @returns {Object} Safe font configuration
|
|
*/
|
|
const getSafeFontConfig = (fontFamily, fontWeight, fontStyle) => {
|
|
if (isFontCombinationSupported(fontFamily, fontWeight, fontStyle)) {
|
|
return {
|
|
fontFamily,
|
|
fontWeight: getFontWeight(fontWeight),
|
|
fontStyle: fontStyle || 'normal',
|
|
};
|
|
}
|
|
|
|
// Fallback to Montserrat normal
|
|
return {
|
|
fontFamily: FONTS.montserrat.family,
|
|
fontWeight: 400,
|
|
fontStyle: 'normal',
|
|
};
|
|
};
|
|
|
|
// =============================================================================
|
|
// FONT LOADING UTILITIES
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Ensure specific fonts are loaded before use
|
|
* @param {Array} fontSpecs - Array of font specifications
|
|
* @returns {Promise} Promise that resolves when fonts are loaded
|
|
*/
|
|
const loadFonts = async (fontSpecs = []) => {
|
|
if (!('fonts' in document)) {
|
|
console.warn('Font Loading API not supported');
|
|
return;
|
|
}
|
|
|
|
const fontPromises = fontSpecs.map(({ fontFamily, fontWeight, fontStyle, fontSize = 16 }) => {
|
|
const weight = getFontWeight(fontWeight);
|
|
const style = fontStyle || 'normal';
|
|
const fontSpec = `${weight} ${style} ${fontSize}px "${fontFamily}"`;
|
|
|
|
return document.fonts.load(fontSpec).catch((err) => {
|
|
console.warn(`Failed to load font: ${fontSpec}`, err);
|
|
return null;
|
|
});
|
|
});
|
|
|
|
await Promise.all(fontPromises);
|
|
|
|
// Allow fonts to settle
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
};
|
|
|
|
/**
|
|
* Load fonts used in timeline elements
|
|
* @param {Array} timelineElements - Array of timeline elements
|
|
* @returns {Promise} Promise that resolves when all fonts are loaded
|
|
*/
|
|
const loadTimelineFonts = async (timelineElements = []) => {
|
|
const fontSpecs = new Set();
|
|
|
|
// Collect text element fonts
|
|
timelineElements
|
|
.filter((el) => el.type === 'text')
|
|
.forEach((text) => {
|
|
const fontFamily = text.fontFamily || FONTS.montserrat.family;
|
|
const fontWeight = text.fontWeight;
|
|
const fontStyle = text.fontStyle;
|
|
|
|
fontSpecs.add(
|
|
JSON.stringify({
|
|
fontFamily,
|
|
fontWeight: getFontWeight(fontWeight),
|
|
fontStyle: fontStyle || 'normal',
|
|
fontSize: Math.max(text.fontSize || 16, 16), // Ensure minimum size for loading
|
|
}),
|
|
);
|
|
});
|
|
|
|
// Add watermark font (Bungee)
|
|
fontSpecs.add(
|
|
JSON.stringify({
|
|
fontFamily: FONTS.bungee.family,
|
|
fontWeight: 400,
|
|
fontStyle: 'normal',
|
|
fontSize: 20,
|
|
}),
|
|
);
|
|
|
|
// Convert back to objects and load
|
|
const uniqueFontSpecs = Array.from(fontSpecs).map((spec) => JSON.parse(spec));
|
|
await loadFonts(uniqueFontSpecs);
|
|
};
|
|
|
|
// =============================================================================
|
|
// PRESET CONFIGURATIONS
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Default text element configuration
|
|
*/
|
|
const DEFAULT_TEXT_CONFIG = {
|
|
fontFamily: FONTS.montserrat.family,
|
|
fontSize: 24,
|
|
fontWeight: 700, // Bold by default
|
|
fontStyle: 'normal',
|
|
fill: '#ffffff',
|
|
stroke: '#000000',
|
|
strokeWidth: 2,
|
|
};
|
|
|
|
/**
|
|
* Watermark configuration
|
|
*/
|
|
const WATERMARK_CONFIG = {
|
|
fontFamily: FONTS.bungee.family,
|
|
fontSize: 20,
|
|
fontWeight: 400,
|
|
fontStyle: 'normal',
|
|
fill: 'white',
|
|
stroke: 'black',
|
|
strokeWidth: 2,
|
|
opacity: 0.5,
|
|
};
|
|
|
|
// =============================================================================
|
|
// EXPORTS
|
|
// =============================================================================
|
|
|
|
// =============================================================================
|
|
// EXPORTS
|
|
// =============================================================================
|
|
|
|
// Named exports for individual functions
|
|
export {
|
|
DEFAULT_TEXT_CONFIG,
|
|
FONTS,
|
|
WATERMARK_CONFIG,
|
|
getAvailableFonts,
|
|
getFontFamily,
|
|
getFontStyle,
|
|
getFontWeight,
|
|
getSafeFontConfig,
|
|
isFontCombinationSupported,
|
|
loadFonts,
|
|
loadTimelineFonts,
|
|
};
|
|
|
|
// Default export with all functions grouped
|
|
export default {
|
|
FONTS,
|
|
getAvailableFonts,
|
|
getFontFamily,
|
|
getFontStyle,
|
|
getFontWeight,
|
|
isFontCombinationSupported,
|
|
getSafeFontConfig,
|
|
loadFonts,
|
|
loadTimelineFonts,
|
|
DEFAULT_TEXT_CONFIG,
|
|
WATERMARK_CONFIG,
|
|
};
|