diff --git a/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts b/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts
index 229aee59649e6..699a95c55ee69 100644
--- a/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts
+++ b/packages/frontend/core/src/components/app-sidebar/category-divider/index.css.ts
@@ -64,3 +64,30 @@ export const collapseIcon = style({
},
},
});
+
+// ------------- mobile -------------
+export const mobileRoot = style([
+ root,
+ {
+ height: 25,
+ padding: '0 16px',
+ selectors: {
+ '&[data-collapsible="true"]:hover': {
+ backgroundColor: 'transparent',
+ },
+ '&[data-collapsible="true"]:active': {
+ backgroundColor: cssVarV2('layer/background/hoverOverlay'),
+ },
+ },
+ },
+]);
+export const mobileLabel = style([
+ label,
+ {
+ color: cssVarV2('text/primary'),
+ fontSize: 20,
+ lineHeight: '25px',
+ letterSpacing: -0.45,
+ fontWeight: 400,
+ },
+]);
diff --git a/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx b/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx
index 3407939d0f436..a459c01e6706e 100644
--- a/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx
+++ b/packages/frontend/core/src/components/app-sidebar/category-divider/index.tsx
@@ -9,6 +9,7 @@ export type CategoryDividerProps = PropsWithChildren<
label: string;
className?: string;
collapsed?: boolean;
+ mobile?: boolean;
setCollapsed?: (collapsed: boolean) => void;
} & {
[key: `data-${string}`]: unknown;
@@ -22,6 +23,7 @@ export const CategoryDivider = forwardRef(
children,
className,
collapsed,
+ mobile,
setCollapsed,
...otherProps
}: CategoryDividerProps,
@@ -31,14 +33,15 @@ export const CategoryDivider = forwardRef(
return (
setCollapsed?.(!collapsed)}
+ data-mobile={mobile}
data-collapsed={collapsed}
data-collapsible={collapsible}
{...otherProps}
>
-
+
{label}
{collapsible ? (
{
+ const mobile = useContext(ExplorerMobileContext);
const section = useService(ExplorerService).sections[name];
const collapsed = useLiveData(section.collapsed$);
@@ -62,6 +70,7 @@ export const CollapsibleSection = ({
data-testid={testId}
>
- {actions}
+ {mobile ? null : actions}
-
+
{children}
diff --git a/packages/frontend/core/src/modules/explorer/views/mobile.context.ts b/packages/frontend/core/src/modules/explorer/views/mobile.context.ts
new file mode 100644
index 0000000000000..2943d1a275758
--- /dev/null
+++ b/packages/frontend/core/src/modules/explorer/views/mobile.context.ts
@@ -0,0 +1,8 @@
+import { createContext } from 'react';
+
+/**
+ * To enable mobile manually
+ * > Using `environment.isMobile` directly will affect current web entry on mobile
+ * > So we control it manually for now
+ */
+export const ExplorerMobileContext = createContext(false);
diff --git a/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts b/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts
index d4f259a7f8253..6e83be77322b5 100644
--- a/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts
+++ b/packages/frontend/core/src/modules/explorer/views/tree/node.css.ts
@@ -36,6 +36,14 @@ export const itemRoot = style({
},
},
});
+export const itemMain = style({
+ display: 'flex',
+ alignItems: 'center',
+ width: 0,
+ flex: 1,
+ position: 'relative',
+ gap: 12,
+});
export const itemRenameAnchor = style({
pointerEvents: 'none',
position: 'absolute',
@@ -55,31 +63,26 @@ export const itemContent = style({
export const postfix = style({
display: 'flex',
alignItems: 'center',
- right: '4px',
+ right: 0,
position: 'absolute',
opacity: 0,
pointerEvents: 'none',
selectors: {
[`${itemRoot}:hover &`]: {
- justifySelf: 'flex-end',
- position: 'initial',
opacity: 1,
- pointerEvents: 'all',
+ pointerEvents: 'initial',
+ position: 'initial',
},
},
});
-export const icon = style({
- color: cssVarV2('icon/primary'),
- fontSize: '20px',
-});
-export const emojiIcon = style({
- width: '20px',
- height: '20px',
+export const iconContainer = style({
display: 'flex',
- justifyContent: 'center',
+ alignContent: 'center',
alignItems: 'center',
+ width: 20,
+ height: 20,
color: cssVarV2('icon/primary'),
- fontSize: cssVar('--affine-font-sm'),
+ fontSize: 20,
});
export const collapsedIconContainer = style({
width: '16px',
@@ -103,13 +106,6 @@ export const collapsedIconContainer = style({
},
},
});
-export const iconsContainer = style({
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'flex-start',
- width: '44px',
- flexShrink: 0,
-});
export const collapsedIcon = style({
transition: 'transform 0.2s ease-in-out',
selectors: {
@@ -182,3 +178,67 @@ export const draggedOverEffect = style({
},
},
});
+
+// ---------- mobile ----------
+export const mobileItemRoot = style([
+ itemRoot,
+ {
+ padding: '8px',
+ borderRadius: 0,
+ flexDirection: 'row-reverse',
+ gap: 12,
+ selectors: {
+ '&:hover': {
+ background: 'transparent',
+ },
+ '&:active': {
+ background: cssVar('hoverColor'),
+ },
+ '&[data-active="true"]': {
+ background: 'transparent',
+ },
+ },
+
+ ':after': {
+ content: '',
+ width: `calc(100% + ${levelIndent})`,
+ height: 0.5,
+ background: cssVar('borderColor'),
+ bottom: 0,
+ position: 'absolute',
+ right: 0,
+ },
+ },
+]);
+export const mobileItemMain = style([itemMain, {}]);
+
+export const mobileIconContainer = style([
+ iconContainer,
+ {
+ width: 32,
+ height: 32,
+ fontSize: 24,
+ },
+]);
+
+export const mobileCollapsedIconContainer = style([
+ collapsedIconContainer,
+ {
+ fontSize: 16,
+ },
+]);
+export const mobileItemContent = style([
+ itemContent,
+ {
+ fontSize: 17,
+ lineHeight: '22px',
+ letterSpacing: -0.43,
+ fontWeight: 400,
+ },
+]);
+export const mobileContentContainer = style([
+ contentContainer,
+ {
+ marginTop: 0,
+ },
+]);
diff --git a/packages/frontend/core/src/modules/explorer/views/tree/node.tsx b/packages/frontend/core/src/modules/explorer/views/tree/node.tsx
index de2cdeca2a26b..a660d8d867969 100644
--- a/packages/frontend/core/src/modules/explorer/views/tree/node.tsx
+++ b/packages/frontend/core/src/modules/explorer/views/tree/node.tsx
@@ -37,6 +37,7 @@ import {
useState,
} from 'react';
+import { ExplorerMobileContext } from '../mobile.context';
import { ExplorerTreeContext } from './context';
import { DropEffect } from './drop-effect';
import * as styles from './node.css';
@@ -108,6 +109,7 @@ export const ExplorerTreeNode = ({
onDrop?: (data: DropTargetDropEvent) => void;
dropEffect?: ExplorerTreeNodeDropEffect;
} & { [key in `data-${string}`]?: any }) => {
+ const mobile = useContext(ExplorerMobileContext);
const t = useI18n();
const cid = useId();
const context = useContext(ExplorerTreeContext);
@@ -306,35 +308,74 @@ export const ExplorerTreeNode = ({
const content = (
-
+
+
+
-
+ {emoji ??
+ (Icon && (
+
+ ))}
+
+
+
+ {name}
+
+
+ {postfix}
+
{
+ // prevent jump to page
+ e.stopPropagation();
+ e.preventDefault();
+ }}
+ >
+ {inlineOperations.map(({ view }, index) => (
+ {view}
+ ))}
+ {menuOperations.length > 0 && (
+
+ )}
- {emoji ? (
-
{emoji}
- ) : (
- Icon && (
-
- )
- )}
+
{renameable && renaming && (
)}
-
-
{name}
-
- {postfix}
-
{
- // prevent jump to page
- e.stopPropagation();
- e.preventDefault();
- }}
- >
- {inlineOperations.map(({ view }, index) => (
- {view}
- ))}
- {menuOperations.length > 0 && (
-
- )}
-
);
@@ -391,7 +401,10 @@ export const ExplorerTreeNode = ({
{...otherProps}
>