Load CNCF banner in home page (#2573)

Related to #2551

Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
Cintia Sánchez García 2022-12-05 14:44:15 +01:00 committed by GitHub
parent f3158534b0
commit a4be2500a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 37 deletions

View File

@ -5,7 +5,6 @@ import { createContext, Dispatch, useContext, useEffect, useReducer, useState }
import API from '../api';
import useSystemThemeMode from '../hooks/useSystemThemeMode';
import { Prefs, Profile, ThemePrefs, UserFullName } from '../types';
import bannerDispatcher from '../utils/bannerDispatcher';
import cleanLoginUrlParams from '../utils/cleanLoginUrlParams';
import detectActiveThemeMode from '../utils/detectActiveThemeMode';
import browserHistory from '../utils/history';
@ -302,7 +301,6 @@ function AppCtxProvider(props: Props) {
? detectActiveThemeMode()
: activeProfilePrefs.theme.configured;
themeBuilder.init();
bannerDispatcher.init();
updateActiveStyleSheet(theme);
setActiveInitialTheme(theme);
refreshUserProfile(dispatch);

View File

@ -54,6 +54,12 @@
text-decoration: none;
}
.banner {
max-height: 350px;
width: 350px;
background-color: var(--body-bg) !important;
}
@media only screen and (max-width: 767.98px) {
.mainTitle {
font-size: 2.5rem !important;

View File

@ -4,8 +4,9 @@ import { FaGithub, FaSlack, FaTwitter } from 'react-icons/fa';
import { Link, useHistory } from 'react-router-dom';
import API from '../../api';
import { RepositoryKind, Stats } from '../../types';
import { Banner as IBanner, RepositoryKind, Stats } from '../../types';
import alertDispatcher from '../../utils/alertDispatcher';
import bannerDispatcher from '../../utils/bannerDispatcher';
import getSampleQueries from '../../utils/getSampleQueries';
import isWhiteLabel from '../../utils/isWhiteLabel';
import ExternalLink from '../common/ExternalLink';
@ -14,6 +15,7 @@ import SampleQueries from '../common/SampleQueries';
import SearchBar from '../common/SearchBar';
import SearchTipsModal from '../common/SearchTipsModal';
import UserInvitation from '../controlPanel/members/UserInvitation';
import Banner from '../package/Banner';
import AccountDeletion from './AccountDeletion';
import Counter from './Counter';
import styles from './HomeView.module.css';
@ -37,6 +39,7 @@ const HomeView = (props: Props) => {
const [isLoadingStats, setIsLoadingStats] = useState(false);
const [stats, setStats] = useState<Stats | null>(null);
const [openTips, setOpenTips] = useState<boolean>(false);
const [banner, setBanner] = useState<IBanner | null>(null);
const whiteLabel = isWhiteLabel();
@ -51,7 +54,18 @@ const HomeView = (props: Props) => {
setIsLoadingStats(false);
}
}
async function getBanner() {
try {
const CNCFBanner = await bannerDispatcher.getBanner();
setBanner(CNCFBanner);
} catch {
setBanner(null);
}
}
fetchStats();
getBanner();
}, []);
useEffect(() => {
@ -138,6 +152,16 @@ const HomeView = (props: Props) => {
<Counter isLoading={isLoadingStats} value={isNull(stats) ? null : stats.releases} name="releases" />
</div>
{!isNull(banner) && (
<Banner
className={`${styles.banner} banner`}
wrapperClassName="d-flex align-items-center justify-content-center mt-4 mt-md-5"
banner={banner}
removeBanner={() => setBanner(null)}
maxEqualRatio
/>
)}
{!whiteLabel && (
<>
<div className={`text-center h5 my-4 mt-md-5 ${styles.legend}`}>

View File

@ -6,25 +6,3 @@
.loaded {
max-height: 1500px;
}
.banner {
margin-top: 25px;
width: 230px;
background-color: var(--color-1-2) !important;
}
.image {
width: auto;
}
@media only screen and (min-width: 1400px) {
.banner {
width: 260px;
}
}
@media only screen and (min-width: 1920px) {
.banner {
width: 310px;
}
}

View File

@ -1,6 +1,6 @@
import classNames from 'classnames';
import { isNull } from 'lodash';
import { useContext, useEffect, useState } from 'react';
import { useContext, useEffect, useRef, useState } from 'react';
import { AppCtx } from '../../context/AppCtx';
import { Banner as IBanner } from '../../types';
@ -8,13 +8,17 @@ import ExternalLink from '../common/ExternalLink';
import styles from './Banner.module.css';
interface Props {
wrapperClassName?: string;
className?: string;
banner: IBanner;
removeBanner: () => void;
maxEqualRatio: boolean;
}
const Banner = (props: Props) => {
const { ctx } = useContext(AppCtx);
const { effective } = ctx.prefs.theme;
const img = useRef<HTMLImageElement>(null);
const [isLoaded, setIsLoaded] = useState<boolean>(false);
const [visibleBanner, setVisibleBanner] = useState<IBanner | null>(props.banner);
const [bannerTimeout, setBannerTimeout] = useState<NodeJS.Timeout | null>(null);
@ -42,14 +46,19 @@ const Banner = (props: Props) => {
if (isNull(visibleBanner)) return null;
const getCardImage = () => (
<div className={`card shadow-sm p-3 mb-2 overflow-hidden ${styles.banner}`}>
<div className={`card flex-row shadow-sm mw-100 p-3 overflow-hidden ${props.className}`}>
<img
ref={img}
src={effective === 'light' ? visibleBanner.images['light-theme'] : visibleBanner.images['dark-theme']}
alt={visibleBanner.name || 'Banner'}
className={`mw-100 rounded mx-auto ${styles.image}`}
className="mw-100 h-auto rounded mx-auto"
onError={props.removeBanner}
onLoad={() => {
setIsLoaded(true);
if (props.maxEqualRatio && img && img.current && img.current.naturalHeight > img.current.naturalWidth) {
setIsLoaded(false);
} else {
setIsLoaded(true);
}
}}
/>
</div>
@ -58,11 +67,15 @@ const Banner = (props: Props) => {
return (
<div className={classNames('overflow-hidden', styles.bannerWrapper, { [styles.loaded]: isLoaded })}>
{visibleBanner.link ? (
<ExternalLink href={visibleBanner.link} label={`${props.banner.name} link` || 'Banner link'}>
<ExternalLink
href={visibleBanner.link}
className={props.wrapperClassName}
label={`${props.banner.name} link` || 'Banner link'}
>
<>{getCardImage()}</>
</ExternalLink>
) : (
<>{getCardImage()}</>
<div className={props.wrapperClassName}>{getCardImage()}</div>
)}
</div>
);

View File

@ -141,6 +141,12 @@
width: 100%;
}
.banner {
margin-top: 25px;
width: 230px;
background-color: var(--color-1-2) !important;
}
@media only screen and (max-width: 767.98px) {
.imageWrapper {
min-width: 50px;
@ -240,7 +246,8 @@
max-width: 260px;
}
.info {
.info,
.banner {
width: 260px;
}
@ -264,7 +271,8 @@
max-width: 310px;
}
.info {
.info,
.banner {
width: 310px;
}

View File

@ -180,8 +180,18 @@ const PackageView = (props: Props) => {
setRelatedPackages([]);
}
}
async function getBanner() {
try {
const CNCFBanner = await bannerDispatcher.getBanner();
setBanner(CNCFBanner);
} catch {
setBanner(null);
}
}
if (!isNull(currentPkgId) && detail) {
setBanner(bannerDispatcher.getBanner());
getBanner();
fetchRelatedPackages(detail);
}
}, [currentPkgId]); /* eslint-disable-line react-hooks/exhaustive-deps */
@ -1187,7 +1197,14 @@ const PackageView = (props: Props) => {
</div>
)}
{!isNull(banner) && <Banner banner={banner} removeBanner={() => setBanner(null)} />}
{!isNull(banner) && (
<Banner
className={`mb-2 ${styles.banner}`}
banner={banner}
removeBanner={() => setBanner(null)}
maxEqualRatio={false}
/>
)}
<div className={`card shadow-sm position-relative info ${styles.info}`}>
<div className={`card-body ${styles.detailsBody}`}>

View File

@ -306,7 +306,7 @@
background-color: var(--color-1-300);
}
.card,
.card:not(.banner),
.card.bg-white,
.list-group-item {
background-color: var(--color-1-500) !important;
@ -314,6 +314,11 @@
box-shadow: none !important;
}
.banner {
border-color: var(--border-md) !important;
box-shadow: none !important;
}
.notificationCard {
box-shadow: 0px 0px 25px 5px var(--color-black-25);
}

View File

@ -6,6 +6,7 @@ import { Banner } from '../types';
import getMetaTag from './getMetaTag';
class BannerDispatcher {
private isInitiated: boolean = false;
private url: string | null = null;
private banners: Banner[] = [];
@ -14,6 +15,7 @@ class BannerDispatcher {
if (!isNull(this.url)) {
this.banners = await this.getBannersInfo(this.url);
}
this.isInitiated = true;
}
private async getBannersInfo(url: string): Promise<Banner[]> {
@ -54,7 +56,10 @@ class BannerDispatcher {
}
}
public getBanner(): Banner | null {
public async getBanner(): Promise<Banner | null> {
if (!this.isInitiated) {
await this.init();
}
if (this.banners.length > 0) {
return this.banners[Math.floor(Math.random() * this.banners.length)];
} else {