generated from nhcarrigan/template
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:
@ -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'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'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'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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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'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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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'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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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'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
|
||||
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'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>
|
||||
</>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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'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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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'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.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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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'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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user