Skip to content
Closed
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
2 changes: 1 addition & 1 deletion src/lib/__tests__/color.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { adjustAccentColor, type ColorResult } from "../color";
import { adjustAccentColor } from "../color";

/**
* adjustAccentColor のユニットテスト
Expand Down
42 changes: 28 additions & 14 deletions src/lib/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,10 @@ const TARGET_MIN_LIGHTNESS = 45;
const TARGET_MAX_LIGHTNESS = 85;
const HOVER_LIGHTEN_AMOUNT = 0.1;

/**
* Adjusts the given color to be suitable for use as an accent color in a dark theme.
* Ensures sufficient saturation and appropriate lightness.
* @param color Hex string or RGB object/array
*/
export function adjustAccentColor(color: string | [number, number, number] | { r: number; g: number; b: number }): ColorResult {
let c;
type ColorInput = string | [number, number, number] | { r: number; g: number; b: number };

function parseColor(color: ColorInput) {
let c;
if (Array.isArray(color)) {
c = colord({ r: color[0], g: color[1], b: color[2] });
} else {
Expand All @@ -39,26 +35,32 @@ export function adjustAccentColor(color: string | [number, number, number] | { r
if (!c.isValid()) {
c = colord(DEFAULT_ACCENT_COLOR);
}
return c;
}

// Adjust saturation: if too low, saturate
function ensureSaturation(c: ReturnType<typeof colord>) {
const s = c.toHsl().s;
if (s < MIN_SATURATION_FOR_HIGH_BOOST) {
c = c.saturate(HIGH_SATURATION_BOOST);
return c.saturate(HIGH_SATURATION_BOOST);
} else if (s < MIN_SATURATION_FOR_LOW_BOOST) {
c = c.saturate(LOW_SATURATION_BOOST);
return c.saturate(LOW_SATURATION_BOOST);
}
return c;
}

// Adjust lightness for dark mode context
// Should be bright enough to glow, but not white
function adjustLightness(c: ReturnType<typeof colord>) {
const l = c.toHsl().l;
if (l < TARGET_MIN_LIGHTNESS) {
// Lift to at least TARGET_MIN_LIGHTNESS
c = c.lighten((TARGET_MIN_LIGHTNESS - l) / 100);
return c.lighten((TARGET_MIN_LIGHTNESS - l) / 100);
} else if (l > TARGET_MAX_LIGHTNESS) {
// Dim to at most TARGET_MAX_LIGHTNESS
c = c.darken((l - TARGET_MAX_LIGHTNESS) / 100);
return c.darken((l - TARGET_MAX_LIGHTNESS) / 100);
}
return c;
}

function generateColorResult(c: ReturnType<typeof colord>): ColorResult {
const hex = c.toHex();
const rgb = c.toRgb();
const rgbString = `${rgb.r}, ${rgb.g}, ${rgb.b}`;
Expand All @@ -72,3 +74,15 @@ export function adjustAccentColor(color: string | [number, number, number] | { r
accentHover: hover,
};
}

/**
* Adjusts the given color to be suitable for use as an accent color in a dark theme.
* Ensures sufficient saturation and appropriate lightness.
* @param color Hex string or RGB object/array
*/
export function adjustAccentColor(color: ColorInput): ColorResult {
let c = parseColor(color);
c = ensureSaturation(c);
c = adjustLightness(c);
return generateColorResult(c);
Comment on lines +84 to +87

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

リファクタリングにより、コードが非常に読みやすくなりました。
adjustAccentColor 関数内で let を使って変数 c を再代入していますが、各処理ステップの結果を const で新しい変数に格納するスタイルにすると、データの変換フローがより明確になり、意図しない変更を防ぐ助けになります。可読性と保守性をさらに高めるために、以下のような実装もご検討ください。

Suggested change
let c = parseColor(color);
c = ensureSaturation(c);
c = adjustLightness(c);
return generateColorResult(c);
const parsed = parseColor(color);
const saturated = ensureSaturation(parsed);
const adjusted = adjustLightness(saturated);
return generateColorResult(adjusted);

}
Loading