UI change

This commit is contained in:
2024-09-08 19:18:53 +10:00
parent 3a424fb971
commit dac257587a
7 changed files with 141 additions and 21 deletions
Binary file not shown.
+43 -3
View File
@@ -22,14 +22,52 @@
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<input type="checkbox" id="select-all" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{% trans "Alias" %}</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<a href="?sort=alias&order={% if current_sort == 'alias' and current_order == 'asc' %}desc{% else %}asc{% endif %}" class="flex items-center">
{% trans "Alias" %}
{% if current_sort == 'alias' %}
<svg class="w-4 h-4 ml-1" 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="M{% if current_order == 'asc' %}19 9l-7 7-7-7{% else %}5 15l7-7 7 7{% endif %}"></path>
</svg>
{% endif %}
</a>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{% trans "Original URL" %}</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{% trans "Clicks" %}</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<a href="?sort=clicks&order={% if current_sort == 'clicks' and current_order == 'asc' %}desc{% else %}asc{% endif %}" class="flex items-center">
{% trans "Clicks" %}
{% if current_sort == 'clicks' %}
<svg class="w-4 h-4 ml-1" 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="M{% if current_order == 'asc' %}19 9l-7 7-7-7{% else %}5 15l7-7 7 7{% endif %}"></path>
</svg>
{% endif %}
</a>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<a href="?sort=created_at&order={% if current_sort == 'created_at' and current_order == 'asc' %}desc{% else %}asc{% endif %}" class="flex items-center">
{% trans "Created At" %}
{% if current_sort == 'created_at' %}
<svg class="w-4 h-4 ml-1" 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="M{% if current_order == 'asc' %}19 9l-7 7-7-7{% else %}5 15l7-7 7 7{% endif %}"></path>
</svg>
{% endif %}
</a>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<a href="?sort=updated_at&order={% if current_sort == 'updated_at' and current_order == 'asc' %}desc{% else %}asc{% endif %}" class="flex items-center">
{% trans "Updated At" %}
{% if current_sort == 'updated_at' %}
<svg class="w-4 h-4 ml-1" 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="M{% if current_order == 'asc' %}19 9l-7 7-7-7{% else %}5 15l7-7 7 7{% endif %}"></path>
</svg>
{% endif %}
</a>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{% for link in object_list %}
{% for link in links %}
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<input type="checkbox" name="selected_links" value="{{ link.id }}" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
@@ -41,6 +79,8 @@
<a href="{{ link.original_url }}" target="_blank" class="text-blue-600 hover:text-blue-900">{{ link.original_url }}</a>
</td>
<td class="px-6 py-4 whitespace-nowrap">{{ link.click_count }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ link.created_at|date:"Y-m-d H:i" }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ link.updated_at|date:"Y-m-d H:i" }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<a href="{% url 'link_update' link.id %}" class="text-indigo-600 hover:text-indigo-900 mr-2">{% trans "Edit" %}</a>
<a href="{% url 'link_delete' link.id %}" class="text-red-600 hover:text-red-900 mr-2">{% trans "Delete" %}</a>
+25
View File
@@ -16,6 +16,31 @@ from django.http import JsonResponse
class LinkListView(ListView):
model = Link
template_name = 'links/link_list.html'
context_object_name = 'links'
def get_queryset(self):
queryset = super().get_queryset()
sort_by = self.request.GET.get('sort', 'alias')
order = self.request.GET.get('order', 'asc')
if sort_by == 'alias':
ordering = F('alias').asc(nulls_last=True) if order == 'asc' else F('alias').desc(nulls_last=True)
elif sort_by == 'clicks':
ordering = F('click_count').asc(nulls_last=True) if order == 'asc' else F('click_count').desc(nulls_last=True)
elif sort_by == 'created_at':
ordering = F('created_at').asc(nulls_last=True) if order == 'asc' else F('created_at').desc(nulls_last=True)
elif sort_by == 'updated_at':
ordering = F('updated_at').asc(nulls_last=True) if order == 'asc' else F('updated_at').desc(nulls_last=True)
else:
ordering = F('alias').asc(nulls_last=True)
return queryset.order_by(ordering)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['current_sort'] = self.request.GET.get('sort', 'alias')
context['current_order'] = self.request.GET.get('order', 'asc')
return context
class LinkCreateView(CreateView):
model = Link
Binary file not shown.
+2 -2
View File
@@ -78,8 +78,8 @@ msgstr "总点击次数"
msgid "Created At"
msgstr "创建时间"
msgid "Last Updated"
msgstr "最后更新"
msgid "Updated At"
msgstr "更新时间"
msgid "Click Statistics"
msgstr "点击统计"
+22
View File
@@ -900,6 +900,18 @@ select {
margin-bottom: 0.5rem;
}
.ml-1 {
margin-left: 0.25rem;
}
.mr-1 {
margin-right: 0.25rem;
}
.mr-4 {
margin-right: 1rem;
}
.block {
display: block;
}
@@ -952,6 +964,10 @@ select {
width: 1rem;
}
.w-64 {
width: 16rem;
}
.min-w-full {
min-width: 100%;
}
@@ -1020,6 +1036,12 @@ select {
margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
}
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(1rem * var(--tw-space-x-reverse));
margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
}
.divide-y > :not([hidden]) ~ :not([hidden]) {
--tw-divide-y-reverse: 0;
border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
+49 -16
View File
@@ -7,6 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans "URL Manager" %}</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>
/* ... other styles ... */
#search-results {
@@ -25,31 +26,63 @@
#search-results div:hover {
background-color: #f7fafc;
}
.language-selector {
position: relative;
cursor: pointer;
}
.language-options {
display: none;
position: absolute;
top: 100%;
right: 0;
background-color: white;
border: 1px solid #e2e8f0;
border-radius: 0.25rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
min-width: 150px; /* Increased width */
}
.language-selector:hover .language-options {
display: block;
}
.language-option {
padding: 0.5rem 1rem;
color: #4a5568;
}
.language-option:hover {
background-color: #f7fafc;
}
</style>
</head>
<body class="bg-gray-100">
<nav class="bg-blue-600 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 "URL Manager" %}</a>
<div class="flex items-center">
<div class="relative mr-2">
<input type="text" id="search-input" class="bg-white text-gray-800 rounded px-2 py-1" placeholder="{% trans 'Search aliases...' %}">
<div class="flex items-center space-x-4"> <!-- Added space-x-4 for more spacing -->
<div class="relative">
<input type="text" id="search-input" class="bg-white text-gray-800 rounded px-4 py-2 w-64" placeholder="{% trans 'Search aliases...' %}"> <!-- Increased width and padding -->
<div id="search-results" class="absolute top-full left-0 right-0 bg-white border border-gray-300 rounded mt-1 hidden"></div>
</div>
<form action="{% url 'set_language' %}" method="post" class="inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">
<select name="language" onchange="this.form.submit()" class="bg-white text-gray-800 rounded px-2 py-1">
<div class="language-selector">
<span class="flex items-center">
<i class="fas fa-globe mr-2"></i> <!-- Increased margin -->
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }}
</option>
{% endfor %}
</select>
</form>
{% get_language_info for LANGUAGE_CODE as current_language %}
{{ current_language.code|upper }}
</span>
<div class="language-options">
<form action="{% url 'set_language' %}" method="post">
{% 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="language-option w-full text-left">
{{ language.name_local }} ({{ language.code|upper }})
</button>
{% endfor %}
</form>
</div>
</div>
</div>
</div>
</nav>