Files
links/templates/base.html
T
2024-11-05 22:31:04 +11:00

282 lines
15 KiB
HTML

{% load i18n %}
{% load static %}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans "GoLinks" %}</title>
<link href="{% static 'css/dist/styles.css' %}" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet">
<style>
.bg-custom-blue {
background-color: #1a2f4e;
}
#search-results {
background-color: white;
border: 1px solid #e2e8f0;
border-top: none;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
max-height: 200px;
overflow-y: auto;
}
#search-results div {
padding: 0.5rem 1rem;
cursor: pointer;
color: #4a5568;
}
#search-results div:hover, #search-results div.active {
background-color: #e2e8f0;
}
.search-container {
position: relative;
width: 40px;
transition: width 0.3s ease-in-out;
}
.search-container.expanded {
width: 200px;
}
#search-input {
width: 100%;
padding-left: 30px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="%23ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>');
background-repeat: no-repeat;
background-position: 8px center;
background-size: 16px;
cursor: pointer;
}
#search-input:focus {
cursor: text;
}
</style>
{{ form.media }}
{% block extra_css %}{% endblock %}
</head>
<body class="bg-gray-100">
<nav class="bg-custom-blue text-white p-4 fixed w-full top-0 z-10">
<div class="container mx-auto flex justify-between items-center">
<a href="{% url 'link_list' %}" class="text-xl font-bold">{% trans "GoLinks" %}</a>
<div class="flex items-center space-x-4">
<div class="search-container">
<input type="text" id="search-input" class="bg-transparent text-white rounded px-2 py-1" placeholder="">
<div id="search-results" class="absolute top-full left-0 right-0 bg-white border border-gray-300 rounded mt-1 hidden"></div>
</div>
<!-- "Menus" 下拉菜单 -->
<div class="relative group">
<button id="more-menu-button" class="flex items-center text-white hover:text-gray-200">
<i class="fas fa-bars mr-2"></i>
{% trans "Menu" %}
</button>
<div id="more-menu-dropdown" class="absolute right-0 mt-2 py-2 w-48 bg-white rounded-md shadow-xl z-20 hidden">
<a href="{% url 'search' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<div class="flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
{% trans "Advanced Search" %}
</div>
</a>
<a href="{% url 'page-list' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<div class="flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9.5a2 2 0 00-2-2h-2"/>
</svg>
{% trans "Pages" %}
</div>
</a>
<a href="{% url 'newsletter-list' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<div class="flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9.5a2 2 0 00-2-2h-2M3 9l9-6 9 6m-1.5 11.5v-5.3a2 2 0 00-2-2h-13a2 2 0 00-2 2v5.3"/>
</svg>
{% trans "Newsletters" %}
</div>
</a>
<a href="{% url 'tools' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<div class="flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
{% trans "Tools" %}
</div>
</a>
<a href="{% url 'help' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<div class="flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
{% trans "Help" %}
</div>
</a>
<a href="{% url 'screenshot-gallery' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<div class="flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
{% trans "Screenshots" %}
</div>
</a>
</div>
</div>
<!-- 语言选择器 -->
<div class="relative">
<button id="language-selector-button" class="flex items-center text-white hover:text-gray-200">
<i class="fas fa-globe mr-2"></i>
{% get_current_language as LANGUAGE_CODE %}
{% get_language_info for LANGUAGE_CODE as current_language %}
{{ current_language.code|upper }}
</button>
<div id="language-options" class="absolute right-0 mt-2 py-2 w-48 bg-white rounded-md shadow-xl z-20 hidden">
<form action="{% url 'set_language' %}" method="post" id="language-form">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<button type="submit" name="language" value="{{ language.code }}" class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 {% if language.code == LANGUAGE_CODE %}font-bold{% endif %}">
{{ language.name_local }} ({{ language.code|upper }})
</button>
{% endfor %}
</form>
</div>
</div>
</div>
</div>
</nav>
<div class="container mx-auto mt-20 p-4">
{% if messages %}
{% for message in messages %}
<div class="bg-{{ message.tags }}-100 bg-yellow-100 border border-{{ message.tags }}-400 text-{{ message.tags }}-700 border-yellow-500 text-yellow-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline">{{ message }}</span>
</div>
{% endfor %}
{% endif %}
{% block content %}
<h1 class="text-2xl font-bold mb-4">Welcome to GoLinks</h1>
<p>If you can see this message, the base template is working correctly.</p>
{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="{% static 'js/navbar.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const searchContainer = document.querySelector('.search-container');
const searchInput = document.getElementById('search-input');
const searchResults = document.getElementById('search-results');
let currentFocus = -1;
searchInput.addEventListener('focus', function() {
searchContainer.classList.add('expanded');
this.placeholder = "{% trans 'Search aliases...' %}";
});
searchInput.addEventListener('blur', function() {
if (this.value === '') {
searchContainer.classList.remove('expanded');
this.placeholder = "";
}
});
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
searchInput.addEventListener('input', debounce(function(e) {
const query = e.target.value.trim();
if (query.length === 0) {
searchResults.style.display = 'none';
return;
}
const url = `/search/?q=${encodeURIComponent(query)}`;
fetch(url)
.then(response => response.json())
.then(data => {
searchResults.innerHTML = '';
if (Array.isArray(data) && data.length > 0) {
data.forEach(item => {
if (item && typeof item === 'object' && 'alias' in item && 'url' in item) {
const div = document.createElement('div');
div.className = 'p-2 hover:bg-gray-100';
const aliasLink = document.createElement('a');
aliasLink.href = item.url;
aliasLink.textContent = item.alias;
aliasLink.className = 'text-blue-600 hover:underline block';
div.appendChild(aliasLink);
searchResults.appendChild(div);
} else {
console.warn('Invalid item in search results:', item);
}
});
searchResults.style.display = 'block';
} else {
searchResults.innerHTML = '<div class="p-2">{% trans "No results found" %}</div>';
searchResults.style.display = 'block';
}
})
.catch(error => {
console.error('Error:', error);
searchResults.style.display = 'none';
});
}, 300));
searchInput.addEventListener('keydown', function(e) {
let x = searchResults.getElementsByTagName("div");
if (e.keyCode == 40) {
currentFocus++;
addActive(x);
} else if (e.keyCode == 38) {
currentFocus--;
addActive(x);
} else if (e.keyCode == 13) {
e.preventDefault();
if (currentFocus > -1) {
if (x) x[currentFocus].querySelector('a').click();
}
}
});
function addActive(x) {
if (!x) return false;
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = (x.length - 1);
x[currentFocus].classList.add("active");
}
function removeActive(x) {
for (let i = 0; i < x.length; i++) {
x[i].classList.remove("active");
}
}
document.addEventListener("click", function (e) {
if (e.target !== searchInput && e.target !== searchResults) {
searchResults.style.display = "none";
}
});
});
</script>
{% block extra_js %}{% endblock %}
</body>
</html>