create for series
This commit is contained in:
parent
fb0457b8d6
commit
d027cb32e1
@ -10,15 +10,9 @@ interface SeriesCardProps {
|
|||||||
selected?: boolean
|
selected?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SeriesCard({ series, onSelect, selected }: SeriesCardProps): React.ReactElement {
|
function SeriesCardContent({ series, onSelect }: { series: Series; onSelect: (seriesId: string | undefined) => void }): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
className={`border rounded-lg p-4 bg-cyber-dark transition-all ${
|
|
||||||
selected
|
|
||||||
? 'border-neon-cyan ring-1 ring-neon-cyan/50 shadow-glow-cyan'
|
|
||||||
: 'border-neon-cyan/30 hover:border-neon-cyan/50 hover:shadow-glow-cyan'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{series.coverUrl && (
|
{series.coverUrl && (
|
||||||
<div className="relative w-full h-40 mb-3 rounded-lg overflow-hidden border border-neon-cyan/20">
|
<div className="relative w-full h-40 mb-3 rounded-lg overflow-hidden border border-neon-cyan/20">
|
||||||
<Image
|
<Image
|
||||||
@ -48,6 +42,17 @@ export function SeriesCard({ series, onSelect, selected }: SeriesCardProps): Rea
|
|||||||
{t('series.view')}
|
{t('series.view')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SeriesCard({ series, onSelect, selected }: SeriesCardProps): React.ReactElement {
|
||||||
|
const cardClasses = selected
|
||||||
|
? 'border-neon-cyan ring-1 ring-neon-cyan/50 shadow-glow-cyan'
|
||||||
|
: 'border-neon-cyan/30 hover:border-neon-cyan/50 hover:shadow-glow-cyan'
|
||||||
|
return (
|
||||||
|
<div className={`border rounded-lg p-4 bg-cyber-dark transition-all ${cardClasses}`}>
|
||||||
|
<SeriesCardContent series={series} onSelect={onSelect} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -175,7 +175,8 @@ function SponsoringFormView(params: {
|
|||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<form onSubmit={params.onSubmit} className="border border-neon-cyan/30 rounded-lg p-4 bg-cyber-dark space-y-4">
|
<Card variant="default" className="space-y-4">
|
||||||
|
<form onSubmit={params.onSubmit} className="space-y-4">
|
||||||
<h3 className="text-lg font-semibold text-neon-cyan">{t('sponsoring.form.title')}</h3>
|
<h3 className="text-lg font-semibold text-neon-cyan">{t('sponsoring.form.title')}</h3>
|
||||||
<p className="text-sm text-cyber-accent/70">{t('sponsoring.form.description', { amount: '0.046' })}</p>
|
<p className="text-sm text-cyber-accent/70">{t('sponsoring.form.description', { amount: '0.046' })}</p>
|
||||||
<Textarea
|
<Textarea
|
||||||
@ -199,5 +200,6 @@ function SponsoringFormView(params: {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ArticleCard } from './ArticleCard'
|
import { ArticleCard } from './ArticleCard'
|
||||||
import { Button } from './ui'
|
import { Button, ErrorState } from './ui'
|
||||||
import type { Article } from '@/types/nostr'
|
import type { Article } from '@/types/nostr'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
@ -28,8 +28,8 @@ const ArticlesLoading = (): React.ReactElement => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const ArticlesError = ({ message }: { message: string }): React.ReactElement => (
|
const ArticlesError = ({ message }: { message: string }): React.ReactElement => (
|
||||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-4">
|
<div className="mb-4">
|
||||||
<p className="text-red-800">{message}</p>
|
<ErrorState message={message} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import Link from 'next/link'
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { CreateSeriesModal } from '@/components/CreateSeriesModal'
|
import { CreateSeriesModal } from '@/components/CreateSeriesModal'
|
||||||
import { SeriesCard } from '@/components/SeriesCard'
|
import { SeriesCard } from '@/components/SeriesCard'
|
||||||
import { Button } from '@/components/ui'
|
import { Button, Card, EmptyState } from '@/components/ui'
|
||||||
import { useNostrAuth } from '@/hooks/useNostrAuth'
|
import { useNostrAuth } from '@/hooks/useNostrAuth'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import type { Series } from '@/types/nostr'
|
import type { Series } from '@/types/nostr'
|
||||||
@ -46,9 +46,9 @@ function SeriesListHeader(params: { isAuthor: boolean; onCreate: () => void }):
|
|||||||
function SeriesGrid(params: { series: Series[] }): React.ReactElement {
|
function SeriesGrid(params: { series: Series[] }): React.ReactElement {
|
||||||
if (params.series.length === 0) {
|
if (params.series.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-cyber-dark/50 border border-neon-cyan/20 rounded-lg p-6">
|
<Card variant="default" className="bg-cyber-dark/50">
|
||||||
<p className="text-cyber-accent">{t('series.empty')}</p>
|
<EmptyState title={t('series.empty')} />
|
||||||
</div>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Button } from '@/components/ui'
|
import { Button, Card } from '@/components/ui'
|
||||||
import { SponsoringForm } from '@/components/SponsoringForm'
|
import { SponsoringForm } from '@/components/SponsoringForm'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import type { AuthorPresentationArticle } from '@/types/nostr'
|
import type { AuthorPresentationArticle } from '@/types/nostr'
|
||||||
@ -15,11 +15,11 @@ export function SponsoringSummary({ totalSponsoring, author, onSponsor }: Sponso
|
|||||||
const [showForm, setShowForm] = useState(false)
|
const [showForm, setShowForm] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-cyber-dark/50 border border-neon-cyan/20 rounded-lg p-6 mb-8">
|
<Card variant="default" className="bg-cyber-dark/50 mb-8">
|
||||||
<SponsoringSummaryHeader showSponsorButton={author !== null} onSponsorClick={() => setShowForm(true)} />
|
<SponsoringSummaryHeader showSponsorButton={author !== null} onSponsorClick={() => setShowForm(true)} />
|
||||||
<SponsoringTotals totalBTC={totalBTC} totalSats={totalSponsoring} />
|
<SponsoringTotals totalBTC={totalBTC} totalSats={totalSponsoring} />
|
||||||
<SponsoringFormPanel show={showForm} author={author} onClose={() => setShowForm(false)} onSponsor={onSponsor} />
|
<SponsoringFormPanel show={showForm} author={author} onClose={() => setShowForm(false)} onSponsor={onSponsor} />
|
||||||
</div>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { FormEvent } from 'react'
|
import type { FormEvent } from 'react'
|
||||||
import { PresentationFormHeader } from '../PresentationFormHeader'
|
import { PresentationFormHeader } from '../PresentationFormHeader'
|
||||||
import { Button, ErrorState } from '../ui'
|
import { Button, Card, ErrorState } from '../ui'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import { PresentationFields } from './fields'
|
import { PresentationFields } from './fields'
|
||||||
import type { AuthorPresentationDraft } from './types'
|
import type { AuthorPresentationDraft } from './types'
|
||||||
@ -19,11 +19,12 @@ export interface PresentationFormProps {
|
|||||||
|
|
||||||
export function PresentationForm(props: PresentationFormProps): React.ReactElement {
|
export function PresentationForm(props: PresentationFormProps): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
|
<Card variant="default" className="space-y-4">
|
||||||
<form
|
<form
|
||||||
onSubmit={(e: FormEvent<HTMLFormElement>) => {
|
onSubmit={(e: FormEvent<HTMLFormElement>) => {
|
||||||
void props.handleSubmit(e)
|
void props.handleSubmit(e)
|
||||||
}}
|
}}
|
||||||
className="border border-neon-cyan/20 rounded-lg p-6 bg-cyber-dark space-y-4"
|
className="space-y-4"
|
||||||
>
|
>
|
||||||
<PresentationFormHeader />
|
<PresentationFormHeader />
|
||||||
<PresentationFields draft={props.draft} onChange={props.setDraft} />
|
<PresentationFields draft={props.draft} onChange={props.setDraft} />
|
||||||
@ -43,6 +44,7 @@ export function PresentationForm(props: PresentationFormProps): React.ReactEleme
|
|||||||
{props.hasExistingPresentation ? <DeleteButton onDelete={props.handleDelete} deleting={props.deleting} /> : null}
|
{props.hasExistingPresentation ? <DeleteButton onDelete={props.handleDelete} deleting={props.deleting} /> : null}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ImageUploadField } from '../ImageUploadField'
|
import { ImageUploadField } from '../ImageUploadField'
|
||||||
import { Button, Input, Textarea } from '../ui'
|
import { Button, Input, Textarea, ErrorState } from '../ui'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import type { SeriesDraft } from './createSeriesModalTypes'
|
import type { SeriesDraft } from './createSeriesModalTypes'
|
||||||
import type { CreateSeriesModalController } from './useCreateSeriesModalController'
|
import type { CreateSeriesModalController } from './useCreateSeriesModalController'
|
||||||
@ -136,11 +136,7 @@ function SeriesError({ error }: { error: string | null }): React.ReactElement |
|
|||||||
if (!error) {
|
if (!error) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return (
|
return <ErrorState message={error} />
|
||||||
<div className="p-4 bg-red-900/30 border border-red-500/50 rounded text-red-300">
|
|
||||||
<p>{error}</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SeriesActions(params: { loading: boolean; canPublish: boolean; onClose: () => void }): React.ReactElement {
|
function SeriesActions(params: { loading: boolean; canPublish: boolean; onClose: () => void }): React.ReactElement {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button } from '@/components/ui'
|
import { Button, ErrorState } from '@/components/ui'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import type { KeyManagementManagerActions } from './useKeyManagementManager'
|
import type { KeyManagementManagerActions } from './useKeyManagementManager'
|
||||||
import type { KeyManagementManagerState } from './keyManagementController'
|
import type { KeyManagementManagerState } from './keyManagementController'
|
||||||
@ -34,8 +34,8 @@ function KeyManagementErrorBanner(params: { error: string | null }): React.React
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="bg-red-900/20 border border-red-400/50 rounded-lg p-4 mb-4">
|
<div className="mb-4">
|
||||||
<p className="text-red-400">{params.error}</p>
|
<ErrorState message={params.error} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { Nip95Config } from '@/lib/configStorageTypes'
|
import type { Nip95Config } from '@/lib/configStorageTypes'
|
||||||
import { Button } from '../ui'
|
import { Button, Card, Input } from '../ui'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import { Nip95ApiList } from './Nip95ApiList'
|
import { Nip95ApiList } from './Nip95ApiList'
|
||||||
|
|
||||||
@ -65,17 +65,14 @@ function Header(params: { showAddForm: boolean; onToggleAddForm: () => void }):
|
|||||||
|
|
||||||
function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => void; onAdd: () => void; onCancel: () => void }): React.ReactElement {
|
function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => void; onAdd: () => void; onCancel: () => void }): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className="bg-cyber-dark border border-neon-cyan/30 rounded p-4 space-y-4">
|
<Card variant="default" className="space-y-4">
|
||||||
<div>
|
<Input
|
||||||
<label className="block text-sm font-medium text-cyber-accent mb-2">{t('settings.nip95.add.url')}</label>
|
|
||||||
<input
|
|
||||||
type="url"
|
type="url"
|
||||||
|
label={t('settings.nip95.add.url')}
|
||||||
value={params.newUrl}
|
value={params.newUrl}
|
||||||
onChange={(e) => params.onNewUrlChange(e.target.value)}
|
onChange={(e) => params.onNewUrlChange(e.target.value)}
|
||||||
placeholder={t('settings.nip95.add.placeholder')}
|
placeholder={t('settings.nip95.add.placeholder')}
|
||||||
className="w-full px-4 py-2 bg-cyber-darker border border-cyber-accent/30 rounded text-cyber-light focus:border-neon-cyan focus:outline-none"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@ -92,7 +89,7 @@ function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => vo
|
|||||||
{t('settings.nip95.add.cancel')}
|
{t('settings.nip95.add.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button } from '../ui'
|
import { Button, Card, Input } from '../ui'
|
||||||
import { t } from '@/lib/i18n'
|
import { t } from '@/lib/i18n'
|
||||||
import { RelayList } from './RelayList'
|
import { RelayList } from './RelayList'
|
||||||
import type { RelayManagerContentProps } from './types'
|
import type { RelayManagerContentProps } from './types'
|
||||||
@ -58,17 +58,14 @@ function Header(params: { showAddForm: boolean; onToggleAddForm: () => void }):
|
|||||||
|
|
||||||
function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => void; onAdd: () => void; onCancel: () => void }): React.ReactElement {
|
function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => void; onAdd: () => void; onCancel: () => void }): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className="bg-cyber-dark border border-neon-cyan/30 rounded p-4 space-y-4">
|
<Card variant="default" className="space-y-4">
|
||||||
<div>
|
<Input
|
||||||
<label className="block text-sm font-medium text-cyber-accent mb-2">{t('settings.relay.add.url')}</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
type="text"
|
||||||
|
label={t('settings.relay.add.url')}
|
||||||
value={params.newUrl}
|
value={params.newUrl}
|
||||||
onChange={(e) => params.onNewUrlChange(e.target.value)}
|
onChange={(e) => params.onNewUrlChange(e.target.value)}
|
||||||
placeholder={t('settings.relay.add.placeholder')}
|
placeholder={t('settings.relay.add.placeholder')}
|
||||||
className="w-full px-4 py-2 bg-cyber-darker border border-cyber-accent/30 rounded text-cyber-light focus:border-neon-cyan focus:outline-none"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@ -85,7 +82,7 @@ function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => vo
|
|||||||
{t('settings.relay.add.cancel')}
|
{t('settings.relay.add.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user