From b538a632f89f0353742b40f6de2908659fc0304a Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sat, 18 Jul 2026 09:11:01 +0100 Subject: [PATCH 01/47] feat: open text assets in code editor --- apps/builder/app/builder/builder.tsx | 52 +++++--- .../app/builder/features/assets/assets.tsx | 9 ++ .../text-file-editor/text-file-editor.tsx | 112 ++++++++++++++++++ .../text-file-editor/text-file-utils.test.ts | 33 ++++++ .../text-file-editor/text-file-utils.ts | 27 +++++ .../builder/app/builder/shared/nano-states.ts | 2 + apps/builder/app/shared/code-editor.tsx | 22 +++- 7 files changed, 237 insertions(+), 20 deletions(-) create mode 100644 apps/builder/app/builder/features/text-file-editor/text-file-editor.tsx create mode 100644 apps/builder/app/builder/features/text-file-editor/text-file-utils.test.ts create mode 100644 apps/builder/app/builder/features/text-file-editor/text-file-utils.ts diff --git a/apps/builder/app/builder/builder.tsx b/apps/builder/app/builder/builder.tsx index 03220d99e35d..a435ed4103d3 100644 --- a/apps/builder/app/builder/builder.tsx +++ b/apps/builder/app/builder/builder.tsx @@ -52,6 +52,7 @@ import { $isCloneDialogOpen, $isUiHidden, $loadingState, + $openedTextAssetId, } from "./shared/nano-states"; import { $pages } from "~/shared/sync/data-stores"; import { CloneProjectDialog } from "~/shared/clone-project"; @@ -85,6 +86,7 @@ import { import type { SidebarPanelName } from "./sidebar-left/types"; import { SidebarLeft } from "./sidebar-left/sidebar-left"; import { useDisableContextMenu } from "./shared/use-disable-context-menu"; +import { TextFileEditor } from "./features/text-file-editor/text-file-editor"; const useSetWindowTitle = () => { const project = useStore($project); @@ -323,6 +325,7 @@ export const Builder = (props: BuilderProps) => { useUnmount(() => { $pages.set(undefined); + $openedTextAssetId.set(undefined); }); useSyncPageUrl(); @@ -340,6 +343,9 @@ export const Builder = (props: BuilderProps) => { const isUiHidden = useStore($isUiHidden); const isDesignMode = useStore($isDesignMode); const isContentMode = useStore($isContentMode); + const openedTextAssetId = useStore($openedTextAssetId); + const isTextFileEditorOpen = + openedTextAssetId !== undefined && isPreviewMode === false; useSetWindowTitle(); @@ -436,19 +442,25 @@ export const Builder = (props: BuilderProps) => { {/* Main must be after left sidebar panels because in content mode the Plus button must be above the left sidebar, otherwise it won't be visible when content is full width */}
- - {dataLoadingState === "loaded" && project && ( - - )} - -
-
- + {isTextFileEditorOpen ? ( + + ) : ( + + {dataLoadingState === "loaded" && project && ( + + )} + + )}
+ {isTextFileEditorOpen === false ? ( +
+ +
+ ) : null} { > -
- -
+ {isTextFileEditorOpen === false ? ( +
+ +
+ ) : null} {project ? ( { } /> ) : null} -
- -
+ {isTextFileEditorOpen === false ? ( +
+ +
+ ) : null} {isFooterVisible &&