);
index += 1;
}
return blocks;
}
async function copyText(text: string) {
if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(text);
return;
}
if (typeof document === 'undefined') {
throw new Error('클립보드 API를 사용할 수 없습니다.');
}
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', 'true');
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
function downloadBlob(content: BlobPart, fileName: string, mimeType = 'text/plain;charset=utf-8') {
if (typeof document === 'undefined') {
throw new Error('다운로드를 사용할 수 없습니다.');
}
const blob = new Blob([content], { type: mimeType });
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = objectUrl;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(objectUrl);
}
function resolveCopyValue({ type, value }: Pick) {
switch (type) {
case 'json':
return stringifyValue(normalizeJsonValue(value));
case 'image':
return String(value ?? '');
default:
return stringifyValue(value);
}
}
function resolveDownloadValue({
type,
value,
downloadValue,
}: Pick) {
if (typeof downloadValue === 'string') {
return downloadValue;
}
if (type === 'image') {
return String(value ?? '');
}
return resolveCopyValue({ type, value });
}
function resolveDownloadFileName({
type,
language,
downloadFileName,
}: Pick) {
if (downloadFileName?.trim()) {
return downloadFileName.trim();
}
switch (type) {
case 'json':
return 'preview.json';
case 'markdown':
return 'preview.md';
case 'code':
return `preview.${language || 'txt'}`;
case 'image':
return 'preview';
default:
return 'preview.txt';
}
}
function renderContent({
type,
value,
language,
format,
imageAlt,
}: Pick) {
const textValue = stringifyValue(value);
const lines = textValue.split('\n').map((line) => line.trim()).filter(Boolean);
const detectedFormat =
format && format !== 'auto'
? format
: lines.length > 0 && lines.every((line) => /^([A-Za-z]:\\|\.{0,2}\/|\/)?[\w@./-]+(?:\/[\w@./-]+)*$/.test(line))
? 'paths'
: lines.length > 0 &&
lines.filter((line) => /^(?:[$>#]\s*)?[a-z0-9_.-]+(?:\s+.+)?$/i.test(line) || /^#/.test(line)).length >=
Math.max(1, Math.ceil(lines.length * 0.6))
? 'terminal'
: 'plain';
switch (type) {
case 'text':
if (detectedFormat === 'terminal') {
return renderEditorBlock(textValue, 'bash', 'code');
}
if (detectedFormat === 'paths') {
return renderEditorBlock(textValue, 'paths', 'code');
}
return
{textValue}
;
case 'json':
return renderEditorBlock(stringifyValue(normalizeJsonValue(value)), 'json', 'json');
case 'code':
return renderEditorBlock(textValue, language ?? 'text', 'code');
case 'image':
return (
);
case 'markdown':
return