mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-23 20:18:42 +08:00
feat(web): improve keyboard navigation in RootAppSidebar (#2256)
Co-authored-by: Himself65 <himself65@outlook.com>
This commit is contained in:
+26
-1
@@ -2,6 +2,7 @@ import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
|||||||
import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons';
|
import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons';
|
||||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
||||||
import type { AllWorkspace } from '../../../../shared';
|
import type { AllWorkspace } from '../../../../shared';
|
||||||
@@ -18,6 +19,10 @@ export type WorkspaceSelectorProps = {
|
|||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo-Doma Co-locate WorkspaceListModal with {@link WorkspaceSelector},
|
||||||
|
* because it's never used elsewhere.
|
||||||
|
*/
|
||||||
export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
|
export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
|
||||||
currentWorkspace,
|
currentWorkspace,
|
||||||
onClick,
|
onClick,
|
||||||
@@ -26,8 +31,28 @@ export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
|
|||||||
currentWorkspace?.blockSuiteWorkspace ?? null
|
currentWorkspace?.blockSuiteWorkspace ?? null
|
||||||
);
|
);
|
||||||
const [workspace] = useCurrentWorkspace();
|
const [workspace] = useCurrentWorkspace();
|
||||||
|
|
||||||
|
// Open dialog when `Enter` or `Space` pressed
|
||||||
|
// TODO-Doma Refactor with `@radix-ui/react-dialog` or other libraries that handle these out of the box and be accessible by default
|
||||||
|
const handleKeyDown = useCallback(
|
||||||
|
(e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
// TODO-Doma Rename this callback to `onOpenDialog` or something to reduce ambiguity.
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onClick]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledSelectorContainer onClick={onClick} data-testid="current-workspace">
|
<StyledSelectorContainer
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={onClick}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
data-testid="current-workspace"
|
||||||
|
>
|
||||||
<WorkspaceAvatar
|
<WorkspaceAvatar
|
||||||
data-testid="workspace-avatar"
|
data-testid="workspace-avatar"
|
||||||
className={workspaceAvatarStyle}
|
className={workspaceAvatarStyle}
|
||||||
|
|||||||
@@ -36,14 +36,6 @@ export const Favorite = ({
|
|||||||
(currentWorkspaceId && paths.favorite(currentWorkspaceId))
|
(currentWorkspaceId && paths.favorite(currentWorkspaceId))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<StyledCollapseButton
|
|
||||||
onClick={useCallback(() => {
|
|
||||||
setOpenSubFavorite(!showSubFavorite);
|
|
||||||
}, [showSubFavorite])}
|
|
||||||
collapse={showSubFavorite}
|
|
||||||
>
|
|
||||||
<ArrowDownSmallIcon />
|
|
||||||
</StyledCollapseButton>
|
|
||||||
<StyledLink
|
<StyledLink
|
||||||
href={{
|
href={{
|
||||||
pathname: currentWorkspaceId && paths.favorite(currentWorkspaceId),
|
pathname: currentWorkspaceId && paths.favorite(currentWorkspaceId),
|
||||||
@@ -52,6 +44,14 @@ export const Favorite = ({
|
|||||||
<FavoriteIcon />
|
<FavoriteIcon />
|
||||||
{t['Favorites']()}
|
{t['Favorites']()}
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
|
<StyledCollapseButton
|
||||||
|
onClick={useCallback(() => {
|
||||||
|
setOpenSubFavorite(!showSubFavorite);
|
||||||
|
}, [showSubFavorite])}
|
||||||
|
collapse={showSubFavorite}
|
||||||
|
>
|
||||||
|
<ArrowDownSmallIcon />
|
||||||
|
</StyledCollapseButton>
|
||||||
</StyledListItem>
|
</StyledListItem>
|
||||||
<FavoriteList
|
<FavoriteList
|
||||||
currentPageId={currentPageId}
|
currentPageId={currentPageId}
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ export const StyledCollapseButton = styled('button')<{
|
|||||||
':hover': {
|
':hover': {
|
||||||
opacity: '1',
|
opacity: '1',
|
||||||
},
|
},
|
||||||
|
':focus-visible': {
|
||||||
|
outline: '-webkit-focus-ring-color auto 1px',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import {
|
|||||||
import type { Page } from '@blocksuite/store';
|
import type { Page } from '@blocksuite/store';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import type { ReactElement, UIEvent } from 'react';
|
import type { ReactElement, UIEvent } from 'react';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import type React from 'react';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import type { AllWorkspace } from '../../shared';
|
import type { AllWorkspace } from '../../shared';
|
||||||
import ChangeLog from '../pure/workspace-slider-bar/changeLog';
|
import ChangeLog from '../pure/workspace-slider-bar/changeLog';
|
||||||
@@ -80,6 +81,16 @@ export const RootAppSidebar = ({
|
|||||||
}
|
}
|
||||||
}, [sidebarOpen]);
|
}, [sidebarOpen]);
|
||||||
const [ref, setRef] = useState<HTMLElement | null>(null);
|
const [ref, setRef] = useState<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
const handleQuickSearchButtonKeyDown = useCallback(
|
||||||
|
(e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
onOpenQuickSearchModal();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onOpenQuickSearchModal]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AppSidebar
|
<AppSidebar
|
||||||
@@ -104,8 +115,11 @@ export const RootAppSidebar = ({
|
|||||||
onClick={useCallback(() => {
|
onClick={useCallback(() => {
|
||||||
onOpenQuickSearchModal();
|
onOpenQuickSearchModal();
|
||||||
}, [onOpenQuickSearchModal])}
|
}, [onOpenQuickSearchModal])}
|
||||||
|
onKeyDown={handleQuickSearchButtonKeyDown}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user