feat(mobile): pwa and browser theme-color optimization (#8168)

[AF-1325](https://linear.app/affine-design/issue/AF-1325/优化-pwa-体验), [AF-1317](https://linear.app/affine-design/issue/AF-1317/优化:-pwa-的顶部-status-bar-颜色应与背景保持一致), [AF-1318](https://linear.app/affine-design/issue/AF-1318/优化:pwa-的底部应当有符合设备安全高度的padding), [AF-1321](https://linear.app/affine-design/issue/AF-1321/更新一下-fail-的-pwa-icon)

- New `<SafeArea />` ui component
- New `useThemeColorV1` / `useThemeColorV2` hook:
    - to modify `<meta name="theme-color" />` with given theme key
This commit is contained in:
CatsJuice
2024-09-11 02:20:59 +00:00
parent 9038592715
commit 81ab8ac8b3
31 changed files with 329 additions and 133 deletions

View File

@@ -111,10 +111,6 @@ export const MobileMenu = ({
className: clsx(className, styles.mobileMenuModal),
...otherContentOptions,
}}
contentWrapperStyle={{
alignItems: 'end',
paddingBottom: 10,
}}
>
<div
ref={setSliderElement}

View File

@@ -15,6 +15,7 @@ import { forwardRef, useCallback, useEffect, useState } from 'react';
import { startScopedViewTransition } from '../../utils';
import type { IconButtonProps } from '../button';
import { IconButton } from '../button';
import { SafeArea } from '../safe-area';
import * as styles from './styles.css';
export interface ModalProps extends DialogProps {
@@ -214,7 +215,9 @@ export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
}}
{...otherOverlayOptions}
>
<div
<SafeArea
bottom={environment.isMobileEdition}
bottomOffset={12}
data-full-screen={fullScreen}
data-modal={modal}
className={clsx(
@@ -278,7 +281,7 @@ export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
{children}
</Dialog.Content>
</div>
</SafeArea>
</Dialog.Overlay>
</Dialog.Portal>
</Dialog.Root>

View File

@@ -83,7 +83,7 @@ export const modalContentWrapper = style({
'screen and (width <= 640px)': {
// todo: adjust animation
alignItems: 'flex-end',
paddingBottom: 32,
paddingBottom: 'env(safe-area-inset-bottom, 20px)',
},
},

View File

@@ -0,0 +1,49 @@
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import { forwardRef, type HTMLAttributes } from 'react';
import { withUnit } from '../../utils/with-unit';
import { bottomOffsetVar, safeArea, topOffsetVar } from './style.css';
interface SafeAreaProps extends HTMLAttributes<HTMLDivElement> {
top?: boolean;
bottom?: boolean;
topOffset?: number | string;
bottomOffset?: number | string;
}
export const SafeArea = forwardRef<HTMLDivElement, SafeAreaProps>(
function SafeArea(
{
children,
className,
style,
top,
bottom,
topOffset = 0,
bottomOffset = 0,
...attrs
},
ref
) {
return (
<div
ref={ref}
className={clsx(safeArea, className)}
data-standalone={environment.isStandalone ? '' : undefined}
data-bottom={bottom ? '' : undefined}
data-top={top ? '' : undefined}
style={{
...style,
...assignInlineVars({
[topOffsetVar]: withUnit(topOffset, 'px'),
[bottomOffsetVar]: withUnit(bottomOffset, 'px'),
}),
}}
{...attrs}
>
{children}
</div>
);
}
);

View File

@@ -0,0 +1,22 @@
import { createVar, style } from '@vanilla-extract/css';
export const topOffsetVar = createVar();
export const bottomOffsetVar = createVar();
export const safeArea = style({
selectors: {
'&[data-top]': {
paddingTop: `calc(${topOffsetVar} + 12px)`,
},
'&[data-bottom]': {
paddingBottom: `calc(${bottomOffsetVar} + 0px)`,
},
'&[data-standalone][data-top]': {
paddingTop: `calc(env(safe-area-inset-top, 12px) + ${topOffsetVar})`,
},
'&[data-standalone][data-bottom]': {
// paddingBottom: 'env(safe-area-inset-bottom, 12px)',
paddingBottom: `calc(env(safe-area-inset-bottom, 0px) + ${bottomOffsetVar})`,
},
},
});