import { create } from 'zustand'; import type { FileNode } from '@glmpilot/shared'; const DEFAULT_FILES: Record = { 'index.html': ` My Project

Hello, GLMPilot!

Start editing to see changes in the live preview.

`, 'style.css': `* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', system-ui, sans-serif; background: #0a0a0f; color: #e8e8e8; min-height: 100vh; display: flex; align-items: center; justify-content: center; } #app { text-align: center; padding: 2rem; } h1 { font-size: 2.5rem; margin-bottom: 0.5rem; background: linear-gradient(135deg, #81f084, #4ade80); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } p { color: #a0a0a0; font-size: 1.1rem; }`, 'script.js': `// Welcome to GLMPilot! console.log("Hello from GLMPilot!"); document.addEventListener('DOMContentLoaded', () => { const app = document.getElementById('app'); const btn = document.createElement('button'); btn.textContent = 'Click me'; btn.style.cssText = 'margin-top:1.5rem;padding:0.75rem 2rem;background:#81f084;color:#000;border:none;border-radius:8px;font-size:1rem;cursor:pointer;font-weight:600'; btn.addEventListener('click', () => alert('GLMPilot is working!')); app?.appendChild(btn); });`, 'README.md': `# My Project\n\nBuilt with GLMPilot — the AI-powered browser IDE.\n`, }; interface FileStore { fileTree: FileNode[]; files: Record; initialized: boolean; setFileTree: (tree: FileNode[]) => void; setFiles: (files: Record) => void; updateFile: (path: string, content: string) => void; createFile: (path: string, content?: string) => void; deleteFile: (path: string) => void; renameFile: (oldPath: string, newPath: string) => void; importFiles: (files: Record, tree: FileNode[]) => void; initialize: () => void; } function buildTreeFromPaths(paths: string[]): FileNode[] { const root: FileNode[] = []; for (const path of paths.sort()) { const parts = path.split('/'); let current = root; for (let i = 0; i < parts.length; i++) { const name = parts[i]; if (i === parts.length - 1) { current.push({ name, path, type: 'file' }); } else { let dir = current.find((n) => n.name === name && n.type === 'directory'); if (!dir) { dir = { name, path: parts.slice(0, i + 1).join('/'), type: 'directory', children: [] }; current.push(dir); } current = dir.children!; } } } return root; } export const useFileStore = create((set, get) => ({ fileTree: [], files: {}, initialized: false, initialize: () => { if (get().initialized) return; // Try loading from localStorage const saved = localStorage.getItem('ff-workspace'); if (saved) { try { const parsed = JSON.parse(saved); if (parsed.files && Object.keys(parsed.files).length > 0) { set({ files: parsed.files, fileTree: buildTreeFromPaths(Object.keys(parsed.files)), initialized: true }); return; } } catch { /* fallback */ } } // Use default files set({ files: DEFAULT_FILES, fileTree: buildTreeFromPaths(Object.keys(DEFAULT_FILES)), initialized: true, }); }, setFileTree: (tree) => set({ fileTree: tree }), setFiles: (files) => set({ files }), updateFile: (path, content) => { set((state) => { const files = { ...state.files, [path]: content }; persist(files); return { files }; }); }, createFile: (path, content = '') => { set((state) => { const files = { ...state.files, [path]: content }; persist(files); return { files, fileTree: buildTreeFromPaths(Object.keys(files)) }; }); }, deleteFile: (path) => { set((state) => { const files = { ...state.files }; delete files[path]; persist(files); return { files, fileTree: buildTreeFromPaths(Object.keys(files)) }; }); }, renameFile: (oldPath, newPath) => { set((state) => { const files = { ...state.files }; files[newPath] = files[oldPath] || ''; delete files[oldPath]; persist(files); return { files, fileTree: buildTreeFromPaths(Object.keys(files)) }; }); }, importFiles: (importedFiles, tree) => { set({ files: importedFiles, fileTree: tree, initialized: true }); persist(importedFiles); }, })); function persist(files: Record) { try { localStorage.setItem('ff-workspace', JSON.stringify({ files })); } catch { /* storage full */ } }