fix: theme not being persisted issue (#2283)

This commit is contained in:
Peng Xiao
2023-05-10 11:04:36 +08:00
committed by GitHub
parent 87ffdad862
commit 0c550a2827
21 changed files with 359 additions and 278 deletions

View File

@@ -110,7 +110,8 @@ export const settingItemLabelHint = style({
export const row = style({
padding: '40px 0',
display: 'flex',
gap: '60px',
columnGap: '60px',
rowGap: '12px',
selectors: {
'&': {
borderBottom: '1px solid var(--affine-border-color)',
@@ -119,22 +120,22 @@ export const row = style({
paddingTop: 0,
},
},
flexWrap: 'wrap',
});
export const col = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
flexShrink: 0,
selectors: {
[`${row} &:nth-child(1)`]: {
flex: 3,
flex: '3 0 200px',
},
[`${row} &:nth-child(2)`]: {
flex: 5,
flex: '5 0 240px',
},
[`${row} &:nth-child(3)`]: {
flex: 2,
flex: '2 0 200px',
alignItems: 'flex-end',
},
},

View File

@@ -88,7 +88,6 @@ export const GeneralPanel: React.FC<PanelProps> = ({
<div className={style.col}>
<StyledInput
width={284}
height={38}
value={input}
data-testid="workspace-name-input"

View File

@@ -1,13 +1,7 @@
import { displayFlex, styled } from '@affine/component';
import { Input } from '@affine/component';
export const StyledInput = styled(Input)(() => {
return {
border: '1px solid var(--affine-border-color)',
borderRadius: '8px',
fontSize: 'var(--affine-font-sm)',
};
});
export const StyledInput = Input;
export const StyledWorkspaceInfo = styled('div')(() => {
return {

View File

@@ -24,10 +24,7 @@ import { useCurrentPageId } from '../../../../hooks/current/use-current-page-id'
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
import { toast } from '../../../../utils';
import { MenuThemeModeSwitch } from '../header-right-items/theme-mode-switch';
import {
StyledHorizontalDivider,
StyledHorizontalDividerContainer,
} from '../styles';
import * as styles from '../styles.css';
import { LanguageMenu } from './language-menu';
const CommonMenu = () => {
const content = (
@@ -120,9 +117,9 @@ const PageMenu = () => {
}}
/>
)}
<StyledHorizontalDividerContainer>
<StyledHorizontalDivider />
</StyledHorizontalDividerContainer>
<div className={styles.horizontalDividerContainer}>
<div className={styles.horizontalDivider} />
</div>
</>
<div

View File

@@ -2,6 +2,7 @@ import { BrowserWarning } from '@affine/component/affine-banner';
import { appSidebarOpenAtom } from '@affine/component/app-sidebar';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { CloseIcon, MinusIcon, RoundedRectangleIcon } from '@blocksuite/icons';
import type { Page } from '@blocksuite/store';
import { useAtom } from 'jotai';
import type { FC, HTMLAttributes, PropsWithChildren } from 'react';
@@ -24,11 +25,7 @@ import { HeaderShareMenu } from './header-right-items/share-menu';
import SyncUser from './header-right-items/sync-user';
import TrashButtonGroup from './header-right-items/trash-button-group';
import UserAvatar from './header-right-items/user-avatar';
import {
StyledHeader,
StyledHeaderContainer,
StyledHeaderRightSide,
} from './styles';
import * as styles from './styles.css';
import { OSWarningMessage, shouldShowWarning } from './utils';
const SidebarSwitch = lazy(() =>
@@ -53,6 +50,9 @@ export const enum HeaderRightItemName {
ShareMenu = 'shareMenu',
EditPage = 'editPage',
UserAvatar = 'userAvatar',
// some windows only items
WindowsAppControls = 'windowsAppControls',
}
type HeaderItem = {
@@ -67,6 +67,7 @@ type HeaderItem = {
}
) => boolean;
};
const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
[HeaderRightItemName.TrashButtonGroup]: {
Component: TrashButtonGroup,
@@ -104,6 +105,44 @@ const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
return !isPublic && !isPreview;
},
},
[HeaderRightItemName.WindowsAppControls]: {
Component: () => {
return (
<div className={styles.windowAppControlsWrapper}>
<button
data-type="minimize"
className={styles.windowAppControl}
onClick={() => {
window.apis?.ui.handleMinimizeApp();
}}
>
<MinusIcon />
</button>
<button
data-type="maximize"
className={styles.windowAppControl}
onClick={() => {
window.apis?.ui.handleMaximizeApp();
}}
>
<RoundedRectangleIcon />
</button>
<button
data-type="close"
className={styles.windowAppControl}
onClick={() => {
window.apis?.ui.handleCloseApp();
}}
>
<CloseIcon />
</button>
</div>
);
},
availableWhen: () => {
return environment.isDesktop && environment.isWindows;
},
},
};
export type HeaderProps = BaseHeaderProps;
@@ -127,9 +166,10 @@ export const Header = forwardRef<
const mode = useCurrentMode();
return (
<StyledHeaderContainer
<div
className={styles.headerContainer}
ref={ref}
hasWarning={showWarning}
data-has-warning={showWarning}
data-open={open}
{...props}
>
@@ -145,11 +185,12 @@ export const Header = forwardRef<
/>
)}
<StyledHeader
hasWarning={showWarning}
<div
className={styles.header}
data-has-warning={showWarning}
data-testid="editor-header-items"
data-tauri-drag-region
isEdgeless={mode === 'edgeless'}
data-is-edgeless={mode === 'edgeless'}
>
<Suspense>
<SidebarSwitch
@@ -160,7 +201,7 @@ export const Header = forwardRef<
</Suspense>
{props.children}
<StyledHeaderRightSide>
<div className={styles.headerRightSide}>
{useMemo(() => {
return Object.entries(HeaderRightItems).map(
([name, { availableWhen, Component }]) => {
@@ -184,10 +225,9 @@ export const Header = forwardRef<
}
);
}, [props])}
{/*<ShareMenu />*/}
</StyledHeaderRightSide>
</StyledHeader>
</StyledHeaderContainer>
</div>
</div>
</div>
);
});

View File

@@ -15,15 +15,7 @@ import { QuickSearchButton } from '../../pure/quick-search-button';
import { EditorModeSwitch } from './editor-mode-switch';
import type { BaseHeaderProps } from './header';
import { Header } from './header';
import {
StyledQuickSearchTipButton,
StyledQuickSearchTipContent,
StyledSearchArrowWrapper,
StyledSwitchWrapper,
StyledTitle,
StyledTitleContainer,
StyledTitleWrapper,
} from './styles';
import * as styles from './styles.css';
export type WorkspaceHeaderProps = BaseHeaderProps;
@@ -61,7 +53,7 @@ export const WorkspaceHeader = forwardRef<
);
const TipsContent = (
<StyledQuickSearchTipContent>
<div className={styles.quickSearchTipContent}>
<div>
Click button
{
@@ -78,22 +70,23 @@ export const WorkspaceHeader = forwardRef<
{isMac() ? ' ⌘ + K' : ' Ctrl + K'} to activate Quick Search. Then you
can search keywords or quickly open recently viewed pages.
</div>
<StyledQuickSearchTipButton
<div
className={styles.quickSearchTipButton}
data-testid="quick-search-got-it"
onClick={() => setShowQuickSearchTips(false)}
>
Got it
</StyledQuickSearchTipButton>
</StyledQuickSearchTipContent>
</div>
</div>
);
return (
<Header ref={ref} {...props}>
{children}
{!isPublic && currentPage && (
<StyledTitleContainer data-tauri-drag-region>
<StyledTitleWrapper>
<StyledSwitchWrapper>
<div className={styles.titleContainer}>
<div className={styles.titleWrapper}>
<div className={styles.switchWrapper}>
<EditorModeSwitch
blockSuiteWorkspace={workspace.blockSuiteWorkspace}
pageId={currentPage.id}
@@ -101,8 +94,8 @@ export const WorkspaceHeader = forwardRef<
marginRight: '12px',
}}
/>
</StyledSwitchWrapper>
<StyledTitle>{title || 'Untitled'}</StyledTitle>
</div>
<div className={styles.title}>{title || 'Untitled'}</div>
<QuickSearchTips
data-testid="quick-search-tips"
content={TipsContent}
@@ -111,16 +104,16 @@ export const WorkspaceHeader = forwardRef<
open={showQuickSearchTips}
offset={[0, -5]}
>
<StyledSearchArrowWrapper>
<div className={styles.searchArrowWrapper}>
<QuickSearchButton
onClick={() => {
setOpenQuickSearch(true);
}}
/>
</StyledSearchArrowWrapper>
</div>
</QuickSearchTips>
</StyledTitleWrapper>
</StyledTitleContainer>
</div>
</div>
)}
</Header>
);

View File

@@ -0,0 +1,216 @@
import { style } from '@vanilla-extract/css';
export const headerContainer = style({
height: '52px',
flexShrink: 0,
position: 'sticky',
top: 0,
background: 'var(--affine-background-primary-color)',
WebkitAppRegion: 'drag',
zIndex: 'var(--affine-z-index-popover)',
'@media': {
'(max-width: 768px)': {
selectors: {
'&[data-open="true"]': {
// @ts-ignore
WebkitAppRegion: 'no-drag',
},
},
},
},
selectors: {
'&[data-has-warning="true"]': {
height: '96px',
},
},
});
export const header = style({
flexShrink: 0,
height: '52px',
width: '100%',
padding: '0 20px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
background: 'var(--affine-background-primary-color)',
zIndex: 99,
position: 'relative',
selectors: {
'&[data-is-edgeless="true"]': {
borderBottom: `1px solid var(--affine-border-color)`,
},
},
});
export const titleContainer = style({
width: '100%',
height: '100%',
margin: 'auto',
position: 'absolute',
inset: 'auto auto auto 50%',
transform: 'translate(-50%, 0px)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
alignContent: 'unset',
fontSize: 'var(--affine-font-base)',
});
export const title = style({
maxWidth: '620px',
transition: 'max-width .15s',
userSelect: 'none',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
'@media': {
'(max-width: 768px)': {
selectors: {
'&[data-open="true"]': {
// @ts-ignore
WebkitAppRegion: 'no-drag',
},
},
},
},
});
export const titleWrapper = style({
height: '100%',
position: 'relative',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
});
export const headerRightSide = style({
height: '100%',
display: 'flex',
alignItems: 'center',
gap: '12px',
zIndex: 1,
});
export const browserWarning = style({
backgroundColor: 'var(--affine-background-warning-color)',
color: 'var(--affine-warning-color)',
height: '36px',
fontSize: 'var(--affine-font-sm)',
display: 'none',
justifyContent: 'center',
alignItems: 'center',
selectors: {
'&[data-show="true"]': {
display: 'flex',
},
},
});
export const closeButton = style({
width: '36px',
height: '36px',
color: 'var(--affine-icon-color)',
cursor: 'pointer',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
right: '15px',
top: 0,
});
export const switchWrapper = style({
position: 'absolute',
right: '100%',
top: 0,
bottom: 0,
margin: 'auto',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
});
export const searchArrowWrapper = style({
position: 'absolute',
left: 'calc(100% + 4px)',
top: 0,
bottom: 0,
margin: 'auto',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
});
export const pageListTitleWrapper = style({
fontSize: 'var(--affine-font-base)',
color: 'var(--affine-text-primary-color)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
});
export const pageListTitleIcon = style({
fontSize: '20px',
height: '1em',
marginRight: '12px',
});
export const quickSearchTipButton = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
marginTop: '12px',
color: '#FFFFFF',
width: '48px',
height: ' 26px',
fontSize: 'var(--affine-font-sm)',
lineHeight: '22px',
background: 'var(--affine-primary-color)',
borderRadius: '8px',
textAlign: 'center',
cursor: 'pointer',
});
export const quickSearchTipContent = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'flex-end',
flexDirection: 'column',
});
export const horizontalDivider = style({
width: '100%',
borderTop: `1px solid var(--affine-border-color)`,
});
export const horizontalDividerContainer = style({
width: '100%',
padding: '14px',
});
export const windowAppControlsWrapper = style({
display: 'flex',
gap: '2px',
transform: 'translateX(8px)',
});
export const windowAppControl = style({
// @ts-ignore
WebkitAppRegion: 'no-drag',
cursor: 'pointer',
display: 'inline-flex',
width: '32px',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '2px',
selectors: {
'&[data-type="close"]:hover': {
background: 'var(--affine-error-color)',
color: '#FFFFFF',
},
'&:hover': {
background: 'var(--affine-background-tertiary-color)',
},
},
});

View File

@@ -1,186 +0,0 @@
import {
absoluteCenter,
displayFlex,
styled,
textEllipsis,
} from '@affine/component';
export const StyledHeaderContainer = styled('div')<{
hasWarning: boolean;
}>(({ hasWarning }) => {
return {
height: hasWarning ? '96px' : '52px',
flexShrink: 0,
position: 'sticky',
top: 0,
background: 'var(--affine-background-primary-color)',
WebkitAppRegion: 'drag',
zIndex: 'var(--affine-z-index-popover)',
'@media (max-width: 768px)': {
'&[data-open="true"]': {
WebkitAppRegion: 'no-drag',
},
},
};
});
export const StyledHeader = styled('div')<{
hasWarning: boolean;
isEdgeless: boolean;
}>(({ isEdgeless }) => {
return {
flexShrink: 0,
height: '52px',
width: '100%',
padding: '0 20px',
...displayFlex('space-between', 'center'),
background: 'var(--affine-background-primary-color)',
zIndex: 99,
position: 'relative',
borderBottom: isEdgeless ? '1px solid var(--affine-border-color)' : 'none',
};
});
export const StyledTitleContainer = styled('div')(() => ({
width: '100%',
height: '100%',
margin: 'auto',
...absoluteCenter({ horizontal: true, position: { top: 0 } }),
...displayFlex('center', 'center'),
fontSize: 'var(--affine-font-base)',
}));
export const StyledTitle = styled('div')(({ theme }) => {
return {
maxWidth: '620px',
[theme.breakpoints.down('lg')]: {
maxWidth: '480px',
},
[theme.breakpoints.down('md')]: {
maxWidth: '240px',
},
[theme.breakpoints.down('sm')]: {
maxWidth: '180px',
},
transition: 'max-width .15s',
userSelect: 'none',
...textEllipsis(1),
};
});
export const StyledTitleWrapper = styled('div')({
height: '100%',
position: 'relative',
...displayFlex('center', 'center'),
});
export const StyledHeaderRightSide = styled('div')({
height: '100%',
display: 'flex',
alignItems: 'center',
'>*:not(:last-child)': {
marginRight: '12px',
},
});
export const StyledBrowserWarning = styled('div')<{ show: boolean }>(
({ show }) => {
return {
backgroundColor: 'var(--affine-background-warning-color)',
color: 'var(--affine-background-warning-color)',
height: '36px',
fontSize: 'var(--affine-font-sm)',
display: show ? 'flex' : 'none',
justifyContent: 'center',
alignItems: 'center',
};
}
);
export const StyledCloseButton = styled('div')(() => {
return {
width: '36px',
height: '36px',
color: 'var(--affine-icon-color)',
cursor: 'pointer',
...displayFlex('center', 'center'),
position: 'absolute',
right: '15px',
top: '0',
svg: {
width: '15px',
height: '15px',
position: 'relative',
zIndex: 1,
},
};
});
export const StyledSwitchWrapper = styled('div')(() => {
return {
position: 'absolute',
right: '100%',
top: 0,
bottom: 0,
margin: 'auto',
...displayFlex('center', 'center'),
};
});
export const StyledSearchArrowWrapper = styled('div')(() => {
return {
position: 'absolute',
left: 'calc(100% + 4px)',
top: 0,
bottom: 0,
margin: 'auto',
...displayFlex('center', 'center'),
};
});
export const StyledPageListTittleWrapper = styled(StyledTitle)(() => {
return {
fontSize: 'var(--affine-font-base)',
color: 'var(--affine-text-primary-color)',
...displayFlex('center', 'center'),
'>svg': {
fontSize: '20px',
marginRight: '12px',
},
};
});
export const StyledQuickSearchTipButton = styled('div')(() => {
return {
...displayFlex('center', 'center'),
marginTop: '12px',
color: '#FFFFFF',
width: '48px',
height: ' 26px',
fontSize: 'var(--affine-font-sm)',
lineHeight: '22px',
background: 'var(--affine-primary-color)',
borderRadius: '8px',
textAlign: 'center',
cursor: 'pointer',
};
});
export const StyledQuickSearchTipContent = styled('div')(() => {
return {
...displayFlex('center', 'flex-end'),
flexDirection: 'column',
};
});
export const StyledHorizontalDivider = styled('div')(() => {
return {
width: '100%',
borderTop: `1px solid var(--affine-border-color)`,
};
});
export const StyledHorizontalDividerContainer = styled('div')(() => {
return {
width: '100%',
padding: '14px',
};
});

View File

@@ -5,7 +5,7 @@ import type React from 'react';
import { openQuickSearchModalAtom } from '../../../atoms';
import type { HeaderProps } from '../../blocksuite/workspace-header/header';
import { Header } from '../../blocksuite/workspace-header/header';
import { StyledPageListTittleWrapper } from '../../blocksuite/workspace-header/styles';
import * as styles from '../../blocksuite/workspace-header/styles.css';
import { QuickSearchButton } from '../quick-search-button';
export type WorkspaceTitleProps = React.PropsWithChildren<
@@ -22,15 +22,15 @@ export const WorkspaceTitle: React.FC<WorkspaceTitleProps> = ({
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
return (
<Header {...props}>
<StyledPageListTittleWrapper>
{icon}
<div className={styles.pageListTitleWrapper}>
<div className={styles.pageListTitleIcon}>{icon}</div>
{children}
<QuickSearchButton
onClick={() => {
setOpenQuickSearch(true);
}}
/>
</StyledPageListTittleWrapper>
</div>
</Header>
);
};

View File

@@ -1,19 +1,22 @@
import type { ThemeProviderProps } from '@affine/component';
import { ThemeProvider as NextThemeProvider, useTheme } from 'next-themes';
import type { PropsWithChildren } from 'react';
import type React from 'react';
import { memo, useRef } from 'react';
const themes = ['dark', 'light'];
// a workaround to sync theme to electron
let firstRender = true;
const DesktopThemeSync = memo(function DesktopThemeSync() {
const { theme } = useTheme();
const lastThemeRef = useRef(theme);
if (lastThemeRef.current !== theme) {
if (lastThemeRef.current !== theme || firstRender) {
if (environment.isDesktop && theme) {
window.apis?.ui.handleThemeChange(theme as 'dark' | 'light' | 'system');
}
lastThemeRef.current = theme;
firstRender = false;
}
return null;
});