Merge pull request #623 from ente-io/collection-bar-tile-redesign
Collection bar tile redesign
This commit is contained in:
commit
4f92c342d6
|
@ -1,10 +1,20 @@
|
||||||
import { Typography } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
|
import { FlexWrapper } from 'components/Container';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import constants from 'utils/strings/constants';
|
import constants from 'utils/strings/constants';
|
||||||
export function CollectionInfo({ name, fileCount }) {
|
interface Iprops {
|
||||||
|
name: string;
|
||||||
|
fileCount: number;
|
||||||
|
endIcon?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CollectionInfo({ name, fileCount, endIcon }: Iprops) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<FlexWrapper>
|
||||||
<Typography variant="subtitle">{name}</Typography>
|
<Typography variant="subtitle">{name}</Typography>
|
||||||
|
{endIcon && <Box ml={1.5}>{endIcon}</Box>}
|
||||||
|
</FlexWrapper>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
{constants.PHOTO_COUNT(fileCount)}
|
{constants.PHOTO_COUNT(fileCount)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
@ -5,7 +5,11 @@ import CollectionOptions from 'components/Collections/CollectionOptions';
|
||||||
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
|
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
|
||||||
import { SpaceBetweenFlex } from 'components/Container';
|
import { SpaceBetweenFlex } from 'components/Container';
|
||||||
import { CollectionInfoBarWrapper } from './styledComponents';
|
import { CollectionInfoBarWrapper } from './styledComponents';
|
||||||
import { isOptionsHavingCollection } from 'utils/collection';
|
import { shouldShowOptions } from 'utils/collection';
|
||||||
|
import { CollectionSummaryType } from 'constants/collection';
|
||||||
|
import Favorite from '@mui/icons-material/Favorite';
|
||||||
|
import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
||||||
|
import Delete from '@mui/icons-material/Delete';
|
||||||
|
|
||||||
interface Iprops {
|
interface Iprops {
|
||||||
activeCollection: Collection;
|
activeCollection: Collection;
|
||||||
|
@ -33,13 +37,28 @@ export default function CollectionInfoWithOptions({
|
||||||
|
|
||||||
const { name, type, fileCount } = collectionSummary;
|
const { name, type, fileCount } = collectionSummary;
|
||||||
|
|
||||||
|
const EndIcon = ({ type }: { type: CollectionSummaryType }) => {
|
||||||
|
switch (type) {
|
||||||
|
case CollectionSummaryType.favorites:
|
||||||
|
return <Favorite />;
|
||||||
|
case CollectionSummaryType.archived:
|
||||||
|
case CollectionSummaryType.archive:
|
||||||
|
return <VisibilityOff />;
|
||||||
|
case CollectionSummaryType.trash:
|
||||||
|
return <Delete />;
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<CollectionInfoBarWrapper>
|
<CollectionInfoBarWrapper>
|
||||||
<SpaceBetweenFlex>
|
<SpaceBetweenFlex>
|
||||||
<CollectionInfo name={name} fileCount={fileCount} />
|
<CollectionInfo
|
||||||
{isOptionsHavingCollection(type) && (
|
name={name}
|
||||||
<CollectionOptions {...props} />
|
fileCount={fileCount}
|
||||||
)}
|
endIcon={<EndIcon type={type} />}
|
||||||
|
/>
|
||||||
|
{shouldShowOptions(type) && <CollectionOptions {...props} />}
|
||||||
</SpaceBetweenFlex>
|
</SpaceBetweenFlex>
|
||||||
</CollectionInfoBarWrapper>
|
</CollectionInfoBarWrapper>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,28 +3,32 @@ import { EnteFile } from 'types/file';
|
||||||
import {
|
import {
|
||||||
ActiveIndicator,
|
ActiveIndicator,
|
||||||
CollectionBarTile,
|
CollectionBarTile,
|
||||||
|
CollectionBarTileIcon,
|
||||||
CollectionBarTileText,
|
CollectionBarTileText,
|
||||||
} from '../styledComponents';
|
} from '../styledComponents';
|
||||||
import CollectionCard from '../CollectionCard';
|
import CollectionCard from '../CollectionCard';
|
||||||
import TruncateText from 'components/TruncateText';
|
import TruncateText from 'components/TruncateText';
|
||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
|
import { CollectionSummaryType } from 'constants/collection';
|
||||||
|
import Favorite from '@mui/icons-material/Favorite';
|
||||||
|
import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
||||||
|
|
||||||
interface Iprops {
|
interface Iprops {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
latestFile: EnteFile;
|
latestFile: EnteFile;
|
||||||
collectionName: string;
|
collectionName: string;
|
||||||
|
collectionType: CollectionSummaryType;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollectionListBarCard = React.forwardRef((props: Iprops, ref: any) => {
|
const CollectionListBarCard = React.forwardRef((props: Iprops, ref: any) => {
|
||||||
const { active, collectionName, ...others } = props;
|
const { active, collectionName, collectionType, ...others } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box ref={ref}>
|
<Box ref={ref}>
|
||||||
<CollectionCard collectionTile={CollectionBarTile} {...others}>
|
<CollectionCard collectionTile={CollectionBarTile} {...others}>
|
||||||
<CollectionBarTileText>
|
<CollectionCardText collectionName={collectionName} />
|
||||||
<TruncateText text={collectionName} />
|
<CollectionCardIcon collectionType={collectionType} />
|
||||||
</CollectionBarTileText>
|
|
||||||
</CollectionCard>
|
</CollectionCard>
|
||||||
{active && <ActiveIndicator />}
|
{active && <ActiveIndicator />}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -32,3 +36,22 @@ const CollectionListBarCard = React.forwardRef((props: Iprops, ref: any) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
export default CollectionListBarCard;
|
export default CollectionListBarCard;
|
||||||
|
|
||||||
|
function CollectionCardText({ collectionName }) {
|
||||||
|
return (
|
||||||
|
<CollectionBarTileText>
|
||||||
|
<TruncateText text={collectionName} />
|
||||||
|
</CollectionBarTileText>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CollectionCardIcon({ collectionType }) {
|
||||||
|
return (
|
||||||
|
<CollectionBarTileIcon>
|
||||||
|
{collectionType === CollectionSummaryType.favorites && <Favorite />}
|
||||||
|
{collectionType === CollectionSummaryType.archived && (
|
||||||
|
<VisibilityOff />
|
||||||
|
)}
|
||||||
|
</CollectionBarTileIcon>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ export default function CollectionListBar(props: IProps) {
|
||||||
ref={collectionChipsRef[item.id]}
|
ref={collectionChipsRef[item.id]}
|
||||||
active={activeCollection === item.id}
|
active={activeCollection === item.id}
|
||||||
onClick={clickHandler(item.id)}
|
onClick={clickHandler(item.id)}
|
||||||
|
collectionType={item.type}
|
||||||
collectionName={item.name}
|
collectionName={item.name}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -82,12 +82,20 @@ export const ResultPreviewTile = styled(CollectionTile)`
|
||||||
export const CollectionBarTileText = styled(Overlay)`
|
export const CollectionBarTileText = styled(Overlay)`
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
180deg,
|
0deg,
|
||||||
rgba(0, 0, 0, 0.1) 0%,
|
rgba(0, 0, 0, 0.1) 0%,
|
||||||
rgba(0, 0, 0, 0.5) 86.46%
|
rgba(0, 0, 0, 0.5) 86.46%
|
||||||
);
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const CollectionBarTileIcon = styled(Overlay)`
|
||||||
|
padding: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
& > .MuiSvgIcon-root {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const AllCollectionTileText = styled(Overlay)`
|
export const AllCollectionTileText = styled(Overlay)`
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { styled, Typography } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
export const EllipseText = styled(Typography)`
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default function TruncateText({ text }) {
|
export default function TruncateText({ text }) {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={text}>
|
<Tooltip title={text}>
|
||||||
<EllipseText variant="body2">{text}</EllipseText>
|
<Box height={34} overflow="hidden">
|
||||||
|
{/* todo add ellipsis */}
|
||||||
|
<Typography variant="body2" sx={{ wordBreak: 'break-word' }}>
|
||||||
|
{text}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,18 @@ export enum CollectionType {
|
||||||
folder = 'folder',
|
folder = 'folder',
|
||||||
favorites = 'favorites',
|
favorites = 'favorites',
|
||||||
album = 'album',
|
album = 'album',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CollectionSummaryType {
|
||||||
|
folder = 'folder',
|
||||||
|
favorites = 'favorites',
|
||||||
|
album = 'album',
|
||||||
archive = 'archive',
|
archive = 'archive',
|
||||||
trash = 'trash',
|
trash = 'trash',
|
||||||
all = 'all',
|
all = 'all',
|
||||||
shared = 'shared',
|
shared = 'shared',
|
||||||
|
archived = 'archived',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum COLLECTION_SORT_BY {
|
export enum COLLECTION_SORT_BY {
|
||||||
NAME,
|
NAME,
|
||||||
CREATION_TIME_ASCENDING,
|
CREATION_TIME_ASCENDING,
|
||||||
|
@ -24,34 +30,37 @@ export const COLLECTION_SHARE_DEFAULT_VALID_DURATION =
|
||||||
export const COLLECTION_SHARE_DEFAULT_DEVICE_LIMIT = 4;
|
export const COLLECTION_SHARE_DEFAULT_DEVICE_LIMIT = 4;
|
||||||
|
|
||||||
export const COLLECTION_SORT_ORDER = new Map([
|
export const COLLECTION_SORT_ORDER = new Map([
|
||||||
[CollectionType.all, 0],
|
[CollectionSummaryType.all, 0],
|
||||||
[CollectionType.favorites, 1],
|
[CollectionSummaryType.favorites, 1],
|
||||||
[CollectionType.album, 2],
|
[CollectionSummaryType.album, 2],
|
||||||
[CollectionType.folder, 2],
|
[CollectionSummaryType.folder, 2],
|
||||||
[CollectionType.shared, 2],
|
[CollectionSummaryType.shared, 2],
|
||||||
[CollectionType.archive, 3],
|
[CollectionSummaryType.archived, 2],
|
||||||
[CollectionType.trash, 4],
|
[CollectionSummaryType.archive, 3],
|
||||||
|
[CollectionSummaryType.trash, 4],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const SYSTEM_COLLECTION_TYPES = new Set([
|
export const SYSTEM_COLLECTION_TYPES = new Set([
|
||||||
CollectionType.all,
|
CollectionSummaryType.all,
|
||||||
CollectionType.archive,
|
CollectionSummaryType.archive,
|
||||||
CollectionType.trash,
|
CollectionSummaryType.trash,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const UPLOAD_ALLOWED_COLLECTION_TYPES = new Set([
|
export const UPLOAD_NOT_ALLOWED_COLLECTION_TYPES = new Set([
|
||||||
CollectionType.album,
|
CollectionSummaryType.all,
|
||||||
CollectionType.folder,
|
CollectionSummaryType.archive,
|
||||||
CollectionType.favorites,
|
CollectionSummaryType.shared,
|
||||||
|
CollectionSummaryType.trash,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const OPTIONS_HAVING_COLLECTION_TYPES = new Set([
|
export const OPTIONS_NOT_HAVING_COLLECTION_TYPES = new Set([
|
||||||
CollectionType.folder,
|
CollectionSummaryType.all,
|
||||||
CollectionType.album,
|
CollectionSummaryType.archive,
|
||||||
CollectionType.trash,
|
CollectionSummaryType.shared,
|
||||||
|
CollectionSummaryType.favorites,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const HIDE_FROM_COLLECTION_BAR_TYPES = new Set([
|
export const HIDE_FROM_COLLECTION_BAR_TYPES = new Set([
|
||||||
CollectionType.trash,
|
CollectionSummaryType.trash,
|
||||||
CollectionType.archive,
|
CollectionSummaryType.archive,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import {
|
||||||
TRASH_SECTION,
|
TRASH_SECTION,
|
||||||
COLLECTION_SORT_ORDER,
|
COLLECTION_SORT_ORDER,
|
||||||
ALL_SECTION,
|
ALL_SECTION,
|
||||||
|
CollectionSummaryType,
|
||||||
} from 'constants/collection';
|
} from 'constants/collection';
|
||||||
import { UpdateMagicMetadataRequest } from 'types/magicMetadata';
|
import { UpdateMagicMetadataRequest } from 'types/magicMetadata';
|
||||||
import { EncryptionResult } from 'types/upload';
|
import { EncryptionResult } from 'types/upload';
|
||||||
|
@ -786,8 +787,10 @@ export function getCollectionSummaries(
|
||||||
updationTime: collection.updationTime,
|
updationTime: collection.updationTime,
|
||||||
type:
|
type:
|
||||||
collection.owner.id !== user.id
|
collection.owner.id !== user.id
|
||||||
? CollectionType.shared
|
? CollectionSummaryType.shared
|
||||||
: collection.type,
|
: IsArchived(collection)
|
||||||
|
? CollectionSummaryType.archived
|
||||||
|
: CollectionSummaryType[collection.type],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,7 +856,7 @@ function getAllCollectionSummaries(
|
||||||
return {
|
return {
|
||||||
id: ALL_SECTION,
|
id: ALL_SECTION,
|
||||||
name: constants.ALL_SECTION_NAME,
|
name: constants.ALL_SECTION_NAME,
|
||||||
type: CollectionType.all,
|
type: CollectionSummaryType.all,
|
||||||
latestFile: collectionsLatestFile.get(ALL_SECTION),
|
latestFile: collectionsLatestFile.get(ALL_SECTION),
|
||||||
fileCount: allSectionFileCount,
|
fileCount: allSectionFileCount,
|
||||||
updationTime: collectionsLatestFile.get(ALL_SECTION)?.updationTime,
|
updationTime: collectionsLatestFile.get(ALL_SECTION)?.updationTime,
|
||||||
|
@ -867,7 +870,7 @@ function getArchivedCollectionSummaries(
|
||||||
return {
|
return {
|
||||||
id: ARCHIVE_SECTION,
|
id: ARCHIVE_SECTION,
|
||||||
name: constants.ARCHIVE_SECTION_NAME,
|
name: constants.ARCHIVE_SECTION_NAME,
|
||||||
type: CollectionType.archive,
|
type: CollectionSummaryType.archive,
|
||||||
latestFile: collectionsLatestFile.get(ARCHIVE_SECTION),
|
latestFile: collectionsLatestFile.get(ARCHIVE_SECTION),
|
||||||
fileCount: collectionFilesCount.get(ARCHIVE_SECTION) ?? 0,
|
fileCount: collectionFilesCount.get(ARCHIVE_SECTION) ?? 0,
|
||||||
updationTime: collectionsLatestFile.get(ARCHIVE_SECTION)?.updationTime,
|
updationTime: collectionsLatestFile.get(ARCHIVE_SECTION)?.updationTime,
|
||||||
|
@ -881,7 +884,7 @@ function getTrashedCollectionSummaries(
|
||||||
return {
|
return {
|
||||||
id: TRASH_SECTION,
|
id: TRASH_SECTION,
|
||||||
name: constants.TRASH,
|
name: constants.TRASH,
|
||||||
type: CollectionType.trash,
|
type: CollectionSummaryType.trash,
|
||||||
latestFile: collectionsLatestFile.get(TRASH_SECTION),
|
latestFile: collectionsLatestFile.get(TRASH_SECTION),
|
||||||
fileCount: collectionFilesCount.get(TRASH_SECTION) ?? 0,
|
fileCount: collectionFilesCount.get(TRASH_SECTION) ?? 0,
|
||||||
updationTime: collectionsLatestFile.get(TRASH_SECTION)?.updationTime,
|
updationTime: collectionsLatestFile.get(TRASH_SECTION)?.updationTime,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { User } from 'types/user';
|
import { User } from 'types/user';
|
||||||
import { EnteFile } from 'types/file';
|
import { EnteFile } from 'types/file';
|
||||||
import { CollectionType } from 'constants/collection';
|
import { CollectionSummaryType, CollectionType } from 'constants/collection';
|
||||||
import { MagicMetadataCore, VISIBILITY_STATE } from 'types/magicMetadata';
|
import { MagicMetadataCore, VISIBILITY_STATE } from 'types/magicMetadata';
|
||||||
|
|
||||||
export interface Collection {
|
export interface Collection {
|
||||||
|
@ -91,7 +91,7 @@ export interface CollectionMagicMetadata
|
||||||
export interface CollectionSummary {
|
export interface CollectionSummary {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
type: CollectionType;
|
type: CollectionSummaryType;
|
||||||
latestFile: EnteFile;
|
latestFile: EnteFile;
|
||||||
fileCount: number;
|
fileCount: number;
|
||||||
updationTime: number;
|
updationTime: number;
|
||||||
|
@ -99,10 +99,3 @@ export interface CollectionSummary {
|
||||||
|
|
||||||
export type CollectionSummaries = Map<number, CollectionSummary>;
|
export type CollectionSummaries = Map<number, CollectionSummary>;
|
||||||
export type CollectionFilesCount = Map<number, number>;
|
export type CollectionFilesCount = Map<number, number>;
|
||||||
|
|
||||||
export interface CollectionInfo {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
fileCount: number;
|
|
||||||
type: CollectionType;
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,11 +20,12 @@ import {
|
||||||
CollectionSummaries,
|
CollectionSummaries,
|
||||||
} from 'types/collection';
|
} from 'types/collection';
|
||||||
import {
|
import {
|
||||||
|
CollectionSummaryType,
|
||||||
CollectionType,
|
CollectionType,
|
||||||
HIDE_FROM_COLLECTION_BAR_TYPES,
|
HIDE_FROM_COLLECTION_BAR_TYPES,
|
||||||
OPTIONS_HAVING_COLLECTION_TYPES,
|
OPTIONS_NOT_HAVING_COLLECTION_TYPES,
|
||||||
SYSTEM_COLLECTION_TYPES,
|
SYSTEM_COLLECTION_TYPES,
|
||||||
UPLOAD_ALLOWED_COLLECTION_TYPES,
|
UPLOAD_NOT_ALLOWED_COLLECTION_TYPES,
|
||||||
} from 'constants/collection';
|
} from 'constants/collection';
|
||||||
import { getAlbumSiteHost } from 'constants/pages';
|
import { getAlbumSiteHost } from 'constants/pages';
|
||||||
import { getUnixTimeInMicroSecondsWithDelta } from 'utils/time';
|
import { getUnixTimeInMicroSecondsWithDelta } from 'utils/time';
|
||||||
|
@ -208,18 +209,18 @@ export const hasNonEmptyCollections = (
|
||||||
return collectionSummaries?.size <= 3;
|
return collectionSummaries?.size <= 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isUploadAllowedCollection = (type: CollectionType) => {
|
export const isUploadAllowedCollection = (type: CollectionSummaryType) => {
|
||||||
return UPLOAD_ALLOWED_COLLECTION_TYPES.has(type);
|
return !UPLOAD_NOT_ALLOWED_COLLECTION_TYPES.has(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isSystemCollection = (type: CollectionType) => {
|
export const isSystemCollection = (type: CollectionSummaryType) => {
|
||||||
return SYSTEM_COLLECTION_TYPES.has(type);
|
return SYSTEM_COLLECTION_TYPES.has(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isOptionsHavingCollection = (type: CollectionType) => {
|
export const shouldShowOptions = (type: CollectionSummaryType) => {
|
||||||
return OPTIONS_HAVING_COLLECTION_TYPES.has(type);
|
return !OPTIONS_NOT_HAVING_COLLECTION_TYPES.has(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const shouldBeShownOnCollectionBar = (type: CollectionType) => {
|
export const shouldBeShownOnCollectionBar = (type: CollectionSummaryType) => {
|
||||||
return !HIDE_FROM_COLLECTION_BAR_TYPES.has(type);
|
return !HIDE_FROM_COLLECTION_BAR_TYPES.has(type);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue