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:
L-Sun
2025-07-15 15:45:37 +08:00
committed by GitHub
parent a597bdcdf6
commit 613597e642
5 changed files with 61 additions and 6 deletions

View File

@@ -7,6 +7,12 @@ export const container = style({
width: '360px',
display: 'flex',
flexDirection: 'column',
selectors: {
'&[data-mobile]': {
width: '100%',
},
},
});
export const header = style({

View File

@@ -90,7 +90,10 @@ export const NotificationList = () => {
}, [notificationListService]);
return (
<div className={styles.container}>
<div
className={styles.container}
data-mobile={BUILD_CONFIG.isMobileEdition ? '' : undefined}
>
<div className={styles.header}>
<span>{t['com.affine.rootAppSidebar.notifications']()}</span>
{notifications.length > 0 && (

View File

@@ -52,11 +52,23 @@ const Section = () => {
export const AppFallback = () => {
return (
<SafeArea top bottom style={{ height: '100dvh', overflow: 'hidden' }}>
{/* setting */}
<div style={{ padding: 10, display: 'flex', justifyContent: 'end' }}>
{/* notification and setting */}
<div
style={{
padding: 10,
paddingTop: 0,
display: 'flex',
justifyContent: 'end',
gap: 10,
}}
>
<Skeleton
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>
{/* workspace card */}

View File

@@ -1,13 +1,16 @@
import {
IconButton,
Menu,
SafeArea,
startScopedViewTransition,
} from '@affine/component';
import { NotificationList } from '@affine/core/components/notification/list';
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { NotificationCountService } from '@affine/core/modules/notification';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { useI18n } from '@affine/i18n';
import { SettingsIcon } from '@blocksuite/icons/rc';
import { useService } from '@toeverything/infra';
import { NotificationIcon, SettingsIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import clsx from 'clsx';
import { useCallback, useRef, useState } from 'react';
@@ -29,6 +32,8 @@ export const HomeHeader = () => {
const floatWorkspaceCardRef = useRef<HTMLDivElement>(null);
const t = useI18n();
const workbench = useService(WorkbenchService).workbench;
const notificationCountService = useService(NotificationCountService);
const notificationCount = useLiveData(notificationCountService.count$);
const navSearch = useCallback(() => {
startScopedViewTransition(searchVTScope, () => {
@@ -70,6 +75,21 @@ export const HomeHeader = () => {
className={styles.floatWsSelector}
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
style={{ transition: 'none' }}
onClick={openSetting}

View File

@@ -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',
});