feat: first commit

This commit is contained in:
2024-10-26 12:10:13 +08:00
parent b244826aa1
commit b064c4cb87
158 changed files with 18888 additions and 1 deletions

View File

@@ -0,0 +1,21 @@
import React, { forwardRef } from 'react';
import { Button } from '@arco-design/web-react';
import styles from './style/icon-button.module.less';
import cs from 'classnames';
function IconButton(props, ref) {
const { icon, className, ...rest } = props;
return (
<Button
ref={ref}
icon={icon}
shape="circle"
type="secondary"
className={cs(styles['icon-button'], className)}
{...rest}
/>
);
}
export default forwardRef(IconButton);

View File

@@ -0,0 +1,165 @@
import React, { useContext } from 'react';
import {
Tooltip,
Avatar,
Select,
Dropdown,
Menu,
Divider,
Message,
Button,
} from '@arco-design/web-react';
import {
IconLanguage,
IconSunFill,
IconMoonFill,
IconUser,
IconSettings,
IconPoweroff,
IconTag,
IconLoading,
} from '@arco-design/web-react/icon';
import { GlobalContext } from '@/context';
import useLocale from '@/utils/useLocale';
import IconButton from './IconButton';
import Settings from '../Settings';
import styles from './style/index.module.less';
import defaultLocale from '@/locale';
import useStorage from '@/utils/useStorage';
import logoIcon from '@/assets/logo.png'
import {useStore} from '@/store';
function Navbar({ show }: { show: boolean }) {
const t = useLocale();
const { userInfo, userLoading } = useStore()
const [_, setUserStatus] = useStorage('userStatus');
const [role, setRole] = useStorage('userRole', 'admin');
const { setLang, lang, theme, setTheme } = useContext(GlobalContext);
function logout() {
setUserStatus('logout');
window.location.href = '/login';
}
function onMenuItemClick(key) {
if (key === 'logout') {
logout();
} else {
Message.info(`You clicked ${key}`);
}
}
if (!show) {
return (
<div className={styles['fixed-settings']}>
<Settings
trigger={
<Button icon={<IconSettings />} type="primary" size="large" />
}
/>
</div>
);
}
const handleChangeRole = () => {
const newRole = role === 'admin' ? 'user' : 'admin';
setRole(newRole);
};
const droplist = (
<Menu onClickMenuItem={onMenuItemClick}>
<Menu.SubMenu
key="role"
title={
<>
<IconUser className={styles['dropdown-icon']} />
<span className={styles['user-role']}>
{role === 'admin'
? t['menu.user.role.admin']
: t['menu.user.role.user']}
</span>
</>
}
>
<Menu.Item onClick={handleChangeRole} key="switch role">
<IconTag className={styles['dropdown-icon']} />
{t['menu.user.switchRoles']}
</Menu.Item>
</Menu.SubMenu>
<Menu.Item key="setting">
<IconSettings className={styles['dropdown-icon']} />
{t['menu.user.setting']}
</Menu.Item>
<Divider style={{ margin: '4px 0' }} />
<Menu.Item key="logout">
<IconPoweroff className={styles['dropdown-icon']} />
{t['navbar.logout']}
</Menu.Item>
</Menu>
);
return (
<div className={styles.navbar}>
<div className={styles.left}>
<div className={styles.logo}>
<img className={styles.logo} src={logoIcon} alt=""/>
<div className={styles['logo-name']}>{import.meta.env.VITE_APP_TITLE}</div>
</div>
</div>
<ul className={styles.right}>
<li>
<Select
triggerElement={<IconButton icon={<IconLanguage />} />}
options={[
{ label: '中文', value: 'zh-CN' },
{ label: 'English', value: 'en-US' },
]}
value={lang}
triggerProps={{
autoAlignPopupWidth: false,
autoAlignPopupMinWidth: true,
position: 'br',
}}
trigger="hover"
onChange={(value) => {
setLang(value);
const nextLang = defaultLocale[value];
Message.info(`${nextLang['message.lang.tips']}${value}`);
}}
/>
</li>
<li>
<Tooltip
content={
theme === 'light'
? t['settings.navbar.theme.toDark']
: t['settings.navbar.theme.toLight']
}
>
<IconButton
icon={theme !== 'dark' ? <IconMoonFill /> : <IconSunFill />}
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
/>
</Tooltip>
</li>
<Settings />
{userInfo && (
<li>
<Dropdown droplist={droplist} position="br" disabled={userLoading}>
<Avatar size={32} style={{ cursor: 'pointer' }}>
{userLoading ? (
<IconLoading />
) : (
<img alt="avatar" src={userInfo?.avatar?.path} />
)}
</Avatar>
</Dropdown>
</li>
)}
</ul>
</div>
);
}
export default Navbar;

View File

@@ -0,0 +1,8 @@
.icon-button {
font-size: 16px;
border: 1px solid var(--color-border-2);
> svg {
vertical-align: -3px;
}
}

View File

@@ -0,0 +1,83 @@
.navbar {
display: flex;
justify-content: space-between;
border-bottom: 1px solid var(--color-border);
box-sizing: border-box;
background-color: var(--color-bg-2);
height: 100%;
}
.left {
display: flex;
align-items: center;
}
.logo {
display: flex;
align-items: center;
width: 44px;
padding-left: 20px;
box-sizing: border-box;
svg{
width: 44px;
height: 44px;
}
}
.logo-name {
color: var(--color-text-1);
font-weight: 500;
font-size: 20px;
margin-left: 10px;
font-family: 'PingFang SC';
white-space: nowrap;
}
.right {
display: flex;
list-style: none;
padding-right: 20px;
li {
padding: 0 8px;
display: flex;
align-items: center;
}
a {
text-decoration: none;
color: var(--color-text-1);
}
}
.username {
cursor: pointer;
}
.round {
:global(.arco-input-inner-wrapper) {
border-radius: 16px;
}
svg {
font-size: 16px;
}
}
.dropdown-icon {
margin-right: 8px;
font-size: 16px;
vertical-align: text-bottom;
}
.fixed-settings {
position: fixed;
top: 280px;
right: 0px;
svg {
font-size: 18px;
vertical-align: -4px;
}
}