mirror of
https://github.com/FranP-code/ChatGPT.git
synced 2025-10-13 00:13:25 +00:00
chore: dashboard
This commit is contained in:
@@ -140,16 +140,6 @@ pub fn parse_prompt(data: String) -> Vec<PromptRecord> {
|
|||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
|
||||||
pub fn window_reload(app: AppHandle, label: &str) {
|
|
||||||
app
|
|
||||||
.app_handle()
|
|
||||||
.get_window(label)
|
|
||||||
.unwrap()
|
|
||||||
.eval("window.location.reload()")
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct ModelRecord {
|
pub struct ModelRecord {
|
||||||
pub cmd: String,
|
pub cmd: String,
|
||||||
@@ -345,8 +335,8 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>>
|
|||||||
"Sync Prompts",
|
"Sync Prompts",
|
||||||
"ChatGPT Prompts data has been synchronized!",
|
"ChatGPT Prompts data has been synchronized!",
|
||||||
);
|
);
|
||||||
window_reload(app.clone(), "core");
|
window::window_reload(app.clone(), "core");
|
||||||
window_reload(app, "tray");
|
window::window_reload(app, "tray");
|
||||||
|
|
||||||
return Some(data2);
|
return Some(data2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::{cmd, window},
|
app::window,
|
||||||
conf::{self, ChatConfJson},
|
conf::{self, ChatConfJson},
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
@@ -250,8 +250,8 @@ pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
|||||||
.set_selected(popup_search)
|
.set_selected(popup_search)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None).unwrap();
|
ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None).unwrap();
|
||||||
cmd::window_reload(app.clone(), "core");
|
window::window_reload(app.clone(), "core");
|
||||||
cmd::window_reload(app, "tray");
|
window::window_reload(app, "tray");
|
||||||
}
|
}
|
||||||
"sync_prompts" => {
|
"sync_prompts" => {
|
||||||
tauri::api::dialog::ask(
|
tauri::api::dialog::ask(
|
||||||
|
|||||||
@@ -50,7 +50,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
} else {
|
} else {
|
||||||
let app = app.handle();
|
let app = app.handle();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let mut main_win = WindowBuilder::new(&app, "core", WindowUrl::App(url.clone().into()))
|
let link = if chat_conf.dashboard {
|
||||||
|
"index.html"
|
||||||
|
} else {
|
||||||
|
&url
|
||||||
|
};
|
||||||
|
let mut main_win = WindowBuilder::new(&app, "core", WindowUrl::App(link.into()))
|
||||||
.title("ChatGPT")
|
.title("ChatGPT")
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.fullscreen(false)
|
.fullscreen(false)
|
||||||
@@ -60,7 +65,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
|
|||||||
main_win = main_win.hidden_title(true);
|
main_win = main_win.hidden_title(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if url == "https://chat.openai.com" {
|
if url == "https://chat.openai.com" && !chat_conf.dashboard {
|
||||||
main_win = main_win
|
main_win = main_win
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
|
|||||||
@@ -97,14 +97,18 @@ pub fn control_window(handle: &tauri::AppHandle) {
|
|||||||
let app = handle.clone();
|
let app = handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
if app.app_handle().get_window("main").is_none() {
|
if app.app_handle().get_window("main").is_none() {
|
||||||
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into()))
|
WindowBuilder::new(
|
||||||
.title("Control Center")
|
&app,
|
||||||
.resizable(true)
|
"main",
|
||||||
.fullscreen(false)
|
WindowUrl::App("index.html?type=control".into()),
|
||||||
.inner_size(1000.0, 700.0)
|
)
|
||||||
.min_inner_size(800.0, 600.0)
|
.title("Control Center")
|
||||||
.build()
|
.resizable(true)
|
||||||
.unwrap();
|
.fullscreen(false)
|
||||||
|
.inner_size(1000.0, 700.0)
|
||||||
|
.min_inner_size(800.0, 600.0)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let main_win = app.app_handle().get_window("main").unwrap();
|
let main_win = app.app_handle().get_window("main").unwrap();
|
||||||
main_win.show().unwrap();
|
main_win.show().unwrap();
|
||||||
@@ -112,3 +116,40 @@ pub fn control_window(handle: &tauri::AppHandle) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn wa_window(
|
||||||
|
app: tauri::AppHandle,
|
||||||
|
label: String,
|
||||||
|
title: String,
|
||||||
|
url: String,
|
||||||
|
script: Option<String>,
|
||||||
|
) {
|
||||||
|
info!("wa_window: {} :=> {}", title, url);
|
||||||
|
let win = app.get_window(&label);
|
||||||
|
if win.is_none() {
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
tauri::WindowBuilder::new(&app, label, tauri::WindowUrl::App(url.parse().unwrap()))
|
||||||
|
.initialization_script(&script.unwrap_or_default())
|
||||||
|
.initialization_script(include_str!("../scripts/core.js"))
|
||||||
|
.title(title)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if !win.clone().unwrap().is_visible().unwrap() {
|
||||||
|
win.clone().unwrap().show().unwrap();
|
||||||
|
}
|
||||||
|
win.unwrap().set_focus().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn window_reload(app: tauri::AppHandle, label: &str) {
|
||||||
|
app
|
||||||
|
.app_handle()
|
||||||
|
.get_window(label)
|
||||||
|
.unwrap()
|
||||||
|
.eval("window.location.reload()")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub const BUY_COFFEE: &str = "https://www.buymeacoffee.com/lencx";
|
|||||||
pub const GITHUB_PROMPTS_CSV_URL: &str =
|
pub const GITHUB_PROMPTS_CSV_URL: &str =
|
||||||
"https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
"https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
||||||
pub const DEFAULT_CHAT_CONF: &str = r#"{
|
pub const DEFAULT_CHAT_CONF: &str = r#"{
|
||||||
|
"dashboard": false,
|
||||||
"stay_on_top": false,
|
"stay_on_top": false,
|
||||||
"auto_update": "Prompt",
|
"auto_update": "Prompt",
|
||||||
"theme": "Light",
|
"theme": "Light",
|
||||||
@@ -33,6 +34,7 @@ pub const DEFAULT_CHAT_CONF: &str = r#"{
|
|||||||
"ua_tray": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
|
"ua_tray": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
|
||||||
}"#;
|
}"#;
|
||||||
pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
|
pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
|
||||||
|
"dashboard": false,
|
||||||
"stay_on_top": false,
|
"stay_on_top": false,
|
||||||
"auto_update": "Prompt",
|
"auto_update": "Prompt",
|
||||||
"theme": "Light",
|
"theme": "Light",
|
||||||
@@ -58,6 +60,7 @@ pub struct ChatConfJson {
|
|||||||
pub theme: String,
|
pub theme: String,
|
||||||
// auto update policy, Prompt/Silent/Disable
|
// auto update policy, Prompt/Silent/Disable
|
||||||
pub auto_update: String,
|
pub auto_update: String,
|
||||||
|
pub dashboard: bool,
|
||||||
pub tray: bool,
|
pub tray: bool,
|
||||||
pub popup_search: bool,
|
pub popup_search: bool,
|
||||||
pub stay_on_top: bool,
|
pub stay_on_top: bool,
|
||||||
@@ -159,15 +162,6 @@ impl ChatConfJson {
|
|||||||
|
|
||||||
if let Some(handle) = app {
|
if let Some(handle) = app {
|
||||||
tauri::api::process::restart(&handle.env());
|
tauri::api::process::restart(&handle.env());
|
||||||
// tauri::api::dialog::ask(
|
|
||||||
// handle.get_window("core").as_ref(),
|
|
||||||
// "ChatGPT Restart",
|
|
||||||
// "Whether to restart immediately?",
|
|
||||||
// move |is_restart| {
|
|
||||||
// if is_restart {
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ mod app;
|
|||||||
mod conf;
|
mod conf;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use app::{cmd, fs_extra, menu, setup};
|
use app::{cmd, fs_extra, menu, setup, window};
|
||||||
use conf::ChatConfJson;
|
use conf::ChatConfJson;
|
||||||
use tauri::api::path;
|
use tauri::api::path;
|
||||||
use tauri_plugin_autostart::MacosLauncher;
|
use tauri_plugin_autostart::MacosLauncher;
|
||||||
@@ -73,13 +73,14 @@ async fn main() {
|
|||||||
cmd::parse_prompt,
|
cmd::parse_prompt,
|
||||||
cmd::sync_prompts,
|
cmd::sync_prompts,
|
||||||
cmd::sync_user_prompts,
|
cmd::sync_user_prompts,
|
||||||
cmd::window_reload,
|
|
||||||
cmd::dalle2_window,
|
cmd::dalle2_window,
|
||||||
cmd::cmd_list,
|
cmd::cmd_list,
|
||||||
cmd::download_list,
|
cmd::download_list,
|
||||||
cmd::get_download_list,
|
cmd::get_download_list,
|
||||||
cmd::get_data,
|
cmd::get_data,
|
||||||
fs_extra::metadata,
|
fs_extra::metadata,
|
||||||
|
window::window_reload,
|
||||||
|
window::wa_window,
|
||||||
])
|
])
|
||||||
.setup(setup::init)
|
.setup(setup::init)
|
||||||
.menu(menu::init());
|
.menu(menu::init());
|
||||||
|
|||||||
125
src/layout/index.tsx
vendored
125
src/layout/index.tsx
vendored
@@ -13,13 +13,18 @@ const { Content, Footer, Sider } = Layout;
|
|||||||
|
|
||||||
export default function ChatLayout() {
|
export default function ChatLayout() {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
const [isDashboard, setDashboard] = useState<any>(null);
|
||||||
const [appInfo, setAppInfo] = useState<Record<string, any>>({});
|
const [appInfo, setAppInfo] = useState<Record<string, any>>({});
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [menuKey, setMenuKey] = useState(location.pathname);
|
const [menuKey, setMenuKey] = useState(location.pathname);
|
||||||
const go = useNavigate();
|
const go = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (location.search === '?type=control') {
|
||||||
|
go('/awesome');
|
||||||
|
}
|
||||||
setMenuKey(location.pathname);
|
setMenuKey(location.pathname);
|
||||||
|
setDashboard(location.pathname === '/');
|
||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
useInit(async () => {
|
useInit(async () => {
|
||||||
@@ -36,69 +41,75 @@ export default function ChatLayout() {
|
|||||||
|
|
||||||
const isDark = appInfo.appTheme === 'dark';
|
const isDark = appInfo.appTheme === 'dark';
|
||||||
|
|
||||||
|
if (isDashboard === null) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigProvider theme={{ algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm }}>
|
<ConfigProvider theme={{ algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm }}>
|
||||||
<Layout style={{ minHeight: '100vh' }} hasSider>
|
{isDashboard ? (
|
||||||
<Sider
|
<Routes />
|
||||||
theme={isDark ? 'dark' : 'light'}
|
) : (
|
||||||
collapsible
|
<Layout style={{ minHeight: '100vh' }} hasSider>
|
||||||
collapsed={collapsed}
|
<Sider
|
||||||
onCollapse={(value) => setCollapsed(value)}
|
theme={isDark ? 'dark' : 'light'}
|
||||||
style={{
|
collapsible
|
||||||
overflow: 'auto',
|
collapsed={collapsed}
|
||||||
height: '100vh',
|
onCollapse={(value) => setCollapsed(value)}
|
||||||
position: 'fixed',
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
zIndex: 999,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="chat-logo">
|
|
||||||
<img src="/logo.png" />
|
|
||||||
</div>
|
|
||||||
<div className="chat-info">
|
|
||||||
<Tag>{appInfo.appName}</Tag>
|
|
||||||
<Tag>
|
|
||||||
<span style={{ marginRight: 5 }}>{appInfo.appVersion}</span>
|
|
||||||
<Tooltip title="click to check update">
|
|
||||||
<a onClick={checkAppUpdate}>
|
|
||||||
<SyncOutlined />
|
|
||||||
</a>
|
|
||||||
</Tooltip>
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Menu
|
|
||||||
selectedKeys={[menuKey]}
|
|
||||||
mode="inline"
|
|
||||||
theme={appInfo.appTheme === 'dark' ? 'dark' : 'light'}
|
|
||||||
inlineIndent={12}
|
|
||||||
items={menuItems}
|
|
||||||
// defaultOpenKeys={['/model']}
|
|
||||||
onClick={(i) => go(i.key)}
|
|
||||||
/>
|
|
||||||
</Sider>
|
|
||||||
<Layout
|
|
||||||
className="chat-layout"
|
|
||||||
style={{ marginLeft: collapsed ? 80 : 200, transition: 'margin-left 300ms ease-out' }}
|
|
||||||
>
|
|
||||||
<Content
|
|
||||||
className="chat-container"
|
|
||||||
style={{
|
style={{
|
||||||
overflow: 'inherit',
|
overflow: 'auto',
|
||||||
|
height: '100vh',
|
||||||
|
position: 'fixed',
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
zIndex: 999,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Routes />
|
<div className="chat-logo">
|
||||||
</Content>
|
<img src="/logo.png" />
|
||||||
<Footer style={{ textAlign: 'center' }}>
|
</div>
|
||||||
<a href="https://github.com/lencx/chatgpt" target="_blank">
|
<div className="chat-info">
|
||||||
ChatGPT Desktop Application
|
<Tag>{appInfo.appName}</Tag>
|
||||||
</a>{' '}
|
<Tag>
|
||||||
©2022 Created by lencx
|
<span style={{ marginRight: 5 }}>{appInfo.appVersion}</span>
|
||||||
</Footer>
|
<Tooltip title="click to check update">
|
||||||
|
<a onClick={checkAppUpdate}>
|
||||||
|
<SyncOutlined />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
selectedKeys={[menuKey]}
|
||||||
|
mode="inline"
|
||||||
|
theme={appInfo.appTheme === 'dark' ? 'dark' : 'light'}
|
||||||
|
inlineIndent={12}
|
||||||
|
items={menuItems}
|
||||||
|
// defaultOpenKeys={['/model']}
|
||||||
|
onClick={(i) => go(i.key)}
|
||||||
|
/>
|
||||||
|
</Sider>
|
||||||
|
<Layout
|
||||||
|
className="chat-layout"
|
||||||
|
style={{ marginLeft: collapsed ? 80 : 200, transition: 'margin-left 300ms ease-out' }}
|
||||||
|
>
|
||||||
|
<Content
|
||||||
|
className="chat-container"
|
||||||
|
style={{
|
||||||
|
overflow: 'inherit',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Routes />
|
||||||
|
</Content>
|
||||||
|
<Footer style={{ textAlign: 'center' }}>
|
||||||
|
<a href="https://github.com/lencx/chatgpt" target="_blank">
|
||||||
|
ChatGPT Desktop Application
|
||||||
|
</a>{' '}
|
||||||
|
©2022 Created by lencx
|
||||||
|
</Footer>
|
||||||
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
)}
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/main.scss
vendored
4
src/main.scss
vendored
@@ -15,9 +15,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body,
|
||||||
|
#root {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-selection-col,
|
.ant-table-selection-col,
|
||||||
|
|||||||
8
src/routes.tsx
vendored
8
src/routes.tsx
vendored
@@ -22,6 +22,7 @@ import SyncRecord from '@/view/model/SyncRecord';
|
|||||||
import Download from '@/view/download';
|
import Download from '@/view/download';
|
||||||
import Notes from '@/view/notes';
|
import Notes from '@/view/notes';
|
||||||
import Markdown from '@/view/markdown';
|
import Markdown from '@/view/markdown';
|
||||||
|
import Dashboard from '@/view/dashboard';
|
||||||
|
|
||||||
export type ChatRouteMetaObject = {
|
export type ChatRouteMetaObject = {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -38,7 +39,7 @@ type ChatRouteObject = {
|
|||||||
|
|
||||||
export const routes: Array<ChatRouteObject> = [
|
export const routes: Array<ChatRouteObject> = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/awesome',
|
||||||
element: <Awesome />,
|
element: <Awesome />,
|
||||||
meta: {
|
meta: {
|
||||||
label: 'Awesome',
|
label: 'Awesome',
|
||||||
@@ -121,6 +122,11 @@ export const routes: Array<ChatRouteObject> = [
|
|||||||
icon: <InfoCircleOutlined />,
|
icon: <InfoCircleOutlined />,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
element: <Dashboard />,
|
||||||
|
hideMenu: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
type MenuItem = Required<MenuProps>['items'][number];
|
type MenuItem = Required<MenuProps>['items'][number];
|
||||||
|
|||||||
43
src/view/dashboard/index.scss
vendored
Normal file
43
src/view/dashboard/index.scss
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
.dashboard {
|
||||||
|
position: fixed;
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
height: calc(100% - 30px);
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.has-top-dom {
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/view/dashboard/index.tsx
vendored
Normal file
78
src/view/dashboard/index.tsx
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { Row, Col, Card } from 'antd';
|
||||||
|
import { os, invoke } from '@tauri-apps/api';
|
||||||
|
|
||||||
|
import useInit from '@/hooks/useInit';
|
||||||
|
import useJson from '@/hooks/useJson';
|
||||||
|
import { CHAT_AWESOME_JSON, CHAT_CONF_JSON, readJSON } from '@/utils';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
export default function Dashboard() {
|
||||||
|
const { json } = useJson<Record<string, any>[]>(CHAT_AWESOME_JSON);
|
||||||
|
const [list, setList] = useState<Array<[string, Record<string, any>[]]>>([]);
|
||||||
|
const [hasClass, setClass] = useState(false);
|
||||||
|
const [theme, setTheme] = useState('');
|
||||||
|
|
||||||
|
useInit(async () => {
|
||||||
|
const getOS = await os.platform();
|
||||||
|
const conf = await readJSON(CHAT_CONF_JSON);
|
||||||
|
const appTheme = await invoke('get_theme');
|
||||||
|
setTheme(appTheme as string);
|
||||||
|
setClass(!conf?.titlebar && getOS === 'darwin');
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const categories = new Map();
|
||||||
|
|
||||||
|
json?.forEach((i) => {
|
||||||
|
if (!i.enable) return;
|
||||||
|
if (!categories.has(i.category)) {
|
||||||
|
categories.set(i.category, []);
|
||||||
|
}
|
||||||
|
categories.get(i?.category).push(i);
|
||||||
|
});
|
||||||
|
setList(Array.from(categories));
|
||||||
|
}, [json?.length]);
|
||||||
|
|
||||||
|
const handleLink = async (item: Record<string, any>) => {
|
||||||
|
await invoke('wa_window', {
|
||||||
|
label: btoa(item.url).replace(/[^a-zA-Z0-9]/g, ''),
|
||||||
|
title: item.title,
|
||||||
|
url: item.url,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx('dashboard', theme, { 'has-top-dom': hasClass })}>
|
||||||
|
<div>
|
||||||
|
{list.map((i) => {
|
||||||
|
return (
|
||||||
|
<div key={i[0]} className="group-item">
|
||||||
|
<Card title={i[0]} size="small">
|
||||||
|
<Row className="list" gutter={[8, 8]}>
|
||||||
|
{i[1].map((j, idx) => {
|
||||||
|
return (
|
||||||
|
<Col
|
||||||
|
title={`${j?.title}: ${j?.url}`}
|
||||||
|
key={`${idx}_${j?.url}`}
|
||||||
|
xl={4}
|
||||||
|
md={6}
|
||||||
|
sm={8}
|
||||||
|
xs={12}
|
||||||
|
>
|
||||||
|
<Card className="item" hoverable onClick={() => handleLink(j)}>
|
||||||
|
<span>{j?.title}</span>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
src/view/settings/General.tsx
vendored
3
src/view/settings/General.tsx
vendored
@@ -60,6 +60,9 @@ export default function General() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Form.Item label="Dashboard" name="dashboard" valuePropName="checked">
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
<Form.Item label="Stay On Top" name="stay_on_top" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
Reference in New Issue
Block a user