Skip to content

Commit 67511ff

Browse files
fix: error when add new color to group
1 parent 528ef6d commit 67511ff

File tree

5 files changed

+79
-31
lines changed

5 files changed

+79
-31
lines changed

apps/studio/electron/main/assets/styles.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export async function updateTailwindColorConfig(
5656
}
5757

5858
const camelCaseName = newName === DEFAULT_COLOR_NAME ? newName : camelCase(newName);
59+
5960
return originalKey
6061
? updateTailwindColorVariable(colorUpdate, originalKey, newColor, camelCaseName, theme)
6162
: createTailwindColorVariable(colorUpdate, newColor, camelCaseName, parentName);
@@ -399,19 +400,37 @@ async function updateTailwindCssVariable(
399400
Once(root: Root) {
400401
let rootValue: string | undefined;
401402
let darkValue: string | undefined;
403+
let hasRootVar = false;
404+
let hasDarkVar = false;
402405

403406
root.walkRules(':root', (rule) => {
404407
rule.walkDecls(`--${originalName}`, (decl) => {
405408
rootValue = decl.value;
409+
hasRootVar = true;
406410
});
407411
});
408412

409413
root.walkRules('.dark', (rule) => {
410414
rule.walkDecls(`--${originalName}`, (decl) => {
411415
darkValue = decl.value;
416+
hasDarkVar = true;
412417
});
413418
});
414419

420+
// Create new variables if they don't exist and we have both newVarName and newColor
421+
if (newVarName && newColor) {
422+
if (!hasRootVar) {
423+
root.walkRules(':root', (rule) => {
424+
rule.append({ prop: `--${newVarName}`, value: newColor });
425+
});
426+
}
427+
if (!hasDarkVar) {
428+
root.walkRules('.dark', (rule) => {
429+
rule.append({ prop: `--${newVarName}`, value: newColor });
430+
});
431+
}
432+
}
433+
415434
// Process both :root and .dark rules
416435
root.walkRules(/^(:root|\.dark)$/, (rule) => {
417436
const isDarkTheme = rule.selector === '.dark';
@@ -636,7 +655,7 @@ async function updateClassReferences(
636655
const oldClassPattern = new RegExp(`(^|-)${oldClass}(-|$)`);
637656
if (oldClassPattern.test(currentClass)) {
638657
hasChanges = true;
639-
return currentClass.replace(oldClass, newClass);
658+
return newClass ? currentClass.replace(oldClass, newClass) : '';
640659
}
641660
}
642661
return currentClass;
@@ -669,6 +688,7 @@ async function updateClassReferences(
669688
async function deleteColorGroup(
670689
{ configPath, cssPath, configContent, cssContent }: ColorUpdate,
671690
groupName: string,
691+
projectRoot: string,
672692
colorName?: string,
673693
): Promise<UpdateResult> {
674694
const camelCaseName = camelCase(groupName);
@@ -757,6 +777,14 @@ async function deleteColorGroup(
757777
const output = generate(updateAst, { retainLines: true, compact: false }, configContent);
758778
fs.writeFileSync(configPath, output.code);
759779

780+
// Also delete the color group in the class references
781+
const replacements: ClassReplacement[] = [];
782+
replacements.push({
783+
oldClass: camelCaseName,
784+
newClass: '',
785+
});
786+
await updateClassReferences(projectRoot, replacements);
787+
760788
return { success: true };
761789
}
762790

@@ -771,7 +799,7 @@ export async function deleteTailwindColorGroup(
771799
return { success: false, error: 'Failed to prepare color update' };
772800
}
773801

774-
return deleteColorGroup(colorUpdate, groupName, colorName);
802+
return deleteColorGroup(colorUpdate, groupName, projectRoot, colorName);
775803
} catch (error) {
776804
return {
777805
success: false,

apps/studio/src/lib/editor/engine/theme/index.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Color } from '@onlook/utility';
88
import { makeAutoObservable } from 'mobx';
99
import colors from 'tailwindcss/colors';
1010
import type { EditorEngine } from '..';
11+
import { camelCase } from 'lodash';
1112

1213
interface ColorValue {
1314
value: string;
@@ -297,8 +298,8 @@ export class ThemeManager {
297298
try {
298299
await invokeMainChannel(MainChannels.UPDATE_TAILWIND_CONFIG, {
299300
projectRoot,
300-
originalKey: oldName.toLowerCase(),
301-
newName: newName.toLowerCase(),
301+
originalKey: oldName,
302+
newName: newName,
302303
});
303304

304305
// Refresh colors after rename
@@ -317,7 +318,7 @@ export class ThemeManager {
317318
try {
318319
await invokeMainChannel(MainChannels.DELETE_TAILWIND_CONFIG, {
319320
projectRoot,
320-
groupName: groupName.toLowerCase(),
321+
groupName: groupName,
321322
colorName,
322323
});
323324

@@ -344,7 +345,10 @@ export class ThemeManager {
344345

345346
try {
346347
// For new colors, pass empty originalKey and parentName
347-
const originalKey = this.brandColors[groupName]?.[index]?.originalKey || '';
348+
const originalGroupName = camelCase(groupName);
349+
const originalParentName = camelCase(parentName);
350+
351+
const originalKey = this.brandColors[originalGroupName]?.[index]?.originalKey || '';
348352

349353
// If is selected element, update the color in real-time
350354
// Base on the class name, find the styles to update
@@ -356,7 +360,7 @@ export class ThemeManager {
356360
originalKey,
357361
newColor: newColor.toHex(),
358362
newName,
359-
parentName,
363+
parentName: originalParentName,
360364
theme,
361365
});
362366

@@ -468,7 +472,15 @@ export class ThemeManager {
468472
: colorToDuplicate.lightColor,
469473
);
470474

471-
await this.update(groupName, group.length, color, newName, groupName.toLowerCase());
475+
await this.update(
476+
groupName,
477+
group.length,
478+
color,
479+
newName,
480+
groupName.toLowerCase(),
481+
theme,
482+
true,
483+
);
472484

473485
this.scanConfig();
474486
}

apps/studio/src/routes/editor/LayersPanel/BrandTab/ColorPanel/ColorPalletGroup.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from '@onlook/
1414
import { Color, toNormalCase } from '@onlook/utility';
1515
import { useState } from 'react';
1616
import { ColorPopover } from './ColorPopover';
17+
import { camelCase } from 'lodash';
1718

1819
export interface ColorItem {
1920
name: string;
@@ -81,7 +82,7 @@ export const BrandPalletGroup = ({
8182
parentName?: string,
8283
) => {
8384
if (onColorChange) {
84-
onColorChange(title.toLowerCase(), index, newColor, newName, parentName);
85+
onColorChange(title, index, newColor, newName, parentName);
8586
}
8687
};
8788

@@ -92,7 +93,7 @@ export const BrandPalletGroup = ({
9293
parentName?: string,
9394
) => {
9495
if (onColorChangeEnd) {
95-
onColorChangeEnd(title.toLowerCase(), index, newColor, newName, parentName);
96+
onColorChangeEnd(title, index, newColor, newName, parentName);
9697
}
9798
setEditingColorIndex(null);
9899
setIsAddingNewColor(false);
@@ -103,12 +104,17 @@ export const BrandPalletGroup = ({
103104
};
104105

105106
const handleRenameClick = () => {
106-
setNewGroupName(title);
107+
setNewGroupName(toNormalCase(title));
107108
setIsRenaming(true);
108109
setLocalError(null);
109110
};
110111

111112
const validateName = (value: string) => {
113+
// Only allow text characters, numbers, and spaces and not start with number
114+
if (!/^[a-zA-Z0-9\s]+$/.test(value) || /^[0-9]/.test(value)) {
115+
return 'Group name can only contain text, numbers, and spaces and not start with number';
116+
}
117+
112118
if (value.trim() === '') {
113119
return 'Group name cannot be empty';
114120
}
@@ -117,7 +123,10 @@ export const BrandPalletGroup = ({
117123
return null;
118124
}
119125

120-
if (Object.keys(themeManager.colorGroups).includes(value.toLowerCase())) {
126+
if (
127+
Object.keys(themeManager.colorGroups).includes(camelCase(value)) &&
128+
camelCase(value) !== title
129+
) {
121130
return 'Group name already exists';
122131
}
123132

@@ -133,7 +142,8 @@ export const BrandPalletGroup = ({
133142

134143
const handleRenameSubmit = () => {
135144
if (!localError && newGroupName.trim() && newGroupName !== title) {
136-
onRename(title.toLowerCase(), newGroupName.trim());
145+
const newName = camelCase(newGroupName);
146+
onRename(title, newName);
137147
}
138148
setIsRenaming(false);
139149
setLocalError(null);
@@ -192,7 +202,7 @@ export const BrandPalletGroup = ({
192202
</Tooltip>
193203
) : (
194204
<span className="text-small text-foreground-secondary font-normal">
195-
{title}
205+
{toNormalCase(title)}
196206
</span>
197207
)}
198208
{!isDefaultPalette && (
@@ -402,20 +412,10 @@ export const BrandPalletGroup = ({
402412
brandColor="New Color"
403413
onClose={() => setIsAddingNewColor(false)}
404414
onColorChange={(newColor, newName) =>
405-
handleColorChange(
406-
colors?.length || 0,
407-
newColor,
408-
newName,
409-
title.toLowerCase(),
410-
)
415+
handleColorChange(colors?.length || 0, newColor, newName, title)
411416
}
412417
onColorChangeEnd={(newColor, newName) =>
413-
handleColorChangeEnd(
414-
colors?.length || 0,
415-
newColor,
416-
newName,
417-
title.toLowerCase(),
418-
)
418+
handleColorChangeEnd(colors?.length || 0, newColor, newName, title)
419419
}
420420
existedName={existedName}
421421
/>

apps/studio/src/routes/editor/LayersPanel/BrandTab/ColorPanel/ColorPopover.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,21 @@ export const ColorPopover = ({
3535
}
3636
};
3737
const handleSave = () => {
38-
const camelCaseName =
39-
editedName === DEFAULT_COLOR_NAME ? editedName : camelCase(editedName);
38+
let camelCaseName = editedName === DEFAULT_COLOR_NAME ? editedName : camelCase(editedName);
4039

4140
if (existedName?.includes(camelCaseName) && camelCaseName !== brandColor) {
4241
setError('Color name already exists');
4342
return;
4443
}
4544

45+
if (!editedName) {
46+
if (!brandColor) {
47+
setError('Color name is required');
48+
return;
49+
}
50+
camelCaseName = brandColor;
51+
}
52+
4653
if (onColorChangeEnd) {
4754
onColorChangeEnd(editedColor, camelCaseName);
4855
}
@@ -81,7 +88,7 @@ export const ColorPopover = ({
8188
'w-full rounded-md border bg-background-secondary px-2 py-1 text-sm',
8289
error ? 'border-red-500' : 'border-white/10',
8390
)}
84-
disabled={isDefaultPalette || editedName === DEFAULT_COLOR_NAME}
91+
disabled={isDefaultPalette || brandColor === DEFAULT_COLOR_NAME}
8592
onKeyDown={(e) => {
8693
if (e.key === 'Enter') {
8794
handleSave();

apps/studio/src/routes/editor/LayersPanel/BrandTab/ColorPanel/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const ColorPanel = observer(({ onClose }: ColorPanelProps) => {
5050
newName: string,
5151
parentName?: string,
5252
) => {
53+
console.log('handleColorChangeEnd', groupName, index, newColor, newName, parentName);
5354
themeManager.update(groupName, index, newColor, newName, parentName, theme, true);
5455
};
5556

@@ -117,7 +118,7 @@ const ColorPanel = observer(({ onClose }: ColorPanelProps) => {
117118
<BrandPalletGroup
118119
key={groupName}
119120
theme={theme}
120-
title={groupName.charAt(0).toUpperCase() + groupName.slice(1)}
121+
title={groupName}
121122
colors={colors}
122123
onRename={handleRename}
123124
onDelete={(colorName) => handleDelete(groupName, colorName)}
@@ -168,7 +169,7 @@ const ColorPanel = observer(({ onClose }: ColorPanelProps) => {
168169
<BrandPalletGroup
169170
key={colorName}
170171
theme={theme}
171-
title={colorName.charAt(0).toUpperCase() + colorName.slice(1)}
172+
title={colorName}
172173
colors={colors}
173174
onRename={handleRename}
174175
onDelete={(colorItem) => handleDelete(colorName, colorItem)}

0 commit comments

Comments
 (0)