diff --git a/client/src/modules/bdwebapi.js b/client/src/modules/bdwebapi.js index b077cc0f..393eb112 100644 --- a/client/src/modules/bdwebapi.js +++ b/client/src/modules/bdwebapi.js @@ -19,6 +19,54 @@ const ENDPOINTS = { 'statistics': `${APIBASE}/statistics` }; +const dummyTags = ['tag1', 'tag2', 'tag3', 'tag4', 'tag5']; +const dummyRepo = { + name: 'ExampleRepository', + baseUri: 'https://github.com/Jiiks/ExampleRepository', + rawUri: 'https://github.com/Jiiks/ExampleRepository/raw/master' +}; +const dummyVersion = () => `${Math.round(Math.random() * 3)}.${Math.round(Math.random() * 10)}.${Math.round(Math.random() * 10)}`; +const dummyFiles = { + readme: 'Example/readme.md', + previews: [{ + large: 'Example/preview1-big.png', + thumb: 'Example/preview1-small.png' + }] +}; +const dummyAuthor = 'DummyAuthor'; +const dummyTimestamp = () => `2018-${Math.floor((Math.random() * 12) + 1).toString().padStart(2, '0')}-${Math.floor((Math.random() * 30) + 1).toString().padStart(2, '0')}T14:51:32.057Z`; + +async function dummyThemes() { + // Simulate get + await new Promise(r => setTimeout(r, Math.random() * 3000)); + const dummies = []; + for (let i = 0; i < 10; i++) { + dummies.push({ + id: `theme${i}${btoa(Math.random()).substring(3, 9)}`, + name: `Dummy ${i}`, + tags: dummyTags, + installs: Math.floor(Math.random() * 10000), + updated: dummyTimestamp(), + rating: Math.floor(Math.random() * 1000), + activeUsers: Math.floor(Math.random() * 1000), + rated: Math.random() > .5, + version: dummyVersion(), + repository: dummyRepo, + files: dummyFiles, + author: dummyAuthor + }); + } + return { + docs: dummies, + pagination: { + total: 25, + pages: 3, + limit: 9, + page: 1 + } + }; +} + export default class BdWebApi { static get themes() { @@ -41,11 +89,14 @@ export default class BdWebApi { } static getThemes(args) { + return dummyThemes(); + /* if (!args) return request.get(ENDPOINTS.themes); const { id } = args; if (id) return request.get(ENDPOINTS.theme(id)); return request.get(ENDPOINTS.themes); + */ } static getUsers(args) { diff --git a/client/src/modules/contentmanager.js b/client/src/modules/contentmanager.js index 7a0076bb..c50c88f7 100644 --- a/client/src/modules/contentmanager.js +++ b/client/src/modules/contentmanager.js @@ -12,6 +12,7 @@ import asar from 'asar'; import path, { dirname } from 'path'; import rimraf from 'rimraf'; +import { remote } from 'electron'; import Content from './content'; import Globals from './globals'; import Database from './database'; @@ -71,6 +72,28 @@ export default class { return Globals.getPath(this.pathId); } + static async packContent(path, contentPath) { + return new Promise((resolve, reject) => { + remote.dialog.showSaveDialog({ + title: 'Save Package', + defaultPath: path, + filters: [ + { + name: 'BetterDiscord Package', + extensions: ['bd'] + } + ] + }, filepath => { + if (!filepath) return; + + asar.uncache(filepath); + asar.createPackage(contentPath, filepath, () => { + resolve(filepath); + }); + }); + }); + } + /** * Load all locally stored content. * @param {bool} suppressErrors Suppress any errors that occur during loading of content diff --git a/client/src/modules/packageinstaller.js b/client/src/modules/packageinstaller.js index 2267dec6..f870c4d8 100644 --- a/client/src/modules/packageinstaller.js +++ b/client/src/modules/packageinstaller.js @@ -13,6 +13,7 @@ import Security from './security'; import { ReactComponents } from './reactcomponents'; import Reflection from './reflection'; import DiscordApi from './discordapi'; +import ThemeManager from './thememanager'; export default class PackageInstaller { @@ -64,47 +65,39 @@ export default class PackageInstaller { /** * Installs or updates defined package * @param {Byte[]|String} bytesOrPath byte array of binary or path to local file - * @param {String} name Package name + * @param {String} nameOrId Package name * @param {Boolean} update Does an older version already exist */ - static async installPackage(bytesOrPath, id, update = false) { + static async installPackage(bytesOrPath, nameOrId, contentType, update = false) { let outputPath = null; try { - const bytes = typeof bytesOrPath === 'string' ? fs.readFileSync(bytesOrPath) : bytesOrPath; - const outputName = `${id}.bd`; - outputPath = path.join(Globals.getPath('plugins'), outputName); + const bytes = typeof bytesOrPath === 'string' ? fs.readFileSync(bytesOrPath) : bytesOrPath; + const outputName = `${nameOrId}.bd`; + + outputPath = path.join(Globals.getPath(`${contentType}s`), outputName); fs.writeFileSync(outputPath, bytes); - if (!update) return PluginManager.preloadPackedContent(outputName); + const manager = contentType === 'plugin' ? PluginManager : ThemeManager; - const oldContent = PluginManager.getPluginById(id); + if (!update) return manager.preloadPackedContent(outputName); - if (update && oldContent.packed && oldContent.packed.packageName !== id) { - await oldContent.unload(true); + const oldContent = manager.findContent(nameOrId); + + await oldContent.unload(true); + + if (oldContent.packed && oldContent.packed.packageName !== nameOrId) { rimraf(oldContent.packed.packagePath, err => { - if(err) console.log(err); + if (err) throw err; }); - - return PluginManager.preloadPackedContent(outputName); - } - - if (update && !oldContent.packed) { - await oldContent.unload(true); + } else { rimraf(oldContent.contentPath, err => { - if (err) console.log(err); + if (err) throw err; }); - - return PluginManager.preloadPackedContent(outputName); } - return PluginManager.reloadContent(oldContent); + return manager.preloadPackedContent(outputName); } catch (err) { - if (outputPath) { - rimraf(outputPath, err => { - if (err) console.log(err); - }); - } throw err; } } diff --git a/client/src/styles/partials/bdsettings/contentview.scss b/client/src/styles/partials/bdsettings/contentview.scss index 86a45795..c0272110 100644 --- a/client/src/styles/partials/bdsettings/contentview.scss +++ b/client/src/styles/partials/bdsettings/contentview.scss @@ -1,9 +1,56 @@ .bd-pluginsview, .bd-themesview { - .bd-onlinePh { + .bd-localPh { + .bd-scroller { + padding: 0 20px 0 0; + } + } + + .bd-onlinePh, + .bd-localPh { display: flex; flex-direction: column; - margin: 10% 0; + margin: 10px 0; + + .bd-spinnerContainer { + display: flex; + justify-content: center; + } + + .bd-onlinePhHeader { + display: flex; + padding: 0 20px 0 10px; + min-height: 80px; + + .bd-flexRow { + min-height: 40px; + } + + .bd-searchHint { + flex-grow: 1; + line-height: 40px; + color: #fff; + } + + .bd-searchSort { + span { + color: #fff; + line-height: 40px; + } + } + } + + .bd-onlinePhBody { + margin-top: 10px; + + .bd-spinnerContainer { + padding: 0; + } + + .bd-scroller { + padding: 0 20px 0 0; + } + } h3 { color: #fff; diff --git a/client/src/styles/partials/bdsettings/remotecard.scss b/client/src/styles/partials/bdsettings/remotecard.scss index 2a851cd8..c50759be 100644 --- a/client/src/styles/partials/bdsettings/remotecard.scss +++ b/client/src/styles/partials/bdsettings/remotecard.scss @@ -1,8 +1,7 @@ .bd-remoteCard { - display: flex; flex-direction: column; margin-top: 10px; - padding: 10px 0; + padding: 10px; border-radius: 0; border-bottom: 1px solid rgba(114, 118, 126, .3); @@ -52,17 +51,19 @@ .bd-remoteCardTags { color: #828a97; font-size: 10px; - line-height: 20px; + display: flex; + flex-direction: column; + justify-content: flex-end; } .bd-buttonGroup { align-self: flex-end; justify-content: flex-end; flex-grow: 1; - max-height: 20px; + max-height: 30px; .bd-button { - font-size: 12px; + font-size: 16px; padding: 5px 10px; } } diff --git a/client/src/styles/partials/generic/forms/text.scss b/client/src/styles/partials/generic/forms/text.scss index 8b3d2650..d73dadd4 100644 --- a/client/src/styles/partials/generic/forms/text.scss +++ b/client/src/styles/partials/generic/forms/text.scss @@ -164,11 +164,11 @@ .bd-fancySearch { display: flex; justify-content: flex-end; - transform: translateY(80px) translateX(-140px); - transition: all .5s ease-in-out; + // transform: translateY(80px) translateX(-140px); + // transition: all .5s ease-in-out; &::before { - content: 'Search by name, description or tag...'; + // content: 'Search by name, description or tag...'; color: #f6f6f7; position: relative; top: -20px; @@ -184,6 +184,12 @@ } } + &.bd-disabled { + .bd-textInput { + opacity: .8; + } + } + .bd-textInput { padding: 10px; display: flex; diff --git a/client/src/styles/partials/sidebarview/settingswrap.scss b/client/src/styles/partials/sidebarview/settingswrap.scss index 57bd0115..b7141d45 100644 --- a/client/src/styles/partials/sidebarview/settingswrap.scss +++ b/client/src/styles/partials/sidebarview/settingswrap.scss @@ -120,8 +120,14 @@ } .bd-settingswrapContents { - padding: 0 20px; - margin-bottom: 84px; + padding: 0 0 0 20px; + } + + .bd-scroller { + .bd-settingswrapContents { + margin-bottom: 84px; + padding: 0 20px; + } } } } diff --git a/client/src/ui/components/bd/PluginCard.vue b/client/src/ui/components/bd/PluginCard.vue index f8cfe65d..3a485936 100644 --- a/client/src/ui/components/bd/PluginCard.vue +++ b/client/src/ui/components/bd/PluginCard.vue @@ -23,11 +23,8 @@