diff --git a/client/src/modules/thememanager.js b/client/src/modules/thememanager.js index e1b56ec8..18490350 100644 --- a/client/src/modules/thememanager.js +++ b/client/src/modules/thememanager.js @@ -10,6 +10,7 @@ import ContentManager from './contentmanager'; import Theme from './theme'; +import { FileUtils } from 'common'; export default class ThemeManager extends ContentManager { @@ -122,6 +123,19 @@ export default class ThemeManager extends ContentManager { return [name, maps.length ? maps.join(', ') + ',' : '()']; } + if (type === 'file' && Array.isArray(value)) { + if (!value || !value.length) return [name, '(),']; + + const files = []; + for (let filepath of value) { + const buffer = await FileUtils.readFileBuffer(filepath); + const type = await FileUtils.getFileType(buffer); + files.push(`(data: ${this.toSCSSString(buffer.toString('base64'))}, type: ${this.toSCSSString(type.mime)}, url: ${this.toSCSSString(await FileUtils.toDataURI(buffer, type.mime))})`); + } + + return [name, files.length ? files.join(', ') : '()']; + } + if (type === 'slider') { return [name, value * setting.multi || 1]; } @@ -135,8 +149,13 @@ export default class ThemeManager extends ContentManager { } if (typeof value === 'string') { - return [name, `'${setting.value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'')}'`]; + return [name, this.toSCSSString(value)]; } } + static toSCSSString(value) { + if (typeof value !== 'string' && value.toString) value = value.toString(); + return `'${typeof value === 'string' ? value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') : ''}'`; + } + } diff --git a/client/webpack.config.js b/client/webpack.config.js index f1941ce1..1760acb3 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -59,4 +59,4 @@ module.exports = { path.resolve(__dirname, '..', 'node_modules') ] }*/ -}; \ No newline at end of file +}; diff --git a/common/modules/utils.js b/common/modules/utils.js index 4f9b4a5a..93caee78 100644 --- a/common/modules/utils.js +++ b/common/modules/utils.js @@ -14,6 +14,7 @@ const _ = require('lodash'); import { Vendor } from 'modules'; +import filetype from 'file-type'; export class Utils { static overload(fn, cb) { @@ -150,6 +151,15 @@ export class FileUtils { }); } + static async readFileBuffer(path, options) { + return new Promise((resolve, reject) => { + fs.readFile(path, options || {}, (err, data) => { + if (err) return reject(err); + resolve(data); + }); + }); + } + static async writeFile(path, data) { return new Promise((resolve, reject) => { fs.writeFile(path, data, err => { @@ -196,4 +206,16 @@ export class FileUtils { static async readDir(path) { return this.listDirectory(path); } + + static async getFileType(buffer) { + if (typeof buffer === 'string') buffer = await this.readFileBuffer(buffer); + + return filetype(buffer); + } + + static async toDataURI(buffer, type) { + if (typeof buffer === 'string') buffer = await this.readFileBuffer(buffer); + if (!type) type = this.getFileType(buffer).mime; + return `data:${type};base64,${buffer.toString('base64')}`; + } } diff --git a/package.json b/package.json index e2a2cf8d..488bbb32 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "electron-rebuild": "^1.7.3", "eslint": "^4.16.0", "eslint-plugin-vue": "^4.2.0", + "file-type": "^7.6.0", "gulp": "^3.9.1", "gulp-babel": "^7.0.0", "gulp-plumber": "^1.2.0", @@ -49,7 +50,7 @@ "build": "npm run build --prefix client && npm run build --prefix core && npm run build --prefix csseditor", "build_client": "npm run build --prefix client", "watch_client": "npm run watch --prefix client", - "build_core": "npm run build --prefix core", + "build_core": "npm run build --prefix core", "watch_core": "npm run watch --prefix core", "watch_csseditor": "npm run watch --prefix csseditor", "lint": "eslint -f unix client/src core/src csseditor/src", diff --git a/tests/themes/Example/config.json b/tests/themes/Example/config.json index d2a59990..74a27f90 100644 --- a/tests/themes/Example/config.json +++ b/tests/themes/Example/config.json @@ -132,8 +132,7 @@ }, { "id": "avatar", - "type": "text", - "value": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Cow_female_black_white.jpg/220px-Cow_female_black_white.jpg", + "type": "file", "text": "Avatar replace", "hint": "Replace all avatars" }, diff --git a/tests/themes/Example/index.scss b/tests/themes/Example/index.scss index f6c8b000..f2940326 100644 --- a/tests/themes/Example/index.scss +++ b/tests/themes/Example/index.scss @@ -1,4 +1,4 @@ -@import 'vars.scss'; +@import 'vars'; div { background: unquote($divBg); @@ -11,7 +11,7 @@ span { } .avatar-large { - background-image: url($avatar) !important; + background-image: url(map-get($avatar, url)) !important; border-radius: $avatarRadius !important; } diff --git a/tests/themes/Example/vars.scss b/tests/themes/Example/vars.scss index 76723b91..09033270 100644 --- a/tests/themes/Example/vars.scss +++ b/tests/themes/Example/vars.scss @@ -1,6 +1,6 @@ $divBg: green !default; $spanOpacity: 0.5 !default; -$avatar: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Cow_female_black_white.jpg/220px-Cow_female_black_white.jpg" !default; +$avatar: (url: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Cow_female_black_white.jpg/220px-Cow_female_black_white.jpg") !default; $avatarRadius: 8px !default; $radioTest: red !default; -$spanOpacity2: 1 !default; \ No newline at end of file +$spanOpacity2: 1 !default;