Merge branch 'worktree-agent-ad7403b5194d75449'

This commit is contained in:
ZacharyZhang-NY committed 2026-10-05 14:38:04 -04:00
commit 009b2bfaf4
110 files changed
+7707 -1

No files matched your search

+44 -1
View File
@@ -1,3 +1,46 @@
package main
var calendarPages = []page{}
const calCategory = "Calendar"
var calendarPages = []page{
{ID: "421", Name: "CalendarMonthView", ZhName: "月视图", Category: calCategory, Demo: calMonthDemo, Code: calCalendarMonthViewCode,
Keys: "Tab reaches day numbers and event chips; arrows move between them; Enter opens; Alt+Left/Right moves an event a day, Alt+Up/Down a week; Escape closes the +N list."},
{ID: "422", Name: "CalendarWeekView", ZhName: "周视图", Category: calCategory, Demo: calWeekDemo, Code: calCalendarWeekViewCode,
Keys: "Tab reaches a day column; Up/Down move the slot cursor, Enter creates a one-slot event; on a chip Alt+Up/Down moves by a slot, Alt+Left/Right by a day, Alt+Shift+Up/Down resizes."},
{ID: "423", Name: "CalendarDayView", ZhName: "日视图", Category: calCategory, Demo: calDayDemo, Code: calCalendarDayViewCode,
Keys: "As the week view: Up/Down and Enter in the column, Alt with arrows on a chip."},
{ID: "424", Name: "AgendaView", ZhName: "日程列表", Category: calCategory, Demo: calAgendaDemo, Code: calAgendaViewCode,
Keys: "Tab enters the list; Up/Down move between events; Enter opens."},
{ID: "425", Name: "YearView", ZhName: "年视图", Category: calCategory, Demo: calYearDemo, Code: calYearViewCode,
Keys: "Tab enters the days; arrows move by day and week, PageUp/PageDown by month, across years; Enter chooses."},
{ID: "426", Name: "EventChip", ZhName: "事件块", Category: calCategory, Demo: calChipDemo, Code: calEventChipCode,
Keys: "Tab focuses the chip; Enter or Space activates it."},
{ID: "427", Name: "EventEditor", ZhName: "事件编辑器", Category: calCategory, Demo: calEditorDemo, Code: calEventEditorCode,
Keys: "Tab moves through the fields; each field keeps its own keys; Save and Cancel are buttons."},
{ID: "428", Name: "EventPopover", ZhName: "事件浮层", Category: calCategory, Demo: calPopoverDemo, Code: calEventPopoverCode,
Keys: "Enter on the chip opens it; Tab reaches Close, Delete and Edit; Escape closes."},
{ID: "429", Name: "CurrentTimeIndicator", ZhName: "当前时间线", Category: calCategory, Demo: calNowDemo, Code: calCurrentTimeIndicatorCode,
Keys: "Not focusable; screen readers read the time from its label."},
{ID: "430", Name: "RecurrenceEditor", ZhName: "重复规则编辑器", Category: calCategory, Demo: calRecurrenceDemo, Code: calRecurrenceEditorCode,
Keys: "Tab moves between the repeat select, interval, weekdays and end choices; each control keeps its own keys."},
{ID: "431", Name: "AvailabilityPicker", ZhName: "空闲时段选择", Category: calCategory, Demo: calAvailabilityDemo, Code: calAvailabilityPickerCode,
Keys: "Tab focuses the grid; arrows move the cursor; Space or Enter toggles the slot."},
{ID: "432", Name: "TimezoneSelect", ZhName: "时区选择", Category: calCategory, Demo: calTimezoneDemo, Code: calTimezoneSelectCode,
Keys: "Enter, Space or Down opens; type to search; Up/Down move; Enter chooses; Escape closes."},
{ID: "433", Name: "ReminderPicker", ZhName: "提醒选择", Category: calCategory, Demo: calReminderDemo, Code: calReminderPickerCode,
Keys: "Tab enters the list; Up/Down move; Space toggles."},
{ID: "434", Name: "AttendeeList", ZhName: "参与者列表", Category: calCategory, Demo: calAttendeeDemo, Code: calAttendeeListCode,
Keys: "Tab reaches each remove button; Enter removes."},
{ID: "435", Name: "WeekPicker", ZhName: "周选择器", Category: calCategory, Demo: calWeekPickerDemo, Code: calWeekPickerCode,
Keys: "Enter, Space or Down opens; arrows move; Enter picks the week; Escape closes."},
{ID: "436", Name: "DurationPicker", ZhName: "时长选择器", Category: calCategory, Demo: calDurationDemo, Code: calDurationPickerCode,
Keys: "Tab moves between hours, minutes and seconds; Up/Down step; type digits and Enter."},
{ID: "437", Name: "CronEditor", ZhName: "Cron 编辑器", Category: calCategory, Demo: calCronDemo, Code: calCronEditorCode,
Keys: "Type in the expression field; errors and the next runs update as you type."},
{ID: "438", Name: "RelativeTime", ZhName: "相对时间", Category: calCategory, Demo: calRelativeDemo, Code: calRelativeTimeCode,
Keys: "Not focusable; the exact time is in its label and tooltip."},
{ID: "439", Name: "Countdown", ZhName: "倒计时", Category: calCategory, Demo: calCountdownDemo, Code: calCountdownCode,
Keys: "Not focusable; reaching zero is announced."},
{ID: "440", Name: "Stopwatch", ZhName: "秒表", Category: calCategory, Demo: calStopwatchDemo, Code: calStopwatchCode,
Keys: "Tab reaches Start/Pause, Lap and Reset; Enter or Space presses."},
}
+253
View File
@@ -0,0 +1,253 @@
package main
// Code snippets mirror example_calendar_test.go.
const (
calCalendarMonthViewCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
events := exampleEvents(loc)
month := mujica.YearMonth{Year: 2026, Month: time.October}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
r := mujica.CalendarMonthView(c, &month, events, mujica.CalendarMonthViewOptions{Location: loc})
if ch, ok := r.Changed(); ok {
fmt.Println("move", ch.ID, "to", ch.Start)
}
}
ui.Render(view, 400, 300, 1)`
calCalendarWeekViewCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
events := exampleEvents(loc)
week := mujica.Date{Year: 2026, Month: time.October, Day: 14}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
r := mujica.CalendarWeekView(c, &week, events, mujica.CalendarWeekViewOptions{Location: loc, SlotMinutes: 15})
if ch, ok := r.Changed(); ok && ch.Kind == mujica.CalendarCreate {
fmt.Println("new event", ch.Start, ch.End)
}
}
ui.Render(view, 400, 300, 1)`
calCalendarDayViewCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
events := exampleEvents(loc)
day := mujica.Date{Year: 2026, Month: time.October, Day: 14}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if id, ok := mujica.CalendarDayView(c, &day, events, mujica.CalendarDayViewOptions{Location: loc}).Opened(); ok {
fmt.Println("open", id)
}
}
ui.Render(view, 400, 300, 1)`
calAgendaViewCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
events := exampleEvents(loc)
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
opts := mujica.AgendaViewOptions{Location: loc, From: mujica.Date{Year: 2026, Month: time.October, Day: 12}, Days: 14}
if id, ok := mujica.AgendaView(c, events, opts).Opened(); ok {
fmt.Println("open", id)
}
}
ui.Render(view, 400, 300, 1)`
calYearViewCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
events := exampleEvents(loc)
year := 2026
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if day, ok := mujica.YearView(c, &year, events, mujica.YearViewOptions{Location: loc}).DayChosen(); ok {
fmt.Println("go to", day)
}
}
ui.Render(view, 400, 300, 1)`
calEventChipCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
ev := exampleEvents(loc)[0]
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.EventChip(c, ev, mujica.EventChipOptions{Location: loc}).Clicked() {
fmt.Println("open", ev.ID)
}
}
ui.Render(view, 400, 300, 1)`
calEventEditorCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
ev := exampleEvents(loc)[0]
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
r := mujica.EventEditor(c, &ev, mujica.EventEditorOptions{Location: loc})
if r.Saved() {
fmt.Println("saved", ev.Title, ev.Start)
}
}
ui.Render(view, 400, 300, 1)`
calEventPopoverCode = `func exampleEvents(loc *time.Location) []mujica.CalendarEvent {
start := time.Date(2026, time.October, 14, 9, 0, 0, 0, loc)
return []mujica.CalendarEvent{
{ID: "rehearsal", Title: "Rehearsal", Start: start, End: start.Add(2 * time.Hour), Location: "Hall"},
{ID: "fitting", Title: "Fitting", Start: start.Add(time.Hour), End: start.Add(90 * time.Minute), Color: mujica.EventInfo},
}
}
loc := time.Local
ev := exampleEvents(loc)[0]
open := false
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
chip := mujica.EventChip(c, ev, mujica.EventChipOptions{Location: loc})
if chip.Clicked() {
open = true
}
r := mujica.EventPopover(c, chip, &open, ev, mujica.EventPopoverOptions{Location: loc})
if r.Delete() {
fmt.Println("delete", ev.ID)
}
}
ui.Render(view, 400, 300, 1)`
calCurrentTimeIndicatorCode = `view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
ui.Box(c).Size(200, 240).Children(func() {
mujica.CurrentTimeIndicator(c, mujica.CurrentTimeIndicatorOptions{Location: time.Local})
})
}
ui.Render(view, 400, 300, 1)`
calRecurrenceEditorCode = `rule := mujica.Recurrence{Unit: mujica.RepeatWeekly, Interval: 1, Weekdays: []time.Weekday{time.Monday}}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
r := mujica.RecurrenceEditor(c, &rule, mujica.RecurrenceEditorOptions{Start: mujica.Date{Year: 2026, Month: time.October, Day: 5}})
if r.Changed() && r.Problem() == "" {
fmt.Println(mujica.RecurrenceSummary(c, rule))
}
}
ui.Render(view, 400, 300, 1)`
calAvailabilityPickerCode = `days := []mujica.Date{{Year: 2026, Month: time.October, Day: 12}, {Year: 2026, Month: time.October, Day: 13}}
mine := [][]bool{make([]bool, 18), make([]bool, 18)}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.AvailabilityPicker(c, &mine, mujica.AvailabilityPickerOptions{Days: days}).Changed() {
fmt.Println("availability changed")
}
}
ui.Render(view, 400, 300, 1)`
calTimezoneSelectCode = `zone := "Asia/Shanghai"
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.TimezoneSelect(c, &zone, mujica.TimezoneSelectOptions{}).Changed() {
fmt.Println("zone", zone)
}
}
ui.Render(view, 400, 300, 1)`
calReminderPickerCode = `reminders := []time.Duration{15 * time.Minute}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.ReminderPicker(c, &reminders, mujica.ReminderPickerOptions{Max: 3}).Changed() {
fmt.Println("reminders", reminders)
}
}
ui.Render(view, 400, 300, 1)`
calAttendeeListCode = `people := []mujica.Attendee{{Name: "Sakiko", Status: mujica.AttendeeAccepted, Organizer: true}, {Name: "Mutsumi"}}
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if i, ok := mujica.AttendeeList(c, people, mujica.AttendeeListOptions{Removable: true}).Removed(); ok {
people = append(people[:i], people[i+1:]...)
}
}
ui.Render(view, 400, 300, 1)`
calWeekPickerCode = `var week mujica.Date
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.WeekPicker(c, &week, mujica.WeekPickerOptions{WeekStart: mujica.WeekStartMonday, Clearable: true}).Changed() {
fmt.Println("week of", week)
}
}
ui.Render(view, 400, 300, 1)`
calDurationPickerCode = `length := 90 * time.Minute
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
opts := mujica.DurationPickerOptions{Min: 15 * time.Minute, Max: 8 * time.Hour}
if mujica.DurationPicker(c, &length, opts).Changed() {
fmt.Println("length", length)
}
}
ui.Render(view, 400, 300, 1)`
calCronEditorCode = `expr := "0 9 * * MON-FRI"
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.CronEditor(c, &expr, mujica.CronEditorOptions{Location: time.Local}).Changed() {
if _, err := mujica.ParseCron(expr); err == nil {
fmt.Println("schedule", expr)
}
}
}
ui.Render(view, 400, 300, 1)`
calRelativeTimeCode = `posted := time.Date(2026, time.October, 5, 9, 0, 0, 0, time.Local)
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
mujica.RelativeTime(c, posted, mujica.RelativeTimeOptions{Location: time.Local})
}
ui.Render(view, 400, 300, 1)`
calCountdownCode = `deadline := time.Date(2026, time.December, 31, 23, 59, 59, 0, time.Local)
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.Countdown(c, deadline, mujica.CountdownOptions{}).Finished() {
fmt.Println("happy new year")
}
}
ui.Render(view, 400, 300, 1)`
calStopwatchCode = `var sw mujica.StopwatchState
view := func(c *ui.Context) {
mujica.Use(c, mujica.Settings{})
if mujica.Stopwatch(c, &sw, mujica.StopwatchOptions{}).Changed() {
fmt.Println("laps", len(sw.Laps))
}
}
ui.Render(view, 400, 300, 1)`
)
+217
View File
@@ -0,0 +1,217 @@
package main
import (
"fmt"
"strings"
"time"
"github.com/egoist/mygo/ui"
mujica "mujicaui"
)
var calColors = []string{"Accent", "Info", "Success", "Warning", "Danger", "Neutral"}
func calChipDemo(c *ui.Context, log func(string)) {
type state struct {
color string
inline, selected, disabled bool
}
s := ui.Local(c.Root(), "426", func() state { return state{color: "Accent"} })
dtSection(c, "EventChip", func() {
dtControls(c, func() {
mujica.Select(c, &s.color, calOptions(calColors), mujica.SelectOptions{Label: "Color"})
mujica.Checkbox(c, &s.inline, "Inline", mujica.CheckboxOptions{})
mujica.Checkbox(c, &s.selected, "Selected", mujica.CheckboxOptions{})
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
ev := calSample()[0]
for i, n := range calColors {
if n == s.color {
ev.Color = mujica.EventColor(i)
}
}
ui.Box(c).Width(240).Children(func() {
if mujica.EventChip(c, ev, mujica.EventChipOptions{Location: time.Local, Inline: s.inline, Selected: s.selected, Disabled: s.disabled}).Clicked() {
log("clicked " + ev.Title)
}
})
})
}
func calEditorDemo(c *ui.Context, log func(string)) {
type state struct {
ev mujica.CalendarEvent
disabled bool
}
s := ui.Local(c.Root(), "427", func() state { return state{ev: calSample()[0]} })
dtSection(c, "EventEditor", func() {
dtControls(c, func() { mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{}) })
r := mujica.EventEditor(c, &s.ev, mujica.EventEditorOptions{Location: time.Local, Disabled: s.disabled})
if r.Saved() {
log(fmt.Sprintf("saved %q %s, %d guests", s.ev.Title, s.ev.Start.Format("Jan 2 15:04"), len(s.ev.Attendees)))
}
if r.Canceled() {
log("canceled")
}
})
}
func calPopoverDemo(c *ui.Context, log func(string)) {
type state struct {
open, readOnly, disabled bool
}
s := ui.Local(c.Root(), "428", func() state { return state{} })
dtSection(c, "EventPopover", func() {
dtControls(c, func() {
mujica.Checkbox(c, &s.readOnly, "Read-only", mujica.CheckboxOptions{})
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
ev := calSample()[0]
ev.Attendees = []mujica.Attendee{{Name: "Sakiko", Status: mujica.AttendeeAccepted, Organizer: true}, {Name: "Mutsumi"}}
ev.Reminders = []time.Duration{15 * time.Minute}
ui.Box(c).Width(240).Children(func() {
chip := mujica.EventChip(c, ev, mujica.EventChipOptions{Location: time.Local, Disabled: s.disabled})
if chip.Clicked() {
s.open = true
log("opened popover")
}
r := mujica.EventPopover(c, chip, &s.open, ev, mujica.EventPopoverOptions{Location: time.Local, ReadOnly: s.readOnly, Disabled: s.disabled})
if r.Edit() {
log("edit " + ev.ID)
}
if r.Delete() {
log("delete " + ev.ID)
}
})
})
}
func calNowDemo(c *ui.Context, log func(string)) {
dtSection(c, "CurrentTimeIndicator", func() {
k := mujica.Tokens(c)
ui.Box(c).Size(320, 240).Border(1, k.Border).Children(func() {
mujica.CurrentTimeIndicator(c, mujica.CurrentTimeIndicatorOptions{Location: time.Local})
})
})
}
func calRecurrenceDemo(c *ui.Context, log func(string)) {
type state struct {
rule mujica.Recurrence
disabled bool
}
s := ui.Local(c.Root(), "430", func() state { return state{} })
dtSection(c, "RecurrenceEditor", func() {
dtControls(c, func() { mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{}) })
r := mujica.RecurrenceEditor(c, &s.rule, mujica.RecurrenceEditorOptions{Start: mujica.DateOf(time.Now()), Disabled: s.disabled})
if r.Changed() {
log(mujica.RecurrenceSummary(c, s.rule) + strings.TrimSpace(" "+r.Problem()))
}
})
}
func calAvailabilityDemo(c *ui.Context, log func(string)) {
type state struct {
mine, theirs [][]bool
days []mujica.Date
others, frozen bool
}
s := ui.Local(c.Root(), "431", func() state {
today := mujica.DateOf(time.Now())
grid := func(seed int) [][]bool {
g := make([][]bool, 5)
for i := range g {
g[i] = make([]bool, 18)
for j := range g[i] {
g[i][j] = (i*7+j*3+seed)%4 == 0
}
}
return g
}
days := []mujica.Date{today, today.AddDays(1), today.AddDays(2), today.AddDays(3), today.AddDays(4)}
return state{mine: grid(2), theirs: grid(1), days: days, others: true}
})
dtSection(c, "AvailabilityPicker", func() {
dtControls(c, func() {
mujica.Checkbox(c, &s.others, "Show Mutsumi", mujica.CheckboxOptions{})
mujica.Checkbox(c, &s.frozen, "Disabled", mujica.CheckboxOptions{})
})
var others []mujica.AvailabilityPerson
if s.others {
others = []mujica.AvailabilityPerson{{Name: "Mutsumi", Free: s.theirs}}
}
if mujica.AvailabilityPicker(c, &s.mine, mujica.AvailabilityPickerOptions{Days: s.days, Others: others, Disabled: s.frozen}).Changed() {
n := 0
for _, d := range s.mine {
for _, v := range d {
if v {
n++
}
}
}
log(fmt.Sprintf("%d free slots", n))
}
})
}
func calTimezoneDemo(c *ui.Context, log func(string)) {
type state struct {
zone string
disabled bool
}
s := ui.Local(c.Root(), "432", func() state { return state{zone: "Asia/Shanghai"} })
dtSection(c, "TimezoneSelect", func() {
dtControls(c, func() { mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{}) })
if mujica.TimezoneSelect(c, &s.zone, mujica.TimezoneSelectOptions{Disabled: s.disabled}).Changed() {
log("zone " + s.zone)
}
})
}
func calReminderDemo(c *ui.Context, log func(string)) {
type state struct {
v []time.Duration
max string
disabled bool
}
s := ui.Local(c.Root(), "433", func() state { return state{v: []time.Duration{15 * time.Minute}, max: "0"} })
dtSection(c, "ReminderPicker", func() {
dtControls(c, func() {
mujica.Select(c, &s.max, calOptions([]string{"0", "2", "3"}), mujica.SelectOptions{Label: "Max (0 = any)"})
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
if limit := calAtoi(s.max); limit > 0 && len(s.v) > limit {
s.v = s.v[:limit]
}
if mujica.ReminderPicker(c, &s.v, mujica.ReminderPickerOptions{Max: calAtoi(s.max), Disabled: s.disabled}).Changed() {
log(fmt.Sprint("reminders ", s.v))
}
})
}
func calAttendeeDemo(c *ui.Context, log func(string)) {
type state struct {
list []mujica.Attendee
removable bool
}
people := func() []mujica.Attendee {
return []mujica.Attendee{{Name: "Sakiko Togawa", Status: mujica.AttendeeAccepted, Organizer: true},
{Name: "Mutsumi Wakaba", Status: mujica.AttendeeTentative}, {Name: "Uika Misumi", Status: mujica.AttendeeDeclined},
{Name: "Nyamu Yuutenji", Email: "nyamu@example.com"}}
}
s := ui.Local(c.Root(), "434", func() state { return state{list: people(), removable: true} })
dtSection(c, "AttendeeList", func() {
dtControls(c, func() {
mujica.Checkbox(c, &s.removable, "Removable", mujica.CheckboxOptions{})
if mujica.Button(c, "Reset", mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() {
s.list = people()
log("reset")
}
})
if i, ok := mujica.AttendeeList(c, s.list, mujica.AttendeeListOptions{Removable: s.removable}).Removed(); ok {
log("removed " + s.list[i].Name)
s.list = append(s.list[:i:i], s.list[i+1:]...)
}
})
}
+128
View File
@@ -0,0 +1,128 @@
package main
import (
"time"
"github.com/egoist/mygo/ui"
mujica "mujicaui"
)
func calWeekPickerDemo(c *ui.Context, log func(string)) {
type state struct {
week mujica.Date
weekStart string
disabled bool
}
s := ui.Local(c.Root(), "435", func() state { return state{weekStart: "Locale"} })
dtSection(c, "WeekPicker", func() {
dtControls(c, func() {
if mujica.Select(c, &s.weekStart, calOptions(calWeekStarts), mujica.SelectOptions{Label: "Week start"}).Changed() {
s.week = mujica.Date{}
log("week start " + s.weekStart + ", value cleared")
}
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
opts := mujica.WeekPickerOptions{WeekStart: calWeekStart(s.weekStart), Clearable: true, Disabled: s.disabled}
if mujica.WeekPicker(c, &s.week, opts).Changed() {
log("week of " + s.week.String())
}
})
}
func calDurationDemo(c *ui.Context, log func(string)) {
type state struct {
v time.Duration
seconds, disabled bool
}
s := ui.Local(c.Root(), "436", func() state { return state{v: 90 * time.Minute} })
dtSection(c, "DurationPicker", func() {
dtControls(c, func() {
mujica.Checkbox(c, &s.seconds, "Seconds", mujica.CheckboxOptions{})
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
opts := mujica.DurationPickerOptions{Seconds: s.seconds, Min: 15 * time.Minute, Max: 8 * time.Hour, Disabled: s.disabled}
if mujica.DurationPicker(c, &s.v, opts).Changed() {
log("duration " + s.v.String())
}
})
}
func calCronDemo(c *ui.Context, log func(string)) {
type state struct {
expr string
disabled bool
}
s := ui.Local(c.Root(), "437", func() state { return state{expr: "*/15 9-17 * * MON-FRI"} })
dtSection(c, "CronEditor", func() {
dtControls(c, func() { mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{}) })
if mujica.CronEditor(c, &s.expr, mujica.CronEditorOptions{Location: time.Local, Disabled: s.disabled}).Changed() {
if _, err := mujica.ParseCron(s.expr); err != nil {
log("invalid: " + s.expr)
} else {
log("schedule " + s.expr)
}
}
})
}
func calRelativeDemo(c *ui.Context, log func(string)) {
type state struct{ at time.Time }
s := ui.Local(c.Root(), "438", func() state { return state{at: time.Now()} })
dtSection(c, "RelativeTime", func() {
dtControls(c, func() {
for _, b := range []struct {
label string
d time.Duration
}{{"Now", 0}, {"5 minutes ago", -5 * time.Minute}, {"In 3 hours", 3 * time.Hour}, {"40 days ago", -40 * 24 * time.Hour}} {
if mujica.Button(c, b.label, mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() {
s.at = time.Now().Add(b.d)
log("time set: " + b.label)
}
}
})
mujica.RelativeTime(c, s.at, mujica.RelativeTimeOptions{Location: time.Local})
})
}
func calCountdownDemo(c *ui.Context, log func(string)) {
type state struct {
deadline time.Time
words bool
}
s := ui.Local(c.Root(), "439", func() state { return state{deadline: time.Now().Add(10 * time.Second)} })
dtSection(c, "Countdown", func() {
dtControls(c, func() {
if mujica.Button(c, "Restart 10 s", mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() {
s.deadline = time.Now().Add(10 * time.Second)
log("restarted")
}
mujica.Checkbox(c, &s.words, "Words", mujica.CheckboxOptions{})
})
format := mujica.CountdownClock
if s.words {
format = mujica.CountdownWords
}
if mujica.Countdown(c, s.deadline, mujica.CountdownOptions{Format: format}).Finished() {
log("finished")
}
})
}
func calStopwatchDemo(c *ui.Context, log func(string)) {
type state struct {
sw mujica.StopwatchState
disabled bool
}
s := ui.Local(c.Root(), "440", func() state { return state{} })
dtSection(c, "Stopwatch", func() {
dtControls(c, func() { mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{}) })
if mujica.Stopwatch(c, &s.sw, mujica.StopwatchOptions{Disabled: s.disabled}).Changed() {
state := "paused"
if s.sw.Running() {
state = "running"
}
log(state + ", " + mujica.StopwatchText(s.sw.Elapsed(time.Now())))
}
})
}
+194
View File
@@ -0,0 +1,194 @@
package main
import (
"fmt"
"strconv"
"time"
"github.com/egoist/mygo/ui"
mujica "mujicaui"
)
// calSample is demo events around today in the local zone.
func calSample() []mujica.CalendarEvent {
now := time.Now()
day := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
at := func(d, h, m, mins int) (time.Time, time.Time) {
s := day.AddDate(0, 0, d).Add(time.Duration(h)*time.Hour + time.Duration(m)*time.Minute)
return s, s.Add(time.Duration(mins) * time.Minute)
}
mk := func(id, title string, color mujica.EventColor, d, h, m, mins int) mujica.CalendarEvent {
s, e := at(d, h, m, mins)
return mujica.CalendarEvent{ID: id, Title: title, Color: color, Start: s, End: e, Location: "Rehearsal hall"}
}
evs := []mujica.CalendarEvent{
mk("1", "Rehearsal", mujica.EventAccent, 0, 9, 0, 120), mk("2", "Costume fitting", mujica.EventInfo, 0, 10, 0, 60),
mk("3", "Lunch", mujica.EventSuccess, 0, 12, 30, 60), mk("4", "Lyrics review", mujica.EventWarning, 1, 14, 0, 90),
mk("5", "Press", mujica.EventDanger, 2, 16, 0, 45), mk("6", "Sound check", mujica.EventNeutral, 3, 18, 0, 60),
mk("7", "Encore notes", mujica.EventInfo, 0, 15, 0, 30), mk("8", "Stage walk", mujica.EventAccent, 0, 17, 0, 30),
}
holiday := mk("9", "Masquerade", mujica.EventAccent, 4, 0, 0, 24*60)
holiday.AllDay, holiday.Start = true, day.AddDate(0, 0, 4)
holiday.End = holiday.Start.AddDate(0, 0, 1)
return append(evs, holiday)
}
// calApply applies and logs a view change.
func calApply(evs *[]mujica.CalendarEvent, ch mujica.CalendarChange, log func(string)) {
switch ch.Kind {
case mujica.CalendarCreate:
id := fmt.Sprint(len(*evs) + 100)
*evs = append(*evs, mujica.CalendarEvent{ID: id, Title: "New event", Start: ch.Start, End: ch.End})
log("created " + ch.Start.Format("Jan 2 15:04") + " – " + ch.End.Format("15:04"))
return
}
for i := range *evs {
if (*evs)[i].ID == ch.ID {
(*evs)[i].Start, (*evs)[i].End = ch.Start, ch.End
}
}
verb := "moved"
if ch.Kind == mujica.CalendarResize {
verb = "resized"
}
log(fmt.Sprintf("%s %s to %s – %s", verb, ch.ID, ch.Start.Format("Jan 2 15:04"), ch.End.Format("15:04")))
}
// calViewResult logs what a view reported and applies its change.
func calViewResult(r mujica.CalendarViewResult, evs *[]mujica.CalendarEvent, version *int, log func(string)) {
if id, ok := r.Opened(); ok {
log("opened " + id)
}
if d, ok := r.DayChosen(); ok {
log("day " + d.String())
}
if ch, ok := r.Changed(); ok {
calApply(evs, ch, log)
*version++
}
}
var calWeekStarts = []string{"Locale", "Sunday", "Monday", "Saturday"}
func calWeekStart(s string) mujica.WeekStart {
for i, n := range calWeekStarts {
if n == s {
return mujica.WeekStart(i)
}
}
panic("gallery: unknown week start " + s)
}
func calMonthDemo(c *ui.Context, log func(string)) {
type state struct {
month mujica.YearMonth
events []mujica.CalendarEvent
version, maxRows int
weekStart, maxStr string
disabled bool
}
s := ui.Local(c.Root(), "421", func() state {
now := time.Now()
return state{month: mujica.YearMonth{Year: now.Year(), Month: now.Month()}, events: calSample(), weekStart: "Locale", maxStr: "3"}
})
dtSection(c, "CalendarMonthView", func() {
dtControls(c, func() {
mujica.Select(c, &s.weekStart, calOptions(calWeekStarts), mujica.SelectOptions{Label: "Week start"})
mujica.Select(c, &s.maxStr, calOptions([]string{"1", "2", "3", "4"}), mujica.SelectOptions{Label: "Rows per day"})
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
s.maxRows = calAtoi(s.maxStr)
r := mujica.CalendarMonthView(c, &s.month, s.events, mujica.CalendarMonthViewOptions{Location: time.Local, Version: s.version,
WeekStart: calWeekStart(s.weekStart), MaxPerDay: s.maxRows, Disabled: s.disabled})
calViewResult(r, &s.events, &s.version, log)
})
}
func calWeekDemo(c *ui.Context, log func(string)) {
type state struct {
week mujica.Date
events []mujica.CalendarEvent
version int
slot string
hour12 bool
disabled bool
}
s := ui.Local(c.Root(), "422", func() state {
return state{week: mujica.DateOf(time.Now()), events: calSample(), slot: "30"}
})
dtSection(c, "CalendarWeekView", func() {
dtControls(c, func() {
mujica.Select(c, &s.slot, calOptions([]string{"15", "30", "60"}), mujica.SelectOptions{Label: "Slot minutes"})
mujica.Checkbox(c, &s.hour12, "12-hour", mujica.CheckboxOptions{})
mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{})
})
slot := calAtoi(s.slot)
r := mujica.CalendarWeekView(c, &s.week, s.events, mujica.CalendarWeekViewOptions{Location: time.Local, Version: s.version,
SlotMinutes: slot, Hour12: s.hour12, Disabled: s.disabled})
calViewResult(r, &s.events, &s.version, log)
})
}
func calDayDemo(c *ui.Context, log func(string)) {
type state struct {
day mujica.Date
events []mujica.CalendarEvent
version int
disabled bool
}
s := ui.Local(c.Root(), "423", func() state { return state{day: mujica.DateOf(time.Now()), events: calSample()} })
dtSection(c, "CalendarDayView", func() {
dtControls(c, func() { mujica.Checkbox(c, &s.disabled, "Disabled", mujica.CheckboxOptions{}) })
r := mujica.CalendarDayView(c, &s.day, s.events, mujica.CalendarDayViewOptions{Location: time.Local, Version: s.version, Disabled: s.disabled})
calViewResult(r, &s.events, &s.version, log)
})
}
func calAgendaDemo(c *ui.Context, log func(string)) {
type state struct {
events []mujica.CalendarEvent
days string
}
s := ui.Local(c.Root(), "424", func() state { return state{events: calSample(), days: "7"} })
dtSection(c, "AgendaView", func() {
dtControls(c, func() {
mujica.Select(c, &s.days, calOptions([]string{"1", "7", "30"}), mujica.SelectOptions{Label: "Days"})
})
days := calAtoi(s.days)
ui.Column(c).Height(420).Children(func() {
if id, ok := mujica.AgendaView(c, s.events, mujica.AgendaViewOptions{Location: time.Local, Days: days}).Opened(); ok {
log("opened " + id)
}
})
})
}
func calYearDemo(c *ui.Context, log func(string)) {
type state struct {
year int
events []mujica.CalendarEvent
}
s := ui.Local(c.Root(), "425", func() state { return state{year: time.Now().Year(), events: calSample()} })
dtSection(c, "YearView", func() {
if d, ok := mujica.YearView(c, &s.year, s.events, mujica.YearViewOptions{Location: time.Local}).DayChosen(); ok {
log("day " + d.String())
}
})
}
func calAtoi(s string) int {
n, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
return n
}
func calOptions(values []string) []mujica.SelectOption[string] {
out := make([]mujica.SelectOption[string], len(values))
for i, v := range values {
out[i] = mujica.SelectOption[string]{Value: v, Label: v}
}
return out
}