Skip to content

Commit 83e5947

Browse files
committed
feat: add actionBar and samples
1 parent fbaeaff commit 83e5947

File tree

7 files changed

+356
-29
lines changed

7 files changed

+356
-29
lines changed

src/components/actionbar/index.tsx

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import './style.scss';
2+
import * as React from 'react';
3+
import { prefixClaName, classNames } from 'mo/common/className';
4+
5+
export interface IActionBarItem<T = any> extends React.ComponentProps<any> {
6+
id: string;
7+
name?: string;
8+
title?: string;
9+
iconName?: string;
10+
disabled?: boolean;
11+
data?: T;
12+
className?: string;
13+
onClick?(event: React.MouseEvent, item: IActionBarItem): void;
14+
}
15+
16+
export interface IActionBar<T = any> {
17+
data: IActionBarItem<T>[];
18+
className?: string;
19+
onClick?(event: React.MouseEvent, item: IActionBarItem): void;
20+
}
21+
22+
const rootClassName = 'action-bar';
23+
24+
export function ActionBarItem(props: IActionBarItem) {
25+
const { id, title, name, onClick } = props;
26+
const click = (e: React.MouseEvent) => {
27+
if (onClick) {
28+
onClick(e, props);
29+
}
30+
}
31+
const disabled = props.disabled ? 'disabled' : null;
32+
const claNames = classNames('action-label', 'codicon', props.iconName, disabled);
33+
return (
34+
<li className={classNames('action-item', disabled)} onClick={click} key={`${id}`}>
35+
<a className={claNames} title={title}>{name}</a>
36+
</li>
37+
)
38+
}
39+
40+
export default function ActionBar<T = any>(props: IActionBar<T>) {
41+
const { data = [], onClick, className, ...others } = props;
42+
43+
const claNames = classNames(prefixClaName(rootClassName), className);
44+
45+
const items = data.map((item: IActionBarItem<T>) => <ActionBarItem key={item.id} {...item} />)
46+
47+
return (
48+
<div className={claNames} {...others}>
49+
<ul className={prefixClaName('container', rootClassName)}>
50+
{ items }
51+
</ul>
52+
</div>
53+
)
54+
}

src/components/actionbar/style.scss

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@import 'mo/style/const';
2+
$actionBar: 'action-bar';
3+
4+
#{prefix($actionBar)} {
5+
overflow: hidden;
6+
text-align: right;
7+
white-space: nowrap;
8+
9+
.#{$actionBar}-container {
10+
display: flex;
11+
justify-content: flex-end;
12+
margin: 0 auto;
13+
padding: 0;
14+
width: 100%;
15+
}
16+
17+
.action-item {
18+
cursor: pointer;
19+
display: inline-block;
20+
position: relative;
21+
transition: transform 50ms ease;
22+
}
23+
24+
.action-label {
25+
align-items: center;
26+
background-position: center center;
27+
background-repeat: no-repeat;
28+
background-size: 16px;
29+
height: 35px;
30+
justify-content: center;
31+
margin-right: 4px;
32+
min-width: 28px;
33+
text-decoration: none;
34+
}
35+
36+
.action-label.codicon {
37+
color: inherit;
38+
line-height: 35px;
39+
}
40+
41+
.disabled {
42+
cursor: default;
43+
opacity: 0.4;
44+
pointer-events: none;
45+
}
46+
}

src/extensions/activityBar/index.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ function initActivityBar(extensionCtx: IExtensionService) {
77
name: 'Settings',
88
iconName: 'codicon-settings-gear',
99
type: 'global',
10+
contextMenu: [{
11+
id: 'CommandPalette',
12+
name: 'Command Palette...',
13+
title: 'Command Palette'
14+
}, {
15+
id: 'Settings',
16+
name: 'Settings',
17+
title: 'Settings'
18+
}, {
19+
id: 'ColorTheme',
20+
name: 'Color Theme',
21+
title: 'Color Theme'
22+
}]
1023
};
1124

1225
const globalUserAccount: IActivityBarItem = {
@@ -29,6 +42,7 @@ function initActivityBar(extensionCtx: IExtensionService) {
2942
const target = data[0].target;
3043
console.log('activityBar onSelect:', data, target);
3144
});
45+
3246
}
3347

3448
export const ExtendActivityBar: IExtension = {

src/extensions/explore/index.tsx

+27-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as React from 'react';
22
import {
33
activityBarService,
4-
ActivityBarEvent,
54
IActivityBarItem,
65
sidebarService,
76
} from 'mo';
@@ -10,40 +9,47 @@ import { Explorer } from './explore';
109
import { ExtensionService } from 'mo/services/extensionService';
1110
import { IExtension } from 'mo/model/extension';
1211

13-
function initActivityBar(extensionCtx: ExtensionService) {
14-
const activeId = 'active-explorer';
12+
function init(extensionCtx: ExtensionService) {
1513
const state = activityBarService.getState();
16-
const folderFeat: IActivityBarItem = {
17-
id: activeId,
14+
const sideBarState = sidebarService.getState();
15+
16+
const exploreActiveItem = {
17+
id: 'active-explorer',
1818
name: 'Explore',
1919
iconName: 'codicon-files',
2020
};
21-
// activityBarService.push(folderFeat);
22-
// state.data?.push(folderFeat);
23-
// state.selected = activeId;
24-
activityBarService.updateState({
25-
selected: activeId,
26-
data: [...state.data, folderFeat],
27-
});
2821

29-
activityBarService.subscribe(ActivityBarEvent.OnClick, (data) => {
30-
console.log('Explore activityBar subscribe onClick:', data);
22+
activityBarService.updateState({
23+
selected: exploreActiveItem.id,
24+
data: [...state.data, exploreActiveItem],
3125
});
32-
}
3326

34-
function initSidebar(extensionCtx: ExtensionService) {
35-
sidebarService.push({
27+
const explorePane = {
3628
id: 'explore',
37-
name: 'EXPLORER',
29+
title: 'EXPLORER',
3830
render() {
3931
return <Explorer />;
4032
},
41-
});
33+
};
34+
35+
// sidebarService.push(explorePane);
36+
sidebarService.updateState({
37+
current: explorePane.id,
38+
panes: [...sideBarState.panes, explorePane]
39+
})
40+
41+
activityBarService.onSelect((e, item: IActivityBarItem) => {
42+
console.log('Search Pane onClick:', e, item);
43+
if (item.id === exploreActiveItem.id) {
44+
sidebarService.updateState({
45+
current: explorePane.id
46+
})
47+
}
48+
})
4249
}
4350

4451
export const ExtendExplore: IExtension = {
4552
activate: function (extensionCtx: ExtensionService) {
46-
initActivityBar(extensionCtx);
47-
initSidebar(extensionCtx);
53+
init(extensionCtx);
4854
},
4955
};

src/extensions/search/index.tsx

+32-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,38 @@
1-
import { activityBarService, IExtensionService } from 'mo';
1+
import * as React from 'react';
2+
import { activityBarService, sidebarService, IExtensionService, IActivityBarItem } from 'mo';
23
import { IExtension } from 'mo/model/extension';
4+
import SearchPane from './searchPane';
5+
6+
function init() {
7+
const searchSidePane = {
8+
id: 'searchPane',
9+
title: 'SEARCH',
10+
render() {
11+
return <SearchPane />
12+
}
13+
};
14+
15+
sidebarService.push(searchSidePane)
16+
17+
const searchActivityItem = {
18+
id: 'search',
19+
name: 'Search',
20+
iconName: 'codicon-search',
21+
};
22+
23+
activityBarService.push(searchActivityItem);
24+
25+
activityBarService.onSelect((e, item: IActivityBarItem) => {
26+
if (item.id === searchActivityItem.id) {
27+
sidebarService.updateState({
28+
current: searchSidePane.id
29+
})
30+
}
31+
})
32+
}
333

434
export const ExtendSearch: IExtension = {
535
activate(extensionCtx: IExtensionService) {
6-
const searchFeat = {
7-
id: 'search',
8-
name: 'Search',
9-
iconName: 'codicon-search',
10-
};
11-
12-
activityBarService.push(searchFeat);
36+
init();
1337
},
1438
};

src/extensions/search/searchPane.tsx

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import * as React from 'react';
2+
import Toolbar from 'mo/components/toolbar';
3+
import { prefixClaName } from 'mo/common/className';
4+
import { Header, Content } from 'mo/workbench/sidebar';
5+
6+
interface ISearchPaneToolBar {}
7+
8+
const initialState = {
9+
input: '',
10+
toolbar: [{
11+
id: 'Refresh',
12+
title: 'Refresh',
13+
disabled: true,
14+
iconName: 'codicon-refresh'
15+
}, {
16+
id: 'Clear',
17+
disabled: true,
18+
title: 'Clear all',
19+
iconName: 'codicon-clear-all'
20+
}, {
21+
id: 'Collapse',
22+
title: 'Collapse all',
23+
disabled: true,
24+
iconName: 'codicon-collapse-all'
25+
}]
26+
}
27+
28+
type State = typeof initialState;
29+
30+
export default class SearchPane extends React.Component<ISearchPaneToolBar, State> {
31+
32+
state: State;
33+
34+
constructor(props) {
35+
super(props);
36+
this.state = initialState;
37+
}
38+
39+
onClick = (e, item) => {
40+
console.log('onClick:', e, item );
41+
}
42+
43+
onInput = (e) => {
44+
const nextToolBar = [...this.state.toolbar];
45+
46+
const value = e.target.value;
47+
if (!value) {
48+
nextToolBar.forEach(item => {
49+
item.disabled = true
50+
});
51+
} else {
52+
nextToolBar.forEach(item => {
53+
item.disabled = false
54+
});
55+
}
56+
this.setState({
57+
input: value,
58+
toolbar: nextToolBar
59+
})
60+
}
61+
62+
render() {
63+
const { toolbar } = this.state;
64+
return (
65+
<div className={prefixClaName('search-pane', 'sidebar')}>
66+
<Header title={'Search'} toolbar={
67+
<Toolbar data={toolbar} onClick={this.onClick} />
68+
} />
69+
<Content>
70+
<h1>Search Pane</h1>
71+
<p>{this.state.input}</p>
72+
<input onInput={this.onInput}/>
73+
</Content>
74+
</div>
75+
)
76+
}
77+
}

0 commit comments

Comments
 (0)