Skip to content

Landing page fixes #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions apps/landing-page/markdoc/tags.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Callout, QuickLink, QuickLinks, CurrentVersion } from '@devfile-web/core';
import clsx from 'clsx';

const tags = {
callout: {
Expand All @@ -19,14 +20,25 @@ const tags = {
src: { type: String },
alt: { type: String },
caption: { type: String },
isZoomable: { type: Boolean, default: false },
hasBackground: { type: Boolean, default: false },
},
render: (props: { src: string; alt: string; caption: string }): JSX.Element => {
const { src, alt = '', caption } = props;
render: (props: {
src: string;
alt: string;
caption: string;
hasBackground: boolean;
}): JSX.Element => {
const { src, alt = '', caption, hasBackground } = props;

return (
<figure>
<figure className="">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={src} alt={alt} />
<img
src={src}
alt={alt}
className={clsx(hasBackground && 'rounded-md border bg-slate-50 p-2')}
/>
<figcaption>{caption}</figcaption>
</figure>
);
Expand Down
40 changes: 34 additions & 6 deletions apps/landing-page/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import {
RedHatIcon,
} from '@devfile-web/core';
import { defaultVersion } from '@devfile-web/docs';
import type { HeaderNavigation, FooterNavigation } from '@devfile-web/core';
import { ViewGridIcon, BookOpenIcon, ViewListIcon } from '@heroicons/react/outline';
import type { HeaderNavigation, FooterNavigation, NavigationElement } from '@devfile-web/core';

export { docsNavigation } from '@devfile-web/docs';

export const headerNavigation: HeaderNavigation = [
{ name: 'Registry', href: 'https://registry.devfile.io' },
{ name: 'Docs', href: `/docs/${defaultVersion}/overview` },
{ name: 'Get Started', href: `/docs/${defaultVersion}/what-is-a-devfile` },
{ name: 'Github', href: 'https://github.com/orgs/devfile/repositories', image: GithubIcon },
{ name: 'Docs', href: `/docs/${defaultVersion}/what-is-a-devfile` },
{ name: 'Get Started', href: `/docs/${defaultVersion}/devfile-ecosystem` },
{ name: 'Github', href: 'https://github.com/devfile/api', image: GithubIcon },
{ name: 'Slack', href: 'https://kubernetes.slack.com/archives/C02SX9E5B55', image: SlackIcon },
];

Expand All @@ -29,12 +30,12 @@ export const footerNavigation: FooterNavigation = {
links: [
{ name: 'Cloud Native Computing Foundation', href: 'https://www.cncf.io' },
{ name: 'Registry', href: 'https://registry.devfile.io' },
{ name: 'Documentation', href: `/docs/${defaultVersion}/overview` },
{ name: 'Documentation', href: `/docs/${defaultVersion}/what-is-a-devfile` },
],
social: [
{
name: 'Github',
href: 'https://github.com/orgs/devfile/repositories',
href: 'https://github.com/devfile/api',
image: GithubIcon,
},
{
Expand All @@ -44,3 +45,30 @@ export const footerNavigation: FooterNavigation = {
},
],
};

export interface Custom404NavigationElement extends NavigationElement {
description: string;
}

export type Custom404Navigation = Custom404NavigationElement[];

export const custom404Navigation: Custom404Navigation = [
{
name: 'Documentation',
description: 'Learn how to integrate devfile with your app',
image: BookOpenIcon,
href: `/docs/${defaultVersion}/what-is-a-devfile`,
},
{
name: 'API Reference',
description: 'A complete API reference for devfile',
image: ViewListIcon,
href: `/docs/${defaultVersion}/devfile-schema`,
},
{
name: 'Registry',
description: 'Browse devfile stacks and samples',
image: ViewGridIcon,
href: 'https://registry.devfile.io',
},
];
88 changes: 88 additions & 0 deletions apps/landing-page/pages/404.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { ChevronRightIcon } from '@heroicons/react/solid';
import { DevfileIcon, LandingPageMeta } from '@devfile-web/core';
import { defaultVersion } from '@devfile-web/docs';
import { useRouter } from 'next/router';
import Link from 'next/link';
import { custom404Navigation } from '../navigation';

export function Custom404(): JSX.Element {
const router = useRouter();

const isDocsPage = router.asPath === '/docs';

return (
<div className="bg-slate-50 dark:bg-slate-900">
<LandingPageMeta title="404: Page not found">
{isDocsPage && (
<meta
httpEquiv="refresh"
content={`0; url=${
custom404Navigation.find((el) => el.name === 'Documentation').href ??
`/docs/${defaultVersion}/what-is-a-devfile`
}`}
/>
)}
</LandingPageMeta>

<main className="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="flex-shrink-0 pt-16">
<DevfileIcon className="fill-devfile mx-auto h-12 w-auto" />
</div>
<div className="mx-auto max-w-xl py-16 sm:py-24">
<div className="text-center">
<p className="text-devfile text-base font-semibold">404</p>
<h1 className="mt-2 text-4xl font-bold tracking-tight text-slate-700 dark:text-sky-100 sm:text-5xl sm:tracking-tight">
This page does not exist.
</h1>
<p className="mt-2 text-lg text-slate-500 dark:text-slate-400">
The page you are looking for could not be found.
</p>
</div>
<div className="mt-12">
<h2 className="text-base font-semibold text-slate-500 dark:text-slate-400">
Popular pages
</h2>
<ul className="mt-4 divide-y divide-slate-200 border-t border-b border-slate-200 dark:divide-slate-800 dark:border-slate-800">
{custom404Navigation.map((link) => (
<li key={link.name} className="group relative flex items-start space-x-4 py-6">
<div className="flex-shrink-0">
<span className="bg-devfile flex h-12 w-12 items-center justify-center rounded-lg">
<link.image className="h-6 w-auto text-sky-100" aria-hidden="true" />
</span>
</div>
<div className="min-w-0 flex-1">
<h3 className="text-base font-medium text-slate-700 group-hover:text-slate-800 dark:text-sky-100 dark:group-hover:text-sky-50">
<Link href={link.href} passHref>
{link.name}
</Link>
</h3>
<p className="text-base text-slate-500 group-hover:text-slate-600 dark:text-slate-400 dark:group-hover:text-slate-300">
{link.description}
</p>
</div>
<div className="flex-shrink-0 self-center">
<ChevronRightIcon
className="h-5 w-5 text-slate-500 group-hover:text-slate-600 dark:text-slate-400 dark:group-hover:text-slate-300"
aria-hidden="true"
/>
</div>
</li>
))}
</ul>
<div className="mt-8">
<Link
href="/"
className="text-base font-medium text-slate-500 hover:text-slate-600 dark:text-slate-400 dark:hover:text-slate-300"
passHref
>
Or go back home<span aria-hidden="true"> &rarr;</span>
</Link>
</div>
</div>
</div>
</main>
</div>
);
}

export default Custom404;
25 changes: 11 additions & 14 deletions apps/landing-page/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type { MarkdocNextJsPageProps } from '@markdoc/next.js';
import type { RenderableTreeNodes, Tag } from '@markdoc/markdoc';
import type { TableOfContents } from '@devfile-web/core';
import type { DocsNavigation } from '@devfile-web/docs';
import { useRouter } from 'next/router';
import { docsNavigation, headerNavigation, footerNavigation } from '../navigation';

const analyticsConfig = {
Expand Down Expand Up @@ -69,20 +68,13 @@ function collectHeadings(
function LandingPage({ Component, pageProps }: AppProps): JSX.Element {
const { markdoc } = pageProps as MarkdocNextJsPageProps;

const router = useRouter();

const title = (markdoc?.frontmatter.title as string) ?? '';

let pageTitle: string;
let description: string;

if (router.asPath.includes('/docs')) {
pageTitle =
(markdoc?.frontmatter.pageTitle as string) ||
`${(markdoc?.frontmatter.title as string) ?? ''} - Docs`;
const pageTitle =
(markdoc?.frontmatter.pageTitle as string) ||
`${(markdoc?.frontmatter.title as string) ?? ''} - Docs`;

description = (markdoc?.frontmatter.description as string) ?? '';
}
const pageDescription = (markdoc?.frontmatter.description as string) ?? '';

const tableOfContents = markdoc?.content ? collectHeadings(markdoc.content) : [];

Expand All @@ -94,10 +86,15 @@ function LandingPage({ Component, pageProps }: AppProps): JSX.Element {
docsNavigation={docsNavigation as DocsNavigation}
>
<div className="flex h-screen min-w-[300px] flex-col justify-between">
<LandingPageMeta title={pageTitle} description={description} />
<div className="grow">
<LandingPageMeta />
<Header />
<Layout title={title} tableOfContents={tableOfContents}>
<Layout
title={title}
tableOfContents={tableOfContents}
pageTitle={pageTitle}
pageDescription={pageDescription}
>
<Component {...pageProps} />
</Layout>
</div>
Expand Down
4 changes: 4 additions & 0 deletions apps/landing-page/public/images/devfile-ecosystem.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/landing-page/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { join } = require('path');
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
join(__dirname, '{src,pages,components}/**/*!(*.stories|*.spec).{ts,tsx,html}'),
join(__dirname, '{src,pages,components,markdoc}/**/*!(*.stories|*.spec).{ts,tsx,html}'),
...createGlobPatternsForDependencies(__dirname),
],
darkMode: 'class',
Expand Down
91 changes: 64 additions & 27 deletions libs/core/src/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import Link from 'next/link';
import clsx from 'clsx';
import { useState, useEffect } from 'react';
import { DotsVerticalIcon } from '@heroicons/react/outline';
import { ChevronRightIcon } from '@heroicons/react/solid';
import { Popover } from '@headlessui/react';
import { useRouter } from 'next/router';
import { DevfileIcon } from '../../icons';
import { MobileNavigation } from '../mobile-navigation/mobile-navigation';
import { LandingPageSearch as Search } from '../landing-page-search/landing-page-search';
Expand All @@ -9,9 +13,13 @@ import { VersionSelector } from '../version-selector/version-selector';
import { useNavigation } from '../../hooks';

export function Header(): JSX.Element {
const { headerNavigation } = useNavigation();
const { headerNavigation, currentSection, currentPage } = useNavigation();

const [isScrolled, setIsScrolled] = useState<boolean>(false);
const router = useRouter();

const is404Page = router.pathname === '/404';
const isDocsPage = router.pathname.includes('docs');

useEffect(() => {
function onScroll(): void {
Expand All @@ -27,58 +35,87 @@ export function Header(): JSX.Element {
return (
<div
className={clsx(
'sticky top-0 z-50 flex justify-center bg-white px-4 py-5 shadow-md shadow-slate-900/5 transition duration-500 dark:shadow-none sm:px-6 lg:px-8',
'sticky top-0 z-50 flex flex-col justify-center border-b border-slate-200 bg-white px-4 py-2 shadow-md shadow-slate-900/5 transition duration-500 dark:border-slate-800 sm:px-6 lg:flex-row lg:px-8',
isScrolled
? 'dark:bg-slate-900/95 dark:backdrop-blur dark:[@supports(backdrop-filter:blur(0))]:bg-slate-900/75'
: 'dark:bg-transparent',
)}
>
<div className="flex max-w-screen-2xl grow flex-wrap items-center justify-between">
<div className="flex items-center">
<div className="mr-6 flex lg:hidden">
<MobileNavigation />
</div>

<Link
href="/"
aria-label="Home page"
passHref
className="my-2 lg:flex lg:items-center lg:gap-4"
>
<DevfileIcon className="fill-devfile h-9 w-9 lg:hidden" />
<DevfileIcon className="fill-devfile hidden h-9 w-auto lg:block" />
<h3 className="hidden text-xl font-semibold text-slate-700 dark:text-sky-100 lg:block">
<Link href="/" aria-label="Home page" passHref className="my-2 flex items-center gap-4">
<DevfileIcon className="fill-devfile h-9 w-auto" />
<h3 className="hidden pr-2 text-xl font-semibold text-slate-700 dark:text-sky-100 sm:block">
Devfile.io
</h3>
{!is404Page && <VersionSelector className="relative z-10" />}
</Link>
</div>

<div className="relative my-2 flex grow items-center justify-end gap-8">
<div className="lg:hidden">
<Search />
</div>
<VersionSelector className="relative z-10" />
<ThemeSelector className="relative z-10 hidden sm:block" />
<div className="my-2 flex grow items-center justify-end gap-4 lg:hidden">
{!is404Page && <Search />}
<Popover className="relative flex items-center">
<Popover.Button>
<DotsVerticalIcon
className="h-6 w-auto stroke-slate-400 hover:fill-slate-500 dark:stroke-slate-500 dark:hover:stroke-slate-400"
aria-hidden="true"
/>
</Popover.Button>

<Popover.Panel className="absolute right-0 top-full z-50 mt-4 w-screen max-w-[250px] rounded-lg bg-white shadow-md shadow-black/5 ring-1 ring-black/5 dark:bg-slate-800 dark:ring-white/5">
<div className="m-6">
<div className="flex flex-col gap-4">
{headerNavigation.map((item) => (
<Link
key={item.name}
href={item.href}
aria-label={item.name}
className="whitespace-nowrap text-base font-medium text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-300"
>
{item.name}
</Link>
))}
</div>
<div className="mt-4 flex items-center justify-between border-t border-slate-200 pt-4 dark:border-slate-700">
<span className="whitespace-nowrap text-base text-slate-500 dark:text-slate-400">
Switch theme
</span>
<ThemeSelector className="relative z-10" isRightAligned />
</div>
</div>
</Popover.Panel>
</Popover>
</div>
<div className="my-2 hidden grow items-center justify-end gap-8 lg:flex">
<ThemeSelector className="relative z-10" />
{headerNavigation.map((item) => (
<Link
key={item.name}
href={item.href}
aria-label={item.name}
className={clsx(
item.image
? 'hidden [@media(min-width:450px)]:block'
: 'hidden whitespace-nowrap text-base font-medium text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-300 lg:block',
)}
className="whitespace-nowrap text-base font-medium text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-slate-300"
>
{item.image ? (
<item.image className="h-6 w-6 fill-slate-500 hover:fill-slate-800 dark:fill-slate-400 dark:hover:fill-slate-300" />
<item.image className="h-6 w-auto fill-slate-500 hover:fill-slate-800 dark:fill-slate-400 dark:hover:fill-slate-300" />
) : (
item.name
)}
</Link>
))}
</div>
</div>
{isDocsPage && (
<div className="my-2 flex max-w-screen-2xl items-center gap-8 border-t border-slate-200 pt-4 dark:border-slate-800 lg:hidden">
<MobileNavigation />
<div className="flex items-center overflow-hidden">
<span className="pr-2 text-slate-500 dark:text-slate-400">{currentSection?.title}</span>
<ChevronRightIcon className="h-4 w-auto flex-none fill-slate-500 pr-2 dark:fill-slate-400" />
<span className="whitespace-nowrap text-slate-700 dark:text-sky-100">
{currentPage?.title}
</span>
</div>
</div>
)}
</div>
);
}
Expand Down
Loading