Add project files

This commit is contained in:
ChaoticByte 2024-08-27 11:55:01 +02:00
parent a19b51acce
commit c77b8fc4e1
No known key found for this signature in database
5 changed files with 198 additions and 0 deletions

3
go.mod Normal file
View file

@ -0,0 +1,3 @@
module github.com/ChaoticByte/plaintext-encyclopedia
go 1.22.4

77
main.go Normal file
View file

@ -0,0 +1,77 @@
package main
import (
"html/template"
"io/fs"
"log"
"net/http"
"os"
"strings"
)
var logger *log.Logger
var appTemplate *template.Template = template.New("app")
type TemplateData struct {
TOC []string
Entry string
Title string
EntryTitle string
}
func loadTemplate() {
data, err := os.ReadFile(TemplateFile)
if err != nil { logger.Panic(err) }
appTemplate.Parse(string(data))
}
func getTOC() []string {
entriesDirFs := os.DirFS(EntriesDirectory)
m, err := fs.Glob(entriesDirFs, "*")
if err != nil { logger.Panic(err) }
return m
}
func getEntry(name string) (string, error) {
data, err := os.ReadFile(strings.TrimRight(EntriesDirectory, "/") + "/" + name)
if err != nil { return "", err }
return string(data), err
}
func handleApplication(w http.ResponseWriter, req *http.Request) {
var entry string
var err error
entryName := strings.Trim(req.URL.Path, "/")
if entryName != "" {
if strings.Contains(entryName, "/") || strings.Contains(entryName, ".") {
// path traversal
logger.Println("Possible path traversal attempt from", req.RemoteAddr, "to", entryName)
w.WriteHeader(http.StatusForbidden)
return
}
// load entry
entry, err = getEntry(entryName)
if err != nil {
logger.Println("Couldn't open entry", entryName)
w.WriteHeader(http.StatusNotFound)
}
}
err = appTemplate.ExecuteTemplate(w, "app", TemplateData{TOC: getTOC(), Entry: entry, Title: MainTitle, EntryTitle: entryName})
if err != nil { logger.Println(err) }
}
func main() {
// get logger
logger = log.Default()
// load template
loadTemplate()
// handle static files
staticHandler := http.StripPrefix("/static/", http.FileServer(http.Dir(StaticDirectory)))
http.Handle("/static/", staticHandler)
// handle application
http.HandleFunc("/", handleApplication)
// start server
logger.Println("Starting server on", ServerListen)
err := http.ListenAndServe(ServerListen, nil)
if err != nil { logger.Panic(err) }
}

27
public/index.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/style.css">
<title>{{ if .EntryTitle }}{{ .EntryTitle }} - {{ end }}{{ .Title }}</title>
</head>
<body>
<label class="sidebar-switch">
<div class="sidebar-symbol">&#x2261;</div>
<input type="checkbox" {{- if not .Entry }}checked{{ end }}>
<div class="sidebar">
{{- range .TOC -}}
<div><a href="{{ . }}">{{ . }}</a></div>
{{- end -}}
</div>
</label>
<div class="main">
<h1>{{ .EntryTitle }}</h1>
<div class="content">
{{ .Entry }}
</div>
</div>
</body>
</html>

84
public/static/style.css Normal file
View file

@ -0,0 +1,84 @@
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
justify-content: left;
align-items: top;
width: 100vw;
font-family: sans-serif;
}
.sidebar-symbol {
margin-left: .5rem;
margin-top: .5rem;
width: 2rem;
height: 2rem;
font-size: 1.8rem;
font-family: monospace;
text-align: center;
user-select: none;
cursor: pointer;
pointer-events: all;
}
.sidebar-switch { pointer-events: none; }
.sidebar-switch > input { display: none; }
.sidebar-switch > .sidebar { display: none; }
.sidebar-switch > input:checked + .sidebar { display: flex; }
.sidebar {
flex-direction: column;
pointer-events: all;
width: max-content;
padding: 1rem;
gap: .25rem;
}
a {
color: black;
text-decoration: none;
}
a:hover { text-decoration: underline; }
.main {
padding-right: 2rem;
margin: 2rem 0;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.main > h1, .content {
width: 70vw;
max-width: 50rem;
}
.main > h1 {
font-size: 1.4rem;
margin-bottom: 0;
}
.content { white-space: pre-line; }
@media only screen and (max-width: 750px) {
body {
flex-direction: column;
align-items: center;
}
.sidebar-symbol {
margin-left: unset;
text-align: left;
}
.sidebar-switch {
width: 90vw;
background-color: white;
}
.sidebar {
width: 100%;
height: max-content;
padding: 1rem 0;
gap: .4rem;
}
.main {
margin-top: .5rem;
padding-right: 0;
}
.main > h1, .content {
width: 90vw;
max-width: unset;
}
}

7
settings.go Normal file
View file

@ -0,0 +1,7 @@
package main
var ServerListen = ":7000"
var EntriesDirectory = "./entries"
var TemplateFile = "./public/index.html"
var StaticDirectory = "./public/static"
var MainTitle = "Encyclopedia"