Homepage v1 done with case study list handling; improvements to icon partial

This commit is contained in:
Andrew Gioia 2026-04-29 13:56:08 -04:00
parent 2b740a7000
commit b0b62bc062
Signed by: andrew
GPG Key ID: FC09694A000800C8
12 changed files with 583 additions and 295 deletions

View File

@ -12,11 +12,10 @@
--yellow-body: #E29900; --yellow-body: #E29900;
--red: #eb452b; --red: #eb452b;
--red-body: #de342a; --red-body: #de342a;
--blue: #3157AE; /*#2F4C8E;*/ --blue: #0070C0;
--blue-body: #0070C0;
--black: #272727; --black: #272727;
--bg1: #E5DAD2; --bg1: #E5DAD2;
--green-body: #03A653; --green: #03A653;
--darkcyan: #008694; --darkcyan: #008694;
@ -51,7 +50,7 @@ a {
color: inherit; color: inherit;
font-weight: 500; font-weight: 500;
text-decoration: underline; text-decoration: underline;
text-decoration-thickness: 1.5px; text-decoration-thickness: 0.1rem;
text-underline-offset: 0.2rem; text-underline-offset: 0.2rem;
&:hover { &:hover {
@ -60,13 +59,17 @@ a {
text-decoration-thickness: 1.5px; text-decoration-thickness: 1.5px;
text-underline-offset: 0.2rem; text-underline-offset: 0.2rem;
} }
&[in] {
text-decoration-style: dotted;
}
} }
h1 { h1 {
font-size: clamp(2.25rem, 9dvw, 4rem); font-size: clamp(2.25rem, 9dvw, 4rem);
font-weight: 700; font-weight: 700;
letter-spacing: -0.5px; letter-spacing: -0.5px;
line-height: 1; line-height: 1.05;
margin: 0 0 1rem; margin: 0 0 1rem;
} }
@ -249,16 +252,18 @@ body {
/* /*
* <main> is case study wrapper and includes: * <main> is case study wrapper and includes:
* 1. <section> is the initial full screen pane * 1. <header> is the initial full screen pane
* 2. <nav> is for the TOC * 2. <nav> is for the TOC
* 3. <article> holds the actual case study * 3. <article> holds the actual case study
*/ */
main { main {
display: grid; display: grid;
grid-template-columns: auto;
grid-template-rows: ;
justify-items: center; justify-items: center;
/* layout handling for the top sections */ /* layout handling for the top sections */
> section { > header {
align-content: start; align-content: start;
display: grid; display: grid;
grid-auto-rows: auto 12rem; grid-auto-rows: auto 12rem;
@ -268,33 +273,40 @@ main {
max-width: 100dvw; max-width: 100dvw;
width: 100dvw; width: 100dvw;
header, hgroup,
aside { aside {
display: flex; display: flex;
width: var(--column-width); width: var(--column-width);
} }
/* top hero */ /* top hero */
header { hgroup {
align-content: end;
display: grid;
padding: 4rem 0 0; padding: 4rem 0 0;
/* temporary height clamping */
&:has(+ aside) {
display: grid;
align-content: end;
/*min-height: clamp(12rem, 50dvh, 18rem);*/
}
.lede { .lede {
margin: 1rem 0 0; margin: 1rem 0 0;
font-size: 1.5rem; font-size: 1.6rem;
font-weight: 500; font-weight: 400;
line-height: 1.5; line-height: 1.5;
strong { strong {
color: var(--blue); color: var(--blue);
font-weight: 800; font-weight: 800;
} }
+ .lede {
margin-top: 1.5rem;
}
a {
text-decoration-thickness: 0.15rem;
&:hover {
text-decoration-thickness: 0.2rem;
}
}
} }
} }
@ -345,179 +357,243 @@ main {
--icon: var(--red); --icon: var(--red);
} }
&:nth-child(4) { &:nth-child(4) {
--icon: var(--green-body); --icon: var(--green);
} }
&:nth-child(5) { &:nth-child(5) {
--icon: var(--blue-body); --icon: var(--blue);
}
}
}
}
}
/* case study hero handling */
body#legacy
{
/*main > section {
background-image: url('/img/kangaroo.svg'), url('/img/nyc.svg');
background-position: bottom left, bottom right;
background-repeat: no-repeat;
background-size: clamp(150px, 20dvw, 320px) auto, clamp(250px, 50dvw, 800px) auto;
}*/
main > section {
background-image: url('/img/nyc.svg');
background-position: bottom 0 right -15dvw;
background-repeat: no-repeat;
background-size: clamp(300px, 50dvw, 800px) auto;
position: relative;
> svg {
bottom: 0;
height: auto;
left: -5dvw;
width: clamp(150px, 20dvw, 320px);
position: absolute;
}
}
}
/* case study content */
article {
background: var(--white);
border-top: 0.5rem solid var(--black);
display: grid;
gap: var(--article-gap);
grid-template-columns: var(--article-grid);
justify-content: center;
padding: var(--article-top) 1.5rem 3rem;
width: 100%;
> nav {
align-self: start;
position: sticky;
margin-left: -1.5rem;
top: 0;
width: calc(100% + 3rem);
overflow-x: hidden;
z-index: 2;
ol {
display: flex;
flex-direction: row;
list-style: decimal-leading-zero;
list-style-position: inside;
margin: 0;
overflow-x: auto;
padding: 0;
a {
color: var(--muted);
text-decoration: none;
transition: padding 125ms ease;
&:hover {
color: var(--text);
}
}
li {
background: var(--white);
border-bottom: 1px solid var(--faded);
height: 3rem;
padding: 0.6rem 1.5rem 0.5rem;
position: relative;
white-space: nowrap;
&::marker {
color: var(--muted);
}
&:last-child {
/*border: none;*/
}
&.active
{
&::after {
background: var(--black);
bottom: 0;
content: '';
display: block;
height: 4px;
left: 1.5rem;
position: absolute;
width: calc(100% - 3rem);
}
a {
color: var(--text);
font-weight: 700;
}
} }
} }
} }
} }
#content { /* case study content */
> article {
background: var(--white);
border-top: 0.5rem solid var(--black);
display: grid; display: grid;
gap: 0; gap: var(--article-gap);
} grid-template-columns: var(--article-grid);
justify-content: center;
section { padding: var(--article-top) 1.5rem 3rem;
width: 100%; width: 100%;
&#intro { #content {
p:first-of-type { display: grid;
font-size: 1.25rem; gap: 0;
}
section {
width: 100%;
&#intro
{
h2 {
padding-top: 0;
}
p:first-of-type {
font-size: 1.25rem;
}
}
}
figure {
/*background: var(--bg);*/
align-items: center;
display: flex;
flex-direction: column;
gap: 1.5rem;
justify-content: center;
margin: 2rem 0;
padding: 0;
position: relative;
img {
max-width: 100%;
&.desktop {
aspect-ratio: 1.4 / 1;
}
&.mobile {
aspect-ratio: 0.46 / 1;
height: 20rem;
}
}
figcaption {
color: var(--muted);
font-size: 0.875rem;
line-height: 1.5;
font-style: italic;
padding-left: 0.125rem;
p {
margin: 0;
}
}
}
ul {
li {
margin-bottom: 1rem;
} }
} }
} }
}
figure { /* list content */
/*background: var(--bg);*/
align-items: center;
display: flex;
flex-direction: column;
gap: 1.5rem;
justify-content: center;
margin: 2rem 0;
padding: 0;
position: relative;
img { section#studies {
max-width: 100%; background: var(--black);
display: grid;
justify-items: center;
padding: 5rem 0 3rem;
&.desktop { h1 {
aspect-ratio: 1.4 / 1; border-bottom: 0.25rem solid var(--white);
} color: #fff;
&.mobile { margin-bottom: 3rem;
aspect-ratio: 0.46 / 1; max-width: var(--column-width);
height: 20rem; padding-bottom: 1rem;
} width: var(--column-width);
}
article {
background-color: var(--blue);
background-image: var(--card-bg);
background-position: top 20rem right -2rem; /* mobile position */
background-repeat: no-repeat;
background-size: 50% auto; /* mobile size */
border: none;
color: #fff;
transition: transform 150ms ease-in, background-position 150ms ease-in;
> a {
color: inherit;
display: block;
height: 100%;
padding: 1.5rem;
text-decoration: none;
width: 100%;
} }
figcaption { h2 {
color: var(--muted); font-size: 2.5rem;
font-size: 0.875rem; padding-top: 0;
line-height: 1.5; text-shadow: none;
font-style: italic; font-weight: 700;
padding-left: 0.125rem; }
p { p:first-of-type {
color: #fff;
font-size: 1.35rem;
font-weight: 500;
line-height: 1.4;
margin: 0 0 0.5rem;
text-shadow: none;
}
&:hover {
background-position: top 19.5rem right -2rem;
transform: translateY(-0.5rem);
}
div {
display: flex;
flex-direction: column;
gap: 1rem;
padding-top: 1rem;
> figure {
margin: 0; margin: 0;
.icon {
color: color-mix(in srgb, var(--icon-color), #fff 50%);
width: 1.25rem;
height: 1.25rem;
}
figcaption {
font-size: 0.875rem;
font-weight: 700;
text-transform: uppercase;
}
} }
} }
} }
}
/* table of contents */
nav {
align-self: start;
position: sticky;
margin-left: -1.5rem;
top: 0;
width: calc(100% + 3rem);
overflow-x: hidden;
z-index: 2;
ol {
display: flex;
flex-direction: row;
list-style: decimal-leading-zero;
list-style-position: inside;
margin: 0;
overflow-x: auto;
padding: 0;
a {
color: var(--muted);
text-decoration: none;
transition: padding 125ms ease;
&:hover {
color: var(--text);
}
}
ul {
li { li {
margin-bottom: 1rem; background: var(--white);
border-bottom: 1px solid var(--faded);
height: 3rem;
padding: 0.6rem 1.5rem 0.5rem;
position: relative;
white-space: nowrap;
&::marker {
color: var(--muted);
}
&:last-child {
/*border: none;*/
}
&.active
{
&::after {
background: var(--black);
bottom: 0;
content: '';
display: block;
height: 4px;
left: 1.5rem;
position: absolute;
width: calc(100% - 3rem);
}
a {
color: var(--text);
font-weight: 700;
}
}
} }
} }
} }
/** /**
* study elements */ * study elements
*/
.icon { .icon {
align-items: center; align-items: center;
@ -544,7 +620,7 @@ article {
--mark-color: var(--red-body); --mark-color: var(--red-body);
} }
&:nth-of-type(3) mark { &:nth-of-type(3) mark {
--mark-color: var(--green-body); --mark-color: var(--green);
} }
} }
@ -642,7 +718,7 @@ details {
} }
mark { mark {
--mark-color: var(--blue-body); --mark-color: var(--blue);
color: var(--mark-color); color: var(--mark-color);
font-weight: 900 !important; font-weight: 900 !important;
background-color: transparent; background-color: transparent;
@ -665,7 +741,7 @@ mark {
} }
&[color="green"] { &[color="green"] {
--mark-color: var(--green-body); --mark-color: var(--green);
} }
p & { p & {
@ -679,6 +755,98 @@ mark {
} }
} }
span[color="blue"] {
color: var(--blue);
}
span[color="red"] {
color: var(--red-body);
}
span[color="yellow"] {
color: var(--yellow-body);
}
/**
* specific page handling
*/
body#default
{
main > header {
overflow-x: hidden;
position: relative;
justify-items: center;
width: 100%;
#circle,
#rectangle,
#semicircle,
#square,
#triangle {
position: absolute;
}
#semicircle {
background: var(--green);
bottom: 12dvw;
height: 10dvw;
border-radius: 10dvw 10dvw 0 0;
left: 52dvw;
width: 20dvw;
}
#square {
background: var(--black);
height: 12dvw;
width: 12dvw;
bottom: 0;
}
#circle {
background: var(--blue);
border-radius: 50%;
height: 20dvw;
bottom: 5dvh;
left: 4dvw;
width: 20dvw;
}
#rectangle {
background: var(--yellow);
height: 5dvh;
width: 36dvw;
left: 2dvw;
bottom: 0;
}
#triangle {
background: var(--red);
height: 40dvw;
width: 40dvw;
bottom: 0;
right: 0;
clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
}
}
body#legacy
{
main > header {
background-image: url('/img/nyc.svg');
background-position: bottom 0 right -15dvw;
background-repeat: no-repeat;
background-size: clamp(300px, 50dvw, 800px) auto;
position: relative;
> svg {
bottom: 0;
height: auto;
left: -5dvw;
width: clamp(150px, 20dvw, 320px);
position: absolute;
}
}
}
/** /**
* display queries */ * display queries */
@ -692,7 +860,7 @@ mark {
/* small height screens override */ /* small height screens override */
@media (max-height: 720px) @media (max-height: 720px)
{ {
main > section { main > header {
grid-auto-rows: auto auto; grid-auto-rows: auto auto;
height: auto; height: auto;
max-height: 100%; max-height: 100%;
@ -705,10 +873,10 @@ mark {
{ {
body#legacy body#legacy
{ {
main > section { main > header {
background-position: bottom 0 right 0; background-position: bottom 0 right 0;
> svg { svg {
left: 0; left: 0;
} }
} }
@ -730,14 +898,15 @@ mark {
} }
} }
main > section { main > header {
min-height: 860px; min-height: 860px;
> header { > hgroup {
.lede { .lede {
max-width: 60%; max-width: 80%;
} }
} }
> aside { > aside {
flex-direction: row; flex-direction: row;
@ -771,6 +940,36 @@ mark {
} }
} }
/* landscape tablets */
@media (min-width: 800px)
{
section#studies
{
article {
background-position: top 2rem right 2rem;
background-size: 20% auto;
width: var(--column-width);
&:hover {
background-position: top 1.5rem right 2rem;
}
a {
padding: 2rem;
}
p {
max-width: 67%;
}
div {
flex-direction: row;
gap: 2rem;
}
}
}
}
/* laptops (nav/article move to columns now) */ /* laptops (nav/article move to columns now) */
@media (min-width: 1024px) @media (min-width: 1024px)
{ {
@ -780,37 +979,100 @@ mark {
--article-top: 2.5rem; --article-top: 2.5rem;
} }
article h1 {
{ max-width: 75%;
> nav { }
margin-left: 0;
top: var(--article-top);
width: 12rem;
ol { main > header {
border-top: 3px solid var(--muted); > hgroup {
flex-direction: column; .lede {
margin-top: 0.75rem; max-width: 60%;
overflow-x: none; }
}
}
li { nav {
height: 2.5rem; margin-left: 0;
padding: 0.4rem 0.25rem 0; top: var(--article-top);
width: 12rem;
&.active ol {
{ border-top: 3px solid var(--muted);
&::after { flex-direction: column;
display: none; margin-top: 0.75rem;
} overflow-x: none;
a { li {
padding-left: 0.25rem; height: 2.5rem;
} padding: 0.4rem 0.25rem 0;
&.active
{
&::after {
display: none;
}
a {
padding-left: 0.25rem;
} }
} }
} }
} }
} }
body#default main
{
> header {
padding: 0 1.5rem;
hgroup {
padding: 10dvh 0 0;
}
#semicircle {
bottom: 57dvh;
height: 12dvh;
border-radius: 12dvh 12dvh 0 0;
width: 24dvh;
left: auto;
right: -1dvw;
}
#square {
bottom: 45dvh;
height: 12dvh;
width: 12dvh;
right: 2dvw;
}
#circle {
height: 15dvh;
left: auto;
bottom: 30dvh;
right: 3dvw;
width: 15dvh;
}
#rectangle {
height: 5dvh;
left: auto;
width: 36dvw;
right: -16dvw;
bottom: 25dvh;
}
#triangle {
height: 25dvh;
right: 6dvw;
width: 25dvh;
}
}
section#studies {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
}
} }
/* desktops */ /* desktops */
@ -826,9 +1088,9 @@ mark {
font-size: 17px; font-size: 17px;
} }
main > section main > header
{ {
> header { > hgroup {
padding-top: 6rem; padding-top: 6rem;
} }
} }
@ -838,7 +1100,7 @@ mark {
@media (min-width: 1440px) @media (min-width: 1440px)
{ {
:root { :root {
--article-grid: 17rem var(--content-width) 7rem; --article-grid: 16rem var(--content-width) 8rem;
--article-top: 4rem; --article-top: 4rem;
} }
@ -852,7 +1114,7 @@ mark {
main main
{ {
> section > aside { > header > aside {
gap: 2rem; gap: 2rem;
} }
@ -860,14 +1122,6 @@ mark {
padding-right: 0; padding-right: 0;
padding-left: 0; padding-left: 0;
> nav {
font-size: 0.925rem;
ol li {
padding-top: 0.5rem;
}
}
figure { figure {
align-items: flex-end; align-items: flex-end;
flex-direction: row; flex-direction: row;
@ -883,19 +1137,27 @@ mark {
} }
} }
} }
nav {
font-size: 0.925rem;
ol li {
padding-top: 0.5rem;
}
}
}
section#studies
{
article {
width: calc(var(--column-width) + 4rem);
}
} }
} }
@media (min-width: 1560px)
/** {
* deprecate? */ :root {
@media (max-width: 900px) { --article-grid: 17rem var(--content-width) 7rem;
article #content {
width: 100%;
}
article section {
width: 100%;
} }
} }

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 192 192" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M108.836,156.725l-26.108,-31.053l37.823,-0l0,66.284l-11.715,0l0,-35.23Z" style="fill:#1a52a3;"/><path d="M132.911,4.571l25.797,25.586l-16.538,9.548l-9.26,-35.134Z" style="fill:#1a52a3;"/><path d="M164.608,11.933l-0.865,23.009l-13.442,-4.968l14.307,-18.041Z" style="fill:#e62a1b;"/><path d="M159.495,27.851l30.384,20.669l-30.384,0.219l0,-20.888Z" style="fill:#272727;"/><path d="M120.551,125.716l-69.791,0c0,-38.519 31.272,-69.791 69.791,-69.791l0,69.791Z" style="fill:#e62a1b;"/><circle cx="155.672" cy="41.663" r="14.262" style="fill:#272727;"/><path d="M108.836,191.955l46.77,0l-35.055,-12.193l-11.715,12.193Z" style="fill:#272727;"/><rect x="133.058" y="86.516" width="8.557" height="27.359" style="fill:#272727;"/><circle cx="139.452" cy="113.875" r="6.393" style="fill:#272727;"/><path d="M120.551,55.926l37.605,0c0,20.755 -16.85,37.605 -37.605,37.605l0,-37.605Z" style="fill:#fcb70d;"/><path d="M50.76,125.716c0.073,10.842 -5.416,56.45 -48.638,66.284c35.145,-3.122 60.636,-17.345 73.575,-48.975c2.177,-5.322 3.845,-11.589 4.234,-17.309c0,0 -29.171,-0.101 -29.171,0Z" style="fill:#fcb70d;"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,5 +1,7 @@
--- ---
title: "Portfolio" title: "Portfolio"
hero:
svg: home.svg
--- ---
Product case studies and selected work. Product case studies and selected work.

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@ -8,16 +8,17 @@ draft: false
hero: hero:
title: "Legacy app refresh" title: "Legacy app refresh"
deck: "Reshaping a critical but outdated school forms workflow into a <strong>calmer, clearer experience</strong> for administrators and families." deck: "Reshaping a critical but outdated school forms workflow into a <strong>calmer, clearer experience</strong> for administrators and families."
tags: svg: kangaroo-eyes.svg
- label: "Figma" list:
tone: "green" more: "Wallabyte supports schools and families through critical paperwork, but was woefully unusable. This case study covers how I approached that challenge—from identifying the highest impact issues to shaping a more coherent forms experience."
- label: "Product Design" img: card-legacy.png
tone: "yellow" facts:
- label: "B2B SaaS" - key: Role
tone: "cyan" color: yellow
- label: "Workflow UX" - key: tools
tone: "blue" color: red
inline_svg: kangaroo-eyes.svg - key: industry
color: green
study: study:
facts: facts:
- label: "Role" - label: "Role"

View File

@ -22,7 +22,7 @@
{{ with resources.Get "css/site.css" }} {{ with resources.Get "css/site.css" }}
<link rel="stylesheet" href="{{ .RelPermalink }}"> <link rel="stylesheet" href="{{ .RelPermalink }}">
{{ end }} {{ end }}
{{ if and .IsPage (eq .Section "studies") .Params.study.toc }} {{ if or .IsHome (and .IsPage (eq .Section "studies") .Params.study.toc) }}
<script src="{{ "js/main.js" | relURL }}" defer></script> <script src="{{ "js/main.js" | relURL }}" defer></script>
{{ end }} {{ end }}
</head> </head>
@ -41,10 +41,10 @@
</div> </div>
<menu aria-label="Primary"> <menu aria-label="Primary">
<li> <li>
<a href="{{ "/studies/" | relURL }}">Case studies</a> <a href='{{ "/#studies" | relURL }}'>Case studies</a>
</li> </li>
<li> <li>
<a href="{{ "/contact/" | relURL }}">Get in touch</a> <a href='{{ "/contact/" | relURL }}'>Get in touch</a>
</li> </li>
</menu> </menu>
</header> </header>

View File

@ -1,36 +1,17 @@
{{- define "main" -}} {{- define "main" -}}
{{- $heroImage := "" -}} {{- $svg := "" -}}
{{- $heroInlineSvg := "" -}} {{- with .Params.hero.svg -}}
{{- with .Params.hero.image -}}
{{- $match := $.Resources.GetMatch . -}} {{- $match := $.Resources.GetMatch . -}}
{{- if not $match -}} {{- if not $match -}}
{{- $match = $.Resources.GetMatch (printf "img/%s" .) -}} {{- $match = $.Resources.GetMatch (printf "img/%s" .) -}}
{{- end -}} {{- end -}}
{{- with $match -}} {{- with $match -}}
{{- $heroImage = .RelPermalink -}} {{- $svg = .Content -}}
{{- end -}}
{{- end -}}
{{- with .Params.hero.inline_svg -}}
{{- $match := $.Resources.GetMatch . -}}
{{- if not $match -}}
{{- $match = $.Resources.GetMatch (printf "img/%s" .) -}}
{{- end -}}
{{- with $match -}}
{{- $heroInlineSvg = .Content -}}
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
<section{{ with $heroImage }} style="--hero-image: url('{{ . }}');"{{ end }}> <header>
<header> <hgroup>
{{- with .Params.hero.tags -}}
<!--<ul class="tag-list" aria-label="Case study tags">
{{- range . -}}
<li>
<span class="tag{{ with .tone }} tag-{{ . }}{{ end }}">{{ .label }}</span>
</li>
{{- end -}}
</ul>-->
{{- end -}}
<h1>{{ with .Params.hero.title }}{{ . }}{{ else }}{{ .Title }}{{ end }}</h1> <h1>{{ with .Params.hero.title }}{{ . }}{{ else }}{{ .Title }}{{ end }}</h1>
{{- with .Params.hero.deck -}} {{- with .Params.hero.deck -}}
<p class="lede">{{ . | markdownify }}</p> <p class="lede">{{ . | markdownify }}</p>
@ -38,31 +19,30 @@
{{- if and (not .Params.hero.deck) .Summary -}} {{- if and (not .Params.hero.deck) .Summary -}}
<p class="lede">{{ .Summary | markdownify }}</p> <p class="lede">{{ .Summary | markdownify }}</p>
{{- end -}} {{- end -}}
</header> </hgroup>
{{- with .Params.study -}} {{- with .Params.study -}}
<aside aria-label="Study metadata"> <aside aria-label="Study metadata">
{{- with .facts -}} {{- with .facts -}}
{{- range . -}} {{- range . -}}
<figure> <figure>
{{- with .icon -}} {{- with .icon -}}
{{ partial "icon.html" (dict "name" .) }} {{ partial "icon.html" (dict "name" .) }}
{{- end -}} {{- end -}}
<label>{{ .label }}</label> <label>{{ .label }}</label>
<figcaption {{ with .class }}class='{{ . }}'{{ end }}>{{ .value | markdownify }}</figcaption> <figcaption {{ with .class }}class='{{ . }}'{{ end }}>{{ .value | markdownify }}</figcaption>
</figure> </figure>
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
</aside> </aside>
{{- end -}} {{- end -}}
{{- with $heroInlineSvg -}} {{- with $svg -}}
{{ . | safeHTML }} {{ . | safeHTML }}
{{- end -}} {{- end -}}
</section> </header>
<article> <article>
{{- with .Params.study.toc -}} {{- with .Params.study.toc -}}
<nav id="toc" aria-label="Table of contents"> <nav aria-label="Table of contents">
<ol> <ol>
{{- range . -}} {{- range . -}}
<li><a href="#{{ .id }}">{{ .label }}</a></li> <li><a href="#{{ .id }}">{{ .label }}</a></li>
@ -70,6 +50,7 @@
</ol> </ol>
</nav> </nav>
{{- end -}} {{- end -}}
<div id="content"> <div id="content">
{{ .Content }} {{ .Content }}
</div> </div>

View File

@ -1,25 +1,64 @@
{{ define "main" }} {{- define "main" -}}
<section class="page-hero"> <header>
<p class="eyebrow">Portfolio</p> <hgroup>
<h1>Case studies with room for the full story.</h1> <h1>
Principle product <span color="blue">designer</span> building <span color="red">thoughtful</span> and <span color="yellow">accessible</span> interfaces.
</h1>
<p class="lede"> <p class="lede">
A custom Hugo setup for showcasing product and UX work without relying on a theme. <b>20 years experience</b> designing and building software for the browser. I balance intentional design principles with a mastery of CSS, HTML, JavaScript, &amp; WCAG to <b>bridge design and engineering</b>. Performance, accessibility, and the semantic web still matter!
</p> </p>
</section> <p class="lede">
Read more about my <a href="design" out>design philosophy</a> or take a look at some <a href="#studies" in>case studies</a> below.
<section class="page-section"> </p>
<div class="section-heading"> </hgroup>
<p class="eyebrow">Selected work</p> <div id="semicircle"></div>
<h2>Current case studies</h2> <div id="square"></div>
</div> <div id="circle"></div>
<div class="study-list"> <div id="rectangle"></div>
{{ range where .Site.RegularPages "Section" "studies" }} <div id="triangle"></div>
<article> </header>
<p class="study-card-meta">{{ with .Params.hero.title }}{{ . }}{{ else }}{{ .Title }}{{ end }}</p> <section id="studies">
<h3><a href="{{ .RelPermalink }}">{{ .Title }}</a></h3> <h1>Case studies</h1>
<p>{{ .Summary }}</p> {{ range where .Site.RegularPages "Section" "studies" }}
</article> {{- $page := . -}}
{{ end }} {{- $cardImage := "" -}}
</div> {{- with .Params.list.img -}}
</section> {{- $match := $page.Resources.GetMatch . -}}
{{- if not $match -}}
{{- $match = $page.Resources.GetMatch (printf "img/%s" .) -}}
{{- end -}}
{{- with $match -}}
{{- $cardImage = .RelPermalink -}}
{{- end -}}
{{- end -}}
<article{{ with $cardImage }} style="--card-bg: url('{{ . }}');"{{ end }}>
<a href="{{ .RelPermalink }}">
<h2>{{ .Title }}</h2>
<p>{{ .Summary }}</p>
{{ with .Params.list.more }}<p>{{ . }}</p>{{ end }}
{{- with .Params.study.facts -}}
<div>
{{- range . -}}
{{- if or (eq .label "Role") (eq .label "Tools") (eq .label "Industry") -}}
{{- $fact := . -}}
{{- $iconColor := "" -}}
{{- range $page.Params.list.facts -}}
{{- if eq (lower .key) (lower $fact.label) -}}
{{- $iconColor = .color -}}
{{- end -}}
{{- end -}}
<figure>
{{- with $fact.icon -}}
{{ partial "icon.html" (dict "name" . "color" $iconColor) }}
{{- end -}}
<figcaption {{ with $fact.class }}class='{{ . }}'{{ end }}>{{ $fact.value | markdownify }}</figcaption>
</figure>
{{- end -}}
{{- end -}}
</div>
{{- end -}}
</a>
</article>
{{- end -}}
</section>
{{ end }} {{ end }}

View File

@ -26,6 +26,7 @@
{{- end -}} {{- end -}}
<section id="end"> <section id="end">
{{ if eq (len $footnotes) 0 }}<big>Ag</big>{{ end }}
<div class="text"> <div class="text">
<p>This is the design portfolio for <a href="https://andrewgioia.com">Andrew Gioia</a>, co-founder of TeachBoost and current Staff Designer at SchoolStatus.</p> <p>This is the design portfolio for <a href="https://andrewgioia.com">Andrew Gioia</a>, co-founder of TeachBoost and current Staff Designer at SchoolStatus.</p>
<div>{{ partial "icon.html" (dict "name" "cc") }} 2026 BY-NC-ND. Please share this responsibly.</div> <div>{{ partial "icon.html" (dict "name" "cc") }} 2026 BY-NC-ND. Please share this responsibly.</div>

View File

@ -1,9 +1,10 @@
{{- $name := .name | default . -}} {{- $name := .name | default . -}}
{{- $class := .class -}} {{- $class := .class -}}
{{- $label := .label -}} {{- $label := .label -}}
{{- $color := .color -}}
{{- $path := printf "icons/%s.svg" $name -}} {{- $path := printf "icons/%s.svg" $name -}}
{{- with resources.Get $path -}} {{- with resources.Get $path -}}
<span class="icon icon-{{ $name }}{{ with $class }} {{ . }}{{ end }}"{{ if $label }} role="img" aria-label="{{ $label }}"{{ else }} aria-hidden="true"{{ end }}> <span class="icon icon-{{ $name }}{{ with $class }} {{ . }}{{ end }}"{{ with $color }} style="--icon-color: var(--{{ . }});"{{ end }}{{ if $label }} role="img" aria-label="{{ $label }}"{{ else }} aria-hidden="true"{{ end }}>
{{ .Content | safeHTML }} {{ .Content | safeHTML }}
</span> </span>
{{- else -}} {{- else -}}

1
static/img/home.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 192 192" id="roll"><circle cx="110.678" cy="33.322" r="33.322" style="fill:#1a52a3"/><rect x="35.476" y="66.644" width="156.524" height="21.6" style="fill:#fcb70d"/><path d="M115.2 88.244v103.714H0z" style="fill:#e62a1b"/></svg>

After

Width:  |  Height:  |  Size: 303 B

View File

@ -1,6 +1,7 @@
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () =>
{
const setupKangarooEye = () => { const setupKangarooEye = () => {
const heroGraphic = document.querySelector("main > section > svg"); const heroGraphic = document.querySelector("main > header > svg");
const eye = heroGraphic?.querySelector("#eye"); const eye = heroGraphic?.querySelector("#eye");
const pupil = heroGraphic?.querySelector("#pupil"); const pupil = heroGraphic?.querySelector("#pupil");
@ -66,8 +67,8 @@ document.addEventListener("DOMContentLoaded", () => {
}; };
const setupToc = () => { const setupToc = () => {
const toc = document.querySelector("article > nav#toc"); const toc = document.querySelector("nav");
const content = document.querySelector("article > div#content"); const content = document.querySelector("article");
const list = toc?.querySelector("ol"); const list = toc?.querySelector("ol");
if (!toc || !content || !list) { if (!toc || !content || !list) {