← Notes results

Notes

ornith 1.0 9b · basic

Initial view of Notes

Browser check: Artifact runtime error. This is a technical check, not a quality review.

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 40,337 bytes · SHA-256 4df47e22aa48
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lumina Notes</title>
<style>
  :root {
    --bg-primary: #ffffff;
    --bg-secondary: #f7f8fa;
    --bg-tertiary: #eef0f4;
    --text-primary: #1a1a2e;
    --text-secondary: #556079;
    --text-muted: #8b98aa;
    --accent: #6c5ce7;
    --accent-light: rgba(108, 92, 231, 0.1);
    --border: #e2e6ea;
    --sidebar-width: 260px;
    --right-panel-width: 280px;
    --radius: 10px;
    --shadow-sm: 0 1px 3px rgba(0,0,0,0.04);
    --shadow-md: 0 4px 16px rgba(0,0,0,0.06);
    --hover-bg: rgba(108,92,231,0.05);
    --active-border: #6c5ce7;
    --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
  }

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

  body {
    font-family: var(--font-body);
    background: var(--bg-primary);
    color: var(--text-primary);
    height: 100vh;
    overflow: hidden;
  }

  /* --- Layout --- */
  .app-container {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr var(--right-panel-width);
    min-height: 100vh;
  }

  .left-sidebar, .editor-area {
    background: var(--bg-primary);
    border-right: 1px solid var(--border);
  }

  .editor-area {
    overflow-y: auto;
    padding: 2rem 3rem;
  }

  .right-panel {
    background: var(--bg-secondary);
    border-left: 1px solid var(--border);
    overflow-y: auto;
  }

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

  /* --- Sidebar Items --- */
  .sidebar-header {
    padding: 20px 20px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .logo {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--accent);
    letter-spacing: -0.5px;
  }

  .search-box {
    flex: 1;
    margin: 12px 16px 24px;
    position: relative;
  }

  .search-box input {
    width: 100%;
    padding: 9px 14px 9px 38px;
    border: 1.5px solid var(--border);
    border-radius: 8px;
    font-size: 0.85rem;
    color: var(--text-primary);
    background: var(--bg-secondary);
    transition: all 0.2s;
    outline: none;
  }

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

  .search-box::before {
    content: '🔍';
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.8rem;
  }

  /* --- Note Group --- */
  .note-group {
    border-left: 3px solid var(--accent);
    margin: 0 16px 24px;
  }

  .group-header {
    padding: 16px 18px 8px;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    font-weight: 600;
  }

  .note-item {
    padding: 12px 18px;
    cursor: pointer;
    border-radius: 8px;
    transition: all 0.2s;
    position: relative;
  }

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

  .note-item.active {
    background: var(--active-border);
    color: white;
  }

  .note-title {
    font-size: 0.9rem;
    font-weight: 600;
    margin-bottom: 4px;
    line-height: 1.35;
  }

  .note-item.active .note-title { color: white; }

  .note-preview {
    font-size: 0.8rem;
    color: var(--text-secondary);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .note-item.active .note-preview { color: rgba(255,255,255,0.7); }

  /* --- Add Note Button --- */
  .add-note-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s;
    color: var(--text-secondary);
  }

  .add-note-btn:hover {
    background: var(--hover-bg);
    color: var(--accent);
  }

  .note-item.active + .add-note-btn,
  .add-note-btn:hover:not(.active) {
    color: var(--accent);
  }

  .btn-icon { font-size: 1.2rem; opacity: 0.5; transition: opacity 0.2s; }
  .add-note-btn:hover .btn-icon { opacity: 1; }

  /* --- Editor Area --- */
  .editor-area { background: var(--bg-primary); }

  .editor-header {
    padding-bottom: 1rem;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--border);
  }

  .breadcrumb {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 4px;
  }

  .note-title-editor {
    width: 100%;
    border: none;
    font-size: 2rem;
    font-weight: 700;
    color: var(--text-primary);
    background: transparent;
    padding: 4px 0;
    outline: none;
    line-height: 1.3;
    letter-spacing: -0.5px;
  }

  .note-meta {
    display: flex;
    gap: 1rem;
    margin-top: 8px;
    font-size: 0.78rem;
    color: var(--text-muted);
  }

  .meta-tag { padding: 2px 8px; border-radius: 6px; background: var(--accent-light); color: var(--accent); font-weight: 500; }
  .meta-date { opacity: 0.7; }

  /* --- Markdown Editor --- */
  #markdown-input {
    width: 100%;
    min-height: calc(100vh - 280px);
    border: none;
    padding: 1rem 0;
    font-family: var(--font-mono);
    font-size: 0.95rem;
    line-height: 1.75;
    color: var(--text-primary);
    background: transparent;
    resize: none;
    outline: none;
  }

  /* --- Rendered Output --- */
  #output-panel {
    display: none;
    padding-bottom: 2rem;
  }

  .render-block { margin-bottom: 1.5em; }
  h1, h2, h3, h4 { color: var(--text-primary); line-height: 1.3; margin-top: 0.8em; }
  h1 { font-size: 2rem; border-bottom: 2px solid var(--border); padding-bottom: 8px; }
  h2 { font-size: 1.5rem; border-left: 4px solid var(--accent); padding-left: 12px; margin-top: 0.6em; }
  h3 { font-size: 1.2rem; color: var(--text-secondary); }
  p { line-height: 1.75; color: var(--text-primary); }

  .code-block {
    background: #f4f5f8;
    border-radius: 8px;
    padding: 16px;
    font-size: 0.9rem;
    overflow-x: auto;
    border: 1px solid var(--border);
    margin-bottom: 1em;
  }

  .code-block code { font-family: var(--font-mono); color: #d63384; }
  pre code { background: none; padding: 0; }

  ul, ol { padding-left: 1.5rem; line-height: 1.75; }
  li { margin-bottom: 0.2em; }

  blockquote {
    border-left: 3px solid var(--accent);
    background: var(--accent-light);
    padding: 12px 16px;
    margin: 0.8em 0;
    font-size: 0.95rem;
    color: var(--text-secondary);
    border-radius: 0 8px 8px 0;
  }

  a { color: var(--accent); text-decoration: none; border-bottom: 1px dashed transparent; transition: all 0.2s; }
  a:hover { border-bottom-color: var(--accent); }

  img { max-width: 100%; border-radius: 8px; margin: 1em 0; }

  hr { border: none; border-top: 2px solid var(--border); margin: 1.5em 0; }
  table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
  th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border); }
  th { color: var(--text-secondary); font-weight: 600; background: var(--bg-secondary); }

  /* --- Right Panel --- */
  .panel-header {
    padding: 24px 24px 16px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1rem;
  }

  .panel-title { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 1px; color: var(--text-muted); font-weight: 600; }

  /* --- Tags Section --- */
  .tag-section { padding: 24px; border-bottom: 1px solid var(--border); margin-bottom: 1rem; }
  .add-tag-input { width: 100%; padding: 8px 14px; border: 1.5px solid var(--border); border-radius: 8px; font-size: 0.85rem; color: var(--text-primary); outline: none; background: var(--bg-secondary); margin-bottom: 12px; transition: all 0.2s; }
  .add-tag-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }

  .tag-list { display: flex; flex-wrap: wrap; gap: 8px; }
  .tag-chip { padding: 5px 14px; background: var(--accent-light); color: var(--accent); border-radius: 20px; font-size: 0.8rem; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 6px; }
  .tag-chip:hover { background: var(--accent) !important; color: white !important; }

  /* --- Metadata Section --- */
  .meta-row { padding: 8px 0; font-size: 0.85rem; }
  .meta-label { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; color: var(--text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; }

  /* --- Create Modal --- */
  .modal-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,0.4); backdrop-filter: blur(4px);
    display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; pointer-events: none; transition: opacity 0.3s;
  }

  .modal-overlay.open { opacity: 1; pointer-events: auto; }

  .modal-card {
    background: var(--bg-primary); border-radius: 16px; padding: 2rem; width: 480px; max-height: 70vh; overflow-y: auto; box-shadow: var(--shadow-md); transform: scale(0.95); transition: transform 0.3s;
  }

  .modal-overlay.open .modal-card { transform: scale(1); }

  .modal-title { font-size: 1.2rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.5rem; }
  .modal-subtitle { font-size: 0.85rem; color: var(--text-muted); margin-bottom: 1.5rem; }

  .form-group { margin-bottom: 1.2rem; }

  .form-label { display: block; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 6px; font-weight: 600; }

  .form-input, .form-textarea {
    width: 100%; padding: 10px 14px; border: 1.5px solid var(--border); border-radius: 8px; font-size: 0.9rem; color: var(--text-primary); background: var(--bg-secondary); outline: none; transition: all 0.2s;
    font-family: var(--font-body);
  }

  .form-input:focus, .form-textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
  .form-textarea { min-height: 80px; resize: vertical; line-height: 1.5; }

  /* --- Action Buttons --- */
  .btn {
    padding: 10px 24px; border-radius: 8px; font-size: 0.9rem; font-weight: 600; cursor: pointer; transition: all 0.2s; border: none;
  }

  .btn-primary { background: var(--accent); color: white; }
  .btn-primary:hover { background: #5a4bd7; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(108,92,231,0.3); }

  .btn-outline { background: transparent; color: var(--text-secondary); border: 1.5px solid var(--border); margin-left: 8px; }
  .btn-outline:hover { border-color: var(--accent); color: var(--accent); }

  /* --- Editor Toolbar --- */
  .editor-toolbar { display: flex; gap: 2px; padding: 6px 0; }

  .toolbar-btn {
    width: 34px; height: 34px; border-radius: 6px; border: none; background: transparent; cursor: pointer; font-size: 1rem; color: var(--text-secondary); display: flex; align-items: center; justify-content: center; transition: all 0.2s;
  }

  .toolbar-btn:hover { background: var(--hover-bg); color: var(--accent); }

  /* --- Empty State --- */
  .empty-state {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center;
    display: none;
  }

  .empty-icon { font-size: 3rem; margin-bottom: 1rem; opacity: 0.4; }
  .empty-text { color: var(--text-muted); font-size: 0.95rem; line-height: 1.6; }
  .empty-sub { color: var(--text-muted); font-size: 0.85rem; margin-top: 4px; opacity: 0.7; }

  /* --- Quick Actions (sidebar bottom) --- */
  .quick-actions { padding: 20px 16px; border-top: 1px solid var(--border); font-size: 0.85rem; }
  .qa-item { display: flex; align-items: center; gap: 10px; padding: 8px 0; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; border-left: 3px solid transparent; margin-left: -16px; }
  .qa-item:hover { color: var(--accent); background: var(--hover-bg); }

  /* --- Toast --- */
  .toast-container { position: fixed; bottom: 24px; right: 24px; z-index: 2000; display: flex; flex-direction: column; gap: 8px; }
  .toast { background: #1a1a2e; color: white; padding: 12px 20px; border-radius: 10px; font-size: 0.85rem; box-shadow: var(--shadow-md); animation: slideIn 0.3s ease forwards; opacity: 0; transform: translateY(20px); }
  .toast.show { opacity: 1; transform: translateY(0); animation: fadeOut 0.4s ease 2.6s forwards; }

  @keyframes slideIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }

  /* --- Selection styling for markdown input --- */
  #markdown-input::selection { background: rgba(108,92,231,0.15); }

  /* --- Code highlight colors --- */
  .hljs-comment { color: #6a737d; font-style: italic; }
  .hljs-keyword { color: #c73e43; }
  .hljs-string { color: #032851; background: #f8f9fa; padding: 1px 4px; border-radius: 3px; }
  .hljs-number { color: #0550ae; font-weight: 600; }

  /* --- Responsive --- */
  @media (max-width: 1200px) {
    :root { --sidebar-width: 240px; --right-panel-width: 0; }
  }

  @media (max-width: 768px) {
    .app-container { grid-template-columns: 1fr !important; }
    .left-sidebar, .right-panel { display: none !important; }
    .editor-area { padding: 1rem; overflow-y: auto !important; min-height: 100vh !important; border-right: none; }
  }

  /* --- Font loading --- */
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');

  /* --- Tags with color coding --- */
  .tag-color-1 { background: #e8f5e9 !important; color: #2e7d32 !important; }
  .tag-color-2 { background: #e3f2fd !important; color: #1565c0 !important; }
  .tag-color-3 { background: #fff3e0 !important; color: #ef6c00 !important; }
  .tag-color-4 { background: #fce4ec !important; color: #c62828 !important; }
</style>
</head>
<body>

<div class="app-container">

  <!-- LEFT SIDEBAR -->
  <div class="left-sidebar">
    <div class="sidebar-header">
      <span class="logo">◈ Lumina Notes</span>
    </div>
    <div class="search-box">
      <input type="text" placeholder="Search notes..." id="sidebar-search">
    </div>

    <div id="note-groups">
      <!-- Dynamically rendered -->
    </div>

    <div class="add-note-btn" id="btn-add-note">
      <span>+ New Note</span>
      <span class="btn-icon">+</span>
    </div>

    <div class="quick-actions">
      <div class="qa-item"><span style="font-size:1.2rem;">📋</span> Export Notes</div>
      <div class="qa-item"><span style="font-size:1.2rem;">⚡</span> Quick Capture</div>
      <div class="qa-item"><span style="font-size:1.2rem;">🌙</span> Toggle Theme</div>
    </div>
  </div>

  <!-- EDITOR AREA -->
  <div class="editor-area" id="editor-area">
    <div id="empty-state" class="empty-state" style="display:block;">
      <div class="empty-icon">◈</div>
      <div class="empty-text">Select a note to start writing,<br>or create one below.</div>
      <div class="empty-sub">Your thoughts, perfectly organized.</div>
    </div>

    <!-- Header -->
    <div class="editor-header" id="header-section" style="display:none;">
      <div class="breadcrumb" id="breadcrumb"></div>
      <input type="text" class="note-title-editor" id="title-input" placeholder="Untitled Note">
      <div class="note-meta" id="meta-info" style="display:none;"></div>
    </div>

    <!-- Toolbar -->
    <div class="editor-toolbar" id="toolbar-section" style="display:none;">
      <button class="toolbar-btn" title="Bold" onclick="insertMarkdown('**')"><b>B</b></button>
      <button class="toolbar-btn" title="Italic" onclick="insertMarkdown('*')"><i>I</i></button>
      <button class="toolbar-btn" title="Strikethrough" onclick="insertMarkdown('~~')"><s>S</s></button>
      <div style="width:1px;background:var(--border);margin:0 4px;"></div>
      <button class="toolbar-btn" title="Heading 1" onclick="insertMarkdown('# ')">H1</button>
      <button class="toolbar-btn" title="Heading 2" onclick="insertMarkdown('## ')">H2</button>
      <button class="toolbar-btn" title="Bullet List" onclick="insertMarkdown('- ')">•</button>
      <button class="toolbar-btn" title="Numbered List" onclick="insertMarkdown('1. ')">1.</button>
      <div style="width:1px;background:var(--border);margin:0 4px;"></div>
      <button class="toolbar-btn" title="Code Block" onclick="insertMarkdown('```')"><code>⌨</code></button>
      <button class="toolbar-btn" title="Blockquote" onclick="insertMarkdown('> ')">"</button>
      <div style="width:1px;background:var(--border);margin:0 4px;"></div>
      <button class="toolbar-btn" title="Link" onclick="insertMarkdown('[text](url)')">🔗</button>
      <button class="toolbar-btn" title="Image" onclick="insertMarkdown('![alt](src)')">🖼️</button>
    </div>

    <!-- Markdown Input -->
    <textarea id="markdown-input" placeholder="Write your thoughts here...&#10;&#10;# Title&#10;&#10;**Bold** and *italic* text&#10;&#10;- List item&#10;&#10;"># Welcome to Lumina Notes

Start by selecting or creating a note. You can write in **Markdown** format, use headings, code blocks, lists — everything you need for powerful notes.
</textarea>
    <div id="output-panel"></div>
  </div>

  <!-- RIGHT PANEL -->
  <div class="right-panel" style="display:none;" id="right-panel">
    <div class="panel-header">
      <span class="panel-title">Metadata</span>
    </div>
    <div class="tag-section">
      <input type="text" class="add-tag-input" placeholder="Add a tag..." id="new-tag-input" style="margin-top:0;">
      <div class="tag-list" id="note-tags"></div>
    </div>

    <div class="panel-header"><span class="panel-title">Properties</span></div>
    <div id="meta-properties">
      <div class="meta-row">
        <div class="meta-label">Created</div>
        <span id="prop-created"></span>
      </div>
      <div class="meta-row">
        <div class="meta-label">Modified</div>
        <span id="prop-modified"></span>
      </div>
    </div>
  </div>

</div>

<!-- Create Modal -->
<div class="modal-overlay" id="create-modal">
  <div class="modal-card">
    <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem;">
      <h3 class="modal-title" style="margin:0;">New Note</h3>
      <button class="btn btn-outline" onclick="closeModal()" style="margin-left:auto;padding:6px 14px;font-size:0.8rem;">✕</button>
    </div>

    <div class="form-group">
      <label class="form-label">Title</label>
      <input type="text" class="form-input" id="modal-title" placeholder="Enter note title...">
    </div>

    <div class="form-group">
      <label class="form-label">Group / Folder</label>
      <select class="form-input" id="modal-folder" style="cursor:pointer;">
        <option value="Inbox">📥 Inbox</option>
        <option value="Ideas">💡 Ideas</option>
        <option value="Projects">🚀 Projects</option>
        <option value="Journal">📔 Journal</option>
      </select>
    </div>

    <div class="form-group" style="margin-top:1rem;">
      <label class="form-label">Quick Capture (Markdown)</label>
      <textarea class="form-textarea" id="modal-content" placeholder="# Title&#10;&#10;Type your note content here..."></textarea>
    </div>

    <div style="display:flex;gap:8px;margin-top:1.5rem;">
      <button class="btn btn-primary" onclick="createNoteFromModal()" style="flex:1;">Create Note</button>
    </div>
  </div>
</div>

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

<script>
// ==================== DATA STORE ====================
const defaultGroups = [
  { name: 'Inbox', notes: [], color: '#6c5ce7' },
  { name: 'Ideas', notes: [], color: '#00b894' },
  { name: 'Projects', notes: [], color: '#fdcb6e' },
  { name: 'Journal', notes: [], color: '#e17055' }
];

let allNotes = [];
let activeNoteId = null;
let searchFilter = '';

// ==================== INIT ====================
function init() {
  // Load from localStorage if available
  const stored = localStorage.getItem('lumina_notes');
  if (stored) {
    try { allNotes = JSON.parse(stored); } catch(e) {}
  } else {
    seedSampleData();
  }

  renderSidebar();
  bindEvents();
}

function seedSampleData() {
  const now = new Date().toISOString();
  allNotes = [
    { id: 'n1', title: 'Getting Started Guide', content: '# Welcome to Lumina Notes\n\nThis is your **personal knowledge base**. Here\'s what you can do:\n\n## Features\n\n- ✍️ Write in rich **Markdown**\n- 📁 Organize notes into groups\n- 🔖 Tag your thoughts for easy retrieval\n- ⚡ Capture ideas instantly with the toolbar buttons\n- 🔍 Search across all your notes\n\n> "Notes are good. The best ones are the ones you\'ll actually read." — Naval Ravikant\n\n## Quick Tips\n\n1. Use `**bold**` and *italic* for emphasis\n2. Press **Ctrl+K** to search quickly\n3. Drag-and-drop files into notes (coming soon)\n4. Tag important notes with colored labels\n\n---\n\nBuilt with ❤️ using modern web technologies.',
      group: 'Inbox', tags: ['getting-started'], created: new Date(Date.now() - 86400000).toISOString(), modified: now, starred: true },
    { id: 'n2', title: 'Project Roadmap Q1 2025', content: '# Project Roadmap\n\n## Current Sprint\n\n### Completed ✅\n- User authentication flow\n- Dashboard layout optimization\n- Dark mode implementation\n\n### In Progress 🔄\n- Analytics integration\n- API rate limiting\n\n### Planned 🔜\n- Real-time collaboration\n- Mobile PWA support\n\n> "The expert in anything was once a beginner." — Helen Hayes',
      group: 'Projects', tags: ['roadmap','planning'], created: new Date(Date.now() - 172800000).toISOString(), modified: now, starred: false },
    { id: 'n3', title: 'Book Club Notes', content: '# Book Club Discussion\n\n## Reading "Atomic Habits" by James Clear\n\n### Key Takeaways\n\n> *"You do not rise to the level of your goals. You fall to the level of your systems."* — James Clear\n\n1. **Identity-based habits** are more powerful than goal-based ones\n2. Environment design matters more than willpower\n3. The 2-minute rule: start small, then expand\n4. Track your behavior — make it visible\n\n### Discussion Questions\n- How do you currently form new habits?\n- What environment changes could help you in 2025?\n',
      group: 'Journal', tags: ['books','reading'], created: new Date(Date.now() - 604800000).toISOString(), modified: now, starred: true },
    { id: 'n4', title: '#! Daily Journal — October 15, 2024', content: '# Daily Reflection\n\n## Today\'s Highlights\n\n- Finished the new design system mockups\n- Had a great conversation about career growth at work\n- Started reading "Zero to One" by Peter Thiel\n\n> *"The best time to plant a tree was 20 years ago. The second best time is now."* — Chinese Proverb',
      group: 'Journal', tags: ['reflection','daily'], created: new Date(Date.now() - 43200000).toISOString(), modified: now, starred: false },
    { id: 'n5', title: 'JavaScript Patterns', content: '# Common JS Patterns\n\n## Module Pattern\n```javascript\nconst myModule = (function() {\n  let privateVar = "secret";\n  return {\n    publicMethod() {\n      console.log(privateVar);\n    }\n  };\n})();\n```\n\n## Observer Pattern\n```javascript\nclass Observable {\n  constructor() { this._observers = []; }\n  subscribe(observer) { this._observers.push(observer); }\n  notify(data) { this._observers.forEach(o => o.update(data)); }\n}\n```\n\n> *"Simplicity is the soul of efficiency."* — Austin Freeman',
      group: 'Ideas', tags: ['coding','javascript'], created: new Date(Date.now() - 259200000).toISOString(), modified: now, starred: false },
    { id: 'n6', title: 'Travel Wishlist', content: '# Places to Visit\n\n## Bucket List\n\n- 🏔️ [ ] Patagonia, Argentina — Hiking & nature\n- 🌊 [ ] Amalfi Coast, Italy — Mediterranean vibes\n- 🏜️ [ ] Sahara Desert, Morocco — Camel trek\n- ⛰️ [ ] Banff National Park, Canada — Mountains & lakes\n- 🏝️ [ ] Okinawa, Japan — Island culture',
      group: 'Inbox', tags: ['travel','wishlist'], created: new Date(Date.now() - 1209600000).toISOString(), modified: now, starred: true },
    { id: 'n7', title: 'Meeting Notes: Product Sync', content: '# Product Sync — Oct 14\n\n## Attendees\n- Sarah (PM), Mike (Dev), Lisa (Design)\n\n## Decisions\n\n1. MVP scope confirmed for Q1 launch\n2. Figma handoff by Friday\n3. Backend API docs needed before sprint planning\n\n## Action Items\n\n| Owner | Task | Deadline |\n|-------|------|----------|\n| Mike | Write API specs | Oct 20 |\n| Lisa | Finalize components | Oct 18 |\n| Sarah | Update roadmap | Oct 17 |\n',
      group: 'Projects', tags: ['meetings','product'], created: new Date(Date.now() - 460800000).toISOString(), modified: now, starred: false },
    { id: 'n8', title: 'Recipe Collection', content: '# My Cookbook\n\n## Breakfast\n\n### Avocado Toast with Everything Seasoning\n```markdown
Ingredients:\n- 2 slices sourdough bread\n- 1 ripe avocado\n- Salt, pepper, everything seasoning\n\nSteps:\n1. Toast the bread until golden\n2. Mash avocado with a fork\n3. Spread on toast and season generously',
      group: 'Journal', tags: ['recipes','food'], created: new Date(Date.now() - 9500000).toISOString(), modified: now, starred: false }
  ];

  // Assign colors to groups that don't have them
  const existingGroups = [];
  defaultGroups.forEach(g => { if (!g.notes) g.notes = []; });
}

// ==================== RENDERING ====================
function renderSidebar() {
  const container = document.getElementById('note-groups');
  
  // Group notes by folder
  const groupsByFolder = {};
  allNotes.forEach(note => {
    const group = note.group || 'Unfiled';
    if (!groupsByFolder[group]) groupsByFolder[group] = [];
    groupsByFolder[group].push(note);
  });

  // Also ensure Inbox exists for new notes
  if (!allNotes.some(n => n.group === 'Inbox')) {
    groupsByFolder['Inbox'] = [];
  }

  let html = '';
  
  Object.entries(groupsByFolder).forEach(([groupName, groupNotes]) => {
    const color = defaultGroups.find(g => g.name === groupName)?.color || '#8b98aa';
    
    if (groupNotes.length === 0) return; // Skip empty groups
    
    html += `<div class="note-group" style="border-left-color: ${color}">`;
    html += `<div class="group-header" style="color:${color};">${groupName}</div>`;
    
    groupNotes.forEach(note => {
      const isActive = activeNoteId === note.id;
      const preview = truncateMarkdown(note.content, 100);
      
      html += `
        <div class="note-item${isActive ? ' active' : ''}" data-id="${note.id}">`;
      html += `<div class="note-title">${escapeHtml(note.title)}</div>`;
      html += `<div class="note-preview">${escapeHtml(preview)}</div>`;
      
      // Tags preview
      if (note.tags && note.tags.length > 0) {
        const tagPreview = note.tags.slice(0, 2).map(t => `#${t}`).join(' ');
        html += `<span style="font-size:0.7rem;color:rgba(255,255,255,0.6);margin-left:4px;">${tagPreview}</span>`;
      }
      
      html += `</div>`;
    });
    
    html += '</div>';
  });

  // Add Unfiled if needed
  const hasUnfiled = Object.keys(groupsByFolder).some(g => g === 'Unfiled');
  
  container.innerHTML = html;
}

function truncateMarkdown(text, maxLen) {
  let processed = text.replace(/^#+\s/gm, '').replace(/\*\*/g, '').replace(/`/g, '');
  if (processed.length > maxLen) processed = processed.substring(0, maxLen - 3) + '...';
  return processed;
}

function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

// ==================== EDITOR FUNCTIONS ====================
function bindEvents() {
  // Note selection
  document.getElementById('note-groups').addEventListener('click', (e) => {
    const noteItem = e.target.closest('.note-item');
    if (!noteItem) return;
    
    activeNoteId = noteItem.dataset.id;
    renderSidebar();
    loadNote(activeNoteId);
  });

  // Title input
  document.getElementById('title-input').addEventListener('input', () => {
    const note = findNoteById(activeNoteId);
    if (note) updateNoteData(activeNoteId, { title: document.getElementById('title-input').value, modified: new Date().toISOString() });
  });

  // Markdown input → live render
  const mdInput = document.getElementById('markdown-input');
  const outputPanel = document.getElementById('output-panel');
  
  function updateOutput() {
    const content = mdInput.value;
    const rendered = markdownToHtml(content);
    
    if (activeNoteId) {
      outputPanel.innerHTML = rendered;
      outputPanel.style.display = 'block';
      
      // Scroll to top on title change
      if (!content.startsWith('#')) {
        window.scrollTo({ top: 0, behavior: 'smooth' });
      }
    } else {
      outputPanel.style.display = 'none';
    }
    
    renderSidebar();
  }
  
  mdInput.addEventListener('input', updateOutput);

  // Search
  document.getElementById('sidebar-search').addEventListener('input', (e) => {
    searchFilter = e.target.value.toLowerCase().trim();
    renderSidebar();
  });

  // Add note button
  document.getElementById('btn-add-note').addEventListener('click', () => {
    openCreateModal();
  });

  // Tag input in right panel
  document.getElementById('new-tag-input').addEventListener('input', (e) => {
    if (e.target.value.length > 3) {
      e.preventDefault();
      const tag = e.target.value.trim().toLowerCase();
      addTagToNote(tag);
      e.target.value = '';
    }
  });

  // Quick capture shortcut
  document.addEventListener('keydown', (e) => {
    if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
      e.preventDefault();
      const searchBox = document.querySelector('#sidebar-search input');
      searchBox.focus();
      searchBox.select();
    }
  });

  // Theme toggle
  document.querySelectorAll('.qa-item').forEach(item => {
    if (item.textContent.includes('Toggle Theme')) {
      item.addEventListener('click', () => {
        const body = document.body;
        body.classList.toggle('dark-theme');
        renderSidebar();
      });
    }
  });
}

function loadNote(id) {
  activeNoteId = id;
  
  if (!id) return;
  
  const note = findNoteById(id);
  if (!note) return;
  
  // Show header
  document.getElementById('empty-state').style.display = 'none';
  document.getElementById('header-section').style.display = 'block';
  document.getElementById('toolbar-section').style.display = 'flex';
  
  // Load content into textarea
  document.getElementById('title-input').value = note.title || '';
  document.getElementById('markdown-input').value = note.content || '';
  
  // Update metadata
  const modifiedDate = new Date(note.modified).toLocaleDateString();
  const createdDate = new Date(note.created).toLocaleDateString();
  
  let metaHtml = `<span class="meta-date">📅 ${modifiedDate}</span>`;
  if (note.starred) metaHtml += ' <span>⭐ Starred</span>';
  
  document.getElementById('meta-info').innerHTML = metaHtml;
  document.getElementById('meta-info').style.display = 'flex';
  
  // Load tags
  loadTags(note);
  
  // Update properties
  document.getElementById('prop-created').textContent = createdDate;
  document.getElementById('prop-modified').textContent = modifiedDate;
  
  // Show right panel
  if (document.getElementById('right-panel').style.display === 'none') {
    document.getElementById('right-panel').style.display = 'block';
  }

  renderSidebar();
}

function findNoteById(id) {
  return allNotes.find(n => n.id === id);
}

function updateNoteData(id, fields) {
  const note = findNoteById(id);
  if (!note) return;
  
  Object.assign(note, fields);
  if (fields.modified) note.modified = new Date(fields.modified).toISOString();
  else note.modified = new Date().toISOString();

  // Save to localStorage
  saveNotes();
}

function deleteNote(id) {
  allNotes = allNotes.filter(n => n.id !== id);
  saveNotes();
  activeNoteId = null;
  
  document.getElementById('empty-state').style.display = 'block';
  document.getElementById('header-section').style.display = 'none';
  document.getElementById('toolbar-section').style.display = 'none';
  document.getElementById('markdown-input').value = '';
  document.getElementById('output-panel').innerHTML = '';
  
  renderSidebar();
}

function insertMarkdown(text) {
  const input = document.getElementById('markdown-input');
  const start = input.selectionStart;
  const end = input.selectionEnd;
  const selectedText = input.value.substring(start, end);
  
  let insertText = text + (selectedText ? ' ' : '');
  
  input.value = input.value.substring(0, start) + insertText + input.value.substring(end);
  input.focus();
  
  // Move cursor after inserted text
  const newCursorPos = start + insertText.length;
  setTimeout(() => { input.selectionStart = input.selectionEnd = newCursorPos; }, 0);
}

// ==================== MARKDOWN RENDERER ====================
function markdownToHtml(md) {
  let html = '';
  
  // Code blocks first (process before other formatting)
  html = md.replace(/```(\w*)\n([\s\S]*?)```/g, '<div class="code-block"><pre><code>$1</code></pre></div>');
  
  // Inline code
  html = html.replace(/`([^`]+)`/g, '<code style="background:rgba(0,0,0,0.06);padding:2px 6px;border-radius:4px;font-size:0.85em;">$1</code>');
  
  // Headers (process from h1 to h4)
  html = html.replace(/^(#{1,4})\s+(.+)$/gm, '<h$1>$2</h$1>');
  
  // Blockquotes
  html = html.replace(/^>\s*(.+)$/gm, '<blockquote>$1</blockquote>');
  
  // Horizontal rules
  html = html.replace(/^---$/gm, '<hr>');
  
  // Bold + Italic (process bold first)
  html = html.replace(/\*\*\*([^\n]+)\*\*/g, '<strong><em>$1</em></strong>');
  html = html.replace(/\*\*([^\n]+)\*\*/g, '<strong>$1</strong>');
  html = html.replace(/\*([^\n]+)\*/g, '<em>$1</em>');
  
  // Links
  html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>');
  
  // Images
  html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
  
  // Tables: detect and convert simple markdown tables
  html = processTables(html);
  
  // Unordered lists (-)
  html = html.replace(/^- (.+)$/gm, '<li>$1</li>');
  
  // Ordered lists (1. or numbered)
  html = html.replace(/^\d+\.\s+(.+)$/gm, '<li style="list-style-type:decimal;">$1</li>');
  
  // Paragraphs (wrap remaining text in p tags, splitting by double newlines)
  html = splitParagraphs(html);
  
  return html;
}

function processTables(mdHtml) {
  const tableRegex = /^(.+)\n\|(.+)\n\|([^\-]+)[\-]+\|/gm;
  let result = '';
  let lastIndex = 0;
  
  function findNextTable() {
    const match = mdHtml.match(tableRegex);
    if (match) return match.index;
    return null;
  }
  
  while ((idx = findNextTable()) !== null) {
    result += mdHtml.substring(lastIndex, idx);
    
    // Parse table rows
    let parsedHeader = '';
    let parsedBody = '';
    
    const headerLine = mdHtml.match(tableRegex)[1];
    const rowLines = [];
    
    for (let i = idx + 4; i < mdHtml.length - 20; i++) {
      if (mdHtml[i] === '|' && mdHtml.substring(i+1, i+5).includes('\n')) break;
      if (i >= idx + 4 && i <= idx + 6) continue; // Skip header and separator
      
      const line = mdHtml.substring(Math.max(idx + 7, i), Math.min(idx + 120, i));
      rowLines.push(line);
      
      if (line.includes('---')) break;
    }
    
    // Parse rows into HTML table
    let tableHtml = '<table>';
    const headerCells = headerLine.split('|').slice(1, -1).map(c => c.trim()).join(',');
    tableHtml += `<tr><th>${headerCells}</th></tr>`;
    
    for (const row of rowLines) {
      if (!row.includes('---')) {
        const cells = row.split('|').slice(1, -1).map(c => c.trim());
        tableHtml += `<tr>${cells.map(c => `<td>${c}</td>`).join('')}</tr>`;
      }
    }
    
    tableHtml += '</table>';
    result += tableHtml;
    lastIndex = idx + 4;
  }
  
  result += mdHtml.substring(lastIndex);
  return result;
}

function splitParagraphs(html) {
  const lines = html.split('\n');
  let result = '';
  let paragraphLines = [];
  
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    if (!line.trim()) {
      if (paragraphLines.length > 0) {
        result += '<p>' + paragraphLines.join('') + '</p>';
        paragraphLines = [];
      }
      result += '\n';
    } else {
      paragraphLines.push(line);
    }
  }
  
  if (paragraphLines.length > 0) {
    result += '<p>' + paragraphLines.join('') + '</p>';
  }
  
  return result;
}

function loadTags(note) {
  const container = document.getElementById('note-tags');
  if (!note.tags || note.tags.length === 0) {
    container.innerHTML = '';
    return;
  }
  
  let html = '<div class="tag-list">';
  note.tags.forEach((tag, index) => {
    const colors = ['tag-color-1', 'tag-color-2', 'tag-color-3', 'tag-color-4'];
    const colorClass = colors[index % colors.length];
    
    html += `<span class="tag-chip ${colorClass}" onclick="removeTagFromNote('${note.id}', '${tag}')">#${tag}</span>`;
  });
  html += '</div>';
  container.innerHTML = html;
}

function addTagToNote(tag) {
  const noteId = activeNoteId;
  if (!noteId) return;
  
  const note = findNoteById(noteId);
  if (note.tags && !note.tags.includes(tag)) {
    note.tags.push(tag);
    updateNoteData(noteId, { tags: [...note.tags] });
    loadTags(note);
    
    // Update sidebar too
    renderSidebar();
  }
}

function removeTagFromNote(id, tag) {
  const note = findNoteById(id);
  if (!note) return;
  
  if (note.tags && note.tags.includes(tag)) {
    note.tags = note.tags.filter(t => t !== tag);
    updateNoteData(id, { tags: [...note.tags] });
    
    // Reload current note
    loadNote(id);
  }
}

// ==================== MODAL ====================
function openCreateModal() {
  document.getElementById('create-modal').classList.add('open');
  setTimeout(() => document.getElementById('modal-title').focus(), 100);
}

function closeModal() {
  document.getElementById('create-modal').classList.remove('open');
}

function createNoteFromModal() {
  const title = document.getElementById('modal-title').value.trim();
  const folder = document.getElementById('modal-folder').value;
  const content = document.getElementById('modal-content').value.trim();
  
  if (!title && !content) {
    showToast('Please add a title or some content');
    return;
  }
  
  const now = new Date().toISOString();
  const id = 'n' + Date.now().toString(36);
  
  const newNote = {
    id,
    title: title || 'Untitled Note',
    content: content || '',
    group: folder,
    tags: [],
    created: now,
    modified: now,
    starred: false
  };
  
  allNotes.push(newNote);
  saveNotes();
  
  closeModal();
  
  // Auto-load the new note
  activeNoteId = id;
  loadNote(id);
  
  showToast('Note created successfully');
}

// ==================== TOAST NOTIFICATIONS ====================
function showToast(message) {
  const container = document.getElementById('toasts');
  const toast = document.createElement('div');
  toast.className = 'toast';
  toast.textContent = message;
  container.appendChild(toast);
  
  setTimeout(() => toast.classList.add('show'), 10);
  setTimeout(() => {
    toast.classList.remove('show');
    setTimeout(() => toast.remove(), 450);
  }, 2600);
}

// ==================== PERSISTENCE ====================
function saveNotes() {
  try {
    localStorage.setItem('lumina_notes', JSON.stringify(allNotes));
  } catch(e) {
    console.warn('Storage full, saving limited data');
  }
}

// ==================== KEYBOARD SHORTCUTS ====================
document.addEventListener('keydown', (e) => {
  if ((e.ctrlKey || e.metaKey)) {
    switch(e.key.toLowerCase()) {
      case 'n': 
        e.preventDefault();
        openCreateModal();
        break;
      case 's':
        e.preventDefault();
        showToast('Notes saved automatically');
        saveNotes();
        break;
    }
  }
});

// ==================== START ====================
init();
</script>
</body>
</html>
<!-- agent-meta {"model":"ornith-1.0-9b","provider":"lmstudio","persona":"basic","sessionId":"c9200f22-f83b-42ef-8a0e-05735abbdb72","tokensIn":217,"tokensOut":12632,"tokensTotal":12849,"turns":1,"toolCalls":0,"failedToolCalls":0,"timestamp":"2026-07-13T17:38:48.539Z"} -->