Split pages and commands into editable modules
This commit is contained in:
+28
-36
@@ -1,44 +1,36 @@
|
||||
import { color, wrap } from './terminal.js';
|
||||
import * as home from './commands/home.js';
|
||||
import * as help from './commands/help.js';
|
||||
import * as pages from './commands/pages.js';
|
||||
import * as open from './commands/open.js';
|
||||
import * as contact from './commands/contact.js';
|
||||
import * as chat from './commands/chat.js';
|
||||
import * as clearCommand from './commands/clear.js';
|
||||
import * as quit from './commands/quit.js';
|
||||
import * as reload from './commands/reload.js';
|
||||
import * as theme from './commands/theme.js';
|
||||
import * as announce from './commands/announce.js';
|
||||
import { pageMap } from './pages/index.js';
|
||||
|
||||
// Add a command module import here to make a new command available.
|
||||
const commands = [home, help, pages, open, contact, chat, clearCommand, quit, reload, theme, announce];
|
||||
|
||||
export function createCommandRouter(api) {
|
||||
const commands = new Map();
|
||||
const add = command => commands.set(command.name, command);
|
||||
const page = name => {
|
||||
const item = api.config.pages?.[name];
|
||||
if (!item) return `${color('red', `No page named “${name}”.`)}\nTry: pages`;
|
||||
return wrap((item.lines || []).join('\n')).join('\n');
|
||||
const commandMap = new Map(commands.map(command => [command.name, command]));
|
||||
const runPage = (ctx, name) => {
|
||||
const page = pageMap.get(name);
|
||||
return page ? page.render({ ...api, api, ctx }) : `No page named “${name}”. Try: pages`;
|
||||
};
|
||||
|
||||
add({ name: 'home', description: 'Return home', run: () => {
|
||||
const p = api.config.persona || {};
|
||||
const status = api.ownerOnline() ? color('green', 'Owner is online') : color(api.config.theme?.muted || 'brightBlack', 'Owner is offline');
|
||||
return `${color(api.config.theme?.accent || 'yellow', `Welcome to ${p.name || 'my portfolio'}`)}\n\n${wrap(p.bio || 'You are exploring a portfolio over SSH. Type “help” to get started.').join('\n')}\n\n${status}\n\nCommands: home · pages · open <page> · chat · contact · clear · quit`;
|
||||
}});
|
||||
add({ name: 'help', description: 'Show this help', run: ctx => {
|
||||
const actions = [...commands.values()].filter(c => !c.admin || api.isAdmin(ctx)).map(c => `${c.name.padEnd(18)} ${c.description}`);
|
||||
const pages = Object.entries(api.config.pages || {}).filter(([name]) => !commands.has(name)).map(([name, item]) => `${name.padEnd(18)} Open ${item.title || name}`);
|
||||
return [...actions, ...pages].join('\n');
|
||||
}});
|
||||
add({ name: 'pages', description: 'List available pages', run: () => Object.entries(api.config.pages || {}).map(([name, item]) => `${color(api.config.theme?.accent || 'yellow', name.padEnd(14))} ${item.title || ''}`).join('\n') || 'No pages configured.' });
|
||||
add({ name: 'open', description: 'Open a page', run: (ctx, arg) => arg ? page(arg) : 'Usage: open <page>' });
|
||||
add({ name: 'contact', description: 'Show contact details', run: () => `Email: ${api.config.persona?.email || 'not configured'}` });
|
||||
add({ name: 'chat', description: 'Chat with the owner/visitors', run: (ctx, arg) => {
|
||||
if (!arg) return 'Usage: chat <message>';
|
||||
const author = api.isAdmin(ctx) ? `${api.config.persona?.name || 'Owner'} [owner]` : (ctx.username || 'visitor');
|
||||
const line = `${author}: ${arg}`; api.broadcast(line); api.sendNotification(line); return api.ownerOnline() ? 'Message sent to the owner.' : 'Message posted; the owner is currently offline.';
|
||||
}});
|
||||
add({ name: 'clear', description: 'Clear the screen', run: () => '' });
|
||||
add({ name: 'quit', description: 'Disconnect', run: ctx => { ctx.channel?.end(); return ''; } });
|
||||
add({ name: 'reload', description: 'Reload configuration', admin: true, run: () => { api.reload(); return 'Configuration reloaded.'; } });
|
||||
add({ name: 'theme', description: 'Set runtime primary color', admin: true, run: (ctx, arg) => { if (!arg) return 'Usage: theme <color>'; api.config.theme.primary = arg; return `Primary color set to ${arg} (runtime only).`; } });
|
||||
add({ name: 'announce', description: 'Broadcast an announcement', admin: true, run: (ctx, arg) => { if (!arg) return 'Usage: announce <message>'; api.broadcast(`OWNER: ${arg}`); api.sendNotification(`OWNER: ${arg}`); return 'Announcement sent.'; } });
|
||||
|
||||
return {
|
||||
home: ctx => commands.get('home').run(ctx, ''),
|
||||
home: ctx => runPage(ctx, 'home'),
|
||||
execute(ctx, input) {
|
||||
const [name, ...rest] = input.trim().split(/\s+/); const command = commands.get(name || 'home') || (api.config.pages?.[name] ? { run: () => page(name) } : null);
|
||||
if (!command || (command.admin && !api.isAdmin(ctx))) return `Unknown command: ${name}. Try “help”.`;
|
||||
return command.run(ctx, rest.join(' '));
|
||||
const [name, ...rest] = input.trim().split(/\s+/); const arg = rest.join(' ');
|
||||
const command = commandMap.get(name || 'home') || pageMap.get(name);
|
||||
if (!command) return `Unknown command: ${name}. Try “help”.`;
|
||||
if (command.admin && !api.isAdmin(ctx)) return `Unknown command: ${name}. Try “help”.`;
|
||||
if (pageMap.has(name) && !command.run) return runPage(ctx, name);
|
||||
const result = command.run({ ...api, api, ctx, arg, config: api.config, pageMap, visibleCommands: commands });
|
||||
if (typeof result === 'string' && result.startsWith('__PAGE__:')) return runPage(ctx, result.slice(9));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user