summaryrefslogtreecommitdiff
path: root/lib/utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils.ts')
-rw-r--r--lib/utils.ts82
1 files changed, 81 insertions, 1 deletions
diff --git a/lib/utils.ts b/lib/utils.ts
index 33b5a0c2..cb15e830 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -194,4 +194,84 @@ export function formatBytes(bytes: number, decimals: number = 2): string {
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]
-} \ No newline at end of file
+}
+
+export async function copyTextToClipboard(text: string) {
+ // 안전 가드: 브라우저 & API 지원 체크
+ if (typeof navigator !== "undefined" && navigator.clipboard) {
+ try {
+ await navigator.clipboard.writeText(text)
+ return true
+ } catch {
+ /* fall through to fallback */
+ }
+ }
+
+ // --- Fallback (execCommand) ---
+ try {
+ const textarea = document.createElement("textarea")
+ textarea.value = text
+ textarea.style.position = "fixed" // iOS
+ textarea.style.opacity = "0"
+ document.body.appendChild(textarea)
+ textarea.focus()
+ textarea.select()
+ const ok = document.execCommand("copy")
+ document.body.removeChild(textarea)
+ return ok
+ } catch {
+ return false
+ }
+}
+
+export function formatHtml(html: string): string {
+ if (!html.trim()) return html;
+
+ // 한 줄짜리 HTML인지 확인
+ const lineCount = html.split('\n').length;
+ const tagCount = (html.match(/<[^>]+>/g) || []).length;
+
+ // 태그가 많은데 줄이 적으면 포맷팅 필요
+ if (tagCount <= 3 || lineCount >= tagCount / 2) {
+ return html; // 이미 포맷팅된 것으로 보임
+ }
+
+ let formatted = html
+ // 태그 앞뒤 공백 정리
+ .replace(/>\s*</g, '><')
+ // 블록 요소들 앞에 줄바꿈
+ .replace(/(<\/?(div|p|h[1-6]|table|tr|td|th|ul|ol|li|header|footer|section|article)[^>]*>)/gi, '\n$1')
+ // 자체 닫는 태그 뒤에 줄바꿈
+ .replace(/(<(br|hr|img|input)[^>]*\/?>)/gi, '$1\n')
+ // 여러 줄바꿈을 하나로
+ .replace(/\n+/g, '\n')
+ .trim();
+
+ // 간단한 들여쓰기
+ const lines = formatted.split('\n');
+ let indent = 0;
+ const result: string[] = [];
+
+ for (let line of lines) {
+ line = line.trim();
+ if (!line) continue;
+
+ // 닫는 태그면 들여쓰기 감소
+ if (line.startsWith('</')) {
+ indent = Math.max(0, indent - 2);
+ }
+
+ result.push(' '.repeat(indent) + line);
+
+ // 여는 태그면 들여쓰기 증가
+ if (line.startsWith('<') && !line.startsWith('</') && !line.endsWith('/>')) {
+ const voidTags = ['br', 'hr', 'img', 'input', 'meta', 'link'];
+ const tagName = line.match(/<(\w+)/)?.[1]?.toLowerCase();
+ if (tagName && !voidTags.includes(tagName) && !line.includes(`</${tagName}>`)) {
+ indent += 2;
+ }
+ }
+ }
+
+ return result.join('\n');
+}