Explore and Search refactor

This commit is contained in:
Paul Clue 2022-12-13 19:13:03 -05:00
parent 4d6b5bd2e9
commit 7ea0815428
5 changed files with 164 additions and 95 deletions

View file

@ -20,6 +20,7 @@ const SubNavigation = props => (
'sub-nav-align-right': props.align === 'right'
}
)}
role={props.role}
>
{props.children}
</div>
@ -27,6 +28,7 @@ const SubNavigation = props => (
SubNavigation.propTypes = {
align: PropTypes.string,
role: PropTypes.string,
children: PropTypes.node,
className: PropTypes.string
};

View file

@ -1,56 +1,92 @@
const classNames = require('classnames');
const PropTypes = require('prop-types');
const { useRef } = require('react');
const {useRef} = require('react');
const React = require('react');
const SubNavigation = require('../../components/subnavigation/subnavigation.jsx');
require('./tabs.scss');
const TabItem = ({ children, ...props }) => {
const tabItemRef = useRef()
return <li ref={tabItemRef} {...props}>{children}</li>
}
/*
* Container for a custom, horizontal list of navigation elements
* that can be displayed within a view or component.
*/
const Tabs = ({ items, activeTabName }) => {
let activeIndex
const itemsRendered = items.map(({ name, onTrigger, getContent }, index) => {
const isActive = name === activeTabName
activeIndex = index
const Tabs = ({items, activeTabName}) => {
const tabElementRefs = useRef({});
const itemsRendered = items.map(({name, onTrigger, getContent}) => {
const isActive = name === activeTabName;
let tabRef;
if (tabElementRefs.current[name]) {
tabRef = tabElementRefs.current[name];
} else {
tabRef = React.createRef();
tabElementRefs.current[name] = tabRef;
}
return (
<li
<button
role="tab"
aria-selected={`${isActive ? 'true' : 'false'}`}
className={`${isActive ? 'active' : ''}`}
onClick={onTrigger}
tabIndex={isActive ? 0 : -1}
key={name}
ref={tabRef}
>
{getContent(isActive)}
</li>
)
})
</button>
);
});
const handleKeyDown = event => {
if (!['ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(event.key)) {
return
return;
}
event.preventDefault()
console.log(
'hi'
)
}
event.preventDefault();
const focusedIndex = Object.values(tabElementRefs.current)
.findIndex(tabElementRef =>
document.activeElement === tabElementRef.current
);
if (event.key === 'ArrowLeft') {
let nextIndex;
if (focusedIndex === 0) {
nextIndex = Object.values(tabElementRefs.current).length - 1;
} else {
nextIndex = focusedIndex - 1;
}
Object.values(tabElementRefs.current)[nextIndex].current.focus();
} else if (event.key === 'ArrowRight') {
let nextIndex;
if (focusedIndex === Object.values(tabElementRefs.current).length - 1) {
nextIndex = 0;
} else {
nextIndex = focusedIndex + 1;
}
Object.values(tabElementRefs.current)[nextIndex].current.focus();
} else if (event.key === 'Home') {
Object.values(tabElementRefs.current)[0].current.focus();
} else if (event.key === 'End') {
const lastTab = Object.values(tabElementRefs.current).length - 1;
Object.values(tabElementRefs.current)[lastTab].current.focus();
} else if (event.key === 'Enter' || event.key === ' ') {
items[focusedIndex].onTrigger();
}
};
return (
<div className="tab-background" onKeyDown={handleKeyDown}>
<SubNavigation className="tabs">
<div
className="tab-background"
onKeyDown={handleKeyDown}// eslint-disable-line
>
<SubNavigation
role="tablist"
className="tabs"
>
{itemsRendered}
</SubNavigation>
</div>
)
);
};
Tabs.propTypes = {
@ -61,7 +97,7 @@ Tabs.propTypes = {
getContent: PropTypes.func.isRequired
})
).isRequired,
activeTabName: PropTypes.string.isRequired,
activeTabName: PropTypes.string.isRequired
};
module.exports = Tabs;

View file

@ -14,13 +14,14 @@
justify-content: center;
}
.tabs li {
.tabs button {
margin: 0;
border: 0;
border-radius: 0;
width: $cols2;
text-align: center;
color: $header-gray;
background-color: transparent;
&.active {
border-bottom: 3px solid $ui-aqua;

View file

@ -26,7 +26,7 @@ class Explore extends React.Component {
'getExploreState',
'handleGetExploreMore',
'handleChangeSortMode',
'getBubble',
'getBubble'
]);
this.state = this.getExploreState();
@ -129,21 +129,24 @@ class Explore extends React.Component {
{
name: 'projects',
onTrigger: () => {
window.location = `${window.location.origin}/explore/projects/${this.state.category}/${this.state.mode}`;
window.location = `${window.location.origin}/explore/projects/` +
`${this.state.category}/${this.state.mode}`;
},
getContent: (isActive) => (
getContent: isActive => (
<div>
{isActive ? (
<img
className="tab-icon projects"
src="/svgs/tabs/projects-active.svg"
/>
) : (
<img
className="tab-icon projects"
src="/svgs/tabs/projects-inactive.svg"
/>
)
<img
className="tab-icon projects"
src="/svgs/tabs/projects-active.svg"
alt=""
/>
) : (
<img
className="tab-icon projects"
src="/svgs/tabs/projects-inactive.svg"
alt=""
/>
)
}
<FormattedMessage id="general.projects" />
</div>
@ -152,28 +155,31 @@ class Explore extends React.Component {
{
name: 'studios',
onTrigger: () => {
window.location = `${window.location.origin}/explore/studios/${this.state.category}/${this.state.mode}`;
window.location = `${window.location.origin}/explore/studios/` +
`${this.state.category}/${this.state.mode}`;
},
getContent: (isActive) => (
getContent: isActive => (
<div>
{isActive ? (
<img
className="tab-icon studios"
src="/svgs/tabs/studios-active.svg"
/>
) : (
<img
className="tab-icon studios"
src="/svgs/tabs/studios-inactive.svg"
/>
)
<img
className="tab-icon studios"
src="/svgs/tabs/studios-active.svg"
alt=""
/>
) : (
<img
className="tab-icon studios"
src="/svgs/tabs/studios-inactive.svg"
alt=""
/>
)
}
<FormattedMessage id="general.studios" />
</div>
)
}
]}
activeTabName={ this.state.itemType }
activeTabName={this.state.itemType}
/>
<div className="sort-controls">
<SubNavigation className="categories">

View file

@ -30,8 +30,7 @@ class Search extends React.Component {
bindAll(this, [
'getSearchState',
'handleChangeSortMode',
'handleGetSearchMore',
'getTab'
'handleGetSearchMore'
]);
this.state = this.getSearchState();
this.state.loaded = [];
@ -150,38 +149,6 @@ class Search extends React.Component {
});
});
}
getTab (type) {
const termText = this.encodeSearchTerm();
let targetUrl = `/search/${type}`;
if (termText) {
targetUrl += `?q=${termText}`;
}
let allTab = (
<a href={targetUrl}>
<li>
<img
className={`tab-icon ${type}`}
src={`/svgs/tabs/${type}-inactive.svg`}
/>
<FormattedMessage id={`general.${type}`} />
</li>
</a>
);
if (this.state.tab === type) {
allTab = (
<a href={targetUrl}>
<li className="active">
<img
className={`tab-icon ${type}`}
src={`/svgs/tabs/${type}-active.svg`}
/>
<FormattedMessage id={`general.${type}`} />
</li>
</a>
);
}
return allTab;
}
getProjectBox () {
const results = (
<Grid
@ -227,10 +194,67 @@ class Search extends React.Component {
</h1>
</div>
</TitleBanner>
<Tabs>
{this.getTab('projects')}
{this.getTab('studios')}
</Tabs>
<Tabs
items={[
{
name: 'projects',
onTrigger: () => {
const termText = this.encodeSearchTerm();
let targetUrl = `/search/projects`;
if (termText) targetUrl += `?q=${termText}`;
window.location = targetUrl;
},
getContent: isActive => (
<div>
{isActive ? (
<img
className="tab-icon projects"
src="/svgs/tabs/projects-active.svg"
alt=""
/>
) : (
<img
className="tab-icon projects"
src="/svgs/tabs/projects-inactive.svg"
alt=""
/>
)
}
<FormattedMessage id="general.projects" />
</div>
)
},
{
name: 'studios',
onTrigger: () => {
const termText = this.encodeSearchTerm();
let targetUrl = `/search/studios`;
if (termText) targetUrl += `?q=${termText}`;
window.location = targetUrl;
},
getContent: isActive => (
<div>
{isActive ? (
<img
className="tab-icon studios"
src="/svgs/tabs/studios-active.svg"
alt=""
/>
) : (
<img
className="tab-icon studios"
src="/svgs/tabs/studios-inactive.svg"
alt=""
/>
)
}
<FormattedMessage id="general.studios" />
</div>
)
}
]}
activeTabName={this.state.tab}
/>
<div className="sort-controls">
<Form className="sort-mode">
<Select