style updates, finish shop table, add shop modal
This commit is contained in:
parent
7a90f296b2
commit
90923cbfe7
@ -104,7 +104,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.light {
|
.light {
|
||||||
color: #999999;
|
color: rgba(0, 0, 0, 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.title {
|
div.title {
|
||||||
@ -186,7 +186,7 @@ button.btn {
|
|||||||
background-color: #808080;
|
background-color: #808080;
|
||||||
background-image: url("/assets/images/overlay.png");
|
background-image: url("/assets/images/overlay.png");
|
||||||
border: 1px solid #808080;
|
border: 1px solid #808080;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.25rem 0.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: white;
|
color: white;
|
||||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
@ -195,6 +195,18 @@ button.btn {
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: #909090;
|
background-color: #909090;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.btn-primary {
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form.standard {
|
form.standard {
|
||||||
@ -325,3 +337,61 @@ div#statbars {
|
|||||||
.inline-block {
|
.inline-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.item-shop {
|
||||||
|
width: 80%;
|
||||||
|
margin: 0px auto;
|
||||||
|
|
||||||
|
td:first-child {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
& > div.content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: white;
|
||||||
|
padding: 1.25rem;
|
||||||
|
min-width: 300px;
|
||||||
|
text-align: center;
|
||||||
|
background-image: url("/assets/images/backgrounds/snowstorm.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
div.buttons {
|
||||||
|
margin-top: 20px;
|
||||||
|
gap: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"dk/internal/template/components"
|
"dk/internal/template/components"
|
||||||
"dk/internal/towns"
|
"dk/internal/towns"
|
||||||
"dk/internal/users"
|
"dk/internal/users"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterTownRoutes(r *router.Router) {
|
func RegisterTownRoutes(r *router.Router) {
|
||||||
@ -33,10 +32,17 @@ func showTown(ctx router.Ctx, _ []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func showInn(ctx router.Ctx, _ []string) {
|
func showInn(ctx router.Ctx, _ []string) {
|
||||||
|
var errorHTML string
|
||||||
|
if flash := auth.GetFlashMessage(ctx); flash != nil {
|
||||||
|
errorHTML = `<div style="color: red; margin-bottom: 1rem;">` + flash.Message + "</div>"
|
||||||
|
}
|
||||||
|
|
||||||
town := ctx.UserValue("town").(*towns.Town)
|
town := ctx.UserValue("town").(*towns.Town)
|
||||||
|
|
||||||
components.RenderPage(ctx, town.Name+" Inn", "town/inn.html", map[string]any{
|
components.RenderPage(ctx, town.Name+" Inn", "town/inn.html", map[string]any{
|
||||||
"town": town,
|
"town": town,
|
||||||
"rested": false,
|
"rested": false,
|
||||||
|
"error_message": errorHTML,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +51,8 @@ func rest(ctx router.Ctx, _ []string) {
|
|||||||
user := ctx.UserValue("user").(*users.User)
|
user := ctx.UserValue("user").(*users.User)
|
||||||
|
|
||||||
if user.Gold < town.InnCost {
|
if user.Gold < town.InnCost {
|
||||||
fmt.Println("Cant afford")
|
auth.SetFlashMessage(ctx, "error", "You can't afford to stay here tonight.")
|
||||||
ctx.Redirect("/town", 303)
|
ctx.Redirect("/town/inn", 303)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +69,11 @@ func rest(ctx router.Ctx, _ []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func showShop(ctx router.Ctx, _ []string) {
|
func showShop(ctx router.Ctx, _ []string) {
|
||||||
|
var errorHTML string
|
||||||
|
if flash := auth.GetFlashMessage(ctx); flash != nil {
|
||||||
|
errorHTML = `<div style="color: red; margin-bottom: 1rem;">` + flash.Message + "</div>"
|
||||||
|
}
|
||||||
|
|
||||||
town := ctx.UserValue("town").(*towns.Town)
|
town := ctx.UserValue("town").(*towns.Town)
|
||||||
|
|
||||||
var itemlist []*items.Item
|
var itemlist []*items.Item
|
||||||
@ -77,7 +88,8 @@ func showShop(ctx router.Ctx, _ []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
components.RenderPage(ctx, town.Name+" Shop", "town/shop.html", map[string]any{
|
components.RenderPage(ctx, town.Name+" Shop", "town/shop.html", map[string]any{
|
||||||
"town": town,
|
"town": town,
|
||||||
"itemlist": itemlist,
|
"itemlist": itemlist,
|
||||||
|
"error_message": errorHTML,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -671,7 +671,18 @@ func (t *Template) findElseAtLevel(content string) int {
|
|||||||
func (t *Template) evaluateCondition(condition string, data map[string]any) bool {
|
func (t *Template) evaluateCondition(condition string, data map[string]any) bool {
|
||||||
condition = strings.TrimSpace(condition)
|
condition = strings.TrimSpace(condition)
|
||||||
|
|
||||||
// Handle 'and' operator
|
// Handle 'or' operator (lower precedence)
|
||||||
|
if strings.Contains(condition, " or ") {
|
||||||
|
parts := strings.SplitSeq(condition, " or ")
|
||||||
|
for part := range parts {
|
||||||
|
if t.evaluateCondition(strings.TrimSpace(part), data) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle 'and' operator (higher precedence)
|
||||||
if strings.Contains(condition, " and ") {
|
if strings.Contains(condition, " and ") {
|
||||||
parts := strings.SplitSeq(condition, " and ")
|
parts := strings.SplitSeq(condition, " and ")
|
||||||
for part := range parts {
|
for part := range parts {
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="btn" type="submit">Log in</button>
|
<button class="btn btn-primary" type="submit">Log in</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -48,5 +48,7 @@
|
|||||||
<div>Version {_version} {_build}</div>
|
<div>Version {_version} {_build}</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{yield "scripts"}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
{block "content"}
|
{block "content"}
|
||||||
<div class="town shop">
|
<div class="town shop">
|
||||||
|
<div class="title"><h3>{town.Name} Shop</h3></div>
|
||||||
|
{error_message}
|
||||||
<section>
|
<section>
|
||||||
<div class="title"><h3>{town.Name} Shop</h3></div>
|
|
||||||
<p>Buying weapons will increase your Attack. Buying armor and shields will increase your Defense.</p>
|
<p>Buying weapons will increase your Attack. Buying armor and shields will increase your Defense.</p>
|
||||||
<p>Click an item name to purchase it.</p>
|
<p>Click an item name to purchase it.</p>
|
||||||
<p>The following items are available at this town:</p>
|
<p>The following items are available at this town:</p>
|
||||||
@ -25,7 +26,30 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{item.Name}
|
{if user.WeaponID == item.ID or user.ArmorID == item.ID or user.ShieldID == item.ID}
|
||||||
|
<span class="light">{item.Name}</span>
|
||||||
|
{else}
|
||||||
|
{if user.Gold >= item.Value}
|
||||||
|
<a class="buy-item" data-item="{item.Name}" data-cost="{item.Value}" href="/town/shop/buy/{item.ID}">{item.Name}</a>
|
||||||
|
{else}
|
||||||
|
<span class="light">{item.Name}</span>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{item.Att}
|
||||||
|
<span class="light">{if item.Type == 1}Attack{else}Defense{/if}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{if user.WeaponID == item.ID or user.ArmorID == item.ID or user.ShieldID == item.ID}
|
||||||
|
<span class="light">Already owned</span>
|
||||||
|
{else}
|
||||||
|
{if user.Gold >= item.Value}
|
||||||
|
{item.Value}G
|
||||||
|
{else}
|
||||||
|
<span class="light">{item.Value}G (can't afford)</span>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/for}
|
{/for}
|
||||||
@ -35,5 +59,76 @@
|
|||||||
<section>
|
<section>
|
||||||
<p>If you've changed your mind, you may also return back to <a href="/town">town</a>.</p>
|
<p>If you've changed your mind, you may also return back to <a href="/town">town</a>.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<div id="shop-modal" class="modal">
|
||||||
|
<div class="content">
|
||||||
|
<p id="msg">Are you sure you want to buy this item?</p>
|
||||||
|
<div class="buttons">
|
||||||
|
<button id="confirm" class="btn btn-primary">Buy Now</button>
|
||||||
|
<button id="cancel" class="btn">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
{block "scripts"}
|
||||||
|
<script>
|
||||||
|
class ShopModal {
|
||||||
|
constructor() {
|
||||||
|
this.modal = document.querySelector("#shop-modal")
|
||||||
|
this.message = this.modal.querySelector("#msg")
|
||||||
|
this.confirmBtn = this.modal.querySelector("#confirm")
|
||||||
|
this.cancelBtn = this.modal.querySelector("#cancel")
|
||||||
|
this.currentUrl = null
|
||||||
|
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
document.querySelectorAll('.buy-item').forEach(link => {
|
||||||
|
link.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
this.show(link.href, link.dataset.item, link.dataset.cost)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
show(url, itemName, itemCost) {
|
||||||
|
this.currentUrl = url
|
||||||
|
this.message.textContent = `Are you sure you want to buy ${itemName} for ${itemCost}G?`
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
new ShopModal()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{/block}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user