Nav menu, styling changes, start world map

This commit is contained in:
Sky Johnson 2024-10-10 13:14:14 -05:00
parent 3c0e7590ce
commit a564a96625
21 changed files with 306 additions and 72 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,9 @@
@import '/assets/css/forms.css'; @import '/assets/css/forms.css';
:root {
font-size: 16px;
}
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -115,24 +119,138 @@ header {
main { main {
padding: 1rem; padding: 1rem;
display: grid; width: 100%;
grid-template-columns: 1fr 8fr 1fr; display: flex;
gap: 2rem; gap: 2rem;
#center {
flex: 1;
}
} }
aside#left { aside {
min-width: 200px;
.box { .box {
background-color: rgba(0, 0, 0, 0.2); background-color: rgba(0, 0, 0, 0.2);
border-radius: 0.15rem; border-radius: 0.15rem;
}
}
&#nav > a { aside#left nav {
& > *:not(:last-child) {
margin-bottom: 0.25rem;
}
div.stack {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 0.15rem;
input[type="checkbox"] {
display: none;
&:checked ~ div.list {
display: block; display: block;
width: 100%; }
&:checked + label {
background-color: rgba(0, 0, 0, 0.5);
color: white;
}
}
label {
display: flex;
align-items: center;
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
border-radius: 0.15rem; border-radius: 0.15rem;
text-decoration: none; text-decoration: none;
color: black; color: black;
transition: color, background-color 0.2s ease; transition: color, background-color 0.2s ease;
cursor: pointer;
img {
height: 18px;
margin-right: 0.25rem;
}
span.text {
display: block;
width: 100%;
}
&:hover {
color: white;
background-color: rgba(0, 0, 0, 0.3);
}
span.arrow {
position: relative;
top: 5px;
}
}
div.list {
display: none;
& > a {
display: block;
width: 100%;
padding: 0.5rem 1rem 0.5rem 1.35rem;
border-radius: 0.15rem;
text-decoration: none;
color: black;
transition: color, background-color 0.2s ease;
&:not(:last-child)::before {
content: '├';
display: inline-block;
margin-right: 0.25rem;
}
&:last-child::before {
content: '└';
display: inline-block;
position: relative;
top: 3px;
margin-right: 0.25rem;
}
&:hover {
background-color: rgba(0, 0, 0, 0.3);
}
&.active {
background-color: #444c55;
color: #ffffff;
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
border: 1px solid;
border-color: #3D444C #2F353B #2C3137;
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
}
}
}
}
& > a {
display: block;
width: 100%;
padding: 0.5rem 1rem;
text-decoration: none;
color: black;
transition: color, background-color 0.2s ease;
background-color: rgba(0, 0, 0, 0.2);
border-radius: 0.15rem;
&:has(img) {
display: flex;
align-items: center;
img {
height: 18px;
margin-right: 0.25rem;
}
}
&:hover, &.active { &:hover, &.active {
color: white; color: white;
@ -151,7 +269,6 @@ aside#left {
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset; box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
} }
} }
}
} }
footer { footer {
@ -171,12 +288,18 @@ footer {
#char-bar { #char-bar {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-around;
padding: 0 1rem; padding: 0 1rem;
height: 34px; height: 34px;
color: white; color: white;
gap: 1rem; gap: 1rem;
background-image: url('/assets/img/bar.jpg'); background-image: url('/assets/img/bar.jpg');
& > div.container {
display: flex;
align-items: center;
gap: 1rem;
& > div { & > div {
display: flex; display: flex;
align-items: center; align-items: center;
@ -186,6 +309,7 @@ footer {
margin-right: 0.5rem; margin-right: 0.5rem;
} }
} }
}
} }
span.badge { span.badge {
@ -325,6 +449,9 @@ h1:has(.badge), h2:has(.badge), h3:has(.badge), h4:has(.badge), h5:has(.badge),
transition: opacity .1s ease, color .1s ease, background .1s ease, box-shadow .1s ease; transition: opacity .1s ease, color .1s ease, background .1s ease, box-shadow .1s ease;
border-radius: .28571429rem; border-radius: .28571429rem;
box-shadow: 0 0 0 1px rgba(34, 36, 38, .22) inset, 0 0 0 0 transparent; box-shadow: 0 0 0 1px rgba(34, 36, 38, .22) inset, 0 0 0 0 transparent;
display: flex;
align-items: center;
justify-content: space-between;
&.success { &.success {
background-color: #f0f9eb; background-color: #f0f9eb;
@ -355,6 +482,13 @@ h1:has(.badge), h2:has(.badge), h3:has(.badge), h4:has(.badge), h5:has(.badge),
color: #2c2c2c; color: #2c2c2c;
border-color: #b3b3b3; border-color: #b3b3b3;
} }
a[alert-close] {
text-decoration: none;
cursor: pointer;
font-size: 2rem;
color: inherit;
}
} }
a { a {
@ -367,3 +501,19 @@ a {
text-decoration: underline; text-decoration: underline;
} }
} }
body::-webkit-scrollbar {
width: 0.5rem;
}
body::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
}
body::-webkit-scrollbar-thumb {
background-color: #444c55;
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
border: 1px solid;
border-color: #3D444C #2F353B #2C3137;
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
}

View File

@ -52,9 +52,14 @@
} }
.character-select > .radio-block { .character-select > .radio-block {
display: inline-block;
background-color: rgba(0, 0, 0, 0.2); background-color: rgba(0, 0, 0, 0.2);
border-radius: 0.15rem; border-radius: 0.15rem;
&:not(:last-child) {
margin-bottom: 0.25rem;
}
& > input[type="radio"] { & > input[type="radio"] {
display: none; display: none;
} }
@ -81,7 +86,7 @@
& > span.selected { & > span.selected {
display: none; display: none;
margin-left: auto; margin-left: 1rem;
color: #a6e3a1; color: #a6e3a1;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -13,7 +13,8 @@ $r = [];
*/ */
router_get($r, '/', function () { router_get($r, '/', function () {
if (user()) must_have_character(); if (user()) must_have_character();
echo render('layouts/basic', ['view' => 'pages/home', 'activeTab' => nav_tabs['home']]); $GLOBALS['active_nav_tab'] = 'home';
echo render('layouts/basic', ['view' => 'pages/home']);
}); });
/* /*
@ -34,6 +35,15 @@ router_get($r, '/character/create-first', 'char_controller_create_first_get');
router_post($r, '/character/create', 'char_controller_create_post'); router_post($r, '/character/create', 'char_controller_create_post');
router_post($r, '/character/delete', 'char_controller_delete_post'); router_post($r, '/character/delete', 'char_controller_delete_post');
/*
World
*/
router_get($r, '/world', function () {
auth_only_and_must_have_character();
$GLOBALS['active_nav_tab'] = 'world';
echo page('world/base');
});
/* /*
Router Router
*/ */
@ -42,8 +52,10 @@ stopwatch_start('router');
$l = router_lookup($r, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']); $l = router_lookup($r, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
stopwatch_stop('router'); stopwatch_stop('router');
stopwatch_start('handler');
if ($l['code'] !== 200) router_error($l['code']); if ($l['code'] !== 200) router_error($l['code']);
$l['handler'](...$l['params'] ?? []); $l['handler'](...$l['params'] ?? []);
stopwatch_stop('handler');
/* /*
Cleanup Cleanup

View File

@ -1,10 +1,5 @@
<?php <?php
const nav_tabs = [
'home' => 0,
'chars' => 1,
];
/** /**
* Render the logout button's form. * Render the logout button's form.
*/ */
@ -29,13 +24,7 @@ function c_char_bar()
*/ */
function c_left_nav() function c_left_nav()
{ {
$tab = match ($GLOBALS['active_nav_tab'] ?? '') { return render('components/left_nav');
'home' => 0,
'chars' => 1,
default => 0
};
return render('components/left_nav', ['ant' => $tab]);
} }
/** /**
@ -57,9 +46,10 @@ function c_char_select_box($id, $char)
/** /**
* Render an alert with a given type and message. * Render an alert with a given type and message.
*/ */
function c_alert($t, $m) function c_alert($type, $message)
{ {
return "<div class=\"alert $t\">$m</div>"; $a = $type !== 'danger' ? ' auto-close="5000"' : '';
return "<div class=\"alert $type\"$a><div>$message</div> <a alert-close>&times;</a></div>";
} }
/** /**
@ -71,7 +61,8 @@ function c_form_errors($placement = '')
if ($errors === false) return ''; if ($errors === false) return '';
$html = ''; $html = '';
foreach ($errors as $field) foreach ($errors as $field)
foreach ($field as $message) $html .= "<p>$message</p>"; if (!empty($field))
foreach ($field as $message) $html .= !empty($message) ? "<p>$message</p>" : '';
return c_alert('danger', $html); return c_alert('danger', $html);
} }

View File

@ -48,7 +48,7 @@ function char_controller_list_post()
change_user_character($char_id); change_user_character($char_id);
flash('alert_character_list_1', ['success', 'Switched to character <b>' . char('name') . '</b>!']); flash('alert_character_list_1', ['success', 'Switched to <b>' . char('name') . '</b>!']);
} }
// If the action is to delete a character, move to the confirmation page. // If the action is to delete a character, move to the confirmation page.

View File

@ -223,3 +223,11 @@ function stopwatch_get($key)
if (empty($GLOBALS['stopwatch'][$key])) return 0; if (empty($GLOBALS['stopwatch'][$key])) return 0;
return number_format($GLOBALS['stopwatch'][$key], 10); return number_format($GLOBALS['stopwatch'][$key], 10);
} }
/**
* Conditional Echo; if the condition is true, echo the value. If the condition is false, echo the $or value.
*/
function ce($condition, $value, $or = '')
{
echo $condition ? $value : $or;
}

View File

@ -1,4 +1,5 @@
<div id="char-bar"> <div id="char-bar">
<div class="container">
<div> <div>
<img class="icon" src="/assets/img/icons/user1.png" alt="User"> <img class="icon" src="/assets/img/icons/user1.png" alt="User">
<?= $char['name'] ?> <span class="badge ml-2 tooltip-hover" data-tooltip-content="Level"><?= $char['level'] ?></span> <?= $char['name'] ?> <span class="badge ml-2 tooltip-hover" data-tooltip-content="Level"><?= $char['level'] ?></span>
@ -31,4 +32,5 @@
<div> <div>
<?= wallet('silver') ?> Silver <?= wallet('silver') ?> Silver
</div> </div>
</div>
</div> </div>

View File

@ -3,6 +3,6 @@
<label for="char_<?= $id ?>"> <label for="char_<?= $id ?>">
<?= $char['name'] ?> <?= $char['name'] ?>
<span class="badge"><?= $char['level'] ?></span> <span class="badge"><?= $char['level'] ?></span>
<span class="selected">Currently Playing</span> <span class="selected">Active</span>
</label> </label>
</div> </div>

View File

@ -3,4 +3,5 @@
<p class="mb-2">Page execution took <?= number_format((microtime(true) - START_TIME), 10) ?> seconds.</p> <p class="mb-2">Page execution took <?= number_format((microtime(true) - START_TIME), 10) ?> seconds.</p>
<p>Bootstrap: <?= stopwatch_get('bootstrap') ?> seconds</p> <p>Bootstrap: <?= stopwatch_get('bootstrap') ?> seconds</p>
<p>Router: <?= stopwatch_get('router') ?> seconds</p> <p>Router: <?= stopwatch_get('router') ?> seconds</p>
<p>Handler: <?= stopwatch_get('handler') ?> seconds</p>
</div> </div>

View File

@ -1,4 +1,18 @@
<div id="nav" class="box"> <nav>
<a href="/" class="<?= $ant === 0 ? 'active' : '' ?>">Home</a> <?php
<a href="/characters" class="<?= $ant === 1 ? 'active' : '' ?>">Characters</a> const links = [
</div> ['/', 'home', 'home', 'Home'],
['/world', 'world', 'earth', 'World'],
['/profile', 'profile', 'user1', 'Profile'],
['/auctions', 'auctions', 'shop', 'Auctions'],
['/characters', 'chars', 'user1', 'Characters'],
['/settings', 'settings', 'settings', 'Settings']
];
foreach (links as $link): ?>
<a href="<?= $link[0] ?>" class="<?= ce(($GLOBALS['active_nav_tab'] ?? '') == $link[1], 'active') ?>">
<img src="/assets/img/icons/<?= $link[2] ?>.png">
<?= $link[3] ?>
</a>
<?php endforeach; ?>
</nav>

View File

@ -0,0 +1,34 @@
<canvas></canvas>
<script>
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
const tile_height = 32;
const tile_width = 32;
const map = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
// render the map
map.forEach((tile, index) => {
const x = (index % 10) * tile_width;
const y = Math.floor(index / 10) * tile_height;
ctx.fillStyle = tile === 0 ? 'black' : 'white';
ctx.fillRect(x, y, tile_width, tile_height);
});
</script>

View File

@ -27,9 +27,7 @@
<main> <main>
<aside id="left"> <aside id="left">
<?php if (user()): ?> <?php if (user()) echo c_left_nav($activeTab ?? 0); ?>
<?= c_left_nav($activeTab ?? 0) ?>
<?php endif; ?>
</aside> </aside>
<div id="center"> <div id="center">
@ -46,8 +44,8 @@
<footer> <footer>
<p>&copy; <?= date('Y') ?> Dragon Knight</p> <p>&copy; <?= date('Y') ?> Dragon Knight</p>
<p>q<?= $GLOBALS['queries'] ?></p> <p>q<?= $GLOBALS['queries'] ?></p>
<p>qt<?= number_format($GLOBALS['query_time'], env('debug', false) === true ? 6 : 2) ?></p> <p>qt<?= number_format($GLOBALS['query_time'], 3) ?></p>
<p>t<?= number_format((microtime(true) - START_TIME), env('debug', false) === true ? 6 : 2) ?></p> <p>t<?= number_format((microtime(true) - START_TIME), 3) ?></p>
<p>v<?= env('version') ?></p> <p>v<?= env('version') ?></p>
</footer> </footer>
@ -61,5 +59,21 @@
import Tooltip from '/assets/scripts/tooltip.js'; import Tooltip from '/assets/scripts/tooltip.js';
Tooltip.init(); Tooltip.init();
</script> </script>
<script>
// Get all elements with data-alert-close attribute; when clicked, delete parent element
document.querySelectorAll('[alert-close]').forEach(function (el) {
el.addEventListener('click', function () {
el.parentNode.remove();
});
});
// Get all elements with a data-auto-close attribute; after x seconds, delete the element
document.querySelectorAll('[auto-close]').forEach(function (el) {
setTimeout(function () {
el.remove();
}, el.getAttribute('auto-close'));
});
</script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,3 @@
<h1>World</h1>
<?= render('components/world_map') ?>