diff --git a/package.json b/package.json
index 04521ca0bf73..d89eefc14c83 100644
--- a/package.json
+++ b/package.json
@@ -46,16 +46,17 @@
},
"dependencies": {
"@kadira/react-split-pane": "^1.4.0",
- "redux": "^3.5.2",
- "mantra-core": "^1.6.1",
"babel-runtime": "^6.5.0",
"deep-equal": "^1.0.1",
"fuzzysearch": "^1.0.3",
"json-stringify-safe": "^5.0.1",
"keycode": "^2.1.1",
"lodash.pick": "^4.2.1",
+ "mantra-core": "^1.6.1",
"qs": "^6.2.0",
- "react-modal": "^1.2.1"
+ "react-fuzzy": "^0.2.2",
+ "react-modal": "^1.2.1",
+ "redux": "^3.5.2"
},
"main": "dist/index.js",
"engines": {
diff --git a/src/libs/key_events.js b/src/libs/key_events.js
index 4a3b674bdfce..95ce146e9c8b 100755
--- a/src/libs/key_events.js
+++ b/src/libs/key_events.js
@@ -8,6 +8,7 @@ export const features = {
ESCAPE: 5,
NEXT_STORY: 6,
PREV_STORY: 7,
+ SEARCH: 8,
};
export function isModifierPressed(e) {
@@ -39,6 +40,9 @@ export default function handle(e) {
case keycode('left'):
e.preventDefault();
return features.PREV_STORY;
+ case keycode('P'):
+ e.preventDefault();
+ return features.SEARCH;
default:
return false;
}
diff --git a/src/modules/shortcuts/configs/reducers/shortcuts.js b/src/modules/shortcuts/configs/reducers/shortcuts.js
index 69cf34515eb1..9febefeb1c67 100755
--- a/src/modules/shortcuts/configs/reducers/shortcuts.js
+++ b/src/modules/shortcuts/configs/reducers/shortcuts.js
@@ -5,6 +5,7 @@ const defaultState = {
goFullScreen: false,
showLeftPanel: true,
showDownPanel: true,
+ showSearchBox: false,
};
export function keyEventToState(state, event) {
@@ -15,6 +16,8 @@ export function keyEventToState(state, event) {
return { showDownPanel: !state.showDownPanel };
case features.LEFT_PANEL:
return { showLeftPanel: !state.showLeftPanel };
+ case features.SEARCH:
+ return { showSearchBox: !state.showSearchBox };
default:
return {};
}
diff --git a/src/modules/ui/components/search_box.js b/src/modules/ui/components/search_box.js
new file mode 100644
index 000000000000..14f2c98475ed
--- /dev/null
+++ b/src/modules/ui/components/search_box.js
@@ -0,0 +1,99 @@
+import React from 'react';
+import FuzzySearch from 'react-fuzzy';
+
+import { features } from '../../../libs/key_events';
+import { baseFonts } from './theme';
+
+const searchBoxStyle = {
+ position: 'absolute',
+ backgroundColor: '#FFF',
+ top: '100px',
+ left: '50%',
+ marginLeft: '-215px',
+ ...baseFonts
+};
+
+const formatStories = function (stories) {
+ const formattedStories = [];
+ let i = 0;
+ stories.forEach((val) => {
+ formattedStories.push({
+ type: 'kind',
+ value: val.kind,
+ id: i++,
+ });
+
+ val.stories.forEach((story) => {
+ formattedStories.push({
+ type: 'story',
+ value: story,
+ id: i++,
+ kind: val.kind,
+ });
+ });
+ });
+
+ return formattedStories;
+};
+
+const suggestionTemplate = function (props, state, styles) {
+ return state.results.map((val, i) => {
+ const style = state.selectedIndex === i ? styles.selectedResultStyle : styles.resultsStyle;
+ return (
+
+ {val.value}
+
+ {val.type === 'story' ? `in ${val.kind}` : 'Kind'}
+
+
+ );
+ });
+};
+
+export default class SearchBox extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onSelect = this.onSelect.bind(this);
+ this.fireOnStory = this.fireOnStory.bind(this);
+ this.fireOnKind = this.fireOnKind.bind(this);
+ }
+
+ onSelect(selected) {
+ const { handleEvent } = this.props;
+ if (selected.type === 'story') this.fireOnStory(selected.value, selected.kind);
+ else this.fireOnKind(selected.value);
+ handleEvent(features.SEARCH);
+ }
+
+ fireOnKind(kind) {
+ const { onSelectStory } = this.props;
+ if (onSelectStory) onSelectStory(kind, null);
+ }
+
+ fireOnStory(story, kind) {
+ const { onSelectStory } = this.props;
+ if (onSelectStory) onSelectStory(kind, story);
+ }
+
+ render() {
+ return (
+
+ {this.props.showSearchBox && }
+
+ );
+ }
+}
+
+SearchBox.propTypes = {
+ showSearchBox: React.PropTypes.bool.isRequired,
+ stories: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
+ onSelectStory: React.PropTypes.func.isRequired,
+ handleEvent: React.PropTypes.func.isRequired,
+};
diff --git a/src/modules/ui/components/shortcuts_help.js b/src/modules/ui/components/shortcuts_help.js
index f05d78fe90df..a3253d38f1ca 100755
--- a/src/modules/ui/components/shortcuts_help.js
+++ b/src/modules/ui/components/shortcuts_help.js
@@ -34,6 +34,11 @@ const modalStyles = {
export const Content = () => (
Keyboard Shortcuts
+
+ ⌘ ⇧ P /
+ ⌃ ⇧ P
+ Toggle SearchBox
+
⌘ ⇧ F /
⌃ ⇧ F
diff --git a/src/modules/ui/containers/layout.js b/src/modules/ui/containers/layout.js
index df8bcfd74551..fc6e44c1c301 100755
--- a/src/modules/ui/containers/layout.js
+++ b/src/modules/ui/containers/layout.js
@@ -4,8 +4,12 @@ import pick from 'lodash.pick';
import reduxComposer from '../libs/redux_composer';
export const composer = ({ shortcuts }) => {
- const data = pick(shortcuts, 'showLeftPanel', 'showDownPanel', 'goFullScreen');
- return data;
+ return pick(
+ shortcuts,
+ 'showLeftPanel',
+ 'showDownPanel',
+ 'goFullScreen'
+ );
};
export default composeAll(
diff --git a/src/modules/ui/containers/search_box.js b/src/modules/ui/containers/search_box.js
new file mode 100644
index 000000000000..6522602e6131
--- /dev/null
+++ b/src/modules/ui/containers/search_box.js
@@ -0,0 +1,18 @@
+import SearchBox from '../components/search_box';
+import { useDeps, composeAll } from 'mantra-core';
+import reduxComposer from '../libs/redux_composer';
+
+export const composer = ({ api, shortcuts }, { actions }) => {
+ const actionMap = actions();
+ return {
+ showSearchBox: shortcuts.showSearchBox,
+ stories: api.stories,
+ onSelectStory: actionMap.api.selectStory,
+ handleEvent: actionMap.shortcuts.handleEvent,
+ };
+};
+
+export default composeAll(
+ reduxComposer(composer),
+ useDeps()
+)(SearchBox);
diff --git a/src/modules/ui/routes.js b/src/modules/ui/routes.js
index 369301599769..894d55ae5fc0 100755
--- a/src/modules/ui/routes.js
+++ b/src/modules/ui/routes.js
@@ -4,10 +4,12 @@ import Layout from './containers/layout';
import LeftPanel from './containers/left_panel';
import ActionLogger from './containers/action_logger';
import ShortcutsHelp from './containers/shortcuts_help';
+import SearchBox from './containers/search_box';
export default function (injectDeps, { reduxStore, provider, domNode }) {
const InjectedLayout = injectDeps(Layout);
const InjectedShortcutsHelp = injectDeps(ShortcutsHelp);
+ const InjectedSearchBox = injectDeps(SearchBox);
// generate preview
const Preview = () => {
@@ -25,6 +27,7 @@ export default function (injectDeps, { reduxStore, provider, domNode }) {
downPanel={() => (
)}
/>
+
);
ReactDOM.render(root, domNode);