1package main
2
3import (
4 "fmt"
5
6 "github.com/bnema/nefergui"
7)
8
9type Model struct {
10 Page, Name, Status string
11 Notes string
12 NewPending bool
13 DarkMode bool
14 Density string
15 Volume float64
16}
17
18func navButton(parent nefergui.Node, m *Model, label, page string) {
19 opts := []nefergui.ButtonOption{nefergui.Key(page), nefergui.Class("menu-item")}
20 if m.Page == page {
21 opts = append(opts, nefergui.Class("active"))
22 }
23 if parent.Button(label, opts...).Activated() {
24 m.Page = page
25 }
26}
27func home(parent nefergui.Node, m *Model) {
28 workspace := parent.Row(nefergui.Class("workspace"))
29 editor := workspace.Column(nefergui.Class("editor-pane"))
30 tab := editor.Row(nefergui.Class("pane-bar"))
31 tab.Text("Untitled.txt", nefergui.Class("document-title"))
32 tab.Spacer(nefergui.Class("stretch"))
33 tab.Text("Plain text", nefergui.Class("hint"))
34 if editor.Textarea("Document", &m.Notes, nefergui.Key("document"), nefergui.Class("document-editor"), nefergui.Placeholder("Start writing…")).Changed() {
35 m.NewPending = false
36 m.Status = "Unsaved changes · session only"
37 }
38 inspector := workspace.Aside(nefergui.Class("inspector"))
39 inspector.Text("PROPERTIES", nefergui.Class("eyebrow"))
40 inspector.Text("Author", nefergui.Class("field-label"))
41 inspector.Input("Author", &m.Name, nefergui.Key("name"), nefergui.Placeholder("Your name"))
42 if inspector.Button("Apply", nefergui.Key("continue"), nefergui.Disabled(m.Name == "")).Activated() {
43 m.Status = "Author set to " + m.Name + " · session only"
44 }
45 inspector.Separator()
46 inspector.Text("Interface density", nefergui.Class("field-label"))
47 for _, d := range []struct{ label, value string }{{"Comfortable", "comfortable"}, {"Compact", "compact"}} {
48 inspector.Radio(d.label, d.value, &m.Density, nefergui.Key(d.value))
49 }
50 inspector.Separator()
51 inspector.Slider(fmt.Sprintf("Volume %.0f %%", m.Volume), &m.Volume, 0, 100, 5, nefergui.Key("volume"))
52 inspector.Spacer(nefergui.Class("stretch"))
53 inspector.Text("Changes stay in this session.", nefergui.Class("hint"))
54}
55func settings(parent nefergui.Node, m *Model) {
56 bar := parent.Row(nefergui.Class("pane-bar"))
57 bar.Text("Preferences", nefergui.Class("document-title"))
58 pane := parent.Column(nefergui.Class("preferences-pane"))
59 pane.Text("Appearance", nefergui.Class("field-label"))
60 pane.Checkbox("Dark mode", &m.DarkMode, nefergui.Key("appearance"))
61 pane.Text("Rendering", nefergui.Class("field-label"))
62 pane.Text("Wayland · Vulkan · UTF-8", nefergui.Class("muted"))
63 pane.Text("Document properties are available in the editor's right pane.", nefergui.Class("hint"))
64}
65
66// requestNew arms confirmation without changing the document. A second request
67// discards it; editing or Cancel disarms the pending request.
68func (m *Model) requestNew() {
69 if m.Notes != "" && !m.NewPending {
70 m.NewPending = true
71 m.Status = "Click Discard & new to replace the current document"
72 return
73 }
74 m.Notes = ""
75 m.NewPending = false
76 m.Page = "home"
77 m.Status = "New document · session only"
78}
79
80func app(f *nefergui.Frame, m *Model) {
81 theme := "light"
82 if m.DarkMode {
83 theme = "dark"
84 }
85 root := f.Root(nefergui.Class("app"), nefergui.Class(theme), nefergui.Class(m.Density))
86 header := root.Header(nefergui.Class("header"))
87 header.Heading("NeferGUI", nefergui.Level(1), nefergui.Class("logo"))
88 newLabel := "New"
89 if m.NewPending {
90 newLabel = "Discard & new"
91 }
92 if header.Button(newLabel, nefergui.Key("new-document")).Activated() {
93 m.requestNew()
94 }
95 if m.NewPending && header.Button("Cancel", nefergui.Key("cancel-new")).Activated() {
96 m.NewPending = false
97 m.Status = "Ready"
98 }
99 header.Text("Untitled.txt", nefergui.Class("muted"))
100 header.Spacer(nefergui.Class("stretch"))
101 label := "Dark mode"
102 if m.DarkMode {
103 label = "Light mode"
104 }
105 if header.Button(label, nefergui.Key("dark-mode"), nefergui.Class("theme-toggle")).Activated() {
106 m.DarkMode = !m.DarkMode
107 }
108 body := root.Row(nefergui.Class("body"))
109 sidebar := body.Aside(nefergui.Class("sidebar"))
110 sidebar.Text("DOCUMENTS", nefergui.Class("eyebrow"))
111 menu := sidebar.Nav(nefergui.Class("menu"))
112 navButton(menu, m, "Untitled.txt", "home")
113 navButton(menu, m, "Preferences", "settings")
114 sidebar.Spacer(nefergui.Class("stretch"))
115 sidebar.Text("Local workspace", nefergui.Class("sidebar-note"))
116 sidebar.Text("1 document · in memory", nefergui.Class("hint"))
117 content := body.Main(nefergui.Class("content"))
118 switch m.Page {
119 case "home":
120 home(content, m)
121 case "settings":
122 settings(content, m)
123 }
124 footer := root.Footer(nefergui.Class("status-bar"))
125 footer.Text(m.Status)
126 footer.Spacer(nefergui.Class("stretch"))
127 footer.Text("UTF-8 • Plain text", nefergui.Class("hint"))
128}