Files
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

78 lines
3.3 KiB
TypeScript

import type { ComponentType, CSSProperties } from 'react'
import { isLightColor } from '@/lib/colors'
import { getAllBlocks } from '@/blocks/registry'
/** A brand icon component that accepts standard styling props. */
export type StyleableIcon = ComponentType<{ className?: string; style?: CSSProperties }>
/**
* Lazily-built lookup from a block's icon component to its theme-safe brand
* {@link BlockConfig.iconColor}. Keyed by component reference so callers that
* already hold the icon (suggested actions, credential pickers, …) never need
* to thread a block type or hand-pick a color. Built once on first read since
* the block registry is static for the app's lifetime.
*/
let iconColorByComponent: Map<StyleableIcon, string> | null = null
function getIconColorMap(): Map<StyleableIcon, string> {
if (iconColorByComponent) return iconColorByComponent
const map = new Map<StyleableIcon, string>()
for (const block of getAllBlocks()) {
if (block.iconColor) map.set(block.icon, block.iconColor)
}
iconColorByComponent = map
return map
}
/**
* Inline `style` for rendering a brand icon bare (without its colored tile
* background): the block's theme-safe {@link BlockConfig.iconColor} as `color`,
* or `undefined` when none is defined so the caller keeps its own default
* icon styling.
*
* Single-fill icons drawn with `fill='currentColor'` (e.g. HubSpot) adopt the
* color; multi-color brand icons that hardcode their own fills (Slack, Gmail,
* Jira, Salesforce, Google Calendar) ignore it and keep their own colors.
*/
export function getBareIconStyle(icon: StyleableIcon): CSSProperties | undefined {
const color = getIconColorMap().get(icon)
return color ? { color } : undefined
}
/**
* Brightness above which a brand tile is "clearly light" and a white foreground
* icon would wash out. Set deliberately high (0.75) so only genuinely light
* tiles flip their icon to dark: it keeps monochrome `currentColor` icons
* legible on their pale tiles (Notion/Mailchimp/Infisical sit at ~0.83+) while
* leaving mid-bright saturated brand tiles (HubSpot orange, amber notes) on the
* white icon they have always used — avoiding a needless app-wide recolor.
*/
const LIGHT_TILE_THRESHOLD = 0.75
/**
* True when a block's {@link BlockConfig.bgColor} tile is light enough that a
* white foreground icon would wash out. Gradients and unknown values are
* treated as dark (the common case for brand tiles).
*/
export function isLightTileColor(bgColor: string | null | undefined): boolean {
return Boolean(bgColor) && isLightColor(bgColor as string, LIGHT_TILE_THRESHOLD)
}
/**
* Tailwind foreground class for a brand icon rendered inside its
* {@link BlockConfig.bgColor} tile. Dark tiles get white; light tiles get
* near-black so monochrome `currentColor` icons (Notion, Mailchimp, …) stay
* legible instead of rendering white-on-white. Hardcoded multi-color icons
* ignore the class and keep their own fills. Pass `important` when overriding
* an inherited text color (the legacy `!text-white` tile rows).
*
* All four literals are spelled out so Tailwind's JIT scanner emits them.
*/
export function getTileIconColorClass(
bgColor: string | null | undefined,
important = false
): string {
if (isLightTileColor(bgColor)) return important ? '!text-black' : 'text-black'
return important ? '!text-white' : 'text-white'
}