Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/images/recommendation/grant-riggle.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 0 additions & 12 deletions src/components/AccessibleDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,3 @@ onBeforeUnmount(() => {
}
});
</script>

<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
15 changes: 15 additions & 0 deletions src/css/support/blog.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
@apply after:right-0 after:top-0 after:bottom-0;
}

.blog-side-nav-icon {
@apply size-5 flex-none;
}

.blog-side-nav-router-link-a-resting {
@apply text-slate-200 hover:text-fuchsia-500 hover:after:bg-fuchsia-600;
@apply dark:text-slate-700 dark:hover:text-teal-600 dark:hover:after:bg-teal-600;
Expand Down Expand Up @@ -205,3 +209,14 @@
@apply shadow-sm dark:shadow-none rounded-md;
max-width: 100%;
}

/* --- transitions --- */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
20 changes: 12 additions & 8 deletions src/pages/AboutPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@

<div class="mt-5 space-y-5">
<h2 class="h2 font-aspekta text-slate-700 dark:text-slate-300">Let's Connect</h2>
<p v-if="profile">
I’m happy to connect by
<a v-lazy-link class="blog-link" title="send me an email" aria-label="send me an email" :href="`mailto:${profile.email}`"> email </a>
to discuss projects and ideas. While I’m not always available for freelance or long-term work, please don’t hesitate to reach out anytime.
</p>
<AboutConnectSkeletonPartial v-else class="min-h-[25rem]" />
<transition name="fade" mode="out-in" appear>
<p v-if="profile" key="connect">
I'm happy to connect by
<a v-lazy-link class="blog-link" title="send me an email" aria-label="send me an email" :href="`mailto:${profile.email}`"> email </a>
to discuss projects and ideas. While I'm not always available for freelance or long-term work, please don't hesitate to reach out anytime.
</p>
<AboutConnectSkeletonPartial v-else key="skeleton" class="min-h-[25rem]" />
</transition>
</div>
</div>
</section>
Expand All @@ -69,8 +71,10 @@
<aside class="md:w-[240px] lg:w-[300px] shrink-0">
<div class="space-y-6">
<WidgetSocialPartial />
<WidgetSkillsSkeletonPartial v-if="isLoadingProfile || !profile" />
<WidgetSkillsPartial v-else :skills="profile.skills" />
<transition name="fade" mode="out-in" appear>
<WidgetSkillsSkeletonPartial v-if="isLoadingProfile || !profile" key="skeleton" />
<WidgetSkillsPartial v-else key="skills" :skills="profile.skills" />
</transition>
</div>
</aside>
</div>
Expand Down
10 changes: 4 additions & 6 deletions src/pages/HomePage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@
<aside class="md:w-[240px] lg:w-[300px] shrink-0">
<div class="space-y-6">
<WidgetOullinPartial />
<template v-if="isLoadingProfile || !profile">
<WidgetSkillsSkeletonPartial />
</template>
<template v-else>
<WidgetSkillsPartial :skills="profile.skills" />
</template>
<transition name="fade" mode="out-in" appear>
<WidgetSkillsSkeletonPartial v-if="isLoadingProfile || !profile" key="skeleton" />
<WidgetSkillsPartial v-else key="skills" :skills="profile.skills" />
</transition>
<WidgetSponsorPartial />
</div>
</aside>
Expand Down
193 changes: 99 additions & 94 deletions src/pages/PostPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,102 +27,107 @@
</RouterLink>
</div>

<PostPageSkeletonPartial v-if="isLoading" class="min-h-[25rem]" />

<article v-else-if="post">
<!-- Post header -->
<header>
<div class="flex items-center justify-between mb-1">
<!-- Post date -->
<div class="text-xs text-slate-500 uppercase">
<span class="text-fuchsia-500 dark:text-teal-600">—</span> {{ date().format(new Date(post.published_at)) }}
<span class="text-slate-400 dark:text-slate-600">·</span>
{{ getReadingTime(post.content) }}
<transition name="fade" mode="out-in" appear>
<PostPageSkeletonPartial v-if="isLoading" key="skeleton" class="min-h-[25rem]" />

<article v-else-if="post" key="post">
<!-- Post header -->
<header>
<div class="flex items-center justify-between mb-1">
<!-- Post date -->
<div class="text-xs text-slate-500 uppercase">
<span class="text-fuchsia-500 dark:text-teal-600">—</span> {{ date().format(new Date(post.published_at)) }}
<span class="text-slate-400 dark:text-slate-600">·</span>
{{ getReadingTime(post.content) }}
</div>
<!-- Share buttons -->
<ul class="inline-flex">
<li>
<a
v-lazy-link
class="flex justify-center items-center text-slate-400 dark:text-slate-500 hover:text-fuchsia-500 dark:hover:text-teal-600 transition duration-150 ease-in-out"
:href="xURLFor(post)"
aria-label="Twitter"
target="_blank"
rel="noopener noreferrer"
>
<svg class="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="m13.063 9 3.495 4.475L20.601 9h2.454l-5.359 5.931L24 23h-4.938l-3.866-4.893L10.771 23H8.316l5.735-6.342L8 9h5.063Zm-.74 1.347h-1.457l8.875 11.232h1.36l-8.778-11.232Z"
></path>
</svg>
</a>
</li>
<li>
<a
v-lazy-link
class="flex justify-center items-center text-slate-400 dark:text-slate-500 hover:text-fuchsia-500 dark:hover:text-teal-600 transition duration-150 ease-in-out"
:href="`https://www.linkedin.com/sharing/share-offsite/?url=${fullURLFor(post)}`"
aria-label="LinkedIn"
target="_blank"
rel="noopener noreferrer"
>
<svg class="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M24,24H20V18.33c0-1.41-.5-2.37-1.75-2.37a1.9,1.9,0,0,0-1.75,1.25c-.06.44-.08,1.06-.08,1.69V24H12V12h4v1.73a3.86,3.86,0,0,1,3.47-1.93c2.52,0,4.53,1.65,4.53,5.15V24ZM8,10a2,2,0,1,1,2-2A2,2,0,0,1,8,10ZM6,24H10V12H6Z"
/>
</svg>
</a>
</li>
<li>
<a
v-lazy-link
class="flex justify-center items-center text-slate-400 dark:text-slate-500 hover:text-fuchsia-500 dark:hover:text-teal-600 transition duration-150 ease-in-out"
href="#"
aria-label="Share"
@click.prevent="sharePost(post)"
>
<svg class="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M20 14c1.654 0 3-1.346 3-3s-1.346-3-3-3-3 1.346-3 3c0 .223.029.439.075.649l-3.22 2.012A2.97 2.97 0 0 0 12 13c-1.654 0-3 1.346-3 3s1.346 3 3 3a2.97 2.97 0 0 0 1.855-.661l3.22 2.012c-.046.21-.075.426-.075.649 0 1.654 1.346 3 3 3s3-1.346 3-3-1.346-3-3-3a2.97 2.97 0 0 0-1.855.661l-3.22-2.012c.046-.21.075-.426.075-.649 0-.223-.029-.439-.075-.649l3.22-2.012A2.97 2.97 0 0 0 20 14Z"
></path>
</svg>
</a>
</li>
</ul>
</div>
<!-- Share buttons -->
<ul class="inline-flex">
<li>
<a
v-lazy-link
class="flex justify-center items-center text-slate-400 dark:text-slate-500 hover:text-fuchsia-500 dark:hover:text-teal-600 transition duration-150 ease-in-out"
:href="xURLFor(post)"
aria-label="Twitter"
target="_blank"
rel="noopener noreferrer"
>
<svg class="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="m13.063 9 3.495 4.475L20.601 9h2.454l-5.359 5.931L24 23h-4.938l-3.866-4.893L10.771 23H8.316l5.735-6.342L8 9h5.063Zm-.74 1.347h-1.457l8.875 11.232h1.36l-8.778-11.232Z"
></path>
</svg>
</a>
</li>
<li>
<a
v-lazy-link
class="flex justify-center items-center text-slate-400 dark:text-slate-500 hover:text-fuchsia-500 dark:hover:text-teal-600 transition duration-150 ease-in-out"
:href="`https://www.linkedin.com/sharing/share-offsite/?url=${fullURLFor(post)}`"
aria-label="LinkedIn"
target="_blank"
rel="noopener noreferrer"
>
<svg class="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M24,24H20V18.33c0-1.41-.5-2.37-1.75-2.37a1.9,1.9,0,0,0-1.75,1.25c-.06.44-.08,1.06-.08,1.69V24H12V12h4v1.73a3.86,3.86,0,0,1,3.47-1.93c2.52,0,4.53,1.65,4.53,5.15V24ZM8,10a2,2,0,1,1,2-2A2,2,0,0,1,8,10ZM6,24H10V12H6Z"
/>
</svg>
</a>
</li>
<li>
<a
v-lazy-link
class="flex justify-center items-center text-slate-400 dark:text-slate-500 hover:text-fuchsia-500 dark:hover:text-teal-600 transition duration-150 ease-in-out"
href="#"
aria-label="Share"
@click.prevent="sharePost(post)"
>
<svg class="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M20 14c1.654 0 3-1.346 3-3s-1.346-3-3-3-3 1.346-3 3c0 .223.029.439.075.649l-3.22 2.012A2.97 2.97 0 0 0 12 13c-1.654 0-3 1.346-3 3s1.346 3 3 3a2.97 2.97 0 0 0 1.855-.661l3.22 2.012c-.046.21-.075.426-.075.649 0 1.654 1.346 3 3 3s3-1.346 3-3-1.346-3-3-3a2.97 2.97 0 0 0-1.855.661l-3.22-2.012c.046-.21.075-.426.075-.649 0-.223-.029-.439-.075-.649l3.22-2.012A2.97 2.97 0 0 0 20 14Z"
></path>
</svg>
</a>
</li>
</ul>

<h1 id="post-top" class="h1 font-aspekta mb-4">{{ post.title }}</h1>

<nav
v-if="post.tags?.length"
class="mt-6 mb-6 text-xs font-semibold uppercase tracking-wide text-slate-600 dark:text-slate-300"
aria-label="Post tags"
data-testid="post-tags"
>
<ul class="flex flex-wrap items-center gap-y-1">
<li v-for="(tag, index) in post.tags" :key="tag.uuid" class="flex items-center">
<RouterLink
:to="Tags.routeFor(tag.name)"
data-testid="post-tag"
class="transition-colors hover:text-fuchsia-500 dark:hover:text-teal-500"
@click="handleTagClick(tag.name)"
>
{{ Tags.formatLabel(tag.name) }}
</RouterLink>
<span v-if="index < post.tags.length - 1" class="mx-2 text-slate-400 dark:text-slate-600" aria-hidden="true" data-testid="post-tag-separator">
/
</span>
</li>
</ul>
</nav>
</header>

<!-- Post content -->
<div class="text-slate-500 dark:text-slate-400 space-y-8">
<p>{{ post.excerpt }}</p>
<CoverImageLoader class="w-full aspect-[16/9]" :src="post.cover_image_url || ''" :alt="post.title" :width="692" :height="390" />
<div ref="postContainer" class="post-markdown" v-html="htmlContent"></div>
</div>
<h1 id="post-top" class="h1 font-aspekta mb-4">{{ post.title }}</h1>
<nav
v-if="post.tags?.length"
class="mt-6 text-xs font-semibold uppercase tracking-wide text-slate-600 dark:text-slate-300"
aria-label="Post tags"
data-testid="post-tags"
>
<ul class="flex flex-wrap items-center gap-y-1">
<li v-for="(tag, index) in post.tags" :key="tag.uuid" class="flex items-center">
<RouterLink
:to="Tags.routeFor(tag.name)"
data-testid="post-tag"
class="transition-colors hover:text-fuchsia-500 dark:hover:text-teal-500"
@click="handleTagClick(tag.name)"
>
{{ Tags.formatLabel(tag.name) }}
</RouterLink>
<span v-if="index < post.tags.length - 1" class="mx-2 text-slate-400 dark:text-slate-600" aria-hidden="true" data-testid="post-tag-separator">
/
</span>
</li>
</ul>
</nav>
</header>
<!-- Post content -->
<div class="text-slate-500 dark:text-slate-400 space-y-8">
<p>{{ post.excerpt }}</p>
<CoverImageLoader class="w-full aspect-[16/9]" :src="post.cover_image_url || ''" :alt="post.title" :width="692" :height="390" />
<div ref="postContainer" class="post-markdown" v-html="htmlContent"></div>
</div>
</article>

<p v-else class="text-slate-500 dark:text-slate-400">We couldn't load this post.</p>
</article>

<p v-else key="error" class="text-slate-500 dark:text-slate-400">We couldn't load this post.</p>
</transition>
</div>
</div>

Expand Down
33 changes: 19 additions & 14 deletions src/pages/ProjectsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<div class="space-y-10">
<div class="mb-5">
<p>
Over the years, Ive built and shared command-line tools and frameworks to tackle real engineering challenges—complete with clear docs and automated
Over the years, I've built and shared command-line tools and frameworks to tackle real engineering challenges—complete with clear docs and automated
tests—and partnered with banks, insurers, and fintech to deliver custom software that balances performance, security, and scalability.
</p>
<p class="mt-2">
Expand All @@ -30,17 +30,20 @@
</div>
<section>
<h2 class="font-aspekta text-xl font-[650] mb-6">Open Source / Client Projects</h2>
<div
data-testid="projects-skeleton-grid"
class="grid sm:grid-cols-2 md:grid-cols-1 lg:grid-cols-2 gap-5"
:class="{ 'min-h-[25rem]': isLoadingProjects || projects.length === 0 }"
>
<template v-if="isLoadingProjects || projects.length === 0">
<ProjectCardSkeletonPartial v-for="index in 4" :key="`projects-page-skeleton-${index}`" :is-animated="isLoadingProjects && projects.length === 0" />
</template>
<template v-else>
<ProjectCardPartial v-for="project in projects" :key="project.uuid" :item="project" />
</template>
<div data-testid="projects-skeleton-grid" class="grid sm:grid-cols-2 md:grid-cols-1 lg:grid-cols-2 gap-5 min-h-[25rem]">
<transition name="fade" mode="out-in" appear>
<div v-if="isLoadingProjects" key="loading" class="contents">
<ProjectCardSkeletonPartial
v-for="index in 4"
:key="`projects-page-skeleton-${index}`"
:is-animated="isLoadingProjects && projects.length === 0"
/>
</div>
<div v-else-if="projects.length > 0" key="projects" class="contents">
<ProjectCardPartial v-for="project in projects" :key="project.uuid" :item="project" />
</div>
<p v-else key="empty" class="col-span-full text-sm text-slate-500 dark:text-slate-400">Projects will be added soon. Check back later!</p>
</transition>
</div>
</section>
</div>
Expand All @@ -52,8 +55,10 @@
<aside class="md:w-[240px] lg:w-[300px] shrink-0">
<div class="space-y-6">
<WidgetSponsorPartial />
<WidgetSkillsSkeletonPartial v-if="isLoadingProfile || !profile" />
<WidgetSkillsPartial v-else :skills="profile.skills" />
<transition name="fade" mode="out-in" appear>
<WidgetSkillsSkeletonPartial v-if="isLoadingProfile || !profile" key="skeleton" />
<WidgetSkillsPartial v-else key="skills" :skills="profile.skills" />
</transition>
</div>
</aside>
</div>
Expand Down
Loading