Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4010a5a24 | ||
|
|
4a8f4e3319 | ||
|
|
ee503c338f | ||
|
|
3e07e611dd | ||
|
|
77a7918569 | ||
|
|
c65187f656 | ||
|
|
2e50e95b68 | ||
|
|
ae970e5bca |
Binary file not shown.
@@ -0,0 +1,383 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
|
|
||||||
|
"verstak/internal/core/actions"
|
||||||
|
"verstak/internal/core/files"
|
||||||
|
"verstak/internal/core/notes"
|
||||||
|
"verstak/internal/core/nodes"
|
||||||
|
"verstak/internal/core/storage"
|
||||||
|
"verstak/internal/core/worklog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App is the Wails v2 application adapter. It wraps core services.
|
||||||
|
type App struct {
|
||||||
|
ctx context.Context
|
||||||
|
db *storage.DB
|
||||||
|
nodes *nodes.Repository
|
||||||
|
files *files.Service
|
||||||
|
notes *notes.Service
|
||||||
|
actions *actions.Service
|
||||||
|
worklog *worklog.Service
|
||||||
|
vault string
|
||||||
|
}
|
||||||
|
|
||||||
|
// startup is called when the app starts. Store context.
|
||||||
|
func (a *App) startup(ctx context.Context) {
|
||||||
|
a.ctx = ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// DTOs
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
type NodeDTO struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
ParentID string `json:"parentId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SectionDTO struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NoteDTO struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileDTO struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
NodeID string `json:"nodeId"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Mime string `json:"mime"`
|
||||||
|
IsDir bool `json:"isDir"`
|
||||||
|
Missing bool `json:"missing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActionDTO struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
NodeID string `json:"nodeId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorklogDTO struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
NodeID string `json:"nodeId"`
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Minutes int `json:"minutes"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchResultDTO struct {
|
||||||
|
NodeID string `json:"nodeId"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Snippet string `json:"snippet"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Sections
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) ListSections() []SectionDTO {
|
||||||
|
return []SectionDTO{
|
||||||
|
{ID: "today", Label: "Сегодня"},
|
||||||
|
{ID: "inbox", Label: "Неразобранное"},
|
||||||
|
{ID: "clients", Label: "Клиенты"},
|
||||||
|
{ID: "projects", Label: "Проекты"},
|
||||||
|
{ID: "recipes", Label: "Рецепты"},
|
||||||
|
{ID: "documents", Label: "Документы"},
|
||||||
|
{ID: "archive", Label: "Архив"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Nodes
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) ListNodesBySection(section string) ([]NodeDTO, error) {
|
||||||
|
list, err := a.nodes.ListRoots(false, section)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toNodeDTOs(list), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) ListChildren(parentID string) ([]NodeDTO, error) {
|
||||||
|
list, err := a.nodes.ListChildren(parentID, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toNodeDTOs(list), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) GetNodeDetail(nodeID string) (*NodeDTO, error) {
|
||||||
|
n, err := a.nodes.GetActive(nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dto := toNodeDTO(n)
|
||||||
|
return &dto, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) CreateNode(parentID, nodeType, title, section string) (*NodeDTO, error) {
|
||||||
|
n, err := a.nodes.Create(parentID, nodeType, title, section)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dto := toNodeDTO(n)
|
||||||
|
return &dto, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) DeleteNode(id string) error {
|
||||||
|
return a.nodes.SoftDelete(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Notes
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// ListNotes returns note-type children of a node.
|
||||||
|
func (a *App) ListNotes(nodeID string) ([]NodeDTO, error) {
|
||||||
|
children, err := a.nodes.ListChildren(nodeID, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result []NodeDTO
|
||||||
|
for i := range children {
|
||||||
|
if children[i].Type == nodes.TypeNote {
|
||||||
|
result = append(result, toNodeDTO(&children[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateNote creates a note under a parent node.
|
||||||
|
func (a *App) CreateNote(parentID, title string) (*NodeDTO, error) {
|
||||||
|
node, _, err := a.notes.Create(parentID, title, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dto := toNodeDTO(node)
|
||||||
|
return &dto, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadNote reads note content.
|
||||||
|
func (a *App) ReadNote(noteID string) (string, error) {
|
||||||
|
return a.notes.Read(noteID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveNote saves note content.
|
||||||
|
func (a *App) SaveNote(noteID, content string) error {
|
||||||
|
return a.notes.Save(noteID, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Files
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) ListFiles(nodeID string) ([]FileDTO, error) {
|
||||||
|
records, err := a.files.ListByNode(nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := make([]FileDTO, len(records))
|
||||||
|
for i := range records {
|
||||||
|
isDir := records[i].MIME == "inode/directory"
|
||||||
|
missing := false
|
||||||
|
result[i] = FileDTO{
|
||||||
|
ID: records[i].ID,
|
||||||
|
NodeID: records[i].NodeID,
|
||||||
|
Name: records[i].Filename,
|
||||||
|
Path: records[i].Path,
|
||||||
|
Size: records[i].Size,
|
||||||
|
Mime: records[i].MIME,
|
||||||
|
IsDir: isDir,
|
||||||
|
Missing: missing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Actions
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) ListActions(nodeID string) ([]ActionDTO, error) {
|
||||||
|
list, err := a.actions.ListByNode(nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := make([]ActionDTO, len(list))
|
||||||
|
for i := range list {
|
||||||
|
data := list[i].Command
|
||||||
|
if list[i].URL != "" {
|
||||||
|
data = list[i].URL
|
||||||
|
}
|
||||||
|
result[i] = ActionDTO{
|
||||||
|
ID: list[i].ID,
|
||||||
|
NodeID: list[i].NodeID,
|
||||||
|
Title: list[i].Title,
|
||||||
|
Type: list[i].Kind,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RunAction(id string) error {
|
||||||
|
_, err := a.actions.Run(id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Worklog
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) ListWorklog(nodeID string) ([]WorklogDTO, error) {
|
||||||
|
list, err := a.worklog.ListByNode(nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := make([]WorklogDTO, len(list))
|
||||||
|
for i := range list {
|
||||||
|
mins := 0
|
||||||
|
if list[i].Minutes != nil {
|
||||||
|
mins = *list[i].Minutes
|
||||||
|
}
|
||||||
|
result[i] = WorklogDTO{
|
||||||
|
ID: list[i].ID,
|
||||||
|
NodeID: list[i].NodeID,
|
||||||
|
Summary: list[i].Summary,
|
||||||
|
Minutes: mins,
|
||||||
|
CreatedAt: list[i].CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) CreateWorklog(nodeID, summary string, minutes int) (*WorklogDTO, error) {
|
||||||
|
entry, err := a.worklog.Add(nodeID, summary, "", minutes, false, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mins := 0
|
||||||
|
if entry.Minutes != nil {
|
||||||
|
mins = *entry.Minutes
|
||||||
|
}
|
||||||
|
dto := &WorklogDTO{
|
||||||
|
ID: entry.ID,
|
||||||
|
NodeID: entry.NodeID,
|
||||||
|
Summary: entry.Summary,
|
||||||
|
Minutes: mins,
|
||||||
|
CreatedAt: entry.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||||
|
}
|
||||||
|
return dto, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Search (stubs — search service not wired yet)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) Search(query string) ([]SearchResultDTO, error) {
|
||||||
|
if strings.TrimSpace(query) == "" {
|
||||||
|
return []SearchResultDTO{}, nil
|
||||||
|
}
|
||||||
|
return []SearchResultDTO{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// File Dialogs (Wails v2 Runtime)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) PickFile() (string, error) {
|
||||||
|
return wailsruntime.OpenFileDialog(a.ctx, wailsruntime.OpenDialogOptions{
|
||||||
|
Title: "Выберите файл",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) PickFiles() ([]string, error) {
|
||||||
|
return wailsruntime.OpenMultipleFilesDialog(a.ctx, wailsruntime.OpenDialogOptions{
|
||||||
|
Title: "Выберите файлы",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) PickDirectory() (string, error) {
|
||||||
|
return wailsruntime.OpenDirectoryDialog(a.ctx, wailsruntime.OpenDialogOptions{
|
||||||
|
Title: "Выберите папку",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// System helpers
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func (a *App) OpenFile(fileID string) error {
|
||||||
|
return fmt.Errorf("not implemented: %s", fileID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) OpenFolder(nodeID string) error {
|
||||||
|
cmd := exec.Command("xdg-open", a.vault)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) VerstakVersion() string {
|
||||||
|
return "verstak-gui/v2"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Helpers
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func toNodeDTO(n *nodes.Node) NodeDTO {
|
||||||
|
parentID := ""
|
||||||
|
if n.ParentID != nil {
|
||||||
|
parentID = *n.ParentID
|
||||||
|
}
|
||||||
|
path := ""
|
||||||
|
if n.Path != nil {
|
||||||
|
path = *n.Path
|
||||||
|
}
|
||||||
|
return NodeDTO{
|
||||||
|
ID: n.ID,
|
||||||
|
ParentID: parentID,
|
||||||
|
Title: n.Title,
|
||||||
|
Type: n.Type,
|
||||||
|
Section: n.Section,
|
||||||
|
Path: path,
|
||||||
|
CreatedAt: n.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toNodeDTOs(list []nodes.Node) []NodeDTO {
|
||||||
|
result := make([]NodeDTO, len(list))
|
||||||
|
for i := range list {
|
||||||
|
result[i] = toNodeDTO(&list[i])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ = os.Getenv
|
||||||
|
_ = exec.Command
|
||||||
|
)
|
||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
.svelte-14ysusk.svelte-14ysusk,.svelte-14ysusk.svelte-14ysusk:before,.svelte-14ysusk.svelte-14ysusk:after{box-sizing:border-box;margin:0;padding:0}.app.svelte-14ysusk.svelte-14ysusk{display:flex;width:100vw;height:100vh;overflow:hidden;background:#13131f;color:#e4e4ef;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px}.sidebar.svelte-14ysusk.svelte-14ysusk{width:260px;min-width:200px;height:100vh;display:flex;flex-direction:column;background:#1a1a28;border-right:1px solid #2a2a3c;flex-shrink:0;overflow:hidden}.sidebar-top.svelte-14ysusk.svelte-14ysusk{padding:16px 20px;display:flex;align-items:center;gap:10px;border-bottom:1px solid #2a2a3c;flex-shrink:0}.logo.svelte-14ysusk.svelte-14ysusk{font-size:20px;line-height:1}.app-name.svelte-14ysusk.svelte-14ysusk{font-size:16px;font-weight:600;color:#e4e4ef}.sidebar-nav.svelte-14ysusk.svelte-14ysusk{flex:1;overflow-y:auto;padding:12px 0}.nav-group.svelte-14ysusk.svelte-14ysusk{margin-bottom:16px}.nav-label.svelte-14ysusk.svelte-14ysusk{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:#666;padding:4px 20px;margin-bottom:4px}.nav-item.svelte-14ysusk.svelte-14ysusk{display:block;width:100%;padding:8px 20px;border:none;background:none;color:#ccc;font-size:13px;text-align:left;cursor:pointer;border-radius:0;font-family:inherit}.nav-item.svelte-14ysusk.svelte-14ysusk:hover{background:#223}.nav-item.selected.svelte-14ysusk.svelte-14ysusk{background:#2a2a4a;color:#fff;font-weight:500}.nav-empty.svelte-14ysusk.svelte-14ysusk{padding:8px 20px;color:#555;font-size:12px}.sidebar-bottom.svelte-14ysusk.svelte-14ysusk{padding:12px 20px;border-top:1px solid #2a2a3c;flex-shrink:0}.version.svelte-14ysusk.svelte-14ysusk{font-size:11px;color:#555}.main.svelte-14ysusk.svelte-14ysusk{flex:1;display:flex;flex-direction:column;height:100vh;min-width:0;overflow:hidden;background:#13131f}.header.svelte-14ysusk.svelte-14ysusk{padding:12px 24px;border-bottom:1px solid #2a2a3c;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;min-height:48px}.crumb.svelte-14ysusk.svelte-14ysusk{font-size:14px;font-weight:500;color:#e4e4ef}.crumb.placeholder.svelte-14ysusk.svelte-14ysusk{color:#666}.search-hint.svelte-14ysusk.svelte-14ysusk{padding:6px 12px;background:#1e1e2e;border:1px solid #2a2a3c;border-radius:4px;color:#666;font-size:12px;cursor:text}.error-banner.svelte-14ysusk.svelte-14ysusk{background:#3a2222;color:#f88;padding:8px 24px;font-size:12px;border-bottom:1px solid #4a2222;flex-shrink:0}.content.svelte-14ysusk.svelte-14ysusk{flex:1;overflow-y:auto;padding:24px}.welcome.svelte-14ysusk h2.svelte-14ysusk{font-size:28px;font-weight:300;margin-bottom:12px;color:#8888a4}.welcome.svelte-14ysusk p.svelte-14ysusk{color:#666;font-size:13px;margin-bottom:4px}.error-text.svelte-14ysusk.svelte-14ysusk{color:#f88;margin-top:12px}.loading.svelte-14ysusk.svelte-14ysusk{color:#666}.node-view.svelte-14ysusk h2.svelte-14ysusk{font-size:24px;margin-bottom:16px}.node-meta.svelte-14ysusk.svelte-14ysusk{display:flex;gap:16px;color:#666;font-size:12px}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/wails.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Верстак</title>
|
||||||
|
<style>
|
||||||
|
/* Critical reset — no white borders, full viewport */
|
||||||
|
html, body, #app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #13131f;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="module" crossorigin src="/assets/index-COs6tJEl.js"></script>
|
||||||
|
<link rel="stylesheet" crossorigin href="/assets/index-ClxkTvdE.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
:root {
|
||||||
|
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||||
|
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
|
sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background-color: rgba(27, 38, 54, 1);
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local(""),
|
||||||
|
url("./Inter-Medium.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 3em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #646cff;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 60px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: none;
|
||||||
|
margin: 0 0 0 20px;
|
||||||
|
padding: 0 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
place-content: center;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.2em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 6em;
|
||||||
|
padding: 1.5em;
|
||||||
|
will-change: filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #e80000aa);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo.vanilla:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #f7df1eaa);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
margin: 1.5rem auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 1rem;
|
||||||
|
align-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
:root {
|
||||||
|
color: #213547;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #747bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.input-box .btn:hover {
|
||||||
|
background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box .input {
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
outline: none;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 10px;
|
||||||
|
color: black;
|
||||||
|
background-color: rgba(240, 240, 240, 1);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box .input:hover {
|
||||||
|
border: none;
|
||||||
|
background-color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box .input:focus {
|
||||||
|
border: none;
|
||||||
|
background-color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="26.6" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 308"><path fill="#FF3E00" d="M239.682 40.707C211.113-.182 154.69-12.301 113.895 13.69L42.247 59.356a82.198 82.198 0 0 0-37.135 55.056a86.566 86.566 0 0 0 8.536 55.576a82.425 82.425 0 0 0-12.296 30.719a87.596 87.596 0 0 0 14.964 66.244c28.574 40.893 84.997 53.007 125.787 27.016l71.648-45.664a82.182 82.182 0 0 0 37.135-55.057a86.601 86.601 0 0 0-8.53-55.577a82.409 82.409 0 0 0 12.29-30.718a87.573 87.573 0 0 0-14.963-66.244"></path><path fill="#FFF" d="M106.889 270.841c-23.102 6.007-47.497-3.036-61.103-22.648a52.685 52.685 0 0 1-9.003-39.85a49.978 49.978 0 0 1 1.713-6.693l1.35-4.115l3.671 2.697a92.447 92.447 0 0 0 28.036 14.007l2.663.808l-.245 2.659a16.067 16.067 0 0 0 2.89 10.656a17.143 17.143 0 0 0 18.397 6.828a15.786 15.786 0 0 0 4.403-1.935l71.67-45.672a14.922 14.922 0 0 0 6.734-9.977a15.923 15.923 0 0 0-2.713-12.011a17.156 17.156 0 0 0-18.404-6.832a15.78 15.78 0 0 0-4.396 1.933l-27.35 17.434a52.298 52.298 0 0 1-14.553 6.391c-23.101 6.007-47.497-3.036-61.101-22.649a52.681 52.681 0 0 1-9.004-39.849a49.428 49.428 0 0 1 22.34-33.114l71.664-45.677a52.218 52.218 0 0 1 14.563-6.398c23.101-6.007 47.497 3.036 61.101 22.648a52.685 52.685 0 0 1 9.004 39.85a50.559 50.559 0 0 1-1.713 6.692l-1.35 4.116l-3.67-2.693a92.373 92.373 0 0 0-28.037-14.013l-2.664-.809l.246-2.658a16.099 16.099 0 0 0-2.89-10.656a17.143 17.143 0 0 0-18.398-6.828a15.786 15.786 0 0 0-4.402 1.935l-71.67 45.674a14.898 14.898 0 0 0-6.73 9.975a15.9 15.9 0 0 0 2.709 12.012a17.156 17.156 0 0 0 18.404 6.832a15.841 15.841 0 0 0 4.402-1.935l27.345-17.427a52.147 52.147 0 0 1 14.552-6.397c23.101-6.006 47.497 3.037 61.102 22.65a52.681 52.681 0 0 1 9.003 39.848a49.453 49.453 0 0 1-22.34 33.12l-71.664 45.673a52.218 52.218 0 0 1-14.563 6.398"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
@@ -0,0 +1,81 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"verstak/internal/core/actions"
|
||||||
|
"verstak/internal/core/files"
|
||||||
|
"verstak/internal/core/notes"
|
||||||
|
"verstak/internal/core/nodes"
|
||||||
|
"verstak/internal/core/plugins"
|
||||||
|
"verstak/internal/core/search"
|
||||||
|
"verstak/internal/core/storage"
|
||||||
|
"verstak/internal/core/worklog"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed all:frontend-dist
|
||||||
|
var assets embed.FS
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
vaultPath := "."
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
vaultPath = os.Args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
abs, err := filepath.Abs(vaultPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbPath := filepath.Join(abs, ".verstak", "index.db")
|
||||||
|
db, err := storage.Open(dbPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Open vault: %v", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Init core services
|
||||||
|
nodeRepo := nodes.NewRepository(db)
|
||||||
|
fileSvc := files.NewService(db, abs)
|
||||||
|
noteSvc := notes.NewService(db, abs, nodeRepo, fileSvc)
|
||||||
|
actionSvc := actions.NewService(db)
|
||||||
|
worklogSvc := worklog.NewService(db)
|
||||||
|
searchSvc := search.NewService(db)
|
||||||
|
plugins.NewManager(abs).Discover()
|
||||||
|
_ = searchSvc
|
||||||
|
|
||||||
|
app := &App{
|
||||||
|
db: db,
|
||||||
|
nodes: nodeRepo,
|
||||||
|
files: fileSvc,
|
||||||
|
notes: noteSvc,
|
||||||
|
actions: actionSvc,
|
||||||
|
worklog: worklogSvc,
|
||||||
|
vault: abs,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = wails.Run(&options.App{
|
||||||
|
Title: "Верстак",
|
||||||
|
Width: 1280,
|
||||||
|
Height: 800,
|
||||||
|
MinWidth: 800,
|
||||||
|
MinHeight: 600,
|
||||||
|
BackgroundColour: &options.RGBA{R: 19, G: 19, B: 31, A: 1},
|
||||||
|
AssetServer: &assetserver.Options{
|
||||||
|
Assets: assets,
|
||||||
|
},
|
||||||
|
OnStartup: app.startup,
|
||||||
|
Bind: []interface{}{app},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
-9
@@ -21,20 +21,62 @@
|
|||||||
| 8 | FTS5 Search | ✅ выполнен |
|
| 8 | FTS5 Search | ✅ выполнен |
|
||||||
| 9 | Section assignment + Sidebar filtering | ✅ выполнен |
|
| 9 | Section assignment + Sidebar filtering | ✅ выполнен |
|
||||||
| 10 | Plugin Manager (discovery + templates) | ✅ выполнен |
|
| 10 | Plugin Manager (discovery + templates) | ✅ выполнен |
|
||||||
| 11 | **Wails Desktop GUI** | ⬜ не начат |
|
| 11 | **Wails Desktop GUI** | 🔄 Wails v2 vertical MVP |
|
||||||
| 12 | **Files/Folders full workflow** | ⬜ не начат |
|
| 12 | **Files/Folders full workflow** | ⬜ следующий этап после vertical MVP |
|
||||||
| 13 | **Drag-and-drop** | ⬜ не начат |
|
| 13 | **Drag-and-drop** | ⬜ не начат |
|
||||||
| 14 | **MVP stabilization** | ⬜ не начат |
|
| 14 | **MVP stabilization** | ⬜ не начат |
|
||||||
| 15 | Sync Server Skeleton | 🔒 приостановлен |
|
| 15 | Sync Server Skeleton | 🔒 PAUSED |
|
||||||
| 16 | Sync Client MVP | 🔒 приостановлен |
|
| 16 | Sync Client MVP | 🔒 PAUSED |
|
||||||
| 17 | Activity + File Scanner/Watcher | 🔒 приостановлен |
|
| 17 | Activity + File Scanner/Watcher | 🔒 PAUSED |
|
||||||
| 18 | TUI MVP (Bubble Tea) | 🔒 приостановлен |
|
| 18 | TUI MVP (Bubble Tea) | 🔒 PAUSED |
|
||||||
| 19 | Integrity Check + Repair | 🔒 приостановлен |
|
| 19 | Integrity Check + Repair | 🔒 PAUSED |
|
||||||
| 20 | Plugins: Lua runtime | 🔒 приостановлен |
|
| 20 | Plugins: Lua runtime | 🔒 PAUSED |
|
||||||
| 21 | DokuWiki Importer (plugin) | 🔒 приостановлен |
|
| 21 | DokuWiki Importer (plugin) | 🔒 PAUSED |
|
||||||
|
| 22 | Calendar/Kanban | 🔒 PAUSED |
|
||||||
|
| 23 | New templates/integrations | 🔒 PAUSED |
|
||||||
|
|
||||||
> 🔒 = **PAUSED** — не начинать до завершения шага 14 (MVP stabilization).
|
> 🔒 = **PAUSED** — не начинать до завершения шага 14 (MVP stabilization).
|
||||||
|
|
||||||
|
> **Wails v3 → v2 migration:** Wails v3 alpha.96 показал SIGSEGV на Linux desktop (GTK/X11). Wails v2 stable выбран как GUI base для MVP. Миграция в процессе (ветка `gui/migrate-wails-v2`).
|
||||||
|
|
||||||
|
**GUI Build (Wails v2):**
|
||||||
|
```bash
|
||||||
|
cd frontend && npm run build && cd ..
|
||||||
|
rm -rf cmd/verstak-gui/frontend-dist && cp -r frontend/dist cmd/verstak-gui/frontend-dist
|
||||||
|
go build -tags "gui production webkit2_41" -o verstak-gui ./cmd/verstak-gui
|
||||||
|
./verstak-gui
|
||||||
|
```
|
||||||
|
|
||||||
|
**GUI Build (Wails v2):**
|
||||||
|
```bash
|
||||||
|
cd frontend && npm run build && cd ..
|
||||||
|
rm -rf cmd/verstak-gui/frontend-dist && cp -r frontend/dist cmd/verstak-gui/frontend-dist
|
||||||
|
go build -tags "gui production webkit2_41" -o verstak-gui ./cmd/verstak-gui
|
||||||
|
./verstak-gui
|
||||||
|
```
|
||||||
|
|
||||||
|
Или для dev режима: `wails dev` (требует Wails v2 CLI)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Текущий этап: Wails v2 Vertical MVP
|
||||||
|
|
||||||
|
**Цель:** базовый рабочий desktop GUI для разделов → дел → заметок.
|
||||||
|
|
||||||
|
**Прогресс:**
|
||||||
|
- ✅ Wails v2 shell (window opens, no SIGSEGV)
|
||||||
|
- ✅ Layout fix (full viewport, dark theme, sidebar+main)
|
||||||
|
- 🔄 Notes bindings + UI
|
||||||
|
- 🔄 Tabs (Overview/Notes/Files/Actions/Worklog/Activity)
|
||||||
|
- 🔄 Node creation
|
||||||
|
- 🔄 Section filtering
|
||||||
|
|
||||||
|
**Пауза (не начинать до завершения vertical MVP):**
|
||||||
|
- Файлы/папки workflow
|
||||||
|
- Drag-and-drop
|
||||||
|
- Sync, plugins, Lua, browser extension, TUI
|
||||||
|
- Новые шаблоны, DokuWiki importer
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Выполненные шаги (1-10)
|
## Выполненные шаги (1-10)
|
||||||
|
|||||||
+17
-7
@@ -1,14 +1,24 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/wails.png" />
|
<link rel="icon" type="image/svg+xml" href="/wails.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="stylesheet" href="/style.css" />
|
<title>Верстак</title>
|
||||||
<title>Wails + Svelte</title>
|
<style>
|
||||||
</head>
|
/* Critical reset — no white borders, full viewport */
|
||||||
<body>
|
html, body, #app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #13131f;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.js"></script>
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Generated
+850
-699
File diff suppressed because it is too large
Load Diff
@@ -5,16 +5,13 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build:dev": "vite build --minify false --mode development",
|
|
||||||
"build": "vite build --mode production",
|
"build": "vite build --mode production",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
"@wailsio/runtime": "latest"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||||
"svelte": "^5.46.4",
|
"svelte": "^4.2.19",
|
||||||
"vite": "^8.0.5"
|
"vite": "^5.4.21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+320
-5
@@ -1,10 +1,325 @@
|
|||||||
<script>
|
<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
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
try {
|
||||||
|
version = 'verstak-gui'
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectNode(node) {
|
||||||
|
selectedNode = node
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div style="display:flex;align-items:center;justify-content:center;height:100vh;background:#13131f;color:#e4e4ef;font-family:sans-serif">
|
<div class="app">
|
||||||
<div style="text-align:center">
|
<!-- Sidebar -->
|
||||||
<h1 style="font-size:28px;margin-bottom:8px">⚒ Верстак</h1>
|
<aside class="sidebar">
|
||||||
<p style="color:#8888a4">Wails desktop app — under construction</p>
|
<div class="sidebar-top">
|
||||||
|
<span class="logo">⚒</span>
|
||||||
|
<span class="app-name">Верстак</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<div class="nav-group">
|
||||||
|
<div class="nav-label">Разделы</div>
|
||||||
|
{#each sections as section}
|
||||||
|
<button class="nav-item {selectedSection === section.id ? 'selected' : ''}"
|
||||||
|
on:click={() => selectSection(section.id)}>
|
||||||
|
{section.label}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-group">
|
||||||
|
<div class="nav-label">Корневые дела</div>
|
||||||
|
{#each nodes as node}
|
||||||
|
<button class="nav-item {selectedNode && selectedNode.id === node.id ? 'selected' : ''}"
|
||||||
|
on:click={() => selectNode(node)}>
|
||||||
|
{node.title}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
{#if nodes.length === 0 && sections.length > 0}
|
||||||
|
<div class="nav-empty">Нет дел</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="sidebar-bottom">
|
||||||
|
<span class="version">{version}</span>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main area -->
|
||||||
|
<main class="main">
|
||||||
|
<!-- Header -->
|
||||||
|
<header class="header">
|
||||||
|
<div class="header-left">
|
||||||
|
{#if selectedNode}
|
||||||
|
<span class="crumb">{selectedNode.title}</span>
|
||||||
|
{:else if selectedSection}
|
||||||
|
<span class="crumb">{#each sections as section}{section.id === selectedSection ? section.label : ''}{/each}</span>
|
||||||
|
{:else}
|
||||||
|
<span class="crumb placeholder">Выберите раздел или дело</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<!-- Search placeholder -->
|
||||||
|
<div class="search-hint">Поиск...</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Error banner -->
|
||||||
|
{#if error}
|
||||||
|
<div class="error-banner">
|
||||||
|
Wails bindings: {error}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="content">
|
||||||
|
{#if selectedNode}
|
||||||
|
<div class="node-view">
|
||||||
|
<h2>{selectedNode.title}</h2>
|
||||||
|
<div class="node-meta">
|
||||||
|
<span>ID: {selectedNode.id}</span>
|
||||||
|
<span>Type: {selectedNode.type}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else if sections.length > 0}
|
||||||
|
<div class="welcome">
|
||||||
|
<h2>Верстак</h2>
|
||||||
|
<p>Разделы: {sections.length} · Дел: {nodes.length}</p>
|
||||||
|
{#if error}
|
||||||
|
<p class="error-text">Go bindings не подключены: {error}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="loading">Загрузка...</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Reset */
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* App shell — full viewport */
|
||||||
|
.app {
|
||||||
|
display: flex;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #13131f;
|
||||||
|
color: #e4e4ef;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== SIDEBAR ===== */
|
||||||
|
.sidebar {
|
||||||
|
width: 260px;
|
||||||
|
min-width: 200px;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #1a1a28;
|
||||||
|
border-right: 1px solid #2a2a3c;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-top {
|
||||||
|
padding: 16px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
border-bottom: 1px solid #2a2a3c;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #e4e4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-label {
|
||||||
|
font-size: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: #666;
|
||||||
|
padding: 4px 20px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 20px;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #222233;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.selected {
|
||||||
|
background: #2a2a4a;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-empty {
|
||||||
|
padding: 8px 20px;
|
||||||
|
color: #555;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-bottom {
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-top: 1px solid #2a2a3c;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== MAIN AREA ===== */
|
||||||
|
.main {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #13131f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-bottom: 1px solid #2a2a3c;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crumb {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #e4e4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crumb.placeholder {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-hint {
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: #1e1e2e;
|
||||||
|
border: 1px solid #2a2a3c;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-banner {
|
||||||
|
background: #3a2222;
|
||||||
|
color: #ff8888;
|
||||||
|
padding: 8px 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #4a2222;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CONTENT ===== */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 300;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #8888a4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome p {
|
||||||
|
color: #666;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: #ff8888;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-view h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// Wails v2 API wrapper — single frontend access point to Go backend
|
||||||
|
|
||||||
|
function wailsCall(method, ...args) {
|
||||||
|
if (window.go && window.go.main && window.go.main.App) {
|
||||||
|
return window.go.main.App[method](...args)
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error('Wails bindings not loaded'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sections
|
||||||
|
export const listSections = () => wailsCall('ListSections')
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
export const listNodesBySection = (section) => wailsCall('ListNodesBySection', section)
|
||||||
|
export const listChildren = (parentID) => wailsCall('ListChildren', parentID)
|
||||||
|
export const getNodeDetail = (id) => wailsCall('GetNodeDetail', id)
|
||||||
|
export const createNode = (parentID, type, title, section) =>
|
||||||
|
wailsCall('CreateNode', parentID, type, title, section)
|
||||||
|
export const deleteNode = (id) => wailsCall('DeleteNode', id)
|
||||||
|
|
||||||
|
// Notes
|
||||||
|
export const listNotes = (nodeID) => wailsCall('ListNotes', nodeID)
|
||||||
|
export const createNote = (parentID, title) => wailsCall('CreateNote', parentID, title)
|
||||||
|
export const readNote = (noteID) => wailsCall('ReadNote', noteID)
|
||||||
|
export const saveNote = (noteID, content) => wailsCall('SaveNote', noteID, content)
|
||||||
|
|
||||||
|
// Files
|
||||||
|
export const listFiles = (nodeID) => wailsCall('ListFiles', nodeID)
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
export const listActions = (nodeID) => wailsCall('ListActions', nodeID)
|
||||||
|
export const runAction = (id) => wailsCall('RunAction', id)
|
||||||
|
|
||||||
|
// Worklog
|
||||||
|
export const listWorklog = (nodeID) => wailsCall('ListWorklog', nodeID)
|
||||||
|
export const createWorklog = (nodeID, summary, minutes) =>
|
||||||
|
wailsCall('CreateWorklog', nodeID, summary, minutes)
|
||||||
|
|
||||||
|
// Search
|
||||||
|
export const search = (query) => wailsCall('Search', query)
|
||||||
|
|
||||||
|
// System
|
||||||
|
export const verstakVersion = () => wailsCall('VerstakVersion')
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { mount } from 'svelte'
|
|
||||||
import App from './App.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 { defineConfig } from "vite";
|
||||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||||
import wails from "@wailsio/runtime/plugins/vite";
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
host: "127.0.0.1",
|
host: "127.0.0.1",
|
||||||
port: Number(process.env.WAILS_VITE_PORT) || 9245,
|
port: 3001,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
},
|
},
|
||||||
plugins: [svelte(), wails("./bindings")],
|
plugins: [svelte()],
|
||||||
|
build: {
|
||||||
|
outDir: "dist",
|
||||||
|
emptyOutDir: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,46 +3,38 @@ module verstak
|
|||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.2 // indirect
|
github.com/mattn/go-sqlite3 v1.14.44
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/wailsapp/wails/v2 v2.12.0
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
github.com/adrg/xdg v0.5.3 // indirect
|
)
|
||||||
github.com/bep/debounce v1.2.1 // indirect
|
|
||||||
github.com/cloudflare/circl v1.6.3 // indirect
|
require (
|
||||||
github.com/coder/websocket v1.8.14 // indirect
|
git.sr.ht/~jackmordaunt/go-toast/v2 v2.0.3 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
github.com/bep/debounce v1.2.1 // indirect
|
||||||
github.com/ebitengine/purego v0.9.1 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.9.0 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/go-git/go-git/v5 v5.19.1 // indirect
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/labstack/echo/v4 v4.13.3 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.2.2 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/leaanthony/gosod v1.0.4 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/leaanthony/slicer v1.6.0 // indirect
|
||||||
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 // indirect
|
github.com/leaanthony/u v1.1.1 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||||
github.com/leaanthony/u v1.1.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/lmittmann/tint v1.1.2 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/samber/lo v1.49.1 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.44 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.6.0 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
github.com/wailsapp/go-webview2 v1.0.22 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
github.com/samber/lo v1.52.0 // indirect
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
github.com/sergi/go-diff v1.4.0 // indirect
|
golang.org/x/net v0.35.0 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.2 // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.96 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
github.com/wailsapp/wails/webview2 v1.0.24 // indirect
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
|
||||||
golang.org/x/crypto v0.50.0 // indirect
|
|
||||||
golang.org/x/net v0.53.0 // indirect
|
|
||||||
golang.org/x/sys v0.43.0 // indirect
|
|
||||||
golang.org/x/text v0.37.0 // indirect
|
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,116 +1,92 @@
|
|||||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
git.sr.ht/~jackmordaunt/go-toast/v2 v2.0.3 h1:N3IGoHHp9pb6mj1cbXbuaSXV/UMKwmbKLf53nQmtqMA=
|
||||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
git.sr.ht/~jackmordaunt/go-toast/v2 v2.0.3/go.mod h1:QtOLZGz8olr4qH2vWK0QH0w0O4T9fEIjMuWpKUsH7nc=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
|
||||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
|
||||||
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
|
|
||||||
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
|
|
||||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
|
||||||
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
|
||||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
|
||||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
|
||||||
github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA=
|
|
||||||
github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
|
|
||||||
github.com/go-git/go-git/v5 v5.19.1 h1:nX27AnaU43/K5bKktKwgBmR9lawoYVe1Ckg0rgzzN00=
|
|
||||||
github.com/go-git/go-git/v5 v5.19.1/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ=
|
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 h1:njuLRcjAuMKr7kI3D85AXWkw6/+v9PwtV6M6o11sWHQ=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||||
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||||
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||||
|
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||||
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
|
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
|
||||||
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
||||||
|
github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI=
|
||||||
|
github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw=
|
||||||
|
github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
|
||||||
|
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
|
||||||
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
|
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
|
||||||
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||||
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
|
|
||||||
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
|
||||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8=
|
github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8=
|
||||||
github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
|
github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
|
||||||
github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
|
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||||
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
|
||||||
github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=
|
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
||||||
github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.96 h1:FmZdo4LiUkFUvz8rZO8f4nGLm5af9J+D3sr3Flset2g=
|
github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58=
|
||||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.96/go.mod h1:p1MUZwFPPQyx81cgejDvKIwU1+x/hndR+4z1uG5bw6s=
|
github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||||
github.com/wailsapp/wails/webview2 v1.0.24 h1:uULnjCSaRfMlU84mS3kjLgPsRosEOIusVK1nFOHZHzs=
|
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||||
github.com/wailsapp/wails/webview2 v1.0.24/go.mod h1:sdf+s0nAdxlzVWf9SCxC15XaxnQPJeY+uU1Ucn3jHQM=
|
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/wailsapp/wails/v2 v2.12.0 h1:BHO/kLNWFHYjCzucxbzAYZWUjub1Tvb4cSguQozHn5c=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/wailsapp/wails/v2 v2.12.0/go.mod h1:mo1bzK1DEJrobt7YrBjgxvb5Sihb1mhAY09hppbibQg=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
-73
@@ -1,73 +0,0 @@
|
|||||||
// This file is only compiled with -tags gui.
|
|
||||||
//go:build gui
|
|
||||||
// +build gui
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
_ "embed"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"verstak/internal/core/storage"
|
|
||||||
"verstak/internal/core/nodes"
|
|
||||||
"verstak/internal/core/files"
|
|
||||||
"verstak/internal/core/notes"
|
|
||||||
"verstak/internal/core/actions"
|
|
||||||
"verstak/internal/core/worklog"
|
|
||||||
"verstak/internal/core/search"
|
|
||||||
"verstak/internal/core/plugins"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v3/pkg/application"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed all:frontend/dist
|
|
||||||
var assets embed.FS
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
vaultPath := "."
|
|
||||||
if len(os.Args) > 1 {
|
|
||||||
vaultPath = os.Args[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
abs, err := filepath.Abs(vaultPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dbPath := filepath.Join(abs, ".verstak", "index.db")
|
|
||||||
db, err := storage.Open(dbPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Open vault: %v", err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
// Initialize core services (registered for Wails bindings).
|
|
||||||
_ = nodes.NewRepository(db)
|
|
||||||
_ = files.NewService(db, abs)
|
|
||||||
_ = notes.NewService(db, abs, nil, nil)
|
|
||||||
_ = actions.NewService(db)
|
|
||||||
_ = worklog.NewService(db)
|
|
||||||
_ = search.NewService(db)
|
|
||||||
plugins.NewManager(abs).Discover()
|
|
||||||
|
|
||||||
app := application.New(application.Options{
|
|
||||||
Name: "verstak",
|
|
||||||
Description: "Verstak — local-first working vault",
|
|
||||||
Assets: application.AssetOptions{
|
|
||||||
Handler: application.AssetFileServerFS(assets),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Window.NewWithOptions(application.WebviewWindowOptions{
|
|
||||||
Title: "Верстак",
|
|
||||||
Width: 1200,
|
|
||||||
Height: 800,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := app.Run(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"verstak/internal/core/nodes"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WailsService exposes core methods to the Wails frontend.
|
|
||||||
type WailsService struct{}
|
|
||||||
|
|
||||||
// ListRootNodes returns root-level nodes.
|
|
||||||
func (s *WailsService) ListRootNodes(ctx context.Context) string {
|
|
||||||
// This is a stub — actual implementation will use injected DB
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListChildren returns children of a node.
|
|
||||||
func (s *WailsService) ListChildren(ctx context.Context, parentID string) string {
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateNode creates a new node.
|
|
||||||
func (s *WailsService) CreateNode(ctx context.Context, parentID, nodeType, title, section string) string {
|
|
||||||
return "{}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListFiles returns files for a node.
|
|
||||||
func (s *WailsService) ListFiles(ctx context.Context, nodeID string) string {
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListActions returns actions for a node.
|
|
||||||
func (s *WailsService) ListActions(ctx context.Context, nodeID string) string {
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListWorklog returns worklog entries for a node.
|
|
||||||
func (s *WailsService) ListWorklog(ctx context.Context, nodeID string) string {
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search performs a search query.
|
|
||||||
func (s *WailsService) Search(ctx context.Context, query string) string {
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListTemplates returns available templates.
|
|
||||||
func (s *WailsService) ListTemplates(ctx context.Context) string {
|
|
||||||
return "[]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListSections returns available sections.
|
|
||||||
func (s *WailsService) ListSections(ctx context.Context) string {
|
|
||||||
sections := []map[string]string{
|
|
||||||
{"id": "today", "label": "Сегодня"},
|
|
||||||
{"id": "inbox", "label": "Неразобранное"},
|
|
||||||
{"id": "clients", "label": "Клиенты"},
|
|
||||||
{"id": "projects", "label": "Проекты"},
|
|
||||||
{"id": "recipes", "label": "Рецепты"},
|
|
||||||
{"id": "documents", "label": "Документы"},
|
|
||||||
{"id": "archive", "label": "Архив"},
|
|
||||||
}
|
|
||||||
data, _ := json.Marshal(sections)
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCurrentSelection returns current selection state.
|
|
||||||
func (s *WailsService) GetCurrentSelection(ctx context.Context) string {
|
|
||||||
sel := map[string]string{"kind": "section", "section": "today"}
|
|
||||||
data, _ := json.Marshal(sel)
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFile opens a file with the system application.
|
|
||||||
func (s *WailsService) OpenFile(ctx context.Context, fileID string) string {
|
|
||||||
return fmt.Sprintf("opened file %s", fileID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFolder opens a folder in the system file manager.
|
|
||||||
func (s *WailsService) OpenFolder(ctx context.Context, nodeID string) string {
|
|
||||||
return fmt.Sprintf("opened folder %s", nodeID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Silence unused import.
|
|
||||||
var _ = nodes.TypeCase
|
|
||||||
Reference in New Issue
Block a user