mirror of
https://github.com/hrfee/jellyfin-accounts.git
synced 2024-12-22 09:00:14 +00:00
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:
parent
ade935da4e
commit
adef32ef89
@ -1,13 +1,11 @@
|
|||||||
# ![jellyfin-accounts](https://raw.githubusercontent.com/hrfee/jellyfin-accounts/master/images/jellyfin-accounts-banner-wide.svg)
|
# ![jellyfin-accounts](https://raw.githubusercontent.com/hrfee/jellyfin-accounts/master/images/jellyfin-accounts-banner-wide.svg)
|
||||||
|
|
||||||
**This branch uses the bootstrap 5 alpha, which works well enough for the most part, but can sometimes be a bit glitchy. Also no more jquery.**
|
|
||||||
|
|
||||||
A basic account management system for [Jellyfin](https://github.com/jellyfin/jellyfin).
|
A basic account management system for [Jellyfin](https://github.com/jellyfin/jellyfin).
|
||||||
* Provides a web interface for creating invite codes, and a simple account creation form
|
* Provides a web interface for creating invite codes, and a simple account creation form
|
||||||
* Sends out emails when a user requests a password reset
|
* Sends out emails when a user requests a password reset
|
||||||
* Uses a basic python jellyfin API client for communication with the server.
|
* Uses a basic python jellyfin API client for communication with the server.
|
||||||
* Uses [Flask](https://github.com/pallets/flask), [HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth), [itsdangerous](https://github.com/pallets/itsdangerous), and [Waitress](https://github.com/Pylons/waitress)
|
* Uses [Flask](https://github.com/pallets/flask), [HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth), [itsdangerous](https://github.com/pallets/itsdangerous), and [Waitress](https://github.com/Pylons/waitress)
|
||||||
* Frontend uses [Bootstrap 5](https://v5.getbootstrap.com)
|
* Frontend uses [Bootstrap](https://v5.getbootstrap.com)
|
||||||
* Password resets are handled using smtplib, requests, and [jinja](https://github.com/pallets/jinja)
|
* Password resets are handled using smtplib, requests, and [jinja](https://github.com/pallets/jinja)
|
||||||
## Interface
|
## Interface
|
||||||
<p align="center">
|
<p align="center">
|
||||||
|
@ -9,9 +9,9 @@ server = http://jellyfin.local:8096
|
|||||||
public_server = https://jellyf.in:443
|
public_server = https://jellyf.in:443
|
||||||
; this and below settings will show on the jellyfin dashboard when the program connects. you may as well leave them alone.
|
; this and below settings will show on the jellyfin dashboard when the program connects. you may as well leave them alone.
|
||||||
client = jf-accounts
|
client = jf-accounts
|
||||||
version = 0.2.5
|
version = 0.3.0
|
||||||
device = jf-accounts
|
device = jf-accounts
|
||||||
device_id = jf-accounts-0.2.5
|
device_id = jf-accounts-0.3.0
|
||||||
|
|
||||||
[ui]
|
[ui]
|
||||||
; settings related to the ui and program functionality.
|
; settings related to the ui and program functionality.
|
||||||
@ -33,6 +33,8 @@ contact_message = Need help? contact me.
|
|||||||
help_message = Enter your details to create an account.
|
help_message = Enter your details to create an account.
|
||||||
; displayed when a user creates an account
|
; displayed when a user creates an account
|
||||||
success_message = Your account has been created. Click below to continue to Jellyfin.
|
success_message = Your account has been created. Click below to continue to Jellyfin.
|
||||||
|
; use bootstrap 5 (currently in alpha). this also removes the need for jquery, so the page should load faster.
|
||||||
|
bs5 = false
|
||||||
|
|
||||||
[password_validation]
|
[password_validation]
|
||||||
; password validation (minimum length, etc.)
|
; password validation (minimum length, etc.)
|
||||||
|
@ -142,6 +142,11 @@ def load_config(config_path, data_dir):
|
|||||||
or config["jellyfin"]["public_server"] == ""
|
or config["jellyfin"]["public_server"] == ""
|
||||||
):
|
):
|
||||||
config["jellyfin"]["public_server"] = config["jellyfin"]["server"]
|
config["jellyfin"]["public_server"] = config["jellyfin"]["server"]
|
||||||
|
if (
|
||||||
|
"bs5" not in config["ui"]
|
||||||
|
or config["ui"]["bs5"] == ""
|
||||||
|
):
|
||||||
|
config["ui"]["bs5"] = "false"
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
@ -185,8 +190,12 @@ data_store = JSONStorage(
|
|||||||
config["files"]["user_configuration"],
|
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 "custom_css" in config["files"]:
|
||||||
if config["files"]["custom_css"] != "":
|
if config["files"]["custom_css"] != "":
|
||||||
try:
|
try:
|
||||||
|
@ -150,6 +150,14 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"value": "Your account has been created. Click below to continue to Jellyfin.",
|
"value": "Your account has been created. Click below to continue to Jellyfin.",
|
||||||
"description": "Displayed when a user creates an account"
|
"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": {
|
"password_validation": {
|
||||||
|
7
jellyfin_accounts/data/static/bs4-jf.css
Normal file
7
jellyfin_accounts/data/static/bs4-jf.css
Normal file
File diff suppressed because one or more lines are too long
7
jellyfin_accounts/data/static/bs4.css
Normal file
7
jellyfin_accounts/data/static/bs4.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7
jellyfin_accounts/data/static/bs5.css
Normal file
7
jellyfin_accounts/data/static/bs5.css
Normal file
File diff suppressed because one or more lines are too long
@ -14,8 +14,15 @@
|
|||||||
|
|
||||||
<title>404</title>
|
<title>404</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
|
<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://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>
|
<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">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
<style>
|
<style>
|
||||||
.messageBox {
|
.messageBox {
|
||||||
|
@ -12,11 +12,18 @@
|
|||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||||
<meta name="msapplication-TileColor" content="#603cba">
|
<meta name="msapplication-TileColor" content="#603cba">
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
|
<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://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">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
<style>
|
<style>
|
||||||
.pageContainer {
|
.pageContainer {
|
||||||
|
@ -1,8 +1,64 @@
|
|||||||
var loginModal = new bootstrap.Modal(document.getElementById('login'));
|
var bsVersion = {{ bsVersion }};
|
||||||
var settingsModal = new bootstrap.Modal(document.getElementById('settingsMenu'));
|
|
||||||
var userDefaultsModal = new bootstrap.Modal(document.getElementById('userDefaults'));
|
if (bsVersion == 5) {
|
||||||
var usersModal = new bootstrap.Modal(document.getElementById('users'));
|
function createModal(id, find = false) {
|
||||||
var restartModal = new bootstrap.Modal(document.getElementById('restartModal'));
|
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) {
|
function parseInvite(invite, empty = false) {
|
||||||
if (empty === true) {
|
if (empty === true) {
|
||||||
@ -612,19 +668,7 @@ document.getElementById('openSettings').onclick = function () {
|
|||||||
settingsModal.show();
|
settingsModal.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('settingsMenu').addEventListener('shown.bs.modal', function() {
|
triggerTooltips();
|
||||||
// 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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
//
|
//
|
||||||
// $('#settingsMenu').on('shown.bs.modal', function() {
|
// $('#settingsMenu').on('shown.bs.modal', function() {
|
||||||
// $("a[data-toggle='tooltip']").each(function (i, obj) {
|
// $("a[data-toggle='tooltip']").each(function (i, obj) {
|
||||||
@ -642,7 +686,7 @@ function sendConfig(modalId) {
|
|||||||
req.onreadystatechange = function() {
|
req.onreadystatechange = function() {
|
||||||
if (this.readyState == 4) {
|
if (this.readyState == 4) {
|
||||||
if (this.status == 200 || this.status == 204) {
|
if (this.status == 200 || this.status == 204) {
|
||||||
bootstrap.Modal.getInstance(document.getElementById(modalId)).hide();
|
createModal(modalId, true).hide();
|
||||||
if (modalId != 'settingsMenu') {
|
if (modalId != 'settingsMenu') {
|
||||||
settingsModal.hide();
|
settingsModal.hide();
|
||||||
};
|
};
|
||||||
@ -699,4 +743,3 @@ document.getElementById('settingsSave').onclick = function() {
|
|||||||
settingsModal.hide();
|
settingsModal.hide();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -14,8 +14,15 @@
|
|||||||
|
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
|
<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://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">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
<style>
|
<style>
|
||||||
.pageContainer {
|
.pageContainer {
|
||||||
@ -109,7 +116,23 @@
|
|||||||
</div>
|
</div>
|
||||||
<script src="serialize.js"></script>
|
<script src="serialize.js"></script>
|
||||||
<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();
|
var code = window.location.href.split('/').pop();
|
||||||
function toggleSpinner () {
|
function toggleSpinner () {
|
||||||
var submitButton = document.getElementById('submitButton');
|
var submitButton = document.getElementById('submitButton');
|
||||||
|
@ -6,8 +6,15 @@
|
|||||||
<title>Invalid Code</title>
|
<title>Invalid Code</title>
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
|
<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://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">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
<style>
|
<style>
|
||||||
.messageBox {
|
.messageBox {
|
||||||
|
@ -11,6 +11,7 @@ def page_not_found(e):
|
|||||||
return (
|
return (
|
||||||
render_template(
|
render_template(
|
||||||
"404.html",
|
"404.html",
|
||||||
|
bs5=config.getboolean('ui', 'bs5'),
|
||||||
css_file=css_file,
|
css_file=css_file,
|
||||||
contactMessage=config["ui"]["contact_message"],
|
contactMessage=config["ui"]["contact_message"],
|
||||||
),
|
),
|
||||||
@ -23,6 +24,7 @@ def admin():
|
|||||||
# return app.send_static_file('admin.html')
|
# return app.send_static_file('admin.html')
|
||||||
return render_template(
|
return render_template(
|
||||||
"admin.html",
|
"admin.html",
|
||||||
|
bs5=config.getboolean('ui', 'bs5'),
|
||||||
css_file=css_file,
|
css_file=css_file,
|
||||||
contactMessage="",
|
contactMessage="",
|
||||||
email_enabled=config.getboolean("invite_emails", "enabled"),
|
email_enabled=config.getboolean("invite_emails", "enabled"),
|
||||||
@ -32,10 +34,18 @@ def admin():
|
|||||||
@app.route("/<path:path>")
|
@app.route("/<path:path>")
|
||||||
def static_proxy(path):
|
def static_proxy(path):
|
||||||
if "html" not in 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 app.send_static_file(path)
|
||||||
return (
|
return (
|
||||||
render_template(
|
render_template(
|
||||||
"404.html",
|
"404.html",
|
||||||
|
bs5=config.getboolean('ui', 'bs5'),
|
||||||
css_file=css_file,
|
css_file=css_file,
|
||||||
contactMessage=config["ui"]["contact_message"],
|
contactMessage=config["ui"]["contact_message"],
|
||||||
),
|
),
|
||||||
@ -53,6 +63,7 @@ def inviteProxy(path):
|
|||||||
email = ""
|
email = ""
|
||||||
return render_template(
|
return render_template(
|
||||||
"form.html",
|
"form.html",
|
||||||
|
bs5=config.getboolean('ui', 'bs5'),
|
||||||
css_file=css_file,
|
css_file=css_file,
|
||||||
contactMessage=config["ui"]["contact_message"],
|
contactMessage=config["ui"]["contact_message"],
|
||||||
helpMessage=config["ui"]["help_message"],
|
helpMessage=config["ui"]["help_message"],
|
||||||
@ -69,6 +80,7 @@ def inviteProxy(path):
|
|||||||
log.debug("Attempted use of invalid invite")
|
log.debug("Attempted use of invalid invite")
|
||||||
return render_template(
|
return render_template(
|
||||||
"invalidCode.html",
|
"invalidCode.html",
|
||||||
|
bs5=config.getboolean('ui', 'bs5'),
|
||||||
css_file=css_file,
|
css_file=css_file,
|
||||||
contactMessage=config["ui"]["contact_message"],
|
contactMessage=config["ui"]["contact_message"],
|
||||||
)
|
)
|
||||||
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -191,6 +191,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.0-alpha1.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.0-alpha1.tgz",
|
||||||
"integrity": "sha512-iwKneP2pLXl8lN0YpnOuOARiNPTzmh/4cw+Un86u4OqrMLuQpyMC7nO07hvivvcg0B/ektJPjuPnS1s+YmRK9A=="
|
"integrity": "sha512-iwKneP2pLXl8lN0YpnOuOARiNPTzmh/4cw+Un86u4OqrMLuQpyMC7nO07hvivvcg0B/ektJPjuPnS1s+YmRK9A=="
|
||||||
},
|
},
|
||||||
|
"bootstrap4": {
|
||||||
|
"version": "npm:bootstrap@4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA=="
|
||||||
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
## SCSS
|
## SCSS
|
||||||
|
|
||||||
* `bs5-jf.scss` contains the source for the customizations to bootstrap. To customize the UI, you can make modifications to this file and then compile it.
|
* `bs<4/5>-jf.scss` contains the source for the customizations to bootstrap. To customize the UI, you can make modifications to this file and then compile it.
|
||||||
|
|
||||||
Note: assumes that bootstrap is installed in `../node_modules/bootstrap` relative to itself.
|
Note: For BS5, it assumes that bootstrap is installed in `../../node_modules/bootstrap` relative to itself.
|
||||||
|
For BS4, it assumes that bootstrap is installed in `../../node_modules/bootstrap4` relative to itself. (`npm install bootstrap4@npm:bootstrap`)
|
||||||
* Compilation requires a sass compiler of your choice, and `postcss-cli`, `autoprefixer` + `clean-css-cli` from npm.
|
* Compilation requires a sass compiler of your choice, and `postcss-cli`, `autoprefixer` + `clean-css-cli` from npm.
|
||||||
* If you're using `sassc`, run `./compile.sh bs5-jf.scss` in this directory. This will create a .css file, and minified .css file.
|
* If you're using `sassc`, run `./compile.sh bs<4/5>-jf.scss` in this directory. This will create a .css file, and minified .css file.
|
||||||
* For `node-sass`, replace the `sassc` line in `compile.sh` with
|
* For `node-sass`, replace the `sassc` line in `compile.sh` with
|
||||||
```
|
```
|
||||||
node-sass --output-style expanded --precision 6 $1 $css_file
|
node-sass --output-style expanded --precision 6 $1 $css_file
|
||||||
```
|
```
|
||||||
and run as above.
|
and run as above.
|
||||||
* If you're building from source, copy the minified css to `<jf-accounts git directory>/jellyfin_accounts/data/static/bs5-jf.css`.
|
* If you're building from source, copy the minified css to `<jf-accounts git directory>/jellyfin_accounts/data/static/bs<4/5>-jf.css`.
|
||||||
* If you're just customizing your install, set `custom_css` in your config as the path to your minified css.
|
* If you're just customizing your install, set `custom_css` in your config as the path to your minified css.
|
||||||
|
|
||||||
|
9548
scss/bs4/bs4-jf.css
Normal file
9548
scss/bs4/bs4-jf.css
Normal file
File diff suppressed because one or more lines are too long
7
scss/bs4/bs4-jf.min.css
vendored
Normal file
7
scss/bs4/bs4-jf.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
scss/bs4/bs4-jf.min.css.map
Normal file
1
scss/bs4/bs4-jf.min.css.map
Normal file
File diff suppressed because one or more lines are too long
136
scss/bs4/bs4-jf.scss
Normal file
136
scss/bs4/bs4-jf.scss
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
$jf-blue: rgb(0, 164, 220);
|
||||||
|
$jf-blue-hover: rgba(0, 164, 220, 0.2);
|
||||||
|
$jf-blue-focus: rgb(12, 176, 232);
|
||||||
|
$jf-blue-light: #4bb3dd;
|
||||||
|
|
||||||
|
$jf-red: rgb(204, 0, 0);
|
||||||
|
$jf-red-light: #e12026;
|
||||||
|
$jf-yellower: #ffc107;
|
||||||
|
$jf-yellow: #e1b222;
|
||||||
|
$jf-orange: #ff870f;
|
||||||
|
$jf-green: #6fbd45;
|
||||||
|
$jf-green-dark: #008040;
|
||||||
|
|
||||||
|
|
||||||
|
$jf-black: #101010; // 16 16 16
|
||||||
|
$jf-gray-90: #202020; // 32 32 32
|
||||||
|
$jf-gray-80: #242424; // jf-card 36 36 36
|
||||||
|
$jf-gray-70: #292929; // jf-input 41 41 41
|
||||||
|
$jf-gray-60: #303030; // jf-button 48 48 48
|
||||||
|
$jf-gray-50: #383838; // jf-button-focus 56 56 56
|
||||||
|
$jf-text-bold: rgba(255, 255, 255, 0.87);
|
||||||
|
$jf-text-primary: rgba(255, 255, 255, 0.8);
|
||||||
|
$jf-text-secondary: rgb(153, 153, 153);
|
||||||
|
|
||||||
|
$primary: $jf-blue;
|
||||||
|
$secondary: $jf-gray-50;
|
||||||
|
$success: $jf-green-dark;
|
||||||
|
$danger: $jf-red-light;
|
||||||
|
$light: $jf-text-primary;
|
||||||
|
$dark: $jf-gray-90;
|
||||||
|
$info: $jf-yellow;
|
||||||
|
$warning: $jf-yellower;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$enable-gradients: false;
|
||||||
|
$enable-shadows: false;
|
||||||
|
|
||||||
|
$enable-rounded: false;
|
||||||
|
$body-bg: $jf-black;
|
||||||
|
$body-color: $jf-text-primary;
|
||||||
|
$border-color: $jf-gray-60;
|
||||||
|
$component-active-color: $jf-text-bold;
|
||||||
|
$component-active-bg: $jf-blue-focus;
|
||||||
|
$text-muted: $jf-text-secondary;
|
||||||
|
$link-color: $jf-blue-focus;
|
||||||
|
$btn-link-disabled-color: $jf-text-secondary;
|
||||||
|
$input-bg: $jf-gray-90;
|
||||||
|
$input-color: $jf-text-primary;
|
||||||
|
$input-focus-bg: $jf-gray-60;
|
||||||
|
$input-focus-border-color: $jf-blue-focus;
|
||||||
|
$input-disabled-bg: $jf-gray-70;
|
||||||
|
input:disabled {
|
||||||
|
color: $text-muted;
|
||||||
|
}
|
||||||
|
$input-border-color: $jf-gray-60;
|
||||||
|
$input-placeholder-color: $text-muted;
|
||||||
|
|
||||||
|
$form-check-input-bg: $jf-gray-60;
|
||||||
|
$form-check-input-border: $jf-gray-50;
|
||||||
|
$form-check-input-checked-color: $jf-blue-focus;
|
||||||
|
$form-check-input-checked-bg-color: $jf-blue-hover;
|
||||||
|
|
||||||
|
$input-group-addon-bg: $input-bg;
|
||||||
|
|
||||||
|
$form-select-disabled-color: $jf-text-secondary;
|
||||||
|
$form-select-disabled-bg: $input-disabled-bg;
|
||||||
|
$form-select-indicator-color: $jf-gray-50;
|
||||||
|
|
||||||
|
$card-bg: $jf-gray-80;
|
||||||
|
$card-border-color: null;
|
||||||
|
|
||||||
|
$tooltip-color: $jf-text-bold;
|
||||||
|
$tooltip-bg: $jf-gray-50;
|
||||||
|
|
||||||
|
$modal-content-bg: $jf-gray-80;
|
||||||
|
$modal-content-border-color: $jf-gray-50;
|
||||||
|
$modal-header-border-color: null;
|
||||||
|
$modal-footer-border-color: null;
|
||||||
|
|
||||||
|
$list-group-bg: $card-bg;
|
||||||
|
$list-group-border-color: $jf-gray-50;
|
||||||
|
$list-group-hover-bg: $jf-blue-hover;
|
||||||
|
$list-group-active-bg: $jf-blue-focus;
|
||||||
|
$list-group-action-color: $jf-text-primary;
|
||||||
|
$list-group-action-hover-color: $jf-text-bold;
|
||||||
|
$list-group-action-active-color: $jf-text-bold;
|
||||||
|
$list-group-action-active-bg: $jf-blue-focus;
|
||||||
|
|
||||||
|
// idk why but i had to put these above and below the import
|
||||||
|
.list-group-item-danger {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
background-color: $danger;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item-success {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
background-color: $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "../../node_modules/bootstrap4/scss/bootstrap";
|
||||||
|
|
||||||
|
.btn-primary, .btn-outline-primary:hover, .btn-outline-primary:active {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
color: $jf-text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close:hover, .close:active {
|
||||||
|
color: $jf-text-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
color: $text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button:hover {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-bright {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item-danger {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
background-color: $danger;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item-success {
|
||||||
|
color: $jf-text-bold;
|
||||||
|
background-color: $success;
|
||||||
|
}
|
||||||
|
|
@ -98,7 +98,7 @@ $list-group-action-active-bg: $jf-blue-focus;
|
|||||||
background-color: $success;
|
background-color: $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "../node_modules/bootstrap/scss/bootstrap";
|
@import "../../node_modules/bootstrap/scss/bootstrap";
|
||||||
|
|
||||||
.btn-primary, .btn-outline-primary:hover, .btn-outline-primary:active {
|
.btn-primary, .btn-outline-primary:hover, .btn-outline-primary:active {
|
||||||
color: $jf-text-bold;
|
color: $jf-text-bold;
|
10
scss/bs5/compile.sh
Executable file
10
scss/bs5/compile.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
css_file=$(echo $1 | sed 's/scss/css/g')
|
||||||
|
min_file=$(echo $1 | sed 's/scss/min.css/g')
|
||||||
|
sassc -t expanded -p 6 $1 $css_file
|
||||||
|
echo "Compiled."
|
||||||
|
postcss $css_file --replace --use autoprefixer
|
||||||
|
echo "Prefixed."
|
||||||
|
echo "Written to $css_file."
|
||||||
|
cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output $min_file $css_file
|
||||||
|
echo "Minified version written to $min_file."
|
Loading…
Reference in New Issue
Block a user