Search Apps Documentation Source Content File Folder Download Copy Actions Download

render_board.gno

4.82 Kb · 189 lines
  1package boards2
  2
  3import (
  4	"strings"
  5
  6	"gno.land/p/gnoland/boards"
  7	"gno.land/p/jeronimoalbi/mdform"
  8	"gno.land/p/jeronimoalbi/pager"
  9	"gno.land/p/moul/md"
 10	"gno.land/p/nt/mdalert"
 11	"gno.land/p/nt/mux"
 12	"gno.land/r/gnoland/boards2/v1/permissions"
 13)
 14
 15func renderBoard(res *mux.ResponseWriter, req *mux.Request) {
 16	name := req.GetVar("board")
 17	board, found := gBoards.GetByName(name)
 18	if !found {
 19		res.Write(md.H3("The board you are looking for does not exist"))
 20		res.Write("Do you want to " + md.Link("create a new board", createBoardURI) + " ?")
 21		return
 22	}
 23
 24	creatorLink := userLink(board.Creator)
 25	date := board.CreatedAt.Format(dateFormat)
 26
 27	res.Write(md.H1(md.Link("Boards", gRealmPath) + " › " + board.Name))
 28	if board.Readonly {
 29		res.Write(
 30			mdalert.Warning("Info", "Creating new threads and commenting are disabled within this board") + "\n",
 31		)
 32	}
 33
 34	res.Write("Created by " + creatorLink + " on " + date + ", #" + board.ID.String())
 35	res.Write("  \n" + renderBoardMenu(board, req))
 36	res.Write(md.HorizontalRule())
 37
 38	if board.Threads.Size() == 0 {
 39		res.Write(md.H3("This board doesn't have any threads"))
 40		if !board.Readonly {
 41			startConversationLink := md.Link("start a new conversation", makeCreateThreadURI(board))
 42			res.Write("Do you want to " + startConversationLink + " in this board ?")
 43		}
 44		return
 45	}
 46
 47	p, err := pager.New(req.RawPath, board.Threads.Size(), pager.WithPageSize(pageSizeDefault))
 48	if err != nil {
 49		panic(err)
 50	}
 51
 52	render := func(thread *boards.Post) bool {
 53		if !thread.Hidden {
 54			res.Write(renderThreadSummary(thread) + "\n")
 55		}
 56		return false
 57	}
 58
 59	res.Write("Sort by: ")
 60
 61	r := parseRealmPath(req.RawPath)
 62	sortOrder := r.Query.Get("order")
 63	if sortOrder == "desc" {
 64		r.Query.Set("order", "asc")
 65		res.Write(md.Link("newest first", r.String()) + "\n\n")
 66	} else {
 67		r.Query.Set("order", "desc")
 68		res.Write(md.Link("oldest first", r.String()) + "\n\n")
 69	}
 70
 71	count := p.PageSize()
 72	if sortOrder == "desc" {
 73		count = -count // Reverse iterate
 74	}
 75
 76	board.Threads.Iterate(p.Offset(), count, render)
 77
 78	if p.HasPages() {
 79		res.Write(md.HorizontalRule())
 80		res.Write(pager.Picker(p))
 81	}
 82}
 83
 84// renderSubMenu renders a sub-menu with a distinct visual pattern.
 85func renderSubMenu(items []string) string {
 86	if len(items) == 0 {
 87		return ""
 88	}
 89	return "└─ " + strings.Join(items, " • ") + "\n"
 90}
 91
 92func renderBoardMenu(board *boards.Board, req *mux.Request) string {
 93	var (
 94		b               strings.Builder
 95		boardMembersURL = makeBoardURI(board) + "/members"
 96	)
 97
 98	if board.Readonly {
 99		b.WriteString(md.Link("List Members", boardMembersURL))
100		b.WriteString(" • ")
101		b.WriteString(md.Link("Unfreeze Board", makeUnfreezeBoardURI(board)))
102		b.WriteString("\n")
103	} else {
104		b.WriteString("↳ ")
105		b.WriteString(md.Link("Create Thread", makeCreateThreadURI(board)))
106		b.WriteString(" • ")
107		b.WriteString(md.Link("Request Invite", makeRequestInviteURI(board)))
108		b.WriteString(" • ")
109
110		menu := getCurrentMenu(req.RawPath)
111		if menu == menuManageBoard {
112			b.WriteString(md.Bold("Manage Board"))
113		} else {
114			b.WriteString(md.Link("Manage Board", menuURL(menuManageBoard)))
115		}
116
117		b.WriteString("  \n")
118
119		if menu == menuManageBoard {
120			subMenuItems := []string{
121				md.Link("Invite Member", makeInviteMemberURI(board)),
122				md.Link("List Invite Requests", makeBoardURI(board)+"/invites"),
123				md.Link("List Members", boardMembersURL),
124				md.Link("List Banned Users", makeBoardURI(board)+"/banned-users"),
125				md.Link("Freeze Board", makeFreezeBoardURI(board)),
126			}
127			b.WriteString(renderSubMenu(subMenuItems))
128		}
129	}
130
131	b.WriteString("\n")
132	return b.String()
133}
134
135func renderInviteMember(res *mux.ResponseWriter, req *mux.Request) {
136	name := req.GetVar("board")
137	board, found := gBoards.GetByName(name)
138	if !found {
139		res.Write("Board does not exist: " + name)
140		return
141	}
142
143	form := mdform.New("exec", "InviteMember")
144	form.Input(
145		"boardID",
146		"placeholder", "Board ID",
147		"value", board.ID.String(),
148		"readonly", "true",
149	)
150	form.Input(
151		"user",
152		"placeholder", "Address",
153		"required", "true",
154	)
155	form.Select(
156		"role",
157		string(permissions.RoleOwner),
158	)
159	form.Select(
160		"role",
161		string(permissions.RoleAdmin),
162	)
163	form.Select(
164		"role",
165		string(permissions.RoleModerator),
166	)
167	form.Select(
168		"role",
169		string(permissions.RoleGuest),
170		"selected", "true",
171	)
172
173	res.Write(md.H1(board.Name + ": Invite Member"))
174	res.Write(
175		md.Paragraph(
176			"Both open and invite only boards can have multiple members with different roles within a "+
177				"board, where members can have a single role at a time.",
178		) +
179			md.Paragraph(
180				"Boards are independent communities which could apply different permissions per role than "+
181					"other boards, but generally Boards2 supports four roles, _owner_, _admin_, _moderator_ "+
182					"and _guest_.",
183			) +
184			md.Paragraph(
185				"Member will be added to "+md.Link(board.Name, makeBoardURI(board))+" board.",
186			),
187	)
188	res.Write(form.String())
189}