frontend added from GoStart scaffolf

This commit is contained in:
0ceanSlim 2024-07-23 16:40:39 -04:00
parent 12e9856169
commit 44636c95d9
13 changed files with 210 additions and 10 deletions

View File

@ -1,5 +1,7 @@
mongodb:
uri: "mongodb://localhost:27017/"
database: "grain"
server:
address: ":8080"
relay:
port: ":8080"
web:
port: ":8181"

23
main.go
View File

@ -8,6 +8,7 @@ import (
"grain/relay"
"grain/relay/db"
"grain/relay/utils"
"grain/web"
"golang.org/x/net/websocket"
)
@ -26,11 +27,23 @@ func main() {
}
defer db.DisconnectDB()
// Start WebSocket relay
http.Handle("/", websocket.Handler(relay.Listener))
fmt.Println("WebSocket server started on", config.Server.Address)
err = http.ListenAndServe(config.Server.Address, nil)
// Run the WebSocket server in a goroutine
go func() {
fmt.Printf("WebSocket server is running on ws://localhost%s\n", config.Relay.Port)
err := http.ListenAndServe(config.Relay.Port, websocket.Handler(relay.Listener))
if err != nil {
fmt.Println("Error starting WebSocket server:", err)
}
}()
// Run the HTTP server for serving static files and home page
mux := http.NewServeMux()
mux.HandleFunc("/", web.RootHandler)
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("web/static"))))
fmt.Printf("Http server is running on http://localhost%s\n", config.Web.Port)
err = http.ListenAndServe(config.Web.Port, mux)
if err != nil {
fmt.Println("Error starting server:", err)
fmt.Println("Error starting web server:", err)
}
}

View File

@ -11,9 +11,12 @@ type Config struct {
URI string `yaml:"uri"`
Database string `yaml:"database"`
} `yaml:"mongodb"`
Server struct {
Address string `yaml:"address"`
} `yaml:"server"`
Relay struct {
Port string `yaml:"port"`
} `yaml:"relay"`
Web struct {
Port string `yaml:"port"`
} `yaml:"web"`
}
func LoadConfig(filename string) (*Config, error) {

61
web/http.go Normal file
View File

@ -0,0 +1,61 @@
package web
import (
"html/template"
"net/http"
)
func RootHandler(w http.ResponseWriter, r *http.Request) {
data := PageData{
Title: "GRAIN Relay",
}
RenderTemplate(w, data, "index.html")
}
type PageData struct {
Title string
Theme string
}
// Define the base directories for views and templates
const (
viewsDir = "web/views/"
templatesDir = "web/views/templates/"
)
// Define the common layout templates filenames
var templateFiles = []string{
"#layout.html",
"header.html",
"footer.html",
}
// Initialize the common templates with full paths
var layout = PrependDir(templatesDir, templateFiles)
func RenderTemplate(w http.ResponseWriter, data PageData, view string) {
// Append the specific template for the route
templates := append(layout, viewsDir+view)
// Parse all templates
tmpl, err := template.ParseFiles(templates...)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Execute the "layout" template
err = tmpl.ExecuteTemplate(w, "layout", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// Helper function to prepend a directory path to a list of filenames
func PrependDir(dir string, files []string) []string {
var fullPaths []string
for _, file := range files {
fullPaths = append(fullPaths, dir+file)
}
return fullPaths
}

1
web/static/custom.min.css vendored Normal file
View File

@ -0,0 +1 @@
/*! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{-webkit-text-size-adjust:100%;font-feature-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-feature-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}:root{--color-bgPrimary:#101010;--color-bgSecondary:#282828;--color-bgInverted:#e1e1e1;--color-textPrimary:#fff;--color-textSecondary:#ebebeb;--color-textMuted:#c8c8c8;--color-textInverted:#101010}:root[data-theme=light]{--color-bgPrimary:#c8c8c8;--color-bgSecondary:#e6e6e6;--color-bgInverted:#505050;--color-textPrimary:#000;--color-textSecondary:#141414;--color-textMuted:#646464;--color-textInverted:#fff}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.mb-8{margin-bottom:2rem}.mt-8{margin-top:2rem}.rounded-md{border-radius:.375rem}.bg-amber-400{--tw-bg-opacity:1;background-color:rgb(251 191 36/var(--tw-bg-opacity))}.bg-bgPrimary{background-color:var(--color-bgPrimary)}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(96 165 250/var(--tw-bg-opacity))}.p-2{padding:.5rem}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.font-bold{font-weight:700}.text-textMuted{color:var(--color-textMuted)}.text-textPrimary{color:var(--color-textPrimary)}.text-textSecondary{color:var(--color-textSecondary)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}

BIN
web/static/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

26
web/style/input.css Normal file
View File

@ -0,0 +1,26 @@
@config "tailwind.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--color-bgPrimary: rgb(16, 16, 16);
--color-bgSecondary: rgb(40, 40, 40);
--color-bgInverted: rgb(225, 225, 225);
--color-textPrimary: rgb(255, 255, 255);
--color-textSecondary: rgb(235, 235, 235);
--color-textMuted: rgb(200, 200, 200);
--color-textInverted: rgb(16, 16, 16);
}
:root[data-theme="light"] {
--color-bgPrimary: rgb(200, 200, 200);
--color-bgSecondary: rgb(230, 230, 230);
--color-bgInverted: rgb(80, 80, 80);
--color-textPrimary: rgb(0, 0, 0);
--color-textSecondary: rgb(20, 20, 20);
--color-textMuted: rgb(100, 100, 100);
--color-textInverted: rgb(255, 255, 255);
}
}

25
web/style/readme.md Normal file
View File

@ -0,0 +1,25 @@
# Information
This repository INCLUDES a minified version of the custom css used to style the web views with themes defined in the input.css. If you want to change anything about the configuration or the input, you will need to rebuild the custom minified css by using the [Tailwind standalone CLI Tool](https://github.com/tailwindlabs/tailwindcss/releases).
For Tailwind to Rebuild the CSS, Tailwind must be run to compile the new styling.
To do this run:
```bash
tailwindcss -i web/style/input.css -o web/static/custom.min.css --minify
```
## Development
You can run a watcher while in development to automatically rebuild the `tailwind.min.css` whenever a file in the project directory is modified.
To do this run:
```bash
tailwindcss -i web/style/input.css -o web/static/custom.min.css --watch --minify
```
### Dark Mode
Yes... This framework is designed with "Dark Mode" as the default theme. As all things should be.

View File

@ -0,0 +1,18 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./**/*.{html,js}"],
theme: {
extend: {
colors: {
bgPrimary: "var(--color-bgPrimary)",
bgSecondary: "var(--color-bgSecondary)",
bgInverted: "var(--color-bgInverted)",
textPrimary: "var(--color-textPrimary)",
textSecondary: "var(--color-textSecondary)",
textMuted: "var(--color-textMuted)",
textInverted: "var(--color-textInverted)",
},
},
},
plugins: [],
};

5
web/views/index.html Normal file
View File

@ -0,0 +1,5 @@
{{define "view"}}
<main class="flex flex-col items-center justify-center p-8">
<div class="mb-4">You are now viewing the {{.Title}}</div>
</main>
{{end}}

View File

@ -0,0 +1,34 @@
{{define "layout"}}
<!DOCTYPE html>
<html lang="en" data-theme="{{.Theme}}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!--
CDNs are used for ease of development. In a Production enviornment,
build a proper minified custom CSS using the Tailwind CLI tool and serve
the latest available minified htmx and custom css directly from your server.
To download a copy of htmx: https://htmx.org/docs/#download-a-copy
<link href="/static/tailwind.min.css" rel="stylesheet" />
<link href="/static/htmx.min.js">
-->
<script src="https://cdn.tailwindcss.com"></script>
<script
src="https://unpkg.com/htmx.org@1.9.12"
integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2"
crossorigin="anonymous"
></script>
<!--
link the custom minified styling included in this repo, built from the configuration
in the /web/style directory
-->
<link href="/static/custom.min.css" rel="stylesheet" />
<link rel="icon" href="/static/img/favicon.ico" type="image/x-icon" />
<title>{{.Title}}</title>
</head>
<body class="font-mono text-center text-textPrimary bg-bgPrimary">
{{template "header" .}} {{template "view" .}} {{template "footer" .}}
</body>
</html>
{{end}}

View File

@ -0,0 +1,5 @@
{{define "footer"}}
<footer class="text-textMuted">
<p>&copy; 2024 GRAIN 🌾, made with 💜 by OceanSlim</p>
</footer>
{{end}}

View File

@ -0,0 +1,7 @@
{{define "header"}}
<header>
<h1 class="mt-8 mb-8 text-3xl font-bold text-textSecondary">
Welcome to the GRAIN Frontend 🌾
</h1>
</header>
{{end}}