mirror of
https://github.com/jaronpate/folio.git
synced 2026-10-19 01:07:39 +00:00
Add selected work section
This commit is contained in:
+265
-121
@@ -6,14 +6,142 @@ let sectionsRevealed = false;
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
useSeoMeta({
|
||||
title: "Hey, I'm Jaron.",
|
||||
ogTitle: "Hey, I'm Jaron.",
|
||||
description:
|
||||
'Software Engineer. I build things to solve problems from the ground up.',
|
||||
ogDescription:
|
||||
'Software Engineer. I build things to solve problems from the ground up.',
|
||||
ogUrl: useRequestURL().href,
|
||||
});
|
||||
|
||||
const titles = [
|
||||
"Hello, I'm Jaron.",
|
||||
"Hey, I'm Jaron.",
|
||||
'Nice to meet you.',
|
||||
'Welcome.',
|
||||
'Willkommen.',
|
||||
'Bienvenue.',
|
||||
];
|
||||
|
||||
const selectedWorks = [
|
||||
{
|
||||
title: 'Edlink',
|
||||
description:
|
||||
"I built many things I'm proud of at Edlink. Notably, I designed and shipped Edlink’s internal billing platform for ~150 clients, a flat file ingestion engine that enabled arbitrary data mapping, client-embedded UI widgets, user onboarding flows, and a secure sandbox for running untrusted code with a live data-preview service.",
|
||||
link: 'https://ed.link',
|
||||
images: [
|
||||
{
|
||||
src: '/work/edlink/embedded-onboarding.gif',
|
||||
alt: 'Embedded Onboarding',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/authentication-widget.gif',
|
||||
alt: 'Auth Widget',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/integration-sharing-rules-widget.png',
|
||||
alt: 'Data Sharing Editor Widget',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/billing-overview.png',
|
||||
alt: 'Billing Overview',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/invoice-sheet.png',
|
||||
alt: 'Invoice View',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/add-payment-method.png',
|
||||
alt: 'Add Payment Method',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/onboarding-select-provider.png',
|
||||
alt: 'Provider Selection',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/onboarding-edit-source.png',
|
||||
alt: 'Source Creation',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/onboarding-start.png',
|
||||
alt: 'Onboarding Start',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/custom-code-editor.png',
|
||||
alt: 'Custom Code Editor',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/edit-licensing-rules.png',
|
||||
alt: 'Licensing Editor',
|
||||
},
|
||||
{
|
||||
src: '/work/edlink/materialization-preview.png',
|
||||
alt: 'Pending Data Change Preview',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const projects = [
|
||||
{
|
||||
title: 'Unicord',
|
||||
href: 'https://unicord.hat.fish/',
|
||||
description: 'Discord bot SDK inspired by webserver architecture.',
|
||||
},
|
||||
{
|
||||
title: 'Mystwright',
|
||||
href: 'https://mystwright.com/',
|
||||
description:
|
||||
'An AI-driven mystery detective game. Generate, investigate, solve.',
|
||||
},
|
||||
{
|
||||
title: 'Rune Buddy',
|
||||
href: 'https://github.com/jaronpate/rift-buddy',
|
||||
description:
|
||||
'League of Legends runepage manager. Save & organise your pages for free.',
|
||||
},
|
||||
];
|
||||
|
||||
const photos = [
|
||||
{
|
||||
src: '/photography/athens_red_scooter.jpg',
|
||||
alt: 'Red scooter in Athens',
|
||||
location: 'Athens',
|
||||
year: '2026',
|
||||
},
|
||||
{
|
||||
src: '/photography/athens_subway.jpg',
|
||||
alt: 'Athens metro station',
|
||||
location: 'Athens',
|
||||
year: '2026',
|
||||
},
|
||||
{
|
||||
src: '/photography/athens_sunset.jpg',
|
||||
alt: 'Athens at sunset',
|
||||
location: 'Athens',
|
||||
year: '2026',
|
||||
},
|
||||
{
|
||||
src: '/photography/london_porsche.jpg',
|
||||
alt: 'Porsche shop in London',
|
||||
location: 'London',
|
||||
year: '2025',
|
||||
},
|
||||
{
|
||||
src: '/photography/underground.jpg',
|
||||
alt: 'Entrace to the London underground',
|
||||
location: 'London',
|
||||
year: '2026',
|
||||
},
|
||||
{
|
||||
src: '/photography/austin_parking.jpg',
|
||||
alt: 'Parking garage in Austin',
|
||||
location: 'Austin',
|
||||
year: '2024',
|
||||
},
|
||||
];
|
||||
|
||||
const pageTitle = ref(titles[0]);
|
||||
|
||||
const rotateTitle = () => {
|
||||
@@ -24,22 +152,6 @@ const rotateTitle = () => {
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
rotateTitle();
|
||||
|
||||
useHead({
|
||||
title: pageTitle,
|
||||
});
|
||||
|
||||
useSeoMeta({
|
||||
title: "Hey, I'm Jaron",
|
||||
ogTitle: "Hey, I'm Jaron",
|
||||
description:
|
||||
'Software Engineer. I build things to solve problems from the ground up.',
|
||||
ogDescription:
|
||||
'Software Engineer. I build things to solve problems from the ground up.',
|
||||
ogUrl: useRequestURL().href,
|
||||
});
|
||||
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
});
|
||||
@@ -48,6 +160,12 @@ const { $gsap } = useNuxtApp();
|
||||
const pageRoot = ref<HTMLElement | null>(null);
|
||||
|
||||
onMounted(() => {
|
||||
rotateTitle();
|
||||
|
||||
useHead({
|
||||
title: pageTitle,
|
||||
});
|
||||
|
||||
if (!$gsap || !pageRoot.value || sectionsRevealed) return;
|
||||
sectionsRevealed = true;
|
||||
|
||||
@@ -84,43 +202,45 @@ onMounted(() => {
|
||||
<template>
|
||||
<div ref="pageRoot">
|
||||
<NuxtLayout name="main">
|
||||
<!-- <section class="work">
|
||||
<section class="selected-work">
|
||||
<h5>Selected Work</h5>
|
||||
<div class="section__content"></div>
|
||||
</section> -->
|
||||
<div class="section__content">
|
||||
<a
|
||||
v-for="work in selectedWorks"
|
||||
:key="work.title"
|
||||
class="work"
|
||||
:href="work.link"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 class="work__title">{{ work.title }}</h3>
|
||||
<p class="work__description">
|
||||
{{ work.description }}
|
||||
</p>
|
||||
<div class="work__images">
|
||||
<figure
|
||||
v-for="image in work.images"
|
||||
:key="image.src"
|
||||
class="work__image"
|
||||
>
|
||||
<img :src="image.src" :alt="image.alt" />
|
||||
</figure>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="projects">
|
||||
<h5>Projects</h5>
|
||||
<div class="section__content">
|
||||
<a
|
||||
href="https://unicord.hat.fish/"
|
||||
v-for="project in projects"
|
||||
:key="project.href"
|
||||
:href="project.href"
|
||||
target="_blank"
|
||||
class="project"
|
||||
>
|
||||
<h3 class="project__title">Unicord</h3>
|
||||
<h3 class="project__title">{{ project.title }}</h3>
|
||||
<p class="project__description">
|
||||
Discord bot SDK inspired by webserver architecture.
|
||||
</p>
|
||||
</a>
|
||||
<a
|
||||
href="https://mystwright.com/"
|
||||
target="_blank"
|
||||
class="project"
|
||||
>
|
||||
<h3 class="project__title">Mystwright</h3>
|
||||
<p class="project__description">
|
||||
An AI-driven mystery detective game. Generate,
|
||||
investigate, solve.
|
||||
</p>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/jaronpate/rift-buddy"
|
||||
target="_blank"
|
||||
class="project"
|
||||
>
|
||||
<h3 class="project__title">Rune Buddy</h3>
|
||||
<p class="project__description">
|
||||
League of Legends runepage manager. Save & organise
|
||||
your pages for free.
|
||||
{{ project.description }}
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
@@ -147,76 +267,17 @@ onMounted(() => {
|
||||
<h5>Photos</h5>
|
||||
<div class="section__content">
|
||||
<div class="photo-grid">
|
||||
<div class="photo-grid__item">
|
||||
<div
|
||||
v-for="photo in photos"
|
||||
:key="photo.src"
|
||||
class="photo-grid__item"
|
||||
>
|
||||
<div class="photo__image">
|
||||
<img
|
||||
src="/photography/athens_red_scooter.jpg"
|
||||
alt="Red scooter in Athens"
|
||||
/>
|
||||
<img :src="photo.src" :alt="photo.alt" />
|
||||
</div>
|
||||
<div class="photo__overlay">
|
||||
<p>Athens</p>
|
||||
<p>2026</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="photo-grid__item">
|
||||
<div class="photo__image">
|
||||
<img
|
||||
src="/photography/athens_subway.jpg"
|
||||
alt="Athens metro station"
|
||||
/>
|
||||
</div>
|
||||
<div class="photo__overlay">
|
||||
<p>Athens</p>
|
||||
<p>2026</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="photo-grid__item">
|
||||
<div class="photo__image">
|
||||
<img
|
||||
src="/photography/athens_sunset.jpg"
|
||||
alt="Athens at sunset"
|
||||
/>
|
||||
</div>
|
||||
<div class="photo__overlay">
|
||||
<p>Athens</p>
|
||||
<p>2026</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="photo-grid__item">
|
||||
<div class="photo__image">
|
||||
<img
|
||||
src="/photography/london_porsche.jpg"
|
||||
alt="Porsche shop in London"
|
||||
/>
|
||||
</div>
|
||||
<div class="photo__overlay">
|
||||
<p>London</p>
|
||||
<p>2025</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="photo-grid__item">
|
||||
<div class="photo__image">
|
||||
<img
|
||||
src="/photography/underground.jpg"
|
||||
alt="Entrace to the London underground"
|
||||
/>
|
||||
</div>
|
||||
<div class="photo__overlay">
|
||||
<p>London</p>
|
||||
<p>2026</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="photo-grid__item">
|
||||
<div class="photo__image">
|
||||
<img
|
||||
src="/photography/austin_parking.jpg"
|
||||
alt="Parking garage in Austin"
|
||||
/>
|
||||
</div>
|
||||
<div class="photo__overlay">
|
||||
<p>Austin</p>
|
||||
<p>2024</p>
|
||||
<p>{{ photo.location }}</p>
|
||||
<p>{{ photo.year }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -268,19 +329,97 @@ section:last-of-type {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.project {
|
||||
border-bottom: 1px solid var(--muted);
|
||||
padding: 1rem 0;
|
||||
.work {
|
||||
}
|
||||
|
||||
.work__images {
|
||||
/*display: flex;
|
||||
flex-wrap: no-wrap;
|
||||
align-items: center;
|
||||
justify-content: center;*/
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: max-content;
|
||||
gap: var(--gap);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-top: var(--gap);
|
||||
}
|
||||
|
||||
.work__image {
|
||||
--dot-size: 6%;
|
||||
|
||||
margin: 0;
|
||||
/*padding: calc(var(--gap) * 2) var(--gap) var(--gap);*/
|
||||
padding: var(--gap);
|
||||
flex-shrink: 0;
|
||||
border-radius: var(--radius);
|
||||
background-image: radial-gradient(
|
||||
circle at 4px 4px,
|
||||
var(--dot-color) var(--dot-size),
|
||||
transparent calc(var(--dot-size) + 1%)
|
||||
);
|
||||
|
||||
background-position: 4px 4px;
|
||||
background-size: 12px 12px;
|
||||
background-repeat: repeat;
|
||||
background-color: var(--bg-secondary);
|
||||
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: var(--gap);
|
||||
}
|
||||
|
||||
.work__image img {
|
||||
border-radius: var(--radius);
|
||||
object-fit: cover;
|
||||
max-height: 350px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 750px) {
|
||||
.work__image img {
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.work__image figcaption {
|
||||
font-size: 0.6rem;
|
||||
line-height: 1;
|
||||
font-family: var(--font-plain);
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 2px;
|
||||
padding: 3px 4px;
|
||||
background: var(--dot-color);
|
||||
/*border: 1px solid var(--dot-color);*/
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.project,
|
||||
.work {
|
||||
/*border-bottom: 1px solid var(--muted);*/
|
||||
padding: var(--gap) 0;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.project:first-of-type {
|
||||
.work {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.project:first-of-type,
|
||||
.work:first-of-type {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.project:last-of-type {
|
||||
.project:last-of-type,
|
||||
.work:last-of-type {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -295,12 +434,15 @@ section:last-of-type {
|
||||
font-family: var(--font-hover);
|
||||
}
|
||||
|
||||
.project__title {
|
||||
.project__title,
|
||||
.work__title {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
margin-bottom: calc(var(--gap) * 0.5);
|
||||
}
|
||||
|
||||
.project__title::after {
|
||||
.project__title::after,
|
||||
.work__title::after {
|
||||
content: '↗';
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
@@ -314,12 +456,14 @@ section:last-of-type {
|
||||
transform 0.25s ease;
|
||||
}
|
||||
|
||||
.project:hover .project__title::after {
|
||||
.project:hover .project__title::after,
|
||||
.work:hover .work__title::after {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
.project__description {
|
||||
.project__description,
|
||||
.work__description {
|
||||
margin: 0;
|
||||
font-size: small;
|
||||
font-weight: 400;
|
||||
|
||||
Reference in New Issue
Block a user