feat(core): linked doc visiblity setting and new sidebar layout (#12836)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a setting to control the visibility of linked document
structures in the sidebar, enabled by default.
- Introduced a "dense" mode for workspace selectors and cards, providing
a more compact display.

- **Improvements**
- Refined sidebar and navigation panel layouts with updated padding,
spacing, and avatar/button sizing for a cleaner and more consistent
appearance.
- Enhanced sidebar appearance settings UI, including new localization
for the linked doc visibility option.
- Updated color theming and spacing in sidebar menu items and quick
search input for better usability.
- Enabled collapsible behavior control for navigation panel tree nodes,
improving user interaction flexibility.

- **Style**
- Adjusted various component styles for improved compactness and
alignment across the sidebar and navigation panels.
- Reduced sizes and padding of buttons and icons for a tidier interface.
- Updated CSS variables and dynamic sizing for workspace cards to
support dense mode.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Cats Juice
2025-06-17 16:09:34 +08:00
committed by GitHub
parent ba718b955a
commit dfe4c22a75
23 changed files with 205 additions and 94 deletions
@@ -5,6 +5,9 @@ export const workspaceAndUserWrapper = style({
alignItems: 'center',
justifyContent: 'space-between',
gap: 8,
width: 'calc(100% + 12px)',
paddingRight: 6,
alignSelf: 'center',
});
export const quickSearchAndNewPage = style({
display: 'flex',
@@ -167,6 +167,7 @@ export const RootAppSidebar = memo((): ReactElement => {
showSyncStatus
open={workspaceSelectorOpen}
onOpenChange={onWorkspaceSelectorOpenChange}
dense
/>
</div>
<UserInfo />
@@ -38,8 +38,14 @@ const menuContentOptions: MenuProps['contentOptions'] = {
const AuthorizedUserInfo = ({ account }: { account: AuthAccountInfo }) => {
return (
<Menu items={<OperationMenu />} contentOptions={menuContentOptions}>
<IconButton data-testid="sidebar-user-avatar" variant="plain" size="24">
<Avatar size={24} name={account.label} url={account.avatar} />
<IconButton
data-testid="sidebar-user-avatar"
variant="plain"
size="20"
style={{ padding: 0 }}
withoutHover
>
<Avatar size={20} name={account.label} url={account.avatar} />
</IconButton>
</Menu>
);
@@ -57,7 +63,7 @@ const UnauthorizedUserInfo = () => {
onClick={openSignInModal}
data-testid="sidebar-user-avatar"
variant="plain"
size="24"
size="20"
>
<UnknownUserIcon />
</IconButton>
@@ -32,6 +32,8 @@ interface WorkspaceSelectorProps {
disable?: boolean;
menuContentOptions?: MenuProps['contentOptions'];
className?: string;
/** if true, will hide cloud/local, and scale the avatar */
dense?: boolean;
}
export const WorkspaceSelector = ({
@@ -46,6 +48,7 @@ export const WorkspaceSelector = ({
showSyncStatus,
className,
menuContentOptions,
dense,
}: WorkspaceSelectorProps) => {
const { workspacesService, globalContextService } = useServices({
GlobalContextService,
@@ -133,6 +136,7 @@ export const WorkspaceSelector = ({
hideCollaborationIcon={true}
hideTeamWorkspaceIcon={true}
data-testid="current-workspace-card"
dense={dense}
/>
) : (
<span></span>
@@ -174,9 +174,11 @@ const usePauseAnimation = (timeToResume = 5000) => {
const WorkspaceSyncInfo = ({
workspaceMetadata,
workspaceProfile,
dense,
}: {
workspaceMetadata: WorkspaceMetadata;
workspaceProfile: WorkspaceProfileInfo;
dense?: boolean;
}) => {
const syncStatus = useSyncEngineSyncProgress(workspaceMetadata);
const isCloud = workspaceMetadata.flavour !== 'local';
@@ -209,15 +211,21 @@ const WorkspaceSyncInfo = ({
}
return (
<div className={styles.workspaceInfoSlider} data-active={delayActive}>
<div
className={styles.workspaceInfoSlider}
data-active={delayActive}
data-dense={dense}
>
<div className={styles.workspaceInfoSlide}>
<div className={styles.workspaceInfo} data-type="normal">
<div className={styles.workspaceName} data-testid="workspace-name">
{workspaceProfile.name}
</div>
<div className={styles.workspaceStatus}>
{isCloud ? <CloudWorkspaceStatus /> : <LocalWorkspaceStatus />}
</div>
{!dense ? (
<div className={styles.workspaceStatus}>
{isCloud ? <CloudWorkspaceStatus /> : <LocalWorkspaceStatus />}
</div>
) : null}
</div>
{/* when syncing/offline/... */}
@@ -250,6 +258,7 @@ export const WorkspaceCard = forwardRef<
hideTeamWorkspaceIcon?: boolean;
active?: boolean;
infoClassName?: string;
dense?: boolean;
onClickOpenSettings?: (workspaceMetadata: WorkspaceMetadata) => void;
onClickEnableCloud?: (workspaceMetadata: WorkspaceMetadata) => void;
}
@@ -259,7 +268,6 @@ export const WorkspaceCard = forwardRef<
workspaceMetadata,
showSyncStatus,
showArrowDownIcon,
avatarSize = 32,
onClickOpenSettings,
onClickEnableCloud,
className,
@@ -268,6 +276,8 @@ export const WorkspaceCard = forwardRef<
hideCollaborationIcon,
hideTeamWorkspaceIcon,
active,
dense,
avatarSize = dense ? 20 : 32,
...props
},
ref
@@ -301,6 +311,7 @@ export const WorkspaceCard = forwardRef<
<div className={clsx(styles.infoContainer, infoClassName)}>
{information ? (
<WorkspaceAvatar
className={styles.avatar}
meta={workspaceMetadata}
rounded={3}
data-testid="workspace-avatar"
@@ -317,6 +328,7 @@ export const WorkspaceCard = forwardRef<
<WorkspaceSyncInfo
workspaceProfile={information}
workspaceMetadata={workspaceMetadata}
dense={dense}
/>
) : (
<span className={styles.workspaceName}>{information.name}</span>
@@ -9,11 +9,10 @@ const wsSlideAnim = {
};
export const container = style({
height: '50px',
display: 'flex',
alignItems: 'center',
gap: 8,
padding: '0 6px',
padding: '4px 6px',
borderRadius: 4,
outline: 'none',
width: '100%',
@@ -48,8 +47,16 @@ export const disable = style({
});
export const workspaceInfoSlider = style({
height: 42,
vars: {
'--h': '42px',
},
height: 'var(--h)',
overflow: 'hidden',
selectors: {
'&[data-dense="true"]': {
vars: { '--h': '22px' },
},
},
});
export const workspaceInfoSlide = style({
display: 'flex',
@@ -59,15 +66,18 @@ export const workspaceInfoSlide = style({
transition: `transform ${wsSlideAnim.duration} ${wsSlideAnim.ease} ${wsSlideAnim.delay}`,
selectors: {
[`.${workspaceInfoSlider}[data-active="true"] &`]: {
transform: 'translateY(-42px)',
transform: 'translateY(calc(var(--h) * -1))',
},
},
});
export const avatar = style({
border: `0.5px solid ${cssVarV2.layer.insideBorder.border}`,
});
export const workspaceInfo = style({
width: '100%',
flexGrow: 1,
overflow: 'hidden',
height: 42,
height: 'var(--h)',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',