Add landing page for kjol, documentation
This commit is contained in:
@@ -13,6 +13,20 @@ func Measure(*vdom.Ref) Rect { return Rect{} }
|
||||
func Viewport() Size { return Size{} }
|
||||
func CSSVarPx(string) float64 { return 0 }
|
||||
|
||||
// Now is 0 on the server: there is no page load to measure from. A component that
|
||||
// reports a timing therefore SSRs an empty reading and fills it in once the client has
|
||||
// taken over — which is the honest answer, since the number IS a property of the client.
|
||||
func Now() float64 { return 0 }
|
||||
|
||||
// The theme is a property of the BROWSER — the OS setting and a localStorage choice,
|
||||
// neither of which the server can see. So the server always renders the light theme, and
|
||||
// the document's boot script (webui.ThemeBootScript) applies the dark class before the
|
||||
// first paint. Nothing here can help with that, and pretending otherwise would just move
|
||||
// the flash somewhere harder to find.
|
||||
func PrefersDark() bool { return false }
|
||||
func OnMediaChange(string, func(bool)) Unsub { return func() {} }
|
||||
func SetRootClass(string, bool) {}
|
||||
|
||||
func RAF(func()) int { return 0 }
|
||||
func CancelRAF(int) {}
|
||||
func AfterRender(func()) {}
|
||||
|
||||
@@ -67,8 +67,63 @@ func CSSVarPx(name string) float64 {
|
||||
return parseCSSLength(raw, style.Get("fontSize").String())
|
||||
}
|
||||
|
||||
// ---- theme ----
|
||||
|
||||
// PrefersDark reports whether the OS asks for a dark colour scheme.
|
||||
func PrefersDark() bool {
|
||||
mq := window.Call("matchMedia", "(prefers-color-scheme: dark)")
|
||||
return mq.Truthy() && mq.Get("matches").Bool()
|
||||
}
|
||||
|
||||
// OnMediaChange watches a media query. The theme controller uses it to follow the OS
|
||||
// while the user has not overridden it — a preference changed in the system settings
|
||||
// should reach an open tab, not wait for a reload.
|
||||
func OnMediaChange(query string, fn func(matches bool)) Unsub {
|
||||
mq := window.Call("matchMedia", query)
|
||||
if !mq.Truthy() {
|
||||
return func() {}
|
||||
}
|
||||
cb := js.FuncOf(func(_ js.Value, args []js.Value) any {
|
||||
matches := false
|
||||
if len(args) > 0 {
|
||||
matches = args[0].Get("matches").Bool()
|
||||
}
|
||||
fn(matches)
|
||||
return nil
|
||||
})
|
||||
mq.Call("addEventListener", "change", cb)
|
||||
return func() {
|
||||
mq.Call("removeEventListener", "change", cb)
|
||||
cb.Release()
|
||||
}
|
||||
}
|
||||
|
||||
// SetRootClass adds or removes a class on <html>.
|
||||
//
|
||||
// The THEME lives there rather than on the app's root element because the page's own
|
||||
// background — the thing behind everything, painted before the app mounts — is styled
|
||||
// from <html>. A dark class on #app leaves a white margin around a dark page.
|
||||
func SetRootClass(class string, on bool) {
|
||||
list := document.Get("documentElement").Get("classList")
|
||||
if on {
|
||||
list.Call("add", class)
|
||||
return
|
||||
}
|
||||
list.Call("remove", class)
|
||||
}
|
||||
|
||||
// ---- frame timing + the post-render hook ----
|
||||
|
||||
// Now is performance.now(): milliseconds since the page began navigating, with
|
||||
// sub-millisecond resolution.
|
||||
//
|
||||
// It is measured from the same origin the browser uses for its own timings, so a
|
||||
// reading taken when the first render commits IS the time it took this app to become
|
||||
// interactive — not an interval the app started and stopped itself.
|
||||
func Now() float64 {
|
||||
return window.Get("performance").Call("now").Float()
|
||||
}
|
||||
|
||||
func RAF(fn func()) int {
|
||||
var cb js.Func
|
||||
cb = js.FuncOf(func(js.Value, []js.Value) any {
|
||||
|
||||
Reference in New Issue
Block a user