mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-12 06:18:58 +08:00
### What problem does this PR solve? Feat: Bind event to the theme Switch #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
000cd6d615
commit
e8b4e8b3d7
@ -1,6 +1,6 @@
|
|||||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||||
|
|
||||||
type Theme = 'dark' | 'light';
|
type Theme = 'dark' | 'light' | 'system';
|
||||||
|
|
||||||
type ThemeProviderProps = {
|
type ThemeProviderProps = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
@ -17,5 +17,14 @@ export const useNavigatePage = () => {
|
|||||||
navigate(Routes.Home);
|
navigate(Routes.Home);
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
return { navigateToDatasetList, navigateToDataset, navigateToHome };
|
const navigateToProfile = useCallback(() => {
|
||||||
|
navigate(Routes.ProfileSetting);
|
||||||
|
}, [navigate]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
navigateToDatasetList,
|
||||||
|
navigateToDataset,
|
||||||
|
navigateToHome,
|
||||||
|
navigateToProfile,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -25,8 +25,7 @@ export function Header() {
|
|||||||
const { t } = useTranslate('header');
|
const { t } = useTranslate('header');
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const navigate = useNavigateWithFromState();
|
const navigate = useNavigateWithFromState();
|
||||||
// const [currentPath, setCurrentPath] = useState(Routes.Home);
|
const { navigateToHome, navigateToProfile } = useNavigatePage();
|
||||||
const { navigateToHome } = useNavigatePage();
|
|
||||||
|
|
||||||
const tagsData = useMemo(
|
const tagsData = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@ -65,7 +64,6 @@ export function Header() {
|
|||||||
|
|
||||||
const handleChange = (path: SegmentedValue) => {
|
const handleChange = (path: SegmentedValue) => {
|
||||||
navigate(path as Routes);
|
navigate(path as Routes);
|
||||||
// setCurrentPath(path as Routes);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLogoClick = useCallback(() => {
|
const handleLogoClick = useCallback(() => {
|
||||||
@ -121,7 +119,10 @@ export function Header() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Container>
|
</Container>
|
||||||
<Container className="px-3 py-2 bg-colors-background-inverse-standard">
|
<Container className="px-3 py-2 bg-colors-background-inverse-standard">
|
||||||
<Avatar className="w-[30px] h-[30px]">
|
<Avatar
|
||||||
|
className="w-[30px] h-[30px] cursor-pointer"
|
||||||
|
onClick={navigateToProfile}
|
||||||
|
>
|
||||||
<AvatarImage src="https://github.com/shadcn.png" />
|
<AvatarImage src="https://github.com/shadcn.png" />
|
||||||
<AvatarFallback>CN</AvatarFallback>
|
<AvatarFallback>CN</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
import { useTheme } from '@/components/theme-provider';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import {
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
} from '@/components/ui/dropdown-menu';
|
|
||||||
import { Moon, Sun } from 'lucide-react';
|
|
||||||
|
|
||||||
export function ModeToggle() {
|
|
||||||
const { setTheme } = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<Button variant="outline" size="icon">
|
|
||||||
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
||||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
||||||
<span className="sr-only">Toggle theme</span>
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent align="end">
|
|
||||||
<DropdownMenuItem onClick={() => setTheme('light')}>
|
|
||||||
Light
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem onClick={() => setTheme('dark')}>
|
|
||||||
Dark
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem onClick={() => setTheme('system')}>
|
|
||||||
System
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Demo = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<ModeToggle></ModeToggle>
|
|
||||||
</div>
|
|
||||||
<Button>Destructive</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Demo;
|
|
@ -1,14 +1,17 @@
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { ArrowLeft } from 'lucide-react';
|
import { ArrowLeft } from 'lucide-react';
|
||||||
import { Outlet } from 'umi';
|
import { Outlet } from 'umi';
|
||||||
import { SideBar } from './sidebar';
|
import { SideBar } from './sidebar';
|
||||||
|
|
||||||
export default function ProfileSetting() {
|
export default function ProfileSetting() {
|
||||||
|
const { navigateToHome } = useNavigatePage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col w-full h-screen bg-background text-foreground">
|
<div className="flex flex-col w-full h-screen bg-background text-foreground">
|
||||||
<header className="flex items-center border-b">
|
<header className="flex items-center border-b">
|
||||||
<div className="flex items-center border-r p-1.5">
|
<div className="flex items-center border-r p-1.5">
|
||||||
<Button variant="ghost" size="icon">
|
<Button variant="ghost" size="icon" onClick={navigateToHome}>
|
||||||
<ArrowLeft className="w-5 h-5" />
|
<ArrowLeft className="w-5 h-5" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from '@/components/theme-provider';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
@ -13,6 +14,7 @@ import {
|
|||||||
LogOut,
|
LogOut,
|
||||||
User,
|
User,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { useHandleMenuClick } from './hooks';
|
import { useHandleMenuClick } from './hooks';
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
@ -49,35 +51,45 @@ const menuItems = [
|
|||||||
export function SideBar() {
|
export function SideBar() {
|
||||||
const pathName = useSecondPathName();
|
const pathName = useSecondPathName();
|
||||||
const { handleMenuClick } = useHandleMenuClick();
|
const { handleMenuClick } = useHandleMenuClick();
|
||||||
|
const { setTheme } = useTheme();
|
||||||
|
|
||||||
|
const handleThemeChange = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
setTheme(checked ? 'dark' : 'light');
|
||||||
|
},
|
||||||
|
[setTheme],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-[303px] bg-background border-r">
|
<aside className="w-[303px] bg-background border-r flex flex-col">
|
||||||
{menuItems.map((section, idx) => (
|
<div className="flex-1 overflow-auto">
|
||||||
<div key={idx}>
|
{menuItems.map((section, idx) => (
|
||||||
<h2 className="p-6 text-sm font-semibold">{section.section}</h2>
|
<div key={idx}>
|
||||||
{section.items.map((item, itemIdx) => {
|
<h2 className="p-6 text-sm font-semibold">{section.section}</h2>
|
||||||
const active = pathName === item.key;
|
{section.items.map((item, itemIdx) => {
|
||||||
return (
|
const active = pathName === item.key;
|
||||||
<Button
|
return (
|
||||||
key={itemIdx}
|
<Button
|
||||||
variant={active ? 'secondary' : 'ghost'}
|
key={itemIdx}
|
||||||
className={cn('w-full justify-start gap-2.5 p-6 relative')}
|
variant={active ? 'secondary' : 'ghost'}
|
||||||
onClick={handleMenuClick(item.key)}
|
className={cn('w-full justify-start gap-2.5 p-6 relative')}
|
||||||
>
|
onClick={handleMenuClick(item.key)}
|
||||||
<item.icon className="w-6 h-6" />
|
>
|
||||||
<span>{item.label}</span>
|
<item.icon className="w-6 h-6" />
|
||||||
{active && (
|
<span>{item.label}</span>
|
||||||
<div className="absolute right-0 w-[5px] h-[66px] bg-primary rounded-l-xl shadow-[0_0_5.94px_#7561ff,0_0_11.88px_#7561ff,0_0_41.58px_#7561ff,0_0_83.16px_#7561ff,0_0_142.56px_#7561ff,0_0_249.48px_#7561ff]" />
|
{active && (
|
||||||
)}
|
<div className="absolute right-0 w-[5px] h-[66px] bg-primary rounded-l-xl shadow-[0_0_5.94px_#7561ff,0_0_11.88px_#7561ff,0_0_41.58px_#7561ff,0_0_83.16px_#7561ff,0_0_142.56px_#7561ff,0_0_249.48px_#7561ff]" />
|
||||||
</Button>
|
)}
|
||||||
);
|
</Button>
|
||||||
})}
|
);
|
||||||
</div>
|
})}
|
||||||
))}
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="p-6 mt-auto border-t">
|
<div className="p-6 mt-auto border-t">
|
||||||
<div className="flex items-center gap-2 mb-6">
|
<div className="flex items-center gap-2 mb-6">
|
||||||
<Switch id="dark-mode" />
|
<Switch id="dark-mode" onCheckedChange={handleThemeChange} />
|
||||||
<Label htmlFor="dark-mode" className="text-sm">
|
<Label htmlFor="dark-mode" className="text-sm">
|
||||||
Dark
|
Dark
|
||||||
</Label>
|
</Label>
|
||||||
|
@ -7,6 +7,7 @@ export enum Routes {
|
|||||||
Agent = '/agent',
|
Agent = '/agent',
|
||||||
Search = '/next-search',
|
Search = '/next-search',
|
||||||
Chat = '/next-chat',
|
Chat = '/next-chat',
|
||||||
|
ProfileSetting = '/profile-setting',
|
||||||
}
|
}
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@ -136,11 +137,6 @@ const routes = [
|
|||||||
component: '@/pages/404',
|
component: '@/pages/404',
|
||||||
layout: false,
|
layout: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/demo',
|
|
||||||
component: '@/pages/demo',
|
|
||||||
layout: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: Routes.Home,
|
path: Routes.Home,
|
||||||
layout: false,
|
layout: false,
|
||||||
@ -223,30 +219,33 @@ const routes = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile-setting',
|
path: Routes.ProfileSetting,
|
||||||
layout: false,
|
layout: false,
|
||||||
component: '@/pages/profile-setting',
|
component: `@/pages${Routes.ProfileSetting}`,
|
||||||
routes: [
|
routes: [
|
||||||
{ path: '/profile-setting', redirect: '/profile-setting/profile' },
|
|
||||||
{
|
{
|
||||||
path: '/profile-setting/profile',
|
path: Routes.ProfileSetting,
|
||||||
component: '@/pages/profile-setting/profile',
|
redirect: `${Routes.ProfileSetting}/profile`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile-setting/team',
|
path: `${Routes.ProfileSetting}/profile`,
|
||||||
component: '@/pages/profile-setting/team',
|
component: `@/pages${Routes.ProfileSetting}/profile`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile-setting/plan',
|
path: `${Routes.ProfileSetting}/team`,
|
||||||
component: '@/pages/profile-setting/plan',
|
component: `@/pages${Routes.ProfileSetting}/team`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile-setting/model',
|
path: `${Routes.ProfileSetting}/plan`,
|
||||||
component: '@/pages/profile-setting/model',
|
component: `@/pages${Routes.ProfileSetting}/plan`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile-setting/prompt',
|
path: `${Routes.ProfileSetting}/model`,
|
||||||
component: '@/pages/profile-setting/prompt',
|
component: `@/pages${Routes.ProfileSetting}/model`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${Routes.ProfileSetting}/prompt`,
|
||||||
|
component: `@/pages${Routes.ProfileSetting}/prompt`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user