5d35dcfe03
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
355 lines
22 KiB
Markdown
355 lines
22 KiB
Markdown
---
|
|
banner: pixel-banner-images/wp4254880-dark-4k-wallpapers.jpg
|
|
banner-height: 460
|
|
pixel-banner-flag-color: white
|
|
---
|
|
# Journal App — Dev Log
|
|
|
|
> Single-file offline journal with timeline UI, calendar navigation, and markdown export.
|
|
> Stack: Pure HTML/CSS/JS · IndexedDB · No dependencies
|
|
> File: `C:\Users\jbrock\Documents\pisyncfolder\Journal App\journal.html`
|
|
|
|
---
|
|
|
|
## Status
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| Version | v1.10 |
|
|
| Status | Active Development |
|
|
| Started | April 7, 2026 |
|
|
| Last Updated | April 27, 2026 (v1.10) |
|
|
|
|
---
|
|
|
|
## Changelog
|
|
|
|
### v1.10 — April 27, 2026
|
|
- **Project card timeline connector** — CSS-only horizontal connector line extending from each breakout card's left edge back to the main timeline vertical line; implemented via `.breakout-card::before` (205px accent-colored line at 50% card height, opacity 0.5) and `.breakout-card::after` (12px dot centered on the timeline line at `left: -211px`); `position: relative` added to `.breakout-card`; no layout constraints broken
|
|
- **Breakout card inline rename** — `edit` button added to breakout card action row (between `open →` and `✕`); clicking it swaps the project name display to a `.breakout-name-input` field and replaces action buttons with `save`/`cancel`; save writes both the `projectName` field on the breakout entry (`updateEntry`) and the canonical name in the projects store (`updateProject`), then refreshes the project cache and re-renders; `Enter` submits, `Escape` cancels; `updateProject(id, fields)` added as a new DB helper on `PROJECTS_STORE`
|
|
|
|
### v1.9 — April 21, 2026
|
|
- **CSS custom properties** — all 8 theme colors now defined as CSS variables in `:root` (`--bg-primary`, `--bg-secondary`, `--bg-accent`, `--accent`, `--accent-hover`, `--text-primary`, `--text-secondary`, `--text-muted`, `--disabled`); all hardcoded hex values replaced throughout `<style>` block; prerequisite for future dark/light theme toggle
|
|
- **Toast notifications** — slide-up toast (bottom-right, 3.5s auto-dismiss, accent border glow) appears on entry save, entry delete, and project note save; error toast shown if a DB call fails
|
|
- **Keyboard shortcut `N`** — press `N` from anywhere (when not in a text field) to jump focus to the main entry textarea; `Escape` closes the side panel or blurs the active input
|
|
- **Scanline overlay** — subtle CRT scanline texture via `body::before` repeating gradient; matches terminal aesthetic
|
|
- **Bug fix: `getKnownProjects()` crash** — function called `.trim()` on `projectId` for all entries including breakout markers, which store `projectId` as a number; fixed by filtering to `type !== 'breakout'` and `typeof projectId === 'string'` before mapping
|
|
- **Bug fix: `activateGroupFilter()` crash** — same root cause; added `type !== 'breakout'` guard to prevent `.trim()` TypeError on numeric project IDs
|
|
- **Error handling in panel submit** — added try/catch to `panelSubmit`; previously failed silently on any DB error; now shows error toast and logs to console
|
|
- **Borrowed from TaskOpi** (`C:\Users\jbrock\Documents\pisyncfolder\taskopi`) — toast pattern, keyboard shortcut pattern, CSS variable architecture, scanline overlay technique
|
|
|
|
### v1.8 — April 21, 2026
|
|
- Added **Project Breakout Panels** — side panel system for project-scoped note-taking alongside the main journal timeline
|
|
- Bumped IndexedDB to **version 2**; added two new object stores: `projects` (id, name, created) and `project_entries` (id, projectId, text, date, timestamp, mood, tags) with a `projectId` index on `project_entries`
|
|
- Added **breakout marker** entry type in the existing `entries` store (`type: 'breakout'`); inserted into the main timeline at the selected date to show where a context switch occurred
|
|
- **Breakout card** renders in the timeline in place of a regular entry — shows project name, live entry count, `open →` button, and a `✕` delete button; card is indented to match timeline flow but uses a card style (no dot/line)
|
|
- **`+ Project` button** added to the input row (left of word count); opens an inline prompt with datalist autocomplete from existing projects; confirm creates/reuses the project and inserts the breakout marker
|
|
- **Side panel** slides in from the right when `open →` is clicked; main timeline stays visible alongside it (`flex-direction: row` layout); panel shows project entries grouped by date, newest first
|
|
- Panel has its own textarea + Add Entry button; Ctrl+Enter also submits; entries are saved to `project_entries` (completely separate from the main journal stream)
|
|
- `closeProjectPanel()` hides the panel and restores single-column layout
|
|
- **Safety guards added**: `exportMarkdown` filters out breakout markers (no `text` field); `activateGroupFilter` skips breakout markers to avoid `.trim()` TypeError on numeric `projectId`
|
|
- New DB helpers: `createProject`, `getAllProjects`, `saveProjectEntry`, `getProjectEntries`, `getProjectEntryCount`, `insertBreakoutMarker`, `deleteBreakoutMarker`
|
|
|
|
### v1.7 — April 13, 2026
|
|
- Added **project ID field** on each entry — optional text input in the new-entry form; saves as `projectId` on the IndexedDB entry object
|
|
- Added **project badge** (`.entry-site-badge`) on every entry card — displays project name in accent red with a left-border pill style; falls back to `"GENERAL"` when no project is set
|
|
- Added **smart autocomplete** for the project field — `getKnownProjects()` reads all unique `projectId` values from IndexedDB and populates a native `<datalist>`; suggestions refresh after every save and on page load
|
|
- **Timeline stays strictly chronological** — all entries sort by timestamp descending regardless of project assignment; project context shown inline via badge rather than separate sections
|
|
- **Chronological group ordering** — when multiple projects are active in a day, sections sort by the most-recent entry timestamp in each group (not alphabetically), preserving the expected reading order
|
|
- Added CSS for collapsible project-section headers (`.project-group`, `.project-group-header`, `.project-group-entries`, `.project-group-chevron`) — available for future use if grouped view is desired
|
|
|
|
### v1.6 — April 8, 2026
|
|
- Added **word count display** in the input actions row (between selected date and Add Entry button)
|
|
- Live counter updates on every keystroke; resets to "0 words" after saving
|
|
- Singular "1 word" / plural "N words" formatting
|
|
- Styled with `text-secondary` color (#888888) at 0.75rem
|
|
|
|
### v1.5 — April 8, 2026
|
|
- Added **Jump to Today** button in month nav row (right of `>` arrow)
|
|
- Resets `currentYear`, `currentMonth`, and `selectedDate` to today; re-renders calendar, timeline, and date display
|
|
- Subtle ghost style (muted border + text); accent hover on approach
|
|
|
|
### v1.4 — April 8, 2026
|
|
- Added **entry count badge** on calendar days with entries
|
|
- `getDaysWithEntries()` now returns `Map<day, count>` instead of `Set<day>`
|
|
- Calendar cells with entries render two-line layout: day number + small count below
|
|
- Badge is bold, slightly transparent white, 0.6rem — stays within the 36px circle
|
|
- Days without entries unchanged
|
|
|
|
### v1.3 — April 8, 2026
|
|
- Added **mood/energy tag** selector in input area (😊 😐 😤 😴) — optional per entry
|
|
- Mood stored as `mood` field on each IndexedDB entry
|
|
- Selected mood highlights with accent border; click again to deselect (toggle)
|
|
- Mood clears automatically after each save
|
|
- Mood emoji shown in entry footer alongside the date
|
|
- Stats bar shows live mood tally for today (e.g. `😊×2 😴`) — hidden if no moods logged today
|
|
- Markdown export includes mood emoji inline with timestamp
|
|
- `saveEntry()` updated with optional `mood = null` parameter
|
|
|
|
### v1.2 — April 8, 2026
|
|
- Added **delete entry** — button appears on hover at end of entry footer; requires confirm before removal
|
|
- Added **edit entry text** — click "edit" to replace entry text with an inline textarea; Enter saves, Escape cancels, blur saves
|
|
- Added **time updater** — click any timestamp to open a native time input inline; Enter/blur saves, Escape cancels
|
|
- Added `deleteEntry(id)` and `updateEntry(id, fields)` IndexedDB helpers
|
|
- Entry HTML now includes `data-id` and `data-date` attributes for DOM-driven edits
|
|
- Entry footer restructured: date (left) + action buttons (right, fade in on hover)
|
|
|
|
### v1.1 — April 8, 2026
|
|
- Added stats bar between header and main
|
|
- Stats: entries today · current streak · peak hour · 30-day activity heatmap
|
|
- Heatmap uses 4-level intensity scale matching accent color palette
|
|
- `renderStatsBar()` called on init and after every new entry save
|
|
|
|
### v1.0 — April 7, 2026
|
|
- Initial build
|
|
- Vertical timeline with connecting line and entry dots
|
|
- 12-hour timestamp format
|
|
- Auto-scroll to newest entry
|
|
- Text input with Ctrl+Enter shortcut
|
|
- Mini calendar (top-right) with entry day highlighting and click-to-navigate
|
|
- Month navigation (Prev/Next)
|
|
- Export current month to Markdown (.md)
|
|
- IndexedDB persistence
|
|
|
|
---
|
|
|
|
## Roadmap
|
|
|
|
Items are ordered by priority within each tier. Check off as completed.
|
|
|
|
### 🔴 High Priority
|
|
|
|
- [x] **Stats bar** — Compact strip above the timeline showing: entries today, current streak (consecutive days with ≥1 entry), most active hour, 30-day activity heatmap (GitHub-style)
|
|
- [x] **Delete entry** — Delete button at end of entry content, subtle styling, confirm step before removal
|
|
- [x] **Edit entry text** — Click entry text to edit inline; save on blur or Enter
|
|
- [x] **Time updater** — Click timestamp to edit it inline; maintain 12-hour format
|
|
- [ ] data storage for notes
|
|
|
|
### 🟡 Medium Priority
|
|
|
|
- [x] **Entry count badge on calendar days** — Show number of entries per day inside the calendar dot/cell
|
|
- [x] **Mood/energy tag** — Optional tag per entry (😊 😐 😤 😴); stored with entry; shown in stats over time
|
|
- [x] **Jump to Today button** — One-click return to today's date from any month view
|
|
- [ ] **Date range export** — Replace current "export this month" with a date picker (from / to) so the user can export any span of days; UI appears as a small inline form triggered from the export button
|
|
- [x] **Word count display** — Live counter in the input area while writing
|
|
- [x] **Project breakout panels** — Insert a breakout card into the main timeline that links to a separate project timeline in a side panel; project entries are independent from the main journal *(Implemented v1.8)*
|
|
|
|
### 🟢 Low Priority
|
|
|
|
- [ ] **Delete project notes** — Delete button on individual entries inside the project side panel; requires `deleteProjectEntry(id)` DB helper on `project_entries` store and re-render of panel timeline + breakout card count
|
|
- [x] **Project card timeline connector** — Visual line extending from the breakout card's left edge to the main timeline vertical line; implemented via `::before`/`::after` pseudo-elements on `.breakout-card` *(v1.10)*
|
|
- [ ] Follow-up: breakout dot still slightly off-center on the timeline — needs positional tweak
|
|
|
|
- [x] **Project grouping within timeline** — Project badge on each entry card; timeline stays chronological; autocomplete from prior project names; collapsible section CSS ready for future grouped view
|
|
- [ ] **Dark/Light theme toggle** — User preference stored in localStorage
|
|
- [ ] **Pinned/starred entries** — Star an entry to surface it at top of day or in a favorites view
|
|
- [ ] **Markdown preview** — Toggle between raw and rendered markdown in entry view
|
|
- [ ] **Keyboard navigation** — Navigate entries with arrow keys
|
|
- [ ] **Backup/Restore** — Export/import entire IndexedDB as JSON
|
|
|
|
---
|
|
# Future update Ideas
|
|
1. Multi team - Groups can work on the same time line for the same day projects.
|
|
1. Time line would show the name of the person who input an entry into the timeline
|
|
2.
|
|
|
|
---
|
|
|
|
## Design Constraints (Do Not Change)
|
|
|
|
These values are calibrated to prevent visual overlap between the timeline line, dot, and timestamp text.
|
|
|
|
| Element | Property | Value |
|
|
|---------|----------|-------|
|
|
| Timeline padding-left | `padding-left` | `120px` |
|
|
| Timeline line position | `left` | `50px` |
|
|
| Entry dot position | `left` | `-75px` |
|
|
| Entry time position | `left` | `-105px` |
|
|
| Entry time width | `width` | `95px` |
|
|
| Entry time text-align | `text-align` | `right` |
|
|
|
|
**Note on new UI elements:** Delete buttons belong at the end of `.entry-content`, small and muted. Edit controls should appear inline without breaking the dot/line layout.
|
|
|
|
---
|
|
|
|
## Color Profile
|
|
|
|
| Token | Hex | Usage |
|
|
|-------|-----|-------|
|
|
| `bg-primary` | `#1a1a2e` | Body background |
|
|
| `bg-secondary` | `#16213e` | Header, entry cards, input section |
|
|
| `bg-accent` | `#0f3460` | Timeline line, borders, inactive states |
|
|
| `accent` | `#e94560` | Dots, buttons, highlights, selected states |
|
|
| `accent-hover` | `#ff6b6b` | Button hover |
|
|
| `text-primary` | `#eaeaea` | Main text |
|
|
| `text-secondary` | `#888888` | Timestamps, labels |
|
|
| `text-muted` | `#666666` | Empty state, entry dates |
|
|
| `disabled` | `#444444` | Disabled button backgrounds |
|
|
|
|
---
|
|
|
|
## Layout
|
|
|
|
# This area needs to be updated
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ [Stats Bar: streak · entries today · heatmap] │
|
|
├─────────────────────────────────────────────────────┤
|
|
│ [Mini Calendar] [Export Button] │
|
|
│ [◄ Month ►] │
|
|
├─────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ 10:30 AM │ ● Entry 3 [edit][del] │
|
|
│ │ │
|
|
│ 8:15 AM │ ● Entry 2 [edit][del] │
|
|
│ │ │
|
|
│ 7:00 AM │ ● Entry 1 [edit][del] │
|
|
│ │ │
|
|
├─────────────────────────────────────────────────────┤
|
|
│ [Text Input Area] [word count] │
|
|
│ [Selected Date] [Add Entry ▶] │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Dev Notes
|
|
|
|
- All CSS lives in the `<style>` block; all JS in the `<script>` block at the bottom — keep it that way
|
|
- To reset data: DevTools (F12) → Application → IndexedDB → Delete `JournalDB`
|
|
- Works in any modern browser with no build step
|
|
- IndexedDB is per-origin — the file needs to be served from the same path to retain data
|
|
|
|
### Future Storage Options (if needed)
|
|
- **SQLite-WASM** — runs in-browser, more robust querying
|
|
- **Electron wrapper** — native app feel, access to filesystem
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
```
|
|
Journal App/
|
|
├── journal.html # The complete application
|
|
└── MASTER_PROJECT_LOG.md # This file
|
|
```
|
|
|
|
---
|
|
## Noted updates
|
|
4/8/2026
|
|
All changes are complete. Here's what was added:
|
|
|
|
**New features:**
|
|
|
|
- **Tag input** in the new-entry form (between mood and textarea) — type a tag and press `Enter` or `,` to add it; `Backspace` removes the last tag; comma-separated pastes work too
|
|
- **Tag chips on entry cards** — saved tags display as `#tagname` pills; clicking one activates the tag filter
|
|
- **Tag filter view** — clicking any tag chip shows all entries with that tag across all dates, grouped by date, with a "Filtered by: #tag [✕ Clear]" bar at the top
|
|
- **Inline tag editing** — a "tags" button on each card opens the tag input widget inline; focus-away saves and reverts to chips
|
|
- **Markdown export** — tags are appended as `#tagname` at the end of each exported entry line
|
|
|
|
**Backward compatible** — existing entries without tags render cleanly with no errors.
|
|
|
|
---
|
|
|
|
## Project Breakout Panels (Future Feature — Fully Planned)
|
|
|
|
**Goal:** Insert a breakout card into the main timeline that links to a separate project timeline displayed in a slide-in side panel. Project entries are completely independent from the main journal.
|
|
|
|
**Motivation:** When switching between multiple tasks/projects during a workday, users need a way to context-switch cleanly — keeping project notes separate from general journal entries, while still seeing where the switch happened in the main timeline.
|
|
|
|
### User Decisions (Finalized)
|
|
- **Panel style:** Side panel — slides in from the right, main timeline stays visible alongside it
|
|
- **Entry ownership:** Project-only — entries added in the panel do not appear in the main day timeline
|
|
- **Insert trigger:** Manual — a "+" button in the input area; user names the project at that moment
|
|
|
|
### Visual Layout
|
|
```
|
|
┌──────────────────────┬─────────────────────────────┐
|
|
│ Main Timeline │ 🔗 BOM Project [✕]│
|
|
│ ───────────────── ├─────────────────────────────┤
|
|
│ 4:24 PM ● [entry] │ 4:24 PM ● Last BOM page │
|
|
│ │ 3:09 PM ● Updating parts │
|
|
│ ┌──────────────────┐ │ │
|
|
│ │ 🔗 BOM Project │ │ ┌─────────────────────────┐ │
|
|
│ │ 3 entries [open→]│─┼▶│ Add note to project... │ │
|
|
│ └──────────────────┘ │ └─────────────────────────┘ │
|
|
│ │ [ Add Entry ] │
|
|
│ 3:09 PM ● [entry] │ │
|
|
└──────────────────────┴─────────────────────────────┘
|
|
```
|
|
|
|
### Data Model
|
|
Requires IndexedDB **version bump from 1 → 2**, adding two new object stores:
|
|
|
|
```javascript
|
|
// 'projects' store
|
|
{ id: number (auto), name: string, created: string (ISO) }
|
|
|
|
// 'project_entries' store (index on projectId)
|
|
{ id: number (auto), projectId: number, text: string,
|
|
date: string, timestamp: number, mood: string|null, tags: string[] }
|
|
|
|
// Breakout markers — stored in existing 'entries' store as a special type:
|
|
{ type: 'breakout', projectId: number, projectName: string, date, timestamp, id }
|
|
```
|
|
|
|
### New DB Functions Needed
|
|
- `createProject(name)` → Promise\<id\>
|
|
- `getAllProjects()` → Promise\<project[]\>
|
|
- `saveProjectEntry(projectId, text, date, mood, tags)` → Promise\<id\>
|
|
- `getProjectEntries(projectId)` → Promise\<entry[]\> sorted desc by timestamp
|
|
- `getProjectEntryCount(projectId)` → Promise\<number\>
|
|
- `insertBreakoutMarker(projectId, projectName, date)` → saves to `entries` store
|
|
- `deleteBreakoutMarker(id)` → deletes from `entries` store
|
|
|
|
### New State Variables
|
|
```javascript
|
|
let activePanelProjectId = null; // number | null
|
|
let existingProjects = []; // cache for autocomplete
|
|
```
|
|
|
|
### HTML Changes
|
|
1. Wrap `timeline-container` + `input-section` in `<div class="main-col">` inside `<main>`
|
|
2. Add `<div id="sidePanel" class="side-panel" style="display:none">` as sibling in `<main>`
|
|
- Contains: header (title + ✕ close), scrollable timeline div, input area (textarea + Add Entry)
|
|
3. Add `<button id="insertBreakoutBtn" class="project-break-btn">+ Project</button>` in `input-actions`
|
|
|
|
### renderTimeline() Changes
|
|
- Detect `entry.type === 'breakout'` in the map — render a breakout card instead of a regular entry
|
|
- Breakout card shows: project name, entry count (loaded async), "open →" button, ✕ delete button
|
|
- Add event listeners: open panel on "open →" click; delete marker on ✕ click
|
|
|
|
### New Functions
|
|
- `openProjectPanel(projectId, projectName)` — shows panel, sets title, calls `renderProjectTimeline()`
|
|
- `closeProjectPanel()` — hides panel, removes `main--panel-open` class
|
|
- `renderProjectTimeline(projectId)` — loads project entries, renders them in panel (grouped by date)
|
|
- `showBreakoutPrompt(projects)` — inline name input with autocomplete; on confirm creates/reuses project and inserts breakout marker
|
|
|
|
### CSS Changes
|
|
- `main.main--panel-open { flex-direction: row; }` — switches main from column to row layout
|
|
- `.main-col { flex: 1; display: flex; flex-direction: column; overflow: hidden; }` — wraps current content
|
|
- `.side-panel { width: 360px; flex-shrink: 0; }` — fixed width panel with slide-in animation
|
|
- `.breakout-card` — styled differently from regular entries; accent left border, card-style with "open →" button
|
|
- `.project-break-btn` — dashed ghost button in input-actions area
|
|
|
|
### Implementation Order
|
|
1. Bump `DB_VERSION` to 2; add `projects` and `project_entries` stores in `onupgradeneeded`
|
|
2. Add all new DB helper functions
|
|
3. Add new state variables
|
|
4. Update HTML: add `.main-col` wrapper, `#sidePanel`, `#insertBreakoutBtn`
|
|
5. Modify `renderTimeline()` to handle `type === 'breakout'` cards
|
|
6. Add `openProjectPanel()`, `closeProjectPanel()`, `renderProjectTimeline()`
|
|
7. Add `showBreakoutPrompt()` and confirm handler
|
|
8. Wire up panel submit handler and close button in `init()`
|
|
9. Add all CSS
|
|
|
|
---
|
|
|
|
## Project Grouping Design (Earlier Exploration — Superseded)
|
|
|
|
*The breakout panel approach above was chosen over this option. Kept for reference.*
|
|
|
|
**Original concept:** Add a `project` field to each regular entry, then group entries by project within the day timeline using section headers. Clicking a header shows a cross-date filtered view for that project.
|
|
|
|
**Why not chosen:** The breakout panel approach is cleaner — project notes stay completely separate from the journal stream, and the side-by-side panel feels more natural for context-switching between tasks. |