Skip to content
Open
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
33 changes: 33 additions & 0 deletions src/browser/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,36 @@ import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

/**
* Compute perceived lightness of a hex color (0–1).
* Uses sRGB relative luminance formula.
*/
function perceivedLightness(hex: string): number {
const r = parseInt(hex.slice(0, 2), 16) / 255;
const g = parseInt(hex.slice(2, 4), 16) / 255;
const b = parseInt(hex.slice(4, 6), 16) / 255;
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

/**
* Returns inline styles for a GitHub-style label.
* In light mode, light-colored labels get a solid background with dark text
* so they remain visible against a white page background.
*/
export function labelStyles(color: string): React.CSSProperties {
const isLight = document.documentElement.classList.contains("light");
const l = perceivedLightness(color);
if (isLight && l > 0.6) {
return {
backgroundColor: `#${color}`,
color: "#1f2328",
border: `1px solid #${color}`,
};
}
return {
backgroundColor: `#${color}20`,
color: `#${color}`,
border: `1px solid #${color}40`,
};
}
4 changes: 2 additions & 2 deletions src/browser/components/app-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export function AppShell() {
return (
<div className="h-screen flex flex-col overflow-hidden bg-background">
{/* Native-style Tab Bar */}
<div className="h-9 bg-[#1a1a1a] flex items-center shrink-0 border-b border-border/50 app-drag-region">
<div className="h-9 bg-muted flex items-center shrink-0 border-b border-border/50 app-drag-region">
{/* Logo with tooltip */}
<div className="h-full flex items-center gap-1.5 px-3 shrink-0 app-no-drag">
<HoverCard openDelay={200} closeDelay={100}>
Expand Down Expand Up @@ -348,7 +348,7 @@ function TabStatusIndicator({ status }: { status?: TabStatus }) {
colorClass = "bg-yellow-500";
title = "Checks running";
} else if (status.checks === "success" || status.checks === "none") {
colorClass = "bg-green-500";
colorClass = "bg-success";
title = status.mergeable ? "Ready to merge" : "Checks passed";
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/browser/components/command-palette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ const FileItem = memo(function FileItem({
</div>
<div className="flex items-center gap-2 text-xs shrink-0">
{file.status === "added" && (
<span className="text-green-500 group-data-[selected=true]:text-green-300">
<span className="text-success-fg group-data-[selected=true]:text-green-300">
+{file.additions}
</span>
)}
Expand All @@ -454,7 +454,7 @@ const FileItem = memo(function FileItem({
)}
{file.status === "modified" && (
<>
<span className="text-green-500 group-data-[selected=true]:text-green-300">
<span className="text-success-fg group-data-[selected=true]:text-green-300">
+{file.additions}
</span>
<span className="text-red-500 group-data-[selected=true]:text-red-300">
Expand All @@ -468,7 +468,7 @@ const FileItem = memo(function FileItem({
</span>
)}
{isViewed && (
<span className="px-1.5 py-0.5 bg-green-500/20 text-green-400 group-data-[selected=true]:bg-green-400/30 group-data-[selected=true]:text-green-200 rounded text-[10px]">
<span className="px-1.5 py-0.5 bg-success-muted-bg text-success-fg group-data-[selected=true]:bg-green-400/30 group-data-[selected=true]:text-green-200 rounded text-[10px]">
viewed
</span>
)}
Expand Down
8 changes: 4 additions & 4 deletions src/browser/components/file-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const FileHeader = memo(function FileHeader({
switch (file.status) {
case "added":
return (
<span className="px-1.5 py-0.5 text-xs rounded bg-green-500/20 text-green-500 font-medium">
<span className="px-1.5 py-0.5 text-xs rounded bg-success-muted-bg text-success-fg font-medium">
Added
</span>
);
Expand Down Expand Up @@ -71,7 +71,7 @@ export const FileHeader = memo(function FileHeader({
</span>
{fileStatusBadge}
<span className="text-xs text-muted-foreground shrink-0">
<span className="text-green-500">+{file.additions}</span>{" "}
<span className="text-success-fg">+{file.additions}</span>{" "}
<span className="text-red-500">−{file.deletions}</span>
</span>
{/* Navigation buttons */}
Expand Down Expand Up @@ -144,11 +144,11 @@ export const FileHeader = memo(function FileHeader({
className={cn(
"flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-md transition-colors shrink-0",
isViewed
? "bg-green-500/20 text-green-500 hover:bg-green-500/30"
? "bg-success-muted-bg text-success-fg hover:bg-success-muted-bg"
: "bg-muted hover:bg-muted/80 text-muted-foreground"
)}
>
<Check className={cn("w-4 h-4", isViewed && "text-green-500")} />
<Check className={cn("w-4 h-4", isViewed && "text-success-fg")} />
{isViewed ? "Viewed" : "Mark as viewed"}
<Keycap keyName="v" size="xs" className="ml-1" />
</button>
Expand Down
6 changes: 3 additions & 3 deletions src/browser/components/file-tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ function buildTree(files: PullRequestFile[]): TreeNode[] {
function getFileIcon(file: PullRequestFile) {
switch (file.status) {
case "added":
return <FilePlus className="w-4 h-4 text-green-500" />;
return <FilePlus className="w-4 h-4 text-success-fg" />;
case "removed":
return <FileMinus className="w-4 h-4 text-red-500" />;
case "modified":
Expand Down Expand Up @@ -349,7 +349,7 @@ export function FileTree({
)}
<span className="truncate flex-1">{node.name}</span>
{allViewed && (
<Check className="w-3 h-3 text-green-500 shrink-0" />
<Check className="w-3 h-3 text-success-fg shrink-0" />
)}
</button>
</ContextMenuTrigger>
Expand Down Expand Up @@ -432,7 +432,7 @@ export function FileTree({
{commentCount}
</span>
)}
{isViewed && <Check className="w-3 h-3 text-green-500" />}
{isViewed && <Check className="w-3 h-3 text-success-fg" />}
</div>
</button>
</ContextMenuTrigger>
Expand Down
8 changes: 2 additions & 6 deletions src/browser/components/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
Clock,
} from "lucide-react";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
import { cn } from "../cn";
import { cn, labelStyles } from "../cn";
import { Skeleton } from "../ui/skeleton";
import { UserHoverCard } from "../ui/user-hover-card";
import {
Expand Down Expand Up @@ -1466,11 +1466,7 @@ function PRListItem({ pr, onSelect }: PRListItemProps) {
<span
key={label.name}
className="px-2 py-0.5 text-[11px] font-medium rounded-full hidden sm:inline-block"
style={{
backgroundColor: `#${label.color}20`,
color: `#${label.color}`,
border: `1px solid #${label.color}40`,
}}
style={labelStyles(label.color)}
>
{label.name}
</span>
Expand Down
6 changes: 3 additions & 3 deletions src/browser/components/pr-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const PRHeader = memo(function PRHeader({
: pr.state === "open"
? pr.draft
? "bg-gray-600"
: "bg-green-600"
: "bg-success"
: "bg-red-600";

return (
Expand Down Expand Up @@ -123,7 +123,7 @@ export const PRHeader = memo(function PRHeader({
<div className="flex items-center gap-2 sm:gap-3 shrink-0">
{/* Line diff stats */}
<span className="text-xs hidden sm:inline">
<span className="text-green-500">+{pr.additions}</span>{" "}
<span className="text-success-fg">+{pr.additions}</span>{" "}
<span className="text-red-500">−{pr.deletions}</span>
</span>

Expand Down Expand Up @@ -158,7 +158,7 @@ function BranchBadge({ branch }: { branch: string }) {
title="Copy branch name"
>
{copied ? (
<Check className="w-3 h-3 text-green-500" />
<Check className="w-3 h-3 text-success-fg" />
) : (
<Copy className="w-3 h-3" />
)}
Expand Down
Loading