The mobile sidebar menu button redirects users to `cloudcli.ai/dashboard` when a
session was active. The redirect happened because
the menu was opened on `touchstart`, which mounted the sidebar before the touch
sequence completed; the follow-up tap/click then landed on the sidebar header
anchor.
This change rewrites mobile menu interaction handling in `MainContent.jsx` to
eliminate touch/click event leakage and ghost-click behavior.
Key changes:
- Added `suppressNextMenuClickRef` to guard against synthetic click events that
fire after a touch interaction.
- Added `openMobileMenu(event)` helper to centralize `preventDefault`,
`stopPropagation`, and `onMenuClick()` invocation.
- Added `handleMobileMenuTouchEnd(event)`:
- opens the menu on `touchend` instead of `touchstart`
- sets a short suppression window (350ms) for the next click.
- Added `handleMobileMenuClick(event)`:
- ignores/suppresses click events during the suppression window
- otherwise opens the menu normally.
- Updated all mobile menu button instances in `MainContent.jsx` (loading state,
no-project state, active header state) to use:
- `onTouchEnd={handleMobileMenuTouchEnd}`
- `onClick={handleMobileMenuClick}`
- Removed the previous `onTouchStart` path that caused premature DOM mutation.
Behavioral impact:
- Mobile sidebar still opens reliably with one tap.
- Tap no longer leaks to newly-mounted sidebar header links.
- Prevents accidental redirects while preserving existing menu UX.
- Replace `src/App.jsx` with `src/App.tsx` and move route-level UI orchestration into `src/components/app/AppContent.tsx`.
This separates provider/bootstrap concerns from runtime app layout logic, keeps route definitions minimal, and improves readability of the root app entry.
- Introduce `src/hooks/useProjectsState.ts` to centralize project/session/sidebar state management previously embedded in `App.jsx`.
This keeps the existing behavior for:
project loading,
Cursor session hydration,
WebSocket `loading_progress` handling,
additive-update protection for active sessions,
URL-based session selection,
sidebar refresh/delete/new-session flows.
The hook now exposes a typed `sidebarSharedProps` contract and typed handlers used by `AppContent`.
- Introduce `src/hooks/useSessionProtection.ts` for active/processing session lifecycle logic.
This preserves session-protection behavior while isolating `activeSessions`, `processingSessions`, and temporary-session replacement into a dedicated reusable hook.
- Replace monolithic `src/components/Sidebar.jsx` with typed `src/components/Sidebar.tsx` as a thin orchestrator.
`Sidebar.tsx` now focuses on wiring controller state/actions, modal visibility, collapsed mode, and version modal behavior instead of rendering every UI branch inline.
- Add `src/hooks/useSidebarController.ts` to encapsulate sidebar interaction/state logic.
This includes expand/collapse state, inline project/session editing state, project starring/sorting/filtering, lazy session pagination, delete confirmations, rename/delete actions, refresh state, and mobile touch click handling.
- Add strongly typed sidebar domain models in `src/components/sidebar/types.ts` and move sidebar-derived helpers into `src/components/sidebar/utils.ts`.
Utility coverage now includes:
session provider normalization,
session view-model creation (name/time/activity/message count),
project sorting/filtering,
task indicator status derivation,
starred-project persistence and readbacks.
- Split sidebar rendering into focused components under `src/components/sidebar/`:
`SidebarContent.tsx` for top-level sidebar layout composition.
`SidebarProjectList.tsx` for project-state branching and project iteration.
`SidebarProjectsState.tsx` for loading/empty/no-search-result placeholders.
`SidebarProjectItem.tsx` for per-project desktop/mobile header rendering and actions.
`SidebarProjectSessions.tsx` for expanded session area, skeletons, pagination, and new-session controls.
`SidebarSessionItem.tsx` for per-session desktop/mobile item rendering and session actions.
`SessionProviderIcon.tsx` for provider icon normalization.
`SidebarHeader.tsx`, `SidebarFooter.tsx`, `SidebarCollapsed.tsx`, and `SidebarModals.tsx` as dedicated typed UI surfaces.
This keeps rendering responsibilities local and significantly improves traceability.
- Convert shared UI primitives from JSX to TSX:
`src/components/ui/button.tsx`,
`src/components/ui/input.tsx`,
`src/components/ui/badge.tsx`,
`src/components/ui/scroll-area.tsx`.
These now provide typed props/variants (`forwardRef` where appropriate) while preserving existing class/behavior.
- Add shared app typings in `src/types/app.ts` for projects/sessions/websocket/loading contracts used by new hooks/components.
- Add global window declarations in `src/types/global.d.ts` for `__ROUTER_BASENAME__`, `refreshProjects`, and `openSettings`, removing implicit `any` usage for global integration points.
- Update `src/main.jsx` to import `App.tsx` and keep app bootstrap consistent with the TS migration.
- Update `src/components/QuickSettingsPanel.jsx` to self-resolve mobile state via `useDeviceSettings` (remove `isMobile` prop dependency), and update `src/components/ChatInterface.jsx` to render `QuickSettingsPanel` directly.
This reduces prop drilling and keeps quick settings colocated with chat UI concerns.
- Add new `useDeviceSettings` hook (`src/hooks/useDeviceSettings.ts`) to centralize
device-related state:
- exposes `isMobile` and `isPWA`
- supports options: `mobileBreakpoint`, `trackMobile`, `trackPWA`
- listens to window resize for mobile updates
- listens to `display-mode: standalone` changes for PWA updates
- includes `matchMedia.addListener/removeListener` fallback for older environments
- Update `AppContent` (`src/App.jsx`) to consume `isMobile` from
`useDeviceSettings({ trackPWA: false })`:
- remove local `isMobile` state/effect
- remove local `isPWA` state/effect
- keep existing `isMobile` behavior for layout and mobile sidebar flow
- stop passing `isPWA` into `Sidebar` props
- Update `Sidebar` (`src/components/Sidebar.jsx`) to own PWA detection:
- consume `isPWA` from `useDeviceSettings({ trackMobile: false })`
- add effect to toggle `pwa-mode` class on `document.documentElement` and `document.body`
- retain use of `isMobile` prop from `App` for sidebar/mobile rendering decisions
Why:
- removes duplicated device-detection logic from `AppContent`
- makes device-state logic reusable and easier to maintain
- keeps PWA-specific behavior where it is actually used (`Sidebar`)
* fix: claude code login issues
1. Now, the browser opens in a new tab automatically
2. Clicking "C" to copy works
3. I have removed the "x-term" link selector since it didn't select the whole link
* fix: remove unnecessary terminal hyperlink for auth URL
* fix(shell): resolve clipboard handling for copy and paste events
* feat(shell): add authentication URL display and copy functionality - allows copy for mobile users
* revert: Update login command for unauthenticated users to use '/exit'
---------
Co-authored-by: Haileyesus <something@gmail.com>
* feat(i18n): add Korean language support
- Add Korean (ko) translation files for all namespaces:
- common.json, auth.json, settings.json, sidebar.json, chat.json, codeEditor.json
- Register Korean locale in config.js and languages.js
- Follow translation guidelines:
- Keep technical terms in English (UI, API, Shell, Git, etc.)
- Use Korean phonetic for some terms (TaskMaster → 테스크마스터)
- Maintain concise translations to match English length where possible
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(i18n): keep technical term "UI" in Korean translation
- Change "인터페이스" back to "UI" in sidebar subtitle
- Keep technical terms in English as per translation guidelines
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: remove unnecessary websocket.js file and replace its usage directly in `WebSocketContext`
* fix: connect() doesn't need to be async
* fix: update WebSocket context import to use useWebSocket hook
* fix: use `useRef` for WebSocketContext
The main issue with using states was, previously the websocket never closed
properly on unmount, so multiple connections could be opened.
This was because the useEffect cleanup function was closing an old websocket
(that was initialized to null) instead of the current one.
We could have fixed this by adding `ws` to the useEffect dependency array, but
this was unnecessary since `ws` doesn't affect rendering so we shouldn't use a state.
* fix: replace `WebSocketContext` default value with null and add type definitions
* fix: add type definition for WebSocket URL and remove redundant protocol declaration
* fix: Prevent WebSocket reconnection attempts after unmount
Right now, when the WebSocketContext component unmounts,
there is still a pending reconnection attempt that tries
to reconnect the WebSocket after 3 seconds.
* refactor: Extract WebSocket URL construction into a separate function
* refactor: Centralize platform mode detection using IS_PLATFORM constant; use `token` from Auth context in WebSocket connection
* refactor: Use IS_PLATFORM constant for platform detection in authenticatedFetch function (backend)
* refactor: move IS_PLATFORM to config file for both frontend and backend
The reason we couldn't place it in shared/modelConstants.js is that the
frontend uses Vite which requires import.meta.env for environment variables,
while the backend uses process.env. Therefore, we created separate config files
for the frontend (src/constants/config.ts) and backend (server/constants/config.js).
* refactor: update import path for IS_PLATFORM constant to use config file
* refactor: replace `messages` with `latestMessage` in WebSocket context and related components
Why?
Because, messages was only being used to access the latest message in the components it's used in.
* refactor: optimize WebSocket connection handling with useCallback and useMemo
* refactor: comment out debug log for render count in AppContent component
* refactor(backend): update environment variable handling and replace VITE_IS_PLATFORM with IS_PLATFORM constant
* refactor: update WebSocket connection effect to depend on token changes for reconnection
---------
The regex only replaced forward slashes, causing Windows paths like
C:\Users\Eric\my_project to remain unchanged instead of being encoded
to C--Users-Eric-my-project. This caused API routes to fail.
- Add path validation to /api/create-folder endpoint (forbidden system dirs)
- Fix repo name extraction to handle trailing slashes in URLs
- Add cleanup of partial clone directory on SSE clone failure
- Remove dead code branch (unreachable message)
- Fix Windows path separator detection in createNewFolder
- Replace alert() with setError() for consistent error handling
- Detect ssh:// URLs in addition to git@ for SSH key display
- Show create folder button for both workspace types
- Add "+" button to create new folders directly from folder browser
- Add SSE endpoint for git clone with real-time progress display
- Show clone progress (receiving objects, resolving deltas) in UI
- Detect SSH URLs and display "SSH Key" instead of "No authentication"
- Hide token section for SSH URLs (tokens only work with HTTPS)
- Fix auto-advance behavior: only auto-advance for "Existing Workspace"
- Fix various misleading UI messages
- Support auth token via query param for SSE endpoints