138138 </style >
139139
140140<script setup lang="ts">
141- const props = defineProps <{ openFiles: string [], rootPath: string }>();
142-
143- const storageKey = computed (() =>
144- props .rootPath ? ` locode:openFolders:${props .rootPath } ` : " locode:openFolders"
145- );
141+ import type { SkeletonNode } from ' ~/composables/useLocodeConfig'
142+ import { DEFAULT_SKELETON } from ' ~/composables/useLocodeConfig'
143+
144+ const props = defineProps <{
145+ openFiles: string [];
146+ rootPath: string ;
147+ initialOpenFolders? : string [];
148+ initialSkeleton? : SkeletonNode [];
149+ }>();
146150const emit = defineEmits <{
147151 (e : " select-file" , path : string ): void ,
148- (e : " select-root" , path : string ): void
152+ (e : " select-root" , path : string ): void ,
153+ (e : " update:openFolders" , folders : string []): void ,
154+ (e : " update:skeleton" , skeleton : SkeletonNode []): void ,
149155}>();
150156
151157const tree = ref <any []>([]);
@@ -154,28 +160,12 @@ const browsing = ref(false);
154160const treeLoading = ref (false );
155161
156162// --- Skeleton blueprint ---
157- type SkeletonNode = { depth: number ; type: string ; width: number };
158- const DEFAULT_SKELETON: SkeletonNode [] = [
159- { depth: 0 , type: " dir" , width: 55 },
160- { depth: 1 , type: " file" , width: 45 },
161- { depth: 1 , type: " file" , width: 50 },
162- { depth: 0 , type: " dir" , width: 60 },
163- { depth: 0 , type: " file" , width: 40 },
164- ];
165-
166- function readSkeletonFromStorage(): SkeletonNode [] {
167- if (! import .meta .client || ! props .rootPath ) return DEFAULT_SKELETON ;
168- try {
169- const saved = localStorage .getItem (` locode:skeleton:${props .rootPath } ` );
170- if (saved ) {
171- const parsed = JSON .parse (saved );
172- if (Array .isArray (parsed ) && parsed .length > 0 ) return parsed ;
173- }
174- } catch {}
163+ function readSkeletonFromProps(): SkeletonNode [] {
164+ if (props .initialSkeleton && props .initialSkeleton .length > 0 ) return props .initialSkeleton ;
175165 return DEFAULT_SKELETON ;
176166}
177167
178- const skeletonBlueprint = ref <SkeletonNode []>(readSkeletonFromStorage ());
168+ const skeletonBlueprint = ref <SkeletonNode []>(readSkeletonFromProps ());
179169
180170function flattenTree(nodes : any [], depth = 0 ): SkeletonNode [] {
181171 const result: SkeletonNode [] = [];
@@ -193,7 +183,7 @@ function saveSkeletonBlueprint() {
193183 if (! props .rootPath ) return ;
194184 const blueprint = flattenTree (tree .value );
195185 if (blueprint .length > 0 ) {
196- localStorage . setItem ( ` locode :skeleton:${ props . rootPath } ` , JSON . stringify ( blueprint ) );
186+ emit ( " update :skeleton" , blueprint );
197187 }
198188}
199189
@@ -237,7 +227,7 @@ function getOpenPaths(nodes: any[]): string[] {
237227}
238228
239229function saveOpenFolders() {
240- localStorage . setItem ( storageKey . value , JSON . stringify ( getOpenPaths (tree .value ) ));
230+ emit ( " update:openFolders " , getOpenPaths (tree .value ));
241231}
242232
243233async function restoreOpenFolders(nodes : any [], openPaths : Set <string >) {
@@ -254,12 +244,9 @@ async function loadWorkTree() {
254244 treeLoading .value = true ;
255245 try {
256246 tree .value = await loadTree (props .rootPath );
257- const saved = localStorage .getItem (storageKey .value );
258- if (saved ) {
259- try {
260- const openPaths = new Set <string >(JSON .parse (saved ));
261- await restoreOpenFolders (tree .value , openPaths );
262- } catch {}
247+ if (props .initialOpenFolders && props .initialOpenFolders .length > 0 ) {
248+ const openPaths = new Set <string >(props .initialOpenFolders );
249+ await restoreOpenFolders (tree .value , openPaths );
263250 }
264251 saveSkeletonBlueprint ();
265252 } finally {
@@ -343,13 +330,28 @@ function onEscape(e: KeyboardEvent) {
343330watch (() => props .rootPath , (newPath ) => {
344331 if (newPath ) {
345332 browsing .value = false ;
346- skeletonBlueprint .value = readSkeletonFromStorage ();
333+ skeletonBlueprint .value = readSkeletonFromProps ();
347334 loadWorkTree ();
348335 }
349336});
350337
338+ // When parent pushes fresh config values (workspace switch), update skeleton
339+ watch (() => props .initialSkeleton , (val ) => {
340+ if (val && val .length > 0 ) skeletonBlueprint .value = val ;
341+ });
342+
343+ // One-shot: re-apply open folders when config loads after the tree is already mounted
344+ // (happens on initial page load when rootPath is pre-set but config loads async)
345+ const unwatchInitialFolders = watch (() => props .initialOpenFolders , async (newVal , oldVal ) => {
346+ // Only fire when going from empty → non-empty (config first load, not workspace switch)
347+ if (! newVal ?.length || oldVal ?.length || treeLoading .value || ! tree .value .length ) return ;
348+ unwatchInitialFolders ();
349+ await restoreOpenFolders (tree .value , new Set (newVal ));
350+ saveSkeletonBlueprint ();
351+ }, { immediate: false });
352+
351353onMounted (async () => {
352- skeletonBlueprint .value = readSkeletonFromStorage ();
354+ skeletonBlueprint .value = readSkeletonFromProps ();
353355 treeLoading .value = true ;
354356 if (! props .rootPath ) {
355357 browsing .value = true ;
0 commit comments