Skip to content

Commit 7947453

Browse files
committed
Convert modals to use the dialog component
1 parent 7e07451 commit 7947453

File tree

11 files changed

+471
-533
lines changed

11 files changed

+471
-533
lines changed

bun.lock

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"lockfileVersion": 1,
3+
"configVersion": 0,
34
"workspaces": {
45
"": {
56
"name": "mux",
@@ -29,6 +30,7 @@
2930
"@radix-ui/react-tabs": "^1.1.13",
3031
"@radix-ui/react-toggle-group": "^1.1.11",
3132
"@radix-ui/react-tooltip": "^1.2.8",
33+
"@radix-ui/react-visually-hidden": "^1.2.4",
3234
"ai": "^5.0.101",
3335
"ai-tokenizer": "^1.0.4",
3436
"chalk": "^5.6.2",
@@ -912,7 +914,7 @@
912914

913915
"@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
914916

915-
"@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
917+
"@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kaeiyGCe844dkb9AVF+rb4yTyb1LiLN/e3es3nLiRyN4dC8AduBYPMnnNlDjX2VDOcvDEiPnRNMJeWCfsX0txg=="],
916918

917919
"@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
918920

@@ -3764,6 +3766,8 @@
37643766

37653767
"@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
37663768

3769+
"@radix-ui/react-select/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
3770+
37673771
"@radix-ui/react-tabs/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
37683772

37693773
"@radix-ui/react-toggle/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
@@ -3774,7 +3778,7 @@
37743778

37753779
"@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
37763780

3777-
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
3781+
"@radix-ui/react-tooltip/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
37783782

37793783
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
37803784

@@ -4230,8 +4234,6 @@
42304234

42314235
"@radix-ui/react-toggle/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
42324236

4233-
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
4234-
42354237
"@testing-library/dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
42364238

42374239
"@testing-library/dom/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"@radix-ui/react-tabs": "^1.1.13",
7171
"@radix-ui/react-toggle-group": "^1.1.11",
7272
"@radix-ui/react-tooltip": "^1.2.8",
73+
"@radix-ui/react-visually-hidden": "^1.2.4",
7374
"ai": "^5.0.101",
7475
"ai-tokenizer": "^1.0.4",
7576
"chalk": "^5.6.2",
Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { useState, useCallback } from "react";
2-
import { Modal } from "./Modal";
2+
import {
3+
Dialog,
4+
DialogContent,
5+
DialogHeader,
6+
DialogTitle,
7+
DialogDescription,
8+
DialogFooter,
9+
} from "@/browser/components/ui/dialog";
10+
import { Button } from "@/browser/components/ui/button";
311

412
interface AuthTokenModalProps {
513
isOpen: boolean;
@@ -48,64 +56,43 @@ export function AuthTokenModal(props: AuthTokenModalProps) {
4856
[token, onSubmit]
4957
);
5058

59+
// This modal cannot be dismissed without providing a token
60+
const handleOpenChange = useCallback(() => {
61+
// Do nothing - modal cannot be closed without submitting
62+
}, []);
63+
5164
return (
52-
<Modal isOpen={props.isOpen} onClose={() => undefined} title="Authentication Required">
53-
<form onSubmit={handleSubmit} style={{ display: "flex", flexDirection: "column", gap: 16 }}>
54-
<p style={{ margin: 0, color: "var(--color-text-secondary)" }}>
55-
This server requires an authentication token. Enter the token provided when the server was
56-
started.
57-
</p>
65+
<Dialog open={props.isOpen} onOpenChange={handleOpenChange}>
66+
<DialogContent showCloseButton={false}>
67+
<DialogHeader>
68+
<DialogTitle>Authentication Required</DialogTitle>
69+
<DialogDescription>
70+
This server requires an authentication token. Enter the token provided when the server
71+
was started.
72+
</DialogDescription>
73+
</DialogHeader>
5874

59-
{props.error && (
60-
<div
61-
style={{
62-
padding: "8px 12px",
63-
borderRadius: 4,
64-
backgroundColor: "var(--color-error-background, rgba(255, 0, 0, 0.1))",
65-
color: "var(--color-error, #ff6b6b)",
66-
fontSize: 13,
67-
}}
68-
>
69-
{props.error}
70-
</div>
71-
)}
75+
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
76+
{props.error && (
77+
<div className="bg-error-bg text-error rounded p-2 px-3 text-[13px]">{props.error}</div>
78+
)}
7279

73-
<input
74-
type="password"
75-
value={token}
76-
onChange={(e) => setToken(e.target.value)}
77-
placeholder="Enter auth token"
78-
autoFocus
79-
style={{
80-
padding: "10px 12px",
81-
borderRadius: 4,
82-
border: "1px solid var(--color-border)",
83-
backgroundColor: "var(--color-input-background)",
84-
color: "var(--color-text)",
85-
fontSize: 14,
86-
outline: "none",
87-
}}
88-
/>
80+
<input
81+
type="password"
82+
value={token}
83+
onChange={(e) => setToken(e.target.value)}
84+
placeholder="Enter auth token"
85+
autoFocus
86+
className="bg-modal-bg border-border-medium focus:border-accent placeholder:text-muted text-foreground rounded border px-3 py-2.5 text-sm focus:outline-none"
87+
/>
8988

90-
<button
91-
type="submit"
92-
disabled={!token.trim()}
93-
style={{
94-
padding: "10px 16px",
95-
borderRadius: 4,
96-
border: "none",
97-
backgroundColor: token.trim()
98-
? "var(--color-primary)"
99-
: "var(--color-button-disabled-background)",
100-
color: token.trim() ? "white" : "var(--color-text-disabled)",
101-
fontSize: 14,
102-
fontWeight: 500,
103-
cursor: token.trim() ? "pointer" : "not-allowed",
104-
}}
105-
>
106-
Connect
107-
</button>
108-
</form>
109-
</Modal>
89+
<DialogFooter className="pt-0">
90+
<Button type="submit" disabled={!token.trim()} className="w-full">
91+
Connect
92+
</Button>
93+
</DialogFooter>
94+
</form>
95+
</DialogContent>
96+
</Dialog>
11097
);
11198
}

src/browser/components/DirectoryPickerModal.tsx

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import React, { useCallback, useEffect, useState } from "react";
2-
import { Modal, ModalActions, CancelButton, PrimaryButton } from "./Modal";
2+
import {
3+
Dialog,
4+
DialogContent,
5+
DialogHeader,
6+
DialogTitle,
7+
DialogDescription,
8+
DialogFooter,
9+
} from "@/browser/components/ui/dialog";
10+
import { Button } from "@/browser/components/ui/button";
311
import type { FileTreeNode } from "@/common/utils/git/numstatParser";
412
import { DirectoryTree } from "./DirectoryTree";
513
import { useAPI } from "@/browser/contexts/API";
@@ -79,38 +87,48 @@ export const DirectoryPickerModal: React.FC<DirectoryPickerModalProps> = ({
7987
onClose();
8088
}, [onClose, onSelectPath, root]);
8189

82-
if (!isOpen) return null;
90+
const handleOpenChange = useCallback(
91+
(open: boolean) => {
92+
if (!open && !isLoading) {
93+
onClose();
94+
}
95+
},
96+
[isLoading, onClose]
97+
);
98+
8399
const entries =
84100
root?.children
85101
.filter((child) => child.isDirectory)
86102
.map((child) => ({ name: child.name, path: child.path })) ?? [];
87103

88104
return (
89-
<Modal
90-
isOpen={isOpen}
91-
title="Select Project Directory"
92-
subtitle={root ? root.path : "Select a directory to use as your project root"}
93-
onClose={onClose}
94-
isLoading={isLoading}
95-
>
96-
{error && <div className="text-error mb-3 text-xs">{error}</div>}
97-
<div className="bg-modal-bg border-border-medium mb-4 h-64 overflow-hidden rounded border">
98-
<DirectoryTree
99-
currentPath={root ? root.path : null}
100-
entries={entries}
101-
isLoading={isLoading}
102-
onNavigateTo={handleNavigateTo}
103-
onNavigateParent={handleNavigateParent}
104-
/>
105-
</div>
106-
<ModalActions>
107-
<CancelButton onClick={onClose} disabled={isLoading}>
108-
Cancel
109-
</CancelButton>
110-
<PrimaryButton onClick={() => void handleConfirm()} disabled={isLoading || !root}>
111-
Select
112-
</PrimaryButton>
113-
</ModalActions>
114-
</Modal>
105+
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
106+
<DialogContent showCloseButton={false}>
107+
<DialogHeader>
108+
<DialogTitle>Select Project Directory</DialogTitle>
109+
<DialogDescription>
110+
{root ? root.path : "Select a directory to use as your project root"}
111+
</DialogDescription>
112+
</DialogHeader>
113+
{error && <div className="text-error mb-3 text-xs">{error}</div>}
114+
<div className="bg-modal-bg border-border-medium mb-4 h-64 overflow-hidden rounded border">
115+
<DirectoryTree
116+
currentPath={root ? root.path : null}
117+
entries={entries}
118+
isLoading={isLoading}
119+
onNavigateTo={handleNavigateTo}
120+
onNavigateParent={handleNavigateParent}
121+
/>
122+
</div>
123+
<DialogFooter>
124+
<Button variant="secondary" onClick={onClose} disabled={isLoading}>
125+
Cancel
126+
</Button>
127+
<Button onClick={() => void handleConfirm()} disabled={isLoading || !root}>
128+
Select
129+
</Button>
130+
</DialogFooter>
131+
</DialogContent>
132+
</Dialog>
115133
);
116134
};
Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useCallback } from "react";
22
import {
3-
Modal,
4-
ModalActions,
5-
CancelButton,
6-
DangerButton,
3+
Dialog,
4+
DialogContent,
5+
DialogHeader,
6+
DialogTitle,
7+
DialogDescription,
8+
DialogFooter,
79
ErrorSection,
810
ErrorLabel,
911
ErrorCodeBlock,
1012
WarningBox,
1113
WarningTitle,
1214
WarningText,
13-
} from "./Modal";
15+
} from "@/browser/components/ui/dialog";
16+
import { Button } from "@/browser/components/ui/button";
1417

1518
interface ForceDeleteModalProps {
1619
isOpen: boolean;
@@ -43,40 +46,47 @@ export const ForceDeleteModal: React.FC<ForceDeleteModalProps> = ({
4346
})();
4447
};
4548

49+
const handleOpenChange = useCallback(
50+
(open: boolean) => {
51+
if (!open && !isDeleting) {
52+
onClose();
53+
}
54+
},
55+
[isDeleting, onClose]
56+
);
57+
4658
return (
47-
<Modal
48-
isOpen={isOpen}
49-
title="Force Delete Workspace?"
50-
subtitle="The workspace could not be removed normally"
51-
onClose={onClose}
52-
maxWidth="600px"
53-
maxHeight="90vh"
54-
isLoading={isDeleting}
55-
>
56-
<ErrorSection>
57-
<ErrorLabel>Git Error</ErrorLabel>
58-
<ErrorCodeBlock>{error}</ErrorCodeBlock>
59-
</ErrorSection>
59+
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
60+
<DialogContent maxWidth="600px" maxHeight="90vh" showCloseButton={false}>
61+
<DialogHeader>
62+
<DialogTitle>Force Delete Workspace?</DialogTitle>
63+
<DialogDescription>The workspace could not be removed normally</DialogDescription>
64+
</DialogHeader>
65+
<ErrorSection>
66+
<ErrorLabel>Git Error</ErrorLabel>
67+
<ErrorCodeBlock>{error}</ErrorCodeBlock>
68+
</ErrorSection>
6069

61-
<WarningBox>
62-
<WarningTitle>This action cannot be undone</WarningTitle>
63-
<WarningText>
64-
Force deleting will permanently remove the workspace and{" "}
65-
{error.includes("unpushed commits:")
66-
? "discard the unpushed commits shown above"
67-
: "may discard uncommitted work or lose data"}
68-
. This action cannot be undone.
69-
</WarningText>
70-
</WarningBox>
70+
<WarningBox>
71+
<WarningTitle>This action cannot be undone</WarningTitle>
72+
<WarningText>
73+
Force deleting will permanently remove the workspace and{" "}
74+
{error.includes("unpushed commits:")
75+
? "discard the unpushed commits shown above"
76+
: "may discard uncommitted work or lose data"}
77+
. This action cannot be undone.
78+
</WarningText>
79+
</WarningBox>
7180

72-
<ModalActions className="justify-center">
73-
<CancelButton onClick={onClose} disabled={isDeleting}>
74-
Cancel
75-
</CancelButton>
76-
<DangerButton onClick={handleForceDelete} disabled={isDeleting}>
77-
{isDeleting ? "Deleting..." : "Force Delete"}
78-
</DangerButton>
79-
</ModalActions>
80-
</Modal>
81+
<DialogFooter className="justify-center">
82+
<Button variant="secondary" onClick={onClose} disabled={isDeleting}>
83+
Cancel
84+
</Button>
85+
<Button variant="destructive" onClick={handleForceDelete} disabled={isDeleting}>
86+
{isDeleting ? "Deleting..." : "Force Delete"}
87+
</Button>
88+
</DialogFooter>
89+
</DialogContent>
90+
</Dialog>
8191
);
8292
};

0 commit comments

Comments
 (0)