fix(settings): normalize Visibility, Privacy, BotSpam tabs to design standards
This commit is contained in:
@@ -91,7 +91,7 @@ export default function SiteBotSpamTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
<ShieldCheck weight="bold" className="w-5 h-5 text-brand-orange" />
|
<ShieldCheck weight="bold" className="w-5 h-5 text-brand-orange" />
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-white">Enable bot filtering</p>
|
<p className="text-sm font-medium text-white">Enable bot filtering</p>
|
||||||
<p className="text-xs text-neutral-400">Filter known bots, crawlers, referrer spam, and suspicious traffic.</p>
|
<p className="text-xs text-neutral-500">Filter known bots, crawlers, referrer spam, and suspicious traffic.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Toggle checked={filterBots} onChange={() => setFilterBots(p => !p)} />
|
<Toggle checked={filterBots} onChange={() => setFilterBots(p => !p)} />
|
||||||
@@ -102,15 +102,15 @@ export default function SiteBotSpamTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
<div className="grid grid-cols-3 gap-3">
|
<div className="grid grid-cols-3 gap-3">
|
||||||
<div className="rounded-xl border border-neutral-800 bg-neutral-800/30 p-4 text-center">
|
<div className="rounded-xl border border-neutral-800 bg-neutral-800/30 p-4 text-center">
|
||||||
<p className="text-2xl font-bold text-white">{botStats.filtered_sessions ?? 0}</p>
|
<p className="text-2xl font-bold text-white">{botStats.filtered_sessions ?? 0}</p>
|
||||||
<p className="text-xs text-neutral-400 mt-1">Sessions filtered</p>
|
<p className="text-xs text-neutral-500 mt-1">Sessions filtered</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl border border-neutral-800 bg-neutral-800/30 p-4 text-center">
|
<div className="rounded-xl border border-neutral-800 bg-neutral-800/30 p-4 text-center">
|
||||||
<p className="text-2xl font-bold text-white">{botStats.filtered_events ?? 0}</p>
|
<p className="text-2xl font-bold text-white">{botStats.filtered_events ?? 0}</p>
|
||||||
<p className="text-xs text-neutral-400 mt-1">Events filtered</p>
|
<p className="text-xs text-neutral-500 mt-1">Events filtered</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl border border-neutral-800 bg-neutral-800/30 p-4 text-center">
|
<div className="rounded-xl border border-neutral-800 bg-neutral-800/30 p-4 text-center">
|
||||||
<p className="text-2xl font-bold text-white">{botStats.auto_blocked_this_month ?? 0}</p>
|
<p className="text-2xl font-bold text-white">{botStats.auto_blocked_this_month ?? 0}</p>
|
||||||
<p className="text-xs text-neutral-400 mt-1">Auto-blocked this month</p>
|
<p className="text-xs text-neutral-500 mt-1">Auto-blocked this month</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -138,16 +138,13 @@ export default function SiteBotSpamTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
|
|
||||||
{/* Suspicious only filter (review mode only) */}
|
{/* Suspicious only filter (review mode only) */}
|
||||||
{botView === 'review' && (
|
{botView === 'review' && (
|
||||||
<label className="flex items-center gap-2 text-sm text-neutral-400">
|
<div className="flex items-center justify-between py-3 px-4 rounded-xl bg-neutral-800/30 border border-neutral-800">
|
||||||
<input
|
<div>
|
||||||
type="checkbox"
|
<p className="text-sm font-medium text-white">Suspicious only</p>
|
||||||
checked={suspiciousOnly}
|
<p className="text-xs text-neutral-500">Show only sessions flagged as suspicious.</p>
|
||||||
onChange={e => setSuspiciousOnly(e.target.checked)}
|
</div>
|
||||||
className="w-4 h-4 rounded"
|
<Toggle checked={suspiciousOnly} onChange={() => setSuspiciousOnly(v => !v)} />
|
||||||
style={{ accentColor: '#FD5E0F' }}
|
</div>
|
||||||
/>
|
|
||||||
Suspicious only
|
|
||||||
</label>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Bulk actions bar */}
|
{/* Bulk actions bar */}
|
||||||
@@ -168,7 +165,7 @@ export default function SiteBotSpamTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
{(sessions || [])
|
{(sessions || [])
|
||||||
.filter(s => botView === 'blocked' ? s.bot_filtered : !s.bot_filtered)
|
.filter(s => botView === 'blocked' ? s.bot_filtered : !s.bot_filtered)
|
||||||
.map(session => (
|
.map(session => (
|
||||||
<div key={session.session_id} className="flex items-center gap-3 p-3 rounded-xl border border-neutral-800 hover:border-neutral-700 transition-colors">
|
<div key={session.session_id} className="flex items-center gap-3 p-3 rounded-xl border border-neutral-800 hover:bg-neutral-800/40 hover:border-neutral-700 transition-colors">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={selectedSessions.has(session.session_id)}
|
checked={selectedSessions.has(session.session_id)}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function PrivacyToggle({ label, desc, checked, onToggle }: { label: string; desc
|
|||||||
<div className="flex items-center justify-between py-3 px-4 rounded-xl hover:bg-neutral-800/20 transition-colors">
|
<div className="flex items-center justify-between py-3 px-4 rounded-xl hover:bg-neutral-800/20 transition-colors">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-white">{label}</p>
|
<p className="text-sm font-medium text-white">{label}</p>
|
||||||
<p className="text-xs text-neutral-400">{desc}</p>
|
<p className="text-xs text-neutral-500">{desc}</p>
|
||||||
</div>
|
</div>
|
||||||
<Toggle checked={checked} onChange={onToggle} />
|
<Toggle checked={checked} onChange={onToggle} />
|
||||||
</div>
|
</div>
|
||||||
@@ -162,11 +162,11 @@ export default function SitePrivacyTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="p-4 bg-neutral-900/50 rounded-xl border border-neutral-800">
|
<div className="p-4 bg-neutral-800/30 rounded-xl border border-neutral-800">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-white text-sm">Keep raw event data for</p>
|
<p className="font-medium text-white text-sm">Keep raw event data for</p>
|
||||||
<p className="text-xs text-neutral-400 mt-0.5">Events older than this are automatically deleted. Aggregated daily stats are kept permanently.</p>
|
<p className="text-xs text-neutral-500 mt-0.5">Events older than this are automatically deleted. Aggregated daily stats are kept permanently.</p>
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
value={String(dataRetention)}
|
value={String(dataRetention)}
|
||||||
@@ -199,7 +199,7 @@ export default function SitePrivacyTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
onChange={e => setExcludedPaths(e.target.value)}
|
onChange={e => setExcludedPaths(e.target.value)}
|
||||||
rows={4}
|
rows={4}
|
||||||
placeholder={"/admin/*\n/staging/*"}
|
placeholder={"/admin/*\n/staging/*"}
|
||||||
className="w-full px-4 py-3 border border-neutral-800 rounded-lg bg-neutral-900/50 text-white font-mono text-sm focus:border-brand-orange focus:ring-4 focus:ring-brand-orange/10 outline-none transition-all"
|
className="w-full px-4 py-3 border border-neutral-800 rounded-lg bg-neutral-800/30 text-white font-mono text-sm focus:border-brand-orange focus:ring-4 focus:ring-brand-orange/10 outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-neutral-500 mt-1">Enter paths to exclude from tracking (one per line). Supports wildcards (e.g., /admin/*).</p>
|
<p className="text-xs text-neutral-500 mt-1">Enter paths to exclude from tracking (one per line). Supports wildcards (e.g., /admin/*).</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,11 +208,11 @@ export default function SitePrivacyTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
{/* PageSpeed Monitoring */}
|
{/* PageSpeed Monitoring */}
|
||||||
<div className="space-y-3 pt-6 border-t border-neutral-800">
|
<div className="space-y-3 pt-6 border-t border-neutral-800">
|
||||||
<h4 className="text-sm font-medium text-neutral-300">PageSpeed Monitoring</h4>
|
<h4 className="text-sm font-medium text-neutral-300">PageSpeed Monitoring</h4>
|
||||||
<div className="p-4 bg-neutral-900/50 rounded-xl border border-neutral-800">
|
<div className="p-4 bg-neutral-800/30 rounded-xl border border-neutral-800">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-white text-sm">Check frequency</p>
|
<p className="font-medium text-white text-sm">Check frequency</p>
|
||||||
<p className="text-xs text-neutral-400 mt-0.5">How often PageSpeed Insights runs automated checks.</p>
|
<p className="text-xs text-neutral-500 mt-0.5">How often PageSpeed Insights runs automated checks.</p>
|
||||||
</div>
|
</div>
|
||||||
{psiConfig?.enabled ? (
|
{psiConfig?.enabled ? (
|
||||||
<Select
|
<Select
|
||||||
@@ -236,14 +236,14 @@ export default function SitePrivacyTab({ siteId, onDirtyChange, onRegisterSave }
|
|||||||
{/* Privacy Policy */}
|
{/* Privacy Policy */}
|
||||||
<div className="space-y-3 pt-6 border-t border-neutral-800">
|
<div className="space-y-3 pt-6 border-t border-neutral-800">
|
||||||
<h4 className="text-sm font-medium text-neutral-300">For your privacy policy</h4>
|
<h4 className="text-sm font-medium text-neutral-300">For your privacy policy</h4>
|
||||||
<p className="text-xs text-neutral-400">Copy the text below into your Privacy Policy. It updates automatically based on your saved settings.</p>
|
<p className="text-xs text-neutral-500">Copy the text below into your Privacy Policy. It updates automatically based on your saved settings.</p>
|
||||||
<p className="text-xs text-amber-600">This is provided for convenience and is not legal advice. Consult a lawyer for compliance requirements.</p>
|
<p className="text-xs text-amber-600 dark:text-amber-500">This is provided for convenience and is not legal advice. Consult a lawyer for compliance requirements.</p>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<textarea
|
<textarea
|
||||||
readOnly
|
readOnly
|
||||||
rows={6}
|
rows={6}
|
||||||
value={generatePrivacySnippet(site)}
|
value={generatePrivacySnippet(site)}
|
||||||
className="w-full px-4 py-3 pr-12 border border-neutral-800 rounded-xl bg-neutral-900/50 text-neutral-300 text-xs font-mono"
|
className="w-full px-4 py-3 pr-12 border border-neutral-800 rounded-xl bg-neutral-800/30 text-neutral-300 text-xs font-mono"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default function SiteVisibilityTab({ siteId, onDirtyChange, onRegisterSav
|
|||||||
<div className="flex items-center justify-between py-3 px-4 rounded-xl bg-neutral-800/30 border border-neutral-800">
|
<div className="flex items-center justify-between py-3 px-4 rounded-xl bg-neutral-800/30 border border-neutral-800">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-white">Public Dashboard</p>
|
<p className="text-sm font-medium text-white">Public Dashboard</p>
|
||||||
<p className="text-xs text-neutral-400">Allow anyone with the link to view this dashboard.</p>
|
<p className="text-xs text-neutral-500">Allow anyone with the link to view this dashboard.</p>
|
||||||
</div>
|
</div>
|
||||||
<Toggle checked={isPublic} onChange={() => setIsPublic(p => !p)} />
|
<Toggle checked={isPublic} onChange={() => setIsPublic(p => !p)} />
|
||||||
</div>
|
</div>
|
||||||
@@ -107,7 +107,7 @@ export default function SiteVisibilityTab({ siteId, onDirtyChange, onRegisterSav
|
|||||||
<Lock weight="bold" className="w-4 h-4 text-neutral-500" />
|
<Lock weight="bold" className="w-4 h-4 text-neutral-500" />
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-white">Password Protection</p>
|
<p className="text-sm font-medium text-white">Password Protection</p>
|
||||||
<p className="text-xs text-neutral-400">Require a password to view the public dashboard.</p>
|
<p className="text-xs text-neutral-500">Require a password to view the public dashboard.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Toggle checked={passwordEnabled} onChange={() => setPasswordEnabled(p => !p)} />
|
<Toggle checked={passwordEnabled} onChange={() => setPasswordEnabled(p => !p)} />
|
||||||
|
|||||||
Reference in New Issue
Block a user