diff options
author | Julien Dessaux | 2024-03-25 13:58:48 +0100 |
---|---|---|
committer | Julien Dessaux | 2024-03-25 13:58:48 +0100 |
commit | 4c9b51b8c6b2ebeea0481d219df89ed4fec1e360 (patch) | |
tree | 4fadf1fb8dc7de8de571d828ecf61014826d9e9e | |
parent | chore(dictionary): go mod init and initial dictionary (diff) | |
download | ods-4c9b51b8c6b2ebeea0481d219df89ed4fec1e360.tar.gz ods-4c9b51b8c6b2ebeea0481d219df89ed4fec1e360.tar.bz2 ods-4c9b51b8c6b2ebeea0481d219df89ed4fec1e360.zip |
feat(ods): implement basic ods functionality
-rw-r--r-- | index.html | 29 | ||||
-rw-r--r-- | main.go | 75 | ||||
-rw-r--r-- | static/favicon.svg | 97 | ||||
-rw-r--r-- | static/index4.css | 57 |
4 files changed, 258 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..f98fd30 --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="icon" href="/static/favicon.svg"> + + <link rel="stylesheet" type="text/css" href="/static/index4.css" media="all"> + <title>ODS</title> + </head> + <body> + <main> + <form action="/" method="post"> + <input class="fullwidth" type="text" placeholder="Entrez un mot" id="query" name="query" value="{{ .Query }}" minlength="2" maxlength="32" onfocus="this.select()" required autofocus/> + <div class=".btn-group"> + <input type="submit" value="Valider"/> + {{ if .HasQuery }} + <input type="submit" formmethod="GET" value="Effacer"/> + {{ end }} + </div> + </form> + <p> + {{ if .HasQuery }} + <a href="https://dictionnaire.lerobert.com/definition/{{ .Query }}">{{ .Query }}</a> est un mot <span class="{{ if .Invalid }}invalid">IN{{ else }}valid">{{ end }}VALIDE</span> au scrabble. + {{ end }} + </p> + </main> + </body> +</html> @@ -0,0 +1,75 @@ +package main + +import ( + "embed" + "html/template" + "log/slog" + "net/http" + "strings" +) + +// Variables to customise the search behaviour +const ( + listenStr = "0.0.0.0:8090" +) + +//go:embed ods.txt +var ods string + +//go:embed index.html +var templatesFS embed.FS + +//go:embed static/* +var static embed.FS + +// html templates +var indexTemplate = template.Must(template.New("index").ParseFS(templatesFS, "index.html")) + +type IndexData struct { + HasQuery bool + Query string + Invalid bool +} + +func getIndex() http.Handler { + data := IndexData{ + HasQuery: false, + Query: "", + Invalid: true, + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "no-store, no-cache") + indexTemplate.ExecuteTemplate(w, "index.html", data) + }) +} + +func postIndex() http.Handler { + words := strings.Split(ods,"\n") + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + data := IndexData{ + HasQuery: true, + Query: r.FormValue("query"), + Invalid: true, + } + query := strings.ToUpper(data.Query) + for _, w := range words { + if w == query { + data.Invalid = false + break + } + } + w.Header().Set("Cache-Control", "no-store, no-cache") + indexTemplate.ExecuteTemplate(w, "index.html", data) + }) +} + +// The main function +func main() { + http.Handle("GET /static/", http.FileServer(http.FS(static))) + http.Handle("GET /", getIndex()) + http.Handle("POST /", postIndex()) + slog.Info("listening", "addr", listenStr) + if err := http.ListenAndServe(listenStr, nil); err != nil && err != http.ErrServerClosed { + slog.Error("error listening and serving", "error", err) + } +} diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000..971d573 --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="180" + height="180" + viewBox="0 0 180 180" + version="1.1" + id="svg5" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" + sodipodi:docname="favicon.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + showgrid="false" + inkscape:zoom="1.3984437" + inkscape:cx="93.675563" + inkscape:cy="74.010846" + inkscape:window-width="1362" + inkscape:window-height="717" + inkscape:window-x="0" + inkscape:window-y="49" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs2"> + <linearGradient + inkscape:collect="always" + id="linearGradient3622"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop3618" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop3620" /> + </linearGradient> + <rect + x="21.339478" + y="33.460999" + width="232.05208" + height="284.04139" + id="rect3591" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3622" + id="linearGradient3624" + x1="19.339844" + y1="108.185" + x2="103.28756" + y2="108.185" + gradientUnits="userSpaceOnUse" /> + </defs> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + style="fill:#fee797;stroke-width:8;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round" + id="rect113" + width="180" + height="180" + x="0" + y="0" /> + <text + xml:space="preserve" + id="text3589" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:186.667px;font-family:monospace;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;white-space:pre;shape-inside:url(#rect3591);fill:#000000;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + transform="translate(-0.935125,-48.075078)"><tspan + x="21.339844" + y="199.55305" + id="tspan7040">A</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.3333px;font-family:monospace;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" + x="138.96565" + y="149.52071" + id="text3732"><tspan + sodipodi:role="line" + id="tspan3730" + x="138.96565" + y="149.52071">1</tspan></text> + </g> +</svg> diff --git a/static/index4.css b/static/index4.css new file mode 100644 index 0000000..34637fe --- /dev/null +++ b/static/index4.css @@ -0,0 +1,57 @@ +* { + box-sizing: border-box; + scrollbar-gutter: stable both-edges; +} + +body { + background: #009E60; + display: grid; + grid-template-rows: auto 1fr auto; + font-family: -apple-system, BlinkMacSystemFont, + "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", + "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + font-feature-settings: "kern" 1; + font-kerning: normal; +} + +form { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: start; +} + +input,.btn-group { + margin-top: 1em; + margin-right: 1.5em; +} + +main { + background: #F6F7EB; + padding-left: 1em; + padding-right: 1em; +} + +@media only screen and (min-width: 48rem) { + body { + max-width:48rem; + margin-left: auto; + margin-right: auto; + } +} + +span { + font-weight: bold; + padding-bottom: 0.1em; + padding-left: 0.5em; + padding-right: 0.5em; + padding-top: 0.1em; +} +.valid { + background: #009E60; + color: #F6F7EB; +} +.invalid { + background: #E94F37; +} |