Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mobile): swipe to open menu for explorer #8953

Merged
merged 1 commit into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/frontend/apps/ios/App/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def capacitor_pods
pod 'CapacitorCordova', :path => '../../../../../node_modules/@capacitor/ios'
pod 'CapacitorApp', :path => '../../../../../node_modules/@capacitor/app'
pod 'CapacitorBrowser', :path => '../../../../../node_modules/@capacitor/browser'
pod 'CapacitorHaptics', :path => '../../../../../node_modules/@capacitor/haptics'
pod 'CapacitorKeyboard', :path => '../../../../../node_modules/@capacitor/keyboard'
end

Expand Down
28 changes: 17 additions & 11 deletions packages/frontend/apps/ios/App/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
PODS:
- Capacitor (6.1.2):
- Capacitor (6.2.0):
- CapacitorCordova
- CapacitorApp (6.0.1):
- CapacitorApp (6.0.2):
- Capacitor
- CapacitorBrowser (6.0.3):
- CapacitorBrowser (6.0.4):
- Capacitor
- CapacitorCordova (6.1.2)
- CapacitorKeyboard (6.0.2):
- CapacitorCordova (6.2.0)
- CapacitorHaptics (6.0.2):
- Capacitor
- CapacitorKeyboard (6.0.3):
- Capacitor
- CryptoSwift (1.8.3)

Expand All @@ -15,6 +17,7 @@ DEPENDENCIES:
- "CapacitorApp (from `../../../../../node_modules/@capacitor/app`)"
- "CapacitorBrowser (from `../../../../../node_modules/@capacitor/browser`)"
- "CapacitorCordova (from `../../../../../node_modules/@capacitor/ios`)"
- "CapacitorHaptics (from `../../../../../node_modules/@capacitor/haptics`)"
- "CapacitorKeyboard (from `../../../../../node_modules/@capacitor/keyboard`)"
- CryptoSwift (~> 1.8.3)

Expand All @@ -31,17 +34,20 @@ EXTERNAL SOURCES:
:path: "../../../../../node_modules/@capacitor/browser"
CapacitorCordova:
:path: "../../../../../node_modules/@capacitor/ios"
CapacitorHaptics:
:path: "../../../../../node_modules/@capacitor/haptics"
CapacitorKeyboard:
:path: "../../../../../node_modules/@capacitor/keyboard"

SPEC CHECKSUMS:
Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2
CapacitorApp: 0bc633b4eae40a1f32cd2834788fad3bc42da6a1
CapacitorBrowser: aab1ed943b01c0365c4810538a8b3477e2d9f72e
CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd
CapacitorKeyboard: 2700f9b18687be021e28b5a09b59eb151a46d5e0
Capacitor: 1f3c7b9802d958cd8c4eb63895fff85dff2e1eea
CapacitorApp: 2a8c3a0b0814322e5e6e15fe595f02c3808f0f8b
CapacitorBrowser: ef0529d16cd8839281050c350e7bbee4f5c6d65f
CapacitorCordova: b33e7f4aa4ed105dd43283acdd940964374a87d9
CapacitorHaptics: b53409aaca1203f79c6d0eb3ed5de40556339518
CapacitorKeyboard: 460c6f9ec5e52c84f2742d5ce2e67bbc7ab0ebb0
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483

PODFILE CHECKSUM: 1b0d3fe81862c0e9ce712ddd0c5a0accd0097698
PODFILE CHECKSUM: e0c0ccf027ea6d51e476f0baf9d44d97b9a90a4b

COCOAPODS: 1.16.2
1 change: 1 addition & 0 deletions packages/frontend/apps/ios/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@capacitor/app": "^6.0.1",
"@capacitor/browser": "^6.0.3",
"@capacitor/core": "^6.1.2",
"@capacitor/haptics": "^6.0.2",
"@capacitor/ios": "^6.1.2",
"@capacitor/keyboard": "^6.0.2",
"@sentry/react": "^8.0.0",
Expand Down
10 changes: 10 additions & 0 deletions packages/frontend/apps/ios/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AffineContext } from '@affine/core/components/context';
import { AppFallback } from '@affine/core/mobile/components/app-fallback';
import { configureMobileModules } from '@affine/core/mobile/modules';
import { HapticProvider } from '@affine/core/mobile/modules/haptics';
import { NavigationGestureProvider } from '@affine/core/mobile/modules/navigation-gesture';
import { VirtualKeyboardProvider } from '@affine/core/mobile/modules/virtual-keyboard';
import { router } from '@affine/core/mobile/router';
Expand All @@ -22,6 +23,7 @@ import {
} from '@affine/core/modules/workspace-engine';
import { App as CapacitorApp } from '@capacitor/app';
import { Browser } from '@capacitor/browser';
import { Haptics } from '@capacitor/haptics';
import { Keyboard } from '@capacitor/keyboard';
import {
Framework,
Expand Down Expand Up @@ -94,6 +96,14 @@ framework.impl(NavigationGestureProvider, {
enable: () => NavigationGesture.enable(),
disable: () => NavigationGesture.disable(),
});
framework.impl(HapticProvider, {
impact: options => Haptics.impact(options as any),
vibrate: options => Haptics.vibrate(options as any),
notification: options => Haptics.notification(options as any),
selectionStart: () => Haptics.selectionStart(),
selectionChanged: () => Haptics.selectionChanged(),
selectionEnd: () => Haptics.selectionEnd(),
});
const frameworkProvider = framework.provider();

// setup application lifecycle events, and emit application start event
Expand Down
23 changes: 23 additions & 0 deletions packages/frontend/apps/mobile/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AffineContext } from '@affine/core/components/context';
import { AppFallback } from '@affine/core/mobile/components/app-fallback';
import { configureMobileModules } from '@affine/core/mobile/modules';
import { HapticProvider } from '@affine/core/mobile/modules/haptics';
import { router } from '@affine/core/mobile/router';
import { configureCommonModules } from '@affine/core/modules';
import { I18nProvider } from '@affine/core/modules/i18n';
Expand Down Expand Up @@ -52,6 +53,28 @@ framework.impl(PopupWindowProvider, {
window.open(url, '_blank', 'noreferrer noopener');
},
});
framework.impl(HapticProvider, {
impact: options => {
return new Promise(resolve => {
const style = options?.style ?? 'LIGHT';
const pattern = {
LIGHT: [10],
MEDIUM: [20],
HEAVY: [30],
}[style];
const result = navigator.vibrate?.(pattern);
if (!result) {
console.warn('vibrate not supported, or user not interacted');
}
resolve();
});
},
notification: () => Promise.reject('Not supported'),
vibrate: () => Promise.reject('Not supported'),
selectionStart: () => Promise.reject('Not supported'),
selectionChanged: () => Promise.reject('Not supported'),
selectionEnd: () => Promise.reject('Not supported'),
});
const frameworkProvider = framework.provider();

// setup application lifecycle events, and emit application start event
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/component/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7",
"@radix-ui/react-visually-hidden": "^1.1.0",
"@toeverything/theme": "^1.0.18",
"@toeverything/theme": "^1.0.21",
"@vanilla-extract/dynamic": "^2.1.0",
"check-password-strength": "^2.0.10",
"clsx": "^2.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@radix-ui/react-toolbar": "^1.0.4",
"@sentry/react": "^8.0.0",
"@toeverything/pdf-viewer": "^0.1.1",
"@toeverything/theme": "^1.0.18",
"@toeverything/theme": "^1.0.21",
"@vanilla-extract/dynamic": "^2.1.0",
"animejs": "^3.2.2",
"bytes": "^3.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export const useExplorerDocNodeOperationsMenu = (
),
},
{
index: 99,
index: 97,
view: (
<MenuItem
prefixIcon={<LinkedPageIcon />}
Expand All @@ -244,7 +244,7 @@ export const useExplorerDocNodeOperationsMenu = (
),
},
{
index: 99,
index: 98,
view: (
<MenuItem prefixIcon={<DuplicateIcon />} onClick={handleDuplicate}>
{t['com.affine.header.option.duplicate']()}
Expand Down
39 changes: 29 additions & 10 deletions packages/frontend/core/src/mobile/components/explorer/tree/node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { BaseExplorerTreeNodeProps } from '@affine/core/modules/explorer';
import { ExplorerTreeContext } from '@affine/core/modules/explorer';
import { WorkbenchLink } from '@affine/core/modules/workbench';
import { extractEmojiIcon } from '@affine/core/utils';
import { ArrowDownSmallIcon } from '@blocksuite/icons/rc';
import { ArrowDownSmallIcon, MoreHorizontalIcon } from '@blocksuite/icons/rc';
import * as Collapsible from '@radix-ui/react-collapsible';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import {
Expand All @@ -15,6 +15,7 @@ import {
useState,
} from 'react';

import { SwipeMenu } from '../../swipe-menu';
import * as styles from './node.css';

interface ExplorerTreeNodeProps extends BaseExplorerTreeNodeProps {}
Expand Down Expand Up @@ -43,6 +44,7 @@ export const ExplorerTreeNode = ({
const clickForCollapse = !onClick && !to && !disabled;
const [childCount, setChildCount] = useState(0);
const rootRef = useRef<HTMLDivElement>(null);
const [menuOpen, setMenuOpen] = useState(false);

const { emoji, name } = useMemo(() => {
if (!extractEmojiAsIcon || !rawName) {
Expand Down Expand Up @@ -160,15 +162,32 @@ export const ExplorerTreeNode = ({
ref={rootRef}
{...otherProps}
>
<div className={styles.contentContainer} data-open={!collapsed}>
{to ? (
<LinkComponent to={to} className={styles.linkItemRoot}>
{content}
</LinkComponent>
) : (
<div>{content}</div>
)}
</div>
<SwipeMenu
onExecute={useCallback(() => setMenuOpen(true), [])}
menu={
<MobileMenu
rootOptions={useMemo(
() => ({ open: menuOpen, onOpenChange: setMenuOpen }),
[menuOpen]
)}
items={menuOperations.map(({ view, index }) => (
<Fragment key={index}>{view}</Fragment>
))}
>
<MoreHorizontalIcon fontSize={24} />
</MobileMenu>
}
>
<div className={styles.contentContainer} data-open={!collapsed}>
{to ? (
<LinkComponent to={to} className={styles.linkItemRoot}>
{content}
</LinkComponent>
) : (
<div>{content}</div>
)}
</div>
</SwipeMenu>
<Collapsible.Content>
{/* For lastInGroup check, the placeholder must be placed above all children in the dom */}
<div className={styles.collapseContentPlaceholder}>
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/core/src/mobile/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export * from './page-header';
export * from './rename';
export * from './search-input';
export * from './search-result';
export * from './swipe-menu';
export * from './user-plan-tag';
export * from './workspace-selector';
Loading
Loading