run prettier

This commit is contained in:
Eigil Nikolajsen 2023-06-10 11:01:25 +02:00
parent 78de709b28
commit a915cbdcb4
43 changed files with 7554 additions and 7484 deletions

View File

@ -1,5 +1,5 @@
{
"printWidth": 120,
"tabWidth": 3,
"semi": false
"printWidth": 120,
"tabWidth": 4,
"semi": false
}

112
404.html
View File

@ -1,62 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Website for Commit Mono - a neutral programming font." />
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Website for Commit Mono - a neutral programming font." />
<!-- favicon -->
<link rel="icon" href="src/favicon/icon.svg" type="image/svg+xml" id="dynamic-favicon" />
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="apple-touch-icon" href="/favicon/apple-touch-icon.png" />
<link rel="manifest" href="/manifest.webmanifest" />
<!-- favicon -->
<link rel="icon" href="src/favicon/icon.svg" type="image/svg+xml" id="dynamic-favicon" />
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="apple-touch-icon" href="/favicon/apple-touch-icon.png" />
<link rel="manifest" href="/manifest.webmanifest" />
<!-- title -->
<title>Commit Mono. Neutral programming typeface.</title>
<!-- title -->
<title>Commit Mono. Neutral programming typeface.</title>
<!-- CSS -->
<style>
@font-face {
font-family: "CommitMono";
src: url("/src/fonts/CommitMonoV118-VF.woff2");
font-style: normal;
font-weight: 450;
font-display: swap;
}
body {
background-color: #aaa;
position: fixed;
inset: 0;
display: grid;
place-content: center;
}
p,
a {
font-family: "CommitMono";
font-size: 0.75rem;
color: #111;
line-height: 1rem;
margin: 0;
width: fit-content;
text-decoration: none;
}
a {
background-color: #111;
color: #aaa;
outline: none;
}
</style>
</head>
<body>
<p>404</p>
<p>page not found</p>
<br />
<a href="/">Press ENTER to go to home page.</a>
<script>
const a = document.querySelector("a")
a.focus()
a.addEventListener("blur", () => a.focus())
</script>
</body>
<!-- CSS -->
<style>
@font-face {
font-family: "CommitMono";
src: url("/src/fonts/CommitMonoV118-VF.woff2");
font-style: normal;
font-weight: 450;
font-display: swap;
}
body {
background-color: #aaa;
position: fixed;
inset: 0;
display: grid;
place-content: center;
}
p,
a {
font-family: "CommitMono";
font-size: 0.75rem;
color: #111;
line-height: 1rem;
margin: 0;
width: fit-content;
text-decoration: none;
}
a {
background-color: #111;
color: #aaa;
outline: none;
}
</style>
</head>
<body>
<p>404</p>
<p>page not found</p>
<br />
<a href="/">Press ENTER to go to home page.</a>
<script>
const a = document.querySelector("a")
a.focus()
a.addEventListener("blur", () => a.focus())
</script>
</body>
</html>

60
calt.js
View File

@ -2,48 +2,48 @@ const fs = require("fs")
const readline = require("readline")
function pbcopy(data) {
var proc = require("child_process").spawn("pbcopy")
proc.stdin.write(data)
proc.stdin.end()
var proc = require("child_process").spawn("pbcopy")
proc.stdin.write(data)
proc.stdin.end()
}
async function featuresToCalt() {
const features = ["ss01_arrows", "ss02_less_equal", "ss03_case", "ss04_ellipsis", "ss05_smartkerning"]
const features = ["ss01_arrows", "ss02_less_equal", "ss03_case", "ss04_ellipsis", "ss05_smartkerning"]
let calt = []
let calt = []
for await (const feature of features) {
const fileStream = fs.createReadStream(`features/${feature}.fea`)
for await (const feature of features) {
const fileStream = fs.createReadStream(`features/${feature}.fea`)
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
})
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
})
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
const lines = []
const lines = []
lines.push(`### feature ${feature} ###`)
lines.push(`### feature ${feature} ###`)
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
// console.log(`Line from file: ${line}`)
lines.push(line)
}
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
// console.log(`Line from file: ${line}`)
lines.push(line)
}
calt.push(lines)
}
calt.push(lines)
}
calt = calt.flat().filter((ln) => !ln.includes("feature") && !ln.includes("} ss"))
calt = calt.map((ln) => {
if (ln.includes("lookup")) return ln.split("lookup ").join("lookup _")
if (ln.includes("} ")) return ln.split("} ").join("} _")
return ln
})
calt = calt.flat().filter((ln) => !ln.includes("feature") && !ln.includes("} ss"))
calt = calt.map((ln) => {
if (ln.includes("lookup")) return ln.split("lookup ").join("lookup _")
if (ln.includes("} ")) return ln.split("} ").join("} _")
return ln
})
// calt.forEach((ln) => console.log(ln))
pbcopy(`
// calt.forEach((ln) => console.log(ln))
pbcopy(`
feature calt {
# Contextual Alternates
# Contains all 'cxxx' features

View File

@ -1,30 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generate Axis Value</title>
</head>
<body>
<br />
<label for="classes">Classes</label>
<br />
<br />
<textarea id="classes" name="classes" rows="20" cols="60"></textarea>
<br />
<br />
<button type="submit" id="submit">Submit</button>
<br />
<br />
<p style="user-select: all" id="result"></p>
<script>
const classes = document.querySelector("#classes")
const result = document.querySelector("#result")
const submit = document.querySelector("#submit")
submit.addEventListener("click", () => {
result.textContent = [...new Set(classes.value.split(" "))].join(" ")
})
</script>
</body>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generate Axis Value</title>
</head>
<body>
<br />
<label for="classes">Classes</label>
<br />
<br />
<textarea id="classes" name="classes" rows="20" cols="60"></textarea>
<br />
<br />
<button type="submit" id="submit">Submit</button>
<br />
<br />
<p style="user-select: all" id="result"></p>
<script>
const classes = document.querySelector("#classes")
const result = document.querySelector("#result")
const submit = document.querySelector("#submit")
submit.addEventListener("click", () => {
result.textContent = [...new Set(classes.value.split(" "))].join(" ")
})
</script>
</body>
</html>

22
f.js
View File

@ -6,10 +6,10 @@
// @c3_3 = [exclam.c3_3 comma.c3_3 period.c3_3 slash.c3_3 colon.c3_3 semicolon.c3_3 question.c3_3 backslash.c3_3 bar.c3_3];
const input =
"exclam exclam.square comma period period.square slash slash.case colon colon.square colon.case colon.case.square semicolon semicolon.square semicolon.case semicolon.case.square question question.square backslash backslash.case bar bar.case less less.case greater greater.case asterisk asterisk.case plus plus.case hyphen hyphen.case equal equal.case asciitilde asciitilde.case"
"exclam exclam.square comma period period.square slash slash.case colon colon.square colon.case colon.case.square semicolon semicolon.square semicolon.case semicolon.case.square question question.square backslash backslash.case bar bar.case less less.case greater greater.case asterisk asterisk.case plus plus.case hyphen hyphen.case equal equal.case asciitilde asciitilde.case"
function c002(input) {
const s = input.split(" ")
return `
const s = input.split(" ")
return `
@dflt = [${input}];
@c2_1 = [${s.join(".c2_1 ")}.c2_1];
@c2_2 = [${s.join(".c2_2 ")}.c2_2];
@ -19,20 +19,20 @@ function c002(input) {
}
function classExcess(c) {
return [...new Set(c.split(" "))].join(" ")
return [...new Set(c.split(" "))].join(" ")
}
function buildGlyphs(g) {
return g
.split(", ")
.map((gl) => gl.split("=")[0])
.join(", ")
return g
.split(", ")
.map((gl) => gl.split("=")[0])
.join(", ")
}
function pbcopy(data) {
var proc = require("child_process").spawn("pbcopy")
proc.stdin.write(data)
proc.stdin.end()
var proc = require("child_process").spawn("pbcopy")
proc.stdin.write(data)
proc.stdin.end()
}
pbcopy(c002(input))

1457
index.html

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generate Axis Value</title>
<style>
#resultButton {
user-select: all;
}
</style>
</head>
<body>
<label for="start">Start value</label>
<input type="text" name="start" id="start" />
<br />
<br />
<label for="end">End value</label>
<input type="text" name="end" id="end" />
<br />
<br />
<label for="precision">Precision</label>
<input type="text" name="precision" id="precision" />
<br />
<br />
<button type="submit" id="submit">Submit</button>
<br />
<br />
<p id="resultButton"></p>
<script>
const submit = document.querySelector("#submit")
const start = document.querySelector("#start")
const end = document.querySelector("#end")
const precision = document.querySelector("#precision")
const resultButton = document.querySelector("#resultButton")
submit.addEventListener("click", () => {
const result = generateAxisValue([+start.value, +end.value], +precision.value)
resultButton.textContent = result
navigator.clipboard.writeText(result)
})
const generateAxisValue = ([start, end], precision) => {
let value = start
let result = ""
while (value <= end) {
result += `"${value}"=${value}, `
value += precision
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generate Axis Value</title>
<style>
#resultButton {
user-select: all;
}
return result.slice(0, -2)
}
</script>
</body>
</style>
</head>
<body>
<label for="start">Start value</label>
<input type="text" name="start" id="start" />
<br />
<br />
<label for="end">End value</label>
<input type="text" name="end" id="end" />
<br />
<br />
<label for="precision">Precision</label>
<input type="text" name="precision" id="precision" />
<br />
<br />
<button type="submit" id="submit">Submit</button>
<br />
<br />
<p id="resultButton"></p>
<script>
const submit = document.querySelector("#submit")
const start = document.querySelector("#start")
const end = document.querySelector("#end")
const precision = document.querySelector("#precision")
const resultButton = document.querySelector("#resultButton")
submit.addEventListener("click", () => {
const result = generateAxisValue([+start.value, +end.value], +precision.value)
resultButton.textContent = result
navigator.clipboard.writeText(result)
})
const generateAxisValue = ([start, end], precision) => {
let value = start
let result = ""
while (value <= end) {
result += `"${value}"=${value}, `
value += precision
}
return result.slice(0, -2)
}
</script>
</body>
</html>

View File

@ -1,27 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
@font-face {
font-family: "CommitMono";
src: url("/fonts/CommitMono.woff2");
font-weight: 450;
}
:root {
--grey: #aaa;
}
button#grey::before {
content: "01";
font-style: italic;
font-size: 2rem;
color: var(--grey);
}
</style>
</head>
<body>
<button id="grey">Commit Mono</button>
</body>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
@font-face {
font-family: "CommitMono";
src: url("/fonts/CommitMono.woff2");
font-weight: 450;
}
:root {
--grey: #aaa;
}
button#grey::before {
content: "01";
font-style: italic;
font-size: 2rem;
color: var(--grey);
}
</style>
</head>
<body>
<button id="grey">Commit Mono</button>
</body>
</html>

View File

@ -6,56 +6,56 @@
*/
function lcs(arr1, arr2) {
let matrix = [...Array(arr1.length + 1)].fill(0).map(() => Array(arr2.length + 1).fill(0))
let matrix = [...Array(arr1.length + 1)].fill(0).map(() => Array(arr2.length + 1).fill(0))
for (let rowIndex = 1; rowIndex <= arr1.length; rowIndex++) {
for (let columnIndex = 1; columnIndex <= arr2.length; columnIndex++) {
if (arr1[rowIndex - 1] === arr2[columnIndex - 1]) {
matrix[rowIndex][columnIndex] = 1 + matrix[rowIndex - 1][columnIndex - 1]
} else {
matrix[rowIndex][columnIndex] = Math.max(
matrix[rowIndex - 1][columnIndex],
matrix[rowIndex][columnIndex - 1]
)
}
}
}
//If there is no match, printing empty string
if (matrix[arr1.length][arr2.index] === 0) {
console.log("")
return
}
for (let rowIndex = 1; rowIndex <= arr1.length; rowIndex++) {
for (let columnIndex = 1; columnIndex <= arr2.length; columnIndex++) {
if (arr1[rowIndex - 1] === arr2[columnIndex - 1]) {
matrix[rowIndex][columnIndex] = 1 + matrix[rowIndex - 1][columnIndex - 1]
} else {
matrix[rowIndex][columnIndex] = Math.max(
matrix[rowIndex - 1][columnIndex],
matrix[rowIndex][columnIndex - 1]
)
}
}
}
//If there is no match, printing empty string
if (matrix[arr1.length][arr2.index] === 0) {
console.log("")
return
}
let result = []
let rowIndex = arr1.length
let columnIndex = arr2.length
let result = []
let rowIndex = arr1.length
let columnIndex = arr2.length
while (rowIndex > 0 && columnIndex > 0) {
if (arr1[rowIndex - 1] === arr2[columnIndex - 1]) {
//Prepending everytime a new character is matched in both strings
result.unshift(arr1[rowIndex - 1])
rowIndex--
columnIndex--
} else if (matrix[rowIndex - 1][columnIndex] === matrix[rowIndex][columnIndex]) {
rowIndex--
} else {
columnIndex--
}
}
//Converting the LCS array into a comma separated string
console.log(result.join(", "))
while (rowIndex > 0 && columnIndex > 0) {
if (arr1[rowIndex - 1] === arr2[columnIndex - 1]) {
//Prepending everytime a new character is matched in both strings
result.unshift(arr1[rowIndex - 1])
rowIndex--
columnIndex--
} else if (matrix[rowIndex - 1][columnIndex] === matrix[rowIndex][columnIndex]) {
rowIndex--
} else {
columnIndex--
}
}
//Converting the LCS array into a comma separated string
console.log(result.join(", "))
}
//Usage Text
const usage = 'Usage: please provide two lists in the format "1, 2, 3, 4, 5"'
if (process.argv.length < 4 || process.argv[2] == "" || process.argv[3] == "") {
console.log(usage)
return
console.log(usage)
return
} else {
const input1 = process.argv[2]
const input2 = process.argv[3]
//Parsing into integers after trimming extra blank spaces
const array1 = input1.split(",").map((x) => parseInt(x.trim(), 10))
const array2 = input2.split(",").map((y) => parseInt(y.trim(), 10))
lcs(array1, array2)
const input1 = process.argv[2]
const input2 = process.argv[3]
//Parsing into integers after trimming extra blank spaces
const array1 = input1.split(",").map((x) => parseInt(x.trim(), 10))
const array2 = input2.split(",").map((y) => parseInt(y.trim(), 10))
lcs(array1, array2)
}

View File

@ -1,22 +1,22 @@
function fibonacci(num: number) {
let n = Number(num)
let elementOne: number = 0
let elementTwo: number = 1
let result: number = 0
let n = Number(num)
let elementOne: number = 0
let elementTwo: number = 1
let result: number = 0
for (let i: number = 1; i <= n; i++) {
result = elementOne + elementTwo
elementOne = elementTwo
elementTwo = result
console.log(`${i}: ${elementOne}`)
}
for (let i: number = 1; i <= n; i++) {
result = elementOne + elementTwo
elementOne = elementTwo
elementTwo = result
console.log(`${i}: ${elementOne}`)
}
}
let num_str = process.argv.length >= 3 ? process.argv[2] : ""
let num: number = parseInt(num_str)
if (isNaN(num)) {
console.log("Usage: please input the count of fibonacci numbers to output")
process.exit(0)
console.log("Usage: please input the count of fibonacci numbers to output")
process.exit(0)
}
fibonacci(num)

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"icons": [
{ "src": "/src/favicon/icon-192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "/src/favicon/icon-512.png", "type": "image/png", "sizes": "512x512" }
]
"icons": [
{ "src": "/src/favicon/icon-192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "/src/favicon/icon-512.png", "type": "image/png", "sizes": "512x512" }
]
}

1772
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
{
"name": "commit-webtests",
"private": true,
"version": "0.0.0",
"type": "commonjs",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^4.1.1"
}
"name": "commit-webtests",
"private": true,
"version": "0.0.0",
"type": "commonjs",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^4.1.1"
}
}

View File

@ -1,69 +1,69 @@
@font-face {
font-family: "CommitMonoLoading";
src: url("data:font/woff2;charset=url-8;base64,d09GMk9UVE8AAAVoAAoAAAAACRAAAAUgAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYcqGhYGYACCcgE2AiQDIgQGBYQhByAbVAgRZJPTIvuRkLnpo1niWFGcZNnEK1FCUU4/x8PT2u/PnZ3dh6g3CJGQRBORpJVGg67f6q9Ns3ed4+/dNQeGD6Q1Nv+/r3HXBE48osgCyvt7NvUTYnINZZJwUNelEzGpqkxUH92fDB0zXaUP82xFMJQsXXOHVdpANttEIhM32xM/y6P+MHZhAh4hJxTKBbrhm89nfEyZeMKSimREp600nifplvNJJ34a/VkBz5F8L+EFZeCFSvKWUsig+NR/R0ZgyZDGIvDSwGSjyt9iLXIEIdUwnqN2Eiag0Go3YpZ2uyOTcHUKJe4KKRInfhZA3BH3KPTa1jUwMjW34E8oZC3tOm14RybSiV8CM8EswZ2BYK7G3WoT1eM4OBCww4CQ/0grvTR5bXZ2cnJ2ztqkpUvXrlvCqo+2rtrF72jXPnwM5x5SebwLrKI9x4/tO2lFSnl5RkqXP9vhF3Ul/HqgT++reCFN7bm85urm6zukd8WH8k80PNbBHMnbfi1Ygsk+Ewyn2MfivKuFiQ361vzVM1du3zn/BDf0iAjL9o2Z7Kaj8lzaxn2+WZ1am9An5uYS0pab2kJMyaNISGuk3cc/AwUa3/jsxbNaA1Zj1eQ+7hzYJknff3H9xQ2X10rviU83nGku0fFVXjj3lKRp3YzUkXqsdcIK7MlRebjPGywHbWdlRmsSq8ar2qD/nYftsKFtQpe269bK+0M6YduD7Q+pd0egDK7T4xblNzXn5TU15i0a6//gheO5RryXpn4MaUzfumjq+JV2jhNSy3PSk4u5wcn0rF1rF8/Uub+bADqw+Nr59fHICkywWC+mvh7ZsjskJtw/ONybOxYRfSpWD8SDuz8zjqTsjuUeteER4r7GX9u189IOPSYHDDabGjkvYx1XZeXVe3auX6lbE7Q5dh+rPn+TZ25+ASst7DVeZPWQegNkD97hJjbwq/CJoeD2h8EGMfUF5N3G9PKkdZlZiUm69/rEZcvXrV+2kBPb+W83Cdj1iIR6GEvzleUvdf2zV4KN6saCJDP1ekAs2yY5sGnDiY364WsyHnLqsB33IgA9hIPie6f1gCbJx/L2Ow0ZC4aw+PcjnpAAOfam9ahZa6dsYk8/GvQnTaw+eot3ukU0PYKqxySUHaWB+QwyMKhka5BhRmuDLakBSj/BFsBwt4SuEx+DCnLUP375st6AVedNNLhy6qPe3VO8n5zHhd5ivMo7ylty1Js/4w3T4gopc6PsthzOKW7fViozCyOr7ihV/Adj6KaLIAu6KMJTL+80vZKGuIJqm/Gc4ARBye4ep2gcIxAk2uHOt6z2oeI+AnMMHrwKfRBX1Yn/XgiqV+jDEvAAaUpQVMbhQqVPiQYFmGITYUPjK626Tk2Kq04ULit/PgOKGsEbWgtt27SjQ6fsHBgRZstv321OjERlQLEZl0IalH5zlJ/leblVov5H/A/7H/o/GFkrVe6Hj7cN3r2/07C4d8BPVfUG4UvYu0B7XoTTKBQvTgILkkKgWl1ZeII95O98bdJy+6Y6fmDlb51Xaocv2hU3QDqOGmDnfJm6PNe1hP6x6pJWSEiBbFwE1Lptypq0/jU2kWUoLNhDkPS4AZUzL5Bt+YHaRHDSBhKjb+N2c7H+U0jpsxD/Imn8NZKvzdrGzuo09DDFCJvgDVwXEcOKxvB0IrnZ0UzDHZbzF5JiEhhaTrOlQlHaWpaS0GVp19ozUcDlJtuojBhThsdj6sLDGy/MoCNODT2409BVrVsWGh9kAA==");
font-style: normal;
font-weight: 450;
font-display: swap;
font-family: "CommitMonoLoading";
src: url("data:font/woff2;charset=url-8;base64,d09GMk9UVE8AAAVoAAoAAAAACRAAAAUgAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYcqGhYGYACCcgE2AiQDIgQGBYQhByAbVAgRZJPTIvuRkLnpo1niWFGcZNnEK1FCUU4/x8PT2u/PnZ3dh6g3CJGQRBORpJVGg67f6q9Ns3ed4+/dNQeGD6Q1Nv+/r3HXBE48osgCyvt7NvUTYnINZZJwUNelEzGpqkxUH92fDB0zXaUP82xFMJQsXXOHVdpANttEIhM32xM/y6P+MHZhAh4hJxTKBbrhm89nfEyZeMKSimREp600nifplvNJJ34a/VkBz5F8L+EFZeCFSvKWUsig+NR/R0ZgyZDGIvDSwGSjyt9iLXIEIdUwnqN2Eiag0Go3YpZ2uyOTcHUKJe4KKRInfhZA3BH3KPTa1jUwMjW34E8oZC3tOm14RybSiV8CM8EswZ2BYK7G3WoT1eM4OBCww4CQ/0grvTR5bXZ2cnJ2ztqkpUvXrlvCqo+2rtrF72jXPnwM5x5SebwLrKI9x4/tO2lFSnl5RkqXP9vhF3Ul/HqgT++reCFN7bm85urm6zukd8WH8k80PNbBHMnbfi1Ygsk+Ewyn2MfivKuFiQ361vzVM1du3zn/BDf0iAjL9o2Z7Kaj8lzaxn2+WZ1am9An5uYS0pab2kJMyaNISGuk3cc/AwUa3/jsxbNaA1Zj1eQ+7hzYJknff3H9xQ2X10rviU83nGku0fFVXjj3lKRp3YzUkXqsdcIK7MlRebjPGywHbWdlRmsSq8ar2qD/nYftsKFtQpe269bK+0M6YduD7Q+pd0egDK7T4xblNzXn5TU15i0a6//gheO5RryXpn4MaUzfumjq+JV2jhNSy3PSk4u5wcn0rF1rF8/Uub+bADqw+Nr59fHICkywWC+mvh7ZsjskJtw/ONybOxYRfSpWD8SDuz8zjqTsjuUeteER4r7GX9u189IOPSYHDDabGjkvYx1XZeXVe3auX6lbE7Q5dh+rPn+TZ25+ASst7DVeZPWQegNkD97hJjbwq/CJoeD2h8EGMfUF5N3G9PKkdZlZiUm69/rEZcvXrV+2kBPb+W83Cdj1iIR6GEvzleUvdf2zV4KN6saCJDP1ekAs2yY5sGnDiY364WsyHnLqsB33IgA9hIPie6f1gCbJx/L2Ow0ZC4aw+PcjnpAAOfam9ahZa6dsYk8/GvQnTaw+eot3ukU0PYKqxySUHaWB+QwyMKhka5BhRmuDLakBSj/BFsBwt4SuEx+DCnLUP375st6AVedNNLhy6qPe3VO8n5zHhd5ivMo7ylty1Js/4w3T4gopc6PsthzOKW7fViozCyOr7ihV/Adj6KaLIAu6KMJTL+80vZKGuIJqm/Gc4ARBye4ep2gcIxAk2uHOt6z2oeI+AnMMHrwKfRBX1Yn/XgiqV+jDEvAAaUpQVMbhQqVPiQYFmGITYUPjK626Tk2Kq04ULit/PgOKGsEbWgtt27SjQ6fsHBgRZstv321OjERlQLEZl0IalH5zlJ/leblVov5H/A/7H/o/GFkrVe6Hj7cN3r2/07C4d8BPVfUG4UvYu0B7XoTTKBQvTgILkkKgWl1ZeII95O98bdJy+6Y6fmDlb51Xaocv2hU3QDqOGmDnfJm6PNe1hP6x6pJWSEiBbFwE1Lptypq0/jU2kWUoLNhDkPS4AZUzL5Bt+YHaRHDSBhKjb+N2c7H+U0jpsxD/Imn8NZKvzdrGzuo09DDFCJvgDVwXEcOKxvB0IrnZ0UzDHZbzF5JiEhhaTrOlQlHaWpaS0GVp19ozUcDlJtuojBhThsdj6sLDGy/MoCNODT2409BVrVsWGh9kAA==");
font-style: normal;
font-weight: 450;
font-display: swap;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--text: #111;
--middle: #555;
--bg: #aaa;
--max-width: 54ch;
font-size: 16px;
--text: #111;
--middle: #555;
--bg: #aaa;
--max-width: 54ch;
font-size: 16px;
}
body {
background: var(--bg);
color: var(--text);
font-family: "CommitMono", monospace;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 0.75rem;
line-height: 1rem;
font-feature-settings: "ss01", "ss03", "ss04", "ss05";
overflow: hidden;
background: var(--bg);
color: var(--text);
font-family: "CommitMono", monospace;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 0.75rem;
line-height: 1rem;
font-feature-settings: "ss01", "ss03", "ss04", "ss05";
overflow: hidden;
}
#loading {
position: fixed;
inset: 0;
display: grid;
place-content: center;
background-color: var(--bg);
z-index: 200;
position: fixed;
inset: 0;
display: grid;
place-content: center;
background-color: var(--bg);
z-index: 200;
}
#loading p {
width: 10ch;
font-family: "CommitMonoLoading";
width: 10ch;
font-family: "CommitMonoLoading";
}
#loading p::after {
content: "...";
animation: 500ms forwards infinite loading_animation;
content: "...";
animation: 500ms forwards infinite loading_animation;
}
@keyframes loading_animation {
0% {
content: "";
}
25% {
content: ".";
}
50% {
content: "..";
}
75% {
content: "...";
}
100% {
content: "";
}
0% {
content: "";
}
25% {
content: ".";
}
50% {
content: "..";
}
75% {
content: "...";
}
100% {
content: "";
}
}

View File

@ -1,19 +1,19 @@
@media (pointer: coarse) and (max-width: 1000px) {
body {
overflow: visible;
}
#main_scale,
main {
position: relative;
}
header #keyboard_section,
#safari {
visibility: hidden;
}
#footer_hint {
display: none;
}
#footer_hint_mobile {
display: block;
}
body {
overflow: visible;
}
#main_scale,
main {
position: relative;
}
header #keyboard_section,
#safari {
visibility: hidden;
}
#footer_hint {
display: none;
}
#footer_hint_mobile {
display: block;
}
}

View File

@ -1,159 +1,159 @@
button {
vertical-align: top;
border: none;
background: transparent;
font-family: inherit;
font-size: 0.75rem;
font-variation-settings: inherit;
line-height: 1rem;
width: max-content;
white-space: nowrap;
text-align: left;
position: relative;
font-feature-settings: inherit;
vertical-align: top;
border: none;
background: transparent;
font-family: inherit;
font-size: 0.75rem;
font-variation-settings: inherit;
line-height: 1rem;
width: max-content;
white-space: nowrap;
text-align: left;
position: relative;
font-feature-settings: inherit;
}
button:active {
background: var(--bg75);
background: var(--bg75);
}
#app_root.no_focus {
opacity: 0.5;
opacity: 0.5;
}
:focus,
input:focus + label {
animation: flicker 60ms 2;
animation: flicker 60ms 2;
}
[contenteditable="true"]:focus {
animation: flicker 200ms 2;
animation: flicker 200ms 2;
}
@keyframes flicker {
0%,
49% {
opacity: 0;
}
50%,
100% {
opacity: 1;
}
0%,
49% {
opacity: 0;
}
50%,
100% {
opacity: 1;
}
}
@keyframes flicker_reverse {
0%,
49% {
opacity: 1;
}
50%,
100% {
opacity: 0;
}
0%,
49% {
opacity: 1;
}
50%,
100% {
opacity: 0;
}
}
.top_container p {
white-space: pre-wrap;
white-space: pre-wrap;
}
.line-through {
text-decoration: line-through;
text-decoration: line-through;
}
h2 {
font-size: 0.75rem;
line-height: 1rem;
font-weight: normal;
width: fit-content;
font-size: 0.75rem;
line-height: 1rem;
font-weight: normal;
width: fit-content;
}
a,
a:visited {
color: var(--text);
color: var(--text);
}
p:focus a,
a:focus {
text-decoration: none;
background-color: var(--text);
color: var(--bg);
text-decoration: none;
text-decoration: none;
background-color: var(--text);
color: var(--bg);
text-decoration: none;
}
#click_focus,
#change_setting {
inset: 0;
position: fixed;
z-index: 999;
display: grid;
place-content: center;
visibility: hidden;
pointer-events: none;
inset: 0;
position: fixed;
z-index: 999;
display: grid;
place-content: center;
visibility: hidden;
pointer-events: none;
}
#safari {
display: none;
display: none;
}
#safari.safari_visible {
display: block;
display: block;
}
#safari:focus p:first-of-type {
background-color: var(--text);
color: var(--bg);
background-color: var(--text);
color: var(--bg);
}
#safari {
background-color: var(--bg);
color: var(--text);
width: max-content;
background-color: var(--bg);
color: var(--text);
width: max-content;
}
#safari:focus p,
#safari:focus ul {
opacity: 1;
opacity: 1;
}
#safari:focus a,
#safari a:focus {
opacity: 1;
opacity: 1;
}
#safari:has(*:focus) * {
opacity: 1;
opacity: 1;
}
#safari #safari_not_working:focus {
background-color: var(--text);
color: var(--bg);
opacity: 1;
background-color: var(--text);
color: var(--bg);
opacity: 1;
}
#safari #safari_not_working {
opacity: 0;
opacity: 0;
}
#safari a:focus + #safari_not_working {
visibility: hidden;
visibility: hidden;
}
.span_key.pressed_key {
position: relative;
background: var(--bg25);
position: relative;
background: var(--bg25);
}
ul:focus .span_key.pressed_key {
background: var(--bg25-i);
background: var(--bg25-i);
}
.span_key.pressed_key::after {
content: " ✓";
position: absolute;
right: -1ch;
top: -0.5rem;
content: " ✓";
position: absolute;
right: -1ch;
top: -0.5rem;
}
#keyboard_container.use_keyboard_animation {
animation: flicker 140ms 8;
animation: flicker 140ms 8;
}

View File

@ -1,74 +1,74 @@
#keyboard_container {
font-size: 0.75rem;
display: flex;
width: max-content;
gap: 4ch;
align-items: end;
font-size: 0.75rem;
display: flex;
width: max-content;
gap: 4ch;
align-items: end;
}
.key_group {
display: flex;
flex-direction: column;
display: flex;
flex-direction: column;
}
.keys {
display: flex;
gap: 0.375ch;
margin-bottom: 0.125rem;
display: flex;
gap: 0.375ch;
margin-bottom: 0.125rem;
}
.key {
line-height: 0.85rem;
display: inline;
border: 0.0625rem solid var(--text);
border-bottom: 0.125rem solid var(--text);
padding: 0 calc(0.5ch - 0.0625rem);
user-select: none;
line-height: 0.85rem;
display: inline;
border: 0.0625rem solid var(--text);
border-bottom: 0.125rem solid var(--text);
padding: 0 calc(0.5ch - 0.0625rem);
user-select: none;
}
.key:hover {
cursor: pointer;
cursor: pointer;
}
.key[data-noclick="true"]:hover {
cursor: not-allowed;
cursor: not-allowed;
}
.key.active_key,
.key:active {
background: var(--text);
color: var(--bg);
line-height: 0.75rem;
margin-top: 0.1rem;
background: var(--text);
color: var(--bg);
line-height: 0.75rem;
margin-top: 0.1rem;
}
#safari p,
#safari ul {
background-color: var(--bg);
color: var(--text);
opacity: 0;
background-color: var(--bg);
color: var(--text);
opacity: 0;
}
#safari a {
opacity: 0;
opacity: 0;
}
#safari p:first-of-type {
opacity: 1;
opacity: 1;
}
#tutorial li {
margin-top: 0.3rem;
margin-top: 0.3rem;
}
.span_key {
display: inline;
border: 0.0625rem solid var(--text);
border-bottom: 0.125rem solid var(--text);
padding: 0 calc(0.5ch - 0.0625rem);
display: inline;
border: 0.0625rem solid var(--text);
border-bottom: 0.125rem solid var(--text);
padding: 0 calc(0.5ch - 0.0625rem);
}
*:focus .span_key {
border: 0.0625rem solid var(--bg);
border-bottom: 0.125rem solid var(--bg);
border: 0.0625rem solid var(--bg);
border-bottom: 0.125rem solid var(--bg);
}

View File

@ -1,79 +1,79 @@
table {
margin: 4rem 0 2rem 0;
border-collapse: collapse;
margin: 4rem 0 2rem 0;
border-collapse: collapse;
}
th > div > p,
td > div > p {
font-size: 0.5rem;
font-weight: normal;
text-align: center;
font-size: 0.5rem;
font-weight: normal;
text-align: center;
}
th > div,
td > div {
width: 6rem;
aspect-ratio: 1 / 1;
display: grid;
justify-content: center;
width: 6rem;
aspect-ratio: 1 / 1;
display: grid;
justify-content: center;
}
tr:first-of-type th > div {
width: 6rem;
aspect-ratio: 3 / 1;
width: 6rem;
aspect-ratio: 3 / 1;
}
td > div > input,
td > div > label,
td > div > p {
grid-row: 1;
grid-column: 1;
display: inline-block;
margin: auto;
white-space: pre;
text-align: center;
line-height: 1.1;
grid-row: 1;
grid-column: 1;
display: inline-block;
margin: auto;
white-space: pre;
text-align: center;
line-height: 1.1;
}
tr th:first-of-type > div {
font-size: 0.5rem;
width: 2rem;
justify-content: start;
font-size: 0.5rem;
width: 2rem;
justify-content: start;
}
tr th:first-of-type > div > p {
font-size: 0.5rem;
text-align: start;
font-size: 0.5rem;
text-align: start;
}
td > div > input + label {
font-size: 4rem;
height: auto;
font-size: 4rem;
height: auto;
}
#section_2 fieldset {
border: none;
display: block;
border: none;
display: block;
}
#section_2 input {
width: 0;
height: 0;
opacity: 0;
width: 0;
height: 0;
opacity: 0;
}
#section_2 input:focus:checked + label {
background-color: var(--text);
color: var(--bg);
transform: scale(4);
z-index: 2;
background-color: var(--text);
color: var(--bg);
transform: scale(4);
z-index: 2;
}
#section_2 input:checked + label::before {
display: none;
display: none;
}
#section_2 input:checked + label:hover::before {
display: block;
background: var(--bg50);
display: block;
background: var(--bg50);
}

View File

@ -1,110 +1,110 @@
#familiar_form fieldset {
border: none;
display: flex;
gap: 1rem;
position: relative;
width: fit-content;
border: none;
display: flex;
gap: 1rem;
position: relative;
width: fit-content;
}
#familiar_form fieldset::before {
content: "";
position: absolute;
height: 0.0625rem;
bottom: 0.125rem;
left: 1rem;
right: 1rem;
background-color: var(--text);
content: "";
position: absolute;
height: 0.0625rem;
bottom: 0.125rem;
left: 1rem;
right: 1rem;
background-color: var(--text);
}
#familiar_form fieldset div {
display: flex;
flex-direction: column-reverse;
align-items: center;
gap: 0.5rem;
display: flex;
flex-direction: column-reverse;
align-items: center;
gap: 0.5rem;
}
#familiar_form input[type="radio"] {
-webkit-appearance: none;
appearance: none;
background-color: var(--text);
-webkit-appearance: none;
appearance: none;
background-color: var(--text);
display: block;
width: 0.375rem;
height: 0.375rem;
display: block;
width: 0.375rem;
height: 0.375rem;
/* display: grid; */
/* place-content: center; */
/* display: grid; */
/* place-content: center; */
}
#familiar_form label {
display: inline;
height: auto;
display: inline;
height: auto;
}
#familiar_form input[type="radio"]:checked {
transform: scale(1.5);
transform: scale(1.5);
}
#familiar_form input[type="radio"]:focus {
transform: scale(2);
transform: scale(2);
}
#familiar_form fieldset > div:nth-child(2) {
margin-left: 16rem;
margin-left: 16rem;
}
#familiar_form fieldset > div:nth-child(3) {
margin-left: 15rem;
margin-left: 15rem;
}
#familiar_form fieldset > div:nth-child(5) {
margin-left: 1rem;
margin-left: 1rem;
}
cite {
font-style: normal;
font-style: normal;
}
figure {
width: max-content;
width: max-content;
}
blockquote,
blockquote ~ * {
font-size: 0.75rem;
padding-left: 2ch;
position: relative;
border-left: 0.0625rem solid var(--text);
max-width: var(--max-width);
font-size: 0.75rem;
padding-left: 2ch;
position: relative;
border-left: 0.0625rem solid var(--text);
max-width: var(--max-width);
}
blockquote::before {
content: "“";
left: -0.5ch;
top: 0;
font-size: 1.5rem;
line-height: 2rem;
content: "“";
left: -0.5ch;
top: 0;
font-size: 1.5rem;
line-height: 2rem;
}
#familiar_container svg {
width: 100rem;
height: 20rem;
width: 100rem;
height: 20rem;
}
#familiar_container svg {
width: 100rem;
height: 20rem;
width: 100rem;
height: 20rem;
}
.svg_container {
width: 100rem;
height: 20rem;
width: 100rem;
height: 20rem;
}
#familiar_container svg path {
fill: var(--text);
fill: var(--text);
}
#familiar_container .svg_container:focus svg path {
fill: var(--bg);
fill: var(--bg);
}

View File

@ -1,126 +1,126 @@
#original figure > div,
#smart_kerning figure > div {
display: flex;
display: flex;
}
#original p,
#smart_kerning p {
font-size: 24rem;
line-height: 1;
position: relative;
border-right: 0.0625rem solid var(--text);
border-left: 0.0625rem solid var(--text);
margin-left: -0.0625rem;
font-size: 24rem;
line-height: 1;
position: relative;
border-right: 0.0625rem solid var(--text);
border-left: 0.0625rem solid var(--text);
margin-left: -0.0625rem;
}
#original p::after,
#smart_kerning p::after {
font-size: 0.75rem;
text-align: center;
display: block;
width: 100%;
font-size: 0.75rem;
text-align: center;
display: block;
width: 100%;
}
#original p:nth-child(1)::after,
#smart_kerning p:nth-child(1)::after {
content: "Wide letter";
content: "Wide letter";
}
#original p:nth-child(2)::after {
content: "Smart kerning OFF";
content: "Smart kerning OFF";
}
#smart_kerning p:nth-child(2)::after {
content: "Smart kerning ON";
content: "Smart kerning ON";
}
#original p:nth-child(3)::after,
#smart_kerning p:nth-child(3)::after {
content: "Narrow letter";
content: "Narrow letter";
}
#smart_kerning p:nth-child(2)::before {
content: "o";
position: absolute;
transform: translateX(calc(24rem / 1000 * 40));
color: var(--middle);
z-index: -1;
content: "o";
position: absolute;
transform: translateX(calc(24rem / 1000 * 40));
color: var(--middle);
z-index: -1;
}
#before p,
#after p {
font-size: 8rem;
line-height: 1;
max-width: none;
white-space: nowrap;
font-size: 8rem;
line-height: 1;
max-width: none;
white-space: nowrap;
}
#before p {
font-feature-settings: "ss05" 0;
font-feature-settings: "ss05" 0;
}
#after p {
font-feature-settings: "ss05" 1;
font-feature-settings: "ss05" 1;
}
#intelligent_form fieldset {
border: none;
display: flex;
gap: 2rem;
font-size: 0.75rem;
line-height: 1rem;
background-color: var(--bg);
width: max-content;
border: none;
display: flex;
gap: 2rem;
font-size: 0.75rem;
line-height: 1rem;
background-color: var(--bg);
width: max-content;
}
#intelligent_form > div {
position: relative;
position: relative;
}
#intelligent_form input {
-webkit-appearance: none;
appearance: none;
background-color: var(--text);
margin: 0;
padding: 0;
border: none;
-webkit-appearance: none;
appearance: none;
background-color: var(--text);
margin: 0;
padding: 0;
border: none;
color: var(--text);
width: 0;
height: 0;
position: relative;
opacity: 1;
display: block;
color: var(--text);
width: 0;
height: 0;
position: relative;
opacity: 1;
display: block;
}
#intelligent_form input + label {
position: relative;
z-index: 1;
position: relative;
z-index: 1;
}
#intelligent_form input + label::before {
z-index: -1;
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: var(--bg);
z-index: -1;
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: var(--bg);
}
#intelligent_form input:focus:checked + label::before {
background-color: var(--text);
background-color: var(--text);
}
#intelligent_form input:focus:checked + label {
color: var(--bg);
color: var(--bg);
}
#intelligent_form input:checked + label::before {
background: var(--bg25);
background: var(--bg25);
}
#intelligent_form input:checked + label {
color: var(--text);
color: var(--text);
}

View File

@ -1,75 +1,75 @@
#code_form fieldset {
font-size: 1.5rem;
line-height: 1.65rem;
gap: 1ch;
font-size: 1.5rem;
line-height: 1.65rem;
gap: 1ch;
}
form fieldset {
border: none;
display: flex;
gap: 4ch;
font-size: 0.75rem;
line-height: 1rem;
background-color: var(--bg);
width: max-content;
border: none;
display: flex;
gap: 4ch;
font-size: 0.75rem;
line-height: 1rem;
background-color: var(--bg);
width: max-content;
}
form > div {
position: relative;
position: relative;
}
form input {
-webkit-appearance: none;
appearance: none;
background-color: var(--text);
margin: 0;
padding: 0;
border: none;
-webkit-appearance: none;
appearance: none;
background-color: var(--text);
margin: 0;
padding: 0;
border: none;
color: var(--text);
width: 0;
height: 0;
position: relative;
opacity: 1;
display: block;
color: var(--text);
width: 0;
height: 0;
position: relative;
opacity: 1;
display: block;
}
form input + label {
position: relative;
z-index: 1;
cursor: pointer;
height: 100%;
display: inline-block;
position: relative;
z-index: 1;
cursor: pointer;
height: 100%;
display: inline-block;
}
form input + label::before {
z-index: -1;
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: var(--bg);
z-index: -1;
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: var(--bg);
}
form input:focus:checked + label::before {
background-color: var(--text);
background-color: var(--text);
}
form input:focus:checked + label {
color: var(--bg);
color: var(--bg);
}
form input:checked + label::before {
background: var(--bg25);
background-position: 1px 0.5px;
background: var(--bg25);
background-position: 1px 0.5px;
}
#canvas {
transform-origin: top left;
transform-origin: top left;
}
#code_description {
height: 4rem;
height: 4rem;
}

View File

@ -1,136 +1,136 @@
#waterfall {
display: flex;
width: min-content;
gap: 2rem;
display: flex;
width: min-content;
gap: 2rem;
}
.waterfall_texts_container {
display: flex;
flex-direction: column;
justify-content: end;
height: 10rem;
display: flex;
flex-direction: column;
justify-content: end;
height: 10rem;
}
.waterfall_texts_container > div {
height: 2.5rem;
display: flex;
align-items: end;
height: 2.5rem;
display: flex;
align-items: end;
}
.waterfall_text {
line-height: 0.6;
white-space: pre;
line-height: 0.6;
white-space: pre;
}
.waterfall_desc {
width: max-content;
white-space: pre;
width: max-content;
white-space: pre;
}
.question_container {
display: flex;
align-items: center;
font-size: 0.75rem;
gap: 2ch;
position: relative;
margin-top: 1rem;
display: flex;
align-items: center;
font-size: 0.75rem;
gap: 2ch;
position: relative;
margin-top: 1rem;
}
.question_character.hide_character {
opacity: 1;
animation: 0ms 0s 3 forwards flicker_reverse;
opacity: 1;
animation: 0ms 0s 3 forwards flicker_reverse;
}
.question_character.show_character {
opacity: 0;
animation: 100ms 0s 3 forwards flicker;
opacity: 0;
animation: 100ms 0s 3 forwards flicker;
}
.button_container button {
display: block;
display: block;
}
:root {
--question-character-size: 6rem;
--question-character-size: 6rem;
}
.question_character {
font-size: var(--question-character-size);
line-height: var(--question-character-size);
border: 0.0625rem solid var(--text);
position: relative;
font-size: var(--question-character-size);
line-height: var(--question-character-size);
border: 0.0625rem solid var(--text);
position: relative;
}
.question_character::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 15%;
/* height: 0.0625rem; */
background-color: var(--text);
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 15%;
/* height: 0.0625rem; */
background-color: var(--text);
}
#score_points {
display: none;
display: none;
}
#score_points.view_score {
display: block;
display: block;
}
.question_button:focus::before,
.question_button:hover::before {
content: "<-";
position: absolute;
left: -2ch;
color: var(--text);
content: "<-";
position: absolute;
left: -2ch;
color: var(--text);
}
.question_button:hover {
background: var(--bg50);
color: var(--bg);
background: var(--bg50);
color: var(--bg);
}
.question_button.right_button::before {
content: "<-";
position: absolute;
left: -2ch;
color: var(--text);
content: "<-";
position: absolute;
left: -2ch;
color: var(--text);
}
.question_button.wrong_button::before {
content: "->";
position: absolute;
left: auto;
right: -2ch;
color: var(--text);
content: "->";
position: absolute;
left: auto;
right: -2ch;
color: var(--text);
}
.question_button.button_choice {
background: var(--bg25);
color: var(--text);
background: var(--bg25);
color: var(--text);
}
.question_button.button_choice:focus {
background: var(--bg75);
color: var(--bg);
background: var(--bg75);
color: var(--bg);
}
.answer_feedback {
position: relative;
font-size: 0.75rem;
top: calc(var(--question-character-size) * 0.5);
top: 40%;
width: 0;
margin-left: -2ch;
left: 0;
position: relative;
font-size: 0.75rem;
top: calc(var(--question-character-size) * 0.5);
top: 40%;
width: 0;
margin-left: -2ch;
left: 0;
}
.question_container.active_question ~ .question_container.active_question {
pointer-events: auto;
display: flex;
pointer-events: auto;
display: flex;
}
.question_container.active_question ~ .question_container {
pointer-events: none;
display: none;
pointer-events: none;
display: none;
}
.question_container.active_question ~ br {
display: none;
display: none;
}

View File

@ -1,97 +1,97 @@
#section_7 #alternates_container fieldset,
#section_7 #features_container fieldset {
display: grid;
grid-template-columns: 21ch 3ch 3ch;
gap: 2ch;
display: grid;
grid-template-columns: 21ch 3ch 3ch;
gap: 2ch;
}
#section_7 #examplesettings_form fieldset p {
white-space: pre;
font-variant-ligatures: none;
white-space: pre;
font-variant-ligatures: none;
}
fieldset.alternates > div {
width: 4ch;
width: 4ch;
}
#section_7 form > div {
position: relative;
position: relative;
}
#examples_container {
width: fit-content;
max-height: 20.6rem;
margin-bottom: 0.4rem;
overflow-y: scroll;
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
width: fit-content;
max-height: 20.6rem;
margin-bottom: 0.4rem;
overflow-y: scroll;
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
}
#examples_container::-webkit-scrollbar {
display: none; /* Safari and Chrome */
display: none; /* Safari and Chrome */
}
p#code_example {
white-space: pre;
max-width: none;
min-width: 102ch;
padding-left: 5ch;
position: relative;
font-variant-ligatures: none;
white-space: pre;
max-width: none;
min-width: 102ch;
padding-left: 5ch;
position: relative;
font-variant-ligatures: none;
}
p#code_example::before {
content: attr(data-before);
position: absolute;
white-space: pre;
left: 0;
top: 0;
height: 100%;
overflow: hidden;
content: attr(data-before);
position: absolute;
white-space: pre;
left: 0;
top: 0;
height: 100%;
overflow: hidden;
}
button:focus a {
color: var(--bg);
text-decoration: none;
color: var(--bg);
text-decoration: none;
}
.download_button {
display: block;
width: max-content;
position: relative;
display: block;
width: max-content;
position: relative;
}
.download_button:hover {
background: var(--bg50);
color: var(--bg);
text-decoration: none;
background: var(--bg50);
color: var(--bg);
text-decoration: none;
}
.download_button:focus {
background-color: var(--text);
color: var(--bg);
text-decoration: none;
background-color: var(--text);
color: var(--bg);
text-decoration: none;
}
.download_button::after {
position: absolute;
color: var(--text);
right: -2ch;
top: 0;
position: absolute;
color: var(--text);
right: -2ch;
top: 0;
}
.download_button.loading::after {
content: ".";
animation: 800ms 0ms steps(4, jump-none) infinite loading;
content: ".";
animation: 800ms 0ms steps(4, jump-none) infinite loading;
}
.download_button.loaded::after {
content: "✓";
animation: none;
content: "✓";
animation: none;
}
.download_button.error::after {
content: "✕";
animation: none;
content: "✕";
animation: none;
}
@keyframes loading {
0% {
transform: translateX(0);
}
100% {
transform: translateX(2ch);
}
0% {
transform: translateX(0);
}
100% {
transform: translateX(2ch);
}
}

View File

@ -1,77 +1,77 @@
ol {
font-size: 0.75rem;
margin-left: 0;
max-width: max-content;
counter-reset: install;
list-style: none;
font-size: 0.75rem;
margin-left: 0;
max-width: max-content;
counter-reset: install;
list-style: none;
}
ol > li {
margin-left: 3ch;
max-width: calc(var(--max-width) - 3ch);
counter-increment: install;
position: relative;
margin-left: 3ch;
max-width: calc(var(--max-width) - 3ch);
counter-increment: install;
position: relative;
}
ol > li p::before {
content: "#" counter(install) " ";
position: absolute;
left: -3ch;
content: "#" counter(install) " ";
position: absolute;
left: -3ch;
}
ol li p {
max-width: calc(var(--max-width) - 6ch);
max-width: calc(var(--max-width) - 6ch);
}
ol:focus li p {
color: var(--bg);
color: var(--bg);
}
ol li ul li p {
position: relative;
position: relative;
}
ol li ul li p::before {
content: "•";
position: absolute;
left: -2ch;
content: "•";
position: absolute;
left: -2ch;
}
details > summary {
cursor: pointer;
list-style: none;
width: fit-content;
max-width: calc(var(--max-width) - 4ch);
margin-left: 4ch;
position: relative;
cursor: pointer;
list-style: none;
width: fit-content;
max-width: calc(var(--max-width) - 4ch);
margin-left: 4ch;
position: relative;
}
details > p {
max-width: calc(var(--max-width) - 4ch);
margin: 0 0 1rem 4ch;
max-width: calc(var(--max-width) - 4ch);
margin: 0 0 1rem 4ch;
}
details > ol {
max-width: calc(var(--max-width) - 4ch);
margin: 0 0 1rem 4ch;
counter-reset: reinstall;
max-width: calc(var(--max-width) - 4ch);
margin: 0 0 1rem 4ch;
counter-reset: reinstall;
}
details > ol li::before {
display: block;
counter-increment: reinstall;
content: "#" counter(reinstall) " ";
position: absolute;
left: -3ch;
display: block;
counter-increment: reinstall;
content: "#" counter(reinstall) " ";
position: absolute;
left: -3ch;
}
details > ol li {
position: relative;
position: relative;
}
details > summary::before {
content: "[+]";
position: absolute;
left: -4ch;
content: "[+]";
position: absolute;
left: -4ch;
}
details[open] > summary::before {
content: "[-]";
content: "[-]";
}
details > summary:focus::before {
color: var(--text);
color: var(--text);
}

View File

@ -1,44 +1,44 @@
.documentation_example {
width: max-content;
font-variant-ligatures: none;
white-space: pre;
font-feature-settings: normal;
.docs_example {
width: max-content;
font-variant-ligatures: none;
white-space: pre;
font-feature-settings: normal;
}
.span_off,
.span_on {
cursor: pointer;
cursor: pointer;
}
.active_feature {
cursor: pointer;
background: var(--bg25);
height: 100%;
display: inline-block;
cursor: pointer;
background: var(--bg25);
height: 100%;
display: inline-block;
}
h2:focus .active_feature {
background: var(--bg25-i);
background: var(--bg25-i);
}
#features_docu h2 {
max-width: var(--max-width);
max-width: var(--max-width);
}
.documentation_alternate {
margin-right: 2rem;
display: inline-block;
vertical-align: baseline;
.docs_alternate {
margin-right: 2rem;
display: inline-block;
vertical-align: baseline;
}
#features_docu > div {
width: max-content;
width: max-content;
}
#charset {
width: var(--max-width);
font-variant-ligatures: none;
white-space: pre-wrap;
font-size: 3rem;
line-height: 4rem;
width: var(--max-width);
font-variant-ligatures: none;
white-space: pre-wrap;
font-size: 3rem;
line-height: 4rem;
}

View File

@ -1,244 +1,244 @@
:root {
--bg25: repeating-conic-gradient(var(--text) 0% 25%, transparent 0% 100%) 1px 0.5px / 2px 2px;
--bg50: repeating-conic-gradient(var(--text) 0% 25%, transparent 0% 50%, var(--text) 0% 75%, transparent 0% 100%) 1px
0.5px / 2px 2px;
--bg75: repeating-conic-gradient(transparent 0% 25%, var(--text) 0% 100%) 1px 0.5px / 2px 2px;
--bg25-i: repeating-conic-gradient(var(--bg) 0% 25%, transparent 0% 100%) 1px 0.5px / 2px 2px;
--bg50-i: repeating-conic-gradient(var(--bg) 0% 25%, transparent 0% 50%, var(--bg) 0% 75%, transparent 0% 100%) 1px
0.5px / 2px 2px;
--bg75-i: repeating-conic-gradient(transparent 0% 25%, var(--bg) 0% 100%) 1px 0.5px / 2px 2px;
--bg25: repeating-conic-gradient(var(--text) 0% 25%, transparent 0% 100%) 1px 0.5px / 2px 2px;
--bg50: repeating-conic-gradient(var(--text) 0% 25%, transparent 0% 50%, var(--text) 0% 75%, transparent 0% 100%)
1px 0.5px / 2px 2px;
--bg75: repeating-conic-gradient(transparent 0% 25%, var(--text) 0% 100%) 1px 0.5px / 2px 2px;
--bg25-i: repeating-conic-gradient(var(--bg) 0% 25%, transparent 0% 100%) 1px 0.5px / 2px 2px;
--bg50-i: repeating-conic-gradient(var(--bg) 0% 25%, transparent 0% 50%, var(--bg) 0% 75%, transparent 0% 100%) 1px
0.5px / 2px 2px;
--bg75-i: repeating-conic-gradient(transparent 0% 25%, var(--bg) 0% 100%) 1px 0.5px / 2px 2px;
}
::selection {
color: var(--text);
background-color: var(--middle);
color: var(--text);
background-color: var(--middle);
}
#block_tab_start,
#block_tab_end {
position: absolute;
top: 0;
position: absolute;
top: 0;
}
#main_scale {
inset: 0;
overflow: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
height: 100vh;
height: 100dvh;
padding-bottom: 10rem;
inset: 0;
overflow: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
height: 100vh;
height: 100dvh;
padding-bottom: 10rem;
}
#main_scale::-webkit-scrollbar {
display: none;
display: none;
}
main {
min-width: 100vw;
width: fit-content;
padding: 4rem 2ch 0 4ch;
min-width: 100vw;
width: fit-content;
padding: 4rem 2ch 0 4ch;
}
header nav {
width: 100vw;
padding: 1rem 4ch 0 4ch;
background-color: var(--bg);
z-index: 100;
position: fixed;
top: 0;
width: 100vw;
padding: 1rem 4ch 0 4ch;
background-color: var(--bg);
z-index: 100;
position: fixed;
top: 0;
}
header #keyboard_section {
width: 100%;
padding: 0.25rem 4ch 1rem 4ch;
background-color: var(--bg);
z-index: 100;
position: fixed;
bottom: 0;
width: 100%;
padding: 0.25rem 4ch 1rem 4ch;
background-color: var(--bg);
z-index: 100;
position: fixed;
bottom: 0;
}
header #keyboard_section,
header nav {
overflow-y: scroll;
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
overflow-y: scroll;
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
}
header #keyboard_section::-webkit-scrollbar,
header nav::-webkit-scrollbar {
display: none; /* Safari and Chrome */
display: none; /* Safari and Chrome */
}
#keyboard_section.hidden {
display: none;
display: none;
}
#nav_form {
display: flex;
gap: 4ch;
font-size: 0.75rem;
line-height: 1rem;
width: max-content;
display: flex;
gap: 4ch;
font-size: 0.75rem;
line-height: 1rem;
width: max-content;
}
#nav_form input {
-webkit-appearance: none;
appearance: none;
width: 0;
height: 0;
opacity: 0;
-webkit-appearance: none;
appearance: none;
width: 0;
height: 0;
opacity: 0;
}
#nav_form input + label {
position: relative;
z-index: 1;
position: relative;
z-index: 1;
}
#nav_form input + label::before {
z-index: -1;
content: "";
position: absolute;
inset: 0;
background-color: var(--bg);
z-index: -1;
content: "";
position: absolute;
inset: 0;
background-color: var(--bg);
}
#nav_form input:focus:checked + label::before {
background-color: var(--text);
background-color: var(--text);
}
#nav_form input:focus:checked + label {
color: var(--bg);
color: var(--bg);
}
#section_container {
inset: 1rem 2rem;
inset: 1rem 2rem;
}
p,
a,
figcaption,
button {
font-size: 0.75rem;
line-height: 1rem;
max-width: var(--max-width);
width: fit-content;
vertical-align: top;
color: inherit;
font-size: 0.75rem;
line-height: 1rem;
max-width: var(--max-width);
width: fit-content;
vertical-align: top;
color: inherit;
}
a,
.download_button {
text-decoration: underline;
text-decoration-skip-ink: none;
text-underline-offset: 0.24ch;
cursor: pointer;
text-decoration: underline;
text-decoration-skip-ink: none;
text-underline-offset: 0.24ch;
cursor: pointer;
}
a:focus,
.download_button:focus {
text-decoration: none;
text-decoration: none;
}
h1 {
font-size: 1.5rem;
line-height: 2rem;
font-weight: normal;
width: fit-content;
font-size: 1.5rem;
line-height: 2rem;
font-weight: normal;
width: fit-content;
}
#change_setting p {
padding: 0 1ch;
background-color: var(--bg);
padding: 0 1ch;
background-color: var(--bg);
}
.faded {
opacity: 0.33;
opacity: 0.33;
}
#mobile {
visibility: hidden;
visibility: hidden;
}
:focus {
text-decoration: none;
color: var(--bg);
background-color: var(--text);
outline: none;
text-decoration: none;
color: var(--bg);
background-color: var(--text);
outline: none;
}
form input:hover + label {
text-decoration: none;
color: var(--bg);
outline: none;
text-decoration: none;
color: var(--bg);
outline: none;
}
form input:hover + label::before {
background: var(--bg50);
background: var(--bg50);
}
form input:checked:hover + label::before {
background: var(--bg75);
background: var(--bg75);
}
ul li,
ol li {
font-size: 0.75rem;
line-height: 1rem;
margin-left: 2ch;
max-width: 54ch;
font-size: 0.75rem;
line-height: 1rem;
margin-left: 2ch;
max-width: 54ch;
}
ul {
list-style-type: none;
max-width: max-content;
list-style-type: none;
max-width: max-content;
}
ol li::before {
display: none;
display: none;
}
ul li::before {
content: "• ";
position: absolute;
margin-left: -2ch;
content: "• ";
position: absolute;
margin-left: -2ch;
}
ul li:focus::before {
background-color: transparent;
color: var(--text);
background-color: transparent;
color: var(--text);
}
#page_animation {
width: 200vw;
height: 200vh;
height: 200dvh;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-color: var(--bg);
pointer-events: none;
width: 200vw;
height: 200vh;
height: 200dvh;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-color: var(--bg);
pointer-events: none;
}
#page_animation.page_animation {
animation: 440ms steps(10, jump-start) forwards page_animation;
animation: 440ms steps(10, jump-start) forwards page_animation;
}
@keyframes page_animation {
0% {
transform: translateY(0vh);
}
99.9% {
visibility: visible;
}
100% {
visibility: hidden;
transform: translateY(200vh);
}
0% {
transform: translateY(0vh);
}
99.9% {
visibility: visible;
}
100% {
visibility: hidden;
transform: translateY(200vh);
}
}
#focus_check {
position: absolute;
position: absolute;
}
#footer_hint_mobile {
display: none;
display: none;
}

View File

@ -3,349 +3,349 @@ const codeFieldset = document.querySelector("#code_form fieldset")
const codeDescription = document.querySelector("#code_description")
function buildCode() {
console.log("buildCode")
websiteData.sections.forEach((section) => {
if (section.name == "code") {
section.content.characters.forEach((character, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "code"
input.id = character.name
input.classList.add("code_character")
input.value = character.name
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = character.value
label.setAttribute("for", character.name)
div.append(input, label)
codeFieldset.append(div)
console.log("buildCode")
websiteData.sections.forEach((section) => {
if (section.name == "code") {
section.content.characters.forEach((character, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "code"
input.id = character.name
input.classList.add("code_character")
input.value = character.name
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = character.value
label.setAttribute("for", character.name)
div.append(input, label)
codeFieldset.append(div)
const p = document.createElement("p")
p.tabIndex = 0
p.dataset.edit = "true"
p.classList.add("code_char")
p.dataset.char = character.name
p.textContent = character.description
p.style.display = "none"
codeDescription.append(p)
})
}
})
const p = document.createElement("p")
p.tabIndex = 0
p.dataset.edit = "true"
p.classList.add("code_char")
p.dataset.char = character.name
p.textContent = character.description
p.style.display = "none"
codeDescription.append(p)
})
}
})
}
function updateCode(event, form) {
console.log("updateCode")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
console.log("updateCode")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
let displayCharacter = ""
let displayName = ""
websiteData.sections.forEach((section) => {
if (section.name == "code") {
section.content.characters.forEach((character, index) => {
if (character.name == output) {
displayCharacter = character.value
displayName = character.name
const ps = document.querySelectorAll(".code_char")
ps.forEach((p) =>
p.dataset.char == character.name ? (p.style.display = "block") : (p.style.display = "none")
)
}
})
}
})
let displayCharacter = ""
let displayName = ""
websiteData.sections.forEach((section) => {
if (section.name == "code") {
section.content.characters.forEach((character, index) => {
if (character.name == output) {
displayCharacter = character.value
displayName = character.name
const ps = document.querySelectorAll(".code_char")
ps.forEach((p) =>
p.dataset.char == character.name ? (p.style.display = "block") : (p.style.display = "none")
)
}
})
}
})
let selectedGlyphData
if (commitMonoFont) {
Object.values(commitMonoFont.glyphs.glyphs).forEach((glyph) => {
if (glyph.name == output) selectedGlyphData = glyph
})
updateCanvas(selectedGlyphData, commitMonoFont, displayCharacter, displayName)
}
let selectedGlyphData
if (commitMonoFont) {
Object.values(commitMonoFont.glyphs.glyphs).forEach((glyph) => {
if (glyph.name == output) selectedGlyphData = glyph
})
updateCanvas(selectedGlyphData, commitMonoFont, displayCharacter, displayName)
}
if (event) event.preventDefault()
if (event) event.preventDefault()
}
const canvasScale = 16
const drawFontLine = (GLYPH_SCALE, ctx, upem, width, name, value, yOffset) => {
let scaledValue = mapRange(value, 0, upem, 0, width * GLYPH_SCALE)
scaledValue = width - scaledValue + (yOffset * GLYPH_SCALE * width) / upem
let scaledValue = mapRange(value, 0, upem, 0, width * GLYPH_SCALE)
scaledValue = width - scaledValue + (yOffset * GLYPH_SCALE * width) / upem
ctx.strokeStyle = getCssVar("--text")
ctx.beginPath()
ctx.moveTo(7 * canvasScale, scaledValue)
ctx.lineTo(width - 7 * canvasScale, scaledValue)
ctx.closePath()
ctx.stroke()
ctx.strokeStyle = getCssVar("--text")
ctx.beginPath()
ctx.moveTo(7 * canvasScale, scaledValue)
ctx.lineTo(width - 7 * canvasScale, scaledValue)
ctx.closePath()
ctx.stroke()
ctx.fillStyle = getCssVar("--text")
ctx.font = `${0.75 * canvasScale}px "CommitMono"`
ctx.textAlign = "left"
ctx.fillText(name, 0, scaledValue + 0.25 * canvasScale)
ctx.textAlign = "left"
ctx.fillText(value, width - 4 * canvasScale, scaledValue + 0.25 * canvasScale)
ctx.fillStyle = getCssVar("--text")
ctx.font = `${0.75 * canvasScale}px "CommitMono"`
ctx.textAlign = "left"
ctx.fillText(name, 0, scaledValue + 0.25 * canvasScale)
ctx.textAlign = "left"
ctx.fillText(value, width - 4 * canvasScale, scaledValue + 0.25 * canvasScale)
}
const drawFontLineVertical = (GLYPH_SCALE, ctx, upem, width, value, yOffset, ascender, descender) => {
let scaledValue1 = mapRange(ascender, 0, upem, 0, width * GLYPH_SCALE)
scaledValue1 = width - scaledValue1 + (yOffset * GLYPH_SCALE * width) / upem
let scaledValue2 = mapRange(descender, 0, upem, 0, width * GLYPH_SCALE)
scaledValue2 = width - scaledValue2 + (yOffset * GLYPH_SCALE * width) / upem
let scaledValue1 = mapRange(ascender, 0, upem, 0, width * GLYPH_SCALE)
scaledValue1 = width - scaledValue1 + (yOffset * GLYPH_SCALE * width) / upem
let scaledValue2 = mapRange(descender, 0, upem, 0, width * GLYPH_SCALE)
scaledValue2 = width - scaledValue2 + (yOffset * GLYPH_SCALE * width) / upem
ctx.strokeStyle = getCssVar("--text")
ctx.beginPath()
ctx.moveTo(value, scaledValue1)
ctx.lineTo(value, scaledValue2)
ctx.closePath()
ctx.stroke()
ctx.strokeStyle = getCssVar("--text")
ctx.beginPath()
ctx.moveTo(value, scaledValue1)
ctx.lineTo(value, scaledValue2)
ctx.closePath()
ctx.stroke()
}
function updateCanvas(selectedGlyphData, selectedFont, displayCharacter, displayName) {
// initialize canvas
let CANVAS_SCALE = window.devicePixelRatio
const canvas = document.querySelector("#canvas")
let canvasWidth = 60 * canvasScale
let canvasHeight = 42 * canvasScale
canvas.style.width = `${canvasWidth}px`
canvas.style.height = `${canvasHeight}px`
canvas.width = canvasWidth * CANVAS_SCALE
canvas.height = canvasHeight * CANVAS_SCALE
const ctx = canvas.getContext("2d")
ctx.scale(CANVAS_SCALE, CANVAS_SCALE)
// initialize canvas
let CANVAS_SCALE = window.devicePixelRatio
const canvas = document.querySelector("#canvas")
let canvasWidth = 60 * canvasScale
let canvasHeight = 42 * canvasScale
canvas.style.width = `${canvasWidth}px`
canvas.style.height = `${canvasHeight}px`
canvas.width = canvasWidth * CANVAS_SCALE
canvas.height = canvasHeight * CANVAS_SCALE
const ctx = canvas.getContext("2d")
ctx.scale(CANVAS_SCALE, CANVAS_SCALE)
let GLYPH_SCALE = 0.6
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
let GLYPH_SCALE = 0.6
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
if (selectedGlyphData.path) {
const CANVAS_GLYPH_COMPOSITION_FILL = [
{
type: "outline",
fill: true,
color: getCssVar("--text"),
pointSize: undefined,
},
]
const CANVAS_GLYPH_COMPOSITION_BEZIER = [
// {
// type: "outline",
// fill: true,
// color: "rgba(0, 0, 0, 0.1)",
// pointSize: undefined,
// },
{
type: "handles",
fill: false,
color: getCssVar("--middle"),
pointSize: undefined,
},
{
type: "outline",
fill: false,
color: getCssVar("--text"),
pointSize: undefined,
},
{
type: "points",
fill: true,
color: getCssVar("--text"),
pointSize: 10, // size of point on bezier glyph
},
{
type: "handle points",
fill: true,
color: getCssVar("--middle"),
pointSize: 10, // size of handles on bezier glyph
},
]
if (selectedGlyphData.path) {
const CANVAS_GLYPH_COMPOSITION_FILL = [
{
type: "outline",
fill: true,
color: getCssVar("--text"),
pointSize: undefined,
},
]
const CANVAS_GLYPH_COMPOSITION_BEZIER = [
// {
// type: "outline",
// fill: true,
// color: "rgba(0, 0, 0, 0.1)",
// pointSize: undefined,
// },
{
type: "handles",
fill: false,
color: getCssVar("--middle"),
pointSize: undefined,
},
{
type: "outline",
fill: false,
color: getCssVar("--text"),
pointSize: undefined,
},
{
type: "points",
fill: true,
color: getCssVar("--text"),
pointSize: 10, // size of point on bezier glyph
},
{
type: "handle points",
fill: true,
color: getCssVar("--middle"),
pointSize: 10, // size of handles on bezier glyph
},
]
const upem = selectedFont?.unitsPerEm || 1000
const width = 60 * canvasScale
const upem = selectedFont?.unitsPerEm || 1000
const width = 60 * canvasScale
const yOffset = -45 * canvasScale
const xOffset = 20 * canvasScale
const ascender = selectedFont?.tables.os2?.sTypoAscender || 750
const capHeight = selectedFont?.tables.os2?.sCapHeight || 700
const xHeight = selectedFont?.tables.os2?.sxHeight
const baseline = 0
const descender = selectedFont?.tables.os2?.sTypoDescender || -200
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Ascender", ascender, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Cap Height", capHeight, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "X-height", xHeight || 500, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Baseline", baseline, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Descender", descender, yOffset)
drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 7 * canvasScale, yOffset, ascender, descender)
drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 30 * canvasScale, yOffset, ascender, descender)
drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 53 * canvasScale, yOffset, ascender, descender)
const yOffset = -45 * canvasScale
const xOffset = 20 * canvasScale
const ascender = selectedFont?.tables.os2?.sTypoAscender || 750
const capHeight = selectedFont?.tables.os2?.sCapHeight || 700
const xHeight = selectedFont?.tables.os2?.sxHeight
const baseline = 0
const descender = selectedFont?.tables.os2?.sTypoDescender || -200
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Ascender", ascender, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Cap Height", capHeight, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "X-height", xHeight || 500, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Baseline", baseline, yOffset)
drawFontLine(GLYPH_SCALE, ctx, upem, width, "Descender", descender, yOffset)
drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 7 * canvasScale, yOffset, ascender, descender)
drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 30 * canvasScale, yOffset, ascender, descender)
drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 53 * canvasScale, yOffset, ascender, descender)
ctx.fillStyle = getCssVar("--text")
ctx.font = `${0.75 * canvasScale}px "CommitMono"`
ctx.textAlign = "center"
ctx.fillText(displayName, (30 - 11.5) * canvasScale, 2.75 * canvasScale)
ctx.fillText(displayName, (30 + 11.5) * canvasScale, 2.75 * canvasScale)
ctx.fillStyle = getCssVar("--text")
ctx.font = `${0.75 * canvasScale}px "CommitMono"`
ctx.textAlign = "center"
ctx.fillText(displayName, (30 - 11.5) * canvasScale, 2.75 * canvasScale)
ctx.fillText(displayName, (30 + 11.5) * canvasScale, 2.75 * canvasScale)
// make ready transformation matrixes for manipulating paths
let firstMatrix = new DOMMatrix()
firstMatrix = firstMatrix.scaleSelf(width / upem)
let secondMatrix = new DOMMatrix()
secondMatrix = secondMatrix.scaleSelf(GLYPH_SCALE)
secondMatrix = secondMatrix.translateSelf(-width * 0.5, -width) // translate to left edge, top
secondMatrix = secondMatrix.translateSelf((width * 0.5) / GLYPH_SCALE, width / GLYPH_SCALE) // translate to center, baseline
secondMatrix = secondMatrix.translateSelf(0, (yOffset * width) / upem) // translate yOffset
secondMatrix = secondMatrix.translateSelf((xOffset * width) / upem, 0) // translate xOffset
// make ready transformation matrixes for manipulating paths
let firstMatrix = new DOMMatrix()
firstMatrix = firstMatrix.scaleSelf(width / upem)
let secondMatrix = new DOMMatrix()
secondMatrix = secondMatrix.scaleSelf(GLYPH_SCALE)
secondMatrix = secondMatrix.translateSelf(-width * 0.5, -width) // translate to left edge, top
secondMatrix = secondMatrix.translateSelf((width * 0.5) / GLYPH_SCALE, width / GLYPH_SCALE) // translate to center, baseline
secondMatrix = secondMatrix.translateSelf(0, (yOffset * width) / upem) // translate yOffset
secondMatrix = secondMatrix.translateSelf((xOffset * width) / upem, 0) // translate xOffset
// set initial value for glyph composition based on if bezier is switched on or off
// let canvasGlyphComposition = bezier ? CANVAS_GLYPH_COMPOSITION_BEZIER : CANVAS_GLYPH_COMPOSITION_FILL
// set initial value for glyph composition based on if bezier is switched on or off
// let canvasGlyphComposition = bezier ? CANVAS_GLYPH_COMPOSITION_BEZIER : CANVAS_GLYPH_COMPOSITION_FILL
CANVAS_GLYPH_COMPOSITION_BEZIER.forEach((composite) => {
const calcPointsize = composite.pointSize * (upem / 1000)
const firstPath2d = glyphBezier(selectedGlyphData, upem, composite.type, calcPointsize)
const secondPath2d = new Path2D()
secondPath2d.addPath(firstPath2d, firstMatrix)
const finalPath2d = new Path2D()
finalPath2d.addPath(secondPath2d, secondMatrix)
CANVAS_GLYPH_COMPOSITION_BEZIER.forEach((composite) => {
const calcPointsize = composite.pointSize * (upem / 1000)
const firstPath2d = glyphBezier(selectedGlyphData, upem, composite.type, calcPointsize)
const secondPath2d = new Path2D()
secondPath2d.addPath(firstPath2d, firstMatrix)
const finalPath2d = new Path2D()
finalPath2d.addPath(secondPath2d, secondMatrix)
if (composite.fill) {
ctx.fillStyle = composite.color
ctx.fill(finalPath2d)
} else {
ctx.strokeStyle = composite.color
ctx.stroke(finalPath2d)
}
})
CANVAS_GLYPH_COMPOSITION_FILL.forEach((composite) => {
secondMatrix = secondMatrix.translateSelf((-2 * xOffset * width) / upem, 0) // translate xOffset
if (composite.fill) {
ctx.fillStyle = composite.color
ctx.fill(finalPath2d)
} else {
ctx.strokeStyle = composite.color
ctx.stroke(finalPath2d)
}
})
CANVAS_GLYPH_COMPOSITION_FILL.forEach((composite) => {
secondMatrix = secondMatrix.translateSelf((-2 * xOffset * width) / upem, 0) // translate xOffset
const calcPointsize = composite.pointSize * (upem / 1000)
const firstPath2d = glyphBezier(selectedGlyphData, upem, composite.type, calcPointsize)
const secondPath2d = new Path2D()
secondPath2d.addPath(firstPath2d, firstMatrix)
const finalPath2d = new Path2D()
finalPath2d.addPath(secondPath2d, secondMatrix)
const calcPointsize = composite.pointSize * (upem / 1000)
const firstPath2d = glyphBezier(selectedGlyphData, upem, composite.type, calcPointsize)
const secondPath2d = new Path2D()
secondPath2d.addPath(firstPath2d, firstMatrix)
const finalPath2d = new Path2D()
finalPath2d.addPath(secondPath2d, secondMatrix)
if (composite.fill) {
ctx.fillStyle = composite.color
ctx.fill(finalPath2d)
} else {
ctx.strokeStyle = composite.color
ctx.stroke(finalPath2d)
}
})
}
if (composite.fill) {
ctx.fillStyle = composite.color
ctx.fill(finalPath2d)
} else {
ctx.strokeStyle = composite.color
ctx.stroke(finalPath2d)
}
})
}
}
function glyphBezier(glyph, upem, typeOfOutline, pointSize) {
let ps = pointSize
let offsetX = (upem - glyph.advanceWidth) * 0.5
let path2d = new Path2D()
let ps = pointSize
let offsetX = (upem - glyph.advanceWidth) * 0.5
let path2d = new Path2D()
if (typeOfOutline == "outline") {
let commandString = ""
glyph.path.commands.forEach((command) => {
switch (command.type) {
case "M":
commandString += `${command.type} `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "L":
commandString += `${command.type} `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "C":
commandString += `${command.type} `
commandString += `${command.x1 + offsetX} ${upem - command.y1}, `
commandString += `${command.x2 + offsetX} ${upem - command.y2}, `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "Q":
commandString += `${command.type} `
commandString += `${command.x1 + offsetX} ${upem - command.y1}, `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "Z":
commandString += `${command.type} `
break
}
})
path2d.addPath(new Path2D(commandString))
}
if (typeOfOutline == "outline") {
let commandString = ""
glyph.path.commands.forEach((command) => {
switch (command.type) {
case "M":
commandString += `${command.type} `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "L":
commandString += `${command.type} `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "C":
commandString += `${command.type} `
commandString += `${command.x1 + offsetX} ${upem - command.y1}, `
commandString += `${command.x2 + offsetX} ${upem - command.y2}, `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "Q":
commandString += `${command.type} `
commandString += `${command.x1 + offsetX} ${upem - command.y1}, `
commandString += `${command.x + offsetX} ${upem - command.y} `
break
case "Z":
commandString += `${command.type} `
break
}
})
path2d.addPath(new Path2D(commandString))
}
if (typeOfOutline == "points") {
glyph.path.commands.forEach((command) => {
let p = new Path2D()
const x = command.x + offsetX
const y = upem - command.y
switch (command.type) {
case "M":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
case "L":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
case "C":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
case "Q":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
}
path2d.addPath(p)
})
}
if (typeOfOutline == "points") {
glyph.path.commands.forEach((command) => {
let p = new Path2D()
const x = command.x + offsetX
const y = upem - command.y
switch (command.type) {
case "M":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
case "L":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
case "C":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
case "Q":
p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps)
break
}
path2d.addPath(p)
})
}
if (typeOfOutline == "handles") {
let p = new Path2D()
glyph.path.commands.forEach((command) => {
switch (command.type) {
case "M":
p.moveTo(command.x + offsetX, upem - command.y)
break
case "L":
p.moveTo(command.x + offsetX, upem - command.y)
break
case "C":
p.lineTo(command.x1 + offsetX, upem - command.y1)
p.moveTo(command.x + offsetX, upem - command.y)
p.lineTo(command.x2 + offsetX, upem - command.y2)
p.moveTo(command.x + offsetX, upem - command.y)
break
case "Q":
p.lineTo(command.x1 + offsetX, upem - command.y1)
p.moveTo(command.x1 + offsetX, upem - command.y1)
p.lineTo(command.x + offsetX, upem - command.y)
break
case "Z":
p.moveTo(command.x + offsetX, upem - command.y)
break
}
})
path2d.addPath(p)
}
if (typeOfOutline == "handles") {
let p = new Path2D()
glyph.path.commands.forEach((command) => {
switch (command.type) {
case "M":
p.moveTo(command.x + offsetX, upem - command.y)
break
case "L":
p.moveTo(command.x + offsetX, upem - command.y)
break
case "C":
p.lineTo(command.x1 + offsetX, upem - command.y1)
p.moveTo(command.x + offsetX, upem - command.y)
p.lineTo(command.x2 + offsetX, upem - command.y2)
p.moveTo(command.x + offsetX, upem - command.y)
break
case "Q":
p.lineTo(command.x1 + offsetX, upem - command.y1)
p.moveTo(command.x1 + offsetX, upem - command.y1)
p.lineTo(command.x + offsetX, upem - command.y)
break
case "Z":
p.moveTo(command.x + offsetX, upem - command.y)
break
}
})
path2d.addPath(p)
}
if (typeOfOutline == "handle points") {
glyph.path.commands.forEach((command) => {
let p = new Path2D()
const x1 = command.x1 + offsetX
const x2 = command.x2 + offsetX
const y1 = upem - command.y1
const y2 = upem - command.y2
switch (command.type) {
case "C":
p.rect(x1 - ps * 0.5, y1 - ps * 0.5, ps, ps)
p.rect(x2 - ps * 0.5, y2 - ps * 0.5, ps, ps)
break
case "Q":
p.rect(x1 - ps * 0.5, y1 - ps * 0.5, ps, ps)
break
}
path2d.addPath(p)
})
}
if (typeOfOutline == "handle points") {
glyph.path.commands.forEach((command) => {
let p = new Path2D()
const x1 = command.x1 + offsetX
const x2 = command.x2 + offsetX
const y1 = upem - command.y1
const y2 = upem - command.y2
switch (command.type) {
case "C":
p.rect(x1 - ps * 0.5, y1 - ps * 0.5, ps, ps)
p.rect(x2 - ps * 0.5, y2 - ps * 0.5, ps, ps)
break
case "Q":
p.rect(x1 - ps * 0.5, y1 - ps * 0.5, ps, ps)
break
}
path2d.addPath(p)
})
}
return path2d
return path2d
}

View File

@ -1,86 +1,86 @@
let waterfall, gtc
websiteData.sections.forEach((section) => {
if (section.name == "distinction") {
waterfall = section.content.waterfall
gtc = section.content.gtc
}
if (section.name == "distinction") {
waterfall = section.content.waterfall
gtc = section.content.gtc
}
})
function updateWaterfall() {
console.log("updateWaterfall")
const waterfallContainer = document.querySelector("#waterfall")
waterfallContainer.innerHTML = ""
waterfall.sizes.forEach((size) => {
const div = document.createElement("div")
div.id = `size_${size}`
console.log("updateWaterfall")
const waterfallContainer = document.querySelector("#waterfall")
waterfallContainer.innerHTML = ""
waterfall.sizes.forEach((size) => {
const div = document.createElement("div")
div.id = `size_${size}`
const desc = document.createElement("p")
desc.classList.add("waterfall_desc")
desc.textContent = `${size}rem\n${Math.round(size * rem * 100) / 100}px`
const desc = document.createElement("p")
desc.classList.add("waterfall_desc")
desc.textContent = `${size}rem\n${Math.round(size * rem * 100) / 100}px`
const textsContainer = document.createElement("div")
textsContainer.classList.add("waterfall_texts_container")
waterfall.texts.forEach((text) => {
const div2 = document.createElement("div")
const p = document.createElement("p")
p.classList.add("waterfall_text")
p.style.fontSize = `${Math.round(size * rem * 100) / 100}px`
p.textContent = text
div2.append(p)
textsContainer.append(div2)
})
div.append(desc, textsContainer)
const textsContainer = document.createElement("div")
textsContainer.classList.add("waterfall_texts_container")
waterfall.texts.forEach((text) => {
const div2 = document.createElement("div")
const p = document.createElement("p")
p.classList.add("waterfall_text")
p.style.fontSize = `${Math.round(size * rem * 100) / 100}px`
p.textContent = text
div2.append(p)
textsContainer.append(div2)
})
div.append(desc, textsContainer)
waterfallContainer.append(div)
})
waterfallContainer.append(div)
})
}
const gtcForm = document.querySelector("#gtc_form")
const gtcFieldset = document.querySelector("#gtc_form fieldset")
function buildDistinction() {
console.log("buildDistinction")
websiteData.sections.forEach((section) => {
if (section.name == "distinction") {
section.content.gtcDifficulties.forEach((difficulty, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "difficulty"
input.id = `difficulty_${difficulty.name}`
input.classList.add("gtc_difficulty")
input.value = difficulty.name
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = difficulty.name
label.setAttribute("for", `difficulty_${difficulty.name}`)
div.append(input, label)
gtcFieldset.append(div)
})
}
})
console.log("buildDistinction")
websiteData.sections.forEach((section) => {
if (section.name == "distinction") {
section.content.gtcDifficulties.forEach((difficulty, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "difficulty"
input.id = `difficulty_${difficulty.name}`
input.classList.add("gtc_difficulty")
input.value = difficulty.name
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = difficulty.name
label.setAttribute("for", `difficulty_${difficulty.name}`)
div.append(input, label)
gtcFieldset.append(div)
})
}
})
}
function updateGTC(event, form) {
console.log("updateGTC")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
websiteData.sections.forEach((section) => {
if (section.name == "distinction") {
section.content.gtcDifficulties.forEach((difficulty) => {
if (difficulty.name == output) {
setCssVar(["--question-character-size", `${difficulty.size}rem`])
}
})
}
})
console.log("updateGTC")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
websiteData.sections.forEach((section) => {
if (section.name == "distinction") {
section.content.gtcDifficulties.forEach((difficulty) => {
if (difficulty.name == output) {
setCssVar(["--question-character-size", `${difficulty.size}rem`])
}
})
}
})
if (event) event.preventDefault()
if (event) event.preventDefault()
}
let answers = []
@ -88,103 +88,105 @@ let score = -1
let currentQuestion = -1
let firstButtons = []
function buildGTC() {
console.log("buildGTC")
const gtcContainer = document.querySelector("#gtc_questions_container")
gtcContainer.innerHTML = ""
answers = []
firstButtons = []
gtc.forEach((question, index) => {
const div = document.createElement("div")
div.classList.add("question_container")
div.dataset.index = index
console.log("buildGTC")
const gtcContainer = document.querySelector("#gtc_questions_container")
gtcContainer.innerHTML = ""
answers = []
firstButtons = []
gtc.forEach((question, index) => {
const div = document.createElement("div")
div.classList.add("question_container")
div.dataset.index = index
const answer = Math.round(Math.random())
const wrongAnswer = (answer + 1) % 2
answers.push(answer)
const answer = Math.round(Math.random())
const wrongAnswer = (answer + 1) % 2
answers.push(answer)
const p = document.createElement("p")
p.classList.add("question_character")
p.textContent = question.value[answer]
const pWrong = document.createElement("p")
pWrong.classList.add("question_character", "wrong_character", "hide_character")
pWrong.textContent = question.value[wrongAnswer]
const buttonContainer = document.createElement("div")
buttonContainer.classList.add("button_container")
const option0 = document.createElement("button")
option0.classList.add("question_button")
option0.textContent = question.options[0]
option0.dataset.questionIndex = index
option0.tabIndex = -1
firstButtons.push(option0)
const option1 = document.createElement("button")
option1.classList.add("question_button")
option1.textContent = question.options[1]
option1.dataset.questionIndex = index
option1.tabIndex = -1
const p = document.createElement("p")
p.classList.add("question_character")
p.textContent = question.value[answer]
const pWrong = document.createElement("p")
pWrong.classList.add("question_character", "wrong_character", "hide_character")
pWrong.textContent = question.value[wrongAnswer]
const buttonContainer = document.createElement("div")
buttonContainer.classList.add("button_container")
const option0 = document.createElement("button")
option0.classList.add("question_button")
option0.textContent = question.options[0]
option0.dataset.questionIndex = index
option0.tabIndex = -1
firstButtons.push(option0)
const option1 = document.createElement("button")
option1.classList.add("question_button")
option1.textContent = question.options[1]
option1.dataset.questionIndex = index
option1.tabIndex = -1
const options = [option0, option1]
options[answer].addEventListener("click", (e) => nextQuestion(true, answer, wrongAnswer, e.pointerType))
options[wrongAnswer].addEventListener("click", (e) => nextQuestion(false, answer, wrongAnswer, e.pointerType))
const options = [option0, option1]
options[answer].addEventListener("click", (e) => nextQuestion(true, answer, wrongAnswer, e.pointerType))
options[wrongAnswer].addEventListener("click", (e) => nextQuestion(false, answer, wrongAnswer, e.pointerType))
const answerFeedback = document.createElement("p")
answerFeedback.classList.add("answer_feedback")
const answerFeedback = document.createElement("p")
answerFeedback.classList.add("answer_feedback")
buttonContainer.append(option0, option1)
const br = document.createElement("br")
div.append(answerFeedback, p, buttonContainer, pWrong)
gtcContainer.append(div)
})
const scorePoints = document.createElement("p")
scorePoints.id = "score_points"
scorePoints.textContent = `You scored ${score} out of ${gtc.length}`
gtcContainer.append(scorePoints)
nextQuestion(true, 0, 1)
buttonContainer.append(option0, option1)
const br = document.createElement("br")
div.append(answerFeedback, p, buttonContainer, pWrong)
gtcContainer.append(div)
})
const scorePoints = document.createElement("p")
scorePoints.id = "score_points"
scorePoints.textContent = `You scored ${score} out of ${gtc.length}`
gtcContainer.append(scorePoints)
nextQuestion(true, 0, 1)
}
function nextQuestion(correct, answer, wrongAnswer, pointerType) {
console.log(pointerType)
const scoreTally = document.querySelector("#score_tally")
const allQuestions = document.querySelectorAll(".question_container")
let answerFeedback
console.log(pointerType)
const scoreTally = document.querySelector("#score_tally")
const allQuestions = document.querySelectorAll(".question_container")
let answerFeedback
if (correct) score++
if (correct) score++
allQuestions.forEach((question, index) => {
const wrongCharacter = question.querySelector(".wrong_character")
allQuestions.forEach((question, index) => {
const wrongCharacter = question.querySelector(".wrong_character")
if (index == currentQuestion) {
question.classList.add("active_question")
const rightButton = question.querySelector(`.button_container .question_button:nth-child(${answer + 1})`)
const wrongButton = question.querySelector(`.button_container .question_button:nth-child(${wrongAnswer + 1})`)
correct ? rightButton.classList.add("button_choice") : wrongButton.classList.add("button_choice")
rightButton.classList.add("right_button")
wrongButton.classList.add("wrong_button")
if (index == currentQuestion) {
question.classList.add("active_question")
const rightButton = question.querySelector(`.button_container .question_button:nth-child(${answer + 1})`)
const wrongButton = question.querySelector(
`.button_container .question_button:nth-child(${wrongAnswer + 1})`
)
correct ? rightButton.classList.add("button_choice") : wrongButton.classList.add("button_choice")
rightButton.classList.add("right_button")
wrongButton.classList.add("wrong_button")
answerFeedback = question.querySelector(".answer_feedback")
answerFeedback.textContent = correct ? "✓" : "✕"
answerFeedback = question.querySelector(".answer_feedback")
answerFeedback.textContent = correct ? "✓" : "✕"
wrongCharacter.classList.remove("hide_character")
wrongCharacter.classList.add("show_character")
} else if (index == currentQuestion + 1) {
question.classList.add("active_question")
} else {
question.classList.remove("active_question")
}
})
wrongCharacter.classList.remove("hide_character")
wrongCharacter.classList.add("show_character")
} else if (index == currentQuestion + 1) {
question.classList.add("active_question")
} else {
question.classList.remove("active_question")
}
})
currentQuestion++
currentQuestion++
allQuestions.forEach((question, index) => {
if (index == currentQuestion) {
question.querySelectorAll(".question_button").forEach((button) => (button.tabIndex = 0))
}
})
scoreTally.textContent = `Score: ${score}/${gtc.length}`
allQuestions.forEach((question, index) => {
if (index == currentQuestion) {
question.querySelectorAll(".question_button").forEach((button) => (button.tabIndex = 0))
}
})
scoreTally.textContent = `Score: ${score}/${gtc.length}`
if (currentQuestion < gtc.length) {
if (!isMobile && pointerType === "") setTimeout(() => firstButtons[currentQuestion]?.focus(), 10)
} else {
scoreTally.tabIndex = 0
setTimeout(() => scoreTally.focus(), 10)
}
if (currentQuestion < gtc.length) {
if (!isMobile && pointerType === "") setTimeout(() => firstButtons[currentQuestion]?.focus(), 10)
} else {
scoreTally.tabIndex = 0
setTimeout(() => scoreTally.focus(), 10)
}
}

97
src/js/docs_section.js Normal file
View File

@ -0,0 +1,97 @@
const featuresDocu = document.querySelector("#features_docu")
let customizeContent
let docsContent
websiteData.sections.forEach((section) => {
if (section.name == "customize") customizeContent = section.content
if (section.name == "docs") docsContent = section.content
})
function buildDocs() {
console.log("buildDocs")
customizeContent.features.forEach((feature) => {
const sizes = [
[3, 4],
[2, 2.5],
[1, 1.5],
[0.75, 1],
[0.5, 1],
]
const container = document.createElement("div")
const h2 = document.createElement("h2")
const featureDescriptionWithSpan = feature.description
.split("|")
.map((l) =>
l == "OFF"
? `<span class="span_off${
!feature.on ? " active_feature" : ""
}" onclick="changeFeatureDocs('disable')">[OFF]</span>`
: l == "ON"
? `<span class="span_on${
feature.on ? " active_feature" : ""
}" onclick="changeFeatureDocs('enable')">[ON]</span>`
: l
)
.join("")
h2.innerHTML = featureDescriptionWithSpan
h2.tabIndex = 0
h2.dataset.edit = "true"
const p = document.createElement("p")
p.textContent = `Default: ${feature.on ? "ON" : "OFF"}`
const br1 = document.createElement("br")
const br2 = document.createElement("br")
const br3 = document.createElement("br")
container.append(br1, br2, h2, p)
sizes.forEach((size) => {
const exampleText = document.createElement("p")
exampleText.textContent = feature.docsExample
exampleText.classList.add("docs_example", `docs_${feature.type}`)
exampleText.dataset.feature = feature.feature
exampleText.style.fontSize = `${size[0]}rem`
exampleText.style.lineHeight = `${size[1]}rem`
container.append(exampleText)
})
featuresDocu.append(container)
})
const charH2 = document.createElement("h2")
charH2.textContent = "Full characterset without alternates. Support for Greek and Cyrillic coming soon."
const charset = document.createElement("p")
const tunedCharset = websiteData.charset.split("").join(" ")
charset.textContent = tunedCharset
charset.id = "charset"
charset.tabIndex = 0
charset.dataset.edit = "true"
const br1 = document.createElement("br")
const br2 = document.createElement("br")
const br3 = document.createElement("br")
const br4 = document.createElement("br")
const end = document.createElement("p")
end.textContent = "End of line."
end.tabIndex = 0
featuresDocu.append(br1, br2, br3, charH2, br4, charset, end)
}
function changeFeatureDocs(enable) {
console.log("changeFeatureDocs")
if (enable == "enable") {
websiteData.enableFeaturesInDocs = true
} else if (enable == "disable") {
websiteData.enableFeaturesInDocs = false
} else if (enable == "switch") {
websiteData.enableFeaturesInDocs = !websiteData.enableFeaturesInDocs
}
const enabled = websiteData.enableFeaturesInDocs
const allExampleTexts = document.querySelectorAll(".docs_example")
allExampleTexts.forEach((text) => {
text.style.fontFeatureSettings = `"${text.dataset.feature}" ${enabled ? 1 : 0}`
})
const allSpanOff = document.querySelectorAll(".span_off")
const allSpanOn = document.querySelectorAll(".span_on")
if (enabled) {
allSpanOff.forEach((span) => span.classList.remove("active_feature"))
allSpanOn.forEach((span) => span.classList.add("active_feature"))
} else {
allSpanOff.forEach((span) => span.classList.add("active_feature"))
allSpanOn.forEach((span) => span.classList.remove("active_feature"))
}
}

View File

@ -1,97 +0,0 @@
const featuresDocu = document.querySelector("#features_docu")
let customizeContent
let documentationContent
websiteData.sections.forEach((section) => {
if (section.name == "customize") customizeContent = section.content
if (section.name == "documentation") documentationContent = section.content
})
function buildDocumentation() {
console.log("buildDocumentation")
customizeContent.features.forEach((feature) => {
const sizes = [
[3, 4],
[2, 2.5],
[1, 1.5],
[0.75, 1],
[0.5, 1],
]
const container = document.createElement("div")
const h2 = document.createElement("h2")
const featureDescriptionWithSpan = feature.description
.split("|")
.map((l) =>
l == "OFF"
? `<span class="span_off${
!feature.on ? " active_feature" : ""
}" onclick="changeFeatureDocumentation('disable')">[OFF]</span>`
: l == "ON"
? `<span class="span_on${
feature.on ? " active_feature" : ""
}" onclick="changeFeatureDocumentation('enable')">[ON]</span>`
: l
)
.join("")
h2.innerHTML = featureDescriptionWithSpan
h2.tabIndex = 0
h2.dataset.edit = "true"
const p = document.createElement("p")
p.textContent = `Default: ${feature.on ? "ON" : "OFF"}`
const br1 = document.createElement("br")
const br2 = document.createElement("br")
const br3 = document.createElement("br")
container.append(br1, br2, h2, p)
sizes.forEach((size) => {
const exampleText = document.createElement("p")
exampleText.textContent = feature.documentationExample
exampleText.classList.add("documentation_example", `documentation_${feature.type}`)
exampleText.dataset.feature = feature.feature
exampleText.style.fontSize = `${size[0]}rem`
exampleText.style.lineHeight = `${size[1]}rem`
container.append(exampleText)
})
featuresDocu.append(container)
})
const charH2 = document.createElement("h2")
charH2.textContent = "Full characterset without alternates. Support for Greek and Cyrillic coming soon."
const charset = document.createElement("p")
const tunedCharset = websiteData.charset.split("").join(" ")
charset.textContent = tunedCharset
charset.id = "charset"
charset.tabIndex = 0
charset.dataset.edit = "true"
const br1 = document.createElement("br")
const br2 = document.createElement("br")
const br3 = document.createElement("br")
const br4 = document.createElement("br")
const end = document.createElement("p")
end.textContent = "End of line."
end.tabIndex = 0
featuresDocu.append(br1, br2, br3, charH2, br4, charset, end)
}
function changeFeatureDocumentation(enable) {
console.log("changeFeatureDocumentation")
if (enable == "enable") {
websiteData.enableFeaturesInDocumentation = true
} else if (enable == "disable") {
websiteData.enableFeaturesInDocumentation = false
} else if (enable == "switch") {
websiteData.enableFeaturesInDocumentation = !websiteData.enableFeaturesInDocumentation
}
const enabled = websiteData.enableFeaturesInDocumentation
const allExampleTexts = document.querySelectorAll(".documentation_example")
allExampleTexts.forEach((text) => {
text.style.fontFeatureSettings = `"${text.dataset.feature}" ${enabled ? 1 : 0}`
})
const allSpanOff = document.querySelectorAll(".span_off")
const allSpanOn = document.querySelectorAll(".span_on")
if (enabled) {
allSpanOff.forEach((span) => span.classList.remove("active_feature"))
allSpanOn.forEach((span) => span.classList.add("active_feature"))
} else {
allSpanOff.forEach((span) => span.classList.add("active_feature"))
allSpanOn.forEach((span) => span.classList.remove("active_feature"))
}
}

View File

@ -1,7 +1,7 @@
document.onvisibilitychange = () => {
// dynamicFavicon()
if (document.visibilityState === "visible") changeFavicon(true)
else changeFavicon(false)
// dynamicFavicon()
if (document.visibilityState === "visible") changeFavicon(true)
else changeFavicon(false)
}
let faviconIntervalID
@ -32,15 +32,15 @@ let faviconCounter = 0
// }
function changeFavicon(hasFocus) {
console.log("changeFavicon")
const link = document.createElement("link"),
oldLink = document.getElementById("dynamic-favicon")
console.log("changeFavicon")
const link = document.createElement("link"),
oldLink = document.getElementById("dynamic-favicon")
link.id = "dynamic-favicon"
link.rel = "icon"
link.href = hasFocus ? "src/favicon/icon-off.svg" : "src/favicon/icon.svg"
if (oldLink) {
document.head.removeChild(oldLink)
}
document.head.appendChild(link)
link.id = "dynamic-favicon"
link.rel = "icon"
link.href = hasFocus ? "src/favicon/icon-off.svg" : "src/favicon/icon.svg"
if (oldLink) {
document.head.removeChild(oldLink)
}
document.head.appendChild(link)
}

View File

@ -8,187 +8,187 @@ const alternatesContainer = document.querySelector("#alternates_container")
const featuresContainer = document.querySelector("#features_container")
function buildExample() {
console.log("buildExample")
websiteData.sections.forEach((section) => {
if (section.name == "customize") {
fontsFieldset.innerHTML = ""
section.content.fonts.forEach((font, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "font"
input.id = font.id
input.classList.add("example_font")
input.value = font.cssName
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = font.name
label.setAttribute("for", font.id)
div.append(input, label)
fontsFieldset.append(div)
})
exampleFieldset.innerHTML = ""
section.content.languages.forEach((language, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "language"
input.id = language.languageName
input.classList.add("example_language")
input.value = language.languageName
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = language.languageName
label.setAttribute("for", language.languageName)
div.append(input, label)
exampleFieldset.append(div)
})
weightFieldset.innerHTML = ""
section.content.weights.forEach((weight, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "weight"
input.id = `weight_${weight}`
input.classList.add("example_weight")
input.value = weight
if (index == 6) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = weight
label.setAttribute("for", `weight_${weight}`)
div.append(input, label)
weightFieldset.append(div)
})
featuresContainer.innerHTML = ""
alternatesContainer.innerHTML = ""
section.content.features.forEach((feature, index) => {
const fieldset = document.createElement("fieldset")
const duo = [0, 0]
const p = document.createElement("p")
p.textContent = feature.label
p.id = `alt_${feature.name}`
fieldset.append(p)
duo.forEach((_, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = feature.name
input.id = `${feature.name}${index}`
input.value = `'${feature.feature}' ${index == 0 ? "off" : "on"}`
if (!feature.on && index == 0) input.setAttribute("checked", "true")
if (feature.on && index == 1) input.setAttribute("checked", "true")
const label = document.createElement("label")
label.textContent = index == 0 ? "OFF" : "ON"
label.setAttribute("for", `${feature.name}${index}`)
div.append(input, label)
fieldset.append(div)
console.log("buildExample")
websiteData.sections.forEach((section) => {
if (section.name == "customize") {
fontsFieldset.innerHTML = ""
section.content.fonts.forEach((font, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "font"
input.id = font.id
input.classList.add("example_font")
input.value = font.cssName
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = font.name
label.setAttribute("for", font.id)
div.append(input, label)
fontsFieldset.append(div)
})
if (feature.type == "feature") featuresContainer.append(fieldset)
else alternatesContainer.append(fieldset)
})
}
})
updateExamples(null, exampleForm)
updateExampleSettings(null, exampleSettingsForm, true)
exampleFieldset.innerHTML = ""
section.content.languages.forEach((language, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "language"
input.id = language.languageName
input.classList.add("example_language")
input.value = language.languageName
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = language.languageName
label.setAttribute("for", language.languageName)
div.append(input, label)
exampleFieldset.append(div)
})
weightFieldset.innerHTML = ""
section.content.weights.forEach((weight, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "weight"
input.id = `weight_${weight}`
input.classList.add("example_weight")
input.value = weight
if (index == 6) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.textContent = weight
label.setAttribute("for", `weight_${weight}`)
div.append(input, label)
weightFieldset.append(div)
})
featuresContainer.innerHTML = ""
alternatesContainer.innerHTML = ""
section.content.features.forEach((feature, index) => {
const fieldset = document.createElement("fieldset")
const duo = [0, 0]
const p = document.createElement("p")
p.textContent = feature.label
p.id = `alt_${feature.name}`
fieldset.append(p)
duo.forEach((_, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = feature.name
input.id = `${feature.name}${index}`
input.value = `'${feature.feature}' ${index == 0 ? "off" : "on"}`
if (!feature.on && index == 0) input.setAttribute("checked", "true")
if (feature.on && index == 1) input.setAttribute("checked", "true")
const label = document.createElement("label")
label.textContent = index == 0 ? "OFF" : "ON"
label.setAttribute("for", `${feature.name}${index}`)
div.append(input, label)
fieldset.append(div)
})
if (feature.type == "feature") featuresContainer.append(fieldset)
else alternatesContainer.append(fieldset)
})
}
})
updateExamples(null, exampleForm)
updateExampleSettings(null, exampleSettingsForm, true)
}
const codeExample = document.querySelector("#code_example")
function updateExamples(event, form) {
console.log("updateExamples")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
console.log("updateExamples")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
websiteData.sections.forEach((section) => {
if (section.name == "customize") {
section.content.languages.forEach((language, index) => {
if (language.languageName == output) {
codeExample.textContent = language.codeExample
let nums = Array.from(new Array(1000), (x, i) => i + 1).join("\n")
codeExample.setAttribute("data-before", nums)
}
})
}
})
websiteData.sections.forEach((section) => {
if (section.name == "customize") {
section.content.languages.forEach((language, index) => {
if (language.languageName == output) {
codeExample.textContent = language.codeExample
let nums = Array.from(new Array(1000), (x, i) => i + 1).join("\n")
codeExample.setAttribute("data-before", nums)
}
})
}
})
if (event) event.preventDefault()
if (event) event.preventDefault()
}
function updateFont(event, form) {
console.log("updateFont")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
codeExample.style.fontFamily = output
console.log("updateFont")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
codeExample.style.fontFamily = output
if (event) event.preventDefault()
if (event) event.preventDefault()
}
function updateWeight(event, form) {
console.log("updateWeight")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = +entry[1]
}
console.log("updateWeight")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = +entry[1]
}
fontDownloadSettings.weight = output
websiteData.weight = output
document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${
websiteData.italic ? "1" : "0"
}`
downloadButton.textContent = areObjectsIdentical(fontDownloadSettings, fontDownloadSettingsDefault)
? "Download default CommitMono"
: "Download custom CommitMono"
fontDownloadSettings.weight = output
websiteData.weight = output
document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${
websiteData.italic ? "1" : "0"
}`
downloadButton.textContent = areObjectsIdentical(fontDownloadSettings, fontDownloadSettingsDefault)
? "Download default CommitMono"
: "Download custom CommitMono"
console.log(fontDownloadSettings)
console.log(fontDownloadSettings)
if (event) event.preventDefault()
if (event) event.preventDefault()
}
function updateExampleSettings(event, form, isDefault) {
console.log("updateExampleSettings")
const data = new FormData(form)
let output = ""
function updateDownloadSettings(type, feature) {
const key = feature.split("' ")[0].slice(1)
const value = feature.split("' ")[1] == "on"
fontDownloadSettings[type][key] = value
if (isDefault) fontDownloadSettingsDefault[type][key] = value
}
for (const entry of data) {
output += `${entry[1]}, `
if (entry[1].includes("cv")) updateDownloadSettings("alternates", entry[1])
if (entry[1].includes("ss")) updateDownloadSettings("features", entry[1])
console.log("updateExampleSettings")
const data = new FormData(form)
let output = ""
function updateDownloadSettings(type, feature) {
const key = feature.split("' ")[0].slice(1)
const value = feature.split("' ")[1] == "on"
fontDownloadSettings[type][key] = value
if (isDefault) fontDownloadSettingsDefault[type][key] = value
}
for (const entry of data) {
output += `${entry[1]}, `
if (entry[1].includes("cv")) updateDownloadSettings("alternates", entry[1])
if (entry[1].includes("ss")) updateDownloadSettings("features", entry[1])
const label = document.querySelector(`#alt_${entry[0]}`)
if (label) label.style.fontFeatureSettings = entry[1]
}
console.log(fontDownloadSettings)
const codeExample = document.querySelector("#code_example")
codeExample.style.fontFeatureSettings = output.slice(0, -2)
const label = document.querySelector(`#alt_${entry[0]}`)
if (label) label.style.fontFeatureSettings = entry[1]
}
console.log(fontDownloadSettings)
const codeExample = document.querySelector("#code_example")
codeExample.style.fontFeatureSettings = output.slice(0, -2)
downloadButton.textContent = areObjectsIdentical(fontDownloadSettings, fontDownloadSettingsDefault)
? "Download default CommitMono"
: "Download custom CommitMono"
downloadButton.textContent = areObjectsIdentical(fontDownloadSettings, fontDownloadSettingsDefault)
? "Download default CommitMono"
: "Download custom CommitMono"
if (event) event.preventDefault()
if (event) event.preventDefault()
}
function areObjectsIdentical(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2)
return JSON.stringify(obj1) === JSON.stringify(obj2)
}

View File

@ -1,53 +1,53 @@
const familiarContainer = document.querySelector("#familiar_container")
function buildFamiliar() {
console.log("buildFamiliar")
websiteData.sections.forEach((section) => {
if (section.name == "familiar") {
familiarContainer.innerHTML = ""
section.content.timeline.forEach((example, index) => {
const div = document.createElement("div")
div.style.display = index != 0 ? "none" : "block"
div.id = example.name
div.dataset.name = example.name
const svgContainer = document.createElement("div")
svgContainer.innerHTML = section.content.svgs[example.name]
svgContainer.tabIndex = 0
svgContainer.classList.add("svg_container")
const img = document.createElement("img")
img.src = `/src/img/familiar/${example.src}`
const p = document.createElement("p")
p.tabIndex = 0
p.dataset.edit = "true"
example.description.forEach((description) => (p.textContent += description + " "))
div.append(p)
const br = document.createElement("br")
div.append(br, svgContainer)
familiarContainer.append(div)
})
}
})
console.log("buildFamiliar")
websiteData.sections.forEach((section) => {
if (section.name == "familiar") {
familiarContainer.innerHTML = ""
section.content.timeline.forEach((example, index) => {
const div = document.createElement("div")
div.style.display = index != 0 ? "none" : "block"
div.id = example.name
div.dataset.name = example.name
const svgContainer = document.createElement("div")
svgContainer.innerHTML = section.content.svgs[example.name]
svgContainer.tabIndex = 0
svgContainer.classList.add("svg_container")
const img = document.createElement("img")
img.src = `/src/img/familiar/${example.src}`
const p = document.createElement("p")
p.tabIndex = 0
p.dataset.edit = "true"
example.description.forEach((description) => (p.textContent += description + " "))
div.append(p)
const br = document.createElement("br")
div.append(br, svgContainer)
familiarContainer.append(div)
})
}
})
}
function updateFamiliar(event, form) {
console.log("updateFamiliar")
buildFamiliar()
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = entry[1]
}
websiteData.sections.forEach((section) => {
if (section.name == "familiar") {
section.content.timeline.forEach((example) => {
const exampleContainer = familiarContainer.querySelector(`#${example.name}`)
if (exampleContainer.dataset.name == output) {
exampleContainer.style.display = "block"
} else {
exampleContainer.style.display = "none"
}
})
}
})
event.preventDefault()
console.log("updateFamiliar")
buildFamiliar()
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = entry[1]
}
websiteData.sections.forEach((section) => {
if (section.name == "familiar") {
section.content.timeline.forEach((example) => {
const exampleContainer = familiarContainer.querySelector(`#${example.name}`)
if (exampleContainer.dataset.name == output) {
exampleContainer.style.display = "block"
} else {
exampleContainer.style.display = "none"
}
})
}
})
event.preventDefault()
}

View File

@ -1,18 +1,18 @@
function updateIntelligent(event, form) {
console.log("updateIntelligent")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
const examples = ["original", "smart_kerning", "before", "after"]
examples.forEach((example) => {
const exampleContainer = document.querySelector(`#${example}`)
if (exampleContainer.id == output) {
exampleContainer.style.display = "block"
} else {
exampleContainer.style.display = "none"
}
})
event.preventDefault()
console.log("updateIntelligent")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
const examples = ["original", "smart_kerning", "before", "after"]
examples.forEach((example) => {
const exampleContainer = document.querySelector(`#${example}`)
if (exampleContainer.id == output) {
exampleContainer.style.display = "block"
} else {
exampleContainer.style.display = "none"
}
})
event.preventDefault()
}

View File

@ -13,428 +13,431 @@ let rem = +document.documentElement.style.fontSize.split("px")[0]
const downloadButton = document.querySelector("#download")
function buildNav() {
console.log("buildNav")
websiteData.sections.forEach((section, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "nav"
input.id = section.name
input.classList.add("nav_section_input")
input.value = `section_${index + 1}`
input.tabIndex = 0
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.for = section.name
label.textContent = `${index + 1 < 10 ? `0${index + 1}` : index + 1} ${capitalize(section.name)}`
label.classList.add("nav_element")
label.dataset.sectionIndex = index + 1
label.setAttribute("for", section.name)
div.append(input, label)
navForm.append(div)
})
console.log("buildNav")
websiteData.sections.forEach((section, index) => {
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.name = "nav"
input.id = section.name
input.classList.add("nav_section_input")
input.value = `section_${index + 1}`
input.tabIndex = 0
if (index == 0) {
input.setAttribute("checked", "true")
}
const label = document.createElement("label")
label.for = section.name
label.textContent = `${index + 1 < 10 ? `0${index + 1}` : index + 1} ${capitalize(section.name)}`
label.classList.add("nav_element")
label.dataset.sectionIndex = index + 1
label.setAttribute("for", section.name)
div.append(input, label)
navForm.append(div)
})
}
function updateNav(event, form) {
console.log("updateNav")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
sectionNavigation(output.split("section_")[1] - 1)
console.log("updateNav")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${entry[1]}`
}
sectionNavigation(output.split("section_")[1] - 1)
if (event) event.preventDefault()
if (event) event.preventDefault()
}
function pageAnimation() {
console.log("pageAnimation")
const element = document.querySelector("#page_animation")
element.classList.remove("page_animation")
setTimeout(() => element.classList.add("page_animation"), 10)
console.log("pageAnimation")
const element = document.querySelector("#page_animation")
element.classList.remove("page_animation")
setTimeout(() => element.classList.add("page_animation"), 10)
}
let currentSection = 1
let insideTextField = false
function enterTextField() {
console.log("enterTextField")
active = document.activeElement
setTimeout(() => {
active.setAttribute("contenteditable", "true")
active.blur()
active.focus()
}, 40)
insideTextField = true
console.log("enterTextField")
active = document.activeElement
setTimeout(() => {
active.setAttribute("contenteditable", "true")
active.blur()
active.focus()
}, 40)
insideTextField = true
}
function exitTextField() {
console.log("exitTextField")
document.activeElement.setAttribute("contenteditable", "false")
insideTextField = false
console.log("exitTextField")
document.activeElement.setAttribute("contenteditable", "false")
insideTextField = false
}
let timesClicked = 0
function onClick(e) {
if (e.pointerType !== "" && !isMobile) {
focusUsingTab = false
timesClicked++
if (timesClicked == 10) {
document.querySelector("#keyboard_container").classList.add("use_keyboard_animation")
showHideChangeSettings("Use keyboard to navigate!", 2400, true)
}
}
if (e.pointerType !== "" && !isMobile) {
focusUsingTab = false
timesClicked++
if (timesClicked == 10) {
document.querySelector("#keyboard_container").classList.add("use_keyboard_animation")
showHideChangeSettings("Use keyboard to navigate!", 2400, true)
}
}
}
document.addEventListener("click", onClick)
const keys = document.querySelectorAll(".key")
keys.forEach((key) => {
key.addEventListener("click", () => {
if (key.dataset.noclick != "true") {
key.dataset.keyCode.includes("Shift")
? keyDown({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: true })
: keyDown({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: false })
key.dataset.keyCode.includes("Shift")
? keyUp({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: true })
: keyUp({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: false })
}
})
key.addEventListener("click", () => {
if (key.dataset.noclick != "true") {
key.dataset.keyCode.includes("Shift")
? keyDown({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: true })
: keyDown({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: false })
key.dataset.keyCode.includes("Shift")
? keyUp({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: true })
: keyUp({ code: key.dataset.keyCode, key: key.dataset.key, shiftKey: false })
}
})
})
let changeSettingTimeoutID
let focusUsingTab = false
function keyDown(e) {
focusUsingTab = true
if (e.code == "Enter" && document.activeElement.dataset.edit == "true" && !insideTextField) enterTextField()
focusUsingTab = true
if (e.code == "Enter" && document.activeElement.dataset.edit == "true" && !insideTextField) enterTextField()
if (!insideTextField || e.code == "Enter") {
const activeKey = !e.shiftKey
? document.querySelector(`.key[data-key-code="${e.code}"]`)
: document.querySelector(`.key[data-key-code="Shift${e.code}"]`)
activeKey?.classList.add("active_key")
if (!insideTextField || e.code == "Enter") {
const activeKey = !e.shiftKey
? document.querySelector(`.key[data-key-code="${e.code}"]`)
: document.querySelector(`.key[data-key-code="Shift${e.code}"]`)
activeKey?.classList.add("active_key")
if (e.code.includes("Digit")) {
const digitNumber = e.code.split("Digit")[1] - 1
sectionNavigation(digitNumber == -1 ? 9 : digitNumber)
}
if (e.code.includes("Digit")) {
const digitNumber = e.code.split("Digit")[1] - 1
sectionNavigation(digitNumber == -1 ? 9 : digitNumber)
}
if (e.code == "KeyO") {
changeFeatureDocumentation("switch")
}
if (e.code == "KeyO") {
changeFeatureDocs("switch")
}
// push page
if (
(e.code == "KeyW" ||
e.code == "KeyA" ||
e.code == "KeyS" ||
e.code == "KeyD" ||
e.code == "KeyR" ||
e.code == "Minus" ||
e.code == "Slash") &&
!e.ctrlKey &&
!e.metaKey
) {
pushPage(e.code)
}
// push page
if (
(e.code == "KeyW" ||
e.code == "KeyA" ||
e.code == "KeyS" ||
e.code == "KeyD" ||
e.code == "KeyR" ||
e.code == "Minus" ||
e.code == "Slash") &&
!e.ctrlKey &&
!e.metaKey
) {
pushPage(e.code)
}
if (e.code == "KeyH") {
document.querySelector("#keyboard_section").classList.toggle("hidden")
}
if (e.code == "KeyH") {
document.querySelector("#keyboard_section").classList.toggle("hidden")
}
if (e.code == "KeyB" || e.code == "KeyL") {
if (e.code == "KeyB") websiteData.weight = websiteData.weight == 700 ? 700 : websiteData.weight + 25
if (e.code == "KeyL") websiteData.weight = websiteData.weight == 300 ? 300 : websiteData.weight - 25
updateCodeFont()
document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${
websiteData.italic ? "1" : "0"
}`
showHideChangeSettings(`Weight: ${websiteData.weight}. Def: 450, Min: 300, Max: 700.`)
document.forms["weight_form"][`weight_${websiteData.weight}`].checked = true
updateWeight(null, weightForm)
}
if (e.code == "KeyB" || e.code == "KeyL") {
if (e.code == "KeyB") websiteData.weight = websiteData.weight == 700 ? 700 : websiteData.weight + 25
if (e.code == "KeyL") websiteData.weight = websiteData.weight == 300 ? 300 : websiteData.weight - 25
updateCodeFont()
document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${
websiteData.italic ? "1" : "0"
}`
showHideChangeSettings(`Weight: ${websiteData.weight}. Def: 450, Min: 300, Max: 700.`)
document.forms["weight_form"][`weight_${websiteData.weight}`].checked = true
updateWeight(null, weightForm)
}
if (e.code == "KeyI") {
websiteData.italic = !websiteData.italic
updateCodeFont()
document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${
websiteData.italic ? "1" : "0"
}`
showHideChangeSettings(`Italic: ${websiteData.italic}.`)
}
if (e.code == "KeyI") {
websiteData.italic = !websiteData.italic
updateCodeFont()
document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${
websiteData.italic ? "1" : "0"
}`
showHideChangeSettings(`Italic: ${websiteData.italic}.`)
}
if (e.code == "KeyM") {
if (websiteData.invert) {
setCssVar(["--bg", "#aaa"])
setCssVar(["--text", "#111"])
} else {
setCssVar(["--bg", "#111"])
setCssVar(["--text", "#aaa"])
}
updateCode(null, codeForm)
websiteData.invert = !websiteData.invert
}
} else if (e.code == "Escape" && insideTextField) {
console.log(insideTextField)
document.querySelector(".key_code_Escape")?.classList.add("pressed_key")
}
if (e.code == "KeyM") {
if (websiteData.invert) {
setCssVar(["--bg", "#aaa"])
setCssVar(["--text", "#111"])
} else {
setCssVar(["--bg", "#111"])
setCssVar(["--text", "#aaa"])
}
updateCode(null, codeForm)
websiteData.invert = !websiteData.invert
}
} else if (e.code == "Escape" && insideTextField) {
console.log(insideTextField)
document.querySelector(".key_code_Escape")?.classList.add("pressed_key")
}
if (e.code == "Escape") exitTextField()
if (e.code == "Escape") exitTextField()
checkTutorialKeys(e)
checkTutorialKeys(e)
}
function keyUp(e) {
const activeKey = document.querySelectorAll(".active_key")
activeKey?.forEach((key) => key.classList.remove("active_key"))
const activeKey = document.querySelectorAll(".active_key")
activeKey?.forEach((key) => key.classList.remove("active_key"))
if (e.code == "Tab" && document.activeElement.id.includes("block_tab")) {
console.log("active nav section then tab")
const checkedMenuInput = document.querySelector("#nav_form input:checked")
checkedMenuInput.focus()
}
if (e.code == "Tab" && document.activeElement.id.includes("block_tab")) {
console.log("active nav section then tab")
const checkedMenuInput = document.querySelector("#nav_form input:checked")
checkedMenuInput.focus()
}
}
document.addEventListener("keydown", keyDown)
document.addEventListener("keyup", keyUp)
function pushPage(keyCode) {
console.log("push page", keyCode)
const x = websiteData.pushPage.coordinates.x
const y = websiteData.pushPage.coordinates.y
const scale = websiteData.pushPage.scale
const dist = websiteData.pushPage.distance
console.log("push page", keyCode)
const x = websiteData.pushPage.coordinates.x
const y = websiteData.pushPage.coordinates.y
const scale = websiteData.pushPage.scale
const dist = websiteData.pushPage.distance
// move left
if (keyCode == "KeyW") {
main.style.transform = `translate(${x}px, ${y + dist}px)`
websiteData.pushPage.coordinates.y += dist
}
// move left
if (keyCode == "KeyW") {
main.style.transform = `translate(${x}px, ${y + dist}px)`
websiteData.pushPage.coordinates.y += dist
}
// move left
else if (keyCode == "KeyA") {
main.style.transform = `translate(${x + dist}px, ${y}px)`
websiteData.pushPage.coordinates.x += dist
}
// move left
else if (keyCode == "KeyA") {
main.style.transform = `translate(${x + dist}px, ${y}px)`
websiteData.pushPage.coordinates.x += dist
}
// move down
else if (keyCode == "KeyS") {
main.style.transform = `translate(${x}px, ${y - dist}px)`
websiteData.pushPage.coordinates.y -= dist
}
// move down
else if (keyCode == "KeyS") {
main.style.transform = `translate(${x}px, ${y - dist}px)`
websiteData.pushPage.coordinates.y -= dist
}
// move right
else if (keyCode == "KeyD") {
main.style.transform = `translate(${x - dist}px, ${y}px)`
websiteData.pushPage.coordinates.x -= dist
}
// move right
else if (keyCode == "KeyD") {
main.style.transform = `translate(${x - dist}px, ${y}px)`
websiteData.pushPage.coordinates.x -= dist
}
// zoom in ("Minus" is the plus key, very confusing)
else if (keyCode == "Minus") {
rem = (+rem * 0.75 + 1) / 0.75
document.documentElement.style.fontSize = `${rem}px`
updateWaterfall()
document.querySelector("#canvas").style.transform = `scale(${rem / 16})`
showHideChangeSettings(`Base font size: ${rem * 0.75}px`)
}
// zoom in ("Minus" is the plus key, very confusing)
else if (keyCode == "Minus") {
rem = (+rem * 0.75 + 1) / 0.75
document.documentElement.style.fontSize = `${rem}px`
updateWaterfall()
document.querySelector("#canvas").style.transform = `scale(${rem / 16})`
showHideChangeSettings(`Base font size: ${rem * 0.75}px`)
}
// zoom out
else if (keyCode == "Slash") {
rem = (+rem * 0.75 - 1) / 0.75
document.documentElement.style.fontSize = `${rem}px`
updateWaterfall()
document.querySelector("#canvas").style.transform = `scale(${rem / 16})`
showHideChangeSettings(`Base font size: ${rem * 0.75}px`)
}
// zoom out
else if (keyCode == "Slash") {
rem = (+rem * 0.75 - 1) / 0.75
document.documentElement.style.fontSize = `${rem}px`
updateWaterfall()
document.querySelector("#canvas").style.transform = `scale(${rem / 16})`
showHideChangeSettings(`Base font size: ${rem * 0.75}px`)
}
// reset transforms
else if (keyCode == "KeyR") {
main.style.transform = `translate(0)`
websiteData.pushPage.coordinates.x = 0
websiteData.pushPage.coordinates.y = 0
websiteData.pushPage.scale = 1
document.querySelector("#canvas").style.transform = "scale(1)"
rem = 16
document.documentElement.style.fontSize = "16px"
websiteData.weight = 450
document.querySelector("body").style.fontVariationSettings = `"wght" 450`
document.querySelector(
"#download"
).textContent = `Download CommitMono-${websiteData.weight} with current settings`
document.forms["weight_form"][`weight_${websiteData.weight}`].checked = true
if (typeof updateCodeFont === "function") updateCodeFont()
if (typeof updateWaterfall === "function") updateWaterfall()
if (typeof buildExample === "function") buildExample()
if (typeof updateWeight === "function") updateWeight(null, weightForm)
}
// reset transforms
else if (keyCode == "KeyR") {
main.style.transform = `translate(0)`
websiteData.pushPage.coordinates.x = 0
websiteData.pushPage.coordinates.y = 0
websiteData.pushPage.scale = 1
document.querySelector("#canvas").style.transform = "scale(1)"
rem = 16
document.documentElement.style.fontSize = "16px"
websiteData.weight = 450
document.querySelector("body").style.fontVariationSettings = `"wght" 450`
document.querySelector(
"#download"
).textContent = `Download CommitMono-${websiteData.weight} with current settings`
document.forms["weight_form"][`weight_${websiteData.weight}`].checked = true
if (typeof updateCodeFont === "function") updateCodeFont()
if (typeof updateWaterfall === "function") updateWaterfall()
if (typeof buildExample === "function") buildExample()
if (typeof updateWeight === "function") updateWeight(null, weightForm)
}
}
let isSafari = 0
let active // saves what DOM element is currently active
let focusTimeOutID // to be able to use clearTimeout()
function onFocusIn(e) {
// console.log("focusin", document.activeElement)
// console.log("focusin", document.activeElement)
// new focus: exit text field
if (document.activeElement != active) exitTextField()
// new focus: exit text field
if (document.activeElement != active) exitTextField()
const prevActive = active
const prevActive = active
// save current focused element
active = document.activeElement
// save current focused element
active = document.activeElement
if (focusUsingTab) {
if (prevActive?.id == "navigate_description" && active.id == "tutorial" && isSafari == 0) {
console.log("safari")
isSafari = 1
document.querySelector("#safari").classList.add("safari_visible")
}
if (focusUsingTab) {
if (prevActive?.id == "navigate_description" && active.id == "tutorial" && isSafari == 0) {
console.log("safari")
isSafari = 1
document.querySelector("#safari").classList.add("safari_visible")
}
if (active.id == "focus_check") {
console.log("not safari")
isSafari = -1
if (prevActive.id == "navigate_description") {
document.querySelector("#tutorial").focus()
}
if (prevActive.id == "tutorial") {
document.querySelector("#navigate_description").focus()
}
document.querySelector("#focus_check")?.remove()
}
}
// // when current focused element is blurred, start a timer of 100ms.
// active.addEventListener("blur", onBlurIn)
// // clear timeout when a new element is focused
// clearTimeout(focusTimeOutID)
// focusTimeOutID = null
if (active.id.includes("block_tab")) {
console.log("BLOCK TAB")
if (prevActive.className.includes("question_button")) {
prevActive.parentElement.querySelector(".question_button").focus()
} else {
prevActive.focus()
// const checkedMenuInput = document.querySelector("#nav_form input:checked")
// checkedMenuInput.focus()
}
}
// if focus using tab, scroll page, if focus reaches bottom or top
if (focusUsingTab) {
const bounds = active.getBoundingClientRect()
const paddingOffsetBottom = 200
if (bounds.top > window.innerHeight - paddingOffsetBottom) {
const numberOfMoves = Math.floor(
(bounds.top - (window.innerHeight - paddingOffsetBottom)) / websiteData.pushPage.distance
)
for (let i = 0; i < numberOfMoves; i++) {
pushPage("KeyS")
}
}
const paddingOffsetTop = 24
if (!document.activeElement.className.includes("nav")) {
if (bounds.top < paddingOffsetTop) {
const numberOfMoves = Math.ceil(
Math.abs(bounds.top - paddingOffsetTop - 32) / websiteData.pushPage.distance
)
console.log("num of moves:", numberOfMoves, "bounds.top:", bounds.top)
for (let i = 0; i < numberOfMoves; i++) {
pushPage("KeyW")
if (active.id == "focus_check") {
console.log("not safari")
isSafari = -1
if (prevActive.id == "navigate_description") {
document.querySelector("#tutorial").focus()
}
}
}
}
if (prevActive.id == "tutorial") {
document.querySelector("#navigate_description").focus()
}
document.querySelector("#focus_check")?.remove()
}
}
// // when current focused element is blurred, start a timer of 100ms.
// active.addEventListener("blur", onBlurIn)
// // clear timeout when a new element is focused
// clearTimeout(focusTimeOutID)
// focusTimeOutID = null
if (active.id.includes("block_tab")) {
console.log("BLOCK TAB")
if (prevActive.className.includes("question_button")) {
prevActive.parentElement.querySelector(".question_button").focus()
} else {
prevActive.focus()
// const checkedMenuInput = document.querySelector("#nav_form input:checked")
// checkedMenuInput.focus()
}
}
// if focus using tab, scroll page, if focus reaches bottom or top
if (focusUsingTab) {
const bounds = active.getBoundingClientRect()
const paddingOffsetBottom = 200
if (bounds.top > window.innerHeight - paddingOffsetBottom) {
const numberOfMoves = Math.floor(
(bounds.top - (window.innerHeight - paddingOffsetBottom)) / websiteData.pushPage.distance
)
for (let i = 0; i < numberOfMoves; i++) {
pushPage("KeyS")
}
}
const paddingOffsetTop = 24
if (!document.activeElement.className.includes("nav")) {
if (bounds.top < paddingOffsetTop) {
const numberOfMoves = Math.ceil(
Math.abs(bounds.top - paddingOffsetTop - 32) / websiteData.pushPage.distance
)
console.log("num of moves:", numberOfMoves, "bounds.top:", bounds.top)
for (let i = 0; i < numberOfMoves; i++) {
pushPage("KeyW")
}
}
}
}
}
document.addEventListener("focusin", onFocusIn)
let prevHasFocus = true
function checkDocumentFocus() {
if (!isMobile) {
if (prevHasFocus != document.hasFocus()) {
changedFocus(document.hasFocus())
}
prevHasFocus = document.hasFocus()
}
if (!isMobile) {
if (prevHasFocus != document.hasFocus()) {
changedFocus(document.hasFocus())
}
prevHasFocus = document.hasFocus()
}
}
function changedFocus(hasFocus) {
if (hasFocus && active) active.focus()
changeFavicon(hasFocus)
hasFocus ? contentRoot.classList.remove("faded") : contentRoot.classList.add("faded")
clickFocus.style.visibility = hasFocus ? "hidden" : "visible"
// updateCode(null, codeForm)
if (hasFocus && active) active.focus()
changeFavicon(hasFocus)
hasFocus ? contentRoot.classList.remove("faded") : contentRoot.classList.add("faded")
clickFocus.style.visibility = hasFocus ? "hidden" : "visible"
// updateCode(null, codeForm)
}
function onBlurIn(e) {
// remove event listener from so they don't stack
e.target.removeEventListener("blur", onBlurIn)
// remove event listener from so they don't stack
e.target.removeEventListener("blur", onBlurIn)
// if this timer runs out before a new element is focused, refocus same element
if (!isMobile) focusTimeOutID = setTimeout(() => active.focus(), 100)
// if this timer runs out before a new element is focused, refocus same element
if (!isMobile) focusTimeOutID = setTimeout(() => active.focus(), 100)
}
let tutorialFinished = false
function checkTutorialKeys(e) {
if (!tutorialFinished) {
websiteData.tutorial.forEach((key) => {
if (e.code == key) {
if (e.code.includes("Arrow")) {
if (document.activeElement.nodeName == "INPUT") {
const keyNode = document.querySelector(`.key_code_${key}`)
keyNode?.classList.add("pressed_key")
}
} else if (e.code == "Enter") {
if (document.activeElement.dataset.edit == "true") {
document.querySelector(".key_code_Enter")?.classList.add("pressed_key")
}
} else if (e.code != "Escape") {
const keyNode = document.querySelector(`.key_code_${key}`)
keyNode?.classList.add("pressed_key")
if (!tutorialFinished) {
websiteData.tutorial.forEach((key) => {
if (e.code == key && e.code != "Tab") {
if (e.code.includes("Arrow")) {
if (document.activeElement.nodeName == "INPUT") {
const keyNode = document.querySelector(`.key_code_${key}`)
keyNode?.classList.add("pressed_key")
}
} else if (e.code == "Enter") {
if (document.activeElement.dataset.edit == "true") {
document.querySelector(".key_code_Enter")?.classList.add("pressed_key")
}
} else if (e.code != "Escape") {
const keyNode = document.querySelector(`.key_code_${key}`)
keyNode?.classList.add("pressed_key")
}
}
}
if (key == "ShiftTab" && e.code == "Tab" && e.shiftKey) {
document.querySelector(".key_code_ShiftTab1").classList.add("pressed_key")
document.querySelector(".key_code_ShiftTab2").classList.add("pressed_key")
}
})
const numnerOfTutorialKeys = document.querySelectorAll(".tutorial_key").length
const numberOfPressedKeys = document.querySelectorAll(".tutorial_key.pressed_key").length
if (e.code == "Tab" && !e.shiftKey) {
document.querySelector(".key_code_Tab").classList.add("pressed_key")
}
if (key == "ShiftTab" && e.code == "Tab" && e.shiftKey) {
document.querySelector(".key_code_ShiftTab1").classList.add("pressed_key")
document.querySelector(".key_code_ShiftTab2").classList.add("pressed_key")
}
})
const numnerOfTutorialKeys = document.querySelectorAll(".tutorial_key").length
const numberOfPressedKeys = document.querySelectorAll(".tutorial_key.pressed_key").length
if (numnerOfTutorialKeys === numberOfPressedKeys) {
console.log("TUTORIAL FINISHED!!")
tutorialFinished = true
const tutorialContainer = document.querySelector("#tutorial_complete")
tutorialContainer.innerHTML = `<p>Tutorial complete! Your present is the variable version of Commit Mono:</p>
if (numnerOfTutorialKeys === numberOfPressedKeys) {
console.log("TUTORIAL FINISHED!!")
tutorialFinished = true
const tutorialContainer = document.querySelector("#tutorial_complete")
tutorialContainer.innerHTML = `<p>Tutorial complete! Your present is the variable version of Commit Mono:</p>
<p><a href="/src/fonts/CommitMonoV120-VF.ttf">Download CommitMono-VF.ttf</a></p>
<p><a href="/src/fonts/CommitMonoV120-VF.woff2">Download CommitMono-VF.woff2</a></p>
<br />`
}
}
}
}
}
function sectionNavigation(sectionIndex) {
const sectionName = websiteData.sections[sectionIndex]?.name
const sectionName = websiteData.sections[sectionIndex]?.name
pageAnimation()
pageAnimation()
const attemptedSection = document.querySelector(`[value="section_${sectionIndex + 1}"]`)
if (attemptedSection && sectionName) {
attemptedSection.focus()
document.forms["nav_form"][sectionName].checked = true
}
const attemptedSection = document.querySelector(`[value="section_${sectionIndex + 1}"]`)
if (attemptedSection && sectionName) {
attemptedSection.focus()
document.forms["nav_form"][sectionName].checked = true
}
websiteData.sections.forEach((section, index) => {
const sectionContainer = document.querySelector(`#section_${index + 1}`)
if (index == sectionIndex) {
sectionContainer.style.display = "block"
} else {
sectionContainer.style.display = "none"
}
})
main.style.transform = `translate(0)`
navForm.style.transform = `translate(0)`
keySection.style.transform = `translate(0)`
websiteData.pushPage.coordinates.x = 0
websiteData.pushPage.coordinates.y = 0
websiteData.pushPage.scale = 1
websiteData.sections.forEach((section, index) => {
const sectionContainer = document.querySelector(`#section_${index + 1}`)
if (index == sectionIndex) {
sectionContainer.style.display = "block"
} else {
sectionContainer.style.display = "none"
}
})
main.style.transform = `translate(0)`
navForm.style.transform = `translate(0)`
keySection.style.transform = `translate(0)`
websiteData.pushPage.coordinates.x = 0
websiteData.pushPage.coordinates.y = 0
websiteData.pushPage.scale = 1
}
// when the user has scrolled manually using the keyboard the page is offset
@ -442,10 +445,10 @@ function sectionNavigation(sectionIndex) {
// this little script combats that
mainScale.addEventListener("scroll", onScroll)
function onScroll(e) {
const { x, y } = websiteData.pushPage.coordinates
if (x != 0 || y != 0) {
main.style.transform = `translate(0)`
websiteData.pushPage.coordinates = { x: 0, y: 0 }
mainScale.scrollBy(-x, -y)
}
const { x, y } = websiteData.pushPage.coordinates
if (x != 0 || y != 0) {
main.style.transform = `translate(0)`
websiteData.pushPage.coordinates = { x: 0, y: 0 }
mainScale.scrollBy(-x, -y)
}
}

View File

@ -1,11 +1,11 @@
const updateOptions = (event, form) => {
console.log("updateOptions")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${output}${entry[0]}=${entry[1]}\n`
}
event.preventDefault()
console.log("updateOptions")
const data = new FormData(form)
let output = ""
for (const entry of data) {
output = `${output}${entry[0]}=${entry[1]}\n`
}
event.preventDefault()
}
let commitMonoFont
@ -13,255 +13,255 @@ let fontDownloadSettings = { weight: 450, italic: false, alternates: {}, feature
let fontDownloadSettingsDefault = { weight: 450, italic: false, alternates: {}, features: {} }
async function updateCodeFont() {
console.log("updateCodeFont")
opentype
.load(
`/src/fonts/CommitMono${versionOfCommitMono}-${websiteData.weight}${
websiteData.italic ? "Italic" : "Regular"
}.otf`
)
.then((font) => {
// console.log(font)
commitMonoFont = font
updateCode(null, codeForm)
})
.catch((err) => console.log(err))
console.log("updateCodeFont")
opentype
.load(
`/src/fonts/CommitMono${versionOfCommitMono}-${websiteData.weight}${
websiteData.italic ? "Italic" : "Regular"
}.otf`
)
.then((font) => {
// console.log(font)
commitMonoFont = font
updateCode(null, codeForm)
})
.catch((err) => console.log(err))
// opentype
// .load("src/fonts/CommitMonoV117-BoldItalic.otf")
// .then((font) => {
// console.log(font)
// // font.download()
// })
// .catch((err) => console.log(err))
// opentype
// .load("src/fonts/CommitMonoV117-Light.otf")
// .then((font) => {
// console.log(font)
// // font.download()
// })
// .catch((err) => console.log(err))
// opentype
// .load("src/fonts/CommitMonoV117-BoldItalic.otf")
// .then((font) => {
// console.log(font)
// // font.download()
// })
// .catch((err) => console.log(err))
// opentype
// .load("src/fonts/CommitMonoV117-Light.otf")
// .then((font) => {
// console.log(font)
// // font.download()
// })
// .catch((err) => console.log(err))
}
let downloadStarted = false
async function downloadFont(button, isDefault) {
console.log("downloadFont")
if (!downloadStarted) {
downloadStarted = true
button.classList.remove("loaded")
button.classList.remove("error")
button.classList.add("loading")
console.log("downloadFont")
if (!downloadStarted) {
downloadStarted = true
button.classList.remove("loaded")
button.classList.remove("error")
button.classList.add("loading")
const allSettings = !isDefault
? {
regular: { ...fontDownloadSettings, style: "Regular" },
italic: { ...fontDownloadSettings, style: "Italic", italic: true },
bold: { ...fontDownloadSettings, style: "Bold", weight: 700 },
bolditalic: { ...fontDownloadSettings, style: "Bold Italic", italic: true, weight: 700 },
}
: {
regular: { ...fontDownloadSettingsDefault, style: "Regular" },
italic: { ...fontDownloadSettingsDefault, style: "Italic", italic: true },
bold: { ...fontDownloadSettingsDefault, style: "Bold", weight: 700 },
bolditalic: { ...fontDownloadSettingsDefault, style: "Bold Italic", italic: true, weight: 700 },
}
const allSettings = !isDefault
? {
regular: { ...fontDownloadSettings, style: "Regular" },
italic: { ...fontDownloadSettings, style: "Italic", italic: true },
bold: { ...fontDownloadSettings, style: "Bold", weight: 700 },
bolditalic: { ...fontDownloadSettings, style: "Bold Italic", italic: true, weight: 700 },
}
: {
regular: { ...fontDownloadSettingsDefault, style: "Regular" },
italic: { ...fontDownloadSettingsDefault, style: "Italic", italic: true },
bold: { ...fontDownloadSettingsDefault, style: "Bold", weight: 700 },
bolditalic: { ...fontDownloadSettingsDefault, style: "Bold Italic", italic: true, weight: 700 },
}
Promise.all([
getFontBlob(allSettings.regular),
getFontBlob(allSettings.italic),
getFontBlob(allSettings.bold),
getFontBlob(allSettings.bolditalic),
])
.then((resolve) => {
const [regular, italic, bold, bolditalic] = resolve
fontFileBlobs.regular = regular
fontFileBlobs.italic = italic
fontFileBlobs.bold = bold
fontFileBlobs.bolditalic = bolditalic
return getZipFileBlob()
})
.then((resolve) => {
downloadStarted = false
button.classList.remove("loading")
button.classList.add("loaded")
downloadFile(resolve)
})
.catch((err) => {
downloadStarted = false
button.classList.remove("loading")
button.classList.add("error")
console.log(err)
})
}
Promise.all([
getFontBlob(allSettings.regular),
getFontBlob(allSettings.italic),
getFontBlob(allSettings.bold),
getFontBlob(allSettings.bolditalic),
])
.then((resolve) => {
const [regular, italic, bold, bolditalic] = resolve
fontFileBlobs.regular = regular
fontFileBlobs.italic = italic
fontFileBlobs.bold = bold
fontFileBlobs.bolditalic = bolditalic
return getZipFileBlob()
})
.then((resolve) => {
downloadStarted = false
button.classList.remove("loading")
button.classList.add("loaded")
downloadFile(resolve)
})
.catch((err) => {
downloadStarted = false
button.classList.remove("loading")
button.classList.add("error")
console.log(err)
})
}
}
const fontFileBlobs = { regular: null, italic: null, bold: null, bolditalic: null }
function getFontBlob(settings) {
console.log("getFontBlob")
console.log("getFontBlob")
const fontFilePath = `/src/fonts/CommitMono${versionOfCommitMono}-${settings.weight}${
settings.italic ? "Italic" : "Regular"
}.otf`
const fontFilePath = `/src/fonts/CommitMono${versionOfCommitMono}-${settings.weight}${
settings.italic ? "Italic" : "Regular"
}.otf`
return opentype
.load(fontFilePath)
.then((font) => {
//
// #1 change alternates by switching their paths
// the below loop does this
// loop through the alternate settings
Object.entries(settings.alternates).forEach(([alternate, active]) => {
return opentype
.load(fontFilePath)
.then((font) => {
//
// filter for only the active ones
if (!active) return
// console.log("alternate", alternate, "active", active)
// #1 change alternates by switching their paths
// the below loop does this
// look at all the fonts features
font.tables.gsub.features.forEach((feature) => {
//
// if the feature matches the alternate we're currently on
if (feature.tag == alternate) {
// console.log("feature", feature)
// loop through the alternate settings
Object.entries(settings.alternates).forEach(([alternate, active]) => {
//
// filter for only the active ones
if (!active) return
// console.log("alternate", alternate, "active", active)
// then loop through the list of lookup indexes of that feature
feature.feature.lookupListIndexes.forEach((lookupIndex) => {
// console.log("lookupIndex", lookupIndex)
// look at all the fonts features
font.tables.gsub.features.forEach((feature) => {
//
// if the feature matches the alternate we're currently on
if (feature.tag == alternate) {
// console.log("feature", feature)
// loop through the subtable of each lookup at the lookup index
font.tables.gsub.lookups[lookupIndex].subtables.forEach((subtable) => {
// console.log("subtable", subtable)
// then loop through the list of lookup indexes of that feature
feature.feature.lookupListIndexes.forEach((lookupIndex) => {
// console.log("lookupIndex", lookupIndex)
// loop through the glyphs of the subtable
subtable.coverage.glyphs.forEach((glyphIndexOriginal, index) => {
//
// glyphIndexOriginal is the index of the original glyph
// glyphIndexSubstitute is the index of the glyph to substitute the original with
const glyphIndexSubstitute = subtable.substitute[index]
// console.log(
// "glyphIndexOriginal",
// glyphIndexOriginal,
// "glyphIndexSubstitute",
// glyphIndexSubstitute
// )
// loop through the subtable of each lookup at the lookup index
font.tables.gsub.lookups[lookupIndex].subtables.forEach((subtable) => {
// console.log("subtable", subtable)
// get the paths for the original and the substitute glyph
const glyphPathOriginal = font.glyphs.glyphs[glyphIndexOriginal].path
const glyphPathSubstitute = font.glyphs.glyphs[glyphIndexSubstitute].path
// loop through the glyphs of the subtable
subtable.coverage.glyphs.forEach((glyphIndexOriginal, index) => {
//
// glyphIndexOriginal is the index of the original glyph
// glyphIndexSubstitute is the index of the glyph to substitute the original with
const glyphIndexSubstitute = subtable.substitute[index]
// console.log(
// "glyphIndexOriginal",
// glyphIndexOriginal,
// "glyphIndexSubstitute",
// glyphIndexSubstitute
// )
// swap the paths, so the original glyph gets the path of the substitute and vice versa
font.glyphs.glyphs[glyphIndexOriginal].path = glyphPathSubstitute
font.glyphs.glyphs[glyphIndexSubstitute].path = glyphPathOriginal
// get the paths for the original and the substitute glyph
const glyphPathOriginal = font.glyphs.glyphs[glyphIndexOriginal].path
const glyphPathSubstitute = font.glyphs.glyphs[glyphIndexSubstitute].path
// swap the paths, so the original glyph gets the path of the substitute and vice versa
font.glyphs.glyphs[glyphIndexOriginal].path = glyphPathSubstitute
font.glyphs.glyphs[glyphIndexSubstitute].path = glyphPathOriginal
})
})
})
})
})
}
}
})
})
})
//
// "2 put active features into calt
// create empty "calt" feature to store the feature
const emptyCalt = { tag: "calt", feature: { featureParams: 0, lookupListIndexes: [] } }
font.tables.gsub.features.push(emptyCalt)
// garbage code that adds a single number to a specific array in the gsub table
// like this [0, 1, 2, 3, 4] => [0, 1, 2, 3, 4, 5]
font.tables.gsub.scripts.forEach((script) =>
script.script.defaultLangSys.featureIndexes.push(script.script.defaultLangSys.featureIndexes.length)
)
// create the empty array that is to be the lookup indexes for the calt feature
const caltLookupIndexes = []
// once again, loop through the alternate settings (feature settings)
Object.entries(settings.features).forEach(([alternate, active]) => {
//
// filter for only the active ones
if (!active) return
// console.log("alternate", alternate, "active", active)
// "2 put active features into calt
// create empty "calt" feature to store the feature
const emptyCalt = { tag: "calt", feature: { featureParams: 0, lookupListIndexes: [] } }
font.tables.gsub.features.push(emptyCalt)
// then loop through all features
font.tables.gsub.features.forEach((feature) => {
//
// and find the ones that match the active tags
if (feature.tag == alternate) {
// console.log("feature", feature)
// garbage code that adds a single number to a specific array in the gsub table
// like this [0, 1, 2, 3, 4] => [0, 1, 2, 3, 4, 5]
font.tables.gsub.scripts.forEach((script) =>
script.script.defaultLangSys.featureIndexes.push(script.script.defaultLangSys.featureIndexes.length)
)
// push the lookup indexes into the empty caltLookupIndexes variable
feature.feature.lookupListIndexes.forEach((lookupIndex) => caltLookupIndexes.push(lookupIndex))
}
// create the empty array that is to be the lookup indexes for the calt feature
const caltLookupIndexes = []
// once again, loop through the alternate settings (feature settings)
Object.entries(settings.features).forEach(([alternate, active]) => {
//
// filter for only the active ones
if (!active) return
// console.log("alternate", alternate, "active", active)
// then loop through all features
font.tables.gsub.features.forEach((feature) => {
//
// and find the ones that match the active tags
if (feature.tag == alternate) {
// console.log("feature", feature)
// push the lookup indexes into the empty caltLookupIndexes variable
feature.feature.lookupListIndexes.forEach((lookupIndex) => caltLookupIndexes.push(lookupIndex))
}
})
// once more loop through all features
font.tables.gsub.features.forEach((feature) => {
//
// when the calt feature is reached (it's the last one)
if (feature.tag === "calt") {
//
// set its lookup indexes to the variable
feature.feature.lookupListIndexes = caltLookupIndexes
// console.log("caltLookupIndexes", caltLookupIndexes)
}
})
})
// once more loop through all features
font.tables.gsub.features.forEach((feature) => {
//
// when the calt feature is reached (it's the last one)
if (feature.tag === "calt") {
//
// set its lookup indexes to the variable
feature.feature.lookupListIndexes = caltLookupIndexes
// console.log("caltLookupIndexes", caltLookupIndexes)
}
})
})
//
// #3 change the names
// give custom names to each member of the style group
font.names.fontFamily.en = "CommitMono"
font.names.fontSubfamily.en = settings.style
font.names.fullName.en = `CommitMono ${settings.style}`
font.names.postScriptName.en = `CommitMono-${settings.style.split(" ").join("")}`
delete font.names.preferredFamily
delete font.names.preferredSubfamily
font.names.uniqueID.en = `Version 0.900;;CommitMono-${settings.style.split(" ").join("")};2023;FL801`
//
// #3 change the names
// give custom names to each member of the style group
font.names.fontFamily.en = "CommitMono"
font.names.fontSubfamily.en = settings.style
font.names.fullName.en = `CommitMono ${settings.style}`
font.names.postScriptName.en = `CommitMono-${settings.style.split(" ").join("")}`
delete font.names.preferredFamily
delete font.names.preferredSubfamily
font.names.uniqueID.en = `Version 0.900;;CommitMono-${settings.style.split(" ").join("")};2023;FL801`
font.tables.cff.topDict.familyName = font.names.fontFamily.en
font.tables.cff.topDict.fullName = font.names.fullName.en
font.tables.cff.topDict.weight = settings.weight == 700 ? "Bold" : "Regular"
font.tables.cff.topDict.familyName = font.names.fontFamily.en
font.tables.cff.topDict.fullName = font.names.fullName.en
font.tables.cff.topDict.weight = settings.weight == 700 ? "Bold" : "Regular"
const macStyles = ["Regular", "Italic", "Bold", "Bold Italic"]
font.tables.head.macStyle = macStyles.indexOf(settings.style)
const macStyles = ["Regular", "Italic", "Bold", "Bold Italic"]
font.tables.head.macStyle = macStyles.indexOf(settings.style)
// make the font.tables.name equal to that of font.names
font.tables.name = font.names
// make the font.tables.name equal to that of font.names
font.tables.name = font.names
// set the correct weight
font.tables.os2.usWeightClass = settings.weight
// set the correct weight
font.tables.os2.usWeightClass = settings.weight
console.log(font)
const fontAB = font.toArrayBuffer()
const fontBlob = new Blob([fontAB], { type: "font/otf" })
console.log(font)
const fontAB = font.toArrayBuffer()
const fontBlob = new Blob([fontAB], { type: "font/otf" })
console.log(fontBlob)
console.log(fontBlob)
return fontBlob
})
.catch((err) => {
return err
})
return fontBlob
})
.catch((err) => {
return err
})
}
async function getZipFileBlob() {
console.log(fontFileBlobs)
const { BlobWriter, BlobReader, HttpReader, TextReader, ZipWriter } = zip
const installationTextURL = "/src/txt/installation.txt"
const zipWriter = new ZipWriter(new BlobWriter("application/zip"))
const { regular, italic, bold, bolditalic } = fontFileBlobs
await Promise.all([
zipWriter.add("installation.txt", new HttpReader(installationTextURL)),
zipWriter.add("CommitMono-Regular.otf", new BlobReader(regular)),
zipWriter.add("CommitMono-Italic.otf", new BlobReader(italic)),
zipWriter.add("CommitMono-Bold.otf", new BlobReader(bold)),
zipWriter.add("CommitMono-BoldItalic.otf", new BlobReader(bolditalic)),
])
return zipWriter.close()
console.log(fontFileBlobs)
const { BlobWriter, BlobReader, HttpReader, TextReader, ZipWriter } = zip
const installationTextURL = "/src/txt/installation.txt"
const zipWriter = new ZipWriter(new BlobWriter("application/zip"))
const { regular, italic, bold, bolditalic } = fontFileBlobs
await Promise.all([
zipWriter.add("installation.txt", new HttpReader(installationTextURL)),
zipWriter.add("CommitMono-Regular.otf", new BlobReader(regular)),
zipWriter.add("CommitMono-Italic.otf", new BlobReader(italic)),
zipWriter.add("CommitMono-Bold.otf", new BlobReader(bold)),
zipWriter.add("CommitMono-BoldItalic.otf", new BlobReader(bolditalic)),
])
return zipWriter.close()
}
function downloadFile(blob) {
const a = document.createElement("a")
a.download = `CommitMono-${Date.now()}.zip`
a.href = URL.createObjectURL(blob)
a.click()
const a = document.createElement("a")
a.download = `CommitMono-${Date.now()}.zip`
a.href = URL.createObjectURL(blob)
a.click()
}

View File

@ -1,18 +1,18 @@
function fillSectionData() {
console.log("fillSectionData")
websiteData.sections.forEach((section, index) => {
const topContainer = document.querySelector(`#section_${index + 1} .top_container`)
if (topContainer) {
const h1 = document.createElement("h1")
h1.textContent = `${index + 1 < 10 ? `0${index + 1}` : index + 1} ${capitalize(section.name)}`
h1.tabIndex = 0
h1.dataset.edit = "true"
const br = document.createElement("br")
const p = document.createElement("p")
p.innerHTML = section.description
p.tabIndex = 0
p.dataset.edit = "true"
topContainer.append(h1, br, p)
}
})
console.log("fillSectionData")
websiteData.sections.forEach((section, index) => {
const topContainer = document.querySelector(`#section_${index + 1} .top_container`)
if (topContainer) {
const h1 = document.createElement("h1")
h1.textContent = `${index + 1 < 10 ? `0${index + 1}` : index + 1} ${capitalize(section.name)}`
h1.tabIndex = 0
h1.dataset.edit = "true"
const br = document.createElement("br")
const p = document.createElement("p")
p.innerHTML = section.description
p.tabIndex = 0
p.dataset.edit = "true"
topContainer.append(h1, br, p)
}
})
}

View File

@ -1,49 +1,49 @@
let waitingForLoadIntervalID = null
let allCssLoaded = false
function startAll() {
console.log("startAll")
console.log("startAll")
appendStyleSheets()
appendStyleSheets()
waitingForLoadIntervalID = setInterval(() => {
if (allCssLoaded) {
document.querySelector("#navigate_description").focus()
document.querySelector("#loading").style.display = "none"
clearInterval(waitingForLoadIntervalID)
waitingForLoadIntervalID = null
}
}, 100)
waitingForLoadIntervalID = setInterval(() => {
if (allCssLoaded) {
document.querySelector("#navigate_description").focus()
document.querySelector("#loading").style.display = "none"
clearInterval(waitingForLoadIntervalID)
waitingForLoadIntervalID = null
}
}, 100)
fillSectionData()
fillSectionData()
buildNav()
buildNav()
buildTable()
buildTable()
buildFamiliar()
buildFamiliar()
buildCode()
buildCode()
buildDistinction()
buildDistinction()
buildGTC()
buildGTC()
buildExample()
buildExample()
buildDocumentation()
buildDocs()
updateCodeFont()
updateCodeFont()
updateWaterfall()
updateWaterfall()
changeFavicon(true)
changeFavicon(true)
sectionNavigation(0)
sectionNavigation(0)
setInterval(checkDocumentFocus, 100)
setInterval(checkDocumentFocus, 100)
}
if (fontsLoaded) {
console.log("fontsLoaded startAll()")
startAll()
console.log("fontsLoaded startAll()")
startAll()
}

View File

@ -1,68 +1,68 @@
function buildTable() {
console.log("buildTable")
const table = document.querySelector("#section_2 .content_container table")
console.log("buildTable")
const table = document.querySelector("#section_2 .content_container table")
for (let i = 0; i <= 6; i++) {
const tr = document.createElement("tr")
const fieldset = document.createElement("fieldset")
tr.append(fieldset)
for (let j = 0; j <= 16; j++) {
if (i == 0 || j == 0) {
const th = document.createElement("th")
const div = document.createElement("div")
const p = document.createElement("p")
if (i != 0 && j == 0) {
p.textContent = createBinaryString(i + 1, 3)
} else if (i == 0 && j != 0) {
p.textContent = createBinaryString(j - 1, 4)
for (let i = 0; i <= 6; i++) {
const tr = document.createElement("tr")
const fieldset = document.createElement("fieldset")
tr.append(fieldset)
for (let j = 0; j <= 16; j++) {
if (i == 0 || j == 0) {
const th = document.createElement("th")
const div = document.createElement("div")
const p = document.createElement("p")
if (i != 0 && j == 0) {
p.textContent = createBinaryString(i + 1, 3)
} else if (i == 0 && j != 0) {
p.textContent = createBinaryString(j - 1, 4)
} else {
p.textContent = ""
}
div.append(p)
th.append(div)
fieldset.append(th)
} else {
p.textContent = ""
}
div.append(p)
th.append(div)
fieldset.append(th)
} else {
const charCode = (i - 1) * 16 + j + 31
const charCode = (i - 1) * 16 + j + 31
const td = document.createElement("td")
td.id = `td_${charCode}`
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.id = `char_${charCode}`
input.name = `row_${i}`
input.value = charCode
if (j == 2) input.setAttribute("checked", "true")
const label = document.createElement("label")
label.textContent = i == 6 && j == 16 ? "" : String.fromCharCode(charCode)
label.setAttribute("for", `char_${charCode}`)
label.dataset.edit = "true"
div.append(input, label)
td.append(div)
fieldset.append(td)
}
}
table.append(tr)
}
const td = document.createElement("td")
td.id = `td_${charCode}`
const div = document.createElement("div")
const input = document.createElement("input")
input.type = "radio"
input.id = `char_${charCode}`
input.name = `row_${i}`
input.value = charCode
if (j == 2) input.setAttribute("checked", "true")
const label = document.createElement("label")
label.textContent = i == 6 && j == 16 ? "" : String.fromCharCode(charCode)
label.setAttribute("for", `char_${charCode}`)
label.dataset.edit = "true"
div.append(input, label)
td.append(div)
fieldset.append(td)
}
}
table.append(tr)
}
}
const createBinaryString = (number, length) => parseInt(number, 10).toString(2).padStart(length, "0")
let previousOutput = [33, 49, 65, 81, 97, 113]
function updateTable(event, form) {
console.log("updateTable")
const data = new FormData(form)
let output = []
for (const entry of data) output.push(+entry[1])
let indexOfChange = 0
let offset = 0
output.forEach((row, index) => (row != previousOutput[index] ? (indexOfChange = index) : null))
output.forEach((row, index) => (index == indexOfChange ? (offset = row - previousOutput[index]) : null))
output.forEach((row, index) => {
if (index != indexOfChange) {
document.forms["table_form"][`char_${row + offset}`].checked = true
output[index] += offset
}
})
previousOutput = [...output]
event.preventDefault()
console.log("updateTable")
const data = new FormData(form)
let output = []
for (const entry of data) output.push(+entry[1])
let indexOfChange = 0
let offset = 0
output.forEach((row, index) => (row != previousOutput[index] ? (indexOfChange = index) : null))
output.forEach((row, index) => (index == indexOfChange ? (offset = row - previousOutput[index]) : null))
output.forEach((row, index) => {
if (index != indexOfChange) {
document.forms["table_form"][`char_${row + offset}`].checked = true
output[index] += offset
}
})
previousOutput = [...output]
event.preventDefault()
}

View File

@ -1,7 +1,7 @@
// takes a string and returns a string, where the first letter is uppercase
function capitalize(string) {
const stringArray = string.split("")
return stringArray.shift().toUpperCase() + stringArray.join("")
const stringArray = string.split("")
return stringArray.shift().toUpperCase() + stringArray.join("")
}
const mapRange = (value, x1, y1, x2, y2) => ((value - x1) * (y2 - x2)) / (y1 - x1) + x2
@ -10,79 +10,79 @@ const getCssVar = (property) => getComputedStyle(document.documentElement).getPr
const setCssVar = ([property, value]) => document.documentElement.style.setProperty(property, value)
const isMobileTest = () => {
if (window.matchMedia("(pointer: coarse) and (max-width: 1000px").matches) {
console.log("(pointer: coarse) and (max-width: 1000px)")
return true
} else return false
if (window.matchMedia("(pointer: coarse) and (max-width: 1000px").matches) {
console.log("(pointer: coarse) and (max-width: 1000px)")
return true
} else return false
}
const mobileMediaQuery = "(pointer: coarse) and (max-width: 1000px)"
const mql = window.matchMedia(mobileMediaQuery)
let isMobile = mql.matches
mql.addEventListener("change", (e) => {
isMobile = e.matches
changedFocus(true)
isMobile = e.matches
changedFocus(true)
})
function wait(milliseconds) {
return new Promise((resolve) => {
setTimeout(resolve, milliseconds)
})
return new Promise((resolve) => {
setTimeout(resolve, milliseconds)
})
}
let checkCssLoadIntervalIDs = []
function appendStyleSheets() {
console.log("appendStyleSheets")
const stylesheetIndexes = [
"style",
"mobile",
"non_essential",
"section_1",
"section_2",
"section_3",
"section_4",
"section_5",
"section_6",
"section_7",
"section_8",
"section_9",
"section_10",
]
const head = document.querySelector("head")
stylesheetIndexes.forEach((stylesheet, index) => {
const link = document.createElement("link")
link.setAttribute("rel", "stylesheet")
link.setAttribute("href", `src/css/${stylesheet}.css`)
head.append(link)
checkCssLoadIntervalIDs[index] = setInterval(() => {
const cssLoaded = Boolean(link.sheet)
if (cssLoaded) {
console.log(`${stylesheet} CSS loaded`)
clearInterval(checkCssLoadIntervalIDs[index])
checkCssLoadIntervalIDs[index] = null
if (index == 3) {
allCssLoaded = true
console.log("ALL CSS LOADED")
console.log("appendStyleSheets")
const stylesheetIndexes = [
"style",
"mobile",
"non_essential",
"section_1",
"section_2",
"section_3",
"section_4",
"section_5",
"section_6",
"section_7",
"section_8",
"section_9",
"section_10",
]
const head = document.querySelector("head")
stylesheetIndexes.forEach((stylesheet, index) => {
const link = document.createElement("link")
link.setAttribute("rel", "stylesheet")
link.setAttribute("href", `src/css/${stylesheet}.css`)
head.append(link)
checkCssLoadIntervalIDs[index] = setInterval(() => {
const cssLoaded = Boolean(link.sheet)
if (cssLoaded) {
console.log(`${stylesheet} CSS loaded`)
clearInterval(checkCssLoadIntervalIDs[index])
checkCssLoadIntervalIDs[index] = null
if (index == 3) {
allCssLoaded = true
console.log("ALL CSS LOADED")
}
}
}
}, 100)
})
}, 100)
})
}
function showHideChangeSettings(text, ms, dim) {
const changeSetting = document.querySelector("#change_setting p")
changeSetting.textContent = text
changeSetting.style.visibility = "visible"
if (dim) {
document.querySelector("#nav_form").classList.add("faded")
document.querySelector("#main_scale").classList.add("faded")
}
clearTimeout(changeSettingTimeoutID)
changeSettingTimeoutID = setTimeout(() => {
changeSetting.style.visibility = "hidden"
if (dim) {
document.querySelector("#nav_form").classList.remove("faded")
document.querySelector("#main_scale").classList.remove("faded")
}
}, ms ?? 500)
const changeSetting = document.querySelector("#change_setting p")
changeSetting.textContent = text
changeSetting.style.visibility = "visible"
if (dim) {
document.querySelector("#nav_form").classList.add("faded")
document.querySelector("#main_scale").classList.add("faded")
}
clearTimeout(changeSettingTimeoutID)
changeSettingTimeoutID = setTimeout(() => {
changeSetting.style.visibility = "hidden"
if (dim) {
document.querySelector("#nav_form").classList.remove("faded")
document.querySelector("#main_scale").classList.remove("faded")
}
}, ms ?? 500)
}

File diff suppressed because one or more lines are too long

View File

@ -1,90 +1,90 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>School timetable</title>
<style>
html {
font-family: sans-serif;
}
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>School timetable</title>
<style>
html {
font-family: sans-serif;
}
table {
border-collapse: collapse;
border: 0.125rem solid rgb(200, 200, 200);
letter-spacing: 0.0625rem;
font-size: 0.8rem;
}
table {
border-collapse: collapse;
border: 0.125rem solid rgb(200, 200, 200);
letter-spacing: 0.0625rem;
font-size: 0.8rem;
}
td,
th {
border: 0.0625rem solid rgb(190, 190, 190);
padding: 10px 20px;
}
td,
th {
border: 0.0625rem solid rgb(190, 190, 190);
padding: 10px 20px;
}
td {
text-align: center;
}
td {
text-align: center;
}
caption {
padding: 10px;
}
</style>
</head>
<body>
<h1>School timetable</h1>
caption {
padding: 10px;
}
</style>
</head>
<body>
<h1>School timetable</h1>
<table>
<tr>
<td>&nbsp;</td>
<th>Mon</th>
<th>Tues</th>
<th>Wed</th>
<th>Thurs</th>
<th>Fri</th>
<th>Sat</th>
<th>Sun</th>
</tr>
<tr>
<th>1st period</th>
<td>English</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>German</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th>2nd period</th>
<td>English</td>
<td>English</td>
<td>&nbsp;</td>
<td>German</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th>3rd period</th>
<td>&nbsp;</td>
<td>German</td>
<td>&nbsp;</td>
<td>German</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th>4th period</th>
<td>&nbsp;</td>
<td>English</td>
<td>&nbsp;</td>
<td>English</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
<table>
<tr>
<td>&nbsp;</td>
<th>Mon</th>
<th>Tues</th>
<th>Wed</th>
<th>Thurs</th>
<th>Fri</th>
<th>Sat</th>
<th>Sun</th>
</tr>
<tr>
<th>1st period</th>
<td>English</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>German</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th>2nd period</th>
<td>English</td>
<td>English</td>
<td>&nbsp;</td>
<td>German</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th>3rd period</th>
<td>&nbsp;</td>
<td>German</td>
<td>&nbsp;</td>
<td>German</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th>4th period</th>
<td>&nbsp;</td>
<td>English</td>
<td>&nbsp;</td>
<td>English</td>
<td>Dutch</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>