diff --git a/index.html b/index.html index c42257f..a0f807c 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + Claude Code UI @@ -12,7 +12,7 @@ - + diff --git a/server/index.js b/server/index.js index d69f825..f6553b8 100755 --- a/server/index.js +++ b/server/index.js @@ -506,7 +506,7 @@ app.get('/api/projects/:projectName/files', authenticateToken, async (req, res) return res.status(404).json({ error: `Project path not found: ${actualPath}` }); } - const files = await getFileTree(actualPath, 3, 0, true); + const files = await getFileTree(actualPath, 10, 0, true); const hiddenFiles = files.filter(f => f.name.startsWith('.')); res.json(files); } catch (error) { diff --git a/server/projects.js b/server/projects.js index 3f0b2b5..4f0aae3 100755 --- a/server/projects.js +++ b/server/projects.js @@ -899,22 +899,16 @@ async function addProjectManually(projectPath, displayName = null) { // Generate project name (encode path for use as directory name) const projectName = absolutePath.replace(/\//g, '-'); - // Check if project already exists in config or as a folder + // Check if project already exists in config const config = await loadProjectConfig(); const projectDir = path.join(process.env.HOME, '.claude', 'projects', projectName); - - try { - await fs.access(projectDir); - throw new Error(`Project already exists for path: ${absolutePath}`); - } catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } - } - + if (config[projectName]) { throw new Error(`Project already configured for path: ${absolutePath}`); } + + // Allow adding projects even if the directory exists - this enables tracking + // existing Claude Code or Cursor projects in the UI // Add to config as manually added project config[projectName] = { diff --git a/src/App.jsx b/src/App.jsx index ccc99ef..b20afb4 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -77,6 +77,37 @@ function AppContent() { const [activeSessions, setActiveSessions] = useState(new Set()); // Track sessions with active conversations const { ws, sendMessage, messages } = useWebSocketContext(); + + // Detect if running as PWA + const [isPWA, setIsPWA] = useState(false); + + useEffect(() => { + // Check if running in standalone mode (PWA) + const checkPWA = () => { + const isStandalone = window.matchMedia('(display-mode: standalone)').matches || + window.navigator.standalone || + document.referrer.includes('android-app://'); + setIsPWA(isStandalone); + + // Add class to html and body for CSS targeting + if (isStandalone) { + document.documentElement.classList.add('pwa-mode'); + document.body.classList.add('pwa-mode'); + } else { + document.documentElement.classList.remove('pwa-mode'); + document.body.classList.remove('pwa-mode'); + } + }; + + checkPWA(); + + // Listen for changes + window.matchMedia('(display-mode: standalone)').addEventListener('change', checkPWA); + + return () => { + window.matchMedia('(display-mode: standalone)').removeEventListener('change', checkPWA); + }; + }, []); useEffect(() => { const checkMobile = () => { @@ -561,6 +592,8 @@ function AppContent() { latestVersion={latestVersion} currentVersion={currentVersion} onShowVersionModal={() => setShowVersionModal(true)} + isPWA={isPWA} + isMobile={isMobile} /> @@ -607,6 +640,8 @@ function AppContent() { latestVersion={latestVersion} currentVersion={currentVersion} onShowVersionModal={() => setShowVersionModal(true)} + isPWA={isPWA} + isMobile={isMobile} /> @@ -623,6 +658,7 @@ function AppContent() { sendMessage={sendMessage} messages={messages} isMobile={isMobile} + isPWA={isPWA} onMenuClick={() => setSidebarOpen(true)} isLoading={isLoadingProjects} onInputFocusChange={setIsInputFocused} diff --git a/src/components/DiffViewer.jsx b/src/components/DiffViewer.jsx new file mode 100644 index 0000000..a624c0b --- /dev/null +++ b/src/components/DiffViewer.jsx @@ -0,0 +1,41 @@ +import React from 'react'; + +function DiffViewer({ diff, fileName, isMobile, wrapText }) { + if (!diff) { + return ( +
+ No diff available +
+ ); + } + + const renderDiffLine = (line, index) => { + const isAddition = line.startsWith('+') && !line.startsWith('+++'); + const isDeletion = line.startsWith('-') && !line.startsWith('---'); + const isHeader = line.startsWith('@@'); + + return ( +
+ {line} +
+ ); + }; + + return ( +
+ {diff.split('\n').map((line, index) => renderDiffLine(line, index))} +
+ ); +} + +export default DiffViewer; \ No newline at end of file diff --git a/src/components/GitPanel.jsx b/src/components/GitPanel.jsx index b71d2ef..5962d29 100644 --- a/src/components/GitPanel.jsx +++ b/src/components/GitPanel.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { GitBranch, GitCommit, Plus, Minus, RefreshCw, Check, X, ChevronDown, ChevronRight, Info, History, FileText, Mic, MicOff, Sparkles, Download, RotateCcw, Trash2, AlertTriangle, Upload } from 'lucide-react'; import { MicButton } from './MicButton.jsx'; import { authenticatedFetch } from '../utils/api'; +import DiffViewer from './DiffViewer.jsx'; function GitPanel({ selectedProject, isMobile }) { const [gitStatus, setGitStatus] = useState(null); @@ -523,27 +524,6 @@ function GitPanel({ selectedProject, isMobile }) { } }; - const renderDiffLine = (line, index) => { - const isAddition = line.startsWith('+') && !line.startsWith('+++'); - const isDeletion = line.startsWith('-') && !line.startsWith('---'); - const isHeader = line.startsWith('@@'); - - return ( -
- {line} -
- ); - }; const getStatusLabel = (status) => { switch (status) { @@ -590,7 +570,7 @@ function GitPanel({ selectedProject, isMobile }) {
{commit.stats}
- {diff.split('\n').map((line, index) => renderDiffLine(line, index))} + )} @@ -705,8 +685,8 @@ function GitPanel({ selectedProject, isMobile }) { )} -
- {diff && diff.split('\n').map((line, index) => renderDiffLine(line, index))} +
+ {diff && }
diff --git a/src/components/MainContent.jsx b/src/components/MainContent.jsx index b915198..676a83f 100644 --- a/src/components/MainContent.jsx +++ b/src/components/MainContent.jsx @@ -37,6 +37,7 @@ function MainContent({ sendMessage, messages, isMobile, + isPWA, onMenuClick, isLoading, onInputFocusChange, @@ -152,10 +153,12 @@ function MainContent({
{/* Header with menu button for mobile */} {isMobile && ( -
+