Files
MujicaUI/examples/gallery/app.go
T

169 lines
4.9 KiB
Go

package main
import (
"fmt"
"log/slog"
"time"
"github.com/egoist/mygo/ui"
mujica "mujicaui"
"mujicaui/icons"
"mujicaui/theme"
)
// event is one line of the gallery's event log.
type event struct {
at time.Time
page string
text string
}
type gallery struct {
pages []page
byID map[string]int
selected string
query string
mode int
density int
zh bool
folded bool
autoFold bool
palette bool
events []event
scrolls map[string]*ui.ScrollState
overture overtureState
// Composition state lives here so it survives page switches.
cSettings settingsDemo
cFiles filesDemo
cForm formSubmitDemo
}
// densities maps the density control's segments to theme densities.
var densities = []theme.Density{theme.Compact, theme.Default, theme.Comfortable}
func newGallery() *gallery {
g := &gallery{pages: catalog(), byID: map[string]int{}, selected: overtureID, density: 1, scrolls: map[string]*ui.ScrollState{},
cSettings: newSettingsDemo(), cFiles: newFilesDemo(), cForm: newFormSubmitDemo()}
for i, p := range g.pages {
if _, dup := g.byID[p.ID]; dup {
panic("gallery: duplicate page " + p.ID)
}
g.byID[p.ID] = i
}
return g
}
// logFor returns the event logger of one page.
func (g *gallery) logFor(id string) func(string) {
return func(s string) {
g.events = append(g.events, event{time.Now(), id, s})
if len(g.events) > 200 {
g.events = g.events[len(g.events)-200:]
}
slog.Info("gallery: event", "page", id, "event", s)
}
}
func (g *gallery) settings() mujica.Settings {
s := mujica.Settings{Mode: mujica.Mode(g.mode), Density: densities[g.density], Locale: mujica.EnUS}
if g.zh {
s.Locale = mujica.ZhCN
}
return s
}
func (g *gallery) view(c *ui.Context) {
mujica.Use(c, g.settings())
w, _ := c.Size()
if narrow := w < 900; narrow != g.autoFold {
g.autoFold, g.folded = narrow, narrow
}
scroll := g.scrolls[g.selected]
if scroll == nil {
scroll = &ui.ScrollState{}
g.scrolls[g.selected] = scroll
}
mujica.AppShell(c, &g.folded, mujica.AppShellOptions{
TitleBar: func() { g.titleBar(c) },
Sidebar: func() { g.sidebar(c) },
Content: func() { g.content(c) },
StatusBar: func() { g.statusBar(c) },
ContentScroll: scroll,
})
g.commandPalette(c)
mujica.Toaster(c)
}
func (g *gallery) titleBar(c *ui.Context) {
mujica.TitleBar(c, "MujicaUI", mujica.TitleBarOptions{Trailing: func() {
ui.Row(c).Gap(8).AlignItems(ui.Center).Children(func() {
mode := g.mode
if mujica.SegmentedControl(c, &g.mode, []mujica.Segment{
{Label: g.t("System", "跟随系统"), Icon: icons.Must("settings"), HideLabel: true},
{Label: g.t("Light", "浅色"), Icon: icons.Must("sun"), HideLabel: true},
{Label: g.t("Dark", "深色"), Icon: icons.Must("moon"), HideLabel: true},
}, mujica.SegmentedControlOptions{Label: g.t("Theme", "主题")}).Changed() && mode != g.mode {
g.logFor("shell")("theme " + mujica.Mode(g.mode).String())
g.overture.switches++
}
density := g.density
if mujica.SegmentedControl(c, &g.density, []mujica.Segment{
{Label: g.t("Compact", "紧凑")}, {Label: g.t("Default", "默认")}, {Label: g.t("Comfortable", "宽松")},
}, mujica.SegmentedControlOptions{Label: g.t("Density", "密度")}).Changed() && density != g.density {
g.logFor("shell")("density " + densities[g.density].String())
g.overture.switches++
}
if mujica.Button(c, g.t("中文", "English"), mujica.ButtonOptions{Variant: mujica.Ghost}).Clicked() {
g.zh = !g.zh
g.logFor("shell")(fmt.Sprintf("locale %s", g.settings().Locale))
}
if mujica.IconButton(c, icons.Must("command"), g.t("Command palette", "命令面板"), mujica.IconButtonOptions{Variant: mujica.Ghost}).Clicked() {
g.palette = true
}
})
}})
}
func (g *gallery) statusBar(c *ui.Context) {
left := []mujica.StatusItem{
{ID: "count", Text: fmt.Sprintf(g.t("%d components", "%d 个组件"), len(g.pages)), Icon: icons.Must("layout-grid")},
{ID: "look", Text: fmt.Sprintf("%s · %s", mujica.Mode(g.mode), densities[g.density]), Secondary: true},
}
var right []mujica.StatusItem
if n := len(g.events); n > 0 {
e := g.events[n-1]
right = append(right, mujica.StatusItem{ID: "last", Text: e.page + " · " + e.text, Icon: icons.Must("bell"), Secondary: true})
}
mujica.StatusBar(c, mujica.StatusBarOptions{Left: left, Right: right})
}
func (g *gallery) content(c *ui.Context) {
ui.Box(c).Key(g.selected).FillWidth().Children(func() {
switch g.selected {
case overtureID:
g.overturePage(c)
case settingsID:
g.compositePage(c, settingsID, g.settingsView)
case filesID:
g.compositePage(c, filesID, g.filesView)
case formID:
g.compositePage(c, formID, g.formView)
default:
i, ok := g.byID[g.selected]
if !ok {
panic("gallery: no page " + g.selected)
}
g.componentPage(c, g.pages[i])
}
})
}
// t picks the English or Chinese copy for the gallery's own text.
func (g *gallery) t(en, zh string) string {
if g.zh {
return zh
}
return en
}