mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
implement new filter to services page
This commit is contained in:
parent
75bf0a99a1
commit
bf7017d256
3 changed files with 93 additions and 360 deletions
|
|
@ -8,6 +8,10 @@ import {
|
|||
SettingsAdvanced,
|
||||
} from "./utils/settings.js";
|
||||
|
||||
import {
|
||||
Filter
|
||||
} from "./utils/dashboard.js";
|
||||
|
||||
class SettingsService {
|
||||
constructor() {
|
||||
this.prefix = "services";
|
||||
|
|
@ -549,130 +553,8 @@ class Dropdown {
|
|||
}
|
||||
}
|
||||
|
||||
class Filter {
|
||||
constructor(prefix = "services") {
|
||||
this.prefix = prefix;
|
||||
this.container =
|
||||
document.querySelector(`[data-${this.prefix}-filter]`) || null;
|
||||
this.keyInp = document.querySelector("input#service-name-keyword");
|
||||
this.stateValue = "all";
|
||||
this.methodValue = "all";
|
||||
this.initHandler();
|
||||
}
|
||||
|
||||
initHandler() {
|
||||
if (!this.container) return;
|
||||
//STATE HANDLER
|
||||
this.container.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"state"
|
||||
) {
|
||||
setTimeout(() => {
|
||||
const value = document
|
||||
.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text="state"]`,
|
||||
)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
|
||||
this.stateValue = value;
|
||||
//run filter
|
||||
this.filter();
|
||||
}, 10);
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
//METHOD HANDLER
|
||||
this.container.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"method"
|
||||
) {
|
||||
setTimeout(() => {
|
||||
const value = document
|
||||
.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text="method"]`,
|
||||
)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
|
||||
this.methodValue = value;
|
||||
//run filter
|
||||
this.filter();
|
||||
}, 10);
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
//KEYWORD HANDLER
|
||||
this.keyInp.addEventListener("input", (e) => {
|
||||
this.filter();
|
||||
});
|
||||
}
|
||||
|
||||
filter() {
|
||||
const services = document.querySelectorAll(`[data-${this.prefix}-card]`);
|
||||
if (services.length === 0) return;
|
||||
//reset
|
||||
for (let i = 0; i < services.length; i++) {
|
||||
const el = services[i];
|
||||
el.classList.remove("hidden");
|
||||
}
|
||||
//filter type
|
||||
this.setFilterState(services);
|
||||
this.setFilterMethod(services);
|
||||
this.setFilterKeyword(services);
|
||||
}
|
||||
|
||||
setFilterState(services) {
|
||||
if (this.stateValue === "all") return;
|
||||
for (let i = 0; i < services.length; i++) {
|
||||
const el = services[i];
|
||||
const type = el
|
||||
.querySelector(`[data-${this.prefix}-state]`)
|
||||
.getAttribute(`data-${this.prefix}-state`)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (type !== this.stateValue) el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
setFilterMethod(services) {
|
||||
if (this.methodValue === "all") return;
|
||||
for (let i = 0; i < services.length; i++) {
|
||||
const el = services[i];
|
||||
const type = el
|
||||
.querySelector(`[data-${this.prefix}-method]`)
|
||||
.getAttribute(`data-${this.prefix}-method`)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (type !== this.methodValue) el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
setFilterKeyword(jobs) {
|
||||
const keyword = this.keyInp.value.trim().toLowerCase();
|
||||
if (!keyword) return;
|
||||
for (let i = 0; i < jobs.length; i++) {
|
||||
const el = jobs[i];
|
||||
const name = el
|
||||
.querySelector(`[data-${this.prefix}-name]`)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
|
||||
if (!name.includes(keyword)) el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const setDropdown = new Dropdown();
|
||||
const setFilter = new Filter();
|
||||
const setTabsSelect = new TabsSelect(
|
||||
document.querySelector("[data-services-tabs-select]"),
|
||||
document.querySelector("[data-advanced][data-services-modal-form]"),
|
||||
|
|
@ -713,22 +595,33 @@ const checkServiceModalSelect = new CheckNoMatchFilter(
|
|||
document.querySelector("[data-services-nomatch]"),
|
||||
);
|
||||
|
||||
try {
|
||||
const checkServiceCardKeyword = new CheckNoMatchFilter(
|
||||
document.querySelectorAll("input#service-name-keyword"),
|
||||
"input",
|
||||
document.querySelectorAll("[data-services-card]"),
|
||||
false,
|
||||
document.querySelector("[data-services-nomatch-card]"),
|
||||
);
|
||||
|
||||
const checkServiceCardSelect = new CheckNoMatchFilter(
|
||||
document.querySelectorAll(
|
||||
"button[data-services-setting-select-dropdown-btn]",
|
||||
),
|
||||
"select",
|
||||
document.querySelectorAll("[data-services-card]"),
|
||||
false,
|
||||
document.querySelector("[data-services-nomatch-card]"),
|
||||
);
|
||||
} catch (e) {}
|
||||
const filterContainer = document.querySelector(`[data-services-filter]`);
|
||||
if(filterContainer) {
|
||||
const noMatchEl = document.querySelector("[data-services-nomatch-card]");
|
||||
const filterEls = document.querySelectorAll(`[data-services-card]`);
|
||||
const keywordFilter = {
|
||||
"handler": document.querySelector("input#service-name-keyword"),
|
||||
"handlerType" : "input",
|
||||
"value" : document.querySelector("input#service-name-keyword").value,
|
||||
"filterEls": filterEls,
|
||||
"filterAtt" : "data-services-name",
|
||||
"filterType" : "keyword",
|
||||
};
|
||||
const methodFilter = {
|
||||
"handler": document.querySelector("[data-services-setting-select-dropdown='method']"),
|
||||
"handlerType" : "select",
|
||||
"value" : document.querySelector("[data-services-setting-select-text='method']").textContent.trim().toLowerCase(),
|
||||
"filterEls": filterEls,
|
||||
"filterAtt" : "data-services-method",
|
||||
"filterType" : "match",
|
||||
};
|
||||
const stateFilter = {
|
||||
"handler": document.querySelector("[data-services-setting-select-dropdown='state']"),
|
||||
"handlerType" : "select",
|
||||
"value" : document.querySelector("[data-services-setting-select-text='state']").textContent.trim().toLowerCase(),
|
||||
"filterEls": filterEls,
|
||||
"filterAtt" : "data-services-state",
|
||||
"filterType" : "match",
|
||||
};
|
||||
new Filter("services", [keywordFilter, methodFilter, stateFilter], null, noMatchEl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// noMatchEl : if exists, will be displayed when no match is found
|
||||
// containerEl : container of the filter elements, case noMatchEl exists, it will be hidden when no match is found
|
||||
class Filter {
|
||||
constructor(prefix, filters, containerEl, noMatchEl) {
|
||||
constructor(prefix, filters, containerEl = null, noMatchEl = null) {
|
||||
this.prefix = prefix;
|
||||
this.filters = filters;
|
||||
this.containerEl = containerEl;
|
||||
|
|
@ -38,11 +38,9 @@ init() {
|
|||
setSelectHandler(handler) {
|
||||
handler.addEventListener("click", (e) => {
|
||||
try {
|
||||
const handlerName = handler.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`);
|
||||
const value = document
|
||||
.querySelector(`[data-${this.prefix}-setting-select-text="${handlerName}"]`)
|
||||
.textContent.trim();
|
||||
this.updateValue(handlerName, value);
|
||||
if(!e.target.closest("button").hasAttribute('data-services-setting-select-dropdown-btn')) return;
|
||||
const value = e.target.closest("button").getAttribute('value');
|
||||
this.updateValue(handler, value);
|
||||
this.filter();
|
||||
|
||||
} catch(err) {}
|
||||
|
|
@ -79,56 +77,53 @@ resetFilter() {
|
|||
});
|
||||
|
||||
if(this.noMatchEl) this.noMatchEl.classList.add("hidden");
|
||||
|
||||
this.containerEl.classList.remove("hidden");
|
||||
if(this.containerEl)this.containerEl.classList.remove("hidden");
|
||||
}
|
||||
|
||||
filter() {
|
||||
// Start by resetting the filter
|
||||
this.resetFilter();
|
||||
// Then apply all filters
|
||||
let isAtLeastOneMatch = false;
|
||||
|
||||
this.filters.forEach((filter) => {
|
||||
const [filterType, value, filterEls, filterAtt] = this.getFilterData(filter);
|
||||
|
||||
// keyword filter means that el filter value must contains the keyword
|
||||
if(filterType === "keyword") {
|
||||
isAtLeastOneMatch = this.filterKeyword(value, filterEls, filterAtt) ? true : isAtLeastOneMatch;
|
||||
this.filterKeyword(value, filterEls, filterAtt);
|
||||
}
|
||||
// match filter means that el filter value must be equal to the filter value
|
||||
if(filterType === "match") {
|
||||
isAtLeastOneMatch = this.filterMatch(value, filterEls, filterAtt) ? true : isAtLeastOneMatch;
|
||||
this.filterMatch(value, filterEls, filterAtt);
|
||||
}
|
||||
// bool filter means that el filter value must be equal to bool value
|
||||
if(filterType === "bool") {
|
||||
isAtLeastOneMatch = this.filterBool(value, filterEls, filterAtt) ? true : isAtLeastOneMatch;
|
||||
this.filterBool(value, filterEls, filterAtt);
|
||||
}
|
||||
// lower than filter means that el filter value must be lower than the filter value
|
||||
if(filterType === "lowerThan") {
|
||||
isAtLeastOneMatch = this.filterLowerThan(value, filterEls, filterAtt) ? true : isAtLeastOneMatch;
|
||||
this.filterLowerThan(value, filterEls, filterAtt);
|
||||
}
|
||||
// higher than filter means that el filter value must be higher than the filter value
|
||||
if(filterType === "higherThan") {
|
||||
isAtLeastOneMatch = this.filterHigherThan(value, filterEls, filterAtt) ? true : isAtLeastOneMatch;
|
||||
this.filterHigherThan(value, filterEls, filterAtt);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// If no match is found, hide the container and display the no match element
|
||||
if(!isAtLeastOneMatch) {
|
||||
this.containerEl.classList.add("hidden");
|
||||
if(this.noMatchEl) this.noMatchEl.classList.remove("hidden");
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if(!this.isAtLeastOneMatch()) {
|
||||
if(this.containerEl) this.containerEl.classList.add("hidden");
|
||||
if(this.noMatchEl) this.noMatchEl.classList.remove("hidden");
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
|
||||
filterKeyword(value, filterEls, filterAtt) {
|
||||
let isAtLeastOneMatch = false;
|
||||
|
||||
const keyword = value.trim().toLowerCase();
|
||||
if (!keyword) return false;
|
||||
|
||||
if (!keyword) return;
|
||||
|
||||
for (let i = 0; i < filterEls.length; i++) {
|
||||
const el = filterEls[i];
|
||||
|
|
@ -137,17 +132,13 @@ filterKeyword(value, filterEls, filterAtt) {
|
|||
el.classList.add("hidden");
|
||||
continue;
|
||||
}
|
||||
isAtLeastOneMatch = true;
|
||||
}
|
||||
|
||||
return isAtLeastOneMatch;
|
||||
return;
|
||||
}
|
||||
|
||||
filterMatch(value, filterEls, filterAtt) {
|
||||
|
||||
if(!value || value === "all") return false;
|
||||
|
||||
let isAtLeastOneMatch = false;
|
||||
if(!value || value === "all") return;
|
||||
|
||||
for (let i = 0; i < filterEls.length; i++) {
|
||||
const el = filterEls[i];
|
||||
|
|
@ -156,18 +147,15 @@ filterMatch(value, filterEls, filterAtt) {
|
|||
el.classList.add("hidden");
|
||||
continue;
|
||||
}
|
||||
isAtLeastOneMatch = true;
|
||||
}
|
||||
|
||||
return isAtLeastOneMatch;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
filterBool(value, filterEls, filterAtt) {
|
||||
// Check if value is undefined or null
|
||||
if(value === undefined || value === null) return false;
|
||||
|
||||
let isAtLeastOneMatch = false;
|
||||
if(value === undefined || value === null) return;
|
||||
|
||||
for (let i = 0; i < filterEls.length; i++) {
|
||||
const el = filterEls[i];
|
||||
|
|
@ -176,7 +164,6 @@ filterBool(value, filterEls, filterAtt) {
|
|||
const isValueTruthy = truthyValues.includes(elValue);
|
||||
|
||||
if(value && isValueTruthy || !value && !isValueTruthy) {
|
||||
isAtLeastOneMatch = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -184,14 +171,13 @@ filterBool(value, filterEls, filterAtt) {
|
|||
|
||||
}
|
||||
|
||||
return isAtLeastOneMatch;
|
||||
return ;
|
||||
}
|
||||
|
||||
filterLowerThan(value, filterEls, filterAtt) {
|
||||
// Check if value is undefined or null
|
||||
if(!value) return false;
|
||||
if(!value) return;
|
||||
|
||||
let isAtLeastOneMatch = false;
|
||||
|
||||
for (let i = 0; i < filterEls.length; i++) {
|
||||
const el = filterEls[i];
|
||||
|
|
@ -208,18 +194,14 @@ filterLowerThan(value, filterEls, filterAtt) {
|
|||
el.classList.add("hidden");
|
||||
continue;
|
||||
}
|
||||
|
||||
isAtLeastOneMatch = true;
|
||||
|
||||
}
|
||||
return isAtLeastOneMatch;
|
||||
return;
|
||||
}
|
||||
|
||||
filterHigherThan(value, filterEls, filterAtt) {
|
||||
// Check if value is undefined or null
|
||||
if(!value) return false;
|
||||
|
||||
let isAtLeastOneMatch = false;
|
||||
if(!value) return;
|
||||
|
||||
for (let i = 0; i < filterEls.length; i++) {
|
||||
const el = filterEls[i];
|
||||
|
|
@ -237,10 +219,27 @@ filterLowerThan(value, filterEls, filterAtt) {
|
|||
continue;
|
||||
}
|
||||
|
||||
isAtLeastOneMatch = true;
|
||||
|
||||
}
|
||||
return isAtLeastOneMatch;
|
||||
return;
|
||||
}
|
||||
|
||||
isAtLeastOneMatch() {
|
||||
// loop on each filterEls and check if at least one is not hidden
|
||||
let isOneMatch = false;
|
||||
for(let i = 0; i < this.filters.length; i++) {
|
||||
const filter = this.filters[i];
|
||||
const filterEls = filter.filterEls;
|
||||
filterEls.forEach((el) => {
|
||||
if(!el.classList.contains("hidden")) {
|
||||
isOneMatch = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
if(isOneMatch) break;
|
||||
}
|
||||
|
||||
return isOneMatch;
|
||||
}
|
||||
|
||||
updateValue(handler, value) {
|
||||
|
|
@ -255,182 +254,20 @@ filterLowerThan(value, filterEls, filterAtt) {
|
|||
}
|
||||
|
||||
getFilterElValue(el, filterAtt) {
|
||||
return filterAtt === "textContent" ? el.textContent.trim().toLowerCase() : el.getAttribute(`data-${this.prefix}-${filterAtt}`).trim().toLowerCase();
|
||||
return filterAtt === "textContent" ? el.textContent.trim().toLowerCase() : el.getAttribute(filterAtt).trim().toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Dropdown {
|
||||
constructor(prefix = "bans") {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector("main");
|
||||
this.lastDrop = "";
|
||||
this.initDropdown();
|
||||
}
|
||||
|
||||
initDropdown() {
|
||||
this.container.addEventListener("click", (e) => {
|
||||
//SELECT BTN LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-setting-select`) &&
|
||||
!e.target.closest("button").hasAttribute(`disabled`)
|
||||
) {
|
||||
const btnName = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
if (this.lastDrop !== btnName) {
|
||||
this.lastDrop = btnName;
|
||||
this.closeAllDrop();
|
||||
}
|
||||
|
||||
this.toggleSelectBtn(e);
|
||||
}
|
||||
} catch (err) {}
|
||||
//SELECT DROPDOWN BTN LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-setting-select-dropdown-btn`)
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
const btnSetting = btn.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown-btn`,
|
||||
);
|
||||
//stop if same value to avoid new fetching
|
||||
const isSameVal = this.isSameValue(btnSetting, btnValue);
|
||||
if (isSameVal) return this.hideDropdown(btnSetting);
|
||||
//else, add new value to custom
|
||||
this.setSelectNewValue(btnSetting, btnValue);
|
||||
//close dropdown and change style
|
||||
this.hideDropdown(btnSetting);
|
||||
|
||||
if (
|
||||
!e.target.closest("button").hasAttribute(`data-${this.prefix}-file`)
|
||||
) {
|
||||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
}
|
||||
//show / hide filter
|
||||
if (btnSetting === "instances") {
|
||||
this.hideFilterOnLocal(btn.getAttribute("data-_type"));
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
}
|
||||
|
||||
closeAllDrop() {
|
||||
const drops = document.querySelectorAll(
|
||||
`[data-${this.prefix}-setting-select-dropdown]`,
|
||||
);
|
||||
drops.forEach((drop) => {
|
||||
drop.classList.add("hidden");
|
||||
drop.classList.remove("flex");
|
||||
document
|
||||
.querySelector(
|
||||
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown`,
|
||||
)}"]`,
|
||||
)
|
||||
.classList.remove("rotate-180");
|
||||
});
|
||||
}
|
||||
|
||||
isSameValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`,
|
||||
);
|
||||
const currVal = selectCustom.textContent;
|
||||
return currVal === value ? true : false;
|
||||
}
|
||||
|
||||
setSelectNewValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select="${btnSetting}"]`,
|
||||
);
|
||||
selectCustom.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text]`,
|
||||
).textContent = value;
|
||||
}
|
||||
|
||||
hideDropdown(btnSetting) {
|
||||
//hide dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
|
||||
);
|
||||
dropdownEl.classList.add("hidden");
|
||||
dropdownEl.classList.remove("flex");
|
||||
//svg effect
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`,
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
}
|
||||
|
||||
changeDropBtnStyle(btnSetting, selectedBtn) {
|
||||
const dropdownEl = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
|
||||
);
|
||||
//reset dropdown btns
|
||||
const btnEls = dropdownEl.querySelectorAll("button");
|
||||
|
||||
btnEls.forEach((btn) => {
|
||||
btn.classList.remove(
|
||||
"bg-primary",
|
||||
"dark:bg-primary",
|
||||
"text-gray-300",
|
||||
"text-gray-300",
|
||||
);
|
||||
btn.classList.add("bg-white", "dark:bg-slate-700", "text-gray-700");
|
||||
});
|
||||
//highlight clicked btn
|
||||
selectedBtn.classList.remove(
|
||||
"bg-white",
|
||||
"dark:bg-slate-700",
|
||||
"text-gray-700",
|
||||
);
|
||||
selectedBtn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
|
||||
}
|
||||
|
||||
toggleSelectBtn(e) {
|
||||
const attribute = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
//toggle dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-dropdown="${attribute}"]`,
|
||||
);
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[data-${this.prefix}-setting-select="${attribute}"]`,
|
||||
);
|
||||
dropdownEl.classList.toggle("hidden");
|
||||
dropdownEl.classList.toggle("flex");
|
||||
dropdownChevron.classList.toggle("rotate-180");
|
||||
}
|
||||
|
||||
//hide date filter on local
|
||||
hideFilterOnLocal(type) {
|
||||
if (type === "local") {
|
||||
this.hideInp(`input#from-date`);
|
||||
this.hideInp(`input#to-date`);
|
||||
constructor()
|
||||
{
|
||||
this.init();
|
||||
}
|
||||
|
||||
if (type !== "local") {
|
||||
this.showInp(`input#from-date`);
|
||||
this.showInp(`input#to-date`);
|
||||
init(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
showInp(selector) {
|
||||
document.querySelector(selector).closest("div").classList.add("flex");
|
||||
document.querySelector(selector).closest("div").classList.remove("hidden");
|
||||
}
|
||||
|
||||
hideInp(selector) {
|
||||
document.querySelector(selector).closest("div").classList.add("hidden");
|
||||
document.querySelector(selector).closest("div").classList.remove("flex");
|
||||
}
|
||||
}
|
||||
export { Filter, Dropdown };
|
||||
9
src/ui/templates/services.html
vendored
9
src/ui/templates/services.html
vendored
|
|
@ -106,7 +106,10 @@
|
|||
{% for service in services %}
|
||||
{% set id_server_name = service["SERVER_NAME"]['value'].replace(".", "-") %}
|
||||
<div data-{{attribute_name}}-card
|
||||
data-settings="{{ service['settings'] }}"
|
||||
data-{{attribute_name}}-name="{{ service["SERVER_NAME"]['value'] }}"
|
||||
data-{{attribute_name}}-method="{{ service["SERVER_NAME"]['method'] }}"
|
||||
data-{{attribute_name}}-state="{{ "draft" if service.get('IS_DRAFT', "no") == "yes" else "online" }}"
|
||||
data-settings="{{ service['settings'] }}"
|
||||
|
||||
data-{{attribute_name}}-service="{{ service['SERVER_NAME']['value'] }}"
|
||||
class="flex flex-col justify-between dark:brightness-110 overflow-hidden hover:scale-102 transition col-span-12 lg:col-span-6 3xl:col-span-4 p-4 w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
|
|
@ -121,11 +124,11 @@
|
|||
data-value="{{ service['SERVER_NAME']['method'] }}"></div>
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="flex flex-col">
|
||||
<h5 data-{{attribute_name}}-name="{{ service["SERVER_NAME"]['value'] }}"
|
||||
<h5
|
||||
class="break-all transition duration-300 ease-in-out text-center sm:text-left mb-1 mr-2 font-bold dark:text-white/90">
|
||||
{{ service["SERVER_NAME"]['value'] }}
|
||||
</h5>
|
||||
<h6 data-{{attribute_name}}-method="{{ service["SERVER_NAME"]['method'] }}"
|
||||
<h6
|
||||
class="text-left sm:mb-2 font-semibold text-gray-600 dark:text-white/80">
|
||||
{{ service["SERVER_NAME"]['method'] }}
|
||||
</h6>
|
||||
|
|
|
|||
Loading…
Reference in a new issue