diff --git a/packages/logos-docusaurus-preset/src/index.ts b/packages/logos-docusaurus-preset/src/index.ts index 3f9d015..1770882 100644 --- a/packages/logos-docusaurus-preset/src/index.ts +++ b/packages/logos-docusaurus-preset/src/index.ts @@ -82,6 +82,7 @@ export default function logosPreset( }) plugins.push('docusaurus-plugin-sass') + themes.push('@docusaurus/theme-mermaid') if (options.theme?.name !== ThemeNames.DocusaurusDefault) plugins.push( diff --git a/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx b/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx index 3f703f7..d295671 100644 --- a/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx +++ b/packages/logos-docusaurus-theme/src/client/components/Icon/Icon.tsx @@ -24,6 +24,8 @@ import StatusSvg from '../../static/icons/status.svg' import TelegramSvg from '../../static/icons/telegram.svg' import TwitterSvg from '../../static/icons/twitter.svg' import EditSvg from '../../static/icons/edit.svg' +import FullscreenSvg from '../../static/icons/fullscreen.svg' +import FullscreenExitSvg from '../../static/icons/fullscreen-exit.svg' type TIconProps = { size?: 's' | 'm' | 'l' @@ -178,3 +180,15 @@ export const IconEdit = (props: TIconProps): JSX.Element => ( ) + +export const IconFullscreen = (props: TIconProps): JSX.Element => ( + + + +) + +export const IconFullscreenExit = (props: TIconProps): JSX.Element => ( + + + +) diff --git a/packages/logos-docusaurus-theme/src/client/containers/LightBox/LightBox.tsx b/packages/logos-docusaurus-theme/src/client/containers/LightBox/LightBox.tsx new file mode 100644 index 0000000..c4c678a --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/containers/LightBox/LightBox.tsx @@ -0,0 +1,161 @@ +import { IconButton } from '@acid-info/lsd-react' +import NavbarLogo from '@theme/Navbar/Logo' +import clsx from 'clsx' +import React, { + CSSProperties, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from 'react' +import { useWindowScroll } from 'react-use' +import { IconFullscreen, IconFullscreenExit } from '../../components/Icon/Icon' +import { Portal } from '../../components/Portal/Portal' +import { useHydrated } from '../../lib/useHydrated' +import styles from './styles.module.scss' + +export const LightBoxProvider: React.FC> = ({ + children, +}) => { + const hydrated = useHydrated() + const scroll = useWindowScroll() + const [active, setActive] = useState(null) + const [activeStyle, setActiveStyle] = useState({ + opacity: '0.5', + }) + + const style: React.CSSProperties = useMemo(() => { + return { + opacity: 1, + transform: 'scale(1) translate(0px, 0px)', + transition: '0.3s', + } + }, [active]) + + const display = (element: HTMLElement) => { + setActive(element) + + const vw = document.body.clientWidth + const vh = document.body.clientHeight + + const maxWidth = window.innerWidth > 768 ? vw * 0.9375 : vw - 32 + const maxHeight = vh - 128 + + const rect = element.getBoundingClientRect() + + const scale = Math.min(maxHeight / rect.height, maxWidth / rect.width) + + const center = [rect.left + rect.width / 2, rect.top + rect.height / 2] + const windowCenter = [vw / 2, vh / 2] + + const translate = windowCenter.map((w, i) => (w - center[i]!) / scale) + + setActiveStyle({ + zIndex: 202, + transform: `scale(${scale}) translate(${translate[0]}px, ${translate[1]}px)`, + position: 'relative', + }) + } + + const close = () => { + setActive(null) + } + + const toggle = (element: HTMLElement) => { + const current = active + + close() + current !== element && display(element) + } + + useEffect(() => { + if (active && window.innerWidth > 768) close() + }, [scroll]) + + return ( + + {children} + {hydrated && ( + +
+ +
+
+ )} +
+ ) +} + +export type LightBoxContextType = { + active: HTMLElement | null + display: (element: HTMLElement) => void + close: () => void + toggle: (element: HTMLElement) => void + style: React.CSSProperties + activeStyle: React.CSSProperties +} + +export const LightBoxContext = React.createContext({ + style: {}, + activeStyle: {}, + active: null, + close: null as any, + toggle: null as any, + display: null as any, +}) + +export const useLightBox = () => { + const ctx = useContext(LightBoxContext) + + const getStyle = (element: HTMLElement) => ({ + ...ctx.style, + ...(element === ctx.active ? ctx.activeStyle : {}), + }) + + return { + getStyle, + style: ctx.style, + activeStyle: ctx.activeStyle, + active: ctx.active, + isActive: !!ctx.active, + close: ctx.close, + toggle: ctx.toggle, + display: ctx.display, + isActiveElement: (el: HTMLElement) => ctx.active === el, + } +} + +export const LightBoxWrapper: React.FC> = ({ + children, +}) => { + const ref = useRef(null) + const { getStyle, display, isActiveElement } = useLightBox() + + return ( +
+ {children} + ref.current && display(ref.current)} + > + + +
+ ) +} diff --git a/packages/logos-docusaurus-theme/src/client/containers/LightBox/index.ts b/packages/logos-docusaurus-theme/src/client/containers/LightBox/index.ts new file mode 100644 index 0000000..db087a9 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/containers/LightBox/index.ts @@ -0,0 +1 @@ +export * from './LightBox' diff --git a/packages/logos-docusaurus-theme/src/client/containers/LightBox/styles.module.scss b/packages/logos-docusaurus-theme/src/client/containers/LightBox/styles.module.scss new file mode 100644 index 0000000..5284325 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/containers/LightBox/styles.module.scss @@ -0,0 +1,69 @@ +@use '../../css/utils'; + +.nav { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgb(var(--lsd-surface-primary)); + z-index: 201; + opacity: 0; + visibility: hidden; +} + +.visible { + opacity: 1; + visibility: visible; +} + +.nav > nav { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + height: var(--ifm-navbar-height); + max-width: var(--container-max-width); + margin: 0 auto; + padding: var(--ifm-navbar-padding-vertical) + var(--ifm-navbar-padding-horizontal); +} + +.wrapper { + position: relative; + + .fullscreenButton { + display: none; + } + + &:not(.active) { + .fullscreenButton { + display: block; + transition: 0.3s; + position: absolute; + bottom: 8px; + right: 8px; + background: rgb(var(--lsd-surface-primary)); + } + + @include utils.responsive('lg', 'up') { + .fullscreenButton { + display: block; + opacity: 0; + visibility: hidden; + transition: 0.3s; + position: absolute; + bottom: 8px; + right: 8px; + background: rgb(var(--lsd-surface-primary)); + } + + &:hover { + .fullscreenButton { + visibility: visible; + opacity: 1; + } + } + } + } +} diff --git a/packages/logos-docusaurus-theme/src/client/static/icons/fullscreen-exit.svg b/packages/logos-docusaurus-theme/src/client/static/icons/fullscreen-exit.svg new file mode 100644 index 0000000..3c283ba --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/static/icons/fullscreen-exit.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/logos-docusaurus-theme/src/client/static/icons/fullscreen.svg b/packages/logos-docusaurus-theme/src/client/static/icons/fullscreen.svg new file mode 100644 index 0000000..3dc6da7 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/static/icons/fullscreen.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/logos-docusaurus-theme/src/client/theme/MDXComponents/Img/index.tsx b/packages/logos-docusaurus-theme/src/client/theme/MDXComponents/Img/index.tsx new file mode 100644 index 0000000..f98178e --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/MDXComponents/Img/index.tsx @@ -0,0 +1,15 @@ +import Img from '@docusaurus/theme-classic/lib/theme/MDXComponents/Img' +import type { WrapperProps } from '@docusaurus/types' +import type ImgType from '@theme/MDXComponents/Img' +import React from 'react' +import { LightBoxWrapper } from '../../../containers/LightBox/LightBox' + +type Props = WrapperProps + +export default function ImgWrapper(props: Props): JSX.Element { + return ( + + + + ) +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/Mermaid/index.tsx b/packages/logos-docusaurus-theme/src/client/theme/Mermaid/index.tsx new file mode 100644 index 0000000..71a58e1 --- /dev/null +++ b/packages/logos-docusaurus-theme/src/client/theme/Mermaid/index.tsx @@ -0,0 +1,16 @@ +// @ts-ignore +import Mermaid from '@docusaurus/theme-mermaid/lib/theme/Mermaid' +import type { WrapperProps } from '@docusaurus/types' +import type MermaidType from '@theme/Mermaid' +import React from 'react' +import { LightBoxWrapper } from '../../containers/LightBox/LightBox' + +type Props = WrapperProps + +export default function MermaidWrapper(props: Props): JSX.Element { + return ( + + + + ) +} diff --git a/packages/logos-docusaurus-theme/src/client/theme/Root.tsx b/packages/logos-docusaurus-theme/src/client/theme/Root.tsx index 4231b8f..7713eb1 100644 --- a/packages/logos-docusaurus-theme/src/client/theme/Root.tsx +++ b/packages/logos-docusaurus-theme/src/client/theme/Root.tsx @@ -1,5 +1,6 @@ import { ColorModeProvider } from '@docusaurus/theme-common/internal' import React from 'react' +import { LightBoxProvider } from '../containers/LightBox/LightBox' import { ThemeProvider } from '../containers/ThemeProvider' import { useDocThemeOptions } from '../lib/useThemeOptions' import styles from './style.module.css' @@ -11,9 +12,11 @@ export default function Root({ children }) { return ( -
- {children} -
+ +
+ {children} +
+
)