diff --git a/packages/common/infra/src/app-config-storage.ts b/packages/common/infra/src/app-config-storage.ts index 36b5698e5937e..5db0127d2d26f 100644 --- a/packages/common/infra/src/app-config-storage.ts +++ b/packages/common/infra/src/app-config-storage.ts @@ -1,11 +1,12 @@ import { z } from 'zod'; -const _appConfigSchema = z.object({ +export const appConfigSchema = z.object({ /** whether to show onboarding first */ onBoarding: z.boolean().optional().default(true), }); -export type AppConfigSchema = z.infer; -export const defaultAppConfig = _appConfigSchema.parse({}); + +export type AppConfigSchema = z.infer; +export const defaultAppConfig = appConfigSchema.parse({}); const _storage: Record = {}; let _inMemoryId = 0; @@ -48,7 +49,7 @@ class Storage { } get(): T; - get(key: keyof T): T[keyof T]; + get(key: K): T[K]; /** * get config, if key is provided, return the value of the key * @param key diff --git a/packages/common/infra/src/atom/settings.ts b/packages/common/infra/src/atom/settings.ts index e0ce75301c5d8..6778e821527ad 100644 --- a/packages/common/infra/src/atom/settings.ts +++ b/packages/common/infra/src/atom/settings.ts @@ -105,6 +105,7 @@ export function setupEditorFlags(docCollection: DocCollection) { type SetStateAction = Value | ((prev: Value) => Value); +// todo(@pengx17): use global state instead const appSettingEffect = atomEffect(get => { const settings = get(appSettingBaseAtom); // some values in settings should be synced into electron side diff --git a/packages/common/infra/src/framework/core/index.ts b/packages/common/infra/src/framework/core/index.ts index c1cce58426e5f..b0edde95c1968 100644 --- a/packages/common/infra/src/framework/core/index.ts +++ b/packages/common/infra/src/framework/core/index.ts @@ -8,4 +8,4 @@ export { Framework } from './framework'; export { createIdentifier } from './identifier'; export type { ResolveOptions } from './provider'; export { FrameworkProvider } from './provider'; -export type { GeneralIdentifier } from './types'; +export type { GeneralIdentifier, Identifier } from './types'; diff --git a/packages/frontend/component/src/components/auth-components/onboarding-page.tsx b/packages/frontend/component/src/components/auth-components/onboarding-page.tsx index d0166240c393d..1fa11ec63fecf 100644 --- a/packages/frontend/component/src/components/auth-components/onboarding-page.tsx +++ b/packages/frontend/component/src/components/auth-components/onboarding-page.tsx @@ -100,11 +100,9 @@ export const ScrollableLayout = ({ export const OnboardingPage = ({ user, onOpenAffine, - windowControl, }: { user: User; onOpenAffine: () => void; - windowControl?: React.ReactNode; }) => { const location = useLocation(); const navigate = useNavigate(); @@ -150,19 +148,16 @@ export const OnboardingPage = ({ return ( - {isWindowsDesktop ? windowControl : null} - - + } isMacosDesktop={isMacosDesktop} isWindowsDesktop={isWindowsDesktop} @@ -265,7 +260,6 @@ export const OnboardingPage = ({ } return ( diff --git a/packages/frontend/component/src/theme/global.css b/packages/frontend/component/src/theme/global.css index 33b73419a7c5f..1907c62220ba3 100644 --- a/packages/frontend/component/src/theme/global.css +++ b/packages/frontend/component/src/theme/global.css @@ -288,6 +288,20 @@ textarea -webkit-app-region: no-drag; } +html[data-active='false'] { + opacity: 0; + transition: opacity 0.2s 0.1s; +} + +html[data-active='true']:has([data-blur-background='true']) { + opacity: 1; + transition: opacity 0.2s; +} + +html[data-active='false'] * { + -webkit-app-region: no-drag !important; +} + html, body { height: 100%; diff --git a/packages/frontend/component/src/ui/notification/notification-card.tsx b/packages/frontend/component/src/ui/notification/notification-card.tsx index 0217ebd59f155..59d0971fc1a4b 100644 --- a/packages/frontend/component/src/ui/notification/notification-card.tsx +++ b/packages/frontend/component/src/ui/notification/notification-card.tsx @@ -80,7 +80,10 @@ export const NotificationCard = ({ notification }: NotificationCardProps) => { data-float={!!thumb} className={clsx(styles.headAlignWrapper, styles.closeButton)} > - + diff --git a/packages/frontend/component/src/ui/scrollbar/scrollbar.tsx b/packages/frontend/component/src/ui/scrollbar/scrollbar.tsx index 2d2291428a3fa..137c8bf2843dd 100644 --- a/packages/frontend/component/src/ui/scrollbar/scrollbar.tsx +++ b/packages/frontend/component/src/ui/scrollbar/scrollbar.tsx @@ -1,7 +1,6 @@ import * as ScrollArea from '@radix-ui/react-scroll-area'; import clsx from 'clsx'; import type { PropsWithChildren } from 'react'; -import { useRef } from 'react'; import * as styles from './index.css'; import { useHasScrollTop } from './use-has-scroll-top'; @@ -24,8 +23,7 @@ export const ScrollableContainer = ({ viewPortClassName, scrollBarClassName, }: PropsWithChildren) => { - const ref = useRef(null); - const hasScrollTop = useHasScrollTop(ref); + const [setContainer, hasScrollTop] = useHasScrollTop(); return (
{children}
diff --git a/packages/frontend/component/src/ui/scrollbar/use-has-scroll-top.tsx b/packages/frontend/component/src/ui/scrollbar/use-has-scroll-top.tsx index b5f5cace49a96..eb0f97225f8d4 100644 --- a/packages/frontend/component/src/ui/scrollbar/use-has-scroll-top.tsx +++ b/packages/frontend/component/src/ui/scrollbar/use-has-scroll-top.tsx @@ -1,31 +1,27 @@ -import type { RefObject } from 'react'; -import { useEffect, useState } from 'react'; +import { debounce } from 'lodash-es'; +import { useMemo, useState } from 'react'; -export function useHasScrollTop(ref: RefObject | null) { +export function useHasScrollTop() { const [hasScrollTop, setHasScrollTop] = useState(false); - - useEffect(() => { - if (!ref?.current) { - return; - } - - const container = ref.current; - - function updateScrollTop() { - if (container) { - setTimeout(() => { - const hasScrollTop = container.scrollTop > 0; - setHasScrollTop(hasScrollTop); - }); - } - } - - container.addEventListener('scroll', updateScrollTop); - updateScrollTop(); - return () => { - container.removeEventListener('scroll', updateScrollTop); + const containerRefFn = useMemo(() => { + let unsub: (() => void) | null = null; + return (container: HTMLElement | null) => { + unsub?.(); + const updateScrollTop = debounce(() => { + if (container) { + setTimeout(() => { + const hasScrollTop = container.scrollTop > 0; + setHasScrollTop(hasScrollTop); + }); + } + }, 50); + container?.addEventListener('scroll', updateScrollTop); + updateScrollTop(); + unsub = () => { + container?.removeEventListener('scroll', updateScrollTop); + }; }; - }, [ref]); + }, []); - return hasScrollTop; + return [containerRefFn, hasScrollTop] as const; } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts index fb6bffe189970..6e55c41b9db9c 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts @@ -168,7 +168,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) { private _renderAIOnboarding() { return this.isLoading || - !this.host.doc.awarenessStore.getFlag('enable_ai_onboarding') + !this.host?.doc.awarenessStore.getFlag('enable_ai_onboarding') ? nothing : html`
{ + // do not float app sidebar on desktop + if (environment.isDesktop) { + return; + } + function onResize() { const isFloatingMaxWidth = window.matchMedia( `(max-width: ${floatingMaxWidth}px)` @@ -75,10 +79,8 @@ export function AppSidebar({ }; }, [open, setFloating, setOpen, width]); + const hasRightBorder = !environment.isDesktop && !clientBorder; const isMacosDesktop = environment.isDesktop && environment.isMacOs; - const hasRightBorder = - !environment.isDesktop || (!clientBorder && !translucentUI); - return ( <>