diff --git a/assets/dk.css b/assets/dk.css index a6c0206..471bc23 100644 --- a/assets/dk.css +++ b/assets/dk.css @@ -391,3 +391,7 @@ div.modal { justify-content: center; } } + +.mt-1 { + margin-top: 1rem; +} diff --git a/assets/scripts/confirm_modal.js b/assets/scripts/confirm_modal.js new file mode 100644 index 0000000..47e9c07 --- /dev/null +++ b/assets/scripts/confirm_modal.js @@ -0,0 +1,62 @@ +class ConfirmModal { + constructor(options = {}) { + this.modal = document.querySelector(options.modalSelector || "#confirm-modal") + this.message = this.modal.querySelector(options.messageSelector || "#msg") + this.confirmBtn = this.modal.querySelector(options.confirmSelector || "#confirm") + this.cancelBtn = this.modal.querySelector(options.cancelSelector || "#cancel") + this.linkSelector = options.linkSelector || '.confirm-link' + this.messageGenerator = options.messageGenerator || this.defaultMessageGenerator.bind(this) + this.currentUrl = null + + if (options.confirmText) this.confirmBtn.textContent = options.confirmText + if (options.cancelText) this.cancelBtn.textContent = options.cancelText + + this.init() + } + + init() { + document.querySelectorAll(this.linkSelector).forEach(link => { + link.addEventListener('click', (e) => { + e.preventDefault() + const message = this.messageGenerator(link) + this.show(link.href, message) + }) + }) + + this.confirmBtn.addEventListener('click', () => this.confirm()) + this.cancelBtn.addEventListener('click', () => this.hide()) + + this.modal.addEventListener('click', (e) => { + if (e.target === this.modal) this.hide() + }) + + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && this.modal.style.display === 'block') { + this.hide() + } + }) + } + + defaultMessageGenerator(link) { + return link.dataset.message || 'Are you sure you want to continue?' + } + + show(url, message) { + this.currentUrl = url + this.message.textContent = message + this.modal.style.display = 'block' + this.confirmBtn.focus() + } + + hide() { + this.modal.style.display = 'none' + this.currentUrl = null + } + + confirm() { + if (this.currentUrl) { + window.location.href = this.currentUrl + } + this.hide() + } +} diff --git a/internal/components/page.go b/internal/components/page.go index 87644bb..6620c66 100644 --- a/internal/components/page.go +++ b/internal/components/page.go @@ -10,6 +10,7 @@ import ( "dk/internal/csrf" "dk/internal/middleware" "dk/internal/router" + "dk/internal/session" "dk/internal/template" ) @@ -24,6 +25,8 @@ func RenderPage(ctx router.Ctx, title, tmplPath string, additionalData map[strin return fmt.Errorf("failed to load layout template: %w", err) } + sess := ctx.UserValue("session").(*session.Session) + var m runtime.MemStats runtime.ReadMemStats(&m) @@ -36,6 +39,8 @@ func RenderPage(ctx router.Ctx, title, tmplPath string, additionalData map[strin "_build": "dev", "user": auth.GetCurrentUser(ctx), "_memalloc": m.Alloc / 1024 / 1024, + "_errormsg": sess.GetFlashMessage("error"), + "_successmsg": sess.GetFlashMessage("success"), } maps.Copy(data, LeftAside(ctx)) diff --git a/internal/components/topnav.go b/internal/components/topnav.go deleted file mode 100644 index 37a7dcf..0000000 --- a/internal/components/topnav.go +++ /dev/null @@ -1,23 +0,0 @@ -package components - -import ( - "dk/internal/auth" - "dk/internal/csrf" - "dk/internal/router" - "fmt" -) - -// GenerateTopNav generates the top navigation HTML based on authentication status -func GenerateTopNav(ctx router.Ctx) string { - if auth.IsAuthenticated(ctx) { - return fmt.Sprintf(`
- %s - -
- Help`, csrf.HiddenField(ctx)) - } else { - return `Log In - Register - Help` - } -} diff --git a/internal/routes/index.go b/internal/routes/index.go index 4411d0a..91526f4 100644 --- a/internal/routes/index.go +++ b/internal/routes/index.go @@ -99,5 +99,6 @@ func Teleport(ctx router.Ctx, params []string) { user.Currently = "In Town" user.Save() + sess.SetFlash("success", "You teleported to "+town.Name+" successfully!") ctx.Redirect("/town", 302) } diff --git a/internal/session/session.go b/internal/session/session.go index ce26fe8..e6fd57d 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -71,6 +71,16 @@ func (s *Session) GetFlash(key string) (any, bool) { return value, exists } +// GetFlashMessage retrieves and removes a flash message as string or empty string +func (s *Session) GetFlashMessage(key string) string { + if flash, exists := s.GetFlash(key); exists { + if msg, ok := flash.(string); ok { + return msg + } + } + return "" +} + // RegenerateID creates a new session ID and updates storage func (s *Session) RegenerateID() { oldID := s.ID diff --git a/templates/auth/login.html b/templates/auth/login.html index e36f096..e4d1d8a 100644 --- a/templates/auth/login.html +++ b/templates/auth/login.html @@ -3,8 +3,6 @@ {block "content"}

Log In

-{error_message} -
{csrf} diff --git a/templates/auth/register.html b/templates/auth/register.html index 013efc9..15a9d0c 100644 --- a/templates/auth/register.html +++ b/templates/auth/register.html @@ -3,8 +3,6 @@ {block "content"}

Register

-{error_message} - {csrf} diff --git a/templates/flashes.html b/templates/flashes.html new file mode 100644 index 0000000..c1444ee --- /dev/null +++ b/templates/flashes.html @@ -0,0 +1,7 @@ +{if _errormsg != ""} +
{_errormsg}
+{/if} + +{if _successmsg != ""} +
{_successmsg}
+{/if} diff --git a/templates/intro.html b/templates/intro.html index 47dee9a..2be2b98 100644 --- a/templates/intro.html +++ b/templates/intro.html @@ -1,5 +1,5 @@ {include "layout.html"} {block "content"} -Hey there, Guest! -{/block} \ No newline at end of file +Hey there! +{/block} diff --git a/templates/layout.html b/templates/layout.html index 5b1996f..2e1cef5 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -8,6 +8,8 @@ + + diff --git a/templates/rightside.html b/templates/rightside.html index fcd8a7a..d41ba18 100644 --- a/templates/rightside.html +++ b/templates/rightside.html @@ -20,19 +20,20 @@
MP - +
TP
- + - + Extended Stats
Inventory
+
Weapon {if user.WeaponName != ""} @@ -60,6 +61,13 @@ {if user.Slot1Name != ""}{slot1name}{/if} {if user.Slot2Name != ""}{slot2name}{/if} {if user.Slot3Name != ""}{slot3name}{/if} + +
    +
  • Strength: {user.Strength}
  • +
  • Dexterity: {user.Dexterity}
  • +
  • Attack: {user.Attack}
  • +
  • Defense: {user.Defense}
  • +
@@ -71,4 +79,4 @@ {else} No known healing spells {/if} -
\ No newline at end of file + diff --git a/templates/town/maps.html b/templates/town/maps.html index 4fbe26a..7099944 100644 --- a/templates/town/maps.html +++ b/templates/town/maps.html @@ -3,7 +3,6 @@ {block "content"}

{town.Name} Maps

- {error_message}

Buying maps will put the town in your Travel To box, and it won't cost you as many TP to get there.

Click a town name to purchase its map.

@@ -16,7 +15,7 @@ {if map.Owned == false} {if user.Gold >= map.Cost} - {map.Name} + {map.Name} {else} {map.Name} {/if} @@ -44,76 +43,18 @@

If you've changed your mind, you may also return back to town.

- -
{/block} {block "scripts"} {/block} diff --git a/templates/town/shop.html b/templates/town/shop.html index b268cb9..8bce181 100644 --- a/templates/town/shop.html +++ b/templates/town/shop.html @@ -3,11 +3,10 @@ {block "content"}

{town.Name} Shop

- {error_message}

Buying weapons will increase your Attack. Buying armor and shields will increase your Defense.

Click an item name to purchase it.

-

The following items are available at this town:

+

The following items are available in {town.Name}:

@@ -38,7 +37,7 @@ {item.Att} - {if item.Type == 1}Attack{else}Defense{/if} + {if item.Type == 1}Attack{else}Defense{/if} {if user.WeaponID == item.ID or user.ArmorID == item.ID or user.ShieldID == item.ID} @@ -59,76 +58,18 @@

If you've changed your mind, you may also return back to town.

- -
{/block} {block "scripts"} {/block}