mirror of
https://github.com/FranP-code/ChatGPT.git
synced 2025-10-13 00:13:25 +00:00
chore: control center
This commit is contained in:
11
src/layout/index.scss
vendored
11
src/layout/index.scss
vendored
@@ -10,4 +10,15 @@
|
||||
|
||||
.chat-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
.ant-menu-item {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-layout-footer {
|
||||
color: #666 !important;
|
||||
opacity: 0.7;
|
||||
}
|
||||
37
src/layout/index.tsx
vendored
37
src/layout/index.tsx
vendored
@@ -1,51 +1,30 @@
|
||||
import { FC, useState } from 'react';
|
||||
import {
|
||||
DesktopOutlined,
|
||||
BulbOutlined
|
||||
} from '@ant-design/icons';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Layout, Menu } from 'antd';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import Routes, { menuItems } from '@/routes';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const { Content, Footer, Sider } = Layout;
|
||||
|
||||
type MenuItem = Required<MenuProps>['items'][number];
|
||||
|
||||
function getItem(
|
||||
label: React.ReactNode,
|
||||
key: React.Key,
|
||||
icon?: React.ReactNode,
|
||||
children?: MenuItem[],
|
||||
): MenuItem {
|
||||
return {
|
||||
key,
|
||||
icon,
|
||||
children,
|
||||
label,
|
||||
} as MenuItem;
|
||||
}
|
||||
|
||||
const items: MenuItem[] = [
|
||||
getItem('General', 'general', <DesktopOutlined />),
|
||||
getItem('ChatGPT Prompts', 'chatgpt-prompts', <BulbOutlined />),
|
||||
];
|
||||
|
||||
interface ChatLayoutProps {
|
||||
children: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const ChatLayout: FC<ChatLayoutProps> = ({ children }) => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const go = useNavigate();
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: '100vh' }}>
|
||||
<Sider theme="light" collapsible collapsed={collapsed} onCollapse={(value) => setCollapsed(value)}>
|
||||
<div className="chat-logo"><img src="/logo.png" /></div>
|
||||
<Menu defaultSelectedKeys={['1']} mode="inline" items={items} />
|
||||
<Menu defaultSelectedKeys={['/']} mode="vertical" items={menuItems} onClick={(i) => go(i.key)} />
|
||||
</Sider>
|
||||
<Layout className="chat-layout">
|
||||
<Content className="chat-container">
|
||||
{children}
|
||||
<Routes />
|
||||
</Content>
|
||||
<Footer style={{ textAlign: 'center' }}>
|
||||
<a href="https://github.com/lencx/chatgpt" target="_blank">ChatGPT Desktop Application</a> ©2022 Created by lencx</Footer>
|
||||
|
||||
4
src/main.tsx
vendored
4
src/main.tsx
vendored
@@ -2,14 +2,14 @@ import { StrictMode, Suspense } from 'react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
import Routes from './routes';
|
||||
import Layout from '@/layout';
|
||||
import './main.scss';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<StrictMode>
|
||||
<Suspense fallback={null}>
|
||||
<BrowserRouter>
|
||||
<Routes />
|
||||
<Layout/>
|
||||
</BrowserRouter>
|
||||
</Suspense>
|
||||
</StrictMode>
|
||||
|
||||
46
src/routes.tsx
vendored
46
src/routes.tsx
vendored
@@ -1,22 +1,44 @@
|
||||
import { useLayoutEffect } from 'react';
|
||||
import { useLocation, useRoutes } from 'react-router-dom';
|
||||
import { useRoutes } from 'react-router-dom';
|
||||
import {
|
||||
DesktopOutlined,
|
||||
BulbOutlined
|
||||
} from '@ant-design/icons';
|
||||
import type { RouteObject } from 'react-router-dom';
|
||||
import type { MenuProps } from 'antd';
|
||||
|
||||
import App from '@view/App';
|
||||
import General from '@view/General';
|
||||
import ChatGPTPrompts from '@view/ChatGPTPrompts';
|
||||
|
||||
const routes: RouteObject[] = [
|
||||
export type ChatRouteObject = {
|
||||
label: string;
|
||||
icon?: React.ReactNode,
|
||||
};
|
||||
|
||||
export const routes: Array<RouteObject & { meta: ChatRouteObject }> = [
|
||||
{
|
||||
path: '/',
|
||||
element: <App />
|
||||
}
|
||||
element: <General />,
|
||||
meta: {
|
||||
label: 'General',
|
||||
icon: <DesktopOutlined />,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/chatgpt-prompts',
|
||||
element: <ChatGPTPrompts />,
|
||||
meta: {
|
||||
label: 'ChatGPT Prompts',
|
||||
icon: <BulbOutlined />,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
type MenuItem = Required<MenuProps>['items'][number];
|
||||
export const menuItems: MenuItem[] = routes.map(i => ({
|
||||
...i.meta,
|
||||
key: i.path || '',
|
||||
}));
|
||||
|
||||
export default () => {
|
||||
const location = useLocation();
|
||||
const pathname = location.pathname;
|
||||
useLayoutEffect(() => {
|
||||
const name = pathname.substring(1).replace(/\//gi, '_');
|
||||
document.body.className = `${name ? name : 'main'}_screen`
|
||||
}, [pathname]);
|
||||
return useRoutes(routes);
|
||||
};
|
||||
9
src/view/App.tsx
vendored
9
src/view/App.tsx
vendored
@@ -1,9 +0,0 @@
|
||||
import Layout from "@layout/index";
|
||||
|
||||
export default function Dashboard() {
|
||||
return (
|
||||
<Layout>
|
||||
Hello
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
7
src/view/ChatGPTPrompts.tsx
vendored
Normal file
7
src/view/ChatGPTPrompts.tsx
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function Dashboard() {
|
||||
return (
|
||||
<div>
|
||||
TODO: ChatGPT Prompts
|
||||
</div>
|
||||
)
|
||||
}
|
||||
93
src/view/General.tsx
vendored
Normal file
93
src/view/General.tsx
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Form, Radio, Switch, Input, Button, Space, message } from 'antd';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { platform } from '@tauri-apps/api/os';
|
||||
import { ask } from '@tauri-apps/api/dialog';
|
||||
import { relaunch } from '@tauri-apps/api/process';
|
||||
import { clone, pick, isEqual } from 'lodash';
|
||||
|
||||
const restartNames = ['origin', 'ua_window', 'ua_tray']
|
||||
|
||||
export default function General() {
|
||||
const [form] = Form.useForm();
|
||||
const [platformInfo, setPlatform] = useState<string>('');
|
||||
const [chatConf, setChatConf] = useState<any>(null);
|
||||
|
||||
const init = async () => {
|
||||
setPlatform(await platform());
|
||||
const chatData = await invoke('get_chat_conf');
|
||||
setChatConf(chatData);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(clone(chatConf));
|
||||
}, [chatConf])
|
||||
|
||||
console.log('«28» /src/view/General.tsx ~> ', chatConf);
|
||||
|
||||
|
||||
const onCancel = () => {
|
||||
form.setFieldsValue(chatConf);
|
||||
};
|
||||
|
||||
const onFinish = async (values: any) => {
|
||||
await invoke('form_confirm', { data: values, label: 'main' });
|
||||
console.log('«33» /src/view/General.tsx ~> ', pick(chatConf, restartNames), pick(values, restartNames));
|
||||
|
||||
if (!isEqual(pick(chatConf, restartNames), pick(values, restartNames))) {
|
||||
const isOk = await ask(`Configuration saved successfully, whether to restart?`, {
|
||||
title: 'ChatGPT Preferences'
|
||||
});
|
||||
if (isOk) relaunch();
|
||||
return;
|
||||
}
|
||||
|
||||
message.success('Configuration saved successfully');
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
style={{ maxWidth: 500 }}
|
||||
onFinish={onFinish}
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 15, offset: 1 }}
|
||||
>
|
||||
<Form.Item label="Theme" name="theme">
|
||||
<Radio.Group>
|
||||
<Radio value="Light">Light</Radio>
|
||||
<Radio value="Dark">Dark</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="Always on Top" name="always_on_top" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
{platformInfo === 'darwin' && (
|
||||
<Form.Item label="Titlebar" name="titlebar" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item label="Switch Origin" name="origin">
|
||||
<Input placeholder="https://chat.openai.com" />
|
||||
</Form.Item>
|
||||
<Form.Item label="User Agent (Window)" name="ua_window">
|
||||
<Input.TextArea autoSize={{ minRows: 2, maxRows: 4 }} placeholder="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" />
|
||||
</Form.Item>
|
||||
<Form.Item label="User Agent (Tray)" name="ua_tray">
|
||||
<Input.TextArea autoSize={{ minRows: 2, maxRows: 4 }} placeholder="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Space size={20}>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user