The names of fonts are rendered using the corresponding font.
Each font's name is rendered to an OffscreenCanvas, and that image is cached in OPFS. There's a list of links to download font files in the preview.
This commit is contained in:
parent
51d57259b0
commit
a4b046a784
3 changed files with 165 additions and 15 deletions
27
index.html
27
index.html
|
@ -9,21 +9,24 @@
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<nav>
|
||||||
<h1>Fontsource font preview</h1>
|
<section id="controls">
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<section id="intro" class="fixed-font">
|
|
||||||
<p>This page shows fonts loaded from <a href="https://fontsource.org">Fontsource</a>.</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="controls" class="fixed-font">
|
|
||||||
<label for="font-family">Font:</label>
|
<label for="font-family">Font:</label>
|
||||||
<select id="font-family">
|
<select id="font-family">
|
||||||
</select>
|
</select>
|
||||||
<button type="button" id="random-font">I'm feeling lucky</button>
|
<button type="button" id="random-font">I'm feeling lucky</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<ul id="font-list"></ul>
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<header>
|
||||||
|
<h1>Fontsource font preview</h1>
|
||||||
|
</header>
|
||||||
|
<section id="intro">
|
||||||
|
<p>This page shows fonts loaded from <a href="https://fontsource.org">Fontsource</a>.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section id="info">
|
<section id="info">
|
||||||
<h2>About this font</h2>
|
<h2>About this font</h2>
|
||||||
|
|
||||||
|
@ -52,6 +55,12 @@
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="files">
|
||||||
|
<h2>Files</h2>
|
||||||
|
<ul id="file-links">
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section id="code">
|
<section id="code">
|
||||||
<h2>CSS</h2>
|
<h2>CSS</h2>
|
||||||
<pre id="css-display"></pre>
|
<pre id="css-display"></pre>
|
||||||
|
|
82
script.js
82
script.js
|
@ -81,6 +81,7 @@ const css_template = (info,range,weight,style,variable_info) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(info.variable) {
|
if(info.variable) {
|
||||||
return `
|
return `
|
||||||
/* ${info.family} variable ${style} ${range} */
|
/* ${info.family} variable ${style} ${range} */
|
||||||
|
@ -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() {
|
async function go() {
|
||||||
let [fonts, axes_info] = await Promise.all([
|
let [fonts, axes_info] = await Promise.all([
|
||||||
|
@ -120,14 +167,20 @@ async function go() {
|
||||||
fetch_json('https://api.fontsource.org/v1/axis-registry')
|
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]));
|
axes_info = Object.fromEntries(Object.entries(axes_info).map(([k,v]) => [k.toLowerCase(), v]));
|
||||||
|
|
||||||
async function use_font() {
|
async function use_font() {
|
||||||
const name = select.value;
|
const name = select.value;
|
||||||
console.log(name);
|
|
||||||
const info = await fetch_json(font_info_url(name));
|
const info = await fetch_json(font_info_url(name));
|
||||||
const variable_info = info.variable ? await fetch_json(variable_info_url(info.id)) : {};
|
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);
|
document.body.style.setProperty('--family',info.family);
|
||||||
|
|
||||||
|
@ -153,7 +206,6 @@ async function go() {
|
||||||
if(info.variable) {
|
if(info.variable) {
|
||||||
const variable_axes = document.getElementById('variable-axes');
|
const variable_axes = document.getElementById('variable-axes');
|
||||||
variable_axes.innerHTML = '';
|
variable_axes.innerHTML = '';
|
||||||
console.log(variable_info);
|
|
||||||
|
|
||||||
const ranges = {};
|
const ranges = {};
|
||||||
|
|
||||||
|
@ -208,7 +260,6 @@ async function go() {
|
||||||
document.body.style['font-variation-settings'] = settings;
|
document.body.style['font-variation-settings'] = settings;
|
||||||
}
|
}
|
||||||
update_variables();
|
update_variables();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const css_declarations = [];
|
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 = '';
|
select.innerHTML = '';
|
||||||
for(let font of fonts) {
|
for(let font of fonts) {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
|
@ -260,6 +311,27 @@ async function go() {
|
||||||
document.getElementById('random-font').addEventListener('click', random_font);
|
document.getElementById('random-font').addEventListener('click', random_font);
|
||||||
|
|
||||||
random_font();
|
random_font();
|
||||||
|
|
||||||
|
const fl = document.getElementById('font-list');
|
||||||
|
const step = 10;
|
||||||
|
for(let i=0;i<fonts.length;i+=step) {
|
||||||
|
await Promise.all(fonts.slice(i+0,i+step).map(async f => {
|
||||||
|
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();
|
go();
|
69
style.css
69
style.css
|
@ -2,10 +2,59 @@
|
||||||
--spacing: 1em;
|
--spacing: 1em;
|
||||||
--family: sans-serif;
|
--family: sans-serif;
|
||||||
|
|
||||||
|
--background: white;
|
||||||
|
--color: black;
|
||||||
|
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
|
height: 100svh;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
body {
|
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);
|
font-family: var(--family);
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-font {
|
.fixed-font {
|
||||||
|
@ -30,3 +79,23 @@ dt {
|
||||||
max-height: 3em;
|
max-height: 3em;
|
||||||
overflow: auto;
|
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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue