mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(docs-gpt): improved mobile responsiveness
This commit is contained in:
1 parent
a0b016ae84
commit
1bc133596c
6 files changed
+103
-52
No files matched your search
@@ -1,67 +1,30 @@
|
||||
import { useTheme } from 'common/Providers'
|
||||
import Image from 'next/image'
|
||||
import { FC, useCallback, useEffect, useState } from 'react'
|
||||
import { FC } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import clippyImageDark from '../../public/img/clippy-dark.png'
|
||||
import clippyImage from '../../public/img/clippy.png'
|
||||
import ClippyBubble from './ClippyBubble'
|
||||
import ClippyModal from './ClippyModal'
|
||||
import { useClippy } from './ClippyProvider'
|
||||
|
||||
const Clippy: FC = () => {
|
||||
const { isDarkMode } = useTheme()
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
|
||||
const onOpen = useCallback(() => {
|
||||
setIsModalOpen(true)
|
||||
document.body.classList.add('DocSearch--active')
|
||||
}, [])
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
setIsModalOpen(false)
|
||||
document.body.classList.remove('DocSearch--active')
|
||||
}, [])
|
||||
|
||||
useSearchKeyboardEvents({
|
||||
onOpen,
|
||||
onClose,
|
||||
})
|
||||
const { isOpen, open, close } = useClippy()
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isModalOpen && (
|
||||
<div className="flex flex-col items-end gap-1 md:gap-4">
|
||||
<ClippyBubble onClick={onOpen} />
|
||||
<div className="w-[120px] md:w-[150px] p-8 md:p-0">
|
||||
{!isOpen && (
|
||||
<div className="hidden md:flex flex-col items-end gap-1 md:gap-4">
|
||||
<ClippyBubble onClick={open} />
|
||||
<div className="w-[100px] lg:w-[150px] p-8 md:p-0">
|
||||
<Image src={isDarkMode ? clippyImageDark : clippyImage} alt="Clippy" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isModalOpen && createPortal(<ClippyModal onClose={onClose} />, document.body)}
|
||||
{isOpen && createPortal(<ClippyModal onClose={close} />, document.body)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Clippy
|
||||
|
||||
function useSearchKeyboardEvents({ onOpen, onClose }) {
|
||||
useEffect(() => {
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
onClose()
|
||||
return
|
||||
case 'j':
|
||||
if (event.metaKey || event.ctrlKey) {
|
||||
onOpen()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', onKeyDown)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', onKeyDown)
|
||||
}
|
||||
}, [onOpen, onClose])
|
||||
}
|
||||
@@ -9,7 +9,7 @@ interface Props {
|
||||
const ClippyBubble: FC<Props> = ({ className, onClick }) => {
|
||||
return (
|
||||
<div
|
||||
className={`flex gap-2 border bg-white dark:bg-scale-300 relative rounded-xl p-6 max-w-sm md:max-w-xs shadow-xl mb-1 md:mb-4 cursor-pointer hover:bg-scale-200 transition-colors border-scale-500 hover:border-scale-700 ${className}`}
|
||||
className={`flex gap-2 border bg-white dark:bg-scale-300 relative rounded-xl p-4 lg:p-6 max-w-sm lg:max-w-xs shadow-xl mb-1 lg:mb-4 cursor-pointer hover:bg-scale-200 transition-colors border-scale-500 hover:border-scale-700 ${className}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<img
|
||||
|
||||
@@ -104,7 +104,7 @@ const ClippyModal: FC<Props> = ({ onClose }) => {
|
||||
return (
|
||||
<Modal size="xlarge" visible={true} onCancel={onClose} closable={false} hideFooter>
|
||||
<div
|
||||
className={`mx-auto max-h-[75vh] flex flex-col gap-4 rounded-lg p-4 md:pt-6 md:px-6 pb-2 w-full max-w-3xl shadow-2xl overflow-hidden border text-left border-scale-500 bg-scale-100 dark:bg-scale-300 cursor-auto relative min-w-[340px]`}
|
||||
className={`mx-auto max-h-[75vh] flex flex-col gap-4 rounded-lg p-4 md:pt-6 md:px-6 pb-2 w-full shadow-2xl overflow-hidden border text-left border-scale-500 bg-scale-100 dark:bg-scale-300 cursor-auto relative min-w-[340px]`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="relative">
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
createContext,
|
||||
FC,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react'
|
||||
|
||||
export type ClippyContextValue = {
|
||||
isOpen: boolean
|
||||
open: () => void
|
||||
close: () => void
|
||||
}
|
||||
|
||||
export const ClippyContext = createContext<ClippyContextValue>(null)
|
||||
|
||||
export const useClippy = () => {
|
||||
const { isOpen, open, close } = useContext(ClippyContext)
|
||||
|
||||
return { isOpen, open, close }
|
||||
}
|
||||
|
||||
const ClippyProvider: FC<PropsWithChildren<{}>> = ({ children }) => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
|
||||
const onOpen = useCallback(() => {
|
||||
setIsModalOpen(true)
|
||||
document.body.classList.add('DocSearch--active')
|
||||
}, [])
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
setIsModalOpen(false)
|
||||
document.body.classList.remove('DocSearch--active')
|
||||
}, [])
|
||||
|
||||
useSearchKeyboardEvents({
|
||||
onOpen,
|
||||
onClose,
|
||||
})
|
||||
return (
|
||||
<ClippyContext.Provider value={{ isOpen: isModalOpen, open: onOpen, close: onClose }}>
|
||||
{children}
|
||||
</ClippyContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
function useSearchKeyboardEvents({ onOpen, onClose }) {
|
||||
useEffect(() => {
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
onClose()
|
||||
return
|
||||
case 'j':
|
||||
if (event.metaKey || event.ctrlKey) {
|
||||
onOpen()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', onKeyDown)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', onKeyDown)
|
||||
}
|
||||
}, [onOpen, onClose])
|
||||
}
|
||||
|
||||
export default ClippyProvider
|
||||
@@ -6,13 +6,17 @@ import { Button, IconCommand, IconGitHub, IconMoon, IconSearch, IconSun } from '
|
||||
import { SearchButton } from '~/components/DocSearch'
|
||||
import { REFERENCES } from '~/components/Navigation/Navigation.constants'
|
||||
import { useTheme } from 'common/Providers'
|
||||
import clippyImageDark from '../../../public/img/clippy-dark.png'
|
||||
import clippyImage from '../../../public/img/clippy.png'
|
||||
|
||||
import { getPageType } from '~/lib/helpers'
|
||||
import { useClippy } from '~/components/Clippy/ClippyProvider'
|
||||
|
||||
const TopNavBarRef: FC = () => {
|
||||
const { isDarkMode, toggleTheme } = useTheme()
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const { open: openClippy } = useClippy()
|
||||
|
||||
const { asPath, push } = useRouter()
|
||||
const pathSegments = asPath.split('/')
|
||||
@@ -84,8 +88,17 @@ const TopNavBarRef: FC = () => {
|
||||
{/* {router.asPath.includes('/reference/') && <RefSwitcher />} */}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-12">
|
||||
<SearchButton className="w-full lg:w-96">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex md:hidden cursor-pointer">
|
||||
<Image
|
||||
onClick={openClippy}
|
||||
width={26}
|
||||
height={29}
|
||||
src={isDarkMode ? clippyImageDark : clippyImage}
|
||||
alt="Clippy"
|
||||
/>
|
||||
</div>
|
||||
<SearchButton className="md:w-full lg:w-96">
|
||||
<div
|
||||
className="
|
||||
flex
|
||||
|
||||
@@ -5,6 +5,7 @@ import { DefaultSeo } from 'next-seo'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { AppPropsWithLayout } from 'types'
|
||||
import ClippyProvider from '~/components/Clippy/ClippyProvider'
|
||||
import { SearchProvider } from '~/components/DocSearch'
|
||||
import Favicons from '~/components/Favicons'
|
||||
import SiteLayout from '~/layouts/SiteLayout'
|
||||
@@ -87,9 +88,11 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
<SessionContextProvider supabaseClient={supabase}>
|
||||
<ThemeProvider>
|
||||
<SearchProvider>
|
||||
<SiteLayout>
|
||||
<Component {...pageProps} />
|
||||
</SiteLayout>
|
||||
<ClippyProvider>
|
||||
<SiteLayout>
|
||||
<Component {...pageProps} />
|
||||
</SiteLayout>
|
||||
</ClippyProvider>
|
||||
</SearchProvider>
|
||||
</ThemeProvider>
|
||||
</SessionContextProvider>
|
||||
|
||||
Reference in new issue
Block a user