Files
MujicaUI/examples/gallery/pages_files_collaboration.go
T

196 lines
6.5 KiB
Go

package main
import (
"fmt"
"time"
"github.com/egoist/mygo/ui"
mujica "mujicaui"
"mujicaui/theme"
)
var filesPeople = []mujica.Collaborator{
{ID: "a", Name: "Ada Lovelace"}, {ID: "b", Name: "Blaise Pascal", Away: true},
{ID: "c", Name: "Carl Gauss"}, {ID: "d", Name: "Dora Maar"}, {ID: "e", Name: "Emmy Noether"},
}
func presenceAvatarsDemo(c *ui.Context, log func(string)) {
type state struct {
following string
disabled, empty bool
max float64
}
s := ui.Local(c.Root(), "392", func() state { return state{max: 3} })
mediaCheck(c, log, &s.disabled, "Disabled")
mediaCheck(c, log, &s.empty, "Empty")
if mujica.NumberInput(c, &s.max, mujica.NumberInputOptions{Min: 1, Max: 5, Step: 1, Label: "Visible avatars"}).Changed() {
log(fmt.Sprintf("Visible: %.0f", s.max))
}
people := filesPeople
if s.empty {
people = nil
}
r := mujica.PresenceAvatars(c, people, mujica.PresenceAvatarsOptions{Following: s.following, Max: int(s.max), Disabled: s.disabled})
if r.Follow != "" {
s.following = r.Follow
log("Follow: " + r.Follow)
}
if r.Unfollow {
s.following = ""
log("Following stopped")
}
}
var filesReactionChoices = []string{"\U0001f44d", "\u2764\ufe0f", "\U0001f389", "\U0001f440", "\U0001f64f"}
func reactionsDemo(c *ui.Context, log func(string)) {
type state struct {
items []mujica.Reaction
disabled bool
}
s := ui.Local(c.Root(), "394", func() state {
return state{items: []mujica.Reaction{{Emoji: filesReactionChoices[0], Count: 3, Mine: true}, {Emoji: filesReactionChoices[2], Count: 1}}}
})
mediaCheck(c, log, &s.disabled, "Disabled")
if mujica.Button(c, "Clear reactions", mujica.ButtonOptions{}).Clicked() {
s.items = nil
log("Reactions cleared")
}
r := mujica.Reactions(c, s.items, mujica.ReactionsOptions{Choices: filesReactionChoices, Disabled: s.disabled})
emoji := r.Toggled
if emoji == "" {
emoji = r.Added
}
if emoji == "" {
return
}
for i := range s.items {
if s.items[i].Emoji == emoji {
if s.items[i].Mine {
s.items[i].Mine = false
s.items[i].Count--
} else {
s.items[i].Mine = true
s.items[i].Count++
}
if s.items[i].Count == 0 {
s.items = append(s.items[:i:i], s.items[i+1:]...)
}
log("Reaction toggled")
return
}
}
s.items = append(s.items, mujica.Reaction{Emoji: emoji, Count: 1, Mine: true})
log("Reaction added")
}
func shareDialogDemo(c *ui.Context, log func(string)) {
type state struct {
members []mujica.ShareMember
open, disabled bool
next int
}
s := ui.Local(c.Root(), "395", func() state {
return state{members: []mujica.ShareMember{
{ID: "owner", Name: "Ada Lovelace", Email: "ada@court.org", Owner: true, Permission: mujica.PermissionEdit},
{ID: "b", Name: "Blaise Pascal", Email: "blaise@court.org", Permission: mujica.PermissionView},
}}
})
mediaCheck(c, log, &s.disabled, "Disabled")
if mujica.Button(c, "Share Ledger", mujica.ButtonOptions{Disabled: s.disabled}).Clicked() {
s.open = true
log("Share dialog opened")
}
was := s.open
r := mujica.ShareDialog(c, &s.open, &s.members, mujica.ShareDialogOptions{Title: "Ledger", Link: "https://court.org/ledger", Disabled: s.disabled, OnCopy: func(link string) { c.WriteClipboard(link); log("Copy callback") }})
if r.Invited != nil {
s.next++
s.members = append(s.members, mujica.ShareMember{ID: fmt.Sprintf("invite-%d", s.next), Name: r.Invited.Email, Email: r.Invited.Email, Permission: r.Invited.Permission})
log("Member invited")
}
if r.Changed != "" {
log("Permission changed: " + r.Changed)
}
if r.Removed != "" {
log("Member removed: " + r.Removed)
}
if r.Copied {
log("Link copied")
}
if was && !s.open {
log("Share dialog closed")
}
}
func permissionSelectDemo(c *ui.Context, log func(string)) {
type state struct {
value mujica.Permission
disabled bool
}
s := ui.Local(c.Root(), "396", func() state { return state{} })
mediaCheck(c, log, &s.disabled, "Disabled")
if mujica.PermissionSelect(c, &s.value, mujica.PermissionSelectOptions{Disabled: s.disabled}).Changed() {
log(fmt.Sprintf("Permission: %d", s.value))
}
}
func liveIndicatorDemo(c *ui.Context, log func(string)) {
type state struct {
status mujica.LiveStatus
showTime bool
}
s := ui.Local(c.Root(), "399", func() state { return state{showTime: true} })
if mujica.Select(c, &s.status, []mujica.SelectOption[mujica.LiveStatus]{{Value: mujica.LiveSynced, Label: "Synced"}, {Value: mujica.LiveSyncing, Label: "Syncing"}, {Value: mujica.LiveReconnecting, Label: "Reconnecting"}, {Value: mujica.LiveOffline, Label: "Offline"}, {Value: mujica.LiveError, Label: "Error"}}, mujica.SelectOptions{Label: "Sync status"}).Changed() {
log(fmt.Sprintf("Sync status: %d", s.status))
}
mediaCheck(c, log, &s.showTime, "Last sync time")
now := time.Date(2026, 10, 5, 12, 0, 0, 0, time.UTC)
opts := mujica.LiveIndicatorOptions{Error: "Server unavailable", Now: now}
if s.showTime {
opts.LastSynced = now.Add(-3 * time.Minute)
}
if mujica.LiveIndicator(c, s.status, opts).Changed() {
s.status = mujica.LiveReconnecting
log("Sync retried")
}
}
func remoteCursorDemo(c *ui.Context, log func(string)) {
type state struct {
offset float64
selection, second bool
}
s := ui.Local(c.Root(), "400", func() state { return state{offset: 48, selection: true, second: true} })
if mujica.NumberInput(c, &s.offset, mujica.NumberInputOptions{Min: 0, Max: 79, Step: 1, Label: "Remote text offset"}).Changed() {
log(fmt.Sprintf("Offset: %.0f", s.offset))
}
mediaCheck(c, log, &s.selection, "Selection")
mediaCheck(c, log, &s.second, "Second collaborator")
carets := []mujica.RemoteCaret{{ID: "ada", Name: "Ada", Offset: int(s.offset), Anchor: int(s.offset)}}
if s.selection {
carets[0].Anchor = max(0, carets[0].Offset-5)
}
if s.second {
carets = append(carets, mujica.RemoteCaret{ID: "blaise", Name: "Blaise", Offset: 8, Anchor: 8})
}
ui.Box(c).Height(140).FillWidth().Background(mujica.Tokens(c).Surface).Children(func() {
ui.Column(c).Children(func() {
for _, line := range []string{"The seal of the court is kept", "by the chancellor, who answers"} {
ui.Text(c, line).Font(theme.MonoFont).FontSize(mujica.FontSize(c, 13)).Height(20)
}
})
at := func(o int) (float32, float32) { return float32(o%40) * 8, float32(o/40) * 20 }
mujica.RemoteCursor(c, carets, mujica.RemoteCursorOptions{
Caret: func(o int) ui.Rect { x, y := at(o); return ui.Rect{X: x, Y: y, H: 20} },
Selection: func(from, to int) []ui.Rect {
var out []ui.Rect
for o := from; o < to; o++ {
x, y := at(o)
out = append(out, ui.Rect{X: x, Y: y, W: 8, H: 20})
}
return out
},
})
})
}