mirror of
https://github.com/YunoHost/apps.git
synced 2024-09-03 20:06:07 +02:00
271 lines
10 KiB
HTML
271 lines
10 KiB
HTML
{% extends "base.html" %}
|
|
{% block main %}
|
|
<div class="mt-5 text-center">
|
|
<h2 class="text-2xl font-bold text-gray-900">
|
|
{{ _("Application Wishlist") }}
|
|
</h2>
|
|
</div>
|
|
|
|
<div class="max-w-screen-md mx-auto mt-3 mb-3">
|
|
<div class="flex flex-row">
|
|
<div class="px-2 inline-block relative basis-2/3 text-gray-700">
|
|
<label for="search" class="sr-only"> {{ _("Search") }} </label>
|
|
|
|
<input
|
|
type="text"
|
|
id="search"
|
|
placeholder="{{ _('Search for...') }}"
|
|
class="w-full rounded-md border-gray-200 shadow-sm sm:text-sm py-2 pe-10"
|
|
/>
|
|
|
|
<span class="absolute inset-y-0 end-0 grid w-10 place-content-center pr-4">
|
|
<i class="fa fa-search" aria-hidden="true"></i>
|
|
</span>
|
|
</div>
|
|
|
|
<a class="btn btn-primary-outline" href="{{ url_for('add_to_wishlist') }}">
|
|
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
|
{{ _("Suggest an app") }}
|
|
</a>
|
|
</div>
|
|
|
|
<div class="flex flex-row justify-center items-center pt-2 text-center text-sm">
|
|
<div class="inline-block px-2">
|
|
{{ _("Sort by") }}
|
|
<select
|
|
name="selectsort"
|
|
id="selectsort"
|
|
class="inline-block rounded-md border-gray-200 text-sm ml-1 pl-1 pr-7 h-8 py-0"
|
|
>
|
|
<option {% if not init_sort %}selected{% endif %} value="">{{ _("Alphabetical") }}</option>
|
|
<option {% if init_sort == "popularity" %}selected{% endif %} value="popularity">{{ _("Popularity") }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="inline-block flex items-center px-2 {% if not user %}text-gray-500{% endif %}" {% if not user %}title="{{ _('Requires to be logged-in') }}"{% endif %}>
|
|
<label for="starsonly" class="inline-block relative mr-2 h-4 w-7 cursor-pointer">
|
|
<input type="checkbox" id="starsonly" class="peer sr-only" {% if user and init_starsonly %}checked{% endif %} {% if not user%}disabled{% endif %} />
|
|
|
|
<span class="absolute inset-0 rounded-full bg-gray-300 transition peer-checked:bg-green-500">
|
|
</span>
|
|
|
|
<span class="absolute inset-y-0 start-0 m-1 h-2 w-2 rounded-full bg-white transition-all peer-checked:start-3">
|
|
</span>
|
|
</label>
|
|
{{ _("Show only apps you starred") }}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="overflow-x-auto max-w-screen-lg mx-auto pt-5">
|
|
<table class="min-w-full divide-y-2 divide-gray-200 bg-white text-sm">
|
|
<thead>
|
|
<tr>
|
|
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900">
|
|
{{ _("Name") }}
|
|
</th>
|
|
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900">
|
|
{{ _("Description") }}
|
|
</th>
|
|
<th class="py-2"></th>
|
|
<th class="py-2"></th>
|
|
<th class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 max-w-[5em]">{{ _("Popularity") }}</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody id="wishlist" class="divide-y divide-gray-200">
|
|
{% for app, infos in wishlist.items() %}
|
|
{% set this_app_stars = stars.get(app, {})|length %}
|
|
{% if user %}
|
|
{% set user_starred_this_app = user['id'] in stars.get(app, {}) %}
|
|
{% else %}
|
|
{% set user_starred_this_app = False %}
|
|
{% endif %}
|
|
<tr class="search-entry"
|
|
data-appid="{{ app }}"
|
|
data-stars="{{ this_app_stars }}"
|
|
data-starred="{{ user_starred_this_app }}"
|
|
>
|
|
<td class="px-4 py-2 font-bold text-gray-900 max-w-[10em]">
|
|
{{ infos['name'] }}
|
|
</td>
|
|
<td class="px-4 py-2 text-gray-700 max-w-md">{{ infos['description'] }}</td>
|
|
<td class="py-2">
|
|
{% if infos['website'] %}
|
|
<a
|
|
href="{{ infos['website'] }}"
|
|
class="inline-block"
|
|
>
|
|
<i class="fa fa-globe rounded-md border px-3 py-2 hover:bg-gray-100" aria-hidden="true"></i>
|
|
</a>
|
|
{% endif %}
|
|
</td>
|
|
<td class="py-2">
|
|
{% if infos['upstream'] %}
|
|
<a
|
|
href="{{ infos['upstream'] }}"
|
|
class="inline-block"
|
|
>
|
|
<i class="fa fa-code rounded-md border px-3 py-2 hover:bg-gray-100" aria-hidden="true"></i>
|
|
</a>
|
|
{% endif %}
|
|
</td>
|
|
<td class="text-center max-w-[5em]">
|
|
|
|
<a
|
|
href="{{ url_for('star_app', app_id=app, action="unstar" if user_starred_this_app else "star") }}"
|
|
class="inline-block group btn-sm border text-violet-600 border-violet-500 hover:bg-violet-500 hover:text-white"
|
|
>
|
|
{% if not user_starred_this_app %}
|
|
<span class="inline-block {% if user %}group-hover:hidden{% endif %}">{{ this_app_stars }}</span>
|
|
<span class="hidden {% if user %}group-hover:inline-block{% endif %}">{{ this_app_stars+1 }}</span>
|
|
<i class="fa fa-star-o inline-block {% if user %}group-hover:hidden{% endif %}" aria-hidden="true"></i>
|
|
<i class="fa fa-star hidden {% if user %}group-hover:inline-block{% endif %}" aria-hidden="true"></i>
|
|
{% else %}
|
|
<span class="inline-block group-hover:hidden">{{ this_app_stars }}</span>
|
|
<span class="hidden group-hover:inline-block">{{ this_app_stars-1 }}</span>
|
|
<i class="fa fa-star inline-block group-hover:hidden" aria-hidden="true"></i>
|
|
<i class="fa fa-star-o hidden group-hover:inline-block" aria-hidden="true"></i>
|
|
{% endif %}
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
<div id="noResultFound" class="text-center pt-5 hidden">
|
|
<p class="text-lg font-bold text-gray-900 mb-5">
|
|
{{ _("No results found.") }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// A little delay
|
|
let typingTimer;
|
|
let typeInterval = 500; // Half a second
|
|
let searchInput = document.getElementById('search');
|
|
let selectSort = document.getElementById('selectsort');
|
|
let toggleStarsonly = document.getElementById('starsonly');
|
|
|
|
function liveSearch() {
|
|
// Locate the card elements
|
|
let entries = document.querySelectorAll('.search-entry')
|
|
// Locate the search input
|
|
let search_query = searchInput.value.trim().toLowerCase();
|
|
let selectedCategory = false;
|
|
let starsOnly = toggleStarsonly.checked;
|
|
let at_least_one_match = false;
|
|
// Loop through the entries
|
|
for (var i = 0; i < entries.length; i++) {
|
|
// If the text is within the card and the text matches the search query
|
|
if ((entries[i].textContent.toLowerCase().includes(search_query))
|
|
&& (! selectedCategory || (entries[i].dataset.category == selectedCategory))
|
|
&& (! starsOnly || (entries[i].dataset.starred == "True")))
|
|
{
|
|
// ...remove the `.is-hidden` class.
|
|
entries[i].classList.remove("hidden");
|
|
at_least_one_match = true;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, add the class.
|
|
entries[i].classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
if (at_least_one_match === false)
|
|
{
|
|
document.getElementById('noResultFound').classList.remove("hidden");
|
|
}
|
|
else
|
|
{
|
|
document.getElementById('noResultFound').classList.add("hidden");
|
|
}
|
|
|
|
updateQueryArgsInURL()
|
|
}
|
|
|
|
function liveSort(container_to_sort) {
|
|
let sortBy = selectSort.value.trim();
|
|
var toSort = document.getElementById(container_to_sort).children;
|
|
toSort = Array.prototype.slice.call(toSort, 0);
|
|
console.log(sortBy);
|
|
if (sortBy === "newest") {
|
|
toSort.sort(function(a, b) {
|
|
return a.dataset.addedincatalog - b.dataset.addedincatalog;
|
|
});
|
|
}
|
|
else if (sortBy === "popularity") {
|
|
toSort.sort(function(a, b) {
|
|
return a.dataset.stars < b.dataset.stars;
|
|
});
|
|
}
|
|
else if (sortBy === "") {
|
|
toSort.sort(function(a, b) {
|
|
return a.dataset.appid > b.dataset.appid;
|
|
});
|
|
}
|
|
var parent = document.getElementById(container_to_sort);
|
|
parent.innerHTML = "";
|
|
|
|
for(var i = 0, l = toSort.length; i < l; i++) {
|
|
parent.appendChild(toSort[i]);
|
|
}
|
|
console.log("gni?")
|
|
updateQueryArgsInURL()
|
|
}
|
|
|
|
function updateQueryArgsInURL() {
|
|
let search_query = searchInput.value.trim();
|
|
let category = false;
|
|
let sortBy = selectSort.value.trim();
|
|
let starsOnly = toggleStarsonly.checked;
|
|
|
|
if ('URLSearchParams' in window) {
|
|
var queryArgs = new URLSearchParams(window.location.search)
|
|
if (search_query) { queryArgs.set("search", search_query) } else { queryArgs.delete("search"); };
|
|
if (category) { queryArgs.set("category", category) } else { queryArgs.delete("category"); };
|
|
if (sortBy) { queryArgs.set("sort", sortBy) } else { queryArgs.delete("sort"); };
|
|
if (starsOnly) { queryArgs.set("starsonly", true) } else { queryArgs.delete("starsonly"); };
|
|
|
|
console.log(queryArgs.toString());
|
|
|
|
let newUrl;
|
|
if (queryArgs.toString())
|
|
{
|
|
newUrl = window.location.pathname + '?' + queryArgs.toString();
|
|
}
|
|
else
|
|
{
|
|
newUrl = window.location.pathname;
|
|
}
|
|
|
|
if (newUrl != window.location.pathname + window.location.search)
|
|
{
|
|
history.pushState(null, '', newUrl);
|
|
}
|
|
}
|
|
}
|
|
|
|
searchInput.addEventListener('keyup', () => {
|
|
clearTimeout(typingTimer);
|
|
typingTimer = setTimeout(liveSearch, typeInterval);
|
|
});
|
|
|
|
selectSort.addEventListener('change', () => {
|
|
liveSort("wishlist");
|
|
});
|
|
|
|
toggleStarsonly.addEventListener('change', () => {
|
|
clearTimeout(typingTimer);
|
|
typingTimer = setTimeout(liveSearch, typeInterval);
|
|
});
|
|
|
|
liveSearch();
|
|
liveSort("wishlist");
|
|
|
|
</script>
|
|
|
|
{% endblock %}
|