From 4f82dbf364ba818d803e5d2250cd7e5bccd3f48d Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Thu, 19 Feb 2026 22:05:53 +0530 Subject: [PATCH 1/4] Phase1:draft-based notes + safe save/load --- .gitignore | 4 + README.md | 213 +++++++++++++++++++------------------------------ app/index.html | 25 ++++++ app/main.js | 171 +++++++++++++++++++++++++++++++++++++++ app/style.css | 52 ++++++++++++ main.js | 17 ++++ package.json | 11 +++ 7 files changed, 363 insertions(+), 130 deletions(-) create mode 100644 app/index.html create mode 100644 app/main.js create mode 100644 app/style.css create mode 100644 main.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore index 9308a4b..02006f1 100644 --- a/.gitignore +++ b/.gitignore @@ -324,3 +324,7 @@ TSWLatexianTemp* # option is specified. Footnotes are the stored in a file with suffix Notes.bib. # Uncomment the next line to have this generated file ignored. #*Notes.bib + +/notes/ +node_modules/ +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index 3c5adf2..d306990 100644 --- a/README.md +++ b/README.md @@ -48,133 +48,115 @@ ---
-

TODO: Project Name

+

Smart Notes

-[TODO](https://TODO.stability.nexus/) is a ... TODO: Project Description. +[Smart Notes](https://github.com/tani-dubey/Smart-Notes) is a local-first, privacy-focused desktop application for personal knowledge management. +It provides a markdown-based note editor with safe file persistence, draft handling, and dynamic titles, forming a solid foundation for future AI-powered semantic search and RAG features. + +The project prioritizes offline usage, user data ownership, and incremental feature development. --- ## 🚀 Features -TODO: List your main features here: - -- **Feature 1**: Description -- **Feature 2**: Description -- **Feature 3**: Description -- **Feature 4**: Description +Core Editor (Current Prototype) + +- **📝 Markdown note editing**: raw text, no rendering yet +- **💾 Explicit Save / Saved state** with dirty-tracking +- **📄 Draft-based note creation**: + - Auto-creates drafts on first typing + - Finalizes drafts on save +- **🏷️ Dynamic note titles**: + - Filename derived from first line of content + - Empty notes handled as `untitled.md` +- **🔁 Safe file switching**: + - Open, edit, and update multiple notes + - No accidental overwrites or data loss +- **📂 Local filesystem storage**: + - Notes stored as `.md` files on disk + - Fully offline by default + + ⚠️ AI features (semantic search, embeddings, RAG) are planned and intentionally not included yet. --- ## 💻 Tech Stack -TODO: Update based on your project - -### Frontend -- React / Next.js / Flutter / React Native -- TypeScript -- TailwindCSS - -### Backend -- Flask / FastAPI / Node.js / Supabase -- Database: PostgreSQL / SQLite / MongoDB +### Desktop Application +- **Electron** — cross-platform desktop shell +- **HTML / CSS / JavaScript** — UI and editor logic +- **Node.js (fs, path)** — local filesystem access -### AI/ML (if applicable) -- LangChain / LangGraph / LlamaIndex -- Google Gemini / OpenAI / Anthropic Claude -- Vector Database: Weaviate / Pinecone / Chroma -- RAG / Prompt Engineering / Agent Frameworks +### Storage +- Local markdown files `(.md)` +- No database, no cloud dependency -### Blockchain (if applicable) -- Solidity / solana / cardano / ergo Smart Contracts -- Hardhat / Truffle / foundry -- Web3.js / Ethers.js / Wagmi -- OpenZeppelin / alchemy / Infura +### AI/ML (Planned) +- Ollama (local LLMs) +- Embeddings + vector store (local) +- Retrieval-Augmented Generation (RAG) --- ## ✅ Project Checklist -TODO: Complete applicable items based on your project type - -- [ ] **The protocol** (if applicable): - - [ ] has been described and formally specified in a paper. - - [ ] has had its main properties mathematically proven. - - [ ] has been formally verified. -- [ ] **The smart contracts** (if applicable): - - [ ] were thoroughly reviewed by at least two knights of The Stable Order. - - [ ] were deployed to: [Add deployment details] -- [ ] **The mobile app** (if applicable): - - [ ] has an _About_ page containing the Stability Nexus's logo and pointing to the social media accounts of the Stability Nexus. - - [ ] is available for download as a release in this repo. - - [ ] is available in the relevant app stores. -- [ ] **The AI/ML components** (if applicable): - - [ ] LLM/model selection and configuration are documented. - - [ ] Prompts and system instructions are version-controlled. - - [ ] Content safety and moderation mechanisms are implemented. - - [ ] API keys and rate limits are properly managed. - ---- - -## 🔗 Repository Links +- ### Editor + - [x] Local-first design + - [x] Draft handling + - [x] Safe save/load + - [x] Dynamic file naming + - [ ] Markdown rendering (planned) + - [ ] Search (planned) -TODO: Update with your repository structure - -1. [Main Repository](https://github.com/AOSSIE-Org/TODO) -2. [Frontend](https://github.com/AOSSIE-Org/TODO/tree/main/frontend) (if separate) -3. [Backend](https://github.com/AOSSIE-Org/TODO/tree/main/backend) (if separate) +- ### AI / ML (Planned) + - [ ] Local embedding pipeline + - [ ] Hybrid search (keyword + vector) + - [ ] On-device RAG + - [ ] Model backend selection --- ## 🏗️ Architecture Diagram -TODO: Add your system architecture diagram here - ``` -[Architecture Diagram Placeholder] -``` - -You can create architecture diagrams using: -- [Draw.io](https://draw.io) -- [Excalidraw](https://excalidraw.com) -- [Lucidchart](https://lucidchart.com) -- [Mermaid](https://mermaid.js.org) (for code-based diagrams) +smart-notes/ +├─ app/ +│ ├─ index.html +│ ├─ style.css +│ └─ main.js +| +├─ notes/ (optional to have) +│ └─ (your .md files go here) +| +├─ main.js (Entrypoint) +├─ package.json +└─ README.md -Example structure to include: -- Frontend components -- Backend services -- Database architecture -- External APIs/services -- Data flow between components +``` +### Planned Extension +- Python backend for embeddings & RAG +- Local IPC between Electron and backend --- ## 🔄 User Flow - -TODO: Add user flow diagrams showing how users interact with your application - -``` -[User Flow Diagram Placeholder] -``` +image ### Key User Journeys -TODO: Document main user flows: - -1. **User Journey 1**: Description - - Step 1 - - Step 2 - - Step 3 - -2. **User Journey 2**: Description - - Step 1 - - Step 2 - - Step 3 +### User Journey: Create & Save a Note +1. User opens the app +2. Starts typing → draft is auto-created +3. First line becomes the title +4. Clicks Save +5. Draft is finalized and stored as a markdown file -3. **User Journey 3**: Description - - Step 1 - - Step 2 - - Step 3 +### User Journey: Edit Existing Note +1. User clicks a note in the sidebar +2. Content loads into editor +3. User edits content +4. Save updates the file safely --- @@ -182,11 +164,8 @@ TODO: Document main user flows: ### Prerequisites -TODO: List what developers need installed - -- Node.js 18+ / Python 3.9+ / Flutter SDK -- npm / yarn / pnpm -- [Any specific tools or accounts needed] +- Node.js 18+ +- npm ### Installation @@ -195,46 +174,22 @@ TODO: Provide detailed setup instructions #### 1. Clone the Repository ```bash -git clone https://github.com/AOSSIE-Org/TODO.git -cd TODO +git clone https://github.com/AOSSIE-Org/SmartNotes.git +cd SmartNotes ``` #### 2. Install Dependencies ```bash npm install -# or -yarn install -# or -pnpm install ``` -#### 3. Configure Environment Variables(.env.example) - -Create a `.env` file in the root directory: - -```env -# Add your environment variables here -API_KEY=your_api_key -DATABASE_URL=your_database_url -``` - -#### 4. Run the Development Server +#### 3. Run the app ```bash -npm run dev -# or -yarn dev -# or -pnpm dev +npm start ``` -#### 5. Open your Browser - -Navigate to [http://localhost:3000](http://localhost:3000) to see the application. - -For detailed setup instructions, please refer to our [Installation Guide](./docs/INSTALL_GUIDE.md) (if you have one). - --- ## 📱 App Screenshots @@ -257,8 +212,6 @@ Thank you for considering contributing to this project! Contributions are highly ## ✨ Maintainers -TODO: Add maintainer information - - [Maintainer Name](https://github.com/username) - [Maintainer Name](https://github.com/username) @@ -273,8 +226,8 @@ See the [LICENSE](LICENSE) file for details. ## 💪 Thanks To All Contributors -Thanks a lot for spending your time helping TODO grow. Keep rocking 🥂 +Thanks a lot for spending your time helping Smart-Notes grow. Keep rocking 🥂 -[![Contributors](https://contrib.rocks/image?repo=AOSSIE-Org/TODO)](https://github.com/AOSSIE-Org/TODO/graphs/contributors) +[![Contributors](https://contrib.rocks/image?repo=AOSSIE-Org/Smart-Notes)](https://github.com/AOSSIE-Org/Smart-Notes/graphs/contributors) -© 2025 AOSSIE +© 2025 AOSSIE \ No newline at end of file diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..a501d3a --- /dev/null +++ b/app/index.html @@ -0,0 +1,25 @@ + + + + + Smart Notes MVP + + + + +
+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/app/main.js b/app/main.js new file mode 100644 index 0000000..0e8af5a --- /dev/null +++ b/app/main.js @@ -0,0 +1,171 @@ +const fs = require("fs"); +const path = require("path"); + +const notesDir = path.join(__dirname, "..", "notes"); + +const editor = document.getElementById("editor"); +const notesList = document.getElementById("notes-list"); +const newNoteBtn = document.getElementById("new-note"); +const saveBtn = document.getElementById("save-note"); + +let currentNote = null; //filename +let isDraft = false; +let isDirty = false; +let count = 0; + +// Ensure notes directory exists +if (!fs.existsSync(notesDir)) { + fs.mkdirSync(notesDir); +} + +//UI helpers +function updateSaveButton() { + if (isDirty) { + saveBtn.innerText = "💾 Save"; + saveBtn.classList.add("unsaved"); + } else { + saveBtn.innerText = "✅ Saved"; + saveBtn.classList.remove("unsaved"); + } +} +//check if file is empty +function isEditorEmpty() { + return editor.value.trim().length === 0; +} +function getNextUntitled(prefix) { + let count = 1; + let name; + + do { + name = `${prefix}-${count}.md`; + count++; + } while (fs.existsSync(path.join(notesDir, name))); + + return name; +} + + +//dynamic title +function titleToFilename(title) { + return title + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, "") + .trim() + .replace(/\s+/g, "-") + .slice(0, 50) || "untitled"; +} +function getTitleFromEditor() { + const firstLine = editor.value.split("\n")[0]; + return firstLine.trim(); +} + +//Editor change tracking +editor.addEventListener("input", () => { + if (!currentNote) { + // const safeName = titleToFilename( getTitleFromEditor()); + const name = `draft-${Date.now()}.md`; + const filePath = path.join(notesDir, name); + + fs.writeFileSync(filePath, ""); + + currentNote = name; + isDraft = true; + } + + isDirty = true; + updateSaveButton(); +}); + + + +//Load notes list +function loadNotes() { + notesList.innerHTML = ""; + + const files = fs.readdirSync(notesDir); + + files.forEach(file => { + const li = document.createElement("li"); + li.textContent = file; + li.onclick = () => loadNote(file); + notesList.appendChild(li); + }); +} + +//Load a note (EXISTING FILE ONLY) +function loadNote(filename) { + filename = path.basename(filename); // safety + + const filePath = path.join(notesDir, filename); + editor.value = fs.readFileSync(filePath, "utf-8"); + + currentNote = filename; + isDraft = filename.startsWith("draft-"); + isDirty = false; + + updateSaveButton(); +} + +// New note (creates a draft) +newNoteBtn.onclick = () => { + // save current draft if needed + if (currentNote && isDraft && isDirty) { + const oldPath = path.join(notesDir, currentNote); + fs.writeFileSync(oldPath, editor.value); + } + + const name = getNextUntitled("draft-untitled"); + const filePath = path.join(notesDir, name); + + fs.writeFileSync(filePath, ""); + + currentNote = name; + isDraft = true; + editor.value = ""; + + isDirty = false; + updateSaveButton(); + loadNotes(); +}; + + +//Save button +saveBtn.onclick = () => { + if (!currentNote || !isDirty) return; + + let filePath = path.join(notesDir, currentNote); + + if (currentNote.startsWith("draft-")) { + let finalName; + + if (isEditorEmpty()) { + // empty content → untitled + finalName = getNextUntitled("untitled"); + } else { + // non-empty → title-based name + const title = getTitleFromEditor(); + const safeName = titleToFilename(title); + finalName = `${safeName}.md`; + } + + const finalPath = path.join(notesDir, finalName); + + fs.renameSync(filePath, finalPath); + currentNote = finalName; + filePath = finalPath; + isDraft = false; + + loadNotes(); + } + + fs.writeFileSync(filePath, editor.value); + + isDirty = false; + updateSaveButton(); +}; + + + +//Initial load +loadNotes(); +updateSaveButton(); \ No newline at end of file diff --git a/app/style.css b/app/style.css new file mode 100644 index 0000000..a036fcf --- /dev/null +++ b/app/style.css @@ -0,0 +1,52 @@ +body { + margin: 0; + font-family: sans-serif; +} + +#container { + display: flex; + height: 100vh; +} + +#sidebar { + width: 200px; + border-right: 1px solid #ccc; + padding: 10px; +} + +#editor { + flex: 1; + padding: 10px; + font-family: monospace; + font-size: 14px; +} + +#save-note { + padding: 6px 10px; + margin-bottom: 8px; + border: 1px solid #ccc; + background-color: #f5f5f5; + cursor: pointer; + font-size: 13px; + border-radius: 4px; +} + +#save-note:hover { + background-color: #eaeaea; +} + +#editor-toolbar { + border-bottom: 1px solid #ddd; + padding: 6px; + background-color: #fafafa; +} + +#save-note.unsaved { + background-color: #ffeeba; + border-color: #f0ad4e; +} + +button { + width: 100%; + margin-bottom: 10px; +} \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..e07e093 --- /dev/null +++ b/main.js @@ -0,0 +1,17 @@ +const { app, BrowserWindow } = require("electron"); +const path = require("path"); + +function createWindow() { + const win = new BrowserWindow({ + width: 900, + height: 600, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + } + }); + + win.loadFile("app/index.html"); +} + +app.whenReady().then(createWindow); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..4309376 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "smart-notes", + "version": "0.1.0", + "main": "main.js", + "scripts": { + "start": "electron ." + }, + "devDependencies": { + "electron": "^28.0.0" + } +} \ No newline at end of file From c3ffbbc748a3ca0c28c813e919ca364cb203492a Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Fri, 20 Feb 2026 18:09:33 +0530 Subject: [PATCH 2/4] Updated as suggested by coderabbit --- .gitignore | 3 +- app/index.html | 8 ++-- app/main.js | 122 +++++++++++++++++++++++++++++++------------------ app/style.css | 11 ++++- package.json | 2 +- 5 files changed, 94 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 02006f1..b1aa25c 100644 --- a/.gitignore +++ b/.gitignore @@ -326,5 +326,4 @@ TSWLatexianTemp* #*Notes.bib /notes/ -node_modules/ -package-lock.json \ No newline at end of file +node_modules/ \ No newline at end of file diff --git a/app/index.html b/app/index.html index a501d3a..07629f0 100644 --- a/app/index.html +++ b/app/index.html @@ -1,7 +1,9 @@ - + + + Smart Notes MVP @@ -13,10 +15,10 @@ +
- +
-
diff --git a/app/main.js b/app/main.js index 0e8af5a..3c67b93 100644 --- a/app/main.js +++ b/app/main.js @@ -8,17 +8,17 @@ const notesList = document.getElementById("notes-list"); const newNoteBtn = document.getElementById("new-note"); const saveBtn = document.getElementById("save-note"); -let currentNote = null; //filename +let currentNote = null; let isDraft = false; let isDirty = false; -let count = 0; // Ensure notes directory exists if (!fs.existsSync(notesDir)) { fs.mkdirSync(notesDir); } -//UI helpers +// -------------------- UI -------------------- + function updateSaveButton() { if (isDirty) { saveBtn.innerText = "💾 Save"; @@ -28,10 +28,11 @@ function updateSaveButton() { saveBtn.classList.remove("unsaved"); } } -//check if file is empty + function isEditorEmpty() { return editor.value.trim().length === 0; } + function getNextUntitled(prefix) { let count = 1; let name; @@ -44,59 +45,73 @@ function getNextUntitled(prefix) { return name; } - -//dynamic title function titleToFilename(title) { - return title - .toLowerCase() - .replace(/[^a-z0-9\s-]/g, "") - .trim() - .replace(/\s+/g, "-") - .slice(0, 50) || "untitled"; + return ( + title + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, "") + .trim() + .replace(/\s+/g, "-") + .slice(0, 50) || "untitled" + ); } + function getTitleFromEditor() { - const firstLine = editor.value.split("\n")[0]; - return firstLine.trim(); + return editor.value.split("\n")[0].trim(); } -//Editor change tracking -editor.addEventListener("input", () => { - if (!currentNote) { - // const safeName = titleToFilename( getTitleFromEditor()); - const name = `draft-${Date.now()}.md`; - const filePath = path.join(notesDir, name); +// -------------------- AUTO SAVE -------------------- - fs.writeFileSync(filePath, ""); +function autoSaveIfDirty() { + if (!currentNote || !isDirty) return; - currentNote = name; - isDraft = true; - } + const filePath = path.join(notesDir, currentNote); + fs.writeFileSync(filePath, editor.value); + isDirty = false; + updateSaveButton(); +} + +// -------------------- EDITOR TRACKING -------------------- + +editor.addEventListener("input", () => { + if (!currentNote) return; isDirty = true; updateSaveButton(); }); +// -------------------- LOAD NOTES LIST -------------------- - -//Load notes list function loadNotes() { notesList.innerHTML = ""; - const files = fs.readdirSync(notesDir); + const files = fs + .readdirSync(notesDir) + .filter(f => f.endsWith(".md")) + .sort(); files.forEach(file => { const li = document.createElement("li"); li.textContent = file; - li.onclick = () => loadNote(file); + + li.addEventListener("click", () => { + autoSaveIfDirty(); + loadNote(file); + }); + notesList.appendChild(li); }); } -//Load a note (EXISTING FILE ONLY) +// -------------------- LOAD NOTE -------------------- + function loadNote(filename) { - filename = path.basename(filename); // safety + filename = path.basename(filename); const filePath = path.join(notesDir, filename); + + if (!fs.existsSync(filePath)) return; + editor.value = fs.readFileSync(filePath, "utf-8"); currentNote = filename; @@ -104,15 +119,16 @@ function loadNote(filename) { isDirty = false; updateSaveButton(); + + editor.readOnly = false; + editor.disabled = false; + editor.focus(); } -// New note (creates a draft) +// -------------------- NEW NOTE -------------------- + newNoteBtn.onclick = () => { - // save current draft if needed - if (currentNote && isDraft && isDirty) { - const oldPath = path.join(notesDir, currentNote); - fs.writeFileSync(oldPath, editor.value); - } + autoSaveIfDirty(); const name = getNextUntitled("draft-untitled"); const filePath = path.join(notesDir, name); @@ -121,51 +137,67 @@ newNoteBtn.onclick = () => { currentNote = name; isDraft = true; + editor.value = ""; + editor.readOnly = false; + editor.disabled = false; + editor.focus(); isDirty = false; updateSaveButton(); loadNotes(); }; +// -------------------- SAVE BUTTON -------------------- -//Save button saveBtn.onclick = () => { - if (!currentNote || !isDirty) return; + if (!currentNote) return; let filePath = path.join(notesDir, currentNote); + let renamed = false; if (currentNote.startsWith("draft-")) { let finalName; if (isEditorEmpty()) { - // empty content → untitled finalName = getNextUntitled("untitled"); } else { - // non-empty → title-based name const title = getTitleFromEditor(); const safeName = titleToFilename(title); - finalName = `${safeName}.md`; + + let candidate = `${safeName}.md`; + let n = 1; + + while ( + fs.existsSync(path.join(notesDir, candidate)) && + candidate !== currentNote + ) { + candidate = `${safeName}-${n++}.md`; + } + + finalName = candidate; } const finalPath = path.join(notesDir, finalName); fs.renameSync(filePath, finalPath); + currentNote = finalName; filePath = finalPath; isDraft = false; - - loadNotes(); + renamed = true; } fs.writeFileSync(filePath, editor.value); isDirty = false; updateSaveButton(); -}; + editor.focus(); + if (renamed) loadNotes(); +}; +// -------------------- INIT -------------------- -//Initial load loadNotes(); updateSaveButton(); \ No newline at end of file diff --git a/app/style.css b/app/style.css index a036fcf..164e1a4 100644 --- a/app/style.css +++ b/app/style.css @@ -14,11 +14,20 @@ body { padding: 10px; } -#editor { +#main-area { + display: flex; + flex-direction: column; flex: 1; +} + +#editor { padding: 10px; font-family: monospace; font-size: 14px; + flex: 1; + border: none; + outline: none; + resize: none; } #save-note { diff --git a/package.json b/package.json index 4309376..9e0253b 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,6 @@ "start": "electron ." }, "devDependencies": { - "electron": "^28.0.0" + "electron": "^40.0.0" } } \ No newline at end of file From c11124adfbd977bd3d10d3f8a7da63ba3c46eab8 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sat, 21 Feb 2026 12:27:47 +0530 Subject: [PATCH 3/4] resolved coderabbitai reviews --- app/index.html | 5 ++- app/main.js | 99 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/app/index.html b/app/index.html index 07629f0..4f09e52 100644 --- a/app/index.html +++ b/app/index.html @@ -9,7 +9,7 @@ -
+
+
diff --git a/app/main.js b/app/main.js index 3c67b93..6c681a4 100644 --- a/app/main.js +++ b/app/main.js @@ -13,8 +13,13 @@ let isDraft = false; let isDirty = false; // Ensure notes directory exists -if (!fs.existsSync(notesDir)) { - fs.mkdirSync(notesDir); +try{ + if (!fs.existsSync(notesDir)) { + fs.mkdirSync(notesDir); +} +} catch (err) { + console.error("Failed to create notes directory:", err); + alert("Failed to initialize notes directory."); } // -------------------- UI -------------------- @@ -28,7 +33,12 @@ function updateSaveButton() { saveBtn.classList.remove("unsaved"); } } +function showError(message, err) { + console.error(message, err); + alert(message); +} +// helpers function isEditorEmpty() { return editor.value.trim().length === 0; } @@ -60,35 +70,44 @@ function getTitleFromEditor() { return editor.value.split("\n")[0].trim(); } -// -------------------- AUTO SAVE -------------------- - +// AUTO SAVE function autoSaveIfDirty() { if (!currentNote || !isDirty) return; - const filePath = path.join(notesDir, currentNote); - fs.writeFileSync(filePath, editor.value); - - isDirty = false; - updateSaveButton(); + try { + fs.writeFileSync( + path.join(notesDir, currentNote), + editor.value + ); + isDirty = false; + updateSaveButton(); + } catch (err) { + showError("Failed to auto-save note.", err); + } } -// -------------------- EDITOR TRACKING -------------------- - +// EDITOR TRACKING editor.addEventListener("input", () => { if (!currentNote) return; isDirty = true; updateSaveButton(); }); -// -------------------- LOAD NOTES LIST -------------------- - +// LOAD NOTES LIST function loadNotes() { notesList.innerHTML = ""; - const files = fs - .readdirSync(notesDir) - .filter(f => f.endsWith(".md")) - .sort(); + let files = []; + + try { + files = fs + .readdirSync(notesDir) + .filter(f => f.endsWith(".md")) + .sort(); + } catch (err) { + showError("Failed to load notes list.", err); + return; + } files.forEach(file => { const li = document.createElement("li"); @@ -103,16 +122,19 @@ function loadNotes() { }); } -// -------------------- LOAD NOTE -------------------- - +// LOAD NOTE function loadNote(filename) { filename = path.basename(filename); const filePath = path.join(notesDir, filename); - if (!fs.existsSync(filePath)) return; - - editor.value = fs.readFileSync(filePath, "utf-8"); + try { + const content = fs.readFileSync(filePath, "utf-8"); + editor.value = content; + } catch (err) { + showError("Failed to load note.", err); + return; + } currentNote = filename; isDraft = filename.startsWith("draft-"); @@ -125,15 +147,19 @@ function loadNote(filename) { editor.focus(); } -// -------------------- NEW NOTE -------------------- - +// NEW NOTE newNoteBtn.onclick = () => { autoSaveIfDirty(); const name = getNextUntitled("draft-untitled"); const filePath = path.join(notesDir, name); - fs.writeFileSync(filePath, ""); + try { + fs.writeFileSync(filePath, ""); + } catch (err) { + showError("Failed to create new note.", err); + return; + } currentNote = name; isDraft = true; @@ -180,15 +206,24 @@ saveBtn.onclick = () => { const finalPath = path.join(notesDir, finalName); - fs.renameSync(filePath, finalPath); - - currentNote = finalName; - filePath = finalPath; - isDraft = false; - renamed = true; + try { + fs.renameSync(filePath, finalPath); + currentNote = finalName; + filePath = finalPath; + isDraft = false; + renamed = true; + } catch (err) { + showError("Failed to rename draft note.", err); + return; + } } - fs.writeFileSync(filePath, editor.value); + try { + fs.writeFileSync(filePath, editor.value); + } catch (err) { + showError("Failed to save note.", err); + return; + } isDirty = false; updateSaveButton(); From 0da8186db28a958f745e066bd96ae6cd19a41218 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sat, 21 Feb 2026 12:52:25 +0530 Subject: [PATCH 4/4] resolved coderabbitai reviews --- app/style.css | 2 +- main.js | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/style.css b/app/style.css index 164e1a4..3a549d7 100644 --- a/app/style.css +++ b/app/style.css @@ -10,8 +10,8 @@ body { #sidebar { width: 200px; - border-right: 1px solid #ccc; padding: 10px; + box-sizing: border-box; } #main-area { diff --git a/main.js b/main.js index e07e093..f51af19 100644 --- a/main.js +++ b/main.js @@ -1,8 +1,10 @@ const { app, BrowserWindow } = require("electron"); const path = require("path"); +let mainWindow; + function createWindow() { - const win = new BrowserWindow({ + mainWindow = new BrowserWindow({ width: 900, height: 600, webPreferences: { @@ -11,7 +13,23 @@ function createWindow() { } }); - win.loadFile("app/index.html"); + mainWindow.loadFile(path.join(__dirname, "app/index.html")); } -app.whenReady().then(createWindow); \ No newline at end of file +app.whenReady().then(() => { + createWindow(); + + app.on("activate", () => { + // On macOS, recreate window when dock icon clicked + if (BrowserWindow.getAllWindows().length === 0) { + createWindow(); + } + }); +}); + +// Quit app when all windows closed (except macOS) +app.on("window-all-closed", () => { + if (process.platform !== "darwin") { + app.quit(); + } +}); \ No newline at end of file