Skip to content

Commit 6a1254b

Browse files
refactor: add font test (#2532)
* add more font test * remove incorrect babel dependency use * remove incorrect use of parse * add font config watcher * refactor traverse classname * add checking font config path
1 parent 7f6f30c commit 6a1254b

File tree

187 files changed

+3786
-684
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

187 files changed

+3786
-684
lines changed

apps/web/client/src/app/project/[id]/_components/editor-bar/div-selected.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import { FontFamilySelector } from './text-inputs/font/font-family-selector';
1919
import { FontSizeSelector } from './text-inputs/font/font-size';
2020
import { FontWeightSelector } from './text-inputs/font/font-weight';
2121
import { TextColor } from './text-inputs/text-color';
22-
import { AdvancedTypography } from './text-inputs/advanced-typography';
2322
import { TextAlignSelector } from './text-inputs/text-align';
2423
import { InputImage } from './inputs/input-image';
24+
import { AdvancedTypography } from './text-inputs/advanced-typography';
2525

2626
// Group definitions for the div-selected toolbar
2727
export const DIV_SELECTED_GROUPS = [

apps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ export const BrandTab = observer(() => {
2222
const editorEngine = useEditorEngine();
2323

2424
useEffect(() => {
25-
editorEngine.font.scanFonts();
26-
}, []);
25+
if (editorEngine.font.fontConfigPath) {
26+
editorEngine.font.scanFonts();
27+
}
28+
}, [editorEngine.font.fontConfigPath]);
2729

2830
// Sample colors for the brand palette
2931
const brandColors = [

apps/web/client/src/app/projects/import/local/_context/index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { type SandboxBrowserSession, type WebSocketSession } from '@codesandbox/
77
import { connectToSandbox } from '@codesandbox/sdk/browser';
88
import { NEXT_JS_FILE_EXTENSIONS, SandboxTemplates, Templates } from '@onlook/constants';
99
import { RouterType } from '@onlook/models';
10-
import { generate, injectPreloadScript, parse } from '@onlook/parser';
10+
import { generate, getAstFromContent, injectPreloadScript } from '@onlook/parser';
1111
import { isRootLayoutFile, isTargetFile } from '@onlook/utility';
1212
import { useRouter } from 'next/navigation';
1313
import type { ReactNode } from 'react';
@@ -315,10 +315,10 @@ export const uploadToSandbox = async (files: ProcessedFile[], session: WebSocket
315315
const isLayout = isRootLayoutFile(file.path);
316316
if (isLayout) {
317317
try {
318-
const ast = parse(content, {
319-
sourceType: 'module',
320-
plugins: ['jsx', 'typescript'],
321-
});
318+
const ast = getAstFromContent(content);
319+
if (!ast) {
320+
throw new Error('Failed to parse layout file');
321+
}
322322
const modifiedAst = injectPreloadScript(ast);
323323
content = generate(modifiedAst, {}, content).code;
324324
} catch (parseError) {

apps/web/client/src/components/store/editor/font/font-config-manager.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import type { ParseResult } from '@babel/parser';
2-
import { DefaultSettings } from '@onlook/constants';
31
import {
42
addGoogleFontSpecifier,
53
generateFontVariableExport,
@@ -9,7 +7,7 @@ import {
97
validateGoogleFontSetup,
108
} from '@onlook/fonts';
119
import { RouterType, type CodeDiff, type Font } from '@onlook/models';
12-
import { generate, parse, types as t, type t as T } from '@onlook/parser';
10+
import { generate, getAstFromContent, types as t, type t as T } from '@onlook/parser';
1311
import { camelCase } from 'lodash';
1412
import { makeAutoObservable, reaction } from 'mobx';
1513
import type { EditorEngine } from '../engine';
@@ -32,11 +30,7 @@ export class FontConfigManager {
3230
);
3331
}
3432

35-
get fontConfigPath(): string {
36-
if (!this._fontConfigPath) {
37-
// Fallback to default if not yet determined
38-
return normalizePath(DefaultSettings.FONT_CONFIG);
39-
}
33+
get fontConfigPath(): string | null {
4034
return this._fontConfigPath;
4135
}
4236

@@ -102,7 +96,7 @@ export class FontConfigManager {
10296
const importName = font.family.replace(/\s+/g, '_');
10397
const fontName = camelCase(font.id);
10498

105-
await this.ensureConfigFileExists();
99+
await this.ensureFontConfigFileExists();
106100

107101
const fontConfig = await this.readFontConfigFile();
108102
if (!fontConfig) {
@@ -141,6 +135,11 @@ export class FontConfigManager {
141135

142136
// Generate and write the updated code back to the file
143137
const { code } = generate(ast);
138+
139+
if (!this.fontConfigPath) {
140+
return false;
141+
}
142+
144143
const success = await this.editorEngine.sandbox.writeFile(this.fontConfigPath, code);
145144

146145
if (!success) {
@@ -167,6 +166,10 @@ export class FontConfigManager {
167166
return false;
168167
}
169168

169+
if (!this.fontConfigPath) {
170+
return false;
171+
}
172+
170173
const { removedFont, fontFilesToDelete, ast } = removeFontDeclaration(font, content);
171174

172175
if (removedFont) {
@@ -219,7 +222,7 @@ export class FontConfigManager {
219222
*/
220223
async readFontConfigFile(): Promise<
221224
| {
222-
ast: ParseResult<T.File>;
225+
ast: T.File;
223226
content: string;
224227
}
225228
| undefined
@@ -230,6 +233,10 @@ export class FontConfigManager {
230233
return;
231234
}
232235

236+
if (!this.fontConfigPath) {
237+
return;
238+
}
239+
233240
const file = await sandbox.readFile(this.fontConfigPath);
234241
if (!file || file.type === 'binary') {
235242
console.error("Font config file is empty or doesn't exist");
@@ -238,10 +245,10 @@ export class FontConfigManager {
238245
const content = file.content;
239246

240247
// Parse the file content using Babel
241-
const ast = parse(content, {
242-
sourceType: 'module',
243-
plugins: ['typescript', 'jsx'],
244-
});
248+
const ast = getAstFromContent(content);
249+
if (!ast) {
250+
throw new Error('Failed to parse font config file');
251+
}
245252

246253
return {
247254
ast,
@@ -252,13 +259,21 @@ export class FontConfigManager {
252259
/**
253260
* Ensures the font configuration file exists
254261
*/
255-
async ensureConfigFileExists(): Promise<void> {
262+
async ensureFontConfigFileExists(): Promise<void> {
256263
const sandbox = this.editorEngine.sandbox;
257264
if (!sandbox) {
258265
console.error('No sandbox session found');
259266
return;
260267
}
261268

269+
if (sandbox.isIndexing) {
270+
return;
271+
}
272+
273+
if (!this.fontConfigPath) {
274+
return;
275+
}
276+
262277
const fontConfigPath = normalizePath(this.fontConfigPath);
263278
const fontConfigExists = await sandbox.fileExists(fontConfigPath);
264279

apps/web/client/src/components/store/editor/font/font-upload-manager.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { ParseResult } from '@babel/parser';
21
import { DefaultSettings } from '@onlook/constants';
32
import {
3+
createFontSrcObjects,
44
createLocalFontConfig,
55
findFontExportDeclaration,
66
hasLocalFontImport,
@@ -31,8 +31,8 @@ export class FontUploadManager {
3131
async uploadFonts(
3232
fontFiles: FontUploadFile[],
3333
basePath: string,
34-
fontConfigAst: ParseResult<T.File>,
35-
): Promise<{ success: boolean; fontConfigAst: ParseResult<T.File> }> {
34+
fontConfigAst: T.File,
35+
): Promise<{ success: boolean; fontConfigAst: T.File }> {
3636
this._isUploading = true;
3737
try {
3838
if (fontFiles.length === 0) {
@@ -48,7 +48,7 @@ export class FontUploadManager {
4848
const { fontNameExists, existingFontNode } = findFontExportDeclaration(fontConfigAst, fontName);
4949

5050
const fontConfigs = await this.processFontFiles(fontFiles, baseFontName, basePath);
51-
const fontsSrc = this.createFontSrcObjects(fontConfigs);
51+
const fontsSrc = createFontSrcObjects(fontConfigs);
5252

5353
await this.updateAstWithFontConfig(
5454
fontConfigAst,
@@ -104,24 +104,11 @@ export class FontUploadManager {
104104
);
105105
}
106106

107-
/**
108-
* Creates font source objects for AST
109-
*/
110-
private createFontSrcObjects(fontConfigs: FontConfig[]): T.ObjectExpression[] {
111-
return fontConfigs.map((config: FontConfig) =>
112-
t.objectExpression([
113-
t.objectProperty(t.identifier('path'), t.stringLiteral(config.path)),
114-
t.objectProperty(t.identifier('weight'), t.stringLiteral(config.weight)),
115-
t.objectProperty(t.identifier('style'), t.stringLiteral(config.style)),
116-
]),
117-
);
118-
}
119-
120107
/**
121108
* Updates AST with font configuration
122109
*/
123110
private async updateAstWithFontConfig(
124-
ast: ParseResult<T.File>,
111+
ast: T.File,
125112
fontName: string,
126113
fontsSrc: T.ObjectExpression[],
127114
fontNameExists: boolean,

apps/web/client/src/components/store/editor/font/index.ts

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ import type { Font } from '@onlook/models/assets';
55
import { generate } from '@onlook/parser';
66
import { makeAutoObservable, reaction } from 'mobx';
77
import type { EditorEngine } from '../engine';
8+
import type { FileEvent } from '../sandbox/file-event-bus';
89
import { FontConfigManager } from './font-config-manager';
910
import { FontSearchManager } from './font-search-manager';
1011
import { FontUploadManager } from './font-upload-manager';
1112
import { LayoutManager } from './layout-manager';
12-
import { addFontToTailwindConfig, ensureTailwindConfigExists, removeFontFromTailwindConfig } from './tailwind-config';
13+
import {
14+
addFontToTailwindConfig,
15+
ensureTailwindConfigExists,
16+
removeFontFromTailwindConfig,
17+
} from './tailwind-config';
1318

1419
export class FontManager {
1520
private _fonts: Font[] = [];
@@ -36,18 +41,54 @@ export class FontManager {
3641

3742
// React to sandbox connection status
3843
reaction(
39-
() => this.editorEngine.sandbox.isIndexed,
40-
async (isIndexedFiles) => {
41-
if (isIndexedFiles) {
42-
await this.loadInitialFonts();
43-
await this.getDefaultFont();
44-
await this.syncFontsWithConfigs();
44+
() => {
45+
return {
46+
isIndexing: this.editorEngine.sandbox.isIndexing,
47+
isIndexed: this.editorEngine.sandbox.isIndexed,
48+
};
49+
},
50+
(sandboxStatus) => {
51+
if (sandboxStatus.isIndexed && !sandboxStatus.isIndexing) {
52+
this.loadInitialFonts();
53+
this.getCurrentDefaultFont();
54+
this.syncFontsWithConfigs();
55+
this.setupFontConfigFileWatcher();
4556
}
4657
},
4758
);
4859
}
4960

50-
get fontConfigPath(): string {
61+
private setupFontConfigFileWatcher(): void {
62+
if (this.fontConfigFileWatcher) {
63+
this.fontConfigFileWatcher();
64+
}
65+
66+
this.fontConfigFileWatcher = this.editorEngine.sandbox.fileEventBus.subscribe(
67+
'*',
68+
this.handleFileEvent.bind(this),
69+
);
70+
}
71+
72+
private async handleFileEvent(event: FileEvent): Promise<void> {
73+
try {
74+
const { paths } = event;
75+
const fontConfigPath = this.fontConfigManager.fontConfigPath;
76+
77+
if (!fontConfigPath) {
78+
return;
79+
}
80+
81+
if (!paths.some((path) => path.includes(fontConfigPath))) {
82+
return;
83+
}
84+
85+
await this.syncFontsWithConfigs();
86+
} catch (error) {
87+
console.error('Error handling file event in FontManager:', error);
88+
}
89+
}
90+
91+
get fontConfigPath(): string | null {
5192
return this.fontConfigManager.fontConfigPath;
5293
}
5394

@@ -194,6 +235,9 @@ export class FontManager {
194235

195236
if (result.success) {
196237
const { code } = generate(result.fontConfigAst);
238+
if (!this.fontConfigManager.fontConfigPath) {
239+
return false;
240+
}
197241
await this.editorEngine.sandbox.writeFile(
198242
this.fontConfigManager.fontConfigPath,
199243
code,
@@ -278,9 +322,9 @@ export class FontManager {
278322
/**
279323
* Gets the default font from the project
280324
*/
281-
private async getDefaultFont(): Promise<string | null> {
325+
private async getCurrentDefaultFont(): Promise<string | null> {
282326
try {
283-
const defaultFont = await this.layoutManager.getDefaultFont();
327+
const defaultFont = await this.layoutManager.getCurrentDefaultFont();
284328
if (defaultFont) {
285329
this._defaultFont = defaultFont;
286330
}
@@ -321,8 +365,8 @@ export class FontManager {
321365

322366
if (addedFonts.length > 0) {
323367
for (const font of addedFonts) {
324-
await this.layoutManager.addFontVariableToRootLayout(font.id);
325368
await addFontToTailwindConfig(font, sandbox);
369+
await this.layoutManager.addFontVariableToRootLayout(font.id);
326370
}
327371
}
328372

@@ -349,7 +393,7 @@ export class FontManager {
349393
}
350394

351395
await Promise.all([
352-
this.fontConfigManager.ensureConfigFileExists(),
396+
this.fontConfigManager.ensureFontConfigFileExists(),
353397
ensureTailwindConfigExists(sandbox),
354398
]);
355399
}

0 commit comments

Comments
 (0)