Back to Main Page

daVinJour

Intro

I was disturbed by the fact that how rigid journalling / note taking on a computer is!
Here is a dev log of the development journey of daVinJour.

Inception

Not everyone is a rigid note taker. By the word 'rigid', I mean following a systematic and organised approach of jotting down notes. At times I am extremely clumsy at noting down observations, while sometimes I love meticulously organising my contents. Presently, I couldn't find anything on the web to suit my odd but reasonable needs. Note taking shouldn't be bound by any constraints, which is in direct contrast of Notion and Obsidian.
I was inspired by da Vinci's approach of note taking a few years ago, the way he scribed down grocery list, portraits and anatomical notes on the same page. This led to the idea of creating a platform where you can have both clumsy notes and organised folders.

daVinJour.


Hits and Trials

The following blocks of code which 'WORK' are a product of many trials and errors. I will be documenting the process of development here. Note: The code snippets are not complete, they are just the parts which I found interesting and worth sharing.

Auto-saving notes


 function queueAutosave() {
      setStatus("Saving…");
      if (saveTimeout) clearTimeout(saveTimeout);
      saveTimeout = setTimeout(saveNow, 1200);
    }

    function cleanup() {
      if (saveTimeout) clearTimeout(saveTimeout);
      if (periodicTimer) clearInterval(periodicTimer);
    }

    updateMetrics();
    setStatus(`Saved at ${formatTime(lastSavedAt)}`);

    // Inline rename by clicking the title (with rebind support and visual affordance)
    setupTitleInlineRename(panel, fileItem);

    panel.querySelector('[data-action="save"]').addEventListener("click", () => {
      saveNow();
      flashButton(panel.querySelector('[data-action="save"]'));
    });
    panel.querySelector('[data-action="close"]').addEventListener("click", () => {
      if (dirty) saveNow();
      cleanup();
      closeOverlay(overlay);
    });

    // Also intercept overlay background click to ensure cleanup
    overlay.addEventListener("click", (e) => {
      if (e.target === overlay) {
        if (dirty) saveNow();
        cleanup();
      }
    });

    // Periodic autosave every 15s if dirty
    periodicTimer = setInterval(() => { if (dirty) saveNow(); }, 15000);

Desktop Snippets


/** @type {Map<string, HTMLElement>} */
const idToIcon = new Map();

function clearDesktop() {
  idToIcon.clear();
  desktop.innerHTML = "";
}

function renderDesktop() {
  const desktopItems = getChildrenOf(null);
  // Keep existing icons when possible to preserve events
  const existingIds = new Set(idToIcon.keys());

  // Remove icons that no longer belong on desktop
  for (const id of existingIds) {
    const it = state.items[id];
    if (!it || it.parentId !== null) {
      const el = idToIcon.get(id);
      if (el && el.parentElement === desktop) desktop.removeChild(el);
      idToIcon.delete(id);
    }
  }

  // Add or update desktop icons
  desktopItems.forEach(item => {
    let iconEl = idToIcon.get(item.id);
    if (!iconEl) {
      iconEl = createIconElement(item);
      idToIcon.set(item.id, iconEl);
      desktop.appendChild(iconEl);
    }
    positionIconElement(iconEl, item.position.x, item.position.y);
    updateIconElement(iconEl, item);
  });
}

function positionIconElement(el, x, y) {
  el.style.left = `${x}px`;
  el.style.top = `${y}px`;
}

function updateIconElement(el, item) {
  const label = el.querySelector(".label");
  const img = el.querySelector("img");
  if (label) label.textContent = item.name;
  if (img) {
    img.src = item.type === "cabinet" ? "icons/cabinet-icon.svg" : "icons/note-icon.svg";
    img.alt = item.type === "cabinet" ? "Cabinet" : "File";
  }
  el.dataset.id = item.id;
  el.dataset.type = item.type;
}

function createIconElement(item) {
  const el = document.createElement("div");
  el.className = "icon";
  el.tabIndex = 0;
  el.dataset.id = item.id;
  el.dataset.type = item.type;

  el.innerHTML = `
    <div class="thumb"><img draggable="false" alt="" /></div>
    <div class="label"></div>
  `;
}

Logs

7 August 2025 0059

8 August 2025 2107

  • Added a basic text editor with a simple toolbar
  • Implemented a basic note saving mechanism using local storage
  • Added a feature to create multiple notes and switch between them
  • Started working on the UI for the note list and note viewer
  • 'Cabinets' to organise related notes added
  • Basic text formatting features
  • Fixed the choppy drag and drop movements on the canvas

21 August 2025 2107

  • This is a project too big for me to pursue alone.
  • My solo work doesn't meet my expecations
  • Put on indefinite hold......