feat: modularise and expand job information, set up testing (#9)

Closes #6
Closes #7
Closes #8

Reviewed-on: https://codeberg.org/nhcarrigan/portfolio/pulls/9
Co-authored-by: Naomi <commits@nhcarrigan.com>
Co-committed-by: Naomi <commits@nhcarrigan.com>
This commit is contained in:
Naomi Carrigan 2024-05-19 05:17:17 +00:00 committed by Naomi Carrigan
parent 41cbd482c4
commit b909f4666c
38 changed files with 2100 additions and 861 deletions

View File

@ -1,6 +1,9 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { AppComponent } from "./app.component";
import { Employment } from "./config/Employment";
import { Logos } from "./config/Logos";
import { Socials } from "./config/Socials";
describe("AppComponent", () => {
let component: AppComponent;
@ -25,3 +28,63 @@ describe("AppComponent", () => {
expect(app.title).toEqual("nhcarrigan");
});
});
describe("Configs", () => {
it("employments should have correct oldest and newest", () => {
const sorted = Employment.sort(
(a, b) => b.start.getTime() - a.start.getTime()
);
const oldest = sorted.at(-1);
const newest = sorted[0];
expect(oldest?.title).toBe("Started Journey");
expect(newest.company).toBe("Your Company!");
});
it("employments should have valid dates", () => {
const sorted = [
...Employment.sort((a, b) => b.start.getTime() - a.start.getTime())
];
const oldest = sorted.pop();
const newest = sorted.shift();
if (!oldest || !newest) {
throw new Error("Failed to parse");
}
for (const job of sorted) {
expect(job.start.getTime())
.withContext(`${job.title} - ${job.company}`)
.toBeGreaterThan(oldest.start.getTime());
// Days should be set to the 5th - this ensures we're
// within the correct month in all timezones.
expect(job.start.getDate())
.withContext(`${job.title} - ${job.company}`)
.toBeGreaterThanOrEqual(4);
expect(job.start.getDate())
.withContext(`${job.title} - ${job.company}`)
.toBeLessThanOrEqual(6);
if (job.end) {
expect(job.end.getTime())
.withContext(`${job.title} - ${job.company}`)
.toBeLessThan(newest.start.getTime());
expect(job.end.getDate())
.withContext(`${job.title} - ${job.company}`)
.toBeGreaterThanOrEqual(4);
expect(job.end.getDate())
.withContext(`${job.title} - ${job.company}`)
.toBeLessThanOrEqual(6);
}
}
});
it("logos should be unique", () => {
const links = new Set(Logos.map((l) => l.link));
const names = new Set(Logos.map((l) => l.alt));
const files = new Set(Logos.map((l) => l.file));
expect(links.size).toBe(Logos.length);
expect(names.size).toBe(Logos.length);
expect(files.size).toBe(Logos.length);
});
it("socials should be unique", () => {
const names = new Set(Socials.map((s) => s.label));
const links = new Set(Socials.map((s) => s.link));
expect(links.size).toBe(Socials.length);
expect(names.size).toBe(Socials.length);
});
});

View File

@ -0,0 +1,326 @@
export const Employment: {
title: string;
company: string;
/**
* Set ALL dates to the 5th. These are not exact days, but intended to avoid month discrepancies
* when dealing with timezones.
*/
start: Date;
/**
* Set ALL dates to the 5th. These are not exact days, but intended to avoid month discrepancies
* when dealing with timezones.
*/
end: Date | null;
link: string;
type: "volunteer" | "fixed" | "project" | "hypothetical";
description: string;
/**
* File name of logo.
*/
logo?: string;
}[] = [
{
title: "Consultant",
company: "Your Company!",
start: new Date(Date.now()),
end: null,
link: "https://topmate.io/nhcarrigan/913920",
type: "hypothetical",
logo: "future.jpeg",
description: `With a deep passion for leveraging technology for positive social impact, I am a community-oriented software engineer dedicated to cultivating safe, inclusive, and welcoming online spaces. My focus on user experience and accessibility drives me to create robust software tools and platforms that prioritize privacy, security, and diversity.
My career reflects a commitment to supporting aspiring developers as they break into the tech industry. Through mentorship, educational initiatives, and advocating for inclusive hiring practices, I strive to remove barriers and empower underrepresented individuals in the digital realm.
For me, software engineering goes beyond codingit's about using technology to drive positive change. By championing diversity, equity, and accessibility in every project, I aim to reshape the tech industry's narrative and contribute to a more equitable future.
Let's connect to drive meaningful impact and foster innovation and inclusivity in technology.`
},
{
title: "Started Journey",
company: "nhcarrigan",
start: new Date("April 5 2020"),
end: null,
link: "https://naomi.lgbt",
type: "hypothetical",
logo: "nhcarrigan.jpeg",
description:
"Began my journey learning to code, starting from the top of the freeCodeCamp curriculum."
},
{
title: "Development Lead",
company: "Artists For Palestine",
start: new Date("November 5 2023"),
end: null,
link: "https://art4palestine.org",
type: "volunteer",
logo: "a4p.jpeg",
description: `As a Development Lead at Art 4 Palestine, I developed a bot that efficiently manages integrations between Airtable forms, Trello boards, and Discord, streamlining workflow and improving productivity. The bot also pulls news articles from reputable sources and cross-posts them into the server, keeping the community informed with reliable updates.
Additionally, I guided and mentored other developers in the design and coding of the website, ensuring high-quality output and consistent alignment with project goals. My contributions have been instrumental in supporting the organization's initiatives and fostering collaboration within the development team.`
},
{
title: "Community Moderator",
company: "AngelRose",
start: new Date("September 5 2023"),
end: null,
link: "https://discord.gg/kYpjgEB",
type: "volunteer",
description: `As a Discord Moderator at AngelRose, I played a key role in maintaining a safe, respectful, and engaging environment for community members. I monitored conversations, enforcing community guidelines to prevent disruptive behavior and protect users. Additionally, I addressed and resolved conflicts, providing support and guidance to members to promote a positive experience. My contributions helped uphold the integrity of the community and foster an inclusive and welcoming space for all participants.`
},
{
title: "Community Bot Engineer",
company: "Deepgram",
start: new Date("July 5 2023"),
end: null,
link: "https://deepgram.com",
type: "project",
logo: "deepgram.jpeg",
description: `As a Community Bot Engineer at Deepgram, I developed a sophisticated Discord bot to enhance community management and streamline user interactions. The bot features an array of capabilities, including the ability to move messages from standard channels to forum channels, maintaining an organized space for discussion. It integrates AI to automatically answer new questions in the forum channel and allows for responses to be marked as correct answers.
I designed the bot to send scheduled messages in the general channel, prompting users to utilize the forum channel for their questions. Additionally, the bot provides daily and weekly aggregations of unanswered questions, cross-posts answered questions to the GitHub discussion board, and reminds users of unanswered questions if they've been inactive for seven days.
The bot also tracks various metrics such as unanswered, answered, and closed questions, as well as questions moved by the bot, to monitor the overall health of the community. Finally, it can post feedback messages to ProductBoard, contributing to product development and user satisfaction.
Through these innovative features, my work has improved community engagement and provided a seamless, organized experience for Deepgram's users.`
},
{
title: "Twitch Integration Engineer",
company: "BigBadBeaver Productions",
start: new Date("May 5 2023"),
end: new Date("January 5 2024"),
link: "https://linktr.ee/bigbadbeaver",
type: "project",
description: `As a Twitch Integration Engineer at Big Bad Beaver Productions, I developed "PrivateTwigs," a custom Twitch chat bot that enhanced stream management and engagement. The bot includes comprehensive logging for all chat messages and stream events, enabling detailed analysis and strategic insights.
Additionally, I implemented custom redemption rewards within the bot, providing viewers with unique opportunities to interact with the stream and engage with content. My work as a Twitch Integration Engineer significantly improved the streaming experience for both streamers and viewers, contributing to a more interactive and dynamic community.`
},
{
title: "Community Manager and Open-Source Engineer",
company: "Sema Software",
start: new Date("May 5 2022"),
end: new Date("September 5 2022"),
link: "https://www.semasoftware.com",
type: "fixed",
logo: "sema.jpeg",
description: `In my role as Community Manager and Open Source Engineer at Sema Software, I significantly shaped and cultivated the Discord community, expanding its membership from 300 to 1,000. This involved fostering engagement and creating a welcoming space for all members.
In addition to community management, I led various open source initiatives across multiple projects. This included creating a base template for starting new projects, providing developers with a structured and efficient foundation. I also managed the Developer Skills Matrix repository and its associated Discord bot, website, and Slack bot, allowing users to take self-assessments across their preferred platforms.
Moreover, I developed a Discord bot to query projects listed on the Open Source Welcoming Committee, enhancing accessibility and visibility for open source projects. Through these contributions, I have played a key role in driving community growth and promoting open source engagement at Sema Software.`
},
{
title: "Community Manager",
company: "4C",
start: new Date("May 5 2022"),
end: new Date("November 5 2022"),
link: "https://discord.com/invite/ns5x8bTz25",
type: "fixed",
description: `As Community Manager at 4C, I played a pivotal role in shaping and nurturing the Discord community, driving significant growth and member engagement. Under my management, the community expanded from 1,100 to 3,350 members, fostering an active and thriving space for all participants. My contributions have been instrumental in creating a welcoming and dynamic environment, promoting meaningful interactions and enhancing overall community satisfaction.`
},
{
title: "Community Manager",
company: "TweetShift",
start: new Date("January 5 2022"),
end: new Date("May 5 2023"),
link: "https://tweetshift.com",
type: "fixed",
description: `As the Community Manager for the TweetShift Discord bot, I provided comprehensive support to a community that utilizes the bot across over 230,000 servers. My focus was on delivering high-quality assistance and ensuring the bot's seamless functionality for users. I also played a key role in moderating the community, maintaining a safe and inclusive environment for all members. Through these efforts, I have fostered a welcoming space and contributed to the overall success and engagement of the TweetShift community.`
},
{
title: "Senior Integrations Engineer",
company: "Rythm",
start: new Date("April 5 2022"),
end: null,
link: "https://rythm.fm",
type: "fixed",
description: `As a Senior Integrations Engineer at Rythm, I specialized in building Discord bots and tools that empower our team to effectively manage a server of over 300,000 members. My work involved creating a comprehensive moderation bot that includes an automoderation system, extensive moderation history, and FAQ responses. This tool offers individual case management, evidence logging, a staff-only note system, and customizable automod rules.
I developed an economy bot that rewards long-term activity with levels, roles, and a currency system that enables members to purchase specialized rewards, personalize their bot profiles, and earn badges. Additionally, I designed a staff incentive bot that allows leadership to recognize volunteer moderators and staff for their exceptional contributions.
My projects also include an analytics bot to monitor user engagement, a trivia bot to entertain members with music-related trivia questions, and a social media bot that cross-posts Twitter updates to the Discord community and internal Slack. Furthermore, I implemented a staff analytics bot to track staff performance, encompassing commands used, messages sent, and modmail threads closed.
Through these tools and bots, I have greatly enhanced the efficiency and engagement within the Rythm server, fostering a vibrant and interactive community.`,
logo: "rythm.jpeg"
},
{
title: "Community Manager and Infrastructure Engineer",
company: "Streamcord",
start: new Date("August 5 2021"),
end: null,
link: "https://streamcord.io",
type: "fixed",
logo: "streamcord.jpeg",
description: `In my role as Community Manager and Infrastructure Engineer at Streamcord, I managed a vibrant community of approximately 50,000 members. I provided support for the Streamcord bot, which is actively used in over 1 million communities, ensuring its seamless operation and addressing user queries. My initiatives included running staff streams and game nights to foster interaction and strengthen the bond between the community and the team. I played a key role in overhauling the community to boost retention and activity, and supported the development process, contributing to the maintenance of the documentation and dashboard site. Additionally, I took charge of interviewing and onboarding new staff, providing comprehensive training and conducting quarterly staff evaluations to ensure a skilled and cohesive team. My work has greatly contributed to the thriving and dynamic environment within the Streamcord community.`
},
{
title: "Community Moderator",
company: "Battlesnake",
start: new Date("June 5 2021"),
end: new Date("November 5 2022"),
link: "https://play.battlesnake.com",
type: "volunteer",
logo: "battlesnake.jpeg",
description: `As a Community Moderator at Battlesnake, I played a vital role in ensuring a safe and welcoming environment for players. My focus was on promoting a positive experience for all members, allowing them to enjoy the game and interact with one another respectfully.
Additionally, I contributed to driving engagement for the Summer League 2021 and the Caster House system, fostering enthusiasm and participation in these events. My efforts helped create an inclusive and vibrant community for Battlesnake enthusiasts.`
},
{
title: "Discord Administrator and Platform Engineering Manager",
company: "Caylus Crew",
start: new Date("June 5 2021"),
end: null,
link: "https://discord.gg/infinite",
type: "volunteer",
description: `As the Discord Administrator and Platform Engineering Manager at Caylus Crew, I developed custom bots that enhanced the community experience and streamlined operations. One such bot posted daily messages wishing happy birthday to members, fostering a sense of connection and camaraderie. I also created a bot to manage sponsor perks, ensuring efficient and accurate distribution of benefits to eligible members.
In addition to technical contributions, I coached and trained moderators, providing quarterly staff reviews to support their professional growth and improve their performance. My work played a pivotal role in maintaining a vibrant, well-managed community and ensuring an exceptional experience for all participants.`
},
{
title: "Integrations Engineer",
company: "Xcentric Collective",
start: new Date("April 5 2021"),
end: new Date("July 5 2023"),
link: "http://discord.gg/U3jQVYNbJt",
type: "volunteer",
description: `As an Integrations Engineer at Xcentric Collective, I developed a custom Discord bot that incorporated a unique Matchmaking Rating (MMR) system to calculate Rocket League proficiency. This system enabled users to track and monitor their skill levels accurately.
The bot also featured the ability to define teams and find matches with opponents of similar skill levels, facilitating balanced and fair gameplay. Additionally, the bot allowed users to schedule matches seamlessly, providing a streamlined and efficient experience for the community. My work enhanced the overall gaming experience and engagement within the Xcentric Collective community.As an Integrations Engineer at Xcentric Collective, I developed a custom Discord bot that incorporated a unique Matchmaking Rating (MMR) system to calculate Rocket League proficiency. This system enabled users to track and monitor their skill levels accurately. The bot also featured the ability to define teams and find matches with opponents of similar skill levels, facilitating balanced and fair gameplay. Additionally, the bot allowed users to schedule matches seamlessly, providing a streamlined and efficient experience for the community. My work enhanced the overall gaming experience and engagement within the Xcentric Collective community.`
},
{
title: "Hacktoberfest Community Moderator",
company: "DigitalOcean",
start: new Date("April 5 2021"),
end: null,
link: "https://hacktoberfest.com",
type: "volunteer",
logo: "digitalocean.jpeg",
description: `As a Hacktoberfest Community Moderator at DigitalOcean, I supported the community by building a custom bot to ensure repository links were correctly included in promotional channel messages, streamlining interactions and providing automated responses for frequently asked questions. This contributed to a smoother experience for participants and enhanced community engagement.
In addition to managing the bot, I answered queries and guided developers in their open source contributions, helping them navigate the Hacktoberfest event and maximize their impact. By maintaining a safe and welcoming community space, I fostered an inclusive environment for developers of all skill levels to collaborate and grow. My efforts played a crucial role in the success of the event and the satisfaction of its participants.`
},
{
title: "Discord Administrator",
company: "EddieHub",
start: new Date("January 5 2021"),
end: new Date("May 5 2023"),
link: "https://www.eddiehub.org",
type: "volunteer",
logo: "eddiehub.jpeg",
description: `As a Discord Administrator for EddieHub, I played a key role in moderating the community and fostering an open and inclusive environment. My focus was on upholding community guidelines and ensuring a positive experience for all members.
I provided support and encouragement to members on their development path, offering guidance and resources to help them grow and succeed. Additionally, I planned and managed community events and initiatives, creating opportunities for members to engage, learn, and collaborate.
My efforts contributed to the vibrancy and success of the EddieHub community, helping to create a welcoming space for developers to thrive.`
},
{
title: "Discord Administrator and Lead Integrations Engineer",
company: "Commit Your Code",
start: new Date("December 5 2020"),
end: null,
link: "https://discord.gg/StwJYeq",
type: "volunteer",
logo: "cyc.jpeg",
description: `As the Discord Administrator and Lead Integrations Engineer at Commit Your Code, I played a key role in fostering a supportive and friendly community environment by moderating interactions and ensuring a positive space for members. I provided guidance to individuals on their development path, offering support as they prepared for their first job or encountered coding challenges.
To enhance community security, I built a robust verification system that significantly reduced the number of compromised accounts, safeguarding members' data and promoting a safe space for collaboration. My contributions have been instrumental in supporting members' growth and maintaining a secure, welcoming atmosphere within the community.`
},
{
title: "Educational Developer and Community Manager",
company: "freeCodeCamp",
start: new Date("December 5, 2020"),
end: null,
link: "https://freecodecamp.org",
type: "fixed",
logo: "fcc.jpeg",
description: `As an Educational Developer and Community Manager at freeCodeCamp, I have played a pivotal role in maintaining and enhancing the platform's open-source curriculum, serving millions of developers globally. I assisted in completely redesigning the Responsive Web Design curriculum to create a more accessible and engaging learning experience. Additionally, I built a moderation bot to improve the safety and functionality of the Discord community and developed a tool to efficiently distribute a weekly email newsletter to millions of subscribers. My work also involves supporting and guiding users on their journey to become web developers while managing the Discord, Forum, and Reddit communities to drive engagement and deliver an exceptional user experience. Through these contributions, I have significantly impacted the growth and success of the freeCodeCamp community, empowering individuals worldwide to achieve their web development goals.As an Educational Developer and Community Manager at freeCodeCamp, I have played a pivotal role in maintaining and enhancing the platform's open-source curriculum, serving millions of developers globally. I assisted in completely redesigning the Responsive Web Design curriculum to create a more accessible and engaging learning experience. Additionally, I built a moderation bot to improve the safety and functionality of the Discord community and developed a tool to efficiently distribute a weekly email newsletter to millions of subscribers. My work also involves supporting and guiding users on their journey to become web developers while managing the Discord, Forum, and Reddit communities to drive engagement and deliver an exceptional user experience. Through these contributions, I have significantly impacted the growth and success of the freeCodeCamp community, empowering individuals worldwide to achieve their web development goals.`
},
{
title: "Discord Moderator",
company: "Virtual Insanity",
start: new Date("May 5 2024"),
end: null,
link: "https://discord.com/invite/GDYNGnrGUs",
type: "volunteer",
description: `As a Discord Moderator for Virtual Insanity, an adult-only community, I was instrumental in cultivating a secure, respectful, and interactive atmosphere for our diverse members. My responsibilities encompassed vigilant monitoring of discussions, ensuring compliance with established guidelines to deter any disruptive conduct and safeguard our users. Alongside conflict resolution, I provided empathetic support and guidance, fostering a harmonious environment conducive to positive interactions. Moreover, I actively assisted in verifying identification documents, reinforcing our commitment to maintaining a safe and authentic community experience. Through these efforts, I contributed to upholding the community's integrity and nurturing an inclusive space for all participants to thrive.`
},
{
title: "Discord Administrator and Integrations Engineer",
company: "Azuliah (VTuber)",
start: new Date("December 5 2023"),
end: new Date("April 5 2024"),
link: "https://discord.com/invite/XNSy8PMvyy",
type: "volunteer",
description: `As a Discord Administrator and Integrations Engineer at Azuliah, I established custom integrations to streamline moderation efforts and enhance community management. These integrations supported the moderation team in maintaining a safe and welcoming space for all members.
In addition to technical contributions, I trained the owner and moderation team on best practices for running a successful community. My guidance included techniques for efficient moderation, conflict resolution, and fostering positive interactions among members. Through my efforts, I played a key role in ensuring the community's smooth operation and promoting a vibrant, supportive environment.`
},
{
title: "Discord Moderator",
company: "Rion Kuroko (VTuber)",
start: new Date("Nov 5 2023"),
end: new Date("Jan 5 2024"),
link: "https://discord.com",
type: "volunteer",
description: `As a Discord Moderator for Rion Kuroko, I constructed the server almost entirely from scratch to tailor it to the specific needs of the community. This involved designing and implementing structures, channels, and rules that supported a smooth and organized environment.
I also provided guidance to the owner on the technical aspects of Discord moderation, sharing best practices and offering solutions to effectively manage the server. My efforts played a key role in establishing a functional, user-friendly community space and empowering the owner with the knowledge needed to maintain and grow the server.`
},
{
title: "Senior Discord Moderator",
company: "Rythm",
start: new Date("Feb 5 2022"),
end: new Date("July 5 2022"),
link: "https://discord.com/invite/rythm",
type: "volunteer",
logo: "rythm.jpeg",
description: `As a Senior Discord Moderator for Rythm, I played a dual role in overseeing community moderation and mentoring the moderation team. My responsibilities included tracking weekly staff activity to monitor performance and identify areas for improvement, ensuring the team remained effective and engaged.
Additionally, I guided and supported moderators, helping them develop their skills and excel in their roles. By identifying opportunities to enhance staff activity, I contributed to the overall health and vibrancy of the community. My efforts were instrumental in maintaining a positive, safe, and well-managed space for all members.`
},
{
title: "Technical Support Staff",
company: "TweetShift",
start: new Date("Oct 5 2021"),
end: new Date("Jan 5 2022"),
link: "https://discord.com/invite/zdfQhjc",
type: "volunteer",
description: `As Technical Support Staff for TweetShift, I responded promptly to user queries, addressing issues and bugs within the bot to ensure a smooth user experience. I provided clear guidance on how to use the bot's features effectively, helping users maximize its capabilities.
My role involved troubleshooting technical challenges and offering solutions to enhance user satisfaction. By delivering efficient support and sharing helpful tips, I contributed to the overall success and reliability of the bot for the TweetShift community.`
},
{
title: "Discord Moderator",
company: "Rythm",
start: new Date("Sept 5 2021"),
end: new Date("Feb 5 2022"),
link: "https://discord.com/invite/rythm",
type: "volunteer",
description: `As a Discord Moderator for Rythm, I played a central role in maintaining a safe, respectful, and welcoming environment for community members. I monitored conversations to ensure compliance with community guidelines and addressed any disruptive behavior promptly.
My efforts helped foster a positive and inclusive space for all members, contributing to the overall health and vibrancy of the Rythm community.`
},
{
title: "Technical Support Staff",
company: "Streamcord",
start: new Date("Mar 5 2021"),
end: new Date("Aug 5 2021"),
link: "https://discord.com/invite/streamcord",
type: "volunteer",
logo: "streamcord.jpeg",
description: `As Technical Support Staff for Streamcord, I provided essential support to users by triaging and debugging issues related to the Streamcord Discord bot. My role involved investigating and resolving technical challenges to ensure a seamless user experience.
Acting as a liaison between users and developers, I facilitated clear communication and reported user feedback to the development team for continuous improvement. Additionally, I moderated and engaged with the community, fostering a positive and inclusive environment for all participants. My efforts contributed to the overall success and satisfaction of the Streamcord community.`
},
{
title: "Community Moderator",
company: "freeCodeCamp",
start: new Date("Jun 5 2020"),
end: new Date("Dec 5 2020"),
link: "https://discord.com/invite/freecodecamp-org-official-fi-fo-692816967895220344",
type: "volunteer",
logo: "fcc.jpeg",
description: `As a Community Moderator for freeCodeCamp, I provided vital support to users (campers) as they navigated the freeCodeCamp curriculum. My role included assisting users in debugging their code and answering questions, ensuring they received the guidance they needed to progress in their learning journey.
I engaged with and moderated the community on the forum and Discord server, fostering a positive, supportive, and inclusive environment for all members. Additionally, I assisted with issue triage and pull request review on GitHub, contributing to the ongoing improvement and development of freeCodeCamp's open-source projects. My efforts played a key role in maintaining the quality of the community and empowering users to achieve their learning goals.`
}
];

904
src/app/config/Icons.ts Normal file
View File

@ -0,0 +1,904 @@
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { faCalendar, faCircle } from "@fortawesome/free-regular-svg-icons";
import { faListCheck } from "@fortawesome/free-solid-svg-icons";
import { Employment } from "./Employment";
export const Codeberg: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
474,
474,
[],
"U+E002",
`M 36.00,373.00
C 19.99,344.87 11.56,324.72 5.00,293.00
5.00,293.00 2.08,280.00 2.08,280.00
2.08,280.00 2.08,271.04 2.08,271.04
1.21,265.55 0.02,268.68 0.00,259.00
0.00,259.00 0.00,232.00 0.00,232.00
0.10,225.30 1.32,226.49 2.08,221.96
2.08,221.96 2.08,214.00 2.08,214.00
2.08,214.00 4.55,203.00 4.55,203.00
8.89,181.33 13.79,163.93 23.75,144.00
23.75,144.00 31.87,128.00 31.87,128.00
40.56,112.80 56.86,91.48 69.17,79.17
69.17,79.17 80.00,69.72 80.00,69.72
90.99,60.09 102.48,51.08 115.00,43.46
115.00,43.46 132.00,34.75 132.00,34.75
194.09,3.71 265.92,2.29 330.00,28.45
346.58,35.22 368.94,48.49 383.00,59.51
383.00,59.51 397.00,71.72 397.00,71.72
418.24,90.34 435.64,113.79 448.25,139.00
460.07,162.66 464.56,176.20 469.80,202.00
471.25,209.15 473.99,218.02 474.00,225.00
474.00,225.00 474.00,270.00 474.00,270.00
474.00,270.00 469.42,294.00 469.42,294.00
469.42,294.00 465.25,313.00 465.25,313.00
465.25,313.00 454.33,343.00 454.33,343.00
454.33,343.00 439.00,373.00 439.00,373.00
439.00,373.00 437.00,373.00 437.00,373.00
437.00,373.00 386.42,307.00 386.42,307.00
386.42,307.00 285.87,177.00 285.87,177.00
285.87,177.00 250.35,131.00 250.35,131.00
247.89,127.81 240.50,116.27 236.17,117.49
234.17,118.05 231.85,121.40 230.58,123.00
230.58,123.00 221.13,135.00 221.13,135.00
221.13,135.00 183.35,184.00 183.35,184.00
183.35,184.00 88.88,306.00 88.88,306.00
88.88,306.00 55.65,349.00 55.65,349.00
50.94,355.09 41.27,368.61 36.00,373.00 Z
M 244.00,138.00
C 244.00,138.00 272.65,174.00 272.65,174.00
272.65,174.00 327.65,245.00 327.65,245.00
327.65,245.00 401.88,341.00 401.88,341.00
401.88,341.00 433.00,382.00 433.00,382.00
433.00,382.00 409.96,410.00 409.96,410.00
409.96,410.00 400.00,419.17 400.00,419.17
400.00,419.17 389.00,429.68 389.00,429.68
389.00,429.68 361.00,449.54 361.00,449.54
361.00,449.54 346.00,457.31 346.00,457.31
346.00,457.31 331.00,465.00 331.00,465.00
331.00,465.00 315.85,409.00 315.85,409.00
315.85,409.00 283.85,289.00 283.85,289.00
283.85,289.00 257.12,189.00 257.12,189.00
257.12,189.00 244.00,138.00 244.00,138.00 Z`
]
} as never;
export const Matrix: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
342,
342,
[],
"U+E002",
`M 138.00,0.53
C 150.87,-1.59 166.46,0.98 179.00,4.13
230.88,17.15 270.41,61.51 279.08,114.00
279.08,114.00 281.00,131.00 281.00,131.00
281.08,137.92 281.47,143.03 277.20,148.99
268.97,160.46 252.22,161.04 243.39,149.98
237.90,143.12 239.56,138.59 238.83,131.00
238.25,124.97 237.10,118.87 235.63,113.00
230.45,92.32 217.03,73.13 200.00,60.48
188.68,52.07 173.95,45.62 160.00,43.28
149.18,41.47 136.43,43.78 128.21,34.91
117.46,23.31 123.25,5.13 138.00,0.53 Z
M 126.00,61.42
C 132.79,60.60 140.80,60.41 147.00,63.67
157.30,69.10 161.07,83.05 155.00,93.00
148.91,102.97 142.67,102.25 133.00,103.17
133.00,103.17 121.00,104.75 121.00,104.75
106.64,107.11 91.56,113.68 80.00,122.50
61.64,136.52 50.33,153.71 44.63,176.00
43.46,180.57 42.62,185.30 42.17,190.00
41.42,197.85 43.18,203.96 37.61,210.99
28.88,221.99 10.70,222.28 2.99,210.00
-0.87,203.84 -0.08,195.99 0.00,189.00
0.10,181.05 1.94,171.72 3.87,164.00
14.25,122.51 43.23,89.80 82.00,72.31
97.65,65.25 109.47,63.78 126.00,61.42 Z
M 315.00,123.64
C 330.97,120.43 341.97,128.41 342.00,145.00
342.03,164.57 338.91,182.06 330.69,200.00
308.91,247.57 260.01,281.64 207.00,281.00
183.02,280.71 177.62,255.16 192.04,243.39
198.72,237.94 203.50,239.55 211.00,238.83
217.03,238.25 223.12,237.09 229.00,235.63
249.81,230.42 269.96,216.52 282.28,199.00
290.55,187.24 296.09,175.19 298.74,161.00
301.56,145.87 296.54,130.60 315.00,123.64 Z
M 78.00,184.53
C 87.56,183.00 96.80,186.96 101.08,196.00
101.08,196.00 105.45,225.00 105.45,225.00
108.31,239.01 115.29,252.68 123.90,264.00
136.86,281.04 157.21,293.39 178.00,298.11
188.70,300.54 202.89,298.40 210.98,304.56
222.59,313.38 221.84,332.30 209.00,339.64
203.20,342.95 194.60,342.07 188.00,342.00
180.39,341.91 168.41,339.51 161.00,337.42
119.62,325.74 86.75,295.86 70.60,256.00
70.60,256.00 66.29,243.00 66.29,243.00
63.87,234.58 62.76,227.67 61.84,219.00
60.14,203.20 59.71,189.94 78.00,184.53 Z`
]
} as never;
export const Peerlist: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
512,
512,
[],
"U+E002",
`M 214.00,0.14
C 214.00,0.14 243.00,0.14 243.00,0.14
243.00,0.14 291.00,0.14 291.00,0.14
291.00,0.14 301.00,1.00 301.00,1.00
301.00,1.00 311.00,1.00 311.00,1.00
311.00,1.00 328.00,2.83 328.00,2.83
375.51,7.58 421.85,17.89 457.91,51.42
483.50,75.23 497.13,112.43 503.80,146.00
507.93,166.77 510.12,187.89 511.04,209.00
511.04,209.00 512.00,220.00 512.00,220.00
512.59,270.71 513.41,322.24 502.42,372.00
495.29,404.31 483.17,434.75 459.72,458.83
437.47,481.67 407.37,493.82 377.00,501.37
326.73,513.88 274.38,512.08 223.00,512.00
223.00,512.00 208.00,511.00 208.00,511.00
208.00,511.00 204.00,511.00 204.00,511.00
204.00,511.00 166.00,507.13 166.00,507.13
125.75,501.54 81.42,488.74 52.28,458.83
18.32,423.96 7.84,375.75 2.84,329.00
2.84,329.00 0.91,302.00 0.91,302.00
0.91,302.00 0.00,290.00 0.00,290.00
0.00,290.00 0.00,253.00 0.00,253.00
0.00,253.00 0.00,223.00 0.00,223.00
0.00,223.00 1.00,205.00 1.00,205.00
1.00,205.00 6.59,155.00 6.59,155.00
11.95,123.04 22.32,89.63 42.81,64.00
74.31,24.60 121.91,10.61 170.00,4.28
170.00,4.28 201.00,1.09 201.00,1.09
201.00,1.09 214.00,0.14 214.00,0.14 Z
M 234.00,18.14
C 227.52,19.22 223.42,18.99 217.00,19.00
217.00,19.00 205.00,20.04 205.00,20.04
205.00,20.04 197.00,20.04 197.00,20.04
149.57,24.69 92.98,33.42 60.44,72.00
34.70,102.51 25.98,143.28 21.84,182.00
21.84,182.00 19.00,224.00 19.00,224.00
19.00,224.00 18.00,241.00 18.00,241.00
18.00,241.00 18.00,273.00 18.00,273.00
18.00,273.00 18.96,283.00 18.96,283.00
18.96,283.00 18.96,297.00 18.96,297.00
18.96,297.00 19.91,307.00 19.91,307.00
19.91,307.00 24.92,353.00 24.92,353.00
30.18,384.75 40.74,418.98 63.09,443.00
93.04,475.19 139.93,485.66 182.00,490.16
182.00,490.16 205.00,492.09 205.00,492.09
205.00,492.09 215.00,493.04 215.00,493.04
215.00,493.04 229.00,493.04 229.00,493.04
229.00,493.04 241.00,494.00 241.00,494.00
241.00,494.00 271.00,494.00 271.00,494.00
271.00,494.00 283.00,493.04 283.00,493.04
283.00,493.04 295.00,493.04 295.00,493.04
295.00,493.04 307.00,492.09 307.00,492.09
327.86,490.66 348.55,488.59 369.00,483.88
398.65,477.06 426.42,466.49 447.96,444.00
469.93,421.06 480.00,389.49 486.00,359.00
490.02,338.59 492.97,308.77 493.00,288.00
493.00,288.00 494.00,271.00 494.00,271.00
494.00,271.00 494.00,241.00 494.00,241.00
494.00,241.00 493.04,229.00 493.04,229.00
493.04,229.00 493.04,217.00 493.04,217.00
493.04,217.00 492.09,205.00 492.09,205.00
490.82,186.52 489.06,168.22 485.40,150.00
478.89,117.63 467.20,84.85 442.00,62.17
412.18,35.33 368.80,25.99 330.00,21.84
330.00,21.84 307.00,19.91 307.00,19.91
307.00,19.91 295.00,18.96 295.00,18.96
295.00,18.96 283.00,18.96 283.00,18.96
283.00,18.96 271.00,18.14 271.00,18.14
271.00,18.14 234.00,18.14 234.00,18.14 Z
M 156.00,101.00
C 156.00,101.00 231.00,101.00 231.00,101.00
231.00,101.00 270.00,101.00 270.00,101.00
304.65,101.05 338.60,117.93 361.91,143.00
370.38,152.10 378.11,164.62 383.14,176.00
398.86,211.57 395.05,254.17 374.58,287.00
365.39,301.73 358.75,306.40 347.28,318.17
331.52,334.35 322.21,343.76 301.00,353.14
279.20,362.77 264.27,364.00 241.00,364.00
241.00,364.00 241.00,411.00 241.00,411.00
241.00,411.00 223.00,411.00 223.00,411.00
223.00,411.00 223.00,429.00 223.00,429.00
223.00,429.00 138.00,429.00 138.00,429.00
138.00,429.00 138.00,119.00 138.00,119.00
138.00,119.00 156.00,119.00 156.00,119.00
156.00,119.00 156.00,101.00 156.00,101.00 Z
M 223.00,329.00
C 263.91,329.00 301.86,332.36 336.00,304.54
349.16,293.81 359.70,280.51 366.69,265.00
374.05,248.67 375.20,234.53 375.00,217.00
374.56,179.46 346.33,143.35 313.00,128.31
291.09,118.42 270.44,118.00 247.00,118.00
247.00,118.00 207.00,118.00 207.00,118.00
207.00,118.00 182.00,118.00 182.00,118.00
180.01,118.00 176.19,117.77 174.60,119.02
172.62,120.59 173.00,124.70 173.00,127.00
173.00,127.00 173.00,332.00 173.00,332.00
173.00,332.00 173.00,385.00 173.00,385.00
173.02,393.64 173.36,393.98 182.00,394.00
182.00,394.00 223.00,394.00 223.00,394.00
223.00,394.00 223.00,329.00 223.00,329.00 Z
M 223.00,166.00
C 223.00,166.00 266.00,166.00 266.00,166.00
306.49,166.06 336.49,205.40 321.39,244.00
319.11,249.82 315.95,255.30 311.82,260.00
300.28,273.13 284.59,280.92 267.00,281.00
267.00,281.00 253.00,281.00 253.00,281.00
253.00,281.00 223.00,281.00 223.00,281.00
223.00,281.00 223.00,166.00 223.00,166.00 Z
M 241.00,202.00
C 241.00,202.00 241.00,255.00 241.00,255.00
241.02,263.64 241.36,263.98 250.00,264.00
258.53,264.02 277.96,264.47 284.58,259.01
289.25,255.16 289.06,244.57 289.00,239.00
288.79,221.67 275.23,207.53 259.00,203.16
253.08,201.56 247.07,202.00 241.00,202.00 Z`
]
} as never;
export const Polywork: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
225, // SVG view box width
225, // SVG view box height
[],
"U+E002", // probably not important for SVG and JS approach
`M 153.00,155.00
C 153.00,177.49 155.16,201.18 134.00,215.78
117.90,226.88 101.50,224.00 83.00,224.00
83.00,224.00 57.00,224.00 57.00,224.00
36.75,224.00 21.13,223.75 8.22,205.00
5.78,201.46 3.67,197.12 2.44,193.00
0.64,186.98 0.01,182.25 0.00,176.00
0.00,176.00 0.00,49.00 0.00,49.00
0.05,19.44 19.43,0.05 49.00,0.00
49.00,0.00 176.00,0.00 176.00,0.00
203.99,0.04 223.96,18.67 224.00,47.00
224.00,47.00 224.00,89.00 224.00,89.00
224.00,112.86 226.74,132.44 204.00,147.95
200.27,150.49 196.33,152.29 192.00,153.56
182.70,156.30 170.69,156.05 161.00,156.00
157.55,155.98 156.36,155.95 153.00,155.00 Z
M 70.00,11.00
C 52.54,11.00 34.21,8.10 21.09,22.01
17.77,25.54 15.22,29.35 13.77,34.00
11.01,42.87 12.00,61.03 12.00,71.00
12.00,71.00 70.00,71.00 70.00,71.00
70.00,71.00 70.00,11.00 70.00,11.00 Z
M 141.00,71.00
C 141.00,71.00 141.00,19.00 141.00,19.00
140.94,10.87 139.73,11.02 132.00,11.00
132.00,11.00 82.94,11.00 82.94,11.00
82.94,11.00 82.94,65.00 82.94,65.00
82.65,71.56 84.51,70.99 91.00,71.00
91.00,71.00 141.00,71.00 141.00,71.00 Z
M 212.00,71.00
C 212.00,71.00 212.00,46.00 212.00,46.00
211.99,40.91 212.06,38.94 210.30,34.00
200.99,7.84 175.95,12.00 154.00,12.00
154.00,12.00 154.00,71.00 154.00,71.00
154.00,71.00 212.00,71.00 212.00,71.00 Z
M 70.00,84.00
C 70.00,84.00 11.00,84.00 11.00,84.00
11.00,84.00 11.00,136.00 11.00,136.00
11.02,144.64 11.36,144.98 20.00,145.00
20.00,145.00 70.00,145.00 70.00,145.00
70.00,145.00 70.00,84.00 70.00,84.00 Z
M 141.00,84.00
C 141.00,84.00 83.00,84.00 83.00,84.00
83.00,84.00 83.00,144.00 83.00,144.00
83.00,144.00 141.00,144.00 141.00,144.00
141.00,144.00 141.00,84.00 141.00,84.00 Z
M 212.00,84.00
C 212.00,84.00 154.00,84.00 154.00,84.00
154.00,84.00 154.00,145.00 154.00,145.00
176.30,145.00 201.22,148.17 210.45,122.00
212.02,117.55 211.99,114.59 212.00,110.00
212.00,110.00 212.00,84.00 212.00,84.00 Z
M 70.00,157.00
C 70.00,157.00 11.00,157.00 11.00,157.00
11.00,177.94 8.44,201.56 33.00,210.30
37.94,212.06 39.91,211.99 45.00,212.00
45.00,212.00 70.00,212.00 70.00,212.00
70.00,212.00 70.00,157.00 70.00,157.00 Z
M 141.00,158.00
C 141.00,158.00 83.00,158.00 83.00,158.00
83.00,158.00 83.00,213.00 83.00,213.00
83.00,213.00 106.00,213.00 106.00,213.00
110.59,212.99 113.55,213.02 118.00,211.45
143.85,202.34 141.00,180.01 141.00,158.00 Z`
]
} as never;
export const JobTypes: {
[key in (typeof Employment)[number]["type"]]: IconDefinition;
} = {
hypothetical: faCircle,
volunteer: {
prefix: "xxx",
iconName: "yyy",
icon: [
1024,
1024,
[],
"U+E002",
`M 400.00,894.00
C 393.17,894.89 374.14,887.23 367.00,884.40
337.83,872.82 313.05,859.89 287.00,842.33
201.70,784.84 140.73,692.77 120.45,592.00
113.21,556.04 112.58,528.31 113.00,492.00
113.00,492.00 113.91,482.00 113.91,482.00
115.58,457.77 119.57,434.55 125.53,411.00
154.89,294.99 237.46,198.14 346.00,148.31
385.38,130.22 427.96,119.14 471.00,114.83
471.00,114.83 494.00,113.00 494.00,113.00
494.00,113.00 532.00,113.00 532.00,113.00
532.00,113.00 542.00,113.91 542.00,113.91
568.64,115.77 592.21,119.87 618.00,126.85
758.81,164.98 868.19,278.92 900.88,421.00
905.70,441.95 908.62,462.59 910.09,484.00
910.09,484.00 911.00,494.00 911.00,494.00
911.39,527.33 910.55,552.96 904.58,586.00
891.40,658.90 857.93,723.53 809.28,779.00
792.87,797.72 774.49,813.80 755.00,829.20
749.42,833.60 737.84,843.77 731.00,844.00
728.01,849.34 721.15,852.51 716.00,855.60
703.56,863.07 691.17,869.28 678.00,875.31
641.79,891.89 597.75,905.01 558.00,908.83
558.00,908.83 528.00,911.00 528.00,911.00
528.00,911.00 496.00,911.00 496.00,911.00
496.00,911.00 484.00,910.09 484.00,910.09
463.73,908.70 443.86,906.17 424.00,901.65
418.56,900.41 403.20,897.89 400.00,894.00 Z
M 745.00,714.00
C 745.00,714.00 757.63,698.00 757.63,698.00
766.05,686.76 775.00,673.35 781.69,661.00
809.23,610.20 820.67,559.53 820.00,502.00
820.00,502.00 819.09,492.00 819.09,492.00
818.06,477.07 816.33,462.67 813.21,448.00
787.94,329.09 694.66,234.49 575.00,210.55
560.13,207.58 547.09,205.95 532.00,204.91
532.00,204.91 522.00,204.00 522.00,204.00
469.75,203.39 418.76,213.14 372.00,237.26
358.36,244.29 341.24,254.73 329.00,263.89
329.00,263.89 310.00,279.00 310.00,279.00
312.13,285.23 315.03,286.64 319.42,291.16
319.42,291.16 341.72,313.42 341.72,313.42
341.72,313.42 412.84,384.58 412.84,384.58
412.84,384.58 435.00,406.84 435.00,406.84
437.17,408.96 442.60,414.77 445.00,415.72
449.00,417.29 452.75,413.42 456.00,411.46
461.69,408.04 463.60,408.01 470.00,408.00
470.00,408.00 553.00,408.00 553.00,408.00
555.59,408.00 558.53,407.87 561.00,408.70
565.25,410.11 577.20,418.95 581.00,422.08
596.88,435.17 612.92,450.77 625.58,467.00
649.77,498.03 667.75,532.22 675.55,571.00
677.70,581.69 679.02,596.10 679.00,607.00
678.99,613.69 677.78,624.35 676.58,631.00
676.05,633.92 673.99,641.67 674.40,644.00
675.17,648.33 687.28,659.10 691.07,662.84
691.07,662.84 726.72,698.28 726.72,698.28
731.59,703.16 738.54,711.74 745.00,714.00 Z
M 445.00,286.00
C 452.54,286.80 458.72,292.04 465.00,295.95
468.14,297.91 472.13,300.69 476.00,300.09
479.96,299.48 483.28,295.70 486.00,293.00
491.51,287.52 501.52,275.82 509.00,274.34
524.32,271.30 531.95,290.81 547.00,289.91
547.00,289.91 571.00,284.22 571.00,284.22
573.70,283.72 578.07,283.00 579.36,286.28
580.36,288.83 578.56,291.88 577.30,294.00
577.30,294.00 568.86,308.00 568.86,308.00
561.04,322.01 546.53,350.92 543.00,366.00
543.00,366.00 488.00,366.00 488.00,366.00
485.90,366.00 482.39,366.25 480.65,365.01
478.31,363.34 474.32,352.20 472.99,349.00
472.99,349.00 454.75,310.00 454.75,310.00
450.91,302.31 445.42,294.64 445.00,286.00 Z
M 416.00,444.00
C 416.00,444.00 381.92,410.07 381.92,410.07
381.92,410.07 314.17,342.58 314.17,342.58
314.17,342.58 290.00,318.00 290.00,318.00
287.86,315.87 283.32,310.70 280.09,311.03
277.98,311.24 276.27,313.52 275.00,315.02
275.00,315.02 265.42,327.00 265.42,327.00
252.81,343.25 241.25,363.31 232.69,382.00
193.14,468.36 194.64,564.63 236.26,650.00
243.09,664.02 251.58,677.29 260.58,690.00
300.75,746.77 357.46,787.24 424.00,807.28
455.72,816.83 488.99,820.38 522.00,820.00
522.00,820.00 532.00,819.09 532.00,819.09
547.91,818.00 563.40,816.04 579.00,812.58
585.72,811.08 602.88,805.91 608.00,806.00
608.00,806.00 622.00,799.80 622.00,799.80
622.00,799.80 649.00,787.89 649.00,787.89
649.00,787.89 686.00,766.28 686.00,766.28
686.00,766.28 714.00,745.00 714.00,745.00
711.59,737.94 702.66,731.07 697.28,725.72
697.28,725.72 669.92,698.07 669.92,698.07
665.14,693.37 658.44,687.61 655.00,682.00
649.32,683.67 638.29,694.47 632.00,698.64
620.59,706.22 604.21,712.80 591.00,716.57
578.14,720.24 549.20,724.94 536.00,725.00
536.00,725.00 517.00,726.00 517.00,726.00
517.00,726.00 487.00,725.00 487.00,725.00
487.00,725.00 461.00,722.27 461.00,722.27
418.48,716.14 374.27,698.72 355.31,657.00
347.38,639.54 344.97,619.97 345.00,601.00
345.06,560.19 364.22,515.43 386.51,482.00
391.39,474.68 397.42,466.67 403.13,460.00
407.31,455.12 413.08,449.45 416.00,444.00 Z
M 470.00,374.57
C 470.00,374.57 497.00,374.00 497.00,374.00
497.00,374.00 546.00,374.00 546.00,374.00
550.21,374.01 554.30,373.78 557.78,376.65
563.51,381.39 563.34,392.77 557.78,397.57
552.71,401.96 541.45,400.01 535.00,400.00
535.00,400.00 518.00,400.00 518.00,400.00
518.00,400.00 500.00,400.83 500.00,400.83
500.00,400.83 492.00,400.02 492.00,400.02
492.00,400.02 477.00,400.02 477.00,400.02
473.06,399.99 469.41,400.33 466.21,397.57
459.68,391.93 460.30,378.47 470.00,374.57 Z
M 459.00,429.00
C 459.00,429.00 458.00,429.00 458.00,429.00
458.00,429.00 459.00,430.00 459.00,430.00
459.00,430.00 459.00,429.00 459.00,429.00 Z
M 462.00,432.00
C 462.00,432.00 461.00,432.00 461.00,432.00
461.00,432.00 462.00,433.00 462.00,433.00
462.00,433.00 462.00,432.00 462.00,432.00 Z
M 464.00,434.00
C 464.00,434.00 463.00,434.00 463.00,434.00
463.00,434.00 464.00,435.00 464.00,435.00
464.00,435.00 464.00,434.00 464.00,434.00 Z
M 467.00,437.00
C 467.00,437.00 466.00,437.00 466.00,437.00
466.00,437.00 467.00,438.00 467.00,438.00
467.00,438.00 467.00,437.00 467.00,437.00 Z
M 470.00,440.00
C 470.00,440.00 469.00,440.00 469.00,440.00
469.00,440.00 470.00,441.00 470.00,441.00
470.00,441.00 470.00,440.00 470.00,440.00 Z
M 472.00,442.00
C 472.00,442.00 471.00,442.00 471.00,442.00
471.00,442.00 472.00,443.00 472.00,443.00
472.00,443.00 472.00,442.00 472.00,442.00 Z
M 475.00,445.00
C 475.00,445.00 474.00,445.00 474.00,445.00
474.00,445.00 475.00,446.00 475.00,446.00
475.00,446.00 475.00,445.00 475.00,445.00 Z
M 419.00,447.00
C 419.00,447.00 418.00,447.00 418.00,447.00
418.00,447.00 419.00,448.00 419.00,448.00
419.00,448.00 419.00,447.00 419.00,447.00 Z
M 478.00,448.00
C 478.00,448.00 477.00,448.00 477.00,448.00
477.00,448.00 478.00,449.00 478.00,449.00
478.00,449.00 478.00,448.00 478.00,448.00 Z
M 422.00,450.00
C 422.00,450.00 421.00,450.00 421.00,450.00
421.00,450.00 422.00,451.00 422.00,451.00
422.00,451.00 422.00,450.00 422.00,450.00 Z
M 480.00,450.00
C 480.00,450.00 479.00,450.00 479.00,450.00
479.00,450.00 480.00,451.00 480.00,451.00
480.00,451.00 480.00,450.00 480.00,450.00 Z
M 483.00,453.00
C 483.00,453.00 482.00,453.00 482.00,453.00
482.00,453.00 483.00,454.00 483.00,454.00
483.00,454.00 483.00,453.00 483.00,453.00 Z
M 427.00,455.00
C 427.00,455.00 426.00,455.00 426.00,455.00
426.00,455.00 427.00,456.00 427.00,456.00
427.00,456.00 427.00,455.00 427.00,455.00 Z
M 486.00,456.00
C 486.00,456.00 485.00,456.00 485.00,456.00
485.00,456.00 486.00,457.00 486.00,457.00
486.00,457.00 486.00,456.00 486.00,456.00 Z
M 430.00,458.00
C 430.00,458.00 429.00,458.00 429.00,458.00
429.00,458.00 430.00,459.00 430.00,459.00
430.00,459.00 430.00,458.00 430.00,458.00 Z
M 433.00,461.00
C 433.00,461.00 432.00,461.00 432.00,461.00
432.00,461.00 433.00,462.00 433.00,462.00
433.00,462.00 433.00,461.00 433.00,461.00 Z
M 491.00,461.00
C 491.00,461.00 490.00,461.00 490.00,461.00
490.00,461.00 491.00,462.00 491.00,462.00
491.00,462.00 491.00,461.00 491.00,461.00 Z
M 435.00,463.00
C 435.00,463.00 434.00,463.00 434.00,463.00
434.00,463.00 435.00,464.00 435.00,464.00
435.00,464.00 435.00,463.00 435.00,463.00 Z
M 567.00,520.00
C 566.65,504.24 556.88,488.77 543.00,481.32
535.67,477.39 528.16,476.54 526.10,475.49
520.81,472.81 524.40,467.66 521.98,464.60
519.97,462.05 505.67,463.00 502.00,463.00
502.00,463.00 502.85,473.00 502.85,473.00
502.85,473.00 518.00,489.96 518.00,489.96
518.00,489.96 551.00,523.00 551.00,523.00
551.00,523.00 567.00,520.00 567.00,520.00 Z
M 436.00,464.00
C 436.00,464.00 435.00,464.00 435.00,464.00
435.00,464.00 436.00,465.00 436.00,465.00
436.00,465.00 436.00,464.00 436.00,464.00 Z
M 494.00,464.00
C 494.00,464.00 493.00,464.00 493.00,464.00
493.00,464.00 494.00,465.00 494.00,465.00
494.00,465.00 494.00,464.00 494.00,464.00 Z
M 438.00,466.00
C 438.00,466.00 437.00,466.00 437.00,466.00
437.00,466.00 438.00,467.00 438.00,467.00
438.00,467.00 438.00,466.00 438.00,466.00 Z
M 496.00,466.00
C 496.00,466.00 495.00,466.00 495.00,466.00
495.00,466.00 496.00,467.00 496.00,467.00
496.00,467.00 496.00,466.00 496.00,466.00 Z
M 499.00,469.00
C 499.00,469.00 498.00,469.00 498.00,469.00
498.00,469.00 499.00,470.00 499.00,470.00
499.00,470.00 499.00,469.00 499.00,469.00 Z
M 443.00,471.00
C 443.00,471.00 442.00,471.00 442.00,471.00
442.00,471.00 443.00,472.00 443.00,472.00
443.00,472.00 443.00,471.00 443.00,471.00 Z
M 501.00,471.00
C 501.00,471.00 500.00,471.00 500.00,471.00
500.00,471.00 501.00,472.00 501.00,472.00
501.00,472.00 501.00,471.00 501.00,471.00 Z
M 446.00,474.00
C 446.00,474.00 445.00,474.00 445.00,474.00
445.00,474.00 446.00,475.00 446.00,475.00
446.00,475.00 446.00,474.00 446.00,474.00 Z
M 449.00,477.00
C 449.00,477.00 448.00,477.00 448.00,477.00
448.00,477.00 449.00,478.00 449.00,478.00
449.00,478.00 449.00,477.00 449.00,477.00 Z
M 451.00,479.00
C 451.00,479.00 450.00,479.00 450.00,479.00
450.00,479.00 451.00,480.00 451.00,480.00
451.00,480.00 451.00,479.00 451.00,479.00 Z
M 454.00,482.00
C 454.00,482.00 453.00,482.00 453.00,482.00
453.00,482.00 454.00,483.00 454.00,483.00
454.00,483.00 454.00,482.00 454.00,482.00 Z
M 459.00,487.00
C 459.00,487.00 458.00,487.00 458.00,487.00
458.00,487.00 459.00,488.00 459.00,488.00
459.00,488.00 459.00,487.00 459.00,487.00 Z
M 462.00,490.00
C 462.00,490.00 461.00,490.00 461.00,490.00
461.00,490.00 462.00,491.00 462.00,491.00
462.00,491.00 462.00,490.00 462.00,490.00 Z
M 466.00,494.00
C 466.00,494.00 465.00,494.00 465.00,494.00
465.00,494.00 466.00,495.00 466.00,495.00
466.00,495.00 466.00,494.00 466.00,494.00 Z
M 522.00,659.00
C 547.74,655.37 571.32,636.69 571.99,609.00
572.04,606.82 572.13,602.98 571.40,601.00
570.05,597.33 557.76,586.06 554.16,582.58
554.16,582.58 505.32,533.88 505.32,533.88
505.32,533.88 477.93,506.07 477.93,506.07
476.09,504.24 469.18,497.08 466.93,496.87
464.26,496.63 462.76,500.05 461.76,502.00
458.45,508.44 457.09,513.77 457.00,521.00
456.78,539.77 459.07,552.64 474.00,565.82
478.69,569.96 485.24,573.66 491.00,576.13
493.96,577.40 499.27,578.55 500.98,581.27
502.21,583.24 502.00,586.72 502.00,589.00
502.00,589.00 502.00,626.00 502.00,626.00
493.16,620.59 487.56,611.13 486.00,601.00
486.00,601.00 461.00,603.72 461.00,603.72
458.73,603.99 454.49,603.70 453.03,605.60
450.60,608.74 455.20,621.40 456.61,625.00
463.79,643.31 481.77,658.54 502.00,659.00
502.00,659.00 502.00,672.00 502.00,672.00
502.00,672.00 522.00,672.00 522.00,672.00
522.00,672.00 522.00,659.00 522.00,659.00 Z
M 558.00,528.00
C 558.00,528.00 557.00,528.00 557.00,528.00
557.00,528.00 558.00,529.00 558.00,529.00
558.00,529.00 558.00,528.00 558.00,528.00 Z
M 560.00,530.00
C 560.00,530.00 559.00,530.00 559.00,530.00
559.00,530.00 560.00,531.00 560.00,531.00
560.00,531.00 560.00,530.00 560.00,530.00 Z
M 563.00,533.00
C 563.00,533.00 562.00,533.00 562.00,533.00
562.00,533.00 563.00,534.00 563.00,534.00
563.00,534.00 563.00,533.00 563.00,533.00 Z
M 566.00,536.00
C 566.00,536.00 565.00,536.00 565.00,536.00
565.00,536.00 566.00,537.00 566.00,537.00
566.00,537.00 566.00,536.00 566.00,536.00 Z
M 571.00,541.00
C 571.00,541.00 570.00,541.00 570.00,541.00
570.00,541.00 571.00,542.00 571.00,542.00
571.00,542.00 571.00,541.00 571.00,541.00 Z
M 574.00,544.00
C 574.00,544.00 573.00,544.00 573.00,544.00
573.00,544.00 574.00,545.00 574.00,545.00
574.00,545.00 574.00,544.00 574.00,544.00 Z
M 576.00,546.00
C 576.00,546.00 575.00,546.00 575.00,546.00
575.00,546.00 576.00,547.00 576.00,547.00
576.00,547.00 576.00,546.00 576.00,546.00 Z
M 579.00,549.00
C 579.00,549.00 578.00,549.00 578.00,549.00
578.00,549.00 579.00,550.00 579.00,550.00
579.00,550.00 579.00,549.00 579.00,549.00 Z
M 582.00,552.00
C 582.00,552.00 581.00,552.00 581.00,552.00
581.00,552.00 582.00,553.00 582.00,553.00
582.00,553.00 582.00,552.00 582.00,552.00 Z
M 584.00,554.00
C 584.00,554.00 583.00,554.00 583.00,554.00
583.00,554.00 584.00,555.00 584.00,555.00
584.00,555.00 584.00,554.00 584.00,554.00 Z
M 587.00,557.00
C 587.00,557.00 586.00,557.00 586.00,557.00
586.00,557.00 587.00,558.00 587.00,558.00
587.00,558.00 587.00,557.00 587.00,557.00 Z
M 590.00,560.00
C 590.00,560.00 589.00,560.00 589.00,560.00
589.00,560.00 590.00,561.00 590.00,561.00
590.00,561.00 590.00,560.00 590.00,560.00 Z
M 592.00,562.00
C 592.00,562.00 591.00,562.00 591.00,562.00
591.00,562.00 592.00,563.00 592.00,563.00
592.00,563.00 592.00,562.00 592.00,562.00 Z
M 595.00,565.00
C 595.00,565.00 594.00,565.00 594.00,565.00
594.00,565.00 595.00,566.00 595.00,566.00
595.00,566.00 595.00,565.00 595.00,565.00 Z
M 598.00,568.00
C 598.00,568.00 597.00,568.00 597.00,568.00
597.00,568.00 598.00,569.00 598.00,569.00
598.00,569.00 598.00,568.00 598.00,568.00 Z
M 600.00,570.00
C 600.00,570.00 599.00,570.00 599.00,570.00
599.00,570.00 600.00,571.00 600.00,571.00
600.00,571.00 600.00,570.00 600.00,570.00 Z
M 603.00,573.00
C 603.00,573.00 602.00,573.00 602.00,573.00
602.00,573.00 603.00,574.00 603.00,574.00
603.00,574.00 603.00,573.00 603.00,573.00 Z
M 606.00,576.00
C 606.00,576.00 605.00,576.00 605.00,576.00
605.00,576.00 606.00,577.00 606.00,577.00
606.00,577.00 606.00,576.00 606.00,576.00 Z
M 608.00,578.00
C 608.00,578.00 607.00,578.00 607.00,578.00
607.00,578.00 608.00,579.00 608.00,579.00
608.00,579.00 608.00,578.00 608.00,578.00 Z
M 611.00,581.00
C 611.00,581.00 610.00,581.00 610.00,581.00
610.00,581.00 611.00,582.00 611.00,582.00
611.00,582.00 611.00,581.00 611.00,581.00 Z
M 614.00,584.00
C 614.00,584.00 613.00,584.00 613.00,584.00
613.00,584.00 614.00,585.00 614.00,585.00
614.00,585.00 614.00,584.00 614.00,584.00 Z
M 616.00,586.00
C 616.00,586.00 615.00,586.00 615.00,586.00
615.00,586.00 616.00,587.00 616.00,587.00
616.00,587.00 616.00,586.00 616.00,586.00 Z
M 619.00,589.00
C 619.00,589.00 618.00,589.00 618.00,589.00
618.00,589.00 619.00,590.00 619.00,590.00
619.00,590.00 619.00,589.00 619.00,589.00 Z
M 624.00,594.00
C 624.00,594.00 623.00,594.00 623.00,594.00
623.00,594.00 624.00,595.00 624.00,595.00
624.00,595.00 624.00,594.00 624.00,594.00 Z
M 627.00,597.00
C 627.00,597.00 626.00,597.00 626.00,597.00
626.00,597.00 627.00,598.00 627.00,598.00
627.00,598.00 627.00,597.00 627.00,597.00 Z
M 629.00,599.00
C 629.00,599.00 628.00,599.00 628.00,599.00
628.00,599.00 629.00,600.00 629.00,600.00
629.00,600.00 629.00,599.00 629.00,599.00 Z
M 630.00,600.00
C 630.00,600.00 629.00,600.00 629.00,600.00
629.00,600.00 630.00,601.00 630.00,601.00
630.00,601.00 630.00,600.00 630.00,600.00 Z
M 577.00,605.00
C 577.00,605.00 576.00,605.00 576.00,605.00
576.00,605.00 577.00,606.00 577.00,606.00
577.00,606.00 577.00,605.00 577.00,605.00 Z
M 635.00,605.00
C 635.00,605.00 634.00,605.00 634.00,605.00
634.00,605.00 635.00,606.00 635.00,606.00
635.00,606.00 635.00,605.00 635.00,605.00 Z
M 638.00,608.00
C 638.00,608.00 637.00,608.00 637.00,608.00
637.00,608.00 638.00,609.00 638.00,609.00
638.00,609.00 638.00,608.00 638.00,608.00 Z
M 639.00,609.00
C 639.00,609.00 638.00,609.00 638.00,609.00
638.00,609.00 639.00,610.00 639.00,610.00
639.00,610.00 639.00,609.00 639.00,609.00 Z
M 582.00,610.00
C 582.00,610.00 581.00,610.00 581.00,610.00
581.00,610.00 582.00,611.00 582.00,611.00
582.00,611.00 582.00,610.00 582.00,610.00 Z
M 640.00,610.00
C 640.00,610.00 639.00,610.00 639.00,610.00
639.00,610.00 640.00,611.00 640.00,611.00
640.00,611.00 640.00,610.00 640.00,610.00 Z
M 643.00,613.00
C 643.00,613.00 642.00,613.00 642.00,613.00
642.00,613.00 643.00,614.00 643.00,614.00
643.00,614.00 643.00,613.00 643.00,613.00 Z
M 587.00,615.00
C 587.00,615.00 586.00,615.00 586.00,615.00
586.00,615.00 587.00,616.00 587.00,616.00
587.00,616.00 587.00,615.00 587.00,615.00 Z
M 646.00,616.00
C 646.00,616.00 645.00,616.00 645.00,616.00
645.00,616.00 646.00,617.00 646.00,617.00
646.00,617.00 646.00,616.00 646.00,616.00 Z
M 590.00,618.00
C 590.00,618.00 589.00,618.00 589.00,618.00
589.00,618.00 590.00,619.00 590.00,619.00
590.00,619.00 590.00,618.00 590.00,618.00 Z
M 648.00,618.00
C 648.00,618.00 647.00,618.00 647.00,618.00
647.00,618.00 648.00,619.00 648.00,619.00
648.00,619.00 648.00,618.00 648.00,618.00 Z
M 593.00,621.00
C 593.00,621.00 592.00,621.00 592.00,621.00
592.00,621.00 593.00,622.00 593.00,622.00
593.00,622.00 593.00,621.00 593.00,621.00 Z
M 651.00,621.00
C 651.00,621.00 650.00,621.00 650.00,621.00
650.00,621.00 651.00,622.00 651.00,622.00
651.00,622.00 651.00,621.00 651.00,621.00 Z
M 595.00,623.00
C 595.00,623.00 594.00,623.00 594.00,623.00
594.00,623.00 595.00,624.00 595.00,624.00
595.00,624.00 595.00,623.00 595.00,623.00 Z
M 654.00,624.00
C 654.00,624.00 653.00,624.00 653.00,624.00
653.00,624.00 654.00,625.00 654.00,625.00
654.00,625.00 654.00,624.00 654.00,624.00 Z
M 598.00,626.00
C 598.00,626.00 597.00,626.00 597.00,626.00
597.00,626.00 598.00,627.00 598.00,627.00
598.00,627.00 598.00,626.00 598.00,626.00 Z
M 656.00,626.00
C 656.00,626.00 655.00,626.00 655.00,626.00
655.00,626.00 656.00,627.00 656.00,627.00
656.00,627.00 656.00,626.00 656.00,626.00 Z
M 601.00,629.00
C 601.00,629.00 600.00,629.00 600.00,629.00
600.00,629.00 601.00,630.00 601.00,630.00
601.00,630.00 601.00,629.00 601.00,629.00 Z
M 659.00,629.00
C 659.00,629.00 658.00,629.00 658.00,629.00
658.00,629.00 659.00,630.00 659.00,630.00
659.00,630.00 659.00,629.00 659.00,629.00 Z
M 603.00,631.00
C 603.00,631.00 602.00,631.00 602.00,631.00
602.00,631.00 603.00,632.00 603.00,632.00
603.00,632.00 603.00,631.00 603.00,631.00 Z
M 662.00,632.00
C 662.00,632.00 661.00,632.00 661.00,632.00
661.00,632.00 662.00,633.00 662.00,633.00
662.00,633.00 662.00,632.00 662.00,632.00 Z
M 606.00,634.00
C 606.00,634.00 605.00,634.00 605.00,634.00
605.00,634.00 606.00,635.00 606.00,635.00
606.00,635.00 606.00,634.00 606.00,634.00 Z
M 664.00,634.00
C 664.00,634.00 663.00,634.00 663.00,634.00
663.00,634.00 664.00,635.00 664.00,635.00
664.00,635.00 664.00,634.00 664.00,634.00 Z
M 609.00,637.00
C 609.00,637.00 608.00,637.00 608.00,637.00
608.00,637.00 609.00,638.00 609.00,638.00
609.00,638.00 609.00,637.00 609.00,637.00 Z
M 667.00,637.00
C 667.00,637.00 666.00,637.00 666.00,637.00
666.00,637.00 667.00,638.00 667.00,638.00
667.00,638.00 667.00,637.00 667.00,637.00 Z
M 611.00,639.00
C 611.00,639.00 610.00,639.00 610.00,639.00
610.00,639.00 611.00,640.00 611.00,640.00
611.00,640.00 611.00,639.00 611.00,639.00 Z
M 670.00,640.00
C 670.00,640.00 669.00,640.00 669.00,640.00
669.00,640.00 670.00,641.00 670.00,641.00
670.00,641.00 670.00,640.00 670.00,640.00 Z
M 614.00,642.00
C 614.00,642.00 613.00,642.00 613.00,642.00
613.00,642.00 614.00,643.00 614.00,643.00
614.00,643.00 614.00,642.00 614.00,642.00 Z
M 672.00,642.00
C 672.00,642.00 671.00,642.00 671.00,642.00
671.00,642.00 672.00,643.00 672.00,643.00
672.00,643.00 672.00,642.00 672.00,642.00 Z
M 619.00,647.00
C 619.00,647.00 618.00,647.00 618.00,647.00
618.00,647.00 619.00,648.00 619.00,648.00
619.00,648.00 619.00,647.00 619.00,647.00 Z
M 620.00,648.00
C 620.00,648.00 619.00,648.00 619.00,648.00
619.00,648.00 620.00,649.00 620.00,649.00
620.00,649.00 620.00,648.00 620.00,648.00 Z
M 622.00,650.00
C 622.00,650.00 621.00,650.00 621.00,650.00
621.00,650.00 622.00,651.00 622.00,651.00
622.00,651.00 622.00,650.00 622.00,650.00 Z
M 625.00,653.00
C 625.00,653.00 624.00,653.00 624.00,653.00
624.00,653.00 625.00,654.00 625.00,654.00
625.00,654.00 625.00,653.00 625.00,653.00 Z
M 627.00,655.00
C 627.00,655.00 626.00,655.00 626.00,655.00
626.00,655.00 627.00,656.00 627.00,656.00
627.00,656.00 627.00,655.00 627.00,655.00 Z
M 633.00,661.00
C 633.00,661.00 632.00,661.00 632.00,661.00
632.00,661.00 633.00,662.00 633.00,662.00
633.00,662.00 633.00,661.00 633.00,661.00 Z
M 635.00,663.00
C 635.00,663.00 634.00,663.00 634.00,663.00
634.00,663.00 635.00,664.00 635.00,664.00
635.00,664.00 635.00,663.00 635.00,663.00 Z
M 638.00,666.00
C 638.00,666.00 637.00,666.00 637.00,666.00
637.00,666.00 638.00,667.00 638.00,667.00
638.00,667.00 638.00,666.00 638.00,666.00 Z
M 641.00,669.00
C 641.00,669.00 640.00,669.00 640.00,669.00
640.00,669.00 641.00,670.00 641.00,670.00
641.00,670.00 641.00,669.00 641.00,669.00 Z
M 646.00,674.00
C 646.00,674.00 645.00,674.00 645.00,674.00
645.00,674.00 646.00,675.00 646.00,675.00
646.00,675.00 646.00,674.00 646.00,674.00 Z
M 649.00,677.00
C 649.00,677.00 648.00,677.00 648.00,677.00
648.00,677.00 649.00,678.00 649.00,678.00
649.00,678.00 649.00,677.00 649.00,677.00 Z
M 651.00,679.00
C 651.00,679.00 650.00,679.00 650.00,679.00
650.00,679.00 651.00,680.00 651.00,680.00
651.00,680.00 651.00,679.00 651.00,679.00 Z`
]
} as never,
fixed: faCalendar,
project: faListCheck
};
export const JobTypeDescriptions: {
[key in (typeof Employment)[number]["type"]]: string;
} = {
hypothetical: "",
volunteer: "Pro-bono work",
fixed: "Fixed-rate contract",
project: "Project-based contract"
};

21
src/app/config/Logos.ts Normal file
View File

@ -0,0 +1,21 @@
export const Logos: {
link: string;
file: string;
alt: string;
}[] = [
{
link: "https://freecodecamp.org",
file: "fcc_primary_large.svg",
alt: "freeCodeCamp"
},
{
link: "https://rythm.fm",
file: "rythm.svg",
alt: "Rythm"
},
{
link: "https://deepgram.com",
file: "deepgram.svg",
alt: "Deepgram AI"
}
];

79
src/app/config/Socials.ts Normal file
View File

@ -0,0 +1,79 @@
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import {
faDiscord,
faGithub,
faHashnode,
faLinkedinIn,
faReddit,
faSlack
} from "@fortawesome/free-brands-svg-icons";
import { Codeberg, Matrix, Peerlist, Polywork } from "./Icons";
export const Socials: {
icon: IconDefinition;
link: string;
label: string;
alt: string;
}[] = [
{
label: "Codeberg",
link: "https://codeberg.org/naomi-lgbt",
alt: "Codeberg Logo",
icon: Codeberg
},
{
label: "GitHub",
link: "https://github.com/nhcarrigan",
alt: "GitHub Logo",
icon: faGithub
},
{
label: "Discord",
link: "https://chat.naomi.lgbt",
alt: "Discord Logo",
icon: faDiscord
},
{
label: "Matrix",
link: "https://matrix.to/#/#naomi:matrix.org",
alt: "Element Logo",
icon: Matrix
},
{
label: "Slack",
link: "https://join.slack.com/t/naomi-lgbt/signup",
alt: "Slack Logo",
icon: faSlack
},
{
label: "Reddit",
link: "https://reddit.com/r/nhcarrigan",
alt: "Reddit Logo",
icon: faReddit
},
{
label: "Blog",
link: "https://blog.nhcarrigan.com",
alt: "Hashnode Logo",
icon: faHashnode
},
{
label: "LinkedIn",
link: "https://linkedin.com/in/naomi-lgbt",
alt: "LinkedIn Logo",
icon: faLinkedinIn
},
{
label: "Resume",
link: "https://resume.nhcarrigan.com",
alt: "Peerlist Logo",
icon: Peerlist
},
{
label: "Polywork",
link: "https://polywork.nhcarrigan.com/",
alt: "Polywork Logo",
icon: Polywork
}
];

View File

@ -1,15 +1,3 @@
@font-face {
font-family: "vt323";
src: url("../../assets/fonts/vt323.woff");
font-display: swap;
}
@font-face {
font-family: "odudo";
src: url("../../assets/fonts/odudo.otf");
font-display: swap;
}
hr {
border: 2px solid var(--text);
margin: 1rem auto;
@ -20,16 +8,16 @@ h2 {
font-size: 1.5rem;
}
section {
margin-bottom: 1rem;
}
.smaller {
font-size: 1rem;
max-width: 1125px;
margin: auto;
}
.logo {
height: 50px;
}
.logo-container {
margin: auto;
max-width: 1125px;
@ -37,169 +25,3 @@ h2 {
justify-content: space-around;
flex-wrap: wrap;
}
.socials {
font-size: 2rem;
margin-bottom: 1rem;
}
.socials a {
margin: auto 10px;
}
.legend {
display: flex;
max-width: 1125px;
margin: auto;
justify-content: space-evenly;
}
.legend p {
font-size: 1rem;
}
.legend .current {
color: #8cff98;
font-family: "odudo";
}
.legend .former {
color: #b48cff;
font-family: "vt323";
}
.legend .volunteer {
padding: 2px;
border: 2px dashed var(--text);
}
.timeline {
position: relative;
max-width: 1200px;
margin: auto;
}
.timeline::after {
content: "";
position: absolute;
width: 6px;
background-color: var(--text);
top: 0;
bottom: 0;
left: 50%;
margin-left: -3px;
}
.container {
padding: 10px 40px;
position: relative;
width: 50%;
background-color: transparent;
color: var(--bg);
}
.info {
color: var(--text);
border-radius: 1rem;
border: 2px solid var(--text);
overflow: hidden;
}
.container::after {
content: "";
position: absolute;
width: 25px;
height: 25px;
right: -12.5px;
background-color: var(--text);
border-radius: 50%;
top: 30px;
z-index: 1;
}
.hypothetical .info {
border-color: white;
border-style: dotted;
}
.hypothetical .info,
.hypothetical a,
.hypothetical a:visited {
color: white;
}
.hypothetical::after {
background-color: white;
}
.current .info {
border-color: #8cff98;
font-family: "odudo";
}
.current .info,
.current a,
.current a:visited {
color: #8cff98;
}
.current::after {
background-color: #8cff98;
}
.former .info {
border-color: #b48cff;
font-family: "vt323";
}
.former .info,
.former a,
.former a:visited {
color: #b48cff;
}
.former::after {
background-color: #b48cff;
}
.volunteer .info {
border-style: dashed;
}
.company {
font-size: 1rem;
}
.left {
left: 0;
}
.right {
left: 50%;
}
.right::after {
left: -12.5px;
}
.date {
font-size: 1rem;
font-style: italic;
}
@media screen and (max-width: 600px) {
.container {
width: 100%;
padding-left: 70px;
padding-right: 25px;
}
.right {
left: 0;
}
.left::after,
.right::after {
left: 17.5px;
}
.timeline::after {
left: 31px;
}
}

View File

@ -8,349 +8,18 @@
vibrant digital spaces can drive engagement and growth.
</p>
<hr />
<h2>Contact</h2>
<div class="socials">
<a
href="https://codeberg.org/naomi-lgbt"
target="_blank"
rel="noopener noreferrer"
aria-label="Codeberg"
><fa-icon alt="Codeberg Logo" [icon]="codeberg"></fa-icon
></a>
<a
href="https://chat.naomi.lgbt"
target="_blank"
rel="noopener noreferrer"
aria-label="Discord"
><fa-icon alt="Discord Logo" [icon]="discord"></fa-icon
></a>
<a
href="https://matrix.to/#/#naomi:matrix.org"
target="_blank"
rel="noopener noreferrer"
aria-label="Matrix"
><fa-icon alt="Element Logo" [icon]="matrix"></fa-icon
></a>
<a
href="https://join.slack.com/t/naomi-lgbt/signup"
target="_blank"
rel="noopener noreferrer"
aria-label="Slack"
><fa-icon alt="Slack Logo" [icon]="slack"></fa-icon
></a>
<a
href="https://reddit.com/r/nhcarrigan"
target="_blank"
rel="noopener noreferrer"
aria-label="Reddit"
><fa-icon alt="Reddit Logo" [icon]="reddit"></fa-icon
></a>
<a
href="https://blog.nhcarrigan.com"
target="_blank"
rel="noopener noreferrer"
aria-label="Hashnode Blog"
><fa-icon alt="Hashnode Logo" [icon]="blog"></fa-icon
></a>
<a
href="https://linkedin.com/in/naomi-lgbt"
target="_blank"
rel="noopener noreferrer"
aria-label="LinkedIn"
><fa-icon alt="LinkedIn Logo" [icon]="linkedIn"></fa-icon
></a>
<a
href="https://resume.nhcarrigan.com"
target="_blank"
rel="noopener noreferrer"
aria-label="Peerlist Resume"
><fa-icon alt="Peerlist Logo" [icon]="peerlist"></fa-icon
></a>
<a
href="https://www.polywork.com/nhcarrigan"
target="_blank"
rel="noopener noreferrer"
aria-label="Polywork"
><fa-icon alt="Polywork Logo" [icon]="polywork"></fa-icon
></a>
</div>
<section>
<h2>Contact</h2>
<app-social *ngFor="let social of socials" [social]="social" />
</section>
<hr />
<h2>Featured Clients</h2>
<div class="logo-container">
<a href="https://freecodecamp.org" target="_blank" rel="noopener noreferrer">
<img
class="logo"
src="../../assets/img/fcc_primary_large.svg"
alt="freeCodeCamp"
height="50px"
/>
</a>
<a href="https://rythm.fm" target="_blank" rel="noopener noreferrer">
<img
class="logo"
src="../../assets/img/rythm.svg"
alt="Rythm"
height="50px"
/>
</a>
<a href="https://deepgram.com" target="_blank" rel="noopener noreferrer">
<img
class="logo"
src="../../assets/img/deepgram.svg"
alt="Deepgram AI"
height="50px"
/>
</a>
</div>
<section>
<h2>Featured Clients</h2>
<div class="logo-container">
<app-logo *ngFor="let logo of logos" [logo]="logo" />
</div>
</section>
<hr />
<h2>All Work</h2>
<div class="legend">
<p class="current">Current</p>
<p class="former">Former</p>
<p class="volunteer">Volunteer</p>
</div>
<div class="timeline">
<div class="container left hypothetical">
<div class="info">
<h2>
<a
href="https://docs.nhcarrigan.com/#/hire"
target="_blank"
rel="noopener noreferrer"
>Consultant</a
>
</h2>
<p class="date">Today</p>
<p class="company">Your Company!</p>
</div>
</div>
<div class="container right current volunteer">
<div class="info">
<h2>
<a
href="https://art4palestine.org/"
target="_blank"
rel="noopener noreferrer"
>Development Lead</a
>
</h2>
<p class="date">November 2023</p>
<p class="company">Art 4 Palestine</p>
</div>
</div>
<div class="container left current volunteer">
<div class="info">
<h2>
<a
href="https://discord.gg/kYpjgEB"
target="_blank"
rel="noopener noreferrer"
>Community Moderator</a
>
</h2>
<p class="date">September 2023</p>
<p class="company">AngelRose</p>
</div>
</div>
<div class="container right current">
<div class="info">
<h2>
<a href="https://deepgram.com" target="_blank" rel="noopener noreferrer"
>Community Bot Engineer</a
>
</h2>
<p class="date">July 2023</p>
<p class="company">Deepgram</p>
</div>
</div>
<div class="container left former">
<div class="info">
<h2>
<a
href="https://linktr.ee/bigbadbeaver"
target="_blank"
rel="noopener noreferrer"
>Twitch Integration Engineer</a
>
</h2>
<p class="date">October 2022</p>
<p class="company">BigBadBeaver Productions</p>
</div>
</div>
<div class="container right former">
<div class="info">
<h2>
<a
href="https://www.semasoftware.com/"
target="_blank"
rel="noopener noreferrer"
>Community Manager and Open-Source Engineer</a
>
</h2>
<p class="date">May 2023</p>
<p class="company">Sema Software</p>
</div>
</div>
<div class="container left former">
<div class="info">
<h2>
<a
href="https://discord.gg/kYpjgEB"
target="_blank"
rel="noopener noreferrer"
>Community Manager</a
>
</h2>
<p class="date">May 2023</p>
<p class="company">4C</p>
</div>
</div>
<div class="container right current">
<div class="info">
<h2>
<a href="https://rythm.fm/" target="_blank" rel="noopener noreferrer"
>Senior Integrations Engineer</a
>
</h2>
<p class="date">April 2022</p>
<p class="company">Rythm</p>
</div>
</div>
<div class="container left former">
<div class="info">
<h2>
<a
href="https://tweetshift.com/"
target="_blank"
rel="noopener noreferrer"
>Community Manager</a
>
</h2>
<p class="date">January 2022</p>
<p class="company">TweetShift</p>
</div>
</div>
<div class="container right current">
<div class="info">
<h2>
<a
href="https://streamcord.io/"
target="_blank"
rel="noopener noreferrer"
>Community Manager and Infrastructure Engineer</a
>
</h2>
<p class="date">August 2021</p>
<p class="company">Streamcord</p>
</div>
</div>
<div class="container left former volunteer">
<div class="info">
<h2>
<a
href="https://play.battlesnake.com/"
target="_blank"
rel="noopener noreferrer"
>Community Moderator</a
>
</h2>
<p class="date">June 2021</p>
<p class="company">Battlesnake</p>
</div>
</div>
<div class="container right current volunteer">
<div class="info">
<h2>
<a
href="https://discord.gg/infinite"
target="_blank"
rel="noopener noreferrer"
>Discord Administrator and Platform Engineering Manager</a
>
</h2>
<p class="date">June 2021</p>
<p class="company">Caylus Crew</p>
</div>
</div>
<div class="container left former volunteer">
<div class="info">
<h2>
<a
href="http://discord.gg/U3jQVYNbJt"
target="_blank"
rel="noopener noreferrer"
>Integrations Engineer</a
>
</h2>
<p class="date">April 2021</p>
<p class="company">Xcentric Collective</p>
</div>
</div>
<div class="container right current volunteer">
<div class="info">
<h2>
<a
href="https://hacktoberfest.com"
target="_blank"
rel="noopener noreferrer"
>Hacktoberfest Community Moderator</a
>
</h2>
<p class="date">April 2021</p>
<p class="company">DigitalOcean</p>
</div>
</div>
<div class="container left former volunteer">
<div class="info">
<h2>
<a
href="https://www.eddiehub.org/"
target="_blank"
rel="noopener noreferrer"
>Discord Administrator</a
>
</h2>
<p class="date">January 2021</p>
<p class="company">EddieHub</p>
</div>
</div>
<div class="container right current volunteer">
<div class="info">
<h2>
<a
href="https://discord.gg/StwJYeq"
target="_blank"
rel="noopener noreferrer"
>Discord Administrator and Lead Integrations Engineer</a
>
</h2>
<p class="date">December 2020</p>
<p class="company">Commit Your Code</p>
</div>
</div>
<div class="container left current volunteer">
<div class="info">
<h2>
<a
href="https://freecodecamp.org"
target="_blank"
rel="noopener noreferrer"
>Educational Developer and Community Manager</a
>
</h2>
<p class="date">December 2020</p>
<p class="company">freeCodeCamp</p>
</div>
</div>
<div class="container right hypothetical">
<div class="info">
<h2>
<a href="https://naomi.lgbt" target="_blank" rel="noopener noreferrer"
>Began Development Journey</a
>
</h2>
<p class="date">April 2020</p>
<p class="company">nhcarrigan</p>
</div>
</div>
</div>
<section>
<app-timeline></app-timeline>
</section>

View File

@ -1,5 +1,8 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Logos } from "../config/Logos";
import { Socials } from "../config/Socials";
import { HomeComponent } from "./home.component";
describe("HomeComponent", () => {
@ -25,5 +28,9 @@ describe("HomeComponent", () => {
it("should render correctly", () => {
const header = compiled.querySelector("h1");
expect(header?.innerText.trim()).toBe("Naomi Carrigan");
const socials = compiled.querySelectorAll("app-social");
expect(socials).toHaveSize(Socials.length);
const logos = compiled.querySelectorAll("app-logo");
expect(logos).toHaveSize(Logos.length);
});
});

View File

@ -1,14 +1,12 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import {
faDiscord,
faReddit,
faLinkedinIn,
faHashnode,
IconDefinition,
faSlack
} from "@fortawesome/free-brands-svg-icons";
import { Logos } from "../config/Logos";
import { Socials } from "../config/Socials";
import { JobComponent } from "../job/job.component";
import { LogoComponent } from "../logo/logo.component";
import { SocialComponent } from "../social/social.component";
import { TimelineComponent } from "../timeline/timeline.component";
/**
*
@ -16,334 +14,17 @@ import {
@Component({
selector: "app-home",
standalone: true,
imports: [CommonModule, FontAwesomeModule],
imports: [
CommonModule,
SocialComponent,
JobComponent,
LogoComponent,
TimelineComponent
],
templateUrl: "./home.component.html",
styleUrl: "./home.component.css"
})
export class HomeComponent {
discord = faDiscord;
reddit = faReddit;
linkedIn = faLinkedinIn;
blog = faHashnode;
slack = faSlack;
codeberg: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
474,
474,
[],
"U+E002",
`M 36.00,373.00
C 19.99,344.87 11.56,324.72 5.00,293.00
5.00,293.00 2.08,280.00 2.08,280.00
2.08,280.00 2.08,271.04 2.08,271.04
1.21,265.55 0.02,268.68 0.00,259.00
0.00,259.00 0.00,232.00 0.00,232.00
0.10,225.30 1.32,226.49 2.08,221.96
2.08,221.96 2.08,214.00 2.08,214.00
2.08,214.00 4.55,203.00 4.55,203.00
8.89,181.33 13.79,163.93 23.75,144.00
23.75,144.00 31.87,128.00 31.87,128.00
40.56,112.80 56.86,91.48 69.17,79.17
69.17,79.17 80.00,69.72 80.00,69.72
90.99,60.09 102.48,51.08 115.00,43.46
115.00,43.46 132.00,34.75 132.00,34.75
194.09,3.71 265.92,2.29 330.00,28.45
346.58,35.22 368.94,48.49 383.00,59.51
383.00,59.51 397.00,71.72 397.00,71.72
418.24,90.34 435.64,113.79 448.25,139.00
460.07,162.66 464.56,176.20 469.80,202.00
471.25,209.15 473.99,218.02 474.00,225.00
474.00,225.00 474.00,270.00 474.00,270.00
474.00,270.00 469.42,294.00 469.42,294.00
469.42,294.00 465.25,313.00 465.25,313.00
465.25,313.00 454.33,343.00 454.33,343.00
454.33,343.00 439.00,373.00 439.00,373.00
439.00,373.00 437.00,373.00 437.00,373.00
437.00,373.00 386.42,307.00 386.42,307.00
386.42,307.00 285.87,177.00 285.87,177.00
285.87,177.00 250.35,131.00 250.35,131.00
247.89,127.81 240.50,116.27 236.17,117.49
234.17,118.05 231.85,121.40 230.58,123.00
230.58,123.00 221.13,135.00 221.13,135.00
221.13,135.00 183.35,184.00 183.35,184.00
183.35,184.00 88.88,306.00 88.88,306.00
88.88,306.00 55.65,349.00 55.65,349.00
50.94,355.09 41.27,368.61 36.00,373.00 Z
M 244.00,138.00
C 244.00,138.00 272.65,174.00 272.65,174.00
272.65,174.00 327.65,245.00 327.65,245.00
327.65,245.00 401.88,341.00 401.88,341.00
401.88,341.00 433.00,382.00 433.00,382.00
433.00,382.00 409.96,410.00 409.96,410.00
409.96,410.00 400.00,419.17 400.00,419.17
400.00,419.17 389.00,429.68 389.00,429.68
389.00,429.68 361.00,449.54 361.00,449.54
361.00,449.54 346.00,457.31 346.00,457.31
346.00,457.31 331.00,465.00 331.00,465.00
331.00,465.00 315.85,409.00 315.85,409.00
315.85,409.00 283.85,289.00 283.85,289.00
283.85,289.00 257.12,189.00 257.12,189.00
257.12,189.00 244.00,138.00 244.00,138.00 Z`
]
} as never;
matrix: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
342,
342,
[],
"U+E002",
`M 138.00,0.53
C 150.87,-1.59 166.46,0.98 179.00,4.13
230.88,17.15 270.41,61.51 279.08,114.00
279.08,114.00 281.00,131.00 281.00,131.00
281.08,137.92 281.47,143.03 277.20,148.99
268.97,160.46 252.22,161.04 243.39,149.98
237.90,143.12 239.56,138.59 238.83,131.00
238.25,124.97 237.10,118.87 235.63,113.00
230.45,92.32 217.03,73.13 200.00,60.48
188.68,52.07 173.95,45.62 160.00,43.28
149.18,41.47 136.43,43.78 128.21,34.91
117.46,23.31 123.25,5.13 138.00,0.53 Z
M 126.00,61.42
C 132.79,60.60 140.80,60.41 147.00,63.67
157.30,69.10 161.07,83.05 155.00,93.00
148.91,102.97 142.67,102.25 133.00,103.17
133.00,103.17 121.00,104.75 121.00,104.75
106.64,107.11 91.56,113.68 80.00,122.50
61.64,136.52 50.33,153.71 44.63,176.00
43.46,180.57 42.62,185.30 42.17,190.00
41.42,197.85 43.18,203.96 37.61,210.99
28.88,221.99 10.70,222.28 2.99,210.00
-0.87,203.84 -0.08,195.99 0.00,189.00
0.10,181.05 1.94,171.72 3.87,164.00
14.25,122.51 43.23,89.80 82.00,72.31
97.65,65.25 109.47,63.78 126.00,61.42 Z
M 315.00,123.64
C 330.97,120.43 341.97,128.41 342.00,145.00
342.03,164.57 338.91,182.06 330.69,200.00
308.91,247.57 260.01,281.64 207.00,281.00
183.02,280.71 177.62,255.16 192.04,243.39
198.72,237.94 203.50,239.55 211.00,238.83
217.03,238.25 223.12,237.09 229.00,235.63
249.81,230.42 269.96,216.52 282.28,199.00
290.55,187.24 296.09,175.19 298.74,161.00
301.56,145.87 296.54,130.60 315.00,123.64 Z
M 78.00,184.53
C 87.56,183.00 96.80,186.96 101.08,196.00
101.08,196.00 105.45,225.00 105.45,225.00
108.31,239.01 115.29,252.68 123.90,264.00
136.86,281.04 157.21,293.39 178.00,298.11
188.70,300.54 202.89,298.40 210.98,304.56
222.59,313.38 221.84,332.30 209.00,339.64
203.20,342.95 194.60,342.07 188.00,342.00
180.39,341.91 168.41,339.51 161.00,337.42
119.62,325.74 86.75,295.86 70.60,256.00
70.60,256.00 66.29,243.00 66.29,243.00
63.87,234.58 62.76,227.67 61.84,219.00
60.14,203.20 59.71,189.94 78.00,184.53 Z`
]
} as never;
peerlist: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
512,
512,
[],
"U+E002",
`M 214.00,0.14
C 214.00,0.14 243.00,0.14 243.00,0.14
243.00,0.14 291.00,0.14 291.00,0.14
291.00,0.14 301.00,1.00 301.00,1.00
301.00,1.00 311.00,1.00 311.00,1.00
311.00,1.00 328.00,2.83 328.00,2.83
375.51,7.58 421.85,17.89 457.91,51.42
483.50,75.23 497.13,112.43 503.80,146.00
507.93,166.77 510.12,187.89 511.04,209.00
511.04,209.00 512.00,220.00 512.00,220.00
512.59,270.71 513.41,322.24 502.42,372.00
495.29,404.31 483.17,434.75 459.72,458.83
437.47,481.67 407.37,493.82 377.00,501.37
326.73,513.88 274.38,512.08 223.00,512.00
223.00,512.00 208.00,511.00 208.00,511.00
208.00,511.00 204.00,511.00 204.00,511.00
204.00,511.00 166.00,507.13 166.00,507.13
125.75,501.54 81.42,488.74 52.28,458.83
18.32,423.96 7.84,375.75 2.84,329.00
2.84,329.00 0.91,302.00 0.91,302.00
0.91,302.00 0.00,290.00 0.00,290.00
0.00,290.00 0.00,253.00 0.00,253.00
0.00,253.00 0.00,223.00 0.00,223.00
0.00,223.00 1.00,205.00 1.00,205.00
1.00,205.00 6.59,155.00 6.59,155.00
11.95,123.04 22.32,89.63 42.81,64.00
74.31,24.60 121.91,10.61 170.00,4.28
170.00,4.28 201.00,1.09 201.00,1.09
201.00,1.09 214.00,0.14 214.00,0.14 Z
M 234.00,18.14
C 227.52,19.22 223.42,18.99 217.00,19.00
217.00,19.00 205.00,20.04 205.00,20.04
205.00,20.04 197.00,20.04 197.00,20.04
149.57,24.69 92.98,33.42 60.44,72.00
34.70,102.51 25.98,143.28 21.84,182.00
21.84,182.00 19.00,224.00 19.00,224.00
19.00,224.00 18.00,241.00 18.00,241.00
18.00,241.00 18.00,273.00 18.00,273.00
18.00,273.00 18.96,283.00 18.96,283.00
18.96,283.00 18.96,297.00 18.96,297.00
18.96,297.00 19.91,307.00 19.91,307.00
19.91,307.00 24.92,353.00 24.92,353.00
30.18,384.75 40.74,418.98 63.09,443.00
93.04,475.19 139.93,485.66 182.00,490.16
182.00,490.16 205.00,492.09 205.00,492.09
205.00,492.09 215.00,493.04 215.00,493.04
215.00,493.04 229.00,493.04 229.00,493.04
229.00,493.04 241.00,494.00 241.00,494.00
241.00,494.00 271.00,494.00 271.00,494.00
271.00,494.00 283.00,493.04 283.00,493.04
283.00,493.04 295.00,493.04 295.00,493.04
295.00,493.04 307.00,492.09 307.00,492.09
327.86,490.66 348.55,488.59 369.00,483.88
398.65,477.06 426.42,466.49 447.96,444.00
469.93,421.06 480.00,389.49 486.00,359.00
490.02,338.59 492.97,308.77 493.00,288.00
493.00,288.00 494.00,271.00 494.00,271.00
494.00,271.00 494.00,241.00 494.00,241.00
494.00,241.00 493.04,229.00 493.04,229.00
493.04,229.00 493.04,217.00 493.04,217.00
493.04,217.00 492.09,205.00 492.09,205.00
490.82,186.52 489.06,168.22 485.40,150.00
478.89,117.63 467.20,84.85 442.00,62.17
412.18,35.33 368.80,25.99 330.00,21.84
330.00,21.84 307.00,19.91 307.00,19.91
307.00,19.91 295.00,18.96 295.00,18.96
295.00,18.96 283.00,18.96 283.00,18.96
283.00,18.96 271.00,18.14 271.00,18.14
271.00,18.14 234.00,18.14 234.00,18.14 Z
M 156.00,101.00
C 156.00,101.00 231.00,101.00 231.00,101.00
231.00,101.00 270.00,101.00 270.00,101.00
304.65,101.05 338.60,117.93 361.91,143.00
370.38,152.10 378.11,164.62 383.14,176.00
398.86,211.57 395.05,254.17 374.58,287.00
365.39,301.73 358.75,306.40 347.28,318.17
331.52,334.35 322.21,343.76 301.00,353.14
279.20,362.77 264.27,364.00 241.00,364.00
241.00,364.00 241.00,411.00 241.00,411.00
241.00,411.00 223.00,411.00 223.00,411.00
223.00,411.00 223.00,429.00 223.00,429.00
223.00,429.00 138.00,429.00 138.00,429.00
138.00,429.00 138.00,119.00 138.00,119.00
138.00,119.00 156.00,119.00 156.00,119.00
156.00,119.00 156.00,101.00 156.00,101.00 Z
M 223.00,329.00
C 263.91,329.00 301.86,332.36 336.00,304.54
349.16,293.81 359.70,280.51 366.69,265.00
374.05,248.67 375.20,234.53 375.00,217.00
374.56,179.46 346.33,143.35 313.00,128.31
291.09,118.42 270.44,118.00 247.00,118.00
247.00,118.00 207.00,118.00 207.00,118.00
207.00,118.00 182.00,118.00 182.00,118.00
180.01,118.00 176.19,117.77 174.60,119.02
172.62,120.59 173.00,124.70 173.00,127.00
173.00,127.00 173.00,332.00 173.00,332.00
173.00,332.00 173.00,385.00 173.00,385.00
173.02,393.64 173.36,393.98 182.00,394.00
182.00,394.00 223.00,394.00 223.00,394.00
223.00,394.00 223.00,329.00 223.00,329.00 Z
M 223.00,166.00
C 223.00,166.00 266.00,166.00 266.00,166.00
306.49,166.06 336.49,205.40 321.39,244.00
319.11,249.82 315.95,255.30 311.82,260.00
300.28,273.13 284.59,280.92 267.00,281.00
267.00,281.00 253.00,281.00 253.00,281.00
253.00,281.00 223.00,281.00 223.00,281.00
223.00,281.00 223.00,166.00 223.00,166.00 Z
M 241.00,202.00
C 241.00,202.00 241.00,255.00 241.00,255.00
241.02,263.64 241.36,263.98 250.00,264.00
258.53,264.02 277.96,264.47 284.58,259.01
289.25,255.16 289.06,244.57 289.00,239.00
288.79,221.67 275.23,207.53 259.00,203.16
253.08,201.56 247.07,202.00 241.00,202.00 Z`
]
} as never;
polywork: IconDefinition = {
prefix: "xxx",
iconName: "yyy",
icon: [
225, // SVG view box width
225, // SVG view box height
[],
"U+E002", // probably not important for SVG and JS approach
`M 153.00,155.00
C 153.00,177.49 155.16,201.18 134.00,215.78
117.90,226.88 101.50,224.00 83.00,224.00
83.00,224.00 57.00,224.00 57.00,224.00
36.75,224.00 21.13,223.75 8.22,205.00
5.78,201.46 3.67,197.12 2.44,193.00
0.64,186.98 0.01,182.25 0.00,176.00
0.00,176.00 0.00,49.00 0.00,49.00
0.05,19.44 19.43,0.05 49.00,0.00
49.00,0.00 176.00,0.00 176.00,0.00
203.99,0.04 223.96,18.67 224.00,47.00
224.00,47.00 224.00,89.00 224.00,89.00
224.00,112.86 226.74,132.44 204.00,147.95
200.27,150.49 196.33,152.29 192.00,153.56
182.70,156.30 170.69,156.05 161.00,156.00
157.55,155.98 156.36,155.95 153.00,155.00 Z
M 70.00,11.00
C 52.54,11.00 34.21,8.10 21.09,22.01
17.77,25.54 15.22,29.35 13.77,34.00
11.01,42.87 12.00,61.03 12.00,71.00
12.00,71.00 70.00,71.00 70.00,71.00
70.00,71.00 70.00,11.00 70.00,11.00 Z
M 141.00,71.00
C 141.00,71.00 141.00,19.00 141.00,19.00
140.94,10.87 139.73,11.02 132.00,11.00
132.00,11.00 82.94,11.00 82.94,11.00
82.94,11.00 82.94,65.00 82.94,65.00
82.65,71.56 84.51,70.99 91.00,71.00
91.00,71.00 141.00,71.00 141.00,71.00 Z
M 212.00,71.00
C 212.00,71.00 212.00,46.00 212.00,46.00
211.99,40.91 212.06,38.94 210.30,34.00
200.99,7.84 175.95,12.00 154.00,12.00
154.00,12.00 154.00,71.00 154.00,71.00
154.00,71.00 212.00,71.00 212.00,71.00 Z
M 70.00,84.00
C 70.00,84.00 11.00,84.00 11.00,84.00
11.00,84.00 11.00,136.00 11.00,136.00
11.02,144.64 11.36,144.98 20.00,145.00
20.00,145.00 70.00,145.00 70.00,145.00
70.00,145.00 70.00,84.00 70.00,84.00 Z
M 141.00,84.00
C 141.00,84.00 83.00,84.00 83.00,84.00
83.00,84.00 83.00,144.00 83.00,144.00
83.00,144.00 141.00,144.00 141.00,144.00
141.00,144.00 141.00,84.00 141.00,84.00 Z
M 212.00,84.00
C 212.00,84.00 154.00,84.00 154.00,84.00
154.00,84.00 154.00,145.00 154.00,145.00
176.30,145.00 201.22,148.17 210.45,122.00
212.02,117.55 211.99,114.59 212.00,110.00
212.00,110.00 212.00,84.00 212.00,84.00 Z
M 70.00,157.00
C 70.00,157.00 11.00,157.00 11.00,157.00
11.00,177.94 8.44,201.56 33.00,210.30
37.94,212.06 39.91,211.99 45.00,212.00
45.00,212.00 70.00,212.00 70.00,212.00
70.00,212.00 70.00,157.00 70.00,157.00 Z
M 141.00,158.00
C 141.00,158.00 83.00,158.00 83.00,158.00
83.00,158.00 83.00,213.00 83.00,213.00
83.00,213.00 106.00,213.00 106.00,213.00
110.59,212.99 113.55,213.02 118.00,211.45
143.85,202.34 141.00,180.01 141.00,158.00 Z`
]
} as never;
public socials = Socials;
public logos = Logos;
}

View File

@ -0,0 +1,120 @@
h2 {
font-size: 2rem;
}
p {
font-size: 1.5rem;
}
article p {
font-size: 1.25rem;
}
button {
cursor: pointer;
}
hr {
border: 1px solid var(--text);
}
.job {
padding: 10px 40px;
position: relative;
width: 50%;
background-color: transparent;
color: var(--bg);
display: block;
border: none;
}
.info {
color: var(--text);
border-radius: 1rem;
border: 2px solid var(--text);
overflow: hidden;
position: relative;
}
.icon {
position: relative;
top: -5rem;
z-index: 1;
background-color: var(--bg);
padding: 0;
border-radius: 50%;
}
.left {
left: 0;
}
.right {
left: 50%;
}
.right::after {
left: -12.5px;
}
.hypothetical .info,
.hypothetical .info hr,
.hypothetical a,
.hypothetical a:visited {
color: white;
border-color: white;
border-style: dotted;
}
.hypothetical.icon {
color: white;
}
.current .info,
.current .info hr,
.current a,
.current a:visited,
.current.icon {
color: #8cff98;
border-color: #8cff98;
}
.former .info,
.former .info hr,
.former a,
.former a:visited,
.former.icon {
color: #b48cff;
border-color: #b48cff;
}
.date,
.desc {
font-style: italic;
}
.logo {
max-height: 100px;
border-radius: 50%;
}
.icon {
font-size: 2rem;
}
@media screen and (max-width: 600px) {
.job {
width: 100%;
padding-left: 70px;
padding-right: 25px;
}
.right {
left: 0;
}
.left::after,
.right::after {
left: 17.5px;
}
.icon {
left: calc(37.5px - 50vw);
}
}

View File

@ -0,0 +1,27 @@
<button class="job {{ align }} {{ type }}" (click)="expand()">
<div class="info">
<h2>{{ job.title }}</h2>
<img
*ngIf="job.logo && expanded"
class="logo"
[src]="'/assets/img/icons/' + job.logo"
[alt]="job.company + ' Logo'"
/>
<p>{{ job.company }}</p>
<p class="date">
{{ date }}
</p>
<p class="desc" *ngIf="icon && expanded">{{ iconDescription }}</p>
<hr *ngIf="expanded" />
<article *ngIf="expanded">
<p *ngFor="let line of description">{{ line }}</p>
</article>
</div>
</button>
<fa-icon
*ngIf="icon"
class="icon {{ type }}"
[icon]="icon"
[attr.alt]="iconDescription"
/>

View File

@ -0,0 +1,189 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Employment } from "../config/Employment";
import { JobTypeDescriptions, JobTypes } from "../config/Icons";
import { JobComponent } from "./job.component";
describe("JobComponent", () => {
let component: JobComponent;
let fixture: ComponentFixture<JobComponent>;
let compiled: HTMLElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [JobComponent]
}).compileComponents();
fixture = TestBed.createComponent(JobComponent);
component = fixture.componentInstance;
compiled = fixture.nativeElement;
});
for (const expected of Employment) {
it("should parse properties correctly", () => {
component.job = expected;
component.align = "left";
fixture.detectChanges();
expect(component.job).toBe(expected);
expect(component.align).toBe("left");
expect(component.type).toBe(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
expect(component.icon).toBe(JobTypes[expected.type]);
expect(component.iconDescription).toBe(
JobTypeDescriptions[expected.type]
);
expect(component.expanded).toBeFalse();
expect(component.description).toEqual(expected.description.split(/\n+/));
expect(component.date).toBe(
expected.end
? `${expected.start.toLocaleDateString()} - ${expected.end.toLocaleDateString()}`
: expected.start.toLocaleDateString()
);
});
it("should render a job correctly", () => {
component.job = expected;
component.ngOnInit();
fixture.detectChanges();
compiled = fixture.nativeElement;
/* Button wrapper */
const button = compiled.querySelector("button");
expect(button?.classList).toContain("left");
expect(button?.classList).toContain(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
/* Timeline Icon */
const icon = compiled.querySelector("fa-icon");
expect(icon?.classList).toContain("icon");
expect(icon?.classList).toContain(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
const svg = icon?.querySelector("svg");
const path = svg?.querySelector("path");
expect(path?.getAttribute("d")).toBe(
JobTypes[expected.type].icon[4] as string
);
/* Rendered content from job object */
const title = compiled.querySelector("h2");
expect(title?.innerText.trim()).toBe(expected.title);
const classList = compiled.querySelector("button")?.classList;
expect(classList).toContain(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
const date = compiled.querySelector(".date");
expect(date?.textContent?.trim()).toBe(
expected.end
? `${expected.start.toLocaleDateString()} - ${expected.end.toLocaleDateString()}`
: expected.start.toLocaleDateString()
);
/* Test the stuff that's hidden */
const article = compiled.querySelector("article");
expect(article).toBeNull();
const logo = compiled.querySelector(".logo");
expect(logo).toBeNull();
const iconDescription = compiled.querySelector(".desc");
expect(iconDescription).toBeNull();
});
it("should expand a job correctly", () => {
component.job = expected;
component.ngOnInit();
if (!component.expanded) {
component.expand();
}
fixture.detectChanges();
compiled = fixture.nativeElement;
expect(component.expanded).toBeTrue();
/* Button wrapper */
const button = compiled.querySelector("button");
expect(button?.classList).toContain("left");
expect(button?.classList).toContain(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
/* Timeline Icon */
const icon = compiled.querySelector("fa-icon");
expect(icon?.classList).toContain("icon");
expect(icon?.classList).toContain(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
const svg = icon?.querySelector("svg");
const path = svg?.querySelector("path");
expect(path?.getAttribute("d")).toBe(
JobTypes[expected.type].icon[4] as string
);
/* Rendered content from job object should NOT be changed */
const title = compiled.querySelector("h2");
expect(title?.innerText.trim()).toBe(expected.title);
const classList = compiled.querySelector("button")?.classList;
expect(classList).toContain(
expected.type === "hypothetical"
? "hypothetical"
: expected.end
? "former"
: "current"
);
const date = compiled.querySelector(".date");
expect(date?.textContent?.trim()).toBe(
expected.end
? `${expected.start.toLocaleDateString()} - ${expected.end.toLocaleDateString()}`
: expected.start.toLocaleDateString()
);
/* Hidden stuff should now be visible */
const article = compiled.querySelector("article");
expect(article?.innerText.replace(/\n+/g, "\n")).toBe(
expected.description
.split(/\n+/)
.map((el) => el.trim())
.join("\n")
);
if (expected.logo) {
const logo = compiled.querySelector(".logo");
expect(logo?.getAttribute("src")).toBe(
`/assets/img/icons/${expected.logo}`
);
expect(logo?.classList).toContain("logo");
}
const iconDescription = compiled.querySelector(".desc");
expect(iconDescription?.textContent?.trim()).toBe(
JobTypeDescriptions[expected.type]
);
});
}
});

View File

@ -0,0 +1,49 @@
import { CommonModule } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { Employment } from "../config/Employment";
import { JobTypeDescriptions, JobTypes } from "../config/Icons";
/**
*
*/
@Component({
selector: "app-job",
standalone: true,
imports: [CommonModule, FontAwesomeModule],
templateUrl: "./job.component.html",
styleUrl: "./job.component.css"
})
export class JobComponent implements OnInit {
@Input() job: (typeof Employment)[number] = {} as never;
@Input() align: "left" | "right" = "left";
public type!: "current" | "former" | (typeof Employment)[number]["type"];
public icon!: IconDefinition;
public iconDescription = "";
public expanded = false;
public description: string[] = [];
public date = "";
/**
*
*/
ngOnInit() {
this.description = this.job.description.split(/\n+/);
this.icon = JobTypes[this.job.type];
this.iconDescription = JobTypeDescriptions[this.job.type];
if (this.job.end) {
this.type = "former";
this.date = `${this.job.start.toLocaleDateString()} - ${this.job.end.toLocaleDateString()}`;
return;
}
this.type = this.job.type === "hypothetical" ? "hypothetical" : "current";
this.date = this.job.start.toLocaleDateString();
}
/** */
expand() {
this.expanded = !this.expanded;
}
}

View File

@ -0,0 +1,3 @@
a {
height: 50px;
}

View File

@ -0,0 +1,3 @@
<a href="{{ link }}" target="_blank" rel="noopener noreferrer">
<img class="logo" src="{{ file }}" alt="{{ alt }}" height="50px" />
</a>

View File

@ -0,0 +1,47 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Logos } from "../config/Logos";
import { LogoComponent } from "./logo.component";
describe("LogoComponent", () => {
let component: LogoComponent;
let fixture: ComponentFixture<LogoComponent>;
let compiled: HTMLElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [LogoComponent]
}).compileComponents();
fixture = TestBed.createComponent(LogoComponent);
component = fixture.componentInstance;
});
for (const expected of Logos) {
it(`should parse ${expected.alt} properties correctly`, () => {
component.logo = expected;
fixture.detectChanges();
expect(component.logo).toBe(expected);
expect(component.link).toBe(expected.link);
expect(component.alt).toBe(expected.alt);
expect(component.file).toBe(`/assets/img/${expected.file}`);
});
it(`should render ${expected.alt} correctly`, () => {
component.logo = expected;
fixture.detectChanges();
compiled = fixture.nativeElement;
const link = compiled.querySelector("a");
expect(link?.href).toContain(expected.link);
expect(link?.target).toBe("_blank");
expect(link?.rel).toBe("noopener noreferrer");
const logo = link?.querySelector("img");
expect(logo?.src).toContain(`/assets/img/${expected.file}`);
expect(logo?.classList).toContain("logo");
expect(logo?.alt).toBe(expected.alt);
expect(logo?.height).toBe(50);
});
}
});

View File

@ -0,0 +1,29 @@
import { Component, Input, OnInit } from "@angular/core";
import { Logos } from "../config/Logos";
/**
*
*/
@Component({
selector: "app-logo",
standalone: true,
imports: [],
templateUrl: "./logo.component.html",
styleUrl: "./logo.component.css"
})
export class LogoComponent implements OnInit {
@Input() logo: (typeof Logos)[number] = {} as never;
public link = "";
public alt = "";
public file = "";
/**
*
*/
ngOnInit(): void {
this.link = this.logo.link;
this.alt = this.logo.alt;
this.file = `/assets/img/${this.logo.file}`;
}
}

View File

@ -0,0 +1,4 @@
a {
font-size: 2rem;
margin: auto 10px;
}

View File

@ -0,0 +1,7 @@
<a
href="{{ social.link }}"
target="_blank"
rel="noopener noreferrer"
attr.aria-label="{{ social.label }}"
><fa-icon attr.alt="{{ social.alt }}" [icon]="social.icon"></fa-icon
></a>

View File

@ -0,0 +1,49 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Socials } from "../config/Socials";
import { SocialComponent } from "./social.component";
describe("SocialComponent", () => {
let component: SocialComponent;
let fixture: ComponentFixture<SocialComponent>;
let compiled: HTMLElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SocialComponent]
}).compileComponents();
fixture = TestBed.createComponent(SocialComponent);
component = fixture.componentInstance;
});
for (const expected of Socials) {
it(`should parse ${expected.label} properties correctly`, () => {
component.social = expected;
fixture.detectChanges();
expect(component.social).toBe(expected);
expect(component.link).toBe(expected.link);
expect(component.alt).toBe(expected.alt);
expect(component.icon).toEqual(expected.icon);
expect(component.label).toBe(expected.label);
});
it("should render an icon correctly", () => {
component.social = expected;
fixture.detectChanges();
compiled = fixture.nativeElement;
const link = compiled.querySelector("a");
expect(link?.href).toContain(expected.link);
expect(link?.rel).toBe("noopener noreferrer");
expect(link?.target).toBe("_blank");
expect(link?.ariaLabel).toBe(expected.label);
const icon = compiled.querySelector("fa-icon");
const svg = icon?.querySelector("svg");
const path = svg?.querySelector("path");
expect(path?.getAttribute("d")).toBe(expected.icon.icon[4] as string);
});
}
});

View File

@ -0,0 +1,33 @@
import { Component, Input, OnInit } from "@angular/core";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { Socials } from "../config/Socials";
/**
*
*/
@Component({
selector: "app-social",
standalone: true,
imports: [FontAwesomeModule],
templateUrl: "./social.component.html",
styleUrl: "./social.component.css"
})
export class SocialComponent implements OnInit {
@Input() social: (typeof Socials)[number] = {} as never;
public link = "";
public label = "";
public alt = "";
public icon: IconDefinition = {} as never;
/**
*
*/
ngOnInit(): void {
this.link = this.social.link;
this.label = this.social.label;
this.alt = this.social.alt;
this.icon = this.social.icon;
}
}

View File

@ -0,0 +1,28 @@
.timeline {
position: relative;
max-width: 1200px;
margin: auto;
}
.desc {
max-width: 1200px;
margin: auto;
font-size: 1.5rem;
}
.timeline::after {
content: "";
position: absolute;
width: 6px;
background-color: var(--text);
top: 0;
bottom: 0;
left: 50%;
margin-left: -3px;
}
@media screen and (max-width: 600px) {
.timeline::after {
left: 31px;
}
}

View File

@ -0,0 +1,13 @@
<h2>All Work</h2>
<p class="desc">
Here you can see a timeline of all of my client work. Items without an end
date (green items) are roles I am still in.
</p>
<div class="timeline">
<div *ngFor="let job of employment">
<app-job
[job]="job"
[align]="employment.indexOf(job) % 2 ? 'right' : 'left'"
/>
</div>
</div>

View File

@ -0,0 +1,38 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Employment } from "../config/Employment";
import { TimelineComponent } from "./timeline.component";
describe("TimelineComponent", () => {
let component: TimelineComponent;
let fixture: ComponentFixture<TimelineComponent>;
let compiled: HTMLElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TimelineComponent]
}).compileComponents();
fixture = TestBed.createComponent(TimelineComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should have expected properties", () => {
expect(component.employment).toEqual(
Employment.sort((a, b) => b.start.getTime() - a.start.getTime())
);
});
it("should render timeline correctly", () => {
compiled = fixture.nativeElement;
const jobs = compiled.querySelectorAll("app-job");
expect(jobs).toHaveSize(Employment.length);
for (let i = 0; i < component.employment.length; i++) {
const job = jobs[i];
const title = job.querySelector("h2");
expect(title?.textContent).toBe(component.employment[i].title);
}
});
});

View File

@ -0,0 +1,21 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { Employment } from "../config/Employment";
import { JobComponent } from "../job/job.component";
/**
*
*/
@Component({
selector: "app-timeline",
standalone: true,
imports: [CommonModule, JobComponent],
templateUrl: "./timeline.component.html",
styleUrl: "./timeline.component.css"
})
export class TimelineComponent {
public employment = Employment.sort(
(a, b) => b.start.getTime() - a.start.getTime()
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -3,10 +3,17 @@
--text: #ff94fd;
}
@font-face {
font-family: "odudo";
src: url("/assets/fonts/odudo.otf");
font-display: swap;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: "odudo", Courier, monospace;
}
a,