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:
Daniel Lautzenheiser
2024-01-03 15:14:09 -05:00
committed by GitHub
parent 682576ffc4
commit 799c7e6936
732 changed files with 48477 additions and 10886 deletions

View File

@ -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;
}

View File

@ -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>
);

View File

@ -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 {

View File

@ -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,

View File

@ -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}

View File

@ -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>
&nbsp;&nbsp;
<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>
&nbsp;&nbsp;
<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>