1st commit
This commit is contained in:
170
wco/adminskull/adminskull.js
Normal file
170
wco/adminskull/adminskull.js
Normal file
@@ -0,0 +1,170 @@
|
||||
var apx = apx || {};
|
||||
apx.adminskull = {};
|
||||
|
||||
apx.adminskull.show = (id) => {
|
||||
document.getElementById("maincontent").innerHTML = `Contenu du wco ${id}`;
|
||||
};
|
||||
apx.adminskull.genereimg = (alias, size = 100) => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
// Couleur de fond basée sur les lettres du nom
|
||||
const colors = apx.data.tpldata.headnav.colorslist;
|
||||
const charCodeSum = alias
|
||||
.split("")
|
||||
.reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
||||
const backgroundColor = colors[charCodeSum % colors.length];
|
||||
context.fillStyle = backgroundColor;
|
||||
context.fillRect(0, 0, size, size);
|
||||
// first and last letter in uppercase
|
||||
const initials =
|
||||
alias.charAt(0).toUpperCase() +
|
||||
alias.charAt(alias.length - 1).toUpperCase();
|
||||
context.font = `${size / 2}px Arial`;
|
||||
context.fillStyle = "#FFFFFF"; // Couleur du texte
|
||||
context.textAlign = "center";
|
||||
context.textBaseline = "middle";
|
||||
context.fillText(initials, size / 2, size / 2);
|
||||
return canvas.toDataURL();
|
||||
};
|
||||
apx.adminskull.togglesidebarmobile = (eltbtn) => {
|
||||
//for mobile need to manage hidden case with other button in headnav
|
||||
sidebar=document.getElementById("sidebar");
|
||||
sidebar.classList.toggle('w-0');
|
||||
sidebar.classList.toggle('w-full'); // Affiche la sidebar sur toute la largeur
|
||||
sidebar.classList.toggle('-translate-x-full');
|
||||
if (sidebar.classList.contains('w-full')){
|
||||
|
||||
sidebar.classList.remove('hidden');
|
||||
}else{
|
||||
sidebar.classList.add('hidden');
|
||||
}
|
||||
};
|
||||
apx.adminskull.toggleheadnav = (icon) => {
|
||||
document
|
||||
.querySelectorAll(`.dropdown`)
|
||||
.forEach((el) => el.classList.add("hidden"));
|
||||
document.querySelector(`.dropdown.${icon}`).classList.remove("hidden");
|
||||
};
|
||||
apx.adminskull.globalevent = () => {
|
||||
// add here any
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
document
|
||||
.querySelectorAll("#headnav .dropdown")
|
||||
.forEach((elt) => elt.classList.add("hidden"));
|
||||
}
|
||||
});
|
||||
document.addEventListener("click", (e) => {
|
||||
//sidebar open close summary details
|
||||
if (e.target.tagName.toLowerCase() === "summary") {
|
||||
document.querySelectorAll("#sidebar ul details").forEach((details) => {
|
||||
if (details !== e.target.parentNode) {
|
||||
details.removeAttribute("open");
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!document.getElementById("headnav").contains(e.target)) {
|
||||
//if click somewhere else than headnav we close all dropdown that are eventually not hidden
|
||||
document
|
||||
.querySelectorAll("#headnav .dropdown")
|
||||
.forEach((elt) => elt.classList.add("hidden"));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
apx.adminskull.navigation = () => {
|
||||
// test si authentification is valid
|
||||
// genere les menu en fonction du contexte
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
sidebar.querySelectorAll("ul").forEach((e) => e.remove());
|
||||
sidebar.innerHTML =
|
||||
sidebar.innerHTML +
|
||||
Mustache.render(
|
||||
apx.data.tpl.adminskullverticalnav,
|
||||
apx.data.tpldata.verticalnav
|
||||
);
|
||||
const headnav = document.getElementById("headnav");
|
||||
const datapagan = { alias: apx.data.headers.xalias };
|
||||
/* for testing */
|
||||
apx.data.itms.notifications = {
|
||||
1: {
|
||||
id: "1",
|
||||
text: "notif 1",
|
||||
from: "apxtri script toto.py",
|
||||
date: "20250101",
|
||||
},
|
||||
2: {
|
||||
id: "2",
|
||||
text: "notif 2",
|
||||
from: "apxtri script toto.py",
|
||||
date: "20250101",
|
||||
},
|
||||
3: {
|
||||
id: "3",
|
||||
text: "notif 3",
|
||||
from: "apxtri script toto.py",
|
||||
date: "20250101",
|
||||
},
|
||||
};
|
||||
|
||||
if (
|
||||
apx.data.itms.notifications &&
|
||||
Object.keys(apx.data.itms.notifications).length > 0
|
||||
) {
|
||||
const notifarray = Object.values(apx.data.itms.notifications);
|
||||
datapagan.numbernotif = notifarray.length;
|
||||
datapagan.notif = notifarray
|
||||
.sort((a, b) => b.date.localeCompare(a.date))
|
||||
.slice(0, 5);
|
||||
datapagan.notifcolor = "green";
|
||||
}
|
||||
if (
|
||||
apx.data.itms.messages &&
|
||||
Object.keys(apx.data.itms.messages).length > 0
|
||||
) {
|
||||
const msgarray = Object.values(apx.data.itms.messages);
|
||||
datapagan.numbermsg = msgarray.length;
|
||||
datapagan.msg = msgarray
|
||||
.sort((a, b) => b.date.localeCompare(a.date))
|
||||
.slice(0, 3);
|
||||
datapagan.msgcolor = "green";
|
||||
}
|
||||
datapagan.aliasimg = apx.adminskull.genereimg(datapagan.alias);
|
||||
headnav.innerHTML = Mustache.render(
|
||||
apx.data.tpl.adminskullheadnav,
|
||||
datapagan
|
||||
);
|
||||
apx.adminskull.globalevent();
|
||||
};
|
||||
|
||||
apx.adminskull.search=(element)=>{
|
||||
const input=element.previousElementSibling
|
||||
if (!input || input.tagName !== 'INPUT'){
|
||||
console.log("Check your component no input avaiilable close to this button")
|
||||
return;
|
||||
}
|
||||
document.getElementById("searchtitle").innerHTML+=" "+input.value
|
||||
// analyse search string + - to convert in json search object with common rules to follow to send some action search in an object
|
||||
const searchjson={searchtxt:input.value}
|
||||
|
||||
if (!apx.data.searchfunction || !apx[apx.data.searchfunction]){
|
||||
console.log("ERROR: your settings is not correct to use search in your project you must define in apxtri the propertie searchfunction with a value and you must have a function in your project apx[apxtri.searchfunction](search) that return search with in search.results=[{thumbnail,titile,description,..}]")
|
||||
return;
|
||||
}
|
||||
|
||||
const result = apx[apx.data.searchfunction](searchjson);
|
||||
result.results.forEach(r=>{
|
||||
if (!r.thumbnail || r.thumbnail=="") {
|
||||
r.thumbnail=apx.adminskull.genereimg(r.title,200)
|
||||
}
|
||||
})
|
||||
document.getElementById("searchresults").innerHTML=Mustache.render(apx.data.tpl.adminskullresult,result)
|
||||
|
||||
document.getElementById("maincontent").classList.add('hidden')
|
||||
document.getElementById("searchcontent").classList.remove('hidden')
|
||||
}
|
||||
|
||||
apx.readyafterupdate(apx.adminskull.navigation);
|
26
wco/adminskull/headnav_fr.json
Normal file
26
wco/adminskull/headnav_fr.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"colorslist": [
|
||||
"#ffc332",
|
||||
"#fa6a31",
|
||||
"#2e7fc8",
|
||||
"#6aa84f",
|
||||
"#218787",
|
||||
"#ffd966",
|
||||
"#fb8c5a",
|
||||
"#1c5a8a",
|
||||
"#4a7c3a",
|
||||
"#1a6d6d",
|
||||
"#e6b800",
|
||||
"#d9531e",
|
||||
"#5fa8d3",
|
||||
"#8fbf4d",
|
||||
"#2d9d9d",
|
||||
"#cca300",
|
||||
"#ff8c69",
|
||||
"#1a3d5c",
|
||||
"#5c7c3a",
|
||||
"#4db3b3"
|
||||
],
|
||||
"notifplus": "En voir plus",
|
||||
"msgplus": "Voir tous..."
|
||||
}
|
93
wco/adminskull/headnav_fr.mustache
Normal file
93
wco/adminskull/headnav_fr.mustache
Normal file
@@ -0,0 +1,93 @@
|
||||
|
||||
<!-- Menu Button -->
|
||||
<div class="flex items-center space-x-4">
|
||||
<button class="text-gray-500 hover:text-gray-700 focus:outline-none" onclick="apx.adminskull.togglesidebarmobile(this)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Search Bar -->
|
||||
<div class="relative">
|
||||
<input type="text" class="bg-gray-100 rounded-full pl-10 pr-10 py-2 text-sm text-black focus:outline-none" placeholder="Rechercher...">
|
||||
<!-- Icône de loupe cliquable à droite -->
|
||||
<button onclick="apx.adminskull.search(this);" class="absolute inset-y-0 right-0 pr-3 flex items-center">
|
||||
<svg class="h-5 w-5 text-black-400 hover:text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: Icons and Profile -->
|
||||
<div class="flex items-center space-x-6">
|
||||
|
||||
<!-- Notification Icon -->
|
||||
{{#notifnumber}}
|
||||
<div class="relative">
|
||||
<button class="relative text-gray-700 hover:text-gray-900 focus:outline-none" onclick="apx.adminskull.toggleheadnav('notifications')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405C18.79 14.79 19 13.895 19 13V10c0-3.866-3.134-7-7-7S5 6.134 5 10v3c0 .895.21 1.79.595 2.595L4 17h5m6 0v2a2 2 0 11-4 0v-2m4 0H9" />
|
||||
</svg>
|
||||
<span class="absolute top-0 right-0 inline-block w-3 h-3 bg-{{notifcolor}}-500 rounded-full text-white text-xs text-center">{{{notifnumber}}}</span>
|
||||
</button>
|
||||
<!-- Dropdown Menu -->
|
||||
<div class="dropdown notifications hidden absolute left-0 mt-2 w-48 bg-white rounded-lg shadow-lg z-50">
|
||||
<ul class="py-2">
|
||||
{{#notif}}
|
||||
<li>
|
||||
<a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">{{text}}<br>{{from}} -- {{date}}</a>
|
||||
</li>
|
||||
{{/notif}}
|
||||
<li><a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">En voir plus...</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/notifnumber}}
|
||||
<!-- Message Icon -->
|
||||
{{#msgnumber}}
|
||||
<div class="relative">
|
||||
<button class="text-gray-700 hover:text-gray-900 focus:outline-none" onclick="apx.adminskull.toggleheadnav('messages')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h8m-8 4h8M5 21l3.386-2.258A8.976 8.976 0 0112 19c4.971 0 9-3.806 9-8.5S16.971 2 12 2 3 5.806 3 10.5c0 1.771.651 3.411 1.748 4.742L5 21z" />
|
||||
</svg>
|
||||
<span class="absolute top-0 right-0 inline-block w-3 h-3 bg-{{msgcolor}}-500 rounded-full text-white text-xs text-center">{{{msgnumber}}}</span>
|
||||
</button>
|
||||
<!-- Dropdown Menu -->
|
||||
<div class="dropdown messages hidden absolute left-0 mt-2 w-48 bg-white rounded-lg shadow-lg z-50">
|
||||
<ul class="py-2">
|
||||
{{#msg}}
|
||||
<li><a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">{{{text}}}<br>{{from}} -- {{date}}</a></li>
|
||||
{{/msg}}
|
||||
<li><a href="#" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">Voir les discussions</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{/msgnumber}}
|
||||
<!-- Language Icon -->
|
||||
<div class="relative">
|
||||
<button class="text-gray-700 hover:text-gray-900 focus:outline-none" onclick="apx.adminskull.toggleheadnav('language')">
|
||||
<span class="inline-block text-sm">🇬🇧</span>
|
||||
</button>
|
||||
<!-- Dropdown Menu -->
|
||||
<div class="dropdown language hidden absolute right-0 mt-2 w-13 bg-white rounded-lg shadow-lg z-50">
|
||||
<ul class="py-2">
|
||||
<li>
|
||||
<a href="admindata_en.html" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">
|
||||
🇬🇧
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="admindata_fr.html" class="block px-4 py-2 text-gray-700 hover:bg-gray-100">
|
||||
🇫🇷
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative flex flex-col items-center justify-center text-center">
|
||||
<!-- Profile Avatar -->
|
||||
<img src="{{{aliasimg}}}" class="rounded-full h-9 w-9" alt="{{alias}}">
|
||||
<span class="text-sm mt-2">{{alias}}</span>
|
||||
</div>
|
||||
</div>
|
0
wco/adminskull/main_fr.mustache
Normal file
0
wco/adminskull/main_fr.mustache
Normal file
16
wco/adminskull/result_fr.mustache
Normal file
16
wco/adminskull/result_fr.mustache
Normal file
@@ -0,0 +1,16 @@
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
||||
{{#results}}
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<!-- Thumbnail -->
|
||||
<figure class="w-full h-48 overflow-hidden">
|
||||
<img src="{{thumbnail}}" alt="{{title}}" class="w-full h-full object-cover" />
|
||||
</figure>
|
||||
|
||||
<!-- Contenu (titre + description) -->
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">{{title}}</h2>
|
||||
<p>{{description}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{/results}}
|
||||
</div>
|
68
wco/adminskull/verticalnav_fr.json
Normal file
68
wco/adminskull/verticalnav_fr.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"sidebarmenutop": [
|
||||
{
|
||||
"profils": [
|
||||
"pagans"
|
||||
],
|
||||
"title": "Articles",
|
||||
"onclick": "apx.adminskull.show('articles','news')",
|
||||
"submenu": [
|
||||
{
|
||||
"title": "Locaux",
|
||||
"onclick": "apx.admindata.articles.show('localnews')"
|
||||
},
|
||||
{
|
||||
"title": "Rediger",
|
||||
"onclick": "apx.admindata.articles.editor()"
|
||||
},
|
||||
{
|
||||
"title": "Mes articles",
|
||||
"onclick": "apx.admindata.articles.show('myarticles')"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"profils": [
|
||||
"pagans"
|
||||
],
|
||||
"title": "Messages",
|
||||
"submenu": [
|
||||
{
|
||||
"title": "Discussions",
|
||||
"onclick": "apx.admindata.messages.show('discussion')"
|
||||
},
|
||||
{
|
||||
"title": "Notification",
|
||||
"onclick": "apx.admindata.messages.show('notification')"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"profils": [
|
||||
"major"
|
||||
],
|
||||
"title": "Admin apxtri",
|
||||
"onclick": "apx.admindata.apxtri.show('dashboard')",
|
||||
"submenu": [
|
||||
{
|
||||
"title": "Towns",
|
||||
"onclick": "apx.admindata.apxtri.show('Town')"
|
||||
},
|
||||
{
|
||||
"title": "Tribes",
|
||||
"onclick": "apx.admindata.apxtri.show('Tribes')"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sidebarmenubottom": [
|
||||
{
|
||||
"title": "Mon profil",
|
||||
"onclick": "apx..()"
|
||||
},
|
||||
{
|
||||
"title": "Log Out",
|
||||
"onclick": "apx.admindata.logout()"
|
||||
}
|
||||
]
|
||||
}
|
25
wco/adminskull/verticalnav_fr.mustache
Normal file
25
wco/adminskull/verticalnav_fr.mustache
Normal file
@@ -0,0 +1,25 @@
|
||||
<!-- Menu Links Section -->
|
||||
<ul class="flex-1 mt-4 space-y-1 px-2 text-sm overflow-y-auto">
|
||||
{{#sidebarmenutop}}
|
||||
<li class="px-4 py-2 hover:bg-gray-700 rounded-md">
|
||||
<details>
|
||||
<summary class="cursor-pointer hover:bg-blue-600">{{title}}</summary>
|
||||
<ul class="pl-4 mt-2 space-y-2">
|
||||
{{#submenu}}
|
||||
<li class="px-4 py-2 cursor-pointer hover:bg-gray-600 rounded-md" onclick="{{{onclick}}}">
|
||||
{{title}}
|
||||
</li>
|
||||
{{/submenu}}
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
{{/sidebarmenutop}}
|
||||
</ul>
|
||||
<!-- Bottom Links Section -->
|
||||
<ul class="mb-6 px-2 text-sm">
|
||||
{{#sidebarmenubottom}}
|
||||
<li class="px-4 py-2 cursor-pointer hover:bg-gray-700 rounded-md" onclick="{{onclick}}">
|
||||
<span>{{{title}}}</span>
|
||||
</li>
|
||||
{{/sidebarmenubottom}}
|
||||
</ul>
|
Reference in New Issue
Block a user