101 lines
3.8 KiB
TypeScript
101 lines
3.8 KiB
TypeScript
import { t } from '@/lib/i18n'
|
||
import { RelayList } from './RelayList'
|
||
import type { RelayManagerContentProps } from './types'
|
||
|
||
export function RelayManagerContent(params: RelayManagerContentProps): React.ReactElement {
|
||
return (
|
||
<div className="space-y-6">
|
||
{params.error ? <ErrorBanner error={params.error} onClear={params.onClearError} /> : null}
|
||
<Header showAddForm={params.showAddForm} onToggleAddForm={params.onToggleAddForm} />
|
||
{params.showAddForm ? <AddForm newUrl={params.newUrl} onNewUrlChange={params.onNewUrlChange} onAdd={params.onAddRelay} onCancel={params.onCancelAdd} /> : null}
|
||
<RelayList
|
||
relays={params.relays}
|
||
editingId={params.editingId}
|
||
draggedId={params.draggedId}
|
||
dragOverId={params.dragOverId}
|
||
onStartEditing={params.onStartEditing}
|
||
onStopEditing={params.onStopEditing}
|
||
onUpdateUrl={params.onUpdateUrl}
|
||
onToggleEnabled={params.onToggleEnabled}
|
||
onRemoveRelay={params.onRemoveRelay}
|
||
onDragStart={params.onDragStart}
|
||
onDragOver={params.onDragOver}
|
||
onDragLeave={params.onDragLeave}
|
||
onDrop={params.onDrop}
|
||
onDragEnd={params.onDragEnd}
|
||
/>
|
||
<Notes />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
function ErrorBanner(params: { error: string; onClear: () => void }): React.ReactElement {
|
||
return (
|
||
<div className="bg-red-900/30 border border-red-500/50 rounded p-4 text-red-300">
|
||
{params.error}
|
||
<button type="button" onClick={params.onClear} className="ml-4 text-red-400 hover:text-red-200">
|
||
×
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
function Header(params: { showAddForm: boolean; onToggleAddForm: () => void }): React.ReactElement {
|
||
return (
|
||
<div className="flex justify-between items-center">
|
||
<h2 className="text-2xl font-bold text-neon-cyan">{t('settings.relay.title')}</h2>
|
||
<button
|
||
type="button"
|
||
onClick={params.onToggleAddForm}
|
||
className="px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border border-neon-cyan/50 rounded transition-colors"
|
||
>
|
||
{params.showAddForm ? t('settings.relay.add.cancel') : t('settings.relay.addButton')}
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
function AddForm(params: { newUrl: string; onNewUrlChange: (value: string) => void; onAdd: () => void; onCancel: () => void }): React.ReactElement {
|
||
return (
|
||
<div className="bg-cyber-dark border border-neon-cyan/30 rounded p-4 space-y-4">
|
||
<div>
|
||
<label className="block text-sm font-medium text-cyber-accent mb-2">{t('settings.relay.add.url')}</label>
|
||
<input
|
||
type="text"
|
||
value={params.newUrl}
|
||
onChange={(e) => params.onNewUrlChange(e.target.value)}
|
||
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">
|
||
<button
|
||
type="button"
|
||
onClick={params.onAdd}
|
||
className="px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border border-neon-cyan/50 rounded transition-colors"
|
||
>
|
||
{t('settings.relay.add.add')}
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={params.onCancel}
|
||
className="px-4 py-2 bg-cyber-accent/20 hover:bg-cyber-accent/30 text-cyber-accent border border-cyber-accent/50 rounded transition-colors"
|
||
>
|
||
{t('settings.relay.add.cancel')}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
function Notes(): React.ReactElement {
|
||
return (
|
||
<div className="text-sm text-cyber-accent space-y-2">
|
||
<p>
|
||
<strong>{t('settings.relay.note.title')}</strong> {t('settings.relay.note.priority')}
|
||
</p>
|
||
<p>{t('settings.relay.note.rotation')}</p>
|
||
</div>
|
||
)
|
||
}
|