Compare commits
49 Commits
5cf8fdf942
...
80d9974c05
Author | SHA1 | Date |
---|---|---|
Alyxia Sother | 80d9974c05 | |
Alyxia Sother | bd4c9d266a | |
Alyxia Sother | 4879b52251 | |
Alyxia Sother | 3b0b6e7974 | |
Alyxia Sother | 7b70fcd297 | |
Alyxia Sother | 6a71b42e66 | |
Ducko | 255062d5d5 | |
Ducko | b8320bb167 | |
Ducko | 4b0de84b00 | |
Ducko | 2cac769291 | |
Ducko | 55578d0773 | |
Ducko | ae6c36373f | |
Ducko | 1a1e3fcbae | |
Ducko | 4e3f301bd6 | |
Ducko | cf61e63df0 | |
Ducko | 758810cfe8 | |
Ducko | 65c93cd135 | |
Ducko | abdad45d2d | |
Ducko | c349fd6ccc | |
Ducko | ea51962e77 | |
Ducko | f2ac90299c | |
PandaDriver | ae21d6d6cc | |
Ducko | 0300abe06e | |
Ducko | 4adf688ee8 | |
Ducko | d05b6c17c5 | |
Ducko | 42e2c02719 | |
Ducko | 8b347972ac | |
Ducko | 0d68aa88c2 | |
Ducko | 9bcf6d59f8 | |
Ducko | 5fe0bdc257 | |
Ducko | 865a105079 | |
Ducko | 549bb1afec | |
Ducko | da87247f5d | |
Ducko | 2db8ae01c4 | |
Ducko | e2f529d7fc | |
Ducko | 9b36c9d799 | |
Ducko | c999320da0 | |
Ducko | e18c019720 | |
Ducko | 41aec3cb61 | |
Ducko | 102f7ab662 | |
Ducko | 833819c63f | |
Ducko | d4b6b0a142 | |
Ducko | d24d0c5b6c | |
Ducko | bec681af2d | |
Ducko | 768db5ae3f | |
Ducko | 8aa61cf30b | |
Ducko | 1a2a0e454c | |
Ducko | 1147791ce8 | |
Alyxia Sother | d209c0665e |
|
@ -1,9 +1,7 @@
|
|||
node_modules
|
||||
.cache
|
||||
|
||||
clones
|
||||
src/gh_pat.json
|
||||
# dist
|
||||
|
||||
src/env.json
|
||||
dist/*
|
||||
devDist
|
||||
devTemp
|
||||
|
|
14
README.md
14
README.md
|
@ -2,4 +2,16 @@
|
|||
|
||||
Builder for Module Store v2.
|
||||
|
||||
**To run this yourself, you need to [get your own GitHub Personal Access Token](https://docs.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) and export it in `src/gh_pat.js`.**
|
||||
|
||||
## Self usage
|
||||
|
||||
To run this yourself, you **need** to:
|
||||
1. [Get your own GitHub Personal Access Token](https://docs.github.com/en/articles/creating-a-personal-access-token-for-the-command-line)
|
||||
2. Get a Discord bot token
|
||||
3. Make a `src/env.js` file like:
|
||||
```js
|
||||
export default {
|
||||
github: '<your github pat>',
|
||||
discord: '<your discord bot token>
|
||||
}
|
||||
```
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -1 +1,2 @@
|
|||
export * as clipboard from './clipboard';
|
||||
export * as clipboard from './clipboard';
|
||||
export * as shell from './shell';
|
|
@ -0,0 +1,5 @@
|
|||
export const openExternal = (url) => {
|
||||
// Discord makes new tabs / windows (via window.open) use electron.shell.openExternal internally, so just use window.open
|
||||
|
||||
window.open(url);
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
import showToast from '@goosemod/toast';
|
||||
import { commands } from '@goosemod/patcher';
|
||||
|
||||
export default class Plugin {
|
||||
constructor() {
|
||||
this.patches = [];
|
||||
this.commands = [];
|
||||
this.stylesheets = [];
|
||||
}
|
||||
|
||||
command(...args) {
|
||||
this.commands.push(args[0]);
|
||||
|
||||
commands.add(...args);
|
||||
}
|
||||
|
||||
enqueueUnpatch(unpatch) {
|
||||
this.patches.push(unpatch);
|
||||
}
|
||||
|
||||
addCss(css) {
|
||||
const el = document.createElement('style');
|
||||
|
||||
el.appendChild(document.createTextNode(css)); // Load the stylesheet via style element w/ CSS text
|
||||
|
||||
document.head.appendChild(el);
|
||||
|
||||
this.stylesheets.push(el); // Push to internal array so we can remove the elements on unload
|
||||
}
|
||||
|
||||
toast(content, options) {
|
||||
showToast(content, {
|
||||
subtext: this.name,
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
goosemodHandlers = {
|
||||
onImport: () => {
|
||||
this.onImport();
|
||||
},
|
||||
|
||||
onRemove: () => {
|
||||
this.patches.forEach((x) => x());
|
||||
this.stylesheets.forEach((x) => x.remove());
|
||||
this.commands.forEach((x) => commands.remove(x));
|
||||
|
||||
this.onRemove();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
module.exports = goosemodScope.webpackModules.common;
|
|
@ -4,5 +4,4 @@ export { default as SliderInput } from './sliderInput';
|
|||
export { default as Divider } from './divider';
|
||||
export { default as ButtonItem } from './buttonItem';
|
||||
export { default as Category } from './category';
|
||||
|
||||
export const SwitchItem = goosemodScope.webpackModules.findByDisplayName('SwitchItem');
|
||||
export { default as SwitchItem } from './switchItem';
|
|
@ -0,0 +1,22 @@
|
|||
const { React } = goosemodScope.webpackModules.common;
|
||||
const SwitchItem = goosemodScope.webpackModules.findByDisplayName('SwitchItem');
|
||||
|
||||
export default class SwitchItemContainer extends React.Component {
|
||||
constructor(props) {
|
||||
const originalHandler = props.onChange;
|
||||
props.onChange = (e) => {
|
||||
originalHandler(e);
|
||||
|
||||
this.props.value = e;
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return React.createElement(SwitchItem, {
|
||||
...this.props
|
||||
});
|
||||
}
|
||||
}
|
|
@ -22,6 +22,18 @@ export class Plugin {
|
|||
Settings.makeStore(this.entityID);
|
||||
}
|
||||
|
||||
// Supposed to return PC manifest, which we don't store so return a rough one based on GM metadata
|
||||
get manifest() {
|
||||
return {
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
version: this.version,
|
||||
|
||||
author: this.authors.toString(),
|
||||
license: 'Unknown'
|
||||
}
|
||||
}
|
||||
|
||||
get entityID() {
|
||||
return this.name;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,16 @@ export const registerCommand = ({ command, alias, description, usage, executor }
|
|||
// TODO: implement alias
|
||||
|
||||
goosemodScope.patcher.commands.add(command, description,
|
||||
async ( { args: [ { text } ] } ) => {
|
||||
const out = await executor(text.split(' ')); // Run original executor func (await incase it's an async function)
|
||||
async (ret) => {
|
||||
// Don't just destructure as using without text arguments returns empty object ({})
|
||||
|
||||
let textGiven = '';
|
||||
if (ret.args) {
|
||||
const { args: [ { text } ] } = ret;
|
||||
textGiven = text;
|
||||
}
|
||||
|
||||
const out = await executor(textGiven.split(' ')); // Run original executor func (await incase it's an async function)
|
||||
|
||||
if (!out.send) {
|
||||
goosemodScope.patcher.internalMessage(out.result); // PC impl. sends internal message when out.send === false, so we also do the same via our previous Patcher API function
|
||||
|
|
|
@ -19,10 +19,14 @@ class SimpleStore {
|
|||
}
|
||||
|
||||
this.store[key] = value;
|
||||
|
||||
return this.store[key];
|
||||
}
|
||||
|
||||
toggleSetting = (key) => {
|
||||
this.store[key] = !this.store[key];
|
||||
|
||||
return this.store[key];
|
||||
}
|
||||
|
||||
deleteSetting = (key) => {
|
||||
|
|
|
@ -27,7 +27,8 @@ module.exports = {
|
|||
},
|
||||
|
||||
getModuleByDisplayName: (displayName) => {
|
||||
return goosemodScope.webpackModules.findByDisplayName(displayName);
|
||||
// Use custom find instead of GM's findByDisplayName as PC's is case insensitive
|
||||
return goosemodScope.webpackModules.find((x) => x.displayName && x.displayName.toLowerCase() === displayName.toLowerCase());
|
||||
},
|
||||
|
||||
...goosemodScope.webpackModules.common // Export common modules (eg: React)
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"glob": "^7.1.6",
|
||||
"parcel-bundler": "^1.12.4"
|
||||
"parcel-bundler": "^1.12.4",
|
||||
"sass": "^1.32.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
@ -1785,9 +1786,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001179",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz",
|
||||
"integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA=="
|
||||
"version": "1.0.30001242",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz",
|
||||
"integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
}
|
||||
},
|
||||
"node_modules/caseless": {
|
||||
"version": "0.12.0",
|
||||
|
@ -4974,6 +4979,17 @@
|
|||
"resolved": "https://registry.npmjs.org/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz",
|
||||
"integrity": "sha1-GN4vl+S/epVRrXURlCtUlverpmA="
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pn": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
|
||||
|
@ -5978,6 +5994,147 @@
|
|||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.35.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.35.1.tgz",
|
||||
"integrity": "sha512-oCisuQJstxMcacOPmxLNiLlj4cUyN2+8xJnG7VanRoh2GOLr9RqkvI4AxA4a6LHVg/rsu+PmxXeGhrdSF9jCiQ==",
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"sass": "sass.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/chokidar": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
|
@ -8829,9 +8986,9 @@
|
|||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001179",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz",
|
||||
"integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA=="
|
||||
"version": "1.0.30001242",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz",
|
||||
"integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug=="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
|
@ -11454,6 +11611,11 @@
|
|||
"resolved": "https://registry.npmjs.org/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz",
|
||||
"integrity": "sha1-GN4vl+S/epVRrXURlCtUlverpmA="
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
|
||||
},
|
||||
"pn": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
|
||||
|
@ -12279,11 +12441,101 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.32.8",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.32.8.tgz",
|
||||
"integrity": "sha512-Sl6mIeGpzjIUZqvKnKETfMf0iDAswD9TNlv13A7aAF3XZlRPMq4VvJWBC2N2DXbp94MQVdNSFG6LfF/iOXrPHQ==",
|
||||
"version": "1.35.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.35.1.tgz",
|
||||
"integrity": "sha512-oCisuQJstxMcacOPmxLNiLlj4cUyN2+8xJnG7VanRoh2GOLr9RqkvI4AxA4a6LHVg/rsu+PmxXeGhrdSF9jCiQ==",
|
||||
"requires": {
|
||||
"chokidar": ">=2.0.0 <4.0.0"
|
||||
"chokidar": ">=3.0.0 <4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
|
||||
},
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"optional": true
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sax": {
|
||||
|
|
13
package.json
13
package.json
|
@ -2,52 +2,43 @@
|
|||
"name": "ms2builder",
|
||||
"version": "1.0.0",
|
||||
"description": "Builder for Module Store v2.",
|
||||
|
||||
"main": "src/index.js",
|
||||
|
||||
"scripts": {
|
||||
"theme": "node ./scripts/add.js theme",
|
||||
"pccompatcheck": "node ./scripts/pccompatCheck.js"
|
||||
},
|
||||
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/GooseMod/MS2Builder.git"
|
||||
},
|
||||
|
||||
"author": "GooseMod",
|
||||
"license": "MIT",
|
||||
|
||||
"bugs": {
|
||||
"url": "https://github.com/GooseMod/MS2Builder/issues"
|
||||
},
|
||||
"homepage": "https://github.com/GooseMod/MS2Builder#readme",
|
||||
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"glob": "^7.1.6",
|
||||
"parcel-bundler": "^1.12.4",
|
||||
"sass": "^1.32.8"
|
||||
},
|
||||
|
||||
"alias": {
|
||||
"@goosemod/patcher": "./moduleWrappers/goosemod/patcher.js",
|
||||
"@goosemod/webpack": "./moduleWrappers/goosemod/webpack.js",
|
||||
"@goosemod/webpack/common": "./moduleWrappers/goosemod/webpackCommon.js",
|
||||
"@goosemod/logger": "./moduleWrappers/goosemod/logger.js",
|
||||
"@goosemod/reactUtils": "./moduleWrappers/goosemod/reactUtils.js",
|
||||
"@goosemod/toast": "./moduleWrappers/goosemod/toast.js",
|
||||
"@goosemod/settings": "./moduleWrappers/goosemod/settings.js",
|
||||
|
||||
"@goosemod/plugin": "./moduleWrappers/goosemod/plugin.js",
|
||||
"powercord/entities": "./moduleWrappers/powercord/entities.js",
|
||||
"powercord/injector": "./moduleWrappers/powercord/injector.js",
|
||||
"powercord/webpack": "./moduleWrappers/powercord/webpack.js",
|
||||
"powercord/util": "./moduleWrappers/powercord/util.js",
|
||||
"powercord/components/settings": "./moduleWrappers/powercord/components/settings/index.js",
|
||||
|
||||
"_powercord/global": "./moduleWrappers/powercord/global/index.js",
|
||||
|
||||
"electron": "./moduleWrappers/electron/index.js"
|
||||
},
|
||||
|
||||
"type": "module"
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ for (const jsFile of glob.sync(`${cloneDir}/**/*.js`).concat(glob.sync(`${cloneD
|
|||
const aliasPath = alias[requirePath];
|
||||
|
||||
if (!aliasPath) {
|
||||
console.log('No alias', requirePath);
|
||||
console.log('No alias', requirePath, '(', imports, ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -56,9 +56,10 @@ for (const jsFile of glob.sync(`${cloneDir}/**/*.js`).concat(glob.sync(`${cloneD
|
|||
for (let imp of imports.split(',')) {
|
||||
imp = imp.trim().split(':')[0];
|
||||
|
||||
const searchRegex = new RegExp(`^export.*${imp}.*$`, 'gm');
|
||||
const searchRegex1 = new RegExp(`^export.*${imp}.*$`, 'gm');
|
||||
const searchRegex2 = new RegExp(`^ *${imp}[:,]`, 'gm');
|
||||
|
||||
const searchMatch = aliasJS.match(searchRegex);
|
||||
const searchMatch = aliasJS.match(searchRegex1) || aliasJS.match(searchRegex2);
|
||||
|
||||
if (!searchMatch) {
|
||||
if (requirePath === 'powercord/webpack') {
|
||||
|
@ -69,6 +70,14 @@ for (const jsFile of glob.sync(`${cloneDir}/**/*.js`).concat(glob.sync(`${cloneD
|
|||
}
|
||||
}
|
||||
|
||||
if (requirePath === 'powercord/util') {
|
||||
const webpackJS = readFileSync(join(__dirname, '..', '..', 'GooseMod', 'src', 'util', 'react.js'), 'utf8');
|
||||
|
||||
if (webpackJS.includes(`export function ${imp}`)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (requirePath === 'powercord/injector') {
|
||||
continue;
|
||||
}
|
||||
|
@ -79,4 +88,4 @@ for (const jsFile of glob.sync(`${cloneDir}/**/*.js`).concat(glob.sync(`${cloneD
|
|||
}
|
||||
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { performance } from 'perf_hooks';
|
||||
import { readFileSync } from 'fs';
|
||||
import axios from 'axios';
|
||||
|
||||
let lastRequest = 0;
|
||||
const userCache = {};
|
||||
|
||||
let file;
|
||||
let botToken;
|
||||
try {
|
||||
file = JSON.parse(readFileSync('./env.json'));
|
||||
botToken = file.dtoken;
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
botToken = process.env.BOTTOKEN;
|
||||
}
|
||||
|
||||
const getUser = async (id) => {
|
||||
if (userCache[id]) return userCache[id];
|
||||
|
||||
while (performance.now() - 500 < lastRequest) {
|
||||
// Has been less than 500ms since last request
|
||||
await new Promise((res) => setTimeout(res, 100));
|
||||
}
|
||||
|
||||
lastRequest = performance.now();
|
||||
|
||||
return (userCache[id] = (
|
||||
await axios.get(`https://discord.com/api/v9/users/${id}`, {
|
||||
headers: {
|
||||
Authorization: `Bot ${botToken}`,
|
||||
},
|
||||
})
|
||||
).data);
|
||||
};
|
||||
|
||||
export default async (id) => {
|
||||
const user = await getUser(id);
|
||||
|
||||
console.log(user);
|
||||
|
||||
return {
|
||||
// Use semi-minified keys as to avoid size
|
||||
i: id, // id
|
||||
|
||||
n: user.username, // name
|
||||
|
||||
a: user.avatar, // avatar
|
||||
};
|
||||
};
|
|
@ -1,15 +1,19 @@
|
|||
const basicIncludes = (bundleCode, code, display = (code[0].toUpperCase() + code.substring(1))) => {
|
||||
const basicIncludes = (bundleCode, code, display = code[0].toUpperCase() + code.substring(1)) => {
|
||||
if (bundleCode.includes(code)) return display;
|
||||
};
|
||||
|
||||
export default (bundleCode) => { // Scans final bundle JS to try and auto-detect things, then adding tags
|
||||
export default (bundleCode, currentTags) => {
|
||||
// Scans final bundle JS to try and auto-detect things, then adding tags
|
||||
const tags = [
|
||||
basicIncludes(bundleCode, 'react'),
|
||||
basicIncludes(bundleCode, 'document', 'DOM'),
|
||||
|
||||
(bundleCode.includes('document.createTextNode') && /document\.createElement\(['"`]style['"`]\)/.test(bundleCode)) ? 'CSS' : undefined,
|
||||
/document\.createElement\(['"`]style['"`]\)/.test(bundleCode) ? 'CSS' : undefined,
|
||||
|
||||
].filter((x) => x !== undefined);
|
||||
currentTags.includes('themes') ? 'theme' : undefined,
|
||||
]
|
||||
.filter((x) => x !== undefined)
|
||||
.concat(currentTags.filter((x) => x !== 'themes'));
|
||||
|
||||
return tags;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { createWriteStream, mkdirSync, copyFileSync, rmSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
export default (manifest) => {
|
||||
return manifest.images ? Promise.all(manifest.images.map(async (x, i) => {
|
||||
const baseDir = join(distDir, 'img', manifest.name);
|
||||
|
||||
const rawFile = join(baseDir, x.split('/').pop());
|
||||
const rawExt = rawFile.split('.').pop();
|
||||
|
||||
const finalName = `${i}.${rawExt === 'gif' ? 'gif' : 'png'}`;
|
||||
const finalFile = join(baseDir, finalName);
|
||||
|
||||
mkdirSync(baseDir, { recursive: true });
|
||||
|
||||
console.log(x, i, rawFile, finalFile);
|
||||
|
||||
const writer = createWriteStream(rawFile);
|
||||
const resp = await axios.get(x, {
|
||||
responseType: 'stream'
|
||||
});
|
||||
|
||||
resp.data.pipe(writer);
|
||||
|
||||
await new Promise((res, rej) => {
|
||||
writer.on('finish', res);
|
||||
writer.on('error', rej);
|
||||
});
|
||||
|
||||
if (rawExt !== 'gif') {
|
||||
try {
|
||||
await new Promise((res) => exec(`convert "${rawFile}" -resize x720 -quality 90 "${finalFile}"`, res));
|
||||
} catch (e) {
|
||||
console.error('Failed to use ImageMagick to resize and compress, copying file as backup');
|
||||
copyFileSync(rawFile, finalFile);
|
||||
}
|
||||
} else {
|
||||
copyFileSync(rawFile, finalFile);
|
||||
}
|
||||
|
||||
try {
|
||||
rmSync(rawFile);
|
||||
} catch (e) { }
|
||||
|
||||
return `/img/${manifest.name}/${finalName}`;
|
||||
})) : [];
|
||||
};
|
192
src/index.js
192
src/index.js
|
@ -1,21 +1,25 @@
|
|||
import ModuleRepos from './modules/index.js';
|
||||
|
||||
import AutoTag from './autoTag.js';
|
||||
import WebhookSend from './webhook.js';
|
||||
import ImageCDN from './imageCdn.js';
|
||||
import AuthorGen from './authorGen.js';
|
||||
import SiteGen from './siteGen/index.js';
|
||||
|
||||
import Parcel from 'parcel-bundler';
|
||||
import axios from 'axios';
|
||||
import glob from 'glob';
|
||||
|
||||
import { rmSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, existsSync, rmdirSync } from 'fs';
|
||||
import { rmSync, mkdirSync, readFileSync, writeFileSync, existsSync } from 'fs';
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
import { dirname } from 'path';
|
||||
import { dirname, sep } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
let file;
|
||||
let githubPAT;
|
||||
try {
|
||||
file = JSON.parse(readFileSync('./gh_pat.json'));
|
||||
file = JSON.parse(readFileSync('./env.json'));
|
||||
githubPAT = file.token;
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
|
@ -24,9 +28,10 @@ try {
|
|||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const clonesDir = `${__dirname.replace('/src', '')}/clones`;
|
||||
const clonesDir = `${__dirname.replace(`${sep}src`, '')}/clones`;
|
||||
|
||||
const distDir = `${__dirname.replace('/src', '')}/dist`;
|
||||
const distDir = `${__dirname.replace(`${sep}src`, '')}/dist`;
|
||||
global.distDir = distDir;
|
||||
|
||||
const modulesDir = `${distDir}/module`;
|
||||
|
||||
|
@ -37,7 +42,7 @@ const resetDir = (dir) => {
|
|||
|
||||
if (process.argv[2] === '-f') {
|
||||
resetDir(clonesDir);
|
||||
|
||||
|
||||
resetDir(distDir);
|
||||
resetDir(modulesDir);
|
||||
}
|
||||
|
@ -46,13 +51,15 @@ let previous = [];
|
|||
if (existsSync(clonesDir)) {
|
||||
for (const cloneDir of glob.sync(`${clonesDir}/*/*`)) {
|
||||
process.chdir(cloneDir);
|
||||
|
||||
const currentHash = await new Promise((res) => exec(`git rev-parse HEAD`, (err, stdout) => res(stdout.trim())));
|
||||
|
||||
const moduleInRepos = ModuleRepos.map(
|
||||
(x) => x.modules.filter(
|
||||
(y) => y[0] === cloneDir.replace(`${clonesDir}/`, '') && (y[1] === currentHash || !y[1])
|
||||
)
|
||||
const currentHash = await new Promise((res) =>
|
||||
exec(`git rev-parse HEAD`, (err, stdout) => res(stdout.trim())),
|
||||
);
|
||||
|
||||
const moduleInRepos = ModuleRepos.map((x) =>
|
||||
x.modules.filter(
|
||||
(y) => y[0] === cloneDir.replace(`${clonesDir}/`, '') && (y[1] === currentHash || !y[1]),
|
||||
),
|
||||
).find((x) => x.length > 0);
|
||||
|
||||
if (moduleInRepos) {
|
||||
|
@ -68,46 +75,48 @@ const parcelOptions = {
|
|||
watch: false,
|
||||
sourceMaps: false,
|
||||
outDir: modulesDir,
|
||||
logLevel: 0
|
||||
logLevel: 0,
|
||||
};
|
||||
|
||||
const githubCache = {};
|
||||
|
||||
const getGithubInfo = async (repo) => {
|
||||
if (githubCache[repo]) return githubCache[repo];
|
||||
|
||||
const info = (await axios.get(`https://api.github.com/repos/${repo}`, {
|
||||
headers: {
|
||||
'Authorization': `token ${githubPAT}`
|
||||
}
|
||||
})).data;
|
||||
|
||||
const info = (
|
||||
await axios.get(`https://api.github.com/repos/${repo}`, {
|
||||
headers: {
|
||||
Authorization: `token ${githubPAT}`,
|
||||
},
|
||||
})
|
||||
).data;
|
||||
|
||||
githubCache[repo] = info;
|
||||
return info;
|
||||
};
|
||||
|
||||
let oldTotalModulesJson = [];
|
||||
|
||||
for (const parentRepo of ModuleRepos) {
|
||||
let moduleJson = {
|
||||
modules: [],
|
||||
meta: parentRepo.meta
|
||||
meta: parentRepo.meta,
|
||||
};
|
||||
|
||||
const repoJsonPath = `${distDir}/${parentRepo.filename}.json`;
|
||||
|
||||
const currentRepoJson = existsSync(repoJsonPath) ? JSON.parse(readFileSync(repoJsonPath, 'utf8')) : undefined;
|
||||
const currentRepoJson = existsSync(repoJsonPath)
|
||||
? JSON.parse(readFileSync(repoJsonPath, 'utf8'))
|
||||
: undefined;
|
||||
|
||||
for (const repo of parentRepo.modules) {
|
||||
console.time(repo.slice(0, 2).join(' @ ')+`${repo[2] ? ` ${repo[2]}` : ''}`);
|
||||
|
||||
console.time(repo.slice(0, 2).join(' @ ') + `${repo[2] ? ` ${repo[2]}` : ''}`);
|
||||
|
||||
const name = repo[0];
|
||||
const cloneDir = `${clonesDir}/${name}`;
|
||||
let moduleDir = repo[2] || '';
|
||||
|
||||
try {
|
||||
if (previous.includes(repo)) {
|
||||
let currentModule = currentRepoJson.modules.filter((x) => x.github.repo === repo[0]);
|
||||
let currentModule = currentRepoJson.modules.filter((x) => x?.github?.repo === repo[0]);
|
||||
if (currentModule.length > 1) {
|
||||
const manifest = JSON.parse(readFileSync(`${cloneDir}${moduleDir}/goosemodModule.json`));
|
||||
|
||||
|
@ -115,123 +124,152 @@ for (const parentRepo of ModuleRepos) {
|
|||
} else {
|
||||
currentModule = currentModule[0];
|
||||
}
|
||||
|
||||
|
||||
moduleJson.modules.push(currentModule);
|
||||
|
||||
|
||||
process.stdout.write('[SKIP] ');
|
||||
|
||||
console.timeEnd(repo.slice(0, 2).join(' @ ')+`${repo[2] ? ` ${repo[2]}` : ''}`);
|
||||
|
||||
|
||||
console.timeEnd(repo.slice(0, 2).join(' @ ') + `${repo[2] ? ` ${repo[2]}` : ''}`);
|
||||
|
||||
continue;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Cache fail', repo[0], e);
|
||||
}
|
||||
|
||||
|
||||
let githubInfo = getGithubInfo(repo[0]);
|
||||
|
||||
// console.log(repo);
|
||||
|
||||
|
||||
const url = `https://github.com/${repo[0]}.git`;
|
||||
const commitHash = repo[1];
|
||||
|
||||
|
||||
const preprocessor = repo[3];
|
||||
|
||||
|
||||
// resetDir(cloneDir);
|
||||
// rmSync(cloneDir, { recursive: true, force: true });
|
||||
|
||||
if (existsSync(cloneDir)) {
|
||||
process.chdir(cloneDir);
|
||||
|
||||
const currentHash = await new Promise((res) => exec(`git rev-parse HEAD`, (err, stdout) => res(stdout.trim())));
|
||||
const currentHash = await new Promise((res) =>
|
||||
exec(`git rev-parse HEAD`, (err, stdout) => res(stdout.trim())),
|
||||
);
|
||||
|
||||
if (currentHash !== repo[1]) rmSync(cloneDir, { recursive: true, force: true });
|
||||
if (currentHash !== repo[1] && repo[1] !== '')
|
||||
rmSync(cloneDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
|
||||
process.chdir(distDir); // Incase current wd is broken, in which case exec / git crashes
|
||||
|
||||
await new Promise((res) => exec(`git clone ${url} ${cloneDir}`, res));
|
||||
|
||||
|
||||
process.chdir(cloneDir);
|
||||
|
||||
const lastHash = await new Promise((res) => exec(`git rev-parse HEAD`, (err, stdout) => res(stdout.trim())));
|
||||
|
||||
|
||||
const lastHash = await new Promise((res) =>
|
||||
exec(`git rev-parse HEAD`, (err, stdout) => res(stdout.trim())),
|
||||
);
|
||||
|
||||
await new Promise((res) => exec(`git checkout ${commitHash}`, res));
|
||||
|
||||
|
||||
const commitTimestamp = await new Promise((res) =>
|
||||
exec(`git log -1 --format="%at" | xargs -I{} date -d @{} +%s`, (err, stdout) =>
|
||||
res(stdout.trim()),
|
||||
),
|
||||
);
|
||||
|
||||
if (preprocessor) {
|
||||
const preOut = (await import(`./preprocessors/${preprocessor}.js`)).default(`${cloneDir}${moduleDir}`, repo);
|
||||
const preOut = (await import(`./preprocessors/${preprocessor}.js`)).default(
|
||||
`${cloneDir}${moduleDir}`,
|
||||
repo,
|
||||
);
|
||||
|
||||
if (preOut !== undefined) {
|
||||
moduleDir = preOut;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const manifest = JSON.parse(readFileSync(`${cloneDir}${moduleDir}/goosemodModule.json`));
|
||||
|
||||
|
||||
// console.log(manifest);
|
||||
|
||||
|
||||
const outFile = `${manifest.name}.js`;
|
||||
|
||||
const bundler = new Parcel(`${cloneDir}${moduleDir}/${manifest.main}`, Object.assign(parcelOptions, {
|
||||
outFile
|
||||
}));
|
||||
|
||||
|
||||
const bundler = new Parcel(
|
||||
`${cloneDir}${moduleDir}/${manifest.main}`,
|
||||
Object.assign(parcelOptions, {
|
||||
outFile,
|
||||
}),
|
||||
);
|
||||
|
||||
const bundle = await bundler.bundle();
|
||||
|
||||
|
||||
const outPath = `${modulesDir}/${outFile}`;
|
||||
let jsCode = readFileSync(outPath, 'utf8');
|
||||
|
||||
|
||||
jsCode = `${jsCode};parcelRequire('${bundle.entryAsset.basename}').default`; // Make eval return the index module's default export
|
||||
|
||||
|
||||
// console.log(jsCode);
|
||||
|
||||
|
||||
writeFileSync(outPath, jsCode);
|
||||
|
||||
|
||||
const jsHash = createHash('sha512').update(jsCode).digest('hex');
|
||||
|
||||
|
||||
githubInfo = await githubInfo; // GitHub info is gotten async during other stuff to reduce time
|
||||
|
||||
const manifestJson = {
|
||||
name: manifest.name,
|
||||
description: manifest.description,
|
||||
|
||||
|
||||
version: manifest.version,
|
||||
|
||||
|
||||
tags: AutoTag(jsCode, manifest.tags),
|
||||
|
||||
|
||||
authors: manifest.authors,
|
||||
|
||||
|
||||
hash: jsHash,
|
||||
|
||||
|
||||
github: {
|
||||
stars: githubInfo.stargazers_count,
|
||||
repo: repo[0]
|
||||
repo: repo[0],
|
||||
},
|
||||
|
||||
...repo[4]
|
||||
lastUpdated: parseInt(commitTimestamp),
|
||||
|
||||
...repo[4],
|
||||
};
|
||||
|
||||
|
||||
if (manifest.images) manifestJson.images = manifest.images;
|
||||
if (manifest.dependencies) manifestJson.dependencies = manifest.dependencies;
|
||||
|
||||
|
||||
manifestJson.images = await ImageCDN(manifestJson);
|
||||
|
||||
if (Array.isArray(manifestJson.authors))
|
||||
manifestJson.authors = await Promise.all(
|
||||
manifestJson.authors.map(async (x) => {
|
||||
if (x.match(/^[0-9]{17,18}$/)) {
|
||||
return await AuthorGen(x);
|
||||
}
|
||||
|
||||
return x;
|
||||
}),
|
||||
);
|
||||
|
||||
moduleJson.modules.push(manifestJson);
|
||||
|
||||
console.timeEnd(repo.slice(0, 2).join(' @ ')+`${repo[2] ? ` ${repo[2]}` : ''}`);
|
||||
|
||||
|
||||
console.timeEnd(repo.slice(0, 2).join(' @ ') + `${repo[2] ? ` ${repo[2]}` : ''}`);
|
||||
|
||||
// console.log(lastHash);
|
||||
|
||||
|
||||
if (commitHash !== '' && lastHash !== commitHash) {
|
||||
console.log('[Warning] Commit hash in modules does not match latest commit in repo');
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(repoJsonPath, JSON.stringify(moduleJson));
|
||||
moduleJson.modules = moduleJson.modules.filter((x) => x !== null);
|
||||
|
||||
oldTotalModulesJson = oldTotalModulesJson.concat(moduleJson.modules);
|
||||
writeFileSync(repoJsonPath, JSON.stringify(moduleJson));
|
||||
}
|
||||
|
||||
writeFileSync(`${distDir}/modules.json`, JSON.stringify(oldTotalModulesJson));
|
||||
|
||||
copyFileSync(`${__dirname.replace('/src', '')}/_headers`, `${distDir}/_headers`);
|
||||
|
||||
WebhookSend();
|
||||
await SiteGen();
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
export default [
|
||||
['RazerMoon/muteNewGuild', 'a8ea528e67089ea00a457623cebbef6a670127fc', '/manifest.json', 'pcPlugin', {
|
||||
authors: ['162970149857656832'],
|
||||
}],
|
||||
['keanuplayz/PC-Clap', 'master', '/manifest.json', 'pcPlugin', {
|
||||
[
|
||||
'keanuplayz/PC-Clap',
|
||||
'master',
|
||||
'/manifest.json',
|
||||
'pcPlugin',
|
||||
{
|
||||
authors: ['717352467280691331'],
|
||||
}],
|
||||
},
|
||||
],
|
||||
];
|
||||
|
|
|
@ -4,7 +4,22 @@ export default [
|
|||
- No hash is provided as ported themes have no risk of RCE / etc
|
||||
*/
|
||||
|
||||
['keanuplayz/usrbg', '', '/powercord_manifest.json', 'pcTheme', {
|
||||
authors: ['717352467280691331']
|
||||
}]
|
||||
[
|
||||
'keanuplayz/usrbg',
|
||||
'',
|
||||
'/powercord_manifest.json',
|
||||
'pcTheme',
|
||||
{
|
||||
authors: ['717352467280691331'],
|
||||
},
|
||||
],
|
||||
[
|
||||
'lexisother/dotfiles-discord-theme',
|
||||
'',
|
||||
'/powercord_manifest.json',
|
||||
'pcTheme',
|
||||
{
|
||||
authors: ['465702500146610176', '364720702252908544'],
|
||||
},
|
||||
],
|
||||
];
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { readFileSync, writeFileSync, mkdirSync, rmSync } from 'fs';
|
||||
|
||||
export default (themePath, repo) => {
|
||||
const content = readFileSync(themePath);
|
||||
|
||||
const content = readFileSync(themePath, 'utf8');
|
||||
|
||||
const metaReg = /@([^ ]*) (.*)/g;
|
||||
|
||||
let manifest = {
|
||||
main: 'index.js',
|
||||
tags: ['theme', 'port']
|
||||
tags: ['theme', 'port'],
|
||||
};
|
||||
|
||||
let match;
|
||||
|
@ -17,7 +17,7 @@ export default (themePath, repo) => {
|
|||
|
||||
value = value.trim();
|
||||
|
||||
// console.log(key, value);
|
||||
// console.log(key, value);
|
||||
|
||||
switch (key) {
|
||||
case 'name':
|
||||
|
@ -33,11 +33,11 @@ export default (themePath, repo) => {
|
|||
break;
|
||||
|
||||
case 'author':
|
||||
manifest.authors = [ value ];
|
||||
manifest.authors = [value];
|
||||
break;
|
||||
|
||||
case 'authorId':
|
||||
manifest.authors = [ value ];
|
||||
manifest.authors = [value];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ export default {
|
|||
)
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
onRemove: async () => {
|
||||
style.remove();
|
||||
},
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
const discordVars = [
|
||||
'--header-primary',
|
||||
'--header-secondary',
|
||||
'--text-normal',
|
||||
'--text-muted',
|
||||
'--text-link',
|
||||
'--channels-default',
|
||||
'--interactive-normal',
|
||||
'--interactive-hover',
|
||||
'--interactive-active',
|
||||
'--interactive-muted',
|
||||
'--background-primary',
|
||||
'--background-secondary',
|
||||
'--background-secondary-alt',
|
||||
'--background-tertiary',
|
||||
'--background-accent',
|
||||
'--background-floating',
|
||||
'--background-mobile-primary',
|
||||
'--background-mobile-secondary',
|
||||
'--background-modifier-hover',
|
||||
'--background-modifier-active',
|
||||
'--background-modifier-selected',
|
||||
'--background-modifier-accent',
|
||||
'--background-mentioned',
|
||||
'--background-mentioned-hover',
|
||||
'--background-message-hover',
|
||||
'--background-help-warning',
|
||||
'--background-help-info',
|
||||
'--scrollbar-thin-thumb',
|
||||
'--scrollbar-thin-track',
|
||||
'--scrollbar-auto-thumb',
|
||||
'--scrollbar-auto-track',
|
||||
'--scrollbar-auto-scrollbar-color-thumb',
|
||||
'--scrollbar-auto-scrollbar-color-track',
|
||||
'--elevation-stroke',
|
||||
'--elevation-low',
|
||||
'--elevation-medium',
|
||||
'--elevation-high',
|
||||
'--logo-primary',
|
||||
'--focus-primary',
|
||||
'--radio-group-dot-foreground',
|
||||
'--guild-header-text-shadow',
|
||||
'--channeltextarea-background',
|
||||
'--activity-card-background',
|
||||
'--textbox-markdown-syntax',
|
||||
'--deprecated-card-bg',
|
||||
'--deprecated-card-editable-bg',
|
||||
'--deprecated-store-bg',
|
||||
'--deprecated-quickswitcher-input-background',
|
||||
'--deprecated-quickswitcher-input-placeholder',
|
||||
'--deprecated-text-input-bg',
|
||||
'--deprecated-text-input-border',
|
||||
'--deprecated-text-input-border-hover',
|
||||
'--deprecated-text-input-border-disabled',
|
||||
'--deprecated-text-input-prefix',
|
||||
];
|
||||
|
||||
export default (manifest, _content, repo) => {
|
||||
const content = _content.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
|
||||
|
||||
let variables = content.match(/--([^*!\n}]*): ([^*!\n}]*);/g) || [];
|
||||
if (variables.length > 0)
|
||||
variables = variables.map((x) => {
|
||||
const spl = x.split(':');
|
||||
|
||||
let name = spl[0].trim();
|
||||
let val = spl.slice(1).join(':').trim().slice(0, -1).replace(' !important', '');
|
||||
|
||||
let type = 'text';
|
||||
|
||||
if (val.match(/(#[0-9a-fA-F]{6}|([0-9]{1,3}, ?[0-9]{1,3}, ?[0-9]{1,3}))/)) {
|
||||
type = 'color';
|
||||
}
|
||||
|
||||
return [name, val, type];
|
||||
});
|
||||
|
||||
// Filter out Discord standard vars, and duplicate names
|
||||
if (variables.length > 0)
|
||||
variables = variables.filter(
|
||||
(x, i, s) =>
|
||||
!discordVars.includes(x[0]) &&
|
||||
!x[1].includes('var(') &&
|
||||
!x[0].includes('glasscord') &&
|
||||
s.indexOf(s.find((y) => y[0] === x[0])) === i,
|
||||
);
|
||||
|
||||
const toShowSettings = repo[5] === true && variables.length > 0;
|
||||
|
||||
console.log(variables, toShowSettings);
|
||||
|
||||
return `// Generated by MS2Builder - genericTheme preprocessor / porter
|
||||
let style;
|
||||
|
||||
export default {
|
||||
goosemodHandlers: {
|
||||
onImport: async () => {
|
||||
style = document.createElement("style");
|
||||
document.head.appendChild(style);
|
||||
style.appendChild(
|
||||
document.createTextNode(
|
||||
\`${content}\`
|
||||
)
|
||||
);
|
||||
|
||||
if (${toShowSettings} || (goosemodScope.settings.gmSettings.get().allThemeSettings)) goosemodScope.settings.createItem('${
|
||||
manifest.name
|
||||
}', [
|
||||
'',
|
||||
|
||||
${variables
|
||||
.map(
|
||||
(x) => `{
|
||||
type: '${x[2] === 'color' ? 'text-and-color' : 'text-input'}',
|
||||
text: '${x[0]
|
||||
.replace('--rs-', '--radial-status:-')
|
||||
.substring(2)
|
||||
.replace(/-/g, ' ')
|
||||
.replace(/\w\S*/g, (_) => _[0].toUpperCase() + _.substring(1).toLowerCase())
|
||||
.replace('Rgb', 'RGB')
|
||||
.replace('Afk', 'AFK')
|
||||
.replace('Dnd', 'DND')}',
|
||||
|
||||
oninput: (val) => {
|
||||
${''/* x[2] === 'color' && x[1][0] !== '#' ? `val = 'rgb(' + parseInt(val.substring(1, 3), 16).toString() + ', ' + parseInt(val.substring(3, 5), 16).toString() + ', ' + parseInt(val.substring(5, 7), 16).toString() + ')'` : '' */}
|
||||
|
||||
document.body.style.setProperty('${x[0]}', val);
|
||||
},
|
||||
initialValue: () => {
|
||||
let val = document.body.style.getPropertyValue(\`${x[0]}\`) || \`${x[1]}\`;
|
||||
${
|
||||
x[2] === 'color'
|
||||
? `if (val[0] !== '#') { val = '#' + val.split(', ').map((x) => parseInt(x).toString(16).padStart(2, '0')).join(''); }`
|
||||
: ''
|
||||
}
|
||||
|
||||
console.log(val);
|
||||
|
||||
return val;
|
||||
}
|
||||
}`,
|
||||
)
|
||||
.join(', ')}
|
||||
])
|
||||
},
|
||||
|
||||
onRemove: async () => {
|
||||
style.remove();
|
||||
|
||||
try {
|
||||
goosemodScope.settings.removeItem('${manifest.name}');
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
getSettings: async () => [${variables
|
||||
.map((x) => `['${x[0]}', document.body.style.getPropertyValue(\`${x[0]}\`)]`)
|
||||
.join(', ')}],
|
||||
loadSettings: async (settings) => {
|
||||
settings.forEach((x) => {
|
||||
document.body.style.setProperty(x[0], x[1]);
|
||||
});
|
||||
}
|
||||
}
|
||||
};`;
|
||||
};
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> 39784f0 ([GenericTheme > Settings] Fix hex color checking when not color type causing bad values oninput)
|
|
@ -41,7 +41,7 @@ export default (manifestPath, repo) => {
|
|||
|
||||
writeFileSync(join(baseDir, `index.js`), content);
|
||||
|
||||
for (const jsFile of glob.sync(`${baseDir}/**/*.js`)) {
|
||||
for (const jsFile of glob.sync(`${baseDir}/**/*.{js,jsx,ts,tsx}`)) {
|
||||
console.log(jsFile);
|
||||
let content = readFileSync(jsFile, 'utf8');
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ export default (manifestPath, repo) => {
|
|||
pcManifest.theme = cssPath;
|
||||
}
|
||||
|
||||
const content = readFileSync(pcManifest.theme, 'utf8').replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
||||
const content = readFileSync(pcManifest.theme, 'utf8');
|
||||
|
||||
const jsCode = `// Generated by MS2Builder - pcTheme preprocessor / porter
|
||||
let style;
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,141 @@
|
|||
import { readFileSync, writeFileSync, copyFileSync } from 'fs';
|
||||
import { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import glob from 'glob';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const genAuthors = (a) => {
|
||||
let authors = [];
|
||||
|
||||
if (typeof a === 'string') {
|
||||
authors = a.split(', ');
|
||||
} else if (Array.isArray(a)) {
|
||||
authors = a;
|
||||
}
|
||||
|
||||
return authors
|
||||
.map((x, i) => {
|
||||
if (typeof x === 'object') {
|
||||
// User object
|
||||
const pfp = `<img loading=lazy style="display: inline; border-radius: 50%; margin-right: 5px; vertical-align: bottom;" src="https://cdn.discordapp.com/avatars/${x.i}/${x.a}.png?size=32">`;
|
||||
const name = `<span class="author" style="line-height: 32px;">${x.n}</span>`; //<span class="description-3_Ncsb">#${result.discriminator}</span></span>`;
|
||||
|
||||
return i > 1 ? pfp : pfp + name;
|
||||
}
|
||||
|
||||
let idMatch = x.match(/(.*) \(([0-9]{17,18})\)/); // "<name> (<id>)"
|
||||
if (idMatch === null) return `<span class="author">${x}</span>`; // "<name>"
|
||||
|
||||
return `<span class="author">${idMatch[1]}</span>`;
|
||||
})
|
||||
.join('<span class="description-3_Ncsb">,</span> ');
|
||||
};
|
||||
|
||||
const makeCard = (m) => {
|
||||
const authors = genAuthors(m.authors);
|
||||
return `<div class="gm-store-card ${m.tags.join(' ')}" data-last-updated=${
|
||||
m.lastUpdated
|
||||
} data-stars=${m.github.stars}>
|
||||
<div style="background-image: url('${m.images?.length ? m.images[0] : ''}');"></div>
|
||||
<div class="title-31JmR4 ${!authors.includes('avatar') ? 'no-pfp' : ''}">${authors}</div>
|
||||
<div class="title-31JmR4">${m.name}</div>
|
||||
<div class="colorStandard-2KCXvj size14-e6ZScH default-3nhoK- formText-3fs7AJ description-3_Ncsb formText-3fs7AJ modeDefault-3a2Ph1">${
|
||||
m.description
|
||||
}</div>
|
||||
<div>
|
||||
<div class="colorStandard-2KCXvj size14-e6ZScH default-3nhoK- formText-3fs7AJ description-3_Ncsb formText-3fs7AJ modeDefault-3a2Ph1">
|
||||
<span>${m.github.stars}</span>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .587l3.668 7.568 8.332 1.151-6.064 5.828 1.48 8.279-7.416-3.967-7.417 3.967 1.481-8.279-6.064-5.828 8.332-1.151z"></path></svg>
|
||||
</div>
|
||||
<div class="colorStandard-2KCXvj size14-e6ZScH default-3nhoK- formText-3fs7AJ description-3_Ncsb formText-3fs7AJ modeDefault-3a2Ph1">${
|
||||
m.version === '0' || m.version.toLowerCase().includes('auto') ? '' : `v${m.version}`
|
||||
}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
const makeRepo = (r) => {
|
||||
return `<a href="${r.filename}" class="repo">
|
||||
<div>
|
||||
<div class="title-31JmR4">${r.name}</div>
|
||||
<div class="colorStandard-2KCXvj size14-e6ZScH default-3nhoK- formText-3fs7AJ description-3_Ncsb formText-3fs7AJ modeDefault-3a2Ph1">${r.description}</div>
|
||||
</div>
|
||||
|
||||
<div class="colorStandard-2KCXvj size14-e6ZScH default-3nhoK- formText-3fs7AJ description-3_Ncsb formText-3fs7AJ modeDefault-3a2Ph1">
|
||||
<div><strong>${r.themes}</strong> themes</div>
|
||||
<div><strong>${r.plugins}</strong> plugins</div>
|
||||
<div><strong>${r.developers}</strong> developers</div>
|
||||
</div>
|
||||
</a>`;
|
||||
};
|
||||
|
||||
export default () => {
|
||||
let template = readFileSync(join(__dirname, 'template.html'), 'utf8');
|
||||
|
||||
const repos = glob.sync(join(global.distDir, '*.json'));
|
||||
|
||||
let cards = [];
|
||||
let metas = [];
|
||||
|
||||
let name = 'NovaGM Store';
|
||||
let description = '';
|
||||
|
||||
for (const repo of repos) {
|
||||
console.log(repo);
|
||||
|
||||
const json = JSON.parse(readFileSync(repo, 'utf8'));
|
||||
|
||||
if (repos.length === 1) {
|
||||
// 1 repo likely means a custom repo, so use that name and description
|
||||
name = json.meta.name;
|
||||
description = `${json.meta.description} `;
|
||||
}
|
||||
|
||||
cards = cards.concat(json.modules);
|
||||
|
||||
metas.push({
|
||||
...json.meta,
|
||||
|
||||
themes: json.modules.filter((x) => x.tags.includes('theme')).length,
|
||||
plugins: json.modules.filter((x) => !x.tags.includes('theme')).length,
|
||||
|
||||
developers: Object.keys(
|
||||
json.modules.reduce((acc, x) => {
|
||||
(!Array.isArray(x.authors) ? [x.authors] : x.authors).forEach(
|
||||
(a) => (acc[typeof a === 'object' ? a.i : a] = true),
|
||||
);
|
||||
return acc;
|
||||
}, {}),
|
||||
).length,
|
||||
|
||||
filename: repo.split('/').pop(),
|
||||
});
|
||||
}
|
||||
|
||||
description += `Browse ${cards.filter((x) => x.tags.includes('theme')).length} themes and ${
|
||||
cards.filter((x) => !x.tags.includes('theme')).length
|
||||
} plugins from ${
|
||||
Object.keys(
|
||||
cards.reduce((acc, x) => {
|
||||
(!Array.isArray(x.authors) ? [x.authors] : x.authors).forEach(
|
||||
(a) => (acc[typeof a === 'object' ? a.i : a] = true),
|
||||
);
|
||||
return acc;
|
||||
}, {}),
|
||||
).length
|
||||
} developers.`;
|
||||
|
||||
cards = cards.sort((a, b) => a.name.localeCompare(b.name)).map((x) => makeCard(x));
|
||||
|
||||
template = template
|
||||
.replace('ALL_CARDS', cards.join('\n'))
|
||||
.replace('REPOS', metas.map((x) => makeRepo(x)).join('\n'))
|
||||
.replace(/NAME/g, name)
|
||||
.replace(/DESCRIPTION/g, description);
|
||||
|
||||
writeFileSync(join(global.distDir, 'index.html'), template);
|
||||
|
||||
copyFileSync(join(__dirname, 'NotoSans-Medium.ttf'), join(global.distDir, 'NotoSans-Medium.ttf'));
|
||||
};
|
|
@ -0,0 +1,503 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>NAME</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
|
||||
<meta itemprop="name" content="NAME">
|
||||
<meta itemprop="description" content="DESCRIPTION">
|
||||
|
||||
<meta property="og:title" content="NAME">
|
||||
<meta property="og:description" content="DESCRIPTION">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="/">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--elevation-medium: 0 4px 4px rgba(0,0,0,0.16);
|
||||
|
||||
--background-secondary: #161A1E;
|
||||
--background-secondary-alt: #0A0D0F;
|
||||
--background-tertiary: #181C20;
|
||||
|
||||
--interactive-normal: #b9bbbe;
|
||||
|
||||
--header-primary: #fff;
|
||||
--header-secondary: #b9bbbe;
|
||||
--text-normal: #dcddde;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans';
|
||||
src: url('NotoSans-Medium.ttf') format('truetype');
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
}
|
||||
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
background-color: #101418;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: inline-block;
|
||||
width: 180px;
|
||||
height: 100vh;
|
||||
vertical-align: top;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.sidebar > div {
|
||||
width: 100%;
|
||||
|
||||
padding: 12px 16px;
|
||||
|
||||
color: var(--text-normal);
|
||||
background-color: var(--background-tertiary);
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sidebar > .sidebar-header {
|
||||
cursor: default;
|
||||
|
||||
color: var(--header-primary);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.sidebar > div.active {
|
||||
background-color: #7289da;
|
||||
}
|
||||
|
||||
.sidebar-button:hover {
|
||||
background-color: #14181C;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 22px;
|
||||
|
||||
width: calc(100vw - 185px);
|
||||
max-height: 100vh;
|
||||
|
||||
overflow-y: scroll;
|
||||
|
||||
display: inline-flex;
|
||||
flex-flow: row wrap;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
.container {
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-break {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
body.themes .gm-store-card:not(.theme) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.plugins .gm-store-card.theme {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container.repos {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.repos .container.cards {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.repos .container.repos {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.container.repos {
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.container .repo {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.repo * {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.repo > :last-child {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.repo > strong {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.gm-inline-dropdown {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
gap: 8px;
|
||||
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.gm-inline-dropdown > :last-child {
|
||||
width: 120px;
|
||||
|
||||
background-color: var(--background-tertiary);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
|
||||
outline: 0px !important;
|
||||
|
||||
padding: 6px;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.gm-store-search {
|
||||
flex-grow: 1;
|
||||
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.gm-store-card, .repo {
|
||||
box-shadow: var(--elevation-medium);
|
||||
background-color: var(--background-secondary);
|
||||
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
padding: 12px;
|
||||
margin: 10px;
|
||||
|
||||
width: 330px;
|
||||
height: 380px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(1) {
|
||||
width: calc(100% + 24px);
|
||||
height: 200px;
|
||||
|
||||
border-radius: 8px 8px 0 0;
|
||||
|
||||
margin-top: -12px;
|
||||
margin-left: -12px;
|
||||
|
||||
background-color: var(--background-secondary-alt);
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: 50%;
|
||||
|
||||
text-align: center;
|
||||
line-height: 200px;
|
||||
|
||||
color: var(--interactive-normal);
|
||||
font-family: var(--font-display);
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(2) {
|
||||
position: absolute;
|
||||
top: 152px;
|
||||
right: 10px;
|
||||
|
||||
opacity: 0.95;
|
||||
|
||||
border-radius: 16px;
|
||||
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
width: fit-content;
|
||||
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(2).no-pfp {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(3) {
|
||||
width: 85%;
|
||||
margin-top: 10px;
|
||||
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
webkit-line-clamp: 1;
|
||||
webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(4) {
|
||||
width: 85%;
|
||||
margin-top: 5px;
|
||||
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
webkit-line-clamp: 3;
|
||||
webkit-box-orient: vertical;
|
||||
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(5) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
order: 2;
|
||||
margin-left: auto;
|
||||
position: absolute;
|
||||
top: 208px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(5) > :nth-child(1) {
|
||||
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(5) > :nth-child(1) > :nth-child(1) {
|
||||
position: relative;
|
||||
top: 7px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(5) > :nth-child(1) > :nth-child(2) {
|
||||
position: relative;
|
||||
top: 8px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(5) > :nth-child(2) {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(6) {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
width: calc(100% - 32px);
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(6) > :nth-child(1) {
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(6) > :nth-child(2) {
|
||||
width: auto;
|
||||
margin-left: 14px;
|
||||
min-width: 0px;
|
||||
padding: 2px 5px;
|
||||
color: rgb(221, 221, 221);
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(6) > :nth-child(3) {
|
||||
margin-top: 4px;
|
||||
position: absolute;
|
||||
right: -10px;
|
||||
}
|
||||
|
||||
.gm-store-card > :nth-child(6) > :nth-child(3).hide-toggle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container-cMG81i, .inner-2P4tQO {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.container-cMG81i {
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-tertiary);
|
||||
}
|
||||
|
||||
.inner-2P4tQO {
|
||||
position: relative;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
padding: 1px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.medium-1LLV3p .input-3Xdcic, .medium-1LLV3p .tag-2gZFdE {
|
||||
font-size: 16px;
|
||||
line-height: 32px;
|
||||
height: 30px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
.input-3Xdcic {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: none;
|
||||
resize: none;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
min-width: 48px;
|
||||
margin: 1px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
color: var(--text-normal);
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
.description-3_Ncsb, .labelDescriptor-1PqHgD {
|
||||
color: var(--header-secondary) !important;
|
||||
}
|
||||
.modeDefault-3a2Ph1 {
|
||||
cursor: default;
|
||||
}
|
||||
.description-3_Ncsb {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.size14-e6ZScH {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.colorStandard-2KCXvj {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.title-31JmR4 {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
color: var(--header-primary);
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
word-wrap: break-word;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="themes">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">NAME</div>
|
||||
<div class="sidebar-button active">Themes</div>
|
||||
<div class="sidebar-button">Plugins</div>
|
||||
<div class="sidebar-button">Repos</div>
|
||||
</div>
|
||||
|
||||
<div class="container cards">
|
||||
<div class="gm-store-search container-cMG81i medium-1LLV3p"><div class="inner-2P4tQO"><input id="search-input" class="input-3Xdcic" placeholder="Search" value=""></div></div>
|
||||
|
||||
<div class="gm-inline-dropdown">
|
||||
<div class="colorStandard-2KCXvj size14-e6ZScH default-3nhoK- formText-3fs7AJ description-3_Ncsb formText-3fs7AJ modeDefault-3a2Ph1">Sort by</div>
|
||||
<select id="sort-select">
|
||||
<option>Stars</option>
|
||||
<option>A-Z</option>
|
||||
<option>Last Updated</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex-break"></div>
|
||||
|
||||
ALL_CARDS
|
||||
</div>
|
||||
|
||||
<div class="container repos">
|
||||
REPOS
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const cards = [...document.getElementsByClassName('gm-store-card')];
|
||||
|
||||
const sortSelectEl = document.getElementById('sort-select');
|
||||
|
||||
sortSelectEl.oninput = () => {
|
||||
switch (sortSelectEl.value) {
|
||||
case 'Stars': {
|
||||
cards.forEach((x) => { x.style.order = 999 - parseInt(x.getAttribute('data-stars')); });
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Last Updated': {
|
||||
cards.forEach((x) => { x.style.order = 3000000000 - parseInt(x.getAttribute('data-last-updated')); });
|
||||
break;
|
||||
}
|
||||
|
||||
case 'A-Z': {
|
||||
cards.forEach((x) => { x.style.order = ''; });
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sortSelectEl.oninput();
|
||||
|
||||
|
||||
const searchInputEl = document.getElementById('search-input');
|
||||
|
||||
searchInputEl.oninput = () => {
|
||||
const fuzzyReg = new RegExp(`.*${searchInputEl.value}.*`, 'i');
|
||||
|
||||
cards.forEach((x) => { x.style.display = fuzzyReg.test(x.children[2].textContent) || fuzzyReg.test(x.children[3].textContent) ? '' : 'none'; });
|
||||
};
|
||||
|
||||
|
||||
const sidebarButtons = [...document.getElementsByClassName('sidebar-button')];
|
||||
|
||||
sidebarButtons.forEach((x) => x.onclick = () => {
|
||||
sidebarButtons.forEach((y) => y.classList.remove('active'));
|
||||
x.classList.add('active');
|
||||
|
||||
document.body.className = x.textContent.toLowerCase();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue