BS4 by default, BS5 optional

Bootstrap 4 w/ jQuery is used by default unless bs5 is enabled in
settings/ui. bs4 also now has a jellyfin-style look.
This commit is contained in:
2020-07-05 14:38:07 +01:00
parent ade935da4e
commit adef32ef89
26 changed files with 19315 additions and 39 deletions

View File

@@ -142,6 +142,11 @@ def load_config(config_path, data_dir):
or config["jellyfin"]["public_server"] == ""
):
config["jellyfin"]["public_server"] = config["jellyfin"]["server"]
if (
"bs5" not in config["ui"]
or config["ui"]["bs5"] == ""
):
config["ui"]["bs5"] = "false"
return config
@@ -185,8 +190,12 @@ data_store = JSONStorage(
config["files"]["user_configuration"],
)
if config.getboolean("ui", "bs5"):
css_file = "bs5-jf.css"
log.debug('Using Bootstrap 5')
else:
css_file = "bs4-jf.css"
css_file = "bs5-jf.css"
if "custom_css" in config["files"]:
if config["files"]["custom_css"] != "":
try:

View File

@@ -150,6 +150,14 @@
"type": "text",
"value": "Your account has been created. Click below to continue to Jellyfin.",
"description": "Displayed when a user creates an account"
},
"bs5": {
"name": "Use Bootstrap 5",
"required": false,
"requires_restart": true,
"type": "bool",
"value": false,
"description": "Use Bootstrap 5 (currently in alpha). This also removes the need for jQuery, so the page should load faster."
}
},
"password_validation": {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -14,8 +14,15 @@
<title>404</title>
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
{% if not bs5 %}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
{% if bs5 %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% else %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
{% endif %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.messageBox {

View File

@@ -12,11 +12,18 @@
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#603cba">
<meta name="theme-color" content="#ffffff">
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
{% if not bs5 %}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% if bs5 %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% else %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
{% endif %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.pageContainer {

View File

@@ -1,8 +1,64 @@
var loginModal = new bootstrap.Modal(document.getElementById('login'));
var settingsModal = new bootstrap.Modal(document.getElementById('settingsMenu'));
var userDefaultsModal = new bootstrap.Modal(document.getElementById('userDefaults'));
var usersModal = new bootstrap.Modal(document.getElementById('users'));
var restartModal = new bootstrap.Modal(document.getElementById('restartModal'));
var bsVersion = {{ bsVersion }};
if (bsVersion == 5) {
function createModal(id, find = false) {
if (find) {
return bootstrap.Modal.getInstance(document.getElementById(modalId));
};
return new bootstrap.Modal(document.getElementById(id));
};
function triggerTooltips() {
document.getElementById('settingsMenu').addEventListener('shown.bs.modal', function() {
// Hack to ensure anything dependent on checkboxes are disabled if necessary
var checkboxes = document.getElementById('settingsMenu').querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].click();
checkboxes[i].click();
};
// Initialize tooltips
var to_trigger = [].slice.call(document.querySelectorAll('a[data-toggle="tooltip"]'));
var tooltips = to_trigger.map(function(el) {
return new bootstrap.Tooltip(el);
});
});
};
// var loginModal = new bootstrap.Modal(document.getElementById('login'));
// var settingsModal = new bootstrap.Modal(document.getElementById('settingsMenu'));
// var userDefaultsModal = new bootstrap.Modal(document.getElementById('userDefaults'));
// var usersModal = new bootstrap.Modal(document.getElementById('users'));
// var restartModal = new bootstrap.Modal(document.getElementById('restartModal'));
} else if (bsVersion == 4) {
document.getElementById('send_to_address_enabled').classList.remove('form-check-input');
function createModal(id, find = false) {
return {
show : function() {
return $('#' + id).modal('show');
},
hide : function() {
return $('#' + id).modal('hide');
}
};
};
function triggerTooltips() {
$('#settingsMenu').on('shown.bs.modal', function() {
var checkboxes = document.getElementById('settingsMenu').querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].click();
checkboxes[i].click();
};
$("a[data-toggle='tooltip']").each(function (i, obj) {
$(obj).tooltip();
});
});
};
};
var loginModal = createModal('login');
var settingsModal = createModal('settingsMenu');
var userDefaultsModal = createModal('userDefaults');
var usersModal = createModal('users');
var restartModal = createModal('restartModal');
function parseInvite(invite, empty = false) {
if (empty === true) {
@@ -612,19 +668,7 @@ document.getElementById('openSettings').onclick = function () {
settingsModal.show();
};
document.getElementById('settingsMenu').addEventListener('shown.bs.modal', function() {
// Hack to ensure anything dependent on checkboxes are disabled if necessary
var checkboxes = document.getElementById('settingsMenu').querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].click();
checkboxes[i].click();
};
// Initialize tooltips
var to_trigger = [].slice.call(document.querySelectorAll('a[data-toggle="tooltip"]'));
var tooltips = to_trigger.map(function(el) {
return new bootstrap.Tooltip(el);
});
});
triggerTooltips();
//
// $('#settingsMenu').on('shown.bs.modal', function() {
// $("a[data-toggle='tooltip']").each(function (i, obj) {
@@ -642,7 +686,7 @@ function sendConfig(modalId) {
req.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200 || this.status == 204) {
bootstrap.Modal.getInstance(document.getElementById(modalId)).hide();
createModal(modalId, true).hide();
if (modalId != 'settingsMenu') {
settingsModal.hide();
};
@@ -699,4 +743,3 @@ document.getElementById('settingsSave').onclick = function() {
settingsModal.hide();
};
};

View File

@@ -14,8 +14,15 @@
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
{% if not bs5 %}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% if bs5 %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% else %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
{% endif %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.pageContainer {
@@ -109,7 +116,23 @@
</div>
<script src="serialize.js"></script>
<script>
var successBox = new bootstrap.Modal(document.getElementById('successBox'));
{% if bs5 %}
var bsVersion = 5;
{% else %}
var bsVersion = 4;
{% endif %}
if (bsVersion == 5) {
var successBox = new bootstrap.Modal(document.getElementById('successBox'));
} else if (bsVersion == 4) {
var successBox = {
show : function() {
return $('#successBox').modal('show');
},
hide : function() {
return $('#successBox').modal('hide');
}
};
};
var code = window.location.href.split('/').pop();
function toggleSpinner () {
var submitButton = document.getElementById('submitButton');

View File

@@ -6,8 +6,15 @@
<title>Invalid Code</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
{% if not bs5 %}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% if bs5 %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
{% else %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
{% endif %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.messageBox {

View File

@@ -11,6 +11,7 @@ def page_not_found(e):
return (
render_template(
"404.html",
bs5=config.getboolean('ui', 'bs5'),
css_file=css_file,
contactMessage=config["ui"]["contact_message"],
),
@@ -23,6 +24,7 @@ def admin():
# return app.send_static_file('admin.html')
return render_template(
"admin.html",
bs5=config.getboolean('ui', 'bs5'),
css_file=css_file,
contactMessage="",
email_enabled=config.getboolean("invite_emails", "enabled"),
@@ -32,10 +34,18 @@ def admin():
@app.route("/<path:path>")
def static_proxy(path):
if "html" not in path:
if "admin.js" in path:
if config.getboolean('ui', 'bs5'):
bsVersion = 5
else:
bsVersion = 4
return render_template("admin.js",
bsVersion=bsVersion)
return app.send_static_file(path)
return (
render_template(
"404.html",
bs5=config.getboolean('ui', 'bs5'),
css_file=css_file,
contactMessage=config["ui"]["contact_message"],
),
@@ -53,6 +63,7 @@ def inviteProxy(path):
email = ""
return render_template(
"form.html",
bs5=config.getboolean('ui', 'bs5'),
css_file=css_file,
contactMessage=config["ui"]["contact_message"],
helpMessage=config["ui"]["help_message"],
@@ -69,6 +80,7 @@ def inviteProxy(path):
log.debug("Attempted use of invalid invite")
return render_template(
"invalidCode.html",
bs5=config.getboolean('ui', 'bs5'),
css_file=css_file,
contactMessage=config["ui"]["contact_message"],
)