Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
3dc4c54
🤖 feat: Add Tailwind CSS and Shadcn UI foundation
kylecarbs Oct 22, 2025
61f668b
🤖 refactor: Convert ToggleGroup and ErrorMessage to Tailwind
kylecarbs Oct 22, 2025
170df51
🤖 docs: Add comprehensive Tailwind migration status
kylecarbs Oct 22, 2025
1792bc8
🤖 refactor: Convert StatusIndicator, Tooltip, ChatToggles, Context1MC…
kylecarbs Oct 22, 2025
81e656c
🤖 refactor: Convert Modal and all modal components to Tailwind
kylecarbs Oct 22, 2025
824f0ac
🤖 refactor: Convert DirectorySelectModal and ToolPrimitives to Tailwind
kylecarbs Oct 22, 2025
367c029
🤖 refactor: Convert HistoryHiddenMessage and TerminalOutput to Tailwind
kylecarbs Oct 22, 2025
ba25510
🤖 refactor: Convert CompactingMessageContent and TypewriterMarkdown
kylecarbs Oct 22, 2025
d17c24e
📊 docs: Update migration status to 20% complete (13/64 components)
kylecarbs Oct 22, 2025
66dcef1
🤖 refactor: Convert LeftSidebar to Tailwind
kylecarbs Oct 22, 2025
7d920ed
🤖 refactor: Convert ErrorBoundary to Tailwind
kylecarbs Oct 22, 2025
dffb762
📊 docs: Update final migration status - 23% complete (15/64)
kylecarbs Oct 22, 2025
82ee5ed
🤖 refactor: Convert RefreshButton to Tailwind
kylecarbs Oct 22, 2025
2790773
🤖 refactor: Convert ModelDisplay to Tailwind
kylecarbs Oct 22, 2025
ff9703d
🤖 refactor: Convert BaseBarrier to Tailwind
kylecarbs Oct 22, 2025
1db6429
🤖 refactor: Convert PinnedTodoList to Tailwind
kylecarbs Oct 22, 2025
0e8c955
🤖 refactor: Convert UserMessage to Tailwind
kylecarbs Oct 22, 2025
cd16a6a
🤖 refactor: Convert RetryBarrier to Tailwind
kylecarbs Oct 22, 2025
61f9ceb
🤖 refactor: Convert StreamingBarrier to Tailwind
kylecarbs Oct 22, 2025
39f9728
🤖 refactor: Convert ReasoningMessage to Tailwind
kylecarbs Oct 22, 2025
8488c3b
🤖 refactor: Convert StreamErrorMessage to Tailwind
kylecarbs Oct 22, 2025
cfc0bf5
🤖 refactor: Convert CompactionBackground to Tailwind
kylecarbs Oct 22, 2025
a309862
🤖 refactor: Convert GitStatusIndicatorView to Tailwind
kylecarbs Oct 22, 2025
640fa2d
🤖 refactor: Convert WorkspaceListItem to Tailwind
kylecarbs Oct 22, 2025
a82abde
🤖 refactor: Convert ImageAttachments, TitleBar, TodoList to Tailwind
kylecarbs Oct 22, 2025
6eff57e
🤖 refactor: Convert ThinkingSlider to Tailwind with CSS variables
kylecarbs Oct 22, 2025
3ee4465
🤖 refactor: Convert ChatInputToast to Tailwind
kylecarbs Oct 22, 2025
9830bbc
🤖 refactor: Convert ForceDeleteModal and TipsCarousel to Tailwind
kylecarbs Oct 22, 2025
6bf2135
🤖 refactor: Convert BashToolCall and FileReadToolCall to Tailwind
kylecarbs Oct 22, 2025
10bd559
🤖 refactor: Convert FileEditToolCall to Tailwind
kylecarbs Oct 22, 2025
661e6c4
🤖 refactor: Convert CommandSuggestions to Tailwind
kylecarbs Oct 22, 2025
221a272
🤖 refactor: Convert ProposePlanToolCall to Tailwind CSS
kylecarbs Oct 22, 2025
b7c4025
🤖 refactor: Convert MarkdownRenderer to Tailwind CSS
kylecarbs Oct 22, 2025
c401fdb
🤖 refactor: Convert AssistantMessage to Tailwind CSS
kylecarbs Oct 22, 2025
f7b85e9
🤖 refactor: Convert MessageWindow to Tailwind CSS
kylecarbs Oct 22, 2025
3f7075b
🤖 refactor: Convert SecretsModal to Tailwind CSS
kylecarbs Oct 22, 2025
c4e19fc
🤖 refactor: Convert NewWorkspaceModal to Tailwind CSS
kylecarbs Oct 22, 2025
dfc0c74
🤖 refactor: Convert StartHereModal to Tailwind CSS
kylecarbs Oct 22, 2025
05c6754
🤖 refactor: Convert TokenMeter to Tailwind CSS
kylecarbs Oct 22, 2025
230919d
🤖 refactor: Convert VerticalTokenMeter to Tailwind CSS
kylecarbs Oct 22, 2025
7678e8e
🤖 refactor: Convert RightSidebar components to Tailwind CSS
kylecarbs Oct 22, 2025
be30b09
🤖 refactor: Convert UntrackedStatus to Tailwind CSS
kylecarbs Oct 22, 2025
948297b
🤖 refactor: Convert ReviewControls to Tailwind CSS
kylecarbs Oct 22, 2025
d422b1b
🤖 refactor: Convert HunkViewer to Tailwind CSS
kylecarbs Oct 22, 2025
ce8a1cb
🤖 refactor: Convert CommandPalette to Tailwind CSS
kylecarbs Oct 22, 2025
d012024
🤖 refactor: Convert ModelSelector to Tailwind CSS
kylecarbs Oct 22, 2025
a9b1087
🤖 refactor: Convert KebabMenu to Tailwind CSS
kylecarbs Oct 22, 2025
bc21dd7
🤖 refactor: Convert VimTextArea to Tailwind CSS
kylecarbs Oct 22, 2025
2895a74
🤖 refactor: Convert DiffRenderer to Tailwind CSS
kylecarbs Oct 22, 2025
585efa5
🤖 refactor: Convert AIView to Tailwind CSS
kylecarbs Oct 22, 2025
c78729b
🤖 refactor: Convert App.tsx to Tailwind CSS
kylecarbs Oct 22, 2025
d7eecbd
🤖 refactor: Convert ChatInput to Tailwind CSS
kylecarbs Oct 22, 2025
e6a0b73
🤖 refactor: Convert story files to Tailwind CSS and remove emotion
kylecarbs Oct 22, 2025
77b8f36
🤖 refactor: Remove temporary migration documentation file
kylecarbs Oct 22, 2025
211681b
🤖 refactor: Remove temporary migration scripts
kylecarbs Oct 22, 2025
e629bc4
🤖 fix: Restore properly converted Tailwind files after rebase
kylecarbs Oct 22, 2025
f1c51bf
🤖 fix: Remove unused imports and fix linting issues
kylecarbs Oct 22, 2025
8136f29
🤖 fix: Add --color-* CSS variable aliases for backwards compatibility
kylecarbs Oct 22, 2025
70d367a
🤖 fix: Correct font-family class names in Tailwind conversions
kylecarbs Oct 22, 2025
2915e39
🤖 Fix: Define font CSS variables and add font-primary class
kylecarbs Oct 22, 2025
04bfcf6
🤖 Fix: Remove quotes from font CSS variables
kylecarbs Oct 22, 2025
cd72e04
🤖 Fix: Remove font-mono from AIView container
kylecarbs Oct 22, 2025
5f65c60
🤖 WIP: Migrate to Tailwind CSS v4
kylecarbs Oct 22, 2025
19e0356
🤖 Fix: Tailwind v4 migration - fix CSS syntax
kylecarbs Oct 22, 2025
488a40c
🤖 Tailwind v4 migration complete (dev mode working)
kylecarbs Oct 22, 2025
321bc8f
🤖 fix: Update Tailwind CSS to v4.1.15 and fix components.json config
kylecarbs Oct 22, 2025
9ae71fa
🤖 Trigger CI re-run for E2E tests
kylecarbs Oct 22, 2025
11df5c6
🤖 Fix: Remove config bypassing in renameWorkspace tests
kylecarbs Oct 22, 2025
6df1ee2
Revert "🤖 Fix: Remove config bypassing in renameWorkspace tests"
kylecarbs Oct 22, 2025
8009896
🤖 Fix worker.plugins syntax for Vite 7 compatibility
kylecarbs Oct 22, 2025
94de92a
🤖 Configure Tailwind to exclude worker files
kylecarbs Oct 22, 2025
7f9a2e1
🤖 Retrigger CI
kylecarbs Oct 22, 2025
9042265
🤖 Prevent Tailwind plugin from applying to worker builds
kylecarbs Oct 22, 2025
aa8dfcd
🤖 Simplify vite config - remove apply() filter
kylecarbs Oct 22, 2025
99b278e
Fix vite config
kylecarbs Oct 22, 2025
6a06258
🤖 Fix worker plugins - use array syntax to match main
kylecarbs Oct 22, 2025
f0a46ad
🤖 Fix mode toggle visibility - correct container query breakpoint
kylecarbs Oct 22, 2025
fc9c414
🤖 Remove git conflict markers from ProjectSidebar
kylecarbs Oct 23, 2025
00e5b17
🤖 Restore ReviewPanel and FileTree from good state
kylecarbs Oct 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import type { Preview } from "@storybook/react";
import { GlobalColors } from "../src/styles/colors";
import { GlobalFonts } from "../src/styles/fonts";
import { GlobalScrollbars } from "../src/styles/scrollbars";
import "../src/styles/globals.css";

const preview: Preview = {
decorators: [
(Story) => (
<>
<GlobalColors />
<GlobalFonts />
<GlobalScrollbars />
<Story />
</>
),
Expand Down
412 changes: 289 additions & 123 deletions bun.lock

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles/globals.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}

25 changes: 18 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,20 @@
"docs:watch": "make docs-watch",
"storybook": "make storybook",
"storybook:build": "make storybook-build",
"test:storybook": "make test-storybook",
"chromatic": "make chromatic"
"test:storybook": "make test-storybook"
},
"dependencies": {
"@ai-sdk/anthropic": "^2.0.29",
"@ai-sdk/openai": "^2.0.52",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"ai": "^5.0.72",
"ai-tokenizer": "^1.0.3",
"chalk": "^5.6.2",
Expand All @@ -68,9 +76,6 @@
"zod-to-json-schema": "^3.24.6"
},
"devDependencies": {
"@emotion/babel-plugin": "^11.13.5",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@eslint/js": "^9.36.0",
"@playwright/test": "^1.56.0",
"@storybook/addon-essentials": "^8.6.14",
Expand All @@ -80,6 +85,7 @@
"@storybook/react": "^8.6.14",
"@storybook/react-vite": "^8.6.14",
"@storybook/test-runner": "^0.23.0",
"@tailwindcss/vite": "^4.1.15",
"@testing-library/react": "^16.3.0",
"@types/bun": "^1.2.23",
"@types/cors": "^2.8.19",
Expand All @@ -98,8 +104,10 @@
"@typescript-eslint/parser": "^8.44.1",
"@typescript/native-preview": "^7.0.0-dev.20251014.1",
"@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.21",
"babel-plugin-react-compiler": "^1.0.0",
"chromatic": "^13.3.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"concurrently": "^8.2.0",
"dotenv": "^17.2.3",
Expand All @@ -114,6 +122,7 @@
"jest": "^30.1.3",
"mermaid": "^11.12.0",
"playwright": "^1.56.0",
"postcss": "^8.5.6",
"posthog-js": "^1.276.0",
"prettier": "^3.6.2",
"react": "^18.2.0",
Expand All @@ -129,11 +138,13 @@
"remark-math": "^6.0.0",
"shiki": "^3.13.0",
"storybook": "^8.6.14",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.15",
"ts-jest": "^29.4.4",
"tsc-alias": "^1.8.16",
"typescript": "^5.1.3",
"typescript-eslint": "^8.45.0",
"vite": "^4.4.0",
"vite": "^7.1.11",
"vite-plugin-svgr": "^4.5.0",
"vite-plugin-top-level-await": "^1.6.0"
},
Expand Down
217 changes: 18 additions & 199 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { useState, useEffect, useCallback, useRef } from "react";
import styled from "@emotion/styled";
import { Global, css } from "@emotion/react";
import { GlobalColors } from "./styles/colors";
import { GlobalFonts } from "./styles/fonts";
import { GlobalScrollbars } from "./styles/scrollbars";
import "./styles/globals.css";
import type { ProjectConfig } from "./config";
import type { WorkspaceSelection } from "./components/ProjectSidebar";
import type { FrontendWorkspaceMetadata } from "./types/workspace";
Expand Down Expand Up @@ -37,187 +33,6 @@ import { useTelemetry } from "./hooks/useTelemetry";

const THINKING_LEVELS: ThinkingLevel[] = ["off", "low", "medium", "high"];

// Global Styles with nice fonts
const globalStyles = css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

html,
body,
#root {
height: 100vh;
overflow: hidden;
background: #1e1e1e;
color: #fff;
font-family: var(--font-primary);
font-size: 14px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

/* Mobile: Improve touch interactions */
@media (max-width: 768px) {
html {
/* Prevent text size adjustment on orientation change */
-webkit-text-size-adjust: 100%;
}

body {
/* Slightly larger font for better readability on mobile */
font-size: 15px;
}

/* Make buttons and interactive elements easier to tap */
button,
a,
[role="button"] {
min-height: 44px;
min-width: 44px;
/* Improve tap responsiveness on buttons only */
touch-action: manipulation;
}

/* Ensure input elements allow default touch behavior for iOS keyboard */
input,
textarea,
select {
touch-action: auto;
}
}

code {
font-family: var(--font-monospace);
}

/* Enable native tooltips */
[title] {
position: relative;
}

[title]:hover::after {
content: attr(title);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 8px;
padding: 6px 10px;
background: #2d2d30;
color: #cccccc;
border: 1px solid #464647;
border-radius: 4px;
font-size: 11px;
white-space: nowrap;
z-index: 1000;
pointer-events: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}

[title]:hover::before {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 3px;
border-width: 5px;
border-style: solid;
border-color: #2d2d30 transparent transparent transparent;
z-index: 1000;
pointer-events: none;
}

/* Search term highlighting - global for consistent styling across components */
/* Applied to <mark> for plain text and <span> for Shiki-highlighted code */
mark.search-highlight,
span.search-highlight {
background: rgba(255, 215, 0, 0.3);
color: inherit;
padding: 0;
border-radius: 2px;
}

/* Override Shiki theme background to use our global color */
.shiki,
.shiki pre {
background: var(--color-code-bg) !important;
}

/* Global styling for markdown code blocks */
pre code {
display: block;
background: var(--color-code-bg);
margin: 1em 0;
border-radius: 4px;
font-size: 12px;
padding: 12px;
overflow: auto;
}
`;

// Styled Components
const AppContainer = styled.div`
display: flex;
height: 100vh;
overflow: hidden;
background: #1e1e1e;

/* Mobile: Ensure content takes full width */
@media (max-width: 768px) {
flex-direction: column;
}
`;

const MainContent = styled.div`
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-width: 0; /* Allow content to shrink below its minimum content size */

/* Mobile: Take full width */
@media (max-width: 768px) {
width: 100%;
}
`;

const ContentArea = styled.div`
flex: 1;
display: flex;
overflow: hidden;

/* Mobile: Stack content vertically if needed */
@media (max-width: 768px) {
flex-direction: column;
}
`;

const WelcomeView = styled.div`
text-align: center;
padding: clamp(40px, 10vh, 100px) 20px;
max-width: 800px;
margin: 0 auto;
width: 100%;

h2 {
color: #fff;
font-size: clamp(24px, 5vw, 36px);
margin-bottom: 16px;
font-weight: 700;
letter-spacing: -1px;
}

p {
color: #888;
font-size: clamp(14px, 2vw, 16px);
line-height: 1.6;
}
`;

function AppInner() {
const [selectedWorkspace, setSelectedWorkspace] = usePersistedState<WorkspaceSelection | null>(
"selectedWorkspace",
Expand Down Expand Up @@ -847,11 +662,7 @@ function AppInner() {

return (
<>
<GlobalColors />
<GlobalFonts />
<GlobalScrollbars />
<Global styles={globalStyles} />
<AppContainer>
<div className="flex h-screen overflow-hidden bg-[#1e1e1e] [@media(max-width:768px)]:flex-col">
<LeftSidebar
projects={projects}
workspaceMetadata={workspaceMetadata}
Expand All @@ -871,8 +682,8 @@ function AppInner() {
sortedWorkspacesByProject={sortedWorkspacesByProject}
workspaceRecency={workspaceRecency}
/>
<MainContent>
<ContentArea>
<div className="flex-1 flex flex-col overflow-hidden min-w-0 [@media(max-width:768px)]:w-full">
<div className="flex-1 flex overflow-hidden [@media(max-width:768px)]:flex-col">
{selectedWorkspace ? (
<ErrorBoundary
workspaceInfo={`${selectedWorkspace.projectName}/${selectedWorkspace.namedWorkspacePath?.split("/").pop() ?? selectedWorkspace.workspaceId}`}
Expand All @@ -889,13 +700,21 @@ function AppInner() {
/>
</ErrorBoundary>
) : (
<WelcomeView>
<h2>Welcome to Cmux</h2>
<div
className="text-center max-w-[800px] mx-auto w-full [&_h2]:text-white [&_h2]:mb-4 [&_h2]:font-bold [&_h2]:tracking-tight [&_p]:text-[#888] [&_p]:leading-[1.6]"
style={{
padding: "clamp(40px, 10vh, 100px) 20px",
fontSize: "clamp(14px, 2vw, 16px)",
}}
>
<h2 style={{ fontSize: "clamp(24px, 5vw, 36px)", letterSpacing: "-1px" }}>
Welcome to Cmux
</h2>
<p>Select a workspace from the sidebar or add a new one to get started.</p>
</WelcomeView>
</div>
)}
</ContentArea>
</MainContent>
</div>
</div>
<CommandPalette
getSlashContext={() => ({
providerNames: [],
Expand All @@ -922,7 +741,7 @@ function AppInner() {
/>
)}
<DirectorySelectModal />
</AppContainer>
</div>
</>
);
}
Expand Down
Loading