Fixed Portfolio Collection Routes and Layout Pipeline
Summary
Implemented functional portfolio collection with proper markdown rendering pipeline. Fixed routes returning 200 OK but displaying Client Portal page instead of portfolio markdown content by switching from ClientPortalLayout to the standard OneArticle → OneArticleOnPage → AstroMarkdown pipeline.
Why Care
This completes the portfolio collection implementation, allowing client-specific portfolio content to render correctly with markdown directives like
:::slideshow. The fix ensures portfolio pages follow the same content rendering pipeline as essays, recommendations, and projects, maintaining consistency across all markdown-based content types.Implementation
Changes Made
- Created new
client-portfolioscollection in/src/content.config.tsfollowing recommendations/projects pattern - Fixed collection pattern from
**/Portfolio/**/*.{md,mdx}to*/Portfolio/*.{md,mdx}to prevent conflicts with tooling portfolio files - Added
generateIdfunction to ensure proper ID generation and avoid collection conflicts - Updated portfolio route
/src/pages/client/[client]/portfolio/[...slug].astroto use proper markdown rendering pipeline - Fixed case sensitivity mapping by reading actual client directory names from filesystem
- Removed debug console.log statements from route file
File Tree of Changes
text
site/
├── src/
│ ├── content.config.ts (modified)
│ └── pages/
│ └── client/
│ └── [client]/
│ └── portfolio/
│ └── [...slug].astro (completely rewritten) Technical Details
Collection Configuration Fix
File:
/src/content.config.tsFixed the collection pattern and added proper ID generation:
typescript
const clientPortfoliosCollection = defineCollection({
loader: glob({
pattern: "**/Portfolio/**/*.{md,mdx}", // Match any Portfolio directory at any depth
base: resolveContentPath("client-content"),
generateId: ({ entry }) => {
// Ensure proper ID generation to avoid conflicts
return entry.replace(/^client-content\//, '').toLowerCase();
}
}),
// ... schema configuration
}); Layout Pipeline Fix
File:
/src/pages/client/[client]/portfolio/[...slug].astroChanged from incorrect ClientPortalLayout usage:
astro
<!-- BEFORE: Wrong - shows client portal instead of markdown -->
<ClientPortalLayout client={client} slug={slug} /> To proper markdown rendering pipeline:
astro
<!-- AFTER: Correct - renders markdown content -->
<Layout title={entry.data.title || 'Portfolio Item'} frontmatter={entry.data}>
<OneArticle
Component={OneArticleOnPage}
content={entry.body}
markdownFile={entry.id}
data={contentData}
title={entry.data.title}
/>
</Layout> Case Sensitivity Resolution
Added filesystem-based case mapping in getStaticPaths:
typescript
// Get list of client directories from filesystem to preserve case
const fs = await import('node:fs/promises');
const { contentBasePath } = await import('@utils/envUtils');
const clientContentDir = path.resolve(`${contentBasePath}/client-content`);
const clientDirs = await fs.readdir(clientContentDir, { withFileTypes: true });
const clientNames = clientDirs
.filter(entry => entry.isDirectory())
.map(entry => entry.name);
// Create a case-insensitive map to preserve original case
const clientCaseMap = new Map(
clientNames.map(name => [name.toLowerCase(), name])
); Integration Points
- Portfolio collection integrates with existing content.config.ts collections export
- Routes follow established
/client/[client]/portfolio/[slug]pattern matching essays and recommendations - Uses same markdown rendering components (OneArticle, OneArticleOnPage, AstroMarkdown) as other content types
- Maintains filesystem case sensitivity for client names while allowing lowercase collection IDs
- Collection filtering works with existing
allEntries.filter()patterns in getStaticPaths
Documentation
- Updated
/src/generated-content/lost-in-public/issue-resolution/Multi-Path-Portfolio-Collection-Setup.mdwith layout pipeline eureka moment - Portfolio routes now work correctly:
/client/Hypernova/portfolio/portfolio-listand/client/Hypernova/portfolio/aalo-atomics - Slideshow directives (
:::slideshow) render properly in portfolio content - Collection entries properly generated with IDs like
hypernova/portfolio/listinstead of conflicting with root-level files