30 Commits

Author SHA1 Message Date
svemagie
f5a62b966d feat: auto-create Microsub source to keep blogroll in sync
When the Microsub plugin is detected and no microsub source exists in
blogrollSources, automatically create one on startup so the periodic
sync picks up all Microsub feed subscriptions without manual config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 10:37:16 +01:00
svemagie
80b86183c5 Merge pull request #1 from svemagie/bookmark-import
feat: bookmark import
2026-03-12 12:26:35 +01:00
svemagie
381b0397a5 feat: guard bookmark hook when microsub is available, update category on tag change
- index: skip direct bookmark import when microsub plugin is present;
  microsub handles the flow and notifies blogroll via notifyBlogroll()
  to avoid duplicate entries
- bookmark-import: when blog already exists and category differs, update it
  instead of skipping (handles tag changes on existing bookmark posts)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 09:33:42 +01:00
svemagie
66bc404f03 feat: pass bookmark post category through to blogroll entry 2026-03-10 19:53:46 +01:00
svemagie
adbdadd508 feat: use bookmark post category as blogroll category 2026-03-10 19:51:08 +01:00
svemagie
34739735e7 feat: integrate bookmark→blogroll hook via contentNegotiationRoutes
Uses res.on('finish') middleware mounted at '/' to detect successful
micropub bookmark creations and auto-import the bookmarked site's feed
into the blogroll. Self-contained within the plugin — no external patch
scripts required.
2026-03-10 19:23:44 +01:00
svemagie
93de24c593 feat: add bookmark-import module for micropub bookmark → blogroll integration 2026-03-10 19:12:14 +01:00
Ricardo
4d56d58703 feat: add lastItemAt field — tracks newest item publish date per blog
Stores the most recent item's published date on the blog document
during feed sync. Exposed in API response alongside lastFetchAt.
Enables sorting/displaying blogs by content freshness rather than
last fetch time.
2026-02-17 17:43:44 +01:00
Ricardo
f02d46e76e fix: resolve [Object Object] bug and add sort/source API params
Rename duplicate "sync" locale key to "syncResult" to fix the sources
list page showing [Object Object] instead of the Sync button label.

Add sort=recent and source= query params to the blogs API for the
sidebar widget tabs feature. Tag FeedLand blogs with source: "feedland"
and expose source field for all blogs in API responses.

Bump version to 1.0.22.
2026-02-17 14:20:10 +01:00
Ricardo
129dc78e09 feat: add FeedLand source type for blogroll
Adds FeedLand (feedland.com or self-hosted) as a new source type alongside
OPML and Microsub. Syncs subscriptions via FeedLand's public OPML endpoint
with optional category filtering and AJAX category discovery in the admin UI.
2026-02-17 13:54:19 +01:00
Ricardo
9a8cb669d1 fix: use {{var}} interpolation syntax instead of %{var}
The i18n library used by Indiekit expects {{variable}} for named
interpolation. The %{variable} syntax was not being substituted,
causing raw template strings in toast notifications.
2026-02-17 10:46:58 +01:00
Ricardo
239059deb7 fix: add missing sync and form locale keys across all languages
Added blogroll.sync.* keys (success, error, already_running, cleared_success)
and sources.form.* keys (microsubChannel, categoryPrefix with hints) that were
referenced in controllers/templates but missing from locale files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:19:15 +01:00
Ricardo
e99adbc1fa feat: add i18n support for 14 languages
Add translations for de, es, es-419, fr, hi, id, it, nl, pl, pt, pt-BR, sr, sv, zh-Hans-CN
to match upstream Indiekit's supported locales.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:33:01 +01:00
Ricardo
1b4cf4a14a docs: add CLAUDE.md and README.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:21:59 +01:00
Ricardo
d634c70cfe fix: store dates as ISO strings instead of Date objects
Prevents dateString.split crash when Nunjucks | date filter receives
Date objects from MongoDB. All stored dates now use .toISOString().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 22:29:13 +01:00
Ricardo
2a98784381 fix: use upstream @indiekit/frontend form classes
Add .input, .select, .textarea, .label, .hint classes to all form
elements. Use input-button-group for discover URL. Replace custom
filter-select with upstream .select class. Remove duplicate CSS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 20:14:49 +01:00
Ricardo
4ad4c13bbc refactor: align views with upstream @indiekit/frontend patterns
- Extract ~560 lines of inline CSS to external assets/styles.css
- Create intermediate layout (layouts/blogroll.njk) for CSS loading
- Use section(), badge(), button(), prose() macros instead of raw HTML
- Remove custom page headers (document.njk heading() handles via title/parent)
- Add parent breadcrumb navigation to all sub-pages
- Add consumeFlashMessage() to dashboard and sources controllers
- Rename CSS class prefix from br-* to blogroll-* for clarity
- Use upstream CSS custom properties without fallback values
- Fix Microsub orphan detection (soft-delete unsubscribed blogs)
- Fix upsert to conditionally set microsub fields (avoid path conflicts)
- Skip soft-deleted blogs during clear-and-resync

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:42:27 +01:00
Ricardo
87851bade2 feat: category tabs, future post badge, HTML entity decoding
- Decode HTML entities (&amp; &#39; etc) in feed titles and summaries
- Add isFuture flag to API items for future-dated posts
- Bump version to 1.0.12

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 21:22:16 +01:00
Ricardo
3bf0e765c7 fix: remove orphaned endfor tag in blogs list template
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 13:09:07 +01:00
Ricardo
c2074ffde5 fix: soft delete blogs to prevent sync from recreating deleted entries
Deleted blogs are now marked with status: "deleted" instead of being
removed from MongoDB. The upsertBlog function skips deleted feedUrls,
preventing OPML/Microsub sync from recreating them. All queries exclude
deleted blogs. Flash messages now use Indiekit's native notificationBanner.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:23:28 +01:00
Ricardo
d7f2344c4b fix: convert Date objects to ISO strings for blog edit items
The Indiekit date filter calls parseISO() which expects a string.
MongoDB returns Date objects for item.published, causing
"dateString.split is not a function" error on the blog edit page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:02:36 +01:00
Ricardo
e0d4de2fea fix: Apply 30-day retention to item counts
- Add date filter to countItems function
- Applies to both regular and Microsub items
- Matches the retention period used in Microsub plugin

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 13:58:57 +01:00
Ricardo
8ace76f8c2 feat: Add Microsub integration with reference-based data approach
- Add Microsub source type to sync subscriptions from Microsub channels
- Use reference-based approach to avoid data duplication:
  - Blogs store microsubFeedId reference instead of copying data
  - Items for Microsub blogs are queried from microsub_items directly
  - No duplicate storage or retention management needed
- Add channel filter and category prefix options for Microsub sources
- Add webhook endpoint for Microsub subscription change notifications
- Update scheduler to skip item fetching for Microsub blogs
- Update items storage to combine results from both collections
- Bump version to 1.0.7

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 12:35:52 +01:00
Ricardo
9556849df0 fix: restore checkbox appearance in forms
The 'appearance: none' CSS rule was hiding checkboxes.
Added 'appearance: auto' to restore native checkbox styling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 18:04:52 +01:00
Ricardo
87ebebfb7a refactor: rename Sources to OPML Sync, remove Manual type
- Remove 'Manual' source type (redundant with Blogs management)
- Rename 'Sources' to 'OPML Sync' for clarity
- Update labels to clarify URL syncs periodically, File is one-time import
- Fix date conversion in sources list controller

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 17:38:19 +01:00
Ricardo
4a53f74bbc feat: add feed auto-discovery to blog add form
- Add feed-discovery.js utility that discovers RSS/Atom/JSON feeds from website URLs
- Add /api/discover endpoint for frontend feed discovery
- Update blog edit form with discovery UI (enter website URL, discover feeds)
- Auto-populate feedUrl, title, and siteUrl from discovery results
- Handle multiple feed options (let user choose)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 15:37:23 +01:00
Ricardo
d45d183024 fix: convert Date objects to ISO strings for template compatibility
The Indiekit date filter expects ISO strings, not JavaScript Date objects.
This fixes 'dateString.split is not a function' errors in the dashboard.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 12:48:29 +01:00
Ricardo
fb6e92b2be fix: rename templates with blogroll- prefix to avoid conflicts with other plugins 2026-02-07 12:24:35 +01:00
Ricardo
8d3cde4eb2 fix: add missing viewsDirectory getter for Indiekit to find templates 2026-02-07 11:22:59 +01:00
Ricardo
8344a59b76 feat: initial blogroll endpoint plugin
OPML/RSS aggregator for IndieWeb blogroll management:
- Multiple source types: OPML URL, OPML file, manual entry
- Background sync scheduler with configurable intervals
- 7-day item retention for fresh content discovery
- MongoDB storage for sources, blogs, items
- Admin UI for sources and blogs management
- Public JSON API endpoints for frontend consumption
- OPML export by category

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 09:55:53 +01:00