diff --git a/index.html b/index.html deleted file mode 100644 index b83255b..0000000 --- a/index.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - go-scan - - - - -
-
-

go-scan

-
-
- -
-
- filename: - -
-
- -
-
- - - - - \ No newline at end of file diff --git a/main.go b/main.go index da791b8..745e4cf 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "embed" _ "embed" "encoding/json" "fmt" @@ -14,8 +15,8 @@ import ( "velvettear/go-scan/util/date" ) -//go:embed index.html -var html []byte +//go:embed resources +var resources embed.FS var configuration config.Config @@ -26,6 +27,8 @@ func main() { func startServer() { serverAddress := configuration.ServerConfig.Address + ":" + configuration.ServerConfig.Port + http.HandleFunc("/favicon.ico", serveResources) + http.HandleFunc("/resources/", serveResources) http.HandleFunc("/", handleHTTPRequests) log.Info("starting server '" + serverAddress + "'...") error := http.ListenAndServe(serverAddress, nil) @@ -34,6 +37,25 @@ func startServer() { } } +func serveResources(writer http.ResponseWriter, request *http.Request) { + var resource string + if strings.HasSuffix(request.URL.Path, "favicon.ico") { + resource = "resources/gopher.png" + } else { + resource = strings.TrimPrefix(request.URL.Path, "/") + } + bytes, error := resources.ReadFile(resource) + if error != nil { + log.Error("an error occured serving the resource '"+resource+"'", error.Error()) + return + } + log.Debug("serving '" + resource + "'...") + if strings.HasSuffix(resource, "svg") { + writer.Header().Set("Content-Type", "image/svg+xml") + } + writer.Write(bytes) +} + func handleHTTPRequests(writer http.ResponseWriter, request *http.Request) { if strings.ToLower(request.Method) == "post" { result := handleScan(request) @@ -42,7 +64,14 @@ func handleHTTPRequests(writer http.ResponseWriter, request *http.Request) { writer.Write(json) return } - writer.Write(html) + resource := "resources/index.html" + bytes, error := resources.ReadFile(resource) + if error != nil { + log.Error("an error occured serving the resource '"+resource+"'", error.Error()) + return + } + log.Debug("serving '" + resource + "'...") + writer.Write(bytes) } func handleScan(request *http.Request) *result { diff --git a/resources/firacode.ttf b/resources/firacode.ttf new file mode 100644 index 0000000..f75b2a2 Binary files /dev/null and b/resources/firacode.ttf differ diff --git a/resources/gopher.png b/resources/gopher.png new file mode 100644 index 0000000..8f29b63 Binary files /dev/null and b/resources/gopher.png differ diff --git a/resources/heart.png b/resources/heart.png new file mode 100644 index 0000000..9b7f140 Binary files /dev/null and b/resources/heart.png differ diff --git a/resources/hearts-fill.svg b/resources/hearts-fill.svg new file mode 100644 index 0000000..5abc1ab --- /dev/null +++ b/resources/hearts-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icon.png b/resources/icon.png new file mode 100644 index 0000000..618ee6a Binary files /dev/null and b/resources/icon.png differ diff --git a/resources/index.html b/resources/index.html new file mode 100644 index 0000000..166f4c8 --- /dev/null +++ b/resources/index.html @@ -0,0 +1,34 @@ + + + + go-scan + + + + + +
+
+

go-scan

+
+
+ +
+
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/resources/main.js b/resources/main.js new file mode 100644 index 0000000..f9cfb90 --- /dev/null +++ b/resources/main.js @@ -0,0 +1,87 @@ +// key listener +document.addEventListener("keypress", function onEvent(event) { + if (event.key !== "Enter") { + return; + } + startScan(); +}); + +let scanInProgress = false; + +// start a scan +function startScan() { + if (scanInProgress === true) { + return; + } + scanInProgress = true; + let button = document.getElementById("button"); + let buttonDefaultColor = button.style.backgroundColor; + button.style.backgroundColor = "#ffee00"; + let buttonImg = document.getElementById("button-img"); + let result = document.getElementById("result"); + result.style.visibility = "hidden"; + let text = document.getElementById("text"); + let input = document.getElementById("input"); + input.style.opacity = "0" + + // start rotate animation + let rotate = true; + let rotationDegree = 0; + let rotationInterval = setInterval(() => { + rotationDegree = rotateElement(buttonImg, rotationInterval, rotationDegree, !rotate, "Y"); + }, 5); + + // call api + fetch('scan', { + method: 'post', + headers: { + "Content-type": "application/json" + }, + body: JSON.stringify({ + filename: document.getElementById("input-filename").value + }) + }).then(response => { + return response.json(); + }).then(response => { + let buttonColor = "#008800"; + result.style.visibility = "visible"; + text.innerHTML = response.Message; + if (response.State !== "ok") { + text.style.color = "#ff0000"; + buttonColor = "#880000"; + text.innerHTML = "an error occured
" + text.innerHTML; + } else { + text.innerHTML = "scan finished
" + text.innerHTML; + } + text.style.opacity = "100"; + button.style.backgroundColor = buttonColor; + rotate = false; + setTimeout(() => { + text.style.opacity = "0"; + result.style.visibility = "hidden"; + button.style.backgroundColor = buttonDefaultColor; + input.style.opacity = "100"; + scanInProgress = false; + }, 5000); + }); +} + +function rotateElement(element, interval, degree, stop, direction) { + if (element === undefined || interval === undefined) { + return; + } + if (degree === undefined) { + degree = 0; + } + if (stop === true && degree % 360 === 0) { + clearInterval(interval); + return; + } + degree++; + let value = "rotate"; + if (direction !== undefined && (direction.toLowerCase() === "x" || direction.toLowerCase() === "y")) { + value += direction; + } + element.style.transform = value + "(" + degree + "deg)"; + return degree; +} \ No newline at end of file diff --git a/resources/styles.css b/resources/styles.css new file mode 100644 index 0000000..bc512a0 --- /dev/null +++ b/resources/styles.css @@ -0,0 +1,105 @@ +#content { + flex: 1 0 auto; +} + +#text { + opacity: 0; + transition: opacity 0.5s; +} + +#result { + margin-top: 5%; + font-weight: 600; + font-size: 1.5em; + transition: opacity 0.5s; +} + +#button { + background-color: #6e6e6e; + margin: auto; + width: fit-content; + height: fit-content; + border: none; + border-radius: 100%; + transition: background-color 0.5s; +} + +#button:hover { + background-color: #4e4e4e; + cursor: pointer; +} + +#button-img { + min-width: 96px; + min-height: 96px; + width: 25vh; + height: 25vh; +} + +#input { + margin-top: 5%; + transition: opacity 0.5s; +} + +#input-filename { + padding: 8px; + border: 0; + border-radius: 8px; + background-color: #f1f1f1; + font-weight: 300; + font-size: 1.5rem; + color: #1e1e1e; + margin: auto; + font-family: 'Fira Code', monospace; +} + +#footer { + display: flex; + flex-direction: row; + justify-content: center; + flex-shrink: 0; + padding: 8px; + background-color: #4e4e4e; + font-weight: 600; + align-items: center; + transition: background-color 0.5s; + border-top: 1px solid #6e6e6e; +} + +#footer:hover { + background-color: #3e3e3e; + cursor: pointer; +} + +#heart-img { + height: 2rem; + margin-left: 8px; + margin-right: 8px; +} + +html, +body { + height: 100%; +} + +body { + font-family: 'Fira Code', monospace !important; + color: #e1e1e1; + background-color: #1e1e1e; + margin: 0; + padding: 0; + text-align: center; + display: flex; + flex-direction: column; +} + +h1 { + font-weight: 900; + font-size: 5rem; + color: #f1f1f1; +} + +a { + text-decoration: none; + color: #f1f1f1; +} \ No newline at end of file