mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-22 09:13:18 +03:00
feat(mobile): mobile app fallback skeleton (#8686)
close AF-1533, AF-1532
This commit is contained in:
parent
5b5dc26abf
commit
fe04ab35cc
@ -1,6 +1,6 @@
|
|||||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
|
||||||
import { AffineContext } from '@affine/core/components/context';
|
import { AffineContext } from '@affine/core/components/context';
|
||||||
import { Telemetry } from '@affine/core/components/telemetry';
|
import { Telemetry } from '@affine/core/components/telemetry';
|
||||||
|
import { AppFallback } from '@affine/core/mobile/components';
|
||||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||||
import { router } from '@affine/core/mobile/router';
|
import { router } from '@affine/core/mobile/router';
|
||||||
import { configureCommonModules } from '@affine/core/modules';
|
import { configureCommonModules } from '@affine/core/modules';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
|
||||||
import { AffineContext } from '@affine/core/components/context';
|
import { AffineContext } from '@affine/core/components/context';
|
||||||
import { Telemetry } from '@affine/core/components/telemetry';
|
import { Telemetry } from '@affine/core/components/telemetry';
|
||||||
|
import { AppFallback } from '@affine/core/mobile/components';
|
||||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||||
import { router } from '@affine/core/mobile/router';
|
import { router } from '@affine/core/mobile/router';
|
||||||
import { configureCommonModules } from '@affine/core/modules';
|
import { configureCommonModules } from '@affine/core/modules';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
|
||||||
import { AffineContext } from '@affine/core/components/context';
|
import { AffineContext } from '@affine/core/components/context';
|
||||||
import { Telemetry } from '@affine/core/components/telemetry';
|
import { Telemetry } from '@affine/core/components/telemetry';
|
||||||
|
import { AppFallback } from '@affine/core/mobile/components';
|
||||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||||
import { router } from '@affine/core/mobile/router';
|
import { router } from '@affine/core/mobile/router';
|
||||||
import { configureCommonModules } from '@affine/core/modules';
|
import { configureCommonModules } from '@affine/core/modules';
|
||||||
|
@ -5,5 +5,6 @@ export * from './rename';
|
|||||||
export * from './search-input';
|
export * from './search-input';
|
||||||
export * from './search-result';
|
export * from './search-result';
|
||||||
export * from './selector';
|
export * from './selector';
|
||||||
|
export * from './skeletons';
|
||||||
export * from './user-plan-tag';
|
export * from './user-plan-tag';
|
||||||
export * from './workspace-selector';
|
export * from './workspace-selector';
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
import { SafeArea, Skeleton } from '@affine/component';
|
||||||
|
|
||||||
|
import { WorkspaceSelector } from '../workspace-selector';
|
||||||
|
|
||||||
|
const SectionTitleFallback = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: '0 16px' }}>
|
||||||
|
<Skeleton
|
||||||
|
animation="wave"
|
||||||
|
style={{ height: 16, borderRadius: 4, width: 93 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const sectionRows = [127, 238, 191, 102];
|
||||||
|
|
||||||
|
const Section = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ marginBottom: 32 }}>
|
||||||
|
<SectionTitleFallback />
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
padding: '0 16px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 24,
|
||||||
|
marginTop: 24,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{sectionRows.map((width, i) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{ display: 'flex', gap: 16, alignItems: 'center' }}
|
||||||
|
key={i}
|
||||||
|
>
|
||||||
|
<Skeleton
|
||||||
|
animation="wave"
|
||||||
|
style={{ width: 23, height: 23, borderRadius: 4 }}
|
||||||
|
/>
|
||||||
|
<Skeleton
|
||||||
|
animation="wave"
|
||||||
|
style={{ width, height: 16, borderRadius: 4 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AppFallback = () => {
|
||||||
|
return (
|
||||||
|
<SafeArea top bottom style={{ height: '100dvh', overflow: 'hidden' }}>
|
||||||
|
{/* setting */}
|
||||||
|
<div style={{ padding: 10, display: 'flex', justifyContent: 'end' }}>
|
||||||
|
<Skeleton
|
||||||
|
animation="wave"
|
||||||
|
style={{ width: 23, height: 23, borderRadius: 4 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* workspace card */}
|
||||||
|
<div style={{ padding: '4px 16px' }}>
|
||||||
|
<WorkspaceSelector />
|
||||||
|
</div>
|
||||||
|
{/* search */}
|
||||||
|
<div style={{ padding: '10px 16px 15px' }}>
|
||||||
|
<Skeleton animation="wave" style={{ height: 44, borderRadius: 10 }} />
|
||||||
|
</div>
|
||||||
|
{/* recent */}
|
||||||
|
<SectionTitleFallback />
|
||||||
|
<div style={{ padding: '16px 16px 32px 16px', display: 'flex', gap: 10 }}>
|
||||||
|
{[1, 2, 3].map(i => (
|
||||||
|
<Skeleton
|
||||||
|
key={i}
|
||||||
|
animation="wave"
|
||||||
|
style={{ width: 172, height: 210, borderRadius: 12 }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Section />
|
||||||
|
<Section />
|
||||||
|
</SafeArea>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './app-fallback';
|
@ -1,8 +1,9 @@
|
|||||||
|
import { Avatar } from '@affine/component';
|
||||||
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
||||||
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
||||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||||
import { ArrowDownSmallIcon } from '@blocksuite/icons/rc';
|
import { ArrowDownSmallIcon } from '@blocksuite/icons/rc';
|
||||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
import { useServiceOptional, WorkspaceService } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { forwardRef, type HTMLAttributes } from 'react';
|
import { forwardRef, type HTMLAttributes } from 'react';
|
||||||
|
|
||||||
@ -15,8 +16,8 @@ export const CurrentWorkspaceCard = forwardRef<
|
|||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
CurrentWorkspaceCardProps
|
CurrentWorkspaceCardProps
|
||||||
>(function CurrentWorkspaceCard({ onClick, className, ...attrs }, ref) {
|
>(function CurrentWorkspaceCard({ onClick, className, ...attrs }, ref) {
|
||||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
const currentWorkspace = useServiceOptional(WorkspaceService)?.workspace;
|
||||||
const info = useWorkspaceInfo(currentWorkspace.meta);
|
const info = useWorkspaceInfo(currentWorkspace?.meta);
|
||||||
const name = info?.name ?? UNTITLED_WORKSPACE_NAME;
|
const name = info?.name ?? UNTITLED_WORKSPACE_NAME;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -26,15 +27,19 @@ export const CurrentWorkspaceCard = forwardRef<
|
|||||||
className={clsx(card, className)}
|
className={clsx(card, className)}
|
||||||
{...attrs}
|
{...attrs}
|
||||||
>
|
>
|
||||||
<WorkspaceAvatar
|
{currentWorkspace ? (
|
||||||
key={currentWorkspace.id}
|
<WorkspaceAvatar
|
||||||
meta={currentWorkspace.meta}
|
key={currentWorkspace?.id}
|
||||||
rounded={3}
|
meta={currentWorkspace?.meta}
|
||||||
data-testid="workspace-avatar"
|
rounded={3}
|
||||||
size={40}
|
data-testid="workspace-avatar"
|
||||||
name={name}
|
size={40}
|
||||||
colorfulFallback
|
name={name}
|
||||||
/>
|
colorfulFallback
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Avatar size={40} rounded={3} colorfulFallback />
|
||||||
|
)}
|
||||||
<div className={label}>
|
<div className={label}>
|
||||||
{name}
|
{name}
|
||||||
<ArrowDownSmallIcon className={dropdownIcon} />
|
<ArrowDownSmallIcon className={dropdownIcon} />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { MobileMenu } from '@affine/component';
|
import { MobileMenu } from '@affine/component';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import { useService, WorkspacesService } from '@toeverything/infra';
|
import { useServiceOptional, WorkspacesService } from '@toeverything/infra';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { CurrentWorkspaceCard } from './current-card';
|
import { CurrentWorkspaceCard } from './current-card';
|
||||||
@ -8,7 +8,7 @@ import { SelectorMenu } from './menu';
|
|||||||
|
|
||||||
export const WorkspaceSelector = () => {
|
export const WorkspaceSelector = () => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const workspaceManager = useService(WorkspacesService);
|
const workspaceManager = useServiceOptional(WorkspacesService);
|
||||||
|
|
||||||
const openMenu = useCallback(() => {
|
const openMenu = useCallback(() => {
|
||||||
track.$.navigationPanel.workspaceList.open();
|
track.$.navigationPanel.workspaceList.open();
|
||||||
@ -20,7 +20,7 @@ export const WorkspaceSelector = () => {
|
|||||||
|
|
||||||
// revalidate workspace list when open workspace list
|
// revalidate workspace list when open workspace list
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) workspaceManager.list.revalidate();
|
if (open) workspaceManager?.list.revalidate();
|
||||||
}, [workspaceManager, open]);
|
}, [workspaceManager, open]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
||||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
|
||||||
import { WorkspaceLayoutProviders } from '@affine/core/components/layouts/workspace-layout';
|
import { WorkspaceLayoutProviders } from '@affine/core/components/layouts/workspace-layout';
|
||||||
import { SWRConfigProvider } from '@affine/core/components/providers/swr-config-provider';
|
import { SWRConfigProvider } from '@affine/core/components/providers/swr-config-provider';
|
||||||
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
|
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
|
||||||
@ -17,6 +16,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
|
import { AppFallback } from '../../components';
|
||||||
import { MobileCurrentWorkspaceModals } from '../../provider/model-provider';
|
import { MobileCurrentWorkspaceModals } from '../../provider/model-provider';
|
||||||
|
|
||||||
// TODO(@forehalo): reuse the global context with [core/electron]
|
// TODO(@forehalo): reuse the global context with [core/electron]
|
||||||
|
Loading…
Reference in New Issue
Block a user