Searchbar (#1132)
* search bar function * Fixes #231, adds searchbar to sketchlist * Fixes #231, update requested changes to searchbar * Fixes #231, reset search term after modal closed
This commit is contained in:
parent
973bf7e98d
commit
3d779734c3
15 changed files with 232 additions and 6 deletions
|
@ -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';
|
||||
|
|
13
client/images/magnifyingglass.svg
Normal file
13
client/images/magnifyingglass.svg
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M57.281,62.129c-4.16,0.4-8.32-0.721-11.92-3.2l-2.56,8.24l-8.24,9.841c-0.72,0.879-1.76,1.119-2.8,1.199
|
||||
c-2.56,0.24-4.96-1.92-5.2-4.4c-0.08-1.039,0.08-2.16,0.72-2.959l8.16-9.841l7.76-4c-3.12-3.04-4.88-7.121-5.28-11.201
|
||||
c-0.8-9.68,6.64-18.32,16.24-19.2c9.601-0.8,18.4,6.56,19.28,16.16c0.4,4.64-0.88,9.281-4,13.041
|
||||
C66.242,59.568,61.842,61.729,57.281,62.129z M56.722,55.328c5.84-0.56,10.4-5.92,9.84-12c-0.479-5.84-6-10.4-11.76-9.84
|
||||
c-6,0.48-10.48,5.92-10,11.76c0.24,2.88,1.52,5.6,3.84,7.52C51.041,54.688,53.922,55.568,56.722,55.328z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
|
@ -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('');
|
||||
}
|
||||
|
|
91
client/modules/IDE/components/Searchbar.jsx
Normal file
91
client/modules/IDE/components/Searchbar.jsx
Normal file
|
@ -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 (
|
||||
<div className="searchbar">
|
||||
<button
|
||||
type="submit"
|
||||
className="searchbar__button"
|
||||
onClick={this.handleSearchEnter}
|
||||
>
|
||||
<InlineSVG className="searchbar__icon" src={searchIcon} />
|
||||
</button>
|
||||
<input
|
||||
className="searchbar__input"
|
||||
type="text"
|
||||
value={searchValue}
|
||||
placeholder="Search files..."
|
||||
onChange={this.handleSearchChange}
|
||||
onKeyUp={this.handleSearchEnter}
|
||||
/>
|
||||
<button
|
||||
className="searchbar__clear-button"
|
||||
onClick={this.handleResetSearch}
|
||||
>clear
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
|
@ -30,7 +30,6 @@ class SketchListRowBase extends React.Component {
|
|||
isFocused: false
|
||||
};
|
||||
}
|
||||
|
||||
onFocusComponent = () => {
|
||||
this.setState({ isFocused: true });
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
>
|
||||
<Searchbar />
|
||||
<SketchList
|
||||
username={this.props.params.username}
|
||||
user={this.props.user}
|
||||
|
|
|
@ -13,6 +13,7 @@ const initialState = {
|
|||
shareModalProjectId: null,
|
||||
shareModalProjectName: null,
|
||||
shareModalProjectUsername: null,
|
||||
sketchlistModalVisible: false,
|
||||
editorOptionsVisible: false,
|
||||
keyboardShortcutVisible: false,
|
||||
unsavedChanges: false,
|
||||
|
|
14
client/modules/IDE/reducers/search.js
Normal file
14
client/modules/IDE/reducers/search.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import * as ActionTypes from '../../../constants';
|
||||
|
||||
const initialState = {
|
||||
searchTerm: ''
|
||||
};
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case ActionTypes.SET_SEARCH_TERM:
|
||||
return { ...state, searchTerm: action.query };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -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) => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
flex-flow: column;
|
||||
max-height: 80%;
|
||||
max-width: 65%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.overlay__header {
|
||||
|
|
61
client/styles/components/_searchbar.scss
Normal file
61
client/styles/components/_searchbar.scss
Normal file
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue