basic reference

This commit is contained in:
Joshua Seigler 2024-04-07 01:01:24 -04:00
commit 63216d92cd
26 changed files with 8721 additions and 0 deletions

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

14
index.html Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>Learn Aurebesh</title>
</head>
<body>
<div id="app"></div>
<script prerender type="module" src="/src/index.tsx"></script>
</body>
</html>

8232
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

26
package.json Normal file
View file

@ -0,0 +1,26 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@preact/signals": "^1.2.3",
"preact": "^10.13.1",
"preact-iso": "^2.6.2",
"preact-render-to-string": "^6.4.1",
"random-words": "^2.0.1"
},
"devDependencies": {
"@preact/preset-vite": "^2.5.0",
"eslint": "^8.57.0",
"eslint-config-preact": "^1.3.0",
"typescript": "^5.4.4",
"vite": "^4.3.2"
},
"eslintConfig": {
"extends": "preact"
}
}

BIN
public/fonts/AB-Equinox.otf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/fonts/Droidobesh.otf Normal file

Binary file not shown.

BIN
public/fonts/LaptiNekAF.otf Normal file

Binary file not shown.

BIN
public/fonts/Maulobesh.otf Normal file

Binary file not shown.

Binary file not shown.

BIN
public/fonts/Skyhook.otf Normal file

Binary file not shown.

22
public/logo.svg Normal file
View file

@ -0,0 +1,22 @@
<svg aria-hidden="true" width="256" height="256" preserveAspectRatio="xMidYMid" viewBox="0 0 252.9 253" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<style>
.letters {
fill: #000;
}
@media (prefers-color-scheme: dark) {
.letters {
fill: #fff;
}
}
</style>
<defs>
<linearGradient id="a">
<stop style="stop-color:#900;" offset="0"/>
<stop style="stop-color:#b50;" offset="1"/>
</linearGradient>
<linearGradient xlink:href="#a" id="b" x1="1.5" y1="128.5" x2="254.5" y2="128.5" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1.5 -2)"/>
</defs>
<circle style="fill:url(#b);" cx="126.5" cy="126.5" r="126.5"/>
<path class="letters" d="M70 74.5H16.2v26.4h40.6Zm-53.8 29.7v26.4H70l-13.2-26.4ZM96 85.7v18.5h-3.4V87.4L70.2 98.6v32h48.2V74.5ZM70.2 74.5v20.7l41.5-20.7Zm51.6 0v26.4h15.5l-14.8 29.7h25.2l28-56.1zm110.4 0-22.4 44.9v11.2h22.4v-29.7h5.6V74.5Zm-25.8 0-5.6 14-5.6-14h-22.4l28 56 28-56z"/>
<path class="letters" d="m72 158.7-12.7-25.5h-38L8.6 158.7Zm-63.4 3.2 12.7 25.5h38L72 161.9Zm111.8-28.7-21.6 43.4v10.8h21.6v-28.7h5.5v-25.5zm-24.9 0-5.4 13.6-5.4-13.6H63l27.1 54.2 27-54.2zm30.6 28.7v25.5h23.8l-12.7-25.5zm30.3-28.7v13.6l-5.4-13.6h-25l27.1 54.2h25v-54.2zm24.9 25.5h50.9v-25.5h-51zm0 28.7h50.9v-25.5h-51z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
src/assets/preact.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="27.68" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 296"><path fill="#673AB8" d="m128 0l128 73.9v147.8l-128 73.9L0 221.7V73.9z"></path><path fill="#FFF" d="M34.865 220.478c17.016 21.78 71.095 5.185 122.15-34.704c51.055-39.888 80.24-88.345 63.224-110.126c-17.017-21.78-71.095-5.184-122.15 34.704c-51.055 39.89-80.24 88.346-63.224 110.126Zm7.27-5.68c-5.644-7.222-3.178-21.402 7.573-39.253c11.322-18.797 30.541-39.548 54.06-57.923c23.52-18.375 48.303-32.004 69.281-38.442c19.922-6.113 34.277-5.075 39.92 2.148c5.644 7.223 3.178 21.403-7.573 39.254c-11.322 18.797-30.541 39.547-54.06 57.923c-23.52 18.375-48.304 32.004-69.281 38.441c-19.922 6.114-34.277 5.076-39.92-2.147Z"></path><path fill="#FFF" d="M220.239 220.478c17.017-21.78-12.169-70.237-63.224-110.126C105.96 70.464 51.88 53.868 34.865 75.648c-17.017 21.78 12.169 70.238 63.224 110.126c51.055 39.889 105.133 56.485 122.15 34.704Zm-7.27-5.68c-5.643 7.224-19.998 8.262-39.92 2.148c-20.978-6.437-45.761-20.066-69.28-38.441c-23.52-18.376-42.74-39.126-54.06-57.923c-10.752-17.851-13.218-32.03-7.575-39.254c5.644-7.223 19.999-8.261 39.92-2.148c20.978 6.438 45.762 20.067 69.281 38.442c23.52 18.375 42.739 39.126 54.06 57.923c10.752 17.85 13.218 32.03 7.574 39.254Z"></path><path fill="#FFF" d="M127.552 167.667c10.827 0 19.603-8.777 19.603-19.604c0-10.826-8.776-19.603-19.603-19.603c-10.827 0-19.604 8.777-19.604 19.603c0 10.827 8.777 19.604 19.604 19.604Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

180
src/index.tsx Normal file
View file

@ -0,0 +1,180 @@
import { hydrate, prerender as ssr } from "preact-iso";
import "./style.css";
import { computed, effect, signal } from "@preact/signals";
const fonts: Record<string, { ligatures: string[]; lowercase: boolean }> = {
"AB-Equinox": {
ligatures: ["ch", "sh", "th", "ae", "eo", "kh", "ng", "oo"],
lowercase: false,
},
"AurebeshAF-Canon": {
ligatures: [],
lowercase: false,
},
"AurebeshAF-CanonTech": {
ligatures: [],
lowercase: false,
},
"AurebeshAF-Legends": {
ligatures: ["ch", "sh", "th", "ae", "eo", "kh", "ng", "oo"],
lowercase: false,
},
"AurebeshAF-LegendsTech": {
ligatures: ["ch", "sh", "th", "ae", "eo", "kh", "ng", "oo"],
lowercase: false,
},
"Aurebesh_Rodian-Oblique": {
ligatures: [],
lowercase: false,
},
"Aurebesh_Rodian-OblqOutline": {
ligatures: [],
lowercase: false,
},
Aurebesh_Rodian: {
ligatures: [],
lowercase: false,
},
"Aurebesh_Rodian-Outline": {
ligatures: [],
lowercase: false,
},
"AurebeshTypewriter-Light": {
ligatures: [],
lowercase: true,
},
"AurebeshTypewriter-Regular": {
ligatures: [],
lowercase: true,
},
Droidobesh: {
ligatures: [],
lowercase: false,
},
LaptiNekAF: {
ligatures: [],
lowercase: false,
},
Maulobesh: {
ligatures: [],
lowercase: false,
},
Nirvanabesh: {
ligatures: [],
lowercase: false,
},
Skyhook: {
ligatures: [],
lowercase: false,
},
};
const fontNames = Object.keys(fonts);
const selectedFont = signal("AurebeshAF-Legends");
effect(() => {
document.documentElement.style.setProperty(
"--font-aurebesh",
selectedFont.value
);
});
const ligatures = computed(() => {
return fonts[selectedFont.value].ligatures;
});
const lowercase = computed(() => {
return fonts[selectedFont.value].lowercase;
});
export function App() {
return (
<>
<header>
<h1>
<DualText>Learn Aurebesh</DualText>
</h1>
</header>
<main>
<div class="content">
<FontPicker />
</div>
<aside class="reference">
<DualText>
{lowercase.value
? "Aa Bb Cc Dd Ee Ff Gg Hh Ii"
: "A B C D E F G H I"}
</DualText>
<DualText>
{lowercase.value
? "Jj Kk Ll Mm Nn Oo Pp Qq Rr"
: "J K L M N O P Q R"}
</DualText>
<DualText>
{lowercase.value ? "Ss Tt Uu Vv Ww Xx Yy Zz" : "S T U V W X Y Z"}
</DualText>
<DualText>0 1 2 3 4 5 6 7 8 9</DualText>
{ligatures.value.length > 0 && (
<DualText>{ligatures.value.join(" ")}</DualText>
)}
<DualText>{`, . ? ! : ; ' " ( )`}</DualText>
</aside>
</main>
</>
);
}
function FontPicker() {
return (
<select
onChange={(event) => {
selectedFont.value = event.currentTarget.value;
}}
>
{fontNames.map((font) => {
return (
<option value={font} selected={font === selectedFont.value}>
{font}
</option>
);
})}
</select>
);
}
function DualText({ children }: { children: string }) {
const words = children.split(/\b/);
return (
<span>
{words.map((word) => {
const letters: string[] = [];
for (let i = 0; i < word.length; i += 1) {
const nextTwoCharacters = word.slice(i, i + 2);
if (ligatures.value.includes(nextTwoCharacters)) {
letters.push(nextTwoCharacters);
i += 1;
} else {
letters.push(nextTwoCharacters[0]);
}
}
return (
<span class="dualtext-word">
<span class="aurebesh">{word}</span>
<div className="dualtext-help">
{letters.map((character) => {
return <span data-character={character} />;
})}
</div>
</span>
);
})}
</span>
);
}
if (typeof window !== "undefined") {
hydrate(<App />, document.getElementById("app"));
}
export async function prerender(data) {
return await ssr(<App {...data} />);
}

188
src/style.css Normal file
View file

@ -0,0 +1,188 @@
@font-face {
font-family: "AB-Equinox";
src: url(fonts/AB-Equinox.otf) format("opentype");
}
@font-face {
font-family: "AurebeshAF-Canon";
src: url(fonts/AurebeshAF-Canon.otf) format("opentype");
}
@font-face {
font-family: "AurebeshAF-CanonTech";
src: url(fonts/AurebeshAF-CanonTech.otf) format("opentype");
}
@font-face {
font-family: "AurebeshAF-Legends";
src: url(fonts/AurebeshAF-Legends.otf) format("opentype");
}
@font-face {
font-family: "AurebeshAF-LegendsTech";
src: url(fonts/AurebeshAF-LegendsTech.otf) format("opentype");
}
@font-face {
font-family: "Aurebesh_Rodian-Oblique";
src: url(fonts/Aurebesh_Rodian-Oblique.otf) format("opentype");
}
@font-face {
font-family: "Aurebesh_Rodian-OblqOutline";
src: url(fonts/Aurebesh_Rodian-OblqOutline.otf) format("opentype");
}
@font-face {
font-family: "Aurebesh_Rodian";
src: url(fonts/Aurebesh_Rodian.otf) format("opentype");
}
@font-face {
font-family: "Aurebesh_Rodian-Outline";
src: url(fonts/Aurebesh_Rodian-Outline.otf) format("opentype");
}
@font-face {
font-family: "AurebeshTypewriter-Light";
src: url(fonts/AurebeshTypewriter-Light.otf) format("opentype");
}
@font-face {
font-family: "AurebeshTypewriter-Regular";
src: url(fonts/AurebeshTypewriter-Regular.otf) format("opentype");
}
@font-face {
font-family: "Droidobesh";
src: url(fonts/Droidobesh.otf) format("opentype");
}
@font-face {
font-family: "LaptiNekAF";
src: url(fonts/LaptiNekAF.otf) format("opentype");
}
@font-face {
font-family: "Maulobesh";
src: url(fonts/Maulobesh.otf) format("opentype");
}
@font-face {
font-family: "Nirvanabesh";
src: url(fonts/Nirvanabesh.otf) format("opentype");
}
@font-face {
font-family: "Skyhook";
src: url(fonts/Skyhook.otf) format("opentype");
}
:root {
font-family: var(--font-standard);
line-height: 1.5;
font-weight: 400;
color: #222;
background-color: #ffffff;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
--color-text-normal: #000d;
--color-text-light: #0007;
--color-background1: #eed;
--color-background2: #bba;
--color-accent1: #900;
--color-accent2: #b50;
--font-aurebesh: Droidobesh;
--font-standard: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
font-size: clamp(100%, 1rem + 2vw, 24px);
box-sizing: border-box;
}
*,
::after,
::before {
box-sizing: inherit;
}
body {
min-height: 100vh;
margin: 0;
display: flex;
color: var(--color-text-normal);
background-image: linear-gradient(
-30deg,
var(--color-background1),
var(--color-background2)
);
}
#app {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
text-align: center;
max-width: 60rem;
padding: 0 1rem;
margin: 0 auto;
}
h1 {
font-size: 3rem;
}
.aurebesh {
font-family: var(--font-aurebesh);
}
@media (prefers-color-scheme: dark) {
:root {
--color-text-normal: #fffd;
--color-text-light: #fff7;
--color-background1: #111;
--color-background2: #333;
}
}
.dualtext-word {
position: relative;
display: inline-block;
white-space: pre;
}
.dualtext-help {
position: absolute;
inset: 0;
flex-direction: row;
justify-content: space-between;
pointer-events: none;
display: flex;
}
.dualtext-help > span {
position: relative;
min-width: 0;
}
.dualtext-help > span::before {
content: attr(data-character);
font-family: var(--font-aurebesh);
color: transparent;
}
.dualtext-help > span::after {
content: attr(data-character);
position: absolute;
left: 0;
right: 0;
top: 70%;
margin: auto;
font-family: var(--font-standard);
font-style: italic;
font-size: 0.5em;
font-weight: 400;
color: var(--color-text-light);
}
.reference {
font-size: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
main {
display: flex;
flex-direction: column;
max-width: 60rem;
margin: 0 auto;
}

20
tsconfig.json Normal file
View file

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"noEmit": true,
"allowJs": true,
"checkJs": true,
/* Preact Config */
"jsx": "react-jsx",
"jsxImportSource": "preact",
"skipLibCheck": true,
"paths": {
"react": ["./node_modules/preact/compat/"],
"react-dom": ["./node_modules/preact/compat/"]
}
},
"include": ["node_modules/vite/client.d.ts", "**/*"]
}

14
vite.config.ts Normal file
View file

@ -0,0 +1,14 @@
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
preact({
prerender: {
enabled: true,
renderTarget: '#app',
},
}),
],
});