introduction of theme engine parsing (themes go in /public/themes!)

v1.18.x
Julian Lam 12 years ago
parent 936d29d907
commit 6e91810231

@ -7,7 +7,7 @@ var nodebb_admin = (function(nodebb_admin) {
themes.render = function(bootswatch) { themes.render = function(bootswatch) {
var themeFrag = document.createDocumentFragment(), var themeFrag = document.createDocumentFragment(),
themeEl = document.createElement('li'), themeEl = document.createElement('li'),
themeContainer = document.querySelector('#content .themes'), themeContainer = document.querySelector('#bootstrap_themes'),
numThemes = bootswatch.themes.length; numThemes = bootswatch.themes.length;
for(var x=0;x<numThemes;x++) { for(var x=0;x<numThemes;x++) {
@ -42,30 +42,33 @@ var nodebb_admin = (function(nodebb_admin) {
scriptEl.src = 'http://api.bootswatch.com?callback=nodebb_admin.themes.render'; scriptEl.src = 'http://api.bootswatch.com?callback=nodebb_admin.themes.render';
document.body.appendChild(scriptEl); document.body.appendChild(scriptEl);
var themeContainer = document.querySelector('#content .themes'); var bootstrapThemeContainer = document.querySelector('#bootstrap_themes'),
themeContainer.addEventListener('click', function(e) { installedThemeContainer = document.querySelector('#installed_themes'),
if (e.target.hasAttribute('data-action')) { themeEvent = function(e) {
switch(e.target.getAttribute('data-action')) { if (e.target.hasAttribute('data-action')) {
case 'preview': switch(e.target.getAttribute('data-action')) {
var cssSrc = $(e.target).parents('li').attr('data-css'), case 'preview':
cssEl = document.getElementById('base-theme'); var cssSrc = $(e.target).parents('li').attr('data-css'),
cssEl = document.getElementById('base-theme');
cssEl.href = cssSrc; cssEl.href = cssSrc;
break; break;
case 'use': case 'use':
var parentEl = $(e.target).parents('li'), var parentEl = $(e.target).parents('li'),
cssSrc = parentEl.attr('data-css'), cssSrc = parentEl.attr('data-css'),
cssName = parentEl.attr('data-theme'); cssName = parentEl.attr('data-theme');
socket.emit('api:config.set', { socket.emit('api:config.set', {
key: 'theme:id', value: 'bootswatch:' + cssName key: 'theme:id', value: 'bootswatch:' + cssName
}); });
socket.emit('api:config.set', { socket.emit('api:config.set', {
key: 'theme:src', value: cssSrc key: 'theme:src', value: cssSrc
}); });
break; break;
}
} }
} };
}, false); bootstrapThemeContainer.addEventListener('click', themeEvent);
installedThemeContainer.addEventListener('click', themeEvent);
var revertEl = document.getElementById('revert_theme'); var revertEl = document.getElementById('revert_theme');
revertEl.addEventListener('click', function() { revertEl.addEventListener('click', function() {
@ -76,4 +79,31 @@ var nodebb_admin = (function(nodebb_admin) {
} }
}); });
}, false); }, false);
// Installed Themes
socket.once('api:admin:themes.getInstalled', function(themes) {
var instListEl = document.getElementById('installed_themes'),
themeFrag = document.createDocumentFragment(),
liEl = document.createElement('li');
for(var x=0,numThemes=themes.length;x<numThemes;x++) {
liEl.setAttribute('data-theme', themes[x].id);
liEl.setAttribute('data-css', themes[x].src);
liEl.innerHTML = '<img src="' + themes[x].thumbnail + '" />' +
'<div>' +
'<div class="pull-right">' +
'<button class="btn btn-primary" data-action="use">Use</button> ' +
'<button class="btn" data-action="preview">Preview</button>' +
'</div>' +
'<h4>' + themes[x].name + '</h4>' +
'<p>' + themes[x].description + '</p>' +
'</div>' +
'<div class="clear">';
themeFrag.appendChild(liEl.cloneNode(true));
}
instListEl.innerHTML = '';
instListEl.appendChild(themeFrag);
});
socket.emit('api:admin:themes.getInstalled');
})(); })();

@ -1,12 +1,20 @@
<h1>Themes</h1> <h1>Themes</h1>
<hr /> <hr />
<h3>Custom Themes</h3>
<p>
The following themes are currently installed in this NodeBB instance.
</p>
<ul class="themes" id="installed_themes">
<li><i class="icon-refresh icon-spin"></i> Checking for installed themes...</li>
</ul>
<h3>Bootswatch Themes</h3> <h3>Bootswatch Themes</h3>
<p> <p>
NodeBB Themes are powered by Bootswatch, a repository containing themes built NodeBB Themes are powered by Bootswatch, a repository containing themes built
with Bootstrap as a base theme. with Bootstrap as a base theme.
</p> </p>
<ul class="themes"> <ul class="themes" id="bootstrap_themes">
<li><i class="icon-refresh icon-spin"></i> Loading Themes</li> <li><i class="icon-refresh icon-spin"></i> Loading Themes</li>
</ul> </ul>

@ -1,6 +1,8 @@
var utils = require('./../public/src/utils.js'), var utils = require('./../public/src/utils.js'),
RDB = require('./redis.js'), RDB = require('./redis.js'),
async = require('async'); async = require('async'),
path = require('path'),
fs = require('fs');
(function(Meta) { (function(Meta) {
Meta.config = { Meta.config = {
@ -42,4 +44,37 @@ var utils = require('./../public/src/utils.js'),
RDB.hdel('config', field); RDB.hdel('config', field);
} }
} }
Meta.themes = {
get: function(callback) {
var themePath = path.join(__dirname, '../', 'public/themes');
fs.readdir(themePath, function(err, files) {
var themeArr = [];
async.each(files, function(file, next) {
fs.lstat(path.join(themePath, file), function(err, stats) {
if(stats.isDirectory()) {
var themeDir = file,
themeConfPath = path.join(themePath, themeDir, 'theme.json');
fs.exists(themeConfPath, function(exists) {
if (exists) {
fs.readFile(themeConfPath, function(err, conf) {
conf = JSON.parse(conf);
conf.src = global.nconf.get('url') + 'themes/' + themeDir + '/' + conf.src;
themeArr.push(conf);
next();
});
}
});
} else next();
});
}, function(err) {
callback(err, themeArr);
});
});
},
saveViaGithub: function(repo_url, callback) {
// ...
}
}
}(exports)); }(exports));

@ -614,6 +614,12 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
else else
socket.emit('api:admin.user.search', null); socket.emit('api:admin.user.search', null);
}); });
socket.on('api:admin:themes.getInstalled', function() {
meta.themes.get(function(err, themeArr) {
socket.emit('api:admin:themes.getInstalled', themeArr);
});
});
}); });
}(SocketIO)); }(SocketIO));

Loading…
Cancel
Save