feat: v4.0.0 (#1016)
Co-authored-by: Denys Konovalov <kontakt@denyskon.de> Co-authored-by: Mathieu COSYNS <64072917+Mathieu-COSYNS@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
682576ffc4
commit
799c7e6936
@ -92,10 +92,13 @@ const useIntersectionObserver = (setActiveId: (activeId: string) => void) => {
|
||||
}
|
||||
|
||||
const callback: IntersectionObserverCallback = headings => {
|
||||
headingElementsRef.current = headings.reduce((map, headingElement) => {
|
||||
map[headingElement.target.id] = headingElement;
|
||||
return map;
|
||||
}, headingElementsRef.current as Record<string, IntersectionObserverEntry>);
|
||||
headingElementsRef.current = headings.reduce(
|
||||
(map, headingElement) => {
|
||||
map[headingElement.target.id] = headingElement;
|
||||
return map;
|
||||
},
|
||||
headingElementsRef.current as Record<string, IntersectionObserverEntry>,
|
||||
);
|
||||
|
||||
// Get all headings that are currently visible on the page
|
||||
const visibleHeadings: IntersectionObserverEntry[] = [];
|
||||
@ -148,6 +151,11 @@ const StyledNav = styled('nav')(
|
||||
overflow-y: auto;
|
||||
top: 16px;
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
${theme.breakpoints.between('md', 'lg')} {
|
||||
top: 24px;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import IconButton from '@mui/material/IconButton';
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Link from 'next/link';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import releases from '../../lib/releases';
|
||||
import Logo from './Logo';
|
||||
@ -19,7 +19,7 @@ import SponsorButton from './SponsorButton';
|
||||
import type { PaletteMode } from '@mui/material';
|
||||
import type { ButtonTypeMap } from '@mui/material/Button';
|
||||
import type { ExtendButtonBase } from '@mui/material/ButtonBase';
|
||||
import type { DocsGroup, MenuItem, SearchablePage } from '../../interface';
|
||||
import type { DocsGroup, MenuItem, MenuLink, SearchablePage } from '../../interface';
|
||||
|
||||
const StyledAppBar = styled(AppBar)(
|
||||
({ theme }) => `
|
||||
@ -55,7 +55,7 @@ const StyledGithubLink = styled('a')(
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
${theme.breakpoints.down('lg')} {
|
||||
${theme.breakpoints.down(1300)} {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
@ -104,6 +104,14 @@ const StyledDesktopLink = styled(Button)(
|
||||
`,
|
||||
) as ExtendButtonBase<ButtonTypeMap<{}, 'a'>>;
|
||||
|
||||
const STATIC_CMS_DOMAIN = 'staticcms.org';
|
||||
const DEFAULT_DEMO_SITE = 'demo.staticcms.org';
|
||||
const STATIC_CMS_DOMAIN_REGEX = /staticcms\.org$/g;
|
||||
|
||||
function createDemoUrl(subdomain?: string): string {
|
||||
return `https://${subdomain ? subdomain : ''}${DEFAULT_DEMO_SITE}/`;
|
||||
}
|
||||
|
||||
interface HeaderProps {
|
||||
mode: PaletteMode;
|
||||
docsGroups: DocsGroup[];
|
||||
@ -115,6 +123,18 @@ const Header = ({ mode, docsGroups, searchablePages, toggleColorMode }: HeaderPr
|
||||
const theme = useTheme();
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
|
||||
const [demoUrl, setDemoUrl] = useState(createDemoUrl());
|
||||
useEffect(() => {
|
||||
if (
|
||||
typeof window === 'undefined' ||
|
||||
!window.location.host.endsWith(STATIC_CMS_DOMAIN) ||
|
||||
window.location.host === `www.${STATIC_CMS_DOMAIN}`
|
||||
) {
|
||||
return;
|
||||
}
|
||||
setDemoUrl(createDemoUrl(window.location.host.replace(STATIC_CMS_DOMAIN_REGEX, '')));
|
||||
}, []);
|
||||
|
||||
const handleDrawerToggle = useCallback(() => {
|
||||
setMobileOpen(!mobileOpen);
|
||||
}, [mobileOpen]);
|
||||
@ -142,12 +162,17 @@ const Header = ({ mode, docsGroups, searchablePages, toggleColorMode }: HeaderPr
|
||||
title: 'Examples',
|
||||
url: '/docs/examples',
|
||||
},
|
||||
{
|
||||
title: 'Demo',
|
||||
url: demoUrl,
|
||||
target: '_blank',
|
||||
},
|
||||
{
|
||||
title: 'Community',
|
||||
url: '/community',
|
||||
},
|
||||
],
|
||||
[docsGroups],
|
||||
[demoUrl, docsGroups],
|
||||
);
|
||||
|
||||
return (
|
||||
@ -198,14 +223,21 @@ const Header = ({ mode, docsGroups, searchablePages, toggleColorMode }: HeaderPr
|
||||
</StyledIconsWrapper>
|
||||
{items.map(item => {
|
||||
let url = '#';
|
||||
let target: MenuLink['target'];
|
||||
if ('url' in item) {
|
||||
url = item.url;
|
||||
target = item.target;
|
||||
} else if (item.groups.length > 0 && item.groups[0].links.length > 0) {
|
||||
url = item.groups[0].links[0].url;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledDesktopLink key={`desktop-${item.title}-${url}`} component={Link} href={url}>
|
||||
<StyledDesktopLink
|
||||
key={`desktop-${item.title}-${url}`}
|
||||
component={Link}
|
||||
href={url}
|
||||
target={target}
|
||||
>
|
||||
{item.title}
|
||||
</StyledDesktopLink>
|
||||
);
|
||||
|
@ -66,7 +66,7 @@ export interface HomepageData {
|
||||
export interface Release {
|
||||
readonly date: string;
|
||||
readonly version: string;
|
||||
readonly type: 'major' | 'minor' | 'patch';
|
||||
readonly type: 'major' | 'minor' | 'patch' | 'pre';
|
||||
readonly description?: string;
|
||||
}
|
||||
|
||||
@ -136,6 +136,7 @@ export interface MenuLink {
|
||||
readonly url: string;
|
||||
readonly beta?: boolean;
|
||||
readonly deprecated?: boolean;
|
||||
readonly target?: '_blank';
|
||||
}
|
||||
|
||||
export interface MenuLinkSubGroup {
|
||||
|
@ -129,18 +129,21 @@ export function fetchDocsContent(): [DocsPage[], DocsGroup[]] {
|
||||
},
|
||||
);
|
||||
|
||||
const pagesByGroup: Record<string, DocsGroupLink[]> = allDocsData.reduce((acc, doc) => {
|
||||
if (!(doc.data.group in acc)) {
|
||||
acc[doc.data.group] = [];
|
||||
}
|
||||
acc[doc.data.group].push({
|
||||
title: doc.data.title,
|
||||
slug: doc.data.slug,
|
||||
beta: doc.data.beta ?? false,
|
||||
deprecated: doc.data.deprecated ?? false,
|
||||
});
|
||||
return acc;
|
||||
}, {} as Record<string, DocsGroupLink[]>);
|
||||
const pagesByGroup: Record<string, DocsGroupLink[]> = allDocsData.reduce(
|
||||
(acc, doc) => {
|
||||
if (!(doc.data.group in acc)) {
|
||||
acc[doc.data.group] = [];
|
||||
}
|
||||
acc[doc.data.group].push({
|
||||
title: doc.data.title,
|
||||
slug: doc.data.slug,
|
||||
beta: doc.data.beta ?? false,
|
||||
deprecated: doc.data.deprecated ?? false,
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, DocsGroupLink[]>,
|
||||
);
|
||||
|
||||
const docsGroups: DocsGroup[] = menu.docs.map(group => ({
|
||||
...group,
|
||||
|
@ -251,7 +251,10 @@ const StyledFeatureText = styled('div')`
|
||||
const Home = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const majorMinorThemes = useMemo(() => releases.filter(r => r.type !== 'patch'), []);
|
||||
const majorMinorReleases = useMemo(
|
||||
() => releases.filter(r => ['major', 'minor'].includes(r.type)),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<Page url="/" docsGroups={docsGroups} searchablePages={searchablePages} fullWidth>
|
||||
@ -328,11 +331,11 @@ const Home = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
<Container>
|
||||
<StyledReleasesSectionContent>
|
||||
{[...Array(3)].map((_, index) => {
|
||||
if (index >= majorMinorThemes.length) {
|
||||
if (index >= majorMinorReleases.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const release = majorMinorThemes[index];
|
||||
const release = majorMinorReleases[index];
|
||||
return (
|
||||
<CardActionArea
|
||||
key={release.version}
|
||||
|
@ -6,6 +6,7 @@ import { styled } from '@mui/material/styles';
|
||||
import format from 'date-fns/format';
|
||||
import parseISO from 'date-fns/parseISO';
|
||||
import Link from 'next/link';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import Container from '../components/layout/Container';
|
||||
import Page from '../components/layout/Page';
|
||||
@ -94,7 +95,33 @@ const StyledLink = styled(Link)(
|
||||
`,
|
||||
);
|
||||
|
||||
function getVersionNumber(version: string): number {
|
||||
return +version.replace('v', '');
|
||||
}
|
||||
|
||||
function isNextVersion(latestMajorVersionNumber: number, version: string): boolean {
|
||||
if (getVersionNumber(version) > latestMajorVersionNumber) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getMajorVersion(version: string): string {
|
||||
return version.split('.')[0];
|
||||
}
|
||||
|
||||
const Releases = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
const latestMajorVersion = useMemo(
|
||||
() => getMajorVersion((releaseData.find(r => r.type === 'major') ?? releaseData[0]).version),
|
||||
[],
|
||||
);
|
||||
|
||||
const latestMajorVersionNumber = useMemo(
|
||||
() => getVersionNumber(latestMajorVersion),
|
||||
[latestMajorVersion],
|
||||
);
|
||||
|
||||
return (
|
||||
<Page url="/releases" docsGroups={docsGroups} searchablePages={searchablePages} fullWidth>
|
||||
<StyledReleaseContent>
|
||||
@ -125,31 +152,50 @@ const Releases = ({ docsGroups, searchablePages }: DocsMenuProps) => {
|
||||
</Container>
|
||||
<Container>
|
||||
<StyledReleaseLinksContent>
|
||||
{releaseData.map(release => (
|
||||
<StyledReleaseSection key={release.version}>
|
||||
<Typography variant="h3" color="primary.main">
|
||||
<strong>{release.version}</strong>
|
||||
|
||||
<Box component="small" sx={{ fontSize: '16px', opacity: 0.75 }}>
|
||||
{format(parseISO(release.date), 'MMM dd, yyyy')}
|
||||
</Box>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body1"
|
||||
component="div"
|
||||
color="inherit"
|
||||
sx={{ display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
{isNotEmpty(release.description) ? release.description : null}
|
||||
<StyledLink
|
||||
href={`${config.repo_url}/releases/tag/${release.version}`}
|
||||
target="_blank"
|
||||
{releaseData.map(release => {
|
||||
const majorVersion = getMajorVersion(release.version);
|
||||
const isNext = isNextVersion(latestMajorVersionNumber, majorVersion);
|
||||
|
||||
return (
|
||||
<StyledReleaseSection key={release.version}>
|
||||
<Typography variant="h3" color="primary.main">
|
||||
<strong>{release.version}</strong>
|
||||
|
||||
<Box component="small" sx={{ fontSize: '16px', opacity: 0.75 }}>
|
||||
{format(parseISO(release.date), 'MMM dd, yyyy')}
|
||||
</Box>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body1"
|
||||
component="div"
|
||||
color="inherit"
|
||||
sx={{ display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
Changelog
|
||||
</StyledLink>
|
||||
</Typography>
|
||||
</StyledReleaseSection>
|
||||
))}
|
||||
{isNotEmpty(release.description) ? release.description : null}
|
||||
<Box sx={{ display: 'flex', gap: '8px' }}>
|
||||
<StyledLink
|
||||
href={`${config.repo_url}/releases/tag/${release.version}`}
|
||||
target="_blank"
|
||||
>
|
||||
Changelog
|
||||
</StyledLink>
|
||||
<StyledLink
|
||||
href={`https://${
|
||||
isNext
|
||||
? 'next'
|
||||
: majorVersion !== latestMajorVersion
|
||||
? majorVersion
|
||||
: 'www'
|
||||
}.staticcms.org/docs`}
|
||||
target={majorVersion !== latestMajorVersion ? '_blank' : undefined}
|
||||
>
|
||||
Docs
|
||||
</StyledLink>
|
||||
</Box>
|
||||
</Typography>
|
||||
</StyledReleaseSection>
|
||||
);
|
||||
})}
|
||||
</StyledReleaseLinksContent>
|
||||
</Container>
|
||||
</StyledReleaseLinks>
|
||||
|
Reference in New Issue
Block a user