UI improvements
parent
45b52fbcf3
commit
fc5c17752a
|
@ -0,0 +1,64 @@
|
||||||
|
import Command from '../command';
|
||||||
|
|
||||||
|
export default class CommandBuilder {
|
||||||
|
constructor() {
|
||||||
|
this.command = new Command();
|
||||||
|
}
|
||||||
|
|
||||||
|
withName(name) {
|
||||||
|
this.command.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withAliases(aliases) {
|
||||||
|
this.command.aliases = Array.isArray(aliases) ? aliases : [aliases];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withCategory(category) {
|
||||||
|
this.command.category = category;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withDescription(description) {
|
||||||
|
this.command.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withArguments(args) {
|
||||||
|
this.command.arguments = args;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withArgument(type, name, optional = false, description = '') {
|
||||||
|
if (!this.command.arguments) {
|
||||||
|
this.command.arguments = [];
|
||||||
|
}
|
||||||
|
this.command.arguments.push({
|
||||||
|
type,
|
||||||
|
name,
|
||||||
|
optional,
|
||||||
|
description
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withHandler(handler) {
|
||||||
|
this.command.handler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
isAsync(value = true) {
|
||||||
|
this.command.async = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
withMetadata(metadata) {
|
||||||
|
Object.assign(this.command, metadata);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
return this.command;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
export default class Command {
|
||||||
|
constructor() {
|
||||||
|
this.name = '';
|
||||||
|
this.aliases = [];
|
||||||
|
this.category = '';
|
||||||
|
this.description = '';
|
||||||
|
this.arguments = [];
|
||||||
|
this.handler = null;
|
||||||
|
this.async = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(args, context) {
|
||||||
|
if (this.handler) {
|
||||||
|
return this.handler(args, context);
|
||||||
|
}
|
||||||
|
throw new Error(`Command ${this.name} has no handler defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMetadata() {
|
||||||
|
return {
|
||||||
|
category: this.category,
|
||||||
|
description: this.description,
|
||||||
|
arguments: this.arguments,
|
||||||
|
async: this.async
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllNames() {
|
||||||
|
return [this.name, ...this.aliases];
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,15 +9,15 @@ import VolumeCommand from "./commands/volume";
|
||||||
import InventoryCommand from "./commands/inventory";
|
import InventoryCommand from "./commands/inventory";
|
||||||
|
|
||||||
const defaultCommands = [
|
const defaultCommands = [
|
||||||
[["look", "l"], LookCommand],
|
LookCommand,
|
||||||
[["use", "interact"], UseCommand],
|
UseCommand,
|
||||||
[["take", "get"], TakeCommand],
|
TakeCommand,
|
||||||
[["drop", "put"], DropCommand],
|
DropCommand,
|
||||||
["echo", EchoCommand],
|
EchoCommand,
|
||||||
["save", SaveCommand],
|
SaveCommand,
|
||||||
["load", LoadCommand],
|
LoadCommand,
|
||||||
["volume", VolumeCommand],
|
VolumeCommand,
|
||||||
[["i", "inv", "inventory"], InventoryCommand]
|
InventoryCommand
|
||||||
];
|
];
|
||||||
|
|
||||||
const directionMap = [
|
const directionMap = [
|
||||||
|
@ -49,8 +49,15 @@ export default class Commands {
|
||||||
}
|
}
|
||||||
const room = this.context.getRoom(this.context.player.currentRoom);
|
const room = this.context.getRoom(this.context.player.currentRoom);
|
||||||
const split = str.split(" ");
|
const split = str.split(" ");
|
||||||
if (this.commands.get(split[0])) {
|
const command = this.commands.get(split[0]);
|
||||||
this.commands.get(split[0])(split, this.context);
|
if (command) {
|
||||||
|
if (command.execute) {
|
||||||
|
// New Command object
|
||||||
|
command.execute(split, this.context);
|
||||||
|
} else {
|
||||||
|
// Old function-based command
|
||||||
|
command(split, this.context);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +78,27 @@ export default class Commands {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addCommandObject(commandObj) {
|
||||||
|
// Add the main command name
|
||||||
|
this.commands.set(commandObj.name, commandObj);
|
||||||
|
// Add all aliases
|
||||||
|
commandObj.aliases.forEach(alias => {
|
||||||
|
this.commands.set(alias, commandObj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addCommands(commands) {
|
addCommands(commands) {
|
||||||
commands.forEach((command) => {
|
commands.forEach((command) => {
|
||||||
|
if (command.execute && command.getAllNames) {
|
||||||
|
// New Command object
|
||||||
|
this.addCommandObject(command);
|
||||||
|
} else if (Array.isArray(command)) {
|
||||||
|
// Old array format
|
||||||
this.addCommand(command[0], command[1]);
|
this.addCommand(command[0], command[1]);
|
||||||
|
} else {
|
||||||
|
// Old single command
|
||||||
|
this.addCommand(command.name, command);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
function DropCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function dropHandler(args, context) {
|
||||||
const room = context.getRoom(context.player.currentRoom);
|
const room = context.getRoom(context.player.currentRoom);
|
||||||
const items = context.player.getInventory();
|
const items = context.player.getInventory();
|
||||||
let item = null;
|
let item = null;
|
||||||
|
@ -21,17 +23,11 @@ function DropCommand(args, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DropCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "Actions",
|
.withName("drop")
|
||||||
description: "Drop an object",
|
.withAliases(["put"])
|
||||||
arguments: [
|
.withCategory("Actions")
|
||||||
{
|
.withDescription("Drop an object")
|
||||||
type: "item",
|
.withArgument("item", "target", false, "Object to drop")
|
||||||
name: "target",
|
.withHandler(dropHandler)
|
||||||
optional: false,
|
.create();
|
||||||
description: "Object to drop"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DropCommand;
|
|
|
@ -1,4 +1,6 @@
|
||||||
function EchoCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function echoHandler(args, context) {
|
||||||
if (args[1] != "on" && args[1] != "off") {
|
if (args[1] != "on" && args[1] != "off") {
|
||||||
context.print(`Usage: echo <on/off>`);
|
context.print(`Usage: echo <on/off>`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -7,18 +9,10 @@ function EchoCommand(args, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EchoCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "System",
|
.withName("echo")
|
||||||
description: "Toggle command echo",
|
.withCategory("System")
|
||||||
arguments: [
|
.withDescription("Toggle command echo")
|
||||||
{
|
.withArgument("select", "state", false, "Echo state")
|
||||||
type: "select",
|
.withHandler(echoHandler)
|
||||||
name: "state",
|
.create();
|
||||||
optional: false,
|
|
||||||
description: "Echo state",
|
|
||||||
options: ["on", "off"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EchoCommand;
|
|
|
@ -1,4 +1,6 @@
|
||||||
function InventoryCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function inventoryHandler(args, context) {
|
||||||
const items = context.player.getInventory();
|
const items = context.player.getInventory();
|
||||||
if (items.length < 1) return context.print(`You're not carrying anything.`);
|
if (items.length < 1) return context.print(`You're not carrying anything.`);
|
||||||
let itemDescription = `You are carrying `;
|
let itemDescription = `You are carrying `;
|
||||||
|
@ -14,10 +16,10 @@ function InventoryCommand(args, context) {
|
||||||
context.print(itemDescription + ".");
|
context.print(itemDescription + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "Actions",
|
.withName("inventory")
|
||||||
description: "View inventory",
|
.withAliases(["i", "inv"])
|
||||||
arguments: []
|
.withCategory("Actions")
|
||||||
};
|
.withDescription("View inventory")
|
||||||
|
.withHandler(inventoryHandler)
|
||||||
export default InventoryCommand;
|
.create();
|
|
@ -1,12 +1,13 @@
|
||||||
function LoadCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function loadHandler(args, context) {
|
||||||
context.print(`Loading game...`);
|
context.print(`Loading game...`);
|
||||||
context.load();
|
context.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "System",
|
.withName("load")
|
||||||
description: "Load game",
|
.withCategory("System")
|
||||||
arguments: []
|
.withDescription("Load game")
|
||||||
};
|
.withHandler(loadHandler)
|
||||||
|
.create();
|
||||||
export default LoadCommand;
|
|
|
@ -1,4 +1,6 @@
|
||||||
function LookCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function lookHandler(args, context) {
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
context.examineRoom();
|
context.examineRoom();
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,17 +31,11 @@ function LookCommand(args, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LookCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "Actions",
|
.withName("look")
|
||||||
description: "Examine room or object",
|
.withAliases(["l"])
|
||||||
arguments: [
|
.withCategory("Actions")
|
||||||
{
|
.withDescription("Examine room or object")
|
||||||
type: "item",
|
.withArgument("item", "target", true, "Object to examine")
|
||||||
name: "target",
|
.withHandler(lookHandler)
|
||||||
optional: true,
|
.create();
|
||||||
description: "Object to examine"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LookCommand;
|
|
|
@ -1,12 +1,13 @@
|
||||||
function SaveCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function saveHandler(args, context) {
|
||||||
context.print(`Saving game...`);
|
context.print(`Saving game...`);
|
||||||
context.save();
|
context.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "System",
|
.withName("save")
|
||||||
description: "Save game",
|
.withCategory("System")
|
||||||
arguments: []
|
.withDescription("Save game")
|
||||||
};
|
.withHandler(saveHandler)
|
||||||
|
.create();
|
||||||
export default SaveCommand;
|
|
|
@ -1,4 +1,6 @@
|
||||||
function TakeCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function takeHandler(args, context) {
|
||||||
const room = context.getRoom(context.player.currentRoom);
|
const room = context.getRoom(context.player.currentRoom);
|
||||||
const items = room.getItems();
|
const items = room.getItems();
|
||||||
let item = null;
|
let item = null;
|
||||||
|
@ -25,17 +27,11 @@ function TakeCommand(args, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TakeCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "Actions",
|
.withName("take")
|
||||||
description: "Take an object",
|
.withAliases(["get"])
|
||||||
arguments: [
|
.withCategory("Actions")
|
||||||
{
|
.withDescription("Take an object")
|
||||||
type: "item",
|
.withArgument("item", "target", false, "Object to take")
|
||||||
name: "target",
|
.withHandler(takeHandler)
|
||||||
optional: false,
|
.create();
|
||||||
description: "Object to take"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TakeCommand;
|
|
|
@ -1,4 +1,6 @@
|
||||||
async function UseCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
async function useHandler(args, context) {
|
||||||
const room = context.getRoom(context.player.currentRoom);
|
const room = context.getRoom(context.player.currentRoom);
|
||||||
const items = room.getItems();
|
const items = room.getItems();
|
||||||
let item = null;
|
let item = null;
|
||||||
|
@ -24,17 +26,12 @@ async function UseCommand(args, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UseCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "Actions",
|
.withName("use")
|
||||||
description: "Use an object",
|
.withAliases(["interact"])
|
||||||
arguments: [
|
.withCategory("Actions")
|
||||||
{
|
.withDescription("Use an object")
|
||||||
type: "item",
|
.withArgument("item", "target", false, "Object to use")
|
||||||
name: "target",
|
.withHandler(useHandler)
|
||||||
optional: false,
|
.isAsync(true)
|
||||||
description: "Object to use"
|
.create();
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UseCommand;
|
|
|
@ -1,4 +1,6 @@
|
||||||
function VolumeCommand(args, context) {
|
import CommandBuilder from "../builders/command";
|
||||||
|
|
||||||
|
function volumeHandler(args, context) {
|
||||||
if (args.length < 3) {
|
if (args.length < 3) {
|
||||||
return context.print(`Usage: volume <music/sfx/ambience> <0-100>`);
|
return context.print(`Usage: volume <music/sfx/ambience> <0-100>`);
|
||||||
}
|
}
|
||||||
|
@ -18,24 +20,11 @@ function VolumeCommand(args, context) {
|
||||||
context.print(`${args[1]} volume set to ${value}%`)
|
context.print(`${args[1]} volume set to ${value}%`)
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "System",
|
.withName("volume")
|
||||||
description: "Adjust volume",
|
.withCategory("System")
|
||||||
arguments: [
|
.withDescription("Adjust volume")
|
||||||
{
|
.withArgument("select", "channel", false, "Audio channel")
|
||||||
type: "select",
|
.withArgument("text", "level", false, "Volume level (1-100)")
|
||||||
name: "channel",
|
.withHandler(volumeHandler)
|
||||||
optional: false,
|
.create();
|
||||||
description: "Audio channel",
|
|
||||||
options: ["music", "sfx", "ambience"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
name: "level",
|
|
||||||
optional: false,
|
|
||||||
description: "Volume level (1-100)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default VolumeCommand;
|
|
|
@ -30,6 +30,90 @@ export default class MobileCommands {
|
||||||
this.modeToggleButton.addEventListener('click', () => this.toggleInputMode());
|
this.modeToggleButton.addEventListener('click', () => this.toggleInputMode());
|
||||||
this.executeButton.addEventListener('click', () => this.executeCommand());
|
this.executeButton.addEventListener('click', () => this.executeCommand());
|
||||||
this.cancelButton.addEventListener('click', () => this.closeDialog());
|
this.cancelButton.addEventListener('click', () => this.closeDialog());
|
||||||
|
|
||||||
|
// Setup tab click handlers
|
||||||
|
this.setupTabHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupTabHandlers() {
|
||||||
|
const tabs = document.querySelectorAll('.command-tab');
|
||||||
|
tabs.forEach(tab => {
|
||||||
|
// Handle click events
|
||||||
|
tab.addEventListener('click', (e) => {
|
||||||
|
const category = e.target.dataset.category;
|
||||||
|
this.switchTab(category);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle keyboard navigation
|
||||||
|
tab.addEventListener('keydown', (e) => {
|
||||||
|
this.handleTabKeydown(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTabKeydown(e) {
|
||||||
|
const tabs = Array.from(document.querySelectorAll('.command-tab'));
|
||||||
|
const currentIndex = tabs.findIndex(tab => tab === e.target);
|
||||||
|
let newIndex = currentIndex;
|
||||||
|
|
||||||
|
switch (e.key) {
|
||||||
|
case 'ArrowLeft':
|
||||||
|
case 'ArrowUp':
|
||||||
|
e.preventDefault();
|
||||||
|
newIndex = currentIndex > 0 ? currentIndex - 1 : tabs.length - 1;
|
||||||
|
break;
|
||||||
|
case 'ArrowRight':
|
||||||
|
case 'ArrowDown':
|
||||||
|
e.preventDefault();
|
||||||
|
newIndex = currentIndex < tabs.length - 1 ? currentIndex + 1 : 0;
|
||||||
|
break;
|
||||||
|
case 'Home':
|
||||||
|
e.preventDefault();
|
||||||
|
newIndex = 0;
|
||||||
|
break;
|
||||||
|
case 'End':
|
||||||
|
e.preventDefault();
|
||||||
|
newIndex = tabs.length - 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newIndex !== currentIndex) {
|
||||||
|
const newTab = tabs[newIndex];
|
||||||
|
const category = newTab.dataset.category;
|
||||||
|
this.switchTab(category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switchTab(category) {
|
||||||
|
// Update all tabs and panels
|
||||||
|
document.querySelectorAll('.command-tab').forEach(tab => {
|
||||||
|
const isActive = tab.dataset.category === category;
|
||||||
|
|
||||||
|
// Update CSS classes
|
||||||
|
tab.classList.toggle('active', isActive);
|
||||||
|
|
||||||
|
// Update ARIA attributes
|
||||||
|
tab.setAttribute('aria-selected', isActive.toString());
|
||||||
|
tab.setAttribute('tabindex', isActive ? '0' : '-1');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.command-panel').forEach(panel => {
|
||||||
|
const isActive = panel.dataset.category === category;
|
||||||
|
|
||||||
|
// Update CSS classes
|
||||||
|
panel.classList.toggle('active', isActive);
|
||||||
|
|
||||||
|
// Update ARIA attributes
|
||||||
|
panel.setAttribute('aria-hidden', (!isActive).toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Focus the active tab for keyboard navigation
|
||||||
|
const activeTab = document.querySelector(`[data-category="${category}"].command-tab`);
|
||||||
|
if (activeTab) {
|
||||||
|
activeTab.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
populateCommands() {
|
populateCommands() {
|
||||||
|
@ -44,7 +128,7 @@ export default class MobileCommands {
|
||||||
|
|
||||||
// Populate each category
|
// Populate each category
|
||||||
Object.entries(categories).forEach(([category, commandList]) => {
|
Object.entries(categories).forEach(([category, commandList]) => {
|
||||||
const container = document.querySelector(`[data-category="${category}"]`);
|
const container = document.querySelector(`[data-category="${category}"].command-list`);
|
||||||
if (container) {
|
if (container) {
|
||||||
commandList.forEach(command => {
|
commandList.forEach(command => {
|
||||||
const button = this.createCommandButton(command);
|
const button = this.createCommandButton(command);
|
||||||
|
@ -66,10 +150,21 @@ export default class MobileCommands {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func.metadata) {
|
let metadata = null;
|
||||||
|
|
||||||
|
// Check for new Command objects with getMetadata() method
|
||||||
|
if (func.getMetadata) {
|
||||||
|
metadata = func.getMetadata();
|
||||||
|
}
|
||||||
|
// Check for old-style metadata property
|
||||||
|
else if (func.metadata) {
|
||||||
|
metadata = func.metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata) {
|
||||||
commands.push({
|
commands.push({
|
||||||
name: name,
|
name: name,
|
||||||
...func.metadata
|
...metadata
|
||||||
});
|
});
|
||||||
seenFunctions.add(func);
|
seenFunctions.add(func);
|
||||||
}
|
}
|
||||||
|
@ -115,6 +210,29 @@ export default class MobileCommands {
|
||||||
<div class="command-description">${command.description}</div>
|
<div class="command-description">${command.description}</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// Add ARIA attributes
|
||||||
|
button.setAttribute('aria-label', `${command.name}: ${command.description}`);
|
||||||
|
button.setAttribute('type', 'button');
|
||||||
|
|
||||||
|
// Add arguments info for screen readers if present
|
||||||
|
if (command.arguments && command.arguments.length > 0) {
|
||||||
|
const argCount = command.arguments.length;
|
||||||
|
const requiredArgs = command.arguments.filter(arg => !arg.optional).length;
|
||||||
|
let ariaDescription = `Requires ${requiredArgs} argument${requiredArgs !== 1 ? 's' : ''}`;
|
||||||
|
if (argCount > requiredArgs) {
|
||||||
|
const optionalArgs = argCount - requiredArgs;
|
||||||
|
ariaDescription += ` with ${optionalArgs} optional argument${optionalArgs !== 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
button.setAttribute('aria-describedby', `${command.name}-args-info`);
|
||||||
|
|
||||||
|
// Create hidden description for screen readers
|
||||||
|
const ariaDescElement = document.createElement('span');
|
||||||
|
ariaDescElement.id = `${command.name}-args-info`;
|
||||||
|
ariaDescElement.className = 'sr-only';
|
||||||
|
ariaDescElement.textContent = ariaDescription;
|
||||||
|
button.appendChild(ariaDescElement);
|
||||||
|
}
|
||||||
|
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
this.selectCommand(command);
|
this.selectCommand(command);
|
||||||
});
|
});
|
||||||
|
@ -362,6 +480,8 @@ export default class MobileCommands {
|
||||||
refreshCommands() {
|
refreshCommands() {
|
||||||
if (this.isMobileMode) {
|
if (this.isMobileMode) {
|
||||||
this.populateCommands();
|
this.populateCommands();
|
||||||
|
// Re-setup tab handlers after commands are populated
|
||||||
|
this.setupTabHandlers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,20 @@ export default class Output {
|
||||||
});
|
});
|
||||||
this.history.appendChild(node);
|
this.history.appendChild(node);
|
||||||
// this.tts.speak(string);
|
// this.tts.speak(string);
|
||||||
|
|
||||||
|
// Auto-scroll to bottom
|
||||||
|
this.scrollToBottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToBottom() {
|
||||||
|
// Find the log area container
|
||||||
|
const logArea = document.querySelector('.log-area');
|
||||||
|
if (logArea) {
|
||||||
|
// Use requestAnimationFrame for smooth scrolling
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
logArea.scrollTop = logArea.scrollHeight;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
play(file) {
|
play(file) {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
async function DarkCommand(args, context) {
|
import CommandBuilder from "../../engine/builders/command";
|
||||||
|
|
||||||
|
async function darkHandler(args, context) {
|
||||||
document.body.classList.toggle('dark-theme');
|
document.body.classList.toggle('dark-theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
DarkCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "System",
|
.withName("dark")
|
||||||
description: "Toggle dark theme",
|
.withCategory("System")
|
||||||
arguments: []
|
.withDescription("Toggle dark theme")
|
||||||
};
|
.withHandler(darkHandler)
|
||||||
|
.isAsync(true)
|
||||||
export default DarkCommand;
|
.create();
|
|
@ -1,11 +1,13 @@
|
||||||
async function MeowCommand(args, context) {
|
import CommandBuilder from "../../engine/builders/command";
|
||||||
|
|
||||||
|
async function meowHandler(args, context) {
|
||||||
context.print(`You meow.`);
|
context.print(`You meow.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
MeowCommand.metadata = {
|
export default new CommandBuilder()
|
||||||
category: "Actions",
|
.withName("meow")
|
||||||
description: "Make a cat sound",
|
.withCategory("Actions")
|
||||||
arguments: []
|
.withDescription("Make a cat sound")
|
||||||
};
|
.withHandler(meowHandler)
|
||||||
|
.isAsync(true)
|
||||||
export default MeowCommand;
|
.create();
|
|
@ -88,11 +88,13 @@
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
font-size: var(--font-size-base);
|
font-size: var(--font-size-base);
|
||||||
line-height: var(--line-height);
|
line-height: var(--line-height);
|
||||||
padding: var(--spacing-xl);
|
padding: 0;
|
||||||
min-height: 100vh;
|
margin: 0;
|
||||||
|
height: 100vh;
|
||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Typography */
|
/* Typography */
|
||||||
|
@ -134,16 +136,102 @@
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Screen reader only content */
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== LAYOUT COMPONENTS ===== */
|
/* ===== LAYOUT COMPONENTS ===== */
|
||||||
.game-container {
|
.game-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
max-width: var(--max-width);
|
max-width: var(--max-width);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: var(--spacing-xl);
|
|
||||||
background: var(--surface-color);
|
background: var(--surface-color);
|
||||||
border-radius: var(--border-radius);
|
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
border: var(--border-width) solid var(--border-color);
|
border-left: var(--border-width) solid var(--border-color);
|
||||||
|
border-right: var(--border-width) solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-container[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-screen {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
max-width: var(--max-width);
|
||||||
|
margin: 0 auto;
|
||||||
|
background: var(--surface-color);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-left: var(--border-width) solid var(--border-color);
|
||||||
|
border-right: var(--border-width) solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-screen[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-header {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--spacing-md) var(--spacing-xl);
|
||||||
|
background: var(--background-color);
|
||||||
|
border-bottom: var(--border-width) solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-area {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: var(--spacing-md) var(--spacing-xl);
|
||||||
|
background: var(--background-color);
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-area::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-area::-webkit-scrollbar-track {
|
||||||
|
background: var(--surface-color);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-area::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--primary-color);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-area::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-area {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: var(--surface-color);
|
||||||
|
border-top: var(--border-width) solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== FORM CONTROLS ===== */
|
/* ===== FORM CONTROLS ===== */
|
||||||
|
@ -258,94 +346,112 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-mode {
|
.input-mode {
|
||||||
margin-top: var(--spacing-md);
|
padding: var(--spacing-md) var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-mode {
|
.mobile-mode {
|
||||||
position: sticky;
|
|
||||||
bottom: 0;
|
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
border-top: 2px solid var(--primary-color);
|
border-top: 2px solid var(--primary-color);
|
||||||
padding: var(--spacing-md);
|
max-height: 40vh;
|
||||||
margin: var(--spacing-md) calc(-1 * var(--spacing-xl)) calc(-1 * var(--spacing-xl)) calc(-1 * var(--spacing-xl));
|
|
||||||
max-height: 50vh;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
padding: var(--spacing-md) var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-interface h3 {
|
.command-interface h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: var(--spacing-md);
|
margin-bottom: var(--spacing-sm);
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
font-size: var(--font-size-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-categories-permanent {
|
.command-categories-permanent {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
flex-direction: column;
|
||||||
gap: var(--spacing-md);
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-category {
|
.command-tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-bottom: var(--border-width) solid var(--border-color);
|
||||||
background: var(--surface-color);
|
background: var(--surface-color);
|
||||||
border: var(--border-width) solid var(--border-color);
|
}
|
||||||
border-radius: var(--border-radius);
|
|
||||||
|
.command-tab {
|
||||||
|
flex: 1;
|
||||||
|
background: var(--surface-color);
|
||||||
|
border: none;
|
||||||
|
border-right: var(--border-width) solid var(--border-color);
|
||||||
padding: var(--spacing-sm);
|
padding: var(--spacing-sm);
|
||||||
transition: all var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-category:hover {
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
box-shadow: var(--shadow-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-category summary {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: var(--spacing-sm);
|
transition: all var(--transition-fast);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-tab:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-tab:hover {
|
||||||
background: var(--primary-color);
|
background: var(--primary-color);
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: var(--border-radius-sm);
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
margin-bottom: var(--spacing-sm);
|
|
||||||
transition: all var(--transition-fast);
|
|
||||||
list-style: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-category summary::-webkit-details-marker {
|
.command-tab.active,
|
||||||
|
.command-tab[aria-selected="true"] {
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
border-bottom: 2px solid var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-panel {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-panel.active,
|
||||||
|
.command-panel[aria-hidden="false"] {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-panel[aria-hidden="true"] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-category summary::before {
|
|
||||||
content: "▶";
|
|
||||||
margin-right: var(--spacing-xs);
|
|
||||||
transition: transform var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-category[open] summary::before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-category summary:hover {
|
|
||||||
background: var(--secondary-color);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-list {
|
.command-list {
|
||||||
padding: var(--spacing-sm) 0;
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: var(--spacing-sm);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-button {
|
.command-button {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: var(--spacing-sm);
|
margin-bottom: var(--spacing-xs);
|
||||||
padding: var(--spacing-sm);
|
padding: var(--spacing-xs) var(--spacing-sm);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border: var(--border-width) solid var(--border-color);
|
border: var(--border-width) solid var(--border-color);
|
||||||
background: var(--surface-color);
|
background: var(--surface-color);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
border-radius: var(--border-radius-sm);
|
border-radius: var(--border-radius-sm);
|
||||||
font-size: var(--font-size-small);
|
font-size: 0.75rem;
|
||||||
transition: all var(--transition-fast);
|
transition: all var(--transition-fast);
|
||||||
|
min-height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-button:hover {
|
.command-button:hover {
|
||||||
|
@ -471,20 +577,41 @@
|
||||||
|
|
||||||
/* Tablet and Mobile */
|
/* Tablet and Mobile */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
body {
|
.game-header {
|
||||||
padding: var(--spacing-md);
|
padding: var(--spacing-sm) var(--spacing-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-container {
|
.log-area {
|
||||||
padding: var(--spacing-md);
|
padding: var(--spacing-sm) var(--spacing-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-categories-permanent {
|
.input-mode {
|
||||||
grid-template-columns: 1fr;
|
padding: var(--spacing-sm) var(--spacing-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-mode {
|
.mobile-mode {
|
||||||
margin: var(--spacing-md) calc(-1 * var(--spacing-md)) calc(-1 * var(--spacing-md)) calc(-1 * var(--spacing-md));
|
padding: var(--spacing-sm) var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-tabs {
|
||||||
|
flex-direction: column;
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: var(--border-width) solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-tab {
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: var(--border-width) solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-tab:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.command-tab.active,
|
||||||
|
.command-tab[aria-selected="true"] {
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: 2px solid var(--secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog {
|
dialog {
|
||||||
|
@ -515,30 +642,39 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Typography adjustments for mobile */
|
/* Typography adjustments for mobile */
|
||||||
h1 { font-size: 2rem; }
|
.game-header h1 { font-size: 1.25rem; }
|
||||||
h2 { font-size: 1.75rem; }
|
h2 { font-size: 1.75rem; }
|
||||||
h3 { font-size: 1.5rem; }
|
h3 { font-size: 1.5rem; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Small Mobile */
|
/* Small Mobile */
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
body {
|
.game-header {
|
||||||
padding: var(--spacing-sm);
|
padding: var(--spacing-xs) var(--spacing-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-container {
|
.log-area {
|
||||||
padding: var(--spacing-sm);
|
padding: var(--spacing-xs) var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-mode {
|
||||||
|
padding: var(--spacing-xs) var(--spacing-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-mode {
|
.mobile-mode {
|
||||||
margin: var(--spacing-sm) calc(-1 * var(--spacing-sm)) calc(-1 * var(--spacing-sm)) calc(-1 * var(--spacing-sm));
|
padding: var(--spacing-xs) var(--spacing-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-categories-permanent {
|
.command-tabs {
|
||||||
gap: var(--spacing-sm);
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 { font-size: 1.75rem; }
|
.command-tab {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-header h1 { font-size: 1.125rem; }
|
||||||
h2 { font-size: 1.5rem; }
|
h2 { font-size: 1.5rem; }
|
||||||
h3 { font-size: 1.25rem; }
|
h3 { font-size: 1.25rem; }
|
||||||
}
|
}
|
||||||
|
@ -582,16 +718,25 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h1>Assassin bug</h1>
|
|
||||||
<div class="game-container" id="play-area" hidden=true>
|
<div class="game-container" id="play-area" hidden=true>
|
||||||
|
<!-- Game Header -->
|
||||||
|
<div class="game-header">
|
||||||
|
<h1>Assassin bug</h1>
|
||||||
<!-- Mode Toggle -->
|
<!-- Mode Toggle -->
|
||||||
<div class="mode-toggle">
|
<div class="mode-toggle">
|
||||||
<button id="toggle-input-mode" class="mode-button">📱 Mobile Mode</button>
|
<button id="toggle-input-mode" class="mode-button">📱 Mobile Mode</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Output Area -->
|
<!-- Game Content -->
|
||||||
|
<div class="game-content">
|
||||||
|
<!-- Log Area -->
|
||||||
|
<div class="log-area">
|
||||||
<div aria-live="polite" id="output-area"></div>
|
<div aria-live="polite" id="output-area"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Input Area -->
|
||||||
|
<div class="input-area">
|
||||||
<!-- Text Input Mode -->
|
<!-- Text Input Mode -->
|
||||||
<div id="text-input-mode" class="input-mode">
|
<div id="text-input-mode" class="input-mode">
|
||||||
<input type="text" id="input-area" placeholder="Type command" />
|
<input type="text" id="input-area" placeholder="Type command" />
|
||||||
|
@ -600,20 +745,67 @@
|
||||||
<!-- Mobile Command Mode -->
|
<!-- Mobile Command Mode -->
|
||||||
<div id="mobile-command-mode" class="input-mode mobile-mode" hidden>
|
<div id="mobile-command-mode" class="input-mode mobile-mode" hidden>
|
||||||
<div class="command-interface">
|
<div class="command-interface">
|
||||||
<h3>Commands</h3>
|
<h3 id="command-interface-title">Commands</h3>
|
||||||
<div class="command-categories-permanent">
|
<div class="command-categories-permanent">
|
||||||
<details class="command-category" open>
|
<div class="command-tabs" role="tablist" aria-labelledby="command-interface-title">
|
||||||
<summary>Movement</summary>
|
<button class="command-tab active"
|
||||||
<div class="command-list" data-category="Movement"></div>
|
role="tab"
|
||||||
</details>
|
aria-selected="true"
|
||||||
<details class="command-category" open>
|
aria-controls="movement-panel"
|
||||||
<summary>Actions</summary>
|
id="movement-tab"
|
||||||
<div class="command-list" data-category="Actions"></div>
|
data-category="Movement"
|
||||||
</details>
|
tabindex="0">Movement</button>
|
||||||
<details class="command-category" open>
|
<button class="command-tab"
|
||||||
<summary>System</summary>
|
role="tab"
|
||||||
<div class="command-list" data-category="System"></div>
|
aria-selected="false"
|
||||||
</details>
|
aria-controls="actions-panel"
|
||||||
|
id="actions-tab"
|
||||||
|
data-category="Actions"
|
||||||
|
tabindex="-1">Actions</button>
|
||||||
|
<button class="command-tab"
|
||||||
|
role="tab"
|
||||||
|
aria-selected="false"
|
||||||
|
aria-controls="system-panel"
|
||||||
|
id="system-tab"
|
||||||
|
data-category="System"
|
||||||
|
tabindex="-1">System</button>
|
||||||
|
</div>
|
||||||
|
<div class="command-content">
|
||||||
|
<div class="command-panel active"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-labelledby="movement-tab"
|
||||||
|
id="movement-panel"
|
||||||
|
data-category="Movement">
|
||||||
|
<div class="command-list"
|
||||||
|
data-category="Movement"
|
||||||
|
role="group"
|
||||||
|
aria-label="Movement commands"></div>
|
||||||
|
</div>
|
||||||
|
<div class="command-panel"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-labelledby="actions-tab"
|
||||||
|
id="actions-panel"
|
||||||
|
data-category="Actions"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="command-list"
|
||||||
|
data-category="Actions"
|
||||||
|
role="group"
|
||||||
|
aria-label="Action commands"></div>
|
||||||
|
</div>
|
||||||
|
<div class="command-panel"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-labelledby="system-tab"
|
||||||
|
id="system-panel"
|
||||||
|
data-category="System"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="command-list"
|
||||||
|
data-category="System"
|
||||||
|
role="group"
|
||||||
|
aria-label="System commands"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -631,15 +823,31 @@
|
||||||
</dialog>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="save-game-found" hidden=true>
|
<div class="welcome-screen" id="save-game-found" hidden=true>
|
||||||
|
<div class="game-header">
|
||||||
<h1>Found a save game</h1>
|
<h1>Found a save game</h1>
|
||||||
|
</div>
|
||||||
|
<div class="game-content">
|
||||||
|
<div class="log-area">
|
||||||
|
<div style="text-align: center; margin-top: 2rem;">
|
||||||
<button id="load-save-game">Load</button>
|
<button id="load-save-game">Load</button>
|
||||||
<button id="start-new-game">New</button>
|
<button id="start-new-game">New</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="before-play">
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="welcome-screen" id="before-play">
|
||||||
|
<div class="game-header">
|
||||||
<h1>Welcome</h1>
|
<h1>Welcome</h1>
|
||||||
|
</div>
|
||||||
|
<div class="game-content">
|
||||||
|
<div class="log-area">
|
||||||
|
<div style="text-align: center; margin-top: 2rem;">
|
||||||
<button id="begin">Begin the adventure</button>
|
<button id="begin">Begin the adventure</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue