feat(core): notification entry for mobile (#13214)
#### PR Dependency Tree * **PR #13214** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a notification icon with a live badge displaying the notification count in the mobile home header. The badge dynamically adjusts and caps the count at "99+". * Introduced a notification menu in the mobile header, allowing users to view their notifications directly. * **Style** * Improved notification list responsiveness on mobile by making it full width. * Enhanced the appearance of the notification badge for better visibility. * Updated the app fallback UI to display skeleton placeholders for both notification and settings icons. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -7,6 +7,12 @@ export const container = style({
|
|||||||
width: '360px',
|
width: '360px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
|
||||||
|
selectors: {
|
||||||
|
'&[data-mobile]': {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const header = style({
|
export const header = style({
|
||||||
|
|||||||
@@ -90,7 +90,10 @@ export const NotificationList = () => {
|
|||||||
}, [notificationListService]);
|
}, [notificationListService]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div
|
||||||
|
className={styles.container}
|
||||||
|
data-mobile={BUILD_CONFIG.isMobileEdition ? '' : undefined}
|
||||||
|
>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<span>{t['com.affine.rootAppSidebar.notifications']()}</span>
|
<span>{t['com.affine.rootAppSidebar.notifications']()}</span>
|
||||||
{notifications.length > 0 && (
|
{notifications.length > 0 && (
|
||||||
|
|||||||
@@ -52,11 +52,23 @@ const Section = () => {
|
|||||||
export const AppFallback = () => {
|
export const AppFallback = () => {
|
||||||
return (
|
return (
|
||||||
<SafeArea top bottom style={{ height: '100dvh', overflow: 'hidden' }}>
|
<SafeArea top bottom style={{ height: '100dvh', overflow: 'hidden' }}>
|
||||||
{/* setting */}
|
{/* notification and setting */}
|
||||||
<div style={{ padding: 10, display: 'flex', justifyContent: 'end' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
padding: 10,
|
||||||
|
paddingTop: 0,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'end',
|
||||||
|
gap: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Skeleton
|
<Skeleton
|
||||||
animation="wave"
|
animation="wave"
|
||||||
style={{ width: 23, height: 23, borderRadius: 4 }}
|
style={{ width: 28, height: 28, borderRadius: 4 }}
|
||||||
|
/>
|
||||||
|
<Skeleton
|
||||||
|
animation="wave"
|
||||||
|
style={{ width: 28, height: 28, borderRadius: 4 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* workspace card */}
|
{/* workspace card */}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
IconButton,
|
IconButton,
|
||||||
|
Menu,
|
||||||
SafeArea,
|
SafeArea,
|
||||||
startScopedViewTransition,
|
startScopedViewTransition,
|
||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
|
import { NotificationList } from '@affine/core/components/notification/list';
|
||||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
|
import { NotificationCountService } from '@affine/core/modules/notification';
|
||||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { SettingsIcon } from '@blocksuite/icons/rc';
|
import { NotificationIcon, SettingsIcon } from '@blocksuite/icons/rc';
|
||||||
import { useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
import { useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
@@ -29,6 +32,8 @@ export const HomeHeader = () => {
|
|||||||
const floatWorkspaceCardRef = useRef<HTMLDivElement>(null);
|
const floatWorkspaceCardRef = useRef<HTMLDivElement>(null);
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
|
const notificationCountService = useService(NotificationCountService);
|
||||||
|
const notificationCount = useLiveData(notificationCountService.count$);
|
||||||
|
|
||||||
const navSearch = useCallback(() => {
|
const navSearch = useCallback(() => {
|
||||||
startScopedViewTransition(searchVTScope, () => {
|
startScopedViewTransition(searchVTScope, () => {
|
||||||
@@ -70,6 +75,21 @@ export const HomeHeader = () => {
|
|||||||
className={styles.floatWsSelector}
|
className={styles.floatWsSelector}
|
||||||
ref={floatWorkspaceCardRef}
|
ref={floatWorkspaceCardRef}
|
||||||
/>
|
/>
|
||||||
|
<Menu items={<NotificationList />}>
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
<NotificationIcon width={28} height={28} />
|
||||||
|
{notificationCount > 0 && (
|
||||||
|
<div
|
||||||
|
className={styles.notificationBadge}
|
||||||
|
style={{
|
||||||
|
fontSize: notificationCount > 99 ? '8px' : '12px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{notificationCount > 99 ? '99+' : notificationCount}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Menu>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={{ transition: 'none' }}
|
style={{ transition: 'none' }}
|
||||||
onClick={openSetting}
|
onClick={openSetting}
|
||||||
|
|||||||
@@ -54,3 +54,17 @@ export const floatWsSelector = style({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const notificationBadge = style({
|
||||||
|
position: 'absolute',
|
||||||
|
top: -2,
|
||||||
|
right: -2,
|
||||||
|
backgroundColor: cssVarV2('button/primary'),
|
||||||
|
color: cssVarV2('text/pureWhite'),
|
||||||
|
width: '16px',
|
||||||
|
height: '16px',
|
||||||
|
fontSize: '12px',
|
||||||
|
lineHeight: '16px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
textAlign: 'center',
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user