mirror of https://github.com/artifacthub/hub.git
Load CNCF banner in home page (#2573)
Related to #2551 Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
parent
f3158534b0
commit
a4be2500a9
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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}`}>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`}>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue