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
4 changes: 2 additions & 2 deletions components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ const route = useRoute();
</HeadlessMenuItem>

<HeadlessMenuItem v-slot="{ active, close }">
<NuxtLink to="/articles">
<NuxtLink to="/blog">
<button
@click="close"
:class="[
active
? 'bg-orange-500/50 text-white dark:text-white'
: 'text-gray-700 dark:text-white',
$route.path === '/articles' ? 'bg-orange-500' : '',
$route.path === '/blog' ? 'bg-orange-500' : '',
'group flex w-full items-center px-2 py-2 text-sm',
]"
>
Expand Down
2 changes: 1 addition & 1 deletion components/section/BlogPosts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ const props = defineProps({
</NuxtLink>
</div>
</div>
<MoreLink to="/articles" />
<MoreLink to="/blog" />
</section>
</template>
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export default defineEventHandler(async (event) => {

// Add non nuxt content endpoints here
sitemap.write({ url: '/' });
sitemap.write({ url: '/articles' });
sitemap.write({ url: '/blog' });

// Dynamically generate routes for Nuxt markdown content
articles.forEach((article) => sitemap.write({ url: article._path, changefreq: 'monthly' }));
Expand Down
56 changes: 56 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { writeFileSync, mkdirSync } from 'fs'
import { join, dirname } from 'path'

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
components: true,
Expand Down Expand Up @@ -48,5 +51,58 @@ export default defineNuxtConfig({
}
},

routeRules: {
'/articles': { redirect: { to: '/blog', statusCode: 301 } },
},

hooks: {
// Generate HTML redirect files for `/articles/**` to `/blog/**`
async 'close'() {
const { readdirSync, statSync } = await import('fs')
const distBlogPath = join(process.cwd(), 'dist', 'blog')
const distArticlesPath = join(process.cwd(), 'dist', 'articles')

try {
if (!statSync(distBlogPath).isDirectory()) {
console.log('Blog directory not found, skipping redirect generation')
return
}

const blogDirs = readdirSync(distBlogPath, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)

console.log(`Generating ${blogDirs.length} redirect files for old /articles paths...`)

for (const slug of blogDirs) {
const oldPath = `/articles/${slug}`
const newPath = `/blog/${slug}`

const redirectHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Redirecting...</title>
<link rel="canonical" href="${newPath}">
<meta http-equiv="refresh" content="0; url=${newPath}">
<script>window.location.href = "${newPath}";</script>
</head>
<body>
<p>This page has moved to <a href="${newPath}">${newPath}</a>.</p>
</body>
</html>`

const outputPath = join(distArticlesPath, slug, 'index.html')
mkdirSync(dirname(outputPath), { recursive: true })
writeFileSync(outputPath, redirectHtml)
}

console.log('Redirect files generated successfully!')
} catch (error) {
console.warn('Could not generate redirect files:', error)
}
}
},

compatibilityDate: '2025-06-03'
});
4 changes: 2 additions & 2 deletions pages/articles/[...slug].vue → pages/blog/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const { data: page } = await useAsyncData(route.path, () => {
class="mr-2 w-min rounded-md bg-background text-xs font-bold uppercase hover:cursor-pointer hover:text-orange-500"
v-for="(category, ix) in page.categories"
:key="ix"
:to="`/articles?category=${category}`"
:to="`/blog?category=${category}`"
>
{{ category }}
</NuxtLink>
Expand All @@ -58,7 +58,7 @@ const { data: page } = await useAsyncData(route.path, () => {
class="mr-2 w-min rounded-md bg-background font-bold hover:cursor-pointer hover:text-orange-500"
v-for="(tag, ix) in page.tags"
:key="ix"
:to="`/articles?tag=${tag}`"
:to="`/blog?tag=${tag}`"
>
{{ tag }}
</NuxtLink>
Expand Down
4 changes: 2 additions & 2 deletions pages/articles/index.vue → pages/blog/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const route = useRoute();
//
// examples
//
// localhost:3000/articles?category=embedded
// localhost:3000/articles?tag=embedded
// localhost:3000/blog?category=embedded
// localhost:3000/blog?tag=embedded

const selectedCategories = ref([]);
if (route.query.category) {
Expand Down
2 changes: 1 addition & 1 deletion server/routes/sitemap.xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineEventHandler(async (event) => {
const sitemap = new SitemapStream({ hostname: 'https://cmpadden.github.io' });

sitemap.write({ url: '/' });
sitemap.write({ url: '/articles' });
sitemap.write({ url: '/blog' });
sitemap.write({ url: '/playground' });
sitemap.write({ url: '/playground/plotter' });
sitemap.write({ url: '/playground/palettes/mountains' });
Expand Down