From 3c19cf1d3264818c7beff61bd677b0843a59bc18 Mon Sep 17 00:00:00 2001 From: jrosh Date: Thu, 29 May 2025 15:04:16 +0200 Subject: [PATCH] update font and style handling --- index.html | 5 +++ src/assets/main.css | 39 ++++++++++++++++- src/assets/{base.css => reset.css} | 13 ------ src/components/FontSelector.vue | 8 +++- src/composables/useStyles.ts | 67 +++++++++++++++++------------- 5 files changed, 87 insertions(+), 45 deletions(-) rename src/assets/{base.css => reset.css} (70%) diff --git a/index.html b/index.html index 64333fa..8483b55 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,11 @@ + + + + + diff --git a/src/assets/main.css b/src/assets/main.css index 8e9efa9..98f0ee0 100755 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,4 +1,41 @@ -@import './base.css'; +@import './reset.css'; + + @font-face { + font-family: 'Fast Sans'; + src: url('/e-inn-reader/fonts/Fast_Sans.ttf') format('truetype'); + font-display: swap; +} + +@font-face { + font-family: 'Fast Serif'; + src: url('/e-inn-reader/fonts/Fast_Serif.ttf') format('truetype'); + font-display: swap; +} + +@font-face { + font-family: 'Fast Mono'; + src: url('/e-inn-reader/fonts/Fast_Mono.ttf') format('truetype'); + font-display: swap; +} + +@font-face { + font-family: 'Fast Dotted'; + src: url('/e-inn-reader/fonts/Fast_Sans_Dotted.ttf') format('truetype'); + font-display: swap; +} + +:root { + /* User defined colors + --text-color + --background-color + --accent-color + */ + --muted-text: color-mix(in srgb, var(--text-color) 60%, transparent); + --divider-color: color-mix(in srgb, var(--text-color) 10%, transparent); + --green: #0a0; + --red: #a00; + --blue: #00c; +} #app{ width: 100%; diff --git a/src/assets/base.css b/src/assets/reset.css similarity index 70% rename from src/assets/base.css rename to src/assets/reset.css index 1de23d2..3a008c9 100755 --- a/src/assets/base.css +++ b/src/assets/reset.css @@ -1,16 +1,3 @@ -:root { - /* custom colors - --text-color - --background-color - --accent-color - */ - --muted-text: color-mix(in srgb, var(--text-color) 60%, transparent); - --divider-color: color-mix(in srgb, var(--text-color) 10%, transparent); - --green: #0a0; - --red: #a00; - --blue: #00c; -} - /* reset.css */ * { margin: 0; diff --git a/src/components/FontSelector.vue b/src/components/FontSelector.vue index da9aae0..ecca8b6 100644 --- a/src/components/FontSelector.vue +++ b/src/components/FontSelector.vue @@ -46,8 +46,14 @@ export default defineComponent({ }, emits: ['update:modelValue'], setup(props, { emit }) { - // Default font options if none provided const defaultFonts: FontOption[] = [ + // Custom Fast fonts https://github.com/Born2Root/Fast-Font + { label: 'Fast Sans', value: '"Fast Sans", sans-serif' }, + { label: 'Fast Serif', value: '"Fast Serif", serif' }, + { label: 'Fast Mono', value: '"Fast Mono", monospace' }, + { label: 'Fast Dotted', value: '"Fast Dotted", sans-serif' }, + + // Standard system fonts { label: 'Arial', value: 'Arial, sans-serif' }, { label: 'Times New Roman', value: 'Times New Roman, serif' }, { label: 'Georgia', value: 'Georgia, serif' }, diff --git a/src/composables/useStyles.ts b/src/composables/useStyles.ts index a8c4616..975278f 100644 --- a/src/composables/useStyles.ts +++ b/src/composables/useStyles.ts @@ -1,5 +1,5 @@ // src/composables/useStyles.ts -import { ref, watch, nextTick, computed } from 'vue'; +import { ref, watch, nextTick } from 'vue'; import { type RenditionTheme, type StylesOptions } from '../types/styles'; export function useStyles(options: StylesOptions = {}) { @@ -12,16 +12,6 @@ export function useStyles(options: StylesOptions = {}) { const stylesModalOpen = ref(false); const rendition = ref(null); - const baseUrl = computed(() => { - return import.meta.env.VITE_BASE_URL; - }); - const customFonts = { - 'Fast Sans': `${baseUrl}fonts/Fast_Sans.ttf`, - 'Fast Serif': `${baseUrl}fonts/Fast_Serif.ttf`, - 'Fast Mono': `${baseUrl}fonts/Fast_Mono.ttf`, - 'Fast Dotted': `${baseUrl}fonts/Fast_Sans_Dotted.ttf` - }; - // Track if hooks are registered to avoid duplicate registration let hooksRegistered = false; @@ -63,21 +53,42 @@ export function useStyles(options: StylesOptions = {}) { setMeta('theme-color', backgroundColor.value); }; - // Create CSS with font-face declarations for epub.js - const createFontFaceCSS = (): string => { - let fontCSS = ''; + // Import stylesheets from document to iframe + const importDocumentStylesheets = (doc: Document) => { + // Skip if already imported + if (doc.querySelector('[data-imported-stylesheets]')) return; - for (const [fontName, fontUrl] of Object.entries(customFonts)) { - fontCSS += ` - @font-face { - font-family: '${fontName}'; - src: url('${fontUrl}') format('truetype'); - font-display: swap; + // Create marker to avoid duplicates + const markerStyle = doc.createElement('style'); + markerStyle.setAttribute('data-imported-stylesheets', 'true'); + markerStyle.textContent = '/* Stylesheets imported */'; + doc.head.appendChild(markerStyle); + + const mainStylesheets = Array.from(document.styleSheets); + + // Check each stylesheet for font-face rules and copy them + let fontFaceCss = ''; + mainStylesheets.forEach(stylesheet => { + try { + // Access rules safely (might throw error for cross-origin sheets) + const rules = stylesheet.cssRules || stylesheet.rules; + if (!rules) return; + + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; + if (rule.constructor.name === 'CSSFontFaceRule') { + fontFaceCss += rule.cssText + '\n'; + } } - `; - } + } catch (e) {} // Silently ignore cross-origin stylesheet errors + }); - return fontCSS; + if (fontFaceCss) { + const fontStyle = doc.createElement('style'); + fontStyle.setAttribute('data-custom-styles', 'imported-fonts'); + fontStyle.textContent = fontFaceCss; + doc.head.appendChild(fontStyle); + } }; // Apply styles to a specific content document @@ -85,15 +96,11 @@ export function useStyles(options: StylesOptions = {}) { const head = doc.head || doc.getElementsByTagName('head')[0]; if (!head) return; - // Remove existing custom styles to avoid duplicates - const existingStyles = head.querySelectorAll('[data-custom-styles]'); + // Remove existing theme styles to avoid duplicates + const existingStyles = head.querySelectorAll('[data-custom-styles="theme"]'); existingStyles.forEach(style => style.remove()); - // Create and inject font styles - const fontStyle = doc.createElement('style'); - fontStyle.setAttribute('data-custom-styles', 'fonts'); - fontStyle.textContent = createFontFaceCSS(); - head.appendChild(fontStyle); + importDocumentStylesheets(doc); // Create and inject theme styles const themeStyle = doc.createElement('style');