mirror of
https://github.com/divan/txqr.git
synced 2026-08-29 22:38:04 +08:00
Initial commit of txqr-tester
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
txqr-tester.js linguist-generated=true
|
||||
txqr-tester.js.map linguist-generated=true
|
||||
css/* linguist-vendored=true
|
||||
@@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/vecty"
|
||||
"github.com/gopherjs/vecty/elem"
|
||||
"github.com/gopherjs/vecty/event"
|
||||
)
|
||||
|
||||
// App is a top-level app component.
|
||||
type App struct {
|
||||
vecty.Core
|
||||
|
||||
session *Session
|
||||
}
|
||||
|
||||
// NewApp creates and inits new app page.
|
||||
func NewApp() *App {
|
||||
app := &App{
|
||||
session: NewSession(),
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// Render implements the vecty.Component interface.
|
||||
func (a *App) Render() vecty.ComponentOrHTML {
|
||||
return elem.Body(
|
||||
a.header(),
|
||||
elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("columns"),
|
||||
),
|
||||
// Left half
|
||||
elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("column", "is-half"),
|
||||
),
|
||||
elem.Div(
|
||||
// TODO
|
||||
vecty.If(a.session.state == StateNew,
|
||||
a.StartQR()),
|
||||
),
|
||||
),
|
||||
// Right half
|
||||
elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("column", "is-half"),
|
||||
),
|
||||
elem.Div(
|
||||
// TODO
|
||||
elem.Heading1(vecty.Text("Right")),
|
||||
),
|
||||
),
|
||||
),
|
||||
vecty.Markup(
|
||||
event.KeyDown(a.KeyListener),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (a *App) header() *vecty.HTML {
|
||||
return elem.Section(
|
||||
elem.Heading1(
|
||||
vecty.Markup(
|
||||
vecty.Class("title", "has-text-weight-light"),
|
||||
),
|
||||
vecty.Text("TXQR Automated Tester"),
|
||||
),
|
||||
elem.Heading6(
|
||||
vecty.Markup(
|
||||
vecty.Class("subtitle", "has-text-weight-light"),
|
||||
),
|
||||
vecty.Text("Run TQXR Reader app on your smartphone and point to the QR code to start testing."),
|
||||
),
|
||||
)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Vendored
+10289
File diff suppressed because it is too large
Load Diff
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
body {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: "Helvetica Neue";
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
|
||||
/* Dark mode */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: #101010 -webkit-gradient(linear, left top, left bottom, from(#050505), to(#101010)) no-repeat;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
/* Light mode */
|
||||
@media (prefers-color-scheme: light) {
|
||||
body {
|
||||
background: #c0c0c0 -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#f0f0f0)) no-repeat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
|
||||
"github.com/gopherjs/vecty"
|
||||
"github.com/gopherjs/vecty/elem"
|
||||
"github.com/gopherjs/vecty/prop"
|
||||
)
|
||||
|
||||
// renderImage is a helper for converting image.Image into vecty-compatible
|
||||
// component displaying this image.
|
||||
func renderImage(img image.Image) vecty.ComponentOrHTML {
|
||||
var buf bytes.Buffer
|
||||
err := png.Encode(&buf, img)
|
||||
if err != nil {
|
||||
// TODO(divan): display the error nicely (why this can even happen?)
|
||||
return elem.Div(vecty.Text(fmt.Sprintf("png error: %v", err)))
|
||||
}
|
||||
src := base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||
src = "data:image/png;base64," + src // prepare to be used as data object in src property
|
||||
return elem.Image(
|
||||
vecty.Markup(
|
||||
prop.Src(src),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<meta http-equiv="Content-Security-Policy-Report-Only" content="default-src http: file:; child-src 'none'; object-src 'none'">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="txqr-tester.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gopherjs/vecty"
|
||||
)
|
||||
|
||||
// KeyListener implements listener for keydown events.
|
||||
func (a *App) KeyListener(e *vecty.Event) {
|
||||
key := e.Get("key").String()
|
||||
switch key {
|
||||
case " ":
|
||||
fmt.Println("Space")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/vecty"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := NewApp()
|
||||
|
||||
vecty.SetTitle("TXQR Automated Tester")
|
||||
vecty.AddStylesheet("css/bulma.css")
|
||||
vecty.AddStylesheet("css/bulma-extensions.min.css")
|
||||
vecty.AddStylesheet("css/custom.css")
|
||||
vecty.RenderBody(app)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
// SessionState defines test session state.
|
||||
type SessionState int
|
||||
|
||||
const (
|
||||
StateNew SessionState = iota // default state
|
||||
StateStarted
|
||||
StatePaused
|
||||
StateFinished
|
||||
StateFailed
|
||||
)
|
||||
|
||||
// Session represents a single test session.
|
||||
type Session struct {
|
||||
state SessionState
|
||||
}
|
||||
|
||||
// NewSession inits new test session.
|
||||
// Default State is StateNew.
|
||||
func NewSession() *Session {
|
||||
return &Session{}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/divan/txqr/qr"
|
||||
"github.com/gopherjs/vecty"
|
||||
"github.com/gopherjs/vecty/elem"
|
||||
)
|
||||
|
||||
// StartQR renders the QR code with information needed to start
|
||||
// a new testing from smartphone.
|
||||
func (a *App) StartQR() vecty.ComponentOrHTML {
|
||||
img, err := qr.Encode("test", 500, qr.Medium)
|
||||
if err != nil {
|
||||
// TODO(divan): display the error nicely (why this can even happen?)
|
||||
return elem.Div(vecty.Text(fmt.Sprintf("qr error: %v", err)))
|
||||
}
|
||||
return elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("card"),
|
||||
),
|
||||
elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("card-header"),
|
||||
),
|
||||
elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("card-header-title", "is-centered"),
|
||||
),
|
||||
elem.Heading1(
|
||||
vecty.Markup(
|
||||
vecty.Class("has-text-weight-bold"),
|
||||
),
|
||||
vecty.Text("Scan QR code to start testing"),
|
||||
),
|
||||
),
|
||||
),
|
||||
elem.Div(
|
||||
vecty.Markup(
|
||||
vecty.Class("card-image", "has-text-centered"),
|
||||
),
|
||||
renderImage(img),
|
||||
),
|
||||
)
|
||||
}
|
||||
Generated
+41652
File diff suppressed because one or more lines are too long
Generated
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user