Skip to content

feat: show recently-opened projects first in picker dropdown#15

Merged
Lexus2016 merged 2 commits into
Lexus2016:mainfrom
apperside:feat/project-picker-recents-first
May 30, 2026
Merged

feat: show recently-opened projects first in picker dropdown#15
Lexus2016 merged 2 commits into
Lexus2016:mainfrom
apperside:feat/project-picker-recents-first

Conversation

@apperside
Copy link
Copy Markdown
Contributor

What

Adds a Recent section to the top of the header project-picker dropdown, showing the most-recently-opened projects first.

Why

The dropdown listed projects in fixed insertion/drag order with no notion of recency, so the project you just worked in could be buried in a long list.

How

  • Recency tracking — project opens are recorded client-side in localStorage (cc_proj_recents, a { projectId: timestamp } map), updated in switchProject() so every entry point (dropdown, sidebar, deep link) counts.
  • Dropdown rendering — when not searching, a labeled Recent group (top N) renders above a divider and the full All projects list. Scope is the header dropdown only; the sidebar keeps its manual drag-reorder. Search/filter keeps the previous flat behavior, and there's no Recent section until a project has actually been opened.
  • Configurable count — N comes from a recentProjectsCount config key (default 5), merged through loadMergedConfig() and editable via the existing config editor (which writes data/config.json). The server-side ?? 5 fallback guarantees the default when unset; set it to 0 to hide the section.
  • i18nproj.recent / proj.all labels added for en/uk/ru.

Files

  • server.js — expose recentProjectsCount (with ?? 5 default) in loadMergedConfig()
  • public/index.html — recency helpers, switchProject hook, dropdown rendering + shared item helper, CSS, i18n

No config.json committed: the runtime config (data/config.json) is gitignored per-install state; the default comes from the server fallback.

Verification

  • node --check server.js and an inline-script parse check pass.
  • Confirmed merge logic yields 5 (unset), respects an explicit value, and honors 0.
  • No build step, no schema/WebSocket changes; public/index.html stays a single file.

🤖 Generated with Claude Code

apperside and others added 2 commits May 30, 2026 02:26
The project picker dropdown listed projects in fixed insertion/drag order
with no notion of recency, so the project you just worked in could be buried.

- Track project opens client-side in localStorage (cc_proj_recents)
- Render a "Recent" section (top N) above a divider and the full list in the
  header dropdown only; sidebar manual drag-order is left untouched
- N comes from a `recentProjectsCount` key in the config (default 5), merged
  in loadMergedConfig() and editable via the existing config editor; the
  server-side `?? 5` fallback guarantees the default when unset
- Search/filter keeps the previous flat behavior; no Recent section until a
  project has been opened
- i18n labels added for en/uk/ru

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Kanban page (public/kanban.html) has its own copy of the project picker,
so the recents-first change to the chat header dropdown didn't appear there.

- Add the same Recent section (top N + divider) to the Kanban picker
- Reuse the shared localStorage store (cc_proj_recents), keyed by project id,
  so recency is shared between the chat page and the Kanban page
- Record an open when a project is picked in the Kanban dropdown
- Fetch /api/config in loadProjects() to read recentProjectsCount (default 5
  via the existing server fallback)
- Add proj.recent i18n label + section-label/divider CSS for en/uk/ru

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Owner

@Lexus2016 Lexus2016 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this contribution, @apperside! 🙏

Reviewed and approved. The implementation is clean and well-scoped:

  • All user-facing strings are properly escaped via escH — no new XSS surface.
  • localStorage access is guarded with try/catch, and recents are filtered against known project ids at render time (no stale/undefined entries).
  • The server-side ?? 5 default plus the 0-to-hide escape hatch is a nice touch.
  • Respects the project's no-build / single-file / vanilla-JS philosophy — no new dependencies, no schema or WebSocket changes. node --check and inline-script parsing pass on the head ref.

Merging now. We're also extending the same Recent UX to the Scheduler view, so the project picker behaves consistently across Chat, Kanban, and Scheduler. It will ship in the next release. Thanks again! 🚀

@Lexus2016 Lexus2016 merged commit 98ea434 into Lexus2016:main May 30, 2026
1 check passed
Lexus2016 added a commit that referenced this pull request May 30, 2026
Mirrors the Chat/Kanban 'Recent' dropdown from #15 into schedule.html:
- recents tracking via the shared cc_proj_recents localStorage key (keyed by project id)
- configurable recentProjectsCount (default 5, 0 hides the section), loaded from /api/config
- 'Recent' section label + divider CSS, i18n labels for uk/en/ru
- shared _projItemHTML helper; search keeps the previous flat behavior
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants