From 2412a3def6bb8d9c03ace9c2d0121e81d7df5656 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 12 Aug 2023 12:48:45 -0700 Subject: [PATCH] Improve responsive design sizing for website --- README.md | 4 +- website/content/_index.md | 178 +++--- website/content/about.md | 10 +- website/content/blog/_index.md | 2 +- website/content/contact.md | 2 +- website/content/donate.md | 4 +- website/content/features.md | 8 +- website/content/learn/node-graph/imaginate.md | 2 +- website/content/license.md | 2 +- website/content/logo.md | 8 +- website/content/press.md | 2 +- website/content/volunteer/_index.md | 7 +- .../contributing-guidelines.md | 2 +- website/sass/base.scss | 546 +++++++++--------- website/sass/blog.scss | 8 +- website/sass/book.scss | 141 ++++- website/sass/index.scss | 298 +++++----- website/sass/volunteer.scss | 9 + website/static/js/book.js | 11 + website/static/js/navbar.js | 7 +- website/static/js/text-justification.js | 28 + website/templates/404.html | 2 +- website/templates/article.html | 2 +- website/templates/base.html | 1 + website/templates/book.html | 72 +-- 25 files changed, 766 insertions(+), 590 deletions(-) create mode 100644 website/static/js/text-justification.js diff --git a/README.md b/README.md index 0d6438e2..91448422 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Launch the latest alpha release of the [Graphite editor](https://editor.graphite ## Building/contributing -We need Rust and web developers! See [instructions here](https://graphite.rs/contribute/) for setting up the project and getting started. +We need Rust and web developers! See [instructions here](https://graphite.rs/volunteer/guide/) for setting up the project and getting started. We are also in search of artists to create beautiful sample work in Graphite and illustrations for the website and social media. Please [get in touch](https://graphite.rs/contact/) if you are able to help out. @@ -36,4 +36,4 @@ By submitting code for inclusion in the project, you are agreeing to license you ## Support the project -Please consider pledging a monthly donation using the "♥ Sponsor" button to the right part of this project repository page. Your contribution helps sustain this volunteer-run open source project and brings powerful, free creative tools to the masses. +Please consider [pledging a monthly donation](https://graphite.rs/donate/). Your contribution helps sustain this volunteer-run open source project and brings powerful, free creative tools to the masses. diff --git a/website/content/_index.md b/website/content/_index.md index 7cccc18d..ad90801e 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -1,21 +1,26 @@ +++ title = "Web-based vector graphics editor and design tool" -template = "section.html" # Avoids needing a separate `index.html` template that's identical to `section.html` +template = "section.html" [extra] css = ["/index.css"] js = ["/image-interaction.js", "/fundraising.js"] +++ + + + + + + +
-
- -# Redefining state-of-the-art graphics editing +

Redefining state‑of‑the‑art graphics editing

Graphite is an in-development raster and vector graphics package that's free and open source. It is powered by a node graph compositing engine that fuses layers with nodes, providing a fully nondestructive editing experience.

+
@@ -52,6 +63,7 @@ js = ["/image-interaction.js", "/fundraising.js"]
+ -
+ + + +
-
+
# Graphite today @@ -129,7 +144,7 @@ js = ["/image-interaction.js", "/fundraising.js"] Graphite is a lightweight vector graphics editor that runs in your browser. Its node-based compositor lets you apply image effects and co-create art with generative AI.
-
+
# Graphite tomorrow @@ -158,10 +173,11 @@ Graphite is a lightweight vector graphics editor that runs in your browser. Its
- + + +
-
@@ -199,13 +215,10 @@ You'll receive your first newsletter email with the next major Graphite news.
-
- -
+ + + +
# Art takes shape @@ -245,12 +259,11 @@ Make vector art out of shapes ranging from simple geometric primitives to comple Style your shapes with strokes, fills, and gradients. Mix your layers with blend modes. Then export as SVG. -
+
-
Vector art of Just of Potted Cactus

@@ -268,44 +281,11 @@ Style your shapes with strokes, fills, and gradients. Mix your layers with blend

- - - + + +
-

Co-createIdeateIllustrateGenerateIterate with Imaginate

@@ -314,9 +294,6 @@ Apply effects directly in the layer stack to modify the artwork underneath. Comb
-
- -
@@ -348,7 +325,6 @@ Apply effects directly in the layer stack to modify the artwork underneath. Comb
Watercolor painting of a light bulb gleaming with an exclamation mark inside
-
## Work fast, be sloppy @@ -380,13 +356,14 @@ Apply effects directly in the layer stack to modify the artwork underneath. Comb
-
- + + +
-
+
@@ -422,9 +399,42 @@ Graphite is built by a small, dedicated crew of volunteers in need of resources
+ + + +
+
-
-
+# Powerful proceduralism + +The data-driven approach to design affords unique capabilities that are presently in-development. + +
+
+ + Fully nondestructive editing with node-driven layers +
+
+ + Infinitely scalable raster content with no pixelation +
+
+ + Integrates generative AI models and graphics algorithms +
+
+ + Procedural pipelines for studio production environments +
+
+ +
+
+ + + +
+
# One app to rule them all @@ -459,37 +469,10 @@ Stop jumping between programs. Planned features will make Graphite a first-class
- -
-
- -# Powerful proceduralism - -The data-driven approach to design affords unique capabilities that are presently in-development. - -
-
- - Fully nondestructive editing with node-driven layers -
-
- - Infinitely scalable raster content with no pixelation -
-
- - Integrates generative AI models and graphics algorithms -
-
- - Procedural pipelines for studio production environments -
-
- -
-
- -
+ + + +
@@ -497,7 +480,9 @@ The data-driven approach to design affords unique capabilities that are presentl
- + + +
@@ -518,3 +503,4 @@ The data-driven approach to design affords unique capabilities that are presentl
+ diff --git a/website/content/about.md b/website/content/about.md index 658bc599..9c4cfd93 100644 --- a/website/content/about.md +++ b/website/content/about.md @@ -5,7 +5,7 @@ title = "About Graphite" css = ["/about.css"] +++ -
+
# About Graphite @@ -15,7 +15,7 @@ Graphite is a community-built, open source software project that is free to use
-
+
## Project @@ -25,7 +25,7 @@ The idea for Graphite began with a desire to create artwork and edit photos usin
-
+
@@ -90,7 +90,7 @@ As an independent community-driven software project, Graphite will always remain })(); --> - +Become the author of release notes, feature announcements, blog posts, website content, the user manual, press releases, social media posts, and industry outreach.
diff --git a/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md b/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md index 458835dd..7100800c 100644 --- a/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md +++ b/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md @@ -44,4 +44,4 @@ Once you begin writing code, please open a pull request immediately and mark it Open a new PR as a draft / convert an existing PR to a draft: -![Screenhots showing GitHub's "Create pull request (arrow) > Create draft pull request" and "Still in progress? Convert to draft" buttons](https://static.graphite.rs/content/contribute/draft-pr.png) +![Screenhots showing GitHub's "Create pull request (arrow) > Create draft pull request" and "Still in progress? Convert to draft" buttons](https://static.graphite.rs/content/volunteer/guide/draft-pr.png) diff --git a/website/sass/base.scss b/website/sass/base.scss index cf420492..b579d5e3 100644 --- a/website/sass/base.scss +++ b/website/sass/base.scss @@ -18,7 +18,7 @@ --color-sage: #739c7e; --color-seaside-rgb: 165, 213, 200; - --font-size-intro-heading: 60px; + --font-size-intro-heading: calc(var(--font-size-heading-h1) * 1.25); --font-size-intro-body: 22px; --font-size-link: 24px; --font-size-heading-h1: 48px; @@ -45,6 +45,7 @@ --font-size-body: 16px; --page-edge-padding: 28px; + --border-thickness: 1px; } @media screen and (max-width: 500px) { @@ -56,7 +57,6 @@ --font-size-body: 16px; --page-edge-padding: 20px; - --border-thickness: 1px; } @media screen and (max-width: 400px) { @@ -162,28 +162,28 @@ p ~ p { margin-top: 1.5em; } -h1 ~ p, -h2 ~ p, -h3 ~ p, -h1 ~ ol li p, -h2 ~ ol li p, -h3 ~ ol li p, -h1 ~ img, -h2 ~ img, -h3 ~ img, -h1 + .section-row, +h1, +h2, +h3 { + & ~ p, + & ~ ol li p, + & ~ img { + margin-top: 20px; + } +} + h1 ~ .informational-group, -.video-embed + p, p ~ h1, p ~ h2, p ~ h3, p ~ details summary, p ~ blockquote, -p ~ video, -p ~ .video-embed, p ~ .informational-group, p ~ .image-comparison, p + .link, +p ~ .video-background, +p ~ .video-embed, +.video-embed + p, .video-embed + .link, .video-embed + .button, img + .link { @@ -216,6 +216,8 @@ 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); @@ -241,6 +243,8 @@ pre { display: block; overflow-x: auto; padding: 20px; + width: 0; + flex: 1 1 auto; } // Language name in top right corner @@ -338,7 +342,6 @@ summary { .reading-material.reading-material.reading-material { max-width: 800px; - flex: 0 1 auto; hr { margin-top: 40px; @@ -396,6 +399,24 @@ summary { } } +.video-background { + position: relative; + font-size: 0; + + video { + max-width: Min(100%, 1280px); + } + + // Uses a white border over the video to cover up the edges of the video which, due to a Chrome rendering bug, displays black edges sometimes when scrolling + &::after { + content: ""; + position: absolute; + inset: 0; + border: 2px solid white; + pointer-events: none; + } +} + .image-comparison { position: relative; touch-action: pan-y pinch-zoom; @@ -793,23 +814,6 @@ hr, } } -.section-row { - display: flex; - align-items: stretch; - gap: calc(40 * var(--variable-px)) calc(80 * var(--variable-px)); - - &.vertical { - flex-direction: column; - } - - @media screen and (max-width: 800px) { - &.section-row { - flex-direction: column; - align-items: center; - } - } -} - .info-box { margin-top: calc(40 * var(--variable-px)); padding: calc(80 * var(--variable-px)); @@ -885,11 +889,6 @@ hr, background: var(--color-crimson); } } - - + div, - hr + .section-row + & { - margin-top: calc(80 * var(--variable-px)); - } } .informational-group { @@ -931,10 +930,21 @@ hr, &.concepts { justify-content: space-between; - + margin: 0 -10px; + width: calc(100% + 20px); + .informational { 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; @@ -942,6 +952,10 @@ hr, object-position: calc(-72px * var(--atlas-index)) 0; margin-bottom: 8px; } + + span { + text-align: center; + } } } @@ -985,255 +999,251 @@ blockquote { } } -// Page content - -.page { +body > .page { box-sizing: border-box; min-width: 320px; - header { - padding: 0 var(--page-edge-padding); - color: var(--color-walnut); - - // var(--max-width) + (80px + 32px) * 2 - @media screen and (max-width: 1824px) { - .ripple { - width: calc(100% + (40px * 2)); - margin-left: -40px; - margin-right: -40px; - } - - hr { - display: none; - } - } - - nav { - margin: auto; - max-width: var(--max-width); - - .row { - display: flex; - justify-content: space-between; - padding: 30px 0; - - @media screen and (max-width: 760px) { - padding: 20px 0; - } - - .left, - .right { - display: flex; - align-items: center; - gap: 40px; - - a { - color: inherit; - font-family: "Bona Nova", Palatino, serif; - font-feature-settings: "lnum"; - line-height: 1.25; - font-weight: 700; - text-decoration: none; - --height: 60px; - --button-padding: 24px; - --nav-font-size: 28px; - font-size: var(--nav-font-size); - - &.button { - height: var(--height); - padding-left: var(--button-padding); - padding-right: var(--button-padding); - line-height: calc(var(--height) - 2 * var(--border-thickness)); - font-size: var(--nav-font-size); - } - - img { - display: block; - width: var(--height); - height: var(--height); - } - } - - &.left img { - // Don't show the alt text if the image doesn't load - font-size: 0; - } - - @media screen and (max-width: 1200px) { - gap: 30px; - - a { - --height: 50px; - --button-padding: 16px; - --nav-font-size: 24px; - } - } - - @media screen and (max-width: 960px) { - gap: 30px; - - a { - --height: 50px; - --button-padding: 16px; - --nav-font-size: 20px; - } - } - - @media screen and (max-width: 880px) { - gap: 20px; - - a { - --height: 40px; - --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; - } - } - - @media screen and (max-width: 600px) { - gap: 12px; - - a { - --height: 24px; - --button-padding: 8px; - --nav-font-size: 13px; - } - } - - @media screen and (max-width: 540px) { - gap: 10px; - - a { - --height: 22px; - --button-padding: 6px; - --nav-font-size: 12px; - } - } - - @media screen and (max-width: 480px) { - gap: 8px; - - a { - --height: 20px; - --button-padding: 4px; - --nav-font-size: 11px; - } - } - - @media screen and (max-width: 430px) { - gap: 6px; - - a { - --height: 20px; - --button-padding: 4px; - --nav-font-size: 10px; - } - } - } - } - } +header { + padding: 0 var(--page-edge-padding); + color: var(--color-walnut); + @media screen and (max-width: 1824px) { .ripple { - display: block; - background: none; - fill: none; - stroke: currentColor; - --ripple-height: 16px; - height: var(--ripple-height); - margin-top: calc(-1 * var(--ripple-height) + var(--border-thickness)); - margin-bottom: calc(-1 * var(--border-thickness)); - stroke-width: var(--border-thickness); - - &::before, - &::after { - content: none; - } + width: calc(100% + (var(--page-edge-padding) * 2)); + margin-left: calc(-1 * var(--page-edge-padding)); + margin-right: calc(-1 * var(--page-edge-padding)); } hr { - background: none; + display: none; } } - main { - padding: 0 var(--page-edge-padding); + nav { + margin: auto; + max-width: var(--max-width); - .content { - padding: calc(120 * var(--variable-px)) 0; - - section { - max-width: var(--max-width); - margin: 0 auto; - // Puts the content in front of the hexagon decoration - position: relative; - z-index: 1; - - ~ section { - margin-top: calc(120 * var(--variable-px)); - } - - p img { - max-width: 100%; - } - - pre { - max-width: 100%; - box-sizing: border-box; - overflow: auto; - } - - details { - width: 100%; - } - } - } - } - - footer { - display: flex; - flex-direction: column; - align-items: center; - gap: 40px; - padding: 40px; - padding-top: 0; - color: var(--color-walnut); - - nav { + .row { display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 8px 40px; - - a { - color: var(--color-walnut); - } - - @media screen and (max-width: 900px) { - max-width: 500px; - } + justify-content: space-between; + padding: 30px 0; @media screen and (max-width: 760px) { - max-width: 440px; + padding: 20px 0; } - @media screen and (max-width: 400px) { - gap: 6px 20px; - } - } + .left, + .right { + display: flex; + align-items: center; + gap: 40px; - span { - text-align: center; + a { + color: inherit; + font-family: "Bona Nova", Palatino, serif; + font-feature-settings: "lnum"; + 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.button { + height: var(--height); + padding-left: var(--button-padding); + padding-right: var(--button-padding); + line-height: calc(var(--height) - 2 * var(--border-thickness)); + font-size: var(--nav-font-size); + } + + img { + display: block; + width: var(--height); + height: var(--height); + } + } + + &.left img { + // Don't show the alt text if the image doesn't load + font-size: 0; + } + + @media screen and (max-width: 1200px) { + gap: 30px; + + a { + --height: 50px; + --button-padding: 16px; + --nav-font-size: 24px; + } + } + + @media screen and (max-width: 960px) { + gap: 30px; + + a { + --height: 50px; + --button-padding: 16px; + --nav-font-size: 20px; + } + } + + @media screen and (max-width: 880px) { + gap: 20px; + + a { + --height: 40px; + --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; + } + } + + @media screen and (max-width: 600px) { + gap: 12px; + + a { + --height: 24px; + --button-padding: 8px; + --nav-font-size: 13px; + } + } + + @media screen and (max-width: 540px) { + gap: 10px; + + a { + --height: 22px; + --button-padding: 6px; + --nav-font-size: 12px; + } + } + + @media screen and (max-width: 480px) { + gap: 8px; + + a { + --height: 20px; + --button-padding: 4px; + --nav-font-size: 11px; + } + } + + @media screen and (max-width: 430px) { + gap: 6px; + + a { + --height: 20px; + --button-padding: 4px; + --nav-font-size: 10px; + } + } + } } } + + .ripple { + display: block; + background: none; + fill: none; + stroke: currentColor; + --ripple-height: 16px; + height: var(--ripple-height); + margin-top: calc(-1 * var(--ripple-height) + var(--border-thickness)); + margin-bottom: calc(-1 * var(--border-thickness)); + stroke-width: var(--border-thickness); + + &::before, + &::after { + content: none; + } + } + + hr { + background: none; + } +} + +main { + padding: 0 var(--page-edge-padding); + + .content { + padding: calc(120 * var(--variable-px)) 0; + + section { + max-width: var(--max-width); + margin: 0 auto; + // Puts the content in front of the hexagon decoration + position: relative; + z-index: 1; + + ~ section { + margin-top: calc(120 * var(--variable-px)); + } + + p img { + max-width: 100%; + } + + pre { + box-sizing: border-box; + overflow: auto; + } + + details { + width: 100%; + } + } + } +} + +footer { + display: flex; + flex-direction: column; + align-items: center; + gap: 40px; + padding: 40px; + padding-top: 0; + color: var(--color-walnut); + + nav { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px 40px; + + a { + color: var(--color-walnut); + } + + @media screen and (max-width: 900px) { + max-width: 500px; + } + + @media screen and (max-width: 760px) { + max-width: 440px; + } + + @media screen and (max-width: 400px) { + gap: 6px 20px; + } + } + + span { + text-align: center; + } +} } .fundraising { diff --git a/website/sass/blog.scss b/website/sass/blog.scss index 3ea84846..8ecbb5e4 100644 --- a/website/sass/blog.scss +++ b/website/sass/blog.scss @@ -46,10 +46,16 @@ @media screen and (max-width: 960px) { flex-wrap: wrap; justify-content: center; + flex-direction: column; .banner.banner { width: 100%; - max-width: 540px; + background: var(--color-fog); + + img { + margin: auto; + max-width: 480px; + } } } diff --git a/website/sass/book.scss b/website/sass/book.scss index 0083474c..06379494 100644 --- a/website/sass/book.scss +++ b/website/sass/book.scss @@ -1,25 +1,153 @@ .three-column-layout { + position: relative; display: flex; + gap: 40px; + transform: translate(0); .reading-material { width: 800px; - + flex: 0 0 auto; + .prev-next { display: flex; justify-content: space-between; width: 100%; - + a { display: flex; align-items: center; gap: 20px; - + svg { fill: var(--color-navy); } } } } + + @media screen and (max-width: 1320px) { + .contents { + display: none; + } + + .reading-material.reading-material { + margin-right: 0; + } + } + + .hamburger-menu-button { + display: none; + border: none; + cursor: pointer; + width: 30px; + height: 30px; + } + + // Overlaid fold-out menu + @media screen and (max-width: 1080px) { + gap: 0; + + .chapters { + position: sticky; + height: 100vh; + width: 0; + margin-top: calc(-120 * var(--variable-px)); + overflow: visible; + z-index: 10; + + &.open .wrapper-outer { + left: 0; + } + + .wrapper-outer { + position: absolute; + background: white; + top: 0; + bottom: 0; + padding-left: var(--page-edge-padding); + margin-left: calc(-1 * var(--page-edge-padding)); + padding-bottom: 120px; + margin-bottom: -120px; + border-right: var(--border-thickness) solid var(--color-walnut); + box-sizing: border-box; + width: 300px; + transition: left 0.2s ease-in-out; + left: -310px; + + &::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + right: -10px; + width: 10px; + background: linear-gradient(to right, rgba(0, 0, 0, 0.2), transparent); + } + + .wrapper-inner { + position: relative; + overflow-y: auto; + height: 100%; + padding-right: var(--page-edge-padding); + padding-bottom: 120px; + + ul:first-of-type { + margin-top: calc(120 * var(--variable-px)); + } + + .hamburger-menu-button.close { + display: inline-block; + background: none; + overflow: hidden; + position: absolute; + top: 20px; + right: 20px; + + &::before, + &::after { + content: ""; + position: absolute; + background: var(--color-walnut); + width: 36px; + height: 4px; + top: 50%; + left: 50%; + transform: translate(-18px, -2px) rotate(45deg); + } + + &::after { + transform: translate(-18px, -2px) rotate(-45deg); + } + } + } + } + } + + .reading-material { + margin-left: auto; + margin-right: auto; + width: 100%; + + .article-title { + display: flex; + white-space: nowrap; + gap: 20px; + + .hamburger-menu-button.open { + flex: 0 0 auto; + position: relative; + display: inline-block; + vertical-align: top; + top: calc(var(--font-size-heading-h1) * 0.25); + background: linear-gradient(to bottom, transparent calc(25% / 3), var(--color-walnut) calc(25% / 3), var(--color-walnut) calc(75% / 3), transparent calc(75% / 3), transparent calc(125% / 3), var(--color-walnut) calc(125% / 3), var(--color-walnut) calc(175% / 3), transparent calc(175% / 3), transparent calc(225% / 3), var(--color-walnut) calc(225% / 3), var(--color-walnut) calc(275% / 3), transparent calc(275% / 3)); + } + + h1 { + white-space: normal; + } + } + } + } aside { position: sticky; @@ -55,8 +183,11 @@ } - &.chapters li.active a { - color: var(--color-ale); + &.chapters { + li.active, + li.active a { + color: var(--color-ale); + } } &.contents { diff --git a/website/sass/index.scss b/website/sass/index.scss index 4f70d2b3..d9f4b016 100644 --- a/website/sass/index.scss +++ b/website/sass/index.scss @@ -2,6 +2,7 @@ overflow: hidden; } +// ▛ LOGO ▜ #logo { display: flex; @@ -11,6 +12,7 @@ max-height: 240px; } } +// ▙ LOGO ▟ .pencil-texture { position: absolute; @@ -26,6 +28,7 @@ } } +// ▛ QUICK LINKS ▜ #quick-links { margin-top: calc(80 * var(--variable-px)); display: flex; @@ -36,15 +39,18 @@ display: flex; gap: calc(var(--font-size-link) * 0.8); flex-direction: row; + flex-wrap: wrap; img { - width: 48px; + width: calc(var(--font-size-link) * 2); display: block; } } } +// ▙ QUICK LINKS ▟ -#hero-message { +// ▛ TAGLINE ▜ +#tagline { h1 { font-size: var(--font-size-intro-heading); } @@ -57,6 +63,7 @@ } } } +// ▙ TAGLINE ▟ .hexagons { max-width: var(--max-width); @@ -90,157 +97,13 @@ } } -#graphite-tomorrow > img { - margin: 16px 0; -} - -#disciplines { - align-items: center; - - .informational-group { - margin-top: 0; - - .informational { - margin-top: 40px; - } - } -} - -// #node-graph { -// #node-graph-intro { -// .section { -// align-items: center; -// } - -// ~ section { -// margin-top: calc(80 * var(--variable-px)); -// } -// } -// } - -#vector-art { - .section { - align-items: center; - - .background-video { - position: relative; - font-size: 0; - - video { - max-width: Min(100%, 1280px); - } - - // Uses a white border over the video to cover up the edges of the video which, due to a Chrome rendering bug, displays black edges sometimes when scrolling - &::after { - content: ""; - position: absolute; - inset: 0; - border: 2px solid white; - pointer-events: none; - } - } - - .download-artwork { - display: flex; - align-items: center; - - img { - width: 128px; - height: 128px; - border: 12px solid var(--color-walnut); - vertical-align: top; - } - - p { - display: flex; - flex-direction: column; - max-width: 300px; - margin-left: 40px; - text-align: left; - } - } - } -} - -#imaginate { - #imaginate-intro { - .alternating-text { - position: relative; - - span { - // Move left by half (since it's centered) the average (half the 74px difference) of the variance in word lengths - margin-left: calc(-1.54em / 2 / 2); - opacity: 0; - $alternate-duration: 15s; - $alternate-words: 5; - animation: $alternate-duration infinite linear 0s fade-word; - - // The 1st child is the widest - &:not(:nth-child(1)) { - position: absolute; - right: 0; - } - - @for $i from 1 through $alternate-words { - &:nth-child(#{$i}) { - animation-delay: ($alternate-duration / $alternate-words * ($i - 1)); - } - } - - @keyframes fade-word { - // Fade in at the start (which begins staggered on each item by `animation-delay`) - #{0.0%} { opacity: 0; } - #{2.5%} { opacity: 1; } - // Remain visible for this item's slice of time, then fade out - #{0.0% + 100% / ($alternate-words + 1)} { opacity: 1; } - #{2.5% + 100% / ($alternate-words + 1)} { opacity: 0; } - } - } - } - - .section { - align-items: center; - } - - ~ section { - margin-top: calc(80 * var(--variable-px)); - } - } - - // #imaginate-creative-concepts-carousel { - // margin-top: 20px; - - // .screenshot-details { - // justify-content: center; - // } - - // + blockquote { - // margin-top: 0; - // } - // } -} - -.feature-explainer { - margin-top: 40px; - - .diptych { - width: 100%; - - .section { - justify-content: center; - align-items: center; - - h2 { - text-align: center; - } - } - } - - .section { - flex: 1 1 calc(50% - (80 * var(--variable-px)) / 2); - } -} +// ▛ SCREENSHOTS ▜ +// ▙ SCREENSHOTS ▟ +// ▛ TODAY AND TOMORROW ▜ +// ▙ TODAY AND TOMORROW ▟ +// +// ▛ COMMUNITY ▜ #community { background-color: var(--color-lime); @@ -273,6 +136,8 @@ display: flex; gap: 20px; flex: 100000 1 0; + flex-wrap: wrap; + min-width: Min(100%, calc(240px + 20px + 240px)); div { min-height: auto; @@ -339,6 +204,7 @@ font-size: calc(var(--font-size-link) * 0.9); color: inherit; border: var(--border-thickness) solid currentColor; + border-radius: 0; // Required for iOS Safari outline: none; margin: 0; padding: 0 var(--font-size-link); @@ -355,6 +221,7 @@ background: none; outline: none; cursor: pointer; + border-radius: 0; // Required for iOS Safari &:focus { border-color: var(--input-focus-color); @@ -394,11 +261,109 @@ } } } +// ▙ COMMUNITY ▟ -#demo-video { - max-width: 1000px; +// ▛ VECTOR ART ▜ +#vector-art { + .section { + align-items: center; + + .download-artwork { + display: flex; + align-items: center; + margin-top: 20px; + + img { + width: 128px; + 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; + } + } + } } +// ▙ VECTOR ART ▟ +// ▛ IMAGINATE ▜ +#imaginate { + > .section { + align-items: center; + + h1 { + text-align: center; + + .alternating-text { + position: relative; + + span { + // Move left by half (since it's centered) the average (half the 74px difference) of the variance in word lengths + margin-left: calc(-1.54em / 2 / 2); + opacity: 0; + $alternate-duration: 15s; + $alternate-words: 5; + animation: $alternate-duration infinite linear 0s fade-word; + + // The 1st child is the widest + &:not(:nth-child(1)) { + position: absolute; + right: 0; + } + + @for $i from 1 through $alternate-words { + &:nth-child(#{$i}) { + animation-delay: ($alternate-duration / $alternate-words * ($i - 1)); + } + } + + @keyframes fade-word { + // Fade in at the start (which begins staggered on each item by `animation-delay`) + #{0.0%} { opacity: 0; } + #{2.5%} { opacity: 1; } + // Remain visible for this item's slice of time, then fade out + #{0.0% + 100% / ($alternate-words + 1)} { opacity: 1; } + #{2.5% + 100% / ($alternate-words + 1)} { opacity: 0; } + } + } + } + } + } + + > .diptych { + margin-top: calc(80 * var(--variable-px)); + + .section { + align-items: center; + + h2 { + text-align: center; + } + } + } + + // #imaginate-creative-concepts-carousel { + // margin-top: 20px; + + // .screenshot-details { + // justify-content: center; + // } + + // + blockquote { + // margin-top: 0; + // } + // } +} +// ▙ IMAGINATE ▟ + +// ▛ FUNDRAISING ▜ #fundraising { background-color: var(--color-seaside); color: rgba(0, 0, 0, 0.9); @@ -407,8 +372,33 @@ max-width: 400px; } } +// ▙ FUNDRAISING ▟ +// ▛ PROCEDURALISM ▜ +#proceduralism .section { + align-items: center; +} +// ▙ PROCEDURALISM ▟ + +// ▛ DISCIPLINES ▜ +#disciplines .section { + align-items: center; + + .informational-group .informational { + margin-top: 40px; + } +} +// ▙ DISCIPLINES ▟ + +// ▛ DEMO VIDEO ▜ +#demo-video { + max-width: 1000px; +} +// ▙ DEMO VIDEO ▟ + +// ▛ GET INVOLVED ▜ #get-involved-box { background-color: var(--color-lemon); background-blend-mode: color-burn; } +// ▙ GET INVOLVED ▟ diff --git a/website/sass/volunteer.scss b/website/sass/volunteer.scss index 5be39929..6e31be31 100644 --- a/website/sass/volunteer.scss +++ b/website/sass/volunteer.scss @@ -17,3 +17,12 @@ background-color: var(--color-ale); } } + +.creative-contributions, +.code-contributions { + .button.button.button { + height: auto; + text-align: left; + white-space: normal; + } +} diff --git a/website/static/js/book.js b/website/static/js/book.js index b637de6d..6419ac72 100644 --- a/website/static/js/book.js +++ b/website/static/js/book.js @@ -1,4 +1,5 @@ addEventListener("DOMContentLoaded", trackScrollHeadingInTOC); +addEventListener("DOMContentLoaded", listenForClickToOpenTOC); // Listen for scroll events and update the active section in the table of contents to match the visible content's heading function trackScrollHeadingInTOC() { @@ -50,3 +51,13 @@ function trackScrollHeadingInTOC() { addEventListener("scroll", updateVisibleHeading); updateVisibleHeading(); } + +function listenForClickToOpenTOC() { + document.querySelector("[data-hamburger-menu-button-open]")?.addEventListener("click", () => { + document.querySelector("[data-chapters]")?.classList.add("open"); + }); + + document.querySelector("[data-hamburger-menu-button-close]")?.addEventListener("click", () => { + document.querySelector("[data-chapters]")?.classList.remove("open"); + }); +} diff --git a/website/static/js/navbar.js b/website/static/js/navbar.js index 71a7ab08..08d41397 100644 --- a/website/static/js/navbar.js +++ b/website/static/js/navbar.js @@ -1,6 +1,6 @@ -const NAV_BUTTON_INITIAL_FONT_SIZE = 32; +const NAV_BUTTON_INITIAL_FONT_SIZE = 28; // Keep up to date with `--nav-font-size` in base.scss const RIPPLE_ANIMATION_MILLISECONDS = 100; -const RIPPLE_WIDTH = 120; +const RIPPLE_WIDTH = 100; const HANDLE_STRETCH = 0.4; let ripplesInitialized; @@ -84,10 +84,11 @@ function animate(forceRefresh) { } function setRipples() { + const rippleStrokeWidth = Number.parseInt(window.getComputedStyle(ripplePath).getPropertyValue("--border-thickness"), 10); const navButtonFontSize = Number.parseInt(window.getComputedStyle(navButtons[0]).fontSize, 10) || NAV_BUTTON_INITIAL_FONT_SIZE; const mediaQueryScaleFactor = navButtonFontSize / NAV_BUTTON_INITIAL_FONT_SIZE; - const rippleHeight = fullRippleHeight * (mediaQueryScaleFactor * 0.5 + 0.5); + const rippleHeight = Math.round(fullRippleHeight * mediaQueryScaleFactor) + (rippleStrokeWidth === 2 ? 0 : 0.5); const rippleSvgRect = rippleSvg.getBoundingClientRect(); const rippleSvgLeft = rippleSvgRect.left; const rippleSvgWidth = rippleSvgRect.width; diff --git a/website/static/js/text-justification.js b/website/static/js/text-justification.js new file mode 100644 index 00000000..589f180a --- /dev/null +++ b/website/static/js/text-justification.js @@ -0,0 +1,28 @@ +window.addEventListener("DOMContentLoaded", () => { + document.querySelectorAll("section p").forEach((paragraph) => { + // Recursively traverse the DOM tree and modify the text nodes + const recursivelyAddWbr = (node) => { + if (node.nodeType === Node.TEXT_NODE) { + const newNodes = node.textContent.split("/"); + for (let i = 0; i < newNodes.length - 1; i++) { + newNodes[i] += "/"; + } + + const tempSpan = document.createElement("span"); + tempSpan.innerHTML = newNodes.join(""); + const replacementNodes = tempSpan.childNodes; + + mutationQueue.push([node, replacementNodes]); + } else { + node.childNodes.forEach(recursivelyAddWbr); + } + }; + + // Perform the recursive traversal and replace the text nodes + const mutationQueue = []; + recursivelyAddWbr(paragraph); + mutationQueue.forEach(([node, newNodes]) => { + node.replaceWith(...newNodes); + }); + }); +}); diff --git a/website/templates/404.html b/website/templates/404.html index a0a47944..4a4ba705 100644 --- a/website/templates/404.html +++ b/website/templates/404.html @@ -3,7 +3,7 @@ {% block title %}Page not found{% endblock title %} {% block content %} -
+

Page not found

Or as the machines like to say it: 404.

diff --git a/website/templates/article.html b/website/templates/article.html index 1d7419b9..aa0ecd57 100644 --- a/website/templates/article.html +++ b/website/templates/article.html @@ -14,7 +14,7 @@ {% block content %} {% set this = section | default(value = page) %} -
+

{{ this.title }}

diff --git a/website/templates/base.html b/website/templates/base.html index e3dd52b2..e2082dfe 100644 --- a/website/templates/base.html +++ b/website/templates/base.html @@ -25,6 +25,7 @@ {% endfor %} {% endif %} +