Compare commits

..

19 commits

Author SHA1 Message Date
Patrick Mulligan
c4a62552cc fix(ui): Add top padding to sort tabs
Add spacing between header border and sort tabs for better visual
separation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 21:33:03 +01:00
Patrick Mulligan
b84b23b9dc fix(ui): Add max-width constraint to feed layout
Constrain feed content to max-w-4xl (896px) and center it, matching
the layout style of sites like programming.dev.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 21:31:01 +01:00
Patrick Mulligan
a0c9a45470 fix(nostr-feed): Fix TypeScript errors and remove unused imports
- Change SubmissionWithMeta from interface to type intersection
- Fix UseSubmissionsReturn types to use proper Ref/ComputedRef
- Remove unused imports across components and services

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 21:28:23 +01:00
Patrick Mulligan
e39cb7acd7 feat(nostr-feed): Replace NostrFeed with SubmissionList on Home page
The link aggregator is now the main feed, replacing the old NostrFeed
component. FAB button navigates to /submit for creating posts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 21:28:12 +01:00
Patrick Mulligan
1036a56cf5 fix(nostr-feed): Fetch profiles for submission authors
Add watchers to fetch profiles when submissions and comments load,
ensuring display names are shown instead of pubkeys.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 21:24:06 +01:00
Patrick Mulligan
92089d63b5 chore(nostr-feed): Remove link aggregator test page
Remove test page with mock data and test relay connection UI.
The link aggregator is now ready for production use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 21:12:24 +01:00
Patrick Mulligan
74ce584eff fix(nostr-feed): Use shadcn-vue Select for time range dropdown
Replace native HTML select with themed Select component for proper
dark mode support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:57:43 +01:00
Patrick Mulligan
b62ef19ced fix(nostr-feed): Use theme-aware colors for comment threading lines
Replace hardcoded Tailwind colors with semantic chart-* colors that
adapt to light/dark theme.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:54:07 +01:00
Patrick Mulligan
56033994b9 feat(nostr-feed): Add inline reply forms for comments
- Add inline reply form that appears below the comment being replied to
- Pass replyingToId and isSubmittingReply props through comment tree
- Add cancel-reply and submit-reply events for inline form handling
- Top composer now only shows for new top-level comments
- Better UX: no need to scroll to top to reply to nested comments

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:47:52 +01:00
Patrick Mulligan
ffd8dac719 fix(nostr-feed): Fix comment threading lines styling
- Change border-* to bg-* classes so threading lines actually display
- Tighten spacing to match Lemmy-style threading (ml-0.5, pl-2, py-1)
- Rename borderColor to depthColor for accuracy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:39:39 +01:00
Patrick Mulligan
afdab94beb feat(nostr-feed): Add submission voting with persistence
- Implement downvote() for submissions using dislikeEvent
- Add refreshAllSubmissionVotes() to update all votes after EOSE
- Refresh submission votes after loading reactions in both subscribe methods
- Fixes vote state not displaying correctly on page load

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:31:13 +01:00
Patrick Mulligan
fa93cc56ba feat(nostr-feed): Add comment voting with persistence
- Add fetchCommentReactions() to load reactions for all comments after EOSE
- Add updateCommentVotes() to refresh comment votes from ReactionService
- Add dislikeEvent() and undislikeEvent() to ReactionService for downvotes
- Update downvoteComment() to use ReactionService for persistence
- Fix vote button styling in SubmissionComment to properly show active state
- Wire up comment vote handlers in SubmissionDetail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:25:35 +01:00
Patrick Mulligan
98e7e1ea89 fix(nostr-feed): Fix comment loading and deduplication
- Add subscribeToSubmission() to fetch submission + comments by ID
- Fix isComment check order - check before parseSubmission (which fails for comments)
- Update comment count on submission when comments are added
- Add duplicate comment detection to prevent double-display
- Update useSubmission composable to auto-subscribe on mount

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:59:49 +01:00
Patrick Mulligan
66fa6459e7 feat(nostr-feed): Complete Phase 4 - comment sorting and submission
- Add createComment() method to SubmissionService for posting comments
- Add getSortedComments() with sort options: best, new, old, controversial
- Wire up comment submission in SubmissionDetail.vue
- Add comment sort dropdown in detail view
- Support replying to specific comments or root submission
- Display comment submission errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:33:26 +01:00
Patrick Mulligan
54d81b7c79 feat(nostr-feed): Add submission composer (Phase 2)
- Create SubmitComposer.vue with post type selector (text/link/media)
- Add debounced link preview fetching on URL input
- Wire up submission publishing via SubmissionService.createSubmission()
- Add /submit route with SubmitPage.vue wrapper
- Support community query param for pre-selection
- Include NSFW toggle and form validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:26:10 +01:00
Patrick Mulligan
d197c53afb feat(nostr-feed): Add submission detail view (Phase 4)
- Add SubmissionDetail.vue for full post view with content display
- Add SubmissionComment.vue for recursive threaded comments
- Add SubmissionDetailPage.vue route wrapper
- Add /submission/:id route to module
- Update SubmissionList share URL to use correct route
- Update test page to navigate to detail view on click
- Update plan document with Phase 4 completion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:01:58 +01:00
Patrick Mulligan
453a4c73ab feat(nostr-feed): Add test page for link aggregator UI
- Add LinkAggregatorTest.vue with mock data and live submission views
- Include direct relay connection for testing kind 1111 events
- Add submission composer with self/link post types
- Add route at /link-aggregator-test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 18:40:33 +01:00
Patrick Mulligan
ecef314442 feat(nostr-feed): Add Reddit/Lemmy-style UI components (Phase 2/3)
Implement minimal, information-dense submission feed UI inspired by
old Reddit and Lemmy designs.

New components:
- VoteControls.vue: Compact vertical upvote/downvote arrows with score
- SubmissionThumbnail.vue: Small square thumbnail with fallback icons
- SubmissionRow.vue: Single submission row with title, metadata, actions
- SortTabs.vue: Sort tabs (hot, new, top, controversial) with time range
- SubmissionList.vue: Main container composing all components

UI features:
- Dense layout showing many items at once
- Hover-reveal secondary actions (share, save, hide, report)
- Domain display for link posts
- NSFW blur/badge support
- Rank numbers (optional)
- Time-ago formatting
- Score formatting (e.g., 1.2k)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-01 18:03:35 +01:00
Patrick Mulligan
037f46fa6b feat(nostr-feed): Add link aggregator core data model (Phase 1)
Implement Reddit-style link aggregator foundation using NIP-72 (Moderated
Communities) and NIP-22 (Comments) specifications.

New files:
- types/submission.ts: Complete type definitions for submissions, voting,
  communities, link previews, and ranking algorithms
- services/SubmissionService.ts: Core service for kind 1111 submission
  events with parsing, creation, voting, and comment threading
- services/LinkPreviewService.ts: Open Graph metadata fetching with
  caching, CORS proxy support, and oEmbed fallbacks
- composables/useSubmissions.ts: Vue composable for reactive submission
  state management
- LINK_AGGREGATOR_PLAN.md: Implementation roadmap

Features:
- Three post types: link, media, self (text)
- NIP-22 compliant community-scoped posts
- NIP-92 media attachments with imeta tags
- Hot/Top/New/Controversial ranking algorithms
- Threaded comment support
- Upvote/downvote via NIP-25 reactions

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-01 17:44:43 +01:00

22
package-lock.json generated
View file

@ -5850,6 +5850,14 @@
"node": ">= 0.4"
}
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
@ -9755,13 +9763,13 @@
}
},
"node_modules/jws": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
"integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
"dev": true,
"license": "MIT",
"dependencies": {
"jwa": "^2.0.1",
"jwa": "^2.0.0",
"safe-buffer": "^5.0.1"
}
},
@ -13971,9 +13979,9 @@
}
},
"node_modules/vite": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"dev": true,
"license": "MIT",
"dependencies": {