restructured project, fixed some errors and fixed ui stuff
This commit is contained in:
parent
efcb1aeda3
commit
670465388e
10 changed files with 259 additions and 168 deletions
165
index.html
165
index.html
|
@ -1,165 +0,0 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>go-scan</title>
|
||||
<style>
|
||||
#content {
|
||||
position: absolute;
|
||||
top: 33%;
|
||||
left: 50%;
|
||||
margin-right: -50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 50%;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#button-img {
|
||||
min-width: 96px;
|
||||
min-height: 96px;
|
||||
width: 25vh;
|
||||
height: 25vh;
|
||||
}
|
||||
|
||||
#input {
|
||||
margin-top: 5%;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
#input-label {
|
||||
font-weight: 600;
|
||||
font-size: 1.5rem;
|
||||
margin-right: 5%;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #e1e1e1;
|
||||
background-color: #1e1e1e;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 900;
|
||||
font-size: 5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content">
|
||||
<div id="heading">
|
||||
<h1>go-scan</h1>
|
||||
</div>
|
||||
<div id="button" onclick="startScan()">
|
||||
<img id="button-img" src="https://cdn2.iconfinder.com/data/icons/usability-test/100/jan_yulck-26-512.png">
|
||||
</div>
|
||||
<div id="input">
|
||||
<span id="input-label">filename:</span>
|
||||
<input id="input-filename" type="text">
|
||||
</div>
|
||||
<div id="result">
|
||||
<span id="text"></span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
function startScan() {
|
||||
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 = "scan finished<br>" + response.Message;
|
||||
if (response.State !== "ok") {
|
||||
text.style.color = "#ff0000";
|
||||
buttonColor = "#880000";
|
||||
text.innerHTML = "an error occured<br>" + 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";
|
||||
}, 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;
|
||||
}
|
||||
</script>
|
||||
|
||||
</html>
|
35
main.go
35
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 {
|
||||
|
|
BIN
resources/firacode.ttf
Normal file
BIN
resources/firacode.ttf
Normal file
Binary file not shown.
BIN
resources/gopher.png
Normal file
BIN
resources/gopher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
resources/heart.png
Normal file
BIN
resources/heart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 713 B |
1
resources/hearts-fill.svg
Normal file
1
resources/hearts-fill.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0H24V24H0z"/><path d="M17.363 11.045c1.404-1.393 3.68-1.393 5.084 0 1.404 1.394 1.404 3.654 0 5.047L17 21.5l-5.447-5.408c-1.404-1.393-1.404-3.653 0-5.047 1.404-1.393 3.68-1.393 5.084 0l.363.36.363-.36zm1.88-6.288c.94.943 1.503 2.118 1.689 3.338-1.333-.248-2.739-.01-3.932.713-2.15-1.303-4.994-1.03-6.856.818-2.131 2.115-2.19 5.515-.178 7.701l.178.185 2.421 2.404L11 21.485 2.52 12.993C.417 10.637.496 7.019 2.757 4.757c2.265-2.264 5.888-2.34 8.244-.228 2.349-2.109 5.979-2.039 8.242.228z"/></svg>
|
After Width: | Height: | Size: 603 B |
BIN
resources/icon.png
Normal file
BIN
resources/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
34
resources/index.html
Normal file
34
resources/index.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>go-scan</title>
|
||||
<link href="/resources/firacode.ttf" rel="stylesheet">
|
||||
<link href="/resources/styles.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content">
|
||||
<div id="heading">
|
||||
<h1>go-scan</h1>
|
||||
</div>
|
||||
<div id="button" onclick="startScan()">
|
||||
<img id="button-img" src="/resources/icon.png">
|
||||
</div>
|
||||
<div id="input">
|
||||
<input id="input-filename" type="text" placeholder="filename...">
|
||||
</div>
|
||||
<div id="result">
|
||||
<span id="text"></span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://velvettear.de" target="_blank">
|
||||
<div id="footer">
|
||||
<span>made with</span>
|
||||
<img id="heart-img" src="/resources/hearts-fill.svg">
|
||||
<span>by velvettear</span>
|
||||
</div>
|
||||
</a>
|
||||
<script src="/resources/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
87
resources/main.js
Normal file
87
resources/main.js
Normal file
|
@ -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<br>" + text.innerHTML;
|
||||
} else {
|
||||
text.innerHTML = "scan finished<br>" + 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;
|
||||
}
|
105
resources/styles.css
Normal file
105
resources/styles.css
Normal file
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue