-
-
Notifications
You must be signed in to change notification settings - Fork 641
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
feat: add fullscreen mode for documentation pages #3365
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,54 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import type { ReactNode } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import React, { useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
interface FullscreenProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
children: ReactNode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const FullscreenToggle: React.FC<FullscreenProps> = ({ children, className = '' }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [isFullscreen, setIsFullscreen] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const toggleFullscreen = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (document.fullscreenElement) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
document | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.exitFullscreen() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.then(() => setIsFullscreen(false)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.catch((err) => console.error('Error attempting to exit fullscreen:', err)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
document.documentElement | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.requestFullscreen() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.then(() => setIsFullscreen(true)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.catch((err) => console.error('Error attempting to enable fullscreen:', err)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+12
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance error handling and browser compatibility The current implementation has two potential issues:
+ const isFullscreenSupported = () => {
+ return document.fullscreenEnabled ||
+ document.webkitFullscreenEnabled ||
+ document.mozFullScreenEnabled ||
+ document.msFullscreenEnabled;
+ };
+
const toggleFullscreen = () => {
+ if (!isFullscreenSupported()) {
+ alert('Fullscreen mode is not supported in your browser');
+ return;
+ }
+
if (document.fullscreenElement) {
document
.exitFullscreen()
.then(() => setIsFullscreen(false))
- .catch((err) => console.error('Error attempting to exit fullscreen:', err));
+ .catch((err) => {
+ console.error('Error attempting to exit fullscreen:', err);
+ alert('Failed to exit fullscreen mode. Please try using Escape key.');
+ });
} else {
document.documentElement
.requestFullscreen()
.then(() => setIsFullscreen(true))
- .catch((err) => console.error('Error attempting to enable fullscreen:', err));
+ .catch((err) => {
+ console.error('Error attempting to enable fullscreen:', err);
+ alert('Failed to enter fullscreen mode. This might be due to browser restrictions.');
+ });
}
}; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className={`relative ${className}`}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onClick={toggleFullscreen} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className='fixed right-4 top-4 z-50 rounded-lg border border-gray-200 bg-white | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
p-2 shadow-sm transition-colors duration-200 hover:bg-gray-50' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{isFullscreen ? ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<svg className='size-5 text-gray-700' fill='none' stroke='currentColor' viewBox='0 0 24 24'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M6 18L18 6M6 6l12 12' /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</svg> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) : ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<svg className='size-5 text-gray-700' fill='none' stroke='currentColor' viewBox='0 0 24 24'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
strokeLinecap='round' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
strokeLinejoin='round' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
strokeWidth={2} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
d='M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</svg> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default FullscreenToggle; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -13,6 +13,7 @@ import { getAllPosts } from '../../utils/api'; | |||||
import Button from '../buttons/Button'; | ||||||
import DocsButton from '../buttons/DocsButton'; | ||||||
import Feedback from '../Feedback'; | ||||||
import FullscreenToggle from '../FullScreenToggle'; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix inconsistent casing in import path The import statement uses 'FullScreenToggle' while the component is named 'FullscreenToggle'. This inconsistency could cause issues on case-sensitive filesystems. -import FullscreenToggle from '../FullScreenToggle';
+import FullscreenToggle from '../FullscreenToggle'; 📝 Committable suggestion
Suggested change
|
||||||
import Head from '../Head'; | ||||||
import ArrowRight from '../icons/ArrowRight'; | ||||||
import IconMenuCenter from '../icons/CenterMenu'; | ||||||
|
@@ -113,103 +114,105 @@ export default function DocsLayout({ post, navItems = {}, children }: IDocsLayou | |||||
} | ||||||
|
||||||
return ( | ||||||
<DocsContext.Provider value={{ post, navItems }}> | ||||||
<div className='w-full bg-white px-4 sm:px-6 lg:px-8 xl:mx-auto xl:max-w-7xl'> | ||||||
{showMenu && <DocsMobileMenu onClickClose={() => setShowMenu(false)} post={post} navigation={navigation} />} | ||||||
<div className='flex flex-row' id='main-content'> | ||||||
{/* <!-- Static sidebar for desktop --> */} | ||||||
{sidebar} | ||||||
<div className='flex w-0 max-w-full flex-1 flex-col lg:max-w-(screen-16)'> | ||||||
<main className='relative z-0 pb-6 pt-2 focus:outline-none md:py-6' tabIndex={0}> | ||||||
{!showMenu && ( | ||||||
<div className='lg:hidden'> | ||||||
<button | ||||||
onClick={() => setShowMenu(true)} | ||||||
className='flex px-4 text-gray-500 hover:text-gray-900 focus:outline-none sm:px-6 md:px-8' | ||||||
aria-label='Open sidebar' | ||||||
> | ||||||
<span>{post.sectionTitle}</span> | ||||||
<ArrowRight className='size-5 rotate-90 pl-1' /> | ||||||
</button> | ||||||
</div> | ||||||
)} | ||||||
|
||||||
{/* @TODO Will uncomment the component once it is in use */} | ||||||
{/* <AnnouncementHero className='ml-6' hideVideo={true} /> */} | ||||||
|
||||||
<div className={`xl:flex ${post.toc && post.toc.length ? 'xl:flex-row-reverse' : ''}`}> | ||||||
<TOC | ||||||
toc={post.toc} | ||||||
depth={3} | ||||||
className='sticky top-20 mt-4 max-h-screen overflow-y-auto bg-blue-100 p-4 xl:mt-0 xl:w-72 xl:bg-transparent xl:pb-8' | ||||||
/> | ||||||
<div className='px-4 sm:px-6 xl:max-w-184 xl:flex-1 xl:px-8'> | ||||||
<Heading level={HeadingLevel.h1} typeStyle={HeadingTypeStyle.lg}> | ||||||
{post.title} | ||||||
</Heading> | ||||||
<div> | ||||||
<p className='font-normal font-sans text-sm text-gray-600 antialiased'> | ||||||
Found an error? Have a suggestion? | ||||||
{generateEditLink(post)} | ||||||
</p> | ||||||
<FullscreenToggle> | ||||||
<DocsContext.Provider value={{ post, navItems }}> | ||||||
<div className='w-full bg-white px-4 sm:px-6 lg:px-8 xl:mx-auto xl:max-w-7xl'> | ||||||
{showMenu && <DocsMobileMenu onClickClose={() => setShowMenu(false)} post={post} navigation={navigation} />} | ||||||
<div className='flex flex-row' id='main-content'> | ||||||
{/* <!-- Static sidebar for desktop --> */} | ||||||
{sidebar} | ||||||
<div className='flex w-0 max-w-full flex-1 flex-col lg:max-w-(screen-16)'> | ||||||
<main className='relative z-0 pb-6 pt-2 focus:outline-none md:py-6' tabIndex={0}> | ||||||
{!showMenu && ( | ||||||
<div className='lg:hidden'> | ||||||
<button | ||||||
onClick={() => setShowMenu(true)} | ||||||
className='flex px-4 text-gray-500 hover:text-gray-900 focus:outline-none sm:px-6 md:px-8' | ||||||
aria-label='Open sidebar' | ||||||
> | ||||||
<span>{post.sectionTitle}</span> | ||||||
<ArrowRight className='size-5 rotate-90 pl-1' /> | ||||||
</button> | ||||||
</div> | ||||||
{post.releaseNoteLink && ( | ||||||
// show only when it is related to specification (/docs/reference/specification) AND is not a pre-release | ||||||
// for example, if the post's title is "3.0.0 (Pre-release)", which will not have RN, so do not render this section. | ||||||
<div className='mt-5 w-full rounded-lg bg-secondary-100 px-2 py-3 text-center'> | ||||||
<div> | ||||||
<span className='font-sans text-sm text-gray-800 antialiased'> | ||||||
{`What is new in v${post.title}? Have a look at the `} | ||||||
</span> | ||||||
<Link | ||||||
href={post.releaseNoteLink} | ||||||
target='_blank' | ||||||
rel='noopener noreferrer' | ||||||
className={ | ||||||
'cursor-pointer font-body text-sm font-medium leading-6 text-secondary-500 underline transition duration-150 ease-in-out hover:text-secondary-600 focus:text-gray-900 focus:outline-none' | ||||||
} | ||||||
> | ||||||
release notes | ||||||
</Link> | ||||||
. | ||||||
</div> | ||||||
<div> | ||||||
<span className='font-sans text-sm text-gray-800 antialiased'> | ||||||
Interested in release notes of other versions of the specification? | ||||||
</span> | ||||||
<span className='font-sans text-sm text-gray-800 antialiased'> | ||||||
Check | ||||||
)} | ||||||
|
||||||
{/* @TODO Will uncomment the component once it is in use */} | ||||||
{/* <AnnouncementHero className='ml-6' hideVideo={true} /> */} | ||||||
|
||||||
<div className={`xl:flex ${post.toc && post.toc.length ? 'xl:flex-row-reverse' : ''}`}> | ||||||
<TOC | ||||||
toc={post.toc} | ||||||
depth={3} | ||||||
className='sticky top-20 mt-4 max-h-screen overflow-y-auto bg-blue-100 p-4 xl:mt-0 xl:w-72 xl:bg-transparent xl:pb-8' | ||||||
/> | ||||||
<div className='px-4 sm:px-6 xl:max-w-184 xl:flex-1 xl:px-8'> | ||||||
<Heading level={HeadingLevel.h1} typeStyle={HeadingTypeStyle.lg}> | ||||||
{post.title} | ||||||
</Heading> | ||||||
<div> | ||||||
<p className='font-normal font-sans text-sm text-gray-600 antialiased'> | ||||||
Found an error? Have a suggestion? | ||||||
{generateEditLink(post)} | ||||||
</p> | ||||||
</div> | ||||||
{post.releaseNoteLink && ( | ||||||
// show only when it is related to specification (/docs/reference/specification) AND is not a pre-release | ||||||
// for example, if the post's title is "3.0.0 (Pre-release)", which will not have RN, so do not render this section. | ||||||
<div className='mt-5 w-full rounded-lg bg-secondary-100 px-2 py-3 text-center'> | ||||||
<div> | ||||||
<span className='font-sans text-sm text-gray-800 antialiased'> | ||||||
{`What is new in v${post.title}? Have a look at the `} | ||||||
</span> | ||||||
<Link | ||||||
href='https://www.asyncapi.com/blog?tags=Release+Notes' | ||||||
href={post.releaseNoteLink} | ||||||
target='_blank' | ||||||
rel='noopener noreferrer' | ||||||
className={ | ||||||
'cursor-pointer font-body text-sm font-medium leading-6 text-secondary-500 underline transition duration-150 ease-in-out hover:text-secondary-600 focus:text-gray-900 focus:outline-none' | ||||||
} | ||||||
> | ||||||
list of release notes | ||||||
release notes | ||||||
</Link> | ||||||
. | ||||||
</span> | ||||||
</div> | ||||||
<div> | ||||||
<span className='font-sans text-sm text-gray-800 antialiased'> | ||||||
Interested in release notes of other versions of the specification? | ||||||
</span> | ||||||
<span className='font-sans text-sm text-gray-800 antialiased'> | ||||||
Check | ||||||
<Link | ||||||
href='https://www.asyncapi.com/blog?tags=Release+Notes' | ||||||
target='_blank' | ||||||
rel='noopener noreferrer' | ||||||
className={ | ||||||
'cursor-pointer font-body text-sm font-medium leading-6 text-secondary-500 underline transition duration-150 ease-in-out hover:text-secondary-600 focus:text-gray-900 focus:outline-none' | ||||||
} | ||||||
> | ||||||
list of release notes | ||||||
</Link> | ||||||
. | ||||||
</span> | ||||||
</div> | ||||||
</div> | ||||||
)} | ||||||
<article className='my-12'> | ||||||
<Head title={post.title} description={post.excerpt} image={post.cover} /> | ||||||
{children} | ||||||
</article> | ||||||
<div> | ||||||
<DocsButton post={post} /> | ||||||
</div> | ||||||
<div className=''> | ||||||
<Feedback /> | ||||||
</div> | ||||||
)} | ||||||
<article className='my-12'> | ||||||
<Head title={post.title} description={post.excerpt} image={post.cover} /> | ||||||
{children} | ||||||
</article> | ||||||
<div> | ||||||
<DocsButton post={post} /> | ||||||
</div> | ||||||
<div className=''> | ||||||
<Feedback /> | ||||||
</div> | ||||||
</div> | ||||||
</div> | ||||||
</main> | ||||||
</main> | ||||||
</div> | ||||||
</div> | ||||||
</div> | ||||||
</div> | ||||||
</DocsContext.Provider> | ||||||
</DocsContext.Provider> | ||||||
</FullscreenToggle> | ||||||
); | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Sync component state with browser's fullscreen state
The initial state might be incorrect if fullscreen is toggled outside the component. Consider adding a useEffect to sync with the browser's fullscreen state.
📝 Committable suggestion