FileThumbnail
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { assertionFailed } from "@/base/assert";
|
||||
import { Overlay } from "@/base/components/containers";
|
||||
import { isSameDay } from "@/base/date";
|
||||
import { EnteFile } from "@/media/file";
|
||||
import { formattedDateRelative } from "@/base/i18n-date";
|
||||
import { downloadManager } from "@/gallery/services/download";
|
||||
import { EnteFile, enteFileDeletionDate } from "@/media/file";
|
||||
import { FileType } from "@/media/file-type";
|
||||
import {
|
||||
GAP_BTW_TILES,
|
||||
IMAGE_CONTAINER_MAX_HEIGHT,
|
||||
@@ -8,8 +12,19 @@ import {
|
||||
MIN_COLUMNS,
|
||||
} from "@/new/photos/components/FileList";
|
||||
import type { GalleryBarMode } from "@/new/photos/components/gallery/reducer";
|
||||
import {
|
||||
LoadingThumbnail,
|
||||
StaticThumbnail,
|
||||
} from "@/new/photos/components/PlaceholderThumbnails";
|
||||
import { TileBottomTextOverlay } from "@/new/photos/components/Tiles";
|
||||
import { TRASH_SECTION } from "@/new/photos/services/collection";
|
||||
import { FlexWrapper } from "@ente/shared/components/Container";
|
||||
import useLongPress from "@ente/shared/hooks/useLongPress";
|
||||
import AlbumOutlinedIcon from "@mui/icons-material/AlbumOutlined";
|
||||
import FavoriteRoundedIcon from "@mui/icons-material/FavoriteRounded";
|
||||
import PlayCircleOutlineOutlinedIcon from "@mui/icons-material/PlayCircleOutlineOutlined";
|
||||
import { Box, Checkbox, Link, Typography, styled } from "@mui/material";
|
||||
import Avatar from "components/pages/gallery/Avatar";
|
||||
import { t } from "i18next";
|
||||
import memoize from "memoize-one";
|
||||
import { GalleryContext } from "pages/gallery";
|
||||
@@ -21,12 +36,12 @@ import {
|
||||
areEqual,
|
||||
} from "react-window";
|
||||
import { SelectedState } from "types/gallery";
|
||||
import { shouldShowAvatar } from "utils/file";
|
||||
import {
|
||||
handleSelectCreator,
|
||||
handleSelectCreatorMulti,
|
||||
} from "utils/photoFrame";
|
||||
import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery";
|
||||
import PreviewCard from "./pages/gallery/PreviewCard";
|
||||
|
||||
export const DATE_CONTAINER_HEIGHT = 48;
|
||||
export const SPACE_BTW_DATES = 44;
|
||||
@@ -747,7 +762,7 @@ export const FileList: React.FC<FileListProps> = ({
|
||||
index: number,
|
||||
isScrolling: boolean,
|
||||
) => (
|
||||
<PreviewCard
|
||||
<FileThumbnail
|
||||
key={`tile-${file.id}-selected-${selected[file.id] ?? false}`}
|
||||
file={file}
|
||||
onClick={() => onItemClick(index)}
|
||||
@@ -1067,3 +1082,305 @@ const PhotoListRow = React.memo(
|
||||
},
|
||||
areEqual,
|
||||
);
|
||||
|
||||
interface FileThumbnailProps {
|
||||
file: EnteFile;
|
||||
onClick: () => void;
|
||||
selectable: boolean;
|
||||
selected: boolean;
|
||||
onSelect: (checked: boolean) => void;
|
||||
onHover: () => void;
|
||||
onRangeSelect: () => void;
|
||||
isRangeSelectActive: boolean;
|
||||
selectOnClick: boolean;
|
||||
isInsSelectRange: boolean;
|
||||
activeCollectionID: number;
|
||||
showPlaceholder: boolean;
|
||||
isFav: boolean;
|
||||
}
|
||||
|
||||
const FileThumbnail: React.FC<FileThumbnailProps> = ({
|
||||
file,
|
||||
onClick,
|
||||
selectable,
|
||||
selected,
|
||||
onSelect,
|
||||
selectOnClick,
|
||||
onHover,
|
||||
onRangeSelect,
|
||||
isRangeSelectActive,
|
||||
isInsSelectRange,
|
||||
isFav,
|
||||
activeCollectionID,
|
||||
showPlaceholder,
|
||||
}) => {
|
||||
const galleryContext = useContext(GalleryContext);
|
||||
|
||||
const [imageURL, setImageURL] = useState<string | undefined>(undefined);
|
||||
|
||||
const longPress = useLongPress(() => onSelect(!selected), 500);
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false;
|
||||
|
||||
void downloadManager
|
||||
.renderableThumbnailURL(file, showPlaceholder)
|
||||
.then((url) => !didCancel && setImageURL(url));
|
||||
|
||||
return () => {
|
||||
didCancel = true;
|
||||
};
|
||||
}, [file, showPlaceholder]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (selectOnClick) {
|
||||
if (isRangeSelectActive) {
|
||||
onRangeSelect();
|
||||
} else {
|
||||
onSelect(!selected);
|
||||
}
|
||||
} else if (imageURL) {
|
||||
onClick?.();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelect: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
if (isRangeSelectActive) {
|
||||
onRangeSelect?.();
|
||||
} else {
|
||||
onSelect(e.target.checked);
|
||||
}
|
||||
};
|
||||
|
||||
const handleHover = () => {
|
||||
if (isRangeSelectActive) {
|
||||
onHover();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FileThumbnail_
|
||||
key={`thumb-${file.id}}`}
|
||||
onClick={handleClick}
|
||||
onMouseEnter={handleHover}
|
||||
disabled={!imageURL}
|
||||
{...(selectable ? longPress : {})}
|
||||
>
|
||||
{selectable && (
|
||||
<Check
|
||||
type="checkbox"
|
||||
checked={selected}
|
||||
onChange={handleSelect}
|
||||
$active={isRangeSelectActive && isInsSelectRange}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
)}
|
||||
{file.metadata.hasStaticThumbnail ? (
|
||||
<StaticThumbnail fileType={file.metadata.fileType} />
|
||||
) : imageURL ? (
|
||||
<img src={imageURL} />
|
||||
) : (
|
||||
<LoadingThumbnail />
|
||||
)}
|
||||
{file.metadata.fileType === FileType.livePhoto ? (
|
||||
<FileTypeIndicatorOverlay>
|
||||
<AlbumOutlinedIcon />
|
||||
</FileTypeIndicatorOverlay>
|
||||
) : (
|
||||
file.metadata.fileType === FileType.video && (
|
||||
<FileTypeIndicatorOverlay>
|
||||
<PlayCircleOutlineOutlinedIcon />
|
||||
</FileTypeIndicatorOverlay>
|
||||
)
|
||||
)}
|
||||
{selected && <SelectedOverlay />}
|
||||
{shouldShowAvatar(file, galleryContext.user) && (
|
||||
<AvatarOverlay>
|
||||
<Avatar file={file} />
|
||||
</AvatarOverlay>
|
||||
)}
|
||||
{isFav && (
|
||||
<FavoriteOverlay>
|
||||
<FavoriteRoundedIcon />
|
||||
</FavoriteOverlay>
|
||||
)}
|
||||
|
||||
<HoverOverlay
|
||||
className="preview-card-hover-overlay"
|
||||
checked={selected}
|
||||
/>
|
||||
{isRangeSelectActive && isInsSelectRange && (
|
||||
<InSelectRangeOverlay />
|
||||
)}
|
||||
|
||||
{activeCollectionID === TRASH_SECTION && file.isTrashed && (
|
||||
<TileBottomTextOverlay>
|
||||
<Typography variant="small">
|
||||
{formattedDateRelative(enteFileDeletionDate(file))}
|
||||
</Typography>
|
||||
</TileBottomTextOverlay>
|
||||
)}
|
||||
</FileThumbnail_>
|
||||
);
|
||||
};
|
||||
|
||||
const FileThumbnail_ = styled("div")<{ disabled: boolean }>`
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
margin-bottom: ${GAP_BTW_TILES}px;
|
||||
min-width: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")};
|
||||
user-select: none;
|
||||
& > img {
|
||||
object-fit: cover;
|
||||
max-width: 100%;
|
||||
min-height: 100%;
|
||||
flex: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
input[type="checkbox"] {
|
||||
visibility: visible;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.preview-card-hover-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
border-radius: 4px;
|
||||
`;
|
||||
|
||||
const Check = styled("input")<{ $active: boolean }>(
|
||||
({ theme, $active }) => `
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
/* Increase z-index in stacking order to capture clicks */
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
@media (pointer: coarse) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
background-color: #ddd;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
vertical-align: bottom;
|
||||
margin: 6px 6px;
|
||||
transition: background-color 0.3s ease;
|
||||
pointer-events: inherit;
|
||||
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
height: 11px;
|
||||
border-right: 2px solid #333;
|
||||
border-bottom: 2px solid #333;
|
||||
transition: transform 0.3s ease;
|
||||
pointer-events: inherit;
|
||||
transform: translate(-18px, 9px) rotate(45deg);
|
||||
}
|
||||
|
||||
/* checkmark background (filled circle) */
|
||||
&:checked::before {
|
||||
content: "";
|
||||
background-color: ${theme.vars.palette.accent.main};
|
||||
border-color: ${theme.vars.palette.accent.main};
|
||||
color: white;
|
||||
}
|
||||
/* checkmark foreground (tick) */
|
||||
&:checked::after {
|
||||
content: "";
|
||||
border-right: 2px solid #ddd;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
visibility: hidden;
|
||||
${$active && "visibility: visible; opacity: 0.5;"};
|
||||
&:checked {
|
||||
visibility: visible;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
const HoverOverlay = styled("div")<{ checked: boolean }>`
|
||||
opacity: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
outline: none;
|
||||
height: 40%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
${(props) =>
|
||||
!props.checked &&
|
||||
"background:linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0))"};
|
||||
`;
|
||||
|
||||
/**
|
||||
* An overlay showing the avatars of the person who shared the item, at the top
|
||||
* right.
|
||||
*/
|
||||
const AvatarOverlay = styled(Overlay)`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-start;
|
||||
padding: 5px;
|
||||
`;
|
||||
|
||||
/**
|
||||
* An overlay showing the favorite icon at bottom left.
|
||||
*/
|
||||
const FavoriteOverlay = styled(Overlay)`
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
opacity: 0.6;
|
||||
`;
|
||||
|
||||
/**
|
||||
* An overlay with a gradient, showing the file type indicator (e.g. live photo,
|
||||
* video) at the bottom right.
|
||||
*/
|
||||
const FileTypeIndicatorOverlay = styled(Overlay)`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
background: linear-gradient(
|
||||
315deg,
|
||||
rgba(0 0 0 / 0.14) 0%,
|
||||
rgba(0 0 0 / 0.05) 30%,
|
||||
transparent 50%
|
||||
);
|
||||
`;
|
||||
|
||||
const InSelectRangeOverlay = styled(Overlay)(
|
||||
({ theme }) => `
|
||||
outline: none;
|
||||
background: ${theme.vars.palette.accent.main};
|
||||
opacity: 0.14;
|
||||
`,
|
||||
);
|
||||
|
||||
const SelectedOverlay = styled(Overlay)(
|
||||
({ theme }) => `
|
||||
border: 2px solid ${theme.vars.palette.accent.main};
|
||||
border-radius: 4px;
|
||||
`,
|
||||
);
|
||||
|
||||
@@ -1,323 +0,0 @@
|
||||
import { Overlay } from "@/base/components/containers";
|
||||
import { formattedDateRelative } from "@/base/i18n-date";
|
||||
import { downloadManager } from "@/gallery/services/download";
|
||||
import { enteFileDeletionDate, type EnteFile } from "@/media/file";
|
||||
import { FileType } from "@/media/file-type";
|
||||
import { GAP_BTW_TILES } from "@/new/photos/components/FileList";
|
||||
import {
|
||||
LoadingThumbnail,
|
||||
StaticThumbnail,
|
||||
} from "@/new/photos/components/PlaceholderThumbnails";
|
||||
import { TileBottomTextOverlay } from "@/new/photos/components/Tiles";
|
||||
import { TRASH_SECTION } from "@/new/photos/services/collection";
|
||||
import useLongPress from "@ente/shared/hooks/useLongPress";
|
||||
import AlbumOutlinedIcon from "@mui/icons-material/AlbumOutlined";
|
||||
import FavoriteRoundedIcon from "@mui/icons-material/FavoriteRounded";
|
||||
import PlayCircleOutlineOutlinedIcon from "@mui/icons-material/PlayCircleOutlineOutlined";
|
||||
import { styled, Typography } from "@mui/material";
|
||||
import { GalleryContext } from "pages/gallery";
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { shouldShowAvatar } from "utils/file";
|
||||
import Avatar from "./Avatar";
|
||||
|
||||
interface PreviewCardProps {
|
||||
file: EnteFile;
|
||||
onClick: () => void;
|
||||
selectable: boolean;
|
||||
selected: boolean;
|
||||
onSelect: (checked: boolean) => void;
|
||||
onHover: () => void;
|
||||
onRangeSelect: () => void;
|
||||
isRangeSelectActive: boolean;
|
||||
selectOnClick: boolean;
|
||||
isInsSelectRange: boolean;
|
||||
activeCollectionID: number;
|
||||
showPlaceholder: boolean;
|
||||
isFav: boolean;
|
||||
}
|
||||
|
||||
const Check = styled("input")<{ $active: boolean }>(
|
||||
({ theme, $active }) => `
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
/* Increase z-index in stacking order to capture clicks */
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
@media (pointer: coarse) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
background-color: #ddd;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
vertical-align: bottom;
|
||||
margin: 6px 6px;
|
||||
transition: background-color 0.3s ease;
|
||||
pointer-events: inherit;
|
||||
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
height: 11px;
|
||||
border-right: 2px solid #333;
|
||||
border-bottom: 2px solid #333;
|
||||
transition: transform 0.3s ease;
|
||||
pointer-events: inherit;
|
||||
transform: translate(-18px, 9px) rotate(45deg);
|
||||
}
|
||||
|
||||
/* checkmark background (filled circle) */
|
||||
&:checked::before {
|
||||
content: "";
|
||||
background-color: ${theme.vars.palette.accent.main};
|
||||
border-color: ${theme.vars.palette.accent.main};
|
||||
color: white;
|
||||
}
|
||||
/* checkmark foreground (tick) */
|
||||
&:checked::after {
|
||||
content: "";
|
||||
border-right: 2px solid #ddd;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
visibility: hidden;
|
||||
${$active && "visibility: visible; opacity: 0.5;"};
|
||||
&:checked {
|
||||
visibility: visible;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
const HoverOverlay = styled("div")<{ checked: boolean }>`
|
||||
opacity: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
outline: none;
|
||||
height: 40%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
${(props) =>
|
||||
!props.checked &&
|
||||
"background:linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0))"};
|
||||
`;
|
||||
|
||||
/**
|
||||
* An overlay showing the avatars of the person who shared the item, at the top
|
||||
* right.
|
||||
*/
|
||||
const AvatarOverlay = styled(Overlay)`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-start;
|
||||
padding: 5px;
|
||||
`;
|
||||
|
||||
/**
|
||||
* An overlay showing the favorite icon at bottom left.
|
||||
*/
|
||||
const FavoriteOverlay = styled(Overlay)`
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
opacity: 0.6;
|
||||
`;
|
||||
|
||||
/**
|
||||
* An overlay with a gradient, showing the file type indicator (e.g. live photo,
|
||||
* video) at the bottom right.
|
||||
*/
|
||||
const FileTypeIndicatorOverlay = styled(Overlay)`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
background: linear-gradient(
|
||||
315deg,
|
||||
rgba(0 0 0 / 0.14) 0%,
|
||||
rgba(0 0 0 / 0.05) 30%,
|
||||
transparent 50%
|
||||
);
|
||||
`;
|
||||
|
||||
const InSelectRangeOverlay = styled(Overlay)(
|
||||
({ theme }) => `
|
||||
outline: none;
|
||||
background: ${theme.vars.palette.accent.main};
|
||||
opacity: 0.14;
|
||||
`,
|
||||
);
|
||||
|
||||
const SelectedOverlay = styled(Overlay)(
|
||||
({ theme }) => `
|
||||
border: 2px solid ${theme.vars.palette.accent.main};
|
||||
border-radius: 4px;
|
||||
`,
|
||||
);
|
||||
|
||||
const Cont = styled("div")<{ disabled: boolean }>`
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
margin-bottom: ${GAP_BTW_TILES}px;
|
||||
min-width: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")};
|
||||
user-select: none;
|
||||
& > img {
|
||||
object-fit: cover;
|
||||
max-width: 100%;
|
||||
min-height: 100%;
|
||||
flex: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
input[type="checkbox"] {
|
||||
visibility: visible;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.preview-card-hover-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
border-radius: 4px;
|
||||
`;
|
||||
|
||||
export default function PreviewCard({
|
||||
file,
|
||||
onClick,
|
||||
selectable,
|
||||
selected,
|
||||
onSelect,
|
||||
selectOnClick,
|
||||
onHover,
|
||||
onRangeSelect,
|
||||
isRangeSelectActive,
|
||||
isInsSelectRange,
|
||||
isFav,
|
||||
activeCollectionID,
|
||||
showPlaceholder,
|
||||
}: PreviewCardProps) {
|
||||
const galleryContext = useContext(GalleryContext);
|
||||
|
||||
const [imageURL, setImageURL] = useState<string | undefined>(undefined);
|
||||
|
||||
const longPress = useLongPress(() => onSelect(!selected), 500);
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false;
|
||||
|
||||
void downloadManager
|
||||
.renderableThumbnailURL(file, showPlaceholder)
|
||||
.then((url) => !didCancel && setImageURL(url));
|
||||
|
||||
return () => {
|
||||
didCancel = true;
|
||||
};
|
||||
}, [file, showPlaceholder]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (selectOnClick) {
|
||||
if (isRangeSelectActive) {
|
||||
onRangeSelect();
|
||||
} else {
|
||||
onSelect(!selected);
|
||||
}
|
||||
} else if (imageURL) {
|
||||
onClick?.();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelect: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
if (isRangeSelectActive) {
|
||||
onRangeSelect?.();
|
||||
} else {
|
||||
onSelect(e.target.checked);
|
||||
}
|
||||
};
|
||||
|
||||
const handleHover = () => {
|
||||
if (isRangeSelectActive) {
|
||||
onHover();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Cont
|
||||
key={`thumb-${file.id}}`}
|
||||
onClick={handleClick}
|
||||
onMouseEnter={handleHover}
|
||||
disabled={!imageURL}
|
||||
{...(selectable ? longPress : {})}
|
||||
>
|
||||
{selectable && (
|
||||
<Check
|
||||
type="checkbox"
|
||||
checked={selected}
|
||||
onChange={handleSelect}
|
||||
$active={isRangeSelectActive && isInsSelectRange}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
)}
|
||||
{file.metadata.hasStaticThumbnail ? (
|
||||
<StaticThumbnail fileType={file.metadata.fileType} />
|
||||
) : imageURL ? (
|
||||
<img src={imageURL} />
|
||||
) : (
|
||||
<LoadingThumbnail />
|
||||
)}
|
||||
{file.metadata.fileType === FileType.livePhoto ? (
|
||||
<FileTypeIndicatorOverlay>
|
||||
<AlbumOutlinedIcon />
|
||||
</FileTypeIndicatorOverlay>
|
||||
) : (
|
||||
file.metadata.fileType === FileType.video && (
|
||||
<FileTypeIndicatorOverlay>
|
||||
<PlayCircleOutlineOutlinedIcon />
|
||||
</FileTypeIndicatorOverlay>
|
||||
)
|
||||
)}
|
||||
{selected && <SelectedOverlay />}
|
||||
{shouldShowAvatar(file, galleryContext.user) && (
|
||||
<AvatarOverlay>
|
||||
<Avatar file={file} />
|
||||
</AvatarOverlay>
|
||||
)}
|
||||
{isFav && (
|
||||
<FavoriteOverlay>
|
||||
<FavoriteRoundedIcon />
|
||||
</FavoriteOverlay>
|
||||
)}
|
||||
|
||||
<HoverOverlay
|
||||
className="preview-card-hover-overlay"
|
||||
checked={selected}
|
||||
/>
|
||||
{isRangeSelectActive && isInsSelectRange && (
|
||||
<InSelectRangeOverlay />
|
||||
)}
|
||||
|
||||
{activeCollectionID === TRASH_SECTION && file.isTrashed && (
|
||||
<TileBottomTextOverlay>
|
||||
<Typography variant="small">
|
||||
{formattedDateRelative(enteFileDeletionDate(file))}
|
||||
</Typography>
|
||||
</TileBottomTextOverlay>
|
||||
)}
|
||||
</Cont>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user