mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-26 14:32:40 +03:00
fix(component): rework tags list collapsing (#5072)
Before: ![CleanShot 2023-11-27 at 16.39.55@2x.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/T2klNLEk0wxLh4NRDzhk/2ac2b8e3-6c30-41f7-a9b2-7a9c81b250fa.png) After: ![CleanShot 2023-11-27 at 16.38.50@2x.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/T2klNLEk0wxLh4NRDzhk/12eac806-e641-45be-9215-d166f8733db9.png)
This commit is contained in:
parent
8841dc3c4e
commit
3891f23dfa
@ -1,4 +1,6 @@
|
|||||||
import { style } from '@vanilla-extract/css';
|
import { createVar, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const hoverMaxWidth = createVar();
|
||||||
|
|
||||||
export const root = style({
|
export const root = style({
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@ -15,7 +17,8 @@ export const tagsContainer = style({
|
|||||||
export const tagsScrollContainer = style([
|
export const tagsScrollContainer = style([
|
||||||
tagsContainer,
|
tagsContainer,
|
||||||
{
|
{
|
||||||
overflow: 'auto',
|
overflowX: 'hidden',
|
||||||
|
position: 'relative',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
gap: '8px',
|
gap: '8px',
|
||||||
},
|
},
|
||||||
@ -41,7 +44,7 @@ export const innerContainer = style({
|
|||||||
transition: 'all 0.2s 0.3s ease-in-out',
|
transition: 'all 0.2s 0.3s ease-in-out',
|
||||||
selectors: {
|
selectors: {
|
||||||
[`${root}:hover &`]: {
|
[`${root}:hover &`]: {
|
||||||
maxWidth: 'var(--hover-max-width)',
|
maxWidth: hoverMaxWidth,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -66,6 +69,16 @@ export const innerBackdrop = style({
|
|||||||
|
|
||||||
export const tag = style({
|
export const tag = style({
|
||||||
height: '20px',
|
height: '20px',
|
||||||
|
display: 'flex',
|
||||||
|
minWidth: 0,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
':last-child': {
|
||||||
|
minWidth: 'max-content',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const tagInnerWrapper = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@ -74,7 +87,7 @@ export const tag = style({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const tagSticky = style([
|
export const tagSticky = style([
|
||||||
tag,
|
tagInnerWrapper,
|
||||||
{
|
{
|
||||||
fontSize: 'var(--affine-font-xs)',
|
fontSize: 'var(--affine-font-xs)',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
@ -82,10 +95,8 @@ export const tagSticky = style([
|
|||||||
border: '1px solid var(--affine-border-color)',
|
border: '1px solid var(--affine-border-color)',
|
||||||
background: 'var(--affine-background-primary-color)',
|
background: 'var(--affine-background-primary-color)',
|
||||||
maxWidth: '128px',
|
maxWidth: '128px',
|
||||||
position: 'sticky',
|
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
left: 0,
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import type { Tag } from '@affine/env/filter';
|
import type { Tag } from '@affine/env/filter';
|
||||||
import { MoreHorizontalIcon } from '@blocksuite/icons';
|
import { MoreHorizontalIcon } from '@blocksuite/icons';
|
||||||
import { Menu } from '@toeverything/components/menu';
|
import { Menu } from '@toeverything/components/menu';
|
||||||
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useRef } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import * as styles from './page-tags.css';
|
import * as styles from './page-tags.css';
|
||||||
import { stopPropagation } from './utils';
|
import { stopPropagation } from './utils';
|
||||||
@ -42,18 +43,22 @@ const TagItem = ({ tag, idx, mode, style }: TagItemProps) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-testid="page-tag"
|
data-testid="page-tag"
|
||||||
className={mode === 'sticky' ? styles.tagSticky : styles.tagListItem}
|
className={styles.tag}
|
||||||
data-idx={idx}
|
data-idx={idx}
|
||||||
title={tag.value}
|
title={tag.value}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={styles.tagIndicator}
|
className={mode === 'sticky' ? styles.tagSticky : styles.tagListItem}
|
||||||
style={{
|
>
|
||||||
backgroundColor: tagColorMap(tag.color),
|
<div
|
||||||
}}
|
className={styles.tagIndicator}
|
||||||
/>
|
style={{
|
||||||
<div className={styles.tagLabel}>{tag.value}</div>
|
backgroundColor: tagColorMap(tag.color),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className={styles.tagLabel}>{tag.value}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -69,26 +74,6 @@ export const PageTags = ({
|
|||||||
? widthOnHover
|
? widthOnHover
|
||||||
: `${widthOnHover}px`
|
: `${widthOnHover}px`
|
||||||
: 'auto';
|
: 'auto';
|
||||||
const tagsContainerRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (tagsContainerRef.current) {
|
|
||||||
const tagsContainer = tagsContainerRef.current;
|
|
||||||
const listener = () => {
|
|
||||||
// on mouseleave, reset scroll position to the hoverExpandDirection
|
|
||||||
tagsContainer.scrollTo({
|
|
||||||
left: hoverExpandDirection === 'left' ? Number.MAX_SAFE_INTEGER : 0,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
listener();
|
|
||||||
tagsContainerRef.current.addEventListener('mouseleave', listener);
|
|
||||||
return () => {
|
|
||||||
tagsContainer.removeEventListener('mouseleave', listener);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}, [hoverExpandDirection]);
|
|
||||||
|
|
||||||
const tagsInPopover = useMemo(() => {
|
const tagsInPopover = useMemo(() => {
|
||||||
const lastTags = tags.slice(maxItems);
|
const lastTags = tags.slice(maxItems);
|
||||||
@ -107,36 +92,17 @@ export const PageTags = ({
|
|||||||
// sort tags by length
|
// sort tags by length
|
||||||
nTags.sort((a, b) => a.value.length - b.value.length);
|
nTags.sort((a, b) => a.value.length - b.value.length);
|
||||||
|
|
||||||
const tagRightCharLength = nTags.reduceRight<number[]>(
|
|
||||||
(acc, tag) => {
|
|
||||||
const curr = acc[0] + Math.min(tag.value.length, 10);
|
|
||||||
return [curr, ...acc];
|
|
||||||
},
|
|
||||||
[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
tagRightCharLength.shift();
|
|
||||||
|
|
||||||
return nTags.map((tag, idx) => (
|
return nTags.map((tag, idx) => (
|
||||||
<TagItem
|
<TagItem key={tag.id} tag={tag} idx={idx} mode="sticky" />
|
||||||
key={tag.id}
|
|
||||||
tag={tag}
|
|
||||||
idx={idx}
|
|
||||||
mode="sticky"
|
|
||||||
style={{
|
|
||||||
right: `calc(${tagRightCharLength[idx]}em)`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
));
|
));
|
||||||
}, [maxItems, tags]);
|
}, [maxItems, tags]);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-testid="page-tags"
|
data-testid="page-tags"
|
||||||
className={styles.root}
|
className={styles.root}
|
||||||
style={{
|
style={assignInlineVars({
|
||||||
// @ts-expect-error it's fine
|
[styles.hoverMaxWidth]: sanitizedWidthOnHover,
|
||||||
'--hover-max-width': sanitizedWidthOnHover,
|
})}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -146,9 +112,7 @@ export const PageTags = ({
|
|||||||
className={clsx(styles.innerContainer)}
|
className={clsx(styles.innerContainer)}
|
||||||
>
|
>
|
||||||
<div className={styles.innerBackdrop} />
|
<div className={styles.innerBackdrop} />
|
||||||
<div className={styles.tagsScrollContainer} ref={tagsContainerRef}>
|
<div className={styles.tagsScrollContainer}>{tagsNormal}</div>
|
||||||
{tagsNormal}
|
|
||||||
</div>
|
|
||||||
{maxItems && tags.length > maxItems ? (
|
{maxItems && tags.length > maxItems ? (
|
||||||
<Menu
|
<Menu
|
||||||
items={tagsInPopover}
|
items={tagsInPopover}
|
||||||
|
Loading…
Reference in New Issue
Block a user