big work on templating, added middleware

This commit is contained in:
Sky Johnson 2025-08-09 09:29:10 -05:00
parent 0c9a701cef
commit a1e8d49c0e
43 changed files with 226 additions and 14 deletions

108
assets/dk.css Normal file
View File

@ -0,0 +1,108 @@
/*
In general, we don't want to stray too far from the original appearance.
We'll optimize the layout for modern CSS and use better styles and fonts
for legibility and design, but keep the soul of the original project.
*/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
color: #222;
font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
font-size: 16px;
}
body {
padding: 1rem;
background-image: url("/assets/images/backgrounds/snowstorm.jpg");
}
div#container {
width: 90vw;
display: flex;
flex-direction: column;
margin: 0px auto;
}
header {
width: 100%;
display: flex;
justify-content: space-between;
nav {
display: flex;
align-items: center;
justify-content: flex-end;
}
}
section#game {
display: grid;
grid-template-columns: 180px 1fr 180px;
margin: 1rem 0;
border-top: 2px solid #000;
& > aside#left {
grid-column: 1;
border-right: 2px solid #000;
padding: 3px;
}
& > main {
grid-column: 2;
padding: 3px;
}
& > aside#right {
grid-column: 3;
border-left: 2px solid #000;
padding: 3px;
}
}
a {
color: #663300;
text-decoration: none;
font-weight: bold;
&:hover {
color: #330000;
}
}
.small {
font-size: 0.75rem;
}
.highlight {
color: red;
}
.light {
color: #999999;
}
.title {
border: solid 1px black;
background-color: #eeeeee;
font-weight: bold;
padding: 5px;
margin: 3px;
}
footer {
display: flex;
justify-content: center;
font-size: 0.75rem;
padding: 0.5rem 0;
& > div {
flex: 0 0 25%;
text-align: center;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

BIN
assets/images/bars_red.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

BIN
assets/images/compass.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

BIN
assets/images/logo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/images/map.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

BIN
assets/images/town_1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/town_2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/town_3.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/town_4.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/images/town_5.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/town_6.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/images/town_7.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/images/town_8.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,4 @@
// Package middleware provides reusable HTTP middleware for the Dragon Knight server.
// Middleware functions wrap request handlers to add cross-cutting functionality
// like timing, logging, authentication, and request processing.
package middleware

View File

@ -0,0 +1,49 @@
package middleware
import (
"fmt"
"time"
"dk/internal/router"
)
const RequestTimerKey = "request_start_time"
// Timing adds request timing functionality
func Timing() router.Middleware {
return func(next router.Handler) router.Handler {
return func(ctx router.Ctx, params []string) {
startTime := time.Now()
ctx.SetUserValue(RequestTimerKey, startTime)
next(ctx, params)
}
}
}
// GetRequestTime returns the total request processing time in seconds (formatted)
func GetRequestTime(ctx router.Ctx) string {
startTime, ok := ctx.UserValue(RequestTimerKey).(time.Time)
if !ok {
return "0"
}
duration := time.Since(startTime)
seconds := duration.Seconds()
if seconds < 0.001 {
return "0"
}
return fmt.Sprintf("%.3f", seconds)
}
// GetRequestDuration returns the raw duration
func GetRequestDuration(ctx router.Ctx) time.Duration {
startTime, ok := ctx.UserValue(RequestTimerKey).(time.Time)
if !ok {
return 0
}
return time.Since(startTime)
}

View File

@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"dk/internal/middleware"
"dk/internal/router"
"dk/internal/template"
@ -23,9 +24,12 @@ func Start(port string) error {
// Initialize router
r := router.New()
// Add timing middleware
r.Use(middleware.Timing())
// Hello world endpoint
r.Get("/", func(ctx router.Ctx, params []string) {
tmpl, err := templateCache.Load("hello.html")
tmpl, err := templateCache.Load("layout.html")
if err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
fmt.Fprintf(ctx, "Template error: %v", err)
@ -34,7 +38,11 @@ func Start(port string) error {
data := map[string]any{
"title": "Dragon Knight",
"message": "Hello World!",
"content": "Hello World!",
"totaltime": middleware.GetRequestTime(ctx),
"numqueries": "0", // Placeholder for now
"version": "1.0.0",
"build": "dev",
}
tmpl.WriteTo(ctx, data)
@ -46,7 +54,7 @@ func Start(port string) error {
// Static file server for /assets
fs := &fasthttp.FS{
Root: assetsDir,
Compress: true,
Compress: false,
}
assetsHandler := fs.NewRequestHandler()

43
templates/layout.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{title}</title>
<link rel="stylesheet" href="/assets/dk.css">
<script>
function open_char_popup()
{
window.open("/showchar", "", "width=210,height=500,scrollbars")
}
function open_map_popup()
{
window.open("/showmap", "", "width=520,height=520,scrollbars")
}
</script>
</head>
<body>
<div id="container">
<header>
<div><img src="/assets/images/logo.gif" alt="Dragon Knight" title="Dragon Knight"></div>
<nav>{topnav}</nav>
</header>
<section id="game">
<aside id="left">{leftside}</aside>
<main>{content}</main>
<aside id="right">{rightside}</aside>
</section>
<footer>
<div>Powered by <a href="/">Dragon Knight</a></div>
<div>&copy; 2025 Sharkk</div>
<div>{totaltime} Seconds, {numqueries} Queries</div>
<div>Version {version} {build}</div>
</footer>
</div>
</body>
</html>