v2.5.0: replace keys table with responsive cards

This commit is contained in:
Виталий Литвинов
2026-04-25 15:52:17 +03:00
parent 7b1a79bba9
commit d62991857f
4 changed files with 143 additions and 34 deletions

View File

@@ -1138,12 +1138,12 @@ function renderUserTraffic() {
}
function renderUsers() {
const tbody = $("#usersTable");
const container = $("#usersTable");
if (!state.users.length) {
tbody.innerHTML = `<tr><td colspan="6" class="empty-cell">${escapeHtml(t("noKeys"))}</td></tr>`;
container.innerHTML = `<div class="empty empty-cell">${escapeHtml(t("noKeys"))}</div>`;
return;
}
tbody.innerHTML = state.users.map((user) => {
container.innerHTML = state.users.map((user) => {
const pending = state.pendingUsers.has(user.name);
const selected = user.name === state.userTrafficUser;
const traffic = user.traffic || {};
@@ -1151,13 +1151,12 @@ function renderUsers() {
const activeIps = Number(traffic.active_unique_ips) || 0;
const maxUniqueIps = Number.isFinite(Number(user.max_unique_ips)) ? Math.max(0, Number(user.max_unique_ips)) : 0;
return `
<tr class="${user.enabled ? "" : "disabled-row"} ${pending ? "pending-row" : ""} ${selected ? "selected-row" : ""}" data-select-user-traffic="${escapeAttr(user.name)}" aria-selected="${selected ? "true" : "false"}">
<td data-label="${escapeAttr(t("tableUser"))}">
<article class="key-card ${user.enabled ? "" : "disabled-row"} ${pending ? "pending-row" : ""} ${selected ? "selected-row" : ""}" data-select-user-traffic="${escapeAttr(user.name)}" aria-selected="${selected ? "true" : "false"}">
<div class="key-card-user">
<span class="field-label">${escapeHtml(t("tableUser"))}</span>
<button class="key-name-button" type="button" data-user-traffic="${escapeAttr(user.name)}">
<strong>${escapeHtml(user.name)}</strong>${user.main ? ` <small>${escapeHtml(t("main"))}</small>` : ""}
</button>
</td>
<td data-label="${escapeAttr(t("tableStatus"))}">
<div class="status-control">
<label class="switch" title="${escapeAttr(user.main ? t("main") : (user.enabled ? t("disableKey") : t("enableKey")))}">
<input type="checkbox" data-toggle-user="${escapeAttr(user.name)}" ${user.enabled ? "checked" : ""} ${user.main || pending ? "disabled" : ""}>
@@ -1165,15 +1164,20 @@ function renderUsers() {
</label>
<strong class="${user.enabled ? "state-on" : "state-off"}">${escapeHtml(pending ? t("applying") : (user.enabled ? t("enabled") : t("disabled")))}</strong>
</div>
</td>
<td data-label="${escapeAttr(t("tableSecret"))}"><code title="${escapeAttr(user.secret)}">${escapeHtml(user.secret)}</code></td>
<td data-label="${escapeAttr(t("tableLink"))}">
</div>
<div class="key-card-secret">
<span class="field-label">${escapeHtml(t("tableSecret"))}</span>
<code title="${escapeAttr(user.secret)}">${escapeHtml(user.secret)}</code>
</div>
<div class="key-card-links">
<span class="field-label">${escapeHtml(t("tableLink"))}</span>
<div class="mini-actions">
<button class="soft" data-copy="${escapeAttr(user.link)}" ${user.enabled ? "" : "disabled"}>${escapeHtml(t("copyLink"))}</button>
<button class="soft" data-user-qr="${escapeAttr(user.name)}">${escapeHtml(t("showQr"))}</button>
</div>
</td>
<td data-label="${escapeAttr(t("tableTraffic"))}">
</div>
<div class="key-card-traffic">
<span class="field-label">${escapeHtml(t("tableTraffic"))}</span>
<div class="traffic-cell">
<div class="traffic-main">
<span>
@@ -1188,14 +1192,15 @@ function renderUsers() {
<button class="soft" type="submit" data-ip-limit-save="${escapeAttr(user.name)}">${escapeHtml(t("saveIpLimit"))}</button>
</form>
</div>
</td>
<td data-label="${escapeAttr(t("tableActions"))}">
</div>
<div class="key-card-actions">
<span class="field-label">${escapeHtml(t("tableActions"))}</span>
<div class="action-buttons">
<button class="soft" data-copy="${escapeAttr(user.secret)}">${escapeHtml(t("copySecret"))}</button>
<button class="danger" data-delete="${escapeAttr(user.name)}" ${user.main ? "disabled" : ""}>${escapeHtml(t("delete"))}</button>
</div>
</td>
</tr>
</div>
</article>
`; }).join("");
}