mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Make builds of the editor and the website serve their own local fonts (#2186)
* WIP * Done? * Install fonts in CI * Use absolute path so minified inlined CSS works * Fix Bezier-rs demo fonts? * Use opsz * Revert removal of text balancer * Pull in the text balancer from our static host
This commit is contained in:
parent
ea59f10b50
commit
e57637aab1
28 changed files with 1305 additions and 755 deletions
7
.github/workflows/website.yml
vendored
7
.github/workflows/website.yml
vendored
|
@ -13,7 +13,7 @@ on:
|
||||||
- website/**
|
- website/**
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
INDEX_HTML_HEAD_INCLUSION: <script defer data-domain="graphite.rs" data-api="/visit/event" src="/visit/script.js"></script>
|
INDEX_HTML_HEAD_INCLUSION: <script defer data-domain="graphite.rs" data-api="/visit/event" src="/visit/script.hash.js"></script>
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -30,7 +30,7 @@ jobs:
|
||||||
- name: 🕸 Install Zola
|
- name: 🕸 Install Zola
|
||||||
uses: taiki-e/install-action@v2
|
uses: taiki-e/install-action@v2
|
||||||
with:
|
with:
|
||||||
tool: zola@0.19.1
|
tool: zola@0.20.0
|
||||||
|
|
||||||
- name: ✂ Replace template in <head> of index.html
|
- name: ✂ Replace template in <head> of index.html
|
||||||
run: |
|
run: |
|
||||||
|
@ -42,7 +42,8 @@ jobs:
|
||||||
MODE: prod
|
MODE: prod
|
||||||
run: |
|
run: |
|
||||||
cd website
|
cd website
|
||||||
zola --config config_prod.toml build
|
npm run install-fonts
|
||||||
|
zola --config config.toml build --minify
|
||||||
|
|
||||||
- name: 🔍 Check if `website/other` directory changed
|
- name: 🔍 Check if `website/other` directory changed
|
||||||
uses: dorny/paths-filter@v3
|
uses: dorny/paths-filter@v3
|
||||||
|
|
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -3362,7 +3362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -6635,9 +6635,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.44.0"
|
version = "1.45.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a"
|
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
|
@ -734,7 +734,7 @@ impl OverlayContext {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_context.set_font("12px Source Sans Pro, Arial, sans-serif");
|
self.render_context.set_font(r#"12px "Source Sans Pro", Arial, sans-serif"#);
|
||||||
self.render_context.set_fill_style_str(font_color);
|
self.render_context.set_fill_style_str(font_color);
|
||||||
self.render_context.fill_text(text, 0., 0.).expect("Failed to draw the text at the calculated position");
|
self.render_context.fill_text(text, 0., 0.).expect("Failed to draw the text at the calculated position");
|
||||||
self.render_context.reset_transform().expect("Failed to reset the render context transform");
|
self.render_context.reset_transform().expect("Failed to reset the render context transform");
|
||||||
|
|
|
@ -22,7 +22,7 @@ Wraps the editor backend codebase (`/editor`) and provides a JS-centric API for
|
||||||
|
|
||||||
## ESLint configurations: `.eslintrc.js`
|
## ESLint configurations: `.eslintrc.js`
|
||||||
|
|
||||||
[ESLint](https://eslint.org/) is the tool which enforces style rules on the JS, TS, and Svelte files in our frontend codebase. As it is set up in this config file, ESLint will complain about bad practices and often help reformat code automatically when (in VS Code) the file is saved or `npm run lint` is executed. (If you don't use VS Code, remember to run this command before committing!) This config file for ESLint sets our style preferences and configures our usage of extensions/plugins for Svelte support, [Airbnb](https://github.com/airbnb/javascript)'s popular catalog of sane defaults, and [Prettier](https://prettier.io/)'s role as a code formatter.
|
[ESLint](https://eslint.org/) is the tool which enforces style rules on the JS, TS, and Svelte files in our frontend codebase. As it is set up in this config file, ESLint will complain about bad practices and often help reformat code automatically when (in VS Code) the file is saved or `npm run lint` is executed. (If you don't use VS Code, remember to run this command before committing!) This config file for ESLint sets our style preferences and configures our usage of extensions/plugins for Svelte support and [Prettier](https://prettier.io/)'s role as a code formatter.
|
||||||
|
|
||||||
## npm ecosystem packages: `package.json`
|
## npm ecosystem packages: `package.json`
|
||||||
|
|
||||||
|
|
|
@ -1,79 +1,54 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<title>Graphite</title>
|
<title>Graphite</title>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=block&family=Source+Sans+Pro:ital,wght@0,400;0,700;1,400;1,700&family=Inconsolata:wght@400;700">
|
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
<link rel="manifest" href="site.webmanifest" />
|
||||||
<link rel="manifest" href="site.webmanifest">
|
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#473a3a" />
|
||||||
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#473a3a">
|
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5">
|
<meta name="apple-mobile-web-app-title" content="Graphite" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Graphite">
|
<meta name="application-name" content="Graphite" />
|
||||||
<meta name="application-name" content="Graphite">
|
<meta name="msapplication-TileColor" content="#ffffff" />
|
||||||
<meta name="msapplication-TileColor" content="#ffffff">
|
<meta name="theme-color" content="#ffffff" />
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="color-scheme" content="dark only" />
|
||||||
<meta name="color-scheme" content="dark only">
|
<meta name="darkreader-lock" />
|
||||||
<meta name="darkreader-lock">
|
<!-- INDEX_HTML_HEAD_REPLACEMENT -->
|
||||||
<!-- INDEX_HTML_HEAD_REPLACEMENT -->
|
</head>
|
||||||
</head>
|
<body>
|
||||||
<body>
|
<noscript>JavaScript is required</noscript>
|
||||||
<noscript>JavaScript is required</noscript>
|
<style>
|
||||||
<style>
|
body {
|
||||||
body {
|
background: #222;
|
||||||
background: #222;
|
height: 100%;
|
||||||
height: 100%;
|
margin: 0;
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 4px solid #eee;
|
|
||||||
border-color: #eee transparent #eee transparent;
|
|
||||||
animation: spinning-loading-indicator 1s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spinning-loading-indicator {
|
|
||||||
0% {
|
|
||||||
transform: translate(-30px, -30px) rotate(0deg);
|
|
||||||
}
|
}
|
||||||
100% {
|
|
||||||
transform: translate(-30px, -30px) rotate(360deg);
|
body::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4px solid #eee;
|
||||||
|
border-color: #eee transparent #eee transparent;
|
||||||
|
animation: spinning-loading-indicator 1s linear infinite;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
// Confirm the browser is compatible before initializing the application
|
|
||||||
|
|
||||||
// Display an error if the browser is incompatible with a required API
|
@keyframes spinning-loading-indicator {
|
||||||
// This is run outside the JS code bundle in case unsupported features cause a syntax error when parsing the bundle, preventing the any bundle code from running
|
0% {
|
||||||
let incompatibility;
|
transform: translate(-30px, -30px) rotate(0deg);
|
||||||
if (!("BigUint64Array" in window)) {
|
}
|
||||||
incompatibility = `
|
100% {
|
||||||
<style>
|
transform: translate(-30px, -30px) rotate(360deg);
|
||||||
body::after { content: none; }
|
}
|
||||||
h2, p, a { text-align: center; color: #eee; font-family: "Source Sans Pro", Arial, sans-serif; }
|
}
|
||||||
</style>
|
</style>
|
||||||
<h2>This browser is too old to run Graphite</h2>
|
<script type="module" src="src/main.ts"></script>
|
||||||
<p>Please upgrade to a modern web browser such as the latest Firefox, Chrome, Edge, or Safari version 15 or newer.</p>
|
</body>
|
||||||
<p>(The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array#browser_compatibility" target="_blank"><code>BigInt64Array</code></a>
|
|
||||||
JavaScript API must be supported by the browser for Graphite to function.)</p>
|
|
||||||
`.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the editor application or display the incompatibility message
|
|
||||||
if (incompatibility) {
|
|
||||||
document.body.innerHTML += incompatibility;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="module" src="src/main.ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
28
frontend/package-lock.json
generated
28
frontend/package-lock.json
generated
|
@ -7,7 +7,8 @@
|
||||||
"name": "graphite-web-frontend",
|
"name": "graphite-web-frontend",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.2.0",
|
"@fontsource/inconsolata": "^5.2.5",
|
||||||
|
"@fontsource/source-sans-pro": "^5.2.5",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"reflect-metadata": "^0.2.2"
|
"reflect-metadata": "^0.2.2"
|
||||||
|
@ -555,6 +556,21 @@
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fontsource/inconsolata": {
|
||||||
|
"version": "5.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/inconsolata/-/inconsolata-5.2.5.tgz",
|
||||||
|
"integrity": "sha512-OvzkZY5qYghv/jEV6cfGZzFhdFTvSnU+ExPC7WcZ7w8PdRhtiu/SpcBWOBt+3LXgS0n9qyepgq4zZmxlDTlGGQ==",
|
||||||
|
"license": "OFL-1.1",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ayuhito"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fontsource/source-sans-pro": {
|
||||||
|
"version": "5.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/source-sans-pro/-/source-sans-pro-5.2.5.tgz",
|
||||||
|
"integrity": "sha512-ypendqc4pYUc+EgF7qqPY9iVYEz1t/Qr03VojKxG/2g3dnpHa1B6DOlDxWQjQXDj5QrG6inEqGT0g+edjALZyg==",
|
||||||
|
"license": "OFL-1.1"
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.13.0",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||||
|
@ -1050,16 +1066,6 @@
|
||||||
"vite": "^5.0.0"
|
"vite": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/api": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==",
|
|
||||||
"license": "Apache-2.0 OR MIT",
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/tauri"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@tsconfig/node10": {
|
"node_modules/@tsconfig/node10": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
"wasm:watch-production": "cargo watch --postpone --watch-when-idle --workdir=wasm --shell \"wasm-pack build . --release --target=web -- --color=always\""
|
"wasm:watch-production": "cargo watch --postpone --watch-when-idle --workdir=wasm --shell \"wasm-pack build . --release --target=web -- --color=always\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource/inconsolata": "^5.2.5",
|
||||||
|
"@fontsource/source-sans-pro": "^5.2.5",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"reflect-metadata": "^0.2.2"
|
"reflect-metadata": "^0.2.2"
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
// This file is the browser's entry point for the JS bundle
|
// This file is the browser's entry point for the JS bundle
|
||||||
|
|
||||||
// reflect-metadata allows for runtime reflection of types in JavaScript.
|
// Fonts
|
||||||
|
import "@fontsource/inconsolata";
|
||||||
|
import "@fontsource/source-sans-pro/400-italic.css";
|
||||||
|
import "@fontsource/source-sans-pro/400.css";
|
||||||
|
import "@fontsource/source-sans-pro/700-italic.css";
|
||||||
|
import "@fontsource/source-sans-pro/700.css";
|
||||||
|
|
||||||
|
// `reflect-metadata` allows for runtime reflection of types in JavaScript.
|
||||||
// It is needed for class-transformer to work and is imported as a side effect.
|
// It is needed for class-transformer to work and is imported as a side effect.
|
||||||
// The library replaces the Reflect API on the window to support more features.
|
// The library replaces the Reflect API on the window to support more features.
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
|
|
|
@ -9,11 +9,13 @@ module.exports = {
|
||||||
ecmaVersion: 2020,
|
ecmaVersion: 2020,
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
// JS defaults
|
"eslint:recommended",
|
||||||
"airbnb-base",
|
"plugin:import/recommended",
|
||||||
// General Prettier defaults
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:import/typescript",
|
||||||
"prettier",
|
"prettier",
|
||||||
],
|
],
|
||||||
|
plugins: ["import", "@typescript-eslint", "prettier"],
|
||||||
settings: {
|
settings: {
|
||||||
// https://github.com/import-js/eslint-plugin-import#resolvers
|
// https://github.com/import-js/eslint-plugin-import#resolvers
|
||||||
"import/resolver": {
|
"import/resolver": {
|
||||||
|
@ -30,7 +32,6 @@ module.exports = {
|
||||||
"!.*.js",
|
"!.*.js",
|
||||||
"!.*.ts",
|
"!.*.ts",
|
||||||
],
|
],
|
||||||
plugins: ["prettier"],
|
|
||||||
rules: {
|
rules: {
|
||||||
// Standard ESLint config
|
// Standard ESLint config
|
||||||
indent: "off",
|
indent: "off",
|
||||||
|
|
2
website/.gitignore
vendored
2
website/.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
public/
|
public/
|
||||||
|
static/fonts/
|
||||||
static/syntax-highlighting.css
|
static/syntax-highlighting.css
|
||||||
|
static/text-balancer.js
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
title = "Graphite"
|
|
||||||
description = "2D raster & vector editor that melds traditional layers & tools with a modern node-based procedural workflow."
|
|
||||||
base_url = "https://graphite.rs"
|
|
||||||
feed_filenames = ["rss.xml"]
|
|
||||||
|
|
||||||
compile_sass = true
|
|
||||||
minify_html = true
|
|
||||||
|
|
||||||
[markdown]
|
|
||||||
highlight_code = true
|
|
||||||
highlight_theme = "css"
|
|
||||||
highlight_themes_css = [
|
|
||||||
{ theme = "kronuz", filename = "syntax-highlighting.css" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[extra]
|
|
||||||
# Put all your custom variables here
|
|
|
@ -3,12 +3,14 @@ title = "Free online vector editor & procedural design tool"
|
||||||
template = "section.html"
|
template = "section.html"
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
css = ["/page/index.css", "/component/carousel.css", "/component/feature-icons.css", "/component/feature-box.css", "/component/youtube-embed.css", "/layout/balance-text.css"]
|
css = ["/page/index.css", "/component/carousel.css", "/component/feature-icons.css", "/component/feature-box.css", "/component/youtube-embed.css"]
|
||||||
js = ["/js/carousel.js", "/js/youtube-embed.js", "/js/video-autoplay.js"]
|
js = ["/js/carousel.js", "/js/youtube-embed.js", "/js/video-autoplay.js"]
|
||||||
linked_js = ["https://static.graphite.rs/text-balancer/text-balancer.js"]
|
linked_js = []
|
||||||
meta_description = "Open source free software. A vector graphics creativity suite with a clean, intuitive interface. Opens instantly (no signup) and runs locally in a browser. Exports SVG, PNG, JPG."
|
meta_description = "Open source free software. A vector graphics creativity suite with a clean, intuitive interface. Opens instantly (no signup) and runs locally in a browser. Exports SVG, PNG, JPG."
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
<!-- replacements::text_balancer() -->
|
||||||
|
|
||||||
<!-- ▛ LOGO ▜ -->
|
<!-- ▛ LOGO ▜ -->
|
||||||
<section id="logo">
|
<section id="logo">
|
||||||
<div class="block">
|
<div class="block">
|
||||||
|
|
|
@ -3,7 +3,6 @@ title = "About Graphite"
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
css = ["/page/about.css", "/component/feature-box.css"]
|
css = ["/page/about.css", "/component/feature-box.css"]
|
||||||
linked_css = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"]
|
|
||||||
+++
|
+++
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
@ -117,7 +116,7 @@ It's easy to learn and teach, yet Graphite's accessible design does not sacrific
|
||||||
|
|
||||||
<img src="https://static.graphite.rs/content/about/core-team-photo-keavon-chambers.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Keavon Chambers" />
|
<img src="https://static.graphite.rs/content/about/core-team-photo-keavon-chambers.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Keavon Chambers" />
|
||||||
|
|
||||||
## Keavon Chambers <span class="handle">(@Keavon)</span> <span class="flag" title="American">🇺🇸</span>
|
## Keavon Chambers <span class="handle">(@Keavon)</span> <img src="https://static.graphite.rs/icons/flags/us.png" class="flag" title="American" />
|
||||||
|
|
||||||
***Founder, UI & product design, frontend, editor systems***
|
***Founder, UI & product design, frontend, editor systems***
|
||||||
|
|
||||||
|
@ -128,7 +127,7 @@ Keavon is a creative generalist with a love for the fusion of arts and technolog
|
||||||
|
|
||||||
<img src="https://static.graphite.rs/content/about/core-team-photo-dennis-kobert.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Dennis Kobert" />
|
<img src="https://static.graphite.rs/content/about/core-team-photo-dennis-kobert.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Dennis Kobert" />
|
||||||
|
|
||||||
## Dennis Kobert <span class="handle">(@TrueDoctor)</span> <span class="flag" title="German">🇩🇪</span>
|
## Dennis Kobert <span class="handle">(@TrueDoctor)</span> <img src="https://static.graphite.rs/icons/flags/de.png" class="flag" title="German" />
|
||||||
|
|
||||||
***Graphene node engine, research, architecture***
|
***Graphene node engine, research, architecture***
|
||||||
|
|
||||||
|
@ -143,7 +142,7 @@ Dennis is a mix between a mathematician and a mad scientist. While still enjoyin
|
||||||
|
|
||||||
<img src="https://static.graphite.rs/content/about/core-team-photo-hypercube__2.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Hypercube" />
|
<img src="https://static.graphite.rs/content/about/core-team-photo-hypercube__2.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Hypercube" />
|
||||||
|
|
||||||
## "Hypercube" <span class="handle">(@0Hypercube)</span> <span class="flag" title="British">🇬🇧</span>
|
## "Hypercube" <span class="handle">(@0Hypercube)</span> <img src="https://static.graphite.rs/icons/flags/gb.png" class="flag" title="British" />
|
||||||
|
|
||||||
***Editor systems, nodes, tools, architecture***
|
***Editor systems, nodes, tools, architecture***
|
||||||
|
|
||||||
|
@ -155,7 +154,7 @@ Dennis is a mix between a mathematician and a mad scientist. While still enjoyin
|
||||||
|
|
||||||
<img src="https://static.graphite.rs/content/about/core-team-photo-adam-gerhant.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Adam Gerhant" />
|
<img src="https://static.graphite.rs/content/about/core-team-photo-adam-gerhant.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Photo of Adam Gerhant" />
|
||||||
|
|
||||||
## Adam Gerhant <span class="handle">(@pendapia)</span> <span class="flag" title="American">🇺🇸</span>
|
## Adam Gerhant <span class="handle">(@pendapia)</span> <img src="https://static.graphite.rs/icons/flags/us.png" class="flag" title="American" />
|
||||||
|
|
||||||
***Editor graph tooling, node data formats***
|
***Editor graph tooling, node data formats***
|
||||||
|
|
||||||
|
|
|
@ -145,17 +145,21 @@ Always on the bleeding edge and built to last— Graphite is written on a robust
|
||||||
<img class="atlas" style="--atlas-index: 7" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 7" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>Desktop app (Windows, Mac, Linux)</span>
|
<span>Desktop app (Windows, Mac, Linux)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon ongoing">
|
<div class="feature-icon ongoing" title="Development Ongoing">
|
||||||
<img class="atlas" style="--atlas-index: 40" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 40" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>Simplified main properties panel</span>
|
<span>Simplified main properties panel</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="feature-icon ongoing" title="Development Ongoing">
|
||||||
<img class="atlas" style="--atlas-index: 12" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 12" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>GPU-accelerated raster rendering</span>
|
<span>GPU-accelerated raster rendering</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<img class="atlas" style="--atlas-index: 14" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 14" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>Infinitely zoomable/panable content</span>
|
<span>Infinitely zoomable/panable raster</span>
|
||||||
|
</div>
|
||||||
|
<div class="feature-icon">
|
||||||
|
<img class="atlas" style="--atlas-index: 21" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
|
<span>Select mode (marquee masking)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<img class="atlas" style="--atlas-index: 41" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 41" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
|
@ -171,7 +175,7 @@ Always on the bleeding edge and built to last— Graphite is written on a robust
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<img class="atlas" style="--atlas-index: 57" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 57" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>Signed distance fields</span>
|
<span>Signed distance field rendering</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<img class="atlas" style="--atlas-index: 56" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 56" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
|
@ -181,10 +185,6 @@ Always on the bleeding edge and built to last— Graphite is written on a robust
|
||||||
<img class="atlas" style="--atlas-index: 52" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 52" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>Command palette and context menus</span>
|
<span>Command palette and context menus</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
|
||||||
<img class="atlas" style="--atlas-index: 21" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
|
||||||
<span>Select mode (marquee masking)</span>
|
|
||||||
</div>
|
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<img class="atlas" style="--atlas-index: 53" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
<img class="atlas" style="--atlas-index: 53" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
|
||||||
<span>Local fonts access</span>
|
<span>Local fonts access</span>
|
||||||
|
|
194
website/install-fonts.js
Normal file
194
website/install-fonts.js
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const https = require("https");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
// Define basePath
|
||||||
|
const basePath = path.resolve(__dirname);
|
||||||
|
|
||||||
|
// Define files to copy as [source, destination] pairs
|
||||||
|
// Files with the same destination will be concatenated
|
||||||
|
const FILES_TO_COPY = [
|
||||||
|
["node_modules/@fontsource-variable/inter/opsz.css", "static/fonts/common.css"],
|
||||||
|
["node_modules/@fontsource-variable/inter/opsz-italic.css", "static/fonts/common.css"],
|
||||||
|
["node_modules/@fontsource/bona-nova/700.css", "static/fonts/common.css"],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Define directories to copy recursively as [source, destination] pairs
|
||||||
|
const DIRECTORIES_TO_COPY = [
|
||||||
|
["node_modules/@fontsource-variable/inter/files", "static/fonts/files"],
|
||||||
|
["node_modules/@fontsource/bona-nova/files", "static/fonts/files"],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Track processed destination files and CSS content
|
||||||
|
const processedDestinations = new Set();
|
||||||
|
const cssDestinations = new Set();
|
||||||
|
const allCopiedFiles = new Set();
|
||||||
|
|
||||||
|
// Process each file
|
||||||
|
FILES_TO_COPY.forEach(([source, dest]) => {
|
||||||
|
// Convert relative paths to absolute paths
|
||||||
|
const sourcePath = path.join(basePath, source);
|
||||||
|
const destPath = path.join(basePath, dest);
|
||||||
|
|
||||||
|
// Track CSS destinations for later analysis
|
||||||
|
if (dest.endsWith(".css")) {
|
||||||
|
cssDestinations.add(destPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure destination directory exists
|
||||||
|
const destDir = path.dirname(destPath);
|
||||||
|
if (!fs.existsSync(destDir)) {
|
||||||
|
fs.mkdirSync(destDir, { recursive: true });
|
||||||
|
console.log(`Created directory: ${destDir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read source file content
|
||||||
|
const content = fs.readFileSync(sourcePath, "utf8");
|
||||||
|
|
||||||
|
// Check if destination has been processed before
|
||||||
|
if (processedDestinations.has(destPath)) {
|
||||||
|
// Append to existing file
|
||||||
|
fs.appendFileSync(destPath, "\n\n" + content);
|
||||||
|
console.log(`Appended: ${sourcePath} → ${destPath}`);
|
||||||
|
} else {
|
||||||
|
// First time writing to this destination - copy the file
|
||||||
|
fs.writeFileSync(destPath, content);
|
||||||
|
processedDestinations.add(destPath);
|
||||||
|
console.log(`Copied: ${sourcePath} → ${destPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all occurrences of "./files" with "/fonts" in the destination file
|
||||||
|
let destFileContent = fs.readFileSync(destPath, "utf8");
|
||||||
|
destFileContent = destFileContent.replaceAll("./files/", "/fonts/files/");
|
||||||
|
fs.writeFileSync(destPath, destFileContent);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error processing ${sourcePath} to ${destPath}:`, error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Function to recursively copy a directory
|
||||||
|
function copyDirectoryRecursive(source, destination) {
|
||||||
|
// Ensure destination directory exists
|
||||||
|
if (!fs.existsSync(destination)) {
|
||||||
|
fs.mkdirSync(destination, { recursive: true });
|
||||||
|
console.log(`Created directory: ${destination}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all items in the source directory
|
||||||
|
const items = fs.readdirSync(source);
|
||||||
|
|
||||||
|
// Process each item
|
||||||
|
items.forEach((item) => {
|
||||||
|
const sourcePath = path.join(source, item);
|
||||||
|
const destPath = path.join(destination, item);
|
||||||
|
|
||||||
|
// Check if item is a directory or file
|
||||||
|
const stats = fs.statSync(sourcePath);
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
// Recursively copy subdirectory
|
||||||
|
copyDirectoryRecursive(sourcePath, destPath);
|
||||||
|
} else {
|
||||||
|
// Copy file and track it
|
||||||
|
fs.copyFileSync(sourcePath, destPath);
|
||||||
|
allCopiedFiles.add(destPath);
|
||||||
|
console.log(`Copied: ${sourcePath} → ${destPath}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each directory
|
||||||
|
DIRECTORIES_TO_COPY.forEach(([source, dest]) => {
|
||||||
|
// Convert relative paths to absolute paths
|
||||||
|
const sourcePath = path.join(basePath, source);
|
||||||
|
const destPath = path.join(basePath, dest);
|
||||||
|
|
||||||
|
try {
|
||||||
|
copyDirectoryRecursive(sourcePath, destPath);
|
||||||
|
console.log(`Copied directory: ${sourcePath} → ${destPath}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error copying directory ${sourcePath} to ${destPath}:`, error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("All files and directories copied successfully!");
|
||||||
|
|
||||||
|
// Now check which of the copied files are actually referenced in CSS
|
||||||
|
console.log("\nChecking for unused font files...");
|
||||||
|
|
||||||
|
// Read all CSS content and join it
|
||||||
|
let allCssContent = "";
|
||||||
|
cssDestinations.forEach((cssPath) => {
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(cssPath, "utf8");
|
||||||
|
allCssContent += content;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error reading CSS file ${cssPath}:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter files that aren't referenced in CSS
|
||||||
|
const unusedFiles = [];
|
||||||
|
allCopiedFiles.forEach((filePath) => {
|
||||||
|
const fileName = path.basename(filePath);
|
||||||
|
|
||||||
|
// Check if the file name is mentioned in any CSS
|
||||||
|
if (!allCssContent.includes(fileName)) {
|
||||||
|
unusedFiles.push(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete unused files
|
||||||
|
if (unusedFiles.length > 0) {
|
||||||
|
console.log(`Found ${unusedFiles.length} unused font files to delete:`);
|
||||||
|
unusedFiles.forEach((filePath) => {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
console.log(`Deleted unused file: ${filePath}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error deleting file ${filePath}:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("No unused font files found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\nFont installation complete!");
|
||||||
|
|
||||||
|
// Fetch and save text-balancer.js, which we don't commit to the repo so we're not version controlling dependency code
|
||||||
|
const textBalancerUrl = "https://static.graphite.rs/text-balancer/text-balancer.js";
|
||||||
|
const textBalancerDest = path.join(basePath, "static", "text-balancer.js");
|
||||||
|
console.log("\nDownloading text-balancer.js...");
|
||||||
|
https
|
||||||
|
.get(textBalancerUrl, (res) => {
|
||||||
|
if (res.statusCode !== 200) {
|
||||||
|
console.error(`Failed to download text-balancer.js. Status code: ${res.statusCode}`);
|
||||||
|
res.resume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = "";
|
||||||
|
res.on("data", (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on("end", () => {
|
||||||
|
try {
|
||||||
|
// Ensure destination directory exists
|
||||||
|
const destDir = path.dirname(textBalancerDest);
|
||||||
|
if (!fs.existsSync(destDir)) {
|
||||||
|
fs.mkdirSync(destDir, { recursive: true });
|
||||||
|
console.log(`Created directory: ${destDir}`);
|
||||||
|
}
|
||||||
|
fs.writeFileSync(textBalancerDest, data, "utf8");
|
||||||
|
console.log(`Downloaded and saved: ${textBalancerDest}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error saving text-balancer.js:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.on("error", (err) => {
|
||||||
|
console.error(`Error downloading text-balancer.js:`, err);
|
||||||
|
});
|
|
@ -4,9 +4,7 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Bezier-rs Interactive Documentation</title>
|
<title>Bezier-rs Interactive Documentation</title>
|
||||||
<link rel="stylesheet" href="./style.css" />
|
<link rel="stylesheet" href="./style.css" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link href="fonts.css" rel="stylesheet" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Bona+Nova:wght@700&family=Inter:wght@500&display=swap" rel="stylesheet" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>JavaScript is required</noscript>
|
<noscript>JavaScript is required</noscript>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter Variable", sans-serif;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,6 @@ mkdir dist/libraries/bezier-rs
|
||||||
cd bezier-rs-demos
|
cd bezier-rs-demos
|
||||||
npm ci
|
npm ci
|
||||||
NODE_ENV=production npm run build
|
NODE_ENV=production npm run build
|
||||||
|
cp ../../static/fonts/common.css dist/fonts.css
|
||||||
mv dist/* ../dist/libraries/bezier-rs
|
mv dist/* ../dist/libraries/bezier-rs
|
||||||
cd ..
|
cd ..
|
||||||
|
|
1507
website/package-lock.json
generated
1507
website/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,6 @@
|
||||||
"name": "graphite-website",
|
"name": "graphite-website",
|
||||||
"description": "Graphite's website. This npm package is for dev tooling only, such as eslint.",
|
"description": "Graphite's website. This npm package is for dev tooling only, such as eslint.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {},
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/GraphiteEditor/Graphite.git"
|
"url": "git+https://github.com/GraphiteEditor/Graphite.git"
|
||||||
|
@ -10,15 +9,22 @@
|
||||||
"author": "Graphite Authors <contact@graphite.rs>",
|
"author": "Graphite Authors <contact@graphite.rs>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"homepage": "https://graphite.rs",
|
"homepage": "https://graphite.rs",
|
||||||
|
"scripts": {
|
||||||
|
"install-fonts": "npm ci && node install-fonts.js"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
||||||
"@typescript-eslint/parser": "^8.7.0",
|
"@typescript-eslint/parser": "^8.7.0",
|
||||||
"eslint": "^9.11.1",
|
"eslint": "^9.11.1",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-import-resolver-typescript": "^3.6.3",
|
||||||
"eslint-plugin-import": "^2.30.0",
|
"eslint-plugin-import": "^2.30.0",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"sass": "^1.78.0"
|
"sass": "1.78.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fontsource-variable/inter": "^5.2.5",
|
||||||
|
"@fontsource/bona-nova": "^5.2.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ html,
|
||||||
body {
|
body {
|
||||||
color: var(--color-navy);
|
color: var(--color-navy);
|
||||||
background: white;
|
background: white;
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter Variable", sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
@ -157,12 +157,12 @@ body > .page {
|
||||||
background-image: url('data:image/svg+xml;utf8,\
|
background-image: url('data:image/svg+xml;utf8,\
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M8,15C5.12471,9.753694 0.5,8.795225 0.5,4.736524 C0.5,-0.507473 7.468734,0 8,4.967381 C8.531266,0 15.5,-0.507473 15.5,4.736524 C15.5,8.795225 10.87529,9.753694 8,15z" fill="%23cc304f" /></svg>\
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M8,15C5.12471,9.753694 0.5,8.795225 0.5,4.736524 C0.5,-0.507473 7.468734,0 8,4.967381 C8.531266,0 15.5,-0.507473 15.5,4.736524 C15.5,8.795225 10.87529,9.753694 8,15z" fill="%23cc304f" /></svg>\
|
||||||
');
|
');
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 0.75em;
|
width: 0.75em;
|
||||||
height: 0.75em;
|
height: 0.75em;
|
||||||
margin-left: 0.25em;
|
margin-left: 0.25em;
|
||||||
margin-bottom: -0.1em;
|
margin-bottom: -0.1em;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,6 @@ body > .page {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
details[open] summary::before {
|
details[open] summary::before {
|
||||||
|
@ -436,7 +435,7 @@ h3,
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter Variable", sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -663,7 +662,7 @@ hr,
|
||||||
|
|
||||||
.arrow::after {
|
.arrow::after {
|
||||||
content: " »";
|
content: " »";
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter Variable", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-background {
|
.video-background {
|
||||||
|
|
|
@ -38,7 +38,7 @@ pre {
|
||||||
content: attr(data-lang);
|
content: attr(data-lang);
|
||||||
color: rgba(var(--color-seaside-rgb), 0.5);
|
color: rgba(var(--color-seaside-rgb), 0.5);
|
||||||
text-transform: lowercase;
|
text-transform: lowercase;
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter Variable", sans-serif;
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
h1.feature-box-header.feature-box-header {
|
h1.feature-box-header.feature-box-header {
|
||||||
&,
|
&,
|
||||||
& a {
|
& a {
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter Variable", sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
// CSS component of the JS text balancer script.
|
|
||||||
// This must be loaded as an inline stylesheet in the head of the
|
|
||||||
// document to avoid the possibility of a visible layout shift.
|
|
||||||
|
|
||||||
.balance-text {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (scripting: none) {
|
|
||||||
.balance-text {
|
|
||||||
visibility: visible !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@supports (text-wrap: balance) {
|
|
||||||
.balance-text,
|
|
||||||
.balanced-text {
|
|
||||||
text-align: left;
|
|
||||||
text-wrap: balance;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,8 +5,12 @@
|
||||||
animation: fadeInAfterWait 2s ease-in 2s forwards;
|
animation: fadeInAfterWait 2s ease-in 2s forwards;
|
||||||
|
|
||||||
@keyframes fadeInAfterWait {
|
@keyframes fadeInAfterWait {
|
||||||
0% { opacity: 0; }
|
0% {
|
||||||
100% { opacity: 1; }
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,11 +38,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.flag {
|
.flag {
|
||||||
font-family: "Noto Color Emoji", sans-serif;
|
width: 1em;
|
||||||
font-style: normal;
|
height: 1em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
font-size: 0.8em;
|
|
||||||
cursor: default;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{%- if not page.summary -%}
|
{%- if not page.summary -%}
|
||||||
{{ throw(message = "ARTICLE HAS NO SUMMARY! After the first paragraph (or two short ones), a `<!-- more -->` comment must be inserted in the markdown. Otherwise the blog page would be missing its preview text." | safe) }}
|
{{ throw(message = "------------------------------------------------------------> ARTICLE HAS NO SUMMARY! After the first paragraph (or two short ones), a `<!-- more -->` comment must be inserted in the markdown. Otherwise the blog page would be missing its preview text." | safe) }}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{%- endblock content -%}
|
{%- endblock content -%}
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,19 @@
|
||||||
{% block rss -%}
|
{% block rss -%}
|
||||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="{{ get_url(path = 'blog/rss.xml', trailing_slash = false) | safe }}" />
|
<link rel="alternate" type="application/rss+xml" title="RSS" href="{{ get_url(path = 'blog/rss.xml', trailing_slash = false) | safe }}" />
|
||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
||||||
|
|
||||||
|
{#- ======================================================================== -#}
|
||||||
|
|
||||||
{#- ON EVERY PAGE OF THE SITE: CSS AND JS TO LOAD EITHER AS A LINK OR INLINE -#}
|
{#- ON EVERY PAGE OF THE SITE: CSS AND JS TO LOAD EITHER AS A LINK OR INLINE -#}
|
||||||
{#- ======================================================================== -#}
|
{#- ======================================================================== -#}
|
||||||
{%- set global_linked_css = ["https://fonts.googleapis.com/css2?family=Bona+Nova:wght@700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"] -%}
|
|
||||||
{%- set global_linked_js = [] -%}
|
{%- set global_linked_js = [] -%}
|
||||||
{%- set global_css = ["/base.css"] -%}
|
{%- set global_linked_css = [] -%}
|
||||||
{%- set global_js = ["/js/text-justification.js", "/js/navbar.js"] -%}
|
{%- set global_js = ["/js/text-justification.js", "/js/navbar.js"] -%}
|
||||||
|
{%- set global_css = ["/base.css", "/fonts/common.css"] -%}
|
||||||
|
{%- set fonts_loaded = load_data(path="static/fonts/common.css", format="plain", required=false) -%}
|
||||||
|
{%- if not fonts_loaded -%}
|
||||||
|
{{ throw(message="------------------------------------------------------------> FONTS ARE NOT INSTALLED! Before running Zola, execute `npm run install-fonts` from the `/website` directory.") }}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
{#- RETRIEVE FROM TEMPLATES AND PAGES: CSS AND JS TO LOAD EITHER AS A LINK OR INLINE -#}
|
{#- RETRIEVE FROM TEMPLATES AND PAGES: CSS AND JS TO LOAD EITHER AS A LINK OR INLINE -#}
|
||||||
{#- ================================================================================ -#}
|
{#- ================================================================================ -#}
|
||||||
|
@ -89,6 +93,7 @@
|
||||||
{{ load_data(path = path) | safe }}
|
{{ load_data(path = path) | safe }}
|
||||||
{{ "</" ~ "script>" | safe }}
|
{{ "</" ~ "script>" | safe }}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
|
||||||
{{- get_env(name = "INDEX_HTML_HEAD_INCLUSION", default = "") | safe }}
|
{{- get_env(name = "INDEX_HTML_HEAD_INCLUSION", default = "") | safe }}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -119,8 +124,10 @@
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
{%- filter replace(from = "<!-- replacements::blog_posts(count = 2) -->", to = replacements::blog_posts(count = 2)) -%}
|
{%- filter replace(from = "<!-- replacements::blog_posts(count = 2) -->", to = replacements::blog_posts(count = 2)) -%}
|
||||||
|
{%- filter replace(from = "<!-- replacements::text_balancer() -->", to = replacements::text_balancer()) -%}
|
||||||
{%- block content -%}{%- endblock -%}
|
{%- block content -%}{%- endblock -%}
|
||||||
{%- endfilter -%}
|
{%- endfilter -%}
|
||||||
|
{%- endfilter -%}
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -12,3 +12,29 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endmacro blog_posts %}
|
{% endmacro blog_posts %}
|
||||||
|
|
||||||
|
{% macro text_balancer() %}
|
||||||
|
<style>
|
||||||
|
.balance-text {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (scripting: none) {
|
||||||
|
.balance-text {
|
||||||
|
visibility: visible !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports (text-wrap: balance) {
|
||||||
|
.balance-text,
|
||||||
|
.balanced-text {
|
||||||
|
text-align: left;
|
||||||
|
text-wrap: balance;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
{{ load_data(path="static/text-balancer.js", format="plain") | safe }}
|
||||||
|
</script>
|
||||||
|
{% endmacro text_balancer %}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue