Refactored dark/light CSS + New Review Tab (#178)

This commit is contained in:
Chris Caron 2024-03-16 12:41:14 -04:00 committed by GitHub
parent 4bf5093d8f
commit 2c7f7b36fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1550 additions and 88 deletions

View File

@ -7,21 +7,23 @@
<meta charset="utf-8">
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}" />
<!--materialize-->
<link rel="stylesheet" href="{% get_static_prefix %}css/{{request.theme|safe}}/materialize.min.css" />
<link rel="stylesheet" href="{% get_static_prefix %}css/materialize.min.css" />
<!--material-design-icons-->
<link rel="stylesheet" href="{% static 'iconfont/material-icons.css' %}">
<!--highlightjs-->
<link rel="stylesheet" href="{% get_static_prefix %}css/highlight.min.css">
<!--common-->
<link rel="stylesheet" href="{% static 'css/base.css' %}" />
<!--highlightjs-->
<link rel="stylesheet" href="{% get_static_prefix %}css/{{request.theme|safe}}/highlight.min.css">
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}" />
<!--materialize-->
<script src="{% static 'js/materialize.min.js' %}"></script>
<!--sweetalert2-->
<script src="{% static 'js/sweetalert2.all.min.js' %}"></script>
<!--highlightjs-->
<script src="{% static 'js/highlight.pack.js' %}"></script>
<!--theme-->
<link rel="stylesheet" href="{% get_static_prefix %}css/theme-{{request.theme|safe}}.min.css">
<title>{% block title %}{% trans "Apprise API" %}{% endblock %}</title>
</head>

View File

@ -2,15 +2,17 @@
{% load i18n %}
{% block body %}
{% if STATEFUL_MODE != 'disabled' %}
<h4>{% trans "Management for Config ID:" %} <em>{{ key }}</em></h4>
<h4>{% trans "Management for Config ID:" %} <code class="config-id">{{ key }}</code></h4>
<div class="row">
<div class="col s12">
<ul class="tabs config-overview">
<li class="tab col s4"><a class="active" href="#overview"><i class="material-icons">info</i>
<li class="tab col s3"><a class="active" href="#overview"><i class="material-icons">info</i>
{% trans "Overview" %}</a></li>
<li class="tab {% if CONFIG_LOCK %}tab-locked {% endif %}col s4"><a href="#config"><i class="material-icons">{% if not CONFIG_LOCK %}settings{% else %}lock{% endif %}</i> {%trans "Configuration" %}</a>
<li class="tab {% if CONFIG_LOCK %}tab-locked {% endif %}col s3"><a href="#config"><i class="material-icons">{% if not CONFIG_LOCK %}settings{% else %}lock{% endif %}</i> {%trans "Configuration" %}</a>
</li>
<li class="tab col s4"><a href="#notify"><i class="material-icons">announcement</i> {%trans "Notifications" %}</a>
<li class="tab {% if CONFIG_LOCK %}tab-locked {% endif %}col s3"><a href="#review"><i class="material-icons">{% if not CONFIG_LOCK %}web{% else %}lock{% endif %}</i> {%trans "Review" %}</a>
</li>
<li class="tab col s3"><a href="#notify"><i class="material-icons">announcement</i> {%trans "Notifications" %}</a>
</li>
</ul>
</div>
@ -123,13 +125,6 @@
&nbsp;&nbsp;&nbsp;&nbsp;"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>{{key}}</em>"</code></pre>
</p>
</div>
<div class="section">
<h5>{% trans "Loaded Configuration" %}</h5>
<div id="url-list"></div>
<div id="url-list-progress" class="progress" style="width:70%">
<div class="indeterminate"></div>
</div>
</div>
</div>
</div>
<div id="config" class="col s12">
@ -150,6 +145,24 @@
{% endif %}
</div>
<div id="review" class="col s12">
{% if not CONFIG_LOCK %}
<p>
{% blocktrans %}The following URLs have been detected:{% endblocktrans %}
</p>
<div class="section">
<h5>{% trans "Loaded Configuration" %}</h5>
<div id="url-list"></div>
<div id="url-list-progress" class="progress" style="width:70%">
<div class="indeterminate"></div>
</div>
</div>
{% else %}
<h5>{% trans "Your Configuration Is Locked" %}</h5>
<p>{% blocktrans %}Access to your configuration has been disabled by your administrator.{% endblocktrans %}
{% endif %}
</div>
<div id="notify" class="col s12">
<p>
{% blocktrans %}
@ -201,10 +214,16 @@ async function main_init(){
let jsonResponse = await fetch('{% url "json_urls" key %}/?privacy=1', {
method: 'GET',
})
if(jsonResponse.status != 200) {
if(jsonResponse.status == 204) {
// Take an early exit
document.querySelector('#url-list-progress').style.display = 'none';
document.querySelector('#url-list').textContent = '{% trans "An error occurred retrieving the list of loaded Apprise URL(s)" %}'
document.querySelector('#url-list').textContent = '{% trans "There are no URLs defined. Click on the ⚙️ Configuration tab and define some." %}'
return;
} else if(jsonResponse.status != 200) {
// Take an early exit
document.querySelector('#url-list-progress').style.display = 'none';
document.querySelector('#url-list').textContent = '{% trans "💣 An error occurred retrieving the list of loaded Apprise URL(s)" %}'
return;
}
@ -212,12 +231,13 @@ async function main_init(){
// choose from. Tags are based off ones found in the saved
// configuration.
const data = await jsonResponse.json();
let external_data = tags.concat(data.tags).reduce(function(result, item) {
const external_data = tags.concat(data.tags).reduce(function(result, item) {
result[item] = null;
return result;
}, {})
M.Chips.init(document.querySelectorAll('.chips'), {
const chipElement = document.querySelector('.chips');
M.Chips.init(chipElement, {
placeholder: 'Optional Tag',
secondaryPlaceholder: 'Another Tag',
autocompleteOptions: {
@ -233,6 +253,23 @@ async function main_init(){
}
});
// our GET parameters to be treated as template values
var tagRe = new RegExp('[^[A-Za-z0-9_-]+');
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
if (params.tag) {
params.tag.split(tagRe).forEach(function (tag, index) {
M.Chips.getInstance(chipElement).addChip({tag: tag, image: ''});
});
}
if (params.title) {
document.querySelector('#id_title').value = params.title;
}
if (params.body) {
document.querySelector('#id_body').value = params.body;
}
// Now build our our loaded list of configuration for our welcome page
let urlList = document.createElement('ul');
@ -248,8 +285,19 @@ async function main_init(){
entry.tags.forEach(function (tag) {
let chip = document.createElement('div');
chip.setAttribute('class', 'chip');
chip.setAttribute('name', tag);
chip.setAttribute('href', `?tag=${tag}#notify`);
chip.textContent = `🏷️ ${tag}`;
li.appendChild(chip);
chip.addEventListener('click', function(e) {
e.preventDefault();
window.history.pushState(null, null, this.getAttribute('href'));
document.querySelector('.config-overview li a[href="#notify"]').click()
const chipElement = document.querySelector('.chips');
M.Chips.getInstance(chipElement).addChip({tag: this.getAttribute('name'), image: ''});
}, false);
});
urlList.appendChild(li);
@ -396,14 +444,47 @@ function config_init() {
}
}
function form_file_input_hack() {
/*
A small hack to remformat all `<input file>` upload options to a more cleaner
and presentable look by wrapping it like this:
<span class="btn btn-file">
<i class="material-icons left">cloud_upload</i>
Browse<input type="file">
</span>
*/
document.querySelectorAll('input[type=file]').forEach(function (entry) {
const div = document.createElement('div');
const selected = document.createElement('div');
selected.style.display = 'none';
selected.setAttribute('class', 'file-selected');
const span = document.createElement('span')
span.setAttribute('class', 'btn btn-file waves-effect waves-light');
const i = document.createElement('i')
span.textContent = '{% trans "Browse" %}';
i.setAttribute('class', 'material-icons right');
i.textContent = 'folder';
div.appendChild(span);
span.appendChild(i);
entry.before(div)
span.appendChild(entry);
span.after(selected);
entry.addEventListener('change', function(e){
const selected = this.parentNode.nextElementSibling;
const file = e.target.files[0];
selected.style.display = 'block'
selected.textContent = file.name;
});
});
}
function notify_init() {
// over-ride manual submit for a nicer user experience
document.querySelector('#donotify').onsubmit = function(event) {
event.preventDefault();
const chipElement = document.querySelector('.chips');
chipElement.querySelector('.chips');
const chipInput = document.querySelector('.chips > input');
if(chipInput.value) {
// This code just handles text typed in the tag section that was
@ -496,8 +577,10 @@ main_init();
{% if not CONFIG_LOCK %}
/* Initialze our configuration */
config_init();
{% endif %}
notify_init();
form_file_input_hack();
{% endif %}
{% endblock %}

View File

@ -40,12 +40,12 @@
<hr/>
<ul class="detail-buttons">
<li><strong>{% blocktrans %}Category{% endblocktrans %}:</strong> {{entry.category}}</li>
<li><strong>{% blocktrans %}Category{% endblocktrans %}:</strong> <code>{{entry.category}}</code></li>
{% if entry.protocols %}
<li><strong>{% blocktrans %}Insecure Schema(s){% endblocktrans %}:</strong> {{ entry.protocols|join:", " }}</li>
<li><strong>{% blocktrans %}Insecure Schema(s){% endblocktrans %}:</strong> <code>{{ entry.protocols|join:", " }}</code></li>
{% endif %}
{% if entry.secure_protocols %}
<li><strong>{% blocktrans %}Secure Schema(s){% endblocktrans %}:</strong> {{ entry.secure_protocols|join:", " }}</li>
<li><strong>{% blocktrans %}Secure Schema(s){% endblocktrans %}:</strong> <code>{{ entry.secure_protocols|join:", " }}</code></li>
{% endif %}
<li><pre><code class="bash">
# {% blocktrans %}Apprise URL Formatting{% endblocktrans %}</br>

View File

@ -22,17 +22,14 @@ input {
display: block;
}
.tabs .tab.disabled a,.tabs .tab.disabled a:hover{font-weight: inherit}
code {
background-color: #eee;
font-family: monospace;
white-space: normal;
padding: 0.2rem;
}
table code {
background-color: inherit;
}
h1, h2, h3, h4, h5 {
margin-top: 0;
}
@ -46,6 +43,10 @@ td, th {
margin-bottom: 0;
}
ul.detail-buttons strong {
font-weight: 800;
}
h4 em {
font-size: 2.0rem;
display: inline-block;
@ -114,13 +115,31 @@ textarea {
display: inline-flex;
vertical-align: middle;
}
#url-list code {
display: block;
background-color: inherit;
#url-list .card-panel {
padding: 0.5rem;
margin: 0.1rem 0;
border-radius: 12px;
width: 50%;
min-width: 35rem;
float: left;
}
#url-list .chip {
margin: 0.3rem;
background-color: inherit;
border: 1px solid #e4e4e4;
cursor: pointer;
}
#url-list code {
overflow-x: hidden;
overflow-y: hidden;
white-space: wrap;
text-wrap: wrap;
overflow-wrap: break-word;
border-radius: 5px;
display: block;
}
/* Notification Details */
@ -179,3 +198,37 @@ h6 {
#overview pre {
margin-left: 2.0rem
}
code.config-id {
font-size: 0.7em;
}
/* file button styled */
.btn-file {
position: relative;
overflow: hidden;
text-transform: uppercase;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;
}
.file-selected {
line-height: 2.0em;
font-size: 1.2rem;
border-radius: 5px;
padding: 0 1em;
overflow: hidden;
}

View File

@ -1 +0,0 @@
.nav.nav-color{background:#4c566a!important}.hljs{display:block;overflow-x:auto;padding:.5em;color:#d8dee9;background:#4c566a;transition:box-shadow .25s,-webkit-box-shadow .25s!important;border-radius:2px!important}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#4fa1ba;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#7091aa}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#a3be8c}.hljs-bullet,.hljs-symbol{color:#b48ead}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.no-config .info{color: #4c566a}.tabs .tab a:hover, .tabs .tab a.active {color: #4c566a}.theme a {color: #d8dee9}.url-enabled{color: #02c7a6}.url-disabled{color:#e00202}.btn, .btn-large,.btn-small {background-color:#333}.btn-large:hover, .btn-small:hover, .btn:hover {background-color:#222}i.material-icons{color:#6e7d9c}i.material-icons:hover{color:#57637a}.nav h1{color:#d8dee9!important}

File diff suppressed because one or more lines are too long

1326
apprise_api/static/css/theme-dark.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
.tabs .tab a {background-color: #f3f3f3;}
.tabs.tabs-transparent .tab a,.tabs.tabs-transparent .tab.disabled a,.tabs.tabs-transparent .tab.disabled a:hover, .tab.disabled i.material-icons{color:#a7a7a7}
.tabs .tab.disabled a,.tabs .tab.disabled a:hover{background-color: #f3f3f3; color:#a7a7a7}
.file-selected {
color: #039be5;
background-color: #f3f3f3;
}