Calendar: components 421-440
This commit is contained in:
110 files changed
+7335
-23
No files matched your search
@@ -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."},
|
||||
}
|
||||
@@ -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)`
|
||||
)
|
||||
@@ -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:]...)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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())))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user