Improve files page design and accessibility

This commit is contained in:
Booteille 2025-05-18 21:57:02 +02:00
parent 6e58023429
commit b5e038ebe7
No known key found for this signature in database
GPG Key ID: 0AB6C6CA01272646
3 changed files with 115 additions and 32 deletions

View File

@ -21,6 +21,11 @@
.button.is-danger { .button.is-danger {
--bulma-button-background-l-delta: 35%; --bulma-button-background-l-delta: 35%;
} }
.panel.is-danger {
--bulma-panel-heading-background-l: 65%;
--bulma-panel-s: 80%;
}
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {

View File

@ -32,16 +32,13 @@ const updateSelection = (event) => {
}; };
const purgeExpired = () => { const purgeExpired = () => {
const files = JSON.parse(localStorage.getItem(`${prefix}files`)); const deletedItemsDOM = document.getElementById("deleted-items-table");
files.forEach((file) => { for (let i = 0; i < deletedItemsDOM.children.length; i++) {
const fileDOM = document.querySelector(`.item-${file.short}`); deleteFromStorage(deletedItemsDOM.children[i].dataset.serverKey);
}
if (fileDOM?.classList.contains("deleted")) { deletedItemsDOM.replaceChildren();
deleteFromStorage(file.short);
fileDOM.remove();
}
});
}; };
const exportStorage = () => { const exportStorage = () => {
@ -135,6 +132,35 @@ const deleteSelection = () => {
const populateFilesTable = () => { const populateFilesTable = () => {
const itemsTableDOM = document.getElementById("items-table"); const itemsTableDOM = document.getElementById("items-table");
const deletedItemsDOM = document.getElementById("deleted-items-table");
const addDeletedItem = (file) => {
const deletedItemDOM = document
.querySelector("template#deleted-item")
.content.cloneNode(true).children[0];
deletedItemDOM.dataset.serverKey = file.short;
deletedItemDOM.querySelector(".name").innerText = file.name;
deletedItemDOM
.querySelector(".delete-at-first-view .icon")
.classList.add(file.del_at_first_view ? "fa-eraser" : "fa-close");
deletedItemDOM
.querySelector(".delete-at-first-view .icon")
.setAttribute("title", file.del_at_first_view ? i18n.yes : i18n.no);
deletedItemDOM.querySelector(".created-at").innerText = formatDate(
file.created_at
);
deletedItemDOM.querySelector(".expires-at").innerText =
file.delay == 0
? i18n.noExpiration
: formatDate(file.delay * 86400 + file.created_at);
deletedItemDOM.querySelector(".counter").innerText = file.counter;
deletedItemsDOM.append(deletedItemDOM);
};
itemsTableDOM.replaceChildren(); itemsTableDOM.replaceChildren();
let files = localStorage.getItem(`${prefix}files`); let files = localStorage.getItem(`${prefix}files`);
@ -175,6 +201,9 @@ const populateFilesTable = () => {
itemDOM itemDOM
.querySelector(".delete-at-first-view .icon") .querySelector(".delete-at-first-view .icon")
.classList.add(file.del_at_first_view ? "fa-eraser" : "fa-close"); .classList.add(file.del_at_first_view ? "fa-eraser" : "fa-close");
itemDOM
.querySelector(".delete-at-first-view .icon")
.setAttribute("title", file.del_at_first_view ? i18n.yes : i18n.no);
itemDOM.querySelector(".created-at").innerText = formatDate( itemDOM.querySelector(".created-at").innerText = formatDate(
file.created_at file.created_at
); );
@ -220,13 +249,19 @@ const populateFilesTable = () => {
countDOM.innerText = data.counter; countDOM.innerText = data.counter;
if (data.deleted) { if (data.deleted) {
countDOM.parentElement.classList.add("deleted"); file.counter = data.counter;
addDeletedItem(file);
countDOM.parentElement.remove();
} }
} else { } else {
alert(data.msg);
countDOM.parentElement.remove(); countDOM.parentElement.remove();
if (data.missing) { if (data.missing) {
console.log(
`$(data.name) ($(data.short)) is missing. Removing it from Storage.`
);
deleteFromStorage(data.short); deleteFromStorage(data.short);
} }
} }

View File

@ -9,48 +9,74 @@
</div> </div>
<div class="buttons"> <article class="panel is-info">
<h2 class="panel-heading"><%= l('Uploaded files') %></h2>
<div class="buttons panel-block">
<button id="action-delete-selection" type="button" class="button is-danger" disabled="disabled"> <button id="action-delete-selection" type="button" class="button is-danger" disabled="disabled">
<span class="icon-text"> <span class="icon-text">
<span class="icon fas fa-trash"></span> <span class="icon fas fa-trash"></span>
<span><%= l('Delete selected files') %></span> <span><%= l('Delete selected files') %></span>
</span> </span>
</button> </button>
<button id="action-purge-expired" type="button" class="button">
<span class="icon-text">
<span class="icon fas fa-recycle"></span>
<span><%= l('Purge expired files') %></span>
</span>
</button>
</div> </div>
<div class="table-container"> <div class="panel-block table-container files-table mb-6">
<table class="table is-stripped is-hoverable"> <table class="table is-stripped is-hoverable">
<thead> <thead>
<tr> <tr>
<th class="has-text-centered"> <th class="has-text-centered">
<div><%= l('Selection') %></div> <div><%= l('Selection') %></div>
<div class="checkbox"> <div class="checkbox">
<input type="checkbox" id="action-select-all"> <input type="checkbox" id="action-select-all" aria-label="<%= l('Select All')%>">
</div> </div>
</th> </th>
<th class="has-text-centered"><%= l('File name') %></th> <th class="has-text-centered is-vcentered"><%= l('File name') %></th>
<th class="has-text-centered"><%= l('Access nb') %></th> <th class="has-text-centered is-vcentered is-narrow"><%= l('Access nb') %></th>
<th class="has-text-centered"><%= l('Delete at first download?') %></th> <th class="has-text-centered is-vcentered is-narrow"><abbr title="<%= l('Delete at first download?') %>"><%= l('Delete after download') %></abbr></th>
<th class="has-text-centered"><%= l('Uploaded at') %></th> <th class="has-text-centered is-vcentered"><%= l('Uploaded at') %></th>
<th class="has-text-centered"><%= l('Expires at') %></th> <th class="has-text-centered is-vcentered"><%= l('Expires at') %></th>
<th class="has-text-centered"><%= l('Download link') %></th> <th class="has-text-centered is-vcentered"><%= l('Download') %></th>
<th class="has-text-centered"><%= l('Share link') %></th> <th class="has-text-centered is-vcentered"><%= l('Share') %></th>
<th class="has-text-centered"><%= l('Deletion link') %></th> <th class="has-text-centered is-vcentered"><%= l('Delete') %></th>
</tr> </tr>
</thead> </thead>
<tbody id="items-table"></tbody> <tbody id="items-table" class="has-text-centered"></tbody>
</table> </table>
</div> </div>
</article>
<div class="buttons"> <article class="panel is-danger">
<h2 class="panel-heading"><%= l('Expired files') %></h2>
<div class="panel-block buttons">
<button id="action-purge-expired" type="button" class="button">
<span class="icon-text">
<span class="icon fas fa-recycle"></span>
<span><%= l('Remore expired files from browser history') %></span>
</span>
</button>
</div>
<div class="panel-block table-container deleted-files-table mb-6">
<table class="table is-stripped is-hoverable is-fullwidth">
<thead>
<tr>
<th class="has-text-centered is-vcentered"><%= l('File name') %></th>
<th class="has-text-centered is-vcentered"><%= l('Access nb') %></th>
<th class="has-text-centered is-vcentered is-narrow"><abbr title="<%= l('Delete at first download?') %>"><%= l('Delete at first download') %></abbr></th>
<th class="has-text-centered is-vcentered"><%= l('Uploaded at') %></th>
<th class="has-text-centered is-vcentered"><%= l('Expires at') %></th>
</tr>
</thead>
<tbody id="deleted-items-table" class="has-text-centered"></tbody>
</table>
</div>
</article>
<div class="buttons is-justify-content-center">
<a id="action-export-storage" href="#" class="button"> <a id="action-export-storage" href="#" class="button">
<span class="icon-text"> <span class="icon-text">
<span class="icon fas fa-download"></span> <span class="icon fas fa-download"></span>
@ -89,7 +115,7 @@
<td class="created-at is-vcentered"></td> <td class="created-at is-vcentered"></td>
<td class="expires-at is-vcentered"></td> <td class="expires-at is-vcentered"></td>
<td class="download is-vcentered"> <td class="download is-vcentered">
<a title="<%= l('Download') %>" href="#"> <a href="#">
<span class="icon-text is-justify-content-center"> <span class="icon-text is-justify-content-center">
<span class="icon fas fa-download" aria-hidden="true"></span> <span class="icon fas fa-download" aria-hidden="true"></span>
<span><%= l('Download') %></span> <span><%= l('Download') %></span>
@ -105,7 +131,7 @@
</a> </a>
</td> </td>
<td class="deletion is-vcentered"> <td class="deletion is-vcentered">
<a class="action-delete-item" title="<%= l('Delete') %>" href="#"> <a class="action-delete-item" href="#">
<span class="icon-text is-justify-content-center"> <span class="icon-text is-justify-content-center">
<span class="icon fas fa-trash" aria-hidden="true"></span> <span class="icon fas fa-trash" aria-hidden="true"></span>
<span><%= l('Delete') %></span> <span><%= l('Delete') %></span>
@ -115,6 +141,21 @@
</tr> </tr>
</template> </template>
<template id="deleted-item">
<tr class="item">
<td class="name is-vcentered"></td>
<td class="counter is-vcentered"></td>
<td class="delete-at-first-view is-vcentered has-text-centered">
<span class="icon-text is-justify-content-center">
<span class="icon fas"></span>
<span class="text"></span>
</span>
</td>
<td class="created-at is-vcentered"></td>
<td class="expires-at is-vcentered"></td>
</tr>
</template>
<script type="text/javascript"> <script type="text/javascript">
% if (defined($self->config('fixed_domain')) && $self->config('fixed_domain')) { % if (defined($self->config('fixed_domain')) && $self->config('fixed_domain')) {
const baseURL = '<%= url_for('/')->host($self->config('fixed_domain'))->to_abs() %>'; const baseURL = '<%= url_for('/')->host($self->config('fixed_domain'))->to_abs() %>';
@ -126,9 +167,11 @@ const actionURL = '<%= url_for('/')->to_abs() %>';
const counterURL = '<%== url_for('counter') %>'; const counterURL = '<%== url_for('counter') %>';
const i18n = { const i18n = {
no: '<%= l('No') %>',
noExpiration: '<%= l('No expiration delay') %>', noExpiration: '<%= l('No expiration delay') %>',
importProcessed: '<%= l('The data has been successfully imported.') %>', importProcessed: '<%= l('The data has been successfully imported.') %>',
importFilesWithoutPrefix: "<%= l('Lufi recently changed its way to store files information.\n\nNo files have been found in the new localStorage location but we found files in the old one.\nDo you want to import those informations?\n\nPlease note that this is the only time that we will ask you this.') %>", importFilesWithoutPrefix: "<%= l('Lufi recently changed its way to store files information.\n\nNo files have been found in the new localStorage location but we found files in the old one.\nDo you want to import those informations?\n\nPlease note that this is the only time that we will ask you this.') %>",
yes: '<%= l('yes') %>'
}; };
</script> </script>
%= javascript '/js/minified/files.min.js', type => "module", defer => "true" %= javascript '/js/minified/files.min.js', type => "module", defer => "true"