feat: add more info to cards & relative time

This commit is contained in:
diced 2022-10-28 17:28:15 -07:00
parent b30b7b1bd3
commit 3df94526b0
No known key found for this signature in database
GPG key ID: 370BD1BA142842D1
5 changed files with 55 additions and 21 deletions

View file

@ -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

View file

@ -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>

View file

@ -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'>

View file

@ -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'>

View file

@ -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'
);
}
} }
} }