mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-04 04:26:38 +08:00
@
feat: Warm Industrial UI redesign + social footer + code deduplication Design System (Phase A): - New palette: warm charcoal #111110 / amber gold #c9954a / sage green #7a9a8a - Fonts: Cabinet Grotesk (heading) + Geist (body) + JetBrains Mono (data) - SVG grain texture overlay, collapsed sidebar with hover expand - Bento grid dashboard with WideContinueCard + PosterCard + QuickLink - Backward-compatible CSS aliases for glass-panel/neon-button/input-base Social Footer (Phase B): - AppFooter component with GitHub repo / author homepage / TG group links - Embedded in LoginPage, Layout (global), and SettingsPage - TG group badge added to README.md Code Cleanup: - Removed deprecated DownloadClientCard / NotifyChannelCard components - Merged downloadClient/notify API clients into unified modules - Route deduplication: removed authed-group duplicates for admin endpoints - Removed redundant AdminPage tabs (sites/downloads/notify/scheduler) - UI fixes: blank pages (discover/download-clients/notify-channels) nil slice defense - Email channel support in NotifyChannelsPage @
This commit is contained in:
@@ -125,6 +125,7 @@ const TYPE_LABELS: Record<NotifyChannel['channel_type'], string> = {
|
||||
wechat: '企业微信',
|
||||
bark: 'Bark',
|
||||
webhook: 'Webhook',
|
||||
email: 'Email',
|
||||
}
|
||||
|
||||
function ChannelCard({
|
||||
@@ -188,6 +189,8 @@ function channelSummary(ch: NotifyChannel): string {
|
||||
return `Device ${String(cfg.device_key ?? '').slice(0, 10)}…`
|
||||
case 'webhook':
|
||||
return `${cfg.method ?? 'POST'} ${cfg.url ?? ''}`
|
||||
case 'email':
|
||||
return `SMTP ${cfg.smtp_host ?? '-'}:${cfg.smtp_port ?? '-'} → ${cfg.to ?? '-'}`
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
@@ -200,6 +203,7 @@ const EMPTY_CONFIG: Record<NotifyChannel['channel_type'], Record<string, string>
|
||||
wechat: { sendkey: '' },
|
||||
bark: { device_key: '', server: '' },
|
||||
webhook: { url: '', method: 'POST', headers: '', body_template: '' },
|
||||
email: { smtp_host: '', smtp_port: '465', username: '', password: '', from: '', to: '', tls: 'true' },
|
||||
}
|
||||
|
||||
function ChannelFormModal({
|
||||
@@ -282,6 +286,7 @@ function ChannelFormModal({
|
||||
<option value="wechat">企业微信 / Server酱</option>
|
||||
<option value="bark">Bark (iOS)</option>
|
||||
<option value="webhook">Webhook</option>
|
||||
<option value="email">Email (SMTP)</option>
|
||||
</select>
|
||||
</Field>
|
||||
|
||||
@@ -383,6 +388,78 @@ function ChannelFormModal({
|
||||
</>
|
||||
)}
|
||||
|
||||
{type === 'email' && (
|
||||
<>
|
||||
<Field label="SMTP 地址">
|
||||
<input
|
||||
required
|
||||
className="input-base"
|
||||
placeholder="smtp.gmail.com"
|
||||
value={config.smtp_host ?? ''}
|
||||
onChange={(e) => updateConfig('smtp_host', e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Field label="SMTP 端口">
|
||||
<input
|
||||
required
|
||||
className="input-base"
|
||||
placeholder="465"
|
||||
value={config.smtp_port ?? ''}
|
||||
onChange={(e) => updateConfig('smtp_port', e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="TLS">
|
||||
<select
|
||||
className="input-base"
|
||||
value={config.tls ?? 'true'}
|
||||
onChange={(e) => updateConfig('tls', e.target.value)}
|
||||
>
|
||||
<option value="true">启用</option>
|
||||
<option value="false">关闭</option>
|
||||
</select>
|
||||
</Field>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Field label="用户名">
|
||||
<input
|
||||
required
|
||||
className="input-base"
|
||||
value={config.username ?? ''}
|
||||
onChange={(e) => updateConfig('username', e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="密码">
|
||||
<input
|
||||
type="password"
|
||||
required
|
||||
className="input-base"
|
||||
value={config.password ?? ''}
|
||||
onChange={(e) => updateConfig('password', e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
<Field label="发件人">
|
||||
<input
|
||||
required
|
||||
className="input-base"
|
||||
placeholder="noreply@example.com"
|
||||
value={config.from ?? ''}
|
||||
onChange={(e) => updateConfig('from', e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="收件人 (多个用逗号分隔)">
|
||||
<input
|
||||
required
|
||||
className="input-base"
|
||||
placeholder="user@example.com"
|
||||
value={config.to ?? ''}
|
||||
onChange={(e) => updateConfig('to', e.target.value)}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
|
||||
<label className="flex cursor-pointer items-center gap-2 text-sm text-slate-300">
|
||||
<input
|
||||
type="checkbox"
|
||||
|
||||
Reference in New Issue
Block a user