mirror of
https://github.com/waynesutton/markdown-site.git
synced 2026-01-12 04:09:14 +00:00
Update: Blog page featured layout ui, mobile menu padding and font change
This commit is contained in:
@@ -105,10 +105,25 @@ export const generateResponse = action({
|
||||
},
|
||||
returns: v.string(),
|
||||
handler: async (ctx, args) => {
|
||||
// Get API key
|
||||
// Get API key - return friendly message if not configured
|
||||
const apiKey = process.env.ANTHROPIC_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("API key is not set");
|
||||
const notConfiguredMessage =
|
||||
"**AI chat is not configured.**\n\n" +
|
||||
"To enable AI responses, add your `ANTHROPIC_API_KEY` to the Convex environment variables.\n\n" +
|
||||
"**Setup steps:**\n" +
|
||||
"1. Get an API key from [Anthropic Console](https://console.anthropic.com/)\n" +
|
||||
"2. Add it to Convex: `npx convex env set ANTHROPIC_API_KEY your-key-here`\n" +
|
||||
"3. For production, set it in the [Convex Dashboard](https://dashboard.convex.dev/)\n\n" +
|
||||
"See the [Convex environment variables docs](https://docs.convex.dev/production/environment-variables) for more details.";
|
||||
|
||||
// Save the message to chat history so it appears in the conversation
|
||||
await ctx.runMutation(internal.aiChats.addAssistantMessage, {
|
||||
chatId: args.chatId,
|
||||
content: notConfiguredMessage,
|
||||
});
|
||||
|
||||
return notConfiguredMessage;
|
||||
}
|
||||
|
||||
// Get chat history
|
||||
|
||||
@@ -25,6 +25,7 @@ export const getAllPosts = query({
|
||||
rightSidebar: v.optional(v.boolean()),
|
||||
showFooter: v.optional(v.boolean()),
|
||||
footer: v.optional(v.string()),
|
||||
blogFeatured: v.optional(v.boolean()),
|
||||
}),
|
||||
),
|
||||
handler: async (ctx) => {
|
||||
@@ -58,6 +59,53 @@ export const getAllPosts = query({
|
||||
layout: post.layout,
|
||||
rightSidebar: post.rightSidebar,
|
||||
showFooter: post.showFooter,
|
||||
blogFeatured: post.blogFeatured,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
// Get all blog featured posts for the /blog page (hero + featured row)
|
||||
// Returns posts with blogFeatured: true, sorted by date descending
|
||||
export const getBlogFeaturedPosts = query({
|
||||
args: {},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
_id: v.id("posts"),
|
||||
slug: v.string(),
|
||||
title: v.string(),
|
||||
description: v.string(),
|
||||
date: v.string(),
|
||||
tags: v.array(v.string()),
|
||||
readTime: v.optional(v.string()),
|
||||
image: v.optional(v.string()),
|
||||
excerpt: v.optional(v.string()),
|
||||
authorName: v.optional(v.string()),
|
||||
authorImage: v.optional(v.string()),
|
||||
}),
|
||||
),
|
||||
handler: async (ctx) => {
|
||||
const posts = await ctx.db
|
||||
.query("posts")
|
||||
.withIndex("by_blogFeatured", (q) => q.eq("blogFeatured", true))
|
||||
.collect();
|
||||
|
||||
// Filter to only published posts and sort by date descending
|
||||
const publishedFeatured = posts
|
||||
.filter((p) => p.published)
|
||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||
|
||||
return publishedFeatured.map((post) => ({
|
||||
_id: post._id,
|
||||
slug: post.slug,
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
date: post.date,
|
||||
tags: post.tags,
|
||||
readTime: post.readTime,
|
||||
image: post.image,
|
||||
excerpt: post.excerpt,
|
||||
authorName: post.authorName,
|
||||
authorImage: post.authorImage,
|
||||
}));
|
||||
},
|
||||
});
|
||||
@@ -194,6 +242,7 @@ export const syncPosts = internalMutation({
|
||||
showFooter: v.optional(v.boolean()),
|
||||
footer: v.optional(v.string()),
|
||||
aiChat: v.optional(v.boolean()),
|
||||
blogFeatured: v.optional(v.boolean()),
|
||||
}),
|
||||
),
|
||||
},
|
||||
@@ -239,6 +288,7 @@ export const syncPosts = internalMutation({
|
||||
showFooter: post.showFooter,
|
||||
footer: post.footer,
|
||||
aiChat: post.aiChat,
|
||||
blogFeatured: post.blogFeatured,
|
||||
lastSyncedAt: now,
|
||||
});
|
||||
updated++;
|
||||
@@ -288,6 +338,7 @@ export const syncPostsPublic = mutation({
|
||||
showFooter: v.optional(v.boolean()),
|
||||
footer: v.optional(v.string()),
|
||||
aiChat: v.optional(v.boolean()),
|
||||
blogFeatured: v.optional(v.boolean()),
|
||||
}),
|
||||
),
|
||||
},
|
||||
@@ -333,6 +384,7 @@ export const syncPostsPublic = mutation({
|
||||
showFooter: post.showFooter,
|
||||
footer: post.footer,
|
||||
aiChat: post.aiChat,
|
||||
blogFeatured: post.blogFeatured,
|
||||
lastSyncedAt: now,
|
||||
});
|
||||
updated++;
|
||||
|
||||
@@ -23,12 +23,14 @@ export default defineSchema({
|
||||
showFooter: v.optional(v.boolean()), // Show footer on this post (overrides siteConfig default)
|
||||
footer: v.optional(v.string()), // Footer markdown content (overrides siteConfig defaultContent)
|
||||
aiChat: v.optional(v.boolean()), // Enable AI chat in right sidebar
|
||||
blogFeatured: v.optional(v.boolean()), // Show as hero featured post on /blog page
|
||||
lastSyncedAt: v.number(),
|
||||
})
|
||||
.index("by_slug", ["slug"])
|
||||
.index("by_date", ["date"])
|
||||
.index("by_published", ["published"])
|
||||
.index("by_featured", ["featured"])
|
||||
.index("by_blogFeatured", ["blogFeatured"])
|
||||
.searchIndex("search_content", {
|
||||
searchField: "content",
|
||||
filterFields: ["published"],
|
||||
|
||||
Reference in New Issue
Block a user