feat: add more info to cards & relative time
This commit is contained in:
parent
b30b7b1bd3
commit
3df94526b0
5 changed files with 55 additions and 21 deletions
|
@ -133,14 +133,15 @@ export default function File({ image, updateImages, disableMediaPreview }) {
|
||||||
<FileMeta
|
<FileMeta
|
||||||
Icon={EyeIcon}
|
Icon={EyeIcon}
|
||||||
title='Max views'
|
title='Max views'
|
||||||
subtitle={image.maxViews.toLocaleString()}
|
subtitle={image?.maxViews?.toLocaleString()}
|
||||||
tooltip={`This file will be deleted after being viewed ${image?.maxViews?.toLocaleString()} times.`}
|
tooltip={`This file will be deleted after being viewed ${image?.maxViews?.toLocaleString()} times.`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<FileMeta
|
<FileMeta
|
||||||
Icon={CalendarIcon}
|
Icon={CalendarIcon}
|
||||||
title='Uploaded at'
|
title='Uploaded'
|
||||||
subtitle={new Date(image.created_at).toLocaleString()}
|
subtitle={relativeTime(new Date(image.created_at))}
|
||||||
|
tooltip={new Date(image?.created_at).toLocaleString()}
|
||||||
/>
|
/>
|
||||||
{image.expires_at && (
|
{image.expires_at && (
|
||||||
<FileMeta
|
<FileMeta
|
||||||
|
|
|
@ -30,7 +30,14 @@ export default function Files({ disableMediaPreview }) {
|
||||||
</Link>
|
</Link>
|
||||||
</Group>
|
</Group>
|
||||||
{favoritePages.isSuccess && favoritePages.data.length ? (
|
{favoritePages.isSuccess && favoritePages.data.length ? (
|
||||||
<Accordion variant='contained' mb='sm'>
|
<Accordion
|
||||||
|
variant='contained'
|
||||||
|
mb='sm'
|
||||||
|
styles={(t) => ({
|
||||||
|
content: { backgroundColor: t.colorScheme === 'dark' ? t.colors.dark[7] : t.colors.gray[0] },
|
||||||
|
control: { backgroundColor: t.colorScheme === 'dark' ? t.colors.dark[7] : t.colors.gray[0] },
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Accordion.Item value='favorite'>
|
<Accordion.Item value='favorite'>
|
||||||
<Accordion.Control>Favorite Files</Accordion.Control>
|
<Accordion.Control>Favorite Files</Accordion.Control>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
Title,
|
Title,
|
||||||
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useClipboard } from '@mantine/hooks';
|
import { useClipboard } from '@mantine/hooks';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
|
@ -21,6 +22,7 @@ import MutedText from 'components/MutedText';
|
||||||
import useFetch from 'hooks/useFetch';
|
import useFetch from 'hooks/useFetch';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { relativeTime } from 'lib/utils/client';
|
||||||
|
|
||||||
const expires = ['30m', '1h', '6h', '12h', '1d', '3d', '5d', '7d', 'never'];
|
const expires = ['30m', '1h', '6h', '12h', '1d', '3d', '5d', '7d', 'never'];
|
||||||
|
|
||||||
|
@ -117,7 +119,7 @@ function CreateInviteModal({ open, setOpen, updateInvites }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Users() {
|
export default function Uz2sers() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const modals = useModals();
|
const modals = useModals();
|
||||||
const clipboard = useClipboard();
|
const clipboard = useClipboard();
|
||||||
|
@ -198,10 +200,20 @@ export default function Users() {
|
||||||
{invite.code}
|
{invite.code}
|
||||||
{invite.used && <> (Used)</>}
|
{invite.used && <> (Used)</>}
|
||||||
</Title>
|
</Title>
|
||||||
<MutedText size='sm'>Created: {new Date(invite.created_at).toLocaleString()}</MutedText>
|
<Tooltip label={new Date(invite.created_at).toLocaleString()}>
|
||||||
|
<div>
|
||||||
<MutedText size='sm'>
|
<MutedText size='sm'>
|
||||||
Expires: {invite.expires_at ? new Date(invite.expires_at).toLocaleString() : 'Never'}
|
Created: {relativeTime(new Date(invite.created_at))}
|
||||||
</MutedText>
|
</MutedText>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label={new Date(invite.expires_at).toLocaleString()}>
|
||||||
|
<div>
|
||||||
|
<MutedText size='sm'>
|
||||||
|
Expires: {relativeTime(new Date(invite.expires_at))}
|
||||||
|
</MutedText>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Group>
|
</Group>
|
||||||
<Group position='right'>
|
<Group position='right'>
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { ActionIcon, Card, Group, LoadingOverlay, Title } from '@mantine/core';
|
import { ActionIcon, Card, Group, LoadingOverlay, Stack, Title, Tooltip } from '@mantine/core';
|
||||||
import { useClipboard } from '@mantine/hooks';
|
import { useClipboard } from '@mantine/hooks';
|
||||||
import { showNotification } from '@mantine/notifications';
|
import { showNotification } from '@mantine/notifications';
|
||||||
import { CopyIcon, CrossIcon, DeleteIcon, ExternalLinkIcon } from 'components/icons';
|
import { CopyIcon, CrossIcon, DeleteIcon, ExternalLinkIcon } from 'components/icons';
|
||||||
import TrashIcon from 'components/icons/TrashIcon';
|
import TrashIcon from 'components/icons/TrashIcon';
|
||||||
|
import Link from 'components/Link';
|
||||||
|
import MutedText from 'components/MutedText';
|
||||||
import { URLResponse, useURLDelete } from 'lib/queries/url';
|
import { URLResponse, useURLDelete } from 'lib/queries/url';
|
||||||
|
import { relativeTime } from 'lib/utils/client';
|
||||||
|
|
||||||
export default function URLCard({ url }: { url: URLResponse }) {
|
export default function URLCard({ url }: { url: URLResponse }) {
|
||||||
const clipboard = useClipboard();
|
const clipboard = useClipboard();
|
||||||
|
@ -46,7 +49,18 @@ export default function URLCard({ url }: { url: URLResponse }) {
|
||||||
|
|
||||||
<Group position='apart'>
|
<Group position='apart'>
|
||||||
<Group position='left'>
|
<Group position='left'>
|
||||||
|
<Stack spacing={0}>
|
||||||
<Title>{url.vanity ?? url.id}</Title>
|
<Title>{url.vanity ?? url.id}</Title>
|
||||||
|
<Tooltip label={new Date(url.created_at).toLocaleString()}>
|
||||||
|
<div>
|
||||||
|
<MutedText size='sm'>Created: {relativeTime(new Date(url.created_at))}</MutedText>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
{url.vanity && <MutedText size='sm'>ID: {url.id}</MutedText>}
|
||||||
|
<MutedText size='sm'>
|
||||||
|
URL: <Link href={url.destination}>{url.destination}</Link>
|
||||||
|
</MutedText>
|
||||||
|
</Stack>
|
||||||
</Group>
|
</Group>
|
||||||
<Group position='right'>
|
<Group position='right'>
|
||||||
<ActionIcon href={url.url} component='a' target='_blank'>
|
<ActionIcon href={url.url} component='a' target='_blank'>
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import type { Image, User } from '@prisma/client';
|
import type { Image, User } from '@prisma/client';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import duration from 'dayjs/plugin/duration';
|
||||||
|
import dayjsRelativeTime from 'dayjs/plugin/relativeTime';
|
||||||
import ms, { StringValue } from 'ms';
|
import ms, { StringValue } from 'ms';
|
||||||
|
dayjs.extend(duration);
|
||||||
|
dayjs.extend(dayjsRelativeTime);
|
||||||
|
|
||||||
export function parse(str: string, image: Image, user: User) {
|
export function parse(str: string, image: Image, user: User) {
|
||||||
if (!str) return null;
|
if (!str) return null;
|
||||||
|
@ -34,17 +39,12 @@ export const units = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function relativeTime(to: Date, from: Date = new Date()) {
|
export function relativeTime(to: Date, from: Date = new Date()) {
|
||||||
const time = new Date(to.getTime() - from.getTime());
|
if (!to) return null;
|
||||||
|
|
||||||
const rtf = new Intl.RelativeTimeFormat('en', { style: 'long' });
|
if (to.getTime() < from.getTime()) {
|
||||||
|
return dayjs(to).from(from);
|
||||||
for (const unit in units) {
|
} else {
|
||||||
if (time > units[unit]) {
|
return dayjs(from).to(to);
|
||||||
return rtf.format(
|
|
||||||
Math.floor(Math.round(time.getTime() / units[unit])),
|
|
||||||
(unit as Intl.RelativeTimeFormatUnit) || 'second'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue