refactor(core): image preview toolbar UI (#7207)
Closes: [AFF-1257](https://linear.app/affine-design/issue/AFF-1257/image-preview-toolbar) * refactor logic * update UI style <img width="617" alt="Screenshot 2024-06-13 at 07 21 52" src="https://github.com/toeverything/AFFiNE/assets/27926/1edc6476-0103-4214-8ef2-41b37d95287b"> <img width="760" alt="Screenshot 2024-06-13 at 07 21 33" src="https://github.com/toeverything/AFFiNE/assets/27926/83d27ab2-143f-4bdd-a932-396289c598ec">
This commit is contained in:
@@ -107,32 +107,44 @@ export const imagePreviewModalCaptionStyle = style({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
export const imagePreviewActionBarStyle = style({
|
export const imagePreviewActionBarStyle = style({
|
||||||
display: 'flex',
|
height: '36px',
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: cssVar('white'),
|
|
||||||
borderRadius: '8px',
|
|
||||||
boxShadow: '2px 2px 4px rgba(0, 0, 0, 0.3)',
|
|
||||||
maxWidth: 'max-content',
|
maxWidth: 'max-content',
|
||||||
minHeight: '44px',
|
padding: '0 6px',
|
||||||
maxHeight: '44px',
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '8px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
border: `0.5px solid ${cssVar('borderColor')}`,
|
||||||
|
backgroundColor: cssVar('white'),
|
||||||
|
boxShadow: '0px 6px 16px 0px rgba(0, 0, 0, 0.14)',
|
||||||
|
boxSizing: 'content-box',
|
||||||
|
color: cssVar('iconColor'),
|
||||||
|
userSelect: 'none',
|
||||||
});
|
});
|
||||||
export const groupStyle = style({
|
export const cursorStyle = style({
|
||||||
padding: '10px 0',
|
display: 'flex',
|
||||||
boxSizing: 'border-box',
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '24px',
|
||||||
|
minWidth: '34px',
|
||||||
|
padding: '1px 2px',
|
||||||
|
fontSize: '14px',
|
||||||
|
});
|
||||||
|
export const dividerStyle = style({
|
||||||
|
width: '0.5px',
|
||||||
|
height: '100%',
|
||||||
|
background: cssVar('borderColor'),
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
borderLeft: '1px solid #E3E2E4',
|
|
||||||
});
|
|
||||||
export const buttonStyle = style({
|
|
||||||
margin: '10px 6px',
|
|
||||||
});
|
});
|
||||||
export const scaleIndicatorButtonStyle = style({
|
export const scaleIndicatorButtonStyle = style({
|
||||||
minHeight: '100%',
|
height: '24px',
|
||||||
maxWidth: 'max-content',
|
padding: '1px 2px',
|
||||||
fontSize: '12px',
|
minWidth: '50px',
|
||||||
padding: '5px 5px',
|
fontSize: '14px',
|
||||||
|
color: `${cssVar('iconColor')} !important`,
|
||||||
':hover': {
|
':hover': {
|
||||||
backgroundColor: cssVar('hoverColor'),
|
backgroundColor: cssVar('hoverColor'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import type { ImageBlockModel } from '@blocksuite/blocks';
|
||||||
import { atom } from 'jotai';
|
import { atom } from 'jotai';
|
||||||
|
|
||||||
export const previewBlockIdAtom = atom<string | null>(null);
|
export const previewBlockIdAtom = atom<string | null>(null);
|
||||||
|
export const previewblocksAtom = atom<ImageBlockModel[]>([]);
|
||||||
export const hasAnimationPlayedAtom = atom<boolean | null>(true);
|
export const hasAnimationPlayedAtom = atom<boolean | null>(true);
|
||||||
|
|
||||||
previewBlockIdAtom.onMount = set => {
|
previewBlockIdAtom.onMount = set => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
PlusIcon,
|
PlusIcon,
|
||||||
ViewBarIcon,
|
ViewBarIcon,
|
||||||
} from '@blocksuite/icons';
|
} from '@blocksuite/icons';
|
||||||
import type { DocCollection } from '@blocksuite/store';
|
import type { BlockModel, DocCollection } from '@blocksuite/store';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useErrorBoundary } from 'foxact/use-error-boundary';
|
import { useErrorBoundary } from 'foxact/use-error-boundary';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
@@ -26,9 +26,9 @@ import useSWR from 'swr';
|
|||||||
|
|
||||||
import { useZoomControls } from './hooks/use-zoom';
|
import { useZoomControls } from './hooks/use-zoom';
|
||||||
import {
|
import {
|
||||||
buttonStyle,
|
|
||||||
captionStyle,
|
captionStyle,
|
||||||
groupStyle,
|
cursorStyle,
|
||||||
|
dividerStyle,
|
||||||
imageBottomContainerStyle,
|
imageBottomContainerStyle,
|
||||||
imagePreviewActionBarStyle,
|
imagePreviewActionBarStyle,
|
||||||
imagePreviewBackgroundStyle,
|
imagePreviewBackgroundStyle,
|
||||||
@@ -41,7 +41,15 @@ import {
|
|||||||
scaleIndicatorButtonStyle,
|
scaleIndicatorButtonStyle,
|
||||||
unloaded,
|
unloaded,
|
||||||
} from './index.css';
|
} from './index.css';
|
||||||
import { hasAnimationPlayedAtom, previewBlockIdAtom } from './index.jotai';
|
import {
|
||||||
|
hasAnimationPlayedAtom,
|
||||||
|
previewBlockIdAtom,
|
||||||
|
previewblocksAtom,
|
||||||
|
} from './index.jotai';
|
||||||
|
|
||||||
|
const filterImageBlock = (block: BlockModel): block is ImageBlockModel => {
|
||||||
|
return block.flavour === 'affine:image';
|
||||||
|
};
|
||||||
|
|
||||||
export type ImagePreviewModalProps = {
|
export type ImagePreviewModalProps = {
|
||||||
docCollection: DocCollection;
|
docCollection: DocCollection;
|
||||||
@@ -54,7 +62,9 @@ const ImagePreviewModalImpl = (
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
): ReactElement | null => {
|
): ReactElement | null => {
|
||||||
|
const [blocks, setBlocks] = useAtom(previewblocksAtom);
|
||||||
const [blockId, setBlockId] = useAtom(previewBlockIdAtom);
|
const [blockId, setBlockId] = useAtom(previewBlockIdAtom);
|
||||||
|
const [cursor, setCursor] = useState(0);
|
||||||
const zoomRef = useRef<HTMLDivElement | null>(null);
|
const zoomRef = useRef<HTMLDivElement | null>(null);
|
||||||
const imageRef = useRef<HTMLImageElement | null>(null);
|
const imageRef = useRef<HTMLImageElement | null>(null);
|
||||||
const {
|
const {
|
||||||
@@ -88,98 +98,72 @@ const ImagePreviewModalImpl = (
|
|||||||
return;
|
return;
|
||||||
}, [isOpen, props, setIsOpen]);
|
}, [isOpen, props, setIsOpen]);
|
||||||
|
|
||||||
const nextImageHandler = useCallback(
|
const goto = useCallback(
|
||||||
(blockId: string | null) => {
|
(index: number) => {
|
||||||
assertExists(blockId);
|
|
||||||
const workspace = props.docCollection;
|
|
||||||
if (!hasPlayedAnimation) {
|
if (!hasPlayedAnimation) {
|
||||||
setHasPlayedAnimation(true);
|
setHasPlayedAnimation(true);
|
||||||
}
|
}
|
||||||
const page = workspace.getDoc(props.pageId);
|
|
||||||
assertExists(page);
|
|
||||||
const block = page.getBlockById(blockId);
|
|
||||||
assertExists(block);
|
|
||||||
const nextBlock = page
|
|
||||||
.getNexts(block)
|
|
||||||
.find(
|
|
||||||
(block): block is ImageBlockModel => block.flavour === 'affine:image'
|
|
||||||
);
|
|
||||||
if (nextBlock) {
|
|
||||||
setBlockId(nextBlock.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[props.pageId, props.docCollection, setBlockId, hasPlayedAnimation]
|
|
||||||
);
|
|
||||||
|
|
||||||
const previousImageHandler = useCallback(
|
|
||||||
(blockId: string | null) => {
|
|
||||||
assertExists(blockId);
|
|
||||||
const workspace = props.docCollection;
|
const workspace = props.docCollection;
|
||||||
const page = workspace.getDoc(props.pageId);
|
const page = workspace.getDoc(props.pageId);
|
||||||
assertExists(page);
|
assertExists(page);
|
||||||
const block = page.getBlockById(blockId);
|
|
||||||
assertExists(block);
|
const block = blocks[index];
|
||||||
const prevBlock = page
|
|
||||||
.getPrevs(block)
|
if (!block) return;
|
||||||
.findLast(
|
|
||||||
(block): block is ImageBlockModel => block.flavour === 'affine:image'
|
setCursor(index);
|
||||||
);
|
setBlockId(block.id);
|
||||||
if (prevBlock) {
|
|
||||||
setBlockId(prevBlock.id);
|
|
||||||
}
|
|
||||||
resetZoom();
|
resetZoom();
|
||||||
},
|
},
|
||||||
[props.pageId, props.docCollection, setBlockId, resetZoom]
|
[
|
||||||
|
props.pageId,
|
||||||
|
props.docCollection,
|
||||||
|
blocks,
|
||||||
|
setBlockId,
|
||||||
|
hasPlayedAnimation,
|
||||||
|
resetZoom,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteHandler = useCallback(
|
const deleteHandler = useCallback(
|
||||||
(blockId: string) => {
|
(index: number) => {
|
||||||
const { pageId, docCollection: workspace, onClose } = props;
|
const { pageId, docCollection: workspace, onClose } = props;
|
||||||
|
|
||||||
const page = workspace.getDoc(pageId);
|
const page = workspace.getDoc(pageId);
|
||||||
assertExists(page);
|
assertExists(page);
|
||||||
const block = page.getBlockById(blockId);
|
|
||||||
assertExists(block);
|
let block = blocks[index];
|
||||||
if (
|
|
||||||
page
|
if (!block) return;
|
||||||
.getPrevs(block)
|
|
||||||
.some(
|
blocks.splice(index, 1);
|
||||||
(block): block is ImageBlockModel =>
|
setBlocks([...blocks]);
|
||||||
block.flavour === 'affine:image'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const prevBlock = page
|
|
||||||
.getPrevs(block)
|
|
||||||
.findLast(
|
|
||||||
(block): block is ImageBlockModel =>
|
|
||||||
block.flavour === 'affine:image'
|
|
||||||
);
|
|
||||||
if (prevBlock) {
|
|
||||||
setBlockId(prevBlock.id);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
page
|
|
||||||
.getNexts(block)
|
|
||||||
.some(
|
|
||||||
(block): block is ImageBlockModel =>
|
|
||||||
block.flavour === 'affine:image'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const nextBlock = page
|
|
||||||
.getNexts(block)
|
|
||||||
.find(
|
|
||||||
(block): block is ImageBlockModel =>
|
|
||||||
block.flavour === 'affine:image'
|
|
||||||
);
|
|
||||||
if (nextBlock) {
|
|
||||||
setBlockId(nextBlock.id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
page.deleteBlock(block);
|
page.deleteBlock(block);
|
||||||
|
|
||||||
|
// next
|
||||||
|
block = blocks[index];
|
||||||
|
|
||||||
|
// prev
|
||||||
|
if (!block) {
|
||||||
|
index -= 1;
|
||||||
|
block = blocks[index];
|
||||||
|
|
||||||
|
if (!block) {
|
||||||
|
onClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBlockId(block.id);
|
||||||
|
|
||||||
|
resetZoom();
|
||||||
},
|
},
|
||||||
[props, setBlockId]
|
[props, blocks, setBlockId, setBlocks, setCursor, resetZoom]
|
||||||
);
|
);
|
||||||
|
|
||||||
const downloadHandler = useCallback(
|
const downloadHandler = useCallback(
|
||||||
@@ -188,7 +172,7 @@ const ImagePreviewModalImpl = (
|
|||||||
const page = workspace.getDoc(props.pageId);
|
const page = workspace.getDoc(props.pageId);
|
||||||
assertExists(page);
|
assertExists(page);
|
||||||
if (typeof blockId === 'string') {
|
if (typeof blockId === 'string') {
|
||||||
const block = page.getBlockById(blockId) as ImageBlockModel;
|
const block = page.getBlockById<ImageBlockModel>(blockId);
|
||||||
assertExists(block);
|
assertExists(block);
|
||||||
const store = block.page.blobSync;
|
const store = block.page.blobSync;
|
||||||
const url = store?.get(block.sourceId as string);
|
const url = store?.get(block.sourceId as string);
|
||||||
@@ -238,27 +222,39 @@ const ImagePreviewModalImpl = (
|
|||||||
},
|
},
|
||||||
[props.pageId, props.docCollection]
|
[props.pageId, props.docCollection]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [caption, setCaption] = useState(() => {
|
const [caption, setCaption] = useState(() => {
|
||||||
const page = props.docCollection.getDoc(props.pageId);
|
const page = props.docCollection.getDoc(props.pageId);
|
||||||
assertExists(page);
|
assertExists(page);
|
||||||
const block = page.getBlockById(props.blockId) as ImageBlockModel;
|
const block = page.getBlockById<ImageBlockModel>(props.blockId);
|
||||||
assertExists(block);
|
assertExists(block);
|
||||||
return block?.caption;
|
return block?.caption;
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const page = props.docCollection.getDoc(props.pageId);
|
const page = props.docCollection.getDoc(props.pageId);
|
||||||
assertExists(page);
|
assertExists(page);
|
||||||
const block = page.getBlockById(props.blockId) as ImageBlockModel;
|
|
||||||
|
const block = page.getBlockById<ImageBlockModel>(props.blockId);
|
||||||
assertExists(block);
|
assertExists(block);
|
||||||
|
|
||||||
|
const prevs = page.getPrevs(block).filter(filterImageBlock);
|
||||||
|
const nexts = page.getNexts(block).filter(filterImageBlock);
|
||||||
|
|
||||||
|
const blocks = [...prevs, block, ...nexts];
|
||||||
|
setBlocks(blocks);
|
||||||
|
setCursor(blocks.length ? prevs.length : 0);
|
||||||
|
|
||||||
setCaption(block?.caption);
|
setCaption(block?.caption);
|
||||||
}, [props.blockId, props.pageId, props.docCollection]);
|
}, [props.blockId, props.pageId, props.docCollection, setBlocks]);
|
||||||
|
|
||||||
const { data, error } = useSWR(
|
const { data, error } = useSWR(
|
||||||
['workspace', 'image', props.pageId, props.blockId],
|
['workspace', 'image', props.pageId, props.blockId],
|
||||||
{
|
{
|
||||||
fetcher: ([_, __, pageId, blockId]) => {
|
fetcher: ([_, __, pageId, blockId]) => {
|
||||||
const page = props.docCollection.getDoc(pageId);
|
const page = props.docCollection.getDoc(pageId);
|
||||||
assertExists(page);
|
assertExists(page);
|
||||||
const block = page.getBlockById(blockId) as ImageBlockModel;
|
const block = page.getBlockById<ImageBlockModel>(blockId);
|
||||||
assertExists(block);
|
assertExists(block);
|
||||||
return props.docCollection.blobSync.get(block?.sourceId as string);
|
return props.docCollection.blobSync.get(block?.sourceId as string);
|
||||||
},
|
},
|
||||||
@@ -335,39 +331,33 @@ const ImagePreviewModalImpl = (
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className={imagePreviewActionBarStyle}>
|
<div className={imagePreviewActionBarStyle}>
|
||||||
<div>
|
|
||||||
<Tooltip content={'Previous'}>
|
<Tooltip content={'Previous'}>
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="previous-image-button"
|
data-testid="previous-image-button"
|
||||||
icon={<ArrowLeftSmallIcon />}
|
icon={<ArrowLeftSmallIcon />}
|
||||||
type="plain"
|
type="plain"
|
||||||
className={buttonStyle}
|
disabled={cursor < 1}
|
||||||
onClick={() => {
|
onClick={() => goto(cursor - 1)}
|
||||||
assertExists(blockId);
|
|
||||||
previousImageHandler(blockId);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<div className={cursorStyle}>
|
||||||
|
{`${blocks.length ? cursor + 1 : 0}/${blocks.length}`}
|
||||||
|
</div>
|
||||||
<Tooltip content={'Next'}>
|
<Tooltip content={'Next'}>
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="next-image-button"
|
data-testid="next-image-button"
|
||||||
icon={<ArrowRightSmallIcon />}
|
icon={<ArrowRightSmallIcon />}
|
||||||
className={buttonStyle}
|
|
||||||
type="plain"
|
type="plain"
|
||||||
onClick={() => {
|
disabled={cursor + 1 === blocks.length}
|
||||||
assertExists(blockId);
|
onClick={() => goto(cursor + 1)}
|
||||||
nextImageHandler(blockId);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
<div className={dividerStyle}></div>
|
||||||
<div className={groupStyle}></div>
|
<Tooltip content={'Fit to screen'}>
|
||||||
<Tooltip content={'Fit to Screen'}>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="fit-to-screen-button"
|
data-testid="fit-to-screen-button"
|
||||||
icon={<ViewBarIcon />}
|
icon={<ViewBarIcon />}
|
||||||
type="plain"
|
type="plain"
|
||||||
className={buttonStyle}
|
|
||||||
onClick={() => resetZoom()}
|
onClick={() => resetZoom()}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -375,16 +365,14 @@ const ImagePreviewModalImpl = (
|
|||||||
<IconButton
|
<IconButton
|
||||||
data-testid="zoom-out-button"
|
data-testid="zoom-out-button"
|
||||||
icon={<MinusIcon />}
|
icon={<MinusIcon />}
|
||||||
className={buttonStyle}
|
|
||||||
type="plain"
|
type="plain"
|
||||||
onClick={zoomOut}
|
onClick={zoomOut}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip content={'Reset Scale'}>
|
<Tooltip content={'Reset scale'}>
|
||||||
<Button
|
<Button
|
||||||
data-testid="reset-scale-button"
|
data-testid="reset-scale-button"
|
||||||
type="plain"
|
type="plain"
|
||||||
size={'large'}
|
|
||||||
className={scaleIndicatorButtonStyle}
|
className={scaleIndicatorButtonStyle}
|
||||||
onClick={resetScale}
|
onClick={resetScale}
|
||||||
>
|
>
|
||||||
@@ -395,18 +383,16 @@ const ImagePreviewModalImpl = (
|
|||||||
<IconButton
|
<IconButton
|
||||||
data-testid="zoom-in-button"
|
data-testid="zoom-in-button"
|
||||||
icon={<PlusIcon />}
|
icon={<PlusIcon />}
|
||||||
className={buttonStyle}
|
|
||||||
type="plain"
|
type="plain"
|
||||||
onClick={() => zoomIn()}
|
onClick={() => zoomIn()}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div className={groupStyle}></div>
|
<div className={dividerStyle}></div>
|
||||||
<Tooltip content={'Download'}>
|
<Tooltip content={'Download'}>
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="download-button"
|
data-testid="download-button"
|
||||||
icon={<DownloadIcon />}
|
icon={<DownloadIcon />}
|
||||||
type="plain"
|
type="plain"
|
||||||
className={buttonStyle}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
assertExists(blockId);
|
assertExists(blockId);
|
||||||
downloadHandler(blockId).catch(err => {
|
downloadHandler(blockId).catch(err => {
|
||||||
@@ -420,7 +406,6 @@ const ImagePreviewModalImpl = (
|
|||||||
data-testid="copy-to-clipboard-button"
|
data-testid="copy-to-clipboard-button"
|
||||||
icon={<CopyIcon />}
|
icon={<CopyIcon />}
|
||||||
type="plain"
|
type="plain"
|
||||||
className={buttonStyle}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!imageRef.current) {
|
if (!imageRef.current) {
|
||||||
return;
|
return;
|
||||||
@@ -455,14 +440,14 @@ const ImagePreviewModalImpl = (
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div className={groupStyle}></div>
|
<div className={dividerStyle}></div>
|
||||||
<Tooltip content={'Delete'}>
|
<Tooltip content={'Delete'}>
|
||||||
<IconButton
|
<IconButton
|
||||||
data-testid="delete-button"
|
data-testid="delete-button"
|
||||||
icon={<DeleteIcon />}
|
icon={<DeleteIcon />}
|
||||||
type="plain"
|
type="plain"
|
||||||
className={buttonStyle}
|
disabled={blocks.length === 0}
|
||||||
onClick={() => blockId && deleteHandler(blockId)}
|
onClick={() => deleteHandler(cursor)}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -582,6 +582,9 @@ test('tooltips for all buttons should be visible when hovering', async ({
|
|||||||
await title.click();
|
await title.click();
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
await importImage(page, 'http://localhost:8081/large-image.png');
|
await importImage(page, 'http://localhost:8081/large-image.png');
|
||||||
|
await page.locator('affine-page-image').first().click();
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
await importImage(page, 'http://localhost:8081/large-image.png');
|
||||||
await page.locator('affine-page-image').first().dblclick();
|
await page.locator('affine-page-image').first().dblclick();
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
blobId = (await page
|
blobId = (await page
|
||||||
@@ -593,13 +596,8 @@ test('tooltips for all buttons should be visible when hovering', async ({
|
|||||||
}
|
}
|
||||||
const locator = page.getByTestId('image-preview-modal');
|
const locator = page.getByTestId('image-preview-modal');
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
await locator.getByTestId('previous-image-button').hover();
|
await locator.getByTestId('previous-image-button').isDisabled();
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
{
|
|
||||||
const element = page.getByRole('tooltip');
|
|
||||||
const previousImageTooltip = await element.getByText('Previous').count();
|
|
||||||
expect(previousImageTooltip).toBe(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
await locator.getByTestId('next-image-button').hover();
|
await locator.getByTestId('next-image-button').hover();
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
@@ -609,6 +607,18 @@ test('tooltips for all buttons should be visible when hovering', async ({
|
|||||||
expect(nextImageTooltip).toBe(1);
|
expect(nextImageTooltip).toBe(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await locator.getByTestId('next-image-button').click();
|
||||||
|
await locator.getByTestId('next-image-button').isDisabled();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
await locator.getByTestId('previous-image-button').hover();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
{
|
||||||
|
const element = page.getByRole('tooltip');
|
||||||
|
const previousImageTooltip = await element.getByText('Previous').count();
|
||||||
|
expect(previousImageTooltip).toBe(1);
|
||||||
|
}
|
||||||
|
|
||||||
await locator.getByTestId('fit-to-screen-button').hover();
|
await locator.getByTestId('fit-to-screen-button').hover();
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user