chore: use our configs, update dependencies (#34)

### Explanation

This gets us in line with our other project standards, and allows us to start testing!

### Issue

Closes #18

### Attestations

- [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [x] I have pinned the dependencies to a specific patch version.

### Style

- [x] I have run the linter and resolved any errors.
- [x] My pull request uses an appropriate title, matching the conventional commit standards.
- [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

Major - My pull request introduces a breaking change.

Reviewed-on: https://codeberg.org/nhcarrigan/portfolio/pulls/34
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
This commit is contained in:
2024-10-30 23:02:42 +00:00
committed by Naomi the Technomancer
parent b24f0e83c2
commit fe370dabb5
58 changed files with 5588 additions and 3166 deletions

View File

@ -1,75 +1,94 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { JSX } from "react";
/**
* Renders the /about page.
* @returns A React Component.
*/
const About = (): JSX.Element => {
return (
<>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">About Naomi</h1>
<section>
<p className="mb-2">
Passionate technologist dedicated to building inclusive tech
communities and empowering individuals to break into the field. With
a rich background in community management, software engineering, and
developer experience, I strive to create accessible pathways for
diverse talent.
</p>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`About Naomi`}</h1>
<section>
<p className="mb-2">
{`Passionate technologist dedicated to building inclusive tech
communities and empowering individuals to break into the field. With
a rich background in community management, software engineering, and
developer experience, I strive to create accessible pathways for
diverse talent.`}
</p>
<p className="mb-2">My expertise spans:</p>
<ul className="w-4/5 m-auto">
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
<strong>Inclusive Community Building:</strong> Cultivated
welcoming communities of 20,000 to 300K+ members across Discord,
Slack, and GitHub, with a focus on supporting underrepresented
groups in tech.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
<strong>Empowering Education:</strong> Contributed to and
maintained open-source curricula used by millions of aspiring
developers globally, focusing on accessibility and engaging
learning experiences.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
<strong>Software Engineering for Inclusivity:</strong> Developed
sophisticated bots and tools that not only streamline moderation
and boost engagement but also promote safe, inclusive spaces for
all community members.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
<strong>Developer Experience (DX):</strong> Led initiatives to
improve documentation, SDK support, and overall developer
satisfaction, with an emphasis on making resources accessible to
newcomers in the field.
</li>
<li className="mb-2">
<strong>Mentorship and Advocacy:</strong> Implemented programs to
support aspiring developers, particularly those from
underrepresented backgrounds, in their journey into tech careers.
</li>
</ul>
<p className="mb-2">
Key achievements include redesigning freeCodeCamp&apos;s Responsive
Web Design curriculum for greater accessibility, developing
AI-powered community management tools that foster inclusive
interactions, and creating engagement systems that significantly
increased participation from diverse user groups.
</p>
<p className="mb-2">{`My expertise spans:`}</p>
<ul className="w-4/5 m-auto">
<li className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]">
<strong>{`Inclusive Community Building:`}</strong>
{` Cultivated
welcoming communities of 20,000 to 300K+ members across Discord,
Slack, and GitHub, with a focus on supporting underrepresented
groups in tech.`}
</li>
<li className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]">
<strong>{`Empowering Education:`}</strong>
{` Contributed to and
maintained open-source curricula used by millions of aspiring
developers globally, focusing on accessibility and engaging
learning experiences.`}
</li>
<li className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]">
<strong>{`Software Engineering for Inclusivity:`}</strong>
{` Developed
sophisticated bots and tools that not only streamline moderation
and boost engagement but also promote safe, inclusive spaces for
all community members.`}
</li>
<li className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]">
<strong>{`Developer Experience (DX):`}</strong>
{` Led initiatives to
improve documentation, SDK support, and overall developer
satisfaction, with an emphasis on making resources accessible to
newcomers in the field.`}
</li>
<li className="mb-2">
<strong>{`Mentorship and Advocacy:`}</strong>
{` Implemented programs to
support aspiring developers, particularly those from
under-represented backgrounds, in their journey into tech careers.`}
</li>
</ul>
<p className="mb-2">
{`Key achievements include redesigning freeCodeCamp's Responsive
Web Design curriculum for greater accessibility, developing
AI-powered community management tools that foster inclusive
interactions, and creating engagement systems that significantly
increased participation from diverse user groups.`}
</p>
<p className="mb-2">
I&apos;m driven by the belief that technology should be a field open
to all. My approach combines technical expertise with a deep
commitment to diversity, equity, and inclusion, resulting in
solutions that not only drive engagement and innovation but also
break down barriers to entry in tech.
</p>
<p className="mb-2">
{`I'm driven by the belief that technology should be a field open
to all. My approach combines technical expertise with a deep
commitment to diversity, equity, and inclusion, resulting in
solutions that not only drive engagement and innovation but also
break down barriers to entry in tech.`}
</p>
<p className="mb-2">
Seeking opportunities to lead transformative projects that expand
access to tech education, foster inclusive community growth, and
empower individuals from all backgrounds to thrive in the tech
industry. Let&apos;s connect to discuss how I can best support your
organisation!
</p>
</section>
</main>
</>
<p className="mb-2">
{`Seeking opportunities to lead transformative projects that expand
access to tech education, foster inclusive community growth, and
empower individuals from all backgrounds to thrive in the tech
industry. Let's connect to discuss how I can best support your
organisation!`}
</p>
</section>
</main>
);
};

View File

@ -1,49 +1,69 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
"use client";
import { Activity } from "@/components/activity";
import { Review } from "@/components/review";
import { Rule } from "@/components/rule";
import { Testimonials } from "@/config/Testimonials";
import { useEffect, useState } from "react";
import { type JSX, useEffect, useState } from "react";
import { Activity } from "../../components/activity";
import { Rule } from "../../components/rule";
const Reviews = (): JSX.Element => {
const [activity, setActivity] = useState<
{
type: string;
date: Date;
repo: string;
/**
* Renders the /activity page.
* @returns A React Component.
*/
const ActivityComponent = (): JSX.Element => {
const [ activity, setActivity ] = useState<
Array<{
type: string;
date: Date;
repo: string;
repoName: string;
}[]
}>
>([]);
useEffect(() => {
fetch("/api/activity")
.then((data) => data.json())
.then((data) => setActivity(data));
void fetch("/api/activity").
then(async(data) => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return (await data.json()) as Array<{
type: string;
date: Date;
repo: string;
repoName: string;
}>;
}).
then((data) => {
setActivity(data);
});
}, []);
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Recent Activity</h1>
<section>
<p className="mb-2">See what Naomi has been up to lately.</p>
<Rule />
<ol className="relative border-s border-[--primary] w-4/5 m-auto">
{activity.map((act, i) => (
<main className="w-[95%] text-center
max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Recent Activity`}</h1>
<section>
<p className="mb-2">{`See what Naomi has been up to lately.`}</p>
<Rule />
<ol className="relative border-s border-[--primary] w-4/5 m-auto">
{activity.map((act, index) => {
return (
<Activity
key={act.date.toString()}
type={act.type}
date={act.date}
heart={index % 2 === 1
? "🩷"
: "🩵"}
key={act.date.toString()}
repo={act.repo}
repoName={act.repoName}
heart={i % 2 ? "🩷" : "🩵"}
type={act.type}
/>
))}
</ol>
</section>
</main>
</>
);
})}
</ol>
</section>
</main>
);
};
export default Reviews;
export default ActivityComponent;

View File

@ -1,17 +1,50 @@
import { getCodebergData } from "@/lib/codeberg";
import { getGithubData } from "@/lib/github";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { NextResponse } from "next/server";
import { getCodebergData } from "../../../lib/codeberg";
import { getGithubData } from "../../../lib/github";
export async function GET() {
/**
* GET route handler for the activity API.
* Loads recent activity from Codeberg and GitHub.
* @returns The formatted data.
*/
export async function GET(): Promise<NextResponse> {
const codeberg = await getCodebergData();
const github = await getGithubData();
const normalised: {
type: string;
date: Date;
repo: string;
const normalised: Array<{
type: string;
date: Date;
repo: string;
repoName: string;
}[] = [...codeberg.map(i => ({ type: i.op_type, date: new Date(i.created), repo: i.repo.html_url, repoName: i.repo.full_name })), ...github.map(i => ({ type: i.type, date: new Date(i.created_at), repo: i.repo.url.replace("api.github.com/repos", "github.com"), repoName: i.repo.name }))]
}> = [
...codeberg.map((index) => {
return {
date: new Date(index.created),
repo: index.repo.html_url,
repoName: index.repo.full_name,
type: index.op_type,
};
}),
...github.map((index) => {
return {
date: new Date(index.created_at),
repo: index.repo.url.replace("api.github.com/repos", "github.com"),
repoName: index.repo.name,
type: index.type,
};
}),
];
return NextResponse.json(normalised.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()).slice(0, 100))
return NextResponse.json(
normalised.
toSorted((a, b) => {
return new Date(b.date).getTime() - new Date(a.date).getTime();
}).
slice(0, 100),
);
}

View File

@ -1,23 +1,45 @@
import { ArtComponent } from "@/components/art";
import { Rule } from "@/components/rule";
import { Art } from "@/config/Art";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { ArtComponent } from "../../components/art";
import { Rule } from "../../components/rule";
import { Art } from "../../config/Art";
import type { JSX } from "react";
/**
* Renders the /art page.
* @returns A React Component.
*/
const Arts = (): JSX.Element => {
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Art</h1>
<section>
<p className="mb-2">See various art depicting Naomi.</p>
<Rule />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-y-5">
{Art.sort((a, b) => a.name.localeCompare(b.name)).map((art) => (
<ArtComponent key={art.name} name={art.name} img={art.img} artist={art.artist} url={art.url} alt={art.alt}/>
))}
</div>
</section>
</main>
</>
<main
className="w-[95%] text-center
max-w-4xl m-auto mt-16 mb-16 rounded-lg"
>
<h1 className="text-5xl">{`Art`}</h1>
<section>
<p className="mb-2">{`See various art depicting Naomi.`}</p>
<Rule />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-y-5">
{Art.toSorted((a, b) => {
return a.name.localeCompare(b.name);
}).map((art) => {
return (
<ArtComponent
alt={art.alt}
artist={art.artist}
img={art.img}
key={art.name}
name={art.name}
url={art.url}
/>
);
})}
</div>
</section>
</main>
);
};

View File

@ -1,35 +1,45 @@
import { Certification } from "@/components/cert";
import { Rule } from "@/components/rule";
import { Certifications } from "@/config/Certifications";
import { Charm } from "next/font/google";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Certification } from "../../components/cert";
import { Rule } from "../../components/rule";
import { Certifications } from "../../config/Certifications";
import type { JSX } from "react";
/**
* Renders the /certs page.
* @returns A React Component.
*/
const Certs = (): JSX.Element => {
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Certs</h1>
<section>
<p className="mb-2">
This page lists the professional certifications Naomi has obtained
throughout her time as a developer.
</p>
<Rule />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-y-5">
{Certifications.sort(
(a, b) => b.date.getTime() - a.date.getTime(),
).map((cert) => (
<Certification
key={cert.name}
name={cert.name}
fileName={cert.fileName}
issuer={cert.issuer}
date={cert.date}
/>
))}
</div>
</section>
</main>
</>
<main className="w-[95%] text-center
max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Certs`}</h1>
<section>
<p className="mb-2">
{`This page lists the professional certifications Naomi has obtained
throughout her time as a developer.`}
</p>
<Rule />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-y-5">
{Certifications.toSorted(
(a, b) => {
return b.date.getTime() - a.date.getTime();
},
).map((cert) => {
return <Certification
date={cert.date}
fileName={cert.fileName}
issuer={cert.issuer}
key={cert.name}
name={cert.name}
/>;
})}
</div>
</section>
</main>
);
};

View File

@ -1,58 +1,70 @@
import { Rule } from "@/components/rule";
import { Social } from "@/components/social";
import { Donate, HireMe, Socials } from "@/config/Socials";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Rule } from "../../components/rule";
import { Social } from "../../components/social";
import { Donate, HireMe, Socials } from "../../config/Socials";
import type { JSX } from "react";
/**
* Renders the /contact page.
* @returns A React Component.
*/
const Contact = (): JSX.Element => {
return (
<>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Contact Us</h1>
<p>
We offer many different ways to get in touch with us. This page lists
all of our available social media accounts. Use the buttons below to
choose your preferred method.
</p>
<p>
Note that the items are sorted alphabetically, not by order of
response times. Monitoring levels and activity may vary by platform.
</p>
<p>
With {Socials.length} choices, you shouldn&apos;t have any complaints!
:3
</p>
<Rule />
<section>
<div>
{[HireMe, Donate].map(
({ link, label, alt, icon, color, background }) => (
<Social
key={label}
link={link}
label={label}
alt={alt}
icon={icon}
color={color}
background={background}
/>
),
)}
{Socials.sort((a, b) => a.label.localeCompare(b.label)).map(
({ link, label, alt, icon, color, background }) => (
<Social
key={label}
link={link}
label={label}
alt={alt}
icon={icon}
color={color}
background={background}
/>
),
)}
</div>
</section>
</main>
</>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Contact Us`}</h1>
<p>
{`We offer many different ways to get in touch with us. This page lists
all of our available social media accounts. Use the buttons below to
choose your preferred method.`}
</p>
<p>
{`Note that the items are sorted alphabetically, not by order of
response times. Monitoring levels and activity may vary by platform.`}
</p>
<p>
{`With ${Socials.length.toLocaleString("en-GB")} choices, you shouldn't have any complaints!
:3`}
</p>
<Rule />
<section>
<div>
{[ HireMe, Donate ].map(
({ link, label, alt, icon, color, background }) => {
return <Social
alt={alt}
background={background}
color={color}
icon={icon}
key={label}
label={label}
link={link}
/>;
}
,
)}
{Socials.toSorted((a, b) => {
return a.label.localeCompare(b.label);
}).map(
({ link, label, alt, icon, color, background }) => {
return <Social
alt={alt}
background={background}
color={color}
icon={icon}
key={label}
label={label}
link={link}
/>;
}
,
)}
</div>
</section>
</main>
);
};

View File

@ -1,26 +1,44 @@
import { Certification } from "@/components/cert";
import { Game } from "@/components/game";
import { Rule } from "@/components/rule";
import { Certifications } from "@/config/Certifications";
import { Games } from "@/config/Games";
import { Charm } from "next/font/google";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Game } from "../../components/game";
import { Rule } from "../../components/rule";
import { Games } from "../../config/Games";
import type { JSX } from "react";
/**
* Renders the /games page.
* @returns A React Component.
*/
const Gamez = (): JSX.Element => {
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Games</h1>
<section>
<p className="mb-2">See how Naomi has appeared in various games.</p>
<Rule />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-y-5">
{Games.sort((a, b) => a.name.localeCompare(b.name)).map((game) => (
<Game key={game.name} name={game.name} img={game.img} alt={game.alt} url={game.url} />
))}
</div>
</section>
</main>
</>
<main
className="w-[95%] text-center
max-w-4xl m-auto mt-16 mb-16 rounded-lg"
>
<h1 className="text-5xl">{`Games`}</h1>
<section>
<p className="mb-2">{`See how Naomi has appeared in various games.`}</p>
<Rule />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-y-5">
{Games.toSorted((a, b) => {
return a.name.localeCompare(b.name);
}).map((game) => {
return (
<Game
alt={game.alt}
img={game.img}
key={game.name}
name={game.name}
url={game.url}
/>
);
})}
</div>
</section>
</main>
);
};

View File

@ -1,75 +1,91 @@
import type { Metadata } from "next";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Inter } from "next/font/google";
import "./globals.css";
import { ClientNavigation } from "@/components/navigation";
import Script from "next/script";
// eslint-disable-next-line import/default, import/no-named-as-default, import/no-named-as-default-member
import PlausibleProvider from "next-plausible";
import { ClientFooter } from "@/components/footer";
import { Footer } from "../components/footer";
import { Navigation } from "../components/navigation";
import type { Metadata } from "next";
import type { JSX, ReactNode } from "react";
// eslint-disable-next-line import/no-unassigned-import
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
// eslint-disable-next-line new-cap
const inter = Inter({ subsets: [ "latin" ] });
export const metadata: Metadata = {
title: "Naomi's Portfolio",
const metadata: Metadata = {
description:
// eslint-disable-next-line stylistic/max-len
"This page tells you everything you could ever want to know about Naomi and her consulting firm nhcarrigan.",
openGraph: {
images: "https://cdn.nhcarrigan.com/background.png",
},
title: "Naomi's Portfolio",
twitter: {
card: "summary_large_image",
site: "@naomi_lgbt",
card: "summary_large_image",
images: "https://cdn.nhcarrigan.com/background.png",
site: "@naomi_lgbt",
},
};
export default function RootLayout({
/**
* The top-level wrapper for the React application.
* Handles mounting the shadow DOM.
* @param opts - The rendering options.
* @param opts.children - The children elements to render.
* @returns A JSX element.
*/
const RootLayout = ({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
children: ReactNode;
}>): JSX.Element => {
return (
<html lang="en">
<Script
strategy="beforeInteractive"
src="https://widgets.tree-nation.com/js/widgets/v1/widgets.min.js?v=1.0"
></Script>
<PlausibleProvider
domain="nhcarrigan.com"
customDomain="https://analytics.nhcarrigan.com"
domain="nhcarrigan.com"
trackFileDownloads={true}
trackOutboundLinks={true}
>
<link
rel="icon"
href="https://cdn.nhcarrigan.com/logo.png"
rel="icon"
sizes="any"
/>
<body className={inter.className}>
<header>
<ClientNavigation />
<Navigation />
</header>
{children}
<video
src="https://cdn.nhcarrigan.com/overlay.webm"
autoPlay
loop
muted
playsInline
autoPlay={true}
className="fixed top-0 left-0 w-full h-full object-cover opacity-25"
loop={true}
muted={true}
playsInline={true}
src="https://cdn.nhcarrigan.com/overlay.webm"
style={{ pointerEvents: "none" }}
/>
<footer>
<ClientFooter />
<Footer />
</footer>
</body>
<Script
type="text/javascript"
async={true}
defer={true}
id="hs-script-loader"
async
defer
src="//js.hs-scripts.com/47086586.js"
type="text/javascript"
></Script>
</PlausibleProvider>
</html>
);
}
};
export { metadata };
export default RootLayout;

View File

@ -1,87 +1,221 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { JSX } from "react";
/**
* Renders the /manifesto page.
* @returns A React Component.
*/
const Manifesto = (): JSX.Element => {
return (
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-3xl">The Lion, The Witch, The Audacity of This Bitch</h1>
<p className="text-2xl italic">Naomi's Transfemme Manifesto</p>
<p>In a world of binaries and boundaries, we emerge - glorious, glistening, and unapologetically ourselves. We are the lionesses who refused to be tamed, the witches who brew potions of self-love, and the audacious beings who dared to rewrite the rules of gender. This is our manifesto, our spell-book, our battle cry.</p>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-3xl">{`The Lion, The Witch, The Audacity of This Bitch`}</h1>
<p className="text-2xl italic">{`Naomi's Transfemme Manifesto`}</p>
<p>
{`In a world of binaries and boundaries, we emerge - glorious, glistening,
and unapologetically ourselves. We are the lionesses who refused to be
tamed, the witches who brew potions of self-love, and the audacious
beings who dared to rewrite the rules of gender. This is our manifesto,
our spell-book, our battle cry.`}
</p>
<h2 className="text-2xl">I. We Are the Lions</h2>
<ol>
<li>Our manes are diverse: short, long, neon, natural - each strand a testament to our journey.</li>
<li>We prowl through life with grace, strength, and an occasional stumble (because even lionesses trip sometimes, darling).</li>
<li>Our roars echo through boardrooms, classrooms, and everywhere we have been told to stay silent.</li>
<li>We fiercely protect our pride - our chosen family, our allies, our community.</li>
<li>Like lions, we bask in the sun of our authenticity, soaking up the warmth of self-acceptance.</li>
</ol>
<h2 className="text-2xl">{`I. We Are the Lions`}</h2>
<ol>
<li>
{`Our manes are diverse: short, long, neon, natural - each strand a
testament to our journey.`}
</li>
<li>
{`We prowl through life with grace, strength, and an occasional stumble
(because even lionesses trip sometimes, darling).`}
</li>
<li>
{`Our roars echo through boardrooms, classrooms, and everywhere we have
been told to stay silent.`}
</li>
<li>
{`We fiercely protect our pride - our chosen family, our allies, our
community.`}
</li>
<li>
{`Like lions, we bask in the sun of our authenticity, soaking up the
warmth of self-acceptance.`}
</li>
</ol>
<h2 className="text-2xl">II. We Are the Witches</h2>
<ol>
<li>Our spellbook is filled with incantations of self-affirmation and hexes against transphobia.</li>
<li>We stir cauldrons of change, mixing potions of progress and elixirs of equality.</li>
<li>Our wands (be they makeup brushes, pens, or literal wands) cast spells of transformation.</li>
<li>We commune with the spirits of our trans ancestors, drawing strength from their legacy.</li>
<li>In our coven, every body is sacred, every identity valid, every expression magical.</li>
</ol>
<h2 className="text-2xl">{`II. We Are the Witches`}</h2>
<ol>
<li>
{`Our spellbook is filled with incantations of self-affirmation and
hexes against transphobia.`}
</li>
<li>
{`We stir cauldrons of change, mixing potions of progress and elixirs of
equality.`}
</li>
<li>
{`Our wands (be they makeup brushes, pens, or literal wands) cast spells
of transformation.`}
</li>
<li>
{`We commune with the spirits of our trans ancestors, drawing strength
from their legacy.`}
</li>
<li>
{`In our coven, every body is sacred, every identity valid, every
expression magical.`}
</li>
</ol>
<h2 className="text-2xl">III. We Have the Audacity</h2>
<ol>
<li>We have the audacity to exist loudly in a world that wishes us to be quiet.</li>
<li>We dare to love our bodies, curves, edges, and all, defying those who say we should not.</li>
<li>We boldly claim our place in women&apos;s spaces, sports, and narratives.</li>
<li>We redefine beauty standards with every strut, sashay, and hair flip.</li>
<li>We have the gall to demand respect, rights, and recognition - and honey, we look fabulous doing it.</li>
</ol>
<h2 className="text-2xl">{`III. We Have the Audacity`}</h2>
<ol>
<li>
{`We have the audacity to exist loudly in a world that wishes us to be
quiet.`}
</li>
<li>
{`We dare to love our bodies, curves, edges, and all, defying those who
say we should not.`}
</li>
<li>
{`We boldly claim our place in women's spaces, sports, and
narratives.`}
</li>
<li>
{`We redefine beauty standards with every strut, sashay, and hair flip.`}
</li>
<li>
{`We have the gall to demand respect, rights, and recognition - and
honey, we look fabulous doing it.`}
</li>
</ol>
<h2 className="text-2xl">IV. Our Decrees</h2>
<ol>
<li>We decree that gender is a playground, not a prison. Swing on the monkey bars of masculinity, slide down the curves of femininity, or build sandcastles of androgyny.</li>
<li>We proclaim that our bodies are our own, to modify or maintain as we see fit. Your opinion on our transitions is like our facial hair - unwanted and about to be removed.</li>
<li>We declare our right to safe spaces, medical care, and public restrooms without fear or judgment.</li>
<li>We assert our humanity in the face of legislation that tries to erase us. Our existence is not up for debate.</li>
<li>We affirm our right to joy, love, and celebration. Our lives are not just about struggle - we're here to thrive, baby!</li>
</ol>
<h2 className="text-2xl">{`IV. Our Decrees`}</h2>
<ol>
<li>
{`We decree that gender is a playground, not a prison. Swing on the
monkey bars of masculinity, slide down the curves of femininity, or
build sandcastles of androgyny.`}
</li>
<li>
{`We proclaim that our bodies are our own, to modify or maintain as we
see fit. Your opinion on our transitions is like our facial hair -
unwanted and about to be removed.`}
</li>
<li>
{`We declare our right to safe spaces, medical care, and public
restrooms without fear or judgment.`}
</li>
<li>
{`We assert our humanity in the face of legislation that tries to erase
us. Our existence is not up for debate.`}
</li>
<li>
{`We affirm our right to joy, love, and celebration. Our lives are not
just about struggle - we're here to thrive, baby!`}
</li>
</ol>
<h2 className="text-2xl">V. Our Commitments</h2>
<ol>
<li>We vow to lift as we climb, ensuring no trans sibling is left behind.</li>
<li>We pledge to celebrate the diversity within our community - every shade, shape, and expression of transness.</li>
<li>We promise to continue educating, even when it's exhausting, because knowledge is the enemy of ignorance.</li>
<li>We commit to loving ourselves fiercely, even on days when the world makes it hard.</li>
<li>We dedicate ourselves to creating art, music, literature, and memes that tell our stories and make our voices heard.</li>
</ol>
<h2 className="text-2xl">{`V. Our Commitments`}</h2>
<ol>
<li>
{`We vow to lift as we climb, ensuring no trans sibling is left behind.`}
</li>
<li>
{`We pledge to celebrate the diversity within our community - every
shade, shape, and expression of transness.`}
</li>
<li>
{`We promise to continue educating, even when it's exhausting, because
knowledge is the enemy of ignorance.`}
</li>
<li>
{`We commit to loving ourselves fiercely, even on days when the world
makes it hard.`}
</li>
<li>
{`We dedicate ourselves to creating art, music, literature, and memes
that tell our stories and make our voices heard.`}
</li>
</ol>
<h2 className="text-2xl">VI. The Transfemme Toolbox</h2>
<ol>
<li>Eyeliner sharp enough to wing and to slay our enemies.</li>
<li>A vocabulary expansive enough to articulate our identities and to eloquently tell transphobes where to go.</li>
<li>Heels high enough to reach new heights (and flats comfortable enough for when the revolution requires running).</li>
<li>A chosen name that feels like home and a dead name composted for future growth.</li>
<li>A support network of fellow lions, witches, and audacious bitches to remind us we're not alone.</li>
</ol>
<h2 className="text-2xl">{`VI. The Transfemme Toolbox`}</h2>
<ol>
<li>{`Eyeliner sharp enough to wing and to slay our enemies.`}</li>
<li>
{`A vocabulary expansive enough to articulate our identities and to
eloquently tell transphobes where to go.`}
</li>
<li>
{`Heels high enough to reach new heights (and flats comfortable enough
for when the revolution requires running).`}
</li>
<li>
{`A chosen name that feels like home and a dead name composted for
future growth.`}
</li>
<li>
{`A support network of fellow lions, witches, and audacious bitches to
remind us we're not alone.`}
</li>
</ol>
<h2 className="text-2xl">VII. Our Vision of the Future</h2>
<p>In our ideal world:</p>
<ol>
<li>Gender reveal parties are replaced by "I'll reveal my gender when I'm good and ready" parties.</li>
<li>The only time we're asked about our genitals is by our doctors or consensual partners.</li>
<li>Trans joy is as commonplace as cis assumptions once were.</li>
<li>Our stories are told by us, not about us, in media, literature, and history books.</li>
<li>The audacity of our existence is celebrated, not merely tolerated.</li>
</ol>
<h2 className="text-2xl">{`VII. Our Vision of the Future`}</h2>
<p>{`In our ideal world:`}</p>
<ol>
<li>
{`Gender reveal parties are replaced by "I'll reveal my gender when I'm
good and ready" parties.`}
</li>
<li>
{`The only time we're asked about our genitals is by our doctors or
consensual partners.`}
</li>
<li>{`Trans joy is as commonplace as cis assumptions once were.`}</li>
<li>
{`Our stories are told by us, not about us, in media, literature, and
history books.`}
</li>
<li>
{`The audacity of our existence is celebrated, not merely tolerated.`}
</li>
</ol>
<h2 className="text-2xl">The Tea is Served</h2>
<p>So here we stand, in all our lionhearted, witchy, audacious glory. We've stirred the pot, we've cast our spells, we've roared our truths. The teacup of tradition lays shattered at our feet, and darling, the brew we're serving now is a potent blend of authenticity, resistance, and fierce, uncompromising love.</p>
<h2 className="text-2xl">{`The Tea is Served`}</h2>
<p>
{`So here we stand, in all our lionhearted, witchy, audacious glory. We've
stirred the pot, we've cast our spells, we've roared our truths. The
teacup of tradition lays shattered at our feet, and darling, the brew
we're serving now is a potent blend of authenticity, resistance, and
fierce, uncompromising love.`}
</p>
<p>To those who support us: we see you, we appreciate you, we invite you to roar alongside us.
To those who don't understand us: we invite you to listen, to learn, and to expand your world.
To those who oppose us: your time is up, your reign is over, the future is gloriously, unapologetically trans.</p>
<p>
{`To those who support us: we see you, we appreciate you, we invite you to
roar alongside us. To those who don't understand us: we invite you to
listen, to learn, and to expand your world. To those who oppose us: your
time is up, your reign is over, the future is gloriously,
unapologetically trans.`}
</p>
<p>Remember, we didn't come this far, break this many barriers, and perfect our contouring skills just to be anything less than the majestic, magical, audacious bitches we are.</p>
<p>
{`Remember, we didn't come this far, break this many barriers, and perfect
our contouring skills just to be anything less than the majestic,
magical, audacious bitches we are.`}
</p>
<p className="text-2xl">The lion has spoken. The witch has cast her spell. This bitch is here to stay.</p>
<p className="text-2xl">
{`The lion has spoken. The witch has cast her spell. This bitch is here to
stay.`}
</p>
<p className="text-3xl">Long live the transfemme revolution! 🦁👑💄🏳</p>
</main>
<p className="text-3xl">
{`Long live the transfemme revolution! 🦁✨👑💄🏳️‍⚧️`}
</p>
</main>
);
};

View File

@ -1,134 +1,172 @@
import { Rule } from "@/components/rule";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import Image from "next/image";
import { Rule } from "../../components/rule";
import type { JSX } from "react";
/**
* Renders the /manual page.
* @returns A React Component.
*/
const Manual = (): JSX.Element => {
return (
<>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Naomi&apos;s User Manual</h1>
<p className="text-3xl">Model T42-P9000</p>
<section>
<p className="mb-2">
Hiya! This page is meant to give you a run-down of what working with
me is like. It&apos;s like a li&apos;l insight into the way I best
interact with people and perform on a team.
</p>
<Image
className="m-auto"
src="https://cdn.nhcarrigan.com/hire.jpeg"
alt="If you knew I was so unstable, why'd you hire me?"
width={500}
height={500}
/>
<Rule />
</section>
<section>
<h2 className="text-3xl">My Values</h2>
<p className="mb-2">
I tend to be very firm in my values, to the degree that I shy away
from organisations or projects which do not align with my ethics.
</p>
<ul className="w-4/5 m-auto">
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
First and foremost, do not pass judgement. I will not begrudge you
for your religious beliefs, political alignments, or any other
aspects of your life. And I expect the same courtesy in return.
You do not have to accept who I am, or support my choices, but we
need to maintain a respectful and cordial professional
relationship. Expressing hateful, mean-spirited, or vitriolic
comments does not foster such an environment, and my tolerance for
such is nil.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
Second, we shall do no harm. I very strongly believe that
technology is meant to advance our society, not regress it.
Software should not be used to automate people&apos;s careers
away, or replace creative works with pale imitations, or
harass/target someone, or restrict access to information.
</li>
</ul>
<Rule />
</section>
<section>
<h2 className="text-3xl">Environment</h2>
<p className="mb-2">
I have found that I best thrive and produce the greatest works in
specific environments.
</p>
<ul className="w-4/5 m-auto">
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
Ideas should be freely discussed, challenged, and evaluated. I am
not a &quot;yes girl&quot; to blindly follow orders. If I hear a
plan that I think misses the mark, I will absolutely voice my
concerns. And I welcome the same scrutiny in return. Discussion
needs to be constructive and fruitful - if we&apos;re going around
in circles, it&apos;s time to table it and sleep on our thoughts.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
We are not our ideas, however. &quot;This is bad and you should
feel bad&quot; helps no one. &quot;I&apos;m not sure that is the
best approach, can we consider doing this instead?&quot; keeps the
conversation focused on the right things and moving forward.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
ADHD means my productivity is highly fluctuating. There are days
where I can sit and bang out a week of work in 16 hours, and there
are days where I stare mindlessly at the screen and then realise
the sun has set already. Flexibility in both schedule and
deadlines is very important to me.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
Likewise, insomnia can rear its ugly head and absolutely wreck my
sleep schedule without any warning. Asynchronous comms are always
preferred over meetings, but if a meeting must happen the
afternoon hours are the best. Too early and I&apos;ll likely fail
to wake up. Too late and I might be incoherent.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
If given something like a Trello or a Monday board, I will 100%
make it pretty and load every single task ever on there. I&apos;m
a sucker for organising workloads and the easiest way for me to be
transparent about the work I&apos;m doing is to just let you look
at a task board. If you say &quot;what did you do yesterday&quot;
I will not remember this for I have slept since then.
</li>
</ul>
<Rule />
</section>
<section>
<h2 className="text-3xl">Communication</h2>
<p>
As with many people, there are certain approaches to communication
that are more effective for me.
</p>
<ul className="w-4/5 m-auto">
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
Don&apos;t just say &quot;hello&quot; in my DMs or ping me without
context. You&apos;ll pull me out of a workflow to wait for the
rest of the message. Send it all at once, or save the ping for the
last part.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
I have generalised anxiety disorder. Please for the love of all
things, do NOT say &quot;we need to talk&quot; or &quot;do you
have time to meet&quot;. I will 100% sit there right up until the
meeting starts stressing about getting fired and not actually
getting any work done. If you need to call me out, just rip the
bandage off and come out of the gate with it.
</li>
<li className="mb-2 relative before:content-['🩵'] before:absolute before:left-[-1em]">
I dunno if you noticed the tone changed in this document about a
million times. That&apos;s pretty much Naomi in a nutshell.
I&apos;ll go from collected and eloquent to manic and sending
messages faster than Discord can process. I try my hardest to stay
professional, but ADHD makes that very hard. I&apos;ll swear
sometimes, I&apos;ll say totally off-the-wall things. But I really
do try!
</li>
</ul>
</section>
</main>
</>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Naomi's User Manual`}</h1>
<p className="text-3xl">{`Model T42-P9000`}</p>
<section>
<p className="mb-2">
{`Hiya! This page is meant to give you a run-down of what working with
me is like. It's like a li'l insight into the way I best
interact with people and perform on a team.`}
</p>
<Image
alt="If you knew I was so unstable, why'd you hire me?"
className="m-auto"
height={500}
src="https://cdn.nhcarrigan.com/hire.jpeg"
width={500}
/>
<Rule />
</section>
<section>
<h2 className="text-3xl">{`My Values`}</h2>
<p className="mb-2">
{`I tend to be very firm in my values, to the degree that I shy away
from organisations or projects which do not align with my ethics.`}
</p>
<ul className="w-4/5 m-auto">
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`First and foremost, do not pass judgement. I will not begrudge you
for your religious beliefs, political alignments, or any other
aspects of your life. And I expect the same courtesy in return.
You do not have to accept who I am, or support my choices, but we
need to maintain a respectful and cordial professional
relationship. Expressing hateful, mean-spirited, or vitriolic
comments does not foster such an environment, and my tolerance for
such is nil.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`Second, we shall do no harm. I very strongly believe that
technology is meant to advance our society, not regress it.
Software should not be used to automate people's careers
away, or replace creative works with pale imitations, or
harass/target someone, or restrict access to information.`}
</li>
</ul>
<Rule />
</section>
<section>
<h2 className="text-3xl">{`Environment`}</h2>
<p className="mb-2">
{`I have found that I best thrive and produce the greatest works in
specific environments.`}
</p>
<ul className="w-4/5 m-auto">
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`Ideas should be freely discussed, challenged, and evaluated. I am
not a "yes girl" to blindly follow orders. If I hear a
plan that I think misses the mark, I will absolutely voice my
concerns. And I welcome the same scrutiny in return. Discussion
needs to be constructive and fruitful - if we're going around
in circles, it's time to table it and sleep on our thoughts.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`We are not our ideas, however. "This is bad and you should
feel bad" helps no one. "I'm not sure that is the
best approach, can we consider doing this instead?" keeps the
conversation focused on the right things and moving forward.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`ADHD means my productivity is highly fluctuating. There are days
where I can sit and bang out a week of work in 16 hours, and there
are days where I stare mindlessly at the screen and then realise
the sun has set already. Flexibility in both schedule and
deadlines is very important to me.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`Likewise, insomnia can rear its ugly head and absolutely wreck my
sleep schedule without any warning. Asynchronous comms are always
preferred over meetings, but if a meeting must happen the
afternoon hours are the best. Too early and I'll likely fail
to wake up. Too late and I might be incoherent.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`If given something like a Trello or a Monday board, I will 100%
make it pretty and load every single task ever on there. I'm
a sucker for organising workloads and the easiest way for me to be
transparent about the work I'm doing is to just let you look
at a task board. If you say "what did you do yesterday"
I will not remember this for I have slept since then.`}
</li>
</ul>
<Rule />
</section>
<section>
<h2 className="text-3xl">{`Communication`}</h2>
<p>
{`As with many people, there are certain approaches to communication
that are more effective for me.`}
</p>
<ul className="w-4/5 m-auto">
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`Don't just say "hello" in my DMs or ping me without
context. You'll pull me out of a workflow to wait for the
rest of the message. Send it all at once, or save the ping for the
last part.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`I have generalised anxiety disorder. Please for the love of all
things, do NOT say "we need to talk" or "do you
have time to meet". I will 100% sit there right up until the
meeting starts stressing about getting fired and not actually
getting any work done. If you need to call me out, just rip the
bandage off and come out of the gate with it.`}
</li>
<li
className="mb-2 relative before:content-['🩵']
before:absolute before:left-[-1em]"
>
{`I dunno if you noticed the tone changed in this document about a
million times. That's pretty much Naomi in a nutshell.
I'll go from collected and eloquent to manic and sending
messages faster than Discord can process. I try my hardest to stay
professional, but ADHD makes that very hard. I'll swear
sometimes, I'll say totally off-the-wall things. But I really
do try!`}
</li>
</ul>
</section>
</main>
);
};

View File

@ -1,55 +1,68 @@
"use client";
import { NavItems } from "@/config/NavItems";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import Image from "next/image";
import React, { useEffect, useState } from "react";
import React, { type JSX } from "react";
import { NavItems } from "../config/NavItems";
export default function Home() {
const [isDarkMode, setIsDarkMode] = useState(false);
useEffect(() => {
const savedTheme = localStorage.getItem("theme");
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)",
).matches;
const isDark = savedTheme === "dark" || (!savedTheme && prefersDark);
document.documentElement.classList.toggle("dark", isDark);
setIsDarkMode(isDark);
}, []);
/**
* Renders the main React component.
* @returns A JSX element.
*/
const Home = (): JSX.Element => {
return (
<div>
<div className="absolute top-0 right-[33vw] z-100 w-[100vh] h-[100vh] rotate-90 hidden lg:block">
<svg viewBox="0 0 500 500" className="absolute">
<div
className="absolute top-0 right-[33vw] z-100
w-[100vh] h-[100vh] rotate-90 hidden lg:block"
>
<svg className="absolute" viewBox="0 0 500 500">
<path
d="M0,100 C150,200 350,0 500,100 L500,00 L0,0 Z"
style={{ stroke: "none", fill: "var(--foreground)" }}
style={{ fill: "var(--foreground)", stroke: "none" }}
></path>
</svg>
</div>
<main className="grid grid-cols-[2fr,1fr] min-h-screen">
<section className="bg-[--background] text-[--foreground] flex flex-col items-left justify-center text-left pl-5">
<h1 className="text-4xl mb-2">Naomi Carrigan</h1>
<section
className="bg-[--background] text-[--foreground]
flex flex-col items-left justify-center text-left pl-5"
>
<h1 className="text-4xl mb-2">{`Naomi Carrigan`}</h1>
<Image
src="https://cdn.nhcarrigan.com/profile.png"
alt="Naomi Carrigan"
width={200}
height={200}
className="rounded-full"
height={200}
src="https://cdn.nhcarrigan.com/profile.png"
width={200}
/>
<p className="text-3xl">Software Engineer</p>
<p className="text-3xl">Community Manager</p>
<p className="text-3xl">{`Software Engineer`}</p>
<p className="text-3xl">{`Community Manager`}</p>
</section>
<section className="bg-[--foreground] text-[--background] flex flex-col items-center justify-center">
{NavItems.map((item, index) => (
<a
key={item.href}
href={item.href}
className="block py-2 px-4 text-2xl hover:bg-[--background] hover:text-[--foreground]"
>
{index % 2 ? "🩷" : "🩵"} {item.text}
</a>
))}
<section
className="bg-[--foreground] text-[--background]
flex flex-col items-center justify-center"
>
{NavItems.map((item, index) => {
return (
<a
className="block py-2 px-4 text-2xl
hover:bg-[--background] hover:text-[--foreground]"
href={item.href}
key={item.href}
>
{index % 2 === 1
? "🩷"
: "🩵"} {item.text}
</a>
);
})}
</section>
</main>
</div>
);
}
};
export default Home;

View File

@ -1,32 +1,41 @@
import { Partner } from "@/components/partner";
import { Rule } from "@/components/rule";
import { Partners } from "@/config/Partners";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Partner } from "../../components/partner";
import { Rule } from "../../components/rule";
import { Partners } from "../../config/Partners";
import type { JSX } from "react";
/**
* Renders the /polycule page.
* @returns A React Component.
*/
const Polycule = (): JSX.Element => {
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Naomi&apos;s Polycule</h1>
<section>
<p className="mb-2">
Meet the people who love and support Naomi to the ends of the earth.
</p>
<Rule />
<div className="w-full">
{Partners.map((member) => (
<Partner
key={member.name}
name={member.name}
url={member.url}
avatar={member.avatar}
anniversary={member.anniversary}
relationship={member.relationship}
/>
))}
</div>
</section>
</main>
</>
<main className="w-[95%] text-center
max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Naomi's Polycule`}</h1>
<section>
<p className="mb-2">
{`Meet the people who love and support Naomi to the ends of the earth.`}
</p>
<Rule />
<div className="w-full">
{Partners.map((member) => {
return <Partner
anniversary={member.anniversary}
avatar={member.avatar}
key={member.name}
name={member.name}
relationship={member.relationship}
url={member.url}
/>;
})}
</div>
</section>
</main>
);
};

View File

@ -1,39 +1,47 @@
import { Certification } from "@/components/cert";
import { Review } from "@/components/review";
import { Rule } from "@/components/rule";
import { Certifications } from "@/config/Certifications";
import { Testimonials } from "@/config/Testimonials";
import { Charm } from "next/font/google";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Review } from "../../components/review";
import { Rule } from "../../components/rule";
import { Testimonials } from "../../config/Testimonials";
import type { JSX } from "react";
/**
* Renders the /reviews page.
* @returns A React Component.
*/
const Reviews = (): JSX.Element => {
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Client Reviews</h1>
<section>
<p className="mb-2">
We think we&apos;re pretty great to work with, but don&apos;t take
our word for it. Here&apos;s what our clients have to say.
</p>
<Rule />
<ol className="relative border-s border-[--primary] w-4/5 m-auto">
{Testimonials.sort(
(a, b) => b.date.getTime() - a.date.getTime(),
).map((review) => (
<Review
key={review.date.toISOString()}
name={review.name}
date={review.date}
content={review.content}
sourceIcon={review.sourceIcon}
sourceUrl={review.sourceUrl}
sourceName={review.sourceName}
/>
))}
</ol>
</section>
</main>
</>
<main className="w-[95%] text-center max-w-4xl
m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Client Reviews`}</h1>
<section>
<p className="mb-2">
{`We think we're pretty great to work with, but don't take
our word for it. Here's what our clients have to say.`}
</p>
<Rule />
<ol className="relative border-s border-[--primary] w-4/5 m-auto">
{Testimonials.toSorted(
(a, b) => {
return b.date.getTime() - a.date.getTime();
},
).map((review) => {
return <Review
content={review.content}
date={review.date}
key={review.date.toISOString()}
name={review.name}
sourceIcon={review.sourceIcon}
sourceName={review.sourceName}
sourceUrl={review.sourceUrl}
/>;
})}
</ol>
</section>
</main>
);
};

View File

@ -1,37 +1,41 @@
import { Certification } from "@/components/cert";
import { Game } from "@/components/game";
import { Member } from "@/components/member";
import { Rule } from "@/components/rule";
import { Certifications } from "@/config/Certifications";
import { Games } from "@/config/Games";
import { TeamMembers } from "@/config/TeamMembers";
import { Charm } from "next/font/google";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Member } from "../../components/member";
import { Rule } from "../../components/rule";
import { TeamMembers } from "../../config/TeamMembers";
import type { JSX } from "react";
/**
* Renders the /team page.
* @returns A React Component.
*/
const Team = (): JSX.Element => {
return (
<>
<main className="w-[95%] text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Our Team</h1>
<section>
<p className="mb-2">
Meet the people behind nhcarrigan&apos;s success!
</p>
<Rule />
<div className="w-full">
{TeamMembers.map((member) => (
<Member
key={member.name}
name={member.name}
url={member.url}
avatar={member.avatar}
joinDate={member.joinDate}
role={member.role}
/>
))}
</div>
</section>
</main>
</>
<main className="w-[95%] text-center
max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Our Team`}</h1>
<section>
<p className="mb-2">
{`Meet the people behind nhcarrigan's success!`}
</p>
<Rule />
<div className="w-full">
{TeamMembers.map((member) => {
return <Member
avatar={member.avatar}
joinDate={member.joinDate}
key={member.name}
name={member.name}
role={member.role}
url={member.url}
/>;
})}
</div>
</section>
</main>
);
};

View File

@ -1,92 +1,103 @@
import { Job } from "@/components/job";
import { Rule } from "@/components/rule";
import { Social } from "@/components/social";
import { Jobs } from "@/config/Jobs";
import { Donate, HireMe, Socials } from "@/config/Socials";
import { Volunteer } from "@/icons/Volunteer";
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { faCalendar, faTasks } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Job } from "../../components/job";
import { Rule } from "../../components/rule";
import { Jobs } from "../../config/Jobs";
import { Volunteer } from "../../icons/Volunteer";
import type { JSX } from "react";
/**
* Renders the /work page.
* @returns A React Component.
*/
const Work = (): JSX.Element => {
return (
<>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">Our Work</h1>
<main className="w-4/5 text-center max-w-4xl m-auto mt-16 mb-16 rounded-lg">
<h1 className="text-5xl">{`Our Work`}</h1>
<p>
{`We run a software engineering and community management firm known as
nhcarrigan.`}
</p>
<Rule />
<section>
<h2 className="text-3xl">{`Legend`}</h2>
<p>
We run a software engineering and community management firm known as
nhcarrigan.
{`Our work is listed here in reverse chronological order. The symbols
and colours have a specific meaning:`}
</p>
<table className="m-auto w-1/2">
<thead>
<tr>
<th>{`Symbol`}</th>
<th>{`Meaning`}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<FontAwesomeIcon className="h-14" icon={faCalendar} />
</td>
<td>{`Fixed-Rate Contract (hourly/salary)`}</td>
</tr>
<tr>
<td>
<FontAwesomeIcon className="h-14" icon={faTasks} />
</td>
<td>{`Project-based Contract`}</td>
</tr>
<tr>
<td>
<FontAwesomeIcon className="h-14" icon={Volunteer} />
</td>
<td>{`Planned`}</td>
</tr>
<tr>
<td>
<p className="h-14 w-14 border-[--current]
border-double border-4"></p>
</td>
<td className="text-[--current]">{`Current Contract`}</td>
</tr>
<tr>
<td>
<p className="h-14 w-14 border-[--former]
border-dashed border-2"></p>
</td>
<td className="text-[--former]">{`Former Contract`}</td>
</tr>
</tbody>
</table>
<Rule />
<section>
<h2 className="text-3xl">Legend</h2>
<p>
Our work is listed here in reverse chronological order. The symbols
and colours have a specific meaning:
</p>
<table className="m-auto w-1/2">
<thead>
<tr>
<th>Symbol</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<FontAwesomeIcon className="h-14" icon={faCalendar} />
</td>
<td>Fixed-Rate Contract (hourly/salary)</td>
</tr>
<tr>
<td>
<FontAwesomeIcon className="h-14" icon={faTasks} />
</td>
<td>Project-based Contract</td>
</tr>
<tr>
<td>
<FontAwesomeIcon className="h-14" icon={Volunteer} />
</td>
<td>Planned</td>
</tr>
<tr>
<td>
<p className="h-14 w-14 border-[--current] border-double border-4"></p>
</td>
<td className="text-[--current]">Current Contract</td>
</tr>
<tr>
<td>
<p className="h-14 w-14 border-[--former] border-dashed border-2"></p>
</td>
<td className="text-[--former]">Former Contract</td>
</tr>
</tbody>
</table>
<Rule />
</section>
<section>
<h2 className="text-3xl">Timeline</h2>
<ol className="relative border-s border-[--primary] w-4/5 m-auto">
{Jobs.sort((a, b) => b.start.getTime() - a.start.getTime()).map(
(job) => (
<Job
key={job.title + " - " + job.company}
title={job.title}
company={job.company}
start={job.start}
end={job.end}
link={job.link}
type={job.type}
description={job.description}
logo={job.logo}
/>
),
)}
</ol>
</section>
</main>
</>
</section>
<section>
<h2 className="text-3xl">{`Timeline`}</h2>
<ol className="relative border-s border-[--primary] w-4/5 m-auto">
{Jobs.toSorted((a, b) => {
return b.start.getTime() - a.start.getTime();
}).map(
(job) => {
return <Job
company={job.company}
description={job.description}
end={job.end}
key={`${job.title} - ${job.company}`}
link={job.link}
logo={job.logo}
start={job.start}
title={job.title}
type={job.type}
/>;
}
,
)}
</ol>
</section>
</main>
);
};