diff --git a/assets/admin.css b/assets/admin.css new file mode 100644 index 0000000..95069f7 --- /dev/null +++ b/assets/admin.css @@ -0,0 +1,230 @@ +@font-face { + font-family: 'Seagram'; + src: url('/assets/fonts/seagram.ttf') format('truetype'); + font-display: swap; +} + +:root { + color: #222; + font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; + font-size: 16px; +} + +.seagram { + font-family: 'Seagram', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: inherit; + font-size: 1rem; +} + +body { + padding: 1rem; + background-image: url("/assets/images/backgrounds/snowstorm.jpg"); +} + +i { font-style: italic; } +b { font-weight: bold; } + +h1, h2, h3, h4, h5 { + font-family: 'Seagram', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; + margin-bottom: 1rem; +} +h1 { font-size: 2rem; } +h2 { font-size: 1.7rem; } +h3 { font-size: 1.4rem; } +h4 { font-size: 1.1rem; } + +p { + margin-bottom: 1rem; + &:last-child { + margin-bottom: 0; + } +} + +div#container { + max-width: 1024px; + display: grid; + grid-template-columns: 180px 1fr; + margin: 0px auto; + gap: 1rem; + + & > footer { + grid-column: 1 / -1 + } +} + +nav { + border-right: 2px solid black; + padding-bottom: 1rem; + + & > section { + display: flex; + flex-direction: column; + padding-bottom: 1rem; + margin-bottom: 1rem; + border-bottom: 2px solid black; + } +} + +table { + border-collapse: collapse; + + th, td { + padding: 0.5rem; + text-align: left; + border: 1px solid rgba(0, 0, 0, 0.2); + } + + th { + background-color: rgba(0, 0, 0, 0.1); + } + + tr:nth-child(even) { + background-color: rgba(0, 0, 0, 0.05); + } +} + +a { + color: #663300; + text-decoration: none; + font-weight: bold; + cursor: pointer; + + &:hover { + color: #330000; + } +} + +.small { + font-size: 0.75rem; +} + +.highlight { + color: red; +} + +.light { + color: rgba(0, 0, 0, 0.35); +} + +button.btn { + font-family: inherit; + font-size: 1rem; + appearance: none; + outline: none; + background-color: #808080; + background-image: url("/assets/images/overlay.png"); + border: 1px solid #808080; + padding: 0.25rem 0.5rem; + cursor: pointer; + color: white; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2); + text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1); + + &:hover { + background-color: #909090; + } + + &.btn-primary { + color: rgba(0, 0, 0, 0.75); + background-color: #F2994A; + background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #F2C94C, #F2994A); + border-color: #F2994A; + + &:hover { + background-color: #ffb574; + background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #ffd965, #ffb574); + } + } + + &.btn-blue { + background-color: #00c6ff; + background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #00c6ff, #0072ff); + border-color: #0072ff; + + &:hover { + background-color: #49d6fd; + background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #49d6fd, #2987fa); + } + } +} + +form.standard { + & > div.row { + display: flex; + flex-direction: column; + margin-bottom: 1.5rem; + + label { + font-weight: bold; + } + } + + span.help { + font-size: 0.8em; + color: #555; + } + + & > div.actions { + margin-top: 1rem; + } + + input.text { + appearance: none; + outline: none; + border: 1px solid transparent; + padding: 0.25rem 0.25rem; + background-color: rgba(0, 0, 0, 0.4); + color: white; + + &:hover { + background-color: rgba(0, 0, 0, 0.5); + } + + &:focus { + background-color: rgba(0, 0, 0, 0.6); + border-color: black; + } + + &::placeholder { + color: rgba(255, 255, 255, 0.6); + } + } + + textarea.text { + appearance: none; + outline: none; + border: 1px solid transparent; + padding: 0.25rem 0.25rem; + background-color: rgba(0, 0, 0, 0.4); + color: white; + min-height: 100px; + resize: vertical; + + &:hover { + background-color: rgba(0, 0, 0, 0.5); + } + + &:focus { + background-color: rgba(0, 0, 0, 0.6); + border-color: black; + } + + &::placeholder { + color: rgba(255, 255, 255, 0.6); + } + } +} + +.w-full { + width: 100%; +} + +.mb-1 { + margin-bottom: 1rem; +} diff --git a/assets/dk.css b/assets/dk.css index cbdb308..a649848 100644 --- a/assets/dk.css +++ b/assets/dk.css @@ -1,9 +1,3 @@ -/* - 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. -*/ - @font-face { font-family: 'Seagram'; src: url('/assets/fonts/seagram.ttf') format('truetype'); @@ -279,7 +273,7 @@ form.standard { } } - textarea.forum-text { + textarea.text { appearance: none; outline: none; border: 1px solid transparent; @@ -321,8 +315,8 @@ form.standard { } div.town { - & > section:not(:last-child) { - margin-bottom: 2rem; + hr { + margin: 2rem 0; } & > section.split { diff --git a/data/dk.db b/data/dk.db index c8e41cd..f795a41 100644 Binary files a/data/dk.db and b/data/dk.db differ diff --git a/internal/components/page.go b/internal/components/page.go index 0ce4d46..c52ac15 100644 --- a/internal/components/page.go +++ b/internal/components/page.go @@ -6,6 +6,7 @@ import ( "runtime" "strings" + "dk/internal/models/users" "dk/internal/template" sushi "git.sharkk.net/Sharkk/Sushi" @@ -44,7 +45,7 @@ func RenderPage(ctx sushi.Ctx, title, tmplPath string, additionalData map[string "_totaltime": totalTime, "_version": "1.0.0", "_build": "dev", - "user": ctx.GetCurrentUser(), + "user": ctx.GetCurrentUser().(*users.User), "_memalloc": m.Alloc / 1024 / 1024, "_errormsg": sess.GetFlashMessage("error"), "_successmsg": sess.GetFlashMessage("success"), @@ -71,3 +72,44 @@ func PageTitle(title string) string { return title + " - Dragon Knight" } + +// RenderAdminPage renders a page using the admin layout template with common data and additional custom data +func RenderAdminPage(ctx sushi.Ctx, title, tmplPath string, additionalData map[string]any) error { + if template.Cache == nil { + return fmt.Errorf("template.Cache not initialized") + } + + tmpl, err := template.Cache.Load(tmplPath) + if err != nil { + return fmt.Errorf("failed to load layout template: %w", err) + } + + var m runtime.MemStats + runtime.ReadMemStats(&m) + + sess := ctx.GetCurrentSession() + + seconds := timing.GetRequestDuration(ctx).Seconds() + var totalTime string + if seconds < 0.001 { + totalTime = fmt.Sprintf("%.0f", seconds) + } else { + totalTime = fmt.Sprintf("%.3f", seconds) + } + + data := map[string]any{ + "_title": PageTitle(title), + "csrf": csrf.HiddenField(ctx), + "_totaltime": totalTime, + "_version": "1.0.0", + "_build": "dev", + "user": ctx.GetCurrentUser().(*users.User), + "_memalloc": m.Alloc / 1024 / 1024, + "_errormsg": sess.GetFlashMessage("error"), + "_successmsg": sess.GetFlashMessage("success"), + } + + maps.Copy(data, additionalData) + + return tmpl.WriteTo(ctx, data) +} diff --git a/internal/components/town.go b/internal/components/town.go index 5e023a5..444ce4b 100644 --- a/internal/components/town.go +++ b/internal/components/town.go @@ -9,12 +9,12 @@ import ( ) func GenerateTownNews() string { - title := `
+ Welcome to the admin panel! Utilize the tools to the left, or head back. Below + are the server stats as of loading this page. +
+ +Memory Allocated | {alloc_mb} MB |
Total Allocated | {total_alloc_mb} MB |
System Memory | {sys_mb} MB |
Heap Allocated | {heap_alloc_mb} MB |
Heap System | {heap_sys_mb} MB |
Heap Released | {heap_released_mb} MB |
GC Cycles | {gc_cycles} |
GC Pause Total | {gc_pause_total} ms |
Goroutines | {goroutines} |
CPU Cores | {cpu_cores} |
Go Version | {go_version} |
+ Write a new news post that will be displayed in every town! You can use basic markdown to style the post. +
+ + +{/block} diff --git a/templates/forum/new.html b/templates/forum/new.html index 10907d7..c308eac 100644 --- a/templates/forum/new.html +++ b/templates/forum/new.html @@ -8,7 +8,7 @@