mirror of
https://github.com/janeczku/calibre-web
synced 2026-10-12 11:01:40 +00:00
Added Theming
This commit is contained in:
+7
-1
@@ -44,7 +44,7 @@ from sqlalchemy.orm.attributes import flag_modified
|
||||
from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError, ArgumentError
|
||||
from sqlalchemy.sql.expression import func, or_, text
|
||||
|
||||
from . import constants, logger, helper, services, cli_param
|
||||
from . import constants, logger, helper, services, cli_param, themes
|
||||
from . import db, calibre_db, ub, web_server, config, updater_thread, gdriveutils, \
|
||||
kobo_sync_status, schedule
|
||||
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash, check_email, \
|
||||
@@ -121,6 +121,8 @@ def before_request():
|
||||
g.allow_anonymous = config.config_anonbrowse
|
||||
g.allow_upload = config.config_uploading
|
||||
g.current_theme = config.config_theme
|
||||
g.themes = themes.get_available_themes()
|
||||
g.theme = themes.get_theme(config.config_theme)
|
||||
g.config_authors_max = config.config_authors_max
|
||||
if ('/static/' not in request.path and not config.db_configured and
|
||||
request.endpoint not in ('admin.ajax_db_config',
|
||||
@@ -589,6 +591,10 @@ def update_view_configuration():
|
||||
return view_configuration()
|
||||
_config_int(to_save, "config_restricted_column")
|
||||
|
||||
if not themes.is_valid_theme(to_save.get("config_theme", "0")):
|
||||
flash(_("Invalid Theme"), category="error")
|
||||
log.debug("Invalid Theme")
|
||||
return view_configuration()
|
||||
_config_int(to_save, "config_theme")
|
||||
_config_int(to_save, "config_random_books")
|
||||
_config_int(to_save, "config_books_per_page")
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
<div class="form-group">
|
||||
<label for="config_theme">{{_('Theme')}}</label>
|
||||
<select name="config_theme" id="config_theme" class="form-control">
|
||||
<option value="0" {% if conf.config_theme == 0 %}selected{% endif %}>{{ _("Standard Theme") }}</option>
|
||||
<option value="1" {% if conf.config_theme == 1 %}selected{% endif %}>{{ _("caliBlur! Dark Theme") }}</option>
|
||||
{% for theme in g.themes %}
|
||||
<option value="{{ theme['id'] }}" {% if conf.config_theme == theme['id'] %}selected{% endif %}>{{ _(theme['label']) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
|
||||
{% if g.current_theme == 1 %}
|
||||
<link href="{{ url_for('static', filename='css/caliBlur.css') }}" rel="stylesheet" media="screen">
|
||||
{% endif %}
|
||||
{% for theme_css in g.theme['css_files'] %}
|
||||
<link href="{{ url_for('static', filename=theme_css) }}" rel="stylesheet" media="screen">
|
||||
{% endfor %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid" style="overflow-y: auto">
|
||||
|
||||
+12
-16
@@ -18,12 +18,11 @@
|
||||
{% block header %}{% endblock %}
|
||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/upload.css') }}" rel="stylesheet" media="screen">
|
||||
{% if g.current_theme == 1 %}
|
||||
<link href="{{ url_for('static', filename='css/caliBlur.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/caliBlur_override.css') }}" rel="stylesheet" media="screen">
|
||||
{% endif %}
|
||||
{% for theme_css in g.theme['css_files'] %}
|
||||
<link href="{{ url_for('static', filename=theme_css) }}" rel="stylesheet" media="screen">
|
||||
{% endfor %}
|
||||
</head>
|
||||
<body class="{{ page }} {{ bodyClass }}{% if g.current_theme == 1 %} blur{% endif %}" data-text="{{_('Home')}}" data-textback="{{_('Back')}}">
|
||||
<body class="{{ page }} {{ bodyClass }}{% if g.theme['body_class'] %} {{ g.theme['body_class'] }}{% endif %}" data-text="{{_('Home')}}" data-textback="{{_('Back')}}">
|
||||
<!-- Static navbar -->
|
||||
<div class="navbar navbar-default navbar-static-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
@@ -36,7 +35,7 @@
|
||||
</button>
|
||||
<a class="navbar-brand" href="{{url_for('web.index')}}">{{instance}}</a>
|
||||
</div>
|
||||
{% if g.current_theme == 1 %}
|
||||
{% if g.theme['show_home_shortcuts'] %}
|
||||
<div class="home-btn"><a class="home-btn-tooltip" href="{{url_for("web.index", page=1)}}" data-toggle="tooltip" title="" data-placement="bottom" data-original-title="Home"></a></div>
|
||||
<div class="plexBack"><a href="{{url_for('web.index')}}"></a></div>
|
||||
{% endif %}
|
||||
@@ -60,7 +59,7 @@
|
||||
{% endif %}
|
||||
<ul class="nav navbar-nav navbar-right" id="main-nav">
|
||||
{% if current_user.is_authenticated or g.allow_anonymous %}
|
||||
{% if g.current_theme == 1 %}
|
||||
{% if g.theme['profile_dropdown'] %}
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle profileDrop" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-user"></span></a>
|
||||
<ul class="dropdown-menu profileDropli">
|
||||
<li><a id="top_user" data-text="{{_('Account')}}" href="{{url_for('web.profile')}}" ><span class="glyphicon glyphicon-user"></span> <span class="hidden-sm">{{current_user.name}}</span></a></li>
|
||||
@@ -92,14 +91,14 @@
|
||||
{% if current_user.role_admin() %}
|
||||
<li><a id="top_admin" data-text="{{_('Settings')}}" href="{{url_for('admin.admin')}}"><span class="glyphicon glyphicon-dashboard"></span> <span class="hidden-sm">{{_('Admin')}}</span></a></li>
|
||||
{% endif %}
|
||||
{% if g.current_theme == 0 %}
|
||||
{% if not g.theme['profile_dropdown'] %}
|
||||
<li><a id="top_user" data-text="{{_('Account')}}" href="{% if not current_user.is_anonymous %}{{url_for('web.profile')}}{% else %}{{url_for('web.login', next=(request.path + "?" + request.query_string.decode("utf-8")).rstrip("?"))}}{% endif %}"><span class="glyphicon glyphicon-user"></span> <span class="hidden-sm">{{current_user.name}}</span></a></li>
|
||||
{% if not current_user.is_anonymous %}
|
||||
<li><a id="logout" href="{{url_for('web.logout', next=(request.path + "?" + request.query_string.decode("utf-8")).rstrip("?"))}}"><span class="glyphicon glyphicon-log-out"></span> <span class="hidden-sm">{{_('Logout')}}</span></a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if g.allow_registration and not current_user.is_authenticated and g.current_theme == 0 %}
|
||||
{% if g.allow_registration and not current_user.is_authenticated and not g.theme['profile_dropdown'] %}
|
||||
<li><a id="login" href="{{url_for('web.login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
|
||||
<li><a id="register" href="{{url_for('web.register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
|
||||
{% endif %}
|
||||
@@ -130,7 +129,7 @@
|
||||
{%endif%}
|
||||
{% endfor %}
|
||||
{% block flash %}{% endblock %}
|
||||
{% if g.current_theme == 1 %}
|
||||
{% if g.theme['show_upload_loader'] %}
|
||||
<div id="loader" hidden="true">
|
||||
<center>
|
||||
<h3>{{_('Uploading...')}}</h3>
|
||||
@@ -217,12 +216,9 @@
|
||||
<script src="{{ url_for('static', filename='js/libs/jquery.form.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/uploadprogress.js') }}"> </script>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
{% if g.current_theme == 1 %}
|
||||
<script src="{{ url_for('static', filename='js/libs/jquery.visible.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/libs/compromise.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/libs/readmore.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/caliBlur.js') }}"></script>
|
||||
{% endif %}
|
||||
{% for theme_js in g.theme['js_files'] %}
|
||||
<script src="{{ url_for('static', filename=theme_js) }}"></script>
|
||||
{% endfor %}
|
||||
{% block js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
{% if config.config_login_type == 0 and mail%}
|
||||
<button type="submit" name="forgot" value="forgot" class="btn btn-default">{{_('Forgot Password?')}}</button>
|
||||
{% endif %}
|
||||
{% if g.current_theme == 1 %}
|
||||
{% if g.theme['login_extra_buttons'] %}
|
||||
{% if g.allow_registration %}
|
||||
<a class="btn btn-default" id="register" href="{{url_for('web.register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -15,10 +15,9 @@
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
|
||||
{% if g.current_theme == 1 %}
|
||||
<link href="{{ url_for('static', filename='css/caliBlur.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/caliBlur_override.css') }}" rel="stylesheet" media="screen">
|
||||
{% endif %}
|
||||
{% for theme_css in g.theme['css_files'] %}
|
||||
<link href="{{ url_for('static', filename=theme_css) }}" rel="stylesheet" media="screen">
|
||||
{% endfor %}
|
||||
{% block header %}{% endblock %}
|
||||
</head>
|
||||
<body class="{{ page }} shelf-down">
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
|
||||
# Copyright (C) 2026
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
THEMES = (
|
||||
{
|
||||
"id": 0,
|
||||
"label": "Standard Theme",
|
||||
"css_files": (),
|
||||
"js_files": (),
|
||||
"body_class": "",
|
||||
"show_home_shortcuts": False,
|
||||
"profile_dropdown": False,
|
||||
"login_extra_buttons": False,
|
||||
"show_upload_loader": False
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"label": "caliBlur! Dark Theme",
|
||||
"css_files": (
|
||||
"css/caliBlur.css",
|
||||
"css/caliBlur_override.css"
|
||||
),
|
||||
"js_files": (
|
||||
"js/libs/jquery.visible.min.js",
|
||||
"js/libs/compromise.min.js",
|
||||
"js/libs/readmore.min.js",
|
||||
"js/caliBlur.js"
|
||||
),
|
||||
"body_class": "blur",
|
||||
"show_home_shortcuts": True,
|
||||
"profile_dropdown": True,
|
||||
"login_extra_buttons": True,
|
||||
"show_upload_loader": True
|
||||
}
|
||||
)
|
||||
|
||||
THEMES_BY_ID = {theme["id"]: theme for theme in THEMES}
|
||||
|
||||
|
||||
def get_available_themes():
|
||||
return THEMES
|
||||
|
||||
|
||||
def get_theme(theme_id):
|
||||
try:
|
||||
theme_id = int(theme_id)
|
||||
except (TypeError, ValueError):
|
||||
theme_id = 0
|
||||
return THEMES_BY_ID.get(theme_id, THEMES_BY_ID[0])
|
||||
|
||||
|
||||
def is_valid_theme(theme_id):
|
||||
try:
|
||||
theme_id = int(theme_id)
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
return theme_id in THEMES_BY_ID
|
||||
Reference in New Issue
Block a user