mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-25 06:18:45 +08:00
fix: adjust some styles (#2438)
This commit is contained in:
@@ -148,7 +148,7 @@ export const WorkspaceListModal = ({
|
|||||||
{environment.isDesktop && (
|
{environment.isDesktop && (
|
||||||
<Menu
|
<Menu
|
||||||
placement="auto"
|
placement="auto"
|
||||||
trigger={['click', 'hover']}
|
trigger={['click']}
|
||||||
zIndex={1000}
|
zIndex={1000}
|
||||||
content={
|
content={
|
||||||
<StyledCreateWorkspaceCardPillContainer>
|
<StyledCreateWorkspaceCardPillContainer>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useMemo, useState } from 'react';
|
|||||||
import { workspacePreferredModeAtom } from '../../../../atoms';
|
import { workspacePreferredModeAtom } from '../../../../atoms';
|
||||||
import type { FavoriteListProps } from '../index';
|
import type { FavoriteListProps } from '../index';
|
||||||
import EmptyItem from './empty-item';
|
import EmptyItem from './empty-item';
|
||||||
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
interface FavoriteMenuItemProps {
|
interface FavoriteMenuItemProps {
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
@@ -33,16 +34,13 @@ function FavoriteMenuItem({
|
|||||||
return [...new Set(references.filter(ref => !parentIds.has(ref)))];
|
return [...new Set(references.filter(ref => !parentIds.has(ref)))];
|
||||||
}, [references, parentIds]);
|
}, [references, parentIds]);
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const collapsible = referencesToShow.length > 0 && parentIds.size === 0;
|
const collapsible = referencesToShow.length > 0;
|
||||||
const showReferences = collapsible ? !collapsed : referencesToShow.length > 0;
|
const showReferences = collapsible ? !collapsed : referencesToShow.length > 0;
|
||||||
const nestedItem = parentIds.size > 0;
|
const nestedItem = parentIds.size > 0;
|
||||||
|
const untitled = !metaMapping[pageId]?.title;
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={styles.favItemWrapper} data-nested={nestedItem}>
|
||||||
<MenuLinkItem
|
<MenuLinkItem
|
||||||
style={{
|
|
||||||
marginLeft: nestedItem ? '12px' : undefined,
|
|
||||||
width: nestedItem ? 'calc(100% - 12px)' : undefined,
|
|
||||||
}}
|
|
||||||
data-type="favorite-list-item"
|
data-type="favorite-list-item"
|
||||||
data-testid={`favorite-list-item-${pageId}`}
|
data-testid={`favorite-list-item-${pageId}`}
|
||||||
active={active}
|
active={active}
|
||||||
@@ -51,7 +49,9 @@ function FavoriteMenuItem({
|
|||||||
collapsed={collapsible ? collapsed : undefined}
|
collapsed={collapsible ? collapsed : undefined}
|
||||||
onCollapsedChange={setCollapsed}
|
onCollapsedChange={setCollapsed}
|
||||||
>
|
>
|
||||||
<span>{metaMapping[pageId]?.title || 'Untitled'}</span>
|
<span className={styles.label} data-untitled={untitled}>
|
||||||
|
{metaMapping[pageId]?.title || 'Untitled'}
|
||||||
|
</span>
|
||||||
</MenuLinkItem>
|
</MenuLinkItem>
|
||||||
{showReferences &&
|
{showReferences &&
|
||||||
referencesToShow.map(ref => {
|
referencesToShow.map(ref => {
|
||||||
@@ -65,7 +65,7 @@ function FavoriteMenuItem({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const label = style({
|
||||||
|
selectors: {
|
||||||
|
'&[data-untitled="true"]': {
|
||||||
|
opacity: 0.6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const favItemWrapper = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '4px',
|
||||||
|
selectors: {
|
||||||
|
'&[data-nested="true"]': {
|
||||||
|
marginLeft: '12px',
|
||||||
|
width: 'calc(100% - 12px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -12,7 +12,6 @@ interface AddPageButtonProps {
|
|||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Although it is called an input, it is actually a button.
|
|
||||||
export function AddPageButton({
|
export function AddPageButton({
|
||||||
onClick,
|
onClick,
|
||||||
className,
|
className,
|
||||||
|
|||||||
@@ -62,11 +62,17 @@ export const closeIcon = style({
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
transition: '0.1s',
|
transition: '0.1s',
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
|
transform: 'scale(0.6)',
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
|
opacity: 0,
|
||||||
selectors: {
|
selectors: {
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
transform: 'scale(1.1)',
|
transform: 'scale(1.1)',
|
||||||
},
|
},
|
||||||
|
[`${root}:hover &`]: {
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'scale(1)',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const navWrapperStyle = style({
|
|||||||
minWidth: navWidthVar,
|
minWidth: navWidthVar,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
|
paddingBottom: '8px',
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
'@media': {
|
'@media': {
|
||||||
[`(max-width: ${floatingMaxWidth}px)`]: {
|
[`(max-width: ${floatingMaxWidth}px)`]: {
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export const iconsContainer = style({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
width: '28px',
|
width: '28px',
|
||||||
|
flexShrink: 0,
|
||||||
selectors: {
|
selectors: {
|
||||||
'&[data-collapsible="true"]': {
|
'&[data-collapsible="true"]': {
|
||||||
width: '40px',
|
width: '40px',
|
||||||
|
|||||||
@@ -39,28 +39,29 @@ export function MenuItem({
|
|||||||
data-disabled={disabled}
|
data-disabled={disabled}
|
||||||
data-collapsible={collapsible}
|
data-collapsible={collapsible}
|
||||||
>
|
>
|
||||||
<div className={styles.iconsContainer} data-collapsible={collapsible}>
|
{icon && (
|
||||||
{collapsible && (
|
<div className={styles.iconsContainer} data-collapsible={collapsible}>
|
||||||
<div
|
{collapsible && (
|
||||||
onClick={e => {
|
<div
|
||||||
e.stopPropagation();
|
onClick={e => {
|
||||||
e.preventDefault(); // for links
|
e.stopPropagation();
|
||||||
onCollapsedChange?.(!collapsed);
|
e.preventDefault(); // for links
|
||||||
}}
|
onCollapsedChange?.(!collapsed);
|
||||||
data-testid="fav-collapsed-button"
|
}}
|
||||||
className={styles.collapsedIconContainer}
|
data-testid="fav-collapsed-button"
|
||||||
>
|
className={styles.collapsedIconContainer}
|
||||||
<ArrowDownSmallIcon
|
>
|
||||||
className={styles.collapsedIcon}
|
<ArrowDownSmallIcon
|
||||||
data-collapsed={collapsed}
|
className={styles.collapsedIcon}
|
||||||
/>
|
data-collapsed={collapsed}
|
||||||
</div>
|
/>
|
||||||
)}
|
</div>
|
||||||
{icon &&
|
)}
|
||||||
React.cloneElement(icon, {
|
{React.cloneElement(icon, {
|
||||||
className: clsx([styles.icon, icon.props.className]),
|
className: clsx([styles.icon, icon.props.className]),
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={styles.content}>{children}</div>
|
<div className={styles.content}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { globalStyle, style } from '@vanilla-extract/css';
|
import { globalStyle, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
export const baseContainer = style({
|
export const baseContainer = style({
|
||||||
padding: '12px 16px',
|
padding: '4px 16px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexFlow: 'column nowrap',
|
flexFlow: 'column nowrap',
|
||||||
rowGap: '4px',
|
rowGap: '4px',
|
||||||
@@ -13,17 +13,27 @@ export const scrollableContainerRoot = style({
|
|||||||
vars: {
|
vars: {
|
||||||
'--scrollbar-width': '10px',
|
'--scrollbar-width': '10px',
|
||||||
},
|
},
|
||||||
transition: 'all .3s .2s',
|
});
|
||||||
borderTop: '1px solid transparent',
|
|
||||||
|
export const scrollTopBorder = style({
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: '16px',
|
||||||
|
right: '16px',
|
||||||
|
height: '1px',
|
||||||
|
transition: 'opacity .3s .2s',
|
||||||
|
opacity: 0,
|
||||||
|
background: 'var(--affine-black-10)',
|
||||||
selectors: {
|
selectors: {
|
||||||
'&[data-has-scroll-top="true"]': {
|
'&[data-has-scroll-top="true"]': {
|
||||||
boxShadow: 'inset 0 8px 8px -8px var(--affine-black-10)',
|
opacity: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const scrollableViewport = style({
|
export const scrollableViewport = style({
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
marginTop: '4px',
|
||||||
});
|
});
|
||||||
|
|
||||||
globalStyle(`${scrollableViewport} > div`, {
|
globalStyle(`${scrollableViewport} > div`, {
|
||||||
|
|||||||
@@ -39,10 +39,11 @@ function useHasScrollTop() {
|
|||||||
export function SidebarScrollableContainer({ children }: PropsWithChildren) {
|
export function SidebarScrollableContainer({ children }: PropsWithChildren) {
|
||||||
const [hasScrollTop, ref] = useHasScrollTop();
|
const [hasScrollTop, ref] = useHasScrollTop();
|
||||||
return (
|
return (
|
||||||
<ScrollArea.Root
|
<ScrollArea.Root className={styles.scrollableContainerRoot}>
|
||||||
data-has-scroll-top={hasScrollTop}
|
<div
|
||||||
className={styles.scrollableContainerRoot}
|
data-has-scroll-top={hasScrollTop}
|
||||||
>
|
className={styles.scrollTopBorder}
|
||||||
|
/>
|
||||||
<ScrollArea.Viewport
|
<ScrollArea.Viewport
|
||||||
className={clsx([styles.scrollableViewport])}
|
className={clsx([styles.scrollableViewport])}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const spotlight = style({
|
|||||||
background: `radial-gradient(${spotlightSize} circle at ${spotlightX} ${spotlightY}, var(--affine-text-primary-color), transparent)`,
|
background: `radial-gradient(${spotlightSize} circle at ${spotlightX} ${spotlightY}, var(--affine-text-primary-color), transparent)`,
|
||||||
inset: '0px',
|
inset: '0px',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
willChange: 'background',
|
willChange: 'background, opacity',
|
||||||
opacity: spotlightOpacity,
|
opacity: spotlightOpacity,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
transition: 'all 0.2s',
|
transition: 'all 0.2s',
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import type { Meta, StoryFn } from '@storybook/react';
|
||||||
|
import { type PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
import { Spotlight } from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/AppSidebar/Spotlight',
|
||||||
|
component: Spotlight,
|
||||||
|
} satisfies Meta;
|
||||||
|
|
||||||
|
const Container = ({ children }: PropsWithChildren) => (
|
||||||
|
<main
|
||||||
|
style={{
|
||||||
|
position: 'relative',
|
||||||
|
width: '320px',
|
||||||
|
height: '320px',
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Default: StoryFn = () => {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Spotlight />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -12,10 +12,10 @@ function useMouseOffset() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current && ref.current.parentElement) {
|
if (ref.current && ref.current.parentElement) {
|
||||||
const el = ref.current.parentElement;
|
const el = ref.current.parentElement;
|
||||||
const bound = el.getBoundingClientRect();
|
|
||||||
|
|
||||||
// debounce?
|
// debounce?
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
const onMouseMove = (e: MouseEvent) => {
|
||||||
|
const bound = el.getBoundingClientRect();
|
||||||
setOffset({ x: e.clientX - bound.x, y: e.clientY - bound.y });
|
setOffset({ x: e.clientX - bound.x, y: e.clientY - bound.y });
|
||||||
setOutside(false);
|
setOutside(false);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user