mirror of
https://github.com/hrfee/jellyfin-accounts.git
synced 2024-12-22 09:00:14 +00:00
Added theme toggle to Admin page
The admin can switch between the two default themes without a page reload, with a nice animation (on small screens). Preference is stored as a cookie, so the default theme setting will still apply to others.
This commit is contained in:
parent
781306f1ef
commit
a3d3d97b3b
@ -9,13 +9,13 @@ server = http://jellyfin.local:8096
|
||||
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.
|
||||
client = jf-accounts
|
||||
version = 0.3.0
|
||||
version = 0.3.2
|
||||
device = jf-accounts
|
||||
device_id = jf-accounts-0.3.0
|
||||
device_id = jf-accounts-0.3.2
|
||||
|
||||
[ui]
|
||||
; settings related to the ui and program functionality.
|
||||
; choose the look of jellyfin-accounts.
|
||||
; default appearance for all users.
|
||||
theme = Jellyfin (Dark)
|
||||
; set 0.0.0.0 to run on localhost
|
||||
host = 0.0.0.0
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
__version__ = "0.3.2"
|
||||
__version__ = "0.3.3"
|
||||
|
||||
import secrets
|
||||
import configparser
|
||||
@ -218,7 +218,7 @@ elif "Custom" in current_theme and "custom_css" in config["files"]:
|
||||
try:
|
||||
css_path = Path(config["files"]["custom_css"])
|
||||
shutil.copy(css_path, (local_dir / "static" / css_path.name))
|
||||
log.debug('Loaded custom CSS "{css_path.name}"')
|
||||
log.debug(f'Loaded custom CSS "{css_path.name}"')
|
||||
css_file = css_path.name
|
||||
except FileNotFoundError:
|
||||
log.error(
|
||||
|
@ -71,7 +71,7 @@
|
||||
"description": "Settings related to the UI and program functionality."
|
||||
},
|
||||
"theme": {
|
||||
"name": "Look",
|
||||
"name": "Default Look",
|
||||
"required": false,
|
||||
"requires_restart": true,
|
||||
"type": "select",
|
||||
@ -81,7 +81,7 @@
|
||||
"Custom CSS"
|
||||
],
|
||||
"value": "Jellyfin (Dark)",
|
||||
"description": "Choose the look of jellyfin-accounts."
|
||||
"description": "Default appearance for all users."
|
||||
},
|
||||
"host": {
|
||||
"name": "Address",
|
||||
|
@ -14,7 +14,39 @@
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<!-- Bootstrap CSS -->
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ css_file }}">
|
||||
<script>
|
||||
function getCookie(cname) {
|
||||
var name = cname + "=";
|
||||
var decodedCookie = decodeURIComponent(document.cookie);
|
||||
var ca = decodedCookie.split(';');
|
||||
for(var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
{% if bs5 %}
|
||||
var bsVersion = 5;
|
||||
{% else %}
|
||||
var bsVersion = 4;
|
||||
{% endif %}
|
||||
var css = document.createElement('link');
|
||||
css.setAttribute('rel', 'stylesheet');
|
||||
css.setAttribute('type', 'text/css');
|
||||
var cssCookie = getCookie("css");
|
||||
if (cssCookie.includes('bs' + bsVersion)) {
|
||||
css.setAttribute('href', cssCookie);
|
||||
} else {
|
||||
css.setAttribute('href', '{{ css_file }}');
|
||||
};
|
||||
document.head.appendChild(css);
|
||||
// document.querySelectorAll('link[rel="stylesheet"][type="text/css"]')[0].href = cssCookie;
|
||||
</script>
|
||||
{% 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 %}
|
||||
@ -53,10 +85,27 @@
|
||||
margin-top: 5%;
|
||||
color: grey;
|
||||
}
|
||||
.circle {
|
||||
/*margin-left: 1rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 50%;
|
||||
z-index: 5000;*/
|
||||
-webkit-transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
-moz-transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
-o-transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190); /* easeInCubic */
|
||||
}
|
||||
.smooth-transition {
|
||||
-webkit-transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
-moz-transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
-o-transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
transition: all 300ms cubic-bezier(0.550, 0.055, 0.675, 0.190); /* easeInCubic */
|
||||
}
|
||||
</style>
|
||||
<title>Admin</title>
|
||||
</head>
|
||||
<body>
|
||||
<body class="smooth-transition">
|
||||
<div class="modal fade" id="login" role="dialog" aria-labelledby="login" aria-hidden="true" data-backdrop="static">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
@ -171,9 +220,11 @@
|
||||
<h1>
|
||||
Accounts admin
|
||||
</h1>
|
||||
<button type="button" class="btn btn-secondary" id="openSettings">
|
||||
<div class="btn-group" role="group" id="headerButtons">
|
||||
<button type="button" class="btn btn-primary" id="openSettings">
|
||||
Settings <i class="fa fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card mb-3 linkGroup">
|
||||
<div class="card-header">Current Invites</div>
|
||||
<ul class="list-group list-group-flush" id="invites">
|
||||
|
@ -1,5 +1,96 @@
|
||||
var bsVersion = {{ bsVersion }};
|
||||
function getCookie(cname) {
|
||||
var name = cname + "=";
|
||||
var decodedCookie = decodeURIComponent(document.cookie);
|
||||
var ca = decodedCookie.split(';');
|
||||
for(var i = 0; i <ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
function whichTransitionEvent(){
|
||||
var t;
|
||||
var el = document.createElement('fakeelement');
|
||||
var transitions = {
|
||||
'transition':'transitionend',
|
||||
'OTransition':'oTransitionEnd',
|
||||
'MozTransition':'transitionend',
|
||||
'WebkitTransition':'webkitTransitionEnd'
|
||||
};
|
||||
|
||||
for(t in transitions){
|
||||
if( el.style[t] !== undefined ){
|
||||
return transitions[t];
|
||||
};
|
||||
};
|
||||
};
|
||||
function toggleCSS() {
|
||||
var cssEl = document.querySelectorAll('link[rel="stylesheet"][type="text/css"]')[0];
|
||||
if (cssEl.href.includes("bs" + bsVersion + "-jf")) {
|
||||
var href = "bs" + bsVersion + ".css";
|
||||
} else {
|
||||
var href = "bs" + bsVersion + "-jf.css";
|
||||
};
|
||||
cssEl.href = href;
|
||||
document.cookie = "css=" + href;
|
||||
};
|
||||
var buttonWidth = 0;
|
||||
var inTransition = false;
|
||||
function toggleCSSAnim(el) {
|
||||
var switchToColor = window.getComputedStyle(document.body, null).backgroundColor;
|
||||
if (window.innerWidth < 1500) {
|
||||
var radius = Math.sqrt(Math.pow(window.innerWidth, 2) + Math.pow(window.innerHeight, 2));
|
||||
var currentRadius = el.getBoundingClientRect().width / 2;
|
||||
var scale = radius / currentRadius;
|
||||
buttonWidth = window.getComputedStyle(el, null).width;
|
||||
document.body.classList.remove('smooth-transition');
|
||||
el.style.transform = 'scale(' + scale + ')';
|
||||
el.style.color = switchToColor;
|
||||
var transitionEnd = whichTransitionEvent();
|
||||
el.addEventListener(transitionEnd, function() {
|
||||
if (this.style.transform.length != 0) {
|
||||
toggleCSS();
|
||||
this.style.removeProperty('transform');
|
||||
document.body.classList.add('smooth-transition');
|
||||
};
|
||||
}, false);
|
||||
} else {
|
||||
toggleCSS();
|
||||
el.style.color = switchToColor;
|
||||
};
|
||||
};
|
||||
var cssFile = "{{ css_file }}";
|
||||
var buttonColor = 'custom';
|
||||
if (cssFile.includes('jf')) {
|
||||
buttonColor = 'rgb(255,255,255)';
|
||||
} else if (cssFile.length == 7) {
|
||||
buttonColor = 'rgb(16,16,16)';
|
||||
}
|
||||
if (buttonColor != 'custom') {
|
||||
var fakeButton = document.createElement('i');
|
||||
fakeButton.classList.add('fa', 'fa-circle', 'circle');
|
||||
// fakeButton.style.color = buttonColor;
|
||||
// fakeButton.style.marginLeft = '2rem;'
|
||||
fakeButton.style = 'color: ' + buttonColor + '; margin-left: 0.4rem;';
|
||||
fakeButton.id = 'fakeButton';
|
||||
var switchButton = document.createElement('button');
|
||||
switchButton.classList.add('btn', 'btn-secondary');
|
||||
switchButton.textContent = 'Theme';
|
||||
switchButton.onclick = function() {
|
||||
var fb = document.getElementById('fakeButton')
|
||||
toggleCSSAnim(fb);
|
||||
};
|
||||
var group = document.getElementById('headerButtons');
|
||||
switchButton.appendChild(fakeButton);
|
||||
group.appendChild(switchButton);
|
||||
};
|
||||
|
||||
var bsVersion = {{ bsVersion }};
|
||||
if (bsVersion == 5) {
|
||||
function createModal(id, find = false) {
|
||||
if (find) {
|
||||
@ -22,13 +113,6 @@ if (bsVersion == 5) {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 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) {
|
||||
|
@ -6,6 +6,12 @@ from jellyfin_accounts import web_log as log
|
||||
from jellyfin_accounts.web_api import config, checkInvite, validator
|
||||
|
||||
|
||||
if config.getboolean("ui", "bs5"):
|
||||
bsVersion = 5
|
||||
else:
|
||||
bsVersion = 4
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return (
|
||||
@ -35,12 +41,10 @@ def admin():
|
||||
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),
|
||||
render_template("admin.js",
|
||||
bsVersion=bsVersion,
|
||||
css_file=css_file),
|
||||
200,
|
||||
{"Content-Type": "text/javascript"},
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "jellyfin-accounts"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
readme = "README.md"
|
||||
description = "A simple account management system for Jellyfin"
|
||||
authors = ["Harvey Tindall <harveyltindall@gmail.com>"]
|
||||
|
Loading…
Reference in New Issue
Block a user