← Notes results

Notes

thinkingcap qwen3.6 27b · 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 81,369 bytes · SHA-256 8b7bb220afa2
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Notes — Your Personal Knowledge Base</title>
<style>
/* ── css: layout ── */
/* ─── Reset & Base ───────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  overflow: hidden;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* ─── CSS Custom Properties (Light Theme) ────────────────────── */
.notes-app {
  --bg: #faf9f7;
  --surface: #ffffff;
  --surface-hover: #f5f4f1;
  --surface-active: #ebe9e4;
  --sidebar-bg: #f3f2ef;
  --border: #e8e6e1;
  --text: #2c2c2c;
  --text-secondary: #7a7a7a;
  --text-tertiary: #a0a0a0;
  --accent: #5b6abf;
  --accent-hover: #4d5aa8;
  --accent-light: rgba(91, 106, 191, 0.08);
  --danger: #c73e3e;
  --danger-hover: #b33535;
  --tag-bg: #edebe6;
  --tag-text: #5a5a5a;
  --editor-bg: #ffffff;
  --toolbar-bg: #faf9f7;
  --shadow: rgba(0, 0, 0, 0.06);
  --checkbox-checked: #5b6abf;
  --search-highlight: #fff3cd;
  --pin-color: #e8a42d;
}

.notes-app.dark {
  --bg: #1a1a1e;
  --surface: #242428;
  --surface-hover: #2c2c30;
  --surface-active: #353539;
  --sidebar-bg: #1e1e22;
  --border: #36363a;
  --text: #d4d4d8;
  --text-secondary: #8b8b90;
  --text-tertiary: #5c5c60;
  --accent: #7c8bd4;
  --accent-hover: #6a7ac2;
  --accent-light: rgba(124, 139, 212, 0.1);
  --danger: #d45555;
  --danger-hover: #c24444;
  --tag-bg: #333338;
  --tag-text: #a0a0a5;
  --editor-bg: #242428;
  --toolbar-bg: #1e1e22;
  --shadow: rgba(0, 0, 0, 0.2);
  --checkbox-checked: #7c8bd4;
  --search-highlight: #5a4f20;
  --pin-color: #d4a030;
}

/* ─── Three-Pane Layout ────────────────────────────────────── */
.notes-app {
  display: flex;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
}

#sidebar {
  width: var(--sidebar-width, 240px);
  min-width: 180px;
  max-width: 400px;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  transition: width 0.2s ease, min-width 0.2s ease, opacity 0.2s ease;
  overflow: hidden;
}

#sidebar.collapsed {
  width: 0 !important;
  min-width: 0 !important;
  border-right: none;
  opacity: 0;
  pointer-events: none;
}

#note-list-pane {
  width: var(--note-list-width, 300px);
  min-width: 220px;
  max-width: 500px;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#editor-pane {
  flex: 1;
  min-width: 300px;
  background: var(--editor-bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ─── Resize Handles ───────────────────────────────────────── */
.resize-handle {
  width: 4px;
  cursor: col-resize;
  background: transparent;
  transition: background 0.15s ease;
  flex-shrink: 0;
  z-index: 10;
}

.resize-handle:hover,
.resize-handle.active {
  background: var(--accent);
}

/* ─── Sidebar Header ───────────────────────────────────────── */
.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 16px 8px;
  flex-shrink: 0;
}

.app-title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
}

/* ─── Sidebar Footer ───────────────────────────────────────── */
.sidebar-footer {
  padding: 8px 12px 16px;
  flex-shrink: 0;
}

.btn-ghost {
  width: 100%;
  padding: 8px 12px;
  background: transparent;
  border: 1px dashed var(--border);
  border-radius: 6px;
  color: var(--text-secondary);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-ghost:hover {
  background: var(--surface-hover);
  color: var(--text);
  border-color: var(--accent);
}

/* ─── Notebook List ────────────────────────────────────────── */
#notebook-list {
  flex: 1;
  overflow-y: auto;
  padding: 4px 8px;
}

.notebook-item {
  display: flex;
  align-items: center;
  padding: 6px 10px;
  margin: 1px 0;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text-secondary);
  transition: all 0.12s ease;
  user-select: none;
}

.notebook-item:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.notebook-item.active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 500;
}

.notebook-icon {
  margin-right: 8px;
  font-size: 14px;
  flex-shrink: 0;
}

.notebook-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.notebook-count {
  font-size: 11px;
  color: var(--text-tertiary);
  margin-left: 6px;
  flex-shrink: 0;
}

.notebook-actions {
  display: none;
  gap: 2px;
  margin-left: 4px;
}

.notebook-item:hover .notebook-actions {
  display: flex;
}

.notebook-action-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px 4px;
  font-size: 12px;
  color: var(--text-tertiary);
  border-radius: 3px;
}

.notebook-action-btn:hover {
  background: var(--surface-active);
  color: var(--text);
}

/* ─── Note List Header ────────────────────────────────────── */
.note-list-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 16px 8px;
  flex-shrink: 0;
}

.note-list-header h2 {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.note-list-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}

#search-input {
  width: 120px;
  padding: 5px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-hover);
  color: var(--text);
  font-size: 12px;
  outline: none;
  transition: all 0.15s ease;
}

#search-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-light);
}

/* ─── Note List ────────────────────────────────────────────── */
#note-list {
  flex: 1;
  overflow-y: auto;
  padding: 4px 8px 16px;
}

.note-item {
  display: flex;
  flex-direction: column;
  padding: 10px 12px;
  margin: 2px 0;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.12s ease;
  position: relative;
}

.note-item:hover {
  background: var(--surface-hover);
}

.note-item.active {
  background: var(--accent-light);
}

.note-item-header {
  display: flex;
  align-items: center;
  gap: 6px;
}

.note-pin-indicator {
  font-size: 10px;
  color: var(--pin-color);
  flex-shrink: 0;
}

.note-title {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

.note-item.active .note-title {
  color: var(--accent);
}

.note-snippet {
  font-size: 12px;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 3px;
  padding-left: 16px;
}

.note-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding-left: 16px;
}

.note-date {
  font-size: 11px;
  color: var(--text-tertiary);
}

.note-tags {
  display: flex;
  gap: 3px;
  flex-wrap: wrap;
}

.note-tag {
  font-size: 10px;
  padding: 1px 6px;
  background: var(--tag-bg);
  color: var(--tag-text);
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.1s ease;
}

.note-tag:hover {
  background: var(--accent-light);
  color: var(--accent);
}

/* ─── Icon Buttons ────────────────────────────────────────── */
.icon-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px 6px;
  font-size: 14px;
  color: var(--text-secondary);
  border-radius: 5px;
  transition: all 0.12s ease;
  line-height: 1;
}

.icon-btn:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.icon-btn.danger:hover {
  background: rgba(199, 62, 62, 0.1);
  color: var(--danger);
}

/* ─── Editor Header ────────────────────────────────────────── */
.editor-header {
  display: flex;
  align-items: center;
  padding: 16px 32px 8px;
  gap: 12px;
  flex-shrink: 0;
}

#note-title-input {
  flex: 1;
  font-size: 24px;
  font-weight: 700;
  border: none;
  background: transparent;
  color: var(--text);
  outline: none;
  font-family: inherit;
  letter-spacing: -0.02em;
}

#note-title-input::placeholder {
  color: var(--text-tertiary);
}

.editor-actions {
  display: flex;
  align-items: center;
  gap: 2px;
}

/* ─── Toolbar ──────────────────────────────────────────────── */
.toolbar {
  display: flex;
  align-items: center;
  padding: 4px 32px;
  gap: 1px;
  border-bottom: 1px solid var(--border);
  background: var(--toolbar-bg);
  flex-shrink: 0;
  flex-wrap: wrap;
}

.toolbar-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 5px 8px;
  font-size: 13px;
  color: var(--text-secondary);
  border-radius: 4px;
  transition: all 0.1s ease;
  font-weight: 500;
  min-width: 28px;
  text-align: center;
}

.toolbar-btn:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.toolbar-btn.active {
  background: var(--accent-light);
  color: var(--accent);
}

.toolbar-separator {
  width: 1px;
  height: 20px;
  background: var(--border);
  margin: 0 4px;
}

/* ─── Editor ──────────────────────────────────────────────── */
#editor {
  flex: 1;
  padding: 24px 32px 64px;
  overflow-y: auto;
  outline: none;
  font-family: Georgia, 'Liberation Serif', 'Times New Roman', serif;
  font-size: 15.5px;
  line-height: 1.75;
  color: var(--text);
}

#editor:empty::before {
  content: "Start writing…";
  color: var(--text-tertiary);
  pointer-events: none;
}

#editor h1 { font-size: 2em; font-weight: 700; margin: 0.6em 0 0.3em; letter-spacing: -0.02em; }
#editor h2 { font-size: 1.5em; font-weight: 600; margin: 0.5em 0 0.25em; }
#editor h3 { font-size: 1.25em; font-weight: 600; margin: 0.4em 0 0.2em; }
#editor blockquote {
  border-left: 3px solid var(--accent);
  padding-left: 16px;
  margin: 8px 0;
  color: var(--text-secondary);
  font-style: italic;
}
#editor code {
  background: var(--surface-hover);
  padding: 2px 5px;
  border-radius: 3px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.9em;
}
#editor hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 16px 0;
}

/* Checklist items */
.checklist-item {
  list-style: none;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 2px 0;
}

.checklist-checkbox {
  width: 16px;
  height: 16px;
  border: 2px solid var(--border);
  border-radius: 3px;
  cursor: pointer;
  flex-shrink: 0;
  margin-top: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.1s ease;
}

.checklist-checkbox.checked {
  background: var(--checkbox-checked);
  border-color: var(--checkbox-checked);
}

.checklist-checkbox.checked::after {
  content: "✓";
  color: white;
  font-size: 10px;
  font-weight: bold;
}

/* ─── Empty State ──────────────────────────────────────────── */
.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  gap: 12px;
}

.empty-state svg {
  opacity: 0.3;
}

.empty-state p {
  font-size: 15px;
}

/* ─── Saved Indicator ──────────────────────────────────────── */
.saved-indicator {
  position: fixed;
  bottom: 20px;
  right: 24px;
  padding: 6px 14px;
  background: var(--accent);
  color: white;
  font-size: 12px;
  border-radius: 20px;
  opacity: 0;
  transform: translateY(8px);
  transition: all 0.3s ease;
  pointer-events: none;
  z-index: 100;
}

.saved-indicator.show {
  opacity: 1;
  transform: translateY(0);
}

/* ─── Dropdown ────────────────────────────────────────────── */
.dropdown {
  position: fixed;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 4px 20px var(--shadow);
  padding: 6px;
  z-index: 50;
  min-width: 160px;
}

.dropdown-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
  padding: 4px 8px 6px;
  font-weight: 600;
}

.dropdown-item {
  padding: 7px 10px;
  font-size: 13px;
  cursor: pointer;
  border-radius: 5px;
  color: var(--text);
  transition: all 0.1s ease;
}

.dropdown-item:hover {
  background: var(--surface-hover);
}

/* ─── Utility ──────────────────────────────────────────────── */
.hidden { display: none !important; }

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

/* ─── Search Highlight ────────────────────────────────────── */
mark.search-match {
  background: var(--search-highlight);
  color: inherit;
  padding: 0 1px;
  border-radius: 2px;
}

/* ─── Tag Input Area ──────────────────────────────────────── */
#tag-display {
  display: flex;
  gap: 4px;
  align-items: center;
  margin-right: 8px;
}

.tag-pill {
  font-size: 11px;
  padding: 2px 8px;
  background: var(--tag-bg);
  color: var(--tag-text);
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 4px;
}

.tag-pill .remove-tag {
  cursor: pointer;
  font-size: 12px;
  opacity: 0.6;
}

.tag-pill .remove-tag:hover {
  opacity: 1;
}

/* ─── Trash-specific styles ──────────────────────────────── */
.trash-actions {
  display: flex;
  gap: 4px;
  margin-top: 4px;
  padding-left: 16px;
}

.trash-btn {
  font-size: 11px;
  padding: 2px 8px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.1s ease;
}

.restore-btn {
  background: var(--accent-light);
  color: var(--accent);
}

.permanent-delete-btn {
  background: rgba(199, 62, 62, 0.1);
  color: var(--danger);
}

/* ─── Sidebar collapse toggle ────────────────────────────── */
#collapse-sidebar-btn {
  display: none;
  position: fixed;
  top: 12px;
  left: 8px;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 8px;
  cursor: pointer;
  font-size: 14px;
  color: var(--text-secondary);
}

#collapse-sidebar-btn:hover {
  background: var(--surface-hover);
}

.sidebar-collapsed-show #collapse-sidebar-btn {
  display: block;
}

/* ─── Rename input inline ────────────────────────────────── */
.notebook-rename-input {
  font-size: 13px;
  border: 1px solid var(--accent);
  border-radius: 4px;
  padding: 2px 6px;
  background: var(--surface);
  color: var(--text);
  outline: none;
  flex: 1;
}

/* ─── Sort indicator ────────────────────────────────────── */
.sort-label {
  font-size: 10px;
  color: var(--text-tertiary);
  padding: 2px 6px;
  border-radius: 3px;
  background: var(--surface-hover);
}

/* ─── Empty note list state ──────────────────────────────── */
.note-list-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
  color: var(--text-tertiary);
  font-size: 13px;
  text-align: center;
  gap: 8px;
}

.note-list-empty .empty-icon {
  font-size: 28px;
  opacity: 0.4;
}
</style>
</head>
<body>
<div id="app" class="notes-app">
  <!-- Sidebar -->
  <aside id="sidebar">
    <div class="sidebar-header">
      <span class="app-title">Notes</span>
      <button id="theme-toggle" class="icon-btn" title="Toggle theme" aria-label="Toggle theme">🌙</button>
    </div>
    <nav id="notebook-list"></nav>
    <div class="sidebar-footer">
      <button id="new-notebook-btn" class="btn-ghost">+ New Notebook</button>
    </div>
  </aside>
  
  <!-- Note List -->
  <section id="note-list-pane">
    <div class="note-list-header">
      <h2 id="note-list-title">All Notes</h2>
      <div class="note-list-actions">
        <button id="sort-toggle" class="icon-btn" title="Sort order" aria-label="Toggle sort order">↕</button>
        <input type="text" id="search-input" placeholder="Search notes…" aria-label="Search notes">
      </div>
    </div>
    <div id="note-list"></div>
  </section>
  
  <!-- Editor -->
  <main id="editor-pane">
    <div id="empty-state" class="empty-state">
      <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line></svg>
      <p>Select or create a note</p>
    </div>
    <div id="editor-container" class="hidden">
      <div class="editor-header">
        <input type="text" id="note-title-input" placeholder="Note title…" aria-label="Note title">
        <div class="editor-actions">
          <span id="tag-display"></span>
          <button id="add-tag-btn" class="icon-btn" title="Add tag" aria-label="Add tag">🏷</button>
          <button id="pin-note-btn" class="icon-btn" title="Pin note" aria-label="Toggle pin">📌</button>
          <button id="move-note-btn" class="icon-btn" title="Move to notebook" aria-label="Move note">↗</button>
          <button id="duplicate-note-btn" class="icon-btn" title="Duplicate" aria-label="Duplicate note">⧉</button>
          <button id="delete-note-btn" class="icon-btn danger" title="Delete" aria-label="Delete note">🗑</button>
        </div>
      </div>
      <div id="toolbar" class="toolbar"></div>
      <div id="editor" contenteditable="true" spellcheck="true" role="textbox" aria-multiline="true"></div>
    </div>
  </main>
  
  <!-- Resize handles -->
  <div id="resize-handle-1" class="resize-handle"></div>
  <div id="resize-handle-2" class="resize-handle"></div>
</div>

<!-- Move note dropdown -->
<div id="move-dropdown" class="dropdown hidden">
  <div class="dropdown-title">Move to…</div>
  <div id="move-notebook-list"></div>
</div>

<!-- Saved indicator -->
<div id="saved-indicator" class="saved-indicator">Saved</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./ui":"src/ui.ts"},"src/state.ts":{"./constants":"src/constants.ts","./types":"src/types.ts"},"src/editor.ts":{"./constants":"src/constants.ts","./types":"src/types.ts"},"src/ui.ts":{"./constants":"src/constants.ts","./state":"src/state.ts","./editor":"src/editor.ts","./types":"src/types.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";
// ─── Entry Point ──────────────────────────────────────────────
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const UI = __importStar(require("./ui"));
function start() {
    // Create collapse sidebar button dynamically
    const app = document.getElementById("app");
    if (app) {
        const btn = document.createElement("button");
        btn.id = "collapse-sidebar-btn";
        btn.className = "icon-btn";
        btn.textContent = "☰";
        btn.title = "Show sidebar";
        app.appendChild(btn);
    }
    // Initialize the UI
    UI.initUI();
}
start();
};

// ── module: src/constants.ts ──
__mods["src/constants.ts"] = function (exports, require, module) {
"use strict";
// ─── Tunable Constants ───────────────────────────────────────────────
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateId = exports.DEFAULT_NOTEBOOKS = exports.ALLOWED_ATTRS = exports.ALLOWED_TAGS = exports.THEME_KEY = exports.LAYOUT_KEY = exports.STORAGE_KEY = exports.SNIPPET_LENGTH = exports.AUTOSAVE_DEBOUNCE = exports.FONTS = exports.COLORS = exports.APP_NAME = void 0;
exports.APP_NAME = "Notes";
exports.COLORS = {
    light: {
        bg: "#faf9f7",
        surface: "#ffffff",
        surfaceHover: "#f5f4f1",
        surfaceActive: "#ebe9e4",
        sidebarBg: "#f3f2ef",
        border: "#e8e6e1",
        text: "#2c2c2c",
        textSecondary: "#7a7a7a",
        textTertiary: "#a0a0a0",
        accent: "#5b6abf",
        accentHover: "#4d5aa8",
        accentLight: "rgba(91, 106, 191, 0.08)",
        danger: "#c73e3e",
        dangerHover: "#b33535",
        tagBg: "#edebe6",
        tagText: "#5a5a5a",
        editorBg: "#ffffff",
        toolbarBg: "#faf9f7",
        shadow: "rgba(0, 0, 0, 0.06)",
        checkboxChecked: "#5b6abf",
        searchHighlight: "#fff3cd",
        pinColor: "#e8a42d",
    },
    dark: {
        bg: "#1a1a1e",
        surface: "#242428",
        surfaceHover: "#2c2c30",
        surfaceActive: "#353539",
        sidebarBg: "#1e1e22",
        border: "#36363a",
        text: "#d4d4d8",
        textSecondary: "#8b8b90",
        textTertiary: "#5c5c60",
        accent: "#7c8bd4",
        accentHover: "#6a7ac2",
        accentLight: "rgba(124, 139, 212, 0.1)",
        danger: "#d45555",
        dangerHover: "#c24444",
        tagBg: "#333338",
        tagText: "#a0a0a5",
        editorBg: "#242428",
        toolbarBg: "#1e1e22",
        shadow: "rgba(0, 0, 0, 0.2)",
        checkboxChecked: "#7c8bd4",
        searchHighlight: "#5a4f20",
        pinColor: "#d4a030",
    },
};
exports.FONTS = {
    ui: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
    editor: "'Georgia', 'Liberation Serif', 'Times New Roman', serif",
    mono: "'JetBrains Mono', 'Fira Code', monospace",
};
exports.AUTOSAVE_DEBOUNCE = 500;
exports.SNIPPET_LENGTH = 80;
exports.STORAGE_KEY = "notes-app-data";
exports.LAYOUT_KEY = "notes-app-layout";
exports.THEME_KEY = "notes-app-theme";
// Allowed HTML tags for sanitization
exports.ALLOWED_TAGS = [
    "p", "br", "strong", "b", "em", "i", "u", "s", "del", "strike",
    "code", "pre", "blockquote", "hr",
    "h1", "h2", "h3", "h4", "h5", "h6",
    "ul", "ol", "li",
    "div", "span",
];
exports.ALLOWED_ATTRS = [
    "style", "class", "data-checked", "checked",
];
// Default notebooks on first load
exports.DEFAULT_NOTEBOOKS = [
    { id: genId(), name: "Personal" },
    { id: genId(), name: "Work" },
    { id: genId(), name: "Ideas" },
];
function genId() {
    return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
}
// Export for use in other modules
exports.generateId = genId;
};

// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
// ─── Data Model Types ──────────────────────────────────────────────
Object.defineProperty(exports, "__esModule", { value: true });
};

// ── module: src/state.ts ──
__mods["src/state.ts"] = function (exports, require, module) {
"use strict";
// ─── State Management & Persistence ────────────────────────────────
Object.defineProperty(exports, "__esModule", { value: true });
exports.getState = getState;
exports.getLayout = getLayout;
exports.getTheme = getTheme;
exports.setSortMode = setSortMode;
exports.setSearchQuery = setSearchQuery;
exports.setTagFilter = setTagFilter;
exports.addNotebook = addNotebook;
exports.renameNotebook = renameNotebook;
exports.deleteNotebook = deleteNotebook;
exports.toggleNotebookCollapsed = toggleNotebookCollapsed;
exports.createNote = createNote;
exports.updateNote = updateNote;
exports.deleteNote = deleteNote;
exports.restoreNote = restoreNote;
exports.permanentlyDeleteNote = permanentlyDeleteNote;
exports.duplicateNote = duplicateNote;
exports.togglePin = togglePin;
exports.moveNote = moveNote;
exports.addTag = addTag;
exports.removeTag = removeTag;
exports.setActiveNotebook = setActiveNotebook;
exports.setActiveNote = setActiveNote;
exports.setSidebarWidth = setSidebarWidth;
exports.setNoteListWidth = setNoteListWidth;
exports.toggleSidebar = toggleSidebar;
exports.toggleTheme = toggleTheme;
exports.getFilteredNotes = getFilteredNotes;
exports.getNoteCountForNotebook = getNoteCountForNotebook;
exports.extractTextFromHtml = extractTextFromHtml;
exports.getSnippet = getSnippet;
exports.getActiveNote = getActiveNote;
const constants_1 = require("./constants");
const defaultNotebooks = JSON.parse(JSON.stringify(constants_1.DEFAULT_NOTEBOOKS));
function createDefaultState() {
    return {
        notebooks: defaultNotebooks,
        notes: [],
        activeNotebookId: defaultNotebooks[0]?.id ?? null,
        activeNoteId: null,
        sortMode: "modified",
        searchQuery: "",
        tagFilter: null,
    };
}
function createDefaultLayout() {
    return {
        sidebarWidth: 240,
        noteListWidth: 300,
        sidebarCollapsed: false,
    };
}
// ─── State ──────────────────────────────────────────────────────
let state = loadState();
let layout = loadLayout();
let theme = loadTheme();
function loadState() {
    try {
        const raw = localStorage.getItem(constants_1.STORAGE_KEY);
        if (raw) {
            const parsed = JSON.parse(raw);
            // Validate structure
            if (parsed && Array.isArray(parsed.notebooks) && Array.isArray(parsed.notes)) {
                return { ...createDefaultState(), ...parsed };
            }
        }
    }
    catch { /* ignore */ }
    return createDefaultState();
}
function loadLayout() {
    try {
        const raw = localStorage.getItem(constants_1.LAYOUT_KEY);
        if (raw) {
            const parsed = JSON.parse(raw);
            if (parsed && typeof parsed.sidebarWidth === "number") {
                return { ...createDefaultLayout(), ...parsed };
            }
        }
    }
    catch { /* ignore */ }
    return createDefaultLayout();
}
function loadTheme() {
    try {
        const raw = localStorage.getItem(constants_1.THEME_KEY);
        if (raw === "dark")
            return "dark";
        if (raw === "light")
            return "light";
    }
    catch { /* ignore */ }
    // Check system preference
    if (window.matchMedia?.("(prefers-color-scheme: dark)").matches)
        return "dark";
    return "light";
}
function saveState() {
    try {
        localStorage.setItem(constants_1.STORAGE_KEY, JSON.stringify(state));
    }
    catch { /* storage full */ }
}
function saveLayout() {
    try {
        localStorage.setItem(constants_1.LAYOUT_KEY, JSON.stringify(layout));
    }
    catch { /* ignore */ }
}
function saveTheme() {
    try {
        localStorage.setItem(constants_1.THEME_KEY, theme);
    }
    catch { /* ignore */ }
}
// ─── Actions ──────────────────────────────────────────────────────
function getState() { return state; }
function getLayout() { return layout; }
function getTheme() { return theme; }
function setSortMode(mode) {
    state.sortMode = mode;
}
function setSearchQuery(q) {
    state.searchQuery = q;
}
function setTagFilter(tag) {
    state.tagFilter = tag;
}
// Notebooks
function addNotebook(name) {
    const nb = { id: (0, constants_1.generateId)(), name };
    state.notebooks.push(nb);
    saveState();
    return nb;
}
function renameNotebook(id, name) {
    const nb = state.notebooks.find(n => n.id === id);
    if (nb) {
        nb.name = name;
        saveState();
    }
}
function deleteNotebook(id) {
    // Move notes to no notebook (or trash)
    state.notes.forEach(n => {
        if (n.notebookId === id)
            n.notebookId = null;
    });
    state.notebooks = state.notebooks.filter(n => n.id !== id);
    if (state.activeNotebookId === id)
        state.activeNotebookId = state.notebooks[0]?.id ?? null;
    saveState();
}
function toggleNotebookCollapsed(id) {
    const nb = state.notebooks.find(n => n.id === id);
    if (nb)
        nb.collapsed = !nb.collapsed;
    saveState();
}
// Notes
function createNote(notebookId, title) {
    const note = {
        id: (0, constants_1.generateId)(),
        notebookId,
        title: title || "",
        content: "",
        tags: [],
        pinned: false,
        createdAt: Date.now(),
        updatedAt: Date.now(),
    };
    state.notes.push(note);
    saveState();
    return note;
}
function updateNote(id, updates) {
    const note = state.notes.find(n => n.id === id);
    if (note) {
        Object.assign(note, updates, { updatedAt: Date.now() });
        saveState();
    }
}
function deleteNote(id) {
    const note = state.notes.find(n => n.id === id);
    if (note && note.notebookId !== null) {
        note.notebookId = null; // Move to trash
        note.updatedAt = Date.now();
        saveState();
    }
}
function restoreNote(id) {
    const note = state.notes.find(n => n.id === id);
    if (note) {
        // Restore to first available notebook
        note.notebookId = state.notebooks[0]?.id ?? null;
        note.updatedAt = Date.now();
        saveState();
    }
}
function permanentlyDeleteNote(id) {
    state.notes = state.notes.filter(n => n.id !== id);
    if (state.activeNoteId === id)
        state.activeNoteId = null;
    saveState();
}
function duplicateNote(id) {
    const note = state.notes.find(n => n.id === id);
    if (!note)
        return;
    const dup = {
        ...JSON.parse(JSON.stringify(note)),
        id: (0, constants_1.generateId)(),
        title: note.title + " (copy)",
        createdAt: Date.now(),
        updatedAt: Date.now(),
    };
    state.notes.push(dup);
    saveState();
    return dup;
}
function togglePin(id) {
    const note = state.notes.find(n => n.id === id);
    if (note) {
        note.pinned = !note.pinned;
        note.updatedAt = Date.now();
        saveState();
    }
}
function moveNote(noteId, targetNotebookId) {
    const note = state.notes.find(n => n.id === noteId);
    if (note) {
        note.notebookId = targetNotebookId;
        note.updatedAt = Date.now();
        saveState();
    }
}
function addTag(noteId, tag) {
    const note = state.notes.find(n => n.id === noteId);
    if (note && !note.tags.includes(tag)) {
        note.tags.push(tag);
        note.updatedAt = Date.now();
        saveState();
    }
}
function removeTag(noteId, tag) {
    const note = state.notes.find(n => n.id === noteId);
    if (note) {
        note.tags = note.tags.filter(t => t !== tag);
        note.updatedAt = Date.now();
        saveState();
    }
}
// Selection
function setActiveNotebook(id) {
    state.activeNotebookId = id;
    if (id === "trash") {
        // Don't auto-select a note in trash
    }
    else {
        state.activeNoteId = null;
    }
}
function setActiveNote(id) {
    state.activeNoteId = id;
}
// Layout
function setSidebarWidth(w) { layout.sidebarWidth = w; saveLayout(); }
function setNoteListWidth(w) { layout.noteListWidth = w; saveLayout(); }
function toggleSidebar() {
    layout.sidebarCollapsed = !layout.sidebarCollapsed;
    saveLayout();
}
// Theme
function toggleTheme() {
    theme = theme === "light" ? "dark" : "light";
    saveTheme();
    return theme;
}
// Get filtered/sorted notes for display
function getFilteredNotes() {
    let notes = state.notes;
    const activeNb = state.activeNotebookId;
    // Filter by notebook
    if (activeNb === "trash") {
        notes = notes.filter(n => n.notebookId === null);
    }
    else if (activeNb !== null) {
        notes = notes.filter(n => n.notebookId === activeNb);
    }
    // Filter by tag
    const tagF = state.tagFilter;
    if (tagF) {
        notes = notes.filter(n => n.tags.includes(tagF));
    }
    // Search filter
    if (state.searchQuery.trim()) {
        const q = state.searchQuery.toLowerCase();
        notes = notes.filter(n => {
            if (n.title.toLowerCase().includes(q))
                return true;
            // Extract text from HTML content for search
            const textContent = extractTextFromHtml(n.content);
            return textContent.toLowerCase().includes(q);
        });
    }
    // Sort: pinned first, then by sort mode
    notes.sort((a, b) => {
        if (a.pinned !== b.pinned)
            return a.pinned ? -1 : 1;
        switch (state.sortMode) {
            case "modified": return b.updatedAt - a.updatedAt;
            case "created": return b.createdAt - a.createdAt;
            case "alphabetical": return a.title.localeCompare(b.title);
            default: return 0;
        }
    });
    return notes;
}
function getNoteCountForNotebook(notebookId) {
    if (notebookId === "trash")
        return state.notes.filter(n => n.notebookId === null).length;
    const nbId = notebookId;
    return state.notes.filter(n => n.notebookId === nbId).length;
}
// Pure text extraction from HTML — used for search and snippets
function extractTextFromHtml(html) {
    if (!html)
        return "";
    const div = document.createElement("div");
    div.innerHTML = html;
    return (div.textContent || div.innerText || "").trim();
}
// Get snippet preview text
function getSnippet(note, len = 80) {
    const text = extractTextFromHtml(note.content);
    if (!text)
        return "Empty note";
    return text.length > len ? text.slice(0, len) + "…" : text;
}
// Get active note
function getActiveNote() {
    if (!state.activeNoteId)
        return undefined;
    return state.notes.find(n => n.id === state.activeNoteId);
}
};

// ── module: src/editor.ts ──
__mods["src/editor.ts"] = function (exports, require, module) {
"use strict";
// ─── Rich Text Editor Module ──────────────────────────────────────
Object.defineProperty(exports, "__esModule", { value: true });
exports.initEditor = initEditor;
exports.setOnSave = setOnSave;
exports.setOnTitleChange = setOnTitleChange;
exports.loadNote = loadNote;
exports.sanitizeHtml = sanitizeHtml;
exports.updateToolbarState = updateToolbarState;
exports.createToolbar = createToolbar;
exports.setupTitleInput = setupTitleInput;
exports.getEditorContent = getEditorContent;
const constants_1 = require("./constants");
let editorEl = null;
let onSaveCallback = null;
let onTitleChangeCallback = null;
// ─── Initialization ──────────────────────────────────────────
function initEditor(editorElement, titleInput) {
    editorEl = editorElement;
    // Setup paste sanitization
    editorEl.addEventListener("paste", handlePaste);
    // Setup keyboard shortcuts
    editorEl.addEventListener("keydown", handleKeyDown);
    // Setup input event for toolbar state updates
    editorEl.addEventListener("input", onEditorInput);
    editorEl.addEventListener("mouseup", updateToolbarState);
    editorEl.addEventListener("keyup", updateToolbarState);
    // Focus management
    editorEl.addEventListener("focus", () => {
        document.execCommand("styleWithCSS", false, "true");
    });
}
function setOnSave(cb) { onSaveCallback = cb; }
function setOnTitleChange(cb) { onTitleChangeCallback = cb; }
// ─── Content Loading ──────────────────────────────────────────
function loadNote(note) {
    if (!editorEl || !note)
        return;
    // Save current content before switching
    saveCurrentContent();
    editorEl.innerHTML = note.content ?? "";
    // Restore checklist checkbox states from data attributes
    restoreCheckboxes(editorEl);
}
function saveCurrentContent() {
    if (!editorEl || !onSaveCallback)
        return;
    onSaveCallback(editorEl.innerHTML);
}
// ─── Paste Sanitization ──────────────────────────────────────
function handlePaste(e) {
    e.preventDefault();
    const html = e.clipboardData?.getData("text/html");
    const text = e.clipboardData?.getData("text/plain");
    if (html) {
        const sanitized = sanitizeHtml(html);
        document.execCommand("insertHTML", false, sanitized);
    }
    else if (text) {
        // Insert plain text with current formatting context
        document.execCommand("insertText", false, text);
    }
}
function sanitizeHtml(html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, "text/html");
    for (const node of Array.from(doc.body.querySelectorAll("*"))) {
        const tag = node.tagName.toLowerCase();
        // Remove script tags and their content entirely
        if (tag === "script" || tag === "style" || tag === "link" || tag === "meta") {
            node.remove();
            continue;
        }
        // Remove disallowed tags but keep their text content
        if (!constants_1.ALLOWED_TAGS.includes(tag)) {
            const fragment = document.createDocumentFragment();
            while (node.firstChild) {
                fragment.appendChild(node.firstChild);
            }
            node.parentNode?.replaceChild(fragment, node);
            continue;
        }
        // Remove disallowed attributes
        for (const attr of Array.from(node.attributes)) {
            if (!constants_1.ALLOWED_ATTRS.includes(attr.name.toLowerCase())) {
                node.removeAttribute(attr.name);
            }
        }
    }
    return doc.body.innerHTML;
}
// ─── Keyboard Handling ──────────────────────────────────────
function handleKeyDown(e) {
    if (!editorEl)
        return;
    // Ctrl/Cmd + B/I/U for formatting
    if (e.ctrlKey || e.metaKey) {
        switch (e.key.toLowerCase()) {
            case "b":
                e.preventDefault();
                document.execCommand("bold");
                updateToolbarState();
                break;
            case "i":
                e.preventDefault();
                document.execCommand("italic");
                updateToolbarState();
                break;
            case "u":
                e.preventDefault();
                document.execCommand("underline");
                updateToolbarState();
                break;
        }
    }
    // Enter key handling for lists and checklists
    if (e.key === "Enter" && !e.shiftKey) {
        handleListEnter(e);
    }
    // Markdown shortcuts on space
    if (e.key === " ") {
        handleMarkdownShortcut();
    }
}
function handleListEnter(e) {
    const sel = window.getSelection();
    if (!sel || !editorEl)
        return;
    const anchorNode = sel.anchorNode;
    let element = anchorNode instanceof Element ? anchorNode : anchorNode?.parentElement;
    // Find the list item we're in
    while (element && element !== editorEl) {
        if (element.tagName === "LI")
            break;
        element = element.parentElement;
    }
    if (!element || element.tagName !== "LI")
        return;
    const li = element;
    const textContent = li.textContent?.trim();
    // If list item is empty, exit the list
    if (!textContent) {
        e.preventDefault();
        // For checklist items, remove the whole LI
        if (li.classList.contains("checklist-item")) {
            const parent = li.parentElement;
            if (parent && parent.childElementCount <= 1) {
                // Last item in list - exit list
                const br = document.createElement("div");
                br.innerHTML = "<br>";
                parent.parentNode?.insertBefore(br, parent.nextSibling);
                parent.remove();
                // Place cursor in the new div
                const range = document.createRange();
                range.setStart(br, 0);
                range.collapse(true);
                sel.removeAllRanges();
                sel.addRange(range);
            }
            else {
                li.remove();
            }
        }
        else {
            // Regular list item - remove it and add a paragraph after
            const parent = li.parentElement;
            if (parent && parent.childElementCount <= 1) {
                const p = document.createElement("p");
                p.innerHTML = "<br>";
                parent.parentNode?.insertBefore(p, parent.nextSibling);
                parent.remove();
                const range = document.createRange();
                range.setStart(p, 0);
                range.collapse(true);
                sel.removeAllRanges();
                sel.addRange(range);
            }
            else {
                li.remove();
            }
        }
        updateToolbarState();
        return;
    }
    // Non-empty list item: continue the list (browser default behavior handles this)
}
// ─── Markdown Shortcuts ──────────────────────────────────────
function handleMarkdownShortcut() {
    if (!editorEl)
        return;
    const sel = window.getSelection();
    if (!sel)
        return;
    // Get the current line text before cursor
    const lineText = getCurrentLinePrefix(sel);
    if (!lineText)
        return;
    let replacement = null;
    let command = null;
    if (lineText === "# ") {
        replacement = "";
        command = "h1";
    }
    else if (lineText === "## ") {
        replacement = "";
        command = "h2";
    }
    else if (lineText === "### ") {
        replacement = "";
        command = "h3";
    }
    else if (lineText === "- ") {
        replacement = "";
        command = "insertUnorderedList";
    }
    else if (lineText === "1. ") {
        replacement = "";
        command = "insertOrderedList";
    }
    else if (lineText === "> ") {
        replacement = "";
        command = "blockquote";
    }
    else if (lineText === "[] ") {
        replacement = "";
        command = "checklist";
    }
    if (!command)
        return;
    // Only trigger at the start of a line/block
    const sel2 = window.getSelection();
    if (!sel2)
        return;
    const anchorNode = sel2.anchorNode;
    let element = anchorNode instanceof Element ? anchorNode : anchorNode?.parentElement;
    while (element && element !== editorEl) {
        if (["P", "DIV", "H1", "H2", "H3", "LI"].includes(element.tagName))
            break;
        element = element.parentElement;
    }
    if (!element || element === editorEl)
        return;
    // Check that the cursor is right after the prefix (at position matching prefix length + 1 for space)
    const range = sel2.getRangeAt(0);
    const textBeforeCursor = getTextBeforeRange(range, element);
    if (textBeforeCursor !== lineText)
        return;
    // Remove the prefix text
    const newRange = document.createRange();
    newRange.setStart(element, 0);
    newRange.setEnd(range.startContainer, range.startOffset);
    newRange.deleteContents();
    // No event to prevent (space key already consumed)
    // Apply formatting
    switch (command) {
        case "h1":
            document.execCommand("formatBlock", false, "H1");
            break;
        case "h2":
            document.execCommand("formatBlock", false, "H2");
            break;
        case "h3":
            document.execCommand("formatBlock", false, "H3");
            break;
        case "blockquote":
            document.execCommand("formatBlock", false, "BLOCKQUOTE");
            break;
        case "insertUnorderedList":
            document.execCommand("insertUnorderedList");
            break;
        case "insertOrderedList":
            document.execCommand("insertOrderedList");
            break;
        case "checklist":
            insertChecklistItem();
            break;
    }
    updateToolbarState();
}
function getCurrentLinePrefix(sel) {
    const anchorNode = sel.anchorNode;
    let element = anchorNode instanceof Element ? anchorNode : anchorNode?.parentElement;
    while (element && element !== editorEl) {
        if (["P", "DIV"].includes(element.tagName))
            break;
        element = element.parentElement;
    }
    if (!element || element === editorEl)
        return null;
    // Get text content up to cursor position
    const range = sel.getRangeAt(0);
    return getTextBeforeRange(range, element);
}
function getTextBeforeRange(range, container) {
    const boundaryRange = document.createRange();
    boundaryRange.selectNodeContents(container);
    boundaryRange.setEnd(range.startContainer, range.startOffset);
    return boundaryRange.toString();
}
function insertChecklistItem() {
    if (!editorEl)
        return;
    const sel = window.getSelection();
    if (!sel)
        return;
    // Create a checklist LI
    const li = document.createElement("li");
    li.className = "checklist-item";
    li.contentEditable = "true";
    const checkbox = document.createElement("span");
    checkbox.className = "checklist-checkbox";
    checkbox.setAttribute("data-checked", "false");
    checkbox.addEventListener("click", handleCheckboxClick);
    const textSpan = document.createElement("span");
    textSpan.contentEditable = "true";
    textSpan.innerHTML = "<br>";
    li.appendChild(checkbox);
    li.appendChild(textSpan);
    // Wrap in UL if not already in one
    let parentUl = null;
    const anchorNode2 = sel.anchorNode;
    let element2 = anchorNode2 instanceof Element ? anchorNode2 : anchorNode2?.parentElement ?? null;
    while (element2 && element2 !== editorEl) {
        if (element2.tagName === "UL") {
            parentUl = element2;
            break;
        }
        element2 = element2.parentElement;
    }
    const targetParent = parentUl || createNewList();
    targetParent.appendChild(li);
    // Place cursor in the text span
    const range = document.createRange();
    range.setStart(textSpan, 0);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
}
function createNewList() {
    if (!editorEl)
        return document.createElement("ul");
    const ul = document.createElement("ul");
    editorEl.appendChild(ul);
    return ul;
}
// ─── Checkbox Handling ──────────────────────────────────────
function handleCheckboxClick(e) {
    e.stopPropagation();
    const checkbox = e.target;
    const isChecked = checkbox.getAttribute("data-checked") === "true";
    if (isChecked) {
        checkbox.setAttribute("data-checked", "false");
        checkbox.classList.remove("checked");
    }
    else {
        checkbox.setAttribute("data-checked", "true");
        checkbox.classList.add("checked");
    }
}
function restoreCheckboxes(container) {
    const checkboxes = container.querySelectorAll(".checklist-checkbox");
    checkboxes.forEach(cb => {
        cb.addEventListener("click", handleCheckboxClick);
        if (cb.getAttribute("data-checked") === "true" || cb.hasAttribute("checked")) {
            cb.setAttribute("data-checked", "true");
            cb.classList.add("checked");
        }
        else {
            cb.setAttribute("data-checked", "false");
            cb.classList.remove("checked");
        }
    });
}
// ─── Toolbar State ──────────────────────────────────────────
function onEditorInput() {
    updateToolbarState();
}
function updateToolbarState() {
    if (!editorEl)
        return;
    const buttons = editorEl.closest(".notes-app")?.querySelectorAll(".toolbar-btn[data-cmd]");
    if (!buttons)
        return;
    for (const btn of Array.from(buttons)) {
        const cmd = btn.getAttribute("data-cmd");
        if (!cmd)
            continue;
        let isActive = false;
        try {
            switch (cmd) {
                case "bold":
                case "italic":
                case "underline":
                case "strikeThrough":
                    isActive = document.queryCommandState(cmd);
                    break;
                case "insertUnorderedList":
                case "insertOrderedList":
                    isActive = document.queryCommandState(cmd);
                    break;
                default:
                    // For heading buttons, check if current block is that heading
                    const sel = window.getSelection();
                    if (sel && sel.anchorNode) {
                        let el = sel.anchorNode instanceof Element ? sel.anchorNode : sel.anchorNode.parentElement;
                        while (el && el !== editorEl) {
                            if (el.tagName === cmd.toUpperCase()) {
                                isActive = true;
                                break;
                            }
                            el = el.parentElement;
                        }
                    }
            }
        }
        catch { /* ignore */ }
        btn.classList.toggle("active", isActive);
    }
}
// ─── Toolbar Creation ──────────────────────────────────────
function createToolbar(toolbarEl) {
    const buttons = [
        { cmd: "bold", label: "B", style: "font-weight:bold" },
        { cmd: "italic", label: "I", style: "font-style:italic" },
        { cmd: "underline", label: "U", style: "text-decoration:underline" },
        { cmd: "strikeThrough", label: "S", style: "text-decoration:line-through" },
        { type: "separator" },
        { cmd: "code", label: "<>", style: "font-family:monospace;font-size:12px" },
        { type: "separator" },
        { cmd: "H1", label: "H1", style: "font-weight:bold;font-size:14px" },
        { cmd: "H2", label: "H2", style: "font-weight:600;font-size:13px" },
        { cmd: "H3", label: "H3", style: "font-weight:500;font-size:12px" },
        { type: "separator" },
        { cmd: "insertUnorderedList", label: "• List" },
        { cmd: "insertOrderedList", label: "1. List" },
        { cmd: "checklist", label: "☐ Check" },
        { type: "separator" },
        { cmd: "formatBlock", label: "Quote", blockTag: "BLOCKQUOTE" },
        { cmd: "insertHorizontalRule", label: "— HR" },
    ];
    toolbarEl.innerHTML = "";
    for (const btn of buttons) {
        if (btn.type === "separator") {
            const sep = document.createElement("div");
            sep.className = "toolbar-separator";
            toolbarEl.appendChild(sep);
            continue;
        }
        const button = document.createElement("button");
        button.className = "toolbar-btn";
        button.textContent = btn.label ?? "";
        if (btn.style)
            button.setAttribute("style", btn.style);
        if (btn.cmd)
            button.setAttribute("data-cmd", btn.cmd);
        button.addEventListener("click", () => {
            editorEl?.focus();
            const cmd = btn.cmd ?? "";
            switch (cmd) {
                case "bold":
                case "italic":
                case "underline":
                case "strikeThrough":
                case "insertUnorderedList":
                case "insertOrderedList":
                case "insertHorizontalRule":
                    document.execCommand(cmd);
                    break;
                case "code":
                    wrapSelection("CODE");
                    break;
                case "H1":
                case "H2":
                case "H3":
                    document.execCommand("formatBlock", false, cmd);
                    break;
                case "checklist":
                    insertChecklistItem();
                    break;
                default:
                    if (btn.blockTag) {
                        document.execCommand("formatBlock", false, btn.blockTag);
                    }
            }
            updateToolbarState();
        });
        toolbarEl.appendChild(button);
    }
}
function wrapSelection(tag) {
    const sel = window.getSelection();
    if (!sel || !sel.rangeCount)
        return;
    const range = sel.getRangeAt(0);
    if (range.collapsed)
        return;
    const el = document.createElement(tag);
    try {
        range.surroundContents(el);
    }
    catch { /* partial selection across blocks */ }
}
// ─── Title Input ──────────────────────────────────────────────
function setupTitleInput(titleInput) {
    titleInput.addEventListener("input", () => {
        onTitleChangeCallback?.(titleInput.value);
    });
    titleInput.addEventListener("keydown", (e) => {
        if (e.key === "Enter") {
            e.preventDefault();
            editorEl?.focus();
        }
    });
}
// ─── Public API ──────────────────────────────────────────────
function getEditorContent() {
    if (!editorEl)
        return "";
    return editorEl.innerHTML;
}
};

// ── module: src/ui.ts ──
__mods["src/ui.ts"] = function (exports, require, module) {
"use strict";
// ─── UI Rendering Module ──────────────────────────────────────
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.initUI = initUI;
exports.renderAll = renderAll;
const constants_1 = require("./constants");
const S = __importStar(require("./state"));
const Editor = __importStar(require("./editor"));
// ─── DOM References ──────────────────────────────────────────
let sidebarEl;
let notebookListEl;
let noteListTitleEl;
let noteListEl;
let editorContainerEl;
let emptyStateEl;
let titleInputEl;
let toolbarEl;
let savedIndicatorEl;
let moveDropdownEl;
let tagDisplayEl;
// ─── State for UI ────────────────────────────────────────────
let autosaveTimer = null;
let savedIndicatorTimeout = null;
const SORT_MODES = ["modified", "created", "alphabetical"];
const SORT_LABELS = {
    modified: "Modified",
    created: "Created",
    alphabetical: "A-Z",
};
// ─── Initialization ──────────────────────────────────────────
function initUI() {
    sidebarEl = document.getElementById("sidebar");
    notebookListEl = document.getElementById("notebook-list");
    noteListTitleEl = document.getElementById("note-list-title");
    noteListEl = document.getElementById("note-list");
    editorContainerEl = document.getElementById("editor-container");
    emptyStateEl = document.getElementById("empty-state");
    titleInputEl = document.getElementById("note-title-input");
    toolbarEl = document.getElementById("toolbar");
    savedIndicatorEl = document.getElementById("saved-indicator");
    moveDropdownEl = document.getElementById("move-dropdown");
    tagDisplayEl = document.getElementById("tag-display");
    // Apply theme
    applyTheme(S.getTheme());
    // Setup editor
    const editorEl = document.getElementById("editor");
    Editor.initEditor(editorEl, titleInputEl);
    Editor.createToolbar(toolbarEl);
    Editor.setOnSave(debounceAutosave);
    Editor.setOnTitleChange(onTitleChanged);
    Editor.setupTitleInput(titleInputEl);
    // Setup sidebar events
    setupSidebar();
    // Create new note button in note list header
    const createNoteBtn = document.createElement("button");
    createNoteBtn.id = "create-note-btn";
    createNoteBtn.className = "icon-btn";
    createNoteBtn.textContent = "+";
    createNoteBtn.title = "New Note";
    createNoteBtn.style.fontSize = "16px";
    createNoteBtn.style.fontWeight = "bold";
    const noteListActions = document.querySelector(".note-list-actions");
    if (noteListActions) {
        noteListActions.insertBefore(createNoteBtn, noteListActions.firstChild);
    }
    createNoteBtn.addEventListener("click", () => {
        const state = S.getState();
        const nbId = state.activeNotebookId === "trash" ? null : state.activeNotebookId;
        if (nbId !== null) {
            const note = S.createNote(nbId);
            S.setActiveNote(note.id);
            renderAll();
        }
    });
    // Setup note list events
    setupNoteListActions();
    // Setup editor actions
    setupEditorActions();
    // Setup resize handles
    setupResizeHandles();
    // Setup search
    setupSearch();
    // Initial render
    renderAll();
}
// ─── Theme ──────────────────────────────────────────────────
function applyTheme(theme) {
    const app = document.getElementById("app");
    if (theme === "dark") {
        app?.classList.add("dark");
    }
    else {
        app?.classList.remove("dark");
    }
    // Update theme toggle button
    const btn = document.getElementById("theme-toggle");
    if (btn)
        btn.textContent = theme === "dark" ? "☀️" : "🌙";
}
// ─── Sidebar Rendering ──────────────────────────────────────
function setupSidebar() {
    // Theme toggle
    const themeBtn = document.getElementById("theme-toggle");
    themeBtn?.addEventListener("click", () => {
        const newTheme = S.toggleTheme();
        applyTheme(newTheme);
    });
    // New notebook button
    const newNbBtn = document.getElementById("new-notebook-btn");
    newNbBtn?.addEventListener("click", () => {
        const name = prompt("Notebook name:");
        if (name?.trim()) {
            S.addNotebook(name.trim());
            renderSidebar();
        }
    });
    // Collapse sidebar toggle (when collapsed)
    const collapseBtn = document.getElementById("collapse-sidebar-btn");
    collapseBtn?.addEventListener("click", () => {
        S.toggleSidebar();
        applyLayout();
        renderSidebar();
    });
}
function renderSidebar() {
    const state = S.getState();
    const layout = S.getLayout();
    // Apply sidebar collapsed state
    if (layout.sidebarCollapsed) {
        sidebarEl.classList.add("collapsed");
    }
    else {
        sidebarEl.classList.remove("collapsed");
    }
    notebookListEl.innerHTML = "";
    // "All Notes" virtual view
    const allNotesItem = createNotebookItem("📋", "All Notes", null, state.activeNotebookId === null, state.notes.length);
    notebookListEl.appendChild(allNotesItem);
    // Notebooks
    for (const nb of state.notebooks) {
        const item = createNotebookItem("📓", nb.name, nb.id, state.activeNotebookId === nb.id, S.getNoteCountForNotebook(nb.id), nb.collapsed ?? false);
        notebookListEl.appendChild(item);
    }
    // Trash
    const trashItem = createNotebookItem("🗑", "Trash", "trash", state.activeNotebookId === "trash", S.getNoteCountForNotebook("trash"));
    notebookListEl.appendChild(trashItem);
}
function createNotebookItem(icon, name, id, active, count, collapsed) {
    const item = document.createElement("div");
    item.className = "notebook-item" + (active ? " active" : "");
    const iconSpan = document.createElement("span");
    iconSpan.className = "notebook-icon";
    iconSpan.textContent = icon;
    item.appendChild(iconSpan);
    const nameSpan = document.createElement("span");
    nameSpan.className = "notebook-name";
    nameSpan.textContent = name;
    item.appendChild(nameSpan);
    const countSpan = document.createElement("span");
    countSpan.className = "notebook-count";
    countSpan.textContent = String(count);
    item.appendChild(countSpan);
    // Actions for real notebooks (not All Notes or Trash)
    if (id && id !== "trash") {
        const actionsDiv = document.createElement("div");
        actionsDiv.className = "notebook-actions";
        const renameBtn = document.createElement("button");
        renameBtn.className = "notebook-action-btn";
        renameBtn.textContent = "✏️";
        renameBtn.title = "Rename";
        renameBtn.addEventListener("click", (e) => {
            e.stopPropagation();
            handleRenameNotebook(id, nameSpan);
        });
        actionsDiv.appendChild(renameBtn);
        const deleteBtn = document.createElement("button");
        deleteBtn.className = "notebook-action-btn";
        deleteBtn.textContent = "🗑";
        deleteBtn.title = "Delete";
        deleteBtn.addEventListener("click", (e) => {
            e.stopPropagation();
            if (confirm(`Delete notebook "${name}"? Notes will be moved to Trash.`)) {
                S.deleteNotebook(id);
                renderAll();
            }
        });
        actionsDiv.appendChild(deleteBtn);
        item.appendChild(actionsDiv);
    }
    // Click handler
    item.addEventListener("click", () => {
        S.setActiveNotebook(id === "trash" ? "trash" : id);
        S.setTagFilter(null);
        renderAll();
    });
    return item;
}
function handleRenameNotebook(id, nameEl) {
    const currentName = nameEl.textContent ?? "";
    const input = document.createElement("input");
    input.type = "text";
    input.className = "notebook-rename-input";
    input.value = currentName;
    nameEl.replaceWith(input);
    input.focus();
    input.select();
    const finish = () => {
        const newName = input.value.trim() || currentName;
        S.renameNotebook(id, newName);
        renderSidebar();
    };
    input.addEventListener("blur", finish);
    input.addEventListener("keydown", (e) => {
        if (e.key === "Enter") {
            e.preventDefault();
            input.blur();
        }
        if (e.key === "Escape") {
            input.value = currentName;
            input.blur();
        }
    });
}
// ─── Note List Rendering ──────────────────────────────────────
function setupNoteListActions() {
    // Sort toggle
    const sortBtn = document.getElementById("sort-toggle");
    sortBtn?.addEventListener("click", () => {
        const state = S.getState();
        const idx = SORT_MODES.indexOf(state.sortMode);
        const next = SORT_MODES[(idx + 1) % SORT_MODES.length];
        S.setSortMode(next);
        renderNoteList();
        sortBtn.textContent = SORT_LABELS[next][0] ?? "↕";
    });
}
function renderNoteList() {
    const state = S.getState();
    // Update title
    if (state.activeNotebookId === null) {
        noteListTitleEl.textContent = "All Notes";
    }
    else if (state.activeNotebookId === "trash") {
        noteListTitleEl.textContent = "Trash";
    }
    else {
        const nb = state.notebooks.find(n => n.id === state.activeNotebookId);
        noteListTitleEl.textContent = nb?.name ?? "Notes";
    }
    // Tag filter indicator
    if (state.tagFilter) {
        noteListTitleEl.textContent += ` — #${state.tagFilter}`;
    }
    const notes = S.getFilteredNotes();
    noteListEl.innerHTML = "";
    if (notes.length === 0) {
        // Show empty state
        const emptyDiv = document.createElement("div");
        emptyDiv.className = "note-list-empty";
        const icon = document.createElement("span");
        icon.className = "empty-icon";
        icon.textContent = S.getState().activeNotebookId === "trash" ? "🗑" : "📝";
        emptyDiv.appendChild(icon);
        const msg = document.createElement("p");
        if (S.getState().searchQuery.trim()) {
            msg.textContent = "No notes match your search";
        }
        else if (S.getState().activeNotebookId === "trash") {
            msg.textContent = "Trash is empty";
        }
        else {
            msg.textContent = "No notes yet\nClick + to create one";
            msg.style.whiteSpace = "pre-line";
        }
        emptyDiv.appendChild(msg);
        noteListEl.appendChild(emptyDiv);
    }
    else {
        for (const note of notes) {
            const item = createNoteItem(note);
            noteListEl.appendChild(item);
        }
    }
    // Update sort button label
    const sortBtn = document.getElementById("sort-toggle");
    if (sortBtn)
        sortBtn.textContent = SORT_LABELS[state.sortMode][0] ?? "↕";
}
function createNoteItem(note) {
    const item = document.createElement("div");
    item.className = "note-item" + (S.getState().activeNoteId === note.id ? " active" : "");
    // Header with pin indicator and title
    const header = document.createElement("div");
    header.className = "note-item-header";
    if (note.pinned) {
        const pin = document.createElement("span");
        pin.className = "note-pin-indicator";
        pin.textContent = "📌";
        header.appendChild(pin);
    }
    const title = document.createElement("span");
    title.className = "note-title";
    title.textContent = note.title || "Untitled";
    header.appendChild(title);
    item.appendChild(header);
    // Snippet
    const snippet = document.createElement("div");
    snippet.className = "note-snippet";
    snippet.textContent = S.getSnippet(note, constants_1.SNIPPET_LENGTH);
    item.appendChild(snippet);
    // Meta: date + tags
    const meta = document.createElement("div");
    meta.className = "note-meta";
    const date = document.createElement("span");
    date.className = "note-date";
    date.textContent = formatRelativeTime(note.updatedAt);
    meta.appendChild(date);
    if (note.tags.length > 0) {
        const tagsDiv = document.createElement("div");
        tagsDiv.className = "note-tags";
        for (const tag of note.tags) {
            const tagEl = document.createElement("span");
            tagEl.className = "note-tag";
            tagEl.textContent = "#" + tag;
            tagEl.addEventListener("click", (e) => {
                e.stopPropagation();
                S.setTagFilter(tag);
                renderAll();
            });
            tagsDiv.appendChild(tagEl);
        }
        meta.appendChild(tagsDiv);
    }
    item.appendChild(meta);
    // Trash actions for trash view
    if (S.getState().activeNotebookId === "trash") {
        const trashActions = document.createElement("div");
        trashActions.className = "trash-actions";
        const restoreBtn = document.createElement("button");
        restoreBtn.className = "trash-btn restore-btn";
        restoreBtn.textContent = "Restore";
        restoreBtn.addEventListener("click", (e) => {
            e.stopPropagation();
            S.restoreNote(note.id);
            renderAll();
        });
        trashActions.appendChild(restoreBtn);
        const permDeleteBtn = document.createElement("button");
        permDeleteBtn.className = "trash-btn permanent-delete-btn";
        permDeleteBtn.textContent = "Delete Forever";
        permDeleteBtn.addEventListener("click", (e) => {
            e.stopPropagation();
            S.permanentlyDeleteNote(note.id);
            renderAll();
        });
        trashActions.appendChild(permDeleteBtn);
        item.appendChild(trashActions);
    }
    // Click to select note
    item.addEventListener("click", () => {
        S.setActiveNote(note.id);
        renderAll();
    });
    return item;
}
// ─── Editor Rendering ──────────────────────────────────────
function setupEditorActions() {
    // Pin button
    const pinBtn = document.getElementById("pin-note-btn");
    pinBtn?.addEventListener("click", () => {
        if (S.getState().activeNoteId) {
            S.togglePin(S.getState().activeNoteId);
            renderAll();
        }
    });
    // Duplicate button
    const dupBtn = document.getElementById("duplicate-note-btn");
    dupBtn?.addEventListener("click", () => {
        if (S.getState().activeNoteId) {
            S.duplicateNote(S.getState().activeNoteId);
            renderAll();
        }
    });
    // Delete button
    const delBtn = document.getElementById("delete-note-btn");
    delBtn?.addEventListener("click", () => {
        if (S.getState().activeNoteId) {
            S.deleteNote(S.getState().activeNoteId);
            renderAll();
        }
    });
    // Move button
    const moveBtn = document.getElementById("move-note-btn");
    moveBtn?.addEventListener("click", () => {
        showMoveDropdown(moveBtn);
    });
    // Add tag button
    const addTagBtn = document.getElementById("add-tag-btn");
    addTagBtn?.addEventListener("click", () => {
        if (S.getState().activeNoteId) {
            const tag = prompt("Enter tag name:");
            if (tag?.trim()) {
                S.addTag(S.getState().activeNoteId, tag.trim());
                renderEditor();
            }
        }
    });
    // Close dropdown on outside click
    document.addEventListener("click", (e) => {
        if (!moveDropdownEl.contains(e.target)) {
            moveDropdownEl.classList.add("hidden");
        }
    });
}
function showMoveDropdown(anchor) {
    const noteId = S.getState().activeNoteId;
    if (!noteId)
        return;
    const rect = anchor.getBoundingClientRect();
    moveDropdownEl.style.top = (rect.bottom + 4) + "px";
    moveDropdownEl.style.left = rect.left + "px";
    moveDropdownEl.classList.remove("hidden");
    const listEl = document.getElementById("move-notebook-list");
    listEl.innerHTML = "";
    for (const nb of S.getState().notebooks) {
        const item = document.createElement("div");
        item.className = "dropdown-item";
        item.textContent = nb.name;
        item.addEventListener("click", () => {
            S.moveNote(noteId, nb.id);
            moveDropdownEl.classList.add("hidden");
            renderAll();
        });
        listEl.appendChild(item);
    }
}
function renderEditor() {
    const note = S.getActiveNote();
    if (!note) {
        editorContainerEl.classList.add("hidden");
        emptyStateEl.classList.remove("hidden");
        return;
    }
    editorContainerEl.classList.remove("hidden");
    emptyStateEl.classList.add("hidden");
    // Load note content into editor
    Editor.loadNote(note);
    // Set title
    titleInputEl.value = note.title;
    // Update pin button state
    const pinBtn = document.getElementById("pin-note-btn");
    if (pinBtn) {
        pinBtn.style.opacity = note.pinned ? "1" : "0.4";
    }
    // Render tags
    tagDisplayEl.innerHTML = "";
    for (const tag of note.tags) {
        const pill = document.createElement("span");
        pill.className = "tag-pill";
        pill.textContent = "#" + tag;
        const removeBtn = document.createElement("span");
        removeBtn.className = "remove-tag";
        removeBtn.textContent = "×";
        removeBtn.addEventListener("click", () => {
            S.removeTag(note.id, tag);
            renderEditor();
        });
        pill.appendChild(removeBtn);
        tagDisplayEl.appendChild(pill);
    }
    // Update toolbar state
    Editor.updateToolbarState();
}
// ─── Autosave ──────────────────────────────────────────────
function debounceAutosave(content) {
    if (autosaveTimer)
        clearTimeout(autosaveTimer);
    autosaveTimer = setTimeout(() => {
        const noteId = S.getState().activeNoteId;
        if (noteId) {
            S.updateNote(noteId, { content });
            showSavedIndicator();
        }
    }, 500);
}
function onTitleChanged(title) {
    // Debounced title save is handled by the same autosave mechanism
    const noteId = S.getState().activeNoteId;
    if (noteId) {
        if (autosaveTimer)
            clearTimeout(autosaveTimer);
        autosaveTimer = setTimeout(() => {
            S.updateNote(noteId, { title });
            showSavedIndicator();
            renderNoteList(); // Update note list with new title
        }, 500);
    }
}
function showSavedIndicator() {
    savedIndicatorEl.classList.add("show");
    if (savedIndicatorTimeout)
        clearTimeout(savedIndicatorTimeout);
    savedIndicatorTimeout = setTimeout(() => {
        savedIndicatorEl.classList.remove("show");
    }, 1500);
}
// ─── Resize Handles ──────────────────────────────────────
function setupResizeHandles() {
    const handle1 = document.getElementById("resize-handle-1");
    const handle2 = document.getElementById("resize-handle-2");
    if (handle1)
        makeResizable(handle1, (delta) => {
            S.setSidebarWidth(Math.max(180, Math.min(400, S.getLayout().sidebarWidth + delta)));
            applyLayout();
        });
    if (handle2)
        makeResizable(handle2, (delta) => {
            S.setNoteListWidth(Math.max(220, Math.min(500, S.getLayout().noteListWidth + delta)));
            applyLayout();
        });
}
function makeResizable(handle, onResize) {
    let startX = 0;
    const onMouseDown = (e) => {
        e.preventDefault();
        startX = e.clientX;
        handle.classList.add("active");
        document.addEventListener("mousemove", onMouseMove);
        document.addEventListener("mouseup", onMouseUp);
    };
    const onMouseMove = (e) => {
        onResize(e.clientX - startX);
        startX = e.clientX;
    };
    const onMouseUp = () => {
        handle.classList.remove("active");
        document.removeEventListener("mousemove", onMouseMove);
        document.removeEventListener("mouseup", onMouseUp);
    };
    handle.addEventListener("mousedown", onMouseDown);
}
// ─── Search ──────────────────────────────────────────────
function setupSearch() {
    const searchInput = document.getElementById("search-input");
    let searchTimer;
    searchInput?.addEventListener("input", () => {
        clearTimeout(searchTimer);
        searchTimer = setTimeout(() => {
            S.setSearchQuery(searchInput.value);
            renderNoteList();
        }, 200);
    });
}
// ─── Layout ──────────────────────────────────────────────
function applyLayout() {
    const layout = S.getLayout();
    sidebarEl.style.setProperty("--sidebar-width", layout.sidebarWidth + "px");
    document.getElementById("note-list-pane").style.setProperty("--note-list-width", layout.noteListWidth + "px");
    // Show/hide collapse button
    const app = document.getElementById("app");
    if (layout.sidebarCollapsed) {
        app?.classList.add("sidebar-collapsed-show");
    }
    else {
        app?.classList.remove("sidebar-collapsed-show");
    }
}
// ─── Render All ──────────────────────────────────────────
function renderAll() {
    applyLayout();
    renderSidebar();
    renderNoteList();
    renderEditor();
}
// ─── Utility ──────────────────────────────────────────────
function formatRelativeTime(timestamp) {
    const now = Date.now();
    const diff = now - timestamp;
    if (diff < 60000)
        return "Just now";
    if (diff < 3600000)
        return Math.floor(diff / 60000) + "m ago";
    if (diff < 86400000)
        return Math.floor(diff / 3600000) + "h ago";
    if (diff < 604800000)
        return Math.floor(diff / 86400000) + "d ago";
    // Fall back to date format
    const d = new Date(timestamp);
    return d.toLocaleDateString(undefined, { month: "short", day: "numeric" });
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingcap-qwen3.6-27b","provider":"lmstudio","persona":"typescript","sessionId":"698750dc-8777-474c-98ad-83a018a5137a","tokensIn":2563797,"tokensOut":55320,"tokensTotal":2619117,"cost":0,"turns":65,"toolCalls":64,"failedToolCalls":2,"timestamp":"2026-07-31T20:05:11.607Z"} -->