From db72a2560f06db56b3ef2e6b53f54d8a824a1700 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 5 Oct 2026 03:15:10 +0200 Subject: [PATCH] Widen the tool rail, set the swap in the color squares' corner, and pick colors as a tool --- src/app/editor/tool-rail.tsx | 8 +- src/components/icons/eyedropper.tsx | 2 +- src/components/icons/swap-corner.tsx | 9 ++ src/components/ui/color-swatch.tsx | 7 +- src/features/paint/colors.tsx | 124 +++++++++++++++++++++------ 5 files changed, 117 insertions(+), 33 deletions(-) create mode 100644 src/components/icons/swap-corner.tsx diff --git a/src/app/editor/tool-rail.tsx b/src/app/editor/tool-rail.tsx index ccfc7b9..0fd3dc2 100644 --- a/src/app/editor/tool-rail.tsx +++ b/src/app/editor/tool-rail.tsx @@ -3,7 +3,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@roprgm/ui/tooltip"; import type { ReactNode } from "react"; import { GithubIcon } from "@/components/icons/github"; import { InfoIcon } from "@/components/icons/info"; -import { PaintColors } from "@/features/paint/colors"; +import { RailPaintColors } from "@/features/paint/colors"; import { type Tool, tools, useTool } from "./tools"; /** Opens in a new tab, leaving the photo open. */ @@ -51,10 +51,11 @@ export function ToolTabList({ }) { const editing = tools.filter((entry) => entry.group === "edit"); return ( + // The tools fill the rail, 6px from the window's edge and 7px from the border. {editing.map((entry) => ( @@ -65,6 +66,7 @@ export function ToolTabList({ value={entry} disabled={!onSelect} size="icon-lg" + className="size-8.5" aria-label={entry.label} /> } @@ -98,7 +100,7 @@ export function ToolRail() { const { tool, setTool } = useTool(); return ( - + ); } diff --git a/src/components/icons/eyedropper.tsx b/src/components/icons/eyedropper.tsx index 685bc7f..f649836 100644 --- a/src/components/icons/eyedropper.tsx +++ b/src/components/icons/eyedropper.tsx @@ -4,7 +4,7 @@ export function EyedropperIcon(props: IconProps) { return ( - + ); diff --git a/src/components/icons/swap-corner.tsx b/src/components/icons/swap-corner.tsx new file mode 100644 index 0000000..c6036fc --- /dev/null +++ b/src/components/icons/swap-corner.tsx @@ -0,0 +1,9 @@ +import { Icon, type IconProps } from "./icon"; + +export function SwapCornerIcon(props: IconProps) { + return ( + + + + ); +} diff --git a/src/components/ui/color-swatch.tsx b/src/components/ui/color-swatch.tsx index 8033b40..85734df 100644 --- a/src/components/ui/color-swatch.tsx +++ b/src/components/ui/color-swatch.tsx @@ -2,8 +2,9 @@ import { cn } from "cn"; import { type ComponentProps, useEffect, useRef } from "react"; /** - * A raised square of a color that opens the browser's color picker. The picker streams changes while - * it moves, and `onClose` follows the last of them. + * A flat square of a color that opens the browser's color picker: a control's shadow without the lit + * top edge, which would tint the color, and a faint edge that parts it from a background of its + * color. The picker streams changes while it moves, and `onClose` follows the last of them. */ export function ColorSwatch({ label, @@ -31,7 +32,7 @@ export function ColorSwatch({ } @@ -64,35 +66,56 @@ function Swatch({ ); } -/** - * Two raised squares, as in Photoshop: the primary over the secondary, with swap and pick after them, - * in a row or, in the tool rail, a column. - */ -export function PaintColors({ vertical = false }: { vertical?: boolean }) { +/** Two squares, as in Photoshop: the primary over the secondary, with `children` in a free corner. */ +function Swatches({ + colors, + side, + className, + swatch, + children, +}: { + colors: ReturnType; + side: Side; + className: string; + swatch: string; + children?: ReactNode; +}) { + return ( +
+ + + {children} +
+ ); +} + +/** The colors in a row, with swap and pick after them. */ +export function PaintColors() { const colors = usePaintColors(); - const side = vertical ? "right" : "top"; return ( -
-
- - -
+
+ ); } + +/** + * The colors in the tool rail: pick as one more tool, then the squares with swap in their free + * corner, as in Photoshop. X swaps from the keyboard, so the arrow takes no focus. + */ +export function RailPaintColors() { + const colors = usePaintColors(); + return ( + <> + {colors.pick && ( + + + + )} + + + + } + > + + + + Swap colors + + + + + ); +}