main bcc9a45

view.go RawHistoryFolder

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}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 12

↑↓ moveenter openesc close