bak
This commit is contained in:
1 parent
03f57cbaee
commit
a9603aa0e8
11 files changed
+1010
-93
No files matched your search
+93
-19
@@ -275,20 +275,43 @@ if (str_starts_with($route, '/api/')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Export — ZIP with JSON dump + uploads
|
||||
// Export — full or selective
|
||||
if ($route === '/api/export' && $method === 'GET') {
|
||||
$cards = $db->query('SELECT * FROM cards ORDER BY id')->fetchAll();
|
||||
$buckets = $db->query('SELECT * FROM buckets ORDER BY id')->fetchAll();
|
||||
$ids = isset($_GET['ids']) ? array_filter(array_map('intval', explode(',', $_GET['ids']))) : null;
|
||||
if ($ids) {
|
||||
$ph = implode(',', array_fill(0, count($ids), '?'));
|
||||
$cards = $db->prepare("SELECT * FROM cards WHERE id IN ($ph) ORDER BY id")->execute($ids) ? $db->prepare("SELECT * FROM cards WHERE id IN ($ph) ORDER BY id") : null;
|
||||
// Re-query properly
|
||||
$stmt = $db->prepare("SELECT * FROM cards WHERE id IN ($ph) ORDER BY id");
|
||||
$stmt->execute($ids);
|
||||
$cards = $stmt->fetchAll();
|
||||
$bucketIds = array_unique(array_filter(array_column($cards, 'bucket_id')));
|
||||
$buckets = [];
|
||||
if ($bucketIds) {
|
||||
$bph = implode(',', array_fill(0, count($bucketIds), '?'));
|
||||
$bstmt = $db->prepare("SELECT * FROM buckets WHERE id IN ($bph)");
|
||||
$bstmt->execute(array_values($bucketIds));
|
||||
$buckets = $bstmt->fetchAll();
|
||||
}
|
||||
} else {
|
||||
$cards = $db->query('SELECT * FROM cards ORDER BY id')->fetchAll();
|
||||
$buckets = $db->query('SELECT * FROM buckets ORDER BY id')->fetchAll();
|
||||
}
|
||||
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'hyprcrd_');
|
||||
$zip = new ZipArchive();
|
||||
$zip->open($tmp, ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('data.json', json_encode(['version' => 1, 'buckets' => $buckets, 'cards' => $cards], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
$zip->addFromString('data.json', json_encode(['version' => 1, 'buckets' => $buckets, 'cards' => $cards, 'selective' => !!$ids], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// Only include referenced uploads
|
||||
$uploadDir = __DIR__ . '/uploads';
|
||||
$allBodies = implode("\n", array_column($cards, 'body'));
|
||||
if (is_dir($uploadDir)) {
|
||||
foreach (glob($uploadDir . '/*') as $f) {
|
||||
if (is_file($f)) $zip->addFile($f, 'uploads/' . basename($f));
|
||||
$name = basename($f);
|
||||
if (is_file($f) && (!$ids || str_contains($allBodies, $name))) {
|
||||
$zip->addFile($f, 'uploads/' . $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
@@ -328,14 +351,23 @@ if (str_starts_with($route, '/api/')) {
|
||||
echo json_encode(['error' => 'invalid data.json']); exit;
|
||||
}
|
||||
|
||||
// Clear existing data
|
||||
$db->exec('DELETE FROM cards');
|
||||
$db->exec('DELETE FROM buckets');
|
||||
$merge = !empty($data['selective']) || !empty($_GET['merge']);
|
||||
|
||||
// Import buckets
|
||||
if (!$merge) {
|
||||
$db->exec('DELETE FROM cards');
|
||||
$db->exec('DELETE FROM buckets');
|
||||
}
|
||||
|
||||
// Import buckets (merge: match by name, create if missing)
|
||||
$bucketMap = [];
|
||||
foreach ($data['buckets'] as $b) {
|
||||
$oldId = $b['id'];
|
||||
if ($merge) {
|
||||
$existing = $db->prepare('SELECT id FROM buckets WHERE name = :name');
|
||||
$existing->execute(['name' => $b['name']]);
|
||||
$found = $existing->fetchColumn();
|
||||
if ($found) { $bucketMap[$oldId] = $found; continue; }
|
||||
}
|
||||
$stmt = $db->prepare('INSERT INTO buckets (name, position, created_at) VALUES (:name, :position, :created_at)');
|
||||
$stmt->execute(['name' => $b['name'], 'position' => $b['position'] ?? 0, 'created_at' => $b['created_at'] ?? date('Y-m-d H:i:s')]);
|
||||
$bucketMap[$oldId] = $db->lastInsertId();
|
||||
@@ -397,11 +429,12 @@ if (str_starts_with($route, '/api/')) {
|
||||
</script>
|
||||
<script>
|
||||
window.themes = {
|
||||
slate: { label:'Slate', vars:{ '--t-bg':'#1e293b','--t-surface':'#273349','--t-raised':'#2e3d56','--t-border':'#384a64','--t-dim':'#64748b','--t-muted':'#94a3b8','--t-text':'#cbd5e1','--t-bright':'#f1f5f9','--t-accent':'#38bdf8','--t-accent2':'#818cf8','--t-danger':'#fb7185','--t-scanline':'rgba(0,0,0,0.04)','--t-overlay':'rgba(15,23,42,0.75)','--t-font-pixel':'"Silkscreen", cursive' }},
|
||||
phosphor: { label:'Phosphor', vars:{ '--t-bg':'#0a0f0a','--t-surface':'#0f1a0f','--t-raised':'#142214','--t-border':'#1a3a1a','--t-dim':'#2d5a2d','--t-muted':'#4a8a4a','--t-text':'#7bc67b','--t-bright':'#b8f0b8','--t-accent':'#4ade80','--t-accent2':'#22d3ee','--t-danger':'#f87171','--t-scanline':'rgba(0,0,0,0.1)','--t-overlay':'rgba(5,10,5,0.85)','--t-font-pixel':'"Silkscreen", cursive' }},
|
||||
midnight: { label:'Midnight', vars:{ '--t-bg':'#0f172a','--t-surface':'#162033','--t-raised':'#1c2940','--t-border':'#263650','--t-dim':'#475882','--t-muted':'#7088b0','--t-text':'#a8bdd8','--t-bright':'#e2e8f0','--t-accent':'#a78bfa','--t-accent2':'#f472b6','--t-danger':'#fb7185','--t-scanline':'rgba(0,0,0,0.06)','--t-overlay':'rgba(10,15,30,0.8)','--t-font-pixel':'"Silkscreen", cursive' }},
|
||||
amber: { label:'Amber', vars:{ '--t-bg':'#1a1408','--t-surface':'#231c0e','--t-raised':'#2c2414','--t-border':'#3d3520','--t-dim':'#6b5c38','--t-muted':'#a08c5a','--t-text':'#d4c088','--t-bright':'#fbe8b0','--t-accent':'#fbbf24','--t-accent2':'#fb923c','--t-danger':'#ef4444','--t-scanline':'rgba(0,0,0,0.08)','--t-overlay':'rgba(20,16,5,0.8)','--t-font-pixel':'"Silkscreen", cursive' }},
|
||||
paper: { label:'Paper', vars:{ '--t-bg':'#f5f1eb','--t-surface':'#ffffff','--t-raised':'#eae5dd','--t-border':'#d6d0c4','--t-dim':'#a8a08e','--t-muted':'#7a7468','--t-text':'#3d3832','--t-bright':'#1a1714','--t-accent':'#2563eb','--t-accent2':'#7c3aed','--t-danger':'#dc2626','--t-scanline':'rgba(0,0,0,0)','--t-overlay':'rgba(245,241,235,0.8)','--t-font-pixel':'"JetBrains Mono", monospace' }},
|
||||
slate: { label:'Slate', vars:{ '--t-bg':'#1e293b','--t-surface':'#273349','--t-raised':'#2e3d56','--t-border':'#384a64','--t-dim':'#64748b','--t-muted':'#94a3b8','--t-text':'#cbd5e1','--t-bright':'#f1f5f9','--t-accent':'#38bdf8','--t-accent2':'#818cf8','--t-danger':'#fb7185','--t-scanline':'rgba(0,0,0,0.04)','--t-overlay':'rgba(15,23,42,0.75)','--t-font-pixel':'"Silkscreen", cursive','--t-cover-gradient':'linear-gradient(180deg, rgba(15,23,42,0.22) 0%, rgba(15,23,42,0.7) 62%, rgba(15,23,42,0.86) 100%)' }},
|
||||
phosphor: { label:'Phosphor', vars:{ '--t-bg':'#0a0f0a','--t-surface':'#0f1a0f','--t-raised':'#142214','--t-border':'#1a3a1a','--t-dim':'#2d5a2d','--t-muted':'#4a8a4a','--t-text':'#7bc67b','--t-bright':'#b8f0b8','--t-accent':'#4ade80','--t-accent2':'#22d3ee','--t-danger':'#f87171','--t-scanline':'rgba(0,0,0,0.1)','--t-overlay':'rgba(5,10,5,0.85)','--t-font-pixel':'"Silkscreen", cursive','--t-cover-gradient':'linear-gradient(180deg, rgba(10,15,10,0.22) 0%, rgba(10,15,10,0.7) 62%, rgba(10,15,10,0.86) 100%)' }},
|
||||
midnight: { label:'Midnight', vars:{ '--t-bg':'#0f172a','--t-surface':'#162033','--t-raised':'#1c2940','--t-border':'#263650','--t-dim':'#475882','--t-muted':'#7088b0','--t-text':'#a8bdd8','--t-bright':'#e2e8f0','--t-accent':'#a78bfa','--t-accent2':'#f472b6','--t-danger':'#fb7185','--t-scanline':'rgba(0,0,0,0.06)','--t-overlay':'rgba(10,15,30,0.8)','--t-font-pixel':'"Silkscreen", cursive','--t-cover-gradient':'linear-gradient(180deg, rgba(15,23,42,0.22) 0%, rgba(15,23,42,0.7) 62%, rgba(15,23,42,0.86) 100%)' }},
|
||||
amber: { label:'Amber', vars:{ '--t-bg':'#1a1408','--t-surface':'#231c0e','--t-raised':'#2c2414','--t-border':'#3d3520','--t-dim':'#6b5c38','--t-muted':'#a08c5a','--t-text':'#d4c088','--t-bright':'#fbe8b0','--t-accent':'#fbbf24','--t-accent2':'#fb923c','--t-danger':'#ef4444','--t-scanline':'rgba(0,0,0,0.08)','--t-overlay':'rgba(20,16,5,0.8)','--t-font-pixel':'"Silkscreen", cursive','--t-cover-gradient':'linear-gradient(180deg, rgba(26,20,8,0.22) 0%, rgba(26,20,8,0.7) 62%, rgba(26,20,8,0.86) 100%)' }},
|
||||
void: { label:'Void', vars:{ '--t-bg':'#000000','--t-surface':'#0a0a0a','--t-raised':'#141414','--t-border':'#222222','--t-dim':'#444444','--t-muted':'#666666','--t-text':'#a0a0a0','--t-bright':'#e0e0e0','--t-accent':'#ffffff','--t-accent2':'#888888','--t-danger':'#ff4444','--t-scanline':'rgba(0,0,0,0)','--t-overlay':'rgba(0,0,0,0.85)','--t-font-pixel':'"Silkscreen", cursive','--t-cover-gradient':'linear-gradient(180deg, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.75) 62%, rgba(0,0,0,0.9) 100%)' }},
|
||||
paper: { label:'Paper', vars:{ '--t-bg':'#f4f4f5','--t-surface':'#ffffff','--t-raised':'#e8e8eb','--t-border':'#d4d4d8','--t-dim':'#a1a1aa','--t-muted':'#71717a','--t-text':'#3f3f46','--t-bright':'#18181b','--t-accent':'#2563eb','--t-accent2':'#7c3aed','--t-danger':'#dc2626','--t-scanline':'rgba(0,0,0,0)','--t-overlay':'rgba(244,244,245,0.8)','--t-font-pixel':'"JetBrains Mono", monospace','--t-cover-gradient':'linear-gradient(180deg, rgba(255,255,255,0.9) 0%, rgba(255,255,255,0.75) 40%, rgba(255,255,255,0.3) 100%)' }},
|
||||
};
|
||||
window.applyTheme = function(name) {
|
||||
const t = themes[name] || themes.slate;
|
||||
@@ -415,7 +448,7 @@ if (str_starts_with($route, '/api/')) {
|
||||
applyTheme(localStorage.getItem('hyprcrd-theme') || 'slate');
|
||||
</script>
|
||||
</head>
|
||||
<!-- tailwind safelist: border-t-bright border-transparent scale-125 text-t-accent line-clamp-2 border-t-danger text-t-danger pr-16 -->
|
||||
<!-- tailwind safelist: border-t-bright border-transparent scale-125 text-t-accent line-clamp-2 line-clamp-5 border-t-danger text-t-danger pr-16 text-amber-400 -->
|
||||
<body class="bg-t-bg text-t-text min-h-screen transition-colors duration-200 flex flex-col">
|
||||
|
||||
<header id="main-header" class="sticky top-0 z-40 bg-t-bg border-b border-t-border shadow-[0_4px_20px_-4px_rgba(0,0,0,0.3)]" style="overflow:hidden;">
|
||||
@@ -573,22 +606,32 @@ if (str_starts_with($route, '/api/')) {
|
||||
<!-- Main content -->
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<div class="card-bar w-full shrink-0" id="detail-color"></div>
|
||||
<div id="detail-controls" class="absolute top-4 right-4 flex gap-2 z-10">
|
||||
<div id="detail-controls" class="flex items-center gap-2 px-4 py-2 border-b border-t-border shrink-0">
|
||||
<button id="detail-edit" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent2 hover:text-t-accent2 transition-colors">
|
||||
<i class="ph ph-pencil-simple text-sm"></i><span class="font-pixel text-[10px]">edit</span>
|
||||
</button>
|
||||
<button id="detail-delete" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-danger hover:text-t-danger transition-colors">
|
||||
<i class="ph ph-trash text-sm"></i><span class="font-pixel text-[10px]">del</span>
|
||||
</button>
|
||||
<button id="detail-extract" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors" title="extract selection to new card">
|
||||
<i class="ph ph-arrow-square-out text-sm"></i>
|
||||
</button>
|
||||
<button id="detail-tree" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors" title="tree view">
|
||||
<i class="ph ph-tree-structure text-sm"></i>
|
||||
</button>
|
||||
<button id="detail-zen" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors" title="zen mode">
|
||||
<i class="ph ph-corners-out text-sm"></i>
|
||||
</button>
|
||||
<div class="flex-1"></div>
|
||||
<button id="split-right-btn" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors" title="split view">
|
||||
<i class="ph ph-split-horizontal text-sm"></i><span class="font-pixel text-[10px]">split</span>
|
||||
</button>
|
||||
<button id="detail-close" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-danger hover:text-t-danger transition-colors">
|
||||
<i class="ph ph-x text-sm"></i><span class="font-pixel text-[10px]">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="detail-scroll" class="p-6 pt-5 flex-1 overflow-y-auto">
|
||||
<h2 id="detail-title" class="font-pixel text-t-bright text-lg mb-4 pr-32 leading-relaxed"></h2>
|
||||
<h2 id="detail-title" class="font-pixel text-t-bright text-lg mb-4 leading-relaxed"></h2>
|
||||
<div id="detail-body" class="prose text-sm text-t-text"></div>
|
||||
<div id="detail-backlinks" class="hidden mt-6 pt-4 border-t border-t-border">
|
||||
<div class="font-pixel text-[10px] text-t-dim mb-2 flex items-center gap-1.5"><i class="ph ph-arrow-bend-left-up text-xs"></i> referenced_by</div>
|
||||
@@ -597,6 +640,16 @@ if (str_starts_with($route, '/api/')) {
|
||||
<div id="detail-meta" class="mt-8 pt-4 border-t border-t-border text-[11px] text-t-dim font-pixel"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Split right pane -->
|
||||
<div id="split-right" class="hidden w-2/5 shrink-0 border-l border-t-border flex flex-col min-w-0">
|
||||
<div class="flex items-center gap-2 px-3 py-2 border-b border-t-border shrink-0">
|
||||
<i class="ph ph-magnifying-glass text-t-dim text-xs"></i>
|
||||
<input type="text" id="split-search" class="flex-1 bg-transparent text-xs text-t-bright placeholder:text-t-dim font-mono focus:outline-none" placeholder="search all cards..." autocomplete="off">
|
||||
<button id="split-close" class="text-t-dim hover:text-t-danger transition-colors"><i class="ph ph-x text-sm"></i></button>
|
||||
</div>
|
||||
<div id="split-picks" class="overflow-y-auto border-b border-t-border"></div>
|
||||
<div id="split-content" class="flex-1 overflow-y-auto p-5"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -618,6 +671,17 @@ if (str_starts_with($route, '/api/')) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selection action bar -->
|
||||
<div id="select-bar" class="fixed bottom-16 left-1/2 -translate-x-1/2 z-[45] bg-t-surface border border-t-border shadow-2xl px-4 py-2 flex items-center gap-3 hidden" style="border-radius:6px;">
|
||||
<span id="select-count" class="font-pixel text-[10px] text-t-accent"></span>
|
||||
<button id="select-export" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors">
|
||||
<i class="ph ph-download-simple text-sm"></i><span class="font-pixel text-[10px]">export</span>
|
||||
</button>
|
||||
<button id="select-clear" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-danger hover:text-t-danger transition-colors">
|
||||
<i class="ph ph-x text-sm"></i><span class="font-pixel text-[10px]">clear</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Context menu -->
|
||||
<div id="ctx-menu" class="fixed z-[85] bg-t-surface border border-t-border shadow-2xl hidden" style="min-width:180px;">
|
||||
<div id="ctx-items" class="py-1"></div>
|
||||
@@ -635,7 +699,9 @@ if (str_starts_with($route, '/api/')) {
|
||||
<div class="flex items-center gap-3"><i class="ph ph-file-plus text-t-accent text-sm"></i><h2 id="modal-title" class="font-pixel text-xs text-t-accent">new_card</h2></div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button id="modal-cancel" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-danger hover:text-t-danger transition-colors"><i class="ph ph-x text-sm"></i><span class="font-pixel text-[10px]">close</span></button>
|
||||
<button id="modal-save" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-accent text-t-accent hover:bg-t-accent/10 transition-colors"><i class="ph ph-floppy-disk text-sm"></i><span class="font-pixel text-[10px]">save</span></button>
|
||||
<button id="modal-save" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors"><i class="ph ph-floppy-disk text-sm"></i><span class="font-pixel text-[10px]">save</span></button>
|
||||
<button id="modal-save-view" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors"><i class="ph ph-eye text-sm"></i><span class="font-pixel text-[10px]">save+view</span></button>
|
||||
<button id="modal-save-close" class="flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-accent text-t-accent hover:bg-t-accent/10 transition-colors"><i class="ph ph-floppy-disk text-sm"></i><span class="font-pixel text-[10px]">save+close</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 px-4 py-2.5 border-b border-t-border shrink-0">
|
||||
@@ -654,6 +720,7 @@ if (str_starts_with($route, '/api/')) {
|
||||
<button data-md="codeblock" title="Code block" class="toolbar-btn"><i class="ph ph-code-block text-sm"></i></button>
|
||||
<div class="w-px h-4 bg-t-border mx-1"></div>
|
||||
<button data-md="ul" title="List" class="toolbar-btn"><i class="ph ph-list-bullets text-sm"></i></button>
|
||||
<button data-md="tree" title="Tree list" class="toolbar-btn"><i class="ph ph-tree-structure text-sm"></i></button>
|
||||
<button data-md="ol" title="Numbered" class="toolbar-btn"><i class="ph ph-list-numbers text-sm"></i></button>
|
||||
<button data-md="quote" title="Quote" class="toolbar-btn"><i class="ph ph-quotes text-sm"></i></button>
|
||||
<button data-md="todo" title="Todo" class="toolbar-btn"><i class="ph ph-check-square text-sm"></i></button>
|
||||
@@ -661,11 +728,18 @@ if (str_starts_with($route, '/api/')) {
|
||||
<button data-md="link" title="Link" class="toolbar-btn"><i class="ph ph-link text-sm"></i></button>
|
||||
<button data-md="cardlink" title="Card ref [[" class="toolbar-btn"><i class="ph ph-arrow-square-out text-sm"></i></button>
|
||||
<button data-md="hr" title="Divider" class="toolbar-btn"><i class="ph ph-minus text-sm"></i></button>
|
||||
<div class="w-px h-4 bg-t-border mx-1"></div>
|
||||
<button data-md="extract" title="Extract selection to new card" class="toolbar-btn"><i class="ph ph-arrow-square-out text-sm"></i></button>
|
||||
<div class="flex-1"></div>
|
||||
<button id="toggle-lines" class="toolbar-btn flex items-center gap-1.5 px-2" title="line numbers"><i class="ph ph-hash text-sm"></i></button>
|
||||
<button id="toggle-preview" class="toolbar-btn flex items-center gap-1.5 px-2"><i class="ph ph-eye text-sm"></i><span class="font-pixel text-[9px]">preview</span></button>
|
||||
</div>
|
||||
<div class="flex flex-1 min-h-0">
|
||||
<textarea id="editor-body" placeholder="> write markdown..." class="flex-1 bg-t-bg text-t-text text-sm p-4 font-mono leading-relaxed placeholder:text-t-dim border-none min-h-full overflow-y-auto"></textarea>
|
||||
<div id="editor-gutter" class="hidden bg-t-bg text-t-dim text-right font-mono text-sm select-none overflow-hidden shrink-0 border-r border-t-border" style="width:3.5em; padding:1rem 0.25rem 1rem 0.5rem; line-height:1.625;"></div>
|
||||
<div class="flex-1 relative min-h-full bg-t-bg">
|
||||
<div id="editor-line-hl" class="absolute pointer-events-none left-0 right-0" style="background:var(--t-border);opacity:0.18;display:none;z-index:1;"></div>
|
||||
<textarea id="editor-body" placeholder="> write markdown..." class="absolute inset-0 w-full h-full text-t-text text-sm font-mono placeholder:text-t-dim border-none overflow-y-auto" style="padding:1rem; line-height:1.625; resize:none; z-index:2; background:transparent;"></textarea>
|
||||
</div>
|
||||
<div id="editor-preview" class="flex-1 border-l border-t-border bg-t-bg p-4 overflow-y-auto hidden"><div id="preview-content" class="prose text-sm text-t-text"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user