mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-12 19:49:59 +05:00
Merge branch 'admin-customize' into support2
This commit is contained in:
commit
53707f20be
@ -15,7 +15,7 @@ define([
|
||||
|
||||
elem.innerHTML = [
|
||||
'<div class="cp-loading-logo">',
|
||||
'<img class="cp-loading-cryptofist" src="/customize/CryptPad_logo.svg?' + urlArgs + '" alt="' + Messages.label_logo + '">',
|
||||
'<img class="cp-loading-cryptofist" src="/api/logo?' + urlArgs + '" alt="' + Messages.label_logo + '">',
|
||||
'</div>',
|
||||
'<div class="cp-loading-container">',
|
||||
'<div class="cp-loading-spinner-container">',
|
||||
|
||||
@ -176,7 +176,7 @@ define([
|
||||
h('div.row.cp-home-hero', [
|
||||
h('div.cp-title.col-lg-6', [
|
||||
h('img', {
|
||||
src: '/customize/CryptPad_logo_hero.svg?' + urlArgs,
|
||||
src: '/api/logo?' + urlArgs,
|
||||
'aria-hidden': 'true',
|
||||
alt: ''
|
||||
}),
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
(function () {
|
||||
var logoPath = '/customize/CryptPad_logo.svg';
|
||||
if (location.pathname === '/' || location.pathname === '/index.html') {
|
||||
logoPath = '/customize/CryptPad_logo_hero.svg';
|
||||
logoPath = '/api/logo';
|
||||
}
|
||||
|
||||
var elem = document.createElement('div');
|
||||
|
||||
@ -9,9 +9,16 @@
|
||||
@colortheme_app-font-size-small: 13px;
|
||||
@colortheme_app-font: @colortheme_app-font-size @colortheme_font;
|
||||
|
||||
// Colors
|
||||
@cryptpad_color_brand: #0087FF;
|
||||
@cryptpad_color_brand_300: lighten(@cryptpad_color_brand, 30%);
|
||||
@cryptpad_color_brand_fade: fade(@cryptpad_color_brand, 75%);
|
||||
@cryptpad_color_brand_fader: fade(@cryptpad_color_brand, 50%);
|
||||
@cryptpad_color_brand_fadest: fade(@cryptpad_color_brand, 25%);
|
||||
|
||||
@colortheme_apps: {
|
||||
default: #0087FF;
|
||||
drive: #0087FF; // Used as icon color in index.js (index.html)
|
||||
default: @cryptpad_color_brand;
|
||||
drive: @cryptpad_color_brand; // Used as icon color in index.js (index.html)
|
||||
pad: #256ad5;
|
||||
code: #EAA000;
|
||||
slide: #e57614;
|
||||
@ -27,18 +34,11 @@
|
||||
}
|
||||
|
||||
@colortheme_static_apps: {
|
||||
default: #0087FF;
|
||||
default: @cryptpad_color_brand;
|
||||
teams: #4A3BBD;
|
||||
contacts: #607B8D;
|
||||
}
|
||||
|
||||
// Colors
|
||||
@cryptpad_color_brand: #0087FF;
|
||||
@cryptpad_color_brand_300: lighten(@cryptpad_color_brand, 30%);
|
||||
@cryptpad_color_brand_fade: fade(@cryptpad_color_brand, 75%);
|
||||
@cryptpad_color_brand_fader: fade(@cryptpad_color_brand, 50%);
|
||||
@cryptpad_color_brand_fadest: fade(@cryptpad_color_brand, 25%);
|
||||
|
||||
@cryptpad_color_white: #FFF;
|
||||
@cryptpad_color_grey_50: #FAFAFA;
|
||||
@cryptpad_color_grey_100: #F5F5F5;
|
||||
|
||||
@ -9,9 +9,16 @@
|
||||
@colortheme_app-font-size-small: 13px;
|
||||
@colortheme_app-font: @colortheme_app-font-size @colortheme_font;
|
||||
|
||||
// Colors
|
||||
@cryptpad_color_brand: #0087FF;
|
||||
@cryptpad_color_brand_300: lighten(@cryptpad_color_brand, 30%);
|
||||
@cryptpad_color_brand_fade: fade(@cryptpad_color_brand, 75%);
|
||||
@cryptpad_color_brand_fader: fade(@cryptpad_color_brand, 50%);
|
||||
@cryptpad_color_brand_fadest: fade(@cryptpad_color_brand, 25%);
|
||||
|
||||
@colortheme_apps: {
|
||||
default: #0087FF;
|
||||
drive: #0087FF; // Used as icon color in index.js (index.html)
|
||||
default: @cryptpad_color_brand;
|
||||
drive: @cryptpad_color_brand; // Used as icon color in index.js (index.html)
|
||||
pad: #256ad5;
|
||||
code: #EAA000;
|
||||
slide: #e57614;
|
||||
@ -27,18 +34,11 @@
|
||||
}
|
||||
|
||||
@colortheme_static_apps: {
|
||||
default: #0087FF;
|
||||
default: @cryptpad_color_brand;
|
||||
teams: #4A3BBD;
|
||||
contacts: #607B8D;
|
||||
}
|
||||
|
||||
// Colors
|
||||
@cryptpad_color_brand: #0087FF;
|
||||
@cryptpad_color_brand_300: lighten(@cryptpad_color_brand, 30%);
|
||||
@cryptpad_color_brand_fade: fade(@cryptpad_color_brand, 75%);
|
||||
@cryptpad_color_brand_fader: fade(@cryptpad_color_brand, 50%);
|
||||
@cryptpad_color_brand_fadest: fade(@cryptpad_color_brand, 25%);
|
||||
|
||||
@cryptpad_color_white: #FFF;
|
||||
@cryptpad_color_grey_50: #FAFAFA;
|
||||
@cryptpad_color_grey_100: #F5F5F5;
|
||||
|
||||
@ -75,7 +75,8 @@
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 90vw;
|
||||
max-height: 300px;
|
||||
max-height: ~"max(40vh, 250px)";
|
||||
//max-height: 300px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin-bottom: 2em;
|
||||
|
||||
@ -179,6 +179,10 @@
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
a {
|
||||
color: @cryptpad_color_link;
|
||||
text-decoration: underline;
|
||||
}
|
||||
table {
|
||||
.cp-strong {
|
||||
font-weight: bold;
|
||||
@ -210,6 +214,11 @@
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
[type="file"] { // XXX hack, to fix with sidebar layout refactoring
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
padding: 6.5px;
|
||||
}
|
||||
.cp-sidebarlayout-input-block {
|
||||
display: inline-flex;
|
||||
width: @sidebar_button-width;
|
||||
|
||||
@ -61,6 +61,9 @@
|
||||
@media screen and (max-width: 990px) {
|
||||
justify-content: center;
|
||||
}
|
||||
img {
|
||||
max-height: ~"max(40vh, 250px)";
|
||||
}
|
||||
}
|
||||
.cp-title {
|
||||
display: flex;
|
||||
|
||||
@ -72,7 +72,7 @@ html:not(.cp-app-noscroll) #placeholder.dark-theme {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 90vw;
|
||||
max-height: 300px;
|
||||
max-height: max(40vh, 250px);
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin-bottom: 2em;
|
||||
|
||||
@ -18,8 +18,9 @@ const BlockStore = require("../storage/block");
|
||||
const MFA = require("../storage/mfa");
|
||||
const ArchiveAccount = require('../archive-account');
|
||||
const { Worker } = require('node:worker_threads');
|
||||
const Fse = require("fs-extra");
|
||||
|
||||
var Fs = require("fs");
|
||||
const Fs = require("fs");
|
||||
|
||||
var Admin = module.exports;
|
||||
|
||||
@ -955,6 +956,72 @@ var archiveSupport = (Env, Server, cb) => {
|
||||
}, [null, supportPinKey]);
|
||||
};
|
||||
|
||||
const MAX_LOGO_SIZE = 200*1024; // 200KB
|
||||
var removeLogo = (Env, Server, cb) => {
|
||||
Fse.unlink('./customize/CryptPad_logo_hero.svg', (err) => {
|
||||
cb(err);
|
||||
});
|
||||
};
|
||||
var uploadLogo = (Env, Server, cb, data, unsafeKey) => {
|
||||
const args = Array.isArray(data) && data[1];
|
||||
if (!args || typeof(args) !== 'object') { return void cb("EINVAL"); }
|
||||
let dataURL = args.dataURL;
|
||||
|
||||
// (size*4/3) + 24 ==> base64 and dataURL overhead
|
||||
if (!dataURL || dataURL.length > ((MAX_LOGO_SIZE*4/3)+24)) {
|
||||
return void cb('E_TOO_LARGE');
|
||||
}
|
||||
|
||||
let s = dataURL.split(',');
|
||||
let base64 = s[1];
|
||||
let mime = s[0].slice(s[0].indexOf(":")+1, s[0].indexOf(";"));
|
||||
if (!base64 || !mime) { return void cb('EINVAL'); }
|
||||
let buf;
|
||||
try {
|
||||
buf = Buffer.from(base64, 'base64');
|
||||
} catch (e) {
|
||||
return void cb(e);
|
||||
}
|
||||
|
||||
nThen(waitFor => {
|
||||
Fse.mkdirp('customize', {}, waitFor((err) => {
|
||||
if (!err) { return; }
|
||||
waitFor.abort();
|
||||
return void cb(err);
|
||||
}));
|
||||
}).nThen(waitFor => {
|
||||
Fse.writeFile('./customize/CryptPad_logo_hero.svg', buf, waitFor((err) => {
|
||||
if (!err) { return; }
|
||||
waitFor.abort();
|
||||
return void cb(err);
|
||||
}));
|
||||
}).nThen(() => {
|
||||
adminDecree(Env, null, function (err) {
|
||||
if (err) { return void cb(err); }
|
||||
Env.flushCache();
|
||||
cb(void 0, true);
|
||||
}, ['UPLOAD_LOGO', [
|
||||
'SET_LOGO_MIME',
|
||||
[mime]
|
||||
]], unsafeKey);
|
||||
});
|
||||
};
|
||||
|
||||
var changeColor = (Env, Server, cb, data, unsafeKey) => {
|
||||
const args = Array.isArray(data) && data[1];
|
||||
if (!args || typeof(args) !== 'object') { return void cb("EINVAL"); }
|
||||
let color = args.color;
|
||||
adminDecree(Env, null, function (err) {
|
||||
if (err) { return void cb(err); }
|
||||
Env.flushCache();
|
||||
cb(void 0, true);
|
||||
}, ['CHANGE_COLOR', [
|
||||
'SET_ACCENT_COLOR',
|
||||
[color]
|
||||
]], unsafeKey);
|
||||
};
|
||||
|
||||
|
||||
var commands = {
|
||||
ACTIVE_SESSIONS: getActiveSessions,
|
||||
ACTIVE_PADS: getActiveChannelCount,
|
||||
@ -1027,6 +1094,10 @@ var commands = {
|
||||
GET_MODERATORS: getModerators,
|
||||
ADD_MODERATOR: addModerator,
|
||||
REMOVE_MODERATOR: removeModerator,
|
||||
|
||||
UPLOAD_LOGO: uploadLogo,
|
||||
REMOVE_LOGO: removeLogo,
|
||||
CHANGE_COLOR: changeColor,
|
||||
};
|
||||
|
||||
// addFirstAdmin is an anon_rpc command
|
||||
|
||||
@ -159,10 +159,16 @@ var makeGenericSetter = function (attr, validator) {
|
||||
};
|
||||
};
|
||||
|
||||
var isString = (str) => {
|
||||
return typeof(str) === "string";
|
||||
};
|
||||
var isInteger = function (n) {
|
||||
return !(typeof(n) !== 'number' || isNaN(n) || (n % 1) !== 0);
|
||||
};
|
||||
|
||||
var args_isString = function (args) {
|
||||
return !(!Array.isArray(args) || !isString(args[0]));
|
||||
};
|
||||
var args_isInteger = function (args) {
|
||||
return !(!Array.isArray(args) || !isInteger(args[0]));
|
||||
};
|
||||
@ -175,6 +181,12 @@ var arg_isPositiveInteger = function (args) {
|
||||
return Array.isArray(args) && isInteger(args[0]) && args[0] > 0;
|
||||
};
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_LOGO_MIME', ['image/png']]], console.log)
|
||||
commands.SET_LOGO_MIME = makeGenericSetter('logoMimeType', args_isString);
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_ACCENT_COLOR', ['#ff0073']]], console.log)
|
||||
commands.SET_ACCENT_COLOR = makeGenericSetter('accentColor', args_isString);
|
||||
|
||||
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['ENABLE_PROFILING', [true]]], console.log)
|
||||
commands.ENABLE_PROFILING = makeBooleanSetter('enableProfiling');
|
||||
|
||||
|
||||
@ -506,6 +506,7 @@ app.use("/block", (req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
app.use("/customize", Express.static('customize'));
|
||||
app.use("/customize", Express.static('customize.dist'));
|
||||
app.use("/customize.dist", Express.static('customize.dist'));
|
||||
@ -625,6 +626,7 @@ var Define = function (obj) {
|
||||
app.get('/api/instance', function (req, res) {
|
||||
res.setHeader('Content-Type', 'text/javascript');
|
||||
res.send(Define({
|
||||
color: Env.accentColor,
|
||||
name: Env.instanceName,
|
||||
description: Env.instanceDescription,
|
||||
location: Env.instanceJurisdiction,
|
||||
@ -686,6 +688,20 @@ app.get('/api/profiling', function (req, res) {
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/logo', function (req, res) {
|
||||
let path = Path.resolve('./customize/CryptPad_logo_hero.svg');
|
||||
let base = Path.resolve('./customize.dist/CryptPad_logo_hero.svg');
|
||||
Fs.exists(path, function (exists) {
|
||||
res.setHeader('Content-Disposition', 'inline');
|
||||
if (exists) {
|
||||
let mime = Env.logoMimeType || 'image/svg+xml';
|
||||
res.setHeader('Content-Type', mime);
|
||||
return res.sendFile(path);
|
||||
}
|
||||
res.sendFile(base);
|
||||
});
|
||||
});
|
||||
|
||||
// This endpoint handles authenticated RPCs over HTTP
|
||||
// via an interactive challenge-response protocol
|
||||
app.use(Express.json());
|
||||
|
||||
@ -72,6 +72,9 @@ define([
|
||||
'cp-admin-jurisdiction',
|
||||
'cp-admin-notice',
|
||||
],
|
||||
'customize': [
|
||||
'cp-admin-logo'
|
||||
],
|
||||
'users': [ // Msg.admin_cat_quota
|
||||
'cp-admin-registration',
|
||||
'cp-admin-invitation',
|
||||
@ -3779,6 +3782,91 @@ Example
|
||||
return $div;
|
||||
};
|
||||
|
||||
// XXX
|
||||
Messages.admin_logoTitle = "Upload Logo";
|
||||
Messages.admin_logoHint = "Max 200KB, svg, png or jpg";
|
||||
Messages.admin_logoButton = "Upload new";
|
||||
Messages.admin_logoRemoveButton = "Restore default";
|
||||
create['logo'] = function () {
|
||||
var key = 'logo';
|
||||
var $div = makeBlock(key, false); // Msg.admin_emailHint, Msg.admin_emailTitle
|
||||
|
||||
var input = h('input', {
|
||||
type: 'file',
|
||||
accept: 'image/*',
|
||||
'aria-labelledby': 'cp-admin-logo'
|
||||
});
|
||||
|
||||
var currentContainer = h('div');
|
||||
let redraw = () => {
|
||||
var current = h('img', {src: '/api/logo?'+(+new Date())});
|
||||
$(currentContainer).empty().append(current);
|
||||
};
|
||||
redraw();
|
||||
|
||||
var upload = h('button.btn.btn-primary', Messages.admin_logoButton);
|
||||
var remove = h('button.btn.btn-danger', Messages.admin_logoRemoveButton);
|
||||
|
||||
$div.append([
|
||||
currentContainer,
|
||||
h('div', input),
|
||||
h('nav', [upload, remove])
|
||||
]);
|
||||
|
||||
let $button = $(upload);
|
||||
let $remove = $(remove);
|
||||
var spinner = UI.makeSpinner($div);
|
||||
|
||||
Util.onClickEnter($button, function () {
|
||||
let files = input.files;
|
||||
if (files.length !== 1) {
|
||||
UI.warn(Messages.error);
|
||||
return;
|
||||
}
|
||||
spinner.spin();
|
||||
$button.attr('disabled', 'disabled');
|
||||
let reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
let dataURL = this.result;
|
||||
sframeCommand('UPLOAD_LOGO', {dataURL}, (err, response) => {
|
||||
$button.removeAttr('disabled');
|
||||
if (err) {
|
||||
UI.warn(Messages.error);
|
||||
$(input).val('');
|
||||
console.error(err, response);
|
||||
spinner.hide();
|
||||
return;
|
||||
}
|
||||
redraw();
|
||||
spinner.done();
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(files[0]);
|
||||
});
|
||||
UI.confirmButton($remove, {
|
||||
classes: 'btn-danger',
|
||||
multiple: true
|
||||
}, function () {
|
||||
spinner.spin();
|
||||
$remove.attr('disabled', 'disabled');
|
||||
sframeCommand('REMOVE_LOGO', {}, (err, response) => {
|
||||
$remove.removeAttr('disabled');
|
||||
if (err) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(err, response);
|
||||
spinner.hide();
|
||||
return;
|
||||
}
|
||||
redraw();
|
||||
spinner.done();
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var hideCategories = function () {
|
||||
APP.$rightside.find('> div').hide();
|
||||
};
|
||||
|
||||
@ -9,8 +9,9 @@ const require = define;
|
||||
*/
|
||||
define([
|
||||
'/api/config',
|
||||
'/api/instance',
|
||||
'/components/nthen/index.js'
|
||||
], function (Config, nThen) { /*::});module.exports = (function() {
|
||||
], function (Config, Instance, nThen) { /*::});module.exports = (function() {
|
||||
const Config = (undefined:any);
|
||||
const nThen = (undefined:any);
|
||||
*/
|
||||
@ -153,6 +154,10 @@ define([
|
||||
].join('\n');
|
||||
text += '\n'+custom;
|
||||
}
|
||||
if (Instance && Instance.color) {
|
||||
let pattern = /_color_brand: ([0-9a-zA-Z#]+);/gm;
|
||||
text = text.replace(pattern, `_color_brand: ${Instance.color};`);
|
||||
}
|
||||
}
|
||||
cached.res = [ text, lastModified ];
|
||||
var queue = cached.queue;
|
||||
|
||||
@ -78,8 +78,10 @@ define([
|
||||
blocks.code = val => {
|
||||
return h('code', val);
|
||||
};
|
||||
blocks.inline = (value) => {
|
||||
return h('span', value);
|
||||
blocks.inline = (value, className) => {
|
||||
let attr = {};
|
||||
if (className) { attr.class = className; }
|
||||
return h('span', attr, value);
|
||||
};
|
||||
blocks.block = (content, className) => {
|
||||
let attr = {};
|
||||
|
||||
@ -19,5 +19,12 @@
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
font: @colortheme_app-font;
|
||||
|
||||
.cp-admin-color-current {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 5px;
|
||||
background: @cryptpad_color_brand;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ define([
|
||||
'json.sortify',
|
||||
'/customize/application_config.js',
|
||||
'/api/config',
|
||||
'/api/instance',
|
||||
'/lib/datepicker/flatpickr.js',
|
||||
'/common/hyperscript.js',
|
||||
'css!/lib/datepicker/flatpickr.min.css',
|
||||
@ -42,6 +43,7 @@ define([
|
||||
Sortify,
|
||||
AppConfig,
|
||||
ApiConfig,
|
||||
Instance,
|
||||
Flatpickr
|
||||
) {
|
||||
var APP = window.APP = {};
|
||||
@ -70,6 +72,13 @@ define([
|
||||
'notice',
|
||||
]
|
||||
},
|
||||
'customize': {
|
||||
icon: 'fa fa-paint-brush',
|
||||
content: [
|
||||
'logo',
|
||||
'color'
|
||||
]
|
||||
},
|
||||
'users' : {
|
||||
icon : 'fa fa-address-card-o',
|
||||
content : [
|
||||
@ -745,6 +754,177 @@ define([
|
||||
cb(form);
|
||||
});
|
||||
|
||||
// XXX
|
||||
Messages.admin_cat_customize = "Customize";
|
||||
Messages.admin_logoTitle = "Upload Logo";
|
||||
Messages.admin_logoHint = "Max 200KB, svg, png or jpg";
|
||||
Messages.admin_logoButton = "Upload new";
|
||||
Messages.admin_logoRemoveButton = "Restore default";
|
||||
Messages.admin_colorTitle = "Main color";
|
||||
Messages.admin_colorHint = "Change the main color of your CryptPad instance. Please pick a color with good contrast with the rest of CryptPad.";
|
||||
Messages.admin_colorCurrent = "Current main color";
|
||||
Messages.admin_colorChange = "Change color";
|
||||
Messages.admin_colorPick = "Pick a color";
|
||||
Messages.admin_colorPreview = "Preview color";
|
||||
|
||||
sidebar.addItem('logo', (cb) => {
|
||||
// Msg.admin_logoHint, Msg.admin_logoTitle
|
||||
|
||||
let input = blocks.input({
|
||||
type: 'file',
|
||||
accept: 'image/*',
|
||||
'aria-labelledby': 'cp-admin-logo'
|
||||
});
|
||||
|
||||
var currentContainer = blocks.block();
|
||||
let redraw = () => {
|
||||
var current = h('img', {src: '/api/logo?'+(+new Date())});
|
||||
$(currentContainer).empty().append(current);
|
||||
};
|
||||
redraw();
|
||||
|
||||
var upload = blocks.button('primary', '', Messages.admin_logoButton);
|
||||
var remove = blocks.button('danger', '', Messages.admin_logoRemoveButton);
|
||||
|
||||
let spinnerBlock = blocks.inline();
|
||||
let spinner = UI.makeSpinner($(spinnerBlock));
|
||||
let form = blocks.form([
|
||||
currentContainer,
|
||||
blocks.block(input),
|
||||
blocks.nav([upload, remove, spinnerBlock])
|
||||
]);
|
||||
|
||||
let $button = $(upload);
|
||||
let $remove = $(remove);
|
||||
|
||||
Util.onClickEnter($button, function () {
|
||||
let files = input.files;
|
||||
if (files.length !== 1) {
|
||||
UI.warn(Messages.error);
|
||||
return;
|
||||
}
|
||||
spinner.spin();
|
||||
$button.attr('disabled', 'disabled');
|
||||
let reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
let dataURL = this.result;
|
||||
sframeCommand('UPLOAD_LOGO', {dataURL}, (err, response) => {
|
||||
$button.removeAttr('disabled');
|
||||
if (err) {
|
||||
UI.warn(Messages.error);
|
||||
$(input).val('');
|
||||
console.error(err, response);
|
||||
spinner.hide();
|
||||
return;
|
||||
}
|
||||
redraw();
|
||||
spinner.done();
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(files[0]);
|
||||
});
|
||||
UI.confirmButton($remove, {
|
||||
classes: 'btn-danger',
|
||||
multiple: true
|
||||
}, function () {
|
||||
spinner.spin();
|
||||
$remove.attr('disabled', 'disabled');
|
||||
sframeCommand('REMOVE_LOGO', {}, (err, response) => {
|
||||
$remove.removeAttr('disabled');
|
||||
if (err) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(err, response);
|
||||
spinner.hide();
|
||||
return;
|
||||
}
|
||||
redraw();
|
||||
spinner.done();
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
});
|
||||
|
||||
cb(form);
|
||||
});
|
||||
|
||||
sidebar.addItem('color', cb => {
|
||||
let input = blocks.input({
|
||||
type: 'color',
|
||||
value: (Instance && Instance.color) || '#0087FF'
|
||||
});
|
||||
let label = blocks.labelledInput(Messages.admin_colorPick, input);
|
||||
let current = blocks.block([], 'cp-admin-color-current');
|
||||
let labelCurrent = blocks.labelledInput(Messages.admin_colorCurrent, current);
|
||||
let preview = blocks.block([
|
||||
blocks.block([
|
||||
blocks.link('CryptPad', '/admin/#customize')
|
||||
]),
|
||||
blocks.nav([
|
||||
blocks.button('primary', 'fa-floppy-o', Messages.settings_save),
|
||||
blocks.button('secondary', 'fa-floppy-o', Messages.settings_save),
|
||||
])
|
||||
], 'cp-admin-color-preview');
|
||||
let labelPreview = blocks.labelledInput(Messages.admin_colorPreview, preview);
|
||||
let $preview = $(preview);
|
||||
|
||||
let remove = blocks.button('danger', '', Messages.admin_logoRemoveButton);
|
||||
let $remove = $(remove);
|
||||
|
||||
let setColor = (color, done) => {
|
||||
sframeCommand('CHANGE_COLOR', {color}, (err, response) => {
|
||||
if (err) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(err, response);
|
||||
done(false);
|
||||
return;
|
||||
}
|
||||
done(true);
|
||||
flushCacheNotice();
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
};
|
||||
|
||||
let btn = blocks.activeButton('primary', '',
|
||||
Messages.admin_colorChange, (done) => {
|
||||
let color = $input.val();
|
||||
setColor(color, done);
|
||||
});
|
||||
|
||||
let $input = $(input).on('change', () => {
|
||||
require(['/lib/less.min.js'], (Less) => {
|
||||
let color = $input.val();
|
||||
let lColor = Less.color(color.slice(1));
|
||||
let lighten = Less.functions.functionRegistry._data.lighten;
|
||||
let lightColor = lighten(lColor, {value:30}).toRGB();
|
||||
$preview.find('.btn-primary').css({
|
||||
'background-color': color
|
||||
});
|
||||
$preview.find('.btn-secondary').css({
|
||||
'border-color': lightColor,
|
||||
'color': lightColor,
|
||||
});
|
||||
$preview.find('a').css({
|
||||
'color': lightColor,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
UI.confirmButton($remove, {
|
||||
classes: 'btn-danger',
|
||||
multiple: true
|
||||
}, function () {
|
||||
$remove.attr('disabled', 'disabled');
|
||||
setColor('', () => {});
|
||||
});
|
||||
|
||||
let form = blocks.form([
|
||||
labelCurrent,
|
||||
label
|
||||
], blocks.nav([btn, remove, btn.spinner]));
|
||||
|
||||
cb([form, labelPreview]);
|
||||
});
|
||||
|
||||
sidebar.addItem('registration', function(cb){
|
||||
var refresh = function () {};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user