@neonwilderness/moveskins 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neonwilderness/moveskins",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Download/Upload/Compare modified skins for selected aliases on Twoday",
5
5
  "keywords": [
6
6
  "antville",
@@ -10,6 +10,9 @@
10
10
  ],
11
11
  "license": "MIT",
12
12
  "author": "NeonWilderness",
13
+ "bin": {
14
+ "moveskins": "./dist/index.js"
15
+ },
13
16
  "files": [
14
17
  "dist",
15
18
  "skins/skinRegister.json",
@@ -22,24 +25,22 @@
22
25
  ],
23
26
  "type": "module",
24
27
  "exports": "./dist/index.js",
25
- "bin": {
26
- "moveskins": "./dist/index.js"
27
- },
28
28
  "scripts": {
29
29
  "update": "ncu -u && npm i",
30
30
  "backup": "node ./src/index --backup --alias=www --from=prod",
31
31
  "dev": "vp run node ./src/index.js",
32
32
  "build": "vp build",
33
33
  "check": "vp check",
34
+ "check:fix": "vp check --fix",
34
35
  "create": "node ./src/create --skin=Site.testskin --alias=talkstraight",
35
36
  "//": "For compare function, live-server module must be installed globally!",
36
37
  "compare": "node ./src/index --compare --alias=help --to=dev && npm run report",
37
38
  "compare:blogs": "node ./src/index --compare --alias=foundation:info --to=prod && npm run report",
38
- "download": "node ./src/index --alias=foundation --from=prod",
39
+ "download": "node ./src/index --alias=www --from=prod --modules",
39
40
  "download2": "node ./src/index --alias=info,help --from=prod",
40
- "download:clean": "node ./src/index --alias=recycle --from=prod --clean",
41
- "download:core": "node ./src/index --alias=* --from=prod",
42
- "download:core:clean": "node ./src/index --alias=* --from=prod --clean",
41
+ "download:clean": "node ./src/index --alias=www --from=prod --clean --modules",
42
+ "download:core": "node ./src/index --alias=* --from=prod --modules",
43
+ "download:core:clean": "node ./src/index --alias=* --from=prod --clean --modules",
43
44
  "report": "live-server --open=./report.html --quiet",
44
45
  "restore": "node ./src/index --backup --alias=www --to=dev",
45
46
  "upload": "node ./src/index --alias=neonwilderness --to=dev",
@@ -51,16 +52,16 @@
51
52
  "test:ui": "vp test --ui"
52
53
  },
53
54
  "dependencies": {
54
- "@neonwilderness/twoday": "^0.6.2",
55
+ "@neonwilderness/twoday": "^0.8.0",
55
56
  "chalk": "^5.6.2",
56
57
  "del": "^8.0.1",
57
58
  "dotenv-safe": "^9.1.0",
58
59
  "yargs": "^18.0.0"
59
60
  },
60
61
  "devDependencies": {
61
- "@vitest/ui": "4.1.2",
62
+ "@vitest/ui": "4.1.5",
62
63
  "slash": "^5.1.0",
63
- "vite-plus": "^0.1.15"
64
+ "vite-plus": "^0.1.19"
64
65
  },
65
66
  "engines": {
66
67
  "node": ">=20"
@@ -218,5 +218,9 @@
218
218
  "Site.flagReasons": {
219
219
  "title": "Globale Texte für Beitragsmarkierungen",
220
220
  "description": "In diesem Systemskin werden die gültigen Beitragsmarkierungsgründe mit ihren jeweiligen Texten in Deutsch (de) und Englisch (en) hinterlegt."
221
+ },
222
+ "Site.adminnavigation": {
223
+ "title": "Navigationsleiste für Site Administratoren",
224
+ "description": "Dieses Skin beinhaltet die zusätzlichen Navigationselemente für Site Administratoren. (z.B. »Einstellungen bearbeiten«, »Skins bearbeiten«, ...)"
221
225
  }
222
226
  }
package/src/_download.js CHANGED
@@ -8,6 +8,28 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
8
8
  import { resolve } from "node:path";
9
9
  import { aliasSkinFolder, skinRegister } from "./_utils.js";
10
10
 
11
+ const capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
12
+
13
+ const findEmbeddedSkinMacros = async (td, alias, skinContent, skinContainer) => {
14
+ const skinMacros = skinContent.match(/<%\s.*?\.skin name=".*?"\s%>/g);
15
+ if (skinMacros) {
16
+ for (let macro of skinMacros) {
17
+ // example: '<% Site.skin name="legalRefs" %>'
18
+ const s = macro.match(/(\w+)\.skin name="(\w+)"/);
19
+ if (!s) continue;
20
+ const skinName = `${capitalize(s[1])}.${s[2]}`;
21
+ const layoutUrl = await td.getActiveLayoutUrl(alias);
22
+ const { skin } = await td.getSkin({
23
+ name: skinName,
24
+ url: `${layoutUrl}/skins/edit?key=${skinName}`,
25
+ });
26
+ skinContainer[skinName] = skin;
27
+ skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
28
+ }
29
+ }
30
+ return skinContainer;
31
+ };
32
+
11
33
  /**
12
34
  * Downloads all customized skins of one or more aliases and stores them in appropriate
13
35
  * subdirectories for subsequent manual edits (or just as backup)
@@ -22,6 +44,7 @@ const downloadModifiedSkins = async (td, aliases, options) => {
22
44
  console.log(chalk.green(`\nNow processing alias "${alias}"...`));
23
45
  const aliasSkinDir = aliasSkinFolder(alias, options.backup);
24
46
  const modifiedSkins = await td.getModifiedSkins(alias);
47
+ let skinContainer = {};
25
48
 
26
49
  if (modifiedSkins.length && !existsSync(aliasSkinDir)) mkdirSync(aliasSkinDir);
27
50
  console.log(
@@ -37,7 +60,32 @@ const downloadModifiedSkins = async (td, aliases, options) => {
37
60
  const { title, description, skin } = await td.getSkin(modSkin);
38
61
 
39
62
  skinRegister.setData(modSkin.name, title, description);
40
- writeFileSync(resolve(aliasSkinDir, `${modSkin.name}.skin`), skin);
63
+ skinContainer[modSkin.name] = skin;
64
+ skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
65
+ }
66
+
67
+ if (options.modules) {
68
+ console.log(chalk.yellow(`Exporting sidebar freetext modules as requested.`));
69
+ const sidebar = await td.getSidebarModules(alias);
70
+ const moduleNames = [...sidebar.sidebar01, ...sidebar.sidebar02];
71
+ for (let module of moduleNames) {
72
+ if (/FreeText\d{2}/.test(module)) {
73
+ console.log(chalk.gray(`Reading sidebar module "${module}".`));
74
+ const { heading, content } = await td.getFreeTextModule(alias, module);
75
+ skinContainer[`Sidebar.${module}`] = `${heading}\n${content}`;
76
+ } else {
77
+ const { skins } = await td.getModuleSkins(alias, module);
78
+ for (let s of skins) {
79
+ const { title, description, skin } = await td.getSkin(s);
80
+ skinRegister.setData(s.name, title, description);
81
+ skinContainer[s.name] = skin;
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ for (const [name, content] of Object.entries(skinContainer)) {
88
+ writeFileSync(resolve(aliasSkinDir, `${name}.skin`), content);
41
89
  }
42
90
  }
43
91
  console.log(chalk.green("Download completed."));
package/src/_upload.js CHANGED
@@ -35,19 +35,41 @@ const uploadModifiedSkins = async (td, aliases, options) => {
35
35
  if (!skinFile.endsWith(".skin")) continue;
36
36
  if (options.skin && !options.skin.test(skinFile)) continue;
37
37
 
38
- const skin = skinRegister.getData(skinFile);
39
- skin.content = readFileSync(resolve(aliasSkinDir, skinFile))
40
- .toString()
41
- .replace(/\r\n/g, "\n");
38
+ const [hoptype, name] = skinFile.split(".");
39
+ if (hoptype === "Sidebar") {
40
+ const module = readFileSync(resolve(aliasSkinDir, skinFile))
41
+ .toString()
42
+ .replace(/\r\n/g, "\n");
43
+ let splitAt = module.indexOf("\n");
44
+ const heading = module.slice(0, splitAt);
45
+ const content = module.slice(++splitAt);
46
+ console.log(chalk.blue(`Now updating sidebar module ${name} (len=${content.length}).`));
47
+ await td.updateFreeTextModule(alias, name, { heading, content });
48
+ console.log(chalk.green(`Update request completed for module: ${name}`));
49
+ } else {
50
+ const { isValid, prototype } = td.isValidHoptype(skinFile.slice(0, -5));
51
+ if (!isValid) {
52
+ console.log(
53
+ chalk.red(
54
+ `Skipping upload for invalid skin hoptype "${prototype}" (Skin file ${skinFile}).`,
55
+ ),
56
+ );
57
+ continue;
58
+ }
59
+ const skin = skinRegister.getData(skinFile);
60
+ skin.content = readFileSync(resolve(aliasSkinDir, skinFile))
61
+ .toString()
62
+ .replace(/\r\n/g, "\n");
42
63
 
43
- console.log(chalk.blue(`Now updating skin ${skin.name} (len=${skin.content.length}).`));
44
- await td.updateSkin(alias, skin.name, {
45
- title: skin.title,
46
- description: skin.description,
47
- skin: skin.content,
48
- diff: options.debug,
49
- });
50
- console.log(chalk.green(`Update request completed for skin: ${skin.name}`));
64
+ console.log(chalk.blue(`Now updating skin ${skin.name} (len=${skin.content.length}).`));
65
+ await td.updateSkin(alias, skin.name, {
66
+ title: skin.title,
67
+ description: skin.description,
68
+ skin: skin.content,
69
+ diff: options.debug,
70
+ });
71
+ console.log(chalk.green(`Update request completed for skin: ${skin.name}`));
72
+ }
51
73
 
52
74
  if (currentSkins.has(skin.name)) currentSkins.delete(skin.name);
53
75
  }
package/src/index.js CHANGED
@@ -33,6 +33,12 @@ const argv = yargs(process.argv.slice(2)).options({
33
33
  description: "Skin selection string (regex) to filter the skins to upload",
34
34
  type: "string",
35
35
  },
36
+ modules: {
37
+ alias: "m",
38
+ description: "Download sidebar module skins/freetext as well",
39
+ default: false,
40
+ type: "boolean",
41
+ },
36
42
  backup: {
37
43
  alias: "b",
38
44
  description: "Backup skins to the local /backup folder to preserve their former status",
@@ -99,7 +105,10 @@ if (argv.compare) {
99
105
  const direction = argv.from ? "from" : "to";
100
106
  const execTask = argv.from ? downloadModifiedSkins : uploadModifiedSkins;
101
107
 
102
- if (action === "down" && argv.clean) cleanupAliasFolder(aliases, argv.backup);
108
+ if (action === "down" && argv.clean) {
109
+ cleanupAliasFolder(aliases, argv.backup);
110
+ console.log(chalk.yellow(`Cleaning target download folder/s for "${aliases}".`));
111
+ }
103
112
 
104
113
  console.log(
105
114
  `Start ${action}loading modified skins of alias${aliases.length > 1 ? "es" : ""} ${chalk.yellow(
@@ -109,6 +118,7 @@ if (argv.compare) {
109
118
  execTask(td, aliases, {
110
119
  backup: argv.backup,
111
120
  debug: argv.debug,
121
+ modules: argv.modules,
112
122
  skin: argv.skin ? new RegExp(argv.skin) : null,
113
123
  });
114
124
  }