Skip to content

Commit 8890f12

Browse files
authored
feat(Search): Implement side page with search feature. (#20)
1 parent 8a194ae commit 8890f12

20 files changed

+512
-91
lines changed

src/components/Button/index.module.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.button {
22
flex-shrink: 0;
3-
padding: 0.25em 1em;
3+
padding: 0.625em;
44
padding-bottom: 0.4em;
55
text-align: left;
66
border: none;

src/components/IconButton/index.module.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,17 @@
2727

2828
.search {
2929
-webkit-mask-position: -196px 96px;
30+
31+
&.active {
32+
background-color: var(--oc-blue-3);
33+
}
3034
}
3135

3236
.clear {
3337
-webkit-mask-position: 0px 144px;
3438
}
39+
40+
.delete {
41+
-webkit-mask-position: -84px 216px;
42+
}
3543
}

src/components/IconButton/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import styles from "./index.module.scss";
22

3-
type Icon = "filter" | "search" | "clear";
3+
type Icon = "filter" | "search" | "clear" | "delete";
44

55
export interface IconButtonProps
66
extends Omit<React.HTMLAttributes<HTMLButtonElement>, "children"> {

src/components/Tabs/index.module.scss

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,24 @@
22
display: grid;
33
height: 100%;
44
grid-template-rows: auto 1fr;
5+
56
.tab-bar {
67
display: flex;
8+
justify-content: space-between;
79
background-color: var(--oc-gray-2);
10+
border-bottom: 1px solid var(--pb-sep);
811

912
@media (prefers-color-scheme: dark) {
1013
background-color: var(--oc-gray-8);
1114
}
15+
16+
.tab-buttons {
17+
display: flex;
18+
}
1219
}
1320
}
1421

1522
.panel {
1623
height: 100%;
17-
padding-left: 12px;
1824
overflow-y: scroll;
1925
}

src/components/Tabs/index.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { memo, useMemo, useState } from "react";
22
import Button from "../Button";
3+
import IconButton from "../IconButton";
34
import styles from "./index.module.scss";
45

56
export interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -9,25 +10,31 @@ export interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {
910
Component: React.ComponentType<any>;
1011
};
1112
};
13+
handleCancelClick?(): void;
1214
}
1315

1416
const Tabs: React.FC<TabsProps> = (props) => {
15-
const { tabs, ...divProps } = props;
17+
const { tabs, handleCancelClick, ...divProps } = props;
1618
const tabTypes = useMemo(() => Object.keys(tabs), [tabs]);
1719
const [currentTabType = tabTypes[0], setCurrentTabType] = useState<string>();
1820
const Component = tabs[currentTabType]?.Component;
1921
return (
2022
<div {...divProps} className={`${styles.tabs} ${props.className ?? ""}`}>
2123
<div className={styles["tab-bar"]}>
22-
{tabTypes.map((tabType) => (
23-
<Button
24-
key={tabType}
25-
onClick={() => setCurrentTabType(tabType)}
26-
data-selected={currentTabType === tabType}
27-
>
28-
{tabs[tabType].label()}
29-
</Button>
30-
))}
24+
<div className={styles["tab-buttons"]}>
25+
{tabTypes.map((tabType) => (
26+
<Button
27+
key={tabType}
28+
onClick={() => setCurrentTabType(tabType)}
29+
data-selected={currentTabType === tabType}
30+
>
31+
{tabs[tabType].label()}
32+
</Button>
33+
))}
34+
</div>
35+
{handleCancelClick && (
36+
<IconButton onClick={handleCancelClick} icon="delete" />
37+
)}
3138
</div>
3239
<div className={styles["panel"]}>{Component && <Component />}</div>
3340
</div>

src/pages/_app.scss

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
--pb-bg: var(--oc-white);
66
--pb-fg: var(--oc-black);
77
--pb-sep: var(--oc-gray-6);
8+
--pb-bg-dark: var(--oc-white);
89
--pb-bg-hover: var(--oc-blue-2);
910
--pb-bg-active: var(--oc-blue-7);
1011
--pb-bg-focus: var(--oc-blue-5);
@@ -16,6 +17,7 @@
1617
--pb-bg: var(--oc-gray-8);
1718
--pb-fg: var(--oc-gray-5);
1819
--pb-sep: var(--oc-gray-7);
20+
--pb-bg-dark: rgba(var(--oc-gray-9-rgb), 0.5);
1921
--pb-bg-hover: var(--oc-blue-7);
2022
--pb-bg-active: var(--oc-gray-9);
2123
--pb-bg-focus: var(--oc-blue-4);
@@ -39,7 +41,16 @@ input {
3941
color: var(--oc-gray-5);
4042
background-color: var(--oc-gray-9);
4143
padding: 0.25em;
42-
width: 100%;
44+
margin: 3px 0px;
45+
46+
&:hover {
47+
box-shadow: 0 0 0 1px var(--pb-sep);
48+
}
49+
50+
&:focus {
51+
outline: none;
52+
box-shadow: 0 0 0 1px var(--oc-blue-7);
53+
}
4354
}
4455

4556
// For compatibility with the Chromium devTools environment.

src/pages/index.module.scss

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
1-
.page {
1+
.main-panel {
2+
display: flex;
3+
}
4+
5+
.side-page {
6+
display: flex;
7+
flex-direction: column;
8+
width: 200px;
9+
10+
background-color: var(--oc-gray-2);
11+
border-right: 1px solid var(--pb-sep);
12+
13+
@media (prefers-color-scheme: dark) {
14+
background-color: var(--oc-gray-8);
15+
}
16+
}
17+
18+
.request-page {
219
display: grid;
320
grid-template-columns: 15em 1fr;
421
grid-template-rows: 100vh;
522
}
623

7-
.sidebar {
24+
.main-page {
25+
flex: 1;
26+
}
27+
28+
.request-list {
829
display: flex;
930
flex-direction: column;
1031

@@ -15,3 +36,11 @@
1536
background-color: var(--oc-gray-8);
1637
}
1738
}
39+
40+
.settings {
41+
background-color: var(--oc-gray-2);
42+
43+
@media (prefers-color-scheme: dark) {
44+
background-color: var(--oc-gray-8);
45+
}
46+
}

src/pages/index.page.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,32 @@ import RequestList from "./index/RequestList";
1919
import { preserveLogAtom } from "./index/atoms/setting";
2020
import Settings from "./index/Settings";
2121
import Experimental from "./index/Experimental";
22+
import SidePage from "./index/SidePage";
23+
import { sidePageStatusAtom } from "./index/atoms/page";
2224

2325
const Page: NextPage = () => {
26+
const [isSidePageOpened] = useAtom(sidePageStatusAtom);
2427
useDevtoolsCommunicationLogic();
2528
return (
26-
<>
27-
<div className={style.page}>
28-
<div className={style.sidebar}>
29+
<div className={style["main-panel"]}>
30+
{isSidePageOpened === "visible" && (
31+
<div className={style["side-page"]}>
32+
<SidePage />
33+
</div>
34+
)}
35+
<div className={style["main-page"]}>
36+
<div className={style.settings}>
2937
<Settings />
3038
{process.env.NODE_ENV === "development" && <Experimental />}
31-
<RequestList />
3239
</div>
33-
<RequestDetail />
40+
<div className={style["request-page"]}>
41+
<div className={style["request-list"]}>
42+
<RequestList />
43+
</div>
44+
<RequestDetail />
45+
</div>
3446
</div>
35-
</>
47+
</div>
3648
);
3749
};
3850

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
.request-detail {
2-
display: flex;
3-
flex-direction: column;
4-
52
@media (prefers-color-scheme: dark) {
63
background-color: var(--oc-gray-9);
74
}
85
}
96

7+
.panel {
8+
display: flex;
9+
flex-direction: column;
10+
padding-left: 12px;
11+
}
12+
1013
.request-detail--paragraph {
1114
white-space: pre;
1215
}

src/pages/index/RequestDetail/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const RequestDetailRequest: React.FC = () => {
3636
const [requestPayloads] = useAtom(selectedRequest.requestPayloadsAtom);
3737
const { requestError } = selectedRequest;
3838
return (
39-
<>
39+
<div className={style["panel"]}>
4040
<h4>Metadata</h4>
4141
<JsonView src={JSON.parse(selectedRequest.metadataJson)} />
4242
{requestPayloads.length > 0 && (
@@ -55,7 +55,7 @@ const RequestDetailRequest: React.FC = () => {
5555
</p>
5656
</>
5757
)}
58-
</>
58+
</div>
5959
);
6060
};
6161

@@ -65,7 +65,7 @@ const RequestDetailResponse: React.FC = () => {
6565
const { headerJson, trailerJson, responseError } = selectedRequest;
6666
const [responsePayloads] = useAtom(selectedRequest.responsePayloadsAtom);
6767
return (
68-
<>
68+
<div className={style["panel"]}>
6969
{headerJson && (
7070
<>
7171
<h4>Header</h4>
@@ -94,6 +94,6 @@ const RequestDetailResponse: React.FC = () => {
9494
</p>
9595
</>
9696
)}
97-
</>
97+
</div>
9898
);
9999
};

src/pages/index/RequestList/index.module.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
display: flex;
1010
justify-content: space-between;
1111

12+
&:nth-child(2n):not(:hover, :active, [data-selected="true"]) {
13+
background-color: var(--pb-bg-dark);
14+
}
15+
1216
.list-main {
1317
.service-path {
1418
font-size: 0.7em;

src/pages/index/RequestList/index.tsx

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useMemo, memo } from "react";
2-
import { atom, useAtom } from "jotai";
3-
import { requestsAtom } from "../atoms/request";
4-
import { filterAtom, searchValueAtom } from "../atoms/setting";
2+
import { useAtom } from "jotai";
3+
import { requestListAtom } from "../atoms/request";
4+
import { filterAtom, filterSettingsAtom } from "../atoms/setting";
55
import { selectedRequestKeyAtom } from "../atoms/ui";
66
import Button from "../../../components/Button";
77
import style from "./index.module.scss";
@@ -13,13 +13,15 @@ const RequestList: React.FC<RequestListProps> = () => {
1313
selectedRequestKeyAtom
1414
);
1515
const [isFilterActive] = useAtom(filterAtom);
16-
const [searchValue] = useAtom(searchValueAtom);
16+
const [filterSettings] = useAtom(filterSettingsAtom);
1717
const memoizedRequestList = useMemo(() => {
18-
if (searchValue.length === 0 || !isFilterActive) return requestList;
18+
const { value, invert } = filterSettings;
19+
if (value.length === 0 || !isFilterActive) return requestList;
1920
return requestList.filter(({ servicePath, rpcName }) => {
20-
return servicePath.includes(searchValue) || rpcName.includes(searchValue);
21+
const isFiltered = servicePath.includes(value) || rpcName.includes(value);
22+
return invert ? !isFiltered : isFiltered;
2123
});
22-
}, [isFilterActive, requestList, searchValue]);
24+
}, [isFilterActive, requestList, filterSettings]);
2325
return (
2426
<div className={style["request-list"]}>
2527
{memoizedRequestList.map(
@@ -51,19 +53,3 @@ const RequestList: React.FC<RequestListProps> = () => {
5153
);
5254
};
5355
export default memo(RequestList);
54-
55-
const requestListAtom = atom((get) => {
56-
const requests = get(requestsAtom);
57-
return Object.keys(requests).map((key) => {
58-
const { servicePath, rpcName, responsePayloadsAtom, responseError } = get(
59-
requests[key]
60-
);
61-
return {
62-
key,
63-
servicePath,
64-
rpcName,
65-
responsePayloads: get(responsePayloadsAtom),
66-
responseError,
67-
};
68-
});
69-
});
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
.settings {
2-
padding: 4px;
32
display: flex;
43
flex-direction: column;
54

65
border-bottom: 1px solid var(--pb-sep);
76

87
> * {
9-
padding: 4px 0;
10-
11-
&:first-child {
12-
padding-top: 0;
13-
}
14-
158
&:not(:first-child) {
169
border-top: 1px solid var(--pb-sep);
1710
}
18-
19-
&:last-child {
20-
padding-bottom: 0;
21-
}
2211
}
2312
}
2413

2514
.search-section {
2615
display: flex;
27-
align-items: center;
16+
height: 26px;
17+
align-items: stretch;
18+
padding-left: 4px;
19+
20+
.filter-input {
21+
width: 163px;
22+
margin-right: 6px;
23+
}
24+
25+
.margin-left {
26+
margin-left: 4px;
27+
}
2828
}
2929

3030
.vertical-sep {
31-
height: 100%;
32-
border-right: 1px solid var(--pb-sep);
33-
margin-right: 0.625em;
31+
width: 1px;
32+
margin: 5px 4px;
33+
background-color: var(--pb-sep);
3434
}

0 commit comments

Comments
 (0)