From 82cd75e4321b2738c95a4dbac13847e7925196df Mon Sep 17 00:00:00 2001 From: mroxso <24775431+mroxso@users.noreply.github.com> Date: Mon, 29 Jul 2024 23:12:30 +0200 Subject: [PATCH] initial commit --- .github/workflows/docker-image.yml | 61 + Dockerfile | 4 +- README.md | 9 +- compose.yaml | 4 +- kustomize/base/deployment.yaml | 19 + kustomize/base/kustomization.yaml | 3 + kustomize/base/service.yaml | 11 + .../environments/beta/kustomization.yaml | 2 + .../environments/prod/kustomization.yaml | 2 + lumina/app/dashboard/[pubkey]/page.tsx | 32 + lumina/app/feed/page.tsx | 61 + lumina/app/global/page.tsx | 32 + lumina/app/icon.tsx | 40 + lumina/app/layout.tsx | 30 +- lumina/app/login/page.tsx | 20 + lumina/app/note/[id]/page.tsx | 39 + lumina/app/notifications/page.tsx | 34 + lumina/app/onboarding/createProfile/page.tsx | 23 + lumina/app/onboarding/page.tsx | 24 + lumina/app/page.tsx | 44 +- lumina/app/profile/[pubkey]/page.tsx | 42 +- lumina/app/profile/settings/page.tsx | 34 + lumina/app/reel/page.tsx | 31 + lumina/app/search/[searchTag]/page.tsx | 57 + lumina/app/search/page.tsx | 24 + lumina/app/tag/[tag]/page.tsx | 13 +- lumina/bun.lockb | Bin 175381 -> 321868 bytes lumina/components/BottomBar.tsx | 55 + lumina/components/CommentCard.tsx | 123 + lumina/components/CommentsCompontent.tsx | 34 + lumina/components/FollowButton.tsx | 97 + lumina/components/FollowerFeed.tsx | 54 + lumina/components/FollowerQuickViewFeed.tsx | 73 + lumina/components/GlobalFeed.tsx | 2 +- lumina/components/LoginForm.tsx | 189 + lumina/components/Navigation.tsx | 16 - lumina/components/NoteCard.tsx | 199 +- lumina/components/NotePageComponent.tsx | 41 + lumina/components/Notification.tsx | 112 + lumina/components/Notifications.tsx | 86 + lumina/components/ProfileFeed.tsx | 4 +- lumina/components/ProfileInfoCard.tsx | 157 +- lumina/components/ProfileQuickViewFeed.tsx | 63 + lumina/components/ProfileTextFeed.tsx | 51 + lumina/components/QuickViewNoteCard.tsx | 86 + lumina/components/ReactionButton.tsx | 103 +- .../components/ReactionButtonReactionList.tsx | 12 + .../ReactionButtonReactionListItem.tsx | 43 + lumina/components/ReelFeed.tsx | 40 + lumina/components/Search.tsx | 62 + lumina/components/TagFeed.tsx | 4 +- lumina/components/TrendingAccount.tsx | 55 + lumina/components/TrendingAccounts.tsx | 57 +- lumina/components/TrendingImage.tsx | 84 + lumina/components/TrendingImages.tsx | 27 + lumina/components/UpdateProfileForm.tsx | 102 + lumina/components/ViewCopyButton.tsx | 91 + lumina/components/ViewNoteButton.tsx | 10 + lumina/components/ViewRawButton.tsx | 6 +- lumina/components/ZapButton.tsx | 122 + lumina/components/ZapButtonList.tsx | 12 + lumina/components/ZapButtonListItem.tsx | 55 + .../components/dashboard/RecentFollower.tsx | 36 + .../dashboard/RecentFollowerCard.tsx | 23 + lumina/components/dashboard/RecentZap.tsx | 45 + .../components/dashboard/RecentZapsCard.tsx | 23 + lumina/components/dashboard/Statistics.tsx | 120 + .../headerComponents/AvatarDropdown.tsx | 63 + .../DropdownThemeMode.tsx | 0 .../headerComponents/LoginButton.tsx | 13 + .../headerComponents/RegisterButton.tsx | 13 + .../headerComponents/TopNavigation.tsx | 37 + .../headerComponents/TopNavigationItems.tsx | 42 + lumina/components/icons.tsx | 31 + lumina/components/nip05.tsx | 45 + .../onboarding/createSecretKeyForm.tsx | 56 + .../searchComponents/SearchNotesBox.tsx | 65 + .../searchComponents/SearchProfilesBox.tsx | 65 + lumina/components/ui/accordion.tsx | 58 + lumina/components/ui/card.tsx | 10 +- lumina/components/ui/dialog.tsx | 122 + lumina/components/ui/form.tsx | 176 + lumina/components/ui/input.tsx | 25 + lumina/components/ui/label.tsx | 26 + lumina/components/ui/scroll-area.tsx | 48 + lumina/components/ui/toast.tsx | 129 + lumina/components/ui/toaster.tsx | 35 + lumina/components/ui/use-toast.ts | 194 + lumina/config/site.ts | 18 + lumina/next.config.mjs | 9 +- lumina/package-lock.json | 4261 ++++++++++++++++- lumina/package.json | 20 +- lumina/public/.well-known/nostr.json | 1 + .../android/android-launchericon-144-144.png | Bin 0 -> 3029 bytes .../android/android-launchericon-192-192.png | Bin 0 -> 3591 bytes .../android/android-launchericon-48-48.png | Bin 0 -> 1842 bytes .../android/android-launchericon-512-512.png | Bin 0 -> 7878 bytes .../android/android-launchericon-72-72.png | Bin 0 -> 2160 bytes .../android/android-launchericon-96-96.png | Bin 0 -> 2404 bytes lumina/public/icons.json | 452 ++ lumina/public/ios/100.png | Bin 0 -> 2446 bytes lumina/public/ios/1024.png | Bin 0 -> 16587 bytes lumina/public/ios/114.png | Bin 0 -> 2626 bytes lumina/public/ios/120.png | Bin 0 -> 2679 bytes lumina/public/ios/128.png | Bin 0 -> 2802 bytes lumina/public/ios/144.png | Bin 0 -> 3029 bytes lumina/public/ios/152.png | Bin 0 -> 3062 bytes lumina/public/ios/16.png | Bin 0 -> 1447 bytes lumina/public/ios/167.png | Bin 0 -> 3327 bytes lumina/public/ios/180.png | Bin 0 -> 3402 bytes lumina/public/ios/192.png | Bin 0 -> 3591 bytes lumina/public/ios/20.png | Bin 0 -> 1519 bytes lumina/public/ios/256.png | Bin 0 -> 4354 bytes lumina/public/ios/29.png | Bin 0 -> 1636 bytes lumina/public/ios/32.png | Bin 0 -> 1658 bytes lumina/public/ios/40.png | Bin 0 -> 1758 bytes lumina/public/ios/50.png | Bin 0 -> 1854 bytes lumina/public/ios/512.png | Bin 0 -> 7878 bytes lumina/public/ios/57.png | Bin 0 -> 1935 bytes lumina/public/ios/58.png | Bin 0 -> 1929 bytes lumina/public/ios/60.png | Bin 0 -> 2002 bytes lumina/public/ios/64.png | Bin 0 -> 2070 bytes lumina/public/ios/72.png | Bin 0 -> 2160 bytes lumina/public/ios/76.png | Bin 0 -> 2187 bytes lumina/public/ios/80.png | Bin 0 -> 2229 bytes lumina/public/ios/87.png | Bin 0 -> 2297 bytes lumina/public/lumina-lightning.png | Bin 0 -> 733625 bytes lumina/public/lumina.png | Bin 0 -> 781085 bytes lumina/public/manifest.json | 459 ++ lumina/public/sw.js | 101 + lumina/public/sw.js.map | 1 + .../public/windows11/LargeTile.scale-100.png | Bin 0 -> 5076 bytes .../public/windows11/LargeTile.scale-125.png | Bin 0 -> 6001 bytes .../public/windows11/LargeTile.scale-150.png | Bin 0 -> 7096 bytes .../public/windows11/LargeTile.scale-200.png | Bin 0 -> 9262 bytes .../public/windows11/LargeTile.scale-400.png | Bin 0 -> 21018 bytes .../public/windows11/SmallTile.scale-100.png | Bin 0 -> 2118 bytes .../public/windows11/SmallTile.scale-125.png | Bin 0 -> 2297 bytes .../public/windows11/SmallTile.scale-150.png | Bin 0 -> 2485 bytes .../public/windows11/SmallTile.scale-200.png | Bin 0 -> 2929 bytes .../public/windows11/SmallTile.scale-400.png | Bin 0 -> 4692 bytes .../windows11/SplashScreen.scale-100.png | Bin 0 -> 5385 bytes .../windows11/SplashScreen.scale-125.png | Bin 0 -> 6556 bytes .../windows11/SplashScreen.scale-150.png | Bin 0 -> 7952 bytes .../windows11/SplashScreen.scale-200.png | Bin 0 -> 10853 bytes .../windows11/SplashScreen.scale-400.png | Bin 0 -> 26639 bytes .../windows11/Square150x150Logo.scale-100.png | Bin 0 -> 3094 bytes .../windows11/Square150x150Logo.scale-125.png | Bin 0 -> 3503 bytes .../windows11/Square150x150Logo.scale-150.png | Bin 0 -> 3929 bytes .../windows11/Square150x150Logo.scale-200.png | Bin 0 -> 4901 bytes .../windows11/Square150x150Logo.scale-400.png | Bin 0 -> 9061 bytes ...go.altform-lightunplated_targetsize-16.png | Bin 0 -> 1480 bytes ...go.altform-lightunplated_targetsize-20.png | Bin 0 -> 1542 bytes ...go.altform-lightunplated_targetsize-24.png | Bin 0 -> 1602 bytes ...o.altform-lightunplated_targetsize-256.png | Bin 0 -> 4694 bytes ...go.altform-lightunplated_targetsize-30.png | Bin 0 -> 1652 bytes ...go.altform-lightunplated_targetsize-32.png | Bin 0 -> 1671 bytes ...go.altform-lightunplated_targetsize-36.png | Bin 0 -> 1760 bytes ...go.altform-lightunplated_targetsize-40.png | Bin 0 -> 1806 bytes ...go.altform-lightunplated_targetsize-44.png | Bin 0 -> 1884 bytes ...go.altform-lightunplated_targetsize-48.png | Bin 0 -> 1921 bytes ...go.altform-lightunplated_targetsize-60.png | Bin 0 -> 2054 bytes ...go.altform-lightunplated_targetsize-64.png | Bin 0 -> 2112 bytes ...go.altform-lightunplated_targetsize-72.png | Bin 0 -> 2226 bytes ...go.altform-lightunplated_targetsize-80.png | Bin 0 -> 2301 bytes ...go.altform-lightunplated_targetsize-96.png | Bin 0 -> 2524 bytes ...x44Logo.altform-unplated_targetsize-16.png | Bin 0 -> 1480 bytes ...x44Logo.altform-unplated_targetsize-20.png | Bin 0 -> 1542 bytes ...x44Logo.altform-unplated_targetsize-24.png | Bin 0 -> 1602 bytes ...44Logo.altform-unplated_targetsize-256.png | Bin 0 -> 4694 bytes ...x44Logo.altform-unplated_targetsize-30.png | Bin 0 -> 1652 bytes ...x44Logo.altform-unplated_targetsize-32.png | Bin 0 -> 1671 bytes ...x44Logo.altform-unplated_targetsize-36.png | Bin 0 -> 1760 bytes ...x44Logo.altform-unplated_targetsize-40.png | Bin 0 -> 1806 bytes ...x44Logo.altform-unplated_targetsize-44.png | Bin 0 -> 1884 bytes ...x44Logo.altform-unplated_targetsize-48.png | Bin 0 -> 1921 bytes ...x44Logo.altform-unplated_targetsize-60.png | Bin 0 -> 2054 bytes ...x44Logo.altform-unplated_targetsize-64.png | Bin 0 -> 2112 bytes ...x44Logo.altform-unplated_targetsize-72.png | Bin 0 -> 2226 bytes ...x44Logo.altform-unplated_targetsize-80.png | Bin 0 -> 2301 bytes ...x44Logo.altform-unplated_targetsize-96.png | Bin 0 -> 2524 bytes .../windows11/Square44x44Logo.scale-100.png | Bin 0 -> 1884 bytes .../windows11/Square44x44Logo.scale-125.png | Bin 0 -> 2022 bytes .../windows11/Square44x44Logo.scale-150.png | Bin 0 -> 2171 bytes .../windows11/Square44x44Logo.scale-200.png | Bin 0 -> 2436 bytes .../windows11/Square44x44Logo.scale-400.png | Bin 0 -> 3572 bytes .../Square44x44Logo.targetsize-16.png | Bin 0 -> 1480 bytes .../Square44x44Logo.targetsize-20.png | Bin 0 -> 1542 bytes .../Square44x44Logo.targetsize-24.png | Bin 0 -> 1602 bytes .../Square44x44Logo.targetsize-256.png | Bin 0 -> 4694 bytes .../Square44x44Logo.targetsize-30.png | Bin 0 -> 1652 bytes .../Square44x44Logo.targetsize-32.png | Bin 0 -> 1671 bytes .../Square44x44Logo.targetsize-36.png | Bin 0 -> 1760 bytes .../Square44x44Logo.targetsize-40.png | Bin 0 -> 1806 bytes .../Square44x44Logo.targetsize-44.png | Bin 0 -> 1884 bytes .../Square44x44Logo.targetsize-48.png | Bin 0 -> 1921 bytes .../Square44x44Logo.targetsize-60.png | Bin 0 -> 2054 bytes .../Square44x44Logo.targetsize-64.png | Bin 0 -> 2112 bytes .../Square44x44Logo.targetsize-72.png | Bin 0 -> 2226 bytes .../Square44x44Logo.targetsize-80.png | Bin 0 -> 2301 bytes .../Square44x44Logo.targetsize-96.png | Bin 0 -> 2524 bytes .../public/windows11/StoreLogo.scale-100.png | Bin 0 -> 1854 bytes .../public/windows11/StoreLogo.scale-125.png | Bin 0 -> 1993 bytes .../public/windows11/StoreLogo.scale-150.png | Bin 0 -> 2185 bytes .../public/windows11/StoreLogo.scale-200.png | Bin 0 -> 2446 bytes .../public/windows11/StoreLogo.scale-400.png | Bin 0 -> 3705 bytes .../windows11/Wide310x150Logo.scale-100.png | Bin 0 -> 3263 bytes .../windows11/Wide310x150Logo.scale-125.png | Bin 0 -> 3760 bytes .../windows11/Wide310x150Logo.scale-150.png | Bin 0 -> 4216 bytes .../windows11/Wide310x150Logo.scale-200.png | Bin 0 -> 5385 bytes .../windows11/Wide310x150Logo.scale-400.png | Bin 0 -> 10853 bytes lumina/public/workbox-bd7e3b9b.js | 2456 ++++++++++ lumina/public/workbox-bd7e3b9b.js.map | 1 + lumina/types/nav.ts | 6 + 214 files changed, 11930 insertions(+), 377 deletions(-) create mode 100644 .github/workflows/docker-image.yml create mode 100644 kustomize/base/deployment.yaml create mode 100644 kustomize/base/kustomization.yaml create mode 100644 kustomize/base/service.yaml create mode 100644 kustomize/environments/beta/kustomization.yaml create mode 100644 kustomize/environments/prod/kustomization.yaml create mode 100644 lumina/app/dashboard/[pubkey]/page.tsx create mode 100644 lumina/app/feed/page.tsx create mode 100644 lumina/app/global/page.tsx create mode 100644 lumina/app/icon.tsx create mode 100644 lumina/app/login/page.tsx create mode 100644 lumina/app/note/[id]/page.tsx create mode 100644 lumina/app/notifications/page.tsx create mode 100644 lumina/app/onboarding/createProfile/page.tsx create mode 100644 lumina/app/onboarding/page.tsx create mode 100644 lumina/app/profile/settings/page.tsx create mode 100644 lumina/app/reel/page.tsx create mode 100644 lumina/app/search/[searchTag]/page.tsx create mode 100644 lumina/app/search/page.tsx create mode 100644 lumina/components/BottomBar.tsx create mode 100644 lumina/components/CommentCard.tsx create mode 100644 lumina/components/CommentsCompontent.tsx create mode 100644 lumina/components/FollowButton.tsx create mode 100644 lumina/components/FollowerFeed.tsx create mode 100644 lumina/components/FollowerQuickViewFeed.tsx create mode 100644 lumina/components/LoginForm.tsx delete mode 100644 lumina/components/Navigation.tsx create mode 100644 lumina/components/NotePageComponent.tsx create mode 100644 lumina/components/Notification.tsx create mode 100644 lumina/components/Notifications.tsx create mode 100644 lumina/components/ProfileQuickViewFeed.tsx create mode 100644 lumina/components/ProfileTextFeed.tsx create mode 100644 lumina/components/QuickViewNoteCard.tsx create mode 100644 lumina/components/ReactionButtonReactionList.tsx create mode 100644 lumina/components/ReactionButtonReactionListItem.tsx create mode 100644 lumina/components/ReelFeed.tsx create mode 100644 lumina/components/Search.tsx create mode 100644 lumina/components/TrendingAccount.tsx create mode 100644 lumina/components/TrendingImage.tsx create mode 100644 lumina/components/TrendingImages.tsx create mode 100644 lumina/components/UpdateProfileForm.tsx create mode 100644 lumina/components/ViewCopyButton.tsx create mode 100644 lumina/components/ViewNoteButton.tsx create mode 100644 lumina/components/ZapButton.tsx create mode 100644 lumina/components/ZapButtonList.tsx create mode 100644 lumina/components/ZapButtonListItem.tsx create mode 100644 lumina/components/dashboard/RecentFollower.tsx create mode 100644 lumina/components/dashboard/RecentFollowerCard.tsx create mode 100644 lumina/components/dashboard/RecentZap.tsx create mode 100644 lumina/components/dashboard/RecentZapsCard.tsx create mode 100644 lumina/components/dashboard/Statistics.tsx create mode 100644 lumina/components/headerComponents/AvatarDropdown.tsx rename lumina/components/{ => headerComponents}/DropdownThemeMode.tsx (100%) create mode 100644 lumina/components/headerComponents/LoginButton.tsx create mode 100644 lumina/components/headerComponents/RegisterButton.tsx create mode 100644 lumina/components/headerComponents/TopNavigation.tsx create mode 100644 lumina/components/headerComponents/TopNavigationItems.tsx create mode 100644 lumina/components/icons.tsx create mode 100644 lumina/components/nip05.tsx create mode 100644 lumina/components/onboarding/createSecretKeyForm.tsx create mode 100644 lumina/components/searchComponents/SearchNotesBox.tsx create mode 100644 lumina/components/searchComponents/SearchProfilesBox.tsx create mode 100644 lumina/components/ui/accordion.tsx create mode 100644 lumina/components/ui/dialog.tsx create mode 100644 lumina/components/ui/form.tsx create mode 100644 lumina/components/ui/input.tsx create mode 100644 lumina/components/ui/label.tsx create mode 100644 lumina/components/ui/scroll-area.tsx create mode 100644 lumina/components/ui/toast.tsx create mode 100644 lumina/components/ui/toaster.tsx create mode 100644 lumina/components/ui/use-toast.ts create mode 100644 lumina/config/site.ts create mode 100644 lumina/public/.well-known/nostr.json create mode 100644 lumina/public/android/android-launchericon-144-144.png create mode 100644 lumina/public/android/android-launchericon-192-192.png create mode 100644 lumina/public/android/android-launchericon-48-48.png create mode 100644 lumina/public/android/android-launchericon-512-512.png create mode 100644 lumina/public/android/android-launchericon-72-72.png create mode 100644 lumina/public/android/android-launchericon-96-96.png create mode 100644 lumina/public/icons.json create mode 100644 lumina/public/ios/100.png create mode 100644 lumina/public/ios/1024.png create mode 100644 lumina/public/ios/114.png create mode 100644 lumina/public/ios/120.png create mode 100644 lumina/public/ios/128.png create mode 100644 lumina/public/ios/144.png create mode 100644 lumina/public/ios/152.png create mode 100644 lumina/public/ios/16.png create mode 100644 lumina/public/ios/167.png create mode 100644 lumina/public/ios/180.png create mode 100644 lumina/public/ios/192.png create mode 100644 lumina/public/ios/20.png create mode 100644 lumina/public/ios/256.png create mode 100644 lumina/public/ios/29.png create mode 100644 lumina/public/ios/32.png create mode 100644 lumina/public/ios/40.png create mode 100644 lumina/public/ios/50.png create mode 100644 lumina/public/ios/512.png create mode 100644 lumina/public/ios/57.png create mode 100644 lumina/public/ios/58.png create mode 100644 lumina/public/ios/60.png create mode 100644 lumina/public/ios/64.png create mode 100644 lumina/public/ios/72.png create mode 100644 lumina/public/ios/76.png create mode 100644 lumina/public/ios/80.png create mode 100644 lumina/public/ios/87.png create mode 100644 lumina/public/lumina-lightning.png create mode 100644 lumina/public/lumina.png create mode 100644 lumina/public/manifest.json create mode 100644 lumina/public/sw.js create mode 100644 lumina/public/sw.js.map create mode 100644 lumina/public/windows11/LargeTile.scale-100.png create mode 100644 lumina/public/windows11/LargeTile.scale-125.png create mode 100644 lumina/public/windows11/LargeTile.scale-150.png create mode 100644 lumina/public/windows11/LargeTile.scale-200.png create mode 100644 lumina/public/windows11/LargeTile.scale-400.png create mode 100644 lumina/public/windows11/SmallTile.scale-100.png create mode 100644 lumina/public/windows11/SmallTile.scale-125.png create mode 100644 lumina/public/windows11/SmallTile.scale-150.png create mode 100644 lumina/public/windows11/SmallTile.scale-200.png create mode 100644 lumina/public/windows11/SmallTile.scale-400.png create mode 100644 lumina/public/windows11/SplashScreen.scale-100.png create mode 100644 lumina/public/windows11/SplashScreen.scale-125.png create mode 100644 lumina/public/windows11/SplashScreen.scale-150.png create mode 100644 lumina/public/windows11/SplashScreen.scale-200.png create mode 100644 lumina/public/windows11/SplashScreen.scale-400.png create mode 100644 lumina/public/windows11/Square150x150Logo.scale-100.png create mode 100644 lumina/public/windows11/Square150x150Logo.scale-125.png create mode 100644 lumina/public/windows11/Square150x150Logo.scale-150.png create mode 100644 lumina/public/windows11/Square150x150Logo.scale-200.png create mode 100644 lumina/public/windows11/Square150x150Logo.scale-400.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-16.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-20.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-24.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-256.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-30.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-32.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-36.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-40.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-44.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-48.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-60.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-64.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-72.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-80.png create mode 100644 lumina/public/windows11/Square44x44Logo.altform-unplated_targetsize-96.png create mode 100644 lumina/public/windows11/Square44x44Logo.scale-100.png create mode 100644 lumina/public/windows11/Square44x44Logo.scale-125.png create mode 100644 lumina/public/windows11/Square44x44Logo.scale-150.png create mode 100644 lumina/public/windows11/Square44x44Logo.scale-200.png create mode 100644 lumina/public/windows11/Square44x44Logo.scale-400.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-16.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-20.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-24.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-256.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-30.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-32.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-36.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-40.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-44.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-48.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-60.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-64.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-72.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-80.png create mode 100644 lumina/public/windows11/Square44x44Logo.targetsize-96.png create mode 100644 lumina/public/windows11/StoreLogo.scale-100.png create mode 100644 lumina/public/windows11/StoreLogo.scale-125.png create mode 100644 lumina/public/windows11/StoreLogo.scale-150.png create mode 100644 lumina/public/windows11/StoreLogo.scale-200.png create mode 100644 lumina/public/windows11/StoreLogo.scale-400.png create mode 100644 lumina/public/windows11/Wide310x150Logo.scale-100.png create mode 100644 lumina/public/windows11/Wide310x150Logo.scale-125.png create mode 100644 lumina/public/windows11/Wide310x150Logo.scale-150.png create mode 100644 lumina/public/windows11/Wide310x150Logo.scale-200.png create mode 100644 lumina/public/windows11/Wide310x150Logo.scale-400.png create mode 100644 lumina/public/workbox-bd7e3b9b.js create mode 100644 lumina/public/workbox-bd7e3b9b.js.map create mode 100644 lumina/types/nav.ts diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..b9467d1 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,61 @@ +name: Docker Build and Push + +on: + workflow_dispatch: + push: + branches: + - main + - master + +env: + REGISTRY_NAME: ghcr.io + IMAGE_NAME: lumina + +jobs: + # ci: + # name: CI + # uses: ./.github/workflows/ci.yml + + build_and_push: + # needs: [ci] + name: Build and Push + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Collecting Metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY_NAME }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + + - name: Building And Pushing Image + id: docker_build + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 83fb74e..c42e560 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine as builder +FROM node:21-alpine3.18 as builder WORKDIR /app COPY lumina/package.json lumina/package-lock.json ./ @@ -6,7 +6,7 @@ RUN npm ci COPY ./lumina/ . RUN npm run build -FROM node:18-alpine as runner +FROM node:21-alpine3.18 as runner WORKDIR /app COPY --from=builder /app/package.json . COPY --from=builder /app/package-lock.json . diff --git a/README.md b/README.md index 7850f12..b602fcb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ -# lumina -A Nostr Client for scrolling through Images on nostr +# lumina.rocks + +A social media for images and pictures 📸 + +## Docker +### Quickstart +`docker run --rm -it -p 3000:3000 ghcr.io/mroxso/lumina-rocks-website:latest` \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 2cf66fa..40d6f4c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,7 +1,7 @@ version: '3' services: - lumina: + lumina-rocks-website: build: . - # image: ghcr.io/lumina-rocks/lumina:latest + # image: ghcr.io/mroxso/lumina-rocks-website:latest ports: - "8080:3000" \ No newline at end of file diff --git a/kustomize/base/deployment.yaml b/kustomize/base/deployment.yaml new file mode 100644 index 0000000..5d43bf4 --- /dev/null +++ b/kustomize/base/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lumina-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: lumina + template: + metadata: + labels: + app: lumina + spec: + containers: + - name: lumina + image: ghcr.io/lumina-rocks/lumina:latest + ports: + - containerPort: 80 diff --git a/kustomize/base/kustomization.yaml b/kustomize/base/kustomization.yaml new file mode 100644 index 0000000..6d1374a --- /dev/null +++ b/kustomize/base/kustomization.yaml @@ -0,0 +1,3 @@ +resources: + - deployment.yaml + - service.yaml diff --git a/kustomize/base/service.yaml b/kustomize/base/service.yaml new file mode 100644 index 0000000..62907a4 --- /dev/null +++ b/kustomize/base/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-app +spec: + selector: + app: my-app + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/kustomize/environments/beta/kustomization.yaml b/kustomize/environments/beta/kustomization.yaml new file mode 100644 index 0000000..fb7dc89 --- /dev/null +++ b/kustomize/environments/beta/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - ../../base diff --git a/kustomize/environments/prod/kustomization.yaml b/kustomize/environments/prod/kustomization.yaml new file mode 100644 index 0000000..fb7dc89 --- /dev/null +++ b/kustomize/environments/prod/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - ../../base diff --git a/lumina/app/dashboard/[pubkey]/page.tsx b/lumina/app/dashboard/[pubkey]/page.tsx new file mode 100644 index 0000000..fdc92fb --- /dev/null +++ b/lumina/app/dashboard/[pubkey]/page.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { useParams } from 'next/navigation' +import { nip19 } from "nostr-tools"; +import { NostrProvider } from "nostr-react"; +import Statistics from '@/components/dashboard/Statistics'; + +const DashboardPage: React.FC= ({ }) => { + + const params = useParams() + let pubkey = params.pubkey + // check if pubkey contains "npub" + // if so, then we need to convert it to a pubkey + if (pubkey.includes("npub")) { + // convert npub to pubkey + pubkey = nip19.decode(pubkey.toString()).data.toString() + } + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + + + + + ); +} + +export default DashboardPage; \ No newline at end of file diff --git a/lumina/app/feed/page.tsx b/lumina/app/feed/page.tsx new file mode 100644 index 0000000..9862352 --- /dev/null +++ b/lumina/app/feed/page.tsx @@ -0,0 +1,61 @@ +'use client'; + +import Head from "next/head"; +import ProfileInfoCard from "@/components/ProfileInfoCard"; +import ProfileFeed from "@/components/ProfileFeed"; +import { useParams } from 'next/navigation' +import { nip19 } from "nostr-tools"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { SectionIcon, GridIcon } from '@radix-ui/react-icons' +import TagFeed from "@/components/TagFeed"; +import { NostrProvider } from "nostr-react"; +import FollowerFeed from "@/components/FollowerFeed"; +import ProfileQuickViewFeed from "@/components/ProfileQuickViewFeed"; +import FollowerQuickViewFeed from "@/components/FollowerQuickViewFeed"; + +export default function FeedPage() { + + let pubkey = null; + if (typeof window !== 'undefined') { + pubkey = window.localStorage.getItem('pubkey'); + } + + // check if pubkey contains "npub" + // if so, then we need to convert it to a pubkey + // if (pubkey.includes("npub")) { + // // convert npub to pubkey + // pubkey = nip19.decode(pubkey.toString()).data.toString() + // } + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + + + LUMINA.rocks - {pubkey} + + + + +
+

Follower Feed

+ + + + + + + + + + + + +
+
+ + ); +} diff --git a/lumina/app/global/page.tsx b/lumina/app/global/page.tsx new file mode 100644 index 0000000..597578b --- /dev/null +++ b/lumina/app/global/page.tsx @@ -0,0 +1,32 @@ +"use client"; + +import GlobalFeed from "@/components/GlobalFeed"; +import { NostrProvider } from "nostr-react"; + +export default function Home() { + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + //
+ //
+ // + // + // + // + // + // Home + // + // + // + // + // + +
+ +
+
+ ); +} diff --git a/lumina/app/icon.tsx b/lumina/app/icon.tsx new file mode 100644 index 0000000..6e49223 --- /dev/null +++ b/lumina/app/icon.tsx @@ -0,0 +1,40 @@ +import { ImageResponse } from 'next/og' + +// Route segment config +export const runtime = 'edge' + +// Image metadata +export const size = { + width: 32, + height: 32, +} +export const contentType = 'image/png' + +// Image generation +export default function Icon() { + return new ImageResponse( + ( + // ImageResponse JSX element +
+ L +
+ ), + // ImageResponse options + { + // For convenience, we can re-use the exported icons size metadata + // config to also set the ImageResponse's width and height. + ...size, + } + ) +} \ No newline at end of file diff --git a/lumina/app/layout.tsx b/lumina/app/layout.tsx index ccf0699..7b3fe80 100644 --- a/lumina/app/layout.tsx +++ b/lumina/app/layout.tsx @@ -1,17 +1,21 @@ -import type { Metadata } from "next"; -import { Inter } from "next/font/google"; +import { Metadata } from "next"; import "./globals.css"; +import { NostrProvider } from "nostr-react"; +import Head from "next/head"; import { ThemeProvider } from "@/components/theme-provider"; -import { DropdownThemeMode } from "@/components/DropdownThemeMode"; -import { Navigation } from "@/components/Navigation"; - -const inter = Inter({ subsets: ["latin"] }); +import { TopNavigation } from "@/components/headerComponents/TopNavigation"; +import BottomBar from "@/components/BottomBar"; +import { Inter } from "next/font/google"; +import { Toaster } from "@/components/ui/toaster" export const metadata: Metadata = { title: "LUMINA", - description: "LUMINA.rocks", + description: "An effortless, enjoyable, and innovative way to capture, enhance, and share moments with everyone, decentralized and boundless.", + manifest: "/manifest.json", }; +const inter = Inter({ subsets: ["latin"] }); + export default function RootLayout({ children, }: Readonly<{ @@ -19,6 +23,10 @@ export default function RootLayout({ }>) { return ( + + + + - - {children} + + +
+ {children} +
+
diff --git a/lumina/app/login/page.tsx b/lumina/app/login/page.tsx new file mode 100644 index 0000000..fabcf76 --- /dev/null +++ b/lumina/app/login/page.tsx @@ -0,0 +1,20 @@ +'use client'; + +import Head from "next/head"; +import { LoginForm } from "@/components/LoginForm"; + +export default function LoginPage() { + return ( + <> + + LUMINA.rocks - Login + + + + +
+ +
+ + ); +} diff --git a/lumina/app/note/[id]/page.tsx b/lumina/app/note/[id]/page.tsx new file mode 100644 index 0000000..cbdc230 --- /dev/null +++ b/lumina/app/note/[id]/page.tsx @@ -0,0 +1,39 @@ +'use client'; + +import Head from "next/head"; +import { useParams } from 'next/navigation' +import NotePageComponent from "@/components/NotePageComponent"; +import { nip19 } from "nostr-tools"; +import { NostrProvider } from "nostr-react"; + +export default function NotePage() { + + const params = useParams() + let id = params.id + + if (id.includes("note1")) { + id = nip19.decode(id.toString()).data.toString() + } + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + + + LUMINA.rocks - {id} + + + + +
+
+ +
+
+
+ + ); +} diff --git a/lumina/app/notifications/page.tsx b/lumina/app/notifications/page.tsx new file mode 100644 index 0000000..05bd74a --- /dev/null +++ b/lumina/app/notifications/page.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { nip19 } from "nostr-tools"; +import { NostrProvider } from "nostr-react"; +import Notifications from '@/components/Notifications'; + +const NotificationsPage: React.FC= ({ }) => { + let pubkey = ''; + + if (typeof window !== 'undefined') { + pubkey = window.localStorage.getItem("pubkey") ?? ''; + } + + // check if pubkey contains "npub" + // if so, then we need to convert it to a pubkey + if (pubkey.includes("npub")) { + // convert npub to pubkey + pubkey = nip19.decode(pubkey.toString()).data.toString() + } + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + + + + + ); +} + +export default NotificationsPage; \ No newline at end of file diff --git a/lumina/app/onboarding/createProfile/page.tsx b/lumina/app/onboarding/createProfile/page.tsx new file mode 100644 index 0000000..7bc560c --- /dev/null +++ b/lumina/app/onboarding/createProfile/page.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { UpdateProfileForm } from "@/components/UpdateProfileForm"; +import { NostrProvider } from "nostr-react"; + + +export default function OnboardingCreateProfile() { + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + +
+

Step 2: Create Profile

+ +
+
+ + ); +} diff --git a/lumina/app/onboarding/page.tsx b/lumina/app/onboarding/page.tsx new file mode 100644 index 0000000..1c7e644 --- /dev/null +++ b/lumina/app/onboarding/page.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { CreateSecretKeyForm } from "@/components/onboarding/createSecretKeyForm"; +import { Button } from "@/components/ui/button"; +import { NostrProvider } from "nostr-react"; + + +export default function OnboardingHome() { + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + +
+

Step 1: Create your secret key

+ +
+
+ + ); +} diff --git a/lumina/app/page.tsx b/lumina/app/page.tsx index 04900de..e3587b4 100644 --- a/lumina/app/page.tsx +++ b/lumina/app/page.tsx @@ -1,36 +1,26 @@ "use client"; -import { Button } from "@/components/ui/button"; -import Image from "next/image"; -import Link from "next/link"; -import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle } from "@/components/ui/navigation-menu"; -import GlobalFeed from "@/components/GlobalFeed"; +import { Search } from "@/components/Search"; +import { TrendingAccounts } from "@/components/TrendingAccounts"; +import { TrendingImages } from "@/components/TrendingImages"; import { NostrProvider } from "nostr-react"; -const relayUrls = [ - "wss://relay.damus.io", - "wss://relay.nostr.band", -]; export default function Home() { + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + return ( - //
- //
- // - // - // - // - // - // Home - // - // - // - // - // - -
- -
-
+ <> + +
+ +
+ {/* */} + +
+ ); } diff --git a/lumina/app/profile/[pubkey]/page.tsx b/lumina/app/profile/[pubkey]/page.tsx index afb9a33..91b628e 100644 --- a/lumina/app/profile/[pubkey]/page.tsx +++ b/lumina/app/profile/[pubkey]/page.tsx @@ -1,20 +1,16 @@ 'use client'; -import Head from "next/head"; -import { NostrProvider } from "nostr-react"; import ProfileInfoCard from "@/components/ProfileInfoCard"; import ProfileFeed from "@/components/ProfileFeed"; import { useParams } from 'next/navigation' import { nip19 } from "nostr-tools"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { SectionIcon, GridIcon } from '@radix-ui/react-icons' +import ProfileQuickViewFeed from "@/components/ProfileQuickViewFeed"; +import ProfileTextFeed from "@/components/ProfileTextFeed"; +import { NostrProvider } from "nostr-react"; -const relayUrls = [ - "wss://relay.damus.io", - "wss://relay.nostr.band", -]; - -export default function Home() { +export default function ProfilePage() { const params = useParams() let pubkey = params.pubkey @@ -25,28 +21,32 @@ export default function Home() { pubkey = nip19.decode(pubkey.toString()).data.toString() } + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + return ( <> - - - LUMINA.rocks - {pubkey} - - - - -
-
+ +
+
- - - + + + + Notes + + + - QuickView coming soon. + + +
diff --git a/lumina/app/profile/settings/page.tsx b/lumina/app/profile/settings/page.tsx new file mode 100644 index 0000000..3fc67d0 --- /dev/null +++ b/lumina/app/profile/settings/page.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { useParams } from 'next/navigation' +import { nip19 } from "nostr-tools"; +import { NostrProvider } from "nostr-react"; +import { UpdateProfileForm } from "@/components/UpdateProfileForm"; + +export default function ProfileSettingsPage() { + + let pubkey = null; + if (typeof window !== 'undefined') { + pubkey = window.localStorage.getItem('pubkey'); + } + // check if pubkey is not null and contains "npub" + // if so, then we need to convert it to a pubkey + if (pubkey && pubkey.includes("npub")) { + // convert npub to pubkey + pubkey = nip19.decode(pubkey.toString()).data.toString() + } + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + +
+ +
+
+ + ); +} diff --git a/lumina/app/reel/page.tsx b/lumina/app/reel/page.tsx new file mode 100644 index 0000000..313a8cd --- /dev/null +++ b/lumina/app/reel/page.tsx @@ -0,0 +1,31 @@ +"use client"; + +import ReelFeed from "@/components/ReelFeed" +import { NostrProvider } from "nostr-react"; + +export default function ReelPage() { + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + //
+ //
+ // + // + // + // + // + // Home + // + // + // + // + // + +
+ +
+
+ ); +} diff --git a/lumina/app/search/[searchTag]/page.tsx b/lumina/app/search/[searchTag]/page.tsx new file mode 100644 index 0000000..6d420b2 --- /dev/null +++ b/lumina/app/search/[searchTag]/page.tsx @@ -0,0 +1,57 @@ +'use client'; + +import Head from "next/head"; +import ProfileInfoCard from "@/components/ProfileInfoCard"; +import ProfileFeed from "@/components/ProfileFeed"; +import { useParams } from 'next/navigation' +import { nip19 } from "nostr-tools"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { SectionIcon, GridIcon } from '@radix-ui/react-icons' +import TagFeed from "@/components/TagFeed"; +import { NostrProvider } from "nostr-react"; +import FollowerFeed from "@/components/FollowerFeed"; +import ProfileQuickViewFeed from "@/components/ProfileQuickViewFeed"; +import FollowerQuickViewFeed from "@/components/FollowerQuickViewFeed"; +import SearchProfilesBox from "@/components/searchComponents/SearchProfilesBox"; +import SearchNotesBox from "@/components/searchComponents/SearchNotesBox"; + +export default function SearchPage() { + + let pubkey = null; + if (typeof window !== 'undefined') { + pubkey = window.localStorage.getItem('pubkey'); + } + + const params = useParams() + let searchTag = params.searchTag + + // check if pubkey contains "npub" + // if so, then we need to convert it to a pubkey + // if (pubkey.includes("npub")) { + // // convert npub to pubkey + // pubkey = nip19.decode(pubkey.toString()).data.toString() + // } + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + + + LUMINA.rocks + + + + +
+
+ + +
+
+
+ + ); +} diff --git a/lumina/app/search/page.tsx b/lumina/app/search/page.tsx new file mode 100644 index 0000000..aad638c --- /dev/null +++ b/lumina/app/search/page.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { Search } from "@/components/Search"; +import { TrendingAccounts } from "@/components/TrendingAccounts"; +import { TrendingImages } from "@/components/TrendingImages"; +import { NostrProvider } from "nostr-react"; + + +export default function SearchMainPage() { + + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + + return ( + <> + +
+ +
+
+ + ); +} diff --git a/lumina/app/tag/[tag]/page.tsx b/lumina/app/tag/[tag]/page.tsx index 6a5512e..c163188 100644 --- a/lumina/app/tag/[tag]/page.tsx +++ b/lumina/app/tag/[tag]/page.tsx @@ -1,7 +1,6 @@ 'use client'; import Head from "next/head"; -import { NostrProvider } from "nostr-react"; import ProfileInfoCard from "@/components/ProfileInfoCard"; import ProfileFeed from "@/components/ProfileFeed"; import { useParams } from 'next/navigation' @@ -9,11 +8,7 @@ import { nip19 } from "nostr-tools"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { SectionIcon, GridIcon } from '@radix-ui/react-icons' import TagFeed from "@/components/TagFeed"; - -const relayUrls = [ - "wss://relay.damus.io", - "wss://relay.nostr.band", -]; +import { NostrProvider } from "nostr-react"; export default function Home() { @@ -26,9 +21,13 @@ export default function Home() { // pubkey = nip19.decode(pubkey.toString()).data.toString() // } + const relayUrls = [ + "wss://relay.lumina.rocks", + ]; + return ( <> - + LUMINA.rocks - {tag} diff --git a/lumina/bun.lockb b/lumina/bun.lockb index 03a51a84131679df1812aa0592f9cd8ebe660ae3..a8ca6e21d89ac163b757affa9b9cf4bd089cc085 100755 GIT binary patch literal 321868 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 P9IjUl0)${lB2onfE_mog1VKST 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 + + useEffect(() => { + return setPubkey(window.localStorage.getItem('pubkey') ?? null); + }, []); + + const pathname = usePathname(); + const isActive = (path: string, currentPath: string) => currentPath === path ? 'text-purple-500' : ''; + + return ( + + ) +} \ No newline at end of file diff --git a/lumina/components/CommentCard.tsx b/lumina/components/CommentCard.tsx new file mode 100644 index 0000000..86c766c --- /dev/null +++ b/lumina/components/CommentCard.tsx @@ -0,0 +1,123 @@ +import React from 'react'; +import { useProfile } from "nostr-react"; +import { + nip19, +} from "nostr-tools"; +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" +import { + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from "@/components/ui/carousel" +import ReactionButton from '@/components/ReactionButton'; +import { Avatar, AvatarImage } from '@/components/ui/avatar'; +import ViewRawButton from '@/components/ViewRawButton'; +import ViewNoteButton from './ViewNoteButton'; +import Link from 'next/link'; + +interface CommentCardProps { + pubkey: string; + text: string; + eventId: string; + tags: string[][]; + event: any; +} + +const NoteCard: React.FC = ({ pubkey, text, eventId, tags, event }) => { + const { data: userData } = useProfile({ + pubkey, + }); + + const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || nip19.npubEncode(pubkey); + const imageSrc = text.match(/https?:\/\/[^ ]*\.(png|jpg|gif)/g); + const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif)/g, ''); + const createdAt = new Date(event.created_at * 1000); + const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`; + const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey; + + return ( + <> + + + + + + + +
+ + + + {title} +
+
+ +

{title}

+
+
+
+ +
+
+ +
+ { +
+ {imageSrc && imageSrc.length > 1 ? ( + + + {imageSrc.map((src, index) => ( + + + + ))} + + + + + ) : ( + imageSrc ? : "" + )} +
+ } +
+
+ {textWithoutImage} +
+
+
+
+
+ +
+ +
+
+ + {createdAt.toLocaleString()} + +
+ + ); +} + +export default NoteCard; \ No newline at end of file diff --git a/lumina/components/CommentsCompontent.tsx b/lumina/components/CommentsCompontent.tsx new file mode 100644 index 0000000..8f913a2 --- /dev/null +++ b/lumina/components/CommentsCompontent.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { useNostrEvents } from "nostr-react"; +import { + nip19, +} from "nostr-tools"; +import CommentCard from '@/components/CommentCard'; + +interface CommentsCompontentProps { + pubkey: string; + event: any; +} + +const CommentsCompontent: React.FC = ({ pubkey, event }) => { + + const { events } = useNostrEvents({ + filter: { + kinds: [1], + '#e': [event.id], + }, + }); + + return ( + <> +

Comments

+ {events.map((event) => ( +
+ +
+ ))} + + ); +} + +export default CommentsCompontent; \ No newline at end of file diff --git a/lumina/components/FollowButton.tsx b/lumina/components/FollowButton.tsx new file mode 100644 index 0000000..a70001c --- /dev/null +++ b/lumina/components/FollowButton.tsx @@ -0,0 +1,97 @@ + +import React, { useEffect, useState } from 'react'; +import { Button } from './ui/button'; +import { useNostr, useNostrEvents } from 'nostr-react'; +import { finalizeEvent } from 'nostr-tools'; +import { sign } from 'crypto'; +import { SignalMedium } from 'lucide-react'; + +interface FollowButtonProps { + pubkey: string; + userPubkey: string; +} + +const FollowButton: React.FC = ({ pubkey, userPubkey }) => { + // const { publish } = useNostr(); + const [isFollowing, setIsFollowing] = useState(false); + + let storedPubkey: string | null = null; + let storedNsec: string | null = null; + let isLoggedIn = false; + if (typeof window !== 'undefined') { + storedPubkey = window.localStorage.getItem('pubkey'); + storedNsec = window.localStorage.getItem('nsec'); + isLoggedIn = storedPubkey !== null; + } + + const { events } = useNostrEvents({ + filter: { + kinds: [3], + authors: [userPubkey], + limit: 1, + }, + }); + + let followingPubkeys = events.flatMap((event) => event.tags.map(tag => tag[1])); + // filter out all null or undefined + followingPubkeys = followingPubkeys.filter((tag) => tag); + + + useEffect(() => { + if (followingPubkeys.includes(pubkey)) { + setIsFollowing(true); + } + }, [followingPubkeys, isFollowing, setIsFollowing]); + + const handleFollow = async () => { + // if (isLoggedIn) { + + // let eventTemplate = { + // kind: 3, + // created_at: Math.floor(Date.now() / 1000), + // tags: [followingPubkeys], + // content: '', + // } + + // console.log(eventTemplate); + + // if (isFollowing) { + // eventTemplate.tags = eventTemplate.tags.filter(tag => tag[1] !== pubkey); + // } else { + // eventTemplate.tags[0].push(pubkey); + // } + + // console.log(eventTemplate); + + // let signedEvent = null; + // if (storedNsec != null) { + // // TODO: Sign Nostr Event with nsec + // const nsecArray = storedNsec ? new TextEncoder().encode(storedNsec) : new Uint8Array(); + // signedEvent = finalizeEvent(eventTemplate, nsecArray); + // console.log(signedEvent); + // } else if (storedPubkey != null) { + // // TODO: Request Extension to sign Nostr Event + // console.log('Requesting Extension to sign Nostr Event..'); + // try { + // signedEvent = await window.nostr.signEvent(eventTemplate); + // } catch (error) { + // console.error('Nostr Extension not found or aborted.'); + // } + // } + + // if (signedEvent !== null) { + // console.log(signedEvent); + // publish(signedEvent); + // setIsFollowing(!isFollowing); + // } + // } + }; + + return ( + + ); +}; + +export default FollowButton; \ No newline at end of file diff --git a/lumina/components/FollowerFeed.tsx b/lumina/components/FollowerFeed.tsx new file mode 100644 index 0000000..4a36966 --- /dev/null +++ b/lumina/components/FollowerFeed.tsx @@ -0,0 +1,54 @@ +import { useRef } from "react"; +import { useNostrEvents, dateToUnix } from "nostr-react"; +import NoteCard from './NoteCard'; + +interface FollowerFeedProps { + pubkey: string; +} + +const FollowerFeed: React.FC = ({ pubkey }) => { + const now = useRef(new Date()); // Make sure current time isn't re-rendered + + const { events: following, isLoading: followingLoading } = useNostrEvents({ + filter: { + kinds: [3], + authors: [pubkey], + limit: 1, + }, + }); + // let followingPubkeys = following.map((event) => event.tags[event.tags.length - 1][1]); + // let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 50); + let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 500); + + const { events } = useNostrEvents({ + filter: { + // since: dateToUnix(now.current), // all new events from now + // since: 0, + limit: 1000, + kinds: [1], + authors: followingPubkeys, + }, + }); + + // const filteredEvents = events.filter((event) => event.content.includes(".jpg")); + // filter events with regex that checks for png, jpg, or gif + let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm)/g)?.[0]); + + // now filter all events with a tag[0] == t and tag[1] == nsfw + filteredEvents = filteredEvents.filter((event) => event.tags.map((tag) => tag[0] == "t" && tag[1] == "nsfw")); + // filter out all replies + filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' })); + + return ( + <> + {filteredEvents.map((event) => ( + //

{event.pubkey} posted: {event.content}

+
+ +
+ ))} + + ); +} + +export default FollowerFeed; \ No newline at end of file diff --git a/lumina/components/FollowerQuickViewFeed.tsx b/lumina/components/FollowerQuickViewFeed.tsx new file mode 100644 index 0000000..8f4c002 --- /dev/null +++ b/lumina/components/FollowerQuickViewFeed.tsx @@ -0,0 +1,73 @@ +import { useRef } from "react"; +import { useNostrEvents, dateToUnix } from "nostr-react"; +import { Skeleton } from "@/components/ui/skeleton"; +import QuickViewNoteCard from "./QuickViewNoteCard"; + +interface FollowerQuickViewFeedProps { + pubkey: string; +} + +const FollowerQuickViewFeed: React.FC = ({ pubkey }) => { + const now = useRef(new Date()); // Make sure current time isn't re-rendered + + const { events: following, isLoading: followingLoading } = useNostrEvents({ + filter: { + kinds: [3], + authors: [pubkey], + limit: 1, + }, + }); + // let followingPubkeys = following.map((event) => event.tags[event.tags.length - 1][1]); + // let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 50); + let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 500); + + const { events } = useNostrEvents({ + filter: { + // since: dateToUnix(now.current), // all new events from now + // since: 0, + limit: 1000, + kinds: [1], + authors: followingPubkeys, + }, + }); + + let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]); + // filter out all replies (tag[0] == e) + filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' })); + + return ( + <> +
+ {filteredEvents.length === 0 ? ( + <> +
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + ) : (filteredEvents.map((event) => ( + + )))} +
+ + ); +} + +export default FollowerQuickViewFeed; \ No newline at end of file diff --git a/lumina/components/GlobalFeed.tsx b/lumina/components/GlobalFeed.tsx index c4b376a..e09a0fa 100644 --- a/lumina/components/GlobalFeed.tsx +++ b/lumina/components/GlobalFeed.tsx @@ -30,7 +30,7 @@ const GlobalFeed: React.FC = () => { {filteredEvents.map((event) => ( //

{event.pubkey} posted: {event.content}

- +
))} diff --git a/lumina/components/LoginForm.tsx b/lumina/components/LoginForm.tsx new file mode 100644 index 0000000..9033685 --- /dev/null +++ b/lumina/components/LoginForm.tsx @@ -0,0 +1,189 @@ +declare global { + interface Window { + nostr: any; + } +} + +import { Button } from "@/components/ui/button" +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion" +import { useEffect, useRef } from "react" +import { getPublicKey, generateSecretKey, nip19 } from 'nostr-tools' +import { InfoIcon } from "lucide-react"; +import Link from "next/link"; +import { bytesToHex, hexToBytes } from '@noble/hashes/utils' + +export function LoginForm() { + + let publicKey = useRef(null); + let nsecInput = useRef(null); + let npubInput = useRef(null); + + useEffect(() => { + // handle Amber Login Response + const urlParams = new URLSearchParams(window.location.search); + const amberResponse = urlParams.get('amberResponse'); + if (amberResponse !== null) { + localStorage.setItem("pubkey", nip19.decode(amberResponse).data.toString()); + localStorage.setItem("loginType", "amber"); + window.location.href = `/profile/${amberResponse}`; + } + }, []); + + + const handleAmber = async () => { + const hostname = window.location.host; + console.log(hostname); + if (!hostname) { + throw new Error("Hostname is null or undefined"); + } + const intent = `intent:#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=get_public_key;S.callbackUrl=http://${hostname}/login?amberResponse=;end`; + window.location.href = intent; + } + + const handleExtensionLogin = async () => { + // eslint-disable-next-line + if (window.nostr !== undefined) { + publicKey.current = await window.nostr.getPublicKey() + console.log("Logged in with pubkey: ", publicKey.current); + if (publicKey.current !== null) { + localStorage.setItem("pubkey", publicKey.current); + localStorage.setItem("loginType", "extension"); + // window.location.reload(); + window.location.href = `/profile/${nip19.npubEncode(publicKey.current)}`; + } + } + }; + + // const handleNsecSignUp = async () => { + // let nsec = generateSecretKey(); + // console.log('nsec: ' + nsec); + + // let nsecHex = bytesToHex(nsec); + // console.log('bytesToHex nsec: ' + nsecHex); + + // let pubkey = getPublicKey(nsec); + // console.log('pubkey: ' + pubkey); + + // localStorage.setItem("nsec", nsecHex); + // localStorage.setItem("pubkey", pubkey); + // localStorage.setItem("loginType", "raw_nsec") + // window.location.href = `/profile/${nip19.npubEncode(pubkey)}`; + // }; + + const handleNsecLogin = async () => { + if (nsecInput.current !== null) { + try { + let input = nsecInput.current.value; + if(input.includes("nsec")) { + input = bytesToHex(nip19.decode(input).data as Uint8Array); + console.log('decoded nsec: ' + input); + } + let nsecBytes = hexToBytes(input); + let nsecHex = bytesToHex(nsecBytes); + let pubkey = getPublicKey(nsecBytes); + + localStorage.setItem("nsec", nsecHex); + localStorage.setItem("pubkey", pubkey); + localStorage.setItem("loginType", "raw_nsec") + + window.location.href = `/profile/${nip19.npubEncode(pubkey)}`; + } catch (e) { + console.error(e); + } + } + }; + + const handleNpubLogin = async () => { + if (npubInput.current !== null) { + try { + let input = npubInput.current.value; + let npub = null; + let pubkey = null; + if(input.startsWith("npub1")) { + npub = input; + pubkey = nip19.decode(input).data.toString(); + } else { + pubkey = input; + npub = nip19.npubEncode(input); + } + + localStorage.setItem("pubkey", pubkey); + localStorage.setItem("loginType", "readOnly_npub") + + window.location.href = `/profile/${npub}`; + } catch (e) { + console.error(e); + } + } + }; + + + return ( + + + Login to Lumina + + Login to your account either with a nostr extension or with your nsec. + + + +
+ + + + +
+
+ + + + +
+
+ or + + + Login with npub (read-only) + +
+ + + +
+
+
+
+ or + + + Login with nsec (not recommended) + +
+ + + +
+
+
+
+
+ + +
+ ) +} \ No newline at end of file diff --git a/lumina/components/Navigation.tsx b/lumina/components/Navigation.tsx deleted file mode 100644 index fc3f125..0000000 --- a/lumina/components/Navigation.tsx +++ /dev/null @@ -1,16 +0,0 @@ -"use client" - -import * as React from "react" -import { MoonIcon, SunIcon } from "@radix-ui/react-icons" -import { DropdownThemeMode } from "@/components/DropdownThemeMode" - -export function Navigation() { - - return ( -
-
- -
-
- ) -} diff --git a/lumina/components/NoteCard.tsx b/lumina/components/NoteCard.tsx index 3671082..3ba7913 100644 --- a/lumina/components/NoteCard.tsx +++ b/lumina/components/NoteCard.tsx @@ -1,14 +1,11 @@ import React from 'react'; -// import Button from 'react-bootstrap/Button'; -import { Button } from '@/components/ui/button'; -import { useNostrEvents, useProfile } from "nostr-react"; +import { useProfile } from "nostr-react"; import { nip19, } from "nostr-tools"; import { Card, CardContent, - CardDescription, CardFooter, CardHeader, CardTitle, @@ -27,113 +24,135 @@ import { CarouselPrevious, } from "@/components/ui/carousel" import ReactionButton from '@/components/ReactionButton'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { Avatar, AvatarImage } from '@/components/ui/avatar'; import ViewRawButton from '@/components/ViewRawButton'; -import Image from 'next/image'; +import ViewNoteButton from './ViewNoteButton'; +import Link from 'next/link'; +import ViewCopyButton from './ViewCopyButton'; +import { Event as NostrEvent } from "nostr-tools"; +import ZapButton from './ZapButton'; interface NoteCardProps { pubkey: string; text: string; eventId: string; tags: string[][]; - event: any; + event: NostrEvent; + showViewNoteCardButton: boolean; } -const NoteCard: React.FC = ({ pubkey, text, eventId, tags, event }) => { +const NoteCard: React.FC = ({ pubkey, text, eventId, tags, event, showViewNoteCardButton }) => { const { data: userData } = useProfile({ pubkey, }); const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || nip19.npubEncode(pubkey); - // const imageSrc = text.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]; - const imageSrc = text.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0].split(' '); - const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif)/g, ''); - // const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif)(\?.*)?/g, ''); + // text = text.replaceAll('\n', '
'); + text = text.replaceAll('\n', ' '); + const imageSrc = text.match(/https?:\/\/[^ ]*\.(png|jpg|gif)/g); + const videoSrc = text.match(/https?:\/\/[^ ]*\.(mp4|webm|mov)/g); + const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm|mov)/g, ''); const createdAt = new Date(event.created_at * 1000); const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`; - // const profileImageSrc = userData?.picture || "https://via.placeholder.com/150"; const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey; return ( <> - - - -
- {/* - - */} - {/* {title} */} - - - - - - - - -

{title}

-
-
-
-
- - {/* Card Description */} - - -
- { - // imageSrc ? imageSrc.map((src, index) => ) : "" -
- {imageSrc && imageSrc.length > 1 ? ( - - - {imageSrc.map((src, index) => ( - - - {/* {textWithoutImage} */} - - ))} - - - - - ) : ( - imageSrc ? : "" - // imageSrc ? {textWithoutImage} : "" - )} + + + + + + + +
+ + + + {title} +
+
+ +

{title}

+
+
+
+ +
+
+ +
+ { +
+
+ {imageSrc && imageSrc.length > 1 ? ( + + + {imageSrc.map((src, index) => ( + + + + ))} + + + + + ) : ( + imageSrc ? : "" + )} +
+
+ {videoSrc && videoSrc.length > 1 ? ( + + + {videoSrc.map((src, index) => ( + + + ))} + + + + + ) : ( + videoSrc ?
+
+ } +
+
+ {textWithoutImage} +
- } -
- {textWithoutImage} -
-
-
- - -
- - - {createdAt.toLocaleString()} - - +
+
+
+ + + {showViewNoteCardButton && } +
+
+ + +
+
+ + + {createdAt.toLocaleString()} + + ); } diff --git a/lumina/components/NotePageComponent.tsx b/lumina/components/NotePageComponent.tsx new file mode 100644 index 0000000..7cfa1d6 --- /dev/null +++ b/lumina/components/NotePageComponent.tsx @@ -0,0 +1,41 @@ +import { useRef } from "react"; +import { useNostrEvents } from "nostr-react"; +import NoteCard from '@/components/NoteCard'; +import CommentsCompontent from "@/components/CommentsCompontent"; + +interface NotePageComponentProps { + id: string; +} + +const NotePageComponent: React.FC = ({ id }) => { + const now = useRef(new Date()); // Make sure current time isn't re-rendered + + const { events } = useNostrEvents({ + filter: { + // since: dateToUnix(now.current), // all new events from now + // since: 0, + ids: [id], + limit: 1, + kinds: [1], + }, + }); + + // filter out all events that also have another e tag with another id + const filteredEvents = events.filter((event) => { return event.tags.filter((tag) => { return tag[0] === '#e' && tag[1] !== id }).length === 0 }); + + return ( + <> + {events.map((event) => ( + //

{event.pubkey} posted: {event.content}

+
+ +
+ +
+
+ ))} + + ); +} + +export default NotePageComponent; \ No newline at end of file diff --git a/lumina/components/Notification.tsx b/lumina/components/Notification.tsx new file mode 100644 index 0000000..3351f41 --- /dev/null +++ b/lumina/components/Notification.tsx @@ -0,0 +1,112 @@ +import React from 'react'; +import { useNostrEvents, useProfile } from "nostr-react"; +import { Card, CardHeader, CardTitle, CardContent, CardFooter, CardDescription } from '@/components/ui/card'; +import { + NostrEvent, + Event, + nip19, +} from "nostr-tools"; +import { Avatar, AvatarImage } from './ui/avatar'; +import Link from 'next/link'; + +interface NotificationProps { + event: NostrEvent; +} + +const Notification: React.FC = ({ event }) => { + let sender = event.pubkey; + let sats = 0; + let reactedToId = ''; + + const { data: userData, isLoading: userDataLoading } = useProfile({ + pubkey: sender, + }); + + if (!event) { + return null; + } + + if (event.kind === 9735) { + for (let tag of event.tags) { + if (tag[0] === 'P') { + sender = tag[1]; + } + if (tag[0] === 'bolt11') { + let bolt11decoded = require('light-bolt11-decoder').decode(tag[1]); + for (let field of bolt11decoded.sections) { + if (field.name === 'amount') { + sats = field.value / 1000; + } + } + } + } + } + + if (event.kind === 7) { + for (let tag of event.tags) { + if (tag[0] === 'e') { + reactedToId = tag[1]; + } + } + } + + let name = userData?.name ?? nip19.npubEncode(event.pubkey).slice(0, 8) + ':' + nip19.npubEncode(event.pubkey).slice(-3); + let createdAt = new Date(event.created_at * 1000); + + return ( + <> +
+ {/* ZAP */} + {event.kind === 9735 && ( +
+

{sats} sats ⚡️

+
+ + + +
+
+

{name} zapped you

+

{createdAt.toLocaleDateString() + ' ' + createdAt.toLocaleTimeString()}

+
+
+ )} + {/* FOLLOW */} + {event.kind === 3 && ( +
+

{event.content}

+
+ + + +
+
+

{name} started following you

+

{createdAt.toLocaleDateString() + ' ' + createdAt.toLocaleTimeString()}

+
+
+ )} + {/* REACTION */} + {event.kind === 7 && ( + +
+

{event.content}

+
+ + + +
+
+

{name} reacted to you

+

{createdAt.toLocaleDateString() + ' ' + createdAt.toLocaleTimeString()}

+
+
+ + )} +
+
+ + ); +} + +export default Notification; \ No newline at end of file diff --git a/lumina/components/Notifications.tsx b/lumina/components/Notifications.tsx new file mode 100644 index 0000000..4920166 --- /dev/null +++ b/lumina/components/Notifications.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { useNostrEvents, useProfile } from "nostr-react"; +import { Card, CardHeader, CardTitle, CardContent, CardFooter, CardDescription } from '@/components/ui/card'; +import { Skeleton } from '@/components/ui/skeleton'; +import { AvatarImage } from '@radix-ui/react-avatar'; +import { Avatar } from '@/components/ui/avatar'; +import NIP05 from '@/components/nip05'; +import { + nip19, +} from "nostr-tools"; +import Notification from './Notification'; + +interface NotificationsProps { + pubkey: string; +} + +const Notifications: React.FC = ({ pubkey }) => { + const { data: userData, isLoading: userDataLoading } = useProfile({ + pubkey, + }); + + + // const { events: followers, isLoading: followersLoading } = useNostrEvents({ + // filter: { + // kinds: [3], + // '#p': [pubkey], + // limit: 50, + // }, + // }); + + const { events: zaps, isLoading: zapsLoading } = useNostrEvents({ + filter: { + kinds: [9735], + '#p': [pubkey], + limit: 20, + }, + }); + + const { events: reactions, isLoading: reactionsLoading } = useNostrEvents({ + filter: { + kinds: [7], + '#p': [pubkey], + limit: 20, + }, + }); + + // const { events: following, isLoading: followingLoading } = useNostrEvents({ + // filter: { + // kinds: [3], + // authors: [pubkey], + // limit: 1, + // }, + // }); + + // filter for only new followings (latest in a users followers list) + // const filteredFollowers = followers.filter(follower => { + // const lastPTag = follower.tags[follower.tags.length - 1]; + // if (lastPTag[0] === "p" && lastPTag[1] === pubkey.toString()) { + // // console.log(follower.tags[follower.tags.length - 1]); + // return true; + // } + // }); + + // let allNotifications = [...filteredFollowers, ...zaps].sort((a, b) => b.created_at - a.created_at); + let allNotifications = [...zaps, ...reactions].sort((a, b) => b.created_at - a.created_at); + + return ( + <> +
+ {/* */} + + + Notifications + + + {allNotifications.map((notification, index) => ( + + ))} + + +
+ + ); +} + +export default Notifications; \ No newline at end of file diff --git a/lumina/components/ProfileFeed.tsx b/lumina/components/ProfileFeed.tsx index b3cedcf..182e6f4 100644 --- a/lumina/components/ProfileFeed.tsx +++ b/lumina/components/ProfileFeed.tsx @@ -20,7 +20,7 @@ const ProfileFeed: React.FC = ({ pubkey }) => { }, }); - let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]); + let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm|mov)/g)?.[0]); // filter out all replies (tag[0] == e) filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' })); @@ -40,7 +40,7 @@ const ProfileFeed: React.FC = ({ pubkey }) => { //

{event.pubkey} posted: {event.content}

//
- +
)))} diff --git a/lumina/components/ProfileInfoCard.tsx b/lumina/components/ProfileInfoCard.tsx index 5ef2bef..3032fa5 100644 --- a/lumina/components/ProfileInfoCard.tsx +++ b/lumina/components/ProfileInfoCard.tsx @@ -1,35 +1,148 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { useProfile } from "nostr-react"; -import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@/components/ui/card'; -import { Skeleton } from './ui/skeleton'; +import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; +import { AvatarImage } from '@radix-ui/react-avatar'; +import { Avatar } from '@/components/ui/avatar'; +import NIP05 from '@/components/nip05'; +import { nip19 } from "nostr-tools"; +import Link from 'next/link'; +import { Button } from './ui/button'; +import { ImStatsDots } from "react-icons/im"; +import FollowButton from './FollowButton'; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer" +import { Input } from './ui/input'; +import { Share1Icon } from '@radix-ui/react-icons'; +import { toast } from './ui/use-toast'; interface ProfileInfoCardProps { pubkey: string; } -const ProfileInfoCard: React.FC = ({ pubkey }) => { - const { data: userData } = useProfile({ - pubkey, - }); +const ProfileInfoCard: React.FC = React.memo(({ pubkey }) => { - const title = userData?.username || userData?.display_name || userData?.name || userData?.npub; + let userPubkey = ''; + let host = ''; + if (typeof window !== 'undefined') { + userPubkey = window.localStorage.getItem('pubkey') ?? ''; + host = window.location.host; + } + + const { data: userData, isLoading } = useProfile({ pubkey }); + + const npubShortened = useMemo(() => { + let encoded = nip19.npubEncode(pubkey); + let parts = encoded.split('npub'); + return 'npub' + parts[1].slice(0, 4) + ':' + parts[1].slice(-3); + }, [pubkey]); + + const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || npubShortened; const description = userData?.about?.replace(/(?:\r\n|\r|\n)/g, '
'); + const nip05 = userData?.nip05; + + const handleCopyLink = async () => { + try { + await navigator.clipboard.writeText(host+"/profile/"+nip19.npubEncode(pubkey)); + toast({ + description: 'URL copied to clipboard', + title: 'Copied' + }); + } catch (err) { + toast({ + description: 'Error copying URL to clipboard', + title: 'Error', + variant: 'destructive' + }); + } + }; + + const handleCopyPublicKey = async () => { + try { + await navigator.clipboard.writeText(nip19.npubEncode(pubkey)); + toast({ + description: 'PublicKey copied to clipboard', + title: 'Copied' + }); + } catch (err) { + toast({ + description: 'Error copying PublicKey to clipboard', + title: 'Error', + variant: 'destructive' + }); + } + }; + return ( - <> -

{title}

-
- {description ? ( - -
-
- ) : ( -
- +
+ + + + +
+ + + + {title} +
+ +
+
+ +
+ {/* */} +
+ +
+ + + + + + + + + + Share this Profile + Share this Profile with others. + +
+ {/*

URL

*/} +
+ + +
+
+ + +
+
+ + + + + +
+
+
+
- )} -
- + + +
+ + +
); -} +}); + +ProfileInfoCard.displayName = 'ProfileInfoCard'; export default ProfileInfoCard; \ No newline at end of file diff --git a/lumina/components/ProfileQuickViewFeed.tsx b/lumina/components/ProfileQuickViewFeed.tsx new file mode 100644 index 0000000..678a4c6 --- /dev/null +++ b/lumina/components/ProfileQuickViewFeed.tsx @@ -0,0 +1,63 @@ +import { useRef, useState } from "react"; +import { useNostrEvents, dateToUnix } from "nostr-react"; +import { Skeleton } from "@/components/ui/skeleton"; +import QuickViewNoteCard from "./QuickViewNoteCard"; +import { Button } from "@/components/ui/button"; + +interface ProfileQuickViewFeedProps { + pubkey: string; +} + +const ProfileQuickViewFeed: React.FC = ({ pubkey }) => { + const now = useRef(new Date()); // Make sure current time isn't re-rendered + const [limit, setLimit] = useState(100); + + const { isLoading ,events } = useNostrEvents({ + filter: { + authors: [pubkey], + limit: limit, + kinds: [1], + }, + }); + + let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm|mov)/g)?.[0]); + // filter out all replies (tag[0] == e) + filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' })); + + const loadMore = () => { + setLimit(limit => limit + 50); + } + + return ( + <> +
+ {filteredEvents.length === 0 && isLoading ? ( + <> +
+ +
+
+ +
+
+ +
+ + ) : ( + <> + {filteredEvents.map((event) => ( + + ))} + + )} +
+ {!isLoading ? ( +
+ +
+ ) : null} + + ); +} + +export default ProfileQuickViewFeed; \ No newline at end of file diff --git a/lumina/components/ProfileTextFeed.tsx b/lumina/components/ProfileTextFeed.tsx new file mode 100644 index 0000000..56f6b71 --- /dev/null +++ b/lumina/components/ProfileTextFeed.tsx @@ -0,0 +1,51 @@ +import { useRef } from "react"; +import { useNostrEvents, dateToUnix } from "nostr-react"; +import NoteCard from '@/components/NoteCard'; +import { Skeleton } from "@/components/ui/skeleton"; + +interface ProfileTextFeedProps { + pubkey: string; +} + +const ProfileTextFeed: React.FC = ({ pubkey }) => { + const now = useRef(new Date()); // Make sure current time isn't re-rendered + + const { events, isLoading } = useNostrEvents({ + filter: { + // since: dateToUnix(now.current), // all new events from now + authors: [pubkey], + // since: 0, + // limit: 10, + kinds: [1], + }, + }); + + // filter out all images since we only want text messages + let filteredEvents = events.filter((event) => !event.content.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]); + // filter out all replies (tag[0] == e) + filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' })); + + return ( + <> + {/*

Profile Feed

*/} + + {filteredEvents.length === 0 && isLoading ? ( +
+ +
+ + +
+
+ ) : (filteredEvents.map((event) => ( + //

{event.pubkey} posted: {event.content}

+ // +
+ +
+ )))} + + ); +} + +export default ProfileTextFeed; \ No newline at end of file diff --git a/lumina/components/QuickViewNoteCard.tsx b/lumina/components/QuickViewNoteCard.tsx new file mode 100644 index 0000000..33e15db --- /dev/null +++ b/lumina/components/QuickViewNoteCard.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { useProfile } from "nostr-react"; +import { + nip19, +} from "nostr-tools"; +import { + Card, + SmallCardContent, +} from "@/components/ui/card" +import Image from 'next/image'; +import Link from 'next/link'; +import { PlayIcon, StackIcon, VideoIcon } from '@radix-ui/react-icons'; + +interface NoteCardProps { + pubkey: string; + text: string; + eventId: string; + tags: string[][]; + event: any; + linkToNote: boolean; +} + +const QuickViewNoteCard: React.FC = ({ pubkey, text, eventId, tags, event, linkToNote }) => { + const { data: userData } = useProfile({ + pubkey, + }); + + const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || nip19.npubEncode(pubkey); + text = text.replaceAll('\n', ' '); + const imageSrc = text.match(/https?:\/\/[^ ]*\.(png|jpg|gif)/g); + const videoSrc = text.match(/https?:\/\/[^ ]*\.(mp4|webm|mov)/g); + const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm|mov)/g, ''); + const createdAt = new Date(event.created_at * 1000); + const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`; + const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey; + const encodedNoteId = nip19.noteEncode(event.id) + + const card = ( + + +
+
+ {imageSrc && imageSrc.length > 1 && !videoSrc ? ( +
+
+ +
+ {text} +
+ ) : imageSrc && imageSrc.length > 0 ? ( +
+ {videoSrc && videoSrc.length > 0 && +
+ +
+ } + {text} +
+ ) : videoSrc && videoSrc.length > 0 ? ( +
+
+ +
+
+ ) : null} +
+
+
+
+ ); + + return ( + <> + {linkToNote ? ( + + {card} + + ) : ( + card + )} + + ); +} + +export default QuickViewNoteCard; \ No newline at end of file diff --git a/lumina/components/ReactionButton.tsx b/lumina/components/ReactionButton.tsx index e1b79fd..16565e8 100644 --- a/lumina/components/ReactionButton.tsx +++ b/lumina/components/ReactionButton.tsx @@ -4,12 +4,24 @@ import { type Event as NostrEvent, getEventHash, getPublicKey, - getSignature, + finalizeEvent, } from "nostr-tools"; import { Button } from "@/components/ui/button"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer" +import { ReloadIcon } from "@radix-ui/react-icons"; +import ReactionButtonReactionList from "./ReactionButtonReactionList"; -export default function ReactionButton(event: any) { - const { events } = useNostrEvents({ +export default function ReactionButton({ event }: { event: any }) { + const { events, isLoading } = useNostrEvents({ filter: { // since: dateToUnix(now.current), // all new events from now // since: 0, @@ -19,40 +31,73 @@ export default function ReactionButton(event: any) { }, }); - const { publish } = useNostr(); + // filter out all events that also have another e tag with another id + // this will filter out likes that are made on comments and not on the note itself + const filteredEvents = events.filter((event) => { return event.tags.filter((tag) => { return tag[0] === '#e' && tag[1] !== event.id }).length === 0 }); - const onPost = async () => { - const privKey = prompt("Paste your private key:"); + // const { publish } = useNostr(); - if (!privKey) { - alert("no private key provided"); - return; - } + // const onPost = async () => { + // const privKey = prompt("Paste your private key:"); - const message = prompt("Enter the message you want to send:"); + // if (!privKey) { + // alert("no private key provided"); + // return; + // } - if (!message) { - alert("no message provided"); - return; - } + // const message = prompt("Enter the message you want to send:"); - const event: NostrEvent = { - content: message, - kind: 1, - tags: [], - created_at: dateToUnix(), - pubkey: getPublicKey(privKey), - id: "", - sig: "" - }; + // if (!message) { + // alert("no message provided"); + // return; + // } - event.id = getEventHash(event); - event.sig = getSignature(event, privKey); + // const event: NostrEvent = { + // content: message, + // kind: 1, + // tags: [], + // created_at: dateToUnix(), + // pubkey: getPublicKey(privKey), + // id: "", + // sig: "" + // }; - publish(event); - }; + // event.id = getEventHash(event); + // event.sig = getSignature(event, privKey); + + // publish(event); + // }; return ( - + + + {/* */} + {isLoading ? ( + + ) : ( + + )} + + + + Reactions + + {/* TODO: Create Reaction Event on Click */} +
+ + + +
+
+ + + + + + +
+
+ + // ); } \ No newline at end of file diff --git a/lumina/components/ReactionButtonReactionList.tsx b/lumina/components/ReactionButtonReactionList.tsx new file mode 100644 index 0000000..13d0a7f --- /dev/null +++ b/lumina/components/ReactionButtonReactionList.tsx @@ -0,0 +1,12 @@ +import { ScrollArea } from "@/components/ui/scroll-area" +import ReactionButtonReactionListItem from "./ReactionButtonReactionListItem"; + +export default function ReactionButtonReactionList({ filteredEvents }: { filteredEvents: any }) { + return ( + + {filteredEvents.map((event: any) => ( + + ))} + + ); +} \ No newline at end of file diff --git a/lumina/components/ReactionButtonReactionListItem.tsx b/lumina/components/ReactionButtonReactionListItem.tsx new file mode 100644 index 0000000..6dff4cc --- /dev/null +++ b/lumina/components/ReactionButtonReactionListItem.tsx @@ -0,0 +1,43 @@ +import Link from "next/link"; +import { useNostr, dateToUnix, useNostrEvents, useProfile } from "nostr-react"; + +import { + type Event as NostrEvent, + getEventHash, + getPublicKey, + finalizeEvent, + nip19, +} from "nostr-tools"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; + +export default function ReactionButtonReactionListItem({ event }: { event: NostrEvent }) { + + let pubkey = event.pubkey; + + const { data: userData } = useProfile({ + pubkey, + }); + + const title = userData?.username || userData?.display_name || userData?.name || nip19.npubEncode(pubkey).slice(0, 8) + ':' + nip19.npubEncode(pubkey).slice(-3);; + const createdAt = new Date(event.created_at * 1000); + const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`; + const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey; + const content = event.content; + + console.log("event", event.content); + + return ( + +
+
+ {/* */} + + + + {title} + {content} +
+
+ + ); +} \ No newline at end of file diff --git a/lumina/components/ReelFeed.tsx b/lumina/components/ReelFeed.tsx new file mode 100644 index 0000000..7cf8f9f --- /dev/null +++ b/lumina/components/ReelFeed.tsx @@ -0,0 +1,40 @@ +import { useRef } from "react"; +import { useNostrEvents, dateToUnix } from "nostr-react"; +import NoteCard from './NoteCard'; + +const ReelFeed: React.FC = () => { + const now = useRef(new Date()); // Make sure current time isn't re-rendered + + const { events } = useNostrEvents({ + filter: { + // since: dateToUnix(now.current), // all new events from now + // since: 0, + // limit: 100, + kinds: [1063], + }, + }); + + // const filteredEvents = events.filter((event) => event.content.includes(".jpg")); + // filter events with regex that checks for png, jpg, or gif + let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]); + + // now filter all events with a tag[0] == t and tag[1] == nsfw + // filteredEvents = filteredEvents.filter((event) => event.tags.map((tag) => tag[0] == "t" && tag[1] == "nsfw")); + filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 't' && tag[1] == 'nsfw'})); + // filter out all replies + filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' })); + + return ( + <> +

Reel Feed

+ {filteredEvents.map((event) => ( + //

{event.pubkey} posted: {event.content}

+
+ +
+ ))} + + ); +} + +export default ReelFeed; \ No newline at end of file diff --git a/lumina/components/Search.tsx b/lumina/components/Search.tsx new file mode 100644 index 0000000..82a2c9e --- /dev/null +++ b/lumina/components/Search.tsx @@ -0,0 +1,62 @@ +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { queryProfile } from "nostr-tools/nip05" +import { nip19 } from "nostr-tools" +import { useState } from 'react'; +import { ReloadIcon } from "@radix-ui/react-icons"; +// import { useRouter } from 'next/router'; +import { useRouter } from 'next/navigation'; + +export function Search() { + const router = useRouter(); + + const [inputValue, setInputValue] = useState(''); + const [isLoading, setIsLoading] = useState(false); // Neuer Zustand für das Laden + + const calculateAndRedirect = async () => { + setIsLoading(true); + + if (inputValue.startsWith('npub')) { // npub Search + // window.location.href = `/profile/${inputValue}`; + router.push(`/profile/${inputValue}`); + } else if (inputValue.startsWith('#')) { // Hashtag Search + // window.location.href = `/tag/${inputValue.replaceAll('#', '')}`; + router.push(`/tag/${inputValue.replaceAll('#', '')}`); + } else if(inputValue.includes('@')) { // NIP-05 Search + // if inputValue starts with @, then add a "_" at the beginning + if(inputValue.startsWith('@')) { + setInputValue('_' + inputValue); + } + + let profile = await queryProfile(inputValue); + if(profile?.pubkey !== undefined) { // Only redirect if profile is found + router.push(`/profile/${nip19.npubEncode(profile?.pubkey)}`); + } + } else { + router.push(`/search/${inputValue}`); + } + setIsLoading(false); + } + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + calculateAndRedirect(); + } + } + + return ( +
+ setInputValue(e.target.value)} + onKeyDown={handleKeyDown} + /> + {/* */} + +
+ ) +} \ No newline at end of file diff --git a/lumina/components/TagFeed.tsx b/lumina/components/TagFeed.tsx index ddcf488..2d38764 100644 --- a/lumina/components/TagFeed.tsx +++ b/lumina/components/TagFeed.tsx @@ -21,7 +21,7 @@ const TagFeed: React.FC = ({tag}) => { // const filteredEvents = events.filter((event) => event.content.includes(".jpg")); // filter events with regex that checks for png, jpg, or gif - let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]); + let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm)/g)?.[0]); // now filter all events with a tag[0] == t and tag[1] == nsfw filteredEvents = filteredEvents.filter((event) => event.tags.map((tag) => tag[0] == "t" && tag[1] == "nsfw")); @@ -34,7 +34,7 @@ const TagFeed: React.FC = ({tag}) => { {filteredEvents.map((event) => ( //

{event.pubkey} posted: {event.content}

- +
))} diff --git a/lumina/components/TrendingAccount.tsx b/lumina/components/TrendingAccount.tsx new file mode 100644 index 0000000..9d844a8 --- /dev/null +++ b/lumina/components/TrendingAccount.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { useProfile } from "nostr-react"; +import { + nip19, +} from "nostr-tools"; +import { + Card, + CardHeader, + CardTitle, + SmallCardContent, +} from "@/components/ui/card" +import { Avatar, AvatarImage } from '@/components/ui/avatar'; +import Link from 'next/link'; + +interface TrendingAccountProps { + pubkey: string; +} + +const TrendingAccount: React.FC = ({ pubkey }) => { + const { data: userData } = useProfile({ + pubkey, + }); + + const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || nip19.npubEncode(pubkey); + const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`; + const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey; + + return ( + <> + + + + +
+ + + + {/* {title.substring(0, 12)} */} + {title} +
+ +
+
+ +
+
+
+
+
+
+ + ); +} + +export default TrendingAccount; \ No newline at end of file diff --git a/lumina/components/TrendingAccounts.tsx b/lumina/components/TrendingAccounts.tsx index d64ad5d..bcc48a2 100644 --- a/lumina/components/TrendingAccounts.tsx +++ b/lumina/components/TrendingAccounts.tsx @@ -1,39 +1,26 @@ -import { useRef } from "react"; -import { useNostrEvents, dateToUnix } from "nostr-react"; -import NoteCard from './NoteCard'; +import React, { useState, useEffect } from 'react'; +import TrendingAccount from '@/components/TrendingAccount'; -const TrendingAccounts: React.FC = () => { - const now = useRef(new Date()); // Make sure current time isn't re-rendered +export function TrendingAccounts() { + const [profiles, setProfiles] = useState([]); - const { events } = useNostrEvents({ - filter: { - // since: dateToUnix(now.current), // all new events from now - // since: 0, - limit: 100, - kinds: [1], - }, - }); + useEffect(() => { + fetch('https://api.nostr.band/v0/trending/profiles') + .then(res => res.json()) + .then(data => setProfiles(data.profiles)) + .catch(error => { + console.error('Error calling trending profiles:', error); + }); + }, []); - // const filteredEvents = events.filter((event) => event.content.includes(".jpg")); - // filter events with regex that checks for png, jpg, or gif - let filteredEvents = events.filter((event) => event.content.match(/https?:\/\/.*\.(?:png|jpg|gif)/g)?.[0]); - - // now filter all events with a tag[0] == t and tag[1] == nsfw - filteredEvents = filteredEvents.filter((event) => event.tags.map((tag) => tag[0] == "t" && tag[1] == "nsfw")); - // filter out all replies - filteredEvents = filteredEvents.filter((event) => event.tags.map((tag) => tag[0] == "e")); - - return ( - <> -

Global Feed

- {filteredEvents.map((event) => ( - //

{event.pubkey} posted: {event.content}

-
- + return ( +
+

Trending Accounts

+
+ {profiles && profiles.length > 0 && profiles.slice(0,4).map((profile, index) => ( + + ))} +
- ))} - - ); -} - -export default TrendingAccounts; \ No newline at end of file + ); +} \ No newline at end of file diff --git a/lumina/components/TrendingImage.tsx b/lumina/components/TrendingImage.tsx new file mode 100644 index 0000000..ecea5cc --- /dev/null +++ b/lumina/components/TrendingImage.tsx @@ -0,0 +1,84 @@ +import React, { useMemo } from 'react'; +import { useNostr, useNostrEvents, useProfile } from "nostr-react"; +import { + nip19, +} from "nostr-tools"; +import { + Card, + CardHeader, + CardTitle, + SmallCardContent, +} from "@/components/ui/card" +import Image from 'next/image'; +import Link from 'next/link'; +import { Avatar } from './ui/avatar'; +import { AvatarImage } from '@radix-ui/react-avatar'; + +interface TrendingImageProps { + eventId: string; + pubkey: string; +} + +const TrendingImage: React.FC = ({ eventId, pubkey }) => { + const { data: userData } = useProfile({ + pubkey, + }); + + const { events } = useNostrEvents({ + filter: { + kinds: [1], + ids: [eventId] + }, + }); + + const npubShortened = useMemo(() => { + let encoded = nip19.npubEncode(pubkey); + let parts = encoded.split('npub'); + return 'npub' + parts[1].slice(0, 4) + ':' + parts[1].slice(-3); + }, [pubkey]); + + let text = events && events.length > 0 ? events[0].content : ''; + const createdAt = events && events.length > 0 ? new Date(events[0].created_at * 1000) : new Date(); + const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || npubShortened; + text = text.replaceAll('\n', ' '); + const imageSrc = text.match(/https?:\/\/[^ ]*\.(png|jpg|gif)/g); + const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif)/g, ''); + const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`; + const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey; + + return ( + <> + + + +
+ + + + {title} +
+
+
+ +
+
+ {imageSrc && imageSrc.length > 0 && ( +
+ + {text} + +
+ // {text} + //
+ // {text} + //
+ )} +
+
+
+
+ + ); +} + +export default TrendingImage; \ No newline at end of file diff --git a/lumina/components/TrendingImages.tsx b/lumina/components/TrendingImages.tsx new file mode 100644 index 0000000..10c09c7 --- /dev/null +++ b/lumina/components/TrendingImages.tsx @@ -0,0 +1,27 @@ +import React, { useState, useEffect } from 'react'; +import TrendingImage from './TrendingImage'; + +export function TrendingImages() { + const [profiles, setProfiles] = useState([]); + + useEffect(() => { + fetch('https://api.nostr.band/v0/trending/images') + .then(res => res.json()) + .then(data => setProfiles(data.images)) + .catch(error => { + console.error('Error calling trending profiles:', error); + }); + }, []); + + return ( +
+

Currently Trending

+
+ {profiles && profiles.length > 0 && profiles.map((profile, index) => ( + //

{profile.id}

+ + ))} +
+
+ ); +} \ No newline at end of file diff --git a/lumina/components/UpdateProfileForm.tsx b/lumina/components/UpdateProfileForm.tsx new file mode 100644 index 0000000..57c5e56 --- /dev/null +++ b/lumina/components/UpdateProfileForm.tsx @@ -0,0 +1,102 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { generateSecretKey, getPublicKey } from 'nostr-tools/pure' +import { nip19 } from "nostr-tools" +import { Label } from "./ui/label" +import { Textarea } from "@/components/ui/textarea" +import { finalizeEvent, verifyEvent } from 'nostr-tools/pure' +import { bytesToHex, hexToBytes } from '@noble/hashes/utils' +import { useNostr, useProfile } from 'nostr-react'; + +export function UpdateProfileForm() { + + const { publish } = useNostr(); + + let npub = ''; + let pubkey = ''; + let nsec: Uint8Array; + + if (typeof window !== 'undefined') { + pubkey = window.localStorage.getItem("pubkey") ?? ''; + const nsecHex = window.localStorage.getItem("nsec"); + + if (pubkey && pubkey.length > 0) { + npub = nip19.npubEncode(pubkey); + } + + if (nsecHex && nsecHex.length > 0) { + nsec = hexToBytes(nsecHex); + } + } + + let { data: userData } = useProfile({ + pubkey, + }); + + const [username, setUsername] = useState(userData?.name); + const [displayName, setDisplayName] = useState(userData?.display_name); + const [bio, setBio] = useState(userData?.about); + + const handleUsernameChange = (event: React.ChangeEvent) => { + setUsername(event.target.value); + }; + const handleDisplayNameChange = (event: React.ChangeEvent) => { + setDisplayName(event.target.value); + }; + const handleBioChange = (event: React.ChangeEvent) => { + setBio(event.target.value); + }; + + async function handleProfileUpdate() { + const username = (document.getElementById('username') as HTMLInputElement).value; + const bio = (document.getElementById('bio') as HTMLInputElement).value; + const displayname = (document.getElementById('displayname') as HTMLInputElement).value; + + if (nsec) { + let event = finalizeEvent({ + kind: 0, + created_at: Math.floor(Date.now() / 1000), + tags: [], + content: `{"name": "${username}", "about": "${bio}"}`, + }, nsec); + + let isGood = verifyEvent(event); + + // console.log('isGood: ' + isGood); + // console.log(event); + + if (isGood) { + publish(event); + window.location.href = `/profile/${npub}`; + } + } + } + + return ( +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + {/* */} +