nicolium: window-controls-overlay improvements
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -54,6 +54,37 @@ const useMinWidth = (query: string) => {
|
||||
return matches;
|
||||
};
|
||||
|
||||
interface WindowControlsOverlay extends EventTarget {
|
||||
visible: boolean;
|
||||
getTitlebarAreaRect(): DOMRect;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Navigator {
|
||||
windowControlsOverlay?: WindowControlsOverlay;
|
||||
}
|
||||
}
|
||||
|
||||
const useWindowControlsOverlay = () => {
|
||||
const getRect = (): DOMRect | null => {
|
||||
const overlay = navigator.windowControlsOverlay;
|
||||
return overlay?.visible ? overlay.getTitlebarAreaRect() : null;
|
||||
};
|
||||
|
||||
const [rect, setRect] = useState<DOMRect | null>(getRect);
|
||||
|
||||
useEffect(() => {
|
||||
const overlay = navigator.windowControlsOverlay;
|
||||
if (!overlay) return;
|
||||
|
||||
const update = () => setRect(overlay.visible ? overlay.getTitlebarAreaRect() : null);
|
||||
overlay.addEventListener('geometrychange', update);
|
||||
return () => overlay.removeEventListener('geometrychange', update);
|
||||
}, []);
|
||||
|
||||
return rect;
|
||||
};
|
||||
|
||||
/** Layout container, to hold Sidebar, Main, and Aside. */
|
||||
const Layout: LayoutComponent = ({ children, fullWidth }) => (
|
||||
<div className='⁂-layout'>
|
||||
@ -70,6 +101,8 @@ const Layout: LayoutComponent = ({ children, fullWidth }) => (
|
||||
/** Left sidebar container in the UI. */
|
||||
const Sidebar: React.FC<ISidebar> = ({ children, shrink }) => {
|
||||
const isVisible = useMinWidth(`(min-width: ${breakpoints.lg})`);
|
||||
const wcoRect = useWindowControlsOverlay();
|
||||
const offsetTop = wcoRect && wcoRect.x > 0 ? 16 + wcoRect.y : 16;
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
@ -77,7 +110,7 @@ const Sidebar: React.FC<ISidebar> = ({ children, shrink }) => {
|
||||
|
||||
return (
|
||||
<div className={clsx('⁂-layout__sidebar', { '⁂-layout__sidebar--shrink': shrink })}>
|
||||
<StickyBox offsetTop={16} className='⁂-layout__sidebar__content'>
|
||||
<StickyBox offsetTop={offsetTop} className='⁂-layout__sidebar__content'>
|
||||
{children}
|
||||
</StickyBox>
|
||||
</div>
|
||||
@ -106,6 +139,8 @@ const Main: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ children, classN
|
||||
/** Right sidebar container in the UI. */
|
||||
const Aside: React.FC<IAside> = ({ children }) => {
|
||||
const isVisible = useMinWidth(`(min-width: ${breakpoints.xl})`);
|
||||
const wcoRect = useWindowControlsOverlay();
|
||||
const offsetTop = wcoRect && wcoRect.x + wcoRect.width < window.innerWidth ? 16 + wcoRect.y : 16;
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
@ -113,7 +148,7 @@ const Aside: React.FC<IAside> = ({ children }) => {
|
||||
|
||||
return (
|
||||
<aside className='⁂-layout__aside'>
|
||||
<StickyBox offsetTop={16} className='⁂-layout__aside__content'>
|
||||
<StickyBox offsetTop={offsetTop} className='⁂-layout__aside__content'>
|
||||
<Suspense>{children}</Suspense>
|
||||
</StickyBox>
|
||||
</aside>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
|
||||
import InlineStyle from '@/components/inline-style';
|
||||
import { useFrontendConfig } from '@/hooks/use-frontend-config';
|
||||
@ -25,6 +25,7 @@ const PlFeHead = () => {
|
||||
} = useSettings();
|
||||
const frontendConfig = useFrontendConfig();
|
||||
const theme = useTheme();
|
||||
const [wcoVisible, setWcoVisible] = React.useState(false);
|
||||
|
||||
const withModals = useHasModals();
|
||||
|
||||
@ -45,6 +46,22 @@ const PlFeHead = () => {
|
||||
}
|
||||
}, [dsn]);
|
||||
|
||||
useEffect(() => {
|
||||
const overlay = navigator.windowControlsOverlay;
|
||||
if (!overlay) return;
|
||||
|
||||
const update = () => setWcoVisible(overlay.visible);
|
||||
overlay.addEventListener('geometrychange', update);
|
||||
return () => overlay.removeEventListener('geometrychange', update);
|
||||
}, []);
|
||||
|
||||
const color = useMemo(() => {
|
||||
if (wcoVisible) {
|
||||
return window.getComputedStyle(document.body, null).getPropertyValue('background-color');
|
||||
}
|
||||
return frontendConfig.brandColor;
|
||||
}, [frontendConfig.brandColor, theme, wcoVisible]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
@ -53,10 +70,11 @@ const PlFeHead = () => {
|
||||
className={clsx(`text-${themeSettings?.interfaceSize ?? 'md'}`, {
|
||||
dark: theme === 'dark',
|
||||
'black dark': theme === 'black',
|
||||
'window-controls-overlay': wcoVisible,
|
||||
})}
|
||||
/>
|
||||
<body className={bodyClass} dir={direction} />
|
||||
<meta name='theme-color' content={frontendConfig.brandColor} />
|
||||
<meta name='theme-color' content={color} />
|
||||
</Helmet>
|
||||
<InlineStyle>{`:root { ${themeCss} }`}</InlineStyle>
|
||||
{['dark', 'black'].includes(theme) && (
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@use 'mixins';
|
||||
@use 'variables';
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
@ -373,6 +374,14 @@ body {
|
||||
&--chats {
|
||||
@apply xl:pb-16;
|
||||
}
|
||||
|
||||
&:is(.window-controls-overlay *) {
|
||||
padding-top: env(titlebar-area-height);
|
||||
|
||||
@media (min-width: variables.$breakpoint-lg) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__aside {
|
||||
|
||||
Reference in New Issue
Block a user