From 180b097b11fcfa518d298efc3ba0bb86e0935687 Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Sat, 14 Mar 2026 15:33:57 +0800 Subject: [PATCH] refactor(login): use auth file checkbox style for login options --- .../ui/SelectionCheckbox.module.scss | 87 +++++++++++++++++++ src/components/ui/SelectionCheckbox.tsx | 50 +++++++++++ .../authFiles/components/AuthFileCard.tsx | 14 ++- src/pages/AuthFilesPage.module.scss | 39 --------- src/pages/LoginPage.tsx | 12 +-- 5 files changed, 149 insertions(+), 53 deletions(-) create mode 100644 src/components/ui/SelectionCheckbox.module.scss create mode 100644 src/components/ui/SelectionCheckbox.tsx diff --git a/src/components/ui/SelectionCheckbox.module.scss b/src/components/ui/SelectionCheckbox.module.scss new file mode 100644 index 0000000..5f25d44 --- /dev/null +++ b/src/components/ui/SelectionCheckbox.module.scss @@ -0,0 +1,87 @@ +@use '../../styles/variables' as *; + +.root { + position: relative; + display: inline-flex; + align-items: center; + gap: $spacing-sm; + cursor: pointer; + user-select: none; +} + +.disabled { + cursor: not-allowed; + opacity: 0.6; +} + +.input { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + overflow: hidden; + clip: rect(0 0 0 0); + clip-path: inset(50%); + white-space: nowrap; +} + +.box { + width: 22px; + height: 22px; + flex-shrink: 0; + border-radius: 7px; + border: 1px solid var(--border-color); + background: color-mix(in srgb, var(--bg-secondary) 92%, transparent); + color: var(--primary-contrast, #fff); + display: inline-flex; + align-items: center; + justify-content: center; + transition: + border-color $transition-fast, + background-color $transition-fast, + box-shadow $transition-fast, + transform $transition-fast; +} + +.root:hover .box { + border-color: var(--primary-color); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 16%, transparent); +} + +.root:active .box { + transform: scale(0.95); +} + +.disabled:hover .box { + border-color: var(--border-color); + box-shadow: none; +} + +.disabled:active .box { + transform: none; +} + +.input:focus-visible + .box { + border-color: var(--primary-color); + box-shadow: + 0 0 0 3px color-mix(in srgb, var(--primary-color) 16%, transparent), + 0 0 0 1px color-mix(in srgb, var(--primary-color) 50%, transparent); +} + +.boxChecked { + border-color: var(--primary-color); + background: var(--primary-color); +} + +.boxChecked svg { + display: block; + stroke-width: 2.4; +} + +.label { + color: var(--text-primary); + font-size: 14px; + font-weight: 500; +} diff --git a/src/components/ui/SelectionCheckbox.tsx b/src/components/ui/SelectionCheckbox.tsx new file mode 100644 index 0000000..f55fac7 --- /dev/null +++ b/src/components/ui/SelectionCheckbox.tsx @@ -0,0 +1,50 @@ +import type { ChangeEvent, ReactNode } from 'react'; +import { IconCheck } from './icons'; +import styles from './SelectionCheckbox.module.scss'; + +interface SelectionCheckboxProps { + checked: boolean; + onChange: (value: boolean) => void; + label?: ReactNode; + ariaLabel?: string; + title?: string; + disabled?: boolean; + className?: string; + labelClassName?: string; +} + +export function SelectionCheckbox({ + checked, + onChange, + label, + ariaLabel, + title, + disabled = false, + className, + labelClassName, +}: SelectionCheckboxProps) { + const rootClassName = [styles.root, disabled ? styles.disabled : '', className] + .filter(Boolean) + .join(' '); + const boxClassName = [styles.box, checked ? styles.boxChecked : ''].filter(Boolean).join(' '); + const textClassName = [styles.label, labelClassName].filter(Boolean).join(' '); + + const handleChange = (event: ChangeEvent) => { + onChange(event.target.checked); + }; + + return ( + + ); +} diff --git a/src/features/authFiles/components/AuthFileCard.tsx b/src/features/authFiles/components/AuthFileCard.tsx index 9e7b910..a6705f3 100644 --- a/src/features/authFiles/components/AuthFileCard.tsx +++ b/src/features/authFiles/components/AuthFileCard.tsx @@ -1,10 +1,10 @@ import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; +import { SelectionCheckbox } from '@/components/ui/SelectionCheckbox'; import { ToggleSwitch } from '@/components/ui/ToggleSwitch'; import { IconBot, - IconCheck, IconCode, IconDownload, IconInfo, @@ -118,18 +118,14 @@ export function AuthFileCard(props: AuthFileCardProps) {
{!isRuntimeOnly && ( - + /> )}
- {t('login.custom_connection_label')}} + label={t('login.custom_connection_label')} + labelClassName={styles.toggleLabel} />
@@ -281,11 +282,12 @@ export function LoginPage() { />
- {t('login.remember_password_label')}} + label={t('login.remember_password_label')} + labelClassName={styles.toggleLabel} />