Skip to content

Commit

Permalink
Webinars page (#2450)
Browse files Browse the repository at this point in the history
* Disentangle Search Bar from Blog page

* Create use-data; use for blog-context

* Explore sections and search bar are components shared by blog and webinars

* Make Breadcrumb a component

* Latest webinars page

* Explore pages

* Search page

* Fix dependency lists

* Remove use of any

* Code review

* 2
  • Loading branch information
RoyEJohnson authored Aug 15, 2023
1 parent d2e6259 commit 4fe02e3
Show file tree
Hide file tree
Showing 53 changed files with 1,164 additions and 706 deletions.
9 changes: 9 additions & 0 deletions src/app/components/breadcrumb/breadcrumb.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.breadcrumb {
align-items: center;
font-weight: bold;
display: flex;
gap: 1rem;
margin: 3rem 0 2rem;
text-decoration: none;
width: 100%;
}
40 changes: 40 additions & 0 deletions src/app/components/breadcrumb/breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import {Link, useNavigate, useLocation} from 'react-router-dom';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faChevronLeft} from '@fortawesome/free-solid-svg-icons/faChevronLeft';
import './breadcrumb.scss';

type BreadcrumbArgs = {
name: string;
};

export default function Breadcrumb({name}: BreadcrumbArgs) {
const {pathname} = useLocation();
// Remove everything after the first slash that follows a character
const topLevel = pathname.replace(/(?<=.)\/.*/, '');
const goBack = useGoBack(topLevel);

return (
<Link to={topLevel} onClick={goBack} className='breadcrumb'>
<FontAwesomeIcon icon={faChevronLeft} />
<span>Back to Main {name}</span>
</Link>
);
}

function useGoBack(path: string) {
const navigate = useNavigate();
const {state} = useLocation();

return React.useCallback(
(e: React.MouseEvent<HTMLAnchorElement>) => {
if (state?.from === path) {
navigate(-1);
} else {
navigate(path, {replace: true});
}
e.preventDefault();
},
[navigate, path, state?.from]
);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
@import 'pattern-library/core/pattern-library/headers';

#explore-collections {
margin-top: 2rem;
width: 100%;

.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(25rem, 1fr));
gap: 3rem;
margin-top: 2rem;
width: 100%;

.card {
Expand All @@ -19,13 +15,15 @@
text-decoration: none;

.centered-image {
align-items: center;
display: flex;
justify-content: center;
padding-bottom: 1rem;
width: 100%;

img {
max-height: 14rem;
min-height: 8rem;
max-width: 100%;
}
}
Expand All @@ -37,6 +35,5 @@
text-align: center;
}
}

}
}
46 changes: 46 additions & 0 deletions src/app/components/explore-by-collection/explore-by-collection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import {Link, useLocation} from 'react-router-dom';
import {Collection} from './types';
import './explore-by-collection.scss';

export default function ExploreCollections({
collections,
analyticsNav
}: {
collections: Collection[];
analyticsNav: string;
}) {
const {pathname} = useLocation();

return (
<section id='explore-collections'>
<h2>Explore collections</h2>
<div className='cards' data-analytics-nav={analyticsNav}>
{collections.map((c) => (
<CollectionLink collection={c} key={c.id} from={pathname} />
))}
</div>
</section>
);
}

function CollectionLink({
collection,
from
}: {
collection: Collection;
from: string;
}) {
return (
<Link
to={`./explore/collections/${encodeURIComponent(collection.name)}`}
state={{from}}
className='card'
>
<div className='centered-image'>
<img src={collection.collectionImage} alt='' />
</div>
<div className='name'>{collection.name}</div>
</Link>
);
}
5 changes: 5 additions & 0 deletions src/app/components/explore-by-collection/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type Collection = {
id: string;
name: string;
collectionImage?: string;
};
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
@import 'pattern-library/core/pattern-library/headers';

#explore-by-subject {
margin-bottom: 3rem;
width: 100%;

.subject-links {
margin-top: 5rem;
display: grid;
gap: 3rem;
grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
gap: 2rem;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
width: 100%;

.card {
@extend %card;

padding-bottom: 1rem;
padding: 0 0 1rem;
margin-top: 2rem;
position: relative;
text-align: center;

Expand All @@ -37,6 +34,11 @@
}
}

a {
color: inherit;
text-decoration: none;
}

.subject-name {
@include set-font(body-large);

Expand All @@ -47,11 +49,6 @@
line-height: 2.5rem;
margin: 0.5rem 1rem;
min-height: 5rem;

a {
color: inherit;
text-decoration: none;
}
}
}
}
Expand Down
46 changes: 46 additions & 0 deletions src/app/components/explore-by-subject/explore-by-subject.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import {Link, useLocation} from 'react-router-dom';
import {Category} from './types';
import './explore-by-subject.scss';

export default function ExploreBySubject({
categories,
analyticsNav
}: {
categories: Category[];
analyticsNav: string;
}) {
const {pathname} = useLocation();

return (
<section id='explore-by-subject'>
<h2>Explore by subject</h2>
<div className='subject-links' data-analytics-nav={analyticsNav}>
{categories.map((c) => (
<SubjectLink category={c} key={c.id} from={pathname} />
))}
</div>
</section>
);
}

function SubjectLink({
category: {name, subjectIcon},
from
}: {
category: Category;
from: string;
}) {
return (
<div className='card'>
<Link to={`./explore/subjects/${encodeURIComponent(name)}`} state={{from}}>
<div className='icon-holder'>
{subjectIcon && <img src={subjectIcon} alt='' />}
</div>
<div className='subject-name'>
{name}
</div>
</Link>
</div>
);
}
5 changes: 5 additions & 0 deletions src/app/components/explore-by-subject/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type Category = {
id: string;
name: string;
subjectIcon?: string;
};
30 changes: 30 additions & 0 deletions src/app/components/explore-page/section/section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import './section.scss';

type SectionArgs = React.PropsWithChildren<{
name: string;
topicHeading?: string;
}> & React.HTMLAttributes<HTMLDivElement>;

export default function Section({name, topicHeading, children, ...divAttributes}: SectionArgs) {
return (
<section {...divAttributes}>
<SectionHeader head={name} subhead={topicHeading} />
{children}
</section>
);
}

type SectionHeaderArgs = {
head: string;
subhead?: string;
}

function SectionHeader({head, subhead}: SectionHeaderArgs) {
return (
<h2 className="section-header">
{head}
{subhead && <span className="section-subhead">{subhead}</span>}
</h2>
);
}
4 changes: 2 additions & 2 deletions src/app/components/jsx-helpers/build-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export default function buildContext({
return React.useContext(Context);
}

function ContextProvider({children, contextValueParameters}) {
function ContextProvider({children, contextValueParameters=undefined}) {
const value = useContextValue(contextValueParameters);

if (typeof value === 'undefined') {
if (value === undefined) {
return null;
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/components/jsx-helpers/loader-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function LoadedPage({
}

export default function LoaderPage({
slug, Child, props={}, preserveWrapping, doDocumentSetup=false,
slug, Child, props={}, preserveWrapping=false, doDocumentSetup=false,
noCamelCase=false
}) {
const data = usePageData(slug, preserveWrapping, noCamelCase);
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/link-with-chevron/link-with-chevron.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faChevronRight} from '@fortawesome/free-solid-svg-icons/faChevronRight';
import './link-with-chevron.scss';

export default function LinkWithChevron({children, className, ...props}) {
export default function LinkWithChevron({children, className=undefined, ...props}) {
return (
<a className={cn('link-with-chevron', className)} {...props}>
{children}{' '}
Expand Down
18 changes: 18 additions & 0 deletions src/app/components/paginator/simple-paginator.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,21 @@ export default function SimplePaginator({currentPage, setPage, totalPages}) {
</div>
);
}

export function itemRangeOnPage(page, perPage, totalCount) {
const end = Math.min(totalCount, page * perPage);
const start = (page - 1) * perPage + 1;

return [start, end];
}

export function Showing({page, perPage=9, totalCount, ofWhat}) {
const [start, end] = itemRangeOnPage(page, perPage, totalCount);
const countMessage = totalCount <= perPage ? 'all' : `${start}-${end} of`;

return (
<div className="whats-showing">
Showing {countMessage} {totalCount} {ofWhat}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import useSearchContext, {SearchContextProvider} from './search-context';
import useBlogContext from '../blog-context';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faTimes} from '@fortawesome/free-solid-svg-icons/faTimes';
import {faSearch} from '@fortawesome/free-solid-svg-icons/faSearch';
import './search-bar.scss';

function SearchInput() {
function SearchInput({amongWhat}) {
const {searchString, setSearchString, doSearch} = useSearchContext();
const onChange = React.useCallback(
(event) => {
Expand All @@ -26,7 +25,7 @@ function SearchInput() {

return (
<input
type="text" placeholder="Search all blog posts" name="search-input"
type="text" placeholder={`Search all ${amongWhat}`} name="search-input"
value={searchString} onChange={onChange} onKeyPress={searchOnEnter}
/>
);
Expand Down Expand Up @@ -73,12 +72,12 @@ function SearchButton() {
);
}

export default function SearchBar() {
export default function SearchBar({searchFor, amongWhat}) {
return (
<SearchContextProvider>
<SearchContextProvider contextValueParameters={{searchFor}}>
<div className="search-bar">
<div className="input-with-clear-button">
<SearchInput />
<SearchInput amongWhat={amongWhat} />
<ClearButton />
</div>
<SearchButton />
Expand All @@ -87,13 +86,11 @@ export default function SearchBar() {
);
}

export function HeadingAndSearchBar({children}) {
const {setPath} = useBlogContext();

export function HeadingAndSearchBar({searchFor, amongWhat, children}) {
return (
<div className="heading-and-searchbar">
{children}
<SearchBar setPath={setPath} />
<SearchBar searchFor={searchFor} amongWhat={amongWhat} />
</div>
);
}
Loading

0 comments on commit 4fe02e3

Please sign in to comment.