mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 18:33:33 +00:00
[enhancement]: apply formatting to card values
This commit is contained in:
parent
38ed083693
commit
aa89c5e80e
9 changed files with 95 additions and 75 deletions
|
|
@ -93,7 +93,7 @@ export const App = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
root.style.setProperty('--image-fit', nativeImageAspect ? 'scale-down' : 'cover');
|
root.style.setProperty('--image-fit', nativeImageAspect ? 'contain' : 'cover');
|
||||||
}, [nativeImageAspect]);
|
}, [nativeImageAspect]);
|
||||||
|
|
||||||
const providerValue = useMemo(() => {
|
const providerValue = useMemo(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import formatDuration from 'format-duration';
|
||||||
import { generatePath } from 'react-router';
|
import { generatePath } from 'react-router';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
@ -6,6 +7,7 @@ import { Album, AlbumArtist, Artist, Playlist, Song } from '/@/renderer/api/type
|
||||||
import { Text } from '/@/renderer/components/text';
|
import { Text } from '/@/renderer/components/text';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { CardRow } from '/@/renderer/types';
|
import { CardRow } from '/@/renderer/types';
|
||||||
|
import { formatDateAbsolute, formatDateRelative, formatRating } from '/@/renderer/utils/format';
|
||||||
|
|
||||||
const Row = styled.div<{ $secondary?: boolean }>`
|
const Row = styled.div<{ $secondary?: boolean }>`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -69,7 +71,10 @@ export const CardRows = ({ data, rows }: CardRowsProps) => {
|
||||||
)}
|
)}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{row.arrayProperty && item[row.arrayProperty]}
|
{row.arrayProperty &&
|
||||||
|
(row.format
|
||||||
|
? row.format(item)
|
||||||
|
: item[row.arrayProperty])}
|
||||||
</Text>
|
</Text>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
|
|
@ -88,7 +93,8 @@ export const CardRows = ({ data, rows }: CardRowsProps) => {
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
size={index > 0 ? 'sm' : 'md'}
|
size={index > 0 ? 'sm' : 'md'}
|
||||||
>
|
>
|
||||||
{row.arrayProperty && item[row.arrayProperty]}
|
{row.arrayProperty &&
|
||||||
|
(row.format ? row.format(item) : item[row.arrayProperty])}
|
||||||
</Text>
|
</Text>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
@ -114,7 +120,7 @@ export const CardRows = ({ data, rows }: CardRowsProps) => {
|
||||||
)}
|
)}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{data && data[row.property]}
|
{data && (row.format ? row.format(data) : data[row.property])}
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Text
|
<Text
|
||||||
|
|
@ -123,7 +129,7 @@ export const CardRows = ({ data, rows }: CardRowsProps) => {
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
size={index > 0 ? 'sm' : 'md'}
|
size={index > 0 ? 'sm' : 'md'}
|
||||||
>
|
>
|
||||||
{data && data[row.property]}
|
{data && (row.format ? row.format(data) : data[row.property])}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
@ -151,12 +157,15 @@ export const ALBUM_CARD_ROWS: { [key: string]: CardRow<Album> } = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
|
format: (song) => formatDateAbsolute(song.createdAt),
|
||||||
property: 'createdAt',
|
property: 'createdAt',
|
||||||
},
|
},
|
||||||
duration: {
|
duration: {
|
||||||
|
format: (album) => (album.duration === null ? null : formatDuration(album.duration)),
|
||||||
property: 'duration',
|
property: 'duration',
|
||||||
},
|
},
|
||||||
lastPlayedAt: {
|
lastPlayedAt: {
|
||||||
|
format: (album) => formatDateRelative(album.lastPlayedAt),
|
||||||
property: 'lastPlayedAt',
|
property: 'lastPlayedAt',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|
@ -170,6 +179,7 @@ export const ALBUM_CARD_ROWS: { [key: string]: CardRow<Album> } = {
|
||||||
property: 'playCount',
|
property: 'playCount',
|
||||||
},
|
},
|
||||||
rating: {
|
rating: {
|
||||||
|
format: (album) => formatRating(album),
|
||||||
property: 'userRating',
|
property: 'userRating',
|
||||||
},
|
},
|
||||||
releaseDate: {
|
releaseDate: {
|
||||||
|
|
@ -208,12 +218,15 @@ export const SONG_CARD_ROWS: { [key: string]: CardRow<Song> } = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
|
format: (song) => formatDateAbsolute(song.createdAt),
|
||||||
property: 'createdAt',
|
property: 'createdAt',
|
||||||
},
|
},
|
||||||
duration: {
|
duration: {
|
||||||
|
format: (song) => (song.duration === null ? null : formatDuration(song.duration)),
|
||||||
property: 'duration',
|
property: 'duration',
|
||||||
},
|
},
|
||||||
lastPlayedAt: {
|
lastPlayedAt: {
|
||||||
|
format: (song) => formatDateRelative(song.lastPlayedAt),
|
||||||
property: 'lastPlayedAt',
|
property: 'lastPlayedAt',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|
@ -227,6 +240,7 @@ export const SONG_CARD_ROWS: { [key: string]: CardRow<Song> } = {
|
||||||
property: 'playCount',
|
property: 'playCount',
|
||||||
},
|
},
|
||||||
rating: {
|
rating: {
|
||||||
|
format: (song) => formatRating(song),
|
||||||
property: 'userRating',
|
property: 'userRating',
|
||||||
},
|
},
|
||||||
releaseDate: {
|
releaseDate: {
|
||||||
|
|
@ -242,12 +256,14 @@ export const ALBUMARTIST_CARD_ROWS: { [key: string]: CardRow<AlbumArtist> } = {
|
||||||
property: 'albumCount',
|
property: 'albumCount',
|
||||||
},
|
},
|
||||||
duration: {
|
duration: {
|
||||||
|
format: (artist) => (artist.duration === null ? null : formatDuration(artist.duration)),
|
||||||
property: 'duration',
|
property: 'duration',
|
||||||
},
|
},
|
||||||
genres: {
|
genres: {
|
||||||
property: 'genres',
|
property: 'genres',
|
||||||
},
|
},
|
||||||
lastPlayedAt: {
|
lastPlayedAt: {
|
||||||
|
format: (artist) => formatDateRelative(artist.lastPlayedAt),
|
||||||
property: 'lastPlayedAt',
|
property: 'lastPlayedAt',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|
@ -261,6 +277,7 @@ export const ALBUMARTIST_CARD_ROWS: { [key: string]: CardRow<AlbumArtist> } = {
|
||||||
property: 'playCount',
|
property: 'playCount',
|
||||||
},
|
},
|
||||||
rating: {
|
rating: {
|
||||||
|
format: (artist) => formatRating(artist),
|
||||||
property: 'userRating',
|
property: 'userRating',
|
||||||
},
|
},
|
||||||
songCount: {
|
songCount: {
|
||||||
|
|
@ -270,6 +287,8 @@ export const ALBUMARTIST_CARD_ROWS: { [key: string]: CardRow<AlbumArtist> } = {
|
||||||
|
|
||||||
export const PLAYLIST_CARD_ROWS: { [key: string]: CardRow<Playlist> } = {
|
export const PLAYLIST_CARD_ROWS: { [key: string]: CardRow<Playlist> } = {
|
||||||
duration: {
|
duration: {
|
||||||
|
format: (playlist) =>
|
||||||
|
playlist.duration === null ? null : formatDuration(playlist.duration),
|
||||||
property: 'duration',
|
property: 'duration',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
|
@ -295,7 +314,4 @@ export const PLAYLIST_CARD_ROWS: { [key: string]: CardRow<Playlist> } = {
|
||||||
songCount: {
|
songCount: {
|
||||||
property: 'songCount',
|
property: 'songCount',
|
||||||
},
|
},
|
||||||
updatedAt: {
|
|
||||||
property: 'songCount',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ import type { AgGridReactProps } from '@ag-grid-community/react';
|
||||||
import { AgGridReact } from '@ag-grid-community/react';
|
import { AgGridReact } from '@ag-grid-community/react';
|
||||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
||||||
import { useClickOutside, useMergedRef } from '@mantine/hooks';
|
import { useClickOutside, useMergedRef } from '@mantine/hooks';
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
||||||
import formatDuration from 'format-duration';
|
import formatDuration from 'format-duration';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import { generatePath } from 'react-router';
|
import { generatePath } from 'react-router';
|
||||||
|
|
@ -43,7 +41,7 @@ import { useFixedTableHeader } from '/@/renderer/components/virtual-table/hooks/
|
||||||
import { NoteCell } from '/@/renderer/components/virtual-table/cells/note-cell';
|
import { NoteCell } from '/@/renderer/components/virtual-table/cells/note-cell';
|
||||||
import { RowIndexCell } from '/@/renderer/components/virtual-table/cells/row-index-cell';
|
import { RowIndexCell } from '/@/renderer/components/virtual-table/cells/row-index-cell';
|
||||||
import i18n from '/@/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
import { formatSizeString } from '/@/renderer/utils/format-size-string';
|
import { formatDateAbsolute, formatDateRelative, formatSizeString } from '/@/renderer/utils/format';
|
||||||
|
|
||||||
export * from './table-config-dropdown';
|
export * from './table-config-dropdown';
|
||||||
export * from './table-pagination';
|
export * from './table-pagination';
|
||||||
|
|
@ -64,8 +62,6 @@ const DummyHeader = styled.div<{ height?: number }>`
|
||||||
height: ${({ height }) => height || 36}px;
|
height: ${({ height }) => height || 36}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
|
||||||
|
|
||||||
const tableColumns: { [key: string]: ColDef } = {
|
const tableColumns: { [key: string]: ColDef } = {
|
||||||
actions: {
|
actions: {
|
||||||
cellClass: 'ag-cell-favorite',
|
cellClass: 'ag-cell-favorite',
|
||||||
|
|
@ -182,8 +178,7 @@ const tableColumns: { [key: string]: ColDef } = {
|
||||||
GenericTableHeader(params, { position: 'center' }),
|
GenericTableHeader(params, { position: 'center' }),
|
||||||
headerName: i18n.t('table.column.dateAdded'),
|
headerName: i18n.t('table.column.dateAdded'),
|
||||||
suppressSizeToFit: true,
|
suppressSizeToFit: true,
|
||||||
valueFormatter: (params: ValueFormatterParams) =>
|
valueFormatter: (params: ValueFormatterParams) => formatDateAbsolute(params.value),
|
||||||
params.value ? dayjs(params.value).format('MMM D, YYYY') : '',
|
|
||||||
valueGetter: (params: ValueGetterParams) =>
|
valueGetter: (params: ValueGetterParams) =>
|
||||||
params.data ? params.data.createdAt : undefined,
|
params.data ? params.data.createdAt : undefined,
|
||||||
width: 130,
|
width: 130,
|
||||||
|
|
@ -225,8 +220,7 @@ const tableColumns: { [key: string]: ColDef } = {
|
||||||
headerComponent: (params: IHeaderParams) =>
|
headerComponent: (params: IHeaderParams) =>
|
||||||
GenericTableHeader(params, { position: 'center' }),
|
GenericTableHeader(params, { position: 'center' }),
|
||||||
headerName: i18n.t('table.column.lastPlayed'),
|
headerName: i18n.t('table.column.lastPlayed'),
|
||||||
valueFormatter: (params: ValueFormatterParams) =>
|
valueFormatter: (params: ValueFormatterParams) => formatDateRelative(params.value),
|
||||||
params.value ? dayjs(params.value).fromNow() : '',
|
|
||||||
valueGetter: (params: ValueGetterParams) =>
|
valueGetter: (params: ValueGetterParams) =>
|
||||||
params.data ? params.data.lastPlayedAt : undefined,
|
params.data ? params.data.lastPlayedAt : undefined,
|
||||||
width: 130,
|
width: 130,
|
||||||
|
|
@ -258,8 +252,7 @@ const tableColumns: { [key: string]: ColDef } = {
|
||||||
GenericTableHeader(params, { position: 'center' }),
|
GenericTableHeader(params, { position: 'center' }),
|
||||||
headerName: i18n.t('table.column.releaseDate'),
|
headerName: i18n.t('table.column.releaseDate'),
|
||||||
suppressSizeToFit: true,
|
suppressSizeToFit: true,
|
||||||
valueFormatter: (params: ValueFormatterParams) =>
|
valueFormatter: (params: ValueFormatterParams) => formatDateAbsolute(params.value),
|
||||||
params.value ? dayjs(params.value).format('MMM D, YYYY') : '',
|
|
||||||
valueGetter: (params: ValueGetterParams) =>
|
valueGetter: (params: ValueGetterParams) =>
|
||||||
params.data ? params.data.releaseDate : undefined,
|
params.data ? params.data.releaseDate : undefined,
|
||||||
width: 130,
|
width: 130,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
import { Group, Table } from '@mantine/core';
|
import { Group, Table } from '@mantine/core';
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { RiCheckFill, RiCloseFill } from 'react-icons/ri';
|
import { RiCheckFill, RiCloseFill } from 'react-icons/ri';
|
||||||
import { TFunction, useTranslation } from 'react-i18next';
|
import { TFunction, useTranslation } from 'react-i18next';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { Album, AlbumArtist, AnyLibraryItem, LibraryItem, Song } from '/@/renderer/api/types';
|
import { Album, AlbumArtist, AnyLibraryItem, LibraryItem, Song } from '/@/renderer/api/types';
|
||||||
import { formatDurationString } from '/@/renderer/utils';
|
import { formatDurationString, formatSizeString } from '/@/renderer/utils';
|
||||||
import { formatSizeString } from '/@/renderer/utils/format-size-string';
|
|
||||||
import { replaceURLWithHTMLLinks } from '/@/renderer/utils/linkify';
|
import { replaceURLWithHTMLLinks } from '/@/renderer/utils/linkify';
|
||||||
import { Rating, Spoiler, Text } from '/@/renderer/components';
|
import { Spoiler, Text } from '/@/renderer/components';
|
||||||
import { sanitize } from '/@/renderer/utils/sanitize';
|
import { sanitize } from '/@/renderer/utils/sanitize';
|
||||||
import { SongPath } from '/@/renderer/features/item-details/components/song-path';
|
import { SongPath } from '/@/renderer/features/item-details/components/song-path';
|
||||||
import { generatePath } from 'react-router';
|
import { generatePath } from 'react-router';
|
||||||
|
|
@ -15,6 +13,7 @@ import { Link } from 'react-router-dom';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { Separator } from '/@/renderer/components/separator';
|
import { Separator } from '/@/renderer/components/separator';
|
||||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||||
|
import { formatDateRelative, formatRating } from '/@/renderer/utils/format';
|
||||||
|
|
||||||
export type ItemDetailsModalProps = {
|
export type ItemDetailsModalProps = {
|
||||||
item: Album | AlbumArtist | Song;
|
item: Album | AlbumArtist | Song;
|
||||||
|
|
@ -82,8 +81,6 @@ const formatArtists = (isAlbumArtist: boolean) => (item: Album | Song) =>
|
||||||
const formatComment = (item: Album | Song) =>
|
const formatComment = (item: Album | Song) =>
|
||||||
item.comment ? <Spoiler maxHeight={50}>{replaceURLWithHTMLLinks(item.comment)}</Spoiler> : null;
|
item.comment ? <Spoiler maxHeight={50}>{replaceURLWithHTMLLinks(item.comment)}</Spoiler> : null;
|
||||||
|
|
||||||
const formatDate = (key: string | null) => (key ? dayjs(key).fromNow() : '');
|
|
||||||
|
|
||||||
const FormatGenre = (item: Album | AlbumArtist | Song) => {
|
const FormatGenre = (item: Album | AlbumArtist | Song) => {
|
||||||
const genreRoute = useGenreRoute();
|
const genreRoute = useGenreRoute();
|
||||||
|
|
||||||
|
|
@ -104,14 +101,6 @@ const FormatGenre = (item: Album | AlbumArtist | Song) => {
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRating = (item: Album | AlbumArtist | Song) =>
|
|
||||||
item.userRating !== null ? (
|
|
||||||
<Rating
|
|
||||||
readOnly
|
|
||||||
value={item.userRating}
|
|
||||||
/>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const BoolField = (key: boolean) =>
|
const BoolField = (key: boolean) =>
|
||||||
key ? <RiCheckFill size="1.1rem" /> : <RiCloseFill size="1.1rem" />;
|
key ? <RiCheckFill size="1.1rem" /> : <RiCloseFill size="1.1rem" />;
|
||||||
|
|
||||||
|
|
@ -139,11 +128,11 @@ const AlbumPropertyMapping: ItemDetailRow<Album>[] = [
|
||||||
{ key: 'playCount', label: 'filter.playCount' },
|
{ key: 'playCount', label: 'filter.playCount' },
|
||||||
{
|
{
|
||||||
label: 'filter.lastPlayed',
|
label: 'filter.lastPlayed',
|
||||||
render: (song) => formatDate(song.lastPlayedAt),
|
render: (song) => formatDateRelative(song.lastPlayedAt),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common.modified',
|
label: 'common.modified',
|
||||||
render: (song) => formatDate(song.updatedAt),
|
render: (song) => formatDateRelative(song.updatedAt),
|
||||||
},
|
},
|
||||||
{ label: 'filter.comment', render: formatComment },
|
{ label: 'filter.comment', render: formatComment },
|
||||||
{
|
{
|
||||||
|
|
@ -178,7 +167,7 @@ const AlbumArtistPropertyMapping: ItemDetailRow<AlbumArtist>[] = [
|
||||||
{ key: 'playCount', label: 'filter.playCount' },
|
{ key: 'playCount', label: 'filter.playCount' },
|
||||||
{
|
{
|
||||||
label: 'filter.lastPlayed',
|
label: 'filter.lastPlayed',
|
||||||
render: (song) => formatDate(song.lastPlayedAt),
|
render: (song) => formatDateRelative(song.lastPlayedAt),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common.mbid',
|
label: 'common.mbid',
|
||||||
|
|
@ -256,11 +245,11 @@ const SongPropertyMapping: ItemDetailRow<Song>[] = [
|
||||||
{ key: 'playCount', label: 'filter.playCount' },
|
{ key: 'playCount', label: 'filter.playCount' },
|
||||||
{
|
{
|
||||||
label: 'filter.lastPlayed',
|
label: 'filter.lastPlayed',
|
||||||
render: (song) => formatDate(song.lastPlayedAt),
|
render: (song) => formatDateRelative(song.lastPlayedAt),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common.modified',
|
label: 'common.modified',
|
||||||
render: (song) => formatDate(song.updatedAt),
|
render: (song) => formatDateRelative(song.updatedAt),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common.albumGain',
|
label: 'common.albumGain',
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { ServerFeatures } from '/@/renderer/api/features-types';
|
import { ServerFeatures } from '/@/renderer/api/features-types';
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
|
|
@ -37,6 +38,7 @@ export type TableType =
|
||||||
|
|
||||||
export type CardRow<T> = {
|
export type CardRow<T> = {
|
||||||
arrayProperty?: string;
|
arrayProperty?: string;
|
||||||
|
format?: (value: T) => ReactNode;
|
||||||
property: keyof T;
|
property: keyof T;
|
||||||
route?: CardRoute;
|
route?: CardRoute;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import formatDuration from 'format-duration';
|
|
||||||
|
|
||||||
export const formatDurationString = (duration: number) => {
|
|
||||||
const rawDuration = formatDuration(duration).split(':');
|
|
||||||
|
|
||||||
let string;
|
|
||||||
|
|
||||||
switch (rawDuration.length) {
|
|
||||||
case 1:
|
|
||||||
string = `${rawDuration[0]} sec`;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
string = `${rawDuration[0]} min ${rawDuration[1]} sec`;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
string = `${rawDuration[0]} hr ${rawDuration[1]} min ${rawDuration[2]} sec`;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
string = `${rawDuration[0]} day ${rawDuration[1]} hr ${rawDuration[2]} min ${rawDuration[3]} sec`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string;
|
|
||||||
};
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
const SIZES = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
|
||||||
|
|
||||||
export const formatSizeString = (size?: number): string => {
|
|
||||||
let count = 0;
|
|
||||||
let finalSize = size ?? 0;
|
|
||||||
while (finalSize > 1024) {
|
|
||||||
finalSize /= 1024;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${finalSize.toFixed(2)} ${SIZES[count]}`;
|
|
||||||
};
|
|
||||||
56
src/renderer/utils/format.tsx
Normal file
56
src/renderer/utils/format.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
|
import formatDuration from 'format-duration';
|
||||||
|
import type { Album, AlbumArtist, Song } from '/@/renderer/api/types';
|
||||||
|
import { Rating } from '/@/renderer/components/rating';
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
|
export const formatDateAbsolute = (key: string | null) =>
|
||||||
|
key ? dayjs(key).format('MMM D, YYYY') : '';
|
||||||
|
|
||||||
|
export const formatDateRelative = (key: string | null) => (key ? dayjs(key).fromNow() : '');
|
||||||
|
|
||||||
|
export const formatDurationString = (duration: number) => {
|
||||||
|
const rawDuration = formatDuration(duration).split(':');
|
||||||
|
|
||||||
|
let string;
|
||||||
|
|
||||||
|
switch (rawDuration.length) {
|
||||||
|
case 1:
|
||||||
|
string = `${rawDuration[0]} sec`;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
string = `${rawDuration[0]} min ${rawDuration[1]} sec`;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
string = `${rawDuration[0]} hr ${rawDuration[1]} min ${rawDuration[2]} sec`;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
string = `${rawDuration[0]} day ${rawDuration[1]} hr ${rawDuration[2]} min ${rawDuration[3]} sec`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formatRating = (item: Album | AlbumArtist | Song) =>
|
||||||
|
item.userRating !== null ? (
|
||||||
|
<Rating
|
||||||
|
readOnly
|
||||||
|
value={item.userRating}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
const SIZES = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
||||||
|
|
||||||
|
export const formatSizeString = (size?: number): string => {
|
||||||
|
let count = 0;
|
||||||
|
let finalSize = size ?? 0;
|
||||||
|
while (finalSize > 1024) {
|
||||||
|
finalSize /= 1024;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${finalSize.toFixed(2)} ${SIZES[count]}`;
|
||||||
|
};
|
||||||
|
|
@ -5,6 +5,6 @@ export * from './constrain-sidebar-width';
|
||||||
export * from './title-case';
|
export * from './title-case';
|
||||||
export * from './get-header-color';
|
export * from './get-header-color';
|
||||||
export * from './parse-search-params';
|
export * from './parse-search-params';
|
||||||
export * from './format-duration-string';
|
|
||||||
export * from './rgb-to-rgba';
|
export * from './rgb-to-rgba';
|
||||||
export * from './sentence-case';
|
export * from './sentence-case';
|
||||||
|
export * from './format';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue