Skip to content

Commit 8319617

Browse files
Extract conflict resolution and delete publish dialogs from app.tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0148504 commit 8319617

3 files changed

Lines changed: 139 additions & 100 deletions

File tree

app/src/app.tsx

Lines changed: 4 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,13 @@ import { type CSSProperties, useState } from "react";
33
import { useTheme } from "@/shared/hooks/use-theme";
44
import { Bar, Container, Section } from "@column-resizer/react";
55

6-
import { Button } from "@/shared/ui/button";
7-
import {
8-
DialogBackdrop,
9-
DialogClose,
10-
DialogPopup,
11-
DialogPortal,
12-
DialogRoot,
13-
DialogTitle,
14-
} from "@/shared/ui/dialog";
156
import { Toaster } from "@/shared/ui/sonner";
167
import { AccountSwitcherDialog } from "@/features/settings/account-switcher-dialog";
178
import { SettingsDialog } from "@/features/settings/settings-dialog";
189
import { CommandPalette } from "@/features/command-palette";
1910
import { BootstrapError } from "@/features/shell/ui/bootstrap-error";
11+
import { ConflictResolutionDialog } from "@/features/shell/ui/conflict-resolution-dialog";
12+
import { DeletePublishDialog } from "@/features/shell/ui/delete-publish-dialog";
2013
import { EditorPane } from "@/features/shell/editor-pane";
2114
import { NoteHistoryDialog } from "@/features/shell/note-history-dialog";
2215
import { NotesPane } from "@/features/notes/ui/notes-pane";
@@ -26,7 +19,6 @@ import { useAppShortcuts } from "@/features/shell/use-app-shortcuts";
2619
import { useRevealMainWindow } from "@/features/shell/use-reveal-main-window";
2720
import { useShellController } from "@/features/shell/use-shell-controller";
2821
import { useUIStore } from "@/features/settings/store/use-ui-store";
29-
import { conflictDialogCopy } from "@/shared/lib/conflict-dialog-copy";
3022

3123
function App() {
3224
useTheme();
@@ -63,17 +55,6 @@ function App() {
6355
return <BootstrapError error={bootstrapError} onRetry={retryBootstrap} />;
6456
}
6557

66-
const chooseConflictDialog = conflictDialogCopy(
67-
chooseConflictDialogProps.hasDeleteCandidate,
68-
);
69-
const defaultRestoreConflictLabel =
70-
chooseConflictDialogProps.hasDeleteCandidate
71-
? "Restore note"
72-
: "Choose shown version";
73-
const restoreConflictLabel = chooseConflictDialogProps.pending
74-
? "Restoring…"
75-
: defaultRestoreConflictLabel;
76-
7758
return (
7859
<div
7960
className="text-foreground relative h-full min-h-0 overflow-hidden"
@@ -137,85 +118,8 @@ function App() {
137118
<PublishDialog {...publishDialogProps} />
138119
<PublishShortNoteDialog {...publishShortNoteDialogProps} />
139120
<NoteHistoryDialog {...noteHistoryDialogProps} />
140-
<DialogRoot
141-
open={chooseConflictDialogProps.open}
142-
onOpenChange={chooseConflictDialogProps.onOpenChange}
143-
>
144-
<DialogPortal>
145-
<DialogBackdrop />
146-
<DialogPopup className="w-full max-w-sm p-6">
147-
<DialogTitle className="text-base font-semibold">
148-
{chooseConflictDialog.title}
149-
</DialogTitle>
150-
<p className="text-muted-foreground mt-2 text-sm">
151-
{chooseConflictDialog.description}
152-
</p>
153-
<div className="mt-5 flex justify-end gap-2">
154-
<DialogClose className="text-muted-foreground hover:text-foreground rounded-md px-3 py-1.5 text-sm transition-colors">
155-
Cancel
156-
</DialogClose>
157-
{chooseConflictDialogProps.hasDeleteCandidate ? (
158-
<Button
159-
disabled={chooseConflictDialogProps.pending}
160-
onClick={chooseConflictDialogProps.onKeepDeleted}
161-
size="sm"
162-
variant="destructive"
163-
>
164-
{chooseConflictDialogProps.pending
165-
? "Deleting…"
166-
: "Keep deleted"}
167-
</Button>
168-
) : null}
169-
<Button
170-
disabled={chooseConflictDialogProps.pending}
171-
onClick={chooseConflictDialogProps.onRestore}
172-
size="sm"
173-
variant="secondary"
174-
>
175-
{restoreConflictLabel}
176-
</Button>
177-
<Button
178-
disabled={chooseConflictDialogProps.pending}
179-
onClick={chooseConflictDialogProps.onMerge}
180-
size="sm"
181-
variant="default"
182-
>
183-
{chooseConflictDialogProps.pending ? "Merging…" : "Merge draft"}
184-
</Button>
185-
</div>
186-
</DialogPopup>
187-
</DialogPortal>
188-
</DialogRoot>
189-
<DialogRoot
190-
open={deletePublishDialogProps.open}
191-
onOpenChange={deletePublishDialogProps.onOpenChange}
192-
>
193-
<DialogPortal>
194-
<DialogBackdrop />
195-
<DialogPopup className="w-full max-w-sm p-6">
196-
<DialogTitle className="text-base font-semibold">
197-
Delete from Nostr?
198-
</DialogTitle>
199-
<p className="text-muted-foreground mt-2 text-sm">
200-
This will request relays to delete the published note. Relays may
201-
not honor the request, and copies may still exist elsewhere.
202-
</p>
203-
<div className="mt-5 flex justify-end gap-2">
204-
<DialogClose className="text-muted-foreground hover:text-foreground rounded-md px-3 py-1.5 text-sm transition-colors">
205-
Cancel
206-
</DialogClose>
207-
<Button
208-
disabled={deletePublishDialogProps.pending}
209-
onClick={deletePublishDialogProps.onConfirm}
210-
size="sm"
211-
variant="destructive"
212-
>
213-
{deletePublishDialogProps.pending ? "Deleting…" : "Delete"}
214-
</Button>
215-
</div>
216-
</DialogPopup>
217-
</DialogPortal>
218-
</DialogRoot>
121+
<ConflictResolutionDialog {...chooseConflictDialogProps} />
122+
<DeletePublishDialog {...deletePublishDialogProps} />
219123
<CommandPalette
220124
availableTagPaths={sidebarPaneProps.availableTagPaths}
221125
open={commandPaletteOpen}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Button } from "@/shared/ui/button";
2+
import {
3+
DialogBackdrop,
4+
DialogClose,
5+
DialogPopup,
6+
DialogPortal,
7+
DialogRoot,
8+
DialogTitle,
9+
} from "@/shared/ui/dialog";
10+
import { conflictDialogCopy } from "@/shared/lib/conflict-dialog-copy";
11+
12+
interface ConflictResolutionDialogProps {
13+
hasDeleteCandidate: boolean;
14+
open: boolean;
15+
pending: boolean;
16+
onKeepDeleted: () => void;
17+
onMerge: () => void;
18+
onOpenChange: (open: boolean) => void;
19+
onRestore: () => void;
20+
}
21+
22+
export function ConflictResolutionDialog({
23+
hasDeleteCandidate,
24+
open,
25+
pending,
26+
onKeepDeleted,
27+
onMerge,
28+
onOpenChange,
29+
onRestore,
30+
}: ConflictResolutionDialogProps) {
31+
const copy = conflictDialogCopy(hasDeleteCandidate);
32+
let restoreLabel = "Choose shown version";
33+
if (pending) restoreLabel = "Restoring…";
34+
else if (hasDeleteCandidate) restoreLabel = "Restore note";
35+
36+
return (
37+
<DialogRoot open={open} onOpenChange={onOpenChange}>
38+
<DialogPortal>
39+
<DialogBackdrop />
40+
<DialogPopup className="w-full max-w-sm p-6">
41+
<DialogTitle className="text-base font-semibold">
42+
{copy.title}
43+
</DialogTitle>
44+
<p className="text-muted-foreground mt-2 text-sm">
45+
{copy.description}
46+
</p>
47+
<div className="mt-5 flex justify-end gap-2">
48+
<DialogClose className="text-muted-foreground hover:text-foreground rounded-md px-3 py-1.5 text-sm transition-colors">
49+
Cancel
50+
</DialogClose>
51+
{hasDeleteCandidate ? (
52+
<Button
53+
disabled={pending}
54+
onClick={onKeepDeleted}
55+
size="sm"
56+
variant="destructive"
57+
>
58+
{pending ? "Deleting…" : "Keep deleted"}
59+
</Button>
60+
) : null}
61+
<Button
62+
disabled={pending}
63+
onClick={onRestore}
64+
size="sm"
65+
variant="secondary"
66+
>
67+
{restoreLabel}
68+
</Button>
69+
<Button
70+
disabled={pending}
71+
onClick={onMerge}
72+
size="sm"
73+
variant="default"
74+
>
75+
{pending ? "Merging…" : "Merge draft"}
76+
</Button>
77+
</div>
78+
</DialogPopup>
79+
</DialogPortal>
80+
</DialogRoot>
81+
);
82+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Button } from "@/shared/ui/button";
2+
import {
3+
DialogBackdrop,
4+
DialogClose,
5+
DialogPopup,
6+
DialogPortal,
7+
DialogRoot,
8+
DialogTitle,
9+
} from "@/shared/ui/dialog";
10+
11+
interface DeletePublishDialogProps {
12+
open: boolean;
13+
pending: boolean;
14+
onConfirm: () => void;
15+
onOpenChange: (open: boolean) => void;
16+
}
17+
18+
export function DeletePublishDialog({
19+
open,
20+
pending,
21+
onConfirm,
22+
onOpenChange,
23+
}: DeletePublishDialogProps) {
24+
return (
25+
<DialogRoot open={open} onOpenChange={onOpenChange}>
26+
<DialogPortal>
27+
<DialogBackdrop />
28+
<DialogPopup className="w-full max-w-sm p-6">
29+
<DialogTitle className="text-base font-semibold">
30+
Delete from Nostr?
31+
</DialogTitle>
32+
<p className="text-muted-foreground mt-2 text-sm">
33+
This will request relays to delete the published note. Relays may
34+
not honor the request, and copies may still exist elsewhere.
35+
</p>
36+
<div className="mt-5 flex justify-end gap-2">
37+
<DialogClose className="text-muted-foreground hover:text-foreground rounded-md px-3 py-1.5 text-sm transition-colors">
38+
Cancel
39+
</DialogClose>
40+
<Button
41+
disabled={pending}
42+
onClick={onConfirm}
43+
size="sm"
44+
variant="destructive"
45+
>
46+
{pending ? "Deleting…" : "Delete"}
47+
</Button>
48+
</div>
49+
</DialogPopup>
50+
</DialogPortal>
51+
</DialogRoot>
52+
);
53+
}

0 commit comments

Comments
 (0)