Commit 220128b5 authored by Øyvind Julsrud's avatar Øyvind Julsrud Committed by Oyvind
Browse files

DEICH-5954: deichman.no: add command search

parent 5e0baffe
import { Text} from "@digibib/deichman-ui";
import { groupBy } from "lodash";
import React, { useEffect, useState } from "react";
import { commandSearch } from "../../constants/commandSearch";
import { useKeyPress } from "../../utilities/hooks/useKeyPress";
import CommandSearchListItem from "./CommandSearchListItem";
import "./styles.css";
const CommandSearch = ({
searchText,
onClickMenuItem,
isTypingCommandSearch
}) => {
const forwardSlash = useKeyPress("/");
const [isShowing, setIsShowing] = useState(isTypingCommandSearch);
const [searchList, setSearchList] = useState(commandSearch);
const [commandSearchText, setCommandSearchText] = useState("");
const groupedSearchObject = groupBy(searchList, "category");
const groupedSearchList = Object.keys(groupedSearchObject);
const filterSearch = searchText => {
const searchTextWithoutSlash = searchText.substring(1);
const newSearchList = [...commandSearch].filter(({ key, keyCode }) => {
if (keyCode.indexOf(searchText) > -1) {
return true;
}
if (key.indexOf(searchTextWithoutSlash) > -1) {
return true;
}
});
setSearchList(newSearchList);
};
useEffect(
() => {
if (forwardSlash) {
setIsShowing(true);
}
if (isTypingCommandSearch) {
const newSearchText = searchText.substring(searchText.indexOf("/"));
setCommandSearchText(newSearchText);
filterSearch(newSearchText);
}
if (!searchText) {
setIsShowing(false);
}
},
[forwardSlash, searchText, isTypingCommandSearch]
);
return (
<>
{isShowing && (
<div className="command-search">
{groupedSearchList.length === 0 && (
<Text bold>Ingen treff</Text>
)}
{groupedSearchList.map(key => {
return (
<CommandSearchListItem
key={key}
items={groupedSearchObject[key]}
title={key}
onClickMenuItem={onClickMenuItem}
commandSearchText={commandSearchText}
/>
);
})}
</div>
)}
</>
);
};
export default CommandSearch;
import { Text } from "@digibib/deichman-ui";
import React from "react";
import { useKeyPress } from "../../utilities/hooks/useKeyPress";
const CommandSearchListItem = ({
items,
title,
onClickMenuItem,
commandSearchText
}) => {
const enter = useKeyPress("Enter");
const handleMenuItemOnClick = (value, commandSearchText, e) => {
return e => {
if (!e.key || enter) {
onClickMenuItem(value, commandSearchText);
}
};
};
return (
<>
<div className="command-search__items">
<Text uppercase>{title}</Text>
{items.map(({ key, keyCode, value }) => {
return (
<div
className="command-search__item"
onClick={handleMenuItemOnClick(value, commandSearchText)}
onKeyPress={handleMenuItemOnClick(value, commandSearchText)}
key={value}
tabIndex="0"
>
<div>
<b>{keyCode}</b>
</div>
<div>
<Text gray>{key}</Text>
</div>
</div>
);
})}
</div>
</>
);
};
export default CommandSearchListItem;
.command-search {
height: 80vh;
overflow-y: auto;
position: absolute;
background-color: var(--col-white);
color: black;
border-radius: var(--border-radius);
width: calc(100vw - var(--spacing-4));
max-width: 600px;
box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.25);
transform: translateY(-1.25rem);
left: calc(var(--spacing-6) * -1);
position: absolute;
top: var(--spacing-8);
margin-top: var(--spacing-4);
padding: var(--spacing-4) var(--spacing-4);
@media (--medium) {
margin-top: var(--spacing-6);
left: 0;
width: 100%;
}
.command-search__items {
padding: var(--spacing-4) 0;
}
.command-search__item {
display: flex;
align-items: center;
justify-content: space-between;
&:hover {
cursor: pointer;
background-color: var(--col-gray-1);
}
}
}
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Icon } from "@digibib/deichman-ui";
import autoBind from "auto-bind";
import Router from "next/router";
import PropTypes from "prop-types";
import React, { Component } from "react";
import { connect } from "react-redux";
import Autocomplete from "../Autocomplete/Autocomplete";
import CommandSearch from "../CommandSearch/CommandSearch";
import { createTracker } from "../tracker/Autocomplete";
import { Icon } from "@digibib/deichman-ui";
import "./styles.css";
class Search extends Component {
......@@ -90,9 +89,25 @@ class Search extends Component {
});
}
handleCommandSearchClick(value, commandSearchText) {
const text = this.state.value.replace(commandSearchText.trim(), value);
const textPosition = text.length - 1;
this.searchInputField.current.focus();
// set cursor to correct position, (key: "|")
window.setTimeout(() => {
this.searchInputField.current.setSelectionRange(
textPosition,
textPosition
);
});
this.setState({ value: text });
}
render() {
const { value, userHasTyped } = this.state;
const isTypingCommandSearch = value?.includes("/");
const { currentQuery, searchApi } = this.props;
let previousSearch = currentQuery || value;
......@@ -134,18 +149,27 @@ class Search extends Component {
data-cy="header-search-input"
/>
</div>
<Autocomplete
name="searchQuery"
value={valueToDisplay}
customClassNames="search__autocomplete"
tracker={this.autocompleteTracker}
onChange={v => {
this.onChange(v);
this.onSubmit(v);
}}
inputRef={this.searchInputField}
hasUserTyped={this.state.userHasTyped}
/>
{isTypingCommandSearch && (
<CommandSearch
searchText={this.state.value}
onClickMenuItem={this.handleCommandSearchClick}
isTypingCommandSearch={isTypingCommandSearch}
/>
)}
{!isTypingCommandSearch && (
<Autocomplete
name="searchQuery"
value={valueToDisplay}
customClassNames="search__autocomplete"
tracker={this.autocompleteTracker}
onChange={v => {
this.onChange(v);
this.onSubmit(v);
}}
inputRef={this.searchInputField}
hasUserTyped={this.state.userHasTyped}
/>
)}
</div>
</form>
</>
......
export const commandSearch = [
{
key: "tittel",
keyCode: "/ti",
value: `tittel: ""`,
category: "Tittel"
},
{
key: "hovedtittel",
keyCode: "/ht",
value: `hovedtittel: ""`,
category: "Tittel"
},
{
key: "deltittel",
keyCode: "/dt",
value: `deltittel: ""`,
category: "Tittel"
},
{
key: "delnummer",
keyCode: "/dn",
value: `delnummer: ""`,
category: "Tittel"
},
{
key: "del",
keyCode: "/del",
value: `del: ""`,
category: "Tittel"
},
{
key: "serie",
keyCode: "/serie",
value: `serie: ""`,
category: "Tittel"
},
{
key: "forfatter",
keyCode: "/fo",
value: `forfatter: ""`,
category: "Person/forfatter"
},
{
key: "oversetter",
keyCode: "/oversetter",
value: `oversetter: ""`,
category: "Person/forfatter"
},
{
key: "redaktør",
keyCode: "/red",
value: `redaktør: ""`,
category: "Person/forfatter"
},
{
key: "illustratør",
keyCode: "/ill",
value: `illustratør: ""`,
category: "Person/forfatter"
},
{
key: "fotograf",
keyCode: "/foto",
value: `fotograf: ""`,
category: "Person/forfatter"
},
{
key: "innleser",
keyCode: "/innleser",
value: `innleser: ""`,
category: "Person/forfatter"
},
{
key: "produsent",
keyCode: "/produsent",
value: `produsent: ""`,
category: "Person/forfatter"
},
{
key: "regissør",
keyCode: "/regissør",
value: `regissør: ""`,
category: "Person/forfatter"
},
{
key: "manusforfatter",
keyCode: "/manusforfatter",
value: `manusforfatter: ""`,
category: "Person/forfatter"
},
{
key: "skuespiller",
keyCode: "/skuespiller",
value: `skuespiller: ""`,
category: "Person/forfatter"
},
{
key: "tekstforfatter",
keyCode: "/tekstforfatter",
value: `tekstforfatter: ""`,
category: "Person/forfatter"
},
{
key: "komponist",
keyCode: "/komp",
value: `komponist: ""`,
category: "Person/forfatter"
},
{
key: "utøver",
keyCode: "/utøver",
value: `utøver: ""`,
category: "Person/forfatter"
},
{
key: "komarrangørponist",
keyCode: "/arrangør",
value: `arrangør: ""`,
category: "Person/forfatter"
},
{
key: "dirigent",
keyCode: "/dirigent",
value: `dirigent: ""`,
category: "Person/forfatter"
},
{
key: "koreograf",
keyCode: "/koreograf",
value: `koreograf: ""`,
category: "Person/forfatter"
},
{
key: "emne",
keyCode: "/em",
value: `emne: ""`,
category: "Emnesøk"
},
{
key: "hylleplassering",
keyCode: "/kd",
value: `hylleplassering: ""`,
category: "Emnesøk"
},
{
key: "deweynummer",
keyCode: "/kl",
value: `deweynummer: ""`,
category: "Emnesøk"
},
{
key: "sjanger",
keyCode: "/sjanger",
value: `sjanger: ""`,
category: "Sjanger"
},
{
key: "form",
keyCode: "/form",
value: `form: ""`,
category: "Form"
},
{
key: "land",
keyCode: "/land",
value: `land: ""`,
category: "Land"
},
{
key: "nasjonalitet",
keyCode: "/nasjonalitet",
value: `nasjonalitet: ""`,
category: "Land"
},
{
key: "språkkode",
keyCode: "/spr",
value: `språkkode: ""`,
category: "Språk"
},
{
key: "originalspråk",
keyCode: "/ospr",
value: `originalspråk: ""`,
category: "Språk"
},
{
key: "undertekst",
keyCode: "/tekst",
value: `undertekst: ""`,
category: "Språk"
},
{
key: "aldersgrense",
keyCode: "/ag",
value: `aldersgrense: ""`,
category: "Aldersgrense"
},
{
key: "utgivelsesår",
keyCode: "/år",
value: `aldersgrense: ""`,
category: "Utgiver/Utgivelsesår"
},
{
key: "første gang utgitt",
keyCode: "/oår",
value: `første gang utgitt: ""`,
category: "Utgiver/Utgivelsesår"
},
{
key: "utgiver",
keyCode: "/utgiver",
value: `utgiver: ""`,
category: "Utgiver/Utgivelsesår"
},
];
import { useEffect, useState } from "react";
export const useKeyPress = targetKey => {
const [keyPressed, setKeyPressed] = useState(false);
const downHandler = ({ key }) => {
if (key === targetKey) {
setKeyPressed(true);
}
};
const upHandler = ({ key }) => {
if (key === targetKey) {
setKeyPressed(false);
}
};
useEffect(() => {
// Add event listeners on mount
window.addEventListener("keydown", downHandler);
window.addEventListener("keyup", upHandler);
// Remove event listeners on cleanup/unmount
return () => {
window.removeEventListener("keydown", downHandler);
window.removeEventListener("keyup", upHandler);
};
}, []);
return keyPressed;
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment