diff --git a/index.html b/index.html
index 98ad76a..11a1c23 100644
--- a/index.html
+++ b/index.html
@@ -9,21 +9,24 @@
-
- Fontsource font preview
-
-
-
-
-
+
+
+
+ Fontsource font preview
+
+
+
About this font
@@ -52,6 +55,12 @@
+
+
CSS
diff --git a/script.js b/script.js
index 6bc1f06..cdaea15 100644
--- a/script.js
+++ b/script.js
@@ -79,7 +79,8 @@ const css_template = (info,range,weight,style,variable_info) => {
if(axes.includes('slnt')) {
extras.push(` font-style: oblique ${variable_info.axes.slnt.min}deg ${variable_info.axes.slnt.max}deg;`);
}
-}
+ }
+
if(info.variable) {
return `
@@ -113,6 +114,52 @@ async function fetch_json(url) {
}
+async function draw_font_preview(f) {
+ const d = await navigator.storage.getDirectory();
+ const filename = `${f.family}.png`;
+ let fh;
+ try {
+ fh = await d.getFileHandle(filename);
+ } catch(e) {
+ const style = document.createElement('style');
+ try {
+ document.head.append(style);
+ const info = await fetch_json(font_info_url(f.id));
+ const variable_info = info.variable ? await fetch_json(variable_info_url(info.id)) : {};
+ const css = css_template(info,info.defSubset,info.weights[0],'normal',variable_info);
+ style.textContent += css;
+ await new Promise((resolve,reject) => {
+ setTimeout(async () => {
+ const ffs = Array.from(document.fonts).filter(ff=>ff.family == `"${f.family}"`);
+ await Promise.all(ffs.map(ff => ff.load())).catch(reject)
+ resolve();
+ },1);
+ });
+ } catch(e) {
+ return;
+ }
+ const cv = new OffscreenCanvas(1,1);
+ const ctx = cv.getContext('2d');
+ const font_style = `100px "${f.family}"`;
+ ctx.font = font_style;
+ const {width, fontBoundingBoxAscent, fontBoundingBoxDescent} = ctx.measureText(f.family);
+ cv.width = width;
+ cv.height = fontBoundingBoxAscent + fontBoundingBoxDescent;
+ ctx.font = font_style;
+ ctx.fillText(f.family,0,fontBoundingBoxAscent);
+ const blob = await cv.toBlob();
+ fh = await d.getFileHandle(filename,{create:true});
+ const w = await fh.createWritable();
+ await w.write(blob);
+ await w.close();
+ window.blob = blob;
+ style.parentElement.removeChild(style);
+ }
+ const file = await fh.getFile();
+ return URL.createObjectURL(file);
+
+}
+
async function go() {
let [fonts, axes_info] = await Promise.all([
@@ -120,14 +167,20 @@ async function go() {
fetch_json('https://api.fontsource.org/v1/axis-registry')
]);
+ window.available_fonts = fonts;
+
axes_info = Object.fromEntries(Object.entries(axes_info).map(([k,v]) => [k.toLowerCase(), v]));
async function use_font() {
const name = select.value;
- console.log(name);
const info = await fetch_json(font_info_url(name));
const variable_info = info.variable ? await fetch_json(variable_info_url(info.id)) : {};
- console.log(info);
+
+ const preview = document.querySelector(`[data-font="${name}"]`);
+ if(preview) {
+ preview.scrollIntoView({block: 'center'});
+ document.body.scrollTop = 0;
+ }
document.body.style.setProperty('--family',info.family);
@@ -153,7 +206,6 @@ async function go() {
if(info.variable) {
const variable_axes = document.getElementById('variable-axes');
variable_axes.innerHTML = '';
- console.log(variable_info);
const ranges = {};
@@ -208,7 +260,6 @@ async function go() {
document.body.style['font-variation-settings'] = settings;
}
update_variables();
-
}
const css_declarations = [];
@@ -240,7 +291,7 @@ async function go() {
}
- fonts = fonts.filter(f=>!f.id.includes('noto'));
+ fonts = fonts.filter(f=>!f.id.match(/noto|playwrite/i));
select.innerHTML = '';
for(let font of fonts) {
const option = document.createElement('option');
@@ -260,6 +311,27 @@ async function go() {
document.getElementById('random-font').addEventListener('click', random_font);
random_font();
+
+ const fl = document.getElementById('font-list');
+ const step = 10;
+ for(let i=0;i {
+ const li = document.createElement('li');
+ fl.append(li);
+ const a = document.createElement('a');
+ li.append(a);
+ a.addEventListener('click', () => {
+ select.value = f.id;
+ use_font();
+ })
+ const img = document.createElement('img');
+ img.dataset.font = f.id;
+ a.append(img);
+ img.src = await draw_font_preview(f);
+ img.style.height = '1em';
+ img.alt = f.family;
+ }));
+ }
}
go();
\ No newline at end of file
diff --git a/style.css b/style.css
index 125118f..8947921 100644
--- a/style.css
+++ b/style.css
@@ -2,10 +2,59 @@
--spacing: 1em;
--family: sans-serif;
+ --background: white;
+ --color: black;
+
color-scheme: light dark;
+ height: 100svh;
+ overflow: hidden;
}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ --background: black;
+ --color: white;
+ }
+
+ #font-list img {
+ filter: invert(100%);
+ }
+}
+
body {
+ display: grid;
+ grid-template-columns: 15em 1fr;
+ gap: var(--spacing);
+ width: 100svw;
+ height: 100svh;
+ margin: 0;
+ overflow: hidden;
+
+ color: var(--color);
+ background: var(--background);
+}
+
+
+nav {
+ height: 100svh;
+ display: flex;
+ flex-direction: column;
+}
+
+#controls {
+ position: sticky;
+ top: 0;
+ background: var(--background);
+ padding: var(--spacing);
+
+ & select {
+ width: 100%;
+ }
+}
+
+main {
font-family: var(--family);
+ overflow: auto;
}
.fixed-font {
@@ -29,4 +78,24 @@ dt {
max-width: 100%;
max-height: 3em;
overflow: auto;
+}
+
+
+#font-list {
+ margin: 0;
+ overflow: auto;
+ width:100%;
+ height:100%;
+
+ font-size: 2rem;
+ padding: 0;
+ list-style: none;
+
+ & li {
+ overflow: hidden;
+ }
+}
+
+#css-display {
+ margin: 0;
}
\ No newline at end of file