2026-01-13 14:49:19 +01:00

133 lines
4.9 KiB
TypeScript

import type { RelayConfig } from '@/lib/configStorageTypes'
import { t } from '@/lib/i18n'
import { DragHandle } from '../DragHandle'
import { getRelayCardClassName } from './controller'
export function RelayCard(params: {
relay: RelayConfig
isEditing: boolean
draggedId: string | null
dragOverId: string | null
onStartEditing: (id: string) => void
onStopEditing: () => void
onUpdateUrl: (id: string, url: string) => void
onToggleEnabled: (id: string, enabled: boolean) => void
onRemoveRelay: (id: string) => void
onDragStart: (e: React.DragEvent<HTMLDivElement>, id: string) => void
onDragOver: (e: React.DragEvent<HTMLDivElement>, id: string) => void
onDragLeave: () => void
onDrop: (e: React.DragEvent<HTMLDivElement>, targetId: string) => void
onDragEnd: () => void
}): React.ReactElement {
return (
<div
onDragOver={(e) => params.onDragOver(e, params.relay.id)}
onDragLeave={params.onDragLeave}
onDrop={(e) => params.onDrop(e, params.relay.id)}
className={`bg-cyber-dark border rounded p-4 space-y-3 transition-all ${getRelayCardClassName(params.relay.id, params.draggedId, params.dragOverId)}`}
>
<div className="flex items-start justify-between gap-4">
<div className="flex items-center gap-3 flex-1">
<DragGrip relayId={params.relay.id} onDragStart={params.onDragStart} onDragEnd={params.onDragEnd} />
<UrlCell relay={params.relay} isEditing={params.isEditing} onStartEditing={params.onStartEditing} onStopEditing={params.onStopEditing} onUpdateUrl={params.onUpdateUrl} />
{params.relay.lastSyncDate ? <LastSync lastSyncDate={params.relay.lastSyncDate} /> : null}
</div>
<ActionsCell relay={params.relay} onToggleEnabled={params.onToggleEnabled} onRemoveRelay={params.onRemoveRelay} />
</div>
</div>
)
}
function DragGrip(params: {
relayId: string
onDragStart: (e: React.DragEvent<HTMLDivElement>, id: string) => void
onDragEnd: () => void
}): React.ReactElement {
return (
<div
className="drag-handle cursor-grab active:cursor-grabbing"
draggable
onDragStart={(e) => params.onDragStart(e, params.relayId)}
onDragEnd={params.onDragEnd}
onMouseDown={(e) => e.stopPropagation()}
>
<DragHandle />
</div>
)
}
function UrlCell(params: {
relay: RelayConfig
isEditing: boolean
onStartEditing: (id: string) => void
onStopEditing: () => void
onUpdateUrl: (id: string, url: string) => void
}): React.ReactElement {
if (params.isEditing) {
return <UrlEditor relay={params.relay} onStop={params.onStopEditing} onUpdate={params.onUpdateUrl} />
}
return (
<div className="text-neon-cyan cursor-pointer hover:text-neon-green transition-colors" onClick={() => params.onStartEditing(params.relay.id)} title={t('settings.relay.list.editUrl')}>
{params.relay.url}
</div>
)
}
function UrlEditor(params: { relay: RelayConfig; onStop: () => void; onUpdate: (id: string, url: string) => void }): React.ReactElement {
return (
<input
type="text"
defaultValue={params.relay.url}
onBlur={(e) => {
const next = e.target.value
if (next !== params.relay.url) {
params.onUpdate(params.relay.id, next)
} else {
params.onStop()
}
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.currentTarget.blur()
} else if (e.key === 'Escape') {
params.onStop()
}
}}
className="w-full px-3 py-2 bg-cyber-darker border border-neon-cyan/50 rounded text-cyber-light focus:border-neon-cyan focus:outline-none"
autoFocus
/>
)
}
function LastSync(params: { lastSyncDate: string }): React.ReactElement {
return (
<div className="text-xs text-cyber-accent/70 mt-1">
{t('settings.relay.list.lastSync')}: {new Date(params.lastSyncDate).toLocaleString()}
</div>
)
}
function ActionsCell(params: { relay: RelayConfig; onToggleEnabled: (id: string, enabled: boolean) => void; onRemoveRelay: (id: string) => void }): React.ReactElement {
return (
<div className="flex items-center gap-2">
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
checked={params.relay.enabled}
onChange={(e) => params.onToggleEnabled(params.relay.id, e.target.checked)}
className="w-4 h-4 text-neon-cyan bg-cyber-darker border-cyber-accent rounded focus:ring-neon-cyan"
/>
<span className="text-sm text-cyber-accent">{params.relay.enabled ? t('settings.relay.list.enabled') : t('settings.relay.list.disabled')}</span>
</label>
<button
type="button"
onClick={() => params.onRemoveRelay(params.relay.id)}
className="px-3 py-1 text-sm bg-red-900/30 hover:bg-red-900/50 text-red-300 border border-red-500/50 rounded transition-colors"
title={t('settings.relay.list.remove')}
>
{t('settings.relay.list.remove')}
</button>
</div>
)
}