-
Notifications
You must be signed in to change notification settings - Fork 12
/
fonts.js
159 lines (141 loc) · 5.57 KB
/
fonts.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
const fontUrlInput = document.getElementById('fontUrlInput');
const addFontButton = document.getElementById('addFontButton');
const progressBar = document.getElementById('progressBar');
const progressBarInner = progressBar.querySelector('.progress-bar');
const previewText = document.getElementById('previewText');
const fontPreviews = document.getElementById('fontPreviews');
let fonts = ['Arial', 'Courier', 'Georgia'];
let storedFonts = JSON.parse(localStorage.getItem('customFonts')) || [];
fonts = [...fonts, ...storedFonts.map(f => f.family)];
function updateFontPreviews() {
fontPreviews.innerHTML = '';
fonts.forEach(font => {
const card = document.createElement('div');
card.className = 'col';
card.innerHTML = `
<div class="card font-preview-card">
<div class="card-body">
<h5 class="card-title">${font}</h5>
<p class="card-text font-preview-text" style="font-family: '${font}';">
${previewText.value}
</p>
</div>
${font !== 'Arial' && font !== 'Courier' && font !== 'Georgia' ?
`<button class="delete-font-btn" data-font="${font}">X</button>` : ''}
</div>
`;
fontPreviews.appendChild(card);
});
}
function addFontFace(fontFamily, fontData) {
const fontFace = new FontFace(fontFamily, fontData);
fontFace.load().then(function(loadedFace) {
document.fonts.add(loadedFace);
updateFontPreviews();
}).catch(function(error) {
console.error('Error loading font:', error);
});
}
storedFonts.forEach(font => addFontFace(font.family, font.data));
updateFontPreviews();
function showProgress(show) {
progressBar.classList.toggle('d-none', !show);
progressBarInner.style.width = '0%';
}
function updateProgress(percent) {
progressBarInner.style.width = `${percent}%`;
}
async function fetchWithProgress(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
let chunks = [];
while(true) {
const {done, value} = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
updateProgress((receivedLength / contentLength) * 100);
}
let chunksAll = new Uint8Array(receivedLength);
let position = 0;
for(let chunk of chunks) {
chunksAll.set(chunk, position);
position += chunk.length;
}
return chunksAll;
}
function resolveUrl(baseUrl, relativeUrl) {
return new URL(relativeUrl, baseUrl).href;
}
function extractFontUrl(css) {
const urlMatch = css.match(/url\s*\(\s*(['"]?)(.+?\.woff2?(?:\?[^'")]+)?)\1\s*\)/i);
return urlMatch ? urlMatch[2] : null;
}
function extractFontFamily(css) {
const familyMatch = css.match(/font-family:\s*(['"])?(.*?)\1?;/i);
return familyMatch ? familyMatch[2].trim() : null;
}
addFontButton.addEventListener('click', async () => {
const fontUrl = fontUrlInput.value;
if (fontUrl) {
showProgress(true);
try {
if (fontUrl.endsWith('.css')) {
const cssResponse = await fetch(fontUrl);
const css = await cssResponse.text();
const relativeFontUrl = extractFontUrl(css);
if (relativeFontUrl) {
const absoluteFontUrl = resolveUrl(cssResponse.url, relativeFontUrl);
const fontData = await fetchWithProgress(absoluteFontUrl);
const fontFamily = extractFontFamily(css);
if (fontFamily) {
addNewFont(fontFamily, fontData);
} else {
throw new Error('Could not extract font family from CSS');
}
} else {
throw new Error('Could not find font file URL in CSS');
}
} else {
const fontData = await fetchWithProgress(fontUrl);
const fontFamily = prompt("Enter a name for this font:");
if (fontFamily) {
addNewFont(fontFamily, fontData);
} else {
throw new Error('Font name is required');
}
}
} catch (error) {
console.error('Error adding font:', error);
alert('Error adding font. Please check the URL and try again.');
} finally {
showProgress(false);
}
}
});
function addNewFont(fontFamily, fontData) {
if (!fonts.includes(fontFamily)) {
addFontFace(fontFamily, fontData);
fonts.push(fontFamily);
storedFonts.push({ family: fontFamily, data: fontData });
localStorage.setItem('customFonts', JSON.stringify(storedFonts));
updateFontPreviews();
fontUrlInput.value = '';
} else {
alert('This font is already added!');
}
}
previewText.addEventListener('input', updateFontPreviews);
fontPreviews.addEventListener('click', function(event) {
if (event.target.classList.contains('delete-font-btn')) {
const fontToDelete = event.target.getAttribute('data-font');
if (confirm(`Are you sure you want to delete the font "${fontToDelete}"?`)) {
fonts = fonts.filter(font => font !== fontToDelete);
storedFonts = storedFonts.filter(font => font.family !== fontToDelete);
localStorage.setItem('customFonts', JSON.stringify(storedFonts));
updateFontPreviews();
}
}
});