Add code for the buttons

main
Ashelyn Dawn 2 weeks ago
parent c4824cf9d6
commit 77d0b2acd5
No known key found for this signature in database
GPG Key ID: D1980B8C6F349BC1

@ -19,7 +19,7 @@ export default function MemberPage({ params: { name } }) {
return ( return (
<> <>
<main className="mainColumn"> <main className="mainColumn card">
<InfoBar memberName={member.name} /> <InfoBar memberName={member.name} />
<Markdown outer="short">{member.bioShort}</Markdown> <Markdown outer="short">{member.bioShort}</Markdown>
<Markdown outer="long">{member.bioContinued}</Markdown> <Markdown outer="long">{member.bioContinued}</Markdown>

@ -8,7 +8,7 @@ export default function Contact() {
<h1 className="pageTitle"> <h1 className="pageTitle">
Contact Contact
</h1> </h1>
<main className="mainColumn"> <main className="mainColumn card">
<InfoBar> <InfoBar>
Be nice. Please don't make us regret putting this here Be nice. Please don't make us regret putting this here
</InfoBar> </InfoBar>

@ -4,7 +4,7 @@ export default function NotFound() {
return ( return (
<> <>
<h1 className="pageTitle">Not Found (404)</h1> <h1 className="pageTitle">Not Found (404)</h1>
<main className="mainColumn"> <main className="mainColumn card">
<InfoBar> <InfoBar>
<strong>Error:&nbsp;</strong> <strong>Error:&nbsp;</strong>
Unable to find the requested resource Unable to find the requested resource

@ -1,43 +1,140 @@
import fs from 'node:fs/promises'
import path from 'node:path'
import Link from 'next/link' import Link from 'next/link'
import styles from '~/styles/index.module.css' import styles from '~/styles/index.module.css'
import sharp from 'sharp'
const mimes = {
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
png: 'image/png',
bmp: 'image/bmp',
gif: 'image/gif'
}
export default async function Index() {
const buttonDir = 'images/buttons/'
const buttonFiles = (await fs.readdir(path.join(process.cwd(), buttonDir)).catch(() => {}) || [])
.filter(buttonName => buttonName.match(/\.(png|gif|jpg|jpeg)$/))
const buttonLinks = (await fs.readFile(path.join(process.cwd(), 'images/buttons/urls.txt'), {encoding: 'utf8'}).catch(() => {}) || '')
.split('\n').filter(line => !!line)
.map(line => line.match(/^([^:]+):\s+(.*)$/))
.filter(match => !!match)
.reduce((acc,[_, name, url]) => ({...acc, [name]: url}), {})
const buttons = await Promise.all(buttonFiles.map(async buttonFile => {
const origImageData = await fs.readFile(path.join(process.cwd(), buttonDir, buttonFile))
let preview = null
const metadata = await sharp(origImageData, {pages: -1}).metadata()
// Generate preview if there's more than one frame
if(metadata.pages > 1) {
preview = await sharp(origImageData, {pages: 1})
.png({quality: 80, force: true})
.toBuffer()
}
return {
name: buttonFile.split('.').slice(0, -1).join('.'),
mime: mimes[buttonFile.split('.').at(-1)] || 'image/*',
url: buttonLinks[buttonFile],
data: origImageData.toString('base64'),
preview: preview?.toString('base64')
}
}))
const friendButtons = buttons.filter(button => button.name !== 'tempest')
const ourButton = buttons.filter(button => button.name === 'tempest')[0]
export default function Index() {
return ( return (
<main className="mainColumn"> <>
<p> <main className="mainColumn card">
Hi, we're tempest! We're a median plural <p>
system of six members, but most of the time you'll probably see us Hi, we're tempest! We're a median plural
operating as one system of six members, but most of the time you'll probably see us
</p> operating as one
</p>
<p>We like coding, VR, and making CG art</p>
<h2>At a glance</h2>
<div className={styles.glance}>
<span className={styles.label}>Pronouns:</span>
<span>they/it</span>
<span className={styles.label}>Cohort:</span>
<span>millenial</span>
<p>We like coding, VR, and making CG art</p> <span className={styles.label}>Orientation:</span>
<span>ace . . . ish</span>
<h2>At a glance</h2> <span className={styles.label}>Partners:</span>
<div className={styles.glance}> <span>several</span>
<span className={styles.label}>Pronouns:</span>
<span>they/it</span>
<span className={styles.label}>Cohort:</span> <span className={styles.label}>Children:</span>
<span>millenial</span> <span>two</span>
<span className={styles.label}>Orientation:</span> <span className={styles.label}>Capitalize name:</span>
<span>ace . . . ish</span> <span>not unless we're at work</span>
</div>
<span className={styles.label}>Partners:</span> <p>
<span>several</span> <em>Note:</em> This is the information for our system in aggregate,
for individual info see our <Link href="/about">about</Link> page
</p>
</main>
{friendButtons.length > 0 && (
<div className="mainColumn postscript">
<h2>Friends and other neighbors:
{ourButton && <a target="_blank" href={`data:${ourButton.mime};base64,${ourButton.data}`} className="asideLink" aria-label="Link back to us">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentcolor" d="M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z"/></svg>
</a>}
</h2>
<div className={styles.the88x31s}>
{friendButtons.map(button => {
const image = <img
data-button-canonical
alt={button.name}
title={button.name}
src={`data:${button.mime};base64,${button.data}`}
/>
<span className={styles.label}>Children:</span> const preview = button.preview ? <img
<span>two</span> data-button-preview
alt={button.name}
title={button.name}
src={`data:image/png;base64,${button.preview}`}
/> : null
<span className={styles.label}>Capitalize name:</span> if(button.url)
<span>not unless we're at work</span> return (
</div> <a target="_blank" rel="noopener" key={button.name} href={button.url}>{image}{preview}</a>
)
else
return (
<a key={button.name}>{image}{preview}</a>
)
})}
<script type="text/javascript" dangerouslySetInnerHTML={{__html: `
const buttons = document.currentScript.parentElement.querySelectorAll('a:has([data-button-preview])')
<p> // Slightly janky way of resetting GIF animations after they go back to the preview state
<em>Note:</em> This is the information for our system in aggregate, buttons.forEach(button => button.addEventListener('mouseleave', () => {
for individual info see our <Link href="/about">about</Link> page const image = button.querySelector('[data-button-canonical]')
</p> const src = image.getAttribute('src')
</main> image.setAttribute('src', '')
setTimeout(() => {
image.setAttribute('src', src)
}, 0)
}))
`}}/>
</div>
</div>
)}
</>
) )
} }

@ -8,7 +8,7 @@ export default function PayTransparency() {
<h1 className="pageTitle"> <h1 className="pageTitle">
Pay Transparency Pay Transparency
</h1> </h1>
<main className="mainColumn"> <main className="mainColumn card">
<InfoBar text="Last updated: November 2023" /> <InfoBar text="Last updated: November 2023" />
<p> <p>
This page lists the title and pay rate of every job we have held This page lists the title and pay rate of every job we have held

@ -18,7 +18,7 @@ export default async function Post({ params: { slug } }) {
<h1 className="pageTitle"> <h1 className="pageTitle">
{post.title} {post.title}
</h1> </h1>
<main className="mainColumn"> <main className="mainColumn card">
<InfoBar authorName={post.author} publishedDate={post.date} /> <InfoBar authorName={post.author} publishedDate={post.date} />
<Markdown>{post.body}</Markdown> <Markdown>{post.body}</Markdown>
</main> </main>

@ -14,7 +14,7 @@ export default async function Posts() {
</h1> </h1>
<main> <main>
{sortedPosts.map((post: Post) => ( {sortedPosts.map((post: Post) => (
<div className="mainColumn"> <div className="mainColumn card">
<InfoBar authorName={post.author} publishedDate={post.date} /> <InfoBar authorName={post.author} publishedDate={post.date} />
<h2>{post.title}</h2> <h2>{post.title}</h2>
<p>{post.subtitle}</p> <p>{post.subtitle}</p>

@ -9,3 +9,42 @@
color: var(--text-dimmed); color: var(--text-dimmed);
margin-right: var(--text-padding); margin-right: var(--text-padding);
} }
.the88x31s {
column-width: 90px;
text-align: center;
}
.the88x31s > a {
width: 88px;
height: 31px;
margin: 2px;
display: inline-block;
}
.the88x31s img {
width: inherit;
height: inherit;
overflow: hidden;
object-fit: cover;
filter: grayscale(1) brightness(.8) opacity(.8);
transition: .4s ease-in-out filter;
}
.the88x31s a:has(img + img) img:first-child {
position: absolute;
display: none;
z-index: 2;
}
.the88x31s a:hover img {
display: initial!important;
filter: none;
transition: .025s ease-in-out filter;
}
@media (pointer:coarse) or (pointer:none) {
.the88x31s img {
filter: contrast(.6) brightness(.6) grayscale(.2);
}
}

@ -13,6 +13,7 @@
--text-dimmed:rgba(255,255,255, .55); --text-dimmed:rgba(255,255,255, .55);
--text-padding: 16px; --text-padding: 16px;
--card-shadow: 0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12); --card-shadow: 0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12);
--current-content-width: min(var(--main-width), calc(100vw - var(--text-padding)));
} }
@media (max-width: 500px) { @media (max-width: 500px) {
@ -166,29 +167,57 @@ header:not(.homepage) ~ h1.pageTitle {
margin-top: -80px; margin-top: -80px;
} }
main.mainColumn {
min-height: calc(var(--header-overlap) + var(--min-main-overhang));
}
.mainColumn { .mainColumn {
width: var(--main-width); width: var(--main-width);
max-width: calc(100vw - var(--text-padding)); max-width: calc(100vw - var(--text-padding));
box-sizing: border-box; box-sizing: border-box;
padding: var(--text-padding); padding: var(--text-padding);
margin: 0 auto; margin: 0 auto;
}
.mainColumn.card {
min-height: calc(var(--header-overlap) + var(--min-main-overhang));
background: var(--main-background); background: var(--main-background);
box-shadow: var(--card-shadow); box-shadow: var(--card-shadow);
} }
header.homepage ~ .mainColumn { .mainColumn.postscript h2:first-child {
margin-top: 24px;
font-weight: 500;
opacity: .6;
font-size: 18px;
position: relative;
}
.mainColumn.postscript h2:first-child::after {
content: ' ';
position: absolute;
display: block;
background: #666;
width: 100%;
height: 1px;
}
.mainColumn.postscript h2 a.asideLink {
position: absolute;
right: 0;
width: 20px;
height: 20px;
}
.mainColumn.postscript p {
opacity: .6;
}
header.homepage ~ .mainColumn.card {
min-height: calc(var(--header-overlap) + var(--min-main-overhang) - var(--header-bar-height)); min-height: calc(var(--header-overlap) + var(--min-main-overhang) - var(--header-bar-height));
} }
.mainColumn ~ .mainColumn { .mainColumn.card ~ .mainColumn.card {
margin-top: calc(2 * var(--text-padding)); margin-top: calc(2 * var(--text-padding));
} }
main.mainColumn > p:first-child { main.mainColumn.card > p:first-child {
margin-top: 0; margin-top: 0;
} }

Loading…
Cancel
Save