Peng Xiao 2023-11-27 09:56:25 +00:00
parent 8841dc3c4e
commit 3891f23dfa
No known key found for this signature in database
GPG Key ID: 23F23D9E8B3971ED
2 changed files with 35 additions and 60 deletions

View File

@ -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,
}, },
]); ]);

View File

@ -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}