Skip to content

Commit 476e4a7

Browse files
committed
feat: clear website and delete tree node
1 parent b5f4d35 commit 476e4a7

File tree

5 files changed

+128
-16
lines changed

5 files changed

+128
-16
lines changed

src/main/preload.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
/* eslint no-unused-vars: off */
33
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
44

5-
export type Channels = 'mount-webview' | 'update-webview-rect';
5+
export type Channels =
6+
| 'mount-webview'
7+
| 'update-webview-rect'
8+
| 'clear-webview';
69

710
const electronHandler = {
811
ipcRenderer: {

src/main/webviewManager.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ const webviewMap = new Map<string, BrowserView>();
77
*/
88
function fixRect(rect: Rectangle): Rectangle {
99
return {
10-
x: Math.round(rect.x),
10+
x: Math.round(rect.x) + 1,
1111
y: Math.round(rect.y) + 28,
12-
width: Math.round(rect.width),
12+
width: Math.round(rect.width) - 1,
1313
height: Math.round(rect.height),
1414
};
1515
}
@@ -47,4 +47,14 @@ export function initWebviewManager(win: BrowserWindow) {
4747
view.setBounds(fixRect(info.rect));
4848
});
4949
});
50+
51+
ipcMain.on('clear-webview', (e) => {
52+
console.log('[clear-webview]');
53+
54+
win.getBrowserViews().forEach((view) => {
55+
win.removeBrowserView(view);
56+
});
57+
58+
webviewMap.clear();
59+
});
5060
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Button } from '@arco-design/web-react';
2+
import React from 'react';
3+
import { useTreeStore } from '../store/tree';
4+
5+
export const ClearWebsiteBtn: React.FC = React.memo(() => {
6+
const { setSelectedNode } = useTreeStore();
7+
8+
return (
9+
<>
10+
<Button
11+
long={true}
12+
onClick={() => {
13+
setSelectedNode(null);
14+
window.electron.ipcRenderer.sendMessage('clear-webview');
15+
}}
16+
>
17+
Clear Website
18+
</Button>
19+
</>
20+
);
21+
});
22+
ClearWebsiteBtn.displayName = 'ClearWebsiteBtn';

src/renderer/components/SideTree.tsx

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,84 @@
1-
import { Tree } from '@arco-design/web-react';
1+
import { Menu, Tooltip, Tree, Trigger } from '@arco-design/web-react';
22
import { IconDown, IconPlus } from '@arco-design/web-react/icon';
33
import React from 'react';
44
import { generateFakeNode, WebsiteTreeNode, useTreeStore } from '../store/tree';
55
import { AddWebsiteBtn } from './AddWebsiteBtn';
66
import styled from 'styled-components';
7+
import { ClearWebsiteBtn } from './ClearWebsiteBtn';
78

89
const StyledTree = styled(Tree)`
10+
margin-top: 0.5rem;
11+
912
.arco-tree-node-title:hover .arco-tree-node-drag-icon {
1013
opacity: 0;
1114
}
15+
16+
.arco-tree-node-title {
17+
padding: 0;
18+
padding-right: 4px;
19+
20+
& .arco-tree-node-title-text > div {
21+
padding: 5px 0 5px 4px;
22+
}
23+
}
1224
` as unknown as typeof Tree;
1325

26+
const StyledMenu = styled(Menu)`
27+
box-shadow: 0 0 5px rgb(0, 0, 0, 0.25);
28+
29+
.arco-menu-item {
30+
line-height: 32px;
31+
}
32+
` as unknown as typeof Menu;
33+
1434
export const SideTree: React.FC = React.memo(() => {
15-
const { treeData, moveTreeNode, setSelectedNode, addTreeNodeChildren } =
16-
useTreeStore();
35+
const {
36+
treeData,
37+
selectedNode,
38+
moveTreeNode,
39+
setSelectedNode,
40+
addTreeNodeChildren,
41+
deleteTreeNode,
42+
} = useTreeStore();
1743

1844
return (
1945
<div>
2046
<AddWebsiteBtn />
47+
<ClearWebsiteBtn />
2148

2249
<StyledTree
2350
draggable={true}
2451
blockNode={true}
52+
selectedKeys={selectedNode ? [selectedNode.key] : []}
2553
treeData={treeData}
2654
icons={{
2755
switcherIcon: <IconDown />,
2856
}}
57+
renderTitle={(props) => (
58+
<Trigger
59+
position="br"
60+
popupAlign={{
61+
right: [20, 20],
62+
}}
63+
popup={() => (
64+
<StyledMenu>
65+
<Menu.Item
66+
key="del"
67+
onClick={() => {
68+
if (props.dataRef && props.dataRef.key) {
69+
deleteTreeNode(props.dataRef.key);
70+
}
71+
}}
72+
>
73+
Delete
74+
</Menu.Item>
75+
</StyledMenu>
76+
)}
77+
trigger={'contextMenu'}
78+
>
79+
<div>{props.title}</div>
80+
</Trigger>
81+
)}
2982
onSelect={(_, extra) => {
3083
const nodeData = extra.node.props.dataRef;
3184
if (nodeData) {

src/renderer/store/tree.ts

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export type WebsiteTreeNode = Pick<TreeDataType, 'title'> & {
1616
interface TreeStoreState {
1717
treeData: WebsiteTreeNode[];
1818
selectedNode: WebsiteTreeNode | null;
19-
setSelectedNode: (selectedNode: WebsiteTreeNode) => void;
19+
setSelectedNode: (selectedNode: WebsiteTreeNode | null) => void;
2020
setTreeData: (treeData: WebsiteTreeNode[]) => void;
2121
addTreeNode: (treeNode: WebsiteTreeNode) => void;
2222
addTreeNodeChildren: (parentKey: string, treeNode: WebsiteTreeNode) => void;
@@ -25,6 +25,7 @@ interface TreeStoreState {
2525
dropNode: NodeInstance | null,
2626
dropPosition: number
2727
) => void;
28+
deleteTreeNode: (key: string) => void;
2829
}
2930

3031
const defaultTreeData = [
@@ -49,7 +50,7 @@ export const useTreeStore = create<TreeStoreState>()(
4950
immer((set) => ({
5051
treeData: defaultTreeData,
5152
selectedNode: null,
52-
setSelectedNode: (selectedNode: WebsiteTreeNode) => {
53+
setSelectedNode: (selectedNode: WebsiteTreeNode | null) => {
5354
set({
5455
selectedNode,
5556
});
@@ -136,6 +137,11 @@ export const useTreeStore = create<TreeStoreState>()(
136137
state.treeData = [...data];
137138
});
138139
},
140+
deleteTreeNode: (key: string) => {
141+
set((state) => {
142+
deleteTreeNode(state.treeData, key);
143+
});
144+
},
139145
})),
140146
{
141147
name: 'webbox-tree',
@@ -148,15 +154,11 @@ function findTreeNode(
148154
treeData: WebsiteTreeNode[],
149155
key: string
150156
): WebsiteTreeNode | null {
151-
const targetNode = treeData.find((node) => {
152-
return node.key === key;
153-
});
154-
155-
if (targetNode) {
156-
return targetNode;
157-
}
158-
159157
for (const node of treeData) {
158+
if (node.key === key) {
159+
return node;
160+
}
161+
160162
if (node.children && node.children.length > 0) {
161163
const res = findTreeNode(node.children, key);
162164
if (res) {
@@ -168,6 +170,28 @@ function findTreeNode(
168170
return null;
169171
}
170172

173+
/**
174+
* in-place algorithm
175+
*/
176+
function deleteTreeNode(treeData: WebsiteTreeNode[], key: string): boolean {
177+
for (let i = 0; i < treeData.length; i++) {
178+
const node = treeData[i];
179+
if (node.key === key) {
180+
treeData.splice(i, 1);
181+
return true;
182+
}
183+
184+
if (node.children && node.children.length > 0) {
185+
const fixed = deleteTreeNode(node.children, key);
186+
if (fixed) {
187+
return true;
188+
}
189+
}
190+
}
191+
192+
return false;
193+
}
194+
171195
export function generateFakeNode(): WebsiteTreeNode {
172196
const key = 'fooo' + Math.random();
173197
return {

0 commit comments

Comments
 (0)