@leftium/logo 0.0.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AppLogo.svelte +146 -0
- package/dist/AppLogo.svelte.d.ts +7 -0
- package/dist/LeftiumLogo.svelte +267 -186
- package/dist/LeftiumLogo.svelte.d.ts +1 -0
- package/dist/app-logo/color-transform.d.ts +40 -0
- package/dist/app-logo/color-transform.js +142 -0
- package/dist/app-logo/config-serialization.d.ts +80 -0
- package/dist/app-logo/config-serialization.js +489 -0
- package/dist/app-logo/defaults.d.ts +60 -0
- package/dist/app-logo/defaults.js +55 -0
- package/dist/app-logo/generate-favicon-set.d.ts +44 -0
- package/dist/app-logo/generate-favicon-set.js +97 -0
- package/dist/app-logo/generate-ico.d.ts +18 -0
- package/dist/app-logo/generate-ico.js +63 -0
- package/dist/app-logo/generate-png.d.ts +16 -0
- package/dist/app-logo/generate-png.js +60 -0
- package/dist/app-logo/generate-svg.d.ts +9 -0
- package/dist/app-logo/generate-svg.js +160 -0
- package/dist/app-logo/iconify.d.ts +35 -0
- package/dist/app-logo/iconify.js +223 -0
- package/dist/app-logo/squircle.d.ts +43 -0
- package/dist/app-logo/squircle.js +213 -0
- package/dist/app-logo/types.d.ts +39 -0
- package/dist/app-logo/types.js +1 -0
- package/dist/assets/logo-parts/glow-squircle.svg +44 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +9 -3
- package/dist/leftium-logo/generate-svg.d.ts +29 -0
- package/dist/leftium-logo/generate-svg.js +470 -0
- package/dist/tooltip.d.ts +18 -0
- package/dist/tooltip.js +38 -0
- package/dist/webgl-ripples/webgl-ripples.d.ts +0 -4
- package/dist/webgl-ripples/webgl-ripples.js +1 -1
- package/package.json +35 -20
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OKLCH-based color transforms for icon color modes.
|
|
3
|
+
*
|
|
4
|
+
* Uses culori for perceptually uniform color manipulation.
|
|
5
|
+
* All transforms operate on individual CSS color strings.
|
|
6
|
+
*/
|
|
7
|
+
import { parse, converter, formatHex, clampChroma, displayable } from 'culori';
|
|
8
|
+
const toOklch = converter('oklch');
|
|
9
|
+
/**
|
|
10
|
+
* Parse a CSS color string to OKLCH components.
|
|
11
|
+
* Returns null if the color can't be parsed.
|
|
12
|
+
*/
|
|
13
|
+
function parseToOklch(color) {
|
|
14
|
+
const parsed = parse(color);
|
|
15
|
+
if (!parsed)
|
|
16
|
+
return null;
|
|
17
|
+
const oklch = toOklch(parsed);
|
|
18
|
+
return {
|
|
19
|
+
l: oklch.l ?? 0,
|
|
20
|
+
c: oklch.c ?? 0,
|
|
21
|
+
h: oklch.h ?? 0,
|
|
22
|
+
alpha: oklch.alpha
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert OKLCH components back to a hex color string.
|
|
27
|
+
* Clamps to sRGB gamut.
|
|
28
|
+
*/
|
|
29
|
+
function oklchToHex(l, c, h, alpha) {
|
|
30
|
+
let color = { mode: 'oklch', l, c, h, alpha };
|
|
31
|
+
// Clamp to displayable sRGB gamut
|
|
32
|
+
if (!displayable(color)) {
|
|
33
|
+
color = clampChroma(color, 'oklch');
|
|
34
|
+
}
|
|
35
|
+
return formatHex(color);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Transform a single CSS color to grayscale using OKLCH.
|
|
39
|
+
* Sets chroma to 0, preserving perceptual lightness.
|
|
40
|
+
* @param lightness Optional lightness multiplier (0-200), default 100 = no change
|
|
41
|
+
*/
|
|
42
|
+
export function toGrayscale(color, lightness = 100) {
|
|
43
|
+
const oklch = parseToOklch(color);
|
|
44
|
+
if (!oklch)
|
|
45
|
+
return color;
|
|
46
|
+
const l = Math.min(1, Math.max(0, oklch.l * (lightness / 100)));
|
|
47
|
+
return oklchToHex(l, 0, 0, oklch.alpha);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Transform a single CSS color to grayscale, then tint toward a target color.
|
|
51
|
+
*
|
|
52
|
+
* The tint color's hue and chroma influence the result, while the original
|
|
53
|
+
* color's lightness is preserved. This unifies a palette while keeping contrast.
|
|
54
|
+
* @param lightness Optional lightness multiplier (0-200), default 100 = no change
|
|
55
|
+
*/
|
|
56
|
+
export function toGrayscaleTint(color, tintColor, lightness = 100) {
|
|
57
|
+
const oklch = parseToOklch(color);
|
|
58
|
+
if (!oklch)
|
|
59
|
+
return color;
|
|
60
|
+
const tint = parseToOklch(tintColor);
|
|
61
|
+
if (!tint)
|
|
62
|
+
return color;
|
|
63
|
+
// Use original lightness (scaled by multiplier), tint's hue, and a fraction of tint's chroma
|
|
64
|
+
// Scale chroma by the ratio of original chroma to max, to preserve some variation
|
|
65
|
+
const l = Math.min(1, Math.max(0, oklch.l * (lightness / 100)));
|
|
66
|
+
const tintChroma = tint.c * 0.7; // 70% of tint chroma for a softer effect
|
|
67
|
+
return oklchToHex(l, tintChroma, tint.h, oklch.alpha);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Remap a single CSS color to a target hue, optionally overriding saturation.
|
|
71
|
+
*
|
|
72
|
+
* Preserves the original lightness. If saturation is provided, it's used as
|
|
73
|
+
* a percentage of the maximum chroma; otherwise, the original chroma is preserved.
|
|
74
|
+
*/
|
|
75
|
+
export function remapHue(color, targetHue, targetSaturation) {
|
|
76
|
+
const oklch = parseToOklch(color);
|
|
77
|
+
if (!oklch)
|
|
78
|
+
return color;
|
|
79
|
+
const c = targetSaturation !== undefined
|
|
80
|
+
? (targetSaturation / 100) * 0.4 // Map 0-100 to 0-0.4 OKLCH chroma range
|
|
81
|
+
: oklch.c;
|
|
82
|
+
return oklchToHex(oklch.l, c, targetHue, oklch.alpha);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Apply a full IconColorMode transformation to SVG content.
|
|
86
|
+
*
|
|
87
|
+
* Handles all modes: 'auto', 'original', 'monochrome', 'grayscale',
|
|
88
|
+
* 'grayscale-tint', and { hue, saturation? }.
|
|
89
|
+
*
|
|
90
|
+
* Color transforms operate on fill/stroke attribute values and style properties,
|
|
91
|
+
* replacing each color with its transformed equivalent.
|
|
92
|
+
*
|
|
93
|
+
* @param grayscaleLightness Lightness multiplier for grayscale modes (0-200), default 100
|
|
94
|
+
*/
|
|
95
|
+
export function applyColorMode(svgContent, isMonochrome, colorMode, iconColor, grayscaleLightness = 100) {
|
|
96
|
+
// Handle simple string modes first
|
|
97
|
+
if (colorMode === 'original') {
|
|
98
|
+
return svgContent;
|
|
99
|
+
}
|
|
100
|
+
if (colorMode === 'auto') {
|
|
101
|
+
if (isMonochrome) {
|
|
102
|
+
return svgContent.replace(/currentColor/g, iconColor);
|
|
103
|
+
}
|
|
104
|
+
return svgContent;
|
|
105
|
+
}
|
|
106
|
+
if (colorMode === 'monochrome') {
|
|
107
|
+
return svgContent
|
|
108
|
+
.replace(/(fill=["'])(?!none)([^"']+)(["'])/gi, `$1${iconColor}$3`)
|
|
109
|
+
.replace(/(stroke=["'])(?!none)([^"']+)(["'])/gi, `$1${iconColor}$3`)
|
|
110
|
+
.replace(/currentColor/g, iconColor);
|
|
111
|
+
}
|
|
112
|
+
// For grayscale, grayscale-tint, and hue remap: transform each color value
|
|
113
|
+
const transformColor = (color) => {
|
|
114
|
+
if (color === 'none' || color === 'inherit' || color === 'transparent') {
|
|
115
|
+
return color;
|
|
116
|
+
}
|
|
117
|
+
// Replace currentColor with iconColor before transforming
|
|
118
|
+
const resolvedColor = color === 'currentColor' ? iconColor : color;
|
|
119
|
+
if (colorMode === 'grayscale') {
|
|
120
|
+
return toGrayscale(resolvedColor, grayscaleLightness);
|
|
121
|
+
}
|
|
122
|
+
if (colorMode === 'grayscale-tint') {
|
|
123
|
+
return toGrayscaleTint(resolvedColor, iconColor, grayscaleLightness);
|
|
124
|
+
}
|
|
125
|
+
// Object mode: { hue, saturation? }
|
|
126
|
+
if (typeof colorMode === 'object') {
|
|
127
|
+
return remapHue(resolvedColor, colorMode.hue, colorMode.saturation);
|
|
128
|
+
}
|
|
129
|
+
return color;
|
|
130
|
+
};
|
|
131
|
+
// Transform fill/stroke attribute values
|
|
132
|
+
let result = svgContent.replace(/((?:fill|stroke)=["'])([^"']+)(["'])/gi, (_match, prefix, value, suffix) => {
|
|
133
|
+
return `${prefix}${transformColor(value.trim())}${suffix}`;
|
|
134
|
+
});
|
|
135
|
+
// Transform fill/stroke in style attributes
|
|
136
|
+
result = result.replace(/((?:fill|stroke)\s*:\s*)([^;"']+)/gi, (_match, prefix, value) => {
|
|
137
|
+
return `${prefix}${transformColor(value.trim())}`;
|
|
138
|
+
});
|
|
139
|
+
// Also replace any remaining currentColor references
|
|
140
|
+
result = result.replace(/currentColor/g, transformColor('currentColor'));
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config serialization: bidirectional conversion between the UI-level ColumnState
|
|
3
|
+
* (flat, slider-friendly) and the export-level AppLogoConfig (structured, spec-compliant).
|
|
4
|
+
*
|
|
5
|
+
* Also handles URL hash encoding/decoding and Svelte snippet generation.
|
|
6
|
+
*/
|
|
7
|
+
import type { AppLogoConfig, CornerShape, GradientConfig, IconColorMode } from './types.js';
|
|
8
|
+
export interface ColumnState {
|
|
9
|
+
icon: string;
|
|
10
|
+
iconColor: string;
|
|
11
|
+
iconColorModeKey: string;
|
|
12
|
+
hueValue: number;
|
|
13
|
+
saturationValue: number;
|
|
14
|
+
iconSize: number;
|
|
15
|
+
iconOffsetX: number;
|
|
16
|
+
iconOffsetY: number;
|
|
17
|
+
iconRotation: number;
|
|
18
|
+
grayscaleLightness: number;
|
|
19
|
+
cornerRadius: number;
|
|
20
|
+
cornerK: number;
|
|
21
|
+
solidColor: string;
|
|
22
|
+
useGradient: boolean;
|
|
23
|
+
gradientAngle: number;
|
|
24
|
+
gradientPosition: number;
|
|
25
|
+
gradientScale: number;
|
|
26
|
+
}
|
|
27
|
+
export declare const DEFAULT_STATE: ColumnState;
|
|
28
|
+
export declare const DEFAULT_LOCKS: Record<keyof ColumnState, boolean>;
|
|
29
|
+
export declare function cornerKToShape(k: number): CornerShape;
|
|
30
|
+
export declare function cornerShapeToK(shape: CornerShape): number;
|
|
31
|
+
export declare function cornerKLabel(k: number): string;
|
|
32
|
+
export declare function iconColorModeFromFlat(key: string, hue: number, saturation: number): IconColorMode;
|
|
33
|
+
export declare function iconColorModeToFlat(mode: IconColorMode): {
|
|
34
|
+
key: string;
|
|
35
|
+
hue: number;
|
|
36
|
+
saturation: number;
|
|
37
|
+
};
|
|
38
|
+
export declare function backgroundFromFlat(col: ColumnState): string | GradientConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Build an AppLogoConfig from the logo and effective favicon ColumnState.
|
|
41
|
+
* Also accepts the lock state to determine which favicon fields are overrides.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildFullConfig(logoState: ColumnState, effectiveFaviconState: ColumnState, lockState: Record<keyof ColumnState, boolean>, emojiStyle?: string): AppLogoConfig;
|
|
44
|
+
/**
|
|
45
|
+
* Build a single-variant AppLogoConfig for export/rendering.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildVariantConfig(col: ColumnState, variant: 'logo' | 'favicon', emojiStyle?: string): AppLogoConfig;
|
|
48
|
+
/**
|
|
49
|
+
* Convert an AppLogoConfig back to ColumnState + lock state.
|
|
50
|
+
* Shared fields populate the logo column. Favicon overrides populate
|
|
51
|
+
* the favicon column and unlock the corresponding locks.
|
|
52
|
+
*/
|
|
53
|
+
export declare function configToUIState(config: AppLogoConfig): {
|
|
54
|
+
logo: ColumnState;
|
|
55
|
+
favicon: ColumnState;
|
|
56
|
+
locks: Record<keyof ColumnState, boolean>;
|
|
57
|
+
emojiStyle: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Encode a config object to a base64url string for URL hash.
|
|
61
|
+
* Uses TextEncoder for Unicode safety (emoji icon names, non-ASCII app names).
|
|
62
|
+
*/
|
|
63
|
+
export declare function encodeConfigToHash(config: AppLogoConfig): string;
|
|
64
|
+
/**
|
|
65
|
+
* Decode a base64url string from URL hash back to AppLogoConfig.
|
|
66
|
+
* Returns null if decoding fails.
|
|
67
|
+
*/
|
|
68
|
+
export declare function decodeConfigFromHash(hash: string): AppLogoConfig | null;
|
|
69
|
+
/**
|
|
70
|
+
* Generate a minimal <AppLogo> Svelte snippet with only non-default props.
|
|
71
|
+
*/
|
|
72
|
+
export declare function generateSvelteSnippet(config: AppLogoConfig): string;
|
|
73
|
+
/**
|
|
74
|
+
* Generate the HTML favicon snippet for clipboard copy.
|
|
75
|
+
* Re-exports the existing function for convenience.
|
|
76
|
+
*/
|
|
77
|
+
export declare function generateHtmlSnippet(appInfo: {
|
|
78
|
+
name?: string;
|
|
79
|
+
shortName?: string;
|
|
80
|
+
}): string;
|