From b697856c4ea9f50b2c17d92df3c4c907271c36c8 Mon Sep 17 00:00:00 2001 From: Valerie Date: Sat, 19 Jun 2021 18:23:44 -0400 Subject: [PATCH] themes registration, starting extensions API --- .vscode/tasks.json | 25 +++++++++++++ content/core/themes/ashe.ts | 0 content/core/themes/standard.ts | 8 +++++ lib/aliases.mjs | 33 +++++++++++++++++ package.json | 5 ++- src/Pawn.ts | 3 +- src/Progressbar.ts | 14 +++++++- src/Time.ts | 4 +-- src/index.ts | 29 +++++++++++---- src/ui/Theme.ts | 44 +++++++++++++---------- test.js | 0 tsconfig.json | 8 +++-- yarn.lock | 63 +++++++++++++++++++++++++++++++++ 13 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 content/core/themes/ashe.ts create mode 100644 content/core/themes/standard.ts create mode 100644 lib/aliases.mjs create mode 100644 test.js diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..aecda74 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,25 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "tsc watch", + "type": "npm", + "script": "compile:watch", + "isBackground": true, + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "never", + "echo": false, + "focus": false, + "panel": "dedicated" + }, + "problemMatcher": { + "base": "$tsc-watch", + "applyTo": "allDocuments" + } + } + ] +} \ No newline at end of file diff --git a/content/core/themes/ashe.ts b/content/core/themes/ashe.ts new file mode 100644 index 0000000..e69de29 diff --git a/content/core/themes/standard.ts b/content/core/themes/standard.ts new file mode 100644 index 0000000..16fd29b --- /dev/null +++ b/content/core/themes/standard.ts @@ -0,0 +1,8 @@ +import { registerTheme } from '@theme'; +import chalk from 'chalk' + +registerTheme("default", {}); + +registerTheme("high contrast", { + selected: chalk.ansi256(250).inverse +}); \ No newline at end of file diff --git a/lib/aliases.mjs b/lib/aliases.mjs new file mode 100644 index 0000000..baca07c --- /dev/null +++ b/lib/aliases.mjs @@ -0,0 +1,33 @@ +import path from 'path'; + +const moduleAliases = { + "@theme": "./out/src/ui/Theme.js" +}; + +const getAliases = () => { + const base = process.cwd(); + const aliases = moduleAliases || {}; + const absoluteAliases = Object.keys(aliases).reduce((acc, key) => + aliases[key][0] === '/' + ? acc + : { ...acc, [key]: 'file:///' + path.join(base, aliases[key]) }, + aliases) + return absoluteAliases; +} + +const isAliasInSpecifier = (path, alias) => { + return path.indexOf(alias) === 0 + && (path.length === alias.length || path[alias.length] === '/') +} + +const aliases = getAliases(); + +export const resolve = (specifier, parentModuleURL, defaultResolve) => { + const alias = Object.keys(aliases).find((key) => isAliasInSpecifier(specifier, key)); + + const newSpecifier = alias === undefined + ? specifier + : path.join(aliases[alias], specifier.substr(alias.length)); + + return defaultResolve(newSpecifier, parentModuleURL); +} \ No newline at end of file diff --git a/package.json b/package.json index ffa6d61..5409b79 100644 --- a/package.json +++ b/package.json @@ -11,22 +11,25 @@ "@types/uuid": "^8.3.0", "bonjour": "^3.5.0", "chalk": "^4.1.1", + "deepmerge": "^4.2.2", "faker": "^5.5.3", "frigid": "^1.3.8", "fs-extra": "^10.0.0", "get-port": "^5.1.1", "logger": "^0.0.1", + "module-alias": "^2.2.2", "neo-blessed": "^0.2.0", "printable-characters": "^1.0.42", "sisteransi": "^1.0.5", "typescript": "^4.3.2", "uuid": "^8.3.2", + "walk-sync": "^3.0.0", "ws": "^7.4.6", "yarn": "^1.22.10" }, "scripts": { "compile:watch": "tsc --watch", - "start": "node --enable-source-maps out/index.js", + "start": "node --loader ./lib/aliases.mjs --enable-source-maps out/src/index.js", "dev": "supervisor -w out -n exit -t -k --exec yarn -- start", "prod": "git fetch && git pull && yarn && tsc && yarn start" } diff --git a/src/Pawn.ts b/src/Pawn.ts index 16ebf57..81317ab 100644 --- a/src/Pawn.ts +++ b/src/Pawn.ts @@ -7,6 +7,7 @@ import { ChopTreeTask } from './tasks/ChopTreeTask.js'; import { Game } from './Game.js'; import { render } from './ui/UI.js'; import { Memory } from './Memory.js'; +import { getTheme } from './ui/Theme.js'; const LABORS = { CUT_TREE: Symbol('CUT_TREE'), @@ -127,7 +128,7 @@ export class Pawn extends Serializable implements Tickable { if(this.job) { return this.job.status; } else { - return this.awake ? chalk.bold.black('IDLE') : chalk.blue('RESTING') + return this.awake ? getTheme().status.idle('IDLE') : getTheme().status.self('RESTING') } } diff --git a/src/Progressbar.ts b/src/Progressbar.ts index ae4d720..a715cfe 100644 --- a/src/Progressbar.ts +++ b/src/Progressbar.ts @@ -23,7 +23,19 @@ export function progressbar(completion: number, width: number, style: Progressba } else if(style === ProgressbarStyle.progress) { chalkFn = getTheme().progressBar.normal; } - const chars = [' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█']; + + const chars = [ + '\u0020', + '\u258f', + '\u258e', + '\u258d', + '\u258c', + '\u258b', + '\u258a', + '\u2589', + '\u2588' + ]; + let str = ''; for(let i = 0; i < width; i ++) { const remainder = Math.floor(Math.min(Math.max(0, (completion * width) - i), 1) * 8); diff --git a/src/Time.ts b/src/Time.ts index 05fafd8..25cf313 100644 --- a/src/Time.ts +++ b/src/Time.ts @@ -58,7 +58,7 @@ export default class Time extends Serializable implements Renderable { render() { const sym = (this.hour >= 6 && this.hour < 20) ? - chalk.ansi256(226).bgAnsi256(27)(' ☀ ') : + chalk.ansi256(226).bgAnsi256(27)(' ☼ ') : chalk.ansi256(254).bgAnsi256(17)(' ☾ ') return `${sym} ${ @@ -74,8 +74,6 @@ export default class Time extends Serializable implements Renderable { this.normalizedYear }`) }`; - - // return '☾' || '☼'; } toString() { diff --git a/src/index.ts b/src/index.ts index 4b91094..fe35d88 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,30 @@ import { Game } from './Game.js'; import { render } from './ui/UI.js'; import { ensureDirSync } from 'fs-extra'; -import { parse } from 'path'; +import { lstatSync } from 'fs'; +import { parse, resolve } from 'path'; +import walkSync from 'walk-sync'; +import { fileURLToPath } from 'url'; const saveFile = process.argv[2] || 'data/world01.json'; ensureDirSync(parse(saveFile).dir); -// TODO move render logic into game, so that the ui doesnt exist until the game does... -// maybe, i mean, an argument could be made for not that, because the game -// isnt necessarily the entire thing, its just one instance of a save file. -// But probably the initial menu screens will be their own thing entirely. -const game = Game.create(saveFile); -render(game); +const extensionsPath = resolve(parse(fileURLToPath(import.meta.url)).dir, '../content'); + +const extensions = walkSync(extensionsPath) + .map(path => resolve(extensionsPath, path)) + .filter(path => lstatSync(path).isFile()) + .filter(path => parse(path).ext === '.js') + .map(path => import(path)); + +Promise.all(extensions).then((extensions) => { + + // TODO move render logic into game, so that the ui doesnt exist until the game does... + // maybe, i mean, an argument could be made for not that, because the game + // isnt necessarily the entire thing, its just one instance of a save file. + // But probably the initial menu screens will be their own thing entirely. + const game = Game.create(saveFile); + render(game); + +}); \ No newline at end of file diff --git a/src/ui/Theme.ts b/src/ui/Theme.ts index 6eb2f38..d1d8436 100644 --- a/src/ui/Theme.ts +++ b/src/ui/Theme.ts @@ -6,6 +6,8 @@ // instead of upsampling them to 16m codes. import chalk from 'chalk'; chalk.level = 2; +import merge from 'deepmerge'; +import log from '../log.js'; type StyleFunction = (text: string) => string; @@ -36,11 +38,11 @@ export type Theme = { status: { idle: StyleFunction, self: StyleFunction, - + work: StyleFunction } } -export const defaultTheme: Theme = { +export const backupTheme: Theme = { header: chalk.ansi256(255).bold, subheader: chalk.ansi256(243).bold, normal: chalk.ansi256(243), @@ -63,27 +65,31 @@ export const defaultTheme: Theme = { buckets: [.1, .25, .95] }, normal: chalk.bgAnsi256(235).ansi256(243) + }, + status: { + idle: chalk.ansi256(243), + self: chalk.ansi256(45), + work: chalk.ansi256(208) } } -const debugStyle = chalk.ansi256(213); -export const debugTheme: Theme = { - header: debugStyle.inverse, - subheader: debugStyle, - normal: debugStyle, - selected: debugStyle.inverse, - hotkey: debugStyle, - tab: { - normal: debugStyle, - selected: debugStyle.inverse, - }, - border: { - focused: '#ff88ff', - normal: '#ff00ff' - }, - progressBar: defaultTheme.progressBar +export type ThemeName = string; + +let currentTheme = backupTheme; +const themes: Map = new Map(); + +export function registerTheme(name: ThemeName, theme: Partial) { + log.info('registering theme', name) + themes.set(name, merge(backupTheme, theme)); +} + +export function setTheme(name: ThemeName): void { + if(!themes.has(name)) return; + currentTheme = themes.get(name); + + // TODO reset borders and other weird shit that wont just update on a re-render } export function getTheme(): Theme { - return defaultTheme; + return currentTheme; } \ No newline at end of file diff --git a/test.js b/test.js new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json index 64a23ae..49ad934 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,13 @@ "allowSyntheticDefaultImports": true, "outDir": "out", "declaration": true, - "sourceMap": true + "sourceMap": true, + "paths": { + "@theme": ["./src/ui/Theme"] + } }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "content/**/*.ts" ] } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 8618512..92e3e54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,6 +18,11 @@ version "5.5.6" resolved "https://registry.yarnpkg.com/@types/faker/-/faker-5.5.6.tgz#039b700a9d8ad9150ecc842bf5e717e2027b6f75" +"@types/minimatch@^3.0.3", "@types/minimatch@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" + integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== + "@types/node@*": version "15.12.2" resolved "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz" @@ -36,6 +41,11 @@ array-flatten@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" @@ -47,6 +57,14 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" @@ -75,6 +93,11 @@ color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + deep-equal@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" @@ -86,6 +109,11 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -109,6 +137,11 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +ensure-posix-path@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce" + integrity sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw== + faker@^5.5.3: version "5.5.3" resolved "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz" @@ -196,6 +229,26 @@ logger@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/logger/-/logger-0.0.1.tgz#cb08171f8a6f6f674b8499dadf50bed4befb72c4" +matcher-collection@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29" + integrity sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ== + dependencies: + "@types/minimatch" "^3.0.3" + minimatch "^3.0.2" + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +module-alias@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" + integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -265,6 +318,16 @@ uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" +walk-sync@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-3.0.0.tgz#67f882925021e20569a1edd560b8da31da8d171c" + integrity sha512-41TvKmDGVpm2iuH7o+DAOt06yyu/cSHpX3uzAwetzASvlNtVddgIjXIb2DfB/Wa20B1Jo86+1Dv1CraSU7hWdw== + dependencies: + "@types/minimatch" "^3.0.4" + ensure-posix-path "^1.1.0" + matcher-collection "^2.0.1" + minimatch "^3.0.4" + ws@^7.4.6: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"