← Notes results

Notes

Qwen 3.6 27B MTP GGUF · typescript

Initial view of Notes

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 76,536 bytes · SHA-256 7c11f25dce73
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Notes — Personal Knowledge Manager</title>
<style>
/* ── css: layout ── */
:root {
  --bg-primary: #faf9f7;
  --bg-secondary: #f3f1ed;
  --bg-tertiary: #ebe8e2;
  --bg-hover: #e2ded7;
  --bg-active: #d5cfc6;
  --bg-selection: rgba(196, 114, 47, 0.08);
  --text-primary: #1a1714;
  --text-secondary: #5c564f;
  --text-tertiary: #8a8279;
  --text-placeholder: #b5afa8;
  --border: #ddd8d1;
  --border-light: #e8e4de;
  --accent: #c4722f;
  --accent-light: #f5e6d6;
  --accent-hover: #a9601f;
  --danger: #c0392b;
  --danger-light: #f8d7d4;
  --success: #27ae60;
  --shadow-sm: 0 1px 3px rgba(44, 40, 37, 0.05);
  --shadow-md: 0 4px 16px rgba(44, 40, 37, 0.08);
  --shadow-lg: 0 8px 30px rgba(44, 40, 37, 0.12);
  --radius: 8px;
  --radius-sm: 5px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-editor: "Georgia", "Iowan Old Style", "Palatino Linotype", "Palatino", "Times New Roman", serif;
  --font-mono: "SF Mono", "Cascadia Code", "Fira Code", "Consolas", "Liberation Mono", monospace;
  --sidebar-width: 250px;
  --notelist-width: 300px;
  --toolbar-height: 44px;
  --transition-fast: 120ms cubic-bezier(0.2, 0, 0, 1);
  --transition-normal: 200ms cubic-bezier(0.2, 0, 0, 1);
  --transition-slow: 300ms cubic-bezier(0.2, 0, 0, 1);
}

[data-theme="dark"] {
  --bg-primary: #1a1a1a;
  --bg-secondary: #222222;
  --bg-tertiary: #2c2c2c;
  --bg-hover: #333333;
  --bg-active: #3c3c3c;
  --bg-selection: rgba(224, 138, 62, 0.12);
  --text-primary: #e8e4e0;
  --text-secondary: #a09a93;
  --text-tertiary: #6e6962;
  --text-placeholder: #4a4742;
  --border: #333333;
  --border-light: #2c2c2c;
  --accent: #e08a3e;
  --accent-light: #3a2a18;
  --accent-hover: #f09a4e;
  --danger: #e74c3c;
  --danger-light: #3a1a1a;
  --success: #2ecc71;
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.2);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.4);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  overflow: hidden;
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-primary);
  background: var(--bg-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
}

/* ── Toolbar ── */
.toolbar-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  height: var(--toolbar-height);
  min-height: var(--toolbar-height);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  z-index: 100;
  user-select: none;
}

.app-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.3px;
  margin-right: auto;
  padding-left: 2px;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: 15px;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.icon-btn:hover { background: var(--bg-hover); color: var(--text-primary); }
.icon-btn:active { background: var(--bg-active); }

.search-container {
  display: flex;
  align-items: center;
  width: 220px;
  max-width: 35vw;
}

.search-input {
  flex: 1;
  height: 30px;
  padding: 0 10px 0 30px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-primary) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%238a8279' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85zm-5.242.656a5 5 0 1 1 0-10 5 5 0 0 1 0 10z'/%3E%3C/svg%3E") no-repeat 10px center;
  color: var(--text-primary);
  font-size: 12px;
  font-family: var(--font-ui);
  outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.search-input::placeholder { color: var(--text-placeholder); }
.search-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}

/* ── Main Layout ── */
.main-layout { display: flex; flex: 1; overflow: hidden; }

.pane { display: flex; flex-direction: column; overflow: hidden; }

.sidebar-pane {
  width: var(--sidebar-width);
  min-width: 160px;
  max-width: 400px;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  flex-shrink: 0;
  transition: width var(--transition-slow);
  overflow-y: auto;
  overflow-x: hidden;
}
.sidebar-pane.collapsed { width: 0 !important; min-width: 0 !important; border-right: none; }

.notelist-pane {
  width: var(--notelist-width);
  min-width: 200px;
  max-width: 500px;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  flex-shrink: 0;
}

.editor-pane {
  flex: 1;
  min-width: 300px;
  background: var(--bg-primary);
  overflow: hidden;
}

/* ── Resizer ── */
.resizer {
  width: 3px;
  cursor: col-resize;
  background: transparent;
  position: relative;
  z-index: 10;
  flex-shrink: 0;
  transition: background var(--transition-fast);
}
.resizer::after {
  content: '';
  position: absolute;
  inset: 0;
  width: 6px;
  margin-left: -2px;
}
.resizer:hover, .resizer.active { background: var(--accent); }

/* ── Sidebar Items ── */
.sidebar-section { padding: 0 6px; }

.sidebar-item {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 12.5px;
  color: var(--text-secondary);
  transition: background var(--transition-fast), color var(--transition-fast);
  user-select: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-item:hover { background: var(--bg-hover); color: var(--text-primary); }
.sidebar-item.active { background: var(--accent-light); color: var(--accent); font-weight: 600; }
.sidebar-item .icon { flex-shrink: 0; width: 18px; text-align: center; font-size: 14px; }
.sidebar-item .count {
  margin-left: auto;
  font-size: 11px;
  color: var(--text-tertiary);
  flex-shrink: 0;
  padding: 0 4px;
}

.sidebar-add-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  margin: 2px 0;
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  font-size: 12px;
  border-radius: var(--radius-sm);
  width: calc(100% - 12px);
  text-align: left;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.sidebar-add-btn:hover { background: var(--bg-hover); color: var(--text-secondary); }

/* Notebook groups */
.notebook-group { margin-bottom: 1px; }

.notebook-header {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 2px 4px;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background var(--transition-fast);
}
.notebook-header:hover { background: var(--bg-hover); }
.notebook-header .chevron {
  font-size: 9px;
  transition: transform var(--transition-fast);
  width: 14px;
  text-align: center;
  color: var(--text-tertiary);
  flex-shrink: 0;
}
.notebook-header .chevron.collapsed { transform: rotate(-90deg); }

.notebook-notes { padding-left: 6px; overflow: hidden; }
.notebook-notes.collapsed { max-height: 0 !important; }

/* ── Note List ── */
.notelist-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--border);
  min-height: 52px;
}
.notelist-header h2 {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.2px;
}
.notelist-actions { display: flex; gap: 1px; }
.notelist-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: 13px;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.notelist-actions button:hover { background: var(--bg-hover); color: var(--text-primary); }

.note-list { flex: 1; overflow-y: auto; padding: 4px 8px 16px; }

.note-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 10px;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
  border: 1px solid transparent;
  margin-bottom: 2px;
}
.note-item:hover { background: var(--bg-hover); }
.note-item.active {
  background: var(--bg-tertiary);
  border-color: var(--border);
  box-shadow: var(--shadow-sm);
}
.note-item.pinned .note-item-title::before {
  content: '📌 ';
  font-size: 10px;
}
.note-item-title {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.35;
}
.note-item-snippet {
  font-size: 11.5px;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
}
.note-item-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  color: var(--text-tertiary);
}
.note-item-tags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px; }
.note-item-tag {
  font-size: 10px;
  padding: 1px 7px;
  border-radius: 10px;
  background: var(--bg-tertiary);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.note-item-tag:hover { background: var(--accent-light); color: var(--accent); }
.note-item-tag.active { background: var(--accent-light); color: var(--accent); }

/* ── Editor ── */
.editor-content {
  display: none;
  flex-direction: column;
  flex: 1;
  overflow: hidden;
}
.editor-content.visible { display: flex; }

.empty-state {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  gap: 16px;
  color: var(--text-tertiary);
}
.empty-state.visible { display: flex; }

.empty-state-icon {
  font-size: 48px;
  opacity: 0.35;
  filter: grayscale(0.5);
}
.empty-state-text {
  font-size: 15px;
  font-weight: 500;
  color: var(--text-tertiary);
}

/* Toolbar */
.editor-toolbar {
  display: none;
  align-items: center;
  gap: 1px;
  padding: 4px 16px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
  min-height: 38px;
}
.editor-toolbar.visible { display: flex; }

.toolbar-group { display: flex; align-items: center; gap: 1px; }
.toolbar-group + .toolbar-group { margin-left: 6px; padding-left: 6px; border-left: 1px solid var(--border); }

.toolbar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 26px;
  padding: 0 5px;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: 4px;
  font-size: 12px;
  font-family: var(--font-ui);
  transition: background var(--transition-fast), color var(--transition-fast);
  user-select: none;
}
.toolbar-btn:hover { background: var(--bg-hover); color: var(--text-primary); }
.toolbar-btn.active { background: var(--accent-light); color: var(--accent); }

.toolbar-select {
  height: 26px;
  padding: 0 6px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: 11px;
  font-family: var(--font-ui);
  cursor: pointer;
  outline: none;
  transition: border-color var(--transition-fast);
}
.toolbar-select:hover { border-color: var(--accent); }
.toolbar-select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }

/* Editor content area */
.editor-wrapper {
  flex: 1;
  overflow-y: auto;
  padding: 32px 48px 60px;
  max-width: 720px;
  margin: 0 auto;
  width: 100%;
}

.note-title {
  font-size: 26px;
  font-weight: 700;
  color: var(--text-primary);
  border: none;
  outline: none;
  padding: 4px 0 6px;
  margin-bottom: 2px;
  background: transparent;
  font-family: var(--font-ui);
  line-height: 1.3;
  letter-spacing: -0.3px;
}
.note-title:empty::before {
  content: attr(data-placeholder);
  color: var(--text-placeholder);
  pointer-events: none;
}

.note-tags {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 0 14px;
  flex-wrap: wrap;
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 10px;
  border-radius: 12px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 11px;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.tag:hover { background: var(--accent-light); color: var(--accent); }

.tag .remove-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 13px;
  height: 13px;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  border-radius: 50%;
  font-size: 10px;
  line-height: 1;
  opacity: 0.5;
  transition: opacity var(--transition-fast);
}
.tag .remove-tag:hover { opacity: 1; }

.add-tag-btn {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border: 1px dashed var(--border);
  border-radius: 12px;
  background: transparent;
  color: var(--text-tertiary);
  font-size: 11px;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}
.add-tag-btn:hover { border-color: var(--accent); color: var(--accent); }

/* Note body */
.note-body {
  flex: 1;
  outline: none;
  font-family: var(--font-editor);
  font-size: 15.5px;
  line-height: 1.8;
  color: var(--text-primary);
  min-height: 150px;
  padding-bottom: 40px;
}
.note-body:empty::before {
  content: attr(data-placeholder);
  color: var(--text-placeholder);
  pointer-events: none;
  font-style: italic;
}

.note-body h1 { font-size: 1.7em; font-weight: 700; margin: 0.6em 0 0.3em; line-height: 1.3; letter-spacing: -0.5px; }
.note-body h2 { font-size: 1.35em; font-weight: 700; margin: 0.5em 0 0.25em; line-height: 1.35; }
.note-body h3 { font-size: 1.15em; font-weight: 600; margin: 0.4em 0 0.15em; line-height: 1.4; }
.note-body blockquote {
  margin: 0.4em 0;
  padding: 0.3em 1em;
  border-left: 3px solid var(--accent);
  color: var(--text-secondary);
  font-style: italic;
  background: var(--bg-tertiary);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.note-body ul, .note-body ol { padding-left: 1.5em; margin: 0.2em 0; }
.note-body li { margin: 0.12em 0; }
.note-body code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  padding: 1px 5px;
  background: var(--bg-tertiary);
  border-radius: 3px;
  color: var(--accent);
}
.note-body hr { margin: 1.2em 0; border: none; height: 1px; background: var(--border); }

/* Checklist */
.checklist-item {
  list-style: none;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0.15em 0;
  padding-left: 0 !important;
}
.checklist-item .check-box {
  flex-shrink: 0;
  width: 17px;
  height: 17px;
  border: 2px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 4px;
  transition: all var(--transition-fast);
  font-size: 10px;
  background: var(--bg-primary);
}
.checklist-item .check-box:hover { border-color: var(--accent); }
.checklist-item .check-box.checked {
  background: var(--accent);
  border-color: var(--accent);
}
.checklist-item .check-box.checked::after { content: '✓'; color: #fff; font-weight: 700; }
.checklist-item.checked-item .check-content { text-decoration: line-through; color: var(--text-tertiary); }

/* Saved indicator */
.saved-indicator {
  position: fixed;
  bottom: 16px;
  right: 20px;
  padding: 5px 14px;
  border-radius: 20px;
  background: var(--bg-secondary);
  color: var(--text-tertiary);
  font-size: 11px;
  font-family: var(--font-ui);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--transition-normal), transform var(--transition-normal);
  pointer-events: none;
  z-index: 1000;
}
.saved-indicator.visible { opacity: 1; transform: translateY(0); }

/* Scrollbar */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--bg-hover); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--bg-active); }

/* Context menu */
.context-menu {
  position: fixed;
  z-index: 1000;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 4px;
  min-width: 180px;
}
.context-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 12.5px;
  color: var(--text-primary);
  transition: background var(--transition-fast);
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  font-family: var(--font-ui);
}
.context-menu-item:hover { background: var(--bg-hover); }
.context-menu-item.danger { color: var(--danger); }
.context-menu-item.danger:hover { background: var(--danger-light); }
.context-menu-separator { height: 1px; background: var(--border); margin: 3px 0; }

.hidden { display: none !important; }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* Move dialog */
.move-dialog-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: fadeIn var(--transition-fast) ease;
  backdrop-filter: blur(2px);
}
.move-dialog {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 20px;
  width: 280px;
}
.move-dialog h3 { font-size: 15px; margin-bottom: 10px; }
.move-dialog-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 13px;
  color: var(--text-primary);
  transition: background var(--transition-fast);
}
.move-dialog-item:hover { background: var(--bg-hover); }
</style>
</head>
<body>
<div id="app" class="app">
  <div id="toolbar-bar" class="toolbar-bar">
    <button id="toggle-sidebar" class="icon-btn" title="Toggle Sidebar">☰</button>
    <div class="app-title">Notes</div>
    <div id="search-container" class="search-container">
      <input id="search-input" type="text" placeholder="Search notes…" class="search-input">
      <button id="clear-search" class="icon-btn hidden">✕</button>
    </div>
    <button id="theme-toggle" class="icon-btn" title="Toggle Theme">🌙</button>
  </div>
  <div id="main-layout" class="main-layout">
    <div id="sidebar-pane" class="pane sidebar-pane"></div>
    <div id="sidebar-resizer" class="resizer"></div>
    <div id="notelist-pane" class="pane notelist-pane"></div>
    <div id="notelist-resizer" class="resizer"></div>
    <div id="editor-pane" class="pane editor-pane">
      <div id="editor-toolbar" class="editor-toolbar"></div>
      <div id="editor-content" class="editor-content">
  <div class="editor-wrapper">
    <div id="note-title" class="note-title" contenteditable="true" data-placeholder="Untitled"></div>
    <div id="note-tags" class="note-tags"></div>
    <div id="note-body" class="note-body" contenteditable="true" data-placeholder="Start writing…"></div>
  </div>
</div>
      <div id="empty-state" class="empty-state">
        <div class="empty-state-icon">📝</div>
        <div class="empty-state-text">Select or create a note</div>
      </div>
    </div>
  </div>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./types":"src/types.ts","./store":"src/store.ts","./sidebar":"src/sidebar.ts","./notelist":"src/notelist.ts","./editor":"src/editor.ts"},"src/store.ts":{"./types":"src/types.ts"},"src/utils.ts":{"./types":"src/types.ts"},"src/sidebar.ts":{"./types":"src/types.ts","./utils":"src/utils.ts"},"src/notelist.ts":{"./types":"src/types.ts","./utils":"src/utils.ts"},"src/editor.ts":{"./types":"src/types.ts","./utils":"src/utils.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("./types");
const store_1 = require("./store");
const sidebar_1 = require("./sidebar");
const notelist_1 = require("./notelist");
const editor_1 = require("./editor");
// Initialize
const state = (0, store_1.initState)();
applyTheme(state.theme);
applyPaneState(state.paneState);
// Reactive render function
let renderLock = false;
function renderAll() {
    if (renderLock)
        return;
    renderLock = true;
    const st = (0, store_1.getState)();
    (0, sidebar_1.renderSidebar)(st);
    (0, notelist_1.renderNoteList)(st);
    renderLock = false;
}
// Wire editor save callback
(0, editor_1.setSaveCallback)((noteId, updates) => {
    const st = (0, store_1.getState)();
    const note = st.notes.find(n => n.id === noteId);
    if (!note)
        return;
    Object.assign(note, updates);
    (0, store_1.setState)(st);
    renderAll();
});
// Initial render
renderAll();
(0, editor_1.initEditor)();
if (state.selectedNoteId) {
    const note = state.notes.find(n => n.id === state.selectedNoteId);
    if (note && !note.trashed) {
        (0, editor_1.setActiveNote)(note);
        (0, editor_1.setNote)(note);
    }
}
// ============ EVENT HANDLERS ============
// Global action handler
document.addEventListener('app-action', (e) => {
    const detail = e.detail;
    handleAppAction(detail.action, detail);
});
// Context menu handler
document.addEventListener('note-context-menu', (e) => {
    const detail = e.detail;
    showNoteContextMenu(detail.noteId, detail.x, detail.y);
});
// Search
const searchInput = document.getElementById('search-input');
const clearSearch = document.getElementById('clear-search');
searchInput.addEventListener('input', () => {
    const st = (0, store_1.getState)();
    (0, store_1.setState)({ ...st, searchQuery: searchInput.value });
    clearSearch.classList.toggle('hidden', !searchInput.value);
    renderAll();
});
clearSearch.addEventListener('click', () => {
    searchInput.value = '';
    const st = (0, store_1.getState)();
    (0, store_1.setState)({ ...st, searchQuery: '' });
    clearSearch.classList.add('hidden');
    renderAll();
    searchInput.focus();
});
// Theme toggle
document.getElementById('theme-toggle').addEventListener('click', () => {
    const st = (0, store_1.getState)();
    const newTheme = st.theme === 'light' ? 'dark' : 'light';
    applyTheme(newTheme);
    (0, store_1.setState)({ ...st, theme: newTheme });
});
// Sidebar toggle
document.getElementById('toggle-sidebar').addEventListener('click', () => {
    const st = (0, store_1.getState)();
    const collapsed = !st.paneState.sidebarCollapsed;
    (0, store_1.setState)({ ...st, paneState: { ...st.paneState, sidebarCollapsed: collapsed } });
    applyPaneState(st.paneState);
});
// Resizers
initResizer('sidebar-resizer', 'sidebar-pane', (delta) => {
    const st = (0, store_1.getState)();
    const newWidth = Math.max(160, Math.min(400, st.paneState.sidebarWidth + delta));
    (0, store_1.setState)({ ...st, paneState: { ...st.paneState, sidebarWidth: newWidth } });
    applyPaneState(st.paneState);
});
initResizer('notelist-resizer', 'notelist-pane', (delta) => {
    const st = (0, store_1.getState)();
    const newWidth = Math.max(180, Math.min(500, st.paneState.notelistWidth + delta));
    (0, store_1.setState)({ ...st, paneState: { ...st.paneState, notelistWidth: newWidth } });
    applyPaneState(st.paneState);
});
// ============ HELPER FUNCTIONS ============
function applyTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
    const btn = document.getElementById('theme-toggle');
    btn.textContent = theme === 'light' ? '🌙' : '☀️';
}
function applyPaneState(ps) {
    const sidebar = document.getElementById('sidebar-pane');
    const notelist = document.getElementById('notelist-pane');
    sidebar.style.width = ps.sidebarWidth + 'px';
    sidebar.classList.toggle('collapsed', ps.sidebarCollapsed);
    notelist.style.width = ps.notelistWidth + 'px';
}
function handleAppAction(action, detail) {
    const st = (0, store_1.getState)();
    switch (action) {
        case 'select-notebook': {
            (0, store_1.setState)({ ...st, selectedNotebookId: detail.notebookId, selectedNoteId: null, activeTagFilter: null });
            (0, editor_1.setActiveNote)(null);
            (0, editor_1.setNote)(null);
            renderAll();
            break;
        }
        case 'toggle-notebook': {
            const nb = st.notebooks.find(n => n.id === detail.notebookId);
            if (nb)
                nb.collapsed = !nb.collapsed;
            (0, store_1.setState)({ ...st, notebooks: [...st.notebooks] });
            renderAll();
            break;
        }
        case 'add-notebook': {
            const name = prompt('Notebook name:');
            if (!name?.trim())
                return;
            const nb = (0, types_1.createNotebook)(name.trim());
            (0, store_1.setState)({ ...st, notebooks: [...st.notebooks, nb] });
            renderAll();
            break;
        }
        case 'rename-notebook': {
            const nb = st.notebooks.find(n => n.id === detail.notebookId);
            if (!nb)
                return;
            const name = prompt('Rename notebook:', nb.name);
            if (!name?.trim())
                return;
            nb.name = name.trim();
            (0, store_1.setState)({ ...st, notebooks: [...st.notebooks] });
            renderAll();
            break;
        }
        case 'delete-notebook': {
            const nb = st.notebooks.find(n => n.id === detail.notebookId);
            if (!nb)
                return;
            if (!confirm(`Delete notebook "${nb.name}" and all its notes?`))
                return;
            const noteIds = st.notes.filter(n => n.notebookId === detail.notebookId).map(n => n.id);
            (0, store_1.setState)({
                ...st,
                notebooks: st.notebooks.filter(n => n.id !== detail.notebookId),
                notes: st.notes.filter(n => !noteIds.includes(n.id)),
                selectedNotebookId: st.selectedNotebookId === detail.notebookId ? null : st.selectedNotebookId,
                selectedNoteId: noteIds.includes(st.selectedNoteId || '') ? null : st.selectedNoteId,
            });
            (0, editor_1.setActiveNote)(null);
            (0, editor_1.setNote)(null);
            renderAll();
            break;
        }
        case 'add-note': {
            const notebookId = detail.notebookId || st.selectedNotebookId || st.notebooks[0]?.id || null;
            if (!notebookId)
                return;
            const note = (0, types_1.createNote)(notebookId);
            (0, store_1.setState)({ ...st, notes: [...st.notes, note], selectedNotebookId: notebookId, selectedNoteId: note.id });
            (0, editor_1.setActiveNote)(note);
            (0, editor_1.setNote)(note);
            renderAll();
            setTimeout(() => document.getElementById('note-title')?.focus(), 50);
            break;
        }
        case 'select-note': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            (0, store_1.setState)({ ...st, selectedNoteId: note.id });
            (0, editor_1.setActiveNote)(note);
            (0, editor_1.setNote)(note);
            renderAll();
            break;
        }
        case 'sort-toggle': {
            const orders = ['modified', 'created', 'alphabetical'];
            const idx = orders.indexOf(st.sortOrder);
            const nextOrder = orders[(idx + 1) % orders.length];
            (0, store_1.setState)({ ...st, sortOrder: nextOrder });
            renderAll();
            break;
        }
        case 'filter-tag': {
            (0, store_1.setState)({ ...st, activeTagFilter: detail.tag });
            renderAll();
            break;
        }
        case 'clear-tag-filter': {
            (0, store_1.setState)({ ...st, activeTagFilter: null });
            renderAll();
            break;
        }
        case 'move-note': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            note.notebookId = detail.targetNotebookId;
            note.updatedAt = Date.now();
            (0, store_1.setState)({ ...st, notes: [...st.notes] });
            renderAll();
            break;
        }
        case 'pin': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            note.pinned = !note.pinned;
            note.updatedAt = Date.now();
            (0, store_1.setState)({ ...st, notes: [...st.notes] });
            renderAll();
            break;
        }
        case 'duplicate': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            const dup = structuredClone(note);
            dup.id = `id_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
            dup.title = note.title + ' (copy)';
            dup.pinned = false;
            dup.createdAt = Date.now();
            dup.updatedAt = Date.now();
            dup.trashed = false;
            dup.trashedAt = null;
            dup.previousNotebookId = null;
            (0, store_1.setState)({ ...st, notes: [...st.notes, dup] });
            renderAll();
            break;
        }
        case 'delete': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            note.trashed = true;
            note.trashedAt = Date.now();
            note.previousNotebookId = note.notebookId;
            (0, store_1.setState)({ ...st, notes: [...st.notes], selectedNoteId: null });
            (0, editor_1.setActiveNote)(null);
            (0, editor_1.setNote)(null);
            renderAll();
            break;
        }
        case 'restore': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            note.trashed = false;
            note.trashedAt = null;
            note.notebookId = note.previousNotebookId || st.notebooks[0]?.id;
            note.previousNotebookId = null;
            note.updatedAt = Date.now();
            (0, store_1.setState)({ ...st, notes: [...st.notes] });
            renderAll();
            break;
        }
        case 'permanently-delete': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (!note)
                return;
            (0, store_1.setState)({
                ...st,
                notes: st.notes.filter(n => n.id !== detail.noteId),
                selectedNoteId: st.selectedNoteId === detail.noteId ? null : st.selectedNoteId,
            });
            renderAll();
            break;
        }
        case 'move': {
            const note = st.notes.find(n => n.id === detail.noteId);
            if (note)
                showMoveDialog(note);
            break;
        }
        default:
            break;
    }
}
// Context menu
function showNoteContextMenu(noteId, x, y) {
    removeContextMenu();
    const st = (0, store_1.getState)();
    const note = st.notes.find(n => n.id === noteId);
    if (!note)
        return;
    const isTrashed = st.selectedNotebookId === 'trash';
    const menu = document.createElement('div');
    menu.className = 'context-menu';
    menu.id = 'context-menu';
    let items = '';
    if (!isTrashed) {
        items += `<button class="context-menu-item" data-ctx-action="pin" data-note-id="${noteId}">${note.pinned ? 'Unpin' : '📌 Pin'}</button>`;
        items += `<button class="context-menu-item" data-ctx-action="duplicate" data-note-id="${noteId}">📋 Duplicate</button>`;
        items += `<div class="context-menu-separator"></div>`;
        items += `<button class="context-menu-item" data-ctx-action="move" data-note-id="${noteId}">📂 Move to…</button>`;
        items += `<div class="context-menu-separator"></div>`;
        items += `<button class="context-menu-item danger" data-ctx-action="delete" data-note-id="${noteId}">🗑️ Delete</button>`;
    }
    else {
        items += `<button class="context-menu-item" data-ctx-action="restore" data-note-id="${noteId}">↩ Restore</button>`;
        items += `<div class="context-menu-separator"></div>`;
        items += `<button class="context-menu-item danger" data-ctx-action="permanently-delete" data-note-id="${noteId}">🗑️ Delete Permanently</button>`;
    }
    menu.innerHTML = items;
    menu.style.left = Math.min(x, window.innerWidth - 200) + 'px';
    menu.style.top = Math.min(y, window.innerHeight - 150) + 'px';
    document.body.appendChild(menu);
    menu.addEventListener('click', (e) => {
        const btn = e.target.closest('.context-menu-item');
        if (!btn)
            return;
        const ctxAction = btn.getAttribute('data-ctx-action');
        const ctxNoteId = btn.getAttribute('data-note-id');
        if (ctxAction === 'permanently-delete') {
            if (!confirm('Permanently delete this note?'))
                return;
        }
        document.dispatchEvent(new CustomEvent('app-action', {
            detail: { action: ctxAction, noteId: ctxNoteId }
        }));
        removeContextMenu();
    });
    setTimeout(() => {
        const closeMenu = (ev) => {
            if (!menu.contains(ev.target)) {
                removeContextMenu();
                document.removeEventListener('mousedown', closeMenu);
            }
        };
        document.addEventListener('mousedown', closeMenu);
    }, 0);
}
function removeContextMenu() {
    const existing = document.getElementById('context-menu');
    if (existing)
        existing.remove();
}
function showMoveDialog(note) {
    const st = (0, store_1.getState)();
    const overlay = document.createElement('div');
    overlay.className = 'move-dialog-overlay';
    const dialog = document.createElement('div');
    dialog.className = 'move-dialog';
    dialog.innerHTML = `<h3>Move to notebook</h3>`;
    st.notebooks.forEach(nb => {
        const item = document.createElement('div');
        item.className = 'move-dialog-item';
        item.innerHTML = `<span>📁</span><span>${nb.name}</span>`;
        if (nb.id === note.notebookId)
            item.style.opacity = '0.5';
        item.addEventListener('click', () => {
            if (nb.id !== note.notebookId) {
                document.dispatchEvent(new CustomEvent('app-action', {
                    detail: { action: 'move-note', noteId: note.id, targetNotebookId: nb.id }
                }));
            }
            overlay.remove();
        });
        dialog.appendChild(item);
    });
    overlay.appendChild(dialog);
    overlay.addEventListener('click', (e) => {
        if (e.target === overlay)
            overlay.remove();
    });
    document.body.appendChild(overlay);
}
// Resizer
function initResizer(resizerId, paneId, onResize) {
    const resizer = document.getElementById(resizerId);
    const pane = document.getElementById(paneId);
    if (!resizer || !pane)
        return;
    resizer.addEventListener('mousedown', (e) => {
        const startX = e.clientX;
        const startWidth = pane.offsetWidth;
        resizer.classList.add('active');
        const onMouseMove = (e) => {
            onResize(e.clientX - startX);
        };
        const onMouseUp = () => {
            resizer.classList.remove('active');
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
        };
        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
    });
}
};

// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CONSTANTS = void 0;
exports.createNotebook = createNotebook;
exports.createNote = createNote;
exports.genId = genId;
exports.emptyState = emptyState;
// Tunable constants
exports.CONSTANTS = {
    // Colors (matching CSS vars, duplicated for JS use)
    colors: {
        accent: '#c4722f',
    },
    // Fonts
    fonts: {
        ui: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
        editor: 'Georgia, "Iowan Old Style", "Palatino Linotype", serif',
    },
    // Autosave
    autosaveDebounceMs: 500,
    // Snippet
    snippetLength: 100,
    // Persistence
    storageKey: 'notes-app-data',
};
function createNotebook(name) {
    return {
        id: genId(),
        name,
        collapsed: false,
        createdAt: Date.now(),
    };
}
function createNote(notebookId, title = '', body = '') {
    const now = Date.now();
    return {
        id: genId(),
        notebookId,
        title,
        body,
        tags: [],
        pinned: false,
        createdAt: now,
        updatedAt: now,
        trashed: false,
        trashedAt: null,
        previousNotebookId: null,
    };
}
let idCounter = 0;
function genId() {
    idCounter++;
    return `id_${Date.now()}_${idCounter}_${Math.random().toString(36).slice(2, 8)}`;
}
function emptyState() {
    return {
        notebooks: [createNotebook('General')],
        notes: [],
        selectedNotebookId: null,
        selectedNoteId: null,
        sortOrder: 'modified',
        searchQuery: '',
        activeTagFilter: null,
        theme: 'light',
        paneState: {
            sidebarWidth: 240,
            notelistWidth: 280,
            sidebarCollapsed: false,
        },
    };
}
};

// ── module: src/store.ts ──
__mods["src/store.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initState = initState;
exports.getState = getState;
exports.setState = setState;
exports.scheduleSave = scheduleSave;
exports.saveImmediately = saveImmediately;
const types_1 = require("./types");
let state;
let saveTimeout = null;
function initState() {
    const loaded = loadState();
    state = loaded || (0, types_1.emptyState)();
    // Migrations
    if (!state.theme)
        state.theme = 'light';
    if (!state.paneState)
        state.paneState = { sidebarWidth: 240, notelistWidth: 280, sidebarCollapsed: false };
    // Ensure note notebookId defaults
    state.notes.forEach(n => { if (!n.notebookId)
        n.notebookId = state.notebooks[0]?.id || ''; });
    return state;
}
function getState() {
    return state;
}
function setState(s) {
    state = s;
    // Persist immediately for state mutations (delete, restore, etc.)
    // Editor input uses scheduleSave for debounce
    saveState();
}
function loadState() {
    try {
        const raw = localStorage.getItem(types_1.CONSTANTS.storageKey);
        if (!raw)
            return null;
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
function saveState() {
    try {
        localStorage.setItem(types_1.CONSTANTS.storageKey, JSON.stringify(state));
    }
    catch (e) {
        console.error('Failed to save state:', e);
    }
}
function scheduleSave(onSaved) {
    if (saveTimeout) {
        clearTimeout(saveTimeout);
    }
    if (onSaved) {
        // Store callback
        saveTimeout.__onSaved = onSaved;
    }
    saveTimeout = setTimeout(() => {
        saveState();
        const cb = saveTimeout.__onSaved;
        delete saveTimeout.__onSaved;
        if (cb)
            cb();
    }, types_1.CONSTANTS.autosaveDebounceMs);
}
function saveImmediately() {
    if (saveTimeout) {
        clearTimeout(saveTimeout);
    }
    saveState();
}
};

// ── module: src/utils.ts ──
__mods["src/utils.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stripHtml = stripHtml;
exports.getSnippet = getSnippet;
exports.sanitizeHtml = sanitizeHtml;
exports.searchNotes = searchNotes;
exports.filterByTag = filterByTag;
exports.sortNotes = sortNotes;
exports.formatTime = formatTime;
exports.getNotesForNotebook = getNotesForNotebook;
exports.countNotes = countNotes;
const types_1 = require("./types");
// Strip HTML tags to get plain text for search/snippets
function stripHtml(html) {
    const tmp = document.createElement('div');
    tmp.innerHTML = html;
    return tmp.textContent || tmp.innerText || '';
}
// Extract text snippet
function getSnippet(note) {
    const text = stripHtml(note.body);
    return text.length > types_1.CONSTANTS.snippetLength
        ? text.slice(0, types_1.CONSTANTS.snippetLength) + '…'
        : text;
}
// Sanitize HTML - remove scripts, event handlers, foreign markup
function sanitizeHtml(html) {
    const tmp = document.createElement('div');
    tmp.innerHTML = html;
    // Remove script and other dangerous elements
    const dangerous = tmp.querySelectorAll('script,style,link,meta,iframe,object,embed,form,button,input,textarea,select');
    dangerous.forEach(el => el.remove());
    // Remove event handlers from all elements
    const all = tmp.querySelectorAll('*');
    all.forEach(el => {
        const attrs = Array.from(el.attributes);
        attrs.forEach(attr => {
            if (attr.name.startsWith('on')) {
                el.removeAttribute(attr.name);
            }
        });
    });
    return tmp.innerHTML;
}
// Search in plain text content
function searchNotes(notes, query) {
    if (!query.trim())
        return notes;
    const q = query.toLowerCase();
    return notes.filter(n => {
        const title = n.title.toLowerCase();
        const text = stripHtml(n.body).toLowerCase();
        return title.includes(q) || text.includes(q);
    });
}
// Filter by tag
function filterByTag(notes, tag) {
    if (!tag)
        return notes;
    return notes.filter(n => n.tags.includes(tag));
}
// Sort notes
function sortNotes(notes, order) {
    const pinned = notes.filter(n => n.pinned);
    const rest = notes.filter(n => !n.pinned);
    const sortFn = (a, b) => {
        switch (order) {
            case 'modified':
                return b.updatedAt - a.updatedAt;
            case 'created':
                return b.createdAt - a.createdAt;
            case 'alphabetical':
                return a.title.localeCompare(b.title) || a.updatedAt - b.updatedAt;
            default:
                return 0;
        }
    };
    return [...pinned.sort(sortFn), ...rest.sort(sortFn)];
}
// Format timestamp
function formatTime(ts) {
    const d = new Date(ts);
    const now = new Date();
    const diff = now.getTime() - ts;
    if (diff < 60 * 1000)
        return 'Just now';
    if (diff < 60 * 60 * 1000)
        return `${Math.floor(diff / 60000)}m ago`;
    if (diff < 24 * 60 * 60 * 1000)
        return `${Math.floor(diff / 3600000)}h ago`;
    if (d.getMonth() === now.getMonth() && d.getFullYear() === now.getFullYear()) {
        return d.toLocaleDateString('en', { month: 'short', day: 'numeric' });
    }
    return d.toLocaleDateString('en', { month: 'short', day: 'numeric', year: 'numeric' });
}
// Get notes for a notebook
function getNotesForNotebook(state) {
    let notes;
    if (state.selectedNotebookId === 'trash') {
        notes = state.notes.filter(n => n.trashed);
    }
    else if (state.selectedNotebookId === null) {
        notes = state.notes.filter(n => !n.trashed);
    }
    else {
        notes = state.notes.filter(n => n.notebookId === state.selectedNotebookId && !n.trashed);
    }
    if (state.activeTagFilter) {
        notes = filterByTag(notes, state.activeTagFilter);
    }
    if (state.searchQuery.trim()) {
        notes = searchNotes(notes, state.searchQuery);
    }
    return sortNotes(notes, state.sortOrder);
}
// Count notes per notebook
function countNotes(notebookId, state) {
    if (notebookId === 'trash')
        return state.notes.filter(n => n.trashed).length;
    if (notebookId === null)
        return state.notes.filter(n => !n.trashed).length;
    return state.notes.filter(n => n.notebookId === notebookId && !n.trashed).length;
}
};

// ── module: src/sidebar.ts ──
__mods["src/sidebar.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderSidebar = renderSidebar;
const utils_1 = require("./utils");
function renderSidebar(state) {
    const pane = document.getElementById('sidebar-pane');
    let html = '';
    // Special sections: All Notes, Trash
    html += renderSpecialItem(state, null, '📋', 'All Notes');
    html += renderSpecialItem(state, 'trash', '🗑️', 'Trash');
    html += '<div class="sidebar-section" style="margin-top: 8px">';
    html += '<div class="sidebar-header"><h2>Notebooks</h2></div>';
    html += '<button class="sidebar-add-btn" data-action="add-notebook">+ New Notebook</button>';
    html += '</div>';
    // Notebook groups
    for (const nb of state.notebooks) {
        html += renderNotebookGroup(state, nb);
    }
    pane.innerHTML = html;
    bindSidebarEvents(state, pane);
}
function renderSpecialItem(state, id, icon, label) {
    const active = state.selectedNotebookId === id ? 'active' : '';
    const count = (0, utils_1.countNotes)(id, state);
    const countStr = count > 0 ? `<span class="count">${count}</span>` : '';
    return `<div class="sidebar-item ${active}" data-notebook-id="${id}">
    <span class="icon">${icon}</span>
    <span>${label}</span>
    ${countStr}
  </div>`;
}
function renderNotebookGroup(state, nb) {
    const active = state.selectedNotebookId === nb.id ? 'active' : '';
    const collapsed = nb.collapsed ? 'collapsed' : '';
    const count = (0, utils_1.countNotes)(nb.id, state);
    const chevronClass = nb.collapsed ? 'chevron collapsed' : 'chevron';
    let html = `<div class="notebook-group" data-notebook-id="${nb.id}">`;
    html += `<div class="notebook-header" data-toggle-notebook="${nb.id}">
    <span class="${chevronClass}">▼</span>
    <span class="sidebar-item ${active}" data-notebook-id="${nb.id}" style="flex:1">
      <span class="icon">📁</span>
      <span>${nb.name}</span>
      <span class="count">${count}</span>
    </span>
    <div class="actions">
      <button data-action="rename-notebook" data-notebook-id="${nb.id}" title="Rename">✎</button>
      <button data-action="delete-notebook" data-notebook-id="${nb.id}" title="Delete">✕</button>
    </div>
  </div>`;
    html += `<div class="notebook-notes ${collapsed}">`;
    html += `<button class="sidebar-add-btn" data-action="add-note" data-notebook-id="${nb.id}">+ New Note</button>`;
    html += '</div>';
    html += '</div>';
    return html;
}
function bindSidebarEvents(_state, pane) {
    // Notebook selection clicks
    pane.addEventListener('click', (e) => {
        const action = e.target.getAttribute('data-action');
        const notebookId = e.target.getAttribute('data-notebook-id');
        const toggleId = e.target.getAttribute('data-toggle-notebook');
        if (action === 'add-notebook') {
            dispatchCustomEvent('app-action', { action: 'add-notebook' });
            return;
        }
        if (action === 'add-note') {
            dispatchCustomEvent('app-action', { action: 'add-note', notebookId });
            return;
        }
        if (action === 'rename-notebook') {
            dispatchCustomEvent('app-action', { action: 'rename-notebook', notebookId });
            return;
        }
        if (action === 'delete-notebook') {
            dispatchCustomEvent('app-action', { action: 'delete-notebook', notebookId });
            return;
        }
        if (toggleId) {
            dispatchCustomEvent('app-action', { action: 'toggle-notebook', notebookId: toggleId });
            return;
        }
        if (notebookId !== null && !action) {
            dispatchCustomEvent('app-action', { action: 'select-notebook', notebookId });
        }
    });
    // Drag and drop for moving notes
    pane.addEventListener('dragover', (e) => {
        e.preventDefault();
        e.stopPropagation();
    });
    pane.addEventListener('drop', (e) => {
        e.preventDefault();
        e.stopPropagation();
        const notebookId = getClosestAttr(e.target, 'data-notebook-id');
        if (notebookId && notebookId !== 'trash') {
            const noteId = (e.dataTransfer?.getData('note-id') || '');
            if (noteId) {
                dispatchCustomEvent('app-action', { action: 'move-note', noteId, targetNotebookId: notebookId });
            }
        }
    });
}
function getClosestAttr(el, attr) {
    let current = el;
    while (current) {
        const val = current.getAttribute(attr);
        if (val !== null)
            return val;
        current = current.parentElement;
    }
    return null;
}
function dispatchCustomEvent(type, detail) {
    document.dispatchEvent(new CustomEvent(type, { detail }));
}
};

// ── module: src/notelist.ts ──
__mods["src/notelist.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderNoteList = renderNoteList;
const utils_1 = require("./utils");
function renderNoteList(state) {
    const pane = document.getElementById('notelist-pane');
    const notes = (0, utils_1.getNotesForNotebook)(state);
    const notebookName = getNotebookName(state);
    const tagFilterText = state.activeTagFilter
        ? `<span style="font-size:12px;color:var(--accent)">Filtering by: #${state.activeTagFilter}</span>`
        : '';
    pane.innerHTML = `
    <div class="notelist-header">
      <div>
        <h2>${notebookName}</h2>
        ${tagFilterText}
      </div>
      <div class="notelist-actions">
        ${state.selectedNotebookId !== 'trash' ? `<button data-action="add-note" title="New Note">+</button>` : ''}
        <button data-action="sort-toggle" title="Sort Order" class="${state.sortOrder}">${sortIcon(state.sortOrder)}</button>
      </div>
    </div>
    <div class="note-list" id="note-list">
      ${notes.length === 0 ? renderEmptyNoteList(state) : notes.map(n => renderNoteItem(n, state)).join('')}
    </div>
  `;
    bindNoteListEvents(state, pane);
}
function getNotebookName(state) {
    if (state.selectedNotebookId === null)
        return 'All Notes';
    if (state.selectedNotebookId === 'trash')
        return 'Trash';
    const nb = state.notebooks.find(n => n.id === state.selectedNotebookId);
    return nb ? nb.name : 'Unknown';
}
function sortIcon(order) {
    switch (order) {
        case 'modified': return '↕';
        case 'created': return '↑';
        case 'alphabetical': return 'A→Z';
        default: return '↕';
    }
}
function renderEmptyNoteList(state) {
    if (state.searchQuery.trim()) {
        return `<div style="padding:24px;text-align:center;color:var(--text-tertiary);font-size:13px">No notes match your search</div>`;
    }
    return `<div style="padding:24px;text-align:center;color:var(--text-tertiary);font-size:13px">No notes yet</div>`;
}
function renderNoteItem(note, state) {
    const active = state.selectedNoteId === note.id ? 'active' : '';
    const pinned = note.pinned ? 'pinned' : '';
    const snippet = (0, utils_1.getSnippet)(note) || (state.selectedNotebookId === 'trash' ? `Trashed ${(0, utils_1.formatTime)(note.trashedAt || 0)}` : 'Empty note');
    const time = (0, utils_1.formatTime)(state.selectedNotebookId === 'trash' && note.trashedAt ? note.trashedAt : note.updatedAt);
    const isTrash = state.selectedNotebookId === 'trash';
    const tagsHtml = note.tags.length > 0
        ? `<div class="note-item-tags">${note.tags.map(t => `<span class="note-item-tag ${state.activeTagFilter === t ? 'active' : ''}" data-tag="${t}">${t}</span>`).join('')}</div>`
        : '';
    return `<div class="note-item ${active} ${pinned}" data-note-id="${note.id}" draggable="${!isTrash}"
    data-note-id="${note.id}">
    <div class="note-item-title">${escapeHtml(note.title) || 'Untitled'}</div>
    <div class="note-item-snippet">${escapeHtml(snippet)}</div>
    <div class="note-item-meta">
      <span>${time}</span>
    </div>
    ${tagsHtml}
  </div>`;
}
function escapeHtml(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
}
function bindNoteListEvents(state, pane) {
    pane.addEventListener('click', (e) => {
        const actionEl = e.target.closest('[data-action]');
        const tagEl = e.target.closest('[data-tag]');
        const noteEl = e.target.closest('[data-note-id]');
        if (actionEl) {
            const action = actionEl.getAttribute('data-action');
            dispatchCustomEvent('app-action', { action });
            return;
        }
        if (tagEl) {
            const tag = tagEl.getAttribute('data-tag');
            if (state.activeTagFilter === tag) {
                dispatchCustomEvent('app-action', { action: 'clear-tag-filter' });
            }
            else {
                dispatchCustomEvent('app-action', { action: 'filter-tag', tag });
            }
            return;
        }
        if (noteEl) {
            const noteId = noteEl.getAttribute('data-note-id');
            dispatchCustomEvent('app-action', { action: 'select-note', noteId });
        }
    });
    // Right-click context menu
    const noteList = pane.querySelector('.note-list');
    if (noteList) {
        noteList.addEventListener('contextmenu', (e) => {
            const me = e;
            const noteEl = e.target.closest('.note-item');
            if (noteEl) {
                e.preventDefault();
                const noteId = noteEl.getAttribute('data-note-id');
                dispatchCustomEvent('note-context-menu', { noteId, x: me.clientX, y: me.clientY });
            }
        });
    }
    // Drag start
    pane.addEventListener('dragstart', (e) => {
        const noteItem = e.target.closest('.note-item');
        if (noteItem && noteItem.draggable) {
            const noteId = noteItem.getAttribute('data-note-id');
            e.dataTransfer?.setData('note-id', noteId);
            e.dataTransfer.effectAllowed = 'move';
        }
    });
    pane.addEventListener('dragend', (e) => {
        const noteItem = e.target.closest('.note-item');
        if (noteItem) {
            noteItem.style.opacity = '';
        }
    });
}
function dispatchCustomEvent(type, detail) {
    document.dispatchEvent(new CustomEvent(type, { detail }));
}
};

// ── module: src/editor.ts ──
__mods["src/editor.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setSaveCallback = setSaveCallback;
exports.setActiveNote = setActiveNote;
exports.initEditor = initEditor;
exports.setNote = setNote;
exports.handleMarkdownShortcut = handleMarkdownShortcut;
const utils_1 = require("./utils");
let saveCallback = null;
let titleSaveTimer = null;
let bodySaveTimer = null;
let _activeNote = null;
function setSaveCallback(cb) {
    saveCallback = cb;
}
function setActiveNote(note) {
    _activeNote = note;
}
function getActiveNote() {
    return _activeNote;
}
function onSave(updates) {
    if (!saveCallback)
        return;
    const note = getActiveNote();
    if (!note)
        return;
    saveCallback(note.id, updates);
}
function initEditor() {
    bindEditorEvents();
    buildToolbar();
}
function setNote(note) {
    const titleEl = document.getElementById('note-title');
    const bodyEl = document.getElementById('note-body');
    const contentEl = document.getElementById('editor-content');
    const emptyEl = document.getElementById('empty-state');
    const toolbarEl = document.getElementById('editor-toolbar');
    const tagsEl = document.getElementById('note-tags');
    if (!note) {
        contentEl.classList.remove('visible');
        toolbarEl.classList.remove('visible');
        emptyEl.classList.add('visible');
        emptyEl.classList.remove('hidden');
        return;
    }
    contentEl.classList.add('visible');
    toolbarEl.classList.add('visible');
    emptyEl.classList.remove('visible');
    emptyEl.classList.add('hidden');
    if (document.activeElement !== titleEl) {
        titleEl.textContent = note.title;
    }
    if (document.activeElement !== bodyEl) {
        bodyEl.innerHTML = note.body || '';
    }
    tagsEl.innerHTML = note.tags.map(t => `<span class="tag" data-tag="${t}">#${escapeHtml(t)}<button class="remove-tag" data-action="remove-tag" data-tag="${escapeHtml(t)}">×</button></span>`).join('') + `<button class="add-tag-btn" data-action="add-tag">+ tag</button>`;
    bindTagEvents(tagsEl);
}
function escapeHtml(s) {
    const d = document.createElement('div');
    d.textContent = s;
    return d.innerHTML;
}
function bindTagEvents(container) {
    container.addEventListener('click', (e) => {
        const removeBtn = e.target.closest('[data-action="remove-tag"]');
        if (removeBtn) {
            e.preventDefault();
            const tag = removeBtn.getAttribute('data-tag');
            const note = getActiveNote();
            if (note) {
                onSave({ tags: note.tags.filter(t => t !== tag) });
            }
            removeBtn.closest('.tag')?.remove();
            return;
        }
        const addBtn = e.target.closest('[data-action="add-tag"]');
        if (addBtn) {
            const tag = prompt('Enter tag name:');
            if (tag && tag.trim()) {
                const note = getActiveNote();
                if (note && !note.tags.includes(tag.trim())) {
                    onSave({ tags: [...note.tags, tag.trim()] });
                    const span = document.createElement('span');
                    span.className = 'tag';
                    span.dataset.tag = tag.trim();
                    span.innerHTML = `#${escapeHtml(tag.trim())}<button class="remove-tag" data-action="remove-tag" data-tag="${escapeHtml(tag.trim())}">×</button>`;
                    addBtn.before(span);
                }
            }
        }
    });
}
function bindEditorEvents() {
    const titleEl = document.getElementById('note-title');
    const bodyEl = document.getElementById('note-body');
    titleEl.addEventListener('input', () => {
        const note = getActiveNote();
        if (!note)
            return;
        if (titleSaveTimer)
            clearTimeout(titleSaveTimer);
        titleSaveTimer = setTimeout(() => {
            const val = titleEl.textContent || '';
            if (note.title !== val) {
                onSave({ title: val, updatedAt: Date.now() });
                showSaved();
            }
        }, 300);
    });
    bodyEl.addEventListener('input', () => {
        const note = getActiveNote();
        if (!note)
            return;
        if (bodySaveTimer)
            clearTimeout(bodySaveTimer);
        bodySaveTimer = setTimeout(() => {
            const val = bodyEl.innerHTML || '';
            if (note.body !== val) {
                onSave({ body: val, updatedAt: Date.now() });
                showSaved();
            }
        }, 300);
    });
    // Markdown shortcuts on keydown before default
    bodyEl.addEventListener('keydown', (e) => {
        // Handle markdown shortcuts (space key)
        if (handleMarkdownShortcut(e, bodyEl))
            return;
        // Ctrl/Cmd+B/I/U
        if ((e.ctrlKey || e.metaKey) && !e.altKey) {
            if (e.key === 'b') {
                e.preventDefault();
                document.execCommand('bold');
                updateToolbarState();
                return;
            }
            if (e.key === 'i') {
                e.preventDefault();
                document.execCommand('italic');
                updateToolbarState();
                return;
            }
            if (e.key === 'u') {
                e.preventDefault();
                document.execCommand('underline');
                updateToolbarState();
                return;
            }
        }
        if (e.key === 'Tab') {
            e.preventDefault();
            document.execCommand('insertText', false, '    ');
            return;
        }
        if (e.key === 'Enter' && !e.shiftKey) {
            handleEnterKey(e, bodyEl);
        }
    });
    // Paste sanitization
    bodyEl.addEventListener('paste', (e) => {
        e.preventDefault();
        const clipboardData = e.clipboardData;
        if (!clipboardData)
            return;
        let html = clipboardData.getData('text/html');
        if (html) {
            html = (0, utils_1.sanitizeHtml)(html);
            html = filterSupportedHtml(html);
            document.execCommand('insertHTML', false, html);
        }
        else {
            const text = clipboardData.getData('text/plain');
            document.execCommand('insertText', false, text);
        }
        updateToolbarState();
    });
    document.addEventListener('selectionchange', () => {
        if (document.activeElement === bodyEl || bodyEl.contains(document.activeElement)) {
            updateToolbarState();
        }
    });
}
function filterSupportedHtml(html) {
    const div = document.createElement('div');
    div.innerHTML = html;
    const unsupported = div.querySelectorAll('table,tbody,thead,tfoot,tr,td,th,svg,canvas,audio,video,map,area,figure,figcaption,details,summary,datalist,optgroup,option,dialog,fieldset,legend,picture,source,track,noscript,template,slot');
    unsupported.forEach(el => {
        el.replaceWith(document.createTextNode(el.textContent || ''));
    });
    return div.innerHTML;
}
function handleEnterKey(e, bodyEl) {
    const sel = window.getSelection();
    if (!sel || sel.rangeCount === 0)
        return;
    const node = sel.anchorNode;
    const element = node?.nodeType === Node.TEXT_NODE ? node.parentElement : node;
    if (!element)
        return;
    const li = element.closest('li');
    if (li) {
        const parentList = li.closest('ul,ol');
        if (parentList) {
            if (li.classList.contains('checklist-item')) {
                const contentSpan = li.querySelector('.check-content');
                const text = contentSpan?.textContent?.trim() || '';
                if (text === '' || text === '<br>') {
                    e.preventDefault();
                    li.remove();
                    if (parentList.children.length === 0) {
                        const p = document.createElement('p');
                        p.innerHTML = '<br>';
                        parentList.replaceWith(p);
                        const range = document.createRange();
                        range.setStart(p, 0);
                        range.collapse(true);
                        sel.removeAllRanges();
                        sel.addRange(range);
                    }
                    return;
                }
                e.preventDefault();
                insertChecklistItem(bodyEl);
                return;
            }
            // Regular list: if empty, exit
            const liText = li.textContent?.trim() || '';
            if (liText === '' || liText === '•' || liText === '-') {
                e.preventDefault();
                li.remove();
                if (parentList.children.length === 0) {
                    const p = document.createElement('p');
                    p.innerHTML = '<br>';
                    parentList.replaceWith(p);
                    const range = document.createRange();
                    range.setStart(p, 0);
                    range.collapse(true);
                    sel.removeAllRanges();
                    sel.addRange(range);
                }
                return;
            }
            // Browser handles list continuation by default
        }
    }
}
function insertChecklistItem(bodyEl) {
    const sel = window.getSelection();
    let ul = null;
    let currentLi = null;
    if (sel && sel.rangeCount > 0) {
        const anchorNode = sel.anchorNode;
        const anchorEl = anchorNode?.nodeType === Node.TEXT_NODE ? anchorNode.parentElement : anchorNode;
        if (anchorEl) {
            ul = anchorEl.closest('ul');
            currentLi = anchorEl?.closest('li') || null;
        }
    }
    const li = document.createElement('li');
    li.className = 'checklist-item';
    const checkbox = document.createElement('span');
    checkbox.className = 'check-box';
    checkbox.contentEditable = 'false';
    checkbox.addEventListener('click', () => {
        checkbox.classList.toggle('checked');
        li.classList.toggle('checked-item');
        // Trigger save
        const note = getActiveNote();
        if (note) {
            onSave({ body: bodyEl.innerHTML, updatedAt: Date.now() });
        }
    });
    const content = document.createElement('span');
    content.className = 'check-content';
    content.contentEditable = 'true';
    content.innerHTML = '';
    li.appendChild(checkbox);
    li.appendChild(content);
    if (ul) {
        if (currentLi) {
            ul.insertBefore(li, currentLi.nextSibling);
        }
        else {
            ul.appendChild(li);
        }
    }
    else {
        ul = document.createElement('ul');
        ul.style.listStyle = 'none';
        ul.appendChild(li);
        bodyEl.appendChild(ul);
    }
    // Also mark parent ul as checklist container
    if (ul && !ul.classList.contains('checklist')) {
        ul.classList.add('checklist');
        // Convert any sibling non-checklist lis
        ul.querySelectorAll('li:not(.checklist-item)').forEach(sibLi => {
            const newLi = document.createElement('li');
            newLi.className = 'checklist-item';
            const cb = document.createElement('span');
            cb.className = 'check-box';
            cb.contentEditable = 'false';
            cb.addEventListener('click', () => {
                cb.classList.toggle('checked');
                newLi.classList.toggle('checked-item');
                const note = getActiveNote();
                if (note)
                    onSave({ body: bodyEl.innerHTML, updatedAt: Date.now() });
            });
            const ct = document.createElement('span');
            ct.className = 'check-content';
            ct.contentEditable = 'true';
            ct.innerHTML = sibLi.innerHTML;
            newLi.appendChild(cb);
            newLi.appendChild(ct);
            sibLi.replaceWith(newLi);
        });
    }
    setTimeout(() => {
        content.focus();
        const range = document.createRange();
        range.setStart(content, 0);
        range.collapse(true);
        if (sel) {
            sel.removeAllRanges();
            sel.addRange(range);
        }
    }, 0);
}
function buildToolbar() {
    const toolbar = document.getElementById('editor-toolbar');
    const buttons = [
        { cmd: 'bold', icon: 'B', label: 'Bold', style: 'font-weight:700' },
        { cmd: 'italic', icon: 'I', label: 'Italic', style: 'font-style:italic' },
        { cmd: 'underline', icon: 'U', label: 'Underline', style: 'text-decoration:underline' },
        { cmd: 'strikeThrough', icon: 'S̶', label: 'Strikethrough', style: 'text-decoration:line-through' },
        { cmd: null, icon: '⟨⟩', label: 'Inline Code', action: 'code', style: '' },
    ];
    toolbar.innerHTML = `
    <div class="toolbar-group">
      ${buttons.map(b => `<button class="toolbar-btn" data-cmd="${b.cmd || ''}" data-action="${b.action || ''}" title="${b.label}" ${b.style ? `style="${b.style}"` : ''}>${b.icon}</button>`).join('')}
    </div>
    <div class="toolbar-group">
      <select class="toolbar-select" id="heading-select">
        <option value="p">Text</option>
        <option value="h1">H1</option>
        <option value="h2">H2</option>
        <option value="h3">H3</option>
      </select>
    </div>
    <div class="toolbar-group">
      <button class="toolbar-btn" data-cmd="insertUnorderedList" title="Bullet List">•≡</button>
      <button class="toolbar-btn" data-cmd="insertOrderedList" title="Numbered List">1.</button>
      <button class="toolbar-btn" data-action="checklist" title="Checklist">☑</button>
    </div>
    <div class="toolbar-group">
      <button class="toolbar-btn" data-action="blockquote" title="Blockquote">❝</button>
      <button class="toolbar-btn" data-cmd="insertHorizontalRule" title="Horizontal Rule">—</button>
    </div>
    <div class="toolbar-group">
      <button class="toolbar-btn" data-cmd="undo" title="Undo (Ctrl+Z)">↩</button>
      <button class="toolbar-btn" data-cmd="redo" title="Redo (Ctrl+Shift+Z)">↪</button>
    </div>
  `;
    toolbar.addEventListener('mousedown', (e) => {
        const btn = e.target.closest('.toolbar-btn');
        if (!btn)
            return;
        e.preventDefault();
        const cmd = btn.getAttribute('data-cmd');
        const action = btn.getAttribute('data-action');
        if (cmd) {
            document.execCommand(cmd, false, undefined);
            updateToolbarState();
            document.getElementById('note-body')?.focus();
        }
        if (action === 'code') {
            wrapSelection('code');
            updateToolbarState();
            document.getElementById('note-body')?.focus();
        }
        if (action === 'checklist') {
            const bodyEl = document.getElementById('note-body');
            insertChecklistItem(bodyEl);
        }
        if (action === 'blockquote') {
            const sel = window.getSelection();
            if (sel && sel.rangeCount > 0) {
                const anchorNode = sel.anchorNode;
                const block = findBlockElement(anchorNode);
                if (block && block.tagName === 'BLOCKQUOTE') {
                    unwrapElement(block);
                }
                else {
                    wrapSelection('blockquote');
                }
            }
            updateToolbarState();
            document.getElementById('note-body')?.focus();
        }
    });
    const headingSelect = toolbar.querySelector('#heading-select');
    headingSelect.addEventListener('change', () => {
        const val = headingSelect.value;
        document.execCommand('formatBlock', false, val);
        updateToolbarState();
    });
}
function findBlockElement(node) {
    if (!node)
        return null;
    let el = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
    while (el && el !== document.body) {
        const display = window.getComputedStyle(el).display;
        if (display === 'block' || display === 'list-item' || display === 'contents')
            return el;
        el = el.parentElement;
    }
    return null;
}
function unwrapElement(el) {
    const parent = el.parentElement;
    if (!parent)
        return;
    while (el.firstChild)
        parent.insertBefore(el.firstChild, el);
    el.remove();
}
function wrapSelection(tag) {
    const sel = window.getSelection();
    if (!sel || sel.rangeCount === 0)
        return;
    const range = sel.getRangeAt(0);
    if (range.collapsed)
        return;
    const el = document.createElement(tag);
    try {
        range.surroundContents(el);
    }
    catch {
        const html = `<${tag}>${range.toString()}</${tag}>`;
        document.execCommand('insertHTML', false, html);
    }
}
function updateToolbarState() {
    const toolbar = document.getElementById('editor-toolbar');
    const cmds = ['bold', 'italic', 'underline', 'strikeThrough'];
    cmds.forEach(cmd => {
        const btn = toolbar.querySelector(`[data-cmd="${cmd}"]`);
        if (btn)
            btn.classList.toggle('active', document.queryCommandState(cmd));
    });
    const headingSel = toolbar.querySelector('#heading-select');
    if (headingSel) {
        const blockFormat = document.queryCommandValue('formatBlock');
        const tag = blockFormat ? blockFormat.replace(/<(.*)>/, '$1').toLowerCase() : 'p';
        headingSel.value = tag === 'div' ? 'p' : tag;
    }
}
function showSaved() {
    let indicator = document.getElementById('saved-indicator');
    if (!indicator) {
        indicator = document.createElement('div');
        indicator.id = 'saved-indicator';
        indicator.className = 'saved-indicator';
        indicator.textContent = 'Saved';
        document.body.appendChild(indicator);
    }
    indicator.textContent = 'Saved';
    indicator.classList.add('visible');
    setTimeout(() => indicator.classList.remove('visible'), 1500);
}
// Markdown shortcut handler
function handleMarkdownShortcut(e, bodyEl) {
    if (e.key !== ' ')
        return false;
    const sel = window.getSelection();
    if (!sel || sel.rangeCount === 0)
        return false;
    const anchorNode = sel.anchorNode;
    if (!anchorNode || anchorNode.nodeType !== Node.TEXT_NODE)
        return false;
    const range = sel.getRangeAt(0);
    if (!range.collapsed)
        return false;
    const textNode = anchorNode;
    const cursorOffset = range.startOffset;
    const lineStart = findLineStart(textNode, cursorOffset);
    // Must be at start of a line
    if (lineStart !== 0 && textNode.textContent[lineStart - 1] !== '\n') {
        // Not at start of line — but actually we check if it's at the start of the text node
        // or after a newline
        if (lineStart !== 0) {
            // Check if there's a newline before
        }
    }
    const prefix = textNode.textContent?.slice(lineStart, cursorOffset) || '';
    let newBlock = null;
    if (prefix === '# ')
        newBlock = 'h1';
    else if (prefix === '## ')
        newBlock = 'h2';
    else if (prefix === '### ')
        newBlock = 'h3';
    else if (prefix === '- ' || prefix === '* ')
        newBlock = 'ul';
    else if (prefix === '1. ')
        newBlock = 'ol';
    else if (prefix === '> ')
        newBlock = 'blockquote';
    else if (prefix === '[] ' || prefix === '[ ]')
        newBlock = 'checklist';
    if (newBlock) {
        e.preventDefault();
        // Remove prefix
        const before = textNode.textContent?.slice(0, lineStart) || '';
        const after = textNode.textContent?.slice(cursorOffset) || '';
        textNode.textContent = before + after;
        const newRange = document.createRange();
        newRange.setStart(textNode, lineStart);
        newRange.collapse(true);
        sel.removeAllRanges();
        sel.addRange(newRange);
        if (newBlock === 'checklist') {
            insertChecklistItem(bodyEl);
        }
        else if (newBlock === 'ul') {
            document.execCommand('insertUnorderedList');
        }
        else if (newBlock === 'ol') {
            document.execCommand('insertOrderedList');
        }
        else if (newBlock === 'blockquote') {
            document.execCommand('formatBlock', false, 'blockquote');
        }
        else {
            document.execCommand('formatBlock', false, newBlock);
        }
        return true;
    }
    return false;
}
function findLineStart(textNode, offset) {
    const before = textNode.textContent?.slice(0, offset) || '';
    const lastNewline = before.lastIndexOf('\n');
    return lastNewline === -1 ? 0 : lastNewline + 1;
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"Qwen3.6-27B-MTP-GGUF","provider":"brigid","persona":"typescript","sessionId":"78ce5e96-e5cb-4173-ac46-7561e4e09ee7","tokensIn":4202274,"tokensOut":65430,"tokensTotal":4267704,"cost":0,"turns":81,"toolCalls":80,"failedToolCalls":2,"timestamp":"2026-08-02T05:55:35.803Z"} -->