From 572ee2dde550b59fe1fa11257377fed7696f81be Mon Sep 17 00:00:00 2001 From: Nicolas Cantu Date: Tue, 6 Jan 2026 08:10:43 +0100 Subject: [PATCH] fix key import --- components/ArticleField.tsx | 1 - components/ArticleFormButtons.tsx | 1 - components/ArticlePreview.tsx | 1 - components/AuthorFilterDropdown.tsx | 1 - components/AuthorPresentationEditor.tsx | 3 +- components/CategorySelect.tsx | 1 - components/CategoryTabs.tsx | 1 - components/ClearButton.tsx | 4 +- components/ConnectButton.tsx | 7 +- components/CreateSeriesModal.tsx | 225 ++++++++++++++++++++++++ components/DocsSidebar.tsx | 9 +- components/FundingGauge.tsx | 15 +- components/HomeView.tsx | 17 +- components/MarkdownEditor.tsx | 3 +- components/Nip95ConfigManager.tsx | 6 +- components/NotificationActions.tsx | 5 +- components/NotificationBadgeButton.tsx | 2 - components/NotificationContent.tsx | 1 - components/NotificationItem.tsx | 1 - components/NotificationPanel.tsx | 1 - components/NotificationPanelHeader.tsx | 2 - components/SearchIcon.tsx | 1 - components/UserArticlesList.tsx | 9 +- components/UserProfileHeader.tsx | 1 - docs/fees-and-contributions.md | 16 ++ hooks/useDocs.ts | 4 +- lib/accessControl.ts | 4 +- lib/articleMutations.ts | 2 +- lib/authorFiltering.ts | 12 -- lib/metadataExtractor.ts | 70 ++++++-- lib/objectModification.ts | 5 +- lib/presentationParsing.ts | 2 +- lib/urlGenerator.ts | 2 +- lib/versionManager.ts | 8 +- locales/en.txt | 33 ++++ locales/fr.txt | 20 +++ pages/author/[pubkey].tsx | 92 ++++++---- pages/docs.tsx | 17 +- public/locales/en.txt | 33 ++++ public/locales/fr.txt | 33 ++++ 40 files changed, 533 insertions(+), 138 deletions(-) create mode 100644 components/CreateSeriesModal.tsx create mode 100644 docs/fees-and-contributions.md diff --git a/components/ArticleField.tsx b/components/ArticleField.tsx index 8fa5873..04ff855 100644 --- a/components/ArticleField.tsx +++ b/components/ArticleField.tsx @@ -1,4 +1,3 @@ -import React from 'react' interface ArticleFieldProps { id: string diff --git a/components/ArticleFormButtons.tsx b/components/ArticleFormButtons.tsx index e0ef943..4b5104b 100644 --- a/components/ArticleFormButtons.tsx +++ b/components/ArticleFormButtons.tsx @@ -1,4 +1,3 @@ -import React from 'react' import { t } from '@/lib/i18n' interface ArticleFormButtonsProps { diff --git a/components/ArticlePreview.tsx b/components/ArticlePreview.tsx index 9651a85..7380c4e 100644 --- a/components/ArticlePreview.tsx +++ b/components/ArticlePreview.tsx @@ -1,4 +1,3 @@ -import React from 'react' import type { Article } from '@/types/nostr' interface ArticlePreviewProps { diff --git a/components/AuthorFilterDropdown.tsx b/components/AuthorFilterDropdown.tsx index 24dd3e3..8a5650c 100644 --- a/components/AuthorFilterDropdown.tsx +++ b/components/AuthorFilterDropdown.tsx @@ -1,4 +1,3 @@ -import React from 'react' import Image from 'next/image' import { t } from '@/lib/i18n' diff --git a/components/AuthorPresentationEditor.tsx b/components/AuthorPresentationEditor.tsx index 4fc5df2..35dbdb6 100644 --- a/components/AuthorPresentationEditor.tsx +++ b/components/AuthorPresentationEditor.tsx @@ -3,7 +3,6 @@ import { useRouter } from 'next/router' import { useNostrAuth } from '@/hooks/useNostrAuth' import { useAuthorPresentation } from '@/hooks/useAuthorPresentation' import { ArticleField } from './ArticleField' -import { ArticleFormButtons } from './ArticleFormButtons' import { CreateAccountModal } from './CreateAccountModal' import { RecoveryStep } from './CreateAccountModalSteps' import { UnlockAccountModal } from './UnlockAccountModal' @@ -251,7 +250,7 @@ function useAuthorPresentationState(pubkey: string | null, existingAuthorName?: presentation, contentDescription, mainnetAddress: existingPresentation.mainnetAddress || '', - pictureUrl: existingPresentation.bannerUrl, + ...(existingPresentation.bannerUrl ? { pictureUrl: existingPresentation.bannerUrl } : {}), } } return { diff --git a/components/CategorySelect.tsx b/components/CategorySelect.tsx index 2a45967..80efe94 100644 --- a/components/CategorySelect.tsx +++ b/components/CategorySelect.tsx @@ -1,4 +1,3 @@ -import React from 'react' import type { ArticleCategory } from '@/types/nostr' interface CategorySelectProps { diff --git a/components/CategoryTabs.tsx b/components/CategoryTabs.tsx index d9db418..42eb36c 100644 --- a/components/CategoryTabs.tsx +++ b/components/CategoryTabs.tsx @@ -1,4 +1,3 @@ -import React from 'react' import { t } from '@/lib/i18n' type CategoryFilter = 'science-fiction' | 'scientific-research' | 'all' | null diff --git a/components/ClearButton.tsx b/components/ClearButton.tsx index 249894f..802d8f7 100644 --- a/components/ClearButton.tsx +++ b/components/ClearButton.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import { t } from '@/lib/i18n' interface ClearButtonProps { onClick: () => void @@ -9,7 +9,7 @@ export function ClearButton({ onClick }: ClearButtonProps) { {error &&

{error}

} @@ -146,7 +147,7 @@ export function ConnectButton() { return } - if (accountExists === true && pubkey && !isUnlocked && !showUnlockModal && !showCreateModal) { + if (accountExists === true && pubkey && !isUnlocked && !showUnlockModal) { return ( void + onSuccess: () => void + authorPubkey: string +} + +interface SeriesDraft { + title: string + description: string + preview: string + coverUrl: string + category: ArticleDraft['category'] +} + +export function CreateSeriesModal({ isOpen, onClose, onSuccess, authorPubkey }: CreateSeriesModalProps) { + const { pubkey, isUnlocked } = useNostrAuth() + const [draft, setDraft] = useState({ + title: '', + description: '', + preview: '', + coverUrl: '', + category: 'science-fiction', + }) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + + if (!isOpen) { + return null + } + + const privateKey = nostrService.getPrivateKey() + const canPublish = pubkey === authorPubkey && isUnlocked && privateKey !== null + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + if (!canPublish) { + setError(t('series.create.error.notAuthor')) + return + } + + if (!draft.title.trim() || !draft.description.trim() || !draft.preview.trim()) { + setError(t('series.create.error.missingFields')) + return + } + + setLoading(true) + setError(null) + + try { + if (!privateKey) { + setError(t('series.create.error.notAuthor')) + return + } + await publishSeries({ + title: draft.title, + description: draft.description, + preview: draft.preview, + ...(draft.coverUrl ? { coverUrl: draft.coverUrl } : {}), + category: draft.category, + authorPubkey, + authorPrivateKey: privateKey, + }) + // Reset form + setDraft({ + title: '', + description: '', + preview: '', + coverUrl: '', + category: 'science-fiction', + }) + onSuccess() + onClose() + } catch (e) { + setError(e instanceof Error ? e.message : t('series.create.error.publishFailed')) + } finally { + setLoading(false) + } + } + + const handleClose = () => { + if (!loading) { + setDraft({ + title: '', + description: '', + preview: '', + coverUrl: '', + category: 'science-fiction', + }) + setError(null) + onClose() + } + } + + return ( +
+
+
+

{t('series.create.title')}

+ +
+ + {!canPublish && ( +
+

{t('series.create.error.notAuthor')}

+
+ )} + +
+
+ + setDraft({ ...draft, title: e.target.value })} + className="w-full px-3 py-2 bg-cyber-darker border border-cyber-accent/30 rounded text-cyber-light focus:border-neon-cyan focus:outline-none" + required + disabled={loading || !canPublish} + /> +
+ +
+ +