- rewritten index file maching project architechture
- sample examples added
This commit is contained in:
Chesterkxng
2026-02-25 00:15:44 +01:00
parent ce0f89acfa
commit d760bbaf1a
+143 -59
View File
@@ -1,72 +1,156 @@
import { useState } from 'react';
import { Box } from '@mui/material';
import React, { useState } from 'react';
import ToolContent from '@components/ToolContent';
import { ToolComponentProps } from '@tools/defineTool';
import ToolTextInput from '@components/input/ToolTextInput';
import ToolTextResult from '@components/result/ToolTextResult';
import { GetGroupsType } from '@components/options/ToolOptions';
import { CardExampleType } from '@components/examples/ToolExamples';
import SelectWithDesc from '@components/options/SelectWithDesc';
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
import { DiscordTimestampGenerator } from './service';
import { useTranslation } from 'react-i18next';
import { DiscordTimestampFormat, InitialValuesType } from './types';
function convertInput(input: string) {
const trimmed = input.trim();
const initialValues: InitialValuesType = {
format: 'F',
enforceUTC: true
};
// Case 1: Discord timestamp → normal date
const match = trimmed.match(/^<t:(\d+):[A-Za-z]>$/);
if (match) {
const unix = Number(match[1]);
const date = new Date(unix * 1000);
if (!isNaN(date.getTime())) {
return date.toISOString().replace('T', ' ').slice(0, 16);
const exampleCards: CardExampleType<InitialValuesType>[] = [
{
title: 'Convert a single datetime',
description:
"In this example, we convert a single datetime into a Discord timestamp using the Long Date & Time format (F). The input is an ISO 8601 datetime string and the output is a Discord timestamp that will display the full date and time in each viewer's local timezone.",
sampleText: `2025-03-15T10:00:00`,
sampleResult: `<t:1742032800:F>`,
sampleOptions: {
...initialValues,
format: 'F'
}
},
{
title: 'Convert multiple datetimes',
description:
'In this example, we convert multiple datetimes at once — one per line. Blank lines are preserved in the output. Each valid datetime is converted to a Discord timestamp using the Short Date & Time format (f).',
sampleText: `2025-03-15T10:00:00
2025-07-20T18:45:00
2025-11-05T08:15:00`,
sampleResult: `<t:1742032800:f>
<t:1753037100:f>
<t:1762330500:f>`,
sampleOptions: {
...initialValues,
format: 'f'
}
},
{
title: 'Relative timestamps',
description:
'In this example, we use the Relative format (R) which displays how long ago or how far in the future a datetime is — for example "2 hours ago" or "in 3 days". This format is useful for countdowns or activity feeds and updates dynamically in Discord.',
sampleText: `2025-03-15T10:00:00
2025-07-20T18:45:00
2025-11-05T08:15:00`,
sampleResult: `<t:1742032800:R>
<t:1753037100:R>
<t:1762330500:R>`,
sampleOptions: {
...initialValues,
format: 'R'
}
}
];
// Case 2: normal date → Discord timestamp
const date = new Date(trimmed);
if (isNaN(date.getTime())) return 'Invalid date/time';
const unix = Math.floor(date.getTime() / 1000);
return `<t:${unix}:F>`;
}
type formatProps = {
label: string;
value: DiscordTimestampFormat;
};
export default function DiscordTimestamp() {
const [value, setValue] = useState('');
const [copied, setCopied] = useState(false);
export default function TruncateClockTime({
title,
longDescription
}: ToolComponentProps) {
const { t } = useTranslation('time');
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
const result = value ? convertInput(value) : '';
const handleCopy = async () => {
if (!result || result === 'Invalid date/time') return;
try {
await navigator.clipboard.writeText(result);
setCopied(true);
setTimeout(() => setCopied(false), 1200);
} catch (e) {
console.error('Copy failed', e);
}
const compute = (optionsValues: InitialValuesType, input: string) => {
setResult(DiscordTimestampGenerator(input, optionsValues));
};
const FORMATS: formatProps[] = [
{ label: t('discordTimestamp.formats.short_time'), value: 't' },
{ label: t('discordTimestamp.formats.long_time'), value: 'T' },
{ label: t('discordTimestamp.formats.short_date'), value: 'd' },
{ label: t('discordTimestamp.formats.long_date'), value: 'D' },
{ label: t('discordTimestamp.formats.short_datetime'), value: 'f' },
{ label: t('discordTimestamp.formats.long_datetime'), value: 'F' },
{ label: t('discordTimestamp.formats.relative'), value: 'R' }
];
const getGroups: GetGroupsType<InitialValuesType> | null = ({
values,
updateField
}) => [
{
title: t('discordTimestamp.utc.title'),
component: (
<Box>
<CheckboxWithDesc
checked={values.enforceUTC}
onChange={(value) => updateField('enforceUTC', value)}
title={t('discordTimestamp.utc.label')}
description={t('discordTimestamp.utc.description')}
/>
</Box>
)
},
{
title: t('discordTimestamp.formats.title'),
component: (
<Box>
<SelectWithDesc
selected={values.format}
onChange={(value) => updateField('format', value)}
options={FORMATS.map((format) => ({
label: format.label,
value: format.value
}))}
description={t('discordTimestamp.formats.description')}
/>
</Box>
)
}
];
return (
<div className="flex gap-3 items-stretch">
<textarea
placeholder="Enter date like: 2026-02-23 18:30"
value={value}
onChange={(e) => setValue(e.target.value)}
className="flex-1 min-h-[140px] p-3 rounded-lg bg-neutral-900 text-white border border-neutral-700 placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<div className="flex-1 relative flex">
<textarea
readOnly
value={value ? result : 'Enter a date to generate timestamp'}
className="flex-1 w-full min-h-[140px] p-3 pr-12 pt-10 rounded-lg bg-neutral-900 text-white border border-neutral-700 focus:outline-none"
<ToolContent
title={title}
input={input}
inputComponent={
<ToolTextInput
value={input}
title={t('discordTimestamp.inputTitle')}
onChange={setInput}
/>
<button
onClick={handleCopy}
disabled={!result || result === 'Invalid date/time'}
className="absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-md bg-neutral-800 border border-neutral-700 hover:bg-neutral-700 text-neutral-200 disabled:opacity-40"
title="Copy to clipboard"
>
{copied ? '✓' : '📋'}
</button>
{copied && (
<span className="absolute top-3 right-12 text-xs text-green-400">
Copied
</span>
)}
</div>
</div>
}
resultComponent={
<ToolTextResult
title={t('discordTimestamp.outputTitle')}
value={result}
/>
}
initialValues={initialValues}
getGroups={getGroups}
setInput={setInput}
compute={compute}
toolInfo={{
title: title,
description: longDescription
}}
exampleCards={exampleCards}
/>
);
}