More website loading speed and code improvements

This commit is contained in:
Keavon Chambers 2025-01-08 20:49:42 -08:00
parent 68e6bec9b5
commit ae2637e08e
44 changed files with 833 additions and 898 deletions

View File

@ -3,7 +3,7 @@ title = "Free online vector editor & procedural design tool"
template = "section.html"
[extra]
css = ["/index.css", "/balance-text.css"]
css = ["/page/index.css", "/component/carousel.css", "/component/feature-icons.css", "/component/feature-box.css", "/component/youtube-embed.css", "/layout/balance-text.css"]
js = ["/js/carousel.js", "/js/youtube-embed.js", "/js/video-autoplay.js"]
linked_js = ["https://static.graphite.rs/text-balancer/text-balancer.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."
@ -456,8 +456,8 @@ Get started with Graphite by following along to a hands-on quickstart tutorial.
<div class="block video-container">
<div>
<div class="video-embed aspect-16x9">
<img data-video-embed="7gjUhl_3X10" loading="lazy" src="https://static.graphite.rs/content/index/tutorial-1-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
<div class="youtube-embed aspect-16x9">
<img data-youtube-embed="7gjUhl_3X10" loading="lazy" src="https://static.graphite.rs/content/index/tutorial-1-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
</div>
</div>
</div>
@ -493,8 +493,8 @@ Get started with Graphite by following along to a hands-on quickstart tutorial.
<section id="demo-video">
<div class="block">
Watch this timelapse showing the process of mixing traditional vector art (tracing a physical sketch and colorizing it, first two minutes) with using Imaginate to generate a background (last 45 seconds).
<div class="video-embed aspect-16x9">
<img data-video-embed="JgJvAHQLnXA" src="https://static.graphite.rs/content/index/commander-basstronaut-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite - Vector Editing: &quot;Commander Basstronaut&quot; Artwork (25x Timelapse)" />
<div class="youtube-embed aspect-16x9">
<img data-youtube-embed="JgJvAHQLnXA" src="https://static.graphite.rs/content/index/commander-basstronaut-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite - Vector Editing: &quot;Commander Basstronaut&quot; Artwork (25x Timelapse)" />
</div>
(Recorded in an older version of Graphite from early 2023.)
</div>

View File

@ -2,7 +2,7 @@
title = "About Graphite"
[extra]
css = ["/about.css"]
css = ["/page/about.css", "/component/feature-box.css"]
linked_css = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"]
+++
@ -117,7 +117,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" />
## Keavon Chambers <span class="handle">(@Keavon)</span> <span class="emoji" title="American">🇺🇸</span>
## Keavon Chambers <span class="handle">(@Keavon)</span> <span class="flag" title="American">🇺🇸</span>
***Founder, UI & product design, frontend, editor systems***
@ -128,7 +128,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" />
## Dennis Kobert <span class="handle">(@TrueDoctor)</span> <span class="emoji" title="German">🇩🇪</span>
## Dennis Kobert <span class="handle">(@TrueDoctor)</span> <span class="flag" title="German">🇩🇪</span>
***Graphene node engine, research, architecture***
@ -143,7 +143,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" />
## "Hypercube" <span class="handle">(@0Hypercube)</span> <span class="emoji" title="British">🇬🇧</span>
## "Hypercube" <span class="handle">(@0Hypercube)</span> <span class="flag" title="British">🇬🇧</span>
***Editor systems, nodes, tools, architecture***
@ -155,7 +155,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" />
## Adam Gerhant <span class="handle">(@pendapia)</span> <span class="emoji" title="American">🇺🇸</span>
## Adam Gerhant <span class="handle">(@pendapia)</span> <span class="flag" title="American">🇺🇸</span>
***Editor graph tooling, node data formats***

View File

@ -11,6 +11,7 @@ reddit = "https://www.reddit.com/r/graphite/comments/18xmoti/blog_post_looking_b
twitter = "https://twitter.com/GraphiteEditor/status/1742576805532577937"
js = ["/js/youtube-embed.js"]
css = ["/component/youtube-embed.css"]
+++
The new year is here, and with so many accomplishments to share from the past twelve months, let's revisit the highlights of 2023 for the Graphite project. Now that winter has entered, let's swing back to the spring, summarize the summer, and follow this fall's noteworthy developments that brought another year of fruitful progress to Graphite's mission of re-envisioning artists' 2D creative workflows with the best free software we can build for the open source community. This past year as a team, we all got closer— to one another from continents apart; to visiting and connecting with our industry peers; and to reaching exciting new development milestones.
@ -92,8 +93,8 @@ The next big news of August was my formation of [Graphite Labs, LLC](https://www
I allocated my time at several points throughout the year into growing and evolving this website with a refreshed and more visually-appealing home page, dedicated pages for information [about](/about) the project and its [features](/features), an area providing resources and help for [volunteers](/volunteer) and [code contributors](/volunteer/guide), and just this month— a [user manual](/learn) complete with an introductory tutorial series. The first video went up yesterday:
<div class="video-embed aspect-16x9">
<img data-video-embed="7gjUhl_3X10" src="https://static.graphite.rs/content/learn/introduction/tutorial-1-vector-art-quickstart-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
<div class="youtube-embed aspect-16x9">
<img data-youtube-embed="7gjUhl_3X10" src="https://static.graphite.rs/content/learn/introduction/tutorial-1-vector-art-quickstart-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
</div>
The user manual and tutorial series will continue expanding throughout the coming weeks. Additional website features including user accounts, forums, and other community features are being planned.

View File

@ -8,6 +8,7 @@ author = "Keavon Chambers & Hypercube"
summary = "Graphite's Q1 2024 update introduces a precise snapping system and a customizable grid for enhanced design control. The update also includes improved procedural scattering with the 'Copy to Points' node, demonstrated in new demo artwork."
reddit = "https://www.reddit.com/r/graphite/comments/1coa0if/blog_post_graphite_progress_report_q1_2024/"
twitter = "https://twitter.com/GraphiteEditor/status/1788698448348266946"
css = ["/component/demo-artwork.css"]
+++
[Graphite](/) is a new 2D vector graphics editor bringing a modern, nondestructive approach to creative workflows with node-based procedural generation. The project is currently three years into development, with a focus on streamlining the creative process for procedural vector artwork. See the [roadmap](/features#roadmap) for a more in-depth summary of the goals for 2024 and beyond.

View File

@ -8,6 +8,7 @@ author = "Keavon Chambers & Hypercube"
summary = "Graphite's Q2 2024 update introduces boolean path operations, a new gradient picker, layer locking, and more improvements."
reddit = "https://www.reddit.com/r/graphite/comments/1ei9ps2/blog_post_graphite_progress_report_q2_2024/"
twitter = "https://x.com/GraphiteEditor/status/1819360794028462569"
css = ["/component/demo-artwork.css"]
+++
[Graphite](/), a new open source 2D procedural graphics editor, has spent AprilJune introducing **boolean path operations, a new gradient picker, layer locking**, and more improvements.

View File

@ -8,6 +8,7 @@ author = "Keavon Chambers & Hypercube"
summary = "Graphite's Q3 2024 update introduces improvements to performance, node graph organization, nondestructive path editing, a new render engine, and more helpful nodes."
reddit = "https://www.reddit.com/r/graphite/comments/1g4h6ya/blog_post_graphite_progress_report_q3_2024/"
twitter = "https://x.com/GraphiteEditor/status/1846283664562573344"
css = ["/component/demo-artwork.css"]
+++
[Graphite](/), a new open source 2D procedural graphics editor, has spent JulySeptember building major improvements to **performance, node graph organization, nondestructive path editing, a new render engine, and more helpful nodes**, amongst over 100 other features and fixes.

View File

@ -1,5 +1,8 @@
+++
title = "Contact the team"
[extra]
css = ["/layout/reading-material.css"]
+++
<section class="reading-material">

View File

@ -2,7 +2,7 @@
title = "Donate"
[extra]
# css = ["/donate.css", "/balance-text.css"]
# css = ["/page/donate.css", "/component/feature-box.css", "/layout/balance-text.css"]
# js = ["/js/fundraising.js"]
# linked_js = ["https://static.graphite.rs/text-balancer/text-balancer.js"]
+++

View File

@ -2,7 +2,7 @@
title = "Graphite features"
[extra]
css = ["/features.css"]
css = ["/page/features.css", "/component/feature-box.css", "/component/feature-icons.css"]
+++
<section>

View File

@ -6,6 +6,7 @@ page_template = "book.html"
[extra]
book = true
js = ["/js/youtube-embed.js"]
css = ["/component/youtube-embed.css"]
+++
Welcome to the Graphite user manual. Keep reading to to learn how the software can help bring your 2D creative ideas to life.
@ -26,6 +27,6 @@ If you're ever stuck or confused, ask your questions in the `#🧭user-help` cha
The fastest way to get started is to watch and follow along steps-by-step in the hands-on quickstart video:
<div class="video-embed aspect-16x9">
<img data-video-embed="7gjUhl_3X10" src="https://static.graphite.rs/content/learn/introduction/tutorial-1-vector-art-quickstart-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
<div class="youtube-embed aspect-16x9">
<img data-youtube-embed="7gjUhl_3X10" src="https://static.graphite.rs/content/learn/introduction/tutorial-1-vector-art-quickstart-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
</div>

View File

@ -4,6 +4,7 @@ title = "Imaginate"
[extra]
order = 2
js = ["/js/carousel.js"]
css = ["/component/carousel.css"]
+++
Imaginate is a useful tool at every stage in the artistic process. Early on it provides inspiration for styles, color palettes, subjects, and composition. It lets you quickly test ideas and explore artistic directions. It's also a useful way to generate placeholder images and content for kit bashing.

View File

@ -6,6 +6,7 @@ page_template = "book.html"
[extra]
order = 1
js = ["/js/youtube-embed.js"]
css = ["/component/youtube-embed.css"]
+++
<!-- Before taking the time to read the coming chapters, let's build some context by jumping straight into a small project that you can follow along with. That way you will have a mental framework for the topics explained in the rest of this manual. -->
@ -20,8 +21,8 @@ One is available now, and more will be released on a regular basis throughout ea
<!-- You can follow along with this starter project either by watching the tutorial video or referencing the step-by-step breakdown. -->
<div class="video-embed aspect-16x9">
<img data-video-embed="7gjUhl_3X10" src="https://static.graphite.rs/content/learn/introduction/tutorial-1-vector-art-quickstart-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
<div class="youtube-embed aspect-16x9">
<img data-youtube-embed="7gjUhl_3X10" src="https://static.graphite.rs/content/learn/introduction/tutorial-1-vector-art-quickstart-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphite Tutorial 1 - Hands-On Quickstart" />
</div>
### Video 2

View File

@ -1,5 +1,8 @@
+++
title = "Graphite license"
[extra]
css = ["/layout/reading-material.css"]
+++
<section class="reading-material">

View File

@ -2,7 +2,7 @@
title = "Graphite logo"
[extra]
css = ["/logo.css"]
css = ["/page/logo.css", "/component/feature-box.css", "/layout/reading-material.css"]
+++
<section class="reading-material">
@ -40,8 +40,6 @@ Download the complete [logo kit](https://static.graphite.rs/logos/graphite-logo-
</div>
</section>
<br />
<section class="feature-box-outer logo-view color">
<div class="feature-box-inner">
<div>

View File

@ -1,5 +1,8 @@
+++
title = "Press resources"
[extra]
css = ["/layout/reading-material.css"]
+++
<section class="reading-material">

View File

@ -2,8 +2,7 @@
title = "Volunteer"
[extra]
css = ["/volunteer.css"]
linked_css = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"]
css = ["/page/volunteer.css", "/component/feature-box.css"]
+++
<section>
@ -62,7 +61,7 @@ The Graphite editor is built much like a game engine, split across user interfac
<img src="https://static.graphite.rs/content/volunteer/creative-contributions.avif" class="feature-box-full-image" style="aspect-ratio: 3/1 auto; background: var(--color-lemon)" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.jpg')" alt="Flavor graphic depicting a fountain pen, ink pots, and a book" />
</a>
Assign yourself the *"<span class="emoji">🙌</span> Interested in helping with art or marketing"* role in the *#welcome* Discord channel. Then mention your experience and how you'd like to help in the *#introductions* channel.
Assign yourself the *"🙌 Interested in helping with art or marketing"* role in the *#welcome* Discord channel. Then mention your experience and how you'd like to help in the *#introductions* channel.
<a href="https://discord.graphite.rs" class="button arrow">Volunteer on Discord</a>
@ -97,7 +96,7 @@ Help write, edit, and design content for this website, social media, newsletters
<img src="https://static.graphite.rs/content/volunteer/user-contributions.avif" class="feature-box-full-image" style="aspect-ratio: 3/1 auto; background: var(--color-lilac)" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.jpg')" alt="Flavor graphic depicting a magnifying glass on the search for a software bug" />
Assign yourself the *"<span class="emoji">🐒</span> Volunteer to get pinged regularly for QA testing"* or *"<span class="emoji">🤖</span> Interested in contributing code"* roles in the *#welcome* Discord channel. In the latter case, drop by the *#development* channel to get advice writing your first node.
Assign yourself the *"🐒 Volunteer to get pinged regularly for QA testing"* or *"🤖 Interested in contributing code"* roles in the *#welcome* Discord channel. In the latter case, drop by the *#development* channel to get advice writing your first node.
<a href="https://discord.graphite.rs" class="button arrow">Volunteer on Discord</a>

View File

@ -6,12 +6,11 @@ aliases = ["/contribute"]
[extra]
book = true
linked_css = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"]
+++
Welcome, potential contributor! We're excited to have you join the Graphite project and it's our goal to make the process as smooth as possible. This guide will serve as your library of knowledge to help you get started contributing to the project. If you find any information missing or unclear, please let us know through Discord or submit a pull request to help document the process for future contributors.
The next page will cover how to compile the Graphite source code. But first, make sure you've joined our [Discord server](https://discord.graphite.rs) and assigned yourself the *"<span class="emoji">🤖</span> Interested in contributing code"* role from the `#🙂welcome` channel. Done that? Alright, proceed!
The next page will cover how to compile the Graphite source code. But first, make sure you've joined our [Discord server](https://discord.graphite.rs) and assigned yourself the *"🤖 Interested in contributing code"* role from the `#🙂welcome` channel. Done that? Alright, proceed!
<p>
<img src="https://static.graphite.rs/content/volunteer/code-contributions.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.jpg')" alt="Flavor graphic depicting a library of knowledge in a digital realm" />

View File

@ -6,12 +6,13 @@ page_template = "book.html"
[extra]
order = 2 # Chapter number
js = ["/js/youtube-embed.js"]
css = ["/component/youtube-embed.css"]
+++
The best introduction for getting up-to-speed with Graphite contribution comes from watching this webcast recording. Before asking questions in Discord, please watch the full video because it gives a comprehensive overview of most things you will need to know.
<div class="video-embed aspect-16x9">
<img data-video-embed="vUzIeg8frh4" src="https://static.graphite.rs/content/volunteer/guide/workshop-intro-to-coding-for-graphite-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Workshop: Intro to Coding for Graphite" />
<div class="youtube-embed aspect-16x9">
<img data-youtube-embed="vUzIeg8frh4" src="https://static.graphite.rs/content/volunteer/guide/workshop-intro-to-coding-for-graphite-youtube.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Workshop: Intro to Coding for Graphite" />
</div>
<!-- ## Tech stack -->

View File

@ -7,7 +7,7 @@ page_template = "book.html"
order = 3 # Chapter number
+++
There are two places to look for beginner-friendly development tasks. Usually, the best option is to select one of the many bite-sized task descriptions marked with a <span class="emoji">‼️</span> reaction in the `#✅code-todo-list` channel of the [Discord server](https://discord.graphite.rs). You may also browse the [task board](https://github.com/orgs/GraphiteEditor/projects/1/views/1), which lists [beginner issues](https://github.com/orgs/GraphiteEditor/projects/1/views/6) to pick from. The Discord option usually has the more approachable tasks compared to the GitHub issues, which tend to have more variability in complexity.
There are two places to look for beginner-friendly development tasks. Usually, the best option is to select one of the many bite-sized task descriptions marked with a ‼️ reaction in the `#✅code-todo-list` channel of the [Discord server](https://discord.graphite.rs). You may also browse the [task board](https://github.com/orgs/GraphiteEditor/projects/1/views/1), which lists [beginner issues](https://github.com/orgs/GraphiteEditor/projects/1/views/6) to pick from. The Discord option usually has the more approachable tasks compared to the GitHub issues, which tend to have more variability in complexity.
If you're unsure about which task to pick, feel free to ask in the `#📄development` channel.

View File

@ -3,7 +3,6 @@ title = "Submitting a contribution"
[extra]
order = 3 # Page number after chapter intro
linked_css = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"]
+++
Collaboration is a key part of real-world software engineering. Graphite follows some basic procedures to keep the process smooth and efficient. You will want to familiarize yourself with these guidelines to save yourself and Graphite maintainers time and confusion.
@ -72,7 +71,7 @@ Upon pushing a commit to your PR's branch, CI will need to build and test your c
You also have to pass `cargo fmt` and `cargo clippy` locally before your PR can be merged.
Your goal is for the check called "Editor: Dev & CI / build (pull_request)" to pass with a <span class="emoji"></span>. If it fails with a <span class="emoji"></span>, you will need to investigate. If you need access to the build logs, ask a maintainer to provide them. Occasionally, other checks may fail, but you likely won't be responsible for fixing those and they can be ignored.
Your goal is for the check called "Editor: Dev & CI / build (pull_request)" to pass with a ✅. If it fails with a ❌, you will need to investigate. If you need access to the build logs, ask a maintainer to provide them. Occasionally, other checks may fail, but you likely won't be responsible for fixing those and they can be ignored.
## Keeping your work up-to-date

View File

@ -3,8 +3,6 @@
// ================================
:root {
--color-black: #000000;
--color-white: #ffffff;
--color-fog: #eeeeee;
--color-parchment: #faefe2;
--color-cloud: #d9e1e4;
@ -22,8 +20,8 @@
--color-seaside: #b0d6cb;
--color-seaside-rgb: 176, 214, 203;
// --color-cove: #83c0b9;
--color-sage: #91b99a;
--color-storm: #627088;
// --color-sage: #91b99a;
// --color-storm: #627088;
--max-width: 1200px;
--max-width-plus-padding: calc(var(--max-width) + 40px * 2);
@ -39,7 +37,7 @@
html,
body {
color: var(--color-navy);
background: var(--color-white);
background: white;
font-family: "Inter", sans-serif;
line-height: 1.5;
font-weight: 500;
@ -107,6 +105,9 @@ body > .page {
display: flex;
align-items: center;
gap: 40px;
--height: 60px;
--button-padding: 24px;
--nav-font-size: 28px; // Keep up to date with `NAV_BUTTON_INITIAL_FONT_SIZE` in navbar.js
a {
font-family: "Bona Nova", Palatino, serif;
@ -114,9 +115,6 @@ body > .page {
line-height: 1.25;
font-weight: 700;
text-decoration: none;
--height: 60px;
--button-padding: 24px;
--nav-font-size: 28px; // Keep up to date with `NAV_BUTTON_INITIAL_FONT_SIZE` in navbar.js
font-size: var(--nav-font-size);
&.button {
@ -150,103 +148,70 @@ body > .page {
@media screen and (max-width: 1200px) {
gap: 30px;
a {
--height: 50px;
--button-padding: 16px;
--nav-font-size: 24px;
}
--height: 50px;
--button-padding: 16px;
--nav-font-size: 24px;
}
@media screen and (max-width: 1000px) {
gap: 30px;
a {
--button-padding: 14px;
--nav-font-size: 20px;
}
--button-padding: 14px;
--nav-font-size: 20px;
}
@media print, screen and (max-width: 900px) {
gap: 20px;
a {
--height: 40px;
--button-padding: 13px;
--nav-font-size: 18px;
}
--height: 40px;
--button-padding: 13px;
--nav-font-size: 18px;
}
@media print, screen and (max-width: 780px) {
gap: 20px;
a {
--button-padding: 12px;
--nav-font-size: 16px;
}
--button-padding: 12px;
--nav-font-size: 16px;
}
@media screen and (max-width: 680px) {
gap: 16px;
a {
--height: 30px;
--button-padding: 8px;
--nav-font-size: 14px;
}
--height: 30px;
--button-padding: 8px;
--nav-font-size: 14px;
}
@media screen and (max-width: 580px) {
gap: 12px;
a {
--height: 24px;
--nav-font-size: 13px;
}
--height: 24px;
--nav-font-size: 13px;
}
@media screen and (max-width: 520px) {
gap: 10px;
a {
--height: 22px;
--button-padding: 6px;
--nav-font-size: 12px;
}
--height: 22px;
--button-padding: 6px;
--nav-font-size: 12px;
}
@media screen and (max-width: 460px) {
gap: 8px;
a {
--height: 20px;
--button-padding: 4px;
--nav-font-size: 11px;
}
--height: 20px;
--button-padding: 4px;
--nav-font-size: 11px;
}
@media screen and (max-width: 420px) {
gap: 6px;
a {
--nav-font-size: 10px;
}
--nav-font-size: 10px;
}
@media screen and (max-width: 380px) {
gap: 6px;
a {
--nav-font-size: 9px;
}
--nav-font-size: 9px;
}
@media screen and (max-width: 350px) {
gap: 6px;
a {
--nav-font-size: 8px;
}
--nav-font-size: 8px;
}
}
}
@ -377,8 +342,8 @@ body > .page {
:is(h1, h2, h3, h4, article > :first-child) ~ :is(p, ul, ol, ol li p, img, a:has(> img:only-child)),
:is(h1, h2, h3, h4, article > :first-child) ~ :is(ul, ol) li p + img,
:is(h1, h2, h3, h4, p) ~ .feature-icons,
p ~ :is(h1, h2, h3, h4, details summary, blockquote, .image-comparison, .video-background, .video-embed),
.video-embed + :is(p, .link, .button),
p ~ :is(h1, h2, h3, h4, details summary, blockquote, .image-comparison, .video-background, .youtube-embed),
.youtube-embed + :is(p, .link, .button),
p + p > .button,
p + :is(.link, section),
table td p ~ p,
@ -526,7 +491,7 @@ hr {
}
code {
color: var(--color-black);
color: black;
background: var(--color-fog);
padding: 0 4px;
overflow-wrap: anywhere;
@ -538,113 +503,6 @@ code {
}
}
pre {
display: flex;
max-width: 100%;
color: var(--color-fog);
// This zero transform sets this element as the root for `position: fixed`
transform: translate(0);
// Color overrides
&,
&.z-code {
background: var(--color-navy);
.z-path {
color: #679f70;
span {
color: #e6e1dc;
}
}
}
// Container for the element (span or table) containing the lines of code
code {
background: initial;
color: inherit;
display: block;
overflow-x: auto;
padding: 20px;
width: 0;
flex: 1 1 auto;
}
// Language name in top right corner
&[data-lang] {
padding-top: 28px;
&::before {
content: attr(data-lang);
color: rgba(var(--color-seaside-rgb), 0.5);
text-transform: lowercase;
font-family: "Inter", sans-serif;
font-size: 0.75em;
font-weight: 700;
font-style: italic;
-webkit-user-select: none;
user-select: none;
pointer-events: none;
position: fixed;
top: 0;
line-height: 28px;
display: block;
width: 100%;
text-indent: 20px;
background: rgba(0, 0, 0, 0.25);
&[data-lang="sh"] {
content: "Shell";
}
&[data-lang="rs"] {
content: "Rust";
}
&[data-lang="js"] {
content: "JavaScript";
}
&[data-lang="ts"] {
content: "TypeScript";
}
}
}
// Code blocks with line numbers
&[data-linenos] table {
border-spacing: 0;
margin: -20px;
tr {
&:first-child td {
padding-top: 20px;
}
&:last-child td {
padding-bottom: 20px;
}
td {
&:first-child {
padding-left: 20px;
padding-right: 10px;
-webkit-user-select: none;
user-select: none;
vertical-align: top;
text-align: right;
background: rgba(0, 0, 0, 0.25);
}
&:last-child {
padding-left: 10px;
padding-right: 20px;
}
}
}
}
}
kbd {
outline: calc(var(--border-thickness) / 2) solid var(--color-navy);
padding: 0 8px;
@ -692,86 +550,9 @@ hr,
}
}
// Using this requires adding this line to the page's frontmatter:
// linked_css = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"]
.emoji {
font-family: "Noto Color Emoji", sans-serif;
font-style: normal;
}
// =======
// LAYOUTS
// =======
.reading-material.reading-material {
max-width: var(--max-width-reading-material);
article {
width: 100%;
h2 {
margin-top: 80px;
}
h3 {
margin-top: 40px;
}
h4 {
margin-top: 20px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
display: block;
&:first-child {
margin-top: 0;
}
}
// Captions below images in blog posts
p:has(> img) + center:has(> em) {
margin-top: 10px;
}
p ~ img {
width: auto;
max-width: 100%;
}
hr {
margin-top: 40px;
margin-bottom: 40px;
}
+ hr {
margin-top: calc(80 * var(--variable-px));
margin-bottom: calc(40 * var(--variable-px));
}
}
}
// .graphic {
// max-width: 200px;
// flex: 1 1 100%;
// display: flex;
// img {
// display: block;
// width: 100%;
// object-fit: contain;
// @media screen and (max-width: 800px) {
// width: auto;
// height: 120px;
// }
// }
// }
// ========================
// COMMON SIMPLE COMPONENTS
// ========================
.block {
display: flex;
@ -782,122 +563,12 @@ hr,
&.centered {
align-items: center;
}
}
:not(.diptych, .triptych) > :is(.block, .diptych, .triptych) + :is(.block, .diptych, .triptych) {
margin-top: calc(120 * var(--variable-px));
}
.feature-box-narrow,
.feature-box-outer {
padding: calc(80 * var(--variable-px));
background-image: url("https://static.graphite.rs/textures/noise.png");
background-blend-mode: overlay;
background-position: center;
}
:where(h1, h2, h3, h4, p) + .feature-box-narrow {
margin-top: calc(40 * var(--variable-px));
}
.feature-box-full-image {
width: calc(100% + 2 * 80 * var(--variable-px));
height: auto;
margin-left: calc(-80 * var(--variable-px));
margin-top: calc(-80 * var(--variable-px));
margin-bottom: calc(40 * var(--variable-px));
display: block;
}
.feature-box-outer {
@media screen and (max-width: 1000px) {
&.feature-box-outer {
margin-left: calc(-1 * var(--page-edge-padding));
margin-right: calc(-1 * var(--page-edge-padding));
padding-left: var(--page-edge-padding);
padding-right: var(--page-edge-padding);
}
}
&.feature-box-outer {
max-width: unset;
}
.feature-box-inner {
max-width: var(--max-width);
margin: 0 auto;
:not(.diptych, .triptych) > .block + & {
margin-top: calc(120 * var(--variable-px));
}
}
h1.feature-box-header.feature-box-header {
&,
& a {
font-family: "Inter", sans-serif;
line-height: 1.5;
font-weight: 800;
text-transform: uppercase;
font-size: calc(1rem * 14 / 9);
}
span {
white-space: pre;
}
~ hr {
margin-top: 20px;
margin-bottom: 40px;
+ p {
margin-top: 0;
}
}
}
.diptych,
.triptych {
display: flex;
flex-wrap: wrap;
gap: calc(80 * var(--variable-px));
.block {
flex: 1 1 0;
}
img[alt=""] {
display: block;
&::after {
content: "";
display: block;
width: 100%;
height: 240px;
background: var(--color-crimson);
}
}
}
.diptych .block {
min-width: 320px;
}
.triptych .block {
min-width: 280px;
}
@media screen and (max-width: 520px) {
.diptych .block {
min-width: 200px;
}
.triptych .block {
min-width: 280px;
}
}
// ========================
// COMMON SIMPLE COMPONENTS
// ========================
.link {
display: inline-block;
font-size: var(--font-size-link);
@ -944,54 +615,6 @@ h1.feature-box-header.feature-box-header {
font-family: "Inter", sans-serif;
}
.demo-artwork {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
> a {
flex: 0 0 auto;
img {
height: 128px;
border: 12px solid var(--color-walnut);
vertical-align: top;
flex: 0 0 auto;
}
}
p {
display: flex;
flex-direction: column;
max-width: 300px;
margin-left: 40px;
text-align: left;
}
}
.video-embed {
position: relative;
width: 100%;
&.aspect-16x9 {
padding-top: calc(100% / (16 / 9));
}
img,
iframe {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
img {
cursor: pointer;
}
}
.video-background {
position: relative;
font-size: 0;
@ -1038,404 +661,3 @@ h1.feature-box-header.feature-box-header {
// right: 16px;
// }
// }
// =========================
// COMMON COMPLEX COMPONENTS
// =========================
.image-comparison {
position: relative;
touch-action: pan-y pinch-zoom;
max-width: Min(100%, 512px);
.crop-container {
height: 100%;
&:nth-child(2) {
overflow: hidden;
width: calc(100% - var(--comparison-percent));
&,
img {
position: absolute;
top: 0;
right: 0;
}
}
&.crop-container.crop-container {
img {
display: block;
width: auto;
height: 100%;
}
&:first-child img {
width: 100%;
}
}
}
.slide-bar {
position: absolute;
background: var(--color-navy);
margin-left: -2px;
width: 4px;
height: 100%;
top: 0;
left: var(--comparison-percent);
box-shadow: 0 0 2px rgba(255, 255, 255, 0.5);
.arrows {
position: absolute;
top: calc(50% - (40px / 2));
left: calc(4px / 2);
width: 0;
height: 0;
opacity: 1;
transition: opacity 0.25s;
svg {
position: absolute;
width: 6.5px;
height: 11px;
top: calc(-11px / 2);
fill: var(--color-white);
@keyframes pulse-left {
from { transform: translateX(3px); }
to { transform: translateX(-3px); }
}
@keyframes pulse-right {
from { transform: scaleX(-1) translateX(3px); }
to { transform: scaleX(-1) translateX(-3px); }
}
@keyframes pulse-opacity {
0% { opacity: 0; }
40% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
&:nth-of-type(1) {
right: 6px;
animation: 3s infinite ease-out pulse-left, 3s infinite ease-out pulse-opacity;
}
&:nth-of-type(2) {
left: 6px;
animation: 3s infinite ease-out pulse-right, 3s infinite ease-out pulse-opacity;
}
}
div {
content: "";
position: absolute;
background: var(--color-navy);
top: 0;
left: 0;
width: 32px;
height: 32px;
transform: translate(-50%, -50%) rotate(45deg);
box-shadow: 0 0 2px rgba(255, 255, 255, 0.5);
}
// Cover up the box-shadow at the top and bottom of the circle so it connects to the vertical line
&::after {
content: "";
position: absolute;
background: var(--color-navy);
left: -2px;
top: -24px;
width: 4px;
height: 48px;
}
}
}
&:hover .slide-bar .arrows {
opacity: 0;
}
}
.carousel {
margin-top: calc(80 * var(--variable-px));
transform: translate(0);
.carousel-slide {
display: flex;
white-space: nowrap;
touch-action: pan-y pinch-zoom;
cursor: grab;
img {
position: relative;
display: inline-block;
user-select: none;
flex: 0 0 auto;
height: auto;
padding: 0 20px;
&:first-child,
&:last-child {
--fade-factor: Min(calc(var(--over-slide-factor, 0) / 1.5 + 0.5), 1);
// Fade to white (combining invert and brightness, see <https://stackoverflow.com/a/78478074/775283>) and desaturate
filter: Invert(calc(var(--fade-factor) / 2)) Brightness(calc(1 + var(--fade-factor))) Grayscale(var(--fade-factor));
}
&:first-child {
margin-left: -20px;
}
&:last-child {
margin-right: -20px;
}
}
}
&:not(.dragging, .jostling) .carousel-slide img {
transition: transform 500ms;
}
.carousel-slide:not(.torn) {
overflow: hidden;
}
.carousel-slide.torn {
position: fixed;
top: 0;
z-index: -1;
// Torn edge mask
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
&.left {
padding-left: 160px;
margin-left: -160px;
-webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-left__2.png");
mask-image: url("https://static.graphite.rs/textures/torn-edge-left__2.png");
-webkit-mask-position: top left;
mask-position: top left;
}
&.right {
padding-right: 160px;
margin-right: -160px;
-webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-right__2.png");
mask-image: url("https://static.graphite.rs/textures/torn-edge-right__2.png");
-webkit-mask-position: top right;
mask-position: top right;
}
}
.screenshot-details {
display: flex;
margin: 20px 0;
gap: 20px 40px;
@media screen and (max-width: 800px) {
flex-wrap: wrap;
justify-content: center;
}
.carousel-controls {
display: flex;
align-items: center;
flex: 0 0 auto;
button {
outline: none;
background: none;
border: none;
padding: 0;
color: inherit;
cursor: pointer;
svg {
display: block;
}
+ button {
margin-left: 20px;
}
}
.direction {
fill: currentColor;
}
.dot {
width: 16px;
height: 16px;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid currentColor;
&.active {
border: none;
background: var(--color-crimson);
}
}
}
.screenshot-description {
display: flex;
align-items: center;
min-height: calc(2em * 1.5);
p + p {
margin: 0;
}
p:not(.active) {
display: none;
}
}
}
&.center {
.screenshot-details {
justify-content: center;
}
}
&.window-size-1 .carousel-slide img {
width: 100%;
}
&.window-size-2 .carousel-slide img {
width: calc((100% / 2) - 10px);
padding: 0 10px;
&:first-child {
margin-left: -10px;
}
&:last-child {
margin-right: -10px;
}
}
&.window-size-3 .carousel-slide img {
width: calc((100% / 3) - 10px * (4 / 3));
padding: 0 10px;
&:first-child {
margin-left: -10px;
}
&:last-child {
margin-right: -10px;
}
}
@media screen and (max-width: 1000px) {
margin-left: calc(-1 * var(--page-edge-padding));
margin-right: calc(-1 * var(--page-edge-padding));
.screenshot-details {
margin-left: var(--page-edge-padding);
margin-right: var(--page-edge-padding);
}
}
@media screen and (max-width: /* The value of --max-width-plus-padding: */ 1280px) {
.carousel-slide.torn {
display: none;
}
}
}
.atlas {
object-fit: cover;
object-position: calc(-48px * var(--atlas-index)) 0;
width: 48px;
height: 48px;
}
.feature-icons {
display: flex;
flex-wrap: wrap;
margin-bottom: 20px;
width: 100%;
gap: 16px;
.feature-icon {
display: flex;
align-items: center;
img {
flex: 0 0 auto;
}
}
&:not(.stacked) .feature-icon {
padding: 16px;
gap: 16px;
// Half width, minus own padding on both sides, minus half a gap
flex: 1 0 calc(50% - (16px * 2) - (16px / 2));
@media screen and (max-width: 1100px) {
// Quarter width, minus own padding on both sides
flex: 1 0 calc(100% - (16px * 2));
}
}
&:not(.no-background) .feature-icon {
background: rgba(0, 0, 0, 0.0625);
}
&.four-wide .feature-icon {
flex: 1 0 calc(25% - (16px * 4) - (16px / 4));
@media screen and (max-width: 1200px) {
// Half width, minus own padding on both sides, minus half a gap
flex: 1 0 calc(50% - (16px * 2) - (16px / 2));
}
@media screen and (max-width: 840px) {
// Quarter width, minus own padding on both sides
flex: 1 0 calc(100% - (16px * 2));
}
}
&.stacked {
justify-content: space-between;
margin: 0 -10px;
width: calc(100% + 20px);
gap: 0;
.feature-icon {
flex-direction: column;
flex: 0 1 auto;
margin: 0 10px;
@media screen and (max-width: 1100px) {
width: calc(100% / 3 - 40px);
}
@media screen and (max-width: 400px) {
width: calc(100% / 2 - 20px);
}
img {
width: 72px;
height: 72px;
object-position: calc(-72px * var(--atlas-index)) 0;
margin-bottom: 8px;
}
span {
text-align: center;
}
}
}
}
p + .feature-icons .feature-icon.feature-icon {
margin-top: calc(40 * var(--variable-px));
}

View File

@ -0,0 +1,189 @@
.carousel {
margin-top: calc(80 * var(--variable-px));
transform: translate(0);
.carousel-slide {
display: flex;
white-space: nowrap;
touch-action: pan-y pinch-zoom;
cursor: grab;
img {
position: relative;
display: inline-block;
user-select: none;
flex: 0 0 auto;
height: auto;
padding: 0 20px;
&:first-child,
&:last-child {
--fade-factor: Min(calc(var(--over-slide-factor, 0) / 1.5 + 0.5), 1);
// Fade to white (combining invert and brightness, see <https://stackoverflow.com/a/78478074/775283>) and desaturate
filter: Invert(calc(var(--fade-factor) / 2)) Brightness(calc(1 + var(--fade-factor))) Grayscale(var(--fade-factor));
}
&:first-child {
margin-left: -20px;
}
&:last-child {
margin-right: -20px;
}
}
}
&:not(.dragging, .jostling) .carousel-slide img {
transition: transform 500ms;
}
.carousel-slide:not(.torn) {
overflow: hidden;
}
.carousel-slide.torn {
position: fixed;
top: 0;
z-index: -1;
// Torn edge mask
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
&.left {
padding-left: 160px;
margin-left: -160px;
-webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-left__2.png");
mask-image: url("https://static.graphite.rs/textures/torn-edge-left__2.png");
-webkit-mask-position: top left;
mask-position: top left;
}
&.right {
padding-right: 160px;
margin-right: -160px;
-webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-right__2.png");
mask-image: url("https://static.graphite.rs/textures/torn-edge-right__2.png");
-webkit-mask-position: top right;
mask-position: top right;
}
}
.screenshot-details {
display: flex;
margin: 20px 0;
gap: 20px 40px;
@media screen and (max-width: 800px) {
flex-wrap: wrap;
justify-content: center;
}
.carousel-controls {
display: flex;
align-items: center;
flex: 0 0 auto;
button {
outline: none;
background: none;
border: none;
padding: 0;
color: inherit;
cursor: pointer;
svg {
display: block;
}
+ button {
margin-left: 20px;
}
}
.direction {
fill: currentColor;
}
.dot {
width: 16px;
height: 16px;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid currentColor;
&.active {
border: none;
background: var(--color-crimson);
}
}
}
.screenshot-description {
display: flex;
align-items: center;
min-height: calc(2em * 1.5);
p + p {
margin: 0;
}
p:not(.active) {
display: none;
}
}
}
&.center {
.screenshot-details {
justify-content: center;
}
}
&.window-size-1 .carousel-slide img {
width: 100%;
}
&.window-size-2 .carousel-slide img {
width: calc((100% / 2) - 10px);
padding: 0 10px;
&:first-child {
margin-left: -10px;
}
&:last-child {
margin-right: -10px;
}
}
&.window-size-3 .carousel-slide img {
width: calc((100% / 3) - 10px * (4 / 3));
padding: 0 10px;
&:first-child {
margin-left: -10px;
}
&:last-child {
margin-right: -10px;
}
}
@media screen and (max-width: 1000px) {
margin-left: calc(-1 * var(--page-edge-padding));
margin-right: calc(-1 * var(--page-edge-padding));
.screenshot-details {
margin-left: var(--page-edge-padding);
margin-right: var(--page-edge-padding);
}
}
@media screen and (max-width: /* The value of --max-width-plus-padding: */ 1280px) {
.carousel-slide.torn {
display: none;
}
}
}

View File

@ -0,0 +1,106 @@
pre {
display: flex;
max-width: 100%;
color: var(--color-fog);
// This zero transform sets this element as the root for `position: fixed`
transform: translate(0);
// Color overrides
&,
&.z-code {
background: var(--color-navy);
.z-path {
color: #679f70;
span {
color: #e6e1dc;
}
}
}
// Container for the element (span or table) containing the lines of code
code {
background: initial;
color: inherit;
display: block;
overflow-x: auto;
padding: 20px;
width: 0;
flex: 1 1 auto;
}
// Language name in top right corner
&[data-lang] {
padding-top: 28px;
&::before {
content: attr(data-lang);
color: rgba(var(--color-seaside-rgb), 0.5);
text-transform: lowercase;
font-family: "Inter", sans-serif;
font-size: 0.75em;
font-weight: 700;
font-style: italic;
-webkit-user-select: none;
user-select: none;
pointer-events: none;
position: fixed;
top: 0;
line-height: 28px;
display: block;
width: 100%;
text-indent: 20px;
background: rgba(0, 0, 0, 0.25);
&[data-lang="sh"] {
content: "Shell";
}
&[data-lang="rs"] {
content: "Rust";
}
&[data-lang="js"] {
content: "JavaScript";
}
&[data-lang="ts"] {
content: "TypeScript";
}
}
}
// Code blocks with line numbers
&[data-linenos] table {
border-spacing: 0;
margin: -20px;
tr {
&:first-child td {
padding-top: 20px;
}
&:last-child td {
padding-bottom: 20px;
}
td {
&:first-child {
padding-left: 20px;
padding-right: 10px;
-webkit-user-select: none;
user-select: none;
vertical-align: top;
text-align: right;
background: rgba(0, 0, 0, 0.25);
}
&:last-child {
padding-left: 10px;
padding-right: 20px;
}
}
}
}
}

View File

@ -0,0 +1,25 @@
.demo-artwork {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
> a {
flex: 0 0 auto;
img {
height: 128px;
border: 12px solid var(--color-walnut);
vertical-align: top;
flex: 0 0 auto;
}
}
p {
display: flex;
flex-direction: column;
max-width: 300px;
margin-left: 40px;
text-align: left;
}
}

View File

@ -0,0 +1,109 @@
:not(.diptych, .triptych) > :is(.block, .diptych, .triptych) + :is(.block, .diptych, .triptych) {
margin-top: calc(120 * var(--variable-px));
}
.feature-box-narrow,
.feature-box-outer {
padding: calc(80 * var(--variable-px));
background-image: url("https://static.graphite.rs/textures/noise.png");
background-blend-mode: overlay;
background-position: center;
}
:where(h1, h2, h3, h4, p) + .feature-box-narrow {
margin-top: calc(40 * var(--variable-px));
}
.feature-box-full-image {
width: calc(100% + 2 * 80 * var(--variable-px));
height: auto;
margin-left: calc(-80 * var(--variable-px));
margin-top: calc(-80 * var(--variable-px));
margin-bottom: calc(40 * var(--variable-px));
display: block;
}
.feature-box-outer {
@media screen and (max-width: 1000px) {
&.feature-box-outer {
margin-left: calc(-1 * var(--page-edge-padding));
margin-right: calc(-1 * var(--page-edge-padding));
padding-left: var(--page-edge-padding);
padding-right: var(--page-edge-padding);
}
}
&.feature-box-outer {
max-width: unset;
}
.feature-box-inner {
max-width: var(--max-width);
margin: 0 auto;
}
}
h1.feature-box-header.feature-box-header {
&,
& a {
font-family: "Inter", sans-serif;
line-height: 1.5;
font-weight: 800;
text-transform: uppercase;
font-size: calc(1rem * 14 / 9);
}
span {
white-space: pre;
}
~ hr {
margin-top: 20px;
margin-bottom: 40px;
+ p {
margin-top: 0;
}
}
}
.diptych,
.triptych {
display: flex;
flex-wrap: wrap;
gap: calc(80 * var(--variable-px));
.block {
flex: 1 1 0;
}
img[alt=""] {
display: block;
&::after {
content: "";
display: block;
width: 100%;
height: 240px;
background: var(--color-crimson);
}
}
}
.diptych .block {
min-width: 320px;
}
.triptych .block {
min-width: 280px;
}
@media screen and (max-width: 520px) {
.diptych .block {
min-width: 200px;
}
.triptych .block {
min-width: 280px;
}
}

View File

@ -0,0 +1,89 @@
.feature-icons {
display: flex;
flex-wrap: wrap;
margin-bottom: 20px;
width: 100%;
gap: 16px;
.atlas {
object-fit: cover;
object-position: calc(-48px * var(--atlas-index)) 0;
width: 48px;
height: 48px;
}
.feature-icon {
display: flex;
align-items: center;
img {
flex: 0 0 auto;
}
p + &.feature-icon {
margin-top: calc(40 * var(--variable-px));
}
}
&:not(.stacked) .feature-icon {
padding: 16px;
gap: 16px;
// Half width, minus own padding on both sides, minus half a gap
flex: 1 0 calc(50% - (16px * 2) - (16px / 2));
@media screen and (max-width: 1100px) {
// Quarter width, minus own padding on both sides
flex: 1 0 calc(100% - (16px * 2));
}
}
&:not(.no-background) .feature-icon {
background: rgba(0, 0, 0, 0.0625);
}
&.four-wide .feature-icon {
flex: 1 0 calc(25% - (16px * 4) - (16px / 4));
@media screen and (max-width: 1200px) {
// Half width, minus own padding on both sides, minus half a gap
flex: 1 0 calc(50% - (16px * 2) - (16px / 2));
}
@media screen and (max-width: 840px) {
// Quarter width, minus own padding on both sides
flex: 1 0 calc(100% - (16px * 2));
}
}
&.stacked {
justify-content: space-between;
margin: 0 -10px;
width: calc(100% + 20px);
gap: 0;
.feature-icon {
flex-direction: column;
flex: 0 1 auto;
margin: 0 10px;
@media screen and (max-width: 1100px) {
width: calc(100% / 3 - 40px);
}
@media screen and (max-width: 400px) {
width: calc(100% / 2 - 20px);
}
img {
width: 72px;
height: 72px;
object-position: calc(-72px * var(--atlas-index)) 0;
margin-bottom: 8px;
}
span {
text-align: center;
}
}
}
}

View File

@ -0,0 +1,116 @@
.image-comparison {
position: relative;
touch-action: pan-y pinch-zoom;
max-width: Min(100%, 512px);
.crop-container {
height: 100%;
&:nth-child(2) {
overflow: hidden;
width: calc(100% - var(--comparison-percent));
&,
img {
position: absolute;
top: 0;
right: 0;
}
}
&.crop-container.crop-container {
img {
display: block;
width: auto;
height: 100%;
}
&:first-child img {
width: 100%;
}
}
}
.slide-bar {
position: absolute;
background: var(--color-navy);
margin-left: -2px;
width: 4px;
height: 100%;
top: 0;
left: var(--comparison-percent);
box-shadow: 0 0 2px rgba(255, 255, 255, 0.5);
.arrows {
position: absolute;
top: calc(50% - (40px / 2));
left: calc(4px / 2);
width: 0;
height: 0;
opacity: 1;
transition: opacity 0.25s;
svg {
position: absolute;
width: 6.5px;
height: 11px;
top: calc(-11px / 2);
fill: white;
@keyframes pulse-left {
from { transform: translateX(3px); }
to { transform: translateX(-3px); }
}
@keyframes pulse-right {
from { transform: scaleX(-1) translateX(3px); }
to { transform: scaleX(-1) translateX(-3px); }
}
@keyframes pulse-opacity {
0% { opacity: 0; }
40% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
&:nth-of-type(1) {
right: 6px;
animation: 3s infinite ease-out pulse-left, 3s infinite ease-out pulse-opacity;
}
&:nth-of-type(2) {
left: 6px;
animation: 3s infinite ease-out pulse-right, 3s infinite ease-out pulse-opacity;
}
}
div {
content: "";
position: absolute;
background: var(--color-navy);
top: 0;
left: 0;
width: 32px;
height: 32px;
transform: translate(-50%, -50%) rotate(45deg);
box-shadow: 0 0 2px rgba(255, 255, 255, 0.5);
}
// Cover up the box-shadow at the top and bottom of the circle so it connects to the vertical line
&::after {
content: "";
position: absolute;
background: var(--color-navy);
left: -2px;
top: -24px;
width: 4px;
height: 48px;
}
}
}
&:hover .slide-bar .arrows {
opacity: 0;
}
}

View File

@ -0,0 +1,21 @@
.youtube-embed {
position: relative;
width: 100%;
&.aspect-16x9 {
padding-top: calc(100% / (16 / 9));
}
img,
iframe {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
img {
cursor: pointer;
}
}

View File

@ -0,0 +1,52 @@
.reading-material.reading-material {
max-width: var(--max-width-reading-material);
article {
width: 100%;
h2 {
margin-top: 80px;
}
h3 {
margin-top: 40px;
}
h4 {
margin-top: 20px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
display: block;
&:first-child {
margin-top: 0;
}
}
// Captions below images in blog posts
p:has(> img) + center:has(> em) {
margin-top: 10px;
}
p ~ img {
width: auto;
max-width: 100%;
}
hr {
margin-top: 40px;
margin-bottom: 40px;
}
+ hr {
margin-top: calc(80 * var(--variable-px));
margin-bottom: calc(40 * var(--variable-px));
}
}
}

View File

@ -33,9 +33,11 @@
color: var(--color-slate);
}
.emoji {
font-size: 0.8em;
.flag {
font-family: "Noto Color Emoji", sans-serif;
font-style: normal;
vertical-align: middle;
font-size: 0.8em;
cursor: default;
}
}

View File

@ -1,35 +1,33 @@
#intro {
.block {
flex: 1 1 100%;
#intro .block {
flex: 1 1 100%;
width: 100%;
.left-right-split {
width: 100%;
margin-top: 20px;
display: flex;
gap: 20px;
justify-content: space-between;
flex-wrap: wrap;
}
.left-right-split {
width: 100%;
margin-top: 20px;
.feed {
margin-top: -4px;
a {
text-decoration: none;
display: flex;
gap: 20px;
justify-content: space-between;
flex-wrap: wrap;
}
gap: 8px;
.feed {
margin-top: -4px;
.icon {
vertical-align: top;
width: calc(var(--font-size-link) * 1.5);
height: calc(var(--font-size-link) * 1.5);
}
a {
text-decoration: none;
display: flex;
gap: 8px;
.icon {
vertical-align: top;
width: calc(var(--font-size-link) * 1.5);
height: calc(var(--font-size-link) * 1.5);
}
.link {
vertical-align: top;
margin-top: 0;
}
.link {
vertical-align: top;
margin-top: 0;
}
}
}

View File

@ -118,11 +118,11 @@
// PROCEDURALISM
#proceduralism {
background-color: var(--color-slate);
color: var(--color-white);
color: white;
margin-top: 0;
.diptych {
background: var(--color-black);
background: black;
color: var(--color-fog);
overflow: hidden; // Clip off a 1px overflow beneath the video which appears at some screen widths
align-items: stretch;

View File

@ -2,16 +2,12 @@
display: flex;
margin: 0 auto;
&.logo-view.logo-view {
+ .logo-view.logo-view {
margin-top: 0;
&:first-of-type {
margin-top: 20px;
}
}
&.color {
background-color: var(--color-white);
background-color: white;
background-blend-mode: hard-light;
}
@ -54,8 +50,4 @@
}
}
}
+ h3 {
margin-top: 20px;
}
}

View File

@ -1,7 +1,7 @@
window.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll("[data-video-embed]").forEach((placeholder) => {
document.querySelectorAll("[data-youtube-embed]").forEach((placeholder) => {
placeholder.addEventListener("click", () => {
const videoId = placeholder.attributes["data-video-embed"].value;
const videoId = placeholder.attributes["data-youtube-embed"].value;
placeholder.outerHTML = `<iframe width="1280" height="720" src="https://www.youtube.com/embed/${videoId}?autoplay=1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
});
});

View File

@ -6,7 +6,7 @@
{%- set meta_image = page.extra.banner_png | safe -%}
{%- set meta_article_type = true -%}
{%- set meta_description = page.extra.summary | default(value = page.content | striptags | safe | linebreaksbr | replace(from = "<br>", to = " ") | replace(from = " ", to = " ") | trim | truncate(length = 200)) -%}
{%- set css = ["/article.css"] -%}
{%- set css = ["/template/article.css", "/layout/reading-material.css"] -%}
{%- endblock head -%}
{%- block content -%}{%- set page = page | default(value = section) -%}

View File

@ -32,9 +32,9 @@
{#- ON EVERY PAGE OF THE SITE: CSS AND JS TO LOAD EITHER AS A LINK OR INLINE -#}
{#- ======================================================================== -#}
{%- set global_linked_css = ["/base.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_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_css = [] -%}
{%- set global_css = ["/base.css"] -%}
{%- set global_js = ["/js/text-justification.js", "/js/navbar.js"] -%}
{#- RETRIEVE FROM TEMPLATES AND PAGES: CSS AND JS TO LOAD EITHER AS A LINK OR INLINE -#}
@ -74,11 +74,13 @@
{#- INSERT INLINE CSS CODE -#}
{#- ====================== -#}
{%- for path in css_list %}
{%- if css_list | length > 0 %}
{{ "<" ~ "style>" | safe }}
{% for path in css_list -%}
{{ load_data(path = path) | safe }}
{% endfor -%}
{{ "</" ~ "style>" | safe }}
{%- endfor %}
{%- endif %}
{#- INSERT INLINE JS CODE -#}
{#- ===================== -#}

View File

@ -3,7 +3,7 @@
{%- block head -%}{%- set page = page | default(value = section) -%}
{%- set title = page.title -%}
{%- set meta_title = "Graphite Blog" -%}
{%- set css = ["/blog.css"] -%}
{%- set css = ["/page/blog.css"] -%}
{%- endblock head -%}
{%- block content -%}{%- set page = page | default(value = section) -%}

View File

@ -5,7 +5,7 @@
{%- set meta_article_type = true -%}
{%- set meta_description = page.extra.summary | default(value = page.content | striptags | safe | linebreaksbr | replace(from = "<br>", to = " ") | replace(from = " ", to = " ") | trim | truncate(length = 200)) -%}
{%- set linked_css = ["/syntax-highlighting.css"] -%}
{%- set css = ["/book.css"] -%}
{%- set css = ["/template/book.css", "/layout/reading-material.css", "/component/code-snippet.css"] -%}
{%- set js = ["/js/book.js"] -%}
{%- endblock head -%}