From 2b740a7000413e3d7ecb23d136b491d904b90ee9 Mon Sep 17 00:00:00 2001 From: Andrew Gioia Date: Tue, 28 Apr 2026 11:07:59 -0400 Subject: [PATCH] Initial draft is done! Design updated and extremely close to final; new hero artwork added; improvements to screen size handling across the board --- assets/css/site.css | 772 +++++++++++++----- assets/icons/cc.svg | 1 + assets/img/kangaroo.svg | 1 + content/studies/legacy/img/context-ds.png | Bin 0 -> 64321 bytes content/studies/legacy/img/context-ds@2x.png | Bin 0 -> 155536 bytes content/studies/legacy/img/context-header.png | Bin 0 -> 197604 bytes content/studies/legacy/img/kangaroo-eyes.svg | 13 + .../studies/legacy/img/problem-critical.png | Bin 0 -> 236948 bytes content/studies/legacy/img/problem-find.png | Bin 0 -> 1008992 bytes .../studies/legacy/img/problem-multiple.png | Bin 0 -> 255867 bytes .../studies/legacy/img/response-forms@2x.png | Bin 0 -> 119783 bytes .../studies/legacy/img/response-users@2x.png | Bin 0 -> 222030 bytes .../legacy/img/response-widget-desktop@2x.png | Bin 0 -> 29512 bytes .../legacy/img/response-widget-mobile@2x.png | Bin 0 -> 307812 bytes content/studies/legacy/index.md | 347 +++++++- layouts/_default/baseof.html | 16 +- layouts/_default/study.html | 87 +- layouts/partials/footer.html | 6 +- layouts/shortcodes/overview.html | 3 - layouts/shortcodes/problem.html | 35 +- layouts/shortcodes/response.html | 18 + layouts/shortcodes/section.html | 9 + static/img/kangaroo-eyes.svg | 13 + static/img/kangaroo.svg | 1 + static/img/nyc.svg | 1 + static/js/main.js | 180 +++- 26 files changed, 1169 insertions(+), 334 deletions(-) create mode 100644 assets/icons/cc.svg create mode 100644 assets/img/kangaroo.svg create mode 100644 content/studies/legacy/img/context-ds.png create mode 100644 content/studies/legacy/img/context-ds@2x.png create mode 100644 content/studies/legacy/img/context-header.png create mode 100644 content/studies/legacy/img/kangaroo-eyes.svg create mode 100644 content/studies/legacy/img/problem-critical.png create mode 100644 content/studies/legacy/img/problem-find.png create mode 100644 content/studies/legacy/img/problem-multiple.png create mode 100644 content/studies/legacy/img/response-forms@2x.png create mode 100644 content/studies/legacy/img/response-users@2x.png create mode 100644 content/studies/legacy/img/response-widget-desktop@2x.png create mode 100644 content/studies/legacy/img/response-widget-mobile@2x.png create mode 100644 layouts/shortcodes/response.html create mode 100644 layouts/shortcodes/section.html create mode 100644 static/img/kangaroo-eyes.svg create mode 100644 static/img/kangaroo.svg create mode 100644 static/img/nyc.svg diff --git a/assets/css/site.css b/assets/css/site.css index a683224..cace71a 100644 --- a/assets/css/site.css +++ b/assets/css/site.css @@ -1,26 +1,41 @@ -:root { +:root +{ --bg: #f0ede6; --text: #171717; --hover: #070707; - --muted: #676767; + --muted: #575757; --faded: #979797; - --primary: #00b0CD; + --primary: #00b0cd; --secondary: #80c0cc; - --gray: #6f6f6f; - --pink: #E463D2; - --cyan: #00C4D8; - --green: #00D771; - --blue: #2096F6; - --orange: #E78B05; + + --yellow: #ECAF21; + --yellow-body: #E29900; + --red: #eb452b; + --red-body: #de342a; + --blue: #3157AE; /*#2F4C8E;*/ + --blue-body: #0070C0; + --black: #272727; + --bg1: #E5DAD2; + --green-body: #03A653; + + --darkcyan: #008694; + + --lightblue: #e6f3fe; + --lightcyan: #e2ffff; /*--line: rgba(23, 23, 23, 0.12);*/ --line: #272727; --light: #dfdfdf; --white: #f7f7f7; --surface: rgba(255, 255, 255, 0.28); + --font-sans: Inter, -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, Arial, sans-serif; --font-serif: "Source Serif", "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif; + --column-width: min(72rem, calc(100% - 3rem)); --content-width: min(48rem, calc(100% - 3rem)); + --article-grid: 1fr; + --article-gap: 2rem; + --article-top: 0; } * { @@ -36,35 +51,19 @@ a { color: inherit; font-weight: 500; text-decoration: underline; - text-decoration-thickness: 1px; + text-decoration-thickness: 1.5px; text-underline-offset: 0.2rem; &:hover { color: var(--hover); text-decoration: underline; - text-decoration-thickness: 1px; + text-decoration-thickness: 1.5px; text-underline-offset: 0.2rem; } } -.icon { - align-items: center; - display: inline-flex; - flex: 0 0 auto; - height: 1em; - justify-content: center; - line-height: 1; - width: 1em; -} - -.icon svg { - display: block; - height: 100%; - width: 100%; -} - h1 { - font-size: clamp(2.5rem, 10dvw, 4rem); + font-size: clamp(2.25rem, 9dvw, 4rem); font-weight: 700; letter-spacing: -0.5px; line-height: 1; @@ -72,17 +71,33 @@ h1 { } h2 { - font-size: clamp(1.5rem, 4vw, 2rem); - font-weight: 700; - line-height: 1.3; + font-size: clamp(1.75rem, 2.25dvw, 2.375rem); + font-weight: 800; + line-height: 1.1; margin: 0 0 1.5rem; + padding-top: 2rem; + text-shadow: 0 1px 0 #fff; } h3 { - color: var(--muted); - font-size: 1.4rem; - font-weight: 700; + color: var(--text); + font-size: clamp(1.33rem, 3vw, 1.625rem); + font-weight: 800; line-height: 1.3; + margin-top: 2rem; + margin-bottom: 1rem; + text-shadow: 0 1px 0 #fff; + + #impact & { + font-size: 1.1rem; + } +} + +h4 { + font-size: 1.1rem; + font-weight: 800; + margin-bottom: 0; + text-shadow: 0 1px 0 #fff; } body { @@ -94,7 +109,7 @@ body { display: grid; font-family: var(--font-sans); grid-template-rows: 5rem 1fr auto; - line-height: 1.6; + line-height: 1.5; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; width: 100dvw; @@ -110,13 +125,14 @@ body { /* site header */ > header { - border-bottom: 1px solid var(--light); + border-bottom: 1px solid var(--black); padding: 0 1.5rem; + position: relative; .title { align-items: center; display: flex; - gap: 1rem; + gap: 0.75rem; height: 100%; align-items: stretch; } @@ -126,57 +142,82 @@ body { align-items: center; display: flex; font-size: 1.5rem; - gap: 0.5rem; + gap: 0.5rem;; text-decoration: none; + + &:hover { + text-decoration: underline; + } } .logo { font-weight: 700; + letter-spacing: -0.04rem } .page { - font-weight: 700; + font-weight: 800; } .logo:has(+ .page) { - color: var(--faded); + font-weight: 500; + letter-spacing: 0; } - .scheme { - color: var(--faded); - } - - .param { - color: var(--text); - } - - nav { + /* right menu */ + menu { align-items: center; display: none; - gap: 1.5rem; + gap: 1rem; font-size: 1rem; + list-style: none; - a { - text-decoration: none; + a:hover { + color: #000; + text-decoration-thickness: 2.5px; } } + + /* line detail */ + &::before, + &::after { + content: ''; + display: block; + width: calc(100% + 1.5rem); + height: 1px; + background: var(--black); + position: absolute; + bottom: -5px; + left: -1.5rem; + } + &::after { + bottom: -9px; + } } /* site footer */ > footer { - color: var(--muted); + background: var(--black); + color: var(--white); display: flex; flex-direction: column; + font-size: 0.875rem; gap: 2rem; - padding-top: 2rem; + line-height: 1.4; + padding: 2rem 1.5rem; + justify-content: center; section { - width: var(--column-width); + display: grid; + grid-template-columns: var(--article-grid); + gap: var(--article-gap); + justify-content: center; } #footnotes ul { + grid-column-start: 2; list-style: none; - margin: 0; + margin: 0 0 0 -1.5rem; padding: 0; li { @@ -185,90 +226,157 @@ body { span.symbol { font-size: 1.25rem; + margin-top: -3px; + } + } + } + + #end { + padding-bottom: 2rem; + + .text { + grid-column-start: 2; + } + } + + big { + color: var(--white); + font-size: 1.5rem; + font-weight: bold; + } + } +} + +/* + *
is case study wrapper and includes: + * 1.
is the initial full screen pane + * 2.
{{- with .Params.study.toc -}} @@ -46,9 +70,8 @@ {{- end -}} -
{{ .Content }}
-{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index ef4f4ce..c65bbba 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -9,6 +9,7 @@ {{- if gt (len $footnotes) 0 -}}
+ Ag
    {{- range $footnotes -}}
  • @@ -25,5 +26,8 @@ {{- end -}}
    -

    Footer.

    +
    +

    This is the design portfolio for Andrew Gioia, co-founder of TeachBoost and current Staff Designer at SchoolStatus.

    +
    {{ partial "icon.html" (dict "name" "cc") }} 2026 BY-NC-ND. Please share this responsibly.
    +
    \ No newline at end of file diff --git a/layouts/shortcodes/overview.html b/layouts/shortcodes/overview.html index 03b1f23..81922cd 100644 --- a/layouts/shortcodes/overview.html +++ b/layouts/shortcodes/overview.html @@ -1,8 +1,5 @@ {{- $id := .Get "id" | default "overview" -}} {{- $title := .Get "title" | default "Project overview" -}} -{{- $businessReasonTitle := .Get "business_reason_title" | default "Business reason for the work" -}} -{{- $mediaCaption := .Get "media_caption" -}} -{{- $mediaPlaceholder := .Get "media_placeholder" | default "Original product screenshot placeholder" -}}

    {{ $title }}

    diff --git a/layouts/shortcodes/problem.html b/layouts/shortcodes/problem.html index 108a83d..fea25a0 100644 --- a/layouts/shortcodes/problem.html +++ b/layouts/shortcodes/problem.html @@ -1,32 +1,9 @@ +{{- $color := .Get "color" -}} {{- $title := .Get "title" -}} -{{- $image := .Get "image" -}} -{{- $alt := .Get "alt" | default $title -}} -{{- $caption := .Get "caption" -}} -{{- $placeholder := .Get "placeholder" | default "Problem screenshot placeholder" -}} -{{- with $title }} -

    {{ . }}

    -{{- end }} - -{{ .Inner | markdownify }} - - \ No newline at end of file + {{ .Inner | markdownify }} + \ No newline at end of file diff --git a/layouts/shortcodes/response.html b/layouts/shortcodes/response.html new file mode 100644 index 0000000..220acf8 --- /dev/null +++ b/layouts/shortcodes/response.html @@ -0,0 +1,18 @@ +{{- $title := .Get "title" -}} +{{- $label := .Get "label" -}} +{{- $lede := .Get "lede" -}} +{{- $body := .Inner -}} +
    +{{- with $label }} + +{{- end -}} +{{- with $title }} +

    {{ . }}

    +{{- end }} +{{- with $lede }} +
    {{ . | markdownify }}
    +{{- end }} +
    +{{ $body | .Page.RenderString }} +
    +
    \ No newline at end of file diff --git a/layouts/shortcodes/section.html b/layouts/shortcodes/section.html new file mode 100644 index 0000000..9ca244b --- /dev/null +++ b/layouts/shortcodes/section.html @@ -0,0 +1,9 @@ +{{- $id := .Get "id" -}} +{{- $title := .Get "title" -}} +{{- $body := .Inner -}} + + {{- with $title }} +

    {{ . }}

    + {{- end }} + {{ $body | .Page.RenderString }} +
    diff --git a/static/img/kangaroo-eyes.svg b/static/img/kangaroo-eyes.svg new file mode 100644 index 0000000..50a7613 --- /dev/null +++ b/static/img/kangaroo-eyes.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/img/kangaroo.svg b/static/img/kangaroo.svg new file mode 100644 index 0000000..e17418f --- /dev/null +++ b/static/img/kangaroo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/nyc.svg b/static/img/nyc.svg new file mode 100644 index 0000000..36cfa90 --- /dev/null +++ b/static/img/nyc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/js/main.js b/static/js/main.js index 7e86e4c..a842406 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -1,44 +1,148 @@ document.addEventListener("DOMContentLoaded", () => { - const toc = document.querySelector("article > nav#toc"); - const content = document.querySelector("article > div#content"); + const setupKangarooEye = () => { + const heroGraphic = document.querySelector("main > section > svg"); + const eye = heroGraphic?.querySelector("#eye"); + const pupil = heroGraphic?.querySelector("#pupil"); - if (!toc || !content) { - return; - } - - const links = Array.from(toc.querySelectorAll('a[href^="#"]')); - const sections = Array.from(content.querySelectorAll("section[id]")); - - if (!links.length || !sections.length) { - return; - } - - const linksById = new Map( - links.map((link) => [decodeURIComponent(link.getAttribute("href").slice(1)), link]), - ); - - const setActive = (id) => { - links.forEach((link) => { - link.classList.toggle("active", linksById.get(id) === link); - }); - }; - - const updateActive = () => { - const threshold = window.innerHeight * 0.25; - let current = sections[0]; - - sections.forEach((section) => { - if (section.getBoundingClientRect().top <= threshold) { - current = section; - } - }); - - if (current?.id) { - setActive(current.id); + if (!heroGraphic || !eye || !pupil) { + return; } + + const limits = { + left: 4, + right: 2, + vertical: 4, + }; + + let frame = null; + let pointer = null; + + const render = () => { + frame = null; + + if (!pointer) { + pupil.setAttribute("transform", "translate(0 0)"); + return; + } + + const rect = heroGraphic.getBoundingClientRect(); + const eyeRect = eye.getBoundingClientRect(); + + if (!rect.width || !rect.height || !eyeRect.width || !eyeRect.height) { + return; + } + + const eyeCenterX = eyeRect.left + (eyeRect.width / 2); + const eyeCenterY = eyeRect.top + (eyeRect.height / 2); + const normalizedX = (pointer.x - eyeCenterX) / (rect.width / 2); + const normalizedY = (pointer.y - eyeCenterY) / (rect.height / 2); + const clampedX = Math.max(-1, Math.min(1, normalizedX)); + const clampedY = Math.max(-1, Math.min(1, normalizedY)); + const moveX = clampedX < 0 ? clampedX * limits.left : clampedX * limits.right; + const moveY = clampedY * limits.vertical; + + pupil.setAttribute("transform", `translate(${moveX.toFixed(2)} ${moveY.toFixed(2)})`); + }; + + const requestRender = () => { + if (frame !== null) { + return; + } + + frame = window.requestAnimationFrame(render); + }; + + window.addEventListener("mousemove", (event) => { + pointer = { x: event.clientX, y: event.clientY }; + requestRender(); + }, { passive: true }); + + window.addEventListener("mouseleave", () => { + pointer = null; + requestRender(); + }); + + requestRender(); }; - updateActive(); - window.addEventListener("scroll", updateActive, { passive: true }); - window.addEventListener("resize", updateActive); + const setupToc = () => { + const toc = document.querySelector("article > nav#toc"); + const content = document.querySelector("article > div#content"); + const list = toc?.querySelector("ol"); + + if (!toc || !content || !list) { + return; + } + + const links = Array.from(toc.querySelectorAll('a[href^="#"]')); + const sections = Array.from(content.querySelectorAll("section[id]")); + let activeId = null; + + if (!links.length || !sections.length) { + return; + } + + const linksById = new Map( + links.map((link) => [decodeURIComponent(link.getAttribute("href").slice(1)), link]), + ); + + const scrollActiveItemIntoView = (link, behavior = "auto") => { + const item = link?.closest("li"); + + if (!item) { + return; + } + + const hasHorizontalOverflow = list.scrollWidth > list.clientWidth; + + if (!hasHorizontalOverflow) { + return; + } + + const itemLeft = item.offsetLeft; + const itemCenter = itemLeft + (item.offsetWidth / 2); + const maxScrollLeft = list.scrollWidth - list.clientWidth; + const targetLeft = Math.max(0, Math.min(maxScrollLeft, itemCenter - (list.clientWidth / 2))); + + list.scrollTo({ + behavior, + left: targetLeft, + }); + }; + + const setActive = (id, behavior = "auto") => { + const activeLink = linksById.get(id); + + links.forEach((link) => { + link.closest("li")?.classList.toggle("active", activeLink === link); + }); + + if (activeLink && activeId !== id) { + activeId = id; + scrollActiveItemIntoView(activeLink, behavior); + } + }; + + const updateActive = (behavior = "auto") => { + const threshold = window.innerHeight * 0.25; + let current = sections[0]; + + sections.forEach((section) => { + if (section.getBoundingClientRect().top <= threshold) { + current = section; + } + }); + + if (current?.id) { + setActive(current.id, behavior); + } + }; + + updateActive(); + window.addEventListener("scroll", () => updateActive("smooth"), { passive: true }); + window.addEventListener("resize", updateActive); + }; + + setupKangarooEye(); + setupToc(); });