@neonwilderness/moveskins 1.1.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/src/create.js ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Creates a new skin locally
3
+ */
4
+ import yargs from "yargs/yargs";
5
+ import chalk from "chalk";
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import * as Twoday from "@neonwilderness/twoday";
9
+ import { skinRegister } from "./_utils.js";
10
+ const argv = yargs(process.argv.slice(2)).argv;
11
+
12
+ // Validates script param --alias (blog name/alias)
13
+ if (!argv.alias) {
14
+ console.log(chalk.red("Error: You must specify a blogname alias with --alias={alias} !!"));
15
+ process.exit(1);
16
+ }
17
+ const alias = argv.alias.trim().toLowerCase();
18
+
19
+ // Validates script param --skin (skin name to be created)
20
+ if (!argv.skin) {
21
+ console.log(
22
+ chalk.red("Error: You must specify a skin name to be created with --skin={skinname} !!"),
23
+ );
24
+ console.log(chalk.blue("Example: node ./src/create --alias=info --skin=Site.mynewskin"));
25
+ process.exit(1);
26
+ }
27
+ const skinName = argv.skin;
28
+
29
+ // Validates skin name syntax (must have 2 strings around a dot)
30
+ const nameParts = skinName.split(".").reduce((all, part) => {
31
+ if (part.trim().length) all.push(part);
32
+ return all;
33
+ }, []);
34
+ if (nameParts.length !== 2) {
35
+ console.log(chalk.red(`Error: Wrong skin name syntax "${skinName}" !!`));
36
+ console.log(chalk.blue("Use skin name syntax: --skin={hoptype}.{name}"));
37
+ process.exit(1);
38
+ }
39
+
40
+ // Main async function to validate hoptype, register the skin and create the physical skin file
41
+ (async () => {
42
+ try {
43
+ const td = new Twoday.Twoday("prod");
44
+ const { valid, prototype, _name } = await td.isValidHoptype(skinName);
45
+
46
+ if (!valid) {
47
+ console.log(
48
+ chalk.red(`Error: Sorry, there is no Hoptype "${prototype}" in the Twoday code base!!`),
49
+ );
50
+ process.exit(1);
51
+ }
52
+
53
+ skinRegister.load();
54
+ const newSkin = "(new skin)";
55
+ skinRegister.setData(skinName, `${skinName} ${newSkin}`, `${newSkin}`);
56
+ skinRegister.store();
57
+
58
+ const dir = path.resolve(process.cwd(), "skins", alias);
59
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir);
60
+ fs.writeFileSync(path.resolve(dir, `${skinName}.skin`), `<p><!-- ${newSkin} --></p>\n`);
61
+ console.log(chalk.green(`New skin "${skinName}" successfully established in /skins/${alias}.`));
62
+ } catch (e) {
63
+ console.log(chalk.red(`An error occured while creating the new skin "${skinName}": ${e}`));
64
+ }
65
+ })();
package/src/images.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Upload /skins/{alias}/images items to create layout images
3
+ */
4
+ import yargs from "yargs/yargs";
5
+ import chalk from "chalk";
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import * as Twoday from "@neonwilderness/twoday";
9
+ import { config } from "dotenv-safe";
10
+ config();
11
+ const argv = yargs(process.argv.slice(2)).argv;
12
+
13
+ // Validates script param --alias (blog name/alias)
14
+ if (!argv.alias) {
15
+ console.log(chalk.red("Error: You must specify a blogname alias with --alias={alias} !!"));
16
+ process.exit(1);
17
+ }
18
+ const alias = argv.alias.trim().toLowerCase();
19
+
20
+ if (!argv.to || (argv.to !== "dev" && argv.to !== "prod")) {
21
+ console.log("Error: You must specify a target platform with --to=dev|prod");
22
+ process.exit(1);
23
+ }
24
+ const platform = argv.to.toLowerCase();
25
+
26
+ (async () => {
27
+ try {
28
+ const td = new Twoday.Twoday(platform);
29
+ await td.login();
30
+
31
+ const imageFolder = path.resolve(process.cwd(), "skins", alias, "images");
32
+ if (!fs.existsSync(imageFolder)) {
33
+ console.log(chalk.red(`Error: image folder for alias ${alias} does not exist!!`));
34
+ process.exit(1);
35
+ }
36
+
37
+ const images = fs.readdirSync(imageFolder);
38
+ let uploaded = 0;
39
+ for (const image of images) {
40
+ const [name, _ext] = image.split(".");
41
+ if (name.startsWith("_")) continue;
42
+ const imgID = await td.createImage(alias, {
43
+ alias: name,
44
+ path: path.resolve(imageFolder, image),
45
+ });
46
+ uploaded++;
47
+ console.log(chalk.green(`New image "${image}" =>${imgID} saved.`));
48
+ }
49
+ console.log(chalk.blue(`${uploaded} images uploaded to alias "${alias}".`));
50
+ } catch (e) {
51
+ console.log(chalk.red(`Error while creating images for alias "${alias}": ${e}`));
52
+ } finally {
53
+ await td.logout();
54
+ }
55
+ })();
package/src/index.js ADDED
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Downloads modified skins from dev|prod Twoday for one or more alias(es) to a local ./skin folder
3
+ * or
4
+ * Uploads local skins to dev|prod Twoday for selected aliases
5
+ * Examples:
6
+ * node ./index --from=dev --alias=www,info (downloads www/info skins from twoday-test.net)
7
+ * node ./index --to=dev --alias=info (uploads local info skins to twoday-test.net)
8
+ * node ./index --from=prod --alias=* (downloads www/info/help/top skins from twoday.net)
9
+ * node ./index --to=prod --alias=www (uploads local www skins to twoday.net)
10
+ * ================================================================================================
11
+ * An Alias of * is equal to the core Twoday blogs: www,info,help,top
12
+ * User/Psw in .env file needs to have admin rights on the selected alias(es) or it won't work!
13
+ */
14
+ import yargs from "yargs/yargs";
15
+ const argv = yargs(process.argv.slice(2)).options({
16
+ from: {
17
+ alias: "f",
18
+ description: 'Platform where to download the skins from: "dev" or "prod"',
19
+ type: "string",
20
+ },
21
+ to: {
22
+ alias: "t",
23
+ description: 'Platform where to compare or upload the skins to: "dev" or "prod"',
24
+ type: "string",
25
+ },
26
+ alias: {
27
+ alias: "a",
28
+ description: "One or more alias blog name/s delimited by comma (no space)",
29
+ type: "string",
30
+ },
31
+ skin: {
32
+ alias: "s",
33
+ description: "Skin selection string (regex) to filter the skins to upload",
34
+ type: "string",
35
+ },
36
+ backup: {
37
+ alias: "b",
38
+ description: "Backup skins to the local /backup folder to preserve their former status",
39
+ type: "boolean",
40
+ },
41
+ clean: {
42
+ default: false,
43
+ description:
44
+ "Cleanup (delete) the alias local skin directory to remove potential old files before new download",
45
+ type: "boolean",
46
+ },
47
+ compare: {
48
+ default: false,
49
+ description: "Compare the local alias skin directory to a remote location (prod/dev)",
50
+ type: "boolean",
51
+ },
52
+ debug: {
53
+ default: false,
54
+ description: "Issue more logging messages and diff analysis (for upload function)",
55
+ type: "boolean",
56
+ },
57
+ }).argv;
58
+ import chalk from "chalk";
59
+ import * as Twoday from "@neonwilderness/twoday";
60
+ import { cleanupAliasFolder, splitAliases } from "./_utils.js";
61
+ import { downloadModifiedSkins } from "./_download.js";
62
+ import { uploadModifiedSkins } from "./_upload.js";
63
+ import { compareLocalToRemoteSkins } from "./_compare.js";
64
+ import { config } from "dotenv-safe";
65
+ config();
66
+
67
+ if (!argv.from && !argv.to) {
68
+ console.log("Desired action must be specified with --from=dev|prod or --to=dev|prod");
69
+ process.exit(1);
70
+ }
71
+ if (argv.from && argv.to) {
72
+ console.log("You cannot specify --from=dev|prod AND --to=dev|prod in one run");
73
+ process.exit(1);
74
+ }
75
+ if (argv.compare && !argv.to) {
76
+ console.log("You must specify a target platform with --to=dev|prod when comparing skins");
77
+ process.exit(1);
78
+ }
79
+ if (!argv.alias) {
80
+ console.log("You must specify the desired alias(es) with --alias=name1,name2,... OR --alias=*");
81
+ process.exit(1);
82
+ }
83
+ const platform = (argv.from || argv.to).toLowerCase();
84
+ const td = new Twoday.Twoday(platform, { delay: 100 });
85
+
86
+ const core = ["www", "info", "help", "top"];
87
+ const aliases = argv.alias === "*" ? core : splitAliases(argv.alias, ",");
88
+
89
+ if (argv.compare) {
90
+ if (aliases.length === 1 && aliases[0].includes(":"))
91
+ console.log(
92
+ `Start comparing local skin files of alias${aliases.length > 1 ? "es" : ""} ${chalk.yellow(
93
+ aliases.join(", "),
94
+ )} to ${chalk.green(td.fullDomain)}...`,
95
+ );
96
+ compareLocalToRemoteSkins(td, aliases);
97
+ } else {
98
+ const action = argv.from ? "down" : "up";
99
+ const direction = argv.from ? "from" : "to";
100
+ const execTask = argv.from ? downloadModifiedSkins : uploadModifiedSkins;
101
+
102
+ if (action === "down" && argv.clean) cleanupAliasFolder(aliases, argv.backup);
103
+
104
+ console.log(
105
+ `Start ${action}loading modified skins of alias${aliases.length > 1 ? "es" : ""} ${chalk.yellow(
106
+ aliases.join(", "),
107
+ )} ${direction} remote ${chalk.green(td.fullDomain)}...`,
108
+ );
109
+ execTask(td, aliases, {
110
+ backup: argv.backup,
111
+ debug: argv.debug,
112
+ skin: argv.skin ? new RegExp(argv.skin) : null,
113
+ });
114
+ }
@@ -0,0 +1,132 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Skin Diff Report</title>
8
+ <style>
9
+ body {
10
+ background: #fff;
11
+ color: #24292e;
12
+ font-family: Arial, Helvetica, sans-serif;
13
+ font-size: 16px;
14
+ }
15
+ del {
16
+ background: #ffdce0;
17
+ text-decoration: none;
18
+ }
19
+ ins {
20
+ background: #ccffd8;
21
+ text-decoration: none;
22
+ }
23
+ del::before,
24
+ ins::before {
25
+ display: inline-block;
26
+ font-weight: bold;
27
+ width: 2rem;
28
+ text-align: center;
29
+ }
30
+ del::before {
31
+ content: "–";
32
+ background: #fdb9c1;
33
+ }
34
+ ins::before {
35
+ content: "+";
36
+ background: #abf2bc;
37
+ }
38
+ h3 {
39
+ padding: 0.5rem;
40
+ }
41
+ .skinbox {
42
+ background: #f5f5f5;
43
+ margin-top: 1rem;
44
+ padding: 0.5rem;
45
+ }
46
+ .skinresult {
47
+ margin-top: 0.5rem;
48
+ }
49
+ .skinresult::before {
50
+ display: inline-block;
51
+ background: #ddd;
52
+ font-size: 11px;
53
+ content: "Skin";
54
+ margin-right: 0.5rem;
55
+ padding: 2px 4px;
56
+ line-height: 1rem;
57
+ border-radius: 5px;
58
+ }
59
+ .identical .skinresult {
60
+ }
61
+ .different .skinresult {
62
+ background: yellow;
63
+ font-weight: bold;
64
+ padding: 0.5rem;
65
+ }
66
+ .new .skinresult {
67
+ background: #abf2bc;
68
+ font-weight: bold;
69
+ padding: 0.5rem;
70
+ }
71
+ .skintoggle {
72
+ border: 0;
73
+ color: #777;
74
+ font-weight: bolder;
75
+ background: #ddd;
76
+ border-radius: 50%;
77
+ line-height: 1rem;
78
+ margin-left: 0.5rem;
79
+ cursor: pointer;
80
+ }
81
+ .resultbox {
82
+ margin-top: 1rem;
83
+ }
84
+ .result {
85
+ margin-top: 0.5rem;
86
+ font-size: 14px;
87
+ }
88
+ .diffs {
89
+ font-family: monospace;
90
+ margin-top: 0.2rem;
91
+ }
92
+ </style>
93
+ </head>
94
+ <body x-data="diffResults">
95
+ <template x-for="(alias, ia) in aliases" :key="ia">
96
+ <div class="aliasbox">
97
+ <h3 x-html="alias.header"></h3>
98
+ <template x-for="(skin, is) in alias.skins" :key="is">
99
+ <div class="skinbox" :class="skin.class">
100
+ <div>
101
+ <span class="skinresult" :class="skin.class" x-text="skin.text"></span>
102
+ <button
103
+ class="skintoggle"
104
+ @click="skin.open = !skin.open"
105
+ x-show="skin.results.length"
106
+ x-text="skin.open ? '-' : '+'"
107
+ ></button>
108
+ </div>
109
+ <div class="resultbox" x-show="skin.open && skin.results.length">
110
+ <template x-for="(result, ir) in skin.results" :key="ir">
111
+ <div class="result">
112
+ <div
113
+ :style="{ color: result.itemChanged ? '#e53935' : '#bdbdbd' }"
114
+ x-text="result.text"
115
+ ></div>
116
+ <div class="diffs" x-html="result.diffs.replace(/\n/g, '<br>')"></div>
117
+ </div>
118
+ </template>
119
+ </div>
120
+ </div>
121
+ </template>
122
+ </div>
123
+ </template>
124
+
125
+ <script>
126
+ document.addEventListener("alpine:init", () => {
127
+ Alpine.data("diffResults", () => $$templateJSON);
128
+ });
129
+ </script>
130
+ <script defer src="https://unpkg.com/alpinejs@latest"></script>
131
+ </body>
132
+ </html>