Skip nav animation in empty state
This commit is contained in:
parent
6c73b14b85
commit
8c6e406904
@ -6,10 +6,8 @@ import {
|
||||
DEFAULT_THEME,
|
||||
PRESERVE_ORIGINAL_UPLOADS,
|
||||
META_DESCRIPTION,
|
||||
NAV_TITLE,
|
||||
META_TITLE,
|
||||
HTML_LANG,
|
||||
NAV_CAPTION,
|
||||
SITE_FEEDS_ENABLED,
|
||||
ADMIN_DEBUG_TOOLS_ENABLED,
|
||||
} from '@/app/config';
|
||||
@ -104,10 +102,7 @@ export default function RootLayout({
|
||||
'mx-3 mb-3',
|
||||
'lg:mx-6 lg:mb-6',
|
||||
)}>
|
||||
<Nav
|
||||
navTitle={NAV_TITLE}
|
||||
navCaption={NAV_CAPTION}
|
||||
/>
|
||||
<Nav />
|
||||
<main>
|
||||
<ShareModals />
|
||||
<RecipeModal />
|
||||
|
||||
@ -866,7 +866,7 @@ export default function AdminAppConfigurationClient({
|
||||
titleShort={(section as AdminConfigSection).titleShort}
|
||||
icon={section.icon}
|
||||
optional={!section.required}
|
||||
updateHashOnVisible={hasScrolled}
|
||||
updateHashOnVisible={hasScrolled && !simplifiedView}
|
||||
>
|
||||
{renderGroupContent(section.title)}
|
||||
</ChecklistGroup>
|
||||
|
||||
125
src/app/Nav.tsx
125
src/app/Nav.tsx
@ -1,117 +1,12 @@
|
||||
'use client';
|
||||
import { getPhotosCached } from '@/photo/cache';
|
||||
import NavClient from './NavClient';
|
||||
import { NAV_CAPTION, NAV_TITLE } from './config';
|
||||
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import AppGrid from '../components/AppGrid';
|
||||
import AppViewSwitcher, { SwitcherSelection } from '@/app/AppViewSwitcher';
|
||||
import {
|
||||
PATH_ROOT,
|
||||
isPathAdmin,
|
||||
isPathFull,
|
||||
isPathGrid,
|
||||
isPathProtected,
|
||||
isPathSignIn,
|
||||
} from '@/app/path';
|
||||
import AnimateItems from '../components/AnimateItems';
|
||||
import {
|
||||
GRID_HOMEPAGE_ENABLED,
|
||||
NAV_CAPTION,
|
||||
} from './config';
|
||||
import { useRef } from 'react';
|
||||
import useStickyNav from './useStickyNav';
|
||||
import { useAppState } from '@/app/AppState';
|
||||
|
||||
const NAV_HEIGHT_CLASS = NAV_CAPTION
|
||||
? 'min-h-[4rem] sm:min-h-[5rem]'
|
||||
: 'min-h-[4rem]';
|
||||
|
||||
export default function Nav({
|
||||
navTitle,
|
||||
navCaption,
|
||||
}: {
|
||||
navTitle: string
|
||||
navCaption?: string
|
||||
}) {
|
||||
const ref = useRef<HTMLElement>(null);
|
||||
|
||||
const pathname = usePathname();
|
||||
const showNav = !isPathSignIn(pathname);
|
||||
|
||||
const {
|
||||
hasLoadedWithAnimations,
|
||||
} = useAppState();
|
||||
|
||||
const {
|
||||
classNameStickyContainer,
|
||||
classNameStickyNav,
|
||||
isNavVisible,
|
||||
} = useStickyNav(ref, !isPathAdmin(pathname));
|
||||
|
||||
const renderLink = (
|
||||
text: string,
|
||||
linkOrAction: string | (() => void),
|
||||
) =>
|
||||
typeof linkOrAction === 'string'
|
||||
? <Link href={linkOrAction}>{text}</Link>
|
||||
: <button onClick={linkOrAction} type="button">{text}</button>;
|
||||
|
||||
const switcherSelectionForPath = (): SwitcherSelection | undefined => {
|
||||
if (pathname === PATH_ROOT) {
|
||||
return GRID_HOMEPAGE_ENABLED ? 'grid' : 'full';
|
||||
} else if (isPathGrid(pathname)) {
|
||||
return 'grid';
|
||||
} else if (isPathFull(pathname)) {
|
||||
return 'full';
|
||||
} else if (isPathProtected(pathname)) {
|
||||
return 'admin';
|
||||
export default async function Nav() {
|
||||
const photos = await getPhotosCached({ limit: 1 }).catch(() => []);
|
||||
return <NavClient
|
||||
navTitle={NAV_TITLE}
|
||||
navCaption={NAV_CAPTION}
|
||||
animate={photos.length > 0}
|
||||
/>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AppGrid
|
||||
className={classNameStickyContainer}
|
||||
classNameMain='pointer-events-auto'
|
||||
contentMain={
|
||||
<AnimateItems
|
||||
animateOnFirstLoadOnly
|
||||
type={!isPathAdmin(pathname) ? 'bottom' : 'none'}
|
||||
distanceOffset={10}
|
||||
items={showNav
|
||||
? [<nav
|
||||
key="nav"
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'w-full flex items-center bg-main',
|
||||
NAV_HEIGHT_CLASS,
|
||||
// Enlarge nav to ensure it fully masks underlying content
|
||||
'md:w-[calc(100%+8px)] md:translate-x-[-4px] md:px-[4px]',
|
||||
classNameStickyNav,
|
||||
)}>
|
||||
<AppViewSwitcher
|
||||
currentSelection={switcherSelectionForPath()}
|
||||
className="translate-x-[-1px]"
|
||||
animate={hasLoadedWithAnimations && isNavVisible}
|
||||
/>
|
||||
<div className={clsx(
|
||||
'grow text-right min-w-0',
|
||||
'translate-y-[-1px]',
|
||||
)}>
|
||||
<div className="truncate overflow-hidden select-none">
|
||||
{renderLink(navTitle, PATH_ROOT)}
|
||||
</div>
|
||||
{navCaption &&
|
||||
<div className={clsx(
|
||||
'hidden sm:block truncate overflow-hidden',
|
||||
'leading-tight text-dim',
|
||||
)}>
|
||||
{navCaption}
|
||||
</div>}
|
||||
</div>
|
||||
</nav>]
|
||||
: []}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
119
src/app/NavClient.tsx
Normal file
119
src/app/NavClient.tsx
Normal file
@ -0,0 +1,119 @@
|
||||
'use client';
|
||||
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import AppGrid from '../components/AppGrid';
|
||||
import AppViewSwitcher, { SwitcherSelection } from '@/app/AppViewSwitcher';
|
||||
import {
|
||||
PATH_ROOT,
|
||||
isPathAdmin,
|
||||
isPathFull,
|
||||
isPathGrid,
|
||||
isPathProtected,
|
||||
isPathSignIn,
|
||||
} from '@/app/path';
|
||||
import AnimateItems from '../components/AnimateItems';
|
||||
import {
|
||||
GRID_HOMEPAGE_ENABLED,
|
||||
NAV_CAPTION,
|
||||
} from './config';
|
||||
import { useRef } from 'react';
|
||||
import useStickyNav from './useStickyNav';
|
||||
import { useAppState } from '@/app/AppState';
|
||||
|
||||
const NAV_HEIGHT_CLASS = NAV_CAPTION
|
||||
? 'min-h-[4rem] sm:min-h-[5rem]'
|
||||
: 'min-h-[4rem]';
|
||||
|
||||
export default function NavClient({
|
||||
navTitle,
|
||||
navCaption,
|
||||
animate,
|
||||
}: {
|
||||
navTitle: string
|
||||
navCaption?: string
|
||||
animate: boolean
|
||||
}) {
|
||||
const ref = useRef<HTMLElement>(null);
|
||||
|
||||
const pathname = usePathname();
|
||||
const showNav = !isPathSignIn(pathname);
|
||||
|
||||
const {
|
||||
hasLoadedWithAnimations,
|
||||
} = useAppState();
|
||||
|
||||
const {
|
||||
classNameStickyContainer,
|
||||
classNameStickyNav,
|
||||
isNavVisible,
|
||||
} = useStickyNav(ref, !isPathAdmin(pathname));
|
||||
|
||||
const renderLink = (
|
||||
text: string,
|
||||
linkOrAction: string | (() => void),
|
||||
) =>
|
||||
typeof linkOrAction === 'string'
|
||||
? <Link href={linkOrAction}>{text}</Link>
|
||||
: <button onClick={linkOrAction} type="button">{text}</button>;
|
||||
|
||||
const switcherSelectionForPath = (): SwitcherSelection | undefined => {
|
||||
if (pathname === PATH_ROOT) {
|
||||
return GRID_HOMEPAGE_ENABLED ? 'grid' : 'full';
|
||||
} else if (isPathGrid(pathname)) {
|
||||
return 'grid';
|
||||
} else if (isPathFull(pathname)) {
|
||||
return 'full';
|
||||
} else if (isPathProtected(pathname)) {
|
||||
return 'admin';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AppGrid
|
||||
className={classNameStickyContainer}
|
||||
classNameMain='pointer-events-auto'
|
||||
contentMain={
|
||||
<AnimateItems
|
||||
animateOnFirstLoadOnly
|
||||
type={animate && !isPathAdmin(pathname) ? 'bottom' : 'none'}
|
||||
distanceOffset={10}
|
||||
items={showNav
|
||||
? [<nav
|
||||
key="nav"
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'w-full flex items-center bg-main',
|
||||
NAV_HEIGHT_CLASS,
|
||||
// Enlarge nav to ensure it fully masks underlying content
|
||||
'md:w-[calc(100%+8px)] md:translate-x-[-4px] md:px-[4px]',
|
||||
classNameStickyNav,
|
||||
)}>
|
||||
<AppViewSwitcher
|
||||
currentSelection={switcherSelectionForPath()}
|
||||
className="translate-x-[-1px]"
|
||||
animate={hasLoadedWithAnimations && isNavVisible}
|
||||
/>
|
||||
<div className={clsx(
|
||||
'grow text-right min-w-0',
|
||||
'translate-y-[-1px]',
|
||||
)}>
|
||||
<div className="truncate overflow-hidden select-none">
|
||||
{renderLink(navTitle, PATH_ROOT)}
|
||||
</div>
|
||||
{navCaption &&
|
||||
<div className={clsx(
|
||||
'hidden sm:block truncate overflow-hidden',
|
||||
'leading-tight text-dim',
|
||||
)}>
|
||||
{navCaption}
|
||||
</div>}
|
||||
</div>
|
||||
</nav>]
|
||||
: []}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -11,7 +11,6 @@ import { revalidatePath } from 'next/cache';
|
||||
import SignInOrUploadClient from '@/admin/SignInOrUploadClient';
|
||||
import Link from 'next/link';
|
||||
import { PATH_ADMIN_CONFIGURATION } from '@/app/path';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import { getAppText } from '@/i18n/state/server';
|
||||
|
||||
export default async function PhotosEmptyState() {
|
||||
@ -20,8 +19,6 @@ export default async function PhotosEmptyState() {
|
||||
return (
|
||||
<AppGrid
|
||||
contentMain={
|
||||
<AnimateItems
|
||||
items={[
|
||||
<Container
|
||||
key="PhotosEmptyState"
|
||||
className="min-h-[20rem] sm:min-h-[30rem] px-8"
|
||||
@ -61,9 +58,7 @@ export default async function PhotosEmptyState() {
|
||||
</Link>
|
||||
</div>
|
||||
</div>}
|
||||
</Container>,
|
||||
]}
|
||||
/>
|
||||
</Container>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user