Unverified Commit 96a01de5 authored by Andrey Azov's avatar Andrey Azov Committed by GitHub
Browse files

Add custom landing page for Help (#531)

Includes:
- Updated the Step component to use the label field instead of title, and to accept children
- Added a custom Help landing page (hiding the bottom section in production)
- Hiding the rest of the pages of the Help app in production
- Allow users to see the help landing page in production (links on the Home page and in the launchbar)
- Fixed the styles on the About page
- Hiding the Custom Download button in the launchbar in production
parent d6b45bdd
Pipeline #178919 passed with stages
in 4 minutes and 38 seconds
...@@ -19,6 +19,13 @@ $article-right-padding: 1.5rem; ...@@ -19,6 +19,13 @@ $article-right-padding: 1.5rem;
box-shadow: 0 2px 3px $grey; box-shadow: 0 2px 3px $grey;
} }
.spinnerContainer {
display: flex;
height: 100%;
justify-content: center;
align-items: center;
}
.grid { .grid {
height: 100%; height: 100%;
padding-left: 80px; padding-left: 80px;
......
...@@ -27,10 +27,12 @@ import { ...@@ -27,10 +27,12 @@ import {
TopMenu, TopMenu,
SideMenu SideMenu
} from 'src/content/app/about/components/about-menu/AboutMenu'; } from 'src/content/app/about/components/about-menu/AboutMenu';
import { CircleLoader } from 'src/shared/components/loader/Loader';
import { Menu as MenuType } from 'src/shared/types/help-and-docs/menu'; import { Menu as MenuType } from 'src/shared/types/help-and-docs/menu';
import { TextArticleData } from 'src/shared/types/help-and-docs/article'; import { TextArticleData } from 'src/shared/types/help-and-docs/article';
import helpStyles from '../help/Help.scss';
import styles from './About.scss'; import styles from './About.scss';
const About = () => { const About = () => {
...@@ -43,15 +45,19 @@ const About = () => { ...@@ -43,15 +45,19 @@ const About = () => {
}); });
return ( return (
<> <div className={helpStyles.help}>
<div> <AppBar />
<AppBar /> <TopMenuBar>
<TopMenuBar> {menu && <TopMenu menu={menu} currentUrl={location.pathname} />}
{menu && <TopMenu menu={menu} currentUrl={location.pathname} />} </TopMenuBar>
</TopMenuBar>
</div>
<HelpArticleGrid className={styles.grid}> <HelpArticleGrid className={styles.grid}>
{article && <TextArticle article={article} />} {article ? (
<TextArticle article={article} />
) : (
<div className={styles.spinnerContainer}>
<CircleLoader />
</div>
)}
<aside className={styles.aside}> <aside className={styles.aside}>
{menu && ( {menu && (
<> <>
...@@ -61,7 +67,7 @@ const About = () => { ...@@ -61,7 +67,7 @@ const About = () => {
)} )}
</aside> </aside>
</HelpArticleGrid> </HelpArticleGrid>
</> </div>
); );
}; };
......
...@@ -23,7 +23,6 @@ $leftMargin: 40px; ...@@ -23,7 +23,6 @@ $leftMargin: 40px;
} }
.description { .description {
margin: 25px 40px;
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -52,12 +51,11 @@ $leftMargin: 40px; ...@@ -52,12 +51,11 @@ $leftMargin: 40px;
} }
.searchDescription { .searchDescription {
margin: 14px 36px; display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 10px;
color: $dark-grey; color: $dark-grey;
.exampleText {
margin: 10px 4px;
}
} }
.speciesSelectorButton { .speciesSelectorButton {
......
...@@ -43,43 +43,46 @@ const BrowserInterstitialInstructions = () => { ...@@ -43,43 +43,46 @@ const BrowserInterstitialInstructions = () => {
<section className={styles.instructionsPanel}> <section className={styles.instructionsPanel}>
<div className={styles.instructionsWrapper}> <div className={styles.instructionsWrapper}>
<div className={styles.stepWrapper}> <div className={styles.stepWrapper}>
<Step count={1} title="Find and add a species" /> <Step count={1} label="Find and add a species">
<div className={styles.description}> <div className={styles.description}>
<ImageButton <ImageButton
className={styles.imageButtonIcon} className={styles.imageButtonIcon}
status={Status.DISABLED} status={Status.DISABLED}
image={SpeciesSelectorIcon} image={SpeciesSelectorIcon}
/> />
<div className={styles.iconLabel}>Species Selector</div> <div className={styles.iconLabel}>Species Selector</div>
</div> </div>
</Step>
</div> </div>
<div className={styles.stepWrapper}> <div className={styles.stepWrapper}>
<Step count={2} title="Return to this app" /> <Step count={2} label="Return to this app">
<div className={styles.description}> <div className={styles.description}>
<ImageButton <ImageButton
className={styles.imageButtonIcon} className={styles.imageButtonIcon}
status={Status.DISABLED} status={Status.DISABLED}
image={BrowserIcon} image={BrowserIcon}
/> />
<div className={styles.iconLabel}>Genome Browser</div> <div className={styles.iconLabel}>Genome Browser</div>
</div> </div>
</Step>
</div> </div>
<div className={styles.stepWrapper}> <div className={styles.stepWrapper}>
<Step <Step
count={3} count={3}
title="Use Search or the example links to view a gene or region" label="Use Search or the example links to view a gene or region"
/> >
<div className={styles.searchDescription}> <div className={styles.searchDescription}>
<ImageButton <ImageButton
className={styles.searchButtonIcon} className={styles.searchButtonIcon}
status={Status.DISABLED} status={Status.DISABLED}
image={SearchIcon} image={SearchIcon}
/> />
<div className={styles.exampleText}>Example gene</div> <div className={styles.exampleText}>Example gene</div>
<div className={styles.exampleText}>Example region</div> <div className={styles.exampleText}>Example region</div>
</div> </div>
</Step>
</div> </div>
<PrimaryButton <PrimaryButton
......
...@@ -23,7 +23,6 @@ $leftMargin: 40px; ...@@ -23,7 +23,6 @@ $leftMargin: 40px;
} }
.description { .description {
margin: 25px 40px;
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -52,12 +51,10 @@ $leftMargin: 40px; ...@@ -52,12 +51,10 @@ $leftMargin: 40px;
} }
.searchDescription { .searchDescription {
margin: 14px 36px; display: flex;
flex-direction: column;
gap: 10px;
color: $dark-grey; color: $dark-grey;
.exampleText {
margin: 10px 4px;
}
} }
.speciesSelectorButton { .speciesSelectorButton {
......
...@@ -43,42 +43,45 @@ const EntityViewerInterstitialInstructions = () => { ...@@ -43,42 +43,45 @@ const EntityViewerInterstitialInstructions = () => {
<section className={styles.instructionsPanel}> <section className={styles.instructionsPanel}>
<div className={styles.instructionsWrapper}> <div className={styles.instructionsWrapper}>
<div className={styles.stepWrapper}> <div className={styles.stepWrapper}>
<Step count={1} title="Find and add a species" /> <Step count={1} label="Find and add a species">
<div className={styles.description}> <div className={styles.description}>
<ImageButton <ImageButton
className={styles.imageButtonIcon} className={styles.imageButtonIcon}
status={Status.DISABLED} status={Status.DISABLED}
image={SpeciesSelectorIcon} image={SpeciesSelectorIcon}
/> />
<div className={styles.iconLabel}>Species Selector</div> <div className={styles.iconLabel}>Species Selector</div>
</div> </div>
</Step>
</div> </div>
<div className={styles.stepWrapper}> <div className={styles.stepWrapper}>
<Step count={2} title="Return to this app" /> <Step count={2} label="Return to this app">
<div className={styles.description}> <div className={styles.description}>
<ImageButton <ImageButton
className={styles.imageButtonIcon} className={styles.imageButtonIcon}
status={Status.DISABLED} status={Status.DISABLED}
image={EntityViewerIcon} image={EntityViewerIcon}
/> />
<div className={styles.iconLabel}>Entity Viewer</div> <div className={styles.iconLabel}>Entity Viewer</div>
</div> </div>
</Step>
</div> </div>
<div className={styles.stepWrapper}> <div className={styles.stepWrapper}>
<Step <Step
count={3} count={3}
title="Use Search or the example links to view a gene" label="Use Search or the example links to view a gene"
/> >
<div className={styles.searchDescription}> <div className={styles.searchDescription}>
<ImageButton <ImageButton
className={styles.searchButtonIcon} className={styles.searchButtonIcon}
status={Status.DISABLED} status={Status.DISABLED}
image={SearchIcon} image={SearchIcon}
/> />
<div className={styles.exampleText}>Example gene</div> <div className={styles.exampleText}>Example gene</div>
</div> </div>
</Step>
</div> </div>
<PrimaryButton <PrimaryButton
......
...@@ -19,9 +19,9 @@ import { useLocation } from 'react-router'; ...@@ -19,9 +19,9 @@ import { useLocation } from 'react-router';
import useApiService from 'src/shared/hooks/useApiService'; import useApiService from 'src/shared/hooks/useApiService';
import HelpMenu from './help-menu/HelpMenu'; import HelpMenu from './components/help-menu/HelpMenu';
import HelpLanding from './components/help-landing/HelpLanding';
import { import {
IndexArticle,
TextArticle, TextArticle,
RelatedArticles, RelatedArticles,
HelpArticleGrid, HelpArticleGrid,
...@@ -31,28 +31,36 @@ import { ...@@ -31,28 +31,36 @@ import {
import { Menu as MenuType } from 'src/shared/types/help-and-docs/menu'; import { Menu as MenuType } from 'src/shared/types/help-and-docs/menu';
import { import {
TextArticleData, TextArticleData,
VideoArticleData, VideoArticleData
IndexArticleData
} from 'src/shared/types/help-and-docs/article'; } from 'src/shared/types/help-and-docs/article';
import styles from './Help.scss'; import styles from './Help.scss';
type ArticleData = TextArticleData | VideoArticleData | IndexArticleData; type ArticleData = TextArticleData | VideoArticleData;
const Help = () => { const Help = () => {
const location = useLocation(); const location = useLocation();
const isIndexPage = isIndexRoute(location.pathname);
const { data: menu } = useApiService<MenuType>({ const { data: menu } = useApiService<MenuType>({
endpoint: `/api/docs/menus?name=help` endpoint: `/api/docs/menus?name=help`
}); });
const { data: article } = useApiService<any>({ const { data: article } = useApiService<any>({
endpoint: `/api/docs/article?url=${encodeURIComponent(location.pathname)}` endpoint: `/api/docs/article?url=${encodeURIComponent(location.pathname)}`,
skip: isIndexPage
}); });
const main = isIndexPage ? (
<main className={styles.main}>
<HelpLanding />
</main>
) : article ? (
<MainContent article={article} />
) : null;
return ( return (
<div className={styles.help}> <div className={styles.help}>
<AppBar /> <AppBar />
{menu && <HelpMenu menu={menu} currentUrl={location.pathname} />} {menu && <HelpMenu menu={menu} currentUrl={location.pathname} />}
{article && <MainContent article={article} />} {main}
</div> </div>
); );
}; };
...@@ -63,26 +71,31 @@ const AppBar = () => { ...@@ -63,26 +71,31 @@ const AppBar = () => {
const MainContent = (props: { article: ArticleData }) => { const MainContent = (props: { article: ArticleData }) => {
const { article } = props; const { article } = props;
let content; if (article.type !== 'article' && article.type !== 'video') {
if (article.type === 'index') { return null;
content = <IndexArticle article={article} />;
} else if (['article', 'video'].includes(article.type)) {
const renderedArticle =
article.type === 'article' ? (
<TextArticle article={article} />
) : (
<VideoArticle video={article} />
);
content = (
<HelpArticleGrid className={styles.articleGrid}>
{renderedArticle}
{!!article.related_articles.length && (
<RelatedArticles articles={article.related_articles} />
)}
</HelpArticleGrid>
);
} }
const renderedArticle =
article.type === 'article' ? (
<TextArticle article={article} />
) : (
<VideoArticle video={article} />
);
const content = (
<HelpArticleGrid className={styles.articleGrid}>
{renderedArticle}
{!!article.related_articles.length && (
<RelatedArticles articles={article.related_articles} />
)}
</HelpArticleGrid>
);
return <main className={styles.main}>{content}</main>; return <main className={styles.main}>{content}</main>;
}; };
const isIndexRoute = (pathname: string) => {
// handle both /help and /help/
return pathname.replaceAll('/', '') === 'help';
};
export default Help; export default Help;
@import 'src/styles/common';
$indent-left: 34px;
.helpLanding {
height: 100%;
overflow: auto;
padding: 0 40px 40px 0;
.showHideWrapper {
display: inline-block;
margin-left: 3ch;
}
section + section {
margin-top: 40px;
}
}
.appsGrid {
display: grid;
grid-template-columns: repeat(auto-fit, 324px);
column-gap: 96px;
row-gap: 30px;
margin-left: $indent-left;
}
.stepsGrid {
display: grid;
grid-template-columns: repeat(auto-fit, 218px);
column-gap: 200px;
max-width: 1200px;
background-color: $light-grey;
margin-top: 1ch;
padding: 20px $indent-left 40px $indent-left;
}
.appBlock {
ul {
margin-top: 1ch;
list-style-type: disc;
padding-left: 15px;
font-size: 12px;
color: $dark-grey;
}
}
.appLabel {
line-height: 1;
margin-bottom: 16px;
}
.searchIcon {
width: 30px;
height: 30px;
fill: $dark-grey;
}
.stepChildren {
display: flex;
flex-direction: column;
gap: 14px;
line-height: 1;
}
.lastSectionGrid {
display: grid;
grid-template-columns: repeat(2, 324px);
column-gap: calc(96px + #{$indent-left});
row-gap: 30px;
p {
padding-left: $indent-left;
}
}
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState } from 'react';
import LabelledAppIcon from '../labelled-app-icon/LabelledAppIcon';
import { Step } from 'src/shared/components/step/Step';
import ShowHide from 'src/shared/components/show-hide/ShowHide';
import { isEnvironment, Environment } from 'src/shared/helpers/environment';
import { ReactComponent as SearchIcon } from 'static/img/sidebar/search.svg';
import styles from './HelpLanding.scss';
const HelpLanding = () => {
return (