Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions src/components/about-dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ const openerState = vi.hoisted(() => ({
openUrlMock: vi.fn(() => Promise.resolve()),
}))

const changelogState = vi.hoisted(() => ({
releases: [] as import("@/hooks/use-changelog").Release[],
loading: false,
error: null as string | null,
}))

vi.mock("@tauri-apps/plugin-opener", () => ({
openUrl: openerState.openUrlMock,
}))

vi.mock("@/hooks/use-changelog", () => ({
useChangelog: () => changelogState,
}))

describe("AboutDialog", () => {
it("renders version, links, and maintainers", () => {
render(<AboutDialog version="1.2.3" onClose={() => {}} />)
Expand Down Expand Up @@ -40,6 +50,20 @@ describe("AboutDialog", () => {
expect(onClose).toHaveBeenCalled()
})

it("goes back to about view on Escape when showing changelog", async () => {
const onClose = vi.fn()
render(<AboutDialog version="1.2.3" onClose={onClose} />)

// Switch to changelog view.
await userEvent.click(screen.getByRole("button", { name: "View Changelog" }))
Comment thread
hearsilent marked this conversation as resolved.

// Press Escape; should go back to About view, not close.
await userEvent.keyboard("{Escape}")

expect(onClose).not.toHaveBeenCalled()
expect(screen.getByText("OpenUsage")).toBeInTheDocument()
})

it("does not close on other keys", async () => {
const onClose = vi.fn()
render(<AboutDialog version="1.2.3" onClose={onClose} />)
Expand Down
41 changes: 36 additions & 5 deletions src/components/about-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { openUrl } from "@tauri-apps/plugin-opener";
import { ChangelogDialog } from "./changelog-dialog";
import { Button } from "@/components/ui/button";

interface AboutDialogProps {
version: string;
Expand Down Expand Up @@ -29,8 +31,14 @@ function ExternalLink({
}

export function AboutDialog({ version, onClose }: AboutDialogProps) {
const [view, setView] = useState<"about" | "changelog">("about");

// Close on ESC key
useEffect(() => {
if (view !== "about") {
return;
}

const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") {
e.preventDefault();
Expand All @@ -39,7 +47,7 @@ export function AboutDialog({ version, onClose }: AboutDialogProps) {
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [onClose]);
}, [onClose, view]);

// Close when panel hides (loses visibility)
useEffect(() => {
Expand All @@ -59,6 +67,18 @@ export function AboutDialog({ version, onClose }: AboutDialogProps) {
}
};

if (view === "changelog") {
return (
<ChangelogDialog
currentVersion={version}
onBack={() => setView("about")}
// In changelog view, Escape should go back to About instead of
// closing the entire dialog, so hand off to setView.
onClose={() => setView("about")}
/>
);
}

return (
<div
className="absolute inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm rounded-xl"
Expand All @@ -73,9 +93,19 @@ export function AboutDialog({ version, onClose }: AboutDialogProps) {

<h2 className="text-xl font-semibold mb-1">OpenUsage</h2>

<span className="inline-block text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded-full mb-4">
v{version}
</span>
<div className="flex flex-col items-center gap-2 mb-4">
<span className="inline-block text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded-full">
v{version}
</span>
<Button
size="xs"
variant="outline"
onClick={() => setView("changelog")}
className="text-[10px] h-5 px-1.5"
>
View Changelog
</Button>
</div>

<div className="text-sm text-muted-foreground space-y-1">
<p>
Expand Down Expand Up @@ -103,3 +133,4 @@ export function AboutDialog({ version, onClose }: AboutDialogProps) {
</div>
);
}

Loading
Loading