From d9f2e6d6144d96ea5857441af25eb500d2c01ee3 Mon Sep 17 00:00:00 2001 From: 7418 <7418@openclaw.ai> Date: Wed, 11 Mar 2026 21:50:20 +0800 Subject: [PATCH] refactor: replace inline layout patterns with SettingsCard/FieldRow/StatusBanner (PR3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings pages: - GeneralSection: 3 inline cards → SettingsCard, 3 field rows → FieldRow, warning banner → StatusBanner - AppearanceSection: card → SettingsCard, mode/family rows → FieldRow, native - + )} ); diff --git a/src/components/bridge/DiscordBridgeSection.tsx b/src/components/bridge/DiscordBridgeSection.tsx index 26ce229..ae2d9b9 100644 --- a/src/components/bridge/DiscordBridgeSection.tsx +++ b/src/components/bridge/DiscordBridgeSection.tsx @@ -13,6 +13,9 @@ import { import { Switch } from "@/components/ui/switch"; import { SpinnerGap, CheckCircle, Warning } from "@phosphor-icons/react"; import { useTranslation } from "@/hooks/useTranslation"; +import { SettingsCard } from "@/components/patterns/SettingsCard"; +import { FieldRow } from "@/components/patterns/FieldRow"; +import { StatusBanner } from "@/components/patterns/StatusBanner"; interface DiscordBridgeSettings { bridge_discord_bot_token: string; @@ -159,14 +162,10 @@ export function DiscordBridgeSection() { return (
{/* Bot Token */} -
-
-

{t("discord.credentials")}

-

- {t("discord.credentialsDesc")} -

-
- +
{verifyResult && ( -
: } > - {verifyResult.ok ? : } {verifyResult.message} -
+ )} -
+
{/* Allowed Users / Channels */} -
-
-

- {t("discord.allowedUsers")} -

-

- {t("discord.allowedUsersDesc")} -

-
- +
-
+ {/* Guild & Group Settings */} -
-
-

- {t("discord.guildSettings")} -

-

- {t("discord.guildSettingsDesc")} -

-
- +
-
-
-

{t("discord.requireMention")}

-

- {t("discord.requireMentionDesc")} -

-
+ -
+ -
-
-

{t("discord.streamPreview")}

-

- {t("discord.streamPreviewDesc")} -

-
+ -
+
-
+ {/* Setup Guide */} -
-

- {t("discord.setupGuide")} -

- +

{t("discord.setupBotTitle")} @@ -370,7 +344,7 @@ export function DiscordBridgeSection() {
  • {t("discord.stepGuildId")}
  • -
    +
    ); } diff --git a/src/components/bridge/FeishuBridgeSection.tsx b/src/components/bridge/FeishuBridgeSection.tsx index c8196da..3ea31b4 100644 --- a/src/components/bridge/FeishuBridgeSection.tsx +++ b/src/components/bridge/FeishuBridgeSection.tsx @@ -13,6 +13,9 @@ import { import { Switch } from "@/components/ui/switch"; import { SpinnerGap, CheckCircle, Warning } from "@phosphor-icons/react"; import { useTranslation } from "@/hooks/useTranslation"; +import { SettingsCard } from "@/components/patterns/SettingsCard"; +import { FieldRow } from "@/components/patterns/FieldRow"; +import { StatusBanner } from "@/components/patterns/StatusBanner"; interface FeishuBridgeSettings { bridge_feishu_app_id: string; @@ -160,14 +163,10 @@ export function FeishuBridgeSection() { return (
    {/* App Credentials */} -
    -
    -

    {t("feishu.credentials")}

    -

    - {t("feishu.credentialsDesc")} -

    -
    - +
    {verifyResult && ( -
    : } > - {verifyResult.ok ? : } {verifyResult.message} -
    + )} -
    +
    {/* Allowed Users */} -
    -
    -

    - {t("feishu.allowedUsers")} -

    -

    - {t("feishu.allowedUsersDesc")} -

    -
    - +
    -
    + {/* Group Chat Settings */} -
    -
    -

    - {t("feishu.groupSettings")} -

    -

    - {t("feishu.groupSettingsDesc")} -

    -
    - +
    )} -
    -
    -

    {t("feishu.requireMention")}

    -

    - {t("feishu.requireMentionDesc")} -

    -
    + -
    +
    -
    + {/* Setup Guide */} -
    -

    - {t("feishu.setupGuide")} -

    +
    1. {t("feishu.step1")}
    2. {t("feishu.step2")}
    3. @@ -358,7 +335,7 @@ export function FeishuBridgeSection() {
    4. {t("feishu.step5")}
    5. {t("feishu.step6")}
    -
    +
    ); } diff --git a/src/components/bridge/QqBridgeSection.tsx b/src/components/bridge/QqBridgeSection.tsx index 5c98e01..2f85c95 100644 --- a/src/components/bridge/QqBridgeSection.tsx +++ b/src/components/bridge/QqBridgeSection.tsx @@ -6,6 +6,9 @@ import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { SpinnerGap, CheckCircle, Warning } from "@phosphor-icons/react"; import { useTranslation } from "@/hooks/useTranslation"; +import { SettingsCard } from "@/components/patterns/SettingsCard"; +import { FieldRow } from "@/components/patterns/FieldRow"; +import { StatusBanner } from "@/components/patterns/StatusBanner"; interface QqBridgeSettings { bridge_qq_app_id: string; @@ -144,14 +147,10 @@ export function QqBridgeSection() { return (
    {/* App Credentials */} -
    -
    -

    {t("qq.credentials")}

    -

    - {t("qq.credentialsDesc")} -

    -
    - +
    {verifyResult && ( -
    : } > - {verifyResult.ok ? : } {verifyResult.message} -
    + )} -
    +
    {/* Allowed Users */} -
    -
    -

    {t("qq.allowedUsers")}

    -

    - {t("qq.allowedUsersDesc")} -

    -
    - +
    {saving ? t("common.loading") : t("common.save")} -
    +
    {/* Image Settings */} -
    -
    -

    {t("qq.imageSettings")}

    -

    - {t("qq.imageSettingsDesc")} -

    -
    - +
    -
    -
    -

    {t("qq.imageEnabled")}

    -

    - {t("qq.imageEnabledDesc")} -

    -
    + -
    + {imageEnabled && (
    @@ -284,11 +268,10 @@ export function QqBridgeSection() { -
    + {/* Setup Guide */} -
    -

    {t("qq.setupGuide")}

    +
    1. {t("qq.step1")}
    2. {t("qq.step2")}
    3. @@ -296,7 +279,7 @@ export function QqBridgeSection() {
    4. {t("qq.step4")}
    5. {t("qq.step5")}
    -
    +
    ); } diff --git a/src/components/bridge/TelegramBridgeSection.tsx b/src/components/bridge/TelegramBridgeSection.tsx index bbf59ee..60205f7 100644 --- a/src/components/bridge/TelegramBridgeSection.tsx +++ b/src/components/bridge/TelegramBridgeSection.tsx @@ -5,6 +5,8 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { SpinnerGap, CheckCircle, Warning } from "@phosphor-icons/react"; import { useTranslation } from "@/hooks/useTranslation"; +import { SettingsCard } from "@/components/patterns/SettingsCard"; +import { StatusBanner } from "@/components/patterns/StatusBanner"; interface TelegramBridgeSettings { telegram_bot_token: string; @@ -172,14 +174,10 @@ export function TelegramBridgeSection() { return (
    {/* Bot Credentials */} -
    -
    -

    {t("telegram.credentials")}

    -

    - {t("telegram.credentialsDesc")} -

    -
    - +
    {verifyResult && ( -
    : } > - {verifyResult.ok ? : } {verifyResult.message} -
    + )} -
    +
    {/* Allowed Users */} -
    -
    -

    {t("bridge.allowedUsers")}

    -

    - {t("bridge.allowedUsersDesc")} -

    -
    - +
    -
    + {/* Setup Guide */} -
    -

    - {t("telegram.setupGuide")} -

    +
    1. {t("telegram.step1")}
    2. {t("telegram.step2")}
    3. @@ -300,7 +287,7 @@ export function TelegramBridgeSection() {
    4. {t("telegram.step5")}
    5. {t("telegram.step6")}
    -
    +
    ); } diff --git a/src/components/settings/AppearanceSection.tsx b/src/components/settings/AppearanceSection.tsx index 84b5df4..7a15094 100644 --- a/src/components/settings/AppearanceSection.tsx +++ b/src/components/settings/AppearanceSection.tsx @@ -17,7 +17,10 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; +import { SettingsCard } from "@/components/patterns/SettingsCard"; +import { FieldRow } from "@/components/patterns/FieldRow"; // ── Theme Mode Pill Selector ──────────────────────────────────────── @@ -40,22 +43,23 @@ function ThemeModePills({ {MODE_OPTIONS.map((opt) => { const selected = value === opt.value; return ( - + ); })}
    @@ -113,15 +117,9 @@ function ShikiCodePreview({ isDark }: { isDark: boolean }) { function UIPreview() { return (
    - - - + + + Badge @@ -159,15 +157,14 @@ export function AppearanceSection() {

    {t("settings.appearanceDesc")}

    -
    + {/* Mode */} -
    -
    -

    {t("settings.themeMode")}

    -

    {t("settings.themeModeDesc")}

    -
    + -
    + {theme === "system" && resolvedTheme && (

    @@ -175,14 +172,12 @@ export function AppearanceSection() {

    )} -
    - {/* Family */} -
    -
    -

    {t("settings.themeFamily")}

    -

    {t("settings.themeFamilyDesc")}

    -
    + -
    - -
    + {/* Preview */} -
    +

    Preview

    -
    +
    ); } diff --git a/src/components/settings/GeneralSection.tsx b/src/components/settings/GeneralSection.tsx index a7e96a0..f75470f 100644 --- a/src/components/settings/GeneralSection.tsx +++ b/src/components/settings/GeneralSection.tsx @@ -19,6 +19,9 @@ import { useTranslation } from "@/hooks/useTranslation"; import { SUPPORTED_LOCALES, type Locale } from "@/i18n"; import type { TranslationKey } from "@/i18n"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { SettingsCard } from "@/components/patterns/SettingsCard"; +import { FieldRow } from "@/components/patterns/FieldRow"; +import { StatusBanner } from "@/components/patterns/StatusBanner"; import { AppearanceSection } from "./AppearanceSection"; function UpdateCard() { @@ -30,7 +33,7 @@ function UpdateCard() { && updateInfo.downloadProgress != null; return ( -
    +

    {t('settings.codepilot')}

    @@ -114,7 +117,7 @@ function UpdateCard() { )}
    )} -
    +
    ); } @@ -210,36 +213,31 @@ export function GeneralSection() { {/* General settings card */} -
    + {/* Auto-approve toggle */} -
    -
    -

    {t('settings.autoApproveTitle')}

    -

    - {t('settings.autoApproveDesc')} -

    -
    + -
    + {skipPermissions && ( -
    - + + {t('settings.autoApproveWarning')} -
    + )} -
    - {/* Language picker */} -
    -
    -

    {t('settings.language')}

    -

    {t('settings.languageDesc')}

    -
    + -
    - -
    + {/* Thinking mode */} -
    -
    -

    {t('settings.thinkingMode' as TranslationKey)}

    -

    {t('settings.thinkingModeDesc' as TranslationKey)}

    -
    + -
    -
    + + {/* Appearance */} {/* Account info */} {accountInfo && ( -
    -

    {t('settings.accountInfo' as TranslationKey)}

    +
    {accountInfo.email && (

    @@ -297,7 +292,7 @@ export function GeneralSection() {

    )}
    -
    + )} {/* Skip-permissions warning dialog */}