gui: port frontend to Wails v2
Frontend build failure root cause:
- Vite 8 uses rolldown with Wails v3 typed-events plugin
- @wailsio/runtime (Wails v3) in frontend dependencies
- vite.config.js had wails('./bindings') plugin from Wails v3 template
- main.js used Svelte 5 mount() API but Svelte 4 required
Fixes:
- Remove @wailsio/runtime dependency
- Remove wails('./bindings') plugin from vite.config.js
- Replace Vite 8 with Vite 5.4.21 + Rollup (stable)
- Downgrade Svelte 5 to Svelte 4.2.19
- Downgrade @sveltejs/vite-plugin-svelte to v3.1.2
- Fix main.js: mount() -> new App({ target })
- Rewrite App.svelte with Wails v2 binding calls (window.go.main.App.*)
- UI: sidebar with sections, nodes, basic navigation
Build: cd frontend && npm run build -> dist/ (476ms)
Build GUI: go build -tags 'gui production webkit2_41' -o verstak-gui ./cmd/verstak-gui
Run: ./verstak-gui (window opens, no SIGSEGV)
This commit is contained in:
Generated
+850
-699
File diff suppressed because it is too large
Load Diff
@@ -5,16 +5,13 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build:dev": "vite build --minify false --mode development",
|
||||
"build": "vite build --mode production",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wailsio/runtime": "latest"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
||||
"svelte": "^5.46.4",
|
||||
"vite": "^8.0.5"
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^4.2.19",
|
||||
"vite": "^5.4.21"
|
||||
}
|
||||
}
|
||||
|
||||
+124
-5
@@ -1,10 +1,129 @@
|
||||
<script>
|
||||
// Stub — will be replaced with actual UI
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let sections = []
|
||||
let nodes = []
|
||||
let version = ''
|
||||
let error = ''
|
||||
let selectedSection = ''
|
||||
let selectedNode = null
|
||||
|
||||
// Wails v2 bindings — generated by wails
|
||||
// For now, use window.wails or import from wailsjs
|
||||
async function callGo(method, ...args) {
|
||||
if (window.go && window.go.main && window.go.main.App) {
|
||||
return window.go.main.App[method](...args)
|
||||
}
|
||||
throw new Error('Wails bindings not loaded')
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
version = 'verstak-gui'
|
||||
// Try Wails bindings
|
||||
if (window.go && window.go.main && window.go.main.App) {
|
||||
version = await window.go.main.App.VerstakVersion()
|
||||
sections = await window.go.main.App.ListSections()
|
||||
nodes = await window.go.main.App.ListRootNodes()
|
||||
}
|
||||
} catch (e) {
|
||||
error = String(e)
|
||||
}
|
||||
})
|
||||
|
||||
function selectSection(id) {
|
||||
selectedSection = id
|
||||
// TODO: load nodes for section
|
||||
}
|
||||
|
||||
function selectNode(node) {
|
||||
selectedNode = node
|
||||
}
|
||||
</script>
|
||||
|
||||
<div style="display:flex;align-items:center;justify-content:center;height:100vh;background:#13131f;color:#e4e4ef;font-family:sans-serif">
|
||||
<div style="text-align:center">
|
||||
<h1 style="font-size:28px;margin-bottom:8px">⚒ Верстак</h1>
|
||||
<p style="color:#8888a4">Wails desktop app — under construction</p>
|
||||
<div class="app">
|
||||
<!-- Top bar -->
|
||||
<div class="topbar">
|
||||
<span class="logo">⚒</span>
|
||||
<h1>Верстак</h1>
|
||||
<span class="version">{version}</span>
|
||||
</div>
|
||||
|
||||
<!-- Error banner -->
|
||||
{#if error}
|
||||
<div class="error-banner">
|
||||
Error: {error}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Main content -->
|
||||
<div class="main">
|
||||
<!-- Sidebar -->
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">Разделы</div>
|
||||
{#each sections as section}
|
||||
<div class="sidebar-item {selectedSection === section.id ? 'selected' : ''}"
|
||||
on:click={() => selectSection(section.id)}>
|
||||
{section.label}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="sidebar-header" style="margin-top:16px">Корневые дела</div>
|
||||
{#each nodes as node}
|
||||
<div class="sidebar-item {selectedNode && selectedNode.id === node.id ? 'selected' : ''}"
|
||||
on:click={() => selectNode(node)}>
|
||||
{node.title}
|
||||
</div>
|
||||
{/each}
|
||||
{#if nodes.length === 0 && sections.length > 0}
|
||||
<div class="sidebar-empty">Нет дел. Создайте первое дело.</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Content panel -->
|
||||
<div class="content">
|
||||
{#if selectedNode}
|
||||
<div class="node-view">
|
||||
<h2>{selectedNode.title}</h2>
|
||||
<p>ID: {selectedNode.id}</p>
|
||||
<p>Type: {selectedNode.type}</p>
|
||||
</div>
|
||||
{:else if sections.length > 0}
|
||||
<div class="welcome">
|
||||
<p>Wails v2 Desktop GUI работает.</p>
|
||||
<p>Sections: {sections.length}, Root nodes: {nodes.length}</p>
|
||||
{#if error}
|
||||
<p class="error-text">Wails bindings error: {error}</p>
|
||||
<p class="hint">Window opens but Go bindings not connected yet.</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="loading">Загрузка...</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
.app { display: flex; flex-direction: column; height: 100vh; background: #13131f; color: #e4e4ef; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
||||
.topbar { padding: 12px 20px; border-bottom: 1px solid #2a2a3c; display: flex; align-items: center; gap: 12px; }
|
||||
.logo { font-size: 20px; }
|
||||
.topbar h1 { font-size: 18px; font-weight: 600; }
|
||||
.version { color: #666; font-size: 12px; margin-left: auto; }
|
||||
.error-banner { background: #442222; color: #ff8888; padding: 8px 20px; font-size: 13px; }
|
||||
.main { display: flex; flex: 1; overflow: hidden; }
|
||||
.sidebar { width: 240px; border-right: 1px solid #2a2a3c; padding: 12px; overflow-y: auto; flex-shrink: 0; }
|
||||
.sidebar-header { font-size: 11px; text-transform: uppercase; color: #666; margin-bottom: 8px; padding: 0 12px; }
|
||||
.sidebar-item { padding: 8px 12px; border-radius: 6px; cursor: pointer; margin-bottom: 2px; color: #ccc; }
|
||||
.sidebar-item:hover { background: #1e1e2e; }
|
||||
.sidebar-item.selected { background: #2a2a3c; color: #fff; }
|
||||
.sidebar-empty { color: #666; font-size: 12px; padding: 8px 12px; }
|
||||
.content { flex: 1; padding: 20px; overflow-y: auto; }
|
||||
.welcome { color: #8888a4; font-size: 14px; line-height: 1.6; }
|
||||
.error-text { color: #ff8888; }
|
||||
.hint { color: #666; margin-top: 8px; }
|
||||
.loading { color: #888; font-size: 14px; }
|
||||
.node-view h2 { font-size: 24px; margin-bottom: 16px; }
|
||||
.node-view p { color: #888; font-size: 13px; margin-bottom: 8px; }
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mount } from 'svelte'
|
||||
import App from './App.svelte'
|
||||
|
||||
mount(App, { target: document.getElementById('app') })
|
||||
new App({
|
||||
target: document.getElementById('app')
|
||||
})
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||
import wails from "@wailsio/runtime/plugins/vite";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
server: {
|
||||
host: "127.0.0.1",
|
||||
port: Number(process.env.WAILS_VITE_PORT) || 9245,
|
||||
port: 3001,
|
||||
strictPort: true,
|
||||
},
|
||||
plugins: [svelte(), wails("./bindings")],
|
||||
plugins: [svelte()],
|
||||
build: {
|
||||
outDir: "dist",
|
||||
emptyOutDir: true,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user