oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1package calls
2
3import (
4 "amadan.net/oficina/home/connect"
5 "bytes"
6 "embed"
7 "io/fs"
8 "testing/fstest"
9
10 "amadan.net/oficina/estilo.git/base"
11 "amadan.net/oficina/estilo.git/callui"
12 "amadan.net/oficina/estilo.git/chrome"
13 "amadan.net/oficina/estilo.git/credits"
14 estilomenu "amadan.net/oficina/estilo.git/menu"
15 "amadan.net/oficina/estilo.git/sky"
16 "html/template"
17 "net/http"
18
19 "amadan.net/rastrillo/rastrillo"
20 "amadan.net/rastrillo/rastrillo/ui"
21
22 "amadan.net/oficina/calls/internal/calls/icons"
23)
24
25//go:embed templates static
26var appFS embed.FS
27
28var assets = rastrillo.NewAssets(callAssets())
29
30func callAssets() fs.FS {
31 // estilo's stylesheets and chrome.js come straight from the estilo
32 // this module pins, so they cannot drift from it: base.css (links),
33 // menu.css (every floating panel), chrome.css (the bar, the account
34 // menu and the sign-in door), sky.css (the sky behind the door),
35 // callui.css (the call's own pieces).
36 files := fstest.MapFS{
37 "static/estilo/base.css": &fstest.MapFile{Data: base.CSS()},
38 "static/estilo/menu.css": &fstest.MapFile{Data: estilomenu.CSS()},
39 "static/estilo/chrome.css": &fstest.MapFile{Data: chrome.CSS()},
40 "static/estilo/chrome.js": &fstest.MapFile{Data: chrome.JS()},
41 "static/estilo/sky.css": &fstest.MapFile{Data: sky.CSS()},
42 "static/callui.css": &fstest.MapFile{Data: callui.CSS()},
43 }
44 if err := fs.WalkDir(appFS, "static", func(path string, entry fs.DirEntry, err error) error {
45 if err != nil {
46 return err
47 }
48 if entry.IsDir() {
49 return nil
50 }
51 data, err := appFS.ReadFile(path)
52 if err != nil {
53 return err
54 }
55 files[path] = &fstest.MapFile{Data: data}
56 return nil
57 }); err != nil {
58 panic(err)
59 }
60 return files
61}
62
63var pageNames = []string{"index", "signin", "signedout", "errors", "welcome", "link_once", "confirm", "join", "room", "settings", "agent_once", "home", "native", "share", "credits", "guest", "meeting_settings"}
64
65var pages = map[string]*template.Template{}
66
67func init() {
68 for _, name := range pageNames {
69 pages[name] = template.Must(buildPage(name).ParseFS(credits.Templates(), "templates/credits.html"))
70 if name == "signin" {
71 // The Keymail continuation's meta refresh (home-oauth-head).
72 pages[name] = template.Must(pages[name].ParseFS(connect.Templates(), "templates/oauth.html"))
73 }
74 if name == "home" {
75 pages[name] = template.Must(pages[name].ParseFS(connect.Templates(), "templates/home_link.html"))
76 }
77 }
78}
79
80// buildPage parses rastrillo's ui partials first, then estilo's chrome
81// and menu templates (the bar, the account menu, the error page body and
82// the sign-in door, which call rastrillo's field and callout partials),
83// then this app's own partials, then the layout and the page, so a page
84// can call confirm-form, field, empty-state and the rest by name with a
85// dict — and chat-panel, the one partial Calls owns, the same way.
86//
87// templates/partials/ is parsed for every page rather than per page
88// that uses it: a partial is defined-but-unused for free, and the
89// alternative is a second list beside pageNames that has to be kept in
90// step with the first.
91func buildPage(name string) *template.Template {
92 t := template.New("layout").
93 Funcs(ui.Funcs(ui.WithIcons(icons.Icon, icons.Assets))).
94 Funcs(template.FuncMap{"asset": assets.Path})
95 t = template.Must(t.ParseFS(ui.Templates(), "*.html"))
96 t = template.Must(t.ParseFS(chrome.Templates(), "templates/*.html"))
97 t = template.Must(t.ParseFS(estilomenu.Templates(), "templates/*.html"))
98 t = template.Must(t.ParseFS(appFS, "templates/partials/*.html"))
99 return template.Must(t.ParseFS(appFS, "templates/layout.html", "templates/"+name+".html"))
100}
101
102// render writes a page. A template failure is logged by nobody and
103// answered in the plainest way left: nothing has been written yet, so
104// the status can still say so.
105func render(w http.ResponseWriter, name string, data any) {
106 var buf bytes.Buffer
107 if err := pages[name].ExecuteTemplate(&buf, "layout", data); err != nil {
108 http.Error(w, "something went wrong", http.StatusInternalServerError)
109 return
110 }
111 if w.Header().Get("Content-Type") == "" {
112 w.Header().Set("Content-Type", "text/html; charset=utf-8")
113 }
114 buf.WriteTo(w)
115}
116