Add featured post flag for homepage
Some checks failed
Build / build (push) Has been cancelled

This commit is contained in:
Neeldhara Misra 2026-06-22 13:08:56 +05:30
parent e7227844c7
commit 3ced32a4d0
19 changed files with 63 additions and 5 deletions

View file

@ -71,6 +71,10 @@ Optional fields currently understood by the sites include `updatedDate`,
`image`, and `authorImage`. Prefer colocated images in the body over remote `image`, and `authorImage`. Prefer colocated images in the body over remote
stock images. stock images.
Use `main-feature: true` on at most one post per blog to pin a fixed featured
post on the `neeldhara.blog` homepage. The homepage still shows the two newest
non-featured posts for that blog, sorted by `pubDate`.
The Quarto import also preserved `sourceCategories` and `sourcePath`. Astro The Quarto import also preserved `sourceCategories` and `sourcePath`. Astro
strips unknown schema fields, but they are useful in Obsidian for provenance. strips unknown schema fields, but they are useful in Obsidian for provenance.

View file

@ -34,7 +34,10 @@ Search for **Blog Family Sync** in the command palette:
Preview starts the matching Astro dev server if the configured local URL is not Preview starts the matching Astro dev server if the configured local URL is not
already responding. Publish syncs first, runs that target's build command, already responding. Publish syncs first, runs that target's build command,
commits staged content changes, and pushes to Forgejo. commits staged content changes, and pushes to Forgejo. For the seven `allblogs`
targets, publish also refreshes and pushes the `home` repo's
`content/blog-index.json` so `neeldhara.blog` redeploys with the newest
featured/latest entries.
## Notes ## Notes

View file

@ -11,6 +11,7 @@ const NPM = `${NODE_BIN}/npm`;
const BLOGS_ROOT = "/Users/neeldhara/forgejo/blogs"; const BLOGS_ROOT = "/Users/neeldhara/forgejo/blogs";
const ALLBLOGS_REPO = `${BLOGS_ROOT}/allblogs`; const ALLBLOGS_REPO = `${BLOGS_ROOT}/allblogs`;
const MICRO_REPO = `${BLOGS_ROOT}/micro`; const MICRO_REPO = `${BLOGS_ROOT}/micro`;
const HOME_REPO = `${BLOGS_ROOT}/home`;
const DEFAULT_TARGETS = [ const DEFAULT_TARGETS = [
{ {
@ -557,14 +558,41 @@ module.exports = class BlogFamilySyncPlugin extends Plugin {
this.updateStatusBar(`Blog sync: pushing ${target.label}...`); this.updateStatusBar(`Blog sync: pushing ${target.label}...`);
const output = await this.runShellCommand(publishCommand, repoFolder); const output = await this.runShellCommand(publishCommand, repoFolder);
let homeOutput = "";
if (path.resolve(target.repoFolder) === path.resolve(ALLBLOGS_REPO)) {
homeOutput = await this.publishHomeIndex();
}
this.updateStatusBar("Blog sync: published"); this.updateStatusBar("Blog sync: published");
new Notice( new Notice(
[
output.includes("No staged changes") output.includes("No staged changes")
? `No ${target.label} changes to publish.` ? `No ${target.label} changes to publish.`
: `${target.label} changes pushed.`, : `${target.label} changes pushed.`,
homeOutput
? homeOutput.includes("No homepage index changes")
? "Homepage index unchanged."
: "Homepage index pushed."
: "",
]
.filter(Boolean)
.join(" "),
); );
} }
async publishHomeIndex() {
this.updateStatusBar("Blog sync: refreshing homepage index...");
const command = [
`${shellQuote(NPM)} run refresh:index`,
"git add content/blog-index.json",
'if git diff --cached --quiet; then echo "No homepage index changes to publish."; else git commit -m "Refresh homepage blog index"; fi',
"git push",
].join(" && ");
return await this.runShellCommand(command, HOME_REPO);
}
async ensureDevServer(target) { async ensureDevServer(target) {
const baseUrl = normalizeBaseUrl(target.devServerUrl); const baseUrl = normalizeBaseUrl(target.devServerUrl);
if (await urlResponds(baseUrl)) { if (await urlResponds(baseUrl)) {

View file

@ -1,7 +1,7 @@
{ {
"id": "microblog-sync", "id": "microblog-sync",
"name": "Blog Family Sync", "name": "Blog Family Sync",
"version": "0.4.0", "version": "0.5.0",
"minAppVersion": "1.5.0", "minAppVersion": "1.5.0",
"description": "Sync the public Obsidian blog folders with the local Astro blog repos.", "description": "Sync the public Obsidian blog folders with the local Astro blog repos.",
"author": "Neeldhara Misra", "author": "Neeldhara Misra",

View file

@ -3,6 +3,7 @@ title: "Creating a Gallery of Solved Crosswords"
description: "H/T Manu: I've discovered the India Mini Crossword series and it's a great two-to-five minute thing to solve every morning! Here's a little workflow I cobbled together to genera..." description: "H/T Manu: I've discovered the India Mini Crossword series and it's a great two-to-five minute thing to solve every morning! Here's a little workflow I cobbled together to genera..."
pubDate: "2024-05-10" pubDate: "2024-05-10"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["workflows"] sourceCategories: ["workflows"]
sourcePath: "indiamini-crosswords/index.qmd" sourcePath: "indiamini-crosswords/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -3,6 +3,7 @@ title: "Poetry"
description: "collect your grief and inject it in words spill them on paper and shred it to tatters to piece yourself together ---" description: "collect your grief and inject it in words spill them on paper and shred it to tatters to piece yourself together ---"
pubDate: "2024-01-01" pubDate: "2024-01-01"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["poem"] sourceCategories: ["poem"]
sourcePath: "poems/poetry/index.qmd" sourcePath: "poems/poetry/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -3,6 +3,7 @@ title: "Dog Bunny Puzzle"
description: "Dog Bunny: A Cute Puzzle Conrad Barski (@lisperati)'s latest, Dog Bunny Puzzle, had jumped to 1 on HN. The puzzle presents the following somewhat minimalist interface: If you ha..." description: "Dog Bunny: A Cute Puzzle Conrad Barski (@lisperati)'s latest, Dog Bunny Puzzle, had jumped to 1 on HN. The puzzle presents the following somewhat minimalist interface: If you ha..."
pubDate: "2022-09-19" pubDate: "2022-09-19"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["puzzles", "exposition"] sourceCategories: ["puzzles", "exposition"]
sourcePath: "dogs-bunny-puzzle/index.qmd" sourcePath: "dogs-bunny-puzzle/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -3,6 +3,7 @@ title: "On Career Choices"
description: "Tip A version of this article was featured in A Lesson from IIT , a column on the Indian Express. The link to the column is here, and this is the link to the present article. Ma..." description: "Tip A version of this article was featured in A Lesson from IIT , a column on the Indian Express. The link to the column is here, and this is the link to the present article. Ma..."
pubDate: "2023-05-26" pubDate: "2023-05-26"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["funda"] sourceCategories: ["funda"]
sourcePath: "on-career-choices/index.qmd" sourcePath: "on-career-choices/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -3,6 +3,7 @@ title: "Intro to Crypto"
description: "Caution Background This post is based on a series of lectures that Venkata Koppula gave at IIT Gandhiangar during the inter-IIT sports meet. Lecture 1: How to define security? N..." description: "Caution Background This post is based on a series of lectures that Venkata Koppula gave at IIT Gandhiangar during the inter-IIT sports meet. Lecture 1: How to define security? N..."
pubDate: "2023-12-21" pubDate: "2023-12-21"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["talk", "exposition"] sourceCategories: ["talk", "exposition"]
sourcePath: "crypto-intro/index.qmd" sourcePath: "crypto-intro/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -3,6 +3,7 @@ title: "Note Taking Resources"
description: "Here is a list of courses, books, essays, youtube playlists, and other miscellany about taking notes, with the act interpreted broadly to include things like systems for filing,..." description: "Here is a list of courses, books, essays, youtube playlists, and other miscellany about taking notes, with the act interpreted broadly to include things like systems for filing,..."
pubDate: "2023-06-02" pubDate: "2023-06-02"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["lists"] sourceCategories: ["lists"]
sourcePath: "note-taking-resources/index.qmd" sourcePath: "note-taking-resources/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({

View file

@ -3,6 +3,7 @@ title: "13 Sheep"
description: "13 Sheep happens to be a cute roll-and-write game designed by Moritz Dressler that involves protecting a bunch of sheep on a grid by placing small fences that have pre-defined s..." description: "13 Sheep happens to be a cute roll-and-write game designed by Moritz Dressler that involves protecting a bunch of sheep on a grid by placing small fences that have pre-defined s..."
pubDate: "2023-03-26" pubDate: "2023-03-26"
authorName: "Neeldhara" authorName: "Neeldhara"
main-feature: true
sourceCategories: ["games", "exposition"] sourceCategories: ["games", "exposition"]
sourcePath: "13sheep/index.qmd" sourcePath: "13sheep/index.qmd"
--- ---

View file

@ -9,6 +9,8 @@ const blogSchema = z.object({
image: z.string().optional(), image: z.string().optional(),
authorImage: z.string().optional(), authorImage: z.string().optional(),
authorName: z.string().optional(), authorName: z.string().optional(),
"main-feature": z.boolean().optional(),
mainFeature: z.boolean().optional(),
}); });
const research = defineCollection({ const research = defineCollection({