Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb787093

Browse files
committed
feat: add /icons page
1 parent71ad590 commitb787093

File tree

5 files changed

+216
-12
lines changed

5 files changed

+216
-12
lines changed

‎site/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
"ts-prune":"0.10.3",
9191
"tzdata":"1.0.30",
9292
"ua-parser-js":"1.0.33",
93+
"ufuzzy":"npm:@leeoniya/ufuzzy@1.0.10",
9394
"unique-names-generator":"4.7.1",
9495
"uuid":"9.0.0",
9596
"vite":"4.4.2",

‎site/pnpm-lock.yaml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎site/src/AppRouter.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ const TemplateInsightsPage = lazy(
193193
);
194194
constHealthPage=lazy(()=>import("./pages/HealthPage/HealthPage"));
195195
constGroupsPage=lazy(()=>import("./pages/GroupsPage/GroupsPage"));
196+
constIconsPage=lazy(()=>import("./pages/IconsPage/IconsPage"));
196197

197198
exportconstAppRouter:FC=()=>{
198199
return(
@@ -207,21 +208,21 @@ export const AppRouter: FC = () => {
207208
<Routeelement={<DashboardLayout/>}>
208209
<Routeindexelement={<Navigateto="/workspaces"replace/>}/>
209210

210-
<Routepath="health"element={<HealthPage/>}/>
211+
<Routepath="/health"element={<HealthPage/>}/>
211212

212213
<Route
213-
path="external-auth/:provider"
214+
path="/external-auth/:provider"
214215
element={<ExternalAuthPage/>}
215216
/>
216217

217-
<Routepath="workspaces"element={<WorkspacesPage/>}/>
218+
<Routepath="/workspaces"element={<WorkspacesPage/>}/>
218219

219-
<Routepath="starter-templates">
220+
<Routepath="/starter-templates">
220221
<Routeindexelement={<StarterTemplatesPage/>}/>
221222
<Routepath=":exampleId"element={<StarterTemplatePage/>}/>
222223
</Route>
223224

224-
<Routepath="templates">
225+
<Routepath="/templates">
225226
<Routeindexelement={<TemplatesPage/>}/>
226227
<Routepath="new"element={<CreateTemplatePage/>}/>
227228
<Routepath=":template">
@@ -261,7 +262,7 @@ export const AppRouter: FC = () => {
261262
</Route>
262263
</Route>
263264

264-
<Routepath="users">
265+
<Routepath="/users">
265266
<Routeelement={<UsersLayout/>}>
266267
<Routeindexelement={<UsersPage/>}/>
267268
</Route>
@@ -302,7 +303,7 @@ export const AppRouter: FC = () => {
302303
/>
303304
</Route>
304305

305-
<Routepath="settings"element={<SettingsLayout/>}>
306+
<Routepath="/settings"element={<SettingsLayout/>}>
306307
<Routepath="account"element={<AccountPage/>}/>
307308
<Routepath="schedule"element={<SchedulePage/>}/>
308309
<Routepath="security"element={<SecurityPage/>}/>
@@ -340,7 +341,8 @@ export const AppRouter: FC = () => {
340341
path="/:username/:workspace/terminal"
341342
element={<TerminalPagerenderer="webgl"/>}
342343
/>
343-
<Routepath="cli-auth"element={<CliAuthenticationPage/>}/>
344+
<Routepath="/cli-auth"element={<CliAuthenticationPage/>}/>
345+
<Routepath="/icons"element={<IconsPage/>}/>
344346
</Route>
345347

346348
{/* Using path="*"" means "match anything", so this route

‎site/src/components/CopyableValue/CopyableValue.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
importTooltipfrom"@mui/material/Tooltip";
1+
importTooltip,{typeTooltipProps}from"@mui/material/Tooltip";
22
import{useClickable}from"hooks/useClickable";
33
import{useClipboard}from"hooks/useClipboard";
4-
import{FC,HTMLProps}from"react";
4+
import{typeFC,typeHTMLProps}from"react";
55

66
interfaceCopyableValuePropsextendsHTMLProps<HTMLDivElement>{
77
value:string;
8+
placement?:TooltipProps["placement"];
9+
PopperProps?:TooltipProps["PopperProps"];
810
}
911

10-
exportconstCopyableValue:FC<CopyableValueProps>=({ value, ...props})=>{
12+
exportconstCopyableValue:FC<CopyableValueProps>=({
13+
value,
14+
placement="bottom-start",
15+
PopperProps,
16+
...props
17+
})=>{
1118
const{ isCopied, copy}=useClipboard(value);
1219
constclickableProps=useClickable<HTMLSpanElement>(copy);
1320

1421
return(
1522
<Tooltip
1623
title={isCopied ?"Copied!" :"Click to copy"}
17-
placement="bottom-start"
24+
placement={placement}
25+
PopperProps={PopperProps}
1826
>
1927
<span{...props}{...clickableProps}css={{cursor:"pointer"}}/>
2028
</Tooltip>
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
importTextFieldfrom"@mui/material/TextField";
2+
importInputAdornmentfrom"@mui/material/InputAdornment";
3+
importTooltipfrom"@mui/material/Tooltip";
4+
importIconButtonfrom"@mui/material/IconButton";
5+
importBoxfrom"@mui/material/Box";
6+
importLinkfrom"@mui/material/Link";
7+
importSearchIconfrom"@mui/icons-material/SearchOutlined";
8+
importClearIconfrom"@mui/icons-material/CloseOutlined";
9+
import{useTheme}from"@emotion/react";
10+
import{typeFC,typeReactNode,useMemo,useState}from"react";
11+
importuFuzzyfrom"ufuzzy";
12+
import{CopyableValue}from"components/CopyableValue/CopyableValue";
13+
import{EmptyState}from"components/EmptyState/EmptyState";
14+
import{Margins}from"components/Margins/Margins";
15+
import{
16+
PageHeader,
17+
PageHeaderSubtitle,
18+
PageHeaderTitle,
19+
}from"components/PageHeader/PageHeader";
20+
import{Stack}from"components/Stack/Stack";
21+
importiconsfrom"theme/icons.json";
22+
23+
consticonsWithoutSuffix=icons.map((icon)=>icon.split(".")[0]);
24+
constfuzzyFinder=newuFuzzy({
25+
intraMode:1,
26+
intraIns:1,
27+
intraSub:1,
28+
intraTrn:1,
29+
intraDel:1,
30+
});
31+
32+
exportconstIconsPage:FC=()=>{
33+
consttheme=useTheme();
34+
const[searchInputText,setSearchInputText]=useState("");
35+
constsearchText=searchInputText.trim();
36+
37+
constsearchedIcons=useMemo(()=>{
38+
if(!searchText){
39+
returnicons.map((icon)=>({url:`/icon/${icon}`,description:icon}));
40+
}
41+
42+
const[map,info,sorted]=fuzzyFinder.search(
43+
iconsWithoutSuffix,
44+
searchText,
45+
);
46+
47+
// We hit an invalid state somehow
48+
if(!map||!info||!sorted){
49+
return[];
50+
}
51+
52+
returnsorted.map((i)=>{
53+
consticonName=icons[info.idx[i]];
54+
constranges=info.ranges[i];
55+
56+
constnodes:ReactNode[]=[];
57+
letcursor=0;
58+
for(letj=0;j<ranges.length;j+=2){
59+
nodes.push(iconName.slice(cursor,ranges[j]));
60+
nodes.push(
61+
<markkey={j+1}>{iconName.slice(ranges[j],ranges[j+1])}</mark>,
62+
);
63+
cursor=ranges[j+1];
64+
}
65+
nodes.push(iconName.slice(cursor));
66+
return{url:`/icon/${iconName}`,description:nodes};
67+
});
68+
},[searchText]);
69+
70+
return(
71+
<Margins>
72+
<PageHeader
73+
actions={
74+
<Tooltip
75+
placement="bottom-end"
76+
title={
77+
<Box
78+
css={{
79+
padding:theme.spacing(1),
80+
fontSize:13,
81+
lineHeight:1.5,
82+
}}
83+
>
84+
You can suggest a new icon by submitting a Pull Request to our
85+
public GitHub repository. Just keep in mind that it should be
86+
relevant to many Coder users, and redistributable under a
87+
permissive license.
88+
</Box>
89+
}
90+
>
91+
<Linkhref="https://github.com/coder/coder/tree/main/site/static/icon">
92+
Suggest an icon
93+
</Link>
94+
</Tooltip>
95+
}
96+
>
97+
<PageHeaderTitle>Icons</PageHeaderTitle>
98+
<PageHeaderSubtitle>
99+
All of the icons included with Coder
100+
</PageHeaderSubtitle>
101+
</PageHeader>
102+
<TextField
103+
size="small"
104+
InputProps={{
105+
"aria-label":"Filter",
106+
name:"query",
107+
placeholder:"Search…",
108+
value:searchInputText,
109+
onChange:(event)=>setSearchInputText(event.target.value),
110+
sx:{
111+
borderRadius:"6px",
112+
marginLeft:"-1px",
113+
"& input::placeholder":{
114+
color:theme.palette.text.secondary,
115+
},
116+
"& .MuiInputAdornment-root":{
117+
marginLeft:0,
118+
},
119+
},
120+
startAdornment:(
121+
<InputAdornmentposition="start">
122+
<SearchIcon
123+
sx={{
124+
fontSize:14,
125+
color:theme.palette.text.secondary,
126+
}}
127+
/>
128+
</InputAdornment>
129+
),
130+
endAdornment:searchInputText&&(
131+
<InputAdornmentposition="end">
132+
<Tooltiptitle="Clear filter">
133+
<IconButtonsize="small"onClick={()=>setSearchInputText("")}>
134+
<ClearIconsx={{fontSize:14}}/>
135+
</IconButton>
136+
</Tooltip>
137+
</InputAdornment>
138+
),
139+
}}
140+
/>
141+
142+
<Stack
143+
direction="row"
144+
wrap="wrap"
145+
spacing={1}
146+
justifyContent="center"
147+
css={(theme)=>({marginTop:theme.spacing(4)})}
148+
>
149+
{searchedIcons.length===0&&(
150+
<EmptyStatemessage="No results matched your search"/>
151+
)}
152+
{searchedIcons.map((icon)=>(
153+
<CopyableValuekey={icon.url}value={icon.url}placement="bottom">
154+
<StackalignItems="center"css={{margin:theme.spacing(1.5)}}>
155+
<img
156+
alt={icon.url}
157+
src={icon.url}
158+
css={{
159+
width:60,
160+
height:60,
161+
objectFit:"contain",
162+
pointerEvents:"none",
163+
padding:theme.spacing(1.5),
164+
}}
165+
/>
166+
<figcaption
167+
css={{
168+
width:88,
169+
height:48,
170+
fontSize:13,
171+
textOverflow:"ellipsis",
172+
textAlign:"center",
173+
overflow:"hidden",
174+
}}
175+
>
176+
{icon.description}
177+
</figcaption>
178+
</Stack>
179+
</CopyableValue>
180+
))}
181+
</Stack>
182+
</Margins>
183+
);
184+
};
185+
186+
exportdefaultIconsPage;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp