feat: raw markdown URLs, author display, GitHub Stars, and frontmatter docs

v1.18.1 - CopyPageDropdown raw markdown URLs
- AI services (ChatGPT, Claude, Perplexity) now receive /raw/{slug}.md URLs
- Direct access to clean markdown content for better AI parsing
- No HTML parsing required by AI services
- Renamed buildUrlFromPageUrl to buildUrlFromRawMarkdown

v1.19.0 - Author display for posts and pages
- New optional authorName and authorImage frontmatter fields
- Round avatar image displayed next to date and read time
- Works on individual post and page views
- Write page updated with new field reference

v1.19.1 - GitHub Stars on Stats page
- Live star count from waynesutton/markdown-site repository
- Fetches from GitHub public API (no token required)
- Stats page now displays 6 cards with responsive grid

Documentation updates
- Frontmatter Flow section added to docs.md, setup-guide.md, files.md
- How frontmatter works with step-by-step processing flow
- Instructions for adding new frontmatter fields

Updated files:
- src/components/CopyPageDropdown.tsx
- src/pages/Stats.tsx
- src/pages/Post.tsx
- src/pages/Write.tsx
- src/styles/global.css
- convex/schema.ts
- convex/posts.ts
- convex/pages.ts
- scripts/sync-posts.ts
- content/blog/setup-guide.md
- content/pages/docs.md
- content/pages/changelog-page.md
- files.md
- README.md
- TASK.md
- changelog.md
- AGENTS.md
This commit is contained in:
Wayne Sutton
2025-12-21 13:59:50 -08:00
parent 29691ee655
commit dd934390cc
36 changed files with 913 additions and 178 deletions

View File

@@ -15,6 +15,8 @@ export const getAllPages = query({
image: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
),
handler: async (ctx) => {
@@ -41,6 +43,8 @@ export const getAllPages = query({
image: page.image,
featured: page.featured,
featuredOrder: page.featuredOrder,
authorName: page.authorName,
authorImage: page.authorImage,
}));
},
});
@@ -101,6 +105,8 @@ export const getPageBySlug = query({
image: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
v.null(),
),
@@ -125,6 +131,8 @@ export const getPageBySlug = query({
image: page.image,
featured: page.featured,
featuredOrder: page.featuredOrder,
authorName: page.authorName,
authorImage: page.authorImage,
};
},
});
@@ -143,6 +151,8 @@ export const syncPagesPublic = mutation({
image: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
),
},
@@ -178,6 +188,8 @@ export const syncPagesPublic = mutation({
image: page.image,
featured: page.featured,
featuredOrder: page.featuredOrder,
authorName: page.authorName,
authorImage: page.authorImage,
lastSyncedAt: now,
});
updated++;

View File

@@ -19,6 +19,8 @@ export const getAllPosts = query({
excerpt: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
),
handler: async (ctx) => {
@@ -47,6 +49,8 @@ export const getAllPosts = query({
excerpt: post.excerpt,
featured: post.featured,
featuredOrder: post.featuredOrder,
authorName: post.authorName,
authorImage: post.authorImage,
}));
},
});
@@ -113,6 +117,8 @@ export const getPostBySlug = query({
excerpt: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
v.null(),
),
@@ -141,6 +147,8 @@ export const getPostBySlug = query({
excerpt: post.excerpt,
featured: post.featured,
featuredOrder: post.featuredOrder,
authorName: post.authorName,
authorImage: post.authorImage,
};
},
});
@@ -162,6 +170,8 @@ export const syncPosts = internalMutation({
excerpt: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
),
},
@@ -200,6 +210,8 @@ export const syncPosts = internalMutation({
excerpt: post.excerpt,
featured: post.featured,
featuredOrder: post.featuredOrder,
authorName: post.authorName,
authorImage: post.authorImage,
lastSyncedAt: now,
});
updated++;
@@ -242,6 +254,8 @@ export const syncPostsPublic = mutation({
excerpt: v.optional(v.string()),
featured: v.optional(v.boolean()),
featuredOrder: v.optional(v.number()),
authorName: v.optional(v.string()),
authorImage: v.optional(v.string()),
}),
),
},
@@ -280,6 +294,8 @@ export const syncPostsPublic = mutation({
excerpt: post.excerpt,
featured: post.featured,
featuredOrder: post.featuredOrder,
authorName: post.authorName,
authorImage: post.authorImage,
lastSyncedAt: now,
});
updated++;

View File

@@ -16,6 +16,8 @@ export default defineSchema({
excerpt: v.optional(v.string()), // Short excerpt for card view
featured: v.optional(v.boolean()), // Show in featured section
featuredOrder: v.optional(v.number()), // Order in featured section (lower = first)
authorName: v.optional(v.string()), // Author display name
authorImage: v.optional(v.string()), // Author avatar image URL (round)
lastSyncedAt: v.number(),
})
.index("by_slug", ["slug"])
@@ -42,6 +44,8 @@ export default defineSchema({
image: v.optional(v.string()), // Thumbnail/OG image URL for featured cards
featured: v.optional(v.boolean()), // Show in featured section
featuredOrder: v.optional(v.number()), // Order in featured section (lower = first)
authorName: v.optional(v.string()), // Author display name
authorImage: v.optional(v.string()), // Author avatar image URL (round)
lastSyncedAt: v.number(),
})
.index("by_slug", ["slug"])