ui: add RadioBasedTabs
does the "tabs" seen on the invite tab (invite expiry/user expiry), and will be used in all other similar cases.
This commit is contained in:
+1
-10
@@ -597,16 +597,7 @@
|
|||||||
<span class="heading">{{ .strings.create }}</span>
|
<span class="heading">{{ .strings.create }}</span>
|
||||||
<div class="flex flex-col md:flex-row gap-3" id="create-inv">
|
<div class="flex flex-col md:flex-row gap-3" id="create-inv">
|
||||||
<div class="card ~neutral @low flex flex-col gap-2 flex-1">
|
<div class="card ~neutral @low flex flex-col gap-2 flex-1">
|
||||||
<div class="flex flex-row gap-2">
|
<div id="invites-duration-type-tabs"></div>
|
||||||
<label class="w-1/2">
|
|
||||||
<input type="radio" name="duration" class="unfocused" id="radio-inv-duration" checked>
|
|
||||||
<span class="button ~neutral @high supra full-width center">{{ .strings.inviteDuration }}</span>
|
|
||||||
</label>
|
|
||||||
<label class="w-1/2">
|
|
||||||
<input type="radio" name="duration" class="unfocused" id="radio-user-expiry">
|
|
||||||
<span class="button ~neutral @low supra full-width center">{{ .strings.userExpiry }}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="inv-duration" class="flex flex-col gap-2">
|
<div id="inv-duration" class="flex flex-col gap-2">
|
||||||
<div class="flex flex-row gap-2">
|
<div class="flex flex-row gap-2">
|
||||||
<div class="grow flex flex-col gap-4">
|
<div class="grow flex flex-col gap-4">
|
||||||
|
|||||||
+11
-1
@@ -2872,7 +2872,17 @@ class UserInfo extends PaginatedList {
|
|||||||
<div class="flex flex-row gap-2">
|
<div class="flex flex-row gap-2">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<h2 class="heading text-2xl">${window.lang.strings("activity")}</h2>
|
<div class="flex flex-row gap-2">
|
||||||
|
<label class="grow">
|
||||||
|
<input type="radio" name="jf-activity-source" class="jf-activity-source-jellyfin unfocused" checked>
|
||||||
|
<span class="button ~neutral @high supra w-full text-center">${window.lang.strings("jellyfin")}</span>
|
||||||
|
</label>
|
||||||
|
<label class="grow">
|
||||||
|
<input type="radio" name="jf-activity-source" class="jf-activity-source-jfa-go unfocused">
|
||||||
|
<span class="button ~neutral @low supra w-full text-center">jfa-go</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!-- <h2 class="heading text-2xl">${window.lang.strings("activity")}</h2> -->
|
||||||
<div class="card @low overflow-x-scroll jf-activity-table">
|
<div class="card @low overflow-x-scroll jf-activity-table">
|
||||||
<table class="table text-xs leading-5">
|
<table class="table text-xs leading-5">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
+15
-27
@@ -13,7 +13,7 @@ import {
|
|||||||
} from "../modules/common.js";
|
} from "../modules/common.js";
|
||||||
import { DiscordSearch, DiscordUser, newDiscordSearch } from "../modules/discord.js";
|
import { DiscordSearch, DiscordUser, newDiscordSearch } from "../modules/discord.js";
|
||||||
import { reloadProfileNames } from "../modules/profiles.js";
|
import { reloadProfileNames } from "../modules/profiles.js";
|
||||||
import { HiddenInputField } from "./ui.js";
|
import { HiddenInputField, RadioBasedTabSelector } from "./ui.js";
|
||||||
|
|
||||||
declare var window: GlobalWindow;
|
declare var window: GlobalWindow;
|
||||||
|
|
||||||
@@ -945,8 +945,8 @@ export class createInvite {
|
|||||||
private _userHours = document.getElementById("user-hours") as HTMLSelectElement;
|
private _userHours = document.getElementById("user-hours") as HTMLSelectElement;
|
||||||
private _userMinutes = document.getElementById("user-minutes") as HTMLSelectElement;
|
private _userMinutes = document.getElementById("user-minutes") as HTMLSelectElement;
|
||||||
|
|
||||||
private _invDurationButton = document.getElementById("radio-inv-duration") as HTMLInputElement;
|
// private _invDurationButton = document.getElementById("radio-inv-duration") as HTMLInputElement;
|
||||||
private _userExpiryButton = document.getElementById("radio-user-expiry") as HTMLInputElement;
|
// private _userExpiryButton = document.getElementById("radio-user-expiry") as HTMLInputElement;
|
||||||
private _invDuration = document.getElementById("inv-duration");
|
private _invDuration = document.getElementById("inv-duration");
|
||||||
private _userExpiry = document.getElementById("user-expiry");
|
private _userExpiry = document.getElementById("user-expiry");
|
||||||
|
|
||||||
@@ -1191,30 +1191,18 @@ export class createInvite {
|
|||||||
this.uses = 1;
|
this.uses = 1;
|
||||||
this.label = "";
|
this.label = "";
|
||||||
|
|
||||||
const checkDuration = () => {
|
new RadioBasedTabSelector(
|
||||||
const invSpan = this._invDurationButton.nextElementSibling as HTMLSpanElement;
|
document.getElementById("invites-duration-type-tabs"),
|
||||||
const userSpan = this._userExpiryButton.nextElementSibling as HTMLSpanElement;
|
"invites-duration-type",
|
||||||
if (this._invDurationButton.checked) {
|
{
|
||||||
this._invDuration.classList.remove("unfocused");
|
name: window.lang.strings("inviteDuration"),
|
||||||
this._userExpiry.classList.add("unfocused");
|
content: this._invDuration,
|
||||||
invSpan.classList.add("@high");
|
},
|
||||||
invSpan.classList.remove("@low");
|
{
|
||||||
userSpan.classList.add("@low");
|
name: window.lang.strings("userExpiry"),
|
||||||
userSpan.classList.remove("@high");
|
content: this._userExpiry,
|
||||||
} else if (this._userExpiryButton.checked) {
|
},
|
||||||
this._userExpiry.classList.remove("unfocused");
|
);
|
||||||
this._invDuration.classList.add("unfocused");
|
|
||||||
invSpan.classList.add("@low");
|
|
||||||
invSpan.classList.remove("@high");
|
|
||||||
userSpan.classList.add("@high");
|
|
||||||
userSpan.classList.remove("@low");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this._userExpiryButton.checked = false;
|
|
||||||
this._invDurationButton.checked = true;
|
|
||||||
this._userExpiryButton.onchange = checkDuration;
|
|
||||||
this._invDurationButton.onchange = checkDuration;
|
|
||||||
|
|
||||||
this._days.onchange = this._checkDurationValidity;
|
this._days.onchange = this._checkDurationValidity;
|
||||||
this._months.onchange = this._checkDurationValidity;
|
this._months.onchange = this._checkDurationValidity;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
declare var window: GlobalWindow;
|
||||||
|
|
||||||
export interface HiddenInputConf {
|
export interface HiddenInputConf {
|
||||||
container: HTMLElement;
|
container: HTMLElement;
|
||||||
onSet: () => void;
|
onSet: () => void;
|
||||||
@@ -109,3 +111,92 @@ export class HiddenInputField {
|
|||||||
this.setEditing(!this.editing, false, noSave);
|
this.setEditing(!this.editing, false, noSave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface RadioBasedTab {
|
||||||
|
name: string;
|
||||||
|
content: HTMLElement;
|
||||||
|
onShow?: () => void;
|
||||||
|
onHide?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RadioBasedTabItem {
|
||||||
|
tab: RadioBasedTab;
|
||||||
|
input: HTMLInputElement;
|
||||||
|
button: HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RadioBasedTabSelector {
|
||||||
|
private _id: string;
|
||||||
|
private _container: HTMLElement;
|
||||||
|
private _tabs: RadioBasedTabItem[];
|
||||||
|
private _selected: string;
|
||||||
|
constructor(container: HTMLElement, id: string, ...tabs: RadioBasedTab[]) {
|
||||||
|
this._container = container;
|
||||||
|
this._container.classList.add("flex", "flex-row", "gap-2");
|
||||||
|
this._tabs = [];
|
||||||
|
this._id = id;
|
||||||
|
let i = 0;
|
||||||
|
const frag = document.createDocumentFragment();
|
||||||
|
for (let tab of tabs) {
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.classList.add("grow");
|
||||||
|
label.innerHTML = `
|
||||||
|
<input type="radio" name="${this._id}" value="${tab.name}" class="unfocused" ${i == 0 ? "checked" : ""}>
|
||||||
|
<span class="button ~neutral ${i == 0 ? "@high" : "@low"} radio-tab-button supra w-full text-center">${tab.name}</span>
|
||||||
|
`;
|
||||||
|
let ft: RadioBasedTabItem = {
|
||||||
|
tab: tab,
|
||||||
|
input: label.getElementsByTagName("input")[0] as HTMLInputElement,
|
||||||
|
button: label.getElementsByClassName("radio-tab-button")[0] as HTMLElement
|
||||||
|
};
|
||||||
|
ft.input.onclick = () => {
|
||||||
|
ft.input.checked = true;
|
||||||
|
this.checkSource();
|
||||||
|
};
|
||||||
|
frag.appendChild(label);
|
||||||
|
this._tabs.push(ft);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
this._container.replaceChildren(frag);
|
||||||
|
this.selected = this._tabs[0].tab.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSource = () => {
|
||||||
|
for (let tab of this._tabs) {
|
||||||
|
if (tab.input.checked) {
|
||||||
|
this._selected = tab.tab.name;
|
||||||
|
tab.tab.content.classList.remove("unfocused");
|
||||||
|
tab.button.classList.add("@high");
|
||||||
|
tab.button.classList.remove("@low");
|
||||||
|
if (tab.tab.onShow) tab.tab.onShow();
|
||||||
|
} else {
|
||||||
|
tab.tab.content.classList.add("unfocused");
|
||||||
|
tab.button.classList.add("@low");
|
||||||
|
tab.button.classList.remove("@high");
|
||||||
|
if (tab.tab.onHide) tab.tab.onHide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
get selected(): string { return this._selected; }
|
||||||
|
set selected(name: string) {
|
||||||
|
for (let tab of this._tabs) {
|
||||||
|
if (tab.tab.name == name) {
|
||||||
|
this._selected = tab.tab.name;
|
||||||
|
tab.input.checked = true;
|
||||||
|
tab.tab.content.classList.remove("unfocused");
|
||||||
|
tab.button.classList.add("@high");
|
||||||
|
tab.button.classList.remove("@low");
|
||||||
|
if (tab.tab.onShow) tab.tab.onShow();
|
||||||
|
} else {
|
||||||
|
tab.input.checked = false;
|
||||||
|
tab.tab.content.classList.add("unfocused");
|
||||||
|
tab.button.classList.add("@low");
|
||||||
|
tab.button.classList.remove("@high");
|
||||||
|
if (tab.tab.onHide) tab.tab.onHide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user