diff --git a/public/css/admin.css b/public/css/admin.css
index c871959..17c7229 100644
--- a/public/css/admin.css
+++ b/public/css/admin.css
@@ -1,5 +1,6 @@
:root {
--font-size: 16px;
+ --font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
* {
@@ -10,7 +11,7 @@
html {
font-size: var(--font-size);
- font-family: sans-serif;
+ font-family: var(--font-family);
}
body {
@@ -49,6 +50,37 @@ main > section {
table {
width: 100%;
+ border-collapse: collapse;
+ outline-width: none;
+ font-family: var(--font-family);
+ border: 1px solid rgba(0, 0, 0, 0.1);
+
+ & > caption {
+ margin: 1rem;
+ }
+
+ & :is(td,th) {
+ border: 1px solid rgba(0, 0, 0, 0.4);
+ padding: 0.5rem 1rem;
+ }
+
+ & thead tr {
+ background: rgba(0, 0, 0, 0.1);
+ }
+
+ & tbody tr:nth-of-type(even) {
+ background: rgba(0, 0, 0, 0.1);
+ &:hover { background: rgba(0, 0, 0, 0.2); }
+ }
+
+ td:hover {
+ color: white;
+ background: rgba(0, 0, 0, 0.1);
+ }
+
+ tr:hover {
+ background: rgba(0, 0, 0, 0.2);
+ }
}
a {
diff --git a/src/actions/admin.php b/src/actions/admin.php
index 776fc24..bb8bdad 100644
--- a/src/actions/admin.php
+++ b/src/actions/admin.php
@@ -5,10 +5,11 @@
namespace Admin;
use Router;
+use SQLite3Result;
function register_routes(Router $r): Router
{
- if (user()->authlevel === 1) {
+ if (user() !== false && user()->authlevel === 1) {
$r->get('/admin', 'Admin\donothing');
$r->form('/admin/main', 'Admin\primary');
@@ -111,21 +112,9 @@ function primary(): string
*/
function items(): string
{
- $items = db()->query('SELECT id, name FROM items ORDER BY id;');
- $page = "
Edit Items
Click an item's name to edit it.
\n";
-
- $hasItems = false;
- while ($row = $items->fetchArray(SQLITE3_BOTH)) {
- $hasItems = true;
- $page .= <<
- {$row["id"]} |
- {$row["name"]} |
-
- HTML;
- }
-
- if (!$hasItems) $page .= "No items found. |
\n";
+ $items = db()->query('SELECT * FROM items ORDER BY id;');
+ $page = "Edit Items
Click an item's name or ID to edit it.
\n";
+ $page .= build_bulk_table($items, 'name', '/admin/items');
page_title('Admin: Items');
return \Render\content($page . '
', 'layouts/admin');
@@ -174,21 +163,9 @@ function edit_item(int $id): string
*/
function drops()
{
+ $drops = db()->query('SELECT * FROM drops ORDER BY id;');
$page = "Edit Drops
Click an item's name to edit it.
\n";
-
- $drops = db()->query('SELECT id, name FROM drops ORDER BY id;');
- $has_drops = false;
- while ($row = $drops->fetchArray(SQLITE3_ASSOC)) {
- $has_drops = true;
- $page .= <<
- {$row["id"]} |
- {$row["name"]} |
-
- HTML;
- }
-
- if (!$has_drops) { $page .= "No drops found. |
\n"; }
+ $page .= build_bulk_table($drops, 'name', '/admin/drops');
page_title('Admin: Drops');
return \Render\content($page . '
', 'layouts/admin');
@@ -870,3 +847,41 @@ function addnews()
display_admin($page, "Add News");
}
+
+/**
+ * Build an HTML table containing all columns and rows of a given data structure. Takes a SQLiteResult3 of a SELECT *
+ * query.
+ */
+function build_bulk_table(SQLite3Result $query_data, string $edit_column, string $edit_link): string
+{
+ $data = [];
+ while ($row = $query_data->fetchArray(SQLITE3_ASSOC)) $data[] = $row;
+ if (empty($data)) return 'No data.';
+
+ $columns = array_diff(array_keys($data[0]), ['password']); // Filter columns inline
+ $html = '';
+ foreach ($columns as $_) $html .= '';
+ $html .= '';
+ foreach ($columns as $column) {
+ if ($column === 'id') $column = 'ID';
+ $html .= '' . make_safe(ucfirst($column)) . ' | ';
+ }
+ $html .= '
';
+
+ foreach ($data as $row) {
+ $html .= '';
+ foreach ($columns as $column) {
+ $name = make_safe($row[$column]);
+ if (in_array($column, ['id', $edit_column])) {
+ $html .= <<{$name}
+ HTML;
+ } else {
+ $html .= "$name | ";
+ }
+ }
+ $html .= '
';
+ }
+
+ return $html . '
';
+}
diff --git a/src/actions/install.php b/src/actions/install.php
index fc64d21..194d267 100644
--- a/src/actions/install.php
+++ b/src/actions/install.php
@@ -21,7 +21,7 @@ function register_routes(Router $r): Router
*/
function first()
{
- echo <<
Dragon Knight Installation
@@ -43,7 +43,7 @@ function second()
{
if (file_exists('../database.db')) unlink('../database.db');
- echo "Dragon Knight InstallationDragon Knight Installation: Page Two
";
+ $page = "Dragon Knight InstallationDragon Knight Installation: Page Two
";
$query = db()->exec(<<exec(<<exec(<<exec(<<exec(<<exec(<<exec(<<exec(<<exec(<<exec(<<exec(<<exec("INSERT INTO news (content) VALUES ('This is the first news post. Please use the admin control panel to add another one and make this one go away.');");
- echo table_status_msg($query === true, 'News', 'populate');
+ $page .= table_status_msg($query === true, 'News', 'populate');
$query = db()->exec(<<exec(<<exec(<<exec(<<exec(<<Database setup complete in $time seconds.
Click here to continue with installation.";
+ return $page . "
Database setup complete in $time seconds.
Click here to continue with installation.";
}
/**
@@ -629,7 +629,7 @@ function second()
*/
function third()
{
- echo <<
Dragon Knight Installation
@@ -678,7 +678,7 @@ function fourth()
file_put_contents('../.installed', date('Y-m-d H:i:s'));
- echo <<
Dragon Knight Installation
@@ -708,7 +708,7 @@ function fifth()
exit('Dragon Knight was unable to send your URL. Please go back and try again, or just continue on to the game.');
}
- echo <<
Dragon Knight Installation
diff --git a/src/actions/users.php b/src/actions/users.php
index ac73490..8f100fb 100644
--- a/src/actions/users.php
+++ b/src/actions/users.php
@@ -26,8 +26,7 @@ function login()
if (is_post()) {
$form = validate($_POST, [
'username' => ['length:3-18', 'alpha-spaces'],
- 'password' => ['length:6-255'],
- 'remember' => ['bool']
+ 'password' => ['length:6-255']
]);
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
diff --git a/src/bootstrap.php b/src/bootstrap.php
index 34304f1..b752958 100644
--- a/src/bootstrap.php
+++ b/src/bootstrap.php
@@ -23,11 +23,18 @@ $uri = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
$GLOBALS['cache'] = [];
$GLOBALS['state'] = [];
-if (!file_exists('../.installed') && $uri[0] !== 'install') {
+/**
+ * These are table names whose data we want to be able to edit in the admin panel in bulk.
+ */
+define('ADMIN_BULK_DATA_STRUCTS', [
+ 'users', 'items', 'drops', 'towns', 'monsters', 'levels', 'spells'
+]);
+
+if (!file_exists('../.installed') && $uri[0] !== 'install') { // need to install the game
redirect('/install');
-} elseif (file_exists(('../.installed')) && $uri[0] === 'install') {
+} elseif (file_exists(('../.installed')) && $uri[0] === 'install') { // game is installed, go play!
redirect('/');
-} elseif (file_exists(('../.installed')) && $uri[0] !== 'install') {
+} elseif (file_exists(('../.installed')) && $uri[0] !== 'install') { // boostrap the game
if (!env('game_open')) {
echo Render\content('The game is currently closed for maintanence. Please check back later.');
exit;