Skip to content

Commit 6e8a0b6

Browse files
add sectioning & history, remove filter
1 parent 0f37170 commit 6e8a0b6

File tree

6 files changed

+228
-92
lines changed

6 files changed

+228
-92
lines changed
Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,43 @@
11
// save recently used items
22

3+
import type { Icon } from "./resources";
4+
35
const _k_store_key = "icons-load-history";
46

57
export class IconsLoadHistory {
6-
private readonly history: Set<string>;
7-
8-
constructor() {
9-
this.history = new Set();
8+
private readonly data: Array<Icon> = [];
109

10+
constructor(readonly max: number = 50) {
1111
const items = localStorage.getItem(_k_store_key);
1212
if (items) {
13-
this.history = new Set(JSON.parse(items));
13+
this.data = JSON.parse(items);
1414
}
1515
}
1616

17-
list(to: number = Infinity) {
18-
return Array.from(this.history).reverse().slice(0, to);
17+
list(to: number = Infinity): Array<Icon> {
18+
return Array.from(this.data).reverse().slice(0, to);
1919
}
2020

21-
push(item: string) {
22-
this.history.delete(item);
23-
this.history.add(item);
21+
push(item: Icon) {
22+
const index = this.data.findIndex(
23+
(i) =>
24+
i.package === item.package &&
25+
i.name === item.name &&
26+
i.variant === item.variant
27+
);
28+
if (index >= 0) {
29+
this.data.splice(index, 1);
30+
}
31+
this.data.push(item);
32+
33+
if (this.data.length > this.max) {
34+
this.data.shift();
35+
}
36+
2437
this.save();
2538
}
2639

2740
private save() {
28-
localStorage.setItem(_k_store_key, JSON.stringify(this.list()));
41+
localStorage.setItem(_k_store_key, JSON.stringify(this.data));
2942
}
3043
}

packages/app-icons-loader/icon-item.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import { assistant as analytics } from "@analytics.bridged.xyz/internal";
1010
import styled from "@emotion/styled";
1111
import { IconMeta, Icon, loadSvg, makeIconUrl, useIcons } from "./resources";
1212

13-
export function IconItem(props: Icon) {
13+
type IconItemProps = Icon & { onClick: () => void };
14+
15+
export function IconItem({ onClick, ...props }: IconItemProps) {
1416
const { package: _package, name, variant } = props;
1517
const [loading, setLoading] = useState(false);
1618
const [loaded, setLoaded] = useState(false);
@@ -52,7 +54,8 @@ export function IconItem(props: Icon) {
5254
}
5355
}
5456

55-
const onClick = () => {
57+
const onclick = () => {
58+
onClick();
5659
_onUserLoadIconToCanvas();
5760
loadData().then((d) => {
5861
parent.postMessage(
@@ -82,7 +85,7 @@ export function IconItem(props: Icon) {
8285
},
8386
}}
8487
>
85-
<IconButton onClick={onClick} disabled={downloading}>
88+
<IconButton onClick={onclick} disabled={downloading}>
8689
{downloading ? (
8790
<CircularProgress size={24} />
8891
) : (

packages/app-icons-loader/icons-loader.tsx

Lines changed: 118 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import React, { useEffect, useRef, useState } from "react";
1+
import React, {
2+
useMemo,
3+
useEffect,
4+
useRef,
5+
useState,
6+
useCallback,
7+
} from "react";
28
import styled from "@emotion/styled";
39
import GridList from "@material-ui/core/GridList";
410
import GridListTile from "@material-ui/core/GridListTile";
@@ -8,6 +14,27 @@ import { IconItem } from "./icon-item";
814
import InfiniteScroll from "react-infinite-scroller";
915
import { debounce } from "./utils";
1016
import { IconSearch } from "./icons-search";
17+
import { IconsLoadHistory } from "./history";
18+
import _ from "lodash";
19+
20+
function useRecentlyUsedIcons(max: number = 20) {
21+
const [recentIcons, setRecentIcons] = useState<Icon[]>([]);
22+
const h = useMemo(() => new IconsLoadHistory(max), []);
23+
24+
useEffect(() => {
25+
setRecentIcons(h.list());
26+
}, [h]);
27+
28+
const addHistory = useCallback(
29+
(icon: Icon) => {
30+
h.push(icon);
31+
setRecentIcons(h.list());
32+
},
33+
[h]
34+
);
35+
36+
return [recentIcons, addHistory] as const;
37+
}
1138

1239
export function IconsLoader() {
1340
const [query, setQuery] = useState<string>(undefined);
@@ -22,6 +49,7 @@ export function IconsLoader() {
2249
host: "material",
2350
});
2451

52+
const [recentlyUsedIcons, addHistory] = useRecentlyUsedIcons();
2553
const { icons, hasMore } = useIcons({
2654
max: max,
2755
query: query,
@@ -32,62 +60,119 @@ export function IconsLoader() {
3260
setMax(100);
3361
}, [iconProperty, query]);
3462

63+
const onIconClick = (icon: Icon) => {
64+
addHistory(icon);
65+
};
66+
67+
const loading = icons === undefined;
68+
const do_show_recently_used = recentlyUsedIcons?.length > 0 && !query;
69+
70+
// group by package
71+
const grouped = _.groupBy(icons ?? [], (d) => d.package);
72+
3573
return (
3674
<>
3775
<IconSearch
3876
onChange={debounce(setQuery, 200)}
3977
onSelectIconProperty={setIconProperty}
4078
/>
4179
<>
42-
{icons === undefined ? (
43-
<StyledLinearProgress />
44-
) : (
45-
<InfiniteScroll
46-
pageStart={0}
47-
hasMore={hasMore}
48-
loadMore={() => {
49-
setMax((d) => d + 100);
50-
}}
51-
>
52-
<IconList icons={icons} />
53-
</InfiniteScroll>
54-
)}
80+
<StyledLinearProgress
81+
style={{
82+
display: loading ? "block" : "none",
83+
}}
84+
/>
85+
86+
<InfiniteScroll
87+
pageStart={0}
88+
hasMore={hasMore}
89+
loadMore={() => {
90+
setMax((d) => d + 100);
91+
}}
92+
>
93+
<ListWrap>
94+
{do_show_recently_used && (
95+
<Section>
96+
<h6 className="title">Frequently used</h6>
97+
<IconList icons={recentlyUsedIcons} onIconClick={onIconClick} />
98+
</Section>
99+
)}
100+
101+
{Object.keys(grouped).map((key) => {
102+
const icons = grouped[key];
103+
return (
104+
<Section key={key}>
105+
<h6 className="title">{key}</h6>
106+
<IconList icons={icons} onIconClick={onIconClick} />
107+
</Section>
108+
);
109+
})}
110+
{/* {icons?.length > 0 && (
111+
<IconList icons={icons} onIconClick={onIconClick} />
112+
)} */}
113+
</ListWrap>
114+
</InfiniteScroll>
55115
</>
56116
</>
57117
);
58118
}
59119

60120
const IconList = React.forwardRef(function (
61-
{ icons }: { icons: Icon[] },
121+
{
122+
icons,
123+
onIconClick,
124+
}: {
125+
icons: Icon[];
126+
onIconClick?: (icon: Icon) => void;
127+
},
62128
ref: any
63129
) {
64130
return (
65131
<>
66-
<ListWrap>
67-
<GridList
68-
cellHeight="auto"
69-
cols={5}
70-
style={{ marginRight: 0, marginLeft: 0 }}
71-
ref={ref}
72-
>
73-
{icons.map((icon) => {
74-
const { package: _p, name, variant } = icon;
75-
return (
76-
<GridItem key={_p + name + variant} classes={{ tile: "tile" }}>
77-
<IconItem {...icon} />
78-
</GridItem>
79-
);
80-
})}
81-
</GridList>
82-
</ListWrap>
132+
<GridList
133+
cellHeight="auto"
134+
cols={5}
135+
style={{ marginRight: 0, marginLeft: 0 }}
136+
ref={ref}
137+
>
138+
{icons.map((icon) => {
139+
const { package: _p, name, variant } = icon;
140+
return (
141+
<GridItem key={_p + name + variant} classes={{ tile: "tile" }}>
142+
<IconItem
143+
{...icon}
144+
onClick={() => {
145+
onIconClick?.(icon);
146+
}}
147+
/>
148+
</GridItem>
149+
);
150+
})}
151+
</GridList>
83152
</>
84153
);
85154
});
86155

156+
const Section = styled.div`
157+
display: flex;
158+
flex-direction: column;
159+
width: 100%;
160+
margin-bottom: 20px;
161+
.title {
162+
margin: 0;
163+
padding: 16px;
164+
font-size: 12px;
165+
font-weight: normal;
166+
color: rgba(0, 0, 0, 0.54);
167+
text-transform: uppercase;
168+
}
169+
`;
170+
87171
const ListWrap = styled.div`
88172
display: flex;
89173
flex-wrap: wrap;
90174
`;
175+
91176
const StyledLinearProgress = styled(LinearProgress)`
92177
/* for reset body margin */
93178
@@ -97,7 +182,7 @@ const StyledLinearProgress = styled(LinearProgress)`
97182
}
98183
99184
&.barColorPrimary {
100-
background-color: #2562ff;
185+
background-color: black;
101186
}
102187
`;
103188

packages/app-icons-loader/icons-search.tsx

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,47 @@ export function IconSearch(props: {
77
onChange: (value: string) => void;
88
onSelectIconProperty: (value: any) => void;
99
}) {
10-
const iconPropertyList = {
11-
default_size: ["Size", "16", "20", "24", "28", "32"],
12-
variant: ["Variant", "Outlined", "Twotone", "Default", "Sharp"],
13-
};
14-
const [iconProperty, setIconProperty] = useState({
15-
default_size: "Size",
16-
variant: "Variant",
17-
});
10+
// const iconPropertyList = {
11+
// default_size: ["Size", "16", "20", "24", "28", "32"],
12+
// variant: ["Variant", "Outlined", "Twotone", "Default", "Sharp"],
13+
// };
14+
// const [iconProperty, setIconProperty] = useState({
15+
// default_size: "Size",
16+
// variant: "Variant",
17+
// });
1818

19-
const BootstrapInput = withStyles((theme) => ({
20-
root: {
21-
"label + &": {
22-
marginTop: theme.spacing(3),
23-
},
24-
},
25-
input: {
26-
fontSize: 14,
27-
},
28-
}))(InputBase);
19+
// const BootstrapInput = withStyles((theme) => ({
20+
// root: {
21+
// "label + &": {
22+
// marginTop: theme.spacing(3),
23+
// },
24+
// },
25+
// input: {
26+
// fontSize: 14,
27+
// },
28+
// }))(InputBase);
2929

30-
const onSelectValue = (type: string, value: any) => {
31-
if (type === "size") {
32-
props.onSelectIconProperty((d) => ({
33-
...d,
34-
default_size: value.toLocaleLowerCase(),
35-
}));
36-
setIconProperty((d) => ({
37-
...d,
38-
default_size: value,
39-
}));
40-
} else if (type === "variant") {
41-
props.onSelectIconProperty((d) => ({
42-
...d,
43-
variant: value.toLocaleLowerCase(),
44-
}));
45-
setIconProperty((d) => ({
46-
...d,
47-
variant: value,
48-
}));
49-
}
50-
};
30+
// const onSelectValue = (type: string, value: any) => {
31+
// if (type === "size") {
32+
// props.onSelectIconProperty((d) => ({
33+
// ...d,
34+
// default_size: value.toLocaleLowerCase(),
35+
// }));
36+
// setIconProperty((d) => ({
37+
// ...d,
38+
// default_size: value,
39+
// }));
40+
// } else if (type === "variant") {
41+
// props.onSelectIconProperty((d) => ({
42+
// ...d,
43+
// variant: value.toLocaleLowerCase(),
44+
// }));
45+
// setIconProperty((d) => ({
46+
// ...d,
47+
// variant: value,
48+
// }));
49+
// }
50+
// };
5151

5252
return (
5353
<ControlsWrapper>
@@ -58,7 +58,7 @@ export function IconSearch(props: {
5858
onChange={(e) => props.onChange(e.target.value.toLocaleLowerCase())}
5959
/>
6060
</SearchBar>
61-
<Filters>
61+
{/* <Filters>
6262
<TypeCheck>
6363
<StyledSelect
6464
classes={{ root: "root" }}
@@ -87,7 +87,7 @@ export function IconSearch(props: {
8787
))}
8888
</StyledSelect>
8989
</SizeCheck>
90-
</Filters>
90+
</Filters> */}
9191
</ControlsWrapper>
9292
);
9393
}

0 commit comments

Comments
 (0)