← Notes results

Notes

thinkingcap qwen3.6 27b · middle

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 39,443 bytes · SHA-256 135f357ea92c
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NoteFlow — Notes App</title>
<style>
  *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
  :root{
    --bg-primary:#ffffff;--bg-secondary:#f7f8fa;--bg-tertiary:#eef0f4;
    --bg-hover:#e2e5eb;--bg-active:#d6dae3;--bg-sidebar:#fafbfc;
    --text-primary:#1a1c20;--text-secondary:#5f6577;--text-tertiary:#8b90a0;
    --accent:#6c5ce7;--accent-hover:#5a4bd1;--accent-light:rgba(108,92,231,.1);
    --border:#e4e6eb;--shadow:0 2px 12px rgba(0,0,0,.08);
    --radius:8px;--radius-lg:12px;
    --font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
    --font-mono:'JetBrains Mono','Fira Code',monospace;
    --sidebar-width:260px;--note-list-width:300px;
    --transition:all .2s ease;
  }
  [data-theme="dark"]{
    --bg-primary:#1e1f25;--bg-secondary:#262730;--bg-tertiary:#2c2d38;
    --bg-hover:#34354a;--bg-active:#3d3e55;--bg-sidebar:#191a20;
    --text-primary:#e4e5ea;--text-secondary:#9b9db4;--text-tertiary:#6b6d82;
    --border:#363744;--shadow:0 2px 12px rgba(0,0,0,.3);
    --accent:#a29bfe;--accent-hover:#8b83f5;--accent-light:rgba(162,155,254,.15);
  }
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
  html,body{height:100%;font-family:var(--font-sans);background:var(--bg-primary);color:var(--text-primary);overflow:hidden}

  /* ── Layout ── */
  .app{display:flex;height:100vh;width:100vw;position:relative}
  
  /* ── Sidebar ── */
  .sidebar{width:var(--sidebar-width);min-width:var(--sidebar-width);background:var(--bg-sidebar);border-right:1px solid var(--border);display:flex;flex-direction:column;transition:transform .3s ease,opacity .3s ease;z-index:20}
  .sidebar.collapsed{transform:translateX(calc(-1 * var(--sidebar-width)));position:absolute;height:100%;opacity:0;pointer-events:none}
  .sidebar-header{padding:20px 16px 8px;display:flex;align-items:center;justify-content:space-between}
  .logo{display:flex;align-items:center;gap:10px;font-weight:700;font-size:18px;color:var(--accent)}
  .logo svg{width:28px;height:28px}
  .sidebar-section{padding:8px 12px}
  .sidebar-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-tertiary);margin-bottom:6px;padding:0 4px;display:flex;align-items:center;justify-content:space-between}
  .folder-item,.tag-item{display:flex;align-items:center;gap:10px;padding:7px 12px;border-radius:var(--radius);cursor:pointer;font-size:13.5px;color:var(--text-secondary);transition:var(--transition);user-select:none;margin-bottom:1px}
  .folder-item:hover,.tag-item:hover{background:var(--bg-hover);color:var(--text-primary)}
  .folder-item.active,.tag-item.active{background:var(--accent-light);color:var(--accent);font-weight:500}
  .folder-icon{width:18px;height:18px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
  .folder-count{margin-left:auto;font-size:11px;color:var(--text-tertiary);background:var(--bg-tertiary);padding:1px 7px;border-radius:10px}
  .add-btn{display:flex;align-items:center;gap:6px;padding:5px 8px;border:none;background:none;color:var(--text-tertiary);cursor:pointer;font-size:13px;border-radius:var(--radius);transition:var(--transition)}
  .add-btn:hover{background:var(--bg-hover);color:var(--text-primary)}

  /* ── Note List Panel ── */
  .note-list-panel{width:var(--note-list-width);min-width:var(--note-list-width);border-right:1px solid var(--border);display:flex;flex-direction:column;background:var(--bg-secondary);transition:transform .3s ease,opacity .3s ease;z-index:10}
  .note-list-panel.collapsed{transform:translateX(calc(-1 * var(--note-list-width)));position:absolute;height:100%;opacity:0;pointer-events:none}
  .search-box{padding:12px;border-bottom:1px solid var(--border)}
  .search-input-wrap{display:flex;align-items:center;background:var(--bg-tertiary);border-radius:var(--radius);padding:0 12px;border:1.5px solid transparent;transition:var(--transition)}
  .search-input-wrap:focus-within{border-color:var(--accent);background:var(--bg-primary)}
  .search-input-wrap svg{width:16px;height:16px;color:var(--text-tertiary);flex-shrink:0}
  .search-input{flex:1;border:none;background:none;padding:9px 8px;font-size:13px;color:var(--text-primary);outline:none;font-family:var(--font-sans)}
  .search-input::placeholder{color:var(--text-tertiary)}
  .note-list-header{padding:12px 16px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border)}
  .note-count{font-size:12px;color:var(--text-tertiary);font-weight:500}
  .sort-btn{background:none;border:none;color:var(--text-tertiary);cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;transition:var(--transition)}
  .sort-btn:hover{color:var(--text-primary);background:var(--bg-hover)}
  .note-list{flex:1;overflow-y:auto;padding:8px}
  .note-card{padding:12px;border-radius:var(--radius-lg);cursor:pointer;margin-bottom:4px;transition:var(--transition);border:1.5px solid transparent;position:relative}
  .note-card:hover{background:var(--bg-hover)}
  .note-card.active{background:var(--accent-light);border-color:var(--accent)}
  .note-card-title{font-size:14px;font-weight:600;margin-bottom:4px;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .note-card-preview{font-size:12.5px;color:var(--text-secondary);line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:6px}
  .note-card-meta{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--text-tertiary)}
  .note-card-tags{display:flex;gap:4px;flex-wrap:wrap;margin-top:6px}
  .mini-tag{font-size:10px;padding:2px 7px;border-radius:10px;background:var(--bg-tertiary);color:var(--text-secondary)}
  .new-note-btn{margin:8px 12px 12px;padding:10px;border:2px dashed var(--border);background:none;color:var(--text-tertiary);border-radius:var(--radius-lg);cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;gap:8px;transition:var(--transition);font-family:var(--font-sans)}
  .new-note-btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-light)}

  /* ── Editor Panel ── */
  .editor-panel{flex:1;display:flex;flex-direction:column;background:var(--bg-primary);min-width:0}
  .toolbar-top{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid var(--border);gap:4px;flex-shrink:0}
  .toggle-btn{background:none;border:none;color:var(--text-tertiary);cursor:pointer;padding:6px;border-radius:var(--radius);display:flex;align-items:center;transition:var(--transition)}
  .toggle-btn:hover{color:var(--text-primary);background:var(--bg-hover)}
  .toolbar-spacer{flex:1}
  .format-toolbar{display:flex;align-items:center;padding:6px 16px;border-bottom:1px solid var(--border);gap:2px;flex-wrap:wrap;flex-shrink:0}
  .fmt-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;padding:6px 8px;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:var(--transition);font-size:13px;font-weight:500}
  .fmt-btn:hover{background:var(--bg-hover);color:var(--text-primary)}
  .fmt-btn.active{background:var(--accent-light);color:var(--accent)}
  .fmt-sep{width:1px;height:20px;background:var(--border);margin:0 4px}
  .editor-header{padding:24px 32px 8px;flex-shrink:0}
  .note-title-input{font-size:28px;font-weight:700;border:none;background:none;color:var(--text-primary);outline:none;width:100%;font-family:var(--font-sans);line-height:1.3}
  .note-title-input::placeholder{color:var(--text-tertiary)}
  .editor-meta{display:flex;align-items:center;gap:12px;padding:4px 32px 8px;font-size:12px;color:var(--text-tertiary);flex-shrink:0}
  .tag-input-wrap{display:flex;align-items:center;gap:4px;flex-wrap:wrap}
  .editor-tag{font-size:11px;padding:3px 8px;border-radius:10px;background:var(--accent-light);color:var(--accent);cursor:pointer;display:flex;align-items:center;gap:4px}
  .tag-remove{font-size:14px;line-height:1;opacity:.6;transition:var(--transition)}
  .tag-remove:hover{opacity:1}
  .editor-area-wrap{flex:1;padding:8px 32px 32px;overflow-y:auto}
  .editor-area{min-height:100%;outline:none;font-size:15px;line-height:1.75;color:var(--text-primary);font-family:var(--font-sans)}
  .editor-area h1,.editor-area h2,.editor-area h3{margin:16px 0 8px;font-weight:700}
  .editor-area h1{font-size:24px}.editor-area h2{font-size:20px}.editor-area h3{font-size:17px}
  .editor-area ul,.editor-area ol{padding-left:24px;margin:8px 0}
  .editor-area blockquote{border-left:3px solid var(--accent);padding-left:16px;color:var(--text-secondary);margin:12px 0;font-style:italic}
  .editor-area code{background:var(--bg-tertiary);padding:2px 6px;border-radius:4px;font-family:var(--font-mono);font-size:.9em}
  .editor-area pre{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin:12px 0;overflow-x:auto}
  .editor-area a{color:var(--accent)}
  .editor-area hr{border:none;border-top:1.5px solid var(--border);margin:20px 0}

  /* ── Empty State ── */
  .empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--text-tertiary);gap:16px;padding:40px}
  .empty-state svg{width:80px;height:80px;opacity:.3}
  .empty-state h2{font-size:20px;font-weight:600;color:var(--text-secondary)}
  .empty-state p{font-size:14px;text-align:center;max-width:320px;line-height:1.6}

  /* ── Modal ── */
  .modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:100;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .2s ease}
  .modal-overlay.show{opacity:1;pointer-events:auto}
  .modal{background:var(--bg-primary);border-radius:var(--radius-lg);padding:24px;width:360px;max-width:90vw;box-shadow:var(--shadow);transform:scale(.95);transition:transform .2s ease}
  .modal-overlay.show .modal{transform:scale(1)}
  .modal h3{font-size:16px;font-weight:700;margin-bottom:16px}
  .modal input[type="text"]{width:100%;padding:10px 12px;border:1.5px solid var(--border);border-radius:var(--radius);background:var(--bg-secondary);color:var(--text-primary);font-size:14px;outline:none;font-family:var(--font-sans);transition:var(--transition)}
  .modal input[type="text"]:focus{border-color:var(--accent)}
  .modal-actions{display:flex;gap:8px;margin-top:16px;justify-content:flex-end}
  .btn{padding:8px 20px;border-radius:var(--radius);font-size:13px;font-weight:500;cursor:pointer;border:none;transition:var(--transition);font-family:var(--font-sans)}
  .btn-primary{background:var(--accent);color:#fff}
  .btn-primary:hover{background:var(--accent-hover)}
  .btn-ghost{background:transparent;color:var(--text-secondary);border:1px solid var(--border)}
  .btn-ghost:hover{background:var(--bg-hover)}

  /* ── Context Menu ── */
  .context-menu{position:fixed;background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius-lg);padding:6px;box-shadow:var(--shadow);z-index:200;min-width:180px;display:none}
  .context-menu.show{display:block}
  .ctx-item{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:6px;font-size:13px;color:var(--text-secondary);cursor:pointer;transition:var(--transition)}
  .ctx-item:hover{background:var(--bg-hover);color:var(--text-primary)}
  .ctx-item.danger{color:#e74c3c}
  .ctx-item.danger:hover{background:rgba(231,76,60,.1)}

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

  /* ── Animations ── */
  @keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
  .note-card{animation:fadeIn .2s ease}

  /* ── Responsive ── */
  @media(max-width:900px){
    :root{--sidebar-width:220px;--note-list-width:240px}
    .editor-header,.editor-meta,.editor-area-wrap{padding-left:20px;padding-right:20px}
  }
  @media(max-width:700px){
    .sidebar{position:absolute;height:100%}.sidebar:not(.collapsed){box-shadow:var(--shadow)}
    .note-list-panel{width:100%;min-width:100%}
  }

  /* ── Toast ── */
  .toast-container{position:fixed;bottom:24px;right:24px;z-index:300;display:flex;flex-direction:column;gap:8px}
  .toast{padding:12px 20px;border-radius:var(--radius);background:var(--bg-primary);border:1px solid var(--border);box-shadow:var(--shadow);font-size:13px;color:var(--text-primary);animation:fadeIn .3s ease;display:flex;align-items:center;gap:8px}
  .toast.success{border-left:3px solid #27ae60}
  .toast.info{border-left:3px solid var(--accent)}

  /* ── Word count bar ── */
  .status-bar{padding:4px 16px;font-size:11px;color:var(--text-tertiary);border-top:1px solid var(--border);display:flex;gap:16px;flex-shrink:0}

  /* ── Pin indicator ── */
  .pin-indicator{position:absolute;top:8px;right:8px;color:var(--accent);font-size:12px}
</style>
</head>
<body>
<div class="app" id="app">
  <!-- Sidebar -->
  <aside class="sidebar" id="sidebar">
    <div class="sidebar-header">
      <div class="logo">
        <svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="7" fill="#6c5ce7"/><path d="M8 9h12M8 14h8M8 19h10" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
        NoteFlow
      </div>
    </div>

    <div class="sidebar-section">
      <div class="sidebar-label">Folders</div>
      <div id="folderList"></div>
      <button class="add-btn" onclick="showFolderModal()">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M12 5v14M5 12h14"/></svg>
        New Folder
      </button>
    </div>

    <div class="sidebar-section">
      <div class="sidebar-label">Tags</div>
      <div id="tagList"></div>
      <button class="add-btn" onclick="showTagModal()">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M12 5v14M5 12h14"/></svg>
        New Tag
      </button>
    </div>

    <div style="flex:1"></div>

    <div class="sidebar-section">
      <button class="add-btn" onclick="toggleTheme()" id="themeBtn" style="width:100%;justify-content:center;padding:8px 12px">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
        <span id="themeLabel">Dark Mode</span>
      </button>
    </div>
  </aside>

  <!-- Note List -->
  <div class="note-list-panel" id="noteListPanel">
    <div class="search-box">
      <div class="search-input-wrap">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
        <input class="search-input" id="searchInput" type="text" placeholder="Search notes…" oninput="filterNotes()">
      </div>
    </div>
    <div class="note-list-header">
      <span class="note-count" id="noteCount">0 notes</span>
      <button class="sort-btn" onclick="toggleSort()" title="Toggle sort order">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M7 12h10M11 18h4"/></svg>
      </button>
    </div>
    <div class="note-list" id="noteList"></div>
    <button class="new-note-btn" onclick="createNote()">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M12 5v14M5 12h14"/></svg>
      New Note
    </button>
  </div>

  <!-- Editor -->
  <main class="editor-panel" id="editorPanel">
    <div class="empty-state" id="emptyState">
      <svg viewBox="0 0 80 80" fill="none"><rect x="16" y="12" width="48" height="56" rx="6" stroke="currentColor" stroke-width="2"/><path d="M26 30h28M26 38h20M26 46h24" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
      <h2>Welcome to NoteFlow</h2>
      <p>Select a note from the list or create a new one to get started. Your notes are saved automatically.</p>
    </div>

    <div id="editorContent" style="display:none;flex-direction:column;height:100%">
      <div class="toolbar-top">
        <button class="toggle-btn" onclick="toggleSidebar()" title="Toggle sidebar">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
        </button>
        <div class="toolbar-spacer"></div>
        <button class="toggle-btn" onclick="duplicateNote()" title="Duplicate note">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
        </button>
        <button class="toggle-btn" onclick="deleteNote()" title="Delete note">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#e74c3c" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14"/></svg>
        </button>
      </div>

      <div class="format-toolbar">
        <button class="fmt-btn" onclick="execCmd('bold')" title="Bold (Ctrl+B)"><b>B</b></button>
        <button class="fmt-btn" onclick="execCmd('italic')" title="Italic (Ctrl+I)" style="font-style:italic">I</button>
        <button class="fmt-btn" onclick="execCmd('underline')" title="Underline (Ctrl+U)" style="text-decoration:underline">U</button>
        <button class="fmt-btn" onclick="execCmd('strikeThrough')" title="Strikethrough" style="text-decoration:line-through">S</button>
        <div class="fmt-sep"></div>
        <button class="fmt-btn" onclick="execHeading('H1')" title="Heading 1">H1</button>
        <button class="fmt-btn" onclick="execHeading('H2')" title="Heading 2">H2</button>
        <button class="fmt-btn" onclick="execHeading('H3')" title="Heading 3">H3</button>
        <div class="fmt-sep"></div>
        <button class="fmt-btn" onclick="execCmd('insertUnorderedList')" title="Bullet list">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg>
        </button>
        <button class="fmt-btn" onclick="execCmd('insertOrderedList')" title="Numbered list">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 6h13M10 12h13M10 18h13"/><text x="1" y="9" font-size="8" fill="currentColor">1</text><text x="1" y="15" font-size="8" fill="currentColor">2</text></svg>
        </button>
        <div class="fmt-sep"></div>
        <button class="fmt-btn" onclick="execCmd('formatBlock','<blockquote>')" title="Quote">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V21z"/><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3z"/></svg>
        </button>
        <button class="fmt-btn" onclick="insertHR()" title="Horizontal rule">―</button>
        <div class="fmt-sep"></div>
        <button class="fmt-btn" onclick="execCmd('removeFormat')" title="Clear formatting">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7V4h16v3M9 20h6M12 4v16"/></svg>
        </button>
      </div>

      <div class="editor-header">
        <input class="note-title-input" id="noteTitleInput" type="text" placeholder="Untitled note…" oninput="onTitleChange()">
      </div>
      <div class="editor-meta">
        <span id="noteDate"></span>
        <span>·</span>
        <div class="tag-input-wrap" id="editorTags"></div>
        <button class="add-btn" onclick="showAddTagToNote()" style="padding:2px 6px;font-size:11px">+ tag</button>
      </div>

      <div class="editor-area-wrap">
        <div class="editor-area" id="editorArea" contenteditable="true" oninput="onContentChange()"></div>
      </div>

      <div class="status-bar">
        <span id="wordCount">0 words</span>
        <span id="charCount">0 characters</span>
        <span id="saveStatus">Saved</span>
      </div>
    </div>
  </main>
</div>

<!-- Folder Modal -->
<div class="modal-overlay" id="folderModal">
  <div class="modal">
    <h3>New Folder</h3>
    <input type="text" id="folderNameInput" placeholder="Folder name…" onkeydown="if(event.key==='Enter')saveFolder()">
    <div class="modal-actions">
      <button class="btn btn-ghost" onclick="closeModal('folderModal')">Cancel</button>
      <button class="btn btn-primary" onclick="saveFolder()">Create</button>
    </div>
  </div>
</div>

<!-- Tag Modal -->
<div class="modal-overlay" id="tagModal">
  <div class="modal">
    <h3>New Tag</h3>
    <input type="text" id="tagNameInput" placeholder="Tag name…" onkeydown="if(event.key==='Enter')saveTag()">
    <div class="modal-actions">
      <button class="btn btn-ghost" onclick="closeModal('tagModal')">Cancel</button>
      <button class="btn btn-primary" onclick="saveTag()">Create</button>
    </div>
  </div>
</div>

<!-- Add Tag to Note Modal -->
<div class="modal-overlay" id="addTagNoteModal">
  <div class="modal">
    <h3>Add Tag</h3>
    <input type="text" id="noteTagNameInput" placeholder="Enter tag name…" onkeydown="if(event.key==='Enter')addTagToNote()">
    <div style="margin-top:12px;font-size:12px;color:var(--text-tertiary)">Or select existing:</div>
    <div id="existingTagsList" style="max-height:150px;overflow-y:auto;margin-top:8px"></div>
    <div class="modal-actions">
      <button class="btn btn-ghost" onclick="closeModal('addTagNoteModal')">Cancel</button>
      <button class="btn btn-primary" onclick="addTagToNote()">Add</button>
    </div>
  </div>
</div>

<!-- Context Menu -->
<div class="context-menu" id="contextMenu">
  <div class="ctx-item" onclick="renameFolderCtx()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 3a2.83 2.83 0 114 4L7.5 20.5 2 22l1.5-5.5z"/></svg> Rename</div>
  <div class="ctx-item danger" onclick="deleteFolderCtx()"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#e74c3c" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14"/></svg> Delete</div>
</div>

<!-- Toast Container -->
<div class="toast-container" id="toastContainer"></div>

<script>
// ── State ──
let state = {
  notes: [],
  folders: [{id:'default',name:'All Notes',icon:'📝'}],
  tags: ['personal','work','ideas'],
  activeNoteId: null,
  activeFolderId: 'default',
  activeTagId: null,
  theme: 'light',
  sortByDate: true
};

// ── Init ──
function init() {
  loadState();
  if (!state.notes.length) seedData();
  applyTheme();
  renderFolders();
  renderTags();
  renderNoteList();
}

function seedData() {
  const now = Date.now();
  state.notes = [
    {id:genId(),title:'Welcome to NoteFlow ✨',content:'<h2>Your personal notes app</h2><p>NoteFlow is a beautiful, distraction-free writing environment. Here are some things you can do:</p><ul><li>Create and organize notes into folders</li><li>Tag your notes for easy filtering</li><li>Use the formatting toolbar to style your text</li><li>Search through all your notes instantly</li></ul><blockquote>Your notes are saved automatically in your browser.</blockquote><h3>Keyboard Shortcuts</h3><p><b>Ctrl+B</b> — Bold<br><b>Ctrl+I</b> — Italic<br><b>Ctrl+U</b> — Underline</p>',folder:'default',tags:['personal'],created:now-86400000,modified:now,pinned:true},
    {id:genId(),title:'Meeting Notes — Q4 Planning',content:'<h3>Attendees</h3><ul><li>Sarah (PM)</li><li>Mike (Design)</li><li>Alex (Engineering)</li></ul><h3>Action Items</h3><ol><li>Finalize product roadmap by Friday</li><li>Schedule design review sessions</li><li>Set up sprint planning board</li></ol><p><i>Follow-up meeting next Tuesday at 2pm.</i></p>',folder:'default',tags:['work'],created:now-172800000,modified:now-3600000,pinned:false},
    {id:genId(),title:'Book Recommendations 📚',content:'<h3>Currently Reading</h3><p><em>Atomic Habits</em> by James Clear — 75% done</p><h3>To Read</h3><ul><li>Digital Minimalism — Cal Newport</li><li>The Design of Everyday Things — Don Norman</li><li>Sapiens — Yuval Noah Harari</li></ul>',folder:'default',tags:['personal','ideas'],created:now-259200000,modified:now-7200000,pinned:false},
    {id:genId(),title:'Project Ideas 💡',content:'<h3>App Concepts</h3><p>A habit tracker with social accountability features. Users can pair up and check in daily.</p><h3>Features to Explore</h3><ul><li>Streak visualization</li><li>Weekly progress reports</li><li>Gamification elements</li></ul>',folder:'default',tags:['ideas'],created:now-345600000,modified:now-86400000,pinned:false},
    {id:genId(),title:'Recipe Collection 🍳',content:'<h3>Pasta Carbonara</h3><p>Ingredients: spaghetti, eggs, pecorino cheese, guanciale, black pepper.</p><p>Cook pasta al dente. Fry guanciale until crispy. Mix eggs with cheese. Combine everything off heat for creamy sauce.</p>',folder:'default',tags:['personal'],created:now-432000000,modified:now-172800000,pinned:false}
  ];
  saveState();
}

// ── Persistence ──
function loadState() {
  try {
    const s = localStorage.getItem('noteflow_state');
    if (s) state = {...state, ...JSON.parse(s)};
  } catch(e) {}
}
function saveState() {
  try { localStorage.setItem('noteflow_state', JSON.stringify(state)); } catch(e) {}
}

// ── Helpers ──
function genId() { return Date.now().toString(36) + Math.random().toString(36).slice(2,8); }
function stripHtml(html) { const d=document.createElement('div');d.innerHTML=html;return d.textContent||''; }
function formatDate(ts) {
  const d=new Date(ts), now=new Date();
  if(d.toDateString()===now.toDateString()) return 'Today';
  const y=new Date(now);y.setDate(y.getDate()-1);
  if(d.toDateString()===y.toDateString()) return 'Yesterday';
  return d.toLocaleDateString('en-US',{month:'short',day:'numeric'});
}

// ── Theme ──
function toggleTheme() {
  state.theme = state.theme==='dark'?'light':'dark';
  applyTheme(); saveState();
}
function applyTheme() {
  document.documentElement.setAttribute('data-theme', state.theme);
  document.getElementById('themeLabel').textContent = state.theme==='dark'?'Light Mode':'Dark Mode';
}

// ── Folders ──
function renderFolders() {
  const el = document.getElementById('folderList');
  let html = `<div class="folder-item ${state.activeFolderId==='default'&&state.activeTagId===null?'active':''}" onclick="selectFolder('default')">
    <span class="folder-icon">📝</span> All Notes <span class="folder-count">${state.notes.length}</span></div>`;
  state.folders.forEach(f => {
    const count = state.notes.filter(n=>n.folder===f.id).length;
    html += `<div class="folder-item ${state.activeFolderId===f.id&&state.activeTagId===null?'active':''}" onclick="selectFolder('${f.id}')" oncontextmenu="showCtxMenu(event,'${f.id}')">
      <span class="folder-icon">${f.icon||'📁'}</span> ${escHtml(f.name)} <span class="folder-count">${count}</span></div>`;
  });
  el.innerHTML = html;
}

function selectFolder(id) {
  state.activeFolderId = id;
  state.activeTagId = null;
  renderFolders(); renderTags(); renderNoteList();
}

function showFolderModal() { document.getElementById('folderModal').classList.add('show'); setTimeout(()=>document.getElementById('folderNameInput').focus(),100); }
function saveFolder() {
  const name = document.getElementById('folderNameInput').value.trim();
  if(!name) return;
  state.folders.push({id:genId(),name,icon:'📁'});
  saveState(); renderFolders(); closeModal('folderModal');
  document.getElementById('folderNameInput').value='';
  toast('Folder created','success');
}

// ── Tags ──
function renderTags() {
  const el = document.getElementById('tagList');
  let html = '';
  state.tags.forEach(t => {
    const count = state.notes.filter(n=>n.tags&&n.tags.includes(t)).length;
    if(count===0 && !state.activeTagId) return; // hide empty tags unless active
    html += `<div class="tag-item ${state.activeTagId===t?'active':''}" onclick="selectTag('${escHtml(t)}')">
      <span style="color:var(--accent)">#</span> ${escHtml(t)} <span class="folder-count">${count}</span></div>`;
  });
  el.innerHTML = html || '<div style="padding:4px 12px;font-size:12px;color:var(--text-tertiary)">No tags yet</div>';
}

function selectTag(tag) {
  state.activeTagId = tag;
  renderFolders(); renderTags(); renderNoteList();
}

function showTagModal() { document.getElementById('tagModal').classList.add('show'); setTimeout(()=>document.getElementById('tagNameInput').focus(),100); }
function saveTag() {
  const name = document.getElementById('tagNameInput').value.trim().toLowerCase();
  if(!name || state.tags.includes(name)) return;
  state.tags.push(name);
  saveState(); renderTags(); closeModal('tagModal');
  document.getElementById('tagNameInput').value='';
  toast('Tag created','success');
}

// ── Notes ──
function getFilteredNotes() {
  let notes = [...state.notes];
  if(state.activeFolderId !== 'default' && !state.activeTagId) notes = notes.filter(n=>n.folder===state.activeFolderId);
  if(state.activeTagId) notes = notes.filter(n=>n.tags&&n.tags.includes(state.activeTagId));
  const q = document.getElementById('searchInput').value.trim().toLowerCase();
  if(q) notes = notes.filter(n => n.title.toLowerCase().includes(q) || stripHtml(n.content).toLowerCase().includes(q));
  // pinned first, then sort
  notes.sort((a,b)=>{
    if(a.pinned && !b.pinned) return -1;
    if(!a.pinned && b.pinned) return 1;
    return state.sortByDate ? (b.modified-a.modified) : a.title.localeCompare(b.title);
  });
  return notes;
}

function renderNoteList() {
  const notes = getFilteredNotes();
  document.getElementById('noteCount').textContent = `${notes.length} note${notes.length!==1?'s':''}`;
  const el = document.getElementById('noteList');
  if(!notes.length) {
    el.innerHTML = '<div style="text-align:center;padding:40px 20px;color:var(--text-tertiary);font-size:13px">No notes found</div>';
    return;
  }
  el.innerHTML = notes.map(n => `
    <div class="note-card ${state.activeNoteId===n.id?'active':''}" onclick="openNote('${n.id}')" oncontextmenu="showNoteCtx(event,'${n.id}')">
      ${n.pinned?'<span class="pin-indicator">📌</span>':''}
      <div class="note-card-title">${escHtml(n.title||'Untitled')}</div>
      <div class="note-card-preview">${stripHtml(n.content).slice(0,120)}</div>
      <div class="note-card-meta"><span>${formatDate(n.modified)}</span></div>
      ${n.tags&&n.tags.length?`<div class="note-card-tags">${n.tags.map(t=>`<span class="mini-tag">#${escHtml(t)}</span>`).join('')}</div>`:''}
    </div>`).join('');
}

function filterNotes() { renderNoteList(); }
function toggleSort() { state.sortByDate=!state.sortByDate; renderNoteList(); toast(state.sortByDate?'Sorted by date':'Sorted alphabetically','info'); }

function createNote() {
  const note = {
    id:genId(), title:'', content:'', folder:state.activeFolderId==='default'?(state.folders[1]?.id||'default'):state.activeFolderId,
    tags:[], created:Date.now(), modified:Date.now(), pinned:false
  };
  state.notes.unshift(note);
  saveState(); renderNoteList(); renderFolders(); openNote(note.id);
}

function openNote(id) {
  const note = state.notes.find(n=>n.id===id);
  if(!note) return;
  state.activeNoteId = id;
  document.getElementById('emptyState').style.display='none';
  const ec = document.getElementById('editorContent');
  ec.style.display='flex';
  document.getElementById('noteTitleInput').value = note.title;
  document.getElementById('editorArea').innerHTML = note.content;
  document.getElementById('noteDate').textContent = `Modified ${formatDate(note.modified)}`;
  renderEditorTags(); updateWordCount(); renderNoteList();
}

function onTitleChange() {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  note.title = document.getElementById('noteTitleInput').value;
  note.modified = Date.now();
  scheduleSave();
}

let saveTimer;
function onContentChange() {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  note.content = document.getElementById('editorArea').innerHTML;
  note.modified = Date.now();
  updateWordCount();
  document.getElementById('saveStatus').textContent='Saving…';
  clearTimeout(saveTimer);
  saveTimer = setTimeout(()=>{
    saveState(); renderNoteList(); renderFolders();
    document.getElementById('noteDate').textContent=`Modified ${formatDate(note.modified)}`;
    document.getElementById('saveStatus').textContent='Saved ✓';
  },500);
}

function scheduleSave() {
  clearTimeout(saveTimer);
  saveTimer = setTimeout(()=>{ saveState(); renderNoteList(); },300);
}

function updateWordCount() {
  const text = stripHtml(document.getElementById('editorArea').innerHTML).trim();
  const words = text?text.split(/\s+/).length:0;
  document.getElementById('wordCount').textContent=`${words} word${words!==1?'s':''}`;
  document.getElementById('charCount').textContent=`${text.length} characters`;
}

// ── Editor Tags ──
function renderEditorTags() {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  const el = document.getElementById('editorTags');
  el.innerHTML = (note.tags||[]).map(t=>`<span class="editor-tag" onclick="removeTagFromNote('${escHtml(t)}')">${escHtml(t)} <span class="tag-remove">×</span></span>`).join('');
}

function removeTagFromNote(tag) {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  note.tags = (note.tags||[]).filter(t=>t!==tag);
  saveState(); renderEditorTags(); renderNoteList(); renderTags();
}

function showAddTagToNote() {
  const el = document.getElementById('existingTagsList');
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  el.innerHTML = (state.tags||[]).filter(t=>!(note?.tags||[]).includes(t)).map(t=>`<div class="folder-item" onclick="applyTagToNote('${escHtml(t)}')" style="padding:6px 8px;font-size:13px"># ${escHtml(t)}</div>`).join('') || '<div style="font-size:12px;color:var(--text-tertiary);padding:4px">No existing tags</div>';
  document.getElementById('addTagNoteModal').classList.add('show');
  setTimeout(()=>document.getElementById('noteTagNameInput').focus(),100);
}

function addTagToNote() {
  const tag = document.getElementById('noteTagNameInput').value.trim().toLowerCase();
  if(!tag) return;
  applyTagToNote(tag);
}

function applyTagToNote(tag) {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  if(!state.tags.includes(tag)) state.tags.push(tag);
  if(!note.tags) note.tags=[];
  if(!note.tags.includes(tag)) note.tags.push(tag);
  saveState(); renderEditorTags(); renderNoteList(); renderTags(); closeModal('addTagNoteModal');
  document.getElementById('noteTagNameInput').value='';
}

// ── Note Actions ──
function deleteNote() {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  if(!confirm(`Delete "${note.title||'Untitled'}"?`)) return;
  state.notes = state.notes.filter(n=>n.id!==note.id);
  state.activeNoteId=null;
  saveState(); renderNoteList(); renderFolders(); renderTags();
  document.getElementById('editorContent').style.display='none';
  document.getElementById('emptyState').style.display='flex';
  toast('Note deleted','info');
}

function duplicateNote() {
  const note = state.notes.find(n=>n.id===state.activeNoteId);
  if(!note) return;
  const dup = {...note, id:genId(), title:note.title+' (copy)', created:Date.now(), modified:Date.now(), tags:[...(note.tags||[])]};
  state.notes.unshift(dup);
  saveState(); renderNoteList(); openNote(dup.id);
  toast('Note duplicated','success');
}

// ── Formatting ──
function execCmd(cmd, val) { document.execCommand(cmd,false,val||null); document.getElementById('editorArea').focus(); }
function execHeading(tag) { document.execCommand('formatBlock',false,tag); document.getElementById('editorArea').focus(); }
function insertHR() { document.execCommand('insertHTML',false,'<hr>'); document.getElementById('editorArea').focus(); }

// ── Sidebar Toggle ──
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('collapsed'); }

// ── Context Menu ──
let ctxTarget = null;
function showCtxMenu(e, folderId) { e.preventDefault(); ctxTarget=folderId; const m=document.getElementById('contextMenu'); m.style.left=e.clientX+'px';m.style.top=e.clientY+'px';m.classList.add('show'); }
function showNoteCtx(e, noteId) { /* future: per-note context menu */ }
document.addEventListener('click',()=>{ document.getElementById('contextMenu').classList.remove('show'); });

function renameFolderCtx() {
  const f = state.folders.find(x=>x.id===ctxTarget);
  if(!f) return;
  const name=prompt('Rename folder:',f.name);
  if(name&&name.trim()){f.name=name.trim();saveState();renderFolders();toast('Renamed','success');}
}
function deleteFolderCtx() {
  const f = state.folders.find(x=>x.id===ctxTarget);
  if(!f) return;
  if(!confirm(`Delete "${f.name}"? Notes will move to All Notes.`)) return;
  state.notes.filter(n=>n.folder===f.id).forEach(n=>n.folder='default');
  state.folders=state.folders.filter(x=>x.id!==f.id);
  saveState();renderFolders();renderNoteList();toast('Folder deleted','info');
}

// ── Modals ──
function closeModal(id) { document.getElementById(id).classList.remove('show'); }
document.querySelectorAll('.modal-overlay').forEach(m => m.addEventListener('click', e=>{ if(e.target===m) closeModal(m.id); }));

// ── Toast ──
function toast(msg, type='info') {
  const el = document.createElement('div');
  el.className=`toast ${type}`;
  el.innerHTML = `${type==='success'?'✓':'ℹ'} ${msg}`;
  document.getElementById('toastContainer').appendChild(el);
  setTimeout(()=>{el.style.opacity='0';el.style.transition='opacity .3s';setTimeout(()=>el.remove(),300)},2500);
}

// ── Escape HTML ──
function escHtml(s) { const d=document.createElement('div');d.textContent=s;return d.innerHTML; }

// ── Keyboard Shortcuts ──
document.addEventListener('keydown', e => {
  if((e.ctrlKey||e.metaKey)&&e.key==='k') { e.preventDefault(); document.getElementById('searchInput').focus(); }
});

// ── Start ──
init();
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingcap-qwen3.6-27b","provider":"lmstudio","persona":"middle","sessionId":"eaeecb39-b13c-4086-90b7-4bb03394b664","tokensIn":15140,"tokensOut":12963,"tokensTotal":28103,"turns":2,"toolCalls":1,"failedToolCalls":0,"timestamp":"2026-07-18T22:41:41.622Z"} -->