* 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:
raclim 2019-08-21 14:08:08 -04:00 committed by Cassie Tarakajian
parent 973bf7e98d
commit 3d779734c3
15 changed files with 232 additions and 6 deletions

View file

@ -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';

View 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

View file

@ -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('');
}

View 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);

View file

@ -30,7 +30,6 @@ class SketchListRowBase extends React.Component {
isFocused: false
};
}
onFocusComponent = () => {
this.setState({ isFocused: true });
}

View file

@ -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}

View file

@ -13,6 +13,7 @@ const initialState = {
shareModalProjectId: null,
shareModalProjectName: null,
shareModalProjectUsername: null,
sketchlistModalVisible: false,
editorOptionsVisible: false,
keyboardShortcutVisible: false,
unsavedChanges: false,

View 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;
}
};

View file

@ -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) => {

View file

@ -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,

View file

@ -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,

View file

@ -24,6 +24,7 @@
flex-flow: column;
max-height: 80%;
max-width: 65%;
position: relative;
}
.overlay__header {

View 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');
}
}
}

View file

@ -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() {

View file

@ -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';