Add: theme switcher
This commit is contained in:
parent
1964e29197
commit
9015a7daa5
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
@ -0,0 +1,90 @@
|
||||
/*!
|
||||
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
|
||||
* Copyright 2011-2023 The Bootstrap Authors
|
||||
* Licensed under the Creative Commons Attribution 3.0 Unported License.
|
||||
*/
|
||||
|
||||
;(() => {
|
||||
"use strict"
|
||||
|
||||
const getStoredTheme = () => localStorage.getItem("theme")
|
||||
const setStoredTheme = (theme) => localStorage.setItem("theme", theme)
|
||||
|
||||
const getPreferredTheme = () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme) {
|
||||
return storedTheme
|
||||
}
|
||||
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light"
|
||||
}
|
||||
|
||||
const setTheme = (theme) => {
|
||||
if (
|
||||
theme === "auto" &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
) {
|
||||
document.documentElement.setAttribute("data-bs-theme", "dark")
|
||||
} else {
|
||||
document.documentElement.setAttribute("data-bs-theme", theme)
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(getPreferredTheme())
|
||||
|
||||
const showActiveTheme = (theme, focus = false) => {
|
||||
const themeSwitcher = document.querySelector("#bd-theme")
|
||||
|
||||
if (!themeSwitcher) {
|
||||
return
|
||||
}
|
||||
|
||||
const themeSwitcherText = document.querySelector("#bd-theme-text")
|
||||
const activeThemeIcon = document.querySelector(".theme-icon-active use")
|
||||
const btnToActive = document.querySelector(
|
||||
`[data-bs-theme-value="${theme}"]`
|
||||
)
|
||||
const svgOfActiveBtn = btnToActive
|
||||
.querySelector("svg use")
|
||||
.getAttribute("href")
|
||||
|
||||
document.querySelectorAll("[data-bs-theme-value]").forEach((element) => {
|
||||
element.classList.remove("active")
|
||||
element.setAttribute("aria-pressed", "false")
|
||||
})
|
||||
|
||||
btnToActive.classList.add("active")
|
||||
btnToActive.setAttribute("aria-pressed", "true")
|
||||
activeThemeIcon.setAttribute("href", svgOfActiveBtn)
|
||||
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
|
||||
themeSwitcher.setAttribute("aria-label", themeSwitcherLabel)
|
||||
|
||||
if (focus) {
|
||||
themeSwitcher.focus()
|
||||
}
|
||||
}
|
||||
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme !== "light" && storedTheme !== "dark") {
|
||||
setTheme(getPreferredTheme())
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
showActiveTheme(getPreferredTheme())
|
||||
|
||||
document.querySelectorAll("[data-bs-theme-value]").forEach((toggle) => {
|
||||
toggle.addEventListener("click", () => {
|
||||
const theme = toggle.getAttribute("data-bs-theme-value")
|
||||
setStoredTheme(theme)
|
||||
setTheme(theme)
|
||||
showActiveTheme(theme, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})()
|
@ -0,0 +1,31 @@
|
||||
$(function () {
|
||||
function deleteArchiveListElement(id) {
|
||||
const archiveList = `#li-archive-${id}`
|
||||
$(archiveList).remove()
|
||||
}
|
||||
$(".btn-archive-eraser").click(function (e) {
|
||||
e.preventDefault();
|
||||
const csrf = $("input[name=csrfmiddlewaretoken]").val()
|
||||
console.log(csrf)
|
||||
const archiveListElement = $(this).attr("data-jq-archive-target");
|
||||
$.ajax({
|
||||
type: "delete",
|
||||
url: $(this).attr("href"),
|
||||
headers: {
|
||||
'X-CSRFToken':csrf,
|
||||
'Content-Type':'application/json'
|
||||
},
|
||||
// beforeSend: function(xhr) {
|
||||
// xhr.setRequestHeader("X-CSRFToken", csrf);
|
||||
// },
|
||||
success: function (response) {
|
||||
console.log(response)
|
||||
deleteArchiveListElement(archiveListElement);
|
||||
},
|
||||
error: function (response) {
|
||||
console.log(response)
|
||||
}
|
||||
});
|
||||
});
|
||||
console.log("JQ is ready to work");
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" data-bs-theme="auto">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
@ -27,6 +27,7 @@
|
||||
href="{% static 'collector/img/favicon-16x16.png' %}"
|
||||
/>
|
||||
<link rel="manifest" href="{% static 'collector/img/site.webmanifest' %}">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
@ -36,6 +37,7 @@
|
||||
</section>
|
||||
</main>
|
||||
<script src="{% static 'collector/js/bootstrap.bundle.min.js' %}"></script>
|
||||
<script src="{% static 'collector/js/bs.theme.mode.js' %}"></script>
|
||||
<script src="{% static 'collector/js/jquery-3.7.0.min.js' %}"></script>
|
||||
{% block bs %}{% endblock bs %}
|
||||
{% block jquery %}{% endblock jquery %}
|
||||
|
@ -1,8 +1,23 @@
|
||||
<header>
|
||||
<section>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
|
||||
<symbol id="check2" viewBox="0 0 16 16">
|
||||
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
|
||||
</symbol>
|
||||
<symbol id="circle-half" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 0 8 1v14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/>
|
||||
</symbol>
|
||||
<symbol id="moon-stars-fill" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"/>
|
||||
<path d="M10.794 3.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387a1.734 1.734 0 0 0-1.097 1.097l-.387 1.162a.217.217 0 0 1-.412 0l-.387-1.162A1.734 1.734 0 0 0 9.31 6.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387a1.734 1.734 0 0 0 1.097-1.097l.387-1.162zM13.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.156 1.156 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.156 1.156 0 0 0-.732-.732l-.774-.258a.145.145 0 0 1 0-.274l.774-.258c.346-.115.617-.386.732-.732L13.863.1z"/>
|
||||
</symbol>
|
||||
<symbol id="sun-fill" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'index' %}">Logs Collector</a>
|
||||
<a class="navbar-brand" href="{% url 'index' %}">Logs Collector <i class="bi bi-file-earmark-zip-fill"></i></a>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
@ -17,14 +32,12 @@
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav ml-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
<button
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#"
|
||||
role="button"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>Tickets</a
|
||||
>
|
||||
>Tickets</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a class="dropdown-item" href="{% url 'index' %}">All</a>
|
||||
@ -39,22 +52,84 @@
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><a class="dropdown-item" href="#">Create ticket</a></li>
|
||||
<li><a class="dropdown-item" href="#"><i class="bi bi-pencil-square"></i> Create ticket</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled">Отключенная</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Search -->
|
||||
<ul class="navbar-nav flex-row flex-wrap ms-md-auto">
|
||||
<li class="nav-item py-2 py-lg-1 col-12 col-lg-auto">
|
||||
<form class="d-flex" role="search">
|
||||
<input
|
||||
class="form-control me-2"
|
||||
type="search"
|
||||
placeholder="Поиск"
|
||||
aria-label="Поиск"
|
||||
placeholder="Search"
|
||||
aria-label="Search"
|
||||
/>
|
||||
<button class="btn btn-outline-success" type="submit">Поиск</button>
|
||||
<button class="btn btn-outline-success" type="submit"><i class="bi bi-search"></i></button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- User settings -->
|
||||
<ul class="navbar-nav flex-row flex-wrap ms-md-auto">
|
||||
<li class="nav-item py-2 py-lg-1 col-12 col-lg-auto">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-person-square"></i> {{ request.user }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span class="visually-hidden">Toggle Dropdown</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><button class="dropdown-item" type="button">Settings</button></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><button class="dropdown-item" type="button">Logout</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<!-- Separator -->
|
||||
<li class="nav-item py-2 py-lg-1 col-12 col-lg-auto">
|
||||
<div class="vr d-none d-lg-flex h-100 mx-lg-2 text-white"></div>
|
||||
<hr class="d-lg-none my-2 text-white-50">
|
||||
</li>
|
||||
<!-- Theme switcher-->
|
||||
<li class="nav-item dropdown">
|
||||
<div class="dropdown bd-mode-toggle">
|
||||
<button class="btn btn-bd-primary py-2 dropdown-toggle d-flex align-items-center"
|
||||
id="bd-theme"
|
||||
type="button"
|
||||
aria-expanded="false"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-label="Toggle theme (auto)">
|
||||
<svg class="bi my-1 theme-icon-active" width="1em" height="1em"><use href="#circle-half"></use></svg>
|
||||
<span class="visually-hidden" id="bd-theme-text">Toggle theme</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end shadow" aria-labelledby="bd-theme-text">
|
||||
<li>
|
||||
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
|
||||
<svg class="bi me-2 opacity-50 theme-icon" width="1em" height="1em"><use href="#sun-fill"></use></svg>
|
||||
Light
|
||||
<svg class="bi ms-auto d-none" width="1em" height="1em"><use href="#check2"></use></svg>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
|
||||
<svg class="bi me-2 opacity-50 theme-icon" width="1em" height="1em"><use href="#moon-stars-fill"></use></svg>
|
||||
Dark
|
||||
<svg class="bi ms-auto d-none" width="1em" height="1em"><use href="#check2"></use></svg>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="auto" aria-pressed="true">
|
||||
<svg class="bi me-2 opacity-50 theme-icon" width="1em" height="1em"><use href="#circle-half"></use></svg>
|
||||
Auto
|
||||
<svg class="bi ms-auto d-none" width="1em" height="1em"><use href="#check2"></use></svg>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -1,36 +1,47 @@
|
||||
{% extends 'collector/base.html' %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
{% include 'collector/navigation.html' %}
|
||||
<main>
|
||||
<section>
|
||||
<div class="container mt-3">
|
||||
<div class="row">
|
||||
<div class="list-group mb-2">
|
||||
<div class="list-group-item list-group-item-action disable" aria-current="true">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body" aria-current="true">
|
||||
<div class="d-flex w-100 justify-content-between mb-2">
|
||||
<h5 class="mb-1">Ticket: {{ ticket.number }}</h5>
|
||||
<h4 class="card-title mb-1">Ticket: {{ ticket.number }}</h4>
|
||||
<small>{{ ticket.time_create }}</small>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-2">
|
||||
<h6 class="mb-1">Platform: {{ ticket.platform.pretty_name }}</h6>
|
||||
<h6 class="mb-1">Owner: {{ ticket.user.username }}</h6>
|
||||
<h6 class="card-title mb-1">Platform: {{ ticket.platform.pretty_name }}</h6>
|
||||
<h6 class="card-title mb-1">Owner: {{ ticket.user.username }}</h6>
|
||||
</div>
|
||||
<div class="col-xl-6 mt-1 mb-2">
|
||||
{% if ticket.note %}
|
||||
<small><b>Note:</b></small>
|
||||
<hr>
|
||||
<p>{{ ticket.note }}</p>
|
||||
<hr>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Note:
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">{{ ticket.note }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- Logs -->
|
||||
{% if ticket.archive_set.all %}
|
||||
<small><b>Logs:</b></small>
|
||||
<ul class="list-group mb-2 mt-2">
|
||||
<ul class="list-group col-xl-6 mb-2 mt-2">
|
||||
{% for archive in ticket.archive_set.all %}
|
||||
<li class="list-group-item list-group-item-action">
|
||||
<p style="word-wrap: break-word" ><b>File:</b> {{ archive.file }}</p>
|
||||
<li
|
||||
id="li-archive-{{ archive.id }}"
|
||||
class="list-group-item list-group-item-action">
|
||||
<smal>
|
||||
<b>File:</b>
|
||||
<span style="word-wrap: break-word">{{ archive.file }}</span>
|
||||
</small>
|
||||
<small>
|
||||
<br>
|
||||
<b>SHA1:</b>
|
||||
<span style="word-wrap: break-word">{{ archive.sha1 }}</span>
|
||||
</small>
|
||||
@ -40,15 +51,17 @@
|
||||
<span style="word-wrap: break-word">{{ archive.size }}</span>
|
||||
</small>
|
||||
<div class="row">
|
||||
<div class="col" >
|
||||
<div class="col-xl-8" >
|
||||
<a
|
||||
class="btn btn-outline-success btn-sm mt-2"
|
||||
href="{{ archive.get_absolute_url }}"
|
||||
>GET</a>
|
||||
><i class="bi bi-download"></i> GET</a>
|
||||
<button
|
||||
button type="button"
|
||||
class="btn btn-outline-danger btn-sm ms-2 mt-2"
|
||||
button type="button" data-bs-toggle="modal" data-bs-target="#modal-archive-del-{{ archive.id }}"
|
||||
>DEL</button>
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#modal-archive-del-{{ archive.id }}"
|
||||
><i class="bi bi-trash"></i> DEL</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@ -60,11 +73,11 @@
|
||||
<a
|
||||
href="{{ ticket.get_absolute_url }}"
|
||||
class="btn btn-outline-warning mb-1 mt-1"
|
||||
>Edit</a>
|
||||
><i class="bi bi-pencil-square"></i> Edit</a>
|
||||
<a
|
||||
href="{{ ticket.get_absolute_url }}"
|
||||
class="btn btn-outline-danger mb-1 mt-1"
|
||||
>Delete</a>
|
||||
><i class="bi bi-trash"></i> Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -82,8 +95,20 @@
|
||||
<p style="word-wrap: break-word">{{ archive.file }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger">Delete</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>Cancel
|
||||
</button>
|
||||
<a
|
||||
href="{% url 'download' archive.file %}"
|
||||
type="button"
|
||||
class="btn btn-danger btn-archive-eraser"
|
||||
data-bs-dismiss="modal"
|
||||
data-jq-archive-target="{{ archive.id }}"
|
||||
>Delete
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -93,3 +118,6 @@
|
||||
</section>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
{% block jquery %}
|
||||
<script src="{% static 'collector/js/jq.delete.archive.js' %}"></script>
|
||||
{% endblock jquery %}
|
@ -93,5 +93,5 @@
|
||||
</div>
|
||||
{% endblock content %}
|
||||
{% block bs %}
|
||||
<script src="{% static 'collector/js/bs-tooltip.js' %}"></script>
|
||||
<script src="{% static 'collector/js/bs.tooltip.js' %}"></script>
|
||||
{% endblock bs %}
|
||||
|
@ -1,25 +1,13 @@
|
||||
# from django.shortcuts import render
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import FileResponse, Http404
|
||||
from django.http import FileResponse, JsonResponse, Http404
|
||||
from django.views import generic
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
# from rest_framework.response import Response
|
||||
|
||||
from .models import Archive, Ticket, Platform
|
||||
|
||||
|
||||
# handles the url "/archives/{PATH}"".
|
||||
@login_required
|
||||
def download(request, path):
|
||||
try:
|
||||
file = Archive.objects.get(file=path)
|
||||
except Archive.DoesNotExist:
|
||||
return Http404
|
||||
|
||||
return FileResponse(file.file)
|
||||
|
||||
|
||||
class ArchiveHandlerView(generic.View):
|
||||
def get(self, request, path):
|
||||
try:
|
||||
@ -29,13 +17,24 @@ class ArchiveHandlerView(generic.View):
|
||||
return FileResponse(file.file)
|
||||
|
||||
def delete(self, request, path):
|
||||
content = {'file': path}
|
||||
try:
|
||||
file = Archive.objects.get(file=path)
|
||||
file.delete()
|
||||
return Response(content, status=status.HTTP_200_OK)
|
||||
except Archive.DoesNot.Exist:
|
||||
return Response(content, status=status.HTTP_204_NO_CONTENT)
|
||||
return JsonResponse(
|
||||
{
|
||||
'file': path,
|
||||
'status': status.HTTP_200_OK
|
||||
},
|
||||
status=status.HTTP_200_OK
|
||||
)
|
||||
except Archive.DoesNotExist:
|
||||
return JsonResponse(
|
||||
{
|
||||
'file': path,
|
||||
'status': status.HTTP_204_NO_CONTENT
|
||||
},
|
||||
status=status.HTTP_204_NO_CONTENT
|
||||
)
|
||||
|
||||
|
||||
class ListAllTickets(generic.ListView):
|
||||
|
Loading…
Reference in New Issue
Block a user