diff --git a/client/constants.js b/client/constants.js
index aaf7637c..f769c33e 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -121,6 +121,9 @@ export const SET_ASSETS = 'SET_ASSETS';
export const TOGGLE_DIRECTION = 'TOGGLE_DIRECTION';
export const SET_SORTING = 'SET_SORTING';
+export const SET_SORT_PARAMS = 'SET_SORT_PARAMS';
+export const SET_SEARCH_TERM = 'SET_SEARCH_TERM';
+export const CLOSE_SKETCHLIST_MODAL = 'CLOSE_SKETCHLIST_MODAL';
export const START_LOADING = 'START_LOADING';
export const STOP_LOADING = 'STOP_LOADING';
diff --git a/client/images/magnifyingglass.svg b/client/images/magnifyingglass.svg
new file mode 100644
index 00000000..38f54010
--- /dev/null
+++ b/client/images/magnifyingglass.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/client/modules/IDE/actions/sorting.js b/client/modules/IDE/actions/sorting.js
index 0e306b46..8feb9b12 100644
--- a/client/modules/IDE/actions/sorting.js
+++ b/client/modules/IDE/actions/sorting.js
@@ -25,3 +25,14 @@ export function toggleDirectionForField(field) {
field
};
}
+
+export function setSearchTerm(searchTerm) {
+ return {
+ type: ActionTypes.SET_SEARCH_TERM,
+ query: searchTerm
+ };
+}
+
+export function resetSearchTerm() {
+ return setSearchTerm('');
+}
diff --git a/client/modules/IDE/components/Searchbar.jsx b/client/modules/IDE/components/Searchbar.jsx
new file mode 100644
index 00000000..f3047b91
--- /dev/null
+++ b/client/modules/IDE/components/Searchbar.jsx
@@ -0,0 +1,91 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import InlineSVG from 'react-inlinesvg';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { throttle } from 'lodash';
+import * as SortingActions from '../actions/sorting';
+
+const searchIcon = require('../../../images/magnifyingglass.svg');
+
+class Searchbar extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ searchValue: this.props.searchTerm
+ };
+ this.throttledSearchChange = throttle(this.searchChange, 500);
+ }
+
+ componentWillUnmount() {
+ this.props.resetSearchTerm();
+ }
+
+ handleResetSearch = () => {
+ this.setState({ searchValue: '' }, () => {
+ this.props.resetSearchTerm();
+ });
+ }
+
+ handleSearchEnter = (e) => {
+ if (e.key === 'Enter') {
+ this.props.setSearchTerm(this.state.searchValue);
+ }
+ }
+
+ searchChange = (value) => {
+ this.props.setSearchTerm(this.state.searchValue);
+ };
+
+ handleSearchChange = (e) => {
+ this.setState({ searchValue: e.target.value }, () => {
+ this.throttledSearchChange(this.state.searchValue);
+ });
+ }
+
+ render() {
+ const { searchValue } = this.state;
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+Searchbar.propTypes = {
+ searchTerm: PropTypes.string.isRequired,
+ setSearchTerm: PropTypes.func.isRequired,
+ resetSearchTerm: PropTypes.func.isRequired
+};
+
+function mapStateToProps(state) {
+ return {
+ searchTerm: state.search.searchTerm
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators(Object.assign({}, SortingActions), dispatch);
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Searchbar);
diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx
index b430df14..bf68aed3 100644
--- a/client/modules/IDE/components/SketchList.jsx
+++ b/client/modules/IDE/components/SketchList.jsx
@@ -30,7 +30,6 @@ class SketchListRowBase extends React.Component {
isFocused: false
};
}
-
onFocusComponent = () => {
this.setState({ isFocused: true });
}
diff --git a/client/modules/IDE/pages/IDEView.jsx b/client/modules/IDE/pages/IDEView.jsx
index b2ae1ebb..179c9739 100644
--- a/client/modules/IDE/pages/IDEView.jsx
+++ b/client/modules/IDE/pages/IDEView.jsx
@@ -30,6 +30,7 @@ import * as ConsoleActions from '../actions/console';
import { getHTMLFile } from '../reducers/files';
import Overlay from '../../App/components/Overlay';
import SketchList from '../components/SketchList';
+import Searchbar from '../components/Searchbar';
import AssetList from '../components/AssetList';
import About from '../components/About';
import Feedback from '../components/Feedback';
@@ -371,6 +372,7 @@ class IDEView extends React.Component {
title="Open a Sketch"
previousPath={this.props.ide.previousPath}
>
+
{
+ switch (action.type) {
+ case ActionTypes.SET_SEARCH_TERM:
+ return { ...state, searchTerm: action.query };
+ default:
+ return state;
+ }
+};
diff --git a/client/modules/IDE/selectors/projects.js b/client/modules/IDE/selectors/projects.js
index 9ff655d3..b2230826 100644
--- a/client/modules/IDE/selectors/projects.js
+++ b/client/modules/IDE/selectors/projects.js
@@ -6,9 +6,27 @@ import { DIRECTION } from '../actions/sorting';
const getSketches = state => state.sketches;
const getField = state => state.sorting.field;
const getDirection = state => state.sorting.direction;
+const getSearchTerm = state => state.search.searchTerm;
+
+const getFilteredSketches = createSelector(
+ getSketches,
+ getSearchTerm,
+ (sketches, search) => {
+ if (search) {
+ const searchStrings = sketches.map((sketch) => {
+ const smallSketch = {
+ name: sketch.name
+ };
+ return { ...sketch, searchString: Object.values(smallSketch).join(' ').toLowerCase() };
+ });
+ return searchStrings.filter(sketch => sketch.searchString.includes(search.toLowerCase()));
+ }
+ return sketches;
+ }
+);
const getSortedSketches = createSelector(
- getSketches,
+ getFilteredSketches,
getField,
getDirection,
(sketches, field, direction) => {
diff --git a/client/reducers.js b/client/reducers.js
index 057dbd62..4a173a8f 100644
--- a/client/reducers.js
+++ b/client/reducers.js
@@ -10,6 +10,7 @@ import sketches from './modules/IDE/reducers/projects';
import toast from './modules/IDE/reducers/toast';
import console from './modules/IDE/reducers/console';
import assets from './modules/IDE/reducers/assets';
+import search from './modules/IDE/reducers/search';
import sorting from './modules/IDE/reducers/sorting';
import loading from './modules/IDE/reducers/loading';
@@ -21,6 +22,7 @@ const rootReducer = combineReducers({
user,
project,
sketches,
+ search,
sorting,
editorAccessibility,
toast,
diff --git a/client/styles/abstracts/_variables.scss b/client/styles/abstracts/_variables.scss
index c4a29fc8..820fb05a 100644
--- a/client/styles/abstracts/_variables.scss
+++ b/client/styles/abstracts/_variables.scss
@@ -57,7 +57,10 @@ $themes: (
input-text-color: #333,
input-border-color: #b5b5b5,
about-list-text-color: #4a4a4a,
- search-background-color: #ebebeb,
+ search-background-color: #ffffff,
+ search-clear-background-color: #e9e9e9,
+ search-hover-text-color: #ffffff,
+ search-hover-background-color: #4d4d4d,
dropdown-color: #414141,
keyboard-shortcut-color: #757575,
nav-hover-color: $p5js-pink,
@@ -106,7 +109,10 @@ $themes: (
input-text-color: #333,
input-border-color: #b5b5b5,
about-list-text-color: #f4f4f4,
- search-background-color: #ebebeb,
+ search-background-color: #ffffff,
+ search-clear-background-color: #4f4f4f,
+ search-hover-text-color: #ffffff,
+ search-hover-background-color: $p5js-pink,
dropdown-color: #dadada,
keyboard-shortcut-color: #B5B5B5,
nav-hover-color: $p5js-pink,
@@ -155,6 +161,9 @@ $themes: (
input-border-color: #b5b5b5,
about-list-text-color: #f4f4f4,
search-background-color: $white,
+ search-clear-background-color: #444,
+ search-hover-text-color: $black,
+ search-hover-background-color: $yellow,
dropdown-color: #e1e1e1,
keyboard-shortcut-color: #e1e1e1,
nav-hover-color: $yellow,
diff --git a/client/styles/components/_overlay.scss b/client/styles/components/_overlay.scss
index 2065a230..58602f5b 100644
--- a/client/styles/components/_overlay.scss
+++ b/client/styles/components/_overlay.scss
@@ -24,6 +24,7 @@
flex-flow: column;
max-height: 80%;
max-width: 65%;
+ position: relative;
}
.overlay__header {
diff --git a/client/styles/components/_searchbar.scss b/client/styles/components/_searchbar.scss
new file mode 100644
index 00000000..47a5fc84
--- /dev/null
+++ b/client/styles/components/_searchbar.scss
@@ -0,0 +1,61 @@
+.searchbar {
+ position: absolute;
+ display: flex;
+ padding-left: #{17 / $base-font-size}rem;
+ right: #{50 / $base-font-size}rem;
+ top: #{14 / $base-font-size}rem;
+}
+
+.searchbar__input {
+ width: #{240 / $base-font-size}rem;
+ height: #{36 / $base-font-size}rem;
+ border: solid 0.5px;
+ padding-left: #{36 / $base-font-size}rem;
+ padding-right: #{38 / $base-font-size}rem;
+ @include themify() {
+ border-color: getThemifyVariable('input-border-color');
+ background-color: getThemifyVariable('search-background-color');
+ }
+}
+
+.searchbar__button {
+ width: #{31 / $base-font-size}rem;
+ height: #{36 / $base-font-size}rem;
+ position: absolute;
+ padding: 0;
+ border-right: solid 1px;
+ @include themify() {
+ border-right-color: getThemifyVariable('input-border-color');
+ }
+}
+
+.searchbar__icon {
+ display: inline-block;
+ & svg {
+ width: #{22 / $base-font-size}rem;
+ height: #{27 / $base-font-size}rem;
+ transform: scaleX(-1);
+ @include themify() {
+ fill: getThemifyVariable('input-text-color');
+ }
+ }
+}
+
+.searchbar__clear-button {
+ font-weight: bold;
+ font-size: #{10 / $base-font-size}rem;
+ text-align: center;
+ border-radius: 2px;
+ align-self: center;
+ position: absolute;
+ padding: #{3 / $base-font-size}rem #{4 / $base-font-size}rem;
+ left: #{216 / $base-font-size}rem;;
+ @include themify() {
+ color: getThemifyVariable('primary-text-color');
+ background-color: getThemifyVariable('search-clear-background-color');
+ &:hover, &:focus {
+ color: getThemifyVariable('search-hover-text-color');
+ background-color: getThemifyVariable('search-hover-background-color');
+ }
+ }
+}
diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss
index dd7252ae..41fee261 100644
--- a/client/styles/components/_sketch-list.scss
+++ b/client/styles/components/_sketch-list.scss
@@ -2,7 +2,8 @@
overflow-y: auto;
max-width: 100%;
width: #{1000 / $base-font-size}rem;
- min-height: #{400 / $base-font-size}rem;
+ height: #{628 / $base-font-size}rem;
+ // min-height: #{400 / $base-font-size}rem;
}
.sketches-table {
@@ -71,7 +72,6 @@
}
}
-
.sketches-table thead {
font-size: #{12 / $base-font-size}rem;
@include themify() {
diff --git a/client/styles/main.scss b/client/styles/main.scss
index 3d9bf977..7bcca6dd 100644
--- a/client/styles/main.scss
+++ b/client/styles/main.scss
@@ -21,6 +21,7 @@
@import 'components/preferences';
@import 'components/reset-password';
@import 'components/new-password';
+@import 'components/searchbar';
@import 'components/sketch-list';
@import 'components/sidebar';
@import 'components/modal';