Illustrations/web/templates/settings/home.html

261 lines
8.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block body_class %}themed-bg{% endblock %}
{% load static %}
{% block content %}
<div class="container">
<h1 class="page-title">Settings</h1>
<!-- Blank Settings box -->
<div class="card" style="padding:20px; margin-bottom:20px;">
<p class="muted small">Add your settings here when youre ready.</p>
<div class="card" style="margin-top:18px; padding:20px;">
<h2 class="page-title">Privacy · Clear My History</h2>
<p class="muted" style="margin:-6px 0 12px;">
Remove your Recent Searches and Recently Viewed illustrations from the Search page.
</p>
<button id="clear-history-btn" class="btn btn-danger">Clear History</button>
</div>
<!-- toast -->
<div id="toast-clear-history"
style="position:fixed; right:16px; bottom:16px; padding:10px 14px; border-radius:10px;
background:#111827; color:#fff; box-shadow:0 6px 20px rgba(0,0,0,.25);
opacity:0; pointer-events:none; transition:opacity .25s;">
History cleared.
</div>
<script>
(function(){
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length === 2) return parts.pop().split(";").shift();
}
var btn = document.getElementById("clear-history-btn");
var toast = document.getElementById("toast-clear-history");
if (!btn) return;
btn.addEventListener("click", function(){
fetch("{% url 'clear_history' %}", {
method: "POST",
headers: { "X-CSRFToken": getCookie("csrftoken") }
})
.then(function(r){ return r.ok ? r.json() : Promise.reject(); })
.then(function(data){
// Clear likely client-side copies too (harmless if not present)
var keys = ["recent_searches","recent_entries","recent_viewed","recently_viewed","recent_results","recentSearches","recentEntries"];
try {
keys.forEach(function(k){ localStorage.removeItem(k); sessionStorage.removeItem(k); });
} catch(e) {}
// Clear same-named cookies if any
try {
var expire = "expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/";
keys.forEach(function(k){ document.cookie = k + "=; " + expire; });
} catch(e) {}
// Toast
if (toast){
toast.textContent = "History cleared.";
toast.style.opacity = "1";
setTimeout(function(){ toast.style.opacity = "0"; }, 1500);
}
// Optional: log which server keys were removed
if (data && data.cleared) { console.log("Cleared server keys:", data.cleared); }
})
.catch(function(){ /* silent per spec */ });
});
})();
</script>
<!-- Your future settings content goes here -->
<div class="card" style="padding:20px; margin-bottom:20px;">
<form method="post" action="{% url 'set_theme' %}">
{% csrf_token %}
<label for="theme">Theme</label>
<select id="theme" name="theme" class="form-control" style="max-width: 320px;">
{% for t in available_themes %}
<option value="{{ t }}" {% if request.session.theme|default:'midnight' == t %}selected{% endif %}>
{{ t|capfirst }}
</option>
{% endfor %}
</select>
<button class="btn btn-primary" style="margin-top:10px;">Save</button>
<small class="text-muted" style="display:block;margin-top:6px;">Changes apply immediately across the site.</small>
</form>
<script>
/* Optional live preview without saving */
document.getElementById('theme').addEventListener('change', function(e){
const name = e.target.value;
document.getElementById('theme-css').href = '{% static "themes/" %}' + name + '.css';
try { localStorage.setItem('theme', name); } catch(e){}
});
</script>
<div class="card" style="padding:20px; margin-bottom:20px;">
<label style="display:flex;gap:10px;align-items:center;">
<input id="highlightHitsToggle" type="checkbox">
<span>Highlight search hits on entry page</span>
</label>
<p class="small muted" style="margin-top:6px;">When on, your last search terms are lightly highlighted on result pages—but only in the fields you searched.</p>
</div>
</div>
</div>
{% if user.is_authenticated and user.is_superuser %}
<h1 class="page-title">Tools</h1>
{% if user.is_superuser %}
<div class="card" style="margin-top:18px; padding:20px;">
<h2 class="page-title">Release Announcement</h2>
<p class="muted" style="margin:-6px 0 12px;">
Publish a message to show once to each user on their next search page load.
</p>
<form method="post" action="{% url 'announcement_tools' %}" class="vertical-stack" style="gap:10px;">
{% csrf_token %}
{% if announcement_form %}
{{ announcement_form.as_p }}
{% else %}
{# If this page isn't rendered via announcement_tools view, render a fresh form #}
<label>Title (optional)</label>
<input type="text" name="title" class="tool-input">
<label>Message</label>
<textarea name="message" rows="6" class="tool-input" placeholder="Whats new in this release…"></textarea>
<label style="display:flex; gap:6px; align-items:center; margin-top:8px;">
<input type="checkbox" name="is_active" checked> Active
</label>
{% endif %}
<button class="btn btn-primary">Publish</button>
</form>
{% if announcements_recent %}
<h3 style="margin-top:16px;">Recent</h3>
<table class="table">
<thead>
<tr><th>ID</th><th>Title</th><th>Active?</th><th>Window</th><th>Created</th></tr>
</thead>
<tbody>
{% for a in announcements_recent %}
<tr>
<td>#{{ a.id }}</td>
<td>{{ a.title|default:"(untitled)" }}</td>
<td>{{ a.is_current|yesno:"✅,—" }}</td>
<td>
{{ a.start_at|date:"Y-m-d H:i" }}
{% if a.end_at %} → {{ a.end_at|date:"Y-m-d H:i" }}{% endif %}
</td>
<td>{{ a.created_at|date:"Y-m-d H:i" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% endif %}
{% if user.is_superuser %}
<div class="card" style="margin-top:18px; padding:20px;">
<h2 class="page-title">Security · Login Attempts (7 days)</h2>
<p class="muted" style="margin:-6px 0 12px;">
View successful and failed login attempts from the last week.
</p>
<a class="btn btn-secondary" href="{% url 'login_attempts' %}">Open Login Attempts</a>
</div>
<div class="card" style="margin-top:18px; padding:20px;">
<h2 class="page-title">Security · Audit Log</h2>
<p class="muted" style="margin:-6px 0 12px;">Track adds, edits (with per-field changes), and deletes. Newest first, latest 100 entries.</p>
<a class="btn btn-secondary" href="{% url 'audit_log' %}">Open Audit Log</a>
</div>
{% endif %}
<style>
.tool-block { margin-bottom:16px; }
.tool-block h3 {
margin:0 0 6px;
font-size:18px;
color:#0f172a;
}
.tool-actions {
display:flex;
flex-wrap:wrap;
gap:10px;
margin-top:8px;
}
.tool-input {
border:1px solid var(--border, #d1d5db);
border-radius:8px;
padding:6px 8px;
font-size:14px;
margin-right:6px;
}
.tool-sep {
border:none;
border-top:1px solid var(--border, #e5e7eb);
margin:18px 0;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const toggle = document.getElementById("darkToggle");
if (!toggle) return;
toggle.addEventListener("click", () => {
document.body.classList.toggle("dark-mode");
localStorage.setItem("darkMode", document.body.classList.contains("dark-mode"));
});
// Restore preference on load
if (localStorage.getItem("darkMode") === "true") {
document.body.classList.add("dark-mode");
}
});
</script>
<script>
document.addEventListener("DOMContentLoaded", async () => {
const toggle = document.getElementById("highlightHitsToggle");
if (!toggle) return;
// Load current prefs
try {
const res = await fetch("/api/get-prefs/");
const data = await res.json();
if (data && typeof data.highlight_search_hits !== "undefined") {
toggle.checked = !!data.highlight_search_hits;
}
} catch (e) { /* ignore */ }
// Save on change
toggle.addEventListener("change", async () => {
const form = new FormData();
form.append("enabled", toggle.checked ? "true" : "false");
try {
await fetch("/api/set-highlight-hits/", { method: "POST", body: form, headers: { "X-CSRFToken": getCookie("csrftoken") }});
} catch (e) {
alert("Could not save the setting. Please try again.");
}
});
// Standard Django CSRF helper
function getCookie(name) {
const m = document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)");
return m ? m.pop() : "";
}
});
</script>
{% endblock %}