Skip to content

Commit 06b3ec4

Browse files
committed
web: add Go code examples section
1 parent 4d8b2c6 commit 06b3ec4

File tree

5 files changed

+276
-7
lines changed

5 files changed

+276
-7
lines changed

web/src/Header.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
import React from 'react';
22
import './Header.css'
3-
import { CommandBar, ICommandBarItemProps } from 'office-ui-fabric-react/lib/CommandBar';
4-
import { getTheme } from '@uifabric/styling';
3+
import {CommandBar, ICommandBarItemProps} from 'office-ui-fabric-react/lib/CommandBar';
4+
import {getTheme} from '@uifabric/styling';
55
import SettingsModal, {SettingsChanges} from './settings/SettingsModal';
66
import AboutModal from './AboutModal';
77
import config from './services/config';
8+
import { getSnippetsMenuItems, SnippetMenuItem } from './utils/headerutils';
89
import {
910
Connect,
10-
newImportFileDispatcher,
11+
dispatchToggleTheme,
1112
formatFileDispatcher,
13+
newBuildParamsChangeDispatcher, newCodeImportDispatcher,
14+
newImportFileDispatcher,
15+
newMonacoParamsChangeDispatcher, newSnippetLoadDispatcher,
1216
runFileDispatcher,
1317
saveFileDispatcher,
14-
dispatchToggleTheme,
15-
shareSnippetDispatcher,
16-
newBuildParamsChangeDispatcher,
17-
newMonacoParamsChangeDispatcher
18+
shareSnippetDispatcher
1819
} from './store';
1920

2021

22+
2123
interface HeaderState {
2224
showSettings: boolean
2325
showAbout: boolean
@@ -27,6 +29,7 @@ interface HeaderState {
2729
@Connect(s => ({darkMode: s.settings.darkMode, loading: s.status?.loading}))
2830
export class Header extends React.Component<any, HeaderState> {
2931
private fileInput?: HTMLInputElement;
32+
private snippetMenuItems = getSnippetsMenuItems(i => this.onSnippetMenuItemClick(i));
3033

3134
constructor(props) {
3235
super(props);
@@ -54,14 +57,23 @@ export class Header extends React.Component<any, HeaderState> {
5457
this.props.dispatch(newImportFileDispatcher(file));
5558
}
5659

60+
onSnippetMenuItemClick(item: SnippetMenuItem) {
61+
const dispatcher = item.snippet ? newSnippetLoadDispatcher(item.snippet) : newCodeImportDispatcher(item.label, item.text as string);
62+
this.props.dispatch(dispatcher);
63+
}
64+
5765
get menuItems(): ICommandBarItemProps[] {
5866
return [
5967
{
6068
key: 'openFile',
6169
text: 'Open',
70+
split: true,
6271
iconProps: {iconName: 'OpenFile'},
6372
disabled: this.props.loading,
6473
onClick: () => this.fileInput?.click(),
74+
subMenuProps: {
75+
items: this.snippetMenuItems,
76+
},
6577
},
6678
{
6779
key: 'run',

web/src/services/go/snippets.json

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
{
2+
"Templates": [
3+
{
4+
"label": "New Empty Test",
5+
"type": "test",
6+
"text": "package main\n\nimport \"testing\"\n\nfunc TestExample(t *testing.T) {\n\tt.Log(\"this is unit test sample\")\n}\n"
7+
},
8+
{
9+
"label": "Example Test",
10+
"type": "test",
11+
"snippet": "GFuPdlBlyMU"
12+
},
13+
{
14+
"label": "Hello World",
15+
"snippet": "NeviD0awXjt"
16+
}
17+
],
18+
"Basic Examples": [
19+
{
20+
"label": "Hello World",
21+
"snippet": "NeviD0awXjt"
22+
},
23+
{
24+
"label": "Maps",
25+
"snippet": "agK2Ro2i-Lu"
26+
},
27+
{
28+
"label": "Sorting",
29+
"snippet": "_gY0tANzJ4l"
30+
},
31+
{
32+
"label": "Custom sort",
33+
"snippet": "h4g4vaLBtkw"
34+
},
35+
{
36+
"label": "Recursion",
37+
"snippet": "smWim1q9ofu"
38+
},
39+
{
40+
"label": "Structs & methods",
41+
"snippet": "4wmDCAydC1e"
42+
},
43+
{
44+
"label": "Interfaces",
45+
"snippet": "XJASG4MxBQr"
46+
},
47+
{
48+
"label": "Errors",
49+
"snippet": "NiJOpCPO3L0"
50+
}
51+
],
52+
"Concurrency": [
53+
{
54+
"label": "Goroutines",
55+
"snippet": "I7scqRijEJt"
56+
},
57+
{
58+
"label": "Channels",
59+
"snippet": "MaLY7AiAkHM"
60+
},
61+
{
62+
"label": "Buffered channels",
63+
"snippet": "3BRCdRnRszb"
64+
},
65+
{
66+
"label": "Select",
67+
"snippet": "FzONhs4-tae"
68+
},
69+
{
70+
"label": "Timeouts",
71+
"snippet": "4oOz0j29MJ6"
72+
},
73+
{
74+
"label": "Non-blocking channel operations",
75+
"snippet": "TFv6-7OVNVq"
76+
},
77+
{
78+
"label": "Closing channels",
79+
"snippet": "yQMclmwOYs9"
80+
},
81+
{
82+
"label": "Timers",
83+
"snippet": "gF7VLRz3URM"
84+
},
85+
{
86+
"label": "Tickers",
87+
"snippet": "gs6zoJP-Pl9"
88+
},
89+
{
90+
"label": "Worker pools",
91+
"snippet": "hiSJJsYZJKL"
92+
},
93+
{
94+
"label": "Rate limit",
95+
"snippet": "20c_m1AtOEI"
96+
},
97+
{
98+
"label": "Atomics",
99+
"snippet": "j-14agntvEO"
100+
},
101+
{
102+
"label": "Mutexes",
103+
"snippet": "0WEmOOjoCjp"
104+
},
105+
{
106+
"label": "Mutexes",
107+
"snippet": "0WEmOOjoCjp"
108+
},
109+
{
110+
"label": "Stateful goroutines",
111+
"snippet": "5mf_P9xqBzk"
112+
},
113+
{
114+
"label": "Context",
115+
"snippet": "0_bu1o8rIBO"
116+
}
117+
],
118+
"Other examples": [
119+
{
120+
"label": "Random number",
121+
"snippet": "PGklfJzErTN"
122+
},
123+
{
124+
"label": "Number parsing",
125+
"snippet": "ZAMEid6Fpmu"
126+
},
127+
{
128+
"label": "Regular expressions",
129+
"snippet": "LEKGY_d3Nu_P"
130+
},
131+
{
132+
"label": "JSON",
133+
"snippet": "JOQpRGJWAxR"
134+
},
135+
{
136+
"label": "HTTP Client",
137+
"snippet": "kHCcVLoz7nd"
138+
},
139+
{
140+
"label": "Time",
141+
"snippet": "YAM3s1KPc8c"
142+
},
143+
{
144+
"label": "Time formatting",
145+
"snippet": "BoZYtr_2j66"
146+
},
147+
{
148+
"label": "SHA1 hash",
149+
"snippet": "XLftf8Gvj4y"
150+
},
151+
{
152+
"label": "Base64 encoding",
153+
"snippet": "S7ff3UgzNlG"
154+
},
155+
{
156+
"label": "Writing files",
157+
"snippet": "fQ7sd4gXv0F"
158+
},
159+
{
160+
"label": "Reading files",
161+
"snippet": "kF0cDC0drsX"
162+
},
163+
{
164+
"label": "Signals",
165+
"snippet": "YRV64KEXJW1"
166+
}
167+
]
168+
169+
}

web/src/services/go/snippets.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import snippets from './snippets.json';
2+
3+
export enum SnippetType {
4+
Test = 'test'
5+
}
6+
7+
export interface Snippet {
8+
/**
9+
* label is snippet label
10+
*/
11+
label: string
12+
13+
/**
14+
* SnippetType is snippet type (if it's a test, etc)
15+
*/
16+
type?: SnippetType
17+
18+
/**
19+
* Snippet is snipped ID to be loaded
20+
*
21+
* Presents if snippet is referenced to snippet ID
22+
*/
23+
snippet?: string
24+
25+
/**
26+
* Text contains snipped code.
27+
*
28+
* Not empty when shipped field is empty
29+
*/
30+
text?: string
31+
}
32+
33+
export default snippets as {[sectionName: string]: Snippet[]}

web/src/store/dispatch.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ export function newImportFileDispatcher(f: File): Dispatcher {
4141
};
4242
}
4343

44+
export function newCodeImportDispatcher(name: string, contents: string): Dispatcher {
45+
return (dispatch: DispatchFn, _: StateProvider) => {
46+
dispatch(newImportFileAction(`${encodeURIComponent(name)}.go`, contents));
47+
};
48+
}
49+
4450
export function newMonacoParamsChangeDispatcher(changes: MonacoParamsChanges): Dispatcher {
4551
return (dispatch: DispatchFn, _: StateProvider) => {
4652
const current = config.monacoSettings;
@@ -66,6 +72,7 @@ export function newSnippetLoadDispatcher(snippetID: string): Dispatcher {
6672
return;
6773
}
6874

75+
dispatch(newLoadingAction());
6976
try {
7077
console.log('loading snippet %s', snippetID);
7178
const resp = await client.getSnippet(snippetID);

web/src/utils/headerutils.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import snippets, {Snippet, SnippetType} from '../services/go/snippets';
2+
import {ContextualMenuItemType, IContextualMenuItem, IIconProps} from "office-ui-fabric-react";
3+
4+
const snippetIconTypeMapping: {[type: string]: IIconProps} = {
5+
[SnippetType.Test]: {
6+
iconName: 'TestPlan'
7+
}
8+
}
9+
10+
export interface SnippetMenuItem extends Snippet {}
11+
12+
/**
13+
* Returns snippets list dropdown menu items
14+
* @param handler menu item click handler
15+
*/
16+
export const getSnippetsMenuItems = (handler: (s: SnippetMenuItem) => void) => {
17+
let menuItems: IContextualMenuItem[] = [];
18+
Object.entries(snippets).forEach((s, i) => {
19+
// this can be done in with ".map().reduce()"
20+
// but imho simple imperative method will look
21+
// more readable in future
22+
const [sectionName, items] = s;
23+
24+
const section = {
25+
key: i.toString(),
26+
text: sectionName,
27+
itemType: ContextualMenuItemType.Header
28+
};
29+
30+
const sectionItems = items.map((item, ii) => {
31+
return {
32+
key: `${i}-${ii}`,
33+
text: item.label,
34+
iconProps: getSnippetIconProps(item.type),
35+
onClick: () => handler(item)
36+
} as IContextualMenuItem;
37+
})
38+
39+
menuItems.push(...[section, ...sectionItems]);
40+
})
41+
return menuItems;
42+
};
43+
44+
const getSnippetIconProps = (snippetType?: SnippetType): IIconProps|undefined => {
45+
if (!snippetType) return;
46+
if (!(snippetType in snippetIconTypeMapping)) return;
47+
return snippetIconTypeMapping[snippetType];
48+
}

0 commit comments

Comments
 (0)