Compare commits

...

1 Commits

Author SHA1 Message Date
Bartek Gatz 25cd91993d feat(ui): add hover animation to Coder logo
Add a subtle jump animation to the Coder logo in the top-left corner
when users hover over it. This adds visual feedback and makes the UI
more interactive, matching the behavior seen on coder.com.

Changes:
- Add logo-jump keyframe animation to Tailwind config
- Apply hover animation to logo NavLink wrapper in NavbarView
- Add test coverage for logo hover animation classes
- Works for both default CoderIcon and custom logo images

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 16:52:05 +00:00
3 changed files with 67 additions and 1 deletions
@@ -0,0 +1,58 @@
import { render } from "testHelpers/renderHelpers";
import { screen } from "@testing-library/react";
import type * as TypesGen from "api/typesGenerated";
import { vi } from "vitest";
import { NavbarView } from "./NavbarView";
const mockUser: TypesGen.User = {
id: "test-user",
username: "testuser",
email: "test@example.com",
name: "Test User",
created_at: "2023-01-01T00:00:00Z",
status: "active",
organization_ids: [],
roles: [],
avatar_url: "",
last_seen_at: "2023-01-01T00:00:00Z",
login_type: "password",
theme_preference: "",
};
describe("NavbarView", () => {
const defaultProps = {
user: mockUser,
supportLinks: [],
onSignOut: vi.fn(),
canViewDeployment: false,
canViewOrganizations: false,
canViewAuditLog: false,
canViewConnectionLog: false,
canViewHealth: false,
canViewAIBridge: false,
};
it("should render logo with hover animation classes", async () => {
render(<NavbarView {...defaultProps} />);
const logoLink = await screen.findByRole("link", { name: /coder logo/i });
expect(logoLink).toHaveClass(
"inline-block",
"transition-transform",
"hover:animate-logo-jump",
);
});
it("should render custom logo with hover animation classes", async () => {
render(
<NavbarView {...defaultProps} logo_url="https://example.com/logo.png" />,
);
const logoLink = await screen.findByRole("link", { name: /custom logo/i });
expect(logoLink).toHaveClass(
"inline-block",
"transition-transform",
"hover:animate-logo-jump",
);
});
});
@@ -62,7 +62,10 @@ export const NavbarView: FC<NavbarViewProps> = ({
return (
<div className="border-0 border-b border-solid h-[72px] min-h-[72px] flex items-center leading-none px-6">
<NavLink to="/workspaces">
<NavLink
to="/workspaces"
className="inline-block transition-transform hover:animate-logo-jump"
>
{logo_url ? (
<ExternalImage className="h-7" src={logo_url} alt="Custom Logo" />
) : (
+5
View File
@@ -87,10 +87,15 @@ module.exports = {
"0%": { left: "0%" },
"100%": { left: "100%" },
},
"logo-jump": {
"0%, 100%": { transform: "translateY(0)" },
"50%": { transform: "translateY(-6px)" },
},
},
animation: {
loading: "loading 2s ease-in-out infinite alternate",
"caret-scan": "caret-scan 3s ease-in-out infinite",
"logo-jump": "logo-jump 0.3s ease-in-out",
},
},
},