mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 12:44:22 +00:00
refactor(frontend): modernize login page with AntD primitives
- Theme cycle button switched from `<button.theme-cycle>` + custom CSS to AntD `<Button shape="circle" className="toolbar-btn">` (matches sub page chrome already established). - Theme icons switched from hand-rolled inline SVG (sun, moon, moon+star) to AntD `<SunOutlined />`, `<MoonOutlined />`, `<MoonFilled />` for the three light / dark / ultra-dark states. - Language popover content switched from `<ul.lang-list>` + `<button.lang-item>` to AntD `<Menu mode="vertical" selectable />` with `selectedKeys=[lang]`; native hover / keyboard nav / active highlight come for free. - Drop CSS for `.theme-cycle`, `.lang-list`, `.lang-item*` (now unused). `.toolbar-btn` retained since it sizes both circular buttons.
This commit is contained in:
parent
7e5f279284
commit
0362590b10
2 changed files with 31 additions and 108 deletions
|
|
@ -228,36 +228,6 @@
|
|||
font-size: 18px;
|
||||
}
|
||||
|
||||
.theme-cycle {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--bg-card);
|
||||
color: var(--color-text);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
backdrop-filter: blur(20px);
|
||||
transition: background-color 0.2s, transform 0.15s, color 0.2s;
|
||||
}
|
||||
|
||||
.theme-cycle:hover,
|
||||
.theme-cycle:focus-visible {
|
||||
background-color: rgba(99, 102, 241, 0.15);
|
||||
color: var(--color-accent);
|
||||
transform: scale(1.05);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.theme-cycle svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.login-wrapper {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
|
|
@ -402,44 +372,3 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.lang-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 160px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.lang-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
text-align: start;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.lang-item:hover,
|
||||
.lang-item:focus-visible {
|
||||
background-color: rgba(99, 102, 241, 0.12);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.lang-item.is-active {
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.lang-item-icon {
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,18 @@ import {
|
|||
Form,
|
||||
Input,
|
||||
Layout,
|
||||
Menu,
|
||||
Popover,
|
||||
Space,
|
||||
Spin,
|
||||
message,
|
||||
} from 'antd';
|
||||
import {
|
||||
KeyOutlined,
|
||||
LockOutlined,
|
||||
MoonFilled,
|
||||
MoonOutlined,
|
||||
SunOutlined,
|
||||
TranslationOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons';
|
||||
|
|
@ -105,26 +110,20 @@ export default function LoginPage() {
|
|||
return classes.join(' ');
|
||||
}, [isDark, isUltra]);
|
||||
|
||||
const langList = useMemo(
|
||||
() => LanguageManager.supportedLanguages as { value: string; name: string; icon: string }[],
|
||||
const langMenuItems = useMemo(
|
||||
() => (LanguageManager.supportedLanguages as { value: string; name: string; icon: string }[]).map((l) => ({
|
||||
key: l.value,
|
||||
label: (
|
||||
<Space size={8}>
|
||||
<span aria-hidden="true">{l.icon}</span>
|
||||
<span>{l.name}</span>
|
||||
</Space>
|
||||
),
|
||||
})),
|
||||
[],
|
||||
);
|
||||
|
||||
const themeIcon = !isDark ? (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="4" />
|
||||
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41" />
|
||||
</svg>
|
||||
) : !isUltra ? (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||
<path fill="none" d="M19 3l0.7 1.4 1.4 0.7-1.4 0.7L19 7.2l-0.7-1.4-1.4-0.7 1.4-0.7z" />
|
||||
</svg>
|
||||
);
|
||||
const themeIcon = !isDark ? <SunOutlined /> : !isUltra ? <MoonOutlined /> : <MoonFilled />;
|
||||
|
||||
return (
|
||||
<ConfigProvider theme={antdThemeConfig}>
|
||||
|
|
@ -132,35 +131,30 @@ export default function LoginPage() {
|
|||
<Layout className={pageClass}>
|
||||
<Layout.Content className="login-content">
|
||||
<div className="login-toolbar">
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
id="login-theme-cycle"
|
||||
className="theme-cycle"
|
||||
shape="circle"
|
||||
size="large"
|
||||
className="toolbar-btn"
|
||||
aria-label={t('menu.theme')}
|
||||
title={t('menu.theme')}
|
||||
icon={themeIcon}
|
||||
onClick={cycleTheme}
|
||||
>
|
||||
{themeIcon}
|
||||
</button>
|
||||
/>
|
||||
<Popover
|
||||
rootClassName={isDark ? 'dark' : 'light'}
|
||||
placement="bottomRight"
|
||||
trigger="click"
|
||||
styles={{ content: { padding: 4 } }}
|
||||
content={
|
||||
<ul className="lang-list">
|
||||
{langList.map((l) => (
|
||||
<li key={l.value}>
|
||||
<button
|
||||
type="button"
|
||||
className={`lang-item${lang === l.value ? ' is-active' : ''}`}
|
||||
onClick={() => onLangChange(l.value)}
|
||||
>
|
||||
<span className="lang-item-icon" aria-hidden="true">{l.icon}</span>
|
||||
<span className="lang-item-name">{l.name}</span>
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Menu
|
||||
mode="vertical"
|
||||
selectable
|
||||
selectedKeys={[lang]}
|
||||
items={langMenuItems}
|
||||
onClick={({ key }) => onLangChange(key)}
|
||||
style={{ border: 'none', minWidth: 160 }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
|
|
|
|||
Loading…
Reference in a new issue