feat: implement dark mode support, update writing route logic, and add content entry placeholder

This commit is contained in:
Jaron
2026-05-12 19:12:41 -05:00
parent ab8eb9ab86
commit 60b5319909
12 changed files with 101 additions and 41 deletions
+1 -17
View File
@@ -2,23 +2,7 @@
import '~/assets/css/main.css'; import '~/assets/css/main.css';
useHead({ useHead({
link: [ link: [{ rel: 'icon', type: 'image/png', href: '/favicon.png' }],
{ rel: 'icon', type: 'image/png', href: '/favicon.png' },
// { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
// {
// rel: 'preconnect',
// href: 'https://fonts.gstatic.com',
// crossorigin: '',
// },
// {
// rel: 'stylesheet',
// href: 'https://fonts.googleapis.com/css2?family=Baskervville:ital,wght@0,400..700;1,400..700&display=swap',
// },
// {
// rel: 'stylesheet',
// href: 'https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&display=swap',
// },
],
}); });
onMounted(() => {}); onMounted(() => {});
Binary file not shown.
+20 -3
View File
@@ -4,14 +4,31 @@
/* --font: 'Baskervville', serif; */ /* --font: 'Baskervville', serif; */
/* --font: 'EB Garamond', serif; */ /* --font: 'EB Garamond', serif; */
/* --font: 'Plantin MT Pro', serif; */ /* --font: 'Plantin MT Pro', serif; */
--font: 'Redaction', serif;
/* --font: 'Young Serif', serif; */ /* --font: 'Young Serif', serif; */
/* --font: "SohneBuch", sans-serif; */ /* --font: "SohneBuch", sans-serif; */
--font: 'Redaction', serif;
--font-hover: 'Redaction 70', serif; --font-hover: 'Redaction 70', serif;
/* --font-hover: var(--font); */ /* --font-hover: var(--font); */
--text: #333; --text: #333;
--muted: #666; --muted: #666;
--bg: #fbfbf7; --bg: #fbfbf7;
--color-white-500: #fbfbf7;
--gap: 1rem;
}
::selection {
background: var(--text);
color: var(--bg);
}
.dark-mode {
--text: #fbfbf7;
--bg: #111111;
--muted: #d1d1d1;
--color-white-500: #fbfbf7;
} }
.flex { .flex {
@@ -70,12 +87,12 @@ body {
display: inline-block; display: inline-block;
vertical-align: bottom; vertical-align: bottom;
position: relative; position: relative;
color: var(--bg); color: var(--color-white-500);
text-decoration: none; text-decoration: none;
transition: all 200ms ease; transition: all 200ms ease;
padding: 0 4px; padding: 0 4px;
margin: 0 -4px; margin: 0 -4px;
background-image: linear-gradient(var(--bg), var(--bg)); background-image: linear-gradient(var(--color-white-500), var(--color-white-500));
background-size: 100% 1px; background-size: 100% 1px;
background-position: bottom; background-position: bottom;
background-repeat: no-repeat; background-repeat: no-repeat;
+34 -7
View File
@@ -3,6 +3,12 @@ defineProps<{
title?: string; title?: string;
description?: string; description?: string;
}>(); }>();
const theme = useColorMode();
const toggleTheme = () => {
theme.preference = theme.preference === 'light' ? 'dark' : 'light';
};
</script> </script>
<template> <template>
@@ -27,14 +33,20 @@ defineProps<{
<div class="header-upper"> <div class="header-upper">
<slot name="header-upper"> <slot name="header-upper">
<div class="flex-center header-upper-nav"> <div class="flex-center header-upper-nav">
<p style="font-family: monospace">🐟🎩.dev</p> <button
class="theme-toggle"
@click="toggleTheme"
v-if="!theme.unknown"
>
{{ theme.value === 'dark' ? '🌚' : '🌝' }}
</button>
<div class="flex-ff"></div> <div class="flex-ff"></div>
<!-- <NuxtLink to="/resume" class="basic-link" <!-- <NuxtLink to="/resume" class="basic-link"
>Resume</NuxtLink >Resume</NuxtLink
> --> > -->
<NuxtLink to="/writing" class="basic-link" <!-- <NuxtLink to="/writing" class="basic-link">
>Writing</NuxtLink Writing
> </NuxtLink> -->
</div> </div>
</slot> </slot>
</div> </div>
@@ -71,8 +83,9 @@ defineProps<{
</div> </div>
</div> </div>
<div class="footer-lower"> <div class="footer-lower">
<div class="flex-center"> <div class="flex-center" style="gap: var(--gap)">
<p style="text-align: right">Est. 2003</p> <p style="text-align: right">Est. 2003</p>
<!-- <p style="font-family: monospace">🐟🎩.dev</p> -->
<div class="flex-ff"></div> <div class="flex-ff"></div>
<p style="text-align: right">Austin, TX</p> <p style="text-align: right">Austin, TX</p>
</div> </div>
@@ -158,7 +171,7 @@ svg[height='0'] {
border-top: 1px solid var(--muted); border-top: 1px solid var(--muted);
border-bottom: 1px solid var(--muted); border-bottom: 1px solid var(--muted);
padding: 2rem; padding: 2rem;
color: var(--bg); color: var(--color-white-500);
position: relative; position: relative;
isolation: isolate; isolation: isolate;
@@ -180,7 +193,7 @@ svg[height='0'] {
border-top: 1px solid var(--muted); border-top: 1px solid var(--muted);
border-bottom: 1px solid var(--muted); border-bottom: 1px solid var(--muted);
padding: 2rem; padding: 2rem;
color: var(--bg); color: var(--color-white-500);
min-height: 10vh; min-height: 10vh;
position: relative; position: relative;
isolation: isolate; isolation: isolate;
@@ -205,6 +218,20 @@ svg[height='0'] {
gap: 1rem; gap: 1rem;
} }
.theme-toggle {
background: transparent;
border: none;
cursor: pointer;
font-size: large;
font-weight: bold;
color: var(--text);
transition: opacity 0.2s ease;
}
.theme-toggle:hover {
opacity: 0.5;
}
@media (max-width: 1024px) { @media (max-width: 1024px) {
.page-wrapper { .page-wrapper {
--main-width: 80vw; --main-width: 80vw;
+13 -6
View File
@@ -73,11 +73,18 @@ definePageMeta({
<h5>About</h5> <h5>About</h5>
<div class="section__content"> <div class="section__content">
<p> <p>
I work across the full stack; backend, frontend, and I enjoy the entire process of building things; backend,
product. My favorite side projects are ones that bring me frontend, product, etc.
new skills. Even better are ones where I solve a problem or </p>
build a tool I can use. I'm always open to interesting work <p>
and conversations. I left school and my job at Chick-fil-A in 2022 to write
code full time. It's definitely one of the best decisions
I've ever made. I've learned so much since then and
<em>still</em> have so much more to learn.
</p>
<p>
If you want to build something cool or connect hit me up! I
still dont know enough people to form a band yet ;)
</p> </p>
</div> </div>
</section> </section>
@@ -300,7 +307,7 @@ section:last-of-type {
font-size: small; font-size: small;
} }
.about p { .about p:last-child {
margin: 0; margin: 0;
} }
+3 -1
View File
@@ -1,7 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
const route = useRoute(); const route = useRoute();
const { data: page } = await useAsyncData(route.path, () => { const { data: page } = await useAsyncData(route.path, () => {
return queryCollection('writing').path(route.path).first(); return queryCollection('writing')
.path(route.path.replace('/writing/', ''))
.first();
}); });
if (!page.value) { if (!page.value) {
+5 -5
View File
@@ -27,20 +27,20 @@ const formatDate = (dateString: string) => {
<section> <section>
<div class="section__content"> <div class="section__content">
<template v-if="pages?.length"> <template v-if="pages?.length">
<a <NuxtLink
v-for="page in pages" v-for="page in pages"
:href="page.path" :to="'/writing/' + page.path"
:key="page.path" :key="page.path"
class="article" class="article"
> >
<h3 class="article__title">{{ page.title }}</h3> <h3 class="article__title">{{ page.title }}</h3>
<p class="article__date"> <!-- <p class="article__date">
{{ formatDate(page.date) }} {{ formatDate(page.date) }}
</p> </p> -->
<p class="article__description"> <p class="article__description">
{{ page.description }} {{ page.description }}
</p> </p>
</a> </NuxtLink>
</template> </template>
<template v-else> <template v-else>
<div class="empty-state"> <div class="empty-state">
+3
View File
@@ -13,6 +13,7 @@
"wrangler": "^4.86.0", "wrangler": "^4.86.0",
}, },
"devDependencies": { "devDependencies": {
"@nuxtjs/color-mode": "^4.0.0",
"prettier": "^3.8.3", "prettier": "^3.8.3",
}, },
}, },
@@ -262,6 +263,8 @@
"@nuxt/vite-builder": ["@nuxt/vite-builder@4.4.2", "", { "dependencies": { "@nuxt/kit": "4.4.2", "@rollup/plugin-replace": "^6.0.3", "@vitejs/plugin-vue": "^6.0.4", "@vitejs/plugin-vue-jsx": "^5.1.4", "autoprefixer": "^10.4.27", "consola": "^3.4.2", "cssnano": "^7.1.3", "defu": "^6.1.4", "escape-string-regexp": "^5.0.0", "exsolve": "^1.0.8", "get-port-please": "^3.2.0", "jiti": "^2.6.1", "knitwork": "^1.3.0", "magic-string": "^0.30.21", "mlly": "^1.8.1", "mocked-exports": "^0.1.1", "nypm": "^0.6.5", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "postcss": "^8.5.8", "seroval": "^1.5.1", "std-env": "^4.0.0", "ufo": "^1.6.3", "unenv": "^2.0.0-rc.24", "vite": "^7.3.1", "vite-node": "^5.3.0", "vite-plugin-checker": "^0.12.0", "vue-bundle-renderer": "^2.2.0" }, "peerDependencies": { "@babel/plugin-proposal-decorators": "^7.25.0", "@babel/plugin-syntax-jsx": "^7.25.0", "nuxt": "4.4.2", "rolldown": "^1.0.0-beta.38", "rollup-plugin-visualizer": "^6.0.0 || ^7.0.1", "vue": "^3.3.4" }, "optionalPeers": ["@babel/plugin-proposal-decorators", "@babel/plugin-syntax-jsx", "rolldown", "rollup-plugin-visualizer"] }, "sha512-fJaIwMA8ID6BU5EqmoDvnhq4qYDJeWjdHk4jfqy8D3Nm7CoUW0BvX7Ee92XoO05rtUiClGlk/NQ1Ii8hs3ZIbw=="], "@nuxt/vite-builder": ["@nuxt/vite-builder@4.4.2", "", { "dependencies": { "@nuxt/kit": "4.4.2", "@rollup/plugin-replace": "^6.0.3", "@vitejs/plugin-vue": "^6.0.4", "@vitejs/plugin-vue-jsx": "^5.1.4", "autoprefixer": "^10.4.27", "consola": "^3.4.2", "cssnano": "^7.1.3", "defu": "^6.1.4", "escape-string-regexp": "^5.0.0", "exsolve": "^1.0.8", "get-port-please": "^3.2.0", "jiti": "^2.6.1", "knitwork": "^1.3.0", "magic-string": "^0.30.21", "mlly": "^1.8.1", "mocked-exports": "^0.1.1", "nypm": "^0.6.5", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "postcss": "^8.5.8", "seroval": "^1.5.1", "std-env": "^4.0.0", "ufo": "^1.6.3", "unenv": "^2.0.0-rc.24", "vite": "^7.3.1", "vite-node": "^5.3.0", "vite-plugin-checker": "^0.12.0", "vue-bundle-renderer": "^2.2.0" }, "peerDependencies": { "@babel/plugin-proposal-decorators": "^7.25.0", "@babel/plugin-syntax-jsx": "^7.25.0", "nuxt": "4.4.2", "rolldown": "^1.0.0-beta.38", "rollup-plugin-visualizer": "^6.0.0 || ^7.0.1", "vue": "^3.3.4" }, "optionalPeers": ["@babel/plugin-proposal-decorators", "@babel/plugin-syntax-jsx", "rolldown", "rollup-plugin-visualizer"] }, "sha512-fJaIwMA8ID6BU5EqmoDvnhq4qYDJeWjdHk4jfqy8D3Nm7CoUW0BvX7Ee92XoO05rtUiClGlk/NQ1Ii8hs3ZIbw=="],
"@nuxtjs/color-mode": ["@nuxtjs/color-mode@4.0.0", "", { "dependencies": { "@nuxt/kit": "^4.2.1", "exsolve": "^1.0.8", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "semver": "^7.7.3" } }, "sha512-xyaVR/TPLdMuRa2VOgH6b75jvmFEsn9QKL6ISldaAw38ooFJfWY1ts2F3ye43wcT/goCbcuvPuskF2f8yUZhlw=="],
"@nuxtjs/mdc": ["@nuxtjs/mdc@0.21.1", "", { "dependencies": { "@nuxt/kit": "^4.4.2", "@shikijs/core": "^4.0.2", "@shikijs/engine-javascript": "^4.0.2", "@shikijs/langs": "^4.0.2", "@shikijs/themes": "^4.0.2", "@shikijs/transformers": "^4.0.2", "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", "@vue/compiler-core": "^3.5.31", "consola": "^3.4.2", "debug": "^4.4.3", "defu": "^6.1.4", "destr": "^2.0.5", "detab": "^3.0.2", "github-slugger": "^2.0.0", "hast-util-format": "^1.1.0", "hast-util-to-mdast": "^10.1.2", "hast-util-to-string": "^3.0.1", "mdast-util-to-hast": "^13.2.1", "micromark-util-sanitize-uri": "^2.0.1", "parse5": "^8.0.0", "pathe": "^2.0.3", "property-information": "^7.1.0", "rehype-external-links": "^3.0.0", "rehype-minify-whitespace": "^6.0.2", "rehype-raw": "^7.0.0", "rehype-remark": "^10.0.1", "rehype-slug": "^6.0.0", "rehype-sort-attribute-values": "^5.0.1", "rehype-sort-attributes": "^5.0.1", "remark-emoji": "^5.0.2", "remark-gfm": "^4.0.1", "remark-mdc": "^3.10.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-stringify": "^11.0.0", "scule": "^1.3.0", "shiki": "^4.0.2", "ufo": "^1.6.3", "unified": "^11.0.5", "unist-builder": "^4.0.0", "unist-util-visit": "^5.1.0", "unwasm": "^0.5.3", "vfile": "^6.0.3" } }, "sha512-DIeUD7IahWVUSoZExysxH9dX51Io6hcQYgGJODq0cMTGqaoDD32lRfHBJxYUmy+sUCV1+1hfa2ixspgJgEd2GA=="], "@nuxtjs/mdc": ["@nuxtjs/mdc@0.21.1", "", { "dependencies": { "@nuxt/kit": "^4.4.2", "@shikijs/core": "^4.0.2", "@shikijs/engine-javascript": "^4.0.2", "@shikijs/langs": "^4.0.2", "@shikijs/themes": "^4.0.2", "@shikijs/transformers": "^4.0.2", "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", "@vue/compiler-core": "^3.5.31", "consola": "^3.4.2", "debug": "^4.4.3", "defu": "^6.1.4", "destr": "^2.0.5", "detab": "^3.0.2", "github-slugger": "^2.0.0", "hast-util-format": "^1.1.0", "hast-util-to-mdast": "^10.1.2", "hast-util-to-string": "^3.0.1", "mdast-util-to-hast": "^13.2.1", "micromark-util-sanitize-uri": "^2.0.1", "parse5": "^8.0.0", "pathe": "^2.0.3", "property-information": "^7.1.0", "rehype-external-links": "^3.0.0", "rehype-minify-whitespace": "^6.0.2", "rehype-raw": "^7.0.0", "rehype-remark": "^10.0.1", "rehype-slug": "^6.0.0", "rehype-sort-attribute-values": "^5.0.1", "rehype-sort-attributes": "^5.0.1", "remark-emoji": "^5.0.2", "remark-gfm": "^4.0.1", "remark-mdc": "^3.10.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-stringify": "^11.0.0", "scule": "^1.3.0", "shiki": "^4.0.2", "ufo": "^1.6.3", "unified": "^11.0.5", "unist-builder": "^4.0.0", "unist-util-visit": "^5.1.0", "unwasm": "^0.5.3", "vfile": "^6.0.3" } }, "sha512-DIeUD7IahWVUSoZExysxH9dX51Io6hcQYgGJODq0cMTGqaoDD32lRfHBJxYUmy+sUCV1+1hfa2ixspgJgEd2GA=="],
"@oxc-minify/binding-android-arm-eabi": ["@oxc-minify/binding-android-arm-eabi@0.117.0", "", { "os": "android", "cpu": "arm" }, "sha512-5Hf2KsGRjxp3HnPU/mse7cQJa5tWfMFUPZQcgSMVsv2JZnGFFOIDzA0Oja2KDD+VPJqMpEJKc2dCHAGZgJxsGg=="], "@oxc-minify/binding-android-arm-eabi": ["@oxc-minify/binding-android-arm-eabi@0.117.0", "", { "os": "android", "cpu": "arm" }, "sha512-5Hf2KsGRjxp3HnPU/mse7cQJa5tWfMFUPZQcgSMVsv2JZnGFFOIDzA0Oja2KDD+VPJqMpEJKc2dCHAGZgJxsGg=="],
+4 -1
View File
@@ -4,7 +4,10 @@ export default defineContentConfig({
collections: { collections: {
writing: defineCollection({ writing: defineCollection({
type: 'page', type: 'page',
source: 'writing/**/*.md', source: {
include: 'writing/**/*.md',
prefix: '',
},
schema: z.object({ schema: z.object({
title: z.string(), title: z.string(),
date: z.coerce.date(), date: z.coerce.date(),
@@ -0,0 +1,7 @@
---
title: 'hot take: frontend developers are underpaid.'
date: 2026-05-03
description: that shit is hard
---
blah blah blah
+10 -1
View File
@@ -45,5 +45,14 @@ export default defineNuxtConfig({
}, },
}, },
modules: ['@nuxt/content'], modules: ['@nuxt/content', '@nuxtjs/color-mode'],
colorMode: {
preference: 'system', // default value of $colorMode.preference
fallback: 'light', // fallback value if not system preference found
globalName: '__NUXT_COLOR_MODE__',
componentName: 'ColorScheme',
classPrefix: '',
classSuffix: '-mode', // Results in .dark-mode or .light-mode
storageKey: 'color-mode',
},
}); });
+1
View File
@@ -19,6 +19,7 @@
"wrangler": "^4.86.0" "wrangler": "^4.86.0"
}, },
"devDependencies": { "devDependencies": {
"@nuxtjs/color-mode": "^4.0.0",
"prettier": "^3.8.3" "prettier": "^3.8.3"
} }
} }