chore: editor store, graph, and vite config updates

This commit is contained in:
2026-06-14 20:38:12 +08:00
parent 48da10147b
commit 59f6956b50
4 changed files with 49 additions and 2 deletions

View File

@@ -49,7 +49,7 @@ function importJSON() {
} }
function testScene(id: string) { function testScene(id: string) {
window.open('/?scene=/scenes/demo.json&startScene=' + id, '_blank') window.open('/?scene=' + store.sourcePath + '&startScene=' + id, '_blank')
} }
async function onFileSelected(e: Event) { async function onFileSelected(e: Event) {

View File

@@ -18,6 +18,7 @@ export function useGraphEditor() {
scenes: { ...store.gameData.scenes, [source]: { ...scene, choices: newChoices } }, scenes: { ...store.gameData.scenes, [source]: { ...scene, choices: newChoices } },
} }
store.markDirty() store.markDirty()
store.autoSave()
} }
return { return {

View File

@@ -7,6 +7,7 @@ export const useEditorStore = defineStore('editor', () => {
const selectedNodeId = ref<string | null>(null) const selectedNodeId = ref<string | null>(null)
const startSceneId = ref('') const startSceneId = ref('')
const dirty = ref(false) const dirty = ref(false)
const sourcePath = ref('/scenes/demo.json')
const selectedScene = computed(() => { const selectedScene = computed(() => {
if (!selectedNodeId.value) return null if (!selectedNodeId.value) return null
@@ -44,6 +45,7 @@ export const useEditorStore = defineStore('editor', () => {
} }
triggerRef(gameData) triggerRef(gameData)
dirty.value = true dirty.value = true
autoSave()
return id return id
} }
@@ -71,6 +73,7 @@ export const useEditorStore = defineStore('editor', () => {
triggerRef(gameData) triggerRef(gameData)
dirty.value = true dirty.value = true
if (selectedNodeId.value === id) selectedNodeId.value = null if (selectedNodeId.value === id) selectedNodeId.value = null
autoSave()
} }
function updateScene(id: string, partial: Partial<SceneNode>) { function updateScene(id: string, partial: Partial<SceneNode>) {
@@ -82,6 +85,7 @@ export const useEditorStore = defineStore('editor', () => {
} }
triggerRef(gameData) triggerRef(gameData)
dirty.value = true dirty.value = true
autoSave()
} }
function addChoice(sourceId: string) { function addChoice(sourceId: string) {
@@ -96,6 +100,7 @@ export const useEditorStore = defineStore('editor', () => {
} }
triggerRef(gameData) triggerRef(gameData)
dirty.value = true dirty.value = true
autoSave()
} }
function updateChoice(sourceId: string, index: number, partial: Partial<Choice>) { function updateChoice(sourceId: string, index: number, partial: Partial<Choice>) {
@@ -108,6 +113,7 @@ export const useEditorStore = defineStore('editor', () => {
} }
triggerRef(gameData) triggerRef(gameData)
dirty.value = true dirty.value = true
autoSave()
} }
function deleteChoice(sourceId: string, index: number) { function deleteChoice(sourceId: string, index: number) {
@@ -124,9 +130,22 @@ export const useEditorStore = defineStore('editor', () => {
dirty.value = true dirty.value = true
} }
function setSourcePath(p: string) { sourcePath.value = p }
async function autoSave() {
try {
await fetch('/api/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path: sourcePath.value, data: gameData.value }),
})
} catch { /* dev server not running */ }
}
return { return {
gameData, selectedNodeId, selectedScene, startSceneId, dirty, gameData, selectedNodeId, selectedScene, startSceneId, dirty, sourcePath,
markDirty, loadJSON, exportJSON, addScene, deleteScene, markDirty, loadJSON, exportJSON, addScene, deleteScene,
updateScene, addChoice, updateChoice, deleteChoice, generateId, updateScene, addChoice, updateChoice, deleteChoice, generateId,
setSourcePath, autoSave,
} }
}) })

View File

@@ -1,6 +1,7 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import { resolve } from 'path' import { resolve } from 'path'
import fs from 'fs'
export default defineConfig({ export default defineConfig({
plugins: [vue()], plugins: [vue()],
@@ -18,4 +19,30 @@ export default defineConfig({
}, },
}, },
}, },
server: {
configureServer(server) {
server.middlewares.use('/api/save', (req, res) => {
if (req.method !== 'POST') { res.writeHead(405); res.end(); return }
let body = ''
req.on('data', (c: string) => body += c)
req.on('end', () => {
try {
const { path, data } = JSON.parse(body)
if (!path || typeof path !== 'string' || !path.startsWith('/scenes/')) {
res.writeHead(400)
res.end(JSON.stringify({ error: 'invalid path' }))
return
}
const safePath = resolve(__dirname, 'public', '.' + path)
fs.writeFileSync(safePath, JSON.stringify(data, null, 2))
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ ok: true }))
} catch (e: any) {
res.writeHead(400)
res.end(JSON.stringify({ error: e.message }))
}
})
})
},
},
}) })