Add a new packages @gitbook/colors (#2854)

Co-authored-by: Zeno Kapitein <zenomilan@me.com>
This commit is contained in:
Valentino Hudhra
2025-02-19 17:17:39 +01:00
committed by GitHub
parent 7419ee7dba
commit 445baaaa61
14 changed files with 145 additions and 28 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@gitbook/colors': minor
---
Initial release
+10
View File
@@ -22,6 +22,13 @@
"wrangler": "3.82.0", "wrangler": "3.82.0",
}, },
}, },
"packages/colors": {
"name": "@gitbook/colors",
"version": "0.1.0",
"devDependencies": {
"typescript": "^5.5.3",
},
},
"packages/emoji-codepoints": { "packages/emoji-codepoints": {
"name": "@gitbook/emoji-codepoints", "name": "@gitbook/emoji-codepoints",
"version": "0.2.0", "version": "0.2.0",
@@ -35,6 +42,7 @@
"dependencies": { "dependencies": {
"@gitbook/api": "^0.93.0", "@gitbook/api": "^0.93.0",
"@gitbook/cache-do": "workspace:*", "@gitbook/cache-do": "workspace:*",
"@gitbook/colors": "workspace:*",
"@gitbook/emoji-codepoints": "workspace:*", "@gitbook/emoji-codepoints": "workspace:*",
"@gitbook/icons": "workspace:*", "@gitbook/icons": "workspace:*",
"@gitbook/openapi-parser": "workspace:*", "@gitbook/openapi-parser": "workspace:*",
@@ -594,6 +602,8 @@
"@gitbook/cache-do": ["@gitbook/cache-do@workspace:packages/cache-do"], "@gitbook/cache-do": ["@gitbook/cache-do@workspace:packages/cache-do"],
"@gitbook/colors": ["@gitbook/colors@workspace:packages/colors"],
"@gitbook/emoji-codepoints": ["@gitbook/emoji-codepoints@workspace:packages/emoji-codepoints"], "@gitbook/emoji-codepoints": ["@gitbook/emoji-codepoints@workspace:packages/emoji-codepoints"],
"@gitbook/fontawesome-pro": ["@gitbook/fontawesome-pro@1.0.8", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "^6.6.0" } }, "sha512-i4PgiuGyUb52Muhc52kK3aMJIMfMkA2RbPW30tre8a6M8T6mWTfYo6gafSgjNvF1vH29zcuB8oBYnF0gO4XcHA=="], "@gitbook/fontawesome-pro": ["@gitbook/fontawesome-pro@1.0.8", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "^6.6.0" } }, "sha512-i4PgiuGyUb52Muhc52kK3aMJIMfMkA2RbPW30tre8a6M8T6mWTfYo6gafSgjNvF1vH29zcuB8oBYnF0gO4XcHA=="],
+1
View File
@@ -0,0 +1 @@
dist/
+3
View File
@@ -0,0 +1,3 @@
# `@gitbook/colors`
A set of default colors and transformation functions used throughout the GitBook Open and app.
+26
View File
@@ -0,0 +1,26 @@
{
"name": "@gitbook/colors",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"development": "./src/index.ts",
"default": "./dist/index.js"
}
},
"version": "0.1.0",
"devDependencies": {
"typescript": "^5.5.3"
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"dev": "tsc -w"
},
"files": [
"dist",
"src",
"README.md",
"CHANGELOG.md"
]
}
+39
View File
@@ -0,0 +1,39 @@
/**
* Default primary color throughout the GitBook ecosystem.
*/
export const DEFAULT_PRIMARY_COLOR = '#346DDB';
/**
* The darkest color that exists in GitBook, used as the relative minimum of every generated color scale.
*/
export const DARK_BASE = '#1D1D1D';
/**
* The lightest color that exists in GitBook, used as the relative maximum of every generated color scale.
*/
export const LIGHT_BASE = '#FFFFFF';
/**
* Used as the basis of all UI elements that are not colored by the primary color. Neutral gray by default, overridden by site customization.
*/
export const DEFAULT_TINT_COLOR = '#787878';
/**
* Used for informational messages and neutral alerts.
*/
export const DEFAULT_HINT_INFO_COLOR = '#787878';
/**
* Used for showing important information or non-critical warnings.
*/
export const DEFAULT_HINT_WARNING_COLOR = '#FE9A00';
/**
* Used for destructive actions or raising attention to critical information.
*/
export const DEFAULT_HINT_DANGER_COLOR = '#FB2C36';
/**
* Used for showing positive actions or achievements.
*/
export const DEFAULT_HINT_SUCCESS_COLOR = '#00C950';
+2
View File
@@ -0,0 +1,2 @@
export * from './colors';
export * from './transformations';
@@ -1,3 +1,5 @@
import { DARK_BASE, LIGHT_BASE, DEFAULT_TINT_COLOR } from './colors';
type ColorShades = { type ColorShades = {
[key: string]: string; [key: string]: string;
}; };
@@ -6,9 +8,6 @@ type RGBColor = [number, number, number];
type OKLABColor = { L: number; A: number; B: number }; type OKLABColor = { L: number; A: number; B: number };
type OKLCHColor = { L: number; C: number; H: number }; type OKLCHColor = { L: number; C: number; H: number };
export const DARK_BASE = '#1d1d1d';
export const LIGHT_BASE = '#ffffff';
export const DEFAULT_TINT_COLOR = '#787878';
const D65 = [95.047, 100.0, 108.883]; // Reference white (D65) const D65 = [95.047, 100.0, 108.883]; // Reference white (D65)
export enum ColorCategory { export enum ColorCategory {
@@ -226,7 +225,7 @@ export function colorScale(
/** /**
* Convert a hex color to an RGB color set. * Convert a hex color to an RGB color set.
*/ */
function hexToRgbArray(hex: string): RGBColor { export function hexToRgbArray(hex: string): RGBColor {
const originalHex = hex; const originalHex = hex;
let value = hex.replace('#', ''); let value = hex.replace('#', '');
@@ -252,7 +251,7 @@ function hexToRgbArray(hex: string): RGBColor {
/** /**
* Convert a RGB color set to a hex color. * Convert a RGB color set to a hex color.
*/ */
function rgbArrayToHex(rgb: RGBColor): string { export function rgbArrayToHex(rgb: RGBColor): string {
return `#${rgb return `#${rgb
.map((channel) => { .map((channel) => {
const component = channel.toString(16); const component = channel.toString(16);
@@ -262,7 +261,7 @@ function rgbArrayToHex(rgb: RGBColor): string {
.join('')}`; .join('')}`;
} }
function getColor(percentage: number, start: RGBColor, end: RGBColor) { export function getColor(percentage: number, start: RGBColor, end: RGBColor) {
const rgb = end.map((channel, index) => { const rgb = end.map((channel, index) => {
return Math.round(channel + percentage * (start[index] - channel)); return Math.round(channel + percentage * (start[index] - channel));
}); });
@@ -271,21 +270,21 @@ function getColor(percentage: number, start: RGBColor, end: RGBColor) {
} }
// Utility constants and helper functions // Utility constants and helper functions
function rgbToLinear(rgb: RGBColor): [number, number, number] { export function rgbToLinear(rgb: RGBColor): [number, number, number] {
return rgb.map((v) => { return rgb.map((v) => {
const scaled = v / 255; const scaled = v / 255;
return scaled <= 0.04045 ? scaled / 12.92 : ((scaled + 0.055) / 1.055) ** 2.4; return scaled <= 0.04045 ? scaled / 12.92 : ((scaled + 0.055) / 1.055) ** 2.4;
}) as [number, number, number]; }) as [number, number, number];
} }
function linearToRgb(linear: [number, number, number]): RGBColor { export function linearToRgb(linear: [number, number, number]): RGBColor {
return linear.map((v) => { return linear.map((v) => {
const scaled = v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055; const scaled = v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;
return Math.round(Math.max(0, Math.min(1, scaled)) * 255); return Math.round(Math.max(0, Math.min(1, scaled)) * 255);
}) as RGBColor; }) as RGBColor;
} }
function rgbToOklab(rgb: RGBColor): OKLABColor { export function rgbToOklab(rgb: RGBColor): OKLABColor {
const [r, g, b] = rgbToLinear(rgb); const [r, g, b] = rgbToLinear(rgb);
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b; const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
@@ -303,7 +302,7 @@ function rgbToOklab(rgb: RGBColor): OKLABColor {
}; };
} }
function oklabToRgb(oklab: OKLABColor): RGBColor { export function oklabToRgb(oklab: OKLABColor): RGBColor {
const { L, A, B } = oklab; const { L, A, B } = oklab;
const lRoot = L + 0.3963377774 * A + 0.2158037573 * B; const lRoot = L + 0.3963377774 * A + 0.2158037573 * B;
@@ -321,14 +320,14 @@ function oklabToRgb(oklab: OKLABColor): RGBColor {
return linearToRgb([r, g, b]); return linearToRgb([r, g, b]);
} }
function oklabToOklch(oklab: OKLABColor): OKLCHColor { export function oklabToOklch(oklab: OKLABColor): OKLCHColor {
const { L, A, B } = oklab; const { L, A, B } = oklab;
const C = Math.sqrt(A ** 2 + B ** 2); const C = Math.sqrt(A ** 2 + B ** 2);
const H = (Math.atan2(B, A) * 180) / Math.PI; const H = (Math.atan2(B, A) * 180) / Math.PI;
return { L, C, H: H < 0 ? H + 360 : H }; return { L, C, H: H < 0 ? H + 360 : H };
} }
function oklchToOklab(oklch: OKLCHColor): OKLABColor { export function oklchToOklab(oklch: OKLCHColor): OKLABColor {
const { L, C, H } = oklch; const { L, C, H } = oklch;
const rad = (H * Math.PI) / 180; const rad = (H * Math.PI) / 180;
return { return {
@@ -338,15 +337,15 @@ function oklchToOklab(oklch: OKLCHColor): OKLABColor {
}; };
} }
function rgbToOklch(rgb: RGBColor): OKLCHColor { export function rgbToOklch(rgb: RGBColor): OKLCHColor {
return oklabToOklch(rgbToOklab(rgb)); return oklabToOklch(rgbToOklab(rgb));
} }
function oklchToRgb(oklch: OKLCHColor): RGBColor { export function oklchToRgb(oklch: OKLCHColor): RGBColor {
return oklabToRgb(oklchToOklab(oklch)); return oklabToRgb(oklchToOklab(oklch));
} }
function rgbToXyz(rgb: RGBColor): [number, number, number] { export function rgbToXyz(rgb: RGBColor): [number, number, number] {
const [r, g, b] = rgbToLinear(rgb); const [r, g, b] = rgbToLinear(rgb);
return [ return [
(r * 0.4124564 + g * 0.3575761 + b * 0.1804375) * 100, (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) * 100,
@@ -355,7 +354,11 @@ function rgbToXyz(rgb: RGBColor): [number, number, number] {
]; ];
} }
function xyzToLab65(xyz: [number, number, number]): { L: number; A: number; B: number } { export function xyzToLab65(xyz: [number, number, number]): {
L: number;
A: number;
B: number;
} {
const [x, y, z] = xyz.map((v, i) => { const [x, y, z] = xyz.map((v, i) => {
const scaled = v / D65[i]; const scaled = v / D65[i];
return scaled > 0.008856 ? Math.cbrt(scaled) : 7.787 * scaled + 16 / 116; return scaled > 0.008856 ? Math.cbrt(scaled) : 7.787 * scaled + 16 / 116;
@@ -368,7 +371,7 @@ function xyzToLab65(xyz: [number, number, number]): { L: number; A: number; B: n
}; };
} }
function rgbTolab65(rgb: RGBColor): { L: number; A: number; B: number } { export function rgbTolab65(rgb: RGBColor): { L: number; A: number; B: number } {
return xyzToLab65(rgbToXyz(rgb)); return xyzToLab65(rgbToXyz(rgb));
} }
@@ -376,7 +379,7 @@ function rgbTolab65(rgb: RGBColor): { L: number; A: number; B: number } {
Delta Phi Star perceptual lightness contrast by Andrew Somers: Delta Phi Star perceptual lightness contrast by Andrew Somers:
https://github.com/Myndex/deltaphistar https://github.com/Myndex/deltaphistar
*/ */
const PHI = 0.5 + Math.sqrt(1.25); export const PHI = 0.5 + Math.sqrt(1.25);
export function dpsContrast(a: RGBColor, b: RGBColor) { export function dpsContrast(a: RGBColor, b: RGBColor) {
const dps = Math.abs(rgbTolab65(a).L ** PHI - rgbTolab65(b).L ** PHI); const dps = Math.abs(rgbTolab65(a).L ** PHI - rgbTolab65(b).L ** PHI);
@@ -387,7 +390,10 @@ export function dpsContrast(a: RGBColor, b: RGBColor) {
export function colorContrast(background: string, foreground: string[] = [LIGHT_BASE, DARK_BASE]) { export function colorContrast(background: string, foreground: string[] = [LIGHT_BASE, DARK_BASE]) {
const bg = hexToRgbArray(background); const bg = hexToRgbArray(background);
const best: { color?: RGBColor; contrast: number } = { color: undefined, contrast: 0 }; const best: { color?: RGBColor; contrast: number } = {
color: undefined,
contrast: 0,
};
for (const color of foreground) { for (const color of foreground) {
const c = hexToRgbArray(color); const c = hexToRgbArray(color);
+24
View File
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": false,
"declaration": true,
"outDir": "dist",
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react",
"incremental": true,
"types": [
"bun-types" // add Bun global
]
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules"]
}
+1
View File
@@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"@gitbook/api": "^0.93.0", "@gitbook/api": "^0.93.0",
"@gitbook/cache-do": "workspace:*", "@gitbook/cache-do": "workspace:*",
"@gitbook/colors": "workspace:*",
"@gitbook/emoji-codepoints": "workspace:*", "@gitbook/emoji-codepoints": "workspace:*",
"@gitbook/icons": "workspace:*", "@gitbook/icons": "workspace:*",
"@gitbook/openapi-parser": "workspace:*", "@gitbook/openapi-parser": "workspace:*",
@@ -1,11 +1,11 @@
import { CustomizationHeaderPreset } from '@gitbook/api'; import { CustomizationHeaderPreset } from '@gitbook/api';
import { colorContrast } from '@gitbook/colors';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { ImageResponse } from 'next/og'; import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server'; import { NextRequest } from 'next/server';
import React from 'react'; import React from 'react';
import { googleFontsMap } from '@/fonts'; import { googleFontsMap } from '@/fonts';
import { colorContrast } from '@/lib/colors';
import { getAbsoluteHref } from '@/lib/links'; import { getAbsoluteHref } from '@/lib/links';
import { filterOutNullable } from '@/lib/typescript'; import { filterOutNullable } from '@/lib/typescript';
import { getContentTitle } from '@/lib/utils'; import { getContentTitle } from '@/lib/utils';
@@ -1,7 +1,7 @@
import { SiteInsightsAd } from '@gitbook/api'; import { SiteInsightsAd } from '@gitbook/api';
import { hexToRgba } from '@gitbook/colors';
import * as React from 'react'; import * as React from 'react';
import { hexToRgba } from '@/lib/colors';
import { getResizedImageURL } from '@/lib/images'; import { getResizedImageURL } from '@/lib/images';
import { tcls } from '@/lib/tailwind'; import { tcls } from '@/lib/tailwind';
@@ -9,18 +9,18 @@ import {
type CustomizationTint, type CustomizationTint,
type SiteCustomizationSettings, type SiteCustomizationSettings,
} from '@gitbook/api'; } from '@gitbook/api';
import { IconsProvider, IconStyle } from '@gitbook/icons';
import { fontNotoColorEmoji, fonts, ibmPlexMono } from '@/fonts';
import { getSpaceLanguage } from '@/intl/server';
import { getStaticFileURL } from '@/lib/assets';
import { import {
colorContrast, colorContrast,
colorScale, colorScale,
type ColorScaleOptions, type ColorScaleOptions,
DEFAULT_TINT_COLOR, DEFAULT_TINT_COLOR,
hexToRgb, hexToRgb,
} from '@/lib/colors'; } from '@gitbook/colors';
import { IconsProvider, IconStyle } from '@gitbook/icons';
import { fontNotoColorEmoji, fonts, ibmPlexMono } from '@/fonts';
import { getSpaceLanguage } from '@/intl/server';
import { getStaticFileURL } from '@/lib/assets';
import { tcls } from '@/lib/tailwind'; import { tcls } from '@/lib/tailwind';
import { ClientContexts } from './ClientContexts'; import { ClientContexts } from './ClientContexts';
+1 -1
View File
@@ -3,7 +3,7 @@ import typography from '@tailwindcss/typography';
import type { Config } from 'tailwindcss'; import type { Config } from 'tailwindcss';
import plugin from 'tailwindcss/plugin'; import plugin from 'tailwindcss/plugin';
import { ColorCategory, hexToRgb, scale, shadesOfColor } from './src/lib/colors'; import { ColorCategory, hexToRgb, scale, shadesOfColor } from '@gitbook/colors';
export const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]; export const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
export const opacities = [0, 4, 8, 12, 16, 24, 40, 64, 72, 88, 96, 100]; export const opacities = [0, 4, 8, 12, 16, 24, 40, 64, 72, 88, 96, 100];