mirror of https://github.com/sylv/micro.git
194 lines
6.3 KiB
TypeScript
194 lines
6.3 KiB
TypeScript
import { CreatePasteBody, GetPasteData } from '@ryanke/micro-api';
|
|
import { useState } from 'react';
|
|
import { Button } from '../../components/button/button';
|
|
import { Container } from '../../components/container';
|
|
import { Select } from '../../components/input/select';
|
|
import { Title } from '../../components/title';
|
|
import { encryptContent } from '../../helpers/encrypt.helper';
|
|
import { http } from '../../helpers/http.helper';
|
|
import ErrorPage from '../_error';
|
|
|
|
const EXPIRY_OPTIONS = [
|
|
{ name: '15 minutes', value: 15 },
|
|
{ name: '30 minutes', value: 30 },
|
|
{ name: '1 hour', value: 60 },
|
|
{ name: '2 hours', value: 120 },
|
|
{ name: '4 hours', value: 240 },
|
|
{ name: '8 hours', value: 480 },
|
|
{ name: '1 day', value: 1440 },
|
|
{ name: '2 days', value: 2880 },
|
|
{ name: '4 days', value: 4320 },
|
|
{ name: '1 week', value: 10080 },
|
|
{ name: '2 weeks', value: 20160 },
|
|
{ name: '1 month', value: 43200 },
|
|
{ name: '1 year', value: 525600 },
|
|
];
|
|
|
|
const TYPE_OPTIONS = [
|
|
{ name: 'Markdown', ext: 'md' },
|
|
{ name: 'Plain Text', ext: 'txt' },
|
|
{ name: 'HTML', ext: 'html' },
|
|
{ name: 'JSON', ext: 'json' },
|
|
{ name: 'XML', ext: 'xml' },
|
|
{ name: 'SQL', ext: 'sql' },
|
|
{ name: 'JavaScript', ext: 'js' },
|
|
{ name: 'TypeScript', ext: 'ts' },
|
|
{ name: 'JSX', ext: 'jsx' },
|
|
{ name: 'TSX', ext: 'tsx' },
|
|
{ name: 'CSS', ext: 'css' },
|
|
{ name: 'SCSS', ext: 'scss' },
|
|
{ name: 'SASS', ext: 'sass' },
|
|
{ name: 'LESS', ext: 'less' },
|
|
{ name: 'GraphQL', ext: 'graphql' },
|
|
{ name: 'C', ext: 'c' },
|
|
{ name: 'C++', ext: 'cpp' },
|
|
{ name: 'C#', ext: 'cs' },
|
|
{ name: 'Python', ext: 'py' },
|
|
{ name: 'R', ext: 'r' },
|
|
{ name: 'Ruby', ext: 'rb' },
|
|
{ name: 'Shell', ext: 'sh' },
|
|
{ name: 'Java', ext: 'java' },
|
|
{ name: 'Kotlin', ext: 'kt' },
|
|
{ name: 'Go', ext: 'go' },
|
|
{ name: 'Swift', ext: 'swift' },
|
|
{ name: 'Rust', ext: 'rs' },
|
|
{ name: 'YAML', ext: 'yaml' },
|
|
{ name: 'PHP', ext: 'php' },
|
|
{ name: 'Perl', ext: 'pl' },
|
|
{ name: 'PowerShell', ext: 'ps1' },
|
|
{ name: 'Batch', ext: 'bat' },
|
|
];
|
|
|
|
export default function Paste() {
|
|
const [expiryMinutes, setExpiryMinutes] = useState(1440);
|
|
const [encrypt, setEncrypt] = useState(true);
|
|
const [burn, setBurn] = useState(false);
|
|
const [paranoid, setParanoid] = useState(false);
|
|
const [content, setContent] = useState('');
|
|
const [extension, setExtension] = useState<string | null>(null);
|
|
const [pasting, setPasting] = useState(false);
|
|
const [error, setError] = useState<any>(null);
|
|
const [title, setTitle] = useState<string | undefined>();
|
|
const inferredExtension = extension || (content.includes('# ') ? 'md' : 'txt');
|
|
console.log({ extension, inferredExtension });
|
|
const submitDisabled = !content || pasting;
|
|
|
|
const submit = async () => {
|
|
try {
|
|
setPasting(true);
|
|
const body: CreatePasteBody = {
|
|
content: content,
|
|
burn: burn,
|
|
encrypted: false,
|
|
extension: inferredExtension,
|
|
paranoid: paranoid,
|
|
title: title,
|
|
};
|
|
|
|
if (expiryMinutes) {
|
|
const expiresInMs = expiryMinutes * 60 * 1000;
|
|
body.expiresAt = Date.now() + expiresInMs;
|
|
}
|
|
|
|
let encryptionKey: string | undefined;
|
|
if (encrypt) {
|
|
const result = await encryptContent(content);
|
|
body.encrypted = true;
|
|
body.content = result.encryptedContent;
|
|
encryptionKey = result.key;
|
|
}
|
|
|
|
const response = await http(`paste`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
});
|
|
|
|
const paste = (await response.json()) as GetPasteData;
|
|
setPasting(false);
|
|
let url = `/p/${paste.id}?burn=false`;
|
|
if (encryptionKey) url += `#key=${encryptionKey}`;
|
|
window.location.href = url;
|
|
} catch (error) {
|
|
setError(error);
|
|
} finally {
|
|
setPasting(false);
|
|
}
|
|
};
|
|
|
|
if (error) {
|
|
return <ErrorPage status={error.status} message={error.text || error.message} />;
|
|
}
|
|
|
|
return (
|
|
<Container>
|
|
<Title>New Paste</Title>
|
|
<div className="flex justify-between items-center">
|
|
<h1 className="text-4xl font-bold mb-4">New Paste</h1>
|
|
<div className="flex items-center gap-2"></div>
|
|
</div>
|
|
<input
|
|
className="w-full bg-dark-400 outline-none focus:outline-purple-400 focus:outline-1 mb-4 px-2 py-1"
|
|
placeholder="Title"
|
|
value={title}
|
|
onChange={(event) => setTitle(event.target.value || undefined)}
|
|
/>
|
|
<textarea
|
|
className="w-full h-64 p-2 bg-dark-400 outline-none focus:outline-purple-400 focus:outline-1 rounded placeholder:text-gray-600"
|
|
value={content}
|
|
autoComplete="off"
|
|
autoCorrect="off"
|
|
spellCheck="false"
|
|
placeholder="Markdown, code or plain text"
|
|
onChange={(event) => {
|
|
setContent(event.target.value);
|
|
}}
|
|
/>
|
|
<div className="flex gap-2 justify-end">
|
|
<label className="flex gap-2 items-center">
|
|
<input type="checkbox" checked={burn} onChange={(event) => setBurn(event.target.checked)} />
|
|
<span className="truncate">Destroy after viewing</span>
|
|
</label>
|
|
<label className="flex gap-2 items-center">
|
|
<input type="checkbox" checked={paranoid} onChange={(event) => setParanoid(event.target.checked)} />
|
|
Paranoid
|
|
</label>
|
|
<label className="flex gap-2 items-center">
|
|
<input type="checkbox" checked={encrypt} onChange={(event) => setEncrypt(event.target.checked)} />
|
|
Encrypt
|
|
</label>
|
|
<Select
|
|
value={expiryMinutes}
|
|
className="w-auto"
|
|
onChange={(event) => {
|
|
setExpiryMinutes(+event.target.value);
|
|
}}
|
|
>
|
|
<option value={0}>No Expiry</option>
|
|
{EXPIRY_OPTIONS.map((option) => (
|
|
<option key={option.value} value={option.value}>
|
|
{option.name}
|
|
</option>
|
|
))}
|
|
</Select>
|
|
<Select
|
|
value={inferredExtension}
|
|
className="w-auto"
|
|
onChange={(event) => {
|
|
setExtension(event.target.value);
|
|
}}
|
|
>
|
|
{TYPE_OPTIONS.map((option) => (
|
|
<option key={option.ext} value={option.ext}>
|
|
{option.name}
|
|
</option>
|
|
))}
|
|
</Select>
|
|
<Button className="w-auto" disabled={submitDisabled} onClick={submit}>
|
|
Submit
|
|
</Button>
|
|
</div>
|
|
</Container>
|
|
);
|
|
}
|