feat: update Sidebar and Login components with icon integration and localization improvements
This commit is contained in:
4
dist/index.html
vendored
4
dist/index.html
vendored
@@ -8,8 +8,8 @@
|
|||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
||||||
/>
|
/>
|
||||||
<script type="module" crossorigin src="./assets/index-XQk97xGQ.js"></script>
|
<script type="module" crossorigin src="./assets/index-BCaudNKp.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-BZXC3Usl.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-zlEBzOiw.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { Book, Clock, Code, Cpu, House, Puzzle, Settings } from 'lucide-react';
|
||||||
import { NAV_ITEMS, normalizeWorkspacePath } from '../../router/routes';
|
import { NAV_ITEMS, normalizeWorkspacePath } from '../../router/routes';
|
||||||
|
|
||||||
const MENU_MARKS: Record<string, string> = {
|
const MENU_MARKS: Record<string, typeof House> = {
|
||||||
'/home': '首',
|
'/home': House,
|
||||||
'/knowledge': '知',
|
'/knowledge': Book,
|
||||||
'/agents': '模',
|
'/agents': Cpu,
|
||||||
'/skills': '技',
|
'/skills': Puzzle,
|
||||||
'/cron': '时',
|
'/cron': Clock,
|
||||||
'/scripts': '脚',
|
'/scripts': Code,
|
||||||
'/setting': '设',
|
'/setting': Settings,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Sidebar() {
|
export default function Sidebar() {
|
||||||
@@ -17,11 +18,12 @@ export default function Sidebar() {
|
|||||||
const currentId = normalizeWorkspacePath(location.pathname);
|
const currentId = normalizeWorkspacePath(location.pathname);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-[80px] h-full box-border flex flex-col items-center pb-[8px]">
|
<aside className="box-border flex h-full w-[80px] flex-col items-center pb-[8px]">
|
||||||
<div className="flex flex-col gap-[16px] w-full">
|
<div className="flex w-full flex-col gap-[16px]">
|
||||||
{NAV_ITEMS.map((item) => {
|
{NAV_ITEMS.map((item) => {
|
||||||
const active = currentId === item.path;
|
const active = currentId === item.path;
|
||||||
const isSetting = item.path === '/setting';
|
const isSetting = item.path === '/setting';
|
||||||
|
const MenuMark = MENU_MARKS[item.path];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -30,25 +32,25 @@ export default function Sidebar() {
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="cursor-pointer flex flex-col items-center justify-center"
|
className="flex cursor-pointer flex-col items-center justify-center"
|
||||||
onClick={() => navigate(item.path)}
|
onClick={() => navigate(item.path)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
'box-border rounded-[16px] w-[48px] h-[48px] flex flex-col items-center justify-center hover:bg-white dark:hover:bg-[#222225]',
|
'box-border flex h-[48px] w-[48px] flex-col items-center justify-center rounded-[16px] hover:bg-white dark:hover:bg-[#222225]',
|
||||||
active ? 'bg-white dark:bg-[#222225]' : '',
|
active ? 'bg-white dark:bg-[#222225]' : '',
|
||||||
].join(' ')}
|
].join(' ')}
|
||||||
>
|
>
|
||||||
<span
|
<MenuMark
|
||||||
className="text-[18px] font-semibold leading-none"
|
aria-hidden="true"
|
||||||
|
className="h-[18px] w-[18px]"
|
||||||
|
strokeWidth={2.1}
|
||||||
style={{ color: active ? '#2B7FFF' : '#525866' }}
|
style={{ color: active ? '#2B7FFF' : '#525866' }}
|
||||||
>
|
/>
|
||||||
{MENU_MARKS[item.path]}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="text-[14px] mt-[4px] mb-[8px] hover:text-[#2B7FFF]"
|
className="mt-[4px] mb-[8px] text-[14px] hover:text-[#2B7FFF]"
|
||||||
style={{ color: active ? '#2B7FFF' : '#525866' }}
|
style={{ color: active ? '#2B7FFF' : '#525866' }}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
@@ -59,7 +61,7 @@ export default function Sidebar() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-[48px] h-[48px] rounded-full overflow-hidden mt-auto bg-white dark:bg-[#222225] flex items-center justify-center border border-black/10 dark:border-[#2a2a2d]">
|
<div className="mt-auto flex h-[48px] w-[48px] items-center justify-center overflow-hidden rounded-full border border-black/10 bg-white dark:border-[#2a2a2d] dark:bg-[#222225]">
|
||||||
<span className="text-[16px] font-bold text-[#2B7FFF]">Z</span>
|
<span className="text-[16px] font-bold text-[#2B7FFF]">Z</span>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { type ChangeEvent, type FormEvent, useEffect, useMemo, useState } from 'react';
|
import { type ChangeEvent, type FormEvent, useEffect, useMemo, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { Lock, User } from 'lucide-react';
|
||||||
|
|
||||||
import blueLogo from '../../assets/images/login/blue_logo.png';
|
import blueLogo from '../../assets/images/login/blue_logo.png';
|
||||||
import loginBackground from '../../assets/images/login/login_bg.png';
|
import loginBackground from '../../assets/images/login/login_bg.png';
|
||||||
@@ -25,6 +26,14 @@ const INITIAL_FORM: LoginFormValues = {
|
|||||||
randomStr: '',
|
randomStr: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const credentialFieldShellClass =
|
||||||
|
'flex h-11 items-center rounded-[10px] border border-black/10 bg-gray-50 transition focus-within:border-[#2B7FFF] focus-within:ring-2 focus-within:ring-[#2B7FFF]/10 dark:border-[#2a2a2d] dark:bg-[#222225]';
|
||||||
|
|
||||||
|
const credentialFieldIconClass = 'ml-4 mr-3 h-4 w-4 shrink-0 text-[#99A0AE] dark:text-gray-500';
|
||||||
|
|
||||||
|
const credentialFieldInputClass =
|
||||||
|
'h-full min-w-0 flex-1 border-0 bg-transparent pr-4 text-[14px] text-gray-800 outline-none placeholder:text-[#99A0AE] disabled:cursor-not-allowed dark:text-gray-100 dark:placeholder:text-gray-500';
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -133,27 +142,30 @@ export default function LoginPage() {
|
|||||||
<div className="mb-6 box-border flex flex-col items-center justify-center pt-10">
|
<div className="mb-6 box-border flex flex-col items-center justify-center pt-10">
|
||||||
<img className="mb-3 h-20 w-20" src={userIcon} alt="" />
|
<img className="mb-3 h-20 w-20" src={userIcon} alt="" />
|
||||||
<div className="mb-1 text-[24px] leading-[32px] font-medium text-gray-800 dark:text-gray-100">
|
<div className="mb-1 text-[24px] leading-[32px] font-medium text-gray-800 dark:text-gray-100">
|
||||||
欢迎回到 zn-ai
|
欢迎回到登录
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[16px] leading-[24px] text-gray-500 dark:text-gray-400">
|
<div className="text-[16px] leading-[24px] text-gray-500 dark:text-gray-400">
|
||||||
请输入账号信息完成登录
|
24小时在岗,从不打烊的数字员工
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form className="mx-auto flex w-[392px] flex-col gap-4" onSubmit={handleSubmit}>
|
<form className="mx-auto flex w-[392px] flex-col gap-4" onSubmit={handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-username">
|
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-username">
|
||||||
用户名
|
账号
|
||||||
</label>
|
</label>
|
||||||
|
<div className={credentialFieldShellClass}>
|
||||||
|
<User aria-hidden="true" className={credentialFieldIconClass} />
|
||||||
<input
|
<input
|
||||||
id="login-username"
|
id="login-username"
|
||||||
className="h-10 w-full rounded-[10px] border border-black/10 bg-gray-50 px-4 text-[14px] text-gray-800 outline-none transition focus:border-[#2B7FFF] dark:border-[#2a2a2d] dark:bg-[#222225] dark:text-gray-100"
|
className={credentialFieldInputClass}
|
||||||
autoComplete="username"
|
autoComplete="username"
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
placeholder="请输入用户名"
|
placeholder="请输入账号"
|
||||||
value={form.username}
|
value={form.username}
|
||||||
onChange={(event) => handleInputChange('username', event)}
|
onChange={(event) => handleInputChange('username', event)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
{errors.username ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.username}</div> : null}
|
{errors.username ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.username}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -161,9 +173,11 @@ export default function LoginPage() {
|
|||||||
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-password">
|
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-password">
|
||||||
密码
|
密码
|
||||||
</label>
|
</label>
|
||||||
|
<div className={credentialFieldShellClass}>
|
||||||
|
<Lock aria-hidden="true" className={credentialFieldIconClass} />
|
||||||
<input
|
<input
|
||||||
id="login-password"
|
id="login-password"
|
||||||
className="h-10 w-full rounded-[10px] border border-black/10 bg-gray-50 px-4 text-[14px] text-gray-800 outline-none transition focus:border-[#2B7FFF] dark:border-[#2a2a2d] dark:bg-[#222225] dark:text-gray-100"
|
className={credentialFieldInputClass}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
placeholder="请输入密码"
|
placeholder="请输入密码"
|
||||||
@@ -171,6 +185,7 @@ export default function LoginPage() {
|
|||||||
value={form.password}
|
value={form.password}
|
||||||
onChange={(event) => handleInputChange('password', event)}
|
onChange={(event) => handleInputChange('password', event)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
{errors.password ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.password}</div> : null}
|
{errors.password ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.password}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user