Skip to content

Commit 2b314d7

Browse files
committed
feat: add header and change url
1 parent 953ebf3 commit 2b314d7

File tree

8 files changed

+170
-61
lines changed

8 files changed

+170
-61
lines changed

release/app/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/webviewManager.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { BrowserView, BrowserWindow, ipcMain, Rectangle } from 'electron';
22

33
interface WebviewInfo {
44
view: BrowserView;
5+
url: string;
56
hidden: boolean;
67
}
78

@@ -21,6 +22,11 @@ function fixRect(rect: Rectangle): Rectangle {
2122

2223
export function initWebviewManager(win: BrowserWindow) {
2324
ipcMain.on('mount-webview', (e, info) => {
25+
if (!win) {
26+
console.log('[mount-webview]', 'cannot get mainWindow');
27+
return;
28+
}
29+
2430
console.log('[mount-webview] info:', info);
2531

2632
const key = info.key;
@@ -33,6 +39,10 @@ export function initWebviewManager(win: BrowserWindow) {
3339
const webview = webviewMap.get(key)!;
3440
win.setTopBrowserView(webview.view);
3541
webview.view.setBounds(fixRect(info.rect));
42+
if (webview.url !== url) {
43+
// url has been change.
44+
webview.view.webContents.loadURL(url);
45+
}
3646
return;
3747
}
3848

@@ -44,7 +54,7 @@ export function initWebviewManager(win: BrowserWindow) {
4454
win.addBrowserView(view);
4555
view.setBounds(fixRect(info.rect));
4656
view.webContents.loadURL(url);
47-
webviewMap.set(key, { view, hidden: false });
57+
webviewMap.set(key, { view, url, hidden: false });
4858
});
4959

5060
ipcMain.on('update-webview-rect', (e, info) => {
@@ -64,6 +74,11 @@ export function initWebviewManager(win: BrowserWindow) {
6474
});
6575

6676
ipcMain.on('clear-all-webview', (e) => {
77+
if (!win) {
78+
console.log('[clear-all-webview]', 'cannot get mainWindow');
79+
return;
80+
}
81+
6782
console.log('[clear-all-webview]');
6883

6984
win.getBrowserViews().forEach((view) => {

src/renderer/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
22
import { Allotment } from 'allotment';
33
import { SideTree } from './components/SideTree';
4-
import { WebContent } from './components/WebContent';
4+
import { WebContent } from './components/main/WebContent';
55

66
function Main() {
77
return (
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Input } from '@arco-design/web-react';
2+
import React from 'react';
3+
import styled from 'styled-components';
4+
import { useTreeStore } from '../../store/tree';
5+
import { useEditValue } from '../../utils/hooks/useEditValue';
6+
import { WebPlaceholder } from './WebPlaceholder';
7+
import { WebviewRender } from './WebviewRender';
8+
9+
const Root = styled.div`
10+
display: flex;
11+
flex-direction: column;
12+
width: 100%;
13+
height: 100%;
14+
15+
> .title {
16+
display: flex;
17+
flex-direction: row;
18+
}
19+
20+
> .main {
21+
flex: 1;
22+
}
23+
`;
24+
25+
export const WebContent: React.FC = React.memo(() => {
26+
const selectedNode = useTreeStore((state) => state.selectedNode);
27+
const [title, setTitle, onTitleBlur] = useEditValue<string>(
28+
selectedNode?.title ?? '',
29+
(val) => useTreeStore.getState().patchSelectedNode('title', val ?? '')
30+
);
31+
const [url, setUrl, onUrlBlur] = useEditValue(
32+
selectedNode?.url ?? '',
33+
(val) => useTreeStore.getState().patchSelectedNode('url', val ?? '')
34+
);
35+
36+
if (!selectedNode) {
37+
return <WebPlaceholder />;
38+
}
39+
40+
return (
41+
<Root>
42+
<div className="title">
43+
<Input
44+
placeholder="Title"
45+
value={title}
46+
onChange={setTitle}
47+
onBlur={onTitleBlur}
48+
onPressEnter={onTitleBlur}
49+
/>
50+
<Input
51+
placeholder="Url"
52+
value={url}
53+
onChange={setUrl}
54+
onBlur={onUrlBlur}
55+
onPressEnter={onUrlBlur}
56+
/>
57+
</div>
58+
<div className="main">
59+
<WebviewRender node={selectedNode} />
60+
</div>
61+
</Root>
62+
);
63+
});
64+
WebContent.displayName = 'WebContent';
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import { useEffect } from 'react';
3+
import styled from 'styled-components';
4+
import webpageSvg from '../../assets/web-page.svg';
5+
import { AddWebsiteBtn } from '../AddWebsiteBtn';
6+
7+
const WebPlaceholderRoot = styled.div`
8+
height: 100%;
9+
width: 100%;
10+
display: flex;
11+
justify-content: center;
12+
align-items: center;
13+
font-size: 24px;
14+
flex-direction: column;
15+
16+
img {
17+
width: 120px;
18+
}
19+
`;
20+
21+
export const WebPlaceholder: React.FC = React.memo(() => {
22+
useEffect(() => {
23+
window.electron.ipcRenderer.sendMessage('hide-all-webview');
24+
}, []);
25+
26+
return (
27+
<WebPlaceholderRoot>
28+
<div>
29+
<img src={webpageSvg} />
30+
</div>
31+
<div>Please Select Any Page on Left</div>
32+
<div>
33+
<small>OR</small>
34+
</div>
35+
<div>
36+
<AddWebsiteBtn />
37+
</div>
38+
</WebPlaceholderRoot>
39+
);
40+
});
41+
WebPlaceholder.displayName = 'WebPlaceholder';
Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import React, { useEffect, useRef } from 'react';
2-
import styled from 'styled-components';
3-
import { useTreeStore, WebsiteTreeNode } from '../store/tree';
4-
import webpageSvg from '../assets/web-page.svg';
5-
import { AddWebsiteBtn } from './AddWebsiteBtn';
2+
import { WebsiteTreeNode } from '../../store/tree';
63

7-
const WebviewRender: React.FC<{ node: WebsiteTreeNode }> = React.memo(
4+
export const WebviewRender: React.FC<{ node: WebsiteTreeNode }> = React.memo(
85
(props) => {
96
const containerRef = useRef<HTMLDivElement>(null);
107
const node = props.node;
@@ -26,7 +23,7 @@ const WebviewRender: React.FC<{ node: WebsiteTreeNode }> = React.memo(
2623
height: rect.height,
2724
},
2825
});
29-
}, [node.key]);
26+
}, [node.key, node.url]);
3027

3128
useEffect(() => {
3229
if (!containerRef.current) {
@@ -66,50 +63,3 @@ const WebviewRender: React.FC<{ node: WebsiteTreeNode }> = React.memo(
6663
}
6764
);
6865
WebviewRender.displayName = 'WebviewRender';
69-
70-
const WebPlaceholderRoot = styled.div`
71-
height: 100%;
72-
width: 100%;
73-
display: flex;
74-
justify-content: center;
75-
align-items: center;
76-
font-size: 24px;
77-
flex-direction: column;
78-
79-
img {
80-
width: 120px;
81-
}
82-
`;
83-
84-
const WebPlaceholder: React.FC = React.memo(() => {
85-
useEffect(() => {
86-
window.electron.ipcRenderer.sendMessage('hide-all-webview');
87-
}, []);
88-
89-
return (
90-
<WebPlaceholderRoot>
91-
<div>
92-
<img src={webpageSvg} />
93-
</div>
94-
<div>Please Select Any Page on Left</div>
95-
<div>
96-
<small>OR</small>
97-
</div>
98-
<div>
99-
<AddWebsiteBtn />
100-
</div>
101-
</WebPlaceholderRoot>
102-
);
103-
});
104-
WebPlaceholder.displayName = 'WebPlaceholder';
105-
106-
export const WebContent: React.FC = React.memo(() => {
107-
const selectedNode = useTreeStore((state) => state.selectedNode);
108-
109-
if (!selectedNode) {
110-
return <WebPlaceholder />;
111-
}
112-
113-
return <WebviewRender node={selectedNode} />;
114-
});
115-
WebContent.displayName = 'WebContent';

src/renderer/store/tree.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { create } from 'zustand';
66
import { persist } from 'zustand/middleware';
77
import { immer } from 'zustand/middleware/immer';
88

9-
export type WebsiteTreeNode = Pick<TreeDataType, 'title'> & {
9+
export type WebsiteTreeNode = {
10+
title: string;
1011
key: string;
1112
children?: WebsiteTreeNode[];
1213
url: string;
@@ -26,6 +27,10 @@ interface TreeStoreState {
2627
dropPosition: number
2728
) => void;
2829
deleteTreeNode: (key: string) => void;
30+
patchSelectedNode: <T extends Exclude<keyof WebsiteTreeNode, 'key'>>(
31+
key: T,
32+
value: WebsiteTreeNode[T]
33+
) => void;
2934
}
3035

3136
const defaultTreeData = [
@@ -55,7 +60,6 @@ export const useTreeStore = create<TreeStoreState>()(
5560
selectedNode,
5661
});
5762
},
58-
5963
setTreeData: (treeData: WebsiteTreeNode[]) => {
6064
set({
6165
treeData,
@@ -146,6 +150,26 @@ export const useTreeStore = create<TreeStoreState>()(
146150
deleteTreeNode(state.treeData, key);
147151
});
148152
},
153+
patchSelectedNode: (key, value) => {
154+
set((state) => {
155+
if (!state.selectedNode) {
156+
return;
157+
}
158+
159+
// Check is changed
160+
if (state.selectedNode[key] === value) {
161+
return;
162+
}
163+
164+
const node = findTreeNode(state.treeData, state.selectedNode.key);
165+
if (!node) {
166+
return;
167+
}
168+
169+
state.selectedNode[key] = value;
170+
node[key] = value;
171+
});
172+
},
149173
})),
150174
{
151175
name: 'webbox-tree',
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
2+
3+
export function useEditValue<T>(value: T, onChange: (val: T) => void) {
4+
const [inner, setInner] = useState(value);
5+
6+
useLayoutEffect(() => {
7+
setInner(value);
8+
}, [value]);
9+
10+
const onSave = useCallback(() => {
11+
onChange(inner);
12+
}, [inner, onChange]);
13+
14+
return [inner, setInner, onSave] as const;
15+
}

0 commit comments

Comments
 (0)