- gestione dell'editor delle pagine (non funzionante!)
This commit is contained in:
@@ -1,11 +0,0 @@
|
|||||||
VITE_APP_ID="16"
|
|
||||||
VITE_APP_URL="https://kolibrilab.it"
|
|
||||||
VITE_MONGODB_HOST="https://www.freeplanet.app:3000"
|
|
||||||
VITE_LOGO_REG='kolibrilab-logo-full.png'
|
|
||||||
VITE_PUBLICKEY_PUSH="BNM-cEpTbPVc_ujXf3QOC8ggf7b-X44P44esfJUWqNOFq1XhWCoZJpOi71_cbXC5SnfO9HassQ6OouAYgtBA9Pw"
|
|
||||||
VITE_DEBUG="0"
|
|
||||||
VITE_VUE_APP_ISTEST=0
|
|
||||||
DIRECTORY_LOCAL=newfreeplanet
|
|
||||||
DIRECTORY_SERVER=freeplanet_serverside
|
|
||||||
SERVERDIR_WEBSITE=kolibrilab.it
|
|
||||||
SERVERPW_WEBSITE=pwdadmin@1AOK
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
VITE_APP_ID="16"
|
|
||||||
VITE_APP_URL="https://test.kolibrilab.it"
|
|
||||||
VITE_MONGODB_HOST="https://test.freeplanet.app:3001"
|
|
||||||
VITE_LOGO_REG='kolibrilab-logo-full.png'
|
|
||||||
VITE_PUBLICKEY_PUSH="BGXRf1TgcqocqD6J7qnRgCG7AvM2lxAoW7peb7UEzB4SxBb6DxGRdJ0UvD9ewnrB9KrSrh0-aDCODXBm7sZ1DDs"
|
|
||||||
VITE_DEBUG="1"
|
|
||||||
VITE_VUE_APP_ISTEST=1
|
|
||||||
DIRECTORY_LOCAL=newfreeplanet
|
|
||||||
DIRECTORY_SERVER=test.freeplanet_serverside
|
|
||||||
SERVERDIR_WEBSITE="test.kolibrilab.it"
|
|
||||||
SERVERPW_WEBSITE="pwdadmin@1AOK"
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,89 +0,0 @@
|
|||||||
import { IEvents } from '../model';
|
|
||||||
|
|
||||||
export const db_data = {
|
|
||||||
URL_FACEBOOK: 'https://www.facebook.com/associazioneshen',
|
|
||||||
|
|
||||||
userdata: {
|
|
||||||
calendar_editable: false,
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
events: [
|
|
||||||
{
|
|
||||||
title: 'Scambi Reiki',
|
|
||||||
details: 'Nelle serate esperienziali è possibile <span class="boldhigh">Dare e Ricevere</span> un trattamento completo.<br />'
|
|
||||||
+ 'Possono partecipare le persone che hanno già preso parte al <span class="boldhigh">seminario di 1° livello</span>, ma anche <span class="boldhigh">tutti quelli che hanno il desiderio di conoscere il Reiki</span> e sperimentarlo per la prima volta: in questo caso invitiamo gli interessati a contattarci per un appuntamento prima dell’inizio della serata per ricevere le informazioni pratiche.',
|
|
||||||
date: '2019-07-11',
|
|
||||||
time: '21:00',
|
|
||||||
duration: 120,
|
|
||||||
side: 'left',
|
|
||||||
bgcolor: 'orange',
|
|
||||||
icon: 'fas fa-praying-hands',
|
|
||||||
img: '/images/reiki/reikisfondo.jpg',
|
|
||||||
where: 'Centro Shen',
|
|
||||||
// whereicon: 'shen.png',
|
|
||||||
teacher: 'Cristina Barattoni',
|
|
||||||
avatar: 'cristina.png',
|
|
||||||
infoextra: '',
|
|
||||||
linkpdf: 'files/eventi/Reiki_aMICHI.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Scambi Reiki',
|
|
||||||
details: 'Nelle serate esperienziali è possibile <span class="boldhigh">Dare e Ricevere</span> un trattamento completo.<br />'
|
|
||||||
+ 'Possono partecipare le persone che hanno già preso parte al <span class="boldhigh">seminario di 1° livello</span>, ma anche <span class="boldhigh">tutti quelli che hanno il desiderio di conoscere il Reiki</span> e sperimentarlo per la prima volta: in questo caso invitiamo gli interessati a contattarci per un appuntamento prima dell’inizio della serata per ricevere le informazioni pratiche.',
|
|
||||||
date: '2019-07-20',
|
|
||||||
time: '21:00',
|
|
||||||
duration: 120,
|
|
||||||
side: 'left',
|
|
||||||
bgcolor: 'orange',
|
|
||||||
icon: 'fas fa-praying-hands',
|
|
||||||
img: '/images/reiki/reikisfondo.jpg',
|
|
||||||
where: 'Centro Shen',
|
|
||||||
// whereicon: 'shen.png',
|
|
||||||
teacher: 'Cristina Barattoni',
|
|
||||||
avatar: 'cristina.png',
|
|
||||||
infoextra: '',
|
|
||||||
linkpdf: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Seminario Reiki 1° Livello',
|
|
||||||
details: 'I seminari vengono organizzati volutamente in gruppi poco numerosi.\n'
|
|
||||||
+ 'Si crea così un ambiente accogliente e tranquillo con un atmosfera conviviale.<br />'
|
|
||||||
+ ''
|
|
||||||
+ 'Per info vedi <a href="reiki/seminari">Seminari Reiki</a>',
|
|
||||||
date: '2019-07-22',
|
|
||||||
days: 2,
|
|
||||||
time: '9:00',
|
|
||||||
side: 'left',
|
|
||||||
bgcolor: 'red',
|
|
||||||
icon: 'fas fa-chalkboard-teacher',
|
|
||||||
img: '/images/reiki/reikisfondo.jpg',
|
|
||||||
where: 'Centro Shen',
|
|
||||||
// whereicon: 'shen.png',
|
|
||||||
teacher: 'Cristina Barattoni',
|
|
||||||
avatar: 'cristina.png',
|
|
||||||
teacher2: 'Elisa Ghizzardi',
|
|
||||||
avatar2: 'elisa.png',
|
|
||||||
infoextra: 'sabato e domenica dalle 10.00 alle 18.00',
|
|
||||||
linkpdf: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Presentazione Corsi per Operatori del Massaggio del Benessere',
|
|
||||||
details: 'Vieni alla presentazione dei Corsi!<br>10 settembre a Ravenna, 17 settembre a Lugo',
|
|
||||||
date: '2019-09-10',
|
|
||||||
time: '20:30',
|
|
||||||
duration: 120,
|
|
||||||
side: 'left',
|
|
||||||
bgcolor: 'blue',
|
|
||||||
icon: 'fas fa-praying-hands',
|
|
||||||
img: '/images/scuolaopbenessere/img1.jpg',
|
|
||||||
where: 'Centro Shen',
|
|
||||||
// whereicon: 'shen.png',
|
|
||||||
teacher: 'Operatori',
|
|
||||||
avatar: 'cristina.png',
|
|
||||||
avatar2: 'elisa.png',
|
|
||||||
infoextra: '',
|
|
||||||
linkpdf: '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
@@ -1,392 +0,0 @@
|
|||||||
const msg_website = {
|
|
||||||
it: {
|
|
||||||
pages: {
|
|
||||||
home: 'Principale',
|
|
||||||
SignUp: 'Registrazione',
|
|
||||||
SignUp2: 'Registrazione2',
|
|
||||||
SignIn: 'Login',
|
|
||||||
vreg: 'Verifica Reg',
|
|
||||||
Test: 'Test',
|
|
||||||
TestLocal: 'TestLocal',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Todo: 'Todo',
|
|
||||||
personal: 'Personale',
|
|
||||||
bacheca: 'Bacheca',
|
|
||||||
shopping: 'Spesa',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
projects: 'Progetti',
|
|
||||||
favproj: 'Favoriti',
|
|
||||||
},
|
|
||||||
projall: 'Tutti',
|
|
||||||
projectsShared: 'Miei Condivisi',
|
|
||||||
myprojects: 'Miei Personali',
|
|
||||||
msg: {
|
|
||||||
hello: 'Buongiorno',
|
|
||||||
myAppName: 'FreePlanet',
|
|
||||||
myAppDescription: 'Il primo Vero Social Libero, Equo e Solidale, dove Vive Consapevolezza e Aiuto Comunitario. Gratuito e senza Pubblicità',
|
|
||||||
underconstruction: 'App in costruzione...',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: 'Il primo Vero Social',
|
|
||||||
sottoTitoloApp2: 'Libero, Equo e Solidale',
|
|
||||||
sottoTitoloApp3: 'dove Vive Consapevolezza e Aiuto Comunitario',
|
|
||||||
sottoTitoloApp4: 'Gratuito e senza Pubblicità',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
descrapp_title1: 'Uniti per Evolvere e Sperimentare',
|
|
||||||
descrapp_pag1: 'Siamo la <strong>Rete Italiana di Scambio Orizzontale</strong>, abbiamo creato questa pittaforma per metterla al servizio di chi vuole riscoprire il valore della <strong>condivisione</strong> e della <strong>cooperazione</strong>. ' +
|
|
||||||
'Valori semplici e profondi che ci aiutano a ritrovare il <strong>senso della vita</strong>, perduto in questa società consumista, e riporti quei <strong>Sani Pricìpi Naturali</strong> ed Umani di <strong>Fratellanza</strong>'
|
|
||||||
+ ' che intere popolazioni antiche conoscevano bene.',
|
|
||||||
descrapp_pag2: 'E\' giunta l\'ora di utilizzare i nuovi strumenti <strong>Tecnologici</strong> a nostro <strong>favore</strong>, per <strong>Liberarci</strong> '
|
|
||||||
+ 'così piano piano dalla <strong>schiavitù</strong> del <strong>"Lavoro per generare Denaro"</strong> e trasformando le nostre <strong>Capacitá</strong> in '
|
|
||||||
+ '<strong>Risorse Umane</strong> per poterci sostenere e vivere in <strong>Armonia</strong> con gli altri.',
|
|
||||||
freesocial: {
|
|
||||||
title: 'Free Social',
|
|
||||||
descr: 'Una Community organizzata per <strong>Categorie</strong>, dove potrai unirti a <strong>Gruppi Tematici</strong>, '
|
|
||||||
+ 'Condividere <strong>Esperienze</strong> e unire Competenze per organizzare e sostenere <strong>Progetti Innovativi</strong> per il Popolo.<br><br>'
|
|
||||||
+ 'Verranno evidenziati sviluppi <strong>Etici</strong> come l\'<strong>Auto-Produzione</strong>, la <strong>Sostenibilitá</strong>, '
|
|
||||||
+ 'la Buona <strong>Salute Naturale</strong> e il <strong>Rispetto per l\'Ambiente</strong> e per tutti gli <strong>Esseri Viventi</strong> di questo '
|
|
||||||
+ '<strong>Pianeta</strong>. Chiunque potrá esprimere il proprio <strong>Consenso o Dissenso</strong> partecipando a <strong>Sondaggi Interattivi</strong>'
|
|
||||||
+ ' e realizzare insieme i <strong>Cambiamenti</strong> necessari alla nostra Società.',
|
|
||||||
},
|
|
||||||
freetalent: {
|
|
||||||
title: 'Free Talent',
|
|
||||||
descr: 'Condividi i tuoi <strong>Talenti</strong> e <strong>Abilità</strong>, '
|
|
||||||
+ 'al posto del denaro guadagnagnerai <strong>Tempo</strong>.<br> '
|
|
||||||
+ '<strong>"1 ora"</strong> diventa moneta di scambio, uguale per tutti.<br>'
|
|
||||||
+ 'Potrai utilizzare questi tuoi <strong>"Crediti Tempo"</strong> per soddisfare le tue necessità, cercando nelle <strong>Competenze Disponibili</strong>.<br>'
|
|
||||||
+ 'Nel Dare e Ricevere, si creeranno così legami di <strong>Amicizia, Solidarietà, Cooperazione e Divertimento</strong><br><br>'
|
|
||||||
+ 'Questo progetto vuole diffondere, ora in maniera informatizzata, questa realtà che gia esiste da tanti anni, e viene chiamata <strong>"Banca del Tempo"</strong>. '
|
|
||||||
+ 'Le <strong>segreterie</strong> sparse in tutto il mondo, serviranno a dare maggiore <strong>affidabilità</strong> e <strong>fiducia</strong> negli scambi di talenti tra persone sconosciute. '
|
|
||||||
+ 'Creeremo così una <strong>rete di fiducia</strong> nel vicinato, come giá viene praticato in numerosi <strong>Ecovillaggi</strong> e Comunità del mondo.',
|
|
||||||
},
|
|
||||||
freegas: {
|
|
||||||
title: 'Free G.A.S.',
|
|
||||||
descr: 'Ti piacerebbe utilizzare una App che ti permetta facilmente di acquistare Prodotti Locali direttamente dal <strong>Produttore</strong>?<br>'
|
|
||||||
+ 'Con i <strong>Gruppi di Acquisto Solidale</strong> si evitano intermediazioni inutili, ottenendo parecchi benefici tra cui:<br>'
|
|
||||||
+ '<ul class="mylist" style="padding-left: 20px;"><li><strong>Qualitá Superiore</strong> del prodotto</li>'
|
|
||||||
+ '<li>Le <strong>Recensioni</strong> dei consumatori favoriranno i Produttori con Sani Intenti</li>'
|
|
||||||
+ '<li>Possiblità d\'interagire con il Produttore</li>'
|
|
||||||
+ '<li>Apertura alle Relazioni tra persone, condividendo <strong>Ricette</strong> e <strong>Consigli</strong> preziosi</li>'
|
|
||||||
+ '<li><strong>Risparmio</strong> di soldi (prezzi all\'Ingrosso)</li>'
|
|
||||||
+ '<li>Valorizzare il <strong>Territorio</strong> e l\'Economia <strong>Locale</strong></li>'
|
|
||||||
+ '<li>Condizioni <strong>Eque</strong> per i Lavoratori</li>'
|
|
||||||
+ '<li>Ridotto <strong>Impatto Ambientale</strong></ul>',
|
|
||||||
},
|
|
||||||
freeliving: {
|
|
||||||
title: 'Free Co-Living',
|
|
||||||
descr: 'Unire più realtà, condividendo l\'esperienza di abitare insieme, per un periodo definito:<br>'
|
|
||||||
+ '1) C\'è chi <strong>Vive solo</strong> ed ha una casa.<br>'
|
|
||||||
+ '2) Chi ha bisogno di un <strong>alloggio</strong> temporaneo.<br><br>'
|
|
||||||
+ 'Oggi sempre più persone <strong>abitano da sole</strong> e vorrebbero continuare a vivere nella propria abitazione.<br>'
|
|
||||||
+ 'Altre persone invece hanno bisogno di una <strong>stanza</strong>, per scelta o per necessita, ed in cambio sono disponibili a '
|
|
||||||
+ '<strong>contribuire alle spese</strong> per le utenze domestiche o magari <strong>aiutare</strong> la persona a <strong>fare la spesa</strong>, cucinare, <strong>pulire casa</strong> oppure offrendogli semplicemente <strong>compagnia</strong>.<br><br>'
|
|
||||||
+ 'Tramite questo strumento, le persone potranno trovarsi, mettersi in contatto e decidere in che forma <strong>co-abitare</strong> e per quanto tempo. Le <strong>recensioni</strong> rilasciate ed il <strong>dettaglio</strong> dei profili utenti, '
|
|
||||||
+ 'aiuterà nella scelta della persona più in <strong>sintonia</strong>.',
|
|
||||||
|
|
||||||
},
|
|
||||||
freecollabora: {
|
|
||||||
title: 'Chi può Collaborare?',
|
|
||||||
descr: 'Tutti coloro che sono in linea con <strong>Princìpi Etici</strong> e ricerca del <strong>Benessere Globale del Pianeta</strong><br>'
|
|
||||||
+ 'Pertanto sono i benvenuti:'
|
|
||||||
+ '<ul class="mylist" style="padding-left: 20px;">'
|
|
||||||
+ '<li><strong>Associazioni no-profit, Ecovillaggi, Comunità</strong></li>'
|
|
||||||
+ '<li>Gruppi che intendono promuovere <strong>Progetti Sociali Innovativi</strong> per una <strong>Decrescita Felice</strong></li>'
|
|
||||||
+ '<li>Chi gestisce un <strong>Gruppo di Acquisto Solidale (G.A.S.)</strong></li>'
|
|
||||||
+ '<li><strong>Produttori Locali Etici</strong></li>'
|
|
||||||
+ '<li>Chi gestisce una <strong>Banca del Tempo</strong></li>'
|
|
||||||
+ '<li><strong>Chiunque voglia partecipare</strong>, nella forma che ritiene più opportuna.</li>'
|
|
||||||
+ '</ul>',
|
|
||||||
},
|
|
||||||
freesostieni: {
|
|
||||||
title: 'Come Sostenere il progetto?',
|
|
||||||
descr: '<ul class="mylist" style="padding-left: 20px;">'
|
|
||||||
+ '<li><strong>Condividendolo</strong> a tutti coloro che vogliono far parte insieme della crescita e sviluppo di una Nuova Era</li>'
|
|
||||||
+ '<li>Rispondendo ai <strong>Sondaggi Popolari</strong> e lasciando <strong>Feedback</strong></li>'
|
|
||||||
+ '<li>Tramite una <strong>donazione</strong> (<strong>anche 1€</strong> ) per le spese.<br>'
|
|
||||||
+ '</ul>'
|
|
||||||
+ 'Vedo un <strong>futuro</strong> dove non si utilizzerà più denaro. Dove le persone si <strong>aiuteranno</strong> a vicenda e non avranno bisogno di "possedere" cose, ma le <strong>condivideranno</strong> con gli altri.<br>',
|
|
||||||
},
|
|
||||||
multiplatform: {
|
|
||||||
title: 'Multi-piattaforma',
|
|
||||||
descr: 'E\' compatibile con Google Chrome, Firefox, Safari, iOS, Android e PC. L\'Applicazione s\'installa facilmente, senza passare dallo store. '
|
|
||||||
+ 'basta condividere il nome del sito <strong>www.freeplanet.app</strong>.<br>'
|
|
||||||
+ 'Dopo la registrazione chiederà di aggiungerlo alla lista delle applicazioni e sullo sfondo',
|
|
||||||
},
|
|
||||||
free: {
|
|
||||||
title: 'Gratuita, Open Source e Niente Pubblicità',
|
|
||||||
descr: 'Questa App <strong>non è in vendita</strong>, non ha scopi commerciali, <strong>non ha prezzo</strong> ed appartiene al <strong>Popolo del Nuovo Mondo</strong>.<br>Chiunque potrá utilizzarla e beneficiarne.<br>A me il compito di gestirla e proteggerla. '
|
|
||||||
+ 'Verranno accettate solo donazioni Libere di privati ed Associazioni no-profit, in linea con i Principi, che serviranno per coprire le spese.<br>' +
|
|
||||||
+ '<strong>Grazie a Tutti per il sostegno</strong>. ',
|
|
||||||
},
|
|
||||||
contacts: 'Contatti',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
es: {
|
|
||||||
pages: {
|
|
||||||
home: 'Principal',
|
|
||||||
SignUp: 'Nueva Cuenta',
|
|
||||||
SignIn: 'Entrar',
|
|
||||||
vreg: 'Verifica Reg',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorías',
|
|
||||||
Todo: 'Tareas',
|
|
||||||
personal: 'Personal',
|
|
||||||
work: 'Trabajo',
|
|
||||||
shopping: 'Compras',
|
|
||||||
Admin: 'Administración',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
projects: 'Proyectos',
|
|
||||||
},
|
|
||||||
favproj: 'Favoritos',
|
|
||||||
projall: 'Todos',
|
|
||||||
projectsShared: 'Mis Compartidos',
|
|
||||||
myprojects: 'Mis Personales',
|
|
||||||
msg: {
|
|
||||||
hello: 'Buenos Días',
|
|
||||||
myAppName: 'FreePlanet',
|
|
||||||
myAppDescription: 'El primer Verdadero Social Libre, justo y Solidario Donde vive Conciencia y Ayuda comunitaria, Gratis y sin publicidad',
|
|
||||||
underconstruction: 'App en construcción...',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: 'El primer Verdadero Social',
|
|
||||||
sottoTitoloApp2: 'Libre, justo y Solidario',
|
|
||||||
sottoTitoloApp3: 'Donde vive Conciencia y Ayuda comunitaria',
|
|
||||||
sottoTitoloApp4: 'Gratis y sin publicidad',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
descrapp_title1: 'Unidos para evolucionar y experimentar',
|
|
||||||
descrapp_pag1: 'Redescubra cómo el valor de <strong>Compartir</strong> y <strong>Cooperación</strong> puede ayudarnos a encontrar el profundo '
|
|
||||||
+ 'sentido de la <strong>Vida</strong>, perdido en esta sociedad consumista, y mostrando esos <strong>Principios Naturales Saludables</strong> y la <strong>Hermandad Humana</strong>'
|
|
||||||
+ 'que toda la población antigua conocía bien.',
|
|
||||||
descrapp_pag2: 'Ha llegado el momento de utilizar las nuevas herramientas <strong>tecnológicas</strong> en nuestro <strong>favor</strong>, para <strong>liberarnos</strong> '
|
|
||||||
+ 'tan lentamente desde la <strong>esclavitud</strong> de <strong>"Trabaja para generar dinero"</strong> y transformando nuestra <strong>Capacidad</strong> en'
|
|
||||||
+ '<strong>Recursos humanos</strong> para poder apoyar y vivir en <strong>Armonia</strong> con otros.',
|
|
||||||
freesocial: {
|
|
||||||
title: 'Free Social',
|
|
||||||
descr: 'Una comunidad organizada por <strong>Categorías</strong>, donde puedes unirte a <strong>Grupos temáticos</strong>, '
|
|
||||||
+ 'Compartir <strong>experiencias</strong> y combinar habilidades para organizar y apoyar <strong>proyectos innovadores</strong> para la gente.<br><br>'
|
|
||||||
+ 'Los desarrollos <strong>éticos</strong> como <strong>:<br>Auto-producción</strong>, <strong>Sostenibilidad</strong>, '
|
|
||||||
+ 'la Buena <strong>Salud natural</strong> y <strong>Respeto por el Medio Ambiente</strong> y para todos los <strong>Seres vivos</strong> de este'
|
|
||||||
+ '<strong>Planeta</strong>. Cualquiera puede expresar su <strong>consentimiento o disidencia</strong> participando en <strong>Encuestas Interactivas</strong> '
|
|
||||||
+ 'y llevar a cabo juntos los <strong>Cambios</strong> necesarios para nuestra sociedad.',
|
|
||||||
},
|
|
||||||
freetalent: {
|
|
||||||
title: 'Free Talent',
|
|
||||||
descr: 'Comparte tus <strong>Talentos</strong> y <strong>Habilidades</strong>, '
|
|
||||||
+ 'en lugar de dinero, ganarás <strong>Tiempo</strong>. <br>'
|
|
||||||
+ '<strong>"1 hora"</strong> se convierte en una moneda de intercambio, igual para todos. <br>'
|
|
||||||
+ 'Puedes usar estos <strong>"Créditos de tiempo"</strong> para satisfacer tus necesidades, buscando en <strong>Habilidades disponibles</strong>. <br> '
|
|
||||||
+ 'En Dar y Recibir, crearemos así vínculos de <strong>Amistad, Solidaridad, Cooperación y Diversión</strong>. <br> <br>'
|
|
||||||
+ 'Este proyecto apunta a difundir esta realidad, que ya existe desde hace muchos años y se llama <strong>"Banco de tiempo"</strong>. '
|
|
||||||
+ 'Las <strong>secretarías</strong> dispersas por todo el mundo, servirán para dar mayor <strong>fiabilidad</strong> y <strong>confianza</strong> en el intercambio de talentos entre personas desconocidas. '
|
|
||||||
+ 'Así crearemos una <strong>red de confianza</strong> en el vecindario, como ya se practica en numerosos <strong>Ecoaldeas</strong> y en la Comunidades del mundo.',
|
|
||||||
},
|
|
||||||
freegas: {
|
|
||||||
title: 'Free G.A.S. (G.C.S.)',
|
|
||||||
descr: '¿Le gustaría usar una aplicación que le permita comprar productos locales directamente desde el <strong>Productor</strong>? <br> '
|
|
||||||
+ 'Con <strong>Grupos de Compra Solidarios</strong> evitamos intermediarios innecesarios, obteniendo muchos beneficios, incluyendo: <br>'
|
|
||||||
+ '<ul class = "mylist" style = "padding-left: 20px;"> <li> <strong>Superior Quality</strong> del producto </li>'
|
|
||||||
+ '<li> Opiniones <strong>de consumidores</strong> favorecerá a los productores con intenciones saludables </li>'
|
|
||||||
+ '<li> Posibilidad de interactuar con el Productor </li>'
|
|
||||||
+ '<li> Abierto a relaciones entre personas, compartiendo <strong>Recetas</strong> y <strong>Consejos</strong> preciosos </li>'
|
|
||||||
+ '<li> <strong>Ahorros</strong> de dinero (precios al por mayor) </li>'
|
|
||||||
+ '<li> Mejorando el <strong>Territorio</strong> y la Economía <strong>Local</strong> </li>'
|
|
||||||
+ '<li> Condiciones <strong>Justa</strong> para Trabajadores </li>'
|
|
||||||
+ '<li> Reducido <strong>Impacto Ambiental</strong> </ul>',
|
|
||||||
},
|
|
||||||
freeliving: {
|
|
||||||
title: 'Free Co-Living',
|
|
||||||
descr: 'Para unir más realidad, compartiendo la experiencia de vivir juntos, por un período definido: <br> '
|
|
||||||
+ '1) Hay quien <strong>vive solo</strong> y tiene un hogar. <br>'
|
|
||||||
+ '2) Quién necesita un alojamiento <strong>temporal</strong>. <br><br>'
|
|
||||||
+ 'Hoy en día, más y más personas <strong>viven solas</strong> y les gustaría seguir viviendo en sus propios hogares. <br>'
|
|
||||||
+ 'Otras personas necesitan una <strong>Habitación</strong>, por elección o por necesidad, y a cambio están disponibles en'
|
|
||||||
+ '<strong>contribuir a los gastos</strong> para los billetes de casa o tal vez <strong>ayuda</strong> a la persona mayor para <strong>ir de compras</strong>, cocinar, <strong>limpiar casa</strong> o simplemente ofreciéndole <strong>compañía</strong>. <br><br> '
|
|
||||||
+ 'A través de esta herramienta, las personas pueden ponerse en contacto y decidir en qué forma <strong>co-habitar</strong>. Los <strong>comentarios</strong> publicados y el <strong>detalle</strong> de los perfiles de usuario, '
|
|
||||||
+ 'ayudará a elegir a la persona más en <strong>armonía</strong>.',
|
|
||||||
|
|
||||||
},
|
|
||||||
freecollabora: {
|
|
||||||
title: '¿Quién puede colaborar?',
|
|
||||||
descr: 'Todos aquellos que están en línea con <strong>Principios éticos</strong> y la investigación de <strong>Bienestar Global del Planeta</strong> <br> '
|
|
||||||
+ 'Por eso son bienvenidos:'
|
|
||||||
+ '<ul class = "mylist" style = "padding-left: 20px;">'
|
|
||||||
+ '<li> <strong>Asociaciones sin ánimo de lucro, Ecoaldeas, Comunidades</strong> </li>'
|
|
||||||
+ '<li> Grupos que desean promover <strong>Proyectos sociales innovadores</strong> para <strong>Feliz Decrecimiento</strong> </li>'
|
|
||||||
+ '<li> Quién administra un <strong>Grupo de Compra Solidario (G.C.S.)</strong> </li>'
|
|
||||||
+ '<li><strong>Productores locales Éticos</strong></li>'
|
|
||||||
+ '<li> Quién administra un <strong>Banco de Tiempo</strong> </li>'
|
|
||||||
+ '<li> <strong>Cualquier persona que quiera participar</strong>, en la forma que considere más apropiada. </li>'
|
|
||||||
+ '</ul>',
|
|
||||||
},
|
|
||||||
freesostieni: {
|
|
||||||
title: '¿Cómo apoyar el proyecto?',
|
|
||||||
descr: '<ul class="mylist" style="padding-left: 20px;">'
|
|
||||||
+ '<li> <strong>Compartiéndolo</strong> a todos aquellos que quieran unirse en el crecimiento y desarrollo de una Nueva Era </li> '
|
|
||||||
+ '<li> Respondiendo a <strong>Encuestas populares</strong> y dejando <strong>Comentarios</strong> </li>'
|
|
||||||
+ '<li> A través de una <strong>donación</strong> (<strong>incluso € 1</strong>) para los gastos. <br>'
|
|
||||||
+ '</ul>'
|
|
||||||
+ '<br>Veo un <strong>futuro</strong> en el que ya no usarás dinero. Donde las personas <strong>se ayudarán unos a otros</strong> y no necesiten "poseer" cosas, pero <strong>compartirán</strong> con otros. <br> ',
|
|
||||||
},
|
|
||||||
multiplatform: {
|
|
||||||
title: 'Multi-plataforma',
|
|
||||||
descr: 'Compatible con Google Chrome, Firefox, Safari, iOS, Android y PC. La aplicación se instala fácilmente, sin pasar por el store. '
|
|
||||||
+ 'para compartirlo, necesita solo el nombre del sitio web: <strong>www.freeplanet.app</strong>.<br>'
|
|
||||||
+ 'Después del registro, le pedirá que lo agregue a la lista de aplicaciones y en la pantalla.',
|
|
||||||
},
|
|
||||||
free: {
|
|
||||||
title: 'Libre, Código Abierto y Sin Publicidad',
|
|
||||||
descr: 'Esta aplicación <strong>no está a la venta</strong>, no tiene un propósito comercial, <strong>no tiene precio</strong> y pertenece a <strong>la Gente del Nuevo Mundo</strong>.<br>'
|
|
||||||
+ 'Cualquiera puede usarla y beneficiarse.<br> A mí la tarea de gestionarlo y protegerlo. '
|
|
||||||
+ 'Solo se aceptarán donaciones de particulares y asociaciones sin änimo de lucro, en línea con los Principios, que se utilizarán para cubrir los gastos. <br>'
|
|
||||||
+ '<strong>Gracias a todos por el apoyo</strong>. ',
|
|
||||||
},
|
|
||||||
contacts: 'Contactos',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
enUs: {
|
|
||||||
pages: {
|
|
||||||
home: 'Dashboard',
|
|
||||||
SignUp: 'SignUp',
|
|
||||||
SignIn: 'SignIn',
|
|
||||||
vreg: 'Verify Reg',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Category',
|
|
||||||
Todo: 'Todo',
|
|
||||||
personal: 'Personal',
|
|
||||||
work: 'Work',
|
|
||||||
shopping: 'Shopping',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
projects: 'Projects',
|
|
||||||
},
|
|
||||||
favproj: 'Favorite',
|
|
||||||
projall: 'All',
|
|
||||||
projectsShared: 'My Shared',
|
|
||||||
myprojects: 'My Personals',
|
|
||||||
msg: {
|
|
||||||
hello: 'Hello!',
|
|
||||||
myAppName: 'FreePlanet',
|
|
||||||
myAppDescription: 'The first Real Social Free, Fair and Equitable Where the conscience and community help live. Free and without advertising',
|
|
||||||
underconstruction: 'App in construction...',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: 'The first Real Social',
|
|
||||||
sottoTitoloApp2: 'Free, Fair and Equitable',
|
|
||||||
sottoTitoloApp3: 'Where the conscience and community help live',
|
|
||||||
sottoTitoloApp4: 'Free and without advertising',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
descrapp_title1: 'Together to Evolve and Experiment',
|
|
||||||
descrapp_pag1: 'Rediscover how the value of <strong>Sharing</strong> and <strong>Cooperation</strong>, can help us find the deep meaning of'
|
|
||||||
+ '<strong>Life</strong>, lost in this consumer society, and showing those <strong>Healthy Natural Principles</strong> and Human <strong>Brotherhood</strong>'
|
|
||||||
+ 'that entire ancient populations knew well.',
|
|
||||||
descrapp_pag2: 'The time has come to use the new <strong>Technological</strong> tools in our <strong>favor</strong>, to <strong>Free ourselves</strong> '
|
|
||||||
+ 'so slowly from the <strong>slavery</strong> of the <strong>"Work to generate Money"</strong> and transforming our <strong>Capacity</strong> into'
|
|
||||||
+ '<strong>Human Resources</strong> to be able to support and live in <strong>Harmony</strong> with others.',
|
|
||||||
freesocial: {
|
|
||||||
title: 'Free Social',
|
|
||||||
descr: 'A Community organized by <strong>Categories</strong>, where you can join <strong>Thematic Groups</strong>, '
|
|
||||||
+ 'Share <strong>Experiences</strong> and combine Skills to organize and support <strong>Innovative Projects</strong> for the People.<br><br>'
|
|
||||||
+ '<strong>Ethical</strong> developments such as <strong>Auto-Production</strong>, <strong>Sustainability</strong>, '
|
|
||||||
+ 'Good <strong>Natural Health</strong> and <strong>Respect for the Environment</strong> and for all <strong>Living Beings</strong> of this'
|
|
||||||
+ '<strong>Planet</strong>. Anyone can express their <strong>Consent or Dissent</strong> by participating in <strong>Interactive Surveys</strong> '
|
|
||||||
+ 'and carry out together the <strong>Changes</strong> needed for our society.',
|
|
||||||
},
|
|
||||||
freetalent: {
|
|
||||||
title: 'Free Talent',
|
|
||||||
descr: 'Share your <strong>Talents</strong> and <strong>Skills</strong>, '
|
|
||||||
+ 'instead of money, you\'ll earn <strong>Time</strong>. <br>'
|
|
||||||
+ '<strong>"1 hour"</strong> becomes a currency of exchange, equal for all. <br>'
|
|
||||||
+ 'You can use these <strong>"Time Credits"</strong> to meet your needs, looking in <strong>Available Skills</strong>. <br>'
|
|
||||||
+ 'In Giving and Receiving, we will thus create bonds of <strong>Friendship, Solidarity, Cooperation and Enjoyment</strong> <br> <br>'
|
|
||||||
+ 'This project aims to spread this reality, which already exists for many years and is called <strong>"Time Bank"</strong>. '
|
|
||||||
+ 'The <strong>secretariats</strong> in all over the world, will serve an extra to give greater <strong>reliability</strong> and <strong>trust</strong> in the exchange of talents between unknown people. '
|
|
||||||
+ 'We will thus create a <strong>trust network</strong> in the neighborhood, as is already practiced in numerous <strong>Ecovillages</strong> and Community of the world. ',
|
|
||||||
},
|
|
||||||
freegas: {
|
|
||||||
title: 'Free G.A.S.',
|
|
||||||
descr: 'Would you like to use an App that allows you to easily Buy Local Products directly from <strong>Manufacturer</strong>? <br> '
|
|
||||||
+ 'With <strong>Solidarity Purchase Groups</strong> (in Italian: "Gruppo di Aacquisto Solidale") we avoid unnecessary intermediaries, obtaining many benefits including: <br>'
|
|
||||||
+ '<ul class="mylist" style="padding-left: 20px;"> <li> <strong>Superior Quality</strong> of the product </li>'
|
|
||||||
+ '<li> Consumer <strong>Reviews</strong> will favor Producers with Healthy Intents </li>'
|
|
||||||
+ '<li> Possibility to interact with the Producer </li>'
|
|
||||||
+ '<li> Open to Relations between people, sharing <strong>Recipes</strong> and precious <strong>Tips</strong> </li>'
|
|
||||||
+ '<li> <strong>Savings</strong> money (wholesale prices) </li>'
|
|
||||||
+ '<li> Enhancing the <strong>Territory</strong> and the <strong>Local Economy</strong> </li>'
|
|
||||||
+ '<li> <strong>Fair Conditions</strong> for Workers </li>'
|
|
||||||
+ '<li> Reduced <strong>Environmental Impact</strong> </ul>',
|
|
||||||
},
|
|
||||||
freeliving: {
|
|
||||||
title: 'Free Co-Living',
|
|
||||||
descr: 'Join more reality, sharing the experience of living together, for a defined period: <br> '
|
|
||||||
+ '1) Someone <strong>Lives alone</strong> and has a house. <br>'
|
|
||||||
+ '2) Who needs a temporary <strong> accommodation </strong>. <br><br>'
|
|
||||||
+ 'Today more and more people <strong> live alone </strong> and would like to continue living in their own house. <br>'
|
|
||||||
+ 'Other people instead need a <strong>room</strong>, by choice or by necessity, and in return they are available to'
|
|
||||||
+ '<strong>contribute to expenses</strong> for households or maybe <strong>help</strong> to <strong>go shopping</strong>, cooking, <strong>cleaning house</strong> or simply offering him <strong>companionship</strong>. <br> '
|
|
||||||
+ 'Through this tool, people can get in touch and decide in which way <strong>co-living</strong>. The <strong>reviews</strong> released and the <strong>detail</strong> of user profiles, '
|
|
||||||
+ 'will help in <strong>choosing</strong> the person more in <strong>tune</strong>.',
|
|
||||||
|
|
||||||
},
|
|
||||||
freecollabora: {
|
|
||||||
title: 'Who can collaborate?',
|
|
||||||
descr: 'All those who are in line with <strong>Ethical Principles</strong> and research of <strong>Global Wellness of the Planet</strong> <br> '
|
|
||||||
+ 'Therefore they are welcome:'
|
|
||||||
+ '<ul class = "mylist" style = "padding-left: 20px;">'
|
|
||||||
+ '<li> <strong>Non-profit associations, Ecovillages, Communities</strong> </li>'
|
|
||||||
+ '<li> Groups that want to promote <strong>Innovative Social Projects</strong> for <strong>Happy Degrowth</strong> </li>'
|
|
||||||
+ '<li> Who manages a <strong>Solidarity Purchase Group</strong> </li>'
|
|
||||||
+ '<li><strong>Local Ethical Producers</strong></li>'
|
|
||||||
+ '<li> Who manages a <strong>Time Bank</strong> </li>'
|
|
||||||
+ '<li> <strong>Anyone who wants to participate</strong>, in the form it considers most appropriate. </li>'
|
|
||||||
+ '</ul>',
|
|
||||||
},
|
|
||||||
freesostieni: {
|
|
||||||
title: 'How to support the project?',
|
|
||||||
descr: '<ul class="mylist" style="padding-left: 20px;">'
|
|
||||||
+ '<li> <strong>Sharing it</strong> to all those who want to join together in the growth and development of a New Era </li> '
|
|
||||||
+ '<li> Answering to <strong>Popular Polls</strong> and leaving <strong>Feedback</strong> </li>'
|
|
||||||
+ '<li> Through a <strong>donation</strong> (<strong>even $ 1</strong>) for expenses. <br>'
|
|
||||||
+ '</ul><br>'
|
|
||||||
+ 'I see a <strong>future</strong> where you will no longer use money. Where people <strong>will help each other</strong> and won\'t need to "own" things, but <strong>will share</strong> with others. <br> ',
|
|
||||||
},
|
|
||||||
multiplatform: {
|
|
||||||
title: 'Multi-platform',
|
|
||||||
descr: 'It is compatible with Google Chrome, Firefox, Safari, iOS, Android and PC. The Application is easily installed, without going through the store. '
|
|
||||||
+ 'just share the nametranslate of this site <strong>www.freeplanet.app</strong>.<br>'
|
|
||||||
+ 'After registration it will ask to be added to the application list and in the screen',
|
|
||||||
},
|
|
||||||
free: {
|
|
||||||
title: 'Free, Open Source and No Advertising',
|
|
||||||
descr: 'This App <strong>is not for sale</strong>, has no commercial purpose, <strong>is priceless</strong> and belongs to the <strong>New World People</strong>.'
|
|
||||||
+ '<br>Anyone can use it and benefit from it.<br>To me the task of managing it and protecting it. '
|
|
||||||
+ 'Only donations from private individuals and non-profit associations will be accepted, in line with the Principles, which will be used to cover the expenses. <br>'
|
|
||||||
+ '<strong>Thanks all for the support</strong>. ',
|
|
||||||
},
|
|
||||||
contacts: 'Contacts',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fr: {
|
|
||||||
pages: {
|
|
||||||
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
de: {
|
|
||||||
pages: {
|
|
||||||
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default msg_website;
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
const msg_website_de = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'AYNI',
|
|
||||||
siteshortname: 'Ayni',
|
|
||||||
botname: 'AYNI BOT',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Home',
|
|
||||||
profile: 'Profilo',
|
|
||||||
payment: 'Pagamenti',
|
|
||||||
regok: 'Registrazione Confermata',
|
|
||||||
presentazione: 'Presentazione',
|
|
||||||
presentazione2: 'Presentazione',
|
|
||||||
invita: 'Invita Persone',
|
|
||||||
SignUp: 'Nuova Registrazione',
|
|
||||||
SignUp_alreadylista: 'Registrazione per quelli che erano già nella lista di Notevole (del 2019) !',
|
|
||||||
SignUp2: 'Registrazione',
|
|
||||||
SignIn: 'Login',
|
|
||||||
status: 'Statistiche',
|
|
||||||
nextzoom: 'Conferenze',
|
|
||||||
requestresetpwd: 'Richiesta Reset Password',
|
|
||||||
vreg: 'Verifica Reg',
|
|
||||||
dashboard: 'Lavagna',
|
|
||||||
statoattuale: 'Stato Attuale',
|
|
||||||
posizione_in_programmazione: 'Lista d\'Imbarco',
|
|
||||||
posizione_in_nave: 'Lista Navi',
|
|
||||||
nave: 'Nave',
|
|
||||||
testimonial: 'Testimonianze',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Admin: 'Admin',
|
|
||||||
extralist: 'Lista Extra',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
chisiamo: 'Chi Siamo',
|
|
||||||
linkamici: 'Link Amici',
|
|
||||||
dovesiamo: 'Dove Siamo',
|
|
||||||
evento: 'Evento',
|
|
||||||
eventodef: 'Evento:',
|
|
||||||
prova: 'prova',
|
|
||||||
dbop: 'Operazioni',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Partecipanti',
|
|
||||||
verifieds: 'Verificati',
|
|
||||||
autorizzati: 'Autorizzati',
|
|
||||||
passeggeri: 'Passeggeri Navi',
|
|
||||||
giainlista: 'Gia in Lista',
|
|
||||||
newreg: 'Ultime Registrazioni:',
|
|
||||||
nationality: 'Nazionalità',
|
|
||||||
verified: 'Verificata',
|
|
||||||
nonverified: 'Non Verificata',
|
|
||||||
req7: 'Con 5 passi entri nella lista d\'Imbarco',
|
|
||||||
req9: 'Con 7 passi aiuti {sitename} a Crescere!',
|
|
||||||
req: 'Passi',
|
|
||||||
people: 'Inv.',
|
|
||||||
peoplelegend: 'Numero d\'Invitati',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppDescription: '',
|
|
||||||
keywords_base: '',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: '',
|
|
||||||
sottoTitoloApp2: '',
|
|
||||||
sottoTitoloApp3: '',
|
|
||||||
sottoTitoloApp4: '',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
nostra_missione: 'Nostra Missione',
|
|
||||||
associazione: '',
|
|
||||||
tit_come_associarsi: 'Come Associarsi',
|
|
||||||
testo_come_associarsi: '',
|
|
||||||
titlecontatti: 'CONTATTI',
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
videotitle: 'VIDEO',
|
|
||||||
how: 'COME FUNZIONA',
|
|
||||||
what: 'COSA TI SERVE',
|
|
||||||
step: 'PASSI DA COMPIERE',
|
|
||||||
testimonial: 'TESTIMONIANZE',
|
|
||||||
faq: 'DOMANDE FREQUENTI (FAQ)',
|
|
||||||
advise: 'SUGGERIMENTI',
|
|
||||||
download: 'MATERIALE DISPONIBILE',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_de;
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
const msg_website_enUs = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'Riso',
|
|
||||||
siteshortname: 'RISO',
|
|
||||||
botname: 'Riso BOT',
|
|
||||||
},
|
|
||||||
products: {
|
|
||||||
quantity: 'Quantità',
|
|
||||||
quantityAvailable: 'Disponibili',
|
|
||||||
weight: 'Peso',
|
|
||||||
stars: 'Voto',
|
|
||||||
color: 'Colore',
|
|
||||||
theme: 'Tema',
|
|
||||||
},
|
|
||||||
hours: {
|
|
||||||
descr: 'Descrizione',
|
|
||||||
date: 'Data',
|
|
||||||
time_start: 'Ora Inizio',
|
|
||||||
time_end: 'Ora Fine',
|
|
||||||
hours: 'Ore',
|
|
||||||
note: 'Note Extra',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Home',
|
|
||||||
profile: 'Profile',
|
|
||||||
profile2: 'ProfiloU',
|
|
||||||
mypage2: 'mypage2',
|
|
||||||
myservice2: 'myservice2',
|
|
||||||
test: 'Test',
|
|
||||||
projects: 'Progetti',
|
|
||||||
report: 'Report Ore',
|
|
||||||
producer: 'Produttore',
|
|
||||||
orderinfo: 'Ordini Effettuati',
|
|
||||||
products: 'Prodotti',
|
|
||||||
productslist: 'Lista Prodotti',
|
|
||||||
collabora: 'Collabora',
|
|
||||||
storehouses: 'Magazzino',
|
|
||||||
departments: 'Uffici',
|
|
||||||
orders: 'Ordini Ricevuti',
|
|
||||||
orders2: 'Ordini Ricevuti',
|
|
||||||
sharewithus: 'Condividi con Noi',
|
|
||||||
checkout: 'Carrello',
|
|
||||||
payment: 'Payments',
|
|
||||||
regok: 'Registration Confirmed',
|
|
||||||
presentazione: 'Presentation',
|
|
||||||
presentazione2: 'Presentation',
|
|
||||||
invita: 'Invite People',
|
|
||||||
SignUp: 'Registration',
|
|
||||||
SignUpIscrizione: 'Diventa Socio CNM',
|
|
||||||
SignUp_alreadylista: 'Registration for those who are already in the List!',
|
|
||||||
SignUp2: 'Registration',
|
|
||||||
SignIn: 'Login',
|
|
||||||
status: 'Current state',
|
|
||||||
nextzoom: 'Conferences',
|
|
||||||
requestresetpwd: 'Password Reset Request',
|
|
||||||
vreg: 'Check Registration',
|
|
||||||
dashboard: 'Dashboard',
|
|
||||||
statoattuale: 'Current Status',
|
|
||||||
posizione_in_programmazione: 'Boarding List',
|
|
||||||
posizione_in_nave: 'Ships List',
|
|
||||||
nave: 'Ship',
|
|
||||||
testimonial: 'Reviews',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Sites: 'Siti Web',
|
|
||||||
extralist: 'Lista Extra',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
chisiamo: 'Chi Siamo',
|
|
||||||
linkamici: 'Link Amici',
|
|
||||||
dovesiamo: 'Dove Siamo',
|
|
||||||
calendarioeventi: 'Calendario Eventi',
|
|
||||||
evento: 'Evento',
|
|
||||||
eventodef: 'Evento:',
|
|
||||||
prova: 'prova',
|
|
||||||
dbop: 'Operazioni',
|
|
||||||
projall: 'Comunitari',
|
|
||||||
groups: 'Lista Gruppi',
|
|
||||||
projectsShared: 'Condivisi da me',
|
|
||||||
myprojects: 'Privati',
|
|
||||||
favproj: 'Favoriti',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Participants',
|
|
||||||
verifieds: 'Verificati',
|
|
||||||
autorizzati: 'Autorizzati',
|
|
||||||
autorizzare: 'In attesa di Abilitazione',
|
|
||||||
passeggeri: 'Passengers Ships',
|
|
||||||
giainlista: 'Already in the List',
|
|
||||||
newreg: 'New registrations:',
|
|
||||||
nationality: 'Nationality',
|
|
||||||
nationality_born: 'Nazione di Nascita',
|
|
||||||
verified: 'Verified',
|
|
||||||
nonverified: 'Not Verified',
|
|
||||||
req7: 'With 5 steps you enter the boarding list.',
|
|
||||||
req9: 'With 7 steps help {sitename} to grow!',
|
|
||||||
req: 'Steps',
|
|
||||||
people: 'Gue.',
|
|
||||||
peoplelegend: 'Number of guests',
|
|
||||||
},
|
|
||||||
admin_ecommerce: 'ECommerce',
|
|
||||||
ecommerce: 'Prodotti',
|
|
||||||
ecommerce_menu: 'ECommerce1',
|
|
||||||
hours: 'Ore',
|
|
||||||
department: 'Uffici',
|
|
||||||
title: 'Titolo',
|
|
||||||
path: 'Percorso',
|
|
||||||
img1: 'Immagine 1',
|
|
||||||
contentfield: 'Testo 1',
|
|
||||||
video1: 'Video 1',
|
|
||||||
ratio1: 'Ratio 1',
|
|
||||||
img2: 'Immagine 2',
|
|
||||||
content2: 'Testo 2',
|
|
||||||
video2: 'Video 2',
|
|
||||||
ratio2: 'Ratio 2',
|
|
||||||
img3: 'Immagine 3',
|
|
||||||
content3: 'Testo 3',
|
|
||||||
video3: 'Video 3',
|
|
||||||
ratio3: 'Ratio 3',
|
|
||||||
content4: 'Testo 4',
|
|
||||||
active: 'Attiva',
|
|
||||||
inmenu: 'Sul Menu',
|
|
||||||
submenu: 'SottoMenu',
|
|
||||||
infooter: 'Sul Footer',
|
|
||||||
internalpage: 'Pagina Interna',
|
|
||||||
order: 'Posizione',
|
|
||||||
icon: 'Icona',
|
|
||||||
imgback: 'Immagine di Sfondo',
|
|
||||||
onlyif_logged: 'Solo se Loggati',
|
|
||||||
only_residenti: 'Solo Residenti',
|
|
||||||
only_consiglio: 'Solo Consiglieri',
|
|
||||||
color: 'Colore',
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppDescription: '',
|
|
||||||
underconstruction: 'App in costruzione...',
|
|
||||||
keywords_base: '',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: '..',
|
|
||||||
sottoTitoloApp2: '..',
|
|
||||||
sottoTitoloApp3: '..',
|
|
||||||
sottoTitoloApp4: '',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
titlecontatti: 'CONTACTS',
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
how: 'HOW TO WORK',
|
|
||||||
what: 'WHAT YOU NEED',
|
|
||||||
step: 'STEPS TO DO',
|
|
||||||
videotitle: 'VIDEO',
|
|
||||||
testimonial: 'REVIEWS',
|
|
||||||
faq: 'FREQUENTLY ASKED QUESTIONS (FAQ)',
|
|
||||||
advise: 'ADVISE',
|
|
||||||
download: 'AVAILABLE DOCUMENTS',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_enUs;
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
const msg_website_es = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'Riso',
|
|
||||||
siteshortname: 'RISO',
|
|
||||||
botname: 'Riso BOT',
|
|
||||||
},
|
|
||||||
products: {
|
|
||||||
quantity: 'Quantità',
|
|
||||||
quantityAvailable: 'Disponibili',
|
|
||||||
weight: 'Peso',
|
|
||||||
stars: 'Voto',
|
|
||||||
color: 'Colore',
|
|
||||||
theme: 'Tema',
|
|
||||||
},
|
|
||||||
hours: {
|
|
||||||
descr: 'Descrizione',
|
|
||||||
date: 'Data',
|
|
||||||
time_start: 'Ora Inizio',
|
|
||||||
time_end: 'Ora Fine',
|
|
||||||
hours: 'Ore',
|
|
||||||
note: 'Note Extra',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Home',
|
|
||||||
profile: 'Perfil',
|
|
||||||
profile2: 'ProfiloU',
|
|
||||||
mypage2: 'mypage2',
|
|
||||||
myservice2: 'myservice2',
|
|
||||||
mygood2: 'mygood2',
|
|
||||||
test: 'Test',
|
|
||||||
projects: 'Progetti',
|
|
||||||
report: 'Report Ore',
|
|
||||||
producer: 'Produttore',
|
|
||||||
orderinfo: 'Ordini Effettuati',
|
|
||||||
products: 'Prodotti',
|
|
||||||
productslist: 'Lista Prodotti',
|
|
||||||
collabora: 'Collabora',
|
|
||||||
storehouses: 'Magazzino',
|
|
||||||
departments: 'Uffici',
|
|
||||||
orders: 'Ordini Ricevuti',
|
|
||||||
orders2: 'Ordini Ricevuti',
|
|
||||||
sharewithus: 'Condividi con Noi',
|
|
||||||
checkout: 'Carrello',
|
|
||||||
payment: 'Paiements',
|
|
||||||
regok: 'Registro confirmado',
|
|
||||||
presentazione: 'Presentación',
|
|
||||||
presentazione2: 'Presentación',
|
|
||||||
invita: 'Invitar a la gente',
|
|
||||||
SignUp: 'Registro',
|
|
||||||
SignUpIscrizione: 'Diventa Socio CNM',
|
|
||||||
SignUp_alreadylista: 'Inscripción para los que ya están en la Lista!',
|
|
||||||
SignUp2: 'Registro',
|
|
||||||
SignIn: 'Login',
|
|
||||||
status: 'Estadísticas',
|
|
||||||
nextzoom: 'Conferencias',
|
|
||||||
requestresetpwd: 'Solicitud de restablecimiento de contraseña',
|
|
||||||
calendarioeventi: 'Calendario Eventos',
|
|
||||||
vreg: 'Verifica Reg',
|
|
||||||
dashboard: 'Tablero',
|
|
||||||
statoattuale: 'Estado Actual',
|
|
||||||
posizione_in_programmazione: 'Lista de embarque',
|
|
||||||
posizione_in_nave: 'Lista de Naves',
|
|
||||||
nave: 'Nave',
|
|
||||||
testimonial: 'Opiniones',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Sites: 'Siti Web',
|
|
||||||
extralist: 'Lista Extra',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
chisiamo: 'Chi Siamo',
|
|
||||||
linkamici: 'Link Amici',
|
|
||||||
dovesiamo: 'Dove Siamo',
|
|
||||||
evento: 'Evento',
|
|
||||||
eventodef: 'Evento:',
|
|
||||||
prova: 'prova',
|
|
||||||
dbop: 'Operazioni',
|
|
||||||
projall: 'Comunitari',
|
|
||||||
groups: 'Lista Gruppi',
|
|
||||||
projectsShared: 'Condivisi da me',
|
|
||||||
myprojects: 'Privati',
|
|
||||||
favproj: 'Favoriti',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Participantes',
|
|
||||||
verifieds: 'Verificati',
|
|
||||||
autorizzati: 'Autorizzati',
|
|
||||||
autorizzare: 'In attesa di Abilitazione',
|
|
||||||
passeggeri: 'Barcos de pasajeros',
|
|
||||||
giainlista: 'Gia in Lista',
|
|
||||||
newreg: 'Nuevas inscripciones :',
|
|
||||||
nationality: 'Nacionalidad',
|
|
||||||
verified: 'Verificada',
|
|
||||||
nonverified: 'No Verificada',
|
|
||||||
req7: 'Con 5 pasos usted entra en la lista de embarque',
|
|
||||||
req9: 'Con 7 pasos ayuda a {sitename} a crecer!',
|
|
||||||
req: 'Pasos',
|
|
||||||
people: 'Inv.',
|
|
||||||
peoplelegend: 'Número de invitados',
|
|
||||||
},
|
|
||||||
admin_ecommerce: 'ECommerce',
|
|
||||||
ecommerce: 'Prodotti',
|
|
||||||
ecommerce_menu: 'ECommerce1',
|
|
||||||
hours: 'Ore',
|
|
||||||
department: 'Uffici',
|
|
||||||
title: 'Titolo',
|
|
||||||
path: 'Percorso',
|
|
||||||
img1: 'Immagine 1',
|
|
||||||
contentfield: 'Testo 1',
|
|
||||||
video1: 'Video 1',
|
|
||||||
ratio1: 'Ratio 1',
|
|
||||||
img2: 'Immagine 2',
|
|
||||||
content2: 'Testo 2',
|
|
||||||
video2: 'Video 2',
|
|
||||||
ratio2: 'Ratio 2',
|
|
||||||
img3: 'Immagine 3',
|
|
||||||
content3: 'Testo 3',
|
|
||||||
video3: 'Video 3',
|
|
||||||
ratio3: 'Ratio 3',
|
|
||||||
content4: 'Testo 4',
|
|
||||||
active: 'Attiva',
|
|
||||||
inmenu: 'Sul Menu',
|
|
||||||
submenu: 'SottoMenu',
|
|
||||||
infooter: 'Sul Footer',
|
|
||||||
internalpage: 'Pagina Interna',
|
|
||||||
order: 'Posizione',
|
|
||||||
icon: 'Icona',
|
|
||||||
imgback: 'Immagine di Sfondo',
|
|
||||||
onlyif_logged: 'Solo se Loggati',
|
|
||||||
only_residenti: 'Solo Residenti',
|
|
||||||
only_consiglio: 'Solo Consiglieri',
|
|
||||||
color: 'Colore',
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppDescription: '',
|
|
||||||
keywords_base: '',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: '..',
|
|
||||||
sottoTitoloApp2: '..',
|
|
||||||
sottoTitoloApp3: '..',
|
|
||||||
sottoTitoloApp4: '',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
titlecontatti: 'CONTACTOS',
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
how: 'COMO FUNCIONA',
|
|
||||||
what: 'QUE NECESITAS',
|
|
||||||
step: 'PASOS A REALIZAR',
|
|
||||||
videotitle: 'VIDEO',
|
|
||||||
testimonial: 'TESTIMONIOS',
|
|
||||||
faq: 'PREGUNTAS FRECUENTES (FAQ)',
|
|
||||||
advise: 'CONSEJOS',
|
|
||||||
download: 'MATERIAL DISPONIBLES',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_es;
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
const msg_website_fr = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'Riso',
|
|
||||||
siteshortname: 'RISO',
|
|
||||||
botname: 'Riso BOT',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
titlecontatti: 'CONTACTS',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Home',
|
|
||||||
profile: 'profil',
|
|
||||||
payment: 'paiements',
|
|
||||||
regok: 'Inscription confirmée',
|
|
||||||
presentazione: 'Présentation',
|
|
||||||
presentazione2: 'Présentation',
|
|
||||||
invita: 'Inviter des personnes',
|
|
||||||
SignUp: 'Inscription',
|
|
||||||
SignUp_alreadylista: 'Inscription pour ceux qui sont déjà inscrits sur la liste!',
|
|
||||||
SignUp2: 'Inscription',
|
|
||||||
SignIn: 'Login',
|
|
||||||
status: 'État actuel',
|
|
||||||
nextzoom: 'Conférences',
|
|
||||||
requestresetpwd: 'Demande de réinitialisation du mot de passe',
|
|
||||||
vreg: 'Vérifier l\'inscription',
|
|
||||||
dashboard: 'Tableau de bord',
|
|
||||||
statoattuale: 'Situation Actuelle',
|
|
||||||
posizione_in_programmazione: 'Liste d\'embarquement',
|
|
||||||
posizione_in_nave: 'Liste des Navires',
|
|
||||||
nave: 'Navires',
|
|
||||||
testimonial: 'Commentaires',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Participants',
|
|
||||||
passeggeri: 'Navires à passagers',
|
|
||||||
giainlista: 'Gia in Lista',
|
|
||||||
newreg: 'Nouvelles inscriptions:',
|
|
||||||
nationality: 'Nationalité',
|
|
||||||
verified: 'Vérifié',
|
|
||||||
nonverified: 'Non Vérifié',
|
|
||||||
req7: 'Avec 5 étapes, vous entrez dans la liste d\'embarquement.',
|
|
||||||
req9: 'Avec 7 étapes, aidez {sitename} à se développer !',
|
|
||||||
req: 'Étapes',
|
|
||||||
people: 'Inv.',
|
|
||||||
peoplelegend: 'Nombre d\'invités',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppDescription: '',
|
|
||||||
keywords_base: '',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: '..',
|
|
||||||
sottoTitoloApp2: '..',
|
|
||||||
sottoTitoloApp3: '..',
|
|
||||||
sottoTitoloApp4: '',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_fr;
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
const msg_website_it = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'KolibriLab',
|
|
||||||
siteshortname: 'KolibriLab',
|
|
||||||
description: '',
|
|
||||||
keywords: '',
|
|
||||||
},
|
|
||||||
products: {
|
|
||||||
quantity: 'Quantità',
|
|
||||||
quantityAvailable: 'Disponibili',
|
|
||||||
weight: 'Peso',
|
|
||||||
stars: 'Voto',
|
|
||||||
color: 'Colore',
|
|
||||||
theme: 'Tema',
|
|
||||||
},
|
|
||||||
hours: {
|
|
||||||
descr: 'Descrizione',
|
|
||||||
date: 'Data',
|
|
||||||
time_start: 'Ora Inizio',
|
|
||||||
time_end: 'Ora Fine',
|
|
||||||
hours: 'Ore',
|
|
||||||
note: 'Note Extra',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Home',
|
|
||||||
profile: 'Profilo',
|
|
||||||
profile2: 'ProfiloU',
|
|
||||||
mypage2: 'mypage2',
|
|
||||||
myservice2: 'myservice2',
|
|
||||||
myhosps2: 'myhosps2',
|
|
||||||
mygood2: 'mygood2',
|
|
||||||
fundraising: 'Sostieni il Progetto',
|
|
||||||
notifs: 'Configura le Notifiche',
|
|
||||||
test: 'Test',
|
|
||||||
projects: 'Progetti',
|
|
||||||
report: 'Report Ore',
|
|
||||||
producer: 'Produttore',
|
|
||||||
orderinfo: 'Ordini Effettuati',
|
|
||||||
products: 'Prodotti',
|
|
||||||
productslist: 'Lista Prodotti',
|
|
||||||
collabora: 'Collabora',
|
|
||||||
storehouses: 'Magazzino',
|
|
||||||
departments: 'Uffici',
|
|
||||||
orders: 'Ordini Ricevuti',
|
|
||||||
orders2: 'Ordini Ricevuti',
|
|
||||||
sharewithus: 'Condividi con Noi',
|
|
||||||
checkout: 'Carrello',
|
|
||||||
payment: 'Pagamenti',
|
|
||||||
regok: 'Registrazione Confermata',
|
|
||||||
presentazione: 'Presentazione',
|
|
||||||
presentazione2: 'Presentazione',
|
|
||||||
invita: 'Invita Persone',
|
|
||||||
SignUp: 'Modulo di Registrazione:',
|
|
||||||
need_Telegram: 'Per poter utilizzare la Piattaforma occorre avere <a href="https://play.google.com/store/apps/details?id=org.telegram.messenger" target="_blank">Telegram</a> installato<br>',
|
|
||||||
Registrazione_Con_Bot: '1) Copia questo username cliccandoci sopra:',
|
|
||||||
SignUpIscrizione: 'Diventa Socio CNM',
|
|
||||||
SignUpArcadei: 'Aderisci ad Arcadei',
|
|
||||||
SignUp_alreadylista: 'Registrazione per quelli che erano già nella lista di Notevole (del 2019) !',
|
|
||||||
SignUp2: 'Registrazione',
|
|
||||||
SignUp4: 'Reg',
|
|
||||||
SignUpBot: 'Registrati',
|
|
||||||
SignIn: 'Login',
|
|
||||||
status: 'Statistiche',
|
|
||||||
nextzoom: 'Conferenze',
|
|
||||||
requestresetpwd: 'Richiesta Reset Password',
|
|
||||||
vreg: 'Verifica Reg',
|
|
||||||
dashboard: 'Lavagna',
|
|
||||||
statoattuale: 'Stato Attuale',
|
|
||||||
posizione_in_programmazione: 'Lista d\'Imbarco',
|
|
||||||
posizione_in_nave: 'Lista Navi',
|
|
||||||
nave: 'Nave',
|
|
||||||
testimonial: 'Testimonianze',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Sites: 'Siti Web',
|
|
||||||
extralist: 'Lista Extra',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
chisiamo: 'Chi Siamo',
|
|
||||||
linkamici: 'Link Amici',
|
|
||||||
dovesiamo: 'Dove Siamo',
|
|
||||||
calendarioeventi: 'Calendario Eventi',
|
|
||||||
evento: 'Evento',
|
|
||||||
eventodef: 'Evento:',
|
|
||||||
prova: 'prova',
|
|
||||||
dbop: 'Operazioni',
|
|
||||||
projall: 'Comunitari',
|
|
||||||
groups: 'Lista Gruppi',
|
|
||||||
projectsShared: 'Condivisi da me',
|
|
||||||
myprojects: 'Privati',
|
|
||||||
favproj: 'Favoriti',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Partecipanti',
|
|
||||||
verifieds: 'Verificati',
|
|
||||||
online_today: 'On Line Oggi',
|
|
||||||
activeusers: 'Utenti Attivi',
|
|
||||||
autorizzati: 'Autorizzati',
|
|
||||||
autorizzare: 'In attesa di Abilitazione',
|
|
||||||
passeggeri: 'Passeggeri Navi',
|
|
||||||
giainlista: 'Gia in Lista',
|
|
||||||
newreg: 'Ultime Registrazioni:',
|
|
||||||
nationality: 'Nazionalità',
|
|
||||||
nationality_born: 'Nazione di Nascita',
|
|
||||||
verified: 'Verificata',
|
|
||||||
nonverified: 'Non Verificata',
|
|
||||||
req7: 'Con 5 passi entri nella lista d\'Imbarco',
|
|
||||||
req9: 'Con 7 passi aiuti {sitename} a Crescere!',
|
|
||||||
req: 'Passi',
|
|
||||||
people: 'Inv.',
|
|
||||||
peoplelegend: 'Numero d\'Invitati',
|
|
||||||
},
|
|
||||||
admin_ecommerce: 'ECommerce',
|
|
||||||
ecommerce: 'Prodotti',
|
|
||||||
ecommerce_menu: 'ECommerce1',
|
|
||||||
hours: 'Ore',
|
|
||||||
department: 'Uffici',
|
|
||||||
title: 'Titolo',
|
|
||||||
subtitle: 'SottoTitolo',
|
|
||||||
path: 'Percorso',
|
|
||||||
img1: 'Immagine 1',
|
|
||||||
imgsize: 'ImgSize',
|
|
||||||
contentfield: 'Testo 1',
|
|
||||||
video1: 'Video 1',
|
|
||||||
ratio1: 'Ratio 1',
|
|
||||||
img2: 'Immagine 2',
|
|
||||||
content2: 'Testo 2',
|
|
||||||
video2: 'Video 2',
|
|
||||||
ratio2: 'Ratio 2',
|
|
||||||
img3: 'Immagine 3',
|
|
||||||
content3: 'Testo 3',
|
|
||||||
video3: 'Video 3',
|
|
||||||
ratio3: 'Ratio 3',
|
|
||||||
content4: 'Testo 4',
|
|
||||||
active: 'Attiva',
|
|
||||||
inmenu: 'Sul Menu',
|
|
||||||
submenu: 'SottoMenu',
|
|
||||||
infooter: 'Sul Footer',
|
|
||||||
internalpage: 'Pagina Interna',
|
|
||||||
order: 'Posizione',
|
|
||||||
icon: 'Icona',
|
|
||||||
imgback: 'Immagine di Sfondo',
|
|
||||||
onlyif_logged: 'Solo se Loggati',
|
|
||||||
only_residenti: 'Solo Residenti',
|
|
||||||
only_consiglio: 'Solo Consiglieri',
|
|
||||||
color: 'Colore',
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppName: 'Arcadei',
|
|
||||||
myAppDescription: 'Modello Comunitario',
|
|
||||||
underconstruction: 'App in costruzione...',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: 'Il primo Vero Social',
|
|
||||||
sottoTitoloApp2: 'Libero, Equo e Solidale',
|
|
||||||
sottoTitoloApp3: 'dove Vive Consapevolezza e Aiuto Comunitario',
|
|
||||||
sottoTitoloApp4: 'Gratuito e senza Pubblicità',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
descrapp_title1: 'Uniti per Evolvere e Sperimentare',
|
|
||||||
descrapp_pag1: 'Siamo la <strong>Rete Italiana di Scambio Orizzontale</strong>, abbiamo creato questa piattaforma per metterla al servizio di chi vuole riscoprire il valore della <strong>condivisione</strong> e della <strong>cooperazione</strong>. ' +
|
|
||||||
'Valori semplici e profondi che ci aiutano a ritrovare il <strong>Senso della Vita</strong>, perduto in questa società consumista, e riporti quei <strong>Sani Pricìpi Naturali</strong> ed Umani di <strong>Fratellanza</strong>'
|
|
||||||
+ ' che intere popolazioni antiche conoscevano bene.',
|
|
||||||
descrapp_pag2: 'E\' giunta l\'ora di utilizzare i nuovi strumenti <strong>Tecnologici</strong> a nostro <strong>favore</strong>, per <strong>Liberarci</strong> '
|
|
||||||
+ 'così piano piano dalla <strong>schiavitù</strong> del <strong>"Lavoro per generare Denaro"</strong> e trasformando le nostre <strong>Capacitá</strong> in '
|
|
||||||
+ '<strong>Risorse Umane</strong> per poterci sostenere e vivere in <strong>Armonia</strong> con gli altri.',
|
|
||||||
freesocial: {
|
|
||||||
title: 'Social',
|
|
||||||
descr: 'Una Community organizzata per <strong>Categorie</strong>, dove potrai unirti a <strong>Gruppi Tematici</strong>, '
|
|
||||||
+ 'Condividere <strong>Esperienze</strong> e unire Competenze per organizzare e sostenere <strong>Progetti Innovativi</strong> per il Popolo.<br><br>'
|
|
||||||
+ 'Verranno evidenziati sviluppi <strong>Etici</strong> come l\'<strong>Auto-Produzione</strong>, la <strong>Sostenibilitá</strong>, '
|
|
||||||
+ 'la Buona <strong>Salute Naturale</strong> e il <strong>Rispetto per l\'Ambiente</strong> e per tutti gli <strong>Esseri Viventi</strong> di questo '
|
|
||||||
+ '<strong>Pianeta</strong>. Chiunque potrá esprimere il proprio <strong>Consenso o Dissenso</strong> partecipando a <strong>Sondaggi Interattivi</strong>'
|
|
||||||
+ ' e realizzare insieme i <strong>Cambiamenti</strong> necessari alla nostra Società.',
|
|
||||||
},
|
|
||||||
freetalent: {
|
|
||||||
title: 'Beni e Servizi',
|
|
||||||
descr: 'Condividi i tuoi <strong>Talenti</strong> e <strong>Abilità</strong>, '
|
|
||||||
+ 'Nel Dare e Ricevere, si creeranno così legami di <strong>Amicizia, Solidarietà, Cooperazione e Divertimento</strong><br><br>' +
|
|
||||||
'Favoriamo lo scambio locale di <strong>Beni e Servizi</strong> grazie ad un sistema di baratto organizzato, in cui la comunità stessa si pone come garante.'
|
|
||||||
},
|
|
||||||
coin: {
|
|
||||||
title: 'RIS - Credito Alternativo',
|
|
||||||
descr: '<strong>Stiamo lavorando</strong> anche per creare una sorta di "moneta alternativa" per conteggiare gli scambi che avvengono tra di noi, quando il semplice baratto risulta non applicabile.<br>' +
|
|
||||||
'Partendo dalle basi del <strong>Si.Cre.Na.C.C - Sistema di Credito Naturale a Copertura Certa</strong>.<br>' +
|
|
||||||
'<em>Ciascun operatore potrà creare moneta all\'occorrenza, se il saldo del suo conto non sarà sufficiente a coprire la spesa. Potrà quindi mandare il suo conto in "scoperto", accollandosi il conseguente' +
|
|
||||||
' Debito, accreditando l\'equivalente somma all\'operatore ricevente, il quale la annovera nel suo conto in qualità di Credito. ' +
|
|
||||||
'L\'equilibrio tra il credito dell\'uno ed il debito dell\'altro ha come conseguenza che il debitore dovrà lavorare per rifondere il debito, mentre il ricevente potrà usare il credito come moneta.</em><br>' +
|
|
||||||
'Per maggiori informazioni consultare il libro gratuito <a href="https://sicrenacc.info/" target="_blank">cliccando qui</a>.'
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
freeliving: {
|
|
||||||
title: 'Gruppi Territoriali',
|
|
||||||
descr: 'Questo progetto vuole diffondere la creazione di Gruppi Territoriali Provinciali,'
|
|
||||||
+ 'per poter favorire progetti condivisi in ambito territoriale e creare così una <strong>Rete di Fiducia</strong> fino al vicinato, come giá viene praticato in piccolo, in numerosi <strong>Ecovillaggi</strong> e Comunità del mondo.',
|
|
||||||
|
|
||||||
},
|
|
||||||
freecollabora: {
|
|
||||||
title: 'Chi può Collaborare?',
|
|
||||||
descr: 'Tutti coloro che sono in linea con <strong>Princìpi Etici</strong> e ricerca del <strong>Benessere Globale del Pianeta</strong><br>'
|
|
||||||
+ 'Pertanto sono i benvenuti:'
|
|
||||||
+ '<ul class="mylist" style="padding-left: 20px;">'
|
|
||||||
+ '<li><strong>Associazioni no-profit, Ecovillaggi, Comunità</strong></li>'
|
|
||||||
+ '<li>Gruppi che intendono promuovere <strong>Progetti Sociali Innovativi</strong> per una <strong>Decrescita Felice</strong></li>'
|
|
||||||
+ '<li>Chi gestisce un <strong>Gruppo di Acquisto Solidale (G.A.S.)</strong></li>'
|
|
||||||
+ '<li><strong>Produttori Locali Etici</strong></li>'
|
|
||||||
+ '<li><strong>Chiunque voglia partecipare</strong>, nella forma che ritiene più opportuna.</li>'
|
|
||||||
+ '</ul>',
|
|
||||||
},
|
|
||||||
freesostieni: {
|
|
||||||
title: 'Come Sostenere il progetto <strong>Riso.app</strong>?',
|
|
||||||
descr: '<ul class="mylist" style="padding-left: 20px;">'
|
|
||||||
+ '<li>📱<strong>Condividendo la APP</strong> a tutti coloro che vogliono far parte insieme della crescita e sviluppo di una Nuova Era</li>'
|
|
||||||
+ '<li>👥 Aiutando a creare Gruppi Territoriali nella vostra città, impegnandosi a realizzare progetti per il Bene Comune, in onore ai principi Amorevoli e di condivisione.</li>'
|
|
||||||
+ '<li>🌱 Sostenendo le persone attorno a voi, e rispettando la nostra vera Casa: Madre Natura e Tutti gli Esseri Viventi. ❤️</li>'
|
|
||||||
+ '<li>👨🏻💻 Con una <strong>piccola donazione</strong> per le spese dei Server, manutenzione e per i continui sviluppi e miglioramenti</li></ul>' +
|
|
||||||
'1) Tramite <strong>Paypal</strong>:<br>' +
|
|
||||||
'<div style="font-size: 1.5rem; background-color: white; color: blue; border: solid 2px #f00; margin: 10px; padding: 10px; border-radius: 10px; " ' +
|
|
||||||
'class="row justify-around">' +
|
|
||||||
'</div><em>clicca sull\'importo per fare una <strong>donazione</strong> </em><br>' +
|
|
||||||
'<br>2) Tramite <strong>Satispay</strong>: <a href="https://www.satispay.com/app/match/link/money-box/S6Y-SVN--62712D42-35B0-4BB9-8511-410C2AB8CD45" target="_blank">Clicca qui</a><br>' +
|
|
||||||
'<div style="font-size: 1rem; background-color: white; color: blue; border: solid 2px #f00; margin: 5px; padding: 5px; border-radius: 10px; " ' +
|
|
||||||
'class="row justify-around">' +
|
|
||||||
'Se ancora non hai Satispay <a href="https://www.satispay.com/promo/PAOLOARENA4">Richiedila cliccando qui</a></br>' +
|
|
||||||
'E\' consigliata se hai un conto bancario come alternativa alla costosa carta di credito/debito</br>' +
|
|
||||||
'👉🏻 <strong>Registrandoti entrambi riceviamo un Bonus di 5 €</strong></br>' +
|
|
||||||
'</div>' +
|
|
||||||
'<br>3) Tramite <strong>Bonifico Bancario</strong>:<br>' +
|
|
||||||
'(Scrivi a Surya (<a href="mailto:surya@riso.app">surya@riso.app</a>) per ricevere le coordinate</br>' +
|
|
||||||
'' +
|
|
||||||
'4) In alternativa scegli tu una forma di scambio da donare a Paolo (per scrivergli su Telegram: <a href="https://t.me/surya1977" target="_blank">Surya Paolo</a>)<br />' +
|
|
||||||
'<span style="color: red; font-size: 2rem;">❤</span> Sono graditi messaggi sia di suggerimenti che di apprezzamenti.<br>' +
|
|
||||||
'Grazie Mille per l\'Aiuto ed il Supporto' +
|
|
||||||
'<br>',
|
|
||||||
},
|
|
||||||
multiplatform: {
|
|
||||||
title: 'Multi-piattaforma',
|
|
||||||
descr: 'E\' compatibile con Google Chrome, Firefox, Opera, Safari, iPhone, Android e PC. L\'Applicazione s\'installa facilmente, senza passare dallo store. '
|
|
||||||
+ 'basta entrare sul sito <strong>www.riso.app</strong>.<br>'
|
|
||||||
+ 'Dopo la registrazione chiederà di aggiungerlo allo schermo (o cliccare sul menu del browser "Installa APP")',
|
|
||||||
},
|
|
||||||
free: {
|
|
||||||
title: 'Gratuita, Open Source e Niente Pubblicità',
|
|
||||||
descr: 'Questa App <strong>non è in vendita</strong>, non ha scopi commerciali, quindi <strong>non ha prezzo</strong> e nessun dato contenuto in esso verrà mai venduto, in quanto appartiene a <strong>Tutti Noi</strong> ed a nessuno in particolare.<br>Chiunque potrá utilizzarla e beneficiarne da essa.<br>' +
|
|
||||||
'<em>Progetto Open Source su <a href="https://github.com/paoloar77/newfreeplanet" target="_blank">GitHub</a>.</em><br><br>'
|
|
||||||
+ '<strong>Grazie a Tutti per il sostegno</strong>. ',
|
|
||||||
},
|
|
||||||
titlecontatti: 'Contatti',
|
|
||||||
contacts: '',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_it;
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
const msg_website_pt = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'Riso',
|
|
||||||
siteshortname: 'RISO',
|
|
||||||
botname: 'Riso BOT',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Home',
|
|
||||||
profile: 'Perfil',
|
|
||||||
payment: 'Pagamentos',
|
|
||||||
regok: 'Inscrição confirmada',
|
|
||||||
presentazione: 'Apresentação',
|
|
||||||
presentazione2: 'Apresentação',
|
|
||||||
invita: 'Convidar Pessoas',
|
|
||||||
SignUp: 'Inscrição',
|
|
||||||
SignUp_alreadylista: 'Inscrição para os que já estão na Lista!',
|
|
||||||
SignUp2: 'Inscrição',
|
|
||||||
SignIn: 'Login',
|
|
||||||
status: 'Estatísticas',
|
|
||||||
nextzoom: 'Conférences',
|
|
||||||
requestresetpwd: 'Pedido de redefinição de senha',
|
|
||||||
vreg: '',
|
|
||||||
dashboard: 'Tablero',
|
|
||||||
statoattuale: 'Status Atual',
|
|
||||||
posizione_in_programmazione: 'Lista de Embarque',
|
|
||||||
posizione_in_nave: 'Lista de Navios',
|
|
||||||
nave: 'Navios',
|
|
||||||
testimonial: 'Opiniones',
|
|
||||||
Test: 'Test',
|
|
||||||
Category: 'Categorie',
|
|
||||||
Admin: 'Admin',
|
|
||||||
Test1: 'Test1',
|
|
||||||
Test2: 'Test2',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Participantes',
|
|
||||||
passeggeri: 'Navios de Passageiros',
|
|
||||||
giainlista: 'Já na lista',
|
|
||||||
newreg: 'Últimas Inscrições:',
|
|
||||||
nationality: 'Nacionalidade',
|
|
||||||
verified: 'Verificado',
|
|
||||||
nonverified: 'Não verificado',
|
|
||||||
req7: 'Com 5 passos, o usuário entra na lista de embarque.',
|
|
||||||
req9: 'Com 7 passos ajudam a {sitename} a crescer!',
|
|
||||||
req: 'Passos',
|
|
||||||
people: 'Con.',
|
|
||||||
peoplelegend: 'Número de convidados',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppDescription: '',
|
|
||||||
keywords_base: '',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: '..',
|
|
||||||
sottoTitoloApp2: '..',
|
|
||||||
sottoTitoloApp3: '..',
|
|
||||||
sottoTitoloApp4: '',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
titlecontatti: 'CONTACTOS',
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
how: 'COMO FUNCIONA',
|
|
||||||
what: 'QUE NECESITAS',
|
|
||||||
step: 'PASOS A REALIZAR',
|
|
||||||
videotitle: 'VIDEO',
|
|
||||||
testimonial: 'TESTIMONIOS',
|
|
||||||
faq: 'PREGUNTAS FRECUENTES (FAQ)',
|
|
||||||
advise: 'CONSEJOS',
|
|
||||||
download: 'MATERIAL DISPONIBLES',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_pt;
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
const msg_website_si = {
|
|
||||||
ws: {
|
|
||||||
sitename: 'Riso',
|
|
||||||
siteshortname: 'RISO',
|
|
||||||
botname: 'Riso BOT',
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: 'Domača stran',
|
|
||||||
profile: 'Profil',
|
|
||||||
payment: 'Plačila',
|
|
||||||
regok: 'Registracija potrjena',
|
|
||||||
presentazione: 'Predstavitev',
|
|
||||||
presentazione2: 'Predstavitev',
|
|
||||||
invita: 'Povabi osebe',
|
|
||||||
SignUp: 'Nova Registracija',
|
|
||||||
SignUp2: 'Registracija',
|
|
||||||
SignIn: 'Vpis',
|
|
||||||
status: 'Statistika',
|
|
||||||
nextzoom: 'Conferenze',
|
|
||||||
requestresetpwd: 'Prošnja za ponastavitev Gesla',
|
|
||||||
vreg: 'Preveri Registracijo',
|
|
||||||
dashboard: 'Tabla',
|
|
||||||
statoattuale: 'TrenutniStatus',
|
|
||||||
posizione_in_programmazione: 'Seznam Plovbe',
|
|
||||||
posizione_in_nave: 'Seznam Ladiji',
|
|
||||||
nave: 'Ladje',
|
|
||||||
Admin: 'Administrator',
|
|
||||||
evento: 'Dogodek',
|
|
||||||
eventodef: 'Dogodek:',
|
|
||||||
statusreg: {
|
|
||||||
reg: 'Udeleženci',
|
|
||||||
passeggeri: 'Potniki Ladjic',
|
|
||||||
giainlista: 'Že na seznamu',
|
|
||||||
newreg: 'Zadnje Registracije:',
|
|
||||||
nationality: 'Nacionalnost',
|
|
||||||
verified: 'Preveri',
|
|
||||||
nonverified: 'Ni preverjeno',
|
|
||||||
req7: 'S 7 koraki vstopis na seznam za plovbo',
|
|
||||||
req9: 'Z 9-imi koraki pomagaš, da {sitename} Raste!',
|
|
||||||
req: 'Koraki',
|
|
||||||
people: 'Pov.',
|
|
||||||
peoplelegend: 'Število \'Povabljenih',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
msg: {
|
|
||||||
myAppDescription: '',
|
|
||||||
keywords_base: '',
|
|
||||||
myDescriz: '',
|
|
||||||
sottoTitoloApp: '',
|
|
||||||
sottoTitoloApp2: '',
|
|
||||||
sottoTitoloApp3: '',
|
|
||||||
sottoTitoloApp4: '',
|
|
||||||
},
|
|
||||||
homepage: {
|
|
||||||
titlecontatti: 'Kontakt',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default msg_website_si;
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import {
|
|
||||||
IListRoutes,
|
|
||||||
ILang,
|
|
||||||
IPreloadImages,
|
|
||||||
ISites,
|
|
||||||
} from '@model'
|
|
||||||
|
|
||||||
const firstPage = {
|
|
||||||
active: true,
|
|
||||||
order: 5,
|
|
||||||
path: '/',
|
|
||||||
materialIcon: 'home',
|
|
||||||
name: 'pages.home',
|
|
||||||
component: () => import('@src/root/home/home.vue'),
|
|
||||||
reqauth: false,
|
|
||||||
inmenu: true,
|
|
||||||
infooter: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDynamicPages(site: ISites): IListRoutes[] {
|
|
||||||
|
|
||||||
const baseroutes: IListRoutes[] = [
|
|
||||||
firstPage,
|
|
||||||
{
|
|
||||||
active: true,
|
|
||||||
order: 120,
|
|
||||||
path: '/editprofile',
|
|
||||||
materialIcon: 'fas fa-user',
|
|
||||||
name: 'pages.profile3',
|
|
||||||
component: () => import('@src/views/user/editprofile/editprofile.vue'),
|
|
||||||
meta: { requiresAuth: true },
|
|
||||||
inmenu: false,
|
|
||||||
infooter: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
active: true,
|
|
||||||
order: 135,
|
|
||||||
path: '/my/:username',
|
|
||||||
materialIcon: 'fas fa-user',
|
|
||||||
name: 'pages.profile2',
|
|
||||||
component: () => import('@src/views/user/myprofile/myprofile.vue'),
|
|
||||||
meta: { requiresAuth: true },
|
|
||||||
inmenu: false,
|
|
||||||
infooter: false,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
return baseroutes
|
|
||||||
}
|
|
||||||
|
|
||||||
export function firstimagehome() {
|
|
||||||
|
|
||||||
let img = 'statics/images/background.jpg'
|
|
||||||
return img
|
|
||||||
}
|
|
||||||
|
|
||||||
const preLoadImages: IPreloadImages[] = []
|
|
||||||
|
|
||||||
export const lang_available: ILang[] = []
|
|
||||||
export const arrLangUsed: string[] = []
|
|
||||||
|
|
||||||
export const preloadedimages = []
|
|
||||||
|
|
||||||
export const routes: IListRoutes[] = [firstPage]
|
|
||||||
|
|
||||||
export const static_data = {
|
|
||||||
routes,
|
|
||||||
arrLangUsed,
|
|
||||||
getDynamicPages,
|
|
||||||
lang_available,
|
|
||||||
preLoadImages,
|
|
||||||
preloadedimages,
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,4 +0,0 @@
|
|||||||
[Dolphin]
|
|
||||||
PreviewsShown=true
|
|
||||||
Timestamp=2022,9,21,18,57,21
|
|
||||||
Version=4
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 92 KiB |
@@ -1,141 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "kolibrilab",
|
|
||||||
"version": "1.2.69",
|
|
||||||
"description": "kolibrilab",
|
|
||||||
"productName": "kolibrilab",
|
|
||||||
"author": "Surya Paolo",
|
|
||||||
"private": true,
|
|
||||||
"keywords": [],
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
|
||||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
|
||||||
"build": "quasar build",
|
|
||||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
|
||||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
|
||||||
"type-check": "vue-tsc --noEmit",
|
|
||||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
|
||||||
"buildspa": "quasar build -m spa",
|
|
||||||
"lint": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./",
|
|
||||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
|
||||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
|
||||||
"fix": "eslint --ext .ts,.vue --ignore-path .gitignore ./ --fix > file.out.txt",
|
|
||||||
"pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.69' quasar dev -m pwa",
|
|
||||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
|
||||||
"spanorefresh": "NODE_ENV=development NODE_OPTIONS=--max_old_space_size=4096 DEBUG=v8:* quasar dev -m spa",
|
|
||||||
"test": "echo \"No test specified\" && exit 0",
|
|
||||||
"generate-sw": "workbox generateSW workbox-config.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@cubejs-client/core": "^1.2.26",
|
|
||||||
"@quasar/extras": "^1.16.17",
|
|
||||||
"@quasar/quasar-ui-qcalendar": "^4.1.2",
|
|
||||||
"@types/jsbarcode": "^3.11.4",
|
|
||||||
"@types/leaflet": "^1.9.17",
|
|
||||||
"@vue/compat": "^3.5.13",
|
|
||||||
"@vue/compiler-sfc": "^3.5.13",
|
|
||||||
"@vuelidate/core": "^2.0.3",
|
|
||||||
"@vuelidate/validators": "^2.0.4",
|
|
||||||
"acorn": "^8.14.1",
|
|
||||||
"animate.css": "^4.1.1",
|
|
||||||
"autoprefixer": "^10.4.21",
|
|
||||||
"axios": "^1.8.4",
|
|
||||||
"bcryptjs": "^3.0.2",
|
|
||||||
"chart.js": "^4.4.8",
|
|
||||||
"core-js": "^3.41.0",
|
|
||||||
"crypto-browserify": "^3.12.1",
|
|
||||||
"date-fns": "^4.1.0",
|
|
||||||
"echarts": "5.6.0",
|
|
||||||
"eslint-plugin-n": "^17.16.2",
|
|
||||||
"eslint-plugin-quasar": "^1.1.0",
|
|
||||||
"graphql": "^16.10.0",
|
|
||||||
"graphql-tag": "^2.12.6",
|
|
||||||
"gsap": "^3.12.7",
|
|
||||||
"html2pdf.js": "^0.10.3",
|
|
||||||
"jquery": "^3.7.1",
|
|
||||||
"js-cookie": "^3.0.5",
|
|
||||||
"jsbarcode": "^3.11.6",
|
|
||||||
"leaflet": "^1.9.4",
|
|
||||||
"leaflet-routing-machine": "^3.2.12",
|
|
||||||
"leaflet.markercluster": "^1.5.3",
|
|
||||||
"localforage": "^1.10.0",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"normalize.css": "^8.0.1",
|
|
||||||
"nprogress": "^0.2.0",
|
|
||||||
"pinia": "^3.0.1",
|
|
||||||
"qrcode-vue3": "^1.7.1",
|
|
||||||
"quasar": "^2.18.1",
|
|
||||||
"quasar-extras": "^2.0.9",
|
|
||||||
"register-service-worker": "^1.7.2",
|
|
||||||
"scrollreveal": "^4.0.9",
|
|
||||||
"typescript-eslint": "^8.27.0",
|
|
||||||
"vee-validate": "^4.15.0",
|
|
||||||
"vue": "^3.5.13",
|
|
||||||
"vue-class-component": "^8.0.0-rc.1",
|
|
||||||
"vue-country-code": "^1.1.3",
|
|
||||||
"vue-echarts": "^7.0.3",
|
|
||||||
"vue-i18n": "^11.1.2",
|
|
||||||
"vue-idb": "^0.2.0",
|
|
||||||
"vue-image-zoomer": "^2.4.4",
|
|
||||||
"vue-property-decorator": "^10.0.0-rc.3",
|
|
||||||
"vue-router": "^4.5.0",
|
|
||||||
"vue-scroll-reveal": "^2.1.0",
|
|
||||||
"vue-social-sharing": "^4.0.0-alpha4",
|
|
||||||
"vue-svgicon": "^4.0.0-alpha.3",
|
|
||||||
"vue-timeago3": "^2.3.2",
|
|
||||||
"vue2-dragula": "^2.5.5",
|
|
||||||
"vue3-pdf-app": "^1.0.3",
|
|
||||||
"vue3-qr-reader": "^1.0.0",
|
|
||||||
"vuex": "^4.1.0",
|
|
||||||
"vuex-router-sync": "^6.0.0-rc.1",
|
|
||||||
"workbox-core": "^7.3.0",
|
|
||||||
"workbox-precaching": "^7.3.0",
|
|
||||||
"workbox-routing": "^7.3.0",
|
|
||||||
"workbox-strategies": "^7.3.0",
|
|
||||||
"workbox-window": "^7.3.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@eslint/js": "^9.23.0",
|
|
||||||
"@intlify/unplugin-vue-i18n": "^6.0.5",
|
|
||||||
"@quasar/app-vite": "^2.1.4",
|
|
||||||
"@types/google.maps": "^3.58.1",
|
|
||||||
"@types/jest": "^29.5.14",
|
|
||||||
"@types/js-cookie": "^3.0.6",
|
|
||||||
"@types/node": "^22.13.11",
|
|
||||||
"@types/nprogress": "^0.2.3",
|
|
||||||
"@types/vue-tel-input": "^2.1.7",
|
|
||||||
"@types/vuelidate": "^0.7.22",
|
|
||||||
"@vue/devtools": "^7.7.2",
|
|
||||||
"@vue/eslint-config-prettier": "^10.2.0",
|
|
||||||
"@vue/eslint-config-typescript": "^14.5.0",
|
|
||||||
"autoprefixer": "^10.4.21",
|
|
||||||
"eslint": "9",
|
|
||||||
"eslint-plugin-import": "^2.31.0",
|
|
||||||
"eslint-plugin-vue": "^10.0.0",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"globals": "^16.0.0",
|
|
||||||
"http-proxy-middleware": "^3.0.3",
|
|
||||||
"jest": "^29.7.0",
|
|
||||||
"json-loader": "^0.5.7",
|
|
||||||
"nodemon": "^3.1.9",
|
|
||||||
"npm-check-updates": "^17.1.16",
|
|
||||||
"parcel": "^2.14.1",
|
|
||||||
"postcss": "^8.5.3",
|
|
||||||
"postcss-loader": "^8.1.1",
|
|
||||||
"prettier": "3",
|
|
||||||
"strip-ansi": "=7.1.0",
|
|
||||||
"ts-jest": "^29.2.6",
|
|
||||||
"typescript": "5.7.3",
|
|
||||||
"vite-plugin-checker": "^0.9.1",
|
|
||||||
"vue-cli-plugin-element-ui": "^1.1.4",
|
|
||||||
"vue-eslint-parser": "^10.1.1",
|
|
||||||
"vue-tsc": "^2.2.8",
|
|
||||||
"vueify": "^9.4.1",
|
|
||||||
"workbox-build": "^7.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^28 || ^26 || ^24 || ^22 || ^20 || ^18",
|
|
||||||
"npm": ">= 6.13.4",
|
|
||||||
"yarn": ">= 1.21.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
source __sites_list.sh
|
|
||||||
|
|
||||||
for mysite in "${sites[@]}"; do
|
|
||||||
if [ -d "$mysite" ]; then
|
|
||||||
rmdir "my$site"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
site=kolibrilab.it
|
|
||||||
|
|
||||||
source __inizia.sh
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
site=kolibrilab.it
|
|
||||||
|
|
||||||
source __termine.sh
|
|
||||||
@@ -178,6 +178,11 @@ export const shared_consts = {
|
|||||||
SECTION: 1000,
|
SECTION: 1000,
|
||||||
ROW: 1100,
|
ROW: 1100,
|
||||||
COLUMN: 1200,
|
COLUMN: 1200,
|
||||||
|
IMAGE_GALLERY: 101,
|
||||||
|
HEADING: 102,
|
||||||
|
LIST: 103,
|
||||||
|
CODE: 104,
|
||||||
|
DIVIDER: 105,
|
||||||
},
|
},
|
||||||
|
|
||||||
QUERYTYPE_MYGROUP: 1,
|
QUERYTYPE_MYGROUP: 1,
|
||||||
|
|||||||
@@ -144,5 +144,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-style: italic;
|
font-size: 0.85em;
|
||||||
}
|
color: #666;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,63 +1,72 @@
|
|||||||
import { computed, defineComponent, onMounted, PropType, ref, toRef, watch } from 'vue'
|
import { computed, defineComponent, PropType } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
import { useUserStore } from '@store/UserStore'
|
const norm = (path: string): string =>
|
||||||
import { useGlobalStore } from '@store/globalStore'
|
path
|
||||||
import { useQuasar } from 'quasar'
|
.trim()
|
||||||
import { costanti } from '@costanti'
|
.replace(/^\/+|\/+$/g, '')
|
||||||
import { fieldsTable } from '@store/Modules/fieldsTable'
|
.toLowerCase();
|
||||||
import { shared_consts } from '@src/common/shared_vuejs'
|
|
||||||
import { IColGridTable, IOperators } from 'model'
|
const toNormPath = (p: any): string => {
|
||||||
import { tools } from '@tools'
|
if (!p) return '';
|
||||||
import { static_data } from '@src/db/static_data'
|
if (typeof p === 'string') return norm(p);
|
||||||
|
return norm(p.path || '');
|
||||||
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CMenuItem',
|
name: 'CMenuItem',
|
||||||
props: {
|
props: {
|
||||||
item: Object,
|
item: { type: Object, required: true },
|
||||||
getroute: Function,
|
tools: { type: Object, required: true },
|
||||||
getmymenuclass: Function,
|
getroute: { type: Function, required: true },
|
||||||
getimgiconclass: Function,
|
getmymenuclass: { type: Function, required: true },
|
||||||
clBase: String,
|
getimgiconclass: { type: Function, required: true },
|
||||||
mainMenu: Boolean,
|
clBase: { type: String, default: '' },
|
||||||
level: {
|
level: { type: Number, default: 1 },
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
setup(props) {
|
||||||
|
const getmenuByPath = (input: any, depth = 0): any => {
|
||||||
|
if (depth > 5) return null;
|
||||||
|
|
||||||
components: {},
|
const path = toNormPath(input);
|
||||||
setup(props, { emit }) {
|
if (!path) return null;
|
||||||
const $q = useQuasar()
|
|
||||||
const { t } = useI18n()
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const globalStore = useGlobalStore()
|
|
||||||
|
|
||||||
function mounted() {
|
let page = props.tools.getmenuByPath ? props.tools.getmenuByPath(path) : null;
|
||||||
// ...
|
if (!page) return null;
|
||||||
|
|
||||||
}
|
// Evita loop
|
||||||
|
const selfPath = toNormPath(props.item);
|
||||||
|
if (selfPath && path === selfPath) return null;
|
||||||
|
|
||||||
function getmenuByPath(pathoobj: any) {
|
return page;
|
||||||
let mymenufind = null
|
};
|
||||||
if (tools.isObject(pathoobj)) {
|
|
||||||
mymenufind = pathoobj
|
|
||||||
} else {
|
|
||||||
mymenufind = static_data.routes.find((menu: any) => menu.path === '/' + pathoobj)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mymenufind
|
const children = computed(() => {
|
||||||
}
|
const item: any = props.item;
|
||||||
|
const r2 = Array.isArray(item.routes2) ? item.routes2 : [];
|
||||||
|
const sm = Array.isArray(item.sottoMenu) ? item.sottoMenu : [];
|
||||||
|
|
||||||
onMounted(mounted)
|
return [...r2, ...sm]
|
||||||
|
.map((ref) =>
|
||||||
|
typeof ref === 'string' || !ref.path ? getmenuByPath(ref, props.level) : ref
|
||||||
|
)
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort((a: any, b: any) => (a.order ?? 0) - (b.order ?? 0));
|
||||||
|
});
|
||||||
|
|
||||||
function makeClick() {
|
const hasChildren = computed(() => children.value.length > 0);
|
||||||
}
|
|
||||||
|
const icon = computed(() => {
|
||||||
|
const item: any = props.item;
|
||||||
|
return item.materialIcon || item.icon || 'far fa-file-alt';
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tools,
|
children,
|
||||||
getmenuByPath,
|
hasChildren,
|
||||||
makeClick,
|
icon,
|
||||||
}
|
makeClick: () => {
|
||||||
}
|
// niente per ora
|
||||||
})
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,57 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ paddingLeft: `${level * 4}px` }">
|
<div :style="{ paddingLeft: `${level * 4}px` }">
|
||||||
|
|
||||||
<q-separator v-if="item.isseparator" />
|
<q-separator v-if="item.isseparator" />
|
||||||
|
|
||||||
|
<!-- Nodo con figli -->
|
||||||
<q-expansion-item
|
<q-expansion-item
|
||||||
v-else-if="item.routes2 || (item.sottoMenu && item.sottoMenu.length > 0)"
|
v-else-if="hasChildren"
|
||||||
:content-inset-level="item.level_parent"
|
|
||||||
:header-class="getmymenuclass(item)"
|
:header-class="getmymenuclass(item)"
|
||||||
:header-inset-level="item.level_parent"
|
|
||||||
:icon="item.materialIcon"
|
:icon="item.materialIcon"
|
||||||
:label="tools.getLabelByItem(item)"
|
:label="tools.getLabelByItem(item)"
|
||||||
|
expand-icon="fas fa-chevron-down"
|
||||||
active-class="my-menu-active"
|
active-class="my-menu-active"
|
||||||
:expand-icon-class="item.mainMenu ? 'my-menu-separat' : ''"
|
|
||||||
:expand-icon="
|
|
||||||
item.mainMenu || item.routes2 ? 'fas fa-chevron-down' : 'none'
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<router-link :to="getroute(item)" custom>
|
<CMenuItem
|
||||||
<c-menu-item
|
v-for="(child, idx) in children"
|
||||||
v-for="(childItem, childIndex) in item.routes2 || (item.sottoMenu && item.sottoMenu.length > 0)"
|
:key="child._id || child.path || idx"
|
||||||
:key="childIndex"
|
:item="child"
|
||||||
:item="getmenuByPath(childItem)"
|
:tools="tools"
|
||||||
:tools="tools"
|
:getroute="getroute"
|
||||||
:getroute="getroute"
|
:getmymenuclass="getmymenuclass"
|
||||||
:getmymenuclass="getmymenuclass"
|
:getimgiconclass="getimgiconclass"
|
||||||
:getimgiconclass="getimgiconclass"
|
:clBase="clBase"
|
||||||
:clBase="clBase"
|
:level="level + 1"
|
||||||
:mainMenu="item.mainMenu"
|
/>
|
||||||
:level="level + 1"
|
|
||||||
/>
|
|
||||||
</router-link>
|
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
<router-link v-else :to="getroute(item)" custom>
|
|
||||||
<q-item
|
<!-- Foglia -->
|
||||||
clickable
|
<router-link v-else :to="getroute(item)">
|
||||||
:to="getroute(item)"
|
<q-item clickable :to="getroute(item)" @click="makeClick" active-class="my-menu-active">
|
||||||
@click="makeClick"
|
|
||||||
:content-inset-level="item.level_parent"
|
|
||||||
:header-inset-level="item.level_parent"
|
|
||||||
active-class="my-menu-active"
|
|
||||||
expand-icon="none"
|
|
||||||
>
|
|
||||||
<q-item-section thumbnail>
|
<q-item-section thumbnail>
|
||||||
<q-avatar
|
<q-avatar
|
||||||
:icon="item.materialIcon"
|
:icon="item.materialIcon"
|
||||||
:size="!!item.iconsize ? item.iconsize : '2rem'"
|
:size="item.iconsize || '2rem'"
|
||||||
:font-size="!!item.iconsize ? item.iconsize : '2rem'"
|
:font-size="item.iconsize || '2rem'"
|
||||||
text-color="primary"
|
text-color="primary"
|
||||||
square
|
square
|
||||||
rounded
|
rounded
|
||||||
>
|
/>
|
||||||
</q-avatar>
|
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<span :class="item.extraclass">{{ tools.getLabelByItem(item) }}</span>
|
<span :class="item.extraclass">{{ tools.getLabelByItem(item) }}</span>
|
||||||
<span v-if="item.subtitle" class="subtitle">{{ item.subtitle }}</span>
|
<span v-if="item.subtitle" class="subtitle">{{ item.subtitle }}</span>
|
||||||
|
|||||||
16
src/components/CMyCode/CMyCode.scss
Executable file
16
src/components/CMyCode/CMyCode.scss
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
.cmy-code {
|
||||||
|
background: #0f172a;
|
||||||
|
color: #e2e8f0;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.code-toolbar { background: rgba(255,255,255,0.04); }
|
||||||
|
.code-pre {
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px 14px 14px;
|
||||||
|
overflow: auto;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/components/CMyCode/CMyCode.ts
Executable file
27
src/components/CMyCode/CMyCode.ts
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
import { defineComponent, ref, computed } from 'vue';
|
||||||
|
import { copyToClipboard } from 'quasar';
|
||||||
|
import './CmyCode.scss';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CmyCode',
|
||||||
|
props: {
|
||||||
|
code: { type: String, required: true },
|
||||||
|
language: { type: String, default: 'text' }
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const copied = ref(false);
|
||||||
|
const language = computed(() => props.language || 'text');
|
||||||
|
|
||||||
|
async function copy() {
|
||||||
|
try {
|
||||||
|
await copyToClipboard(props.code || '');
|
||||||
|
copied.value = true;
|
||||||
|
setTimeout(() => (copied.value = false), 1200);
|
||||||
|
} catch (e) {
|
||||||
|
// opzionale: notifica $q.notify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { copy, copied, language, code: props.code };
|
||||||
|
}
|
||||||
|
});
|
||||||
19
src/components/CMyCode/CMyCode.vue
Executable file
19
src/components/CMyCode/CMyCode.vue
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cmy-code">
|
||||||
|
<div class="code-toolbar row items-center justify-between q-px-sm q-pt-sm">
|
||||||
|
<div class="text-caption">{{ language?.toUpperCase() || 'CODE' }}</div>
|
||||||
|
<q-btn flat dense icon="content_copy" @click="copy" :label="copied ? 'Copiato' : 'Copia'" />
|
||||||
|
</div>
|
||||||
|
<pre class="code-pre"><code :class="`lang-${language || 'text'}`">{{ code }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" src="./CMyCode.ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './CMyCode.scss';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
1
src/components/CMyCode/index.ts
Executable file
1
src/components/CMyCode/index.ts
Executable file
@@ -0,0 +1 @@
|
|||||||
|
export {default as CMyCode} from './CMyCode.vue'
|
||||||
12
src/components/CMyDivider/CMyDivider.scss
Executable file
12
src/components/CMyDivider/CMyDivider.scss
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
.cmy-divider {
|
||||||
|
.q-separator {
|
||||||
|
&[class~="is-dotted"] { border-top-style: dotted !important; }
|
||||||
|
border-color: var(--divider-color, currentColor);
|
||||||
|
}
|
||||||
|
.divider-label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
opacity: 0.7;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/components/CMyDivider/CMyDivider.ts
Executable file
30
src/components/CMyDivider/CMyDivider.ts
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
import { defineComponent, computed } from 'vue';
|
||||||
|
import './CMyDivider.scss';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CMyDivider',
|
||||||
|
props: {
|
||||||
|
label: { type: String, default: '' },
|
||||||
|
color: { type: String, default: '' }, // quasar key o hex
|
||||||
|
size: { type: Number, default: 1 }, // px
|
||||||
|
dotted: { type: Boolean, default: false },
|
||||||
|
inset: { type: Boolean, default: false },
|
||||||
|
marginY: { type: Number, default: 0 }
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const qColor = computed(() =>
|
||||||
|
props.color && !props.color.startsWith('#') ? props.color : undefined
|
||||||
|
);
|
||||||
|
const sizePx = computed(() => props.size + 'px');
|
||||||
|
const sepClass = computed(() => (props.dotted ? 'is-dotted' : ''));
|
||||||
|
|
||||||
|
const styleVars = computed(() => {
|
||||||
|
const style: Record<string, string> = {};
|
||||||
|
if (props.marginY != null) style.margin = `${props.marginY}px 0`;
|
||||||
|
if (props.color && props.color.startsWith('#')) style['--divider-color'] = props.color;
|
||||||
|
return style;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { styleVars, qColor, sepClass, sizePx, inset: props.inset, label: props.label };
|
||||||
|
}
|
||||||
|
});
|
||||||
16
src/components/CMyDivider/CMyDivider.vue
Executable file
16
src/components/CMyDivider/CMyDivider.vue
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cmy-divider" :style="styleVars">
|
||||||
|
<q-separator :spaced="false" :inset="inset" :color="qColor" :size="sizePx" :class="sepClass" />
|
||||||
|
<div v-if="label" class="divider-label">{{ label }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" src="./CMyDivider.ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './CMyDivider.scss';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
1
src/components/CMyDivider/index.ts
Executable file
1
src/components/CMyDivider/index.ts
Executable file
@@ -0,0 +1 @@
|
|||||||
|
export {default as CMyDivider} from './CMyDivider.vue'
|
||||||
@@ -41,6 +41,7 @@ import { CMySize } from '@src/components/CMySize';
|
|||||||
import { CBorders } from '@src/components/CBorders';
|
import { CBorders } from '@src/components/CBorders';
|
||||||
import { CMyDimensioni } from '@src/components/CMyDimensioni';
|
import { CMyDimensioni } from '@src/components/CMyDimensioni';
|
||||||
import { CMyText } from '@src/components/CMyText';
|
import { CMyText } from '@src/components/CMyText';
|
||||||
|
import { CPickColor } from '@src/components/CPickColor';
|
||||||
|
|
||||||
import MixinMetaTags from '@src/mixins/mixin-metatags';
|
import MixinMetaTags from '@src/mixins/mixin-metatags';
|
||||||
import MixinBase from '@src/mixins/mixin-base';
|
import MixinBase from '@src/mixins/mixin-base';
|
||||||
@@ -76,6 +77,7 @@ export default defineComponent({
|
|||||||
CMyText,
|
CMyText,
|
||||||
CMySlideNumber,
|
CMySlideNumber,
|
||||||
CMyElemAdd,
|
CMyElemAdd,
|
||||||
|
CPickColor,
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'saveElem',
|
'saveElem',
|
||||||
@@ -138,6 +140,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
const Products = useProducts();
|
const Products = useProducts();
|
||||||
|
|
||||||
|
const colorPicker = ref(null);
|
||||||
|
|
||||||
const neworder = ref(<number | undefined>0);
|
const neworder = ref(<number | undefined>0);
|
||||||
|
|
||||||
const idSchedaDaCopiare = ref('');
|
const idSchedaDaCopiare = ref('');
|
||||||
@@ -811,6 +815,11 @@ export default defineComponent({
|
|||||||
emit('selElemClick', newrec);
|
emit('selElemClick', newrec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openColorPicker() {
|
||||||
|
// Apre la finestra del picker
|
||||||
|
colorPicker.value.openDialog();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(mounted);
|
onMounted(mounted);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -879,6 +888,8 @@ export default defineComponent({
|
|||||||
naviga,
|
naviga,
|
||||||
isElementoSpecifico,
|
isElementoSpecifico,
|
||||||
AddedNewElem,
|
AddedNewElem,
|
||||||
|
openColorPicker,
|
||||||
|
colorPicker,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1097,6 +1097,47 @@
|
|||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.HEADING">
|
||||||
|
<div
|
||||||
|
v-if="enableEdit"
|
||||||
|
class="row q-col-gutter-sm"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
label="Titolo:"
|
||||||
|
@update:model-value="modifElem"
|
||||||
|
v-model="myel.container"
|
||||||
|
filled
|
||||||
|
v-on:keyup.enter="saveElem"
|
||||||
|
>
|
||||||
|
</q-input>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
label="Livello:"
|
||||||
|
@update:model-value="modifElem"
|
||||||
|
v-model="myel.number"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="5"
|
||||||
|
filled
|
||||||
|
v-on:keyup.enter="saveElem"
|
||||||
|
>
|
||||||
|
</q-input>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
icon="fas fa-palette"
|
||||||
|
color="primary"
|
||||||
|
@click="openColorPicker"
|
||||||
|
>
|
||||||
|
</q-btn>
|
||||||
|
<CPickColor
|
||||||
|
ref="colorPicker"
|
||||||
|
v-model="myel.color"
|
||||||
|
@update:model-value="modifElem"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO_YOUTUBE">
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO_YOUTUBE">
|
||||||
<div
|
<div
|
||||||
v-if="enableEdit"
|
v-if="enableEdit"
|
||||||
@@ -1141,7 +1182,6 @@
|
|||||||
v-on:keyup.enter="saveElem"
|
v-on:keyup.enter="saveElem"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.FOOTER"></div>
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.FOOTER"></div>
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ import { CNotifAtTop } from '@src/components/CNotifAtTop';
|
|||||||
import { CPresentazione } from '@src/components/CPresentazione';
|
import { CPresentazione } from '@src/components/CPresentazione';
|
||||||
import { CRegistration } from '@src/components/CRegistration';
|
import { CRegistration } from '@src/components/CRegistration';
|
||||||
import { CShareSocial } from '@src/components/CShareSocial';
|
import { CShareSocial } from '@src/components/CShareSocial';
|
||||||
|
import { CMyImageGallery } from '@src/components/CMyImageGallery';
|
||||||
|
import { CMyHeading } from '@src/components/CMyHeading';
|
||||||
|
import { CMyList } from '@src/components/CMyList';
|
||||||
|
import { CMyCode } from '@src/components/CMyCode';
|
||||||
|
import { CMyDivider } from '@src/components/CMyDivider';
|
||||||
import { CVisuVideoPromoAndPDF } from '@src/components/CVisuVideoPromoAndPDF';
|
import { CVisuVideoPromoAndPDF } from '@src/components/CVisuVideoPromoAndPDF';
|
||||||
|
|
||||||
import MixinMetaTags from '@src/mixins/mixin-metatags';
|
import MixinMetaTags from '@src/mixins/mixin-metatags';
|
||||||
@@ -119,6 +124,11 @@ export default defineComponent({
|
|||||||
CRow,
|
CRow,
|
||||||
CColumn,
|
CColumn,
|
||||||
CMyVideoYoutube,
|
CMyVideoYoutube,
|
||||||
|
CMyDivider,
|
||||||
|
CMyImageGallery,
|
||||||
|
CMyHeading,
|
||||||
|
CMyList,
|
||||||
|
CMyCode,
|
||||||
// , //CMapMarker,
|
// , //CMapMarker,
|
||||||
},
|
},
|
||||||
emits: ['selElemClick'],
|
emits: ['selElemClick'],
|
||||||
|
|||||||
@@ -355,6 +355,26 @@
|
|||||||
:ccLoad="myelem.ccLoad ?? false"
|
:ccLoad="myelem.ccLoad ?? false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGE_GALLERY">
|
||||||
|
<CMyImageGallery> </CMyImageGallery>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.HEADING">
|
||||||
|
<CMyHeading
|
||||||
|
:text="myel.container"
|
||||||
|
:level="myelem.number"
|
||||||
|
:color="myelem.color"
|
||||||
|
>
|
||||||
|
</CMyHeading>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.LIST">
|
||||||
|
<CMyList> </CMyList>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CODE">
|
||||||
|
<CMyCode> </CMyCode>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.DIVIDER">
|
||||||
|
<CMyDivider> </CMyDivider>
|
||||||
|
</div>
|
||||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGE">
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGE">
|
||||||
<div
|
<div
|
||||||
:class="myel.class + (editOn ? ` clEdit` : ``) + getClass()"
|
:class="myel.class + (editOn ? ` clEdit` : ``) + getClass()"
|
||||||
|
|||||||
4
src/components/CMyHeading/CMyHeading.scss
Executable file
4
src/components/CMyHeading/CMyHeading.scss
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
.cmy-heading {
|
||||||
|
margin: 0;
|
||||||
|
&.underline { text-decoration: underline; text-underline-offset: 4px; }
|
||||||
|
}
|
||||||
30
src/components/CMyHeading/CMyHeading.ts
Executable file
30
src/components/CMyHeading/CMyHeading.ts
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
import { defineComponent, computed } from 'vue';
|
||||||
|
import './CMyHEADING.scss';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CMyHeading',
|
||||||
|
props: {
|
||||||
|
text: { type: String, default: '' },
|
||||||
|
level: { type: Number as () => 1|2|3|4|5|6, default: 2 },
|
||||||
|
align: { type: String as () => 'left'|'center'|'right'|'justify', default: 'center' },
|
||||||
|
color: { type: String, default: '' }, // quasar key o hex
|
||||||
|
weight: { type: [String, Number] as () => 'light'|'normal'|'medium'|'bold'|number, default: 'bold' },
|
||||||
|
underline: { type: Boolean, default: false }
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const tagName = computed(() => `h${props.level}`);
|
||||||
|
const alignClass = computed(() => {
|
||||||
|
switch (props.align) {
|
||||||
|
case 'center': return 'text-center';
|
||||||
|
case 'right': return 'text-right';
|
||||||
|
case 'justify': return 'text-justify';
|
||||||
|
default: return 'text-left';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const styleVars = computed(() => {
|
||||||
|
const color = props.color ? (props.color.startsWith('#') ? props.color : `var(--q-${props.color})`) : 'inherit';
|
||||||
|
return { color, fontWeight: String(props.weight) } as Record<string, string>;
|
||||||
|
});
|
||||||
|
return { tagName, alignClass, styleVars };
|
||||||
|
}
|
||||||
|
});
|
||||||
19
src/components/CMyHeading/CMyHeading.vue
Executable file
19
src/components/CMyHeading/CMyHeading.vue
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<component
|
||||||
|
:is="tagName"
|
||||||
|
class="cmy-heading"
|
||||||
|
:class="[{ underline }, alignClass]"
|
||||||
|
:style="styleVars"
|
||||||
|
>
|
||||||
|
<slot>{{ text }}</slot>
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./CMyHeading.ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './CMyHeading.scss';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
1
src/components/CMyHeading/index.ts
Executable file
1
src/components/CMyHeading/index.ts
Executable file
@@ -0,0 +1 @@
|
|||||||
|
export {default as CMyHeading} from './CMyHeading.vue'
|
||||||
15
src/components/CMyImageGallery/CMyImageGallery.scss
Executable file
15
src/components/CMyImageGallery/CMyImageGallery.scss
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
.cmy-image-gallery {
|
||||||
|
&.layout-grid {
|
||||||
|
.gallery-grid { display: grid; }
|
||||||
|
.gallery-item {
|
||||||
|
cursor: pointer;
|
||||||
|
.gallery-img { border-radius: 10px; overflow: hidden; }
|
||||||
|
.gallery-caption { font-size: 0.9rem; opacity: 0.8; margin-top: 6px; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.layout-carousel {
|
||||||
|
.carousel-img { max-width: 100%; border-radius: 12px; }
|
||||||
|
}
|
||||||
|
.lightbox-card { width: min(92vw, 1100px); }
|
||||||
|
.lightbox-img { max-height: 76vh; object-fit: contain; }
|
||||||
|
}
|
||||||
59
src/components/CMyImageGallery/CMyImageGallery.ts
Executable file
59
src/components/CMyImageGallery/CMyImageGallery.ts
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
import { defineComponent, ref, computed, type Ref } from 'vue';
|
||||||
|
|
||||||
|
export type GalleryImage = {
|
||||||
|
src: string;
|
||||||
|
alt?: string;
|
||||||
|
caption?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CMyImageGallery',
|
||||||
|
props: {
|
||||||
|
images: { type: Array as () => GalleryImage[], required: true },
|
||||||
|
layout: { type: String as () => 'grid' | 'carousel', default: 'grid' },
|
||||||
|
cols: { type: Number, default: 3 },
|
||||||
|
gap: { type: Number, default: 12 },
|
||||||
|
ratio: { type: Number, default: 1 },
|
||||||
|
lightbox: { type: Boolean, default: false }
|
||||||
|
},
|
||||||
|
emits: ['imageClick'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const slide: Ref<number> = ref(0);
|
||||||
|
const lightboxOpen = ref(false);
|
||||||
|
const currentIndex = ref(0);
|
||||||
|
|
||||||
|
const gridStyle = computed(() => ({
|
||||||
|
gridTemplateColumns: `repeat(${props.cols}, 1fr)`,
|
||||||
|
gap: props.gap + 'px'
|
||||||
|
}));
|
||||||
|
|
||||||
|
const currentImage = computed(() => props.images?.[currentIndex.value] ?? null);
|
||||||
|
|
||||||
|
function onImageClick(idx: number) {
|
||||||
|
emit('imageClick', idx, props.images[idx]);
|
||||||
|
if (props.lightbox) {
|
||||||
|
currentIndex.value = idx;
|
||||||
|
lightboxOpen.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function next() {
|
||||||
|
if (!props.images?.length) return;
|
||||||
|
currentIndex.value = (currentIndex.value + 1) % props.images.length;
|
||||||
|
}
|
||||||
|
function prev() {
|
||||||
|
if (!props.images?.length) return;
|
||||||
|
currentIndex.value = (currentIndex.value - 1 + props.images.length) % props.images.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
slide,
|
||||||
|
lightboxOpen,
|
||||||
|
currentIndex,
|
||||||
|
currentImage,
|
||||||
|
gridStyle,
|
||||||
|
onImageClick,
|
||||||
|
next,
|
||||||
|
prev
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
67
src/components/CMyImageGallery/CMyImageGallery.vue
Executable file
67
src/components/CMyImageGallery/CMyImageGallery.vue
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cmy-image-gallery" :class="[`layout-${layout}`]">
|
||||||
|
<!-- GRID -->
|
||||||
|
<div v-if="layout === 'grid'" class="gallery-grid" :style="gridStyle">
|
||||||
|
<div
|
||||||
|
v-for="(img, idx) in images"
|
||||||
|
:key="idx"
|
||||||
|
class="gallery-item"
|
||||||
|
@click="onImageClick(idx)"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<q-img :src="img.src" :alt="img.alt || ''" :ratio="ratio" class="gallery-img" />
|
||||||
|
<div v-if="img.caption" class="gallery-caption">{{ img.caption }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CAROUSEL -->
|
||||||
|
<q-carousel
|
||||||
|
v-else
|
||||||
|
v-model="slide"
|
||||||
|
animated
|
||||||
|
arrows
|
||||||
|
swipeable
|
||||||
|
infinite
|
||||||
|
class="gallery-carousel"
|
||||||
|
height="auto"
|
||||||
|
>
|
||||||
|
<q-carousel-slide
|
||||||
|
v-for="(img, idx) in images"
|
||||||
|
:key="idx"
|
||||||
|
:name="idx"
|
||||||
|
class="column items-center q-pa-md"
|
||||||
|
>
|
||||||
|
<q-img :src="img.src" :alt="img.alt || ''" :ratio="ratio" class="carousel-img" />
|
||||||
|
<div v-if="img.caption" class="gallery-caption q-mt-sm">{{ img.caption }}</div>
|
||||||
|
</q-carousel-slide>
|
||||||
|
</q-carousel>
|
||||||
|
|
||||||
|
<!-- Lightbox -->
|
||||||
|
<q-dialog v-model="lightboxOpen" persistent>
|
||||||
|
<q-card class="lightbox-card">
|
||||||
|
<q-card-section class="row items-center justify-between">
|
||||||
|
<div class="text-subtitle1">{{ currentImage?.caption }}</div>
|
||||||
|
<q-btn flat round icon="close" @click="lightboxOpen = false" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator />
|
||||||
|
<q-card-section class="q-pa-none">
|
||||||
|
<q-img :src="currentImage?.src" :alt="currentImage?.alt || ''" class="lightbox-img" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="between">
|
||||||
|
<q-btn flat icon="chevron_left" @click="prev" />
|
||||||
|
<q-btn flat icon="chevron_right" @click="next" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./CMyImageGallery.ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './CMyImageGallery.scss';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
1
src/components/CMyImageGallery/index.ts
Executable file
1
src/components/CMyImageGallery/index.ts
Executable file
@@ -0,0 +1 @@
|
|||||||
|
export {default as CMyImageGallery} from './CMyImageGallery.vue'
|
||||||
9
src/components/CMyList/CMyList.scss
Executable file
9
src/components/CMyList/CMyList.scss
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
.cmy-list {
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
margin: 0;
|
||||||
|
&.dense .list-item { margin-bottom: 2px; }
|
||||||
|
.list-item {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
.list-text { line-height: 1.5; }
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/components/CMyList/CMyList.ts
Executable file
22
src/components/CMyList/CMyList.ts
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
import { defineComponent, computed } from 'vue';
|
||||||
|
import './CMyList.scss';
|
||||||
|
|
||||||
|
export type ListItem = { text: string; icon?: string };
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CMyList',
|
||||||
|
props: {
|
||||||
|
items: { type: Array as () => Array<string | ListItem>, required: true },
|
||||||
|
ordered: { type: Boolean, default: false },
|
||||||
|
dense: { type: Boolean, default: false }
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const listTag = computed(() => (props.ordered ? 'ol' : 'ul'));
|
||||||
|
const normalized = computed<ListItem[]>(() =>
|
||||||
|
(props.items || []).map(it => (typeof it === 'string' ? { text: it } : it))
|
||||||
|
);
|
||||||
|
const ordered = computed(() => !!props.ordered);
|
||||||
|
const dense = computed(() => !!props.dense);
|
||||||
|
return { listTag, normalized, ordered, dense };
|
||||||
|
}
|
||||||
|
});
|
||||||
18
src/components/CMyList/CMyList.vue
Executable file
18
src/components/CMyList/CMyList.vue
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<component :is="listTag" class="cmy-list" :class="[dense ? 'dense' : '']">
|
||||||
|
<li v-for="(item, idx) in normalized" :key="idx" class="list-item row items-start no-wrap">
|
||||||
|
<q-icon v-if="item.icon && !ordered" :name="item.icon" class="q-mr-sm" />
|
||||||
|
<span class="list-text" v-html="item.text"></span>
|
||||||
|
</li>
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" src="./CMyList.ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './CMyList.scss';
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
1
src/components/CMyList/index.ts
Executable file
1
src/components/CMyList/index.ts
Executable file
@@ -0,0 +1 @@
|
|||||||
|
export {default as CMyList} from './CMyList.vue'
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.indent-spacer {
|
||||||
|
width: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import { defineComponent, ref, computed, onMounted, watch, onBeforeUnmount } from 'vue';
|
|
||||||
import { IMyPage } from 'app/src/model';
|
|
||||||
|
|
||||||
type PageWithKey = IMyPage & { __key?: string };
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'MenuPageItem',
|
|
||||||
props: {
|
|
||||||
item: { type: Object as () => PageWithKey, required: true },
|
|
||||||
selected: { type: Boolean, default: false },
|
|
||||||
active: { type: Boolean, default: false }, // v-model:active
|
|
||||||
variant: { type: String as () => 'menu' | 'off', default: 'menu' },
|
|
||||||
showGrip: { type: Boolean, default: true },
|
|
||||||
draggableHandleClass: { type: String, default: 'drag-handle' },
|
|
||||||
depth: { type: Number, default: 0 },
|
|
||||||
},
|
|
||||||
emits: ['select', 'edit', 'delete', 'open', 'update:active', 'update:item'],
|
|
||||||
setup(props, { emit }) {
|
|
||||||
function displayPath(path?: string) {
|
|
||||||
if (!path) return '-';
|
|
||||||
return path.startsWith('/') ? path : '/' + path;
|
|
||||||
}
|
|
||||||
function emitSelect() {
|
|
||||||
emit('select', props.item.__key);
|
|
||||||
}
|
|
||||||
function emitEdit() {
|
|
||||||
emit('edit', props.item.__key);
|
|
||||||
}
|
|
||||||
function emitDelete() {
|
|
||||||
emit('delete', props.item.__key);
|
|
||||||
}
|
|
||||||
function emitOpen() {
|
|
||||||
emit('open', props.item.__key);
|
|
||||||
}
|
|
||||||
|
|
||||||
const indentSpacerStyle = computed(() => {
|
|
||||||
const px = Math.min(props.depth, 6) * 16; // max 6 livelli x 16px
|
|
||||||
return { width: `${px}px`, minWidth: `${px}px` };
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
displayPath,
|
|
||||||
emitSelect,
|
|
||||||
emitEdit,
|
|
||||||
emitDelete,
|
|
||||||
emitOpen,
|
|
||||||
indentSpacerStyle,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
clickable
|
clickable
|
||||||
:active="selected"
|
:active="selected"
|
||||||
@click="emitSelect"
|
@click="emitSelect"
|
||||||
|
:class="{ 'menu-item': variant === 'menu' }"
|
||||||
>
|
>
|
||||||
<q-item-section
|
<q-item-section
|
||||||
v-if="showGrip"
|
v-if="showGrip"
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
dense
|
dense
|
||||||
:class="draggableHandleClass"
|
class="drag-handle"
|
||||||
icon="fas fa-grip-vertical"
|
icon="fas fa-grip-vertical"
|
||||||
@click.stop
|
@click.stop
|
||||||
/>
|
/>
|
||||||
@@ -23,18 +24,9 @@
|
|||||||
avatar
|
avatar
|
||||||
class="q-pr-none"
|
class="q-pr-none"
|
||||||
>
|
>
|
||||||
<div :style="indentSpacerStyle" />
|
<div :style="{ paddingLeft: `${depth * 20}px` }" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<!--<q-item-section side>
|
|
||||||
<q-toggle
|
|
||||||
:model-value="active"
|
|
||||||
:color="active ? 'green' : 'grey'"
|
|
||||||
@update:model-value="val => $emit('update:active', val)"
|
|
||||||
@click.stop
|
|
||||||
/>
|
|
||||||
</q-item-section>-->
|
|
||||||
|
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon :name="item.icon || 'far fa-file-alt'" />
|
<q-icon :name="item.icon || 'far fa-file-alt'" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
@@ -74,71 +66,84 @@
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<slot name="actions">
|
<q-btn
|
||||||
<div
|
dense
|
||||||
class="column q-gutter-xs"
|
round
|
||||||
v-if="true"
|
color="primary"
|
||||||
>
|
icon="fas fa-ellipsis-v"
|
||||||
<q-btn
|
class="q-mr-xs"
|
||||||
dense
|
@click.stop
|
||||||
round
|
>
|
||||||
color="primary"
|
<q-menu>
|
||||||
icon="fas fa-ellipsis-v"
|
<q-list style="min-width: 140px">
|
||||||
class="q-mr-xs"
|
<q-item
|
||||||
@click.stop
|
clickable
|
||||||
>
|
v-close-popup
|
||||||
<q-menu>
|
@click="emitOpen"
|
||||||
<q-list style="min-width: 140px">
|
>
|
||||||
<q-item
|
<q-item-section side><q-icon name="fas fa-edit" /></q-item-section>
|
||||||
clickable
|
<q-item-section>Modifica</q-item-section>
|
||||||
v-close-popup
|
</q-item>
|
||||||
@click="emitOpen"
|
<q-item
|
||||||
>
|
clickable
|
||||||
<q-item-section side><q-icon name="fas fa-edit" /></q-item-section>
|
v-close-popup
|
||||||
<q-item-section>Modifica</q-item-section>
|
@click="emitEdit"
|
||||||
</q-item>
|
>
|
||||||
<q-item
|
<q-item-section side><q-icon name="fas fa-cog" /></q-item-section>
|
||||||
clickable
|
<q-item-section>Impostazioni</q-item-section>
|
||||||
v-close-popup
|
</q-item>
|
||||||
@click="emitEdit"
|
<q-item
|
||||||
>
|
clickable
|
||||||
<q-item-section side><q-icon name="fas fa-cog" /></q-item-section>
|
v-close-popup
|
||||||
<q-item-section>Impostazioni</q-item-section>
|
@click="emitDelete"
|
||||||
</q-item>
|
>
|
||||||
<q-item
|
<q-item-section side
|
||||||
clickable
|
><q-icon
|
||||||
v-close-popup
|
name="fas fa-trash"
|
||||||
@click="emitDelete"
|
color="red"
|
||||||
>
|
/></q-item-section>
|
||||||
<q-item-section side
|
<q-item-section>Elimina</q-item-section>
|
||||||
><q-icon
|
</q-item>
|
||||||
name="fas fa-trash"
|
</q-list>
|
||||||
color="red"
|
</q-menu>
|
||||||
/></q-item-section>
|
</q-btn>
|
||||||
<q-item-section>Elimina</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="column q-gutter-xs"
|
|
||||||
v-else
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
dense
|
|
||||||
round
|
|
||||||
color="negative"
|
|
||||||
icon="fas fa-trash"
|
|
||||||
@click.stop="emitDelete"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</slot>
|
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" src="./MenuPageItem.ts"></script>
|
<script lang="ts">
|
||||||
|
import { defineComponent, computed } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MenuPageItem',
|
||||||
|
props: {
|
||||||
|
item: { type: Object, required: true },
|
||||||
|
selected: { type: Boolean, default: false },
|
||||||
|
active: { type: Boolean, default: true },
|
||||||
|
depth: { type: Number, default: 0 },
|
||||||
|
variant: { type: String, required: true },
|
||||||
|
},
|
||||||
|
emits: ['select', 'update:active', 'edit', 'delete', 'open'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const showGrip = true // computed(() => props.variant === 'menu');
|
||||||
|
|
||||||
|
const displayPath = (path?: string) => {
|
||||||
|
if (!path) return '-';
|
||||||
|
return path.startsWith('/') ? path : '/' + path;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
showGrip,
|
||||||
|
displayPath,
|
||||||
|
emitSelect: () => emit('select', props.item.__key),
|
||||||
|
emitEdit: () => emit('edit', props.item.__key),
|
||||||
|
emitDelete: () => emit('delete', props.item.__key),
|
||||||
|
emitOpen: () => emit('open', props.item.__key),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import './MenuPageItem.scss';
|
@import './MenuPageItem.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,225 +1,506 @@
|
|||||||
import {
|
import { defineComponent, ref, computed, watch, reactive, toRaw, nextTick } from 'vue';
|
||||||
defineComponent, ref, computed, watch, reactive, toRaw, nextTick
|
import { useQuasar } from 'quasar';
|
||||||
} from 'vue'
|
import IconPicker from '../IconPicker/IconPicker.vue';
|
||||||
import { useQuasar } from 'quasar'
|
import { IMyPage } from 'app/src/model';
|
||||||
import IconPicker from '../IconPicker/IconPicker.vue'
|
import { useGlobalStore } from 'app/src/store';
|
||||||
import { IMyPage } from 'app/src/model'
|
import { storeToRefs } from 'pinia';
|
||||||
import { useGlobalStore } from 'app/src/store'
|
import { useI18n } from 'vue-i18n';
|
||||||
import { storeToRefs } from 'pinia'
|
import { costanti } from '@costanti';
|
||||||
import { useI18n } from 'vue-i18n'
|
import { CMyFieldRec } from '@src/components/CMyFieldRec';
|
||||||
import { costanti } from '@costanti'
|
|
||||||
|
|
||||||
import { CMyFieldRec } from '@src/components/CMyFieldRec'
|
const norm = (s?: string) => (s || '').trim().replace(/^\//, '').toLowerCase();
|
||||||
|
const withSlash = (s?: string) => {
|
||||||
|
const p = (s || '').trim();
|
||||||
|
if (!p) return '/';
|
||||||
|
return p.startsWith('/') ? p : `/${p}`;
|
||||||
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'PageEditor',
|
name: 'PageEditor',
|
||||||
components: { IconPicker, CMyFieldRec },
|
components: { IconPicker, CMyFieldRec },
|
||||||
props: {
|
props: {
|
||||||
modelValue: { type: Object as () => IMyPage, required: true },
|
modelValue: { type: Object as () => IMyPage, required: true },
|
||||||
nuovaPagina: { type: Boolean, required: true } // <-- modalità "bozza"
|
nuovaPagina: { type: Boolean, required: true },
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue', 'apply', 'hide'],
|
emits: ['update:modelValue', 'apply', 'hide'],
|
||||||
setup (props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const $q = useQuasar()
|
const $q = useQuasar();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const globalStore = useGlobalStore();
|
||||||
|
const { mypage } = storeToRefs(globalStore);
|
||||||
|
|
||||||
const { t } = useI18n()
|
const draft = reactive<IMyPage>({ ...props.modelValue });
|
||||||
const globalStore = useGlobalStore()
|
|
||||||
const { mypage } = storeToRefs(globalStore)
|
|
||||||
|
|
||||||
// Draft locale indipendente dal parent (specie in nuovaPagina)
|
const ui = reactive({
|
||||||
const draft = reactive<IMyPage>({ ...props.modelValue })
|
pathText: toUiPath(draft.path),
|
||||||
|
isSubmenu: !!draft.submenu,
|
||||||
|
parentId: null as string | null,
|
||||||
|
childrenPaths: [] as string[],
|
||||||
|
});
|
||||||
|
|
||||||
// UI helper: path mostrato con "/" iniziale
|
watch(
|
||||||
const ui = reactive({ pathText: toUiPath(draft.path) })
|
() => ui.isSubmenu,
|
||||||
|
(isSub) => {
|
||||||
|
draft.submenu = !!isSub;
|
||||||
|
if (isSub) {
|
||||||
|
// una pagina figlia non gestisce figli propri
|
||||||
|
ui.childrenPaths = [];
|
||||||
|
// se non c'è un parent pre-selezionato, azzera
|
||||||
|
if (!ui.parentId) ui.parentId = findParentIdForChild(draft.path);
|
||||||
|
} else {
|
||||||
|
// tornando top-level, nessun parent selezionato
|
||||||
|
ui.parentId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const saving = ref(false)
|
// Draft indipendente
|
||||||
const syncingFromProps = ref(false) // anti-loop
|
const saving = ref(false);
|
||||||
|
const syncingFromProps = ref(false);
|
||||||
|
const previousPath = ref<string>(draft.path || '');
|
||||||
|
|
||||||
// --- Sync IN: quando cambia il valore del parent, aggiorna solo il draft
|
// ===== INIT =====
|
||||||
|
// parent corrente (se questa pagina è sottomenu)
|
||||||
|
ui.parentId = findParentIdForChild(draft.path);
|
||||||
|
// inizializza lista figli (per TOP-LEVEL) con i path presenti nel draft
|
||||||
|
ui.childrenPaths = Array.isArray(draft.sottoMenu)
|
||||||
|
? draft.sottoMenu.map((p) => withSlash(p))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// --- Sync IN: quando cambia il modelValue (esterno)
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
async v => {
|
async (v) => {
|
||||||
syncingFromProps.value = true
|
syncingFromProps.value = true;
|
||||||
Object.assign(draft, v || {})
|
Object.assign(draft, v || {});
|
||||||
ui.pathText = toUiPath(draft.path)
|
ui.pathText = toUiPath(draft.path);
|
||||||
await nextTick()
|
ui.isSubmenu = !!draft.submenu;
|
||||||
syncingFromProps.value = false
|
ui.parentId = findParentIdForChild(draft.path);
|
||||||
|
ui.childrenPaths = Array.isArray(draft.sottoMenu)
|
||||||
|
? draft.sottoMenu.map((p) => withSlash(p))
|
||||||
|
: [];
|
||||||
|
previousPath.value = draft.path || '';
|
||||||
|
await nextTick();
|
||||||
|
syncingFromProps.value = false;
|
||||||
},
|
},
|
||||||
{ deep: false }
|
{ deep: false }
|
||||||
)
|
);
|
||||||
|
|
||||||
// --- Modifiche live: SE NON è nuovaPagina, aggiorna store e v-model del parent
|
// --- Propagazione live (solo se NON nuovaPagina)
|
||||||
watch(
|
watch(
|
||||||
draft,
|
draft,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (syncingFromProps.value) return
|
if (syncingFromProps.value) return;
|
||||||
if (props.nuovaPagina) return // <-- blocca ogni propagazione durante "nuova pagina"
|
if (props.nuovaPagina) return;
|
||||||
upsertIntoStore(val, mypage.value)
|
upsertIntoStore(val, mypage.value);
|
||||||
emit('update:modelValue', { ...val })
|
emit('update:modelValue', { ...val });
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
)
|
);
|
||||||
|
|
||||||
// --- Helpers path
|
function onToggleSubmenu(val: boolean) {
|
||||||
function toUiPath (storePath?: string) {
|
draft.submenu = !!val;
|
||||||
const p = (storePath || '').trim()
|
if (val) {
|
||||||
if (!p) return '/'
|
draft.inmenu = true;
|
||||||
return p.startsWith('/') ? p : `/${p}`
|
ui.childrenPaths = []; // sicurezza
|
||||||
}
|
}
|
||||||
function toStorePath (uiPath?: string) {
|
|
||||||
const p = (uiPath || '').trim()
|
|
||||||
if (!p) return ''
|
|
||||||
return p.startsWith('/') ? p.slice(1) : p
|
|
||||||
}
|
|
||||||
function normalizeAndApplyPath () {
|
|
||||||
// normalizza: niente spazi → trattini
|
|
||||||
let p = (ui.pathText || '/').trim()
|
|
||||||
p = p.replace(/\s+/g, '-')
|
|
||||||
if (!p.startsWith('/')) p = '/' + p
|
|
||||||
ui.pathText = p
|
|
||||||
draft.path = toStorePath(p) // NB: scrive sul draft (watch sopra gestisce la propagazione)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pathRule (v: string) {
|
// ======= OPTIONS =======
|
||||||
if (!v) return 'Percorso richiesto'
|
const parentOptions = computed(() =>
|
||||||
if (!v.startsWith('/')) return 'Deve iniziare con /'
|
(mypage.value || [])
|
||||||
if (/\s/.test(v)) return 'Nessuno spazio nel path'
|
.filter(
|
||||||
return true
|
(p) =>
|
||||||
|
p &&
|
||||||
|
p.inmenu &&
|
||||||
|
!p.submenu &&
|
||||||
|
norm(p.path) !== norm(draft.path) &&
|
||||||
|
p._id !== draft._id // <-- escludi se stesso
|
||||||
|
)
|
||||||
|
.map((p) => ({
|
||||||
|
value: (p._id || p.path || '') as string,
|
||||||
|
label: `${p.title || withSlash(p.path)}`,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mappa path (display) -> page
|
||||||
|
const pageByDisplayPath = computed(() => {
|
||||||
|
const m = new Map<string, IMyPage>();
|
||||||
|
(mypage.value || []).forEach((p) => {
|
||||||
|
m.set(withSlash(p.path).toLowerCase(), p);
|
||||||
|
});
|
||||||
|
return m;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mappa childPathDisplay -> parentId
|
||||||
|
const parentByChildPath = computed(() => {
|
||||||
|
const map = new Map<string, string>();
|
||||||
|
(mypage.value || []).forEach((p) => {
|
||||||
|
if (p && p.inmenu && !p.submenu && Array.isArray(p.sottoMenu)) {
|
||||||
|
p.sottoMenu.forEach((sp) => {
|
||||||
|
map.set(withSlash(sp).toLowerCase(), (p._id || p.path) as string);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Candidati figli per il selettore (indent: 0 per "disponibili", 1 per "già figli di altri", 1 anche per già figli miei)
|
||||||
|
const childCandidateOptions = computed(() => {
|
||||||
|
const selfPathDisp = withSlash(draft.path).toLowerCase();
|
||||||
|
const mine = new Set(ui.childrenPaths.map((x) => x.toLowerCase()));
|
||||||
|
const opts: Array<{
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
level: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
hint?: string;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
(mypage.value || [])
|
||||||
|
.filter((p) => p._id !== draft._id && norm(p.path) !== norm(draft.path)) // escludi se stesso
|
||||||
|
.forEach((p) => {
|
||||||
|
const disp = withSlash(p.path);
|
||||||
|
const dispKey = disp.toLowerCase();
|
||||||
|
const parentId = parentByChildPath.value.get(dispKey);
|
||||||
|
|
||||||
|
if (mine.has(dispKey)) {
|
||||||
|
// già selezionato come mio figlio
|
||||||
|
opts.push({
|
||||||
|
value: disp,
|
||||||
|
label: labelForPage(p),
|
||||||
|
level: 1,
|
||||||
|
hint: 'figlio di questa pagina',
|
||||||
|
});
|
||||||
|
} else if (!parentId || parentId === (draft._id || draft.path)) {
|
||||||
|
// orfano (o già mio → già gestito sopra)
|
||||||
|
opts.push({
|
||||||
|
value: disp,
|
||||||
|
label: labelForPage(p),
|
||||||
|
level: 0,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// figlio di un altro parent → lo mostro ma lo disabilito
|
||||||
|
const parent = (mypage.value || []).find(
|
||||||
|
(pp) => (pp._id || pp.path) === parentId
|
||||||
|
);
|
||||||
|
opts.push({
|
||||||
|
value: disp,
|
||||||
|
label: labelForPage(p),
|
||||||
|
level: 1,
|
||||||
|
disabled: true,
|
||||||
|
hint: `già sotto " ${parent?.title || withSlash(parent?.path)}"`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ordina per livello e label
|
||||||
|
return opts.sort((a, b) => a.level - b.level || a.label.localeCompare(b.label));
|
||||||
|
});
|
||||||
|
|
||||||
|
function toUiPath(storePath?: string) {
|
||||||
|
const p = (storePath || '').trim();
|
||||||
|
if (!p) return '/';
|
||||||
|
return p.startsWith('/') ? p : `/${p}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Upsert nello store.mypage (usato solo quando NON è nuovaPagina o dopo il save)
|
function toStorePath(uiPath?: string) {
|
||||||
function upsertIntoStore (page: IMyPage, arr: IMyPage[]) {
|
const p = (uiPath || '').trim();
|
||||||
if (!page) return
|
if (!p) return '';
|
||||||
const keyId = page._id
|
return p.startsWith('/') ? p.slice(1) : p;
|
||||||
const keyPath = page.path || ''
|
|
||||||
let idx = -1
|
|
||||||
if (keyId) idx = arr.findIndex(p => p._id === keyId)
|
|
||||||
if (idx < 0 && keyPath) idx = arr.findIndex(p => (p.path || '') === keyPath)
|
|
||||||
if (idx >= 0) arr[idx] = { ...arr[idx], ...toRaw(page) }
|
|
||||||
else arr.push({ ...toRaw(page) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- VALIDAZIONE + COMMIT per nuova pagina (o anche per edit espliciti)
|
function normalizeAndApplyPath() {
|
||||||
async function checkAndSave (payloadDraft?: IMyPage) {
|
let p = (ui.pathText || '/').trim();
|
||||||
const cur = payloadDraft || draft
|
p = p.replace(/\s+/g, '-');
|
||||||
|
if (!p.startsWith('/')) p = '/' + p;
|
||||||
|
ui.pathText = p;
|
||||||
|
draft.path = toStorePath(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathRule(v: string) {
|
||||||
|
if (!v) return 'Percorso richiesto';
|
||||||
|
if (!v.startsWith('/')) return 'Deve iniziare con /';
|
||||||
|
if (/\s/.test(v)) return 'Nessuno spazio nel path';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======= STORE UTILS =======
|
||||||
|
function upsertIntoStore(page: IMyPage, arr: IMyPage[]) {
|
||||||
|
if (!page) return;
|
||||||
|
const keyId = page._id;
|
||||||
|
const keyPath = page.path || '';
|
||||||
|
let idx = -1;
|
||||||
|
if (keyId) idx = arr.findIndex((p) => p._id === keyId);
|
||||||
|
if (idx < 0 && keyPath) idx = arr.findIndex((p) => (p.path || '') === keyPath);
|
||||||
|
if (idx >= 0) arr[idx] = { ...arr[idx], ...toRaw(page) };
|
||||||
|
else arr.push({ ...toRaw(page) });
|
||||||
|
}
|
||||||
|
|
||||||
|
function findParentIdForChild(childPath?: string | null): string | null {
|
||||||
|
const target = withSlash(childPath || '');
|
||||||
|
for (const p of mypage.value) {
|
||||||
|
if (p && p.inmenu && !p.submenu && Array.isArray(p.sottoMenu)) {
|
||||||
|
if (
|
||||||
|
p.sottoMenu.some((sp) => withSlash(sp).toLowerCase() === target.toLowerCase())
|
||||||
|
) {
|
||||||
|
return (p._id || p.path) as string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findParentsReferencing(childDisplayPath: string): IMyPage[] {
|
||||||
|
const target = withSlash(childDisplayPath).toLowerCase();
|
||||||
|
return (mypage.value || []).filter(
|
||||||
|
(p) =>
|
||||||
|
p &&
|
||||||
|
p.inmenu &&
|
||||||
|
!p.submenu &&
|
||||||
|
Array.isArray(p.sottoMenu) &&
|
||||||
|
p.sottoMenu.some((sp) => withSlash(sp).toLowerCase() === target)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addChildToParent(parent: IMyPage, childDisplayPath: string) {
|
||||||
|
if (!Array.isArray(parent.sottoMenu)) parent.sottoMenu = [];
|
||||||
|
const target = withSlash(childDisplayPath);
|
||||||
|
if (
|
||||||
|
!parent.sottoMenu.some(
|
||||||
|
(sp) => withSlash(sp).toLowerCase() === target.toLowerCase()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
parent.sottoMenu.push(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeChildFromParent(parent: IMyPage, childDisplayPath: string) {
|
||||||
|
if (!Array.isArray(parent.sottoMenu)) return;
|
||||||
|
const target = withSlash(childDisplayPath).toLowerCase();
|
||||||
|
parent.sottoMenu = parent.sottoMenu.filter(
|
||||||
|
(sp) => withSlash(sp).toLowerCase() !== target
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======= SAVE =======
|
||||||
|
async function checkAndSave(payloadDraft?: IMyPage) {
|
||||||
|
const cur = payloadDraft || draft;
|
||||||
|
|
||||||
// validazioni base
|
// validazioni base
|
||||||
if (!cur.title?.trim()) {
|
if (!cur.title?.trim()) {
|
||||||
$q.notify({ message: 'Inserisci il titolo della pagina', type: 'warning' })
|
$q.notify({ message: 'Inserisci il titolo della pagina', type: 'warning' });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
const pathText = (ui.pathText || '').trim();
|
||||||
const pathText = (ui.pathText || '').trim()
|
|
||||||
if (!pathText) {
|
if (!pathText) {
|
||||||
$q.notify({ message: 'Inserisci il percorso della pagina', type: 'warning' })
|
$q.notify({ message: 'Inserisci il percorso della pagina', type: 'warning' });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const candidatePath = toStorePath(pathText).toLowerCase()
|
const candidatePath = toStorePath(pathText).toLowerCase();
|
||||||
|
|
||||||
// unicità PATH (ignora se stesso quando editing)
|
|
||||||
const existPath = globalStore.mypage.find(
|
const existPath = globalStore.mypage.find(
|
||||||
(r) => (r.path || '').toLowerCase() === candidatePath && r._id !== cur._id
|
(r) => (r.path || '').toLowerCase() === candidatePath && r._id !== cur._id
|
||||||
)
|
);
|
||||||
if (existPath) {
|
if (existPath) {
|
||||||
$q.notify({ message: 'Esiste già un’altra pagina con questo percorso', type: 'warning' })
|
$q.notify({
|
||||||
return
|
message: "Esiste già un'altra pagina con questo percorso",
|
||||||
|
type: 'warning',
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unicità TITOLO (ignora se stesso quando editing)
|
const candidateTitle = (cur.title || '').toLowerCase();
|
||||||
const candidateTitle = (cur.title || '').toLowerCase()
|
|
||||||
const existName = globalStore.mypage.find(
|
const existName = globalStore.mypage.find(
|
||||||
(r) => (r.title || '').toLowerCase() === candidateTitle && r._id !== cur._id
|
(r) => (r.title || '').toLowerCase() === candidateTitle && r._id !== cur._id
|
||||||
)
|
);
|
||||||
if (existName) {
|
if (existName) {
|
||||||
$q.notify({ message: 'Il nome della pagina esiste già', type: 'warning' })
|
$q.notify({ message: 'Il nome della pagina esiste già', type: 'warning' });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await save() // esegue commit vero
|
if (ui.isSubmenu && !ui.parentId) {
|
||||||
emit('hide') // chiudi il dialog (se usi dialog)
|
$q.notify({
|
||||||
|
message: 'Seleziona la pagina padre per questo sottomenu',
|
||||||
|
type: 'warning',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await save();
|
||||||
|
emit('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Salvataggio esplicito (commit). Qui propaghiamo SEMPRE al parent/store.
|
async function save() {
|
||||||
async function save () {
|
|
||||||
try {
|
try {
|
||||||
saving.value = true
|
saving.value = true;
|
||||||
normalizeAndApplyPath() // assicura path coerente
|
normalizeAndApplyPath();
|
||||||
|
|
||||||
const payload: IMyPage = { ...toRaw(draft), path: draft.path || '' }
|
// sync flag submenu
|
||||||
const saved = await globalStore.savePage(payload)
|
draft.submenu = !!ui.isSubmenu;
|
||||||
|
|
||||||
|
// se top-level, sincronizza anche i figli dal selettore
|
||||||
|
if (!ui.isSubmenu) {
|
||||||
|
draft.sottoMenu = ui.childrenPaths.slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- salva/aggiorna pagina corrente
|
||||||
|
const payload: IMyPage = { ...toRaw(draft), path: draft.path || '' };
|
||||||
|
const saved = await globalStore.savePage(payload);
|
||||||
if (saved && typeof saved === 'object') {
|
if (saved && typeof saved === 'object') {
|
||||||
syncingFromProps.value = true
|
syncingFromProps.value = true;
|
||||||
Object.assign(draft, saved)
|
Object.assign(draft, saved);
|
||||||
upsertIntoStore(draft, mypage.value) // ora è lecito anche per nuovaPagina
|
upsertIntoStore(draft, mypage.value);
|
||||||
await nextTick()
|
await nextTick();
|
||||||
syncingFromProps.value = false
|
syncingFromProps.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANTISSIMO: in nuovaPagina non abbiamo mai emesso prima → emettiamo ora
|
// --- aggiorna legami parentali
|
||||||
emit('update:modelValue', { ...draft })
|
const prevDisplay = withSlash(previousPath.value);
|
||||||
emit('apply', { ...draft })
|
const newDisplay = withSlash(draft.path);
|
||||||
$q.notify({ type: 'positive', message: 'Pagina salvata' })
|
|
||||||
|
// 1) questa pagina è figlia? collega/sgancia dal parent
|
||||||
|
const parentsPrev = findParentsReferencing(prevDisplay);
|
||||||
|
for (const p of parentsPrev) {
|
||||||
|
// se la pagina è ancora sottomenu con lo stesso parent e path invariato, mantieni
|
||||||
|
const keep =
|
||||||
|
ui.isSubmenu &&
|
||||||
|
ui.parentId === (p._id || p.path) &&
|
||||||
|
prevDisplay.toLowerCase() === newDisplay.toLowerCase();
|
||||||
|
if (!keep) {
|
||||||
|
removeChildFromParent(p, prevDisplay);
|
||||||
|
await globalStore.savePage(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ui.isSubmenu && ui.parentId) {
|
||||||
|
const parent =
|
||||||
|
mypage.value.find((pp) => (pp._id || pp.path) === ui.parentId) || null;
|
||||||
|
if (parent) {
|
||||||
|
parent.inmenu = true;
|
||||||
|
parent.submenu = false;
|
||||||
|
addChildToParent(parent, newDisplay);
|
||||||
|
await globalStore.savePage(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) se questa pagina è TOP-LEVEL, salva i riferimenti dei figli
|
||||||
|
if (!ui.isSubmenu) {
|
||||||
|
// rimuovi da tutti i parent eventuali vecchi riferimenti ai miei figli (che non sono più nella lista)
|
||||||
|
const still = new Set(ui.childrenPaths.map((x) => x.toLowerCase()));
|
||||||
|
const parentsTouch = (mypage.value || []).filter(
|
||||||
|
(p) => p.inmenu && !p.submenu && Array.isArray(p.sottoMenu)
|
||||||
|
);
|
||||||
|
for (const pr of parentsTouch) {
|
||||||
|
const before = (pr.sottoMenu || []).slice();
|
||||||
|
pr.sottoMenu = (pr.sottoMenu || []).filter((sp) => {
|
||||||
|
const spKey = withSlash(sp).toLowerCase();
|
||||||
|
// tieni solo i figli che non appartengono a me oppure appartengono a me e sono ancora in lista
|
||||||
|
const belongsToMe = (pr._id || pr.path) === (draft._id || draft.path);
|
||||||
|
return !belongsToMe || still.has(spKey);
|
||||||
|
});
|
||||||
|
if (JSON.stringify(before) !== JSON.stringify(pr.sottoMenu)) {
|
||||||
|
await globalStore.savePage(pr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('update:modelValue', { ...draft });
|
||||||
|
emit('apply', { ...draft });
|
||||||
|
$q.notify({ type: 'positive', message: 'Pagina salvata' });
|
||||||
|
|
||||||
|
previousPath.value = draft.path || '';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err);
|
||||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio' })
|
$q.notify({ type: 'negative', message: 'Errore nel salvataggio' });
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false
|
saving.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Ricarica (per editing). In modalità nuovaPagina non propaghiamo al parent.
|
async function reloadFromStore() {
|
||||||
async function reloadFromStore () {
|
|
||||||
try {
|
try {
|
||||||
const absolute = ui.pathText || '/'
|
const absolute = ui.pathText || '/';
|
||||||
const page = await globalStore.loadPage(absolute, '', true)
|
const page = await globalStore.loadPage(absolute, '', true);
|
||||||
if (page) {
|
if (page) {
|
||||||
syncingFromProps.value = true
|
syncingFromProps.value = true;
|
||||||
Object.assign(draft, page)
|
Object.assign(draft, page);
|
||||||
ui.pathText = toUiPath(draft.path)
|
ui.pathText = toUiPath(draft.path);
|
||||||
upsertIntoStore(draft, mypage.value)
|
ui.isSubmenu = !!draft.submenu;
|
||||||
if (!props.nuovaPagina) emit('update:modelValue', { ...draft }) // <-- no propagate in nuovaPagina
|
ui.parentId = findParentIdForChild(draft.path);
|
||||||
await nextTick()
|
ui.childrenPaths = Array.isArray(draft.sottoMenu)
|
||||||
syncingFromProps.value = false
|
? draft.sottoMenu.map((p) => withSlash(p))
|
||||||
$q.notify({ type: 'info', message: 'Pagina ricaricata' })
|
: [];
|
||||||
|
upsertIntoStore(draft, mypage.value);
|
||||||
|
if (!props.nuovaPagina) emit('update:modelValue', { ...draft });
|
||||||
|
await nextTick();
|
||||||
|
syncingFromProps.value = false;
|
||||||
|
previousPath.value = draft.path || '';
|
||||||
|
$q.notify({ type: 'info', message: 'Pagina ricaricata' });
|
||||||
} else {
|
} else {
|
||||||
$q.notify({ type: 'warning', message: 'Pagina non trovata' })
|
$q.notify({ type: 'warning', message: 'Pagina non trovata' });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err);
|
||||||
$q.notify({ type: 'negative', message: 'Errore nel ricaricare la pagina' })
|
$q.notify({ type: 'negative', message: 'Errore nel ricaricare la pagina' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetDraft () {
|
function resetDraft() {
|
||||||
syncingFromProps.value = true
|
syncingFromProps.value = true;
|
||||||
Object.assign(draft, props.modelValue || {})
|
Object.assign(draft, props.modelValue || {});
|
||||||
ui.pathText = toUiPath(draft.path)
|
ui.pathText = toUiPath(draft.path);
|
||||||
if (!props.nuovaPagina) emit('update:modelValue', { ...draft }) // <-- no propagate in nuovaPagina
|
ui.isSubmenu = !!draft.submenu;
|
||||||
nextTick(() => { syncingFromProps.value = false })
|
ui.parentId = findParentIdForChild(draft.path);
|
||||||
|
ui.childrenPaths = Array.isArray(draft.sottoMenu)
|
||||||
|
? draft.sottoMenu.map((p) => withSlash(p))
|
||||||
|
: [];
|
||||||
|
if (!props.nuovaPagina) emit('update:modelValue', { ...draft });
|
||||||
|
nextTick(() => {
|
||||||
|
syncingFromProps.value = false;
|
||||||
|
});
|
||||||
|
previousPath.value = draft.path || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// === LABEL UTILS ===
|
||||||
|
function labelForPage(p: IMyPage) {
|
||||||
|
return p.title || withSlash(p.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function labelForPath(dispPath: string) {
|
||||||
|
const p = pageByDisplayPath.value.get(dispPath.toLowerCase());
|
||||||
|
return p ? labelForPage(p) : dispPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function modifElem() {
|
function modifElem() {
|
||||||
|
/* per compat compat con CMyFieldRec */
|
||||||
}
|
}
|
||||||
|
|
||||||
const absolutePath = computed(() => toUiPath(draft.path))
|
const absolutePath = computed(() => toUiPath(draft.path));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
draft,
|
draft,
|
||||||
ui,
|
ui,
|
||||||
saving,
|
saving,
|
||||||
|
t,
|
||||||
|
costanti,
|
||||||
|
// helpers UI
|
||||||
pathRule,
|
pathRule,
|
||||||
normalizeAndApplyPath,
|
normalizeAndApplyPath,
|
||||||
|
labelForPath,
|
||||||
|
labelForPage,
|
||||||
|
withSlash,
|
||||||
|
// actions
|
||||||
|
checkAndSave,
|
||||||
save,
|
save,
|
||||||
reloadFromStore,
|
reloadFromStore,
|
||||||
resetDraft,
|
resetDraft,
|
||||||
absolutePath,
|
|
||||||
checkAndSave,
|
|
||||||
t,
|
|
||||||
costanti,
|
|
||||||
modifElem,
|
modifElem,
|
||||||
}
|
onToggleSubmenu,
|
||||||
}
|
// options
|
||||||
})
|
parentOptions,
|
||||||
|
childCandidateOptions,
|
||||||
|
// expose util
|
||||||
|
absolutePath,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
class="q-pa-md"
|
class="q-pa-md"
|
||||||
>
|
>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
|
<!-- PATH -->
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="ui.pathText"
|
v-model="ui.pathText"
|
||||||
@@ -13,12 +14,11 @@
|
|||||||
:rules="[pathRule]"
|
:rules="[pathRule]"
|
||||||
@blur="normalizeAndApplyPath"
|
@blur="normalizeAndApplyPath"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend><q-icon name="fas fa-link" /></template>
|
||||||
<q-icon name="fas fa-link" />
|
|
||||||
</template>
|
|
||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- TITOLO -->
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="draft.title"
|
v-model="draft.title"
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ORDINE -->
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<q-input
|
<q-input
|
||||||
v-model.number="draft.order"
|
v-model.number="draft.order"
|
||||||
@@ -41,25 +42,12 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
SottoMenu:
|
<!-- ICONA -->
|
||||||
<CMyFieldRec
|
|
||||||
title="SottoMenu:"
|
|
||||||
table="pages"
|
|
||||||
:id="draft._id"
|
|
||||||
:rec="draft"
|
|
||||||
field="sottoMenu"
|
|
||||||
@update:model-value="modifElem"
|
|
||||||
:canEdit="true"
|
|
||||||
:canModify="true"
|
|
||||||
:nosaveToDb="true"
|
|
||||||
:fieldtype="costanti.FieldType.multiselect"
|
|
||||||
>
|
|
||||||
</CMyFieldRec>
|
|
||||||
|
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<icon-picker v-model="draft.icon" />
|
<icon-picker v-model="draft.icon" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- STATO & VISIBILITÀ -->
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<q-separator spaced />
|
<q-separator spaced />
|
||||||
<div class="row items-center q-col-gutter-md">
|
<div class="row items-center q-col-gutter-md">
|
||||||
@@ -89,8 +77,91 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- GESTIONE FIGLI (solo se questa pagina è TOP-LEVEL) -->
|
||||||
|
<div
|
||||||
|
class="col-12"
|
||||||
|
v-if="!ui.isSubmenu"
|
||||||
|
>
|
||||||
|
<q-separator spaced />
|
||||||
|
<div class="text-subtitle2 q-mb-sm">SottoMenu</div>
|
||||||
|
|
||||||
|
<!-- Selettore multivalore dei figli (con label indentata nell'option slot) -->
|
||||||
|
<q-select
|
||||||
|
v-model="ui.childrenPaths"
|
||||||
|
:options="childCandidateOptions"
|
||||||
|
multiple
|
||||||
|
use-chips
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
emit-value
|
||||||
|
map-options
|
||||||
|
label="Pagine figlie"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<q-item-section>
|
||||||
|
<div :style="{ paddingLeft: scope.opt.level * 14 + 'px' }">
|
||||||
|
{{ scope.opt.label }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="scope.opt.hint"
|
||||||
|
class="text-caption text-grey-7"
|
||||||
|
>
|
||||||
|
{{ scope.opt.hint }}
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section
|
||||||
|
side
|
||||||
|
v-if="scope.opt.disabled"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
name="lock"
|
||||||
|
class="text-grey-6"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
|
||||||
|
<!-- Preview gerarchica reale (indentata) -->
|
||||||
|
<div class="q-mt-md">
|
||||||
|
<div class="text-caption text-grey-7 q-mb-xs">Anteprima struttura</div>
|
||||||
|
<q-list
|
||||||
|
bordered
|
||||||
|
class="rounded-borders"
|
||||||
|
>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section>
|
||||||
|
<div class="text-weight-medium">
|
||||||
|
{{ draft.title || withSlash(draft.path) }}
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator />
|
||||||
|
<template v-if="ui.childrenPaths.length">
|
||||||
|
<q-item
|
||||||
|
v-for="(cp, i) in ui.childrenPaths"
|
||||||
|
:key="i"
|
||||||
|
class="q-pl-md"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<div class="text-body2">— {{ labelForPath(cp) }}</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="q-pa-sm text-grey-7 text-caption"
|
||||||
|
>
|
||||||
|
Nessun sottomenu selezionato.
|
||||||
|
</div>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- AZIONI -->
|
||||||
<q-card-actions
|
<q-card-actions
|
||||||
align="center"
|
align="center"
|
||||||
class="q-pa-md q-gutter-md"
|
class="q-pa-md q-gutter-md"
|
||||||
@@ -111,7 +182,6 @@
|
|||||||
label="Chiudi"
|
label="Chiudi"
|
||||||
v-close-popup
|
v-close-popup
|
||||||
/>
|
/>
|
||||||
<!--<q-btn flat color="grey-7" label="Reset draft" @click="resetDraft" />-->
|
|
||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.menu-container {
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,164 +35,168 @@ export default defineComponent({
|
|||||||
|
|
||||||
const visualizzaEditor = ref(false);
|
const visualizzaEditor = ref(false);
|
||||||
const nuovaPagina = ref(false);
|
const nuovaPagina = ref(false);
|
||||||
|
const selectedKey = ref<string | null>(null);
|
||||||
|
|
||||||
const ORDER_STEP = 10;
|
// Configurazione ordinamento gerarchico
|
||||||
const MIN_GAP = 1;
|
const ORDER_GROUP_STEP = 1000; // Passo per i top-level (1000, 2000, 3000...)
|
||||||
|
const ORDER_CHILD_STEP = 100; // Passo per i sottomenu (100, 200, 300...)
|
||||||
|
|
||||||
function getPageByKey(key?: string) {
|
function getPageByKey(key?: string) {
|
||||||
return key ? pages.value.find((p) => p.__key === key) : undefined;
|
return key ? pages.value.find((p) => p.__key === key) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrderOfRow(row?: PageRow) {
|
// ===== NUOVO SISTEMA DI ORDINAMENTO GERARCHICO =====
|
||||||
const p = row ? getPageByKey(row.__key) : undefined;
|
|
||||||
return typeof p?.order === 'number' ? (p!.order as number) : undefined;
|
/**
|
||||||
|
* Calcola l'ordine gerarchico in base alla posizione nella struttura
|
||||||
|
* Formato: [gruppo].[ordine] dove:
|
||||||
|
* - gruppo: identifica il livello gerarchico (1000 per top-level, 1100 per sottomenu del primo top-level, ecc.)
|
||||||
|
* - ordine: posizione all'interno del gruppo
|
||||||
|
*/
|
||||||
|
function calculateHierarchicalOrder(rows: PageRow[], index: number): number {
|
||||||
|
const row = rows[index];
|
||||||
|
|
||||||
|
// Se è un top-level (depth 0)
|
||||||
|
if (row.__depth === 0) {
|
||||||
|
// Conta quanti top-level ci sono prima di questo
|
||||||
|
let topLevelCount = 0;
|
||||||
|
for (let i = 0; i <= index; i++) {
|
||||||
|
if (rows[i].__depth === 0) topLevelCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assegna un ordine multiplo di 1000 (1000, 2000, 3000, ...)
|
||||||
|
return topLevelCount * ORDER_GROUP_STEP;
|
||||||
|
}
|
||||||
|
// Se è un sottomenu (depth 1)
|
||||||
|
else {
|
||||||
|
// Trova il parent (l'ultimo top-level prima di questo elemento)
|
||||||
|
let parentIndex = -1;
|
||||||
|
for (let i = index - 1; i >= 0; i--) {
|
||||||
|
if (rows[i].__depth === 0) {
|
||||||
|
parentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentIndex === -1) {
|
||||||
|
// Nessun parent trovato - fallback a top-level
|
||||||
|
return calculateHierarchicalOrder(rows, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcola l'ordine del parent
|
||||||
|
const parentOrder = calculateHierarchicalOrder(rows, parentIndex);
|
||||||
|
|
||||||
|
// Conta quanti sottomenu ci sono sotto lo stesso parent fino a questo punto
|
||||||
|
let childCount = 0;
|
||||||
|
for (let i = parentIndex + 1; i <= index; i++) {
|
||||||
|
if (rows[i].__depth === 1) childCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assegna un ordine nel formato parentOrder + childCount * 100 (es. 1000 + 100 = 1100)
|
||||||
|
return parentOrder + childCount * ORDER_CHILD_STEP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assegna l'order SOLO all'elemento spostato (e, se serve, a una piccola finestra attorno)
|
* Aggiorna gli ordini di TUTTI gli elementi in base alla loro posizione nella struttura
|
||||||
* usando un ordinamento "sparso": media fra i vicini, oppure reseed locale.
|
* Questo è il cuore del nuovo sistema di ordinamento
|
||||||
* Ritorna i delta {id, order} da salvare.
|
|
||||||
*/
|
*/
|
||||||
function sparseAssignOrder(
|
function updateAllOrders(rows: PageRow[]): { id: string; order: number }[] {
|
||||||
rows: PageRow[],
|
|
||||||
movedIndex: number
|
|
||||||
): { id: string; order: number }[] {
|
|
||||||
const deltas: { id: string; order: number }[] = [];
|
const deltas: { id: string; order: number }[] = [];
|
||||||
const curRow = rows[movedIndex];
|
|
||||||
if (!curRow?.__key) return deltas;
|
|
||||||
|
|
||||||
const cur = getPageByKey(curRow.__key);
|
for (let i = 0; i < rows.length; i++) {
|
||||||
if (!cur) return deltas;
|
const row = rows[i];
|
||||||
|
const page = getPageByKey(row.__key);
|
||||||
|
|
||||||
const prevOrder = getOrderOfRow(rows[movedIndex - 1]);
|
if (!page) continue;
|
||||||
const nextOrder = getOrderOfRow(rows[movedIndex + 1]);
|
|
||||||
|
|
||||||
const pushDelta = (p: PageWithKey, val: number) => {
|
const newOrder = calculateHierarchicalOrder(rows, i);
|
||||||
if (p.order !== val) {
|
|
||||||
p.order = val;
|
if (page.order !== newOrder) {
|
||||||
if (p._id) deltas.push({ id: p._id, order: val });
|
page.order = newOrder;
|
||||||
|
if (page._id) {
|
||||||
|
deltas.push({ id: page._id, order: newOrder });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Caso 1: abbiamo spazio tra prev e next → usa media
|
|
||||||
if (
|
|
||||||
prevOrder !== undefined &&
|
|
||||||
nextOrder !== undefined &&
|
|
||||||
nextOrder - prevOrder > MIN_GAP
|
|
||||||
) {
|
|
||||||
const mid = prevOrder + Math.floor((nextOrder - prevOrder) / 2);
|
|
||||||
pushDelta(cur, mid);
|
|
||||||
return deltas;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caso 2: in testa → prima del first
|
|
||||||
if (prevOrder === undefined && nextOrder !== undefined) {
|
|
||||||
pushDelta(cur, nextOrder - ORDER_STEP);
|
|
||||||
return deltas;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caso 3: in coda → dopo l'ultimo
|
|
||||||
if (prevOrder !== undefined && nextOrder === undefined) {
|
|
||||||
pushDelta(cur, prevOrder + ORDER_STEP);
|
|
||||||
return deltas;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caso 4: nessuno spazio (o ordini uguali) → reseed locale (finestra stretta)
|
|
||||||
const start = Math.max(0, movedIndex - 3);
|
|
||||||
const end = Math.min(rows.length - 1, movedIndex + 3);
|
|
||||||
|
|
||||||
// base = order dell’elemento appena prima della finestra (se esiste), altrimenti 0
|
|
||||||
let base = getOrderOfRow(rows[start - 1]) ?? 0;
|
|
||||||
for (let i = start; i <= end; i++) {
|
|
||||||
const r = rows[i];
|
|
||||||
const p = getPageByKey(r.__key!);
|
|
||||||
if (!p) continue;
|
|
||||||
base += ORDER_STEP;
|
|
||||||
pushDelta(p, base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return deltas;
|
return deltas;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** order per append in fondo a "menu" */
|
/**
|
||||||
function computeAppendOrderForMenu(): number {
|
* Calcola la profondità (depth) di un elemento basandosi sulla posizione nel drag
|
||||||
let max = 0;
|
* @param newRows - l'intera lista di righe dopo il drag
|
||||||
for (const p of pages.value)
|
* @param targetIndex - l'indice di destinazione
|
||||||
if (p.inmenu && typeof p.order === 'number') max = Math.max(max, p.order!);
|
* @param sourceIndex - l'indice di origine
|
||||||
return max + ORDER_STEP;
|
* @returns la profondità calcolata (0 per top-level, 1 per sottomenu)
|
||||||
}
|
*/
|
||||||
|
function calculateDepth(
|
||||||
|
newRows: PageRow[],
|
||||||
|
targetIndex: number,
|
||||||
|
sourceIndex: number
|
||||||
|
): number {
|
||||||
|
// Se è il primo elemento, non può essere un sottomenu
|
||||||
|
if (targetIndex === 0) return 0;
|
||||||
|
|
||||||
/** order per append in fondo a "off" (dopo tutti) */
|
// Se è stato spostato verso l'alto, controlla l'elemento prima di esso
|
||||||
function computeAppendOrderForOff(): number {
|
const prevRow = newRows[targetIndex - 1];
|
||||||
let max = 0;
|
|
||||||
for (const p of pages.value)
|
|
||||||
if (typeof p.order === 'number') max = Math.max(max, p.order!);
|
|
||||||
return max + ORDER_STEP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- STATE BASE --------------------------------------------------------
|
// Se l'elemento precedente è un top-level, potrebbe essere un sottomenu
|
||||||
const pages = ref<PageWithKey[]>(
|
if (prevRow.__depth === 0) {
|
||||||
props.modelValue ? props.modelValue.map((p) => ({ ...p })) : []
|
// Calcola la distanza visiva tra l'elemento trascinato e il precedente
|
||||||
);
|
const visualDistance = calculateVisualDistance(targetIndex, sourceIndex);
|
||||||
ensureKeys(pages.value);
|
|
||||||
pages.value.sort(byOrder)
|
|
||||||
|
|
||||||
const selectedKey = ref<string | null>(null);
|
// Se la distanza è piccola (es. < 30px), consideralo un sottomenu
|
||||||
|
if (visualDistance < 30) {
|
||||||
// Liste derivate per UI
|
return 1;
|
||||||
const menuRows = ref<PageRow[]>([]); // lista piatta (top + figli) con depth
|
|
||||||
const offList = ref<PageWithKey[]>([]); // voci fuori menu (inmenu=false)
|
|
||||||
const applyingRows = ref(false); // guard per evitare rientri
|
|
||||||
|
|
||||||
// ---- BUILDERS (no side-effects) ---------------------------------------
|
|
||||||
function rebuildMenuRows() {
|
|
||||||
const mapByPath = new Map<string, PageWithKey>();
|
|
||||||
for (const p of pages.value) mapByPath.set(norm(p.path), p);
|
|
||||||
|
|
||||||
const tops = pages.value
|
|
||||||
.filter((p) => p.inmenu && !p.submenu)
|
|
||||||
.sort(byOrder) as PageWithKey[];
|
|
||||||
|
|
||||||
const rows: PageRow[] = [];
|
|
||||||
const usedChildKeys = new Set<string>();
|
|
||||||
|
|
||||||
for (const parent of tops) {
|
|
||||||
rows.push({ ...(parent as any), __depth: 0 });
|
|
||||||
const arr = Array.isArray(parent.sottoMenu) ? parent.sottoMenu : [];
|
|
||||||
for (const childPath of arr) {
|
|
||||||
const child = mapByPath.get(norm(childPath));
|
|
||||||
if (child && child.inmenu !== false && child.submenu === true) {
|
|
||||||
rows.push({ ...(child as any), __depth: 1 });
|
|
||||||
if (child.__key) usedChildKeys.add(child.__key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orfani: sottomenu==true ma non referenziati da alcun parent
|
// Se è stato spostato tra due sottomenu dello stesso gruppo
|
||||||
const orphans = (pages.value as PageWithKey[])
|
if (prevRow.__depth === 1 && targetIndex > 1) {
|
||||||
.filter((p) => p.inmenu && p.submenu && p.__key && !usedChildKeys.has(p.__key))
|
const grandParentRow = newRows[targetIndex - 2];
|
||||||
.sort(byOrder);
|
if (grandParentRow && grandParentRow.__depth === 0) {
|
||||||
for (const ch of orphans) {
|
return 1;
|
||||||
rows.push({ ...(ch as any), __depth: 0 }); // fallback: top-level
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menuRows.value = rows;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rebuildOffList() {
|
/**
|
||||||
offList.value = pages.value.filter((p) => !p.inmenu).sort(byOrder);
|
* Calcola la distanza visiva tra l'elemento trascinato e l'elemento precedente
|
||||||
|
* @param targetIndex - indice di destinazione
|
||||||
|
* @param sourceIndex - indice di origine
|
||||||
|
* @returns distanza in pixel
|
||||||
|
*/
|
||||||
|
function calculateVisualDistance(targetIndex: number, sourceIndex: number): number {
|
||||||
|
try {
|
||||||
|
const menuContainer = document.querySelector('.menu-container');
|
||||||
|
if (!menuContainer) return Infinity;
|
||||||
|
|
||||||
|
const items = menuContainer.querySelectorAll('.menu-item');
|
||||||
|
if (targetIndex >= items.length || targetIndex <= 0) return Infinity;
|
||||||
|
|
||||||
|
const prevItem = items[targetIndex - 1] as HTMLElement;
|
||||||
|
const draggedItem = items[sourceIndex] as HTMLElement;
|
||||||
|
|
||||||
|
if (!prevItem || !draggedItem) return Infinity;
|
||||||
|
|
||||||
|
const prevRect = prevItem.getBoundingClientRect();
|
||||||
|
const draggedRect = draggedItem.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Calcola la distanza verticale tra il fondo del precedente e l'inizio del trascinato
|
||||||
|
return draggedRect.top - prevRect.bottom;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Errore nel calcolo della distanza visiva:', e);
|
||||||
|
return 30; // Valore di default che indica "non troppo vicino"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rebuildAllViews() {
|
/**
|
||||||
rebuildMenuRows();
|
* Aggiorna la struttura gerarchica e gli ordini
|
||||||
rebuildOffList();
|
*/
|
||||||
globalStore.aggiornaMenu($router);
|
function applyMenuRows(newRows: PageRow[]): { id: string; order: number }[] {
|
||||||
}
|
|
||||||
// ⬇️ Sostituisci completamente la funzione esistente
|
|
||||||
function applyMenuRows(
|
|
||||||
newRows: PageRow[],
|
|
||||||
movedIndex?: number
|
|
||||||
): { id: string; order: number }[] {
|
|
||||||
// 1) svuota i sottoMenu dei parent (ricostruiremo i link)
|
// 1) svuota i sottoMenu dei parent (ricostruiremo i link)
|
||||||
for (const p of pages.value) {
|
for (const p of pages.value) {
|
||||||
if (p.inmenu && !p.submenu) p.sottoMenu = [];
|
if (p.inmenu && !p.submenu) p.sottoMenu = [];
|
||||||
@@ -228,14 +232,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4) assegna order in modalità "sparsa" SOLO per l’elemento spostato (e finestra vicina)
|
// 4) aggiorna TUTTI gli ordini in base alla posizione nella struttura
|
||||||
if (typeof movedIndex === 'number') {
|
return updateAllOrders(newRows);
|
||||||
return sparseAssignOrder(newRows, movedIndex);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⬇️ Sostituisci completamente la funzione esistente
|
|
||||||
function applyOffList(
|
function applyOffList(
|
||||||
newOff: PageWithKey[],
|
newOff: PageWithKey[],
|
||||||
movedIndex?: number
|
movedIndex?: number
|
||||||
@@ -276,54 +276,242 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (prevO !== undefined && nextO !== undefined && nextO - prevO > MIN_GAP) {
|
// Calcola un nuovo ordine per l'elemento spostato
|
||||||
|
if (prevO !== undefined && nextO !== undefined) {
|
||||||
pushDelta(curP!, prevO + Math.floor((nextO - prevO) / 2));
|
pushDelta(curP!, prevO + Math.floor((nextO - prevO) / 2));
|
||||||
} else if (prevO !== undefined && nextO === undefined) {
|
} else if (prevO !== undefined) {
|
||||||
pushDelta(curP!, prevO + ORDER_STEP);
|
pushDelta(curP!, prevO + 10);
|
||||||
} else if (prevO === undefined && nextO !== undefined) {
|
} else if (nextO !== undefined) {
|
||||||
pushDelta(curP!, nextO - ORDER_STEP);
|
pushDelta(curP!, nextO - 10);
|
||||||
} else {
|
} else {
|
||||||
// reseed locale nell'offList
|
pushDelta(curP!, 10000); // Default per elementi in fondo
|
||||||
const start = Math.max(0, movedIndex - 3);
|
|
||||||
const end = Math.min(newOff.length - 1, movedIndex + 3);
|
|
||||||
let base =
|
|
||||||
start > 0 ? (getPageByKey(newOff[start - 1].__key!)?.order ?? 0) : 0;
|
|
||||||
for (let i = start; i <= end; i++) {
|
|
||||||
const r = newOff[i];
|
|
||||||
const p = getPageByKey(r.__key!);
|
|
||||||
if (!p) continue;
|
|
||||||
base += ORDER_STEP;
|
|
||||||
pushDelta(p, base);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return deltas;
|
return deltas;
|
||||||
}
|
}
|
||||||
// ---- WATCHERS ----------------------------------------------------------
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(v) => {
|
|
||||||
pages.value = (v || []).map((p) => ({ ...p }));
|
|
||||||
ensureKeys(pages.value);
|
|
||||||
pages.value.sort(byOrder)
|
|
||||||
rebuildAllViews();
|
|
||||||
if (!pages.value.find((p) => p.__key === selectedKey.value))
|
|
||||||
selectedKey.value = null;
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// ricostruisci la vista quando pages cambia (evita durante apply)
|
/**
|
||||||
watch(
|
* Gestisce il drag nel menu
|
||||||
() => pages.value,
|
*/
|
||||||
() => {
|
function onMenuDragChange(evt: any) {
|
||||||
if (applyingRows.value) return;
|
console.log('onMenuDragChange', evt);
|
||||||
rebuildAllViews();
|
applyingRows.value = true;
|
||||||
},
|
let deltas: { id: string; order: number }[] = [];
|
||||||
{ deep: true, immediate: true }
|
|
||||||
|
const removed = evt?.removed;
|
||||||
|
const added = evt?.added;
|
||||||
|
const moved = evt?.moved;
|
||||||
|
|
||||||
|
// Creiamo una copia della lista corrente
|
||||||
|
const newRows = [...menuRows.value];
|
||||||
|
|
||||||
|
// Gestisci la rimozione (da menu a fuori menu)
|
||||||
|
if (removed) {
|
||||||
|
const { element, oldIndex } = removed;
|
||||||
|
const page = getPageByKey(element.__key);
|
||||||
|
if (page) {
|
||||||
|
// Imposta come non nel menu
|
||||||
|
page.inmenu = false;
|
||||||
|
page.submenu = false;
|
||||||
|
// Rimuovi dai sottoMenu di tutti i parent
|
||||||
|
for (const parent of pages.value) {
|
||||||
|
if (parent.inmenu && !parent.submenu && Array.isArray(parent.sottoMenu)) {
|
||||||
|
parent.sottoMenu = parent.sottoMenu.filter(
|
||||||
|
(p) => norm(p) !== norm(page.path)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestisci l'aggiunta (da off a menu)
|
||||||
|
if (added) {
|
||||||
|
const { element, newIndex } = added;
|
||||||
|
|
||||||
|
// Determina la profondità iniziale (0 = top-level)
|
||||||
|
newRows[newIndex].__depth = 0;
|
||||||
|
|
||||||
|
// Imposta come nel menu
|
||||||
|
const page = getPageByKey(element.__key);
|
||||||
|
if (page) {
|
||||||
|
page.inmenu = true;
|
||||||
|
page.submenu = false; // inizialmente top-level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestisci lo spostamento interno
|
||||||
|
if (moved) {
|
||||||
|
const { newIndex, oldIndex } = moved;
|
||||||
|
|
||||||
|
// Calcola la nuova profondità basata sulla posizione
|
||||||
|
const newDepth = calculateDepth(newRows, newIndex, oldIndex);
|
||||||
|
newRows[newIndex].__depth = newDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggiorna la struttura gerarchica e calcola i delta di ordine
|
||||||
|
deltas = applyMenuRows(newRows);
|
||||||
|
|
||||||
|
// Aggiorna le liste
|
||||||
|
menuRows.value = newRows;
|
||||||
|
|
||||||
|
applyingRows.value = false;
|
||||||
|
rebuildAllViews();
|
||||||
|
|
||||||
|
// Comunica i cambiamenti
|
||||||
|
emit(
|
||||||
|
'update:modelValue',
|
||||||
|
pages.value.map((p) => ({ ...p }))
|
||||||
|
);
|
||||||
|
if (deltas.length) emit('change-order', deltas);
|
||||||
|
try {
|
||||||
|
globalStore.aggiornaMenu($router);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Errore nell'aggiornamento del menu:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestisce il drag nella lista "fuori menu"
|
||||||
|
*/
|
||||||
|
function onOffDragChange(evt: any) {
|
||||||
|
console.log('onOffDragChange...', evt);
|
||||||
|
applyingRows.value = true;
|
||||||
|
|
||||||
|
// Creiamo una copia della lista corrente
|
||||||
|
const newOff = [...offList.value];
|
||||||
|
let deltas: { id: string; order: number }[] = [];
|
||||||
|
|
||||||
|
// Gestisci la rimozione (da off a menu)
|
||||||
|
if (evt?.removed) {
|
||||||
|
const { element, oldIndex } = evt.removed;
|
||||||
|
const page = getPageByKey(element.__key);
|
||||||
|
if (page) {
|
||||||
|
// Imposta come nel menu
|
||||||
|
page.inmenu = true;
|
||||||
|
// Non impostiamo submenu qui, verrà gestito in onMenuDragChange
|
||||||
|
|
||||||
|
// Aggiorna l'ordine per la nuova voce di menu
|
||||||
|
page.order = 10000; // Sarà ricalcolato quando verrà spostato nel menu
|
||||||
|
|
||||||
|
// Salva immediatamente la pagina per riflettere il cambiamento
|
||||||
|
if (page._id) {
|
||||||
|
globalStore.savePage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestisci l'aggiunta (da menu a off)
|
||||||
|
if (evt?.added) {
|
||||||
|
const { element, newIndex } = evt.added;
|
||||||
|
const page = getPageByKey(element.__key);
|
||||||
|
if (page) {
|
||||||
|
// Imposta come non nel menu
|
||||||
|
page.inmenu = false;
|
||||||
|
page.submenu = false;
|
||||||
|
// Rimuovi dai sottoMenu di tutti i parent
|
||||||
|
for (const parent of pages.value) {
|
||||||
|
if (parent.inmenu && !parent.submenu && Array.isArray(parent.sottoMenu)) {
|
||||||
|
parent.sottoMenu = parent.sottoMenu.filter(
|
||||||
|
(p) => norm(p) !== norm(page.path)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestiamo gli eventi di spostamento
|
||||||
|
if (evt?.moved) {
|
||||||
|
const { newIndex, oldIndex } = evt.moved;
|
||||||
|
deltas = applyOffList(newOff, newIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggiorna la lista
|
||||||
|
offList.value = newOff;
|
||||||
|
|
||||||
|
applyingRows.value = false;
|
||||||
|
rebuildAllViews();
|
||||||
|
|
||||||
|
// Comunica i cambiamenti
|
||||||
|
emit(
|
||||||
|
'update:modelValue',
|
||||||
|
pages.value.map((p) => ({ ...p }))
|
||||||
|
);
|
||||||
|
if (deltas.length) emit('change-order', deltas);
|
||||||
|
try {
|
||||||
|
globalStore.aggiornaMenu($router);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Errore nell'aggiornamento del menu:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- STATE BASE --------------------------------------------------------
|
||||||
|
const pages = ref<PageWithKey[]>(
|
||||||
|
props.modelValue ? props.modelValue.map((p) => ({ ...p })) : []
|
||||||
);
|
);
|
||||||
|
ensureKeys(pages.value);
|
||||||
|
pages.value.sort(byOrder);
|
||||||
|
|
||||||
|
// Liste derivate per UI
|
||||||
|
const menuRows = ref<PageRow[]>([]); // lista piatta (top + figli) con depth
|
||||||
|
const offList = ref<PageWithKey[]>([]); // voci fuori menu (inmenu=false)
|
||||||
|
const applyingRows = ref(false); // guard per evitare rientri
|
||||||
|
|
||||||
|
// ---- BUILDERS (no side-effects) ---------------------------------------
|
||||||
|
function rebuildMenuRows() {
|
||||||
|
const mapByPath = new Map<string, PageWithKey>();
|
||||||
|
for (const p of pages.value) mapByPath.set(norm(p.path), p);
|
||||||
|
|
||||||
|
const tops = pages.value
|
||||||
|
.filter((p) => p.inmenu && !p.submenu)
|
||||||
|
.sort(byOrder) as PageWithKey[];
|
||||||
|
|
||||||
|
const rows: PageRow[] = [];
|
||||||
|
const usedChildKeys = new Set<string>();
|
||||||
|
|
||||||
|
for (const parent of tops) {
|
||||||
|
rows.push({ ...(parent as any), __depth: 0 });
|
||||||
|
const arr = Array.isArray(parent.sottoMenu) ? parent.sottoMenu : [];
|
||||||
|
for (const childPath of arr) {
|
||||||
|
const child = mapByPath.get(norm(childPath));
|
||||||
|
if (child && child.inmenu !== false && child.submenu === true) {
|
||||||
|
rows.push({ ...(child as any), __depth: 1 });
|
||||||
|
if (child.__key) usedChildKeys.add(child.__key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orfani: sottomenu==true ma non referenziati da alcun parent
|
||||||
|
const orphans = (pages.value as PageWithKey[])
|
||||||
|
.filter((p) => p.inmenu && p.submenu && p.__key && !usedChildKeys.has(p.__key))
|
||||||
|
.sort(byOrder);
|
||||||
|
for (const ch of orphans) {
|
||||||
|
rows.push({ ...(ch as any), __depth: 0 }); // fallback: top-level
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordina le righe in base all'ordine gerarchico
|
||||||
|
rows.sort((a, b) => {
|
||||||
|
// Prima per ordine
|
||||||
|
const orderDiff = (a.order ?? 0) - (b.order ?? 0);
|
||||||
|
if (orderDiff !== 0) return orderDiff;
|
||||||
|
|
||||||
|
// Poi per profondità (top-level prima dei sottomenu)
|
||||||
|
return a.__depth - b.__depth;
|
||||||
|
});
|
||||||
|
|
||||||
|
menuRows.value = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rebuildOffList() {
|
||||||
|
offList.value = pages.value.filter((p) => !p.inmenu).sort(byOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rebuildAllViews() {
|
||||||
|
rebuildMenuRows();
|
||||||
|
rebuildOffList();
|
||||||
|
globalStore.aggiornaMenu($router);
|
||||||
|
}
|
||||||
|
|
||||||
// ---- SELEZIONE / UTILS -------------------------------------------------
|
// ---- SELEZIONE / UTILS -------------------------------------------------
|
||||||
const currentIdx = computed(() =>
|
const currentIdx = computed(() =>
|
||||||
@@ -340,34 +528,33 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- AZIONI UI ---------------------------------------------------------
|
// ---- AZIONI UI ---------------------------------------------------------
|
||||||
function addSubmenu() {
|
|
||||||
const p = pages.value.find((x) => x.__key === selectedKey.value);
|
|
||||||
if (!p) return;
|
|
||||||
|
|
||||||
if (!Array.isArray(p.sottoMenu)) p.sottoMenu = [];
|
|
||||||
if (p.submenu !== true) p.submenu = true;
|
|
||||||
if (p.mainMenu !== true) p.mainMenu = true;
|
|
||||||
|
|
||||||
// placeholder path
|
|
||||||
const base = '/nuova-voce';
|
|
||||||
let name = base;
|
|
||||||
let i = 1;
|
|
||||||
while (p.sottoMenu.includes(name)) {
|
|
||||||
i++;
|
|
||||||
name = `${base}-${i}`;
|
|
||||||
}
|
|
||||||
p.sottoMenu.push(name);
|
|
||||||
|
|
||||||
emit(
|
|
||||||
'update:modelValue',
|
|
||||||
pages.value.map((x) => ({ ...x }))
|
|
||||||
);
|
|
||||||
rebuildAllViews();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addPage(bucket: Bucket) {
|
function addPage(bucket: Bucket) {
|
||||||
visualizzaEditor.value = true; // ⬅️ aggiungi
|
visualizzaEditor.value = true;
|
||||||
nuovaPagina.value = true; // ⬅️ aggiungi
|
nuovaPagina.value = true;
|
||||||
|
|
||||||
|
// Calcola l'ordine in base al bucket
|
||||||
|
let order = 0;
|
||||||
|
if (bucket === 'menu') {
|
||||||
|
// Per il menu, usa il sistema gerarchico
|
||||||
|
const newRows = [
|
||||||
|
...menuRows.value,
|
||||||
|
{
|
||||||
|
__key: `tmp_${uidSeed}`,
|
||||||
|
__depth: 0,
|
||||||
|
inmenu: true,
|
||||||
|
submenu: false,
|
||||||
|
path: '/nuova-pagina',
|
||||||
|
title: '',
|
||||||
|
order: 0,
|
||||||
|
} as any,
|
||||||
|
];
|
||||||
|
order = calculateHierarchicalOrder(newRows, newRows.length - 1);
|
||||||
|
} else {
|
||||||
|
// Per "off", usa l'ordine massimo + 10
|
||||||
|
order = Math.max(...pages.value.map((p) => p.order || 0)) + 10;
|
||||||
|
}
|
||||||
|
|
||||||
const np: PageWithKey = {
|
const np: PageWithKey = {
|
||||||
title: '',
|
title: '',
|
||||||
path: '/nuova-pagina',
|
path: '/nuova-pagina',
|
||||||
@@ -377,8 +564,7 @@ export default defineComponent({
|
|||||||
inmenu: bucket === 'menu',
|
inmenu: bucket === 'menu',
|
||||||
submenu: false,
|
submenu: false,
|
||||||
onlyif_logged: false,
|
onlyif_logged: false,
|
||||||
order:
|
order: order,
|
||||||
bucket === 'menu' ? computeAppendOrderForMenu() : computeAppendOrderForOff(),
|
|
||||||
__key: `tmp_${uidSeed++}`,
|
__key: `tmp_${uidSeed++}`,
|
||||||
};
|
};
|
||||||
pages.value.push(np);
|
pages.value.push(np);
|
||||||
@@ -427,68 +613,20 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function move(bucket: Bucket, idx: number, delta: number) {
|
function editAt(idx: number) {
|
||||||
if (bucket === 'menu') {
|
const key = (menuRows.value[idx] || offList.value[idx])?.__key;
|
||||||
const list = menuRows.value.slice();
|
selectedKey.value = key || selectedKey.value;
|
||||||
const to = idx + delta;
|
|
||||||
if (to < 0 || to >= list.length) return;
|
visualizzaEditor.value = true;
|
||||||
const [it] = list.splice(idx, 1);
|
nuovaPagina.value = false;
|
||||||
list.splice(to, 0, it);
|
|
||||||
menuRows.value = list;
|
|
||||||
onMenuDragChange({ moved: { newIndex: to } }); // ⬅️ usa handler con indice
|
|
||||||
selectedKey.value = it.__key!;
|
|
||||||
} else {
|
|
||||||
const list = offList.value.slice();
|
|
||||||
const to = idx + delta;
|
|
||||||
if (to < 0 || to >= list.length) return;
|
|
||||||
const [it] = list.splice(idx, 1);
|
|
||||||
list.splice(to, 0, it);
|
|
||||||
offList.value = list;
|
|
||||||
onOffDragChange({ moved: { newIndex: to } }); // ⬅️ idem
|
|
||||||
selectedKey.value = it.__key!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⬇️ Sostituisci la tua onMenuDragChange
|
function openKey(key?: string) {
|
||||||
function onMenuDragChange(evt?: any) {
|
const p = pages.value.find((x) => x.__key === key);
|
||||||
const movedIndex: number | undefined = evt?.moved?.newIndex;
|
if (!p) return;
|
||||||
applyingRows.value = true;
|
$router.push(`/${p.path}?edit=1`);
|
||||||
let deltas: { id: string; order: number }[] = [];
|
|
||||||
try {
|
|
||||||
deltas = applyMenuRows(menuRows.value, movedIndex);
|
|
||||||
} finally {
|
|
||||||
applyingRows.value = false;
|
|
||||||
rebuildAllViews();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(
|
|
||||||
'update:modelValue',
|
|
||||||
pages.value.map((p) => ({ ...p }))
|
|
||||||
);
|
|
||||||
if (deltas.length) emit('change-order', deltas);
|
|
||||||
if (typeof globalStore.aggiornaMenu === 'function') {
|
|
||||||
try {
|
|
||||||
globalStore.aggiornaMenu($router);
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ⬇️ Sostituisci la tua onOffDragChange
|
|
||||||
function onOffDragChange(evt?: any) {
|
|
||||||
const movedIndex: number | undefined = evt?.moved?.newIndex;
|
|
||||||
const deltas = applyOffList(offList.value, movedIndex);
|
|
||||||
|
|
||||||
rebuildAllViews();
|
|
||||||
emit(
|
|
||||||
'update:modelValue',
|
|
||||||
pages.value.map((p) => ({ ...p }))
|
|
||||||
);
|
|
||||||
if (deltas.length) emit('change-order', deltas);
|
|
||||||
if (typeof globalStore.aggiornaMenu === 'function') {
|
|
||||||
try {
|
|
||||||
globalStore.aggiornaMenu($router);
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function onApply() {
|
function onApply() {
|
||||||
emit(
|
emit(
|
||||||
'update:modelValue',
|
'update:modelValue',
|
||||||
@@ -497,24 +635,33 @@ export default defineComponent({
|
|||||||
const cur = currentIdx.value >= 0 ? pages.value[currentIdx.value] : undefined;
|
const cur = currentIdx.value >= 0 ? pages.value[currentIdx.value] : undefined;
|
||||||
emit('save', cur);
|
emit('save', cur);
|
||||||
rebuildAllViews();
|
rebuildAllViews();
|
||||||
|
visualizzaEditor.value = false;
|
||||||
visualizzaEditor.value = false; // ⬅️ aggiungi
|
nuovaPagina.value = false;
|
||||||
nuovaPagina.value = false; // ⬅️ aggiungi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function editAt(idx: number) {
|
// ---- WATCHERS ----------------------------------------------------------
|
||||||
const key = (menuRows.value[idx] || offList.value[idx])?.__key;
|
watch(
|
||||||
selectedKey.value = key || selectedKey.value;
|
() => props.modelValue,
|
||||||
|
(v) => {
|
||||||
|
pages.value = (v || []).map((p) => ({ ...p }));
|
||||||
|
ensureKeys(pages.value);
|
||||||
|
pages.value.sort(byOrder);
|
||||||
|
rebuildAllViews();
|
||||||
|
if (!pages.value.find((p) => p.__key === selectedKey.value))
|
||||||
|
selectedKey.value = null;
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
visualizzaEditor.value = true; // ⬅️ aggiungi
|
// ricostruisci la vista quando pages cambia (evita durante apply)
|
||||||
nuovaPagina.value = false; // ⬅️ aggiungi
|
watch(
|
||||||
}
|
() => pages.value,
|
||||||
|
() => {
|
||||||
function openKey(key?: string) {
|
if (applyingRows.value) return;
|
||||||
const p = pages.value.find((x) => x.__key === key);
|
rebuildAllViews();
|
||||||
if (!p) return;
|
},
|
||||||
$router.push(`/${p.path}?edit=1`);
|
{ deep: true, immediate: true }
|
||||||
}
|
);
|
||||||
|
|
||||||
// ---- EXPOSE ------------------------------------------------------------
|
// ---- EXPOSE ------------------------------------------------------------
|
||||||
return {
|
return {
|
||||||
@@ -526,17 +673,15 @@ export default defineComponent({
|
|||||||
// actions
|
// actions
|
||||||
select,
|
select,
|
||||||
addPage,
|
addPage,
|
||||||
addSubmenu,
|
|
||||||
removeAt,
|
removeAt,
|
||||||
move,
|
editAt,
|
||||||
onMenuDragChange,
|
onMenuDragChange,
|
||||||
onOffDragChange,
|
onOffDragChange,
|
||||||
onApply,
|
onApply,
|
||||||
displayPath,
|
displayPath,
|
||||||
editAt,
|
|
||||||
openKey,
|
openKey,
|
||||||
visualizzaEditor, // ⬅️ aggiungi
|
visualizzaEditor,
|
||||||
nuovaPagina, // ⬅️ aggiungi
|
nuovaPagina,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<q-card
|
<q-card
|
||||||
flat
|
flat
|
||||||
bordered
|
bordered
|
||||||
|
class="menu-container"
|
||||||
>
|
>
|
||||||
<q-toolbar>
|
<q-toolbar>
|
||||||
<q-toolbar-title>Menu</q-toolbar-title>
|
<q-toolbar-title>Menu</q-toolbar-title>
|
||||||
@@ -16,16 +17,9 @@
|
|||||||
<q-btn
|
<q-btn
|
||||||
dense
|
dense
|
||||||
icon="fas fa-plus"
|
icon="fas fa-plus"
|
||||||
label="Nuovo"
|
label="Nuova Pagina"
|
||||||
@click="addPage('menu')"
|
@click="addPage('menu')"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
|
||||||
dense
|
|
||||||
icon="fas fa-sitemap"
|
|
||||||
label="SottoMenu"
|
|
||||||
:disable="!selectedKey"
|
|
||||||
@click="addSubmenu()"
|
|
||||||
/>
|
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
|
|
||||||
<draggable
|
<draggable
|
||||||
@@ -44,6 +38,7 @@
|
|||||||
v-model:active="element.active"
|
v-model:active="element.active"
|
||||||
:depth="element.__depth"
|
:depth="element.__depth"
|
||||||
variant="menu"
|
variant="menu"
|
||||||
|
class="menu-item"
|
||||||
@select="select(element.__key)"
|
@select="select(element.__key)"
|
||||||
@edit="editAt(index)"
|
@edit="editAt(index)"
|
||||||
@delete="removeAt('menu', index)"
|
@delete="removeAt('menu', index)"
|
||||||
@@ -103,7 +98,6 @@
|
|||||||
<!-- Editor -->
|
<!-- Editor -->
|
||||||
<q-dialog
|
<q-dialog
|
||||||
v-model="visualizzaEditor"
|
v-model="visualizzaEditor"
|
||||||
persistent
|
|
||||||
>
|
>
|
||||||
<page-editor
|
<page-editor
|
||||||
v-if="currentIdx !== -1"
|
v-if="currentIdx !== -1"
|
||||||
@@ -119,4 +113,8 @@
|
|||||||
<script lang="ts" src="./PagesConfigurator.ts"></script>
|
<script lang="ts" src="./PagesConfigurator.ts"></script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import './PagesConfigurator.scss';
|
@import './PagesConfigurator.scss';
|
||||||
|
|
||||||
|
.menu-container {
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,30 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="finishLoading" class="no-border">
|
<!-- Loading -->
|
||||||
|
<div
|
||||||
|
v-if="!finishLoading"
|
||||||
|
class="q-pa-md"
|
||||||
|
>
|
||||||
|
<q-skeleton
|
||||||
|
v-for="i in 4"
|
||||||
|
:key="i"
|
||||||
|
type="text"
|
||||||
|
class="q-mb-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="no-border"
|
||||||
|
>
|
||||||
<q-list class="rounded-borders text-primary">
|
<q-list class="rounded-borders text-primary">
|
||||||
<template v-for="menuItem in getmenu" :key="menuItem">
|
<!-- Top-level items -->
|
||||||
<template v-for="(route, index) in myroutes" :key="index">
|
<template v-if="myroutes && myroutes.length">
|
||||||
<CMenuItem
|
<CMenuItem
|
||||||
v-if="
|
v-for="route in myroutes.filter(
|
||||||
route.active &&
|
(r) => r && r.active && r.inmenu && !r.submenu && tools.visumenu(r)
|
||||||
!route.submenu &&
|
)"
|
||||||
route.inmenu &&
|
:key="route._id || route.path || route.title"
|
||||||
tools.visumenu(route)
|
:item="route"
|
||||||
"
|
:tools="tools"
|
||||||
:item="route"
|
:getroute="getroute"
|
||||||
:getroute="getroute"
|
:getmymenuclass="getmymenuclass"
|
||||||
:getmymenuclass="getmymenuclass"
|
:getimgiconclass="getimgiconclass"
|
||||||
:getimgiconclass="getimgiconclass"
|
:clBase="clBase"
|
||||||
:clBase="clBase"
|
:level="1"
|
||||||
:level="1"
|
/>
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Empty state -->
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="q-pa-md text-grey-7 text-caption"
|
||||||
|
>
|
||||||
|
Nessuna voce di menu disponibile.
|
||||||
|
</div>
|
||||||
</q-list>
|
</q-list>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" src="./menuOne.ts">
|
<script lang="ts" src="./menuOne.ts"></script>
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './menuOne.scss';
|
@import './menuOne.scss';
|
||||||
|
|||||||
@@ -252,7 +252,6 @@ export interface IMyPage {
|
|||||||
extraclass?: string
|
extraclass?: string
|
||||||
loadFirst?: boolean
|
loadFirst?: boolean
|
||||||
showFooter?: boolean
|
showFooter?: boolean
|
||||||
mainMenu?: boolean
|
|
||||||
sottoMenu?: string[]
|
sottoMenu?: string[]
|
||||||
hideHeader?: boolean
|
hideHeader?: boolean
|
||||||
|
|
||||||
@@ -628,7 +627,6 @@ export interface IListRoutes {
|
|||||||
idelem?: string
|
idelem?: string
|
||||||
urlroute?: string
|
urlroute?: string
|
||||||
img?: string
|
img?: string
|
||||||
mainMenu?: boolean
|
|
||||||
sottoMenu?: string[]
|
sottoMenu?: string[]
|
||||||
// ------------------------
|
// ------------------------
|
||||||
faIcon?: string
|
faIcon?: string
|
||||||
|
|||||||
@@ -1037,11 +1037,6 @@ export const colmypage = [
|
|||||||
}),
|
}),
|
||||||
AddCol({ name: 'title', label_trans: 'pages.title' }),
|
AddCol({ name: 'title', label_trans: 'pages.title' }),
|
||||||
AddCol({ name: 'subtitle', label_trans: 'pages.subtitle' }),
|
AddCol({ name: 'subtitle', label_trans: 'pages.subtitle' }),
|
||||||
AddCol({
|
|
||||||
name: 'mainMenu',
|
|
||||||
label_trans: 'pages.mainMenu',
|
|
||||||
fieldtype: costanti.FieldType.boolean,
|
|
||||||
}),
|
|
||||||
AddCol({
|
AddCol({
|
||||||
name: 'sottoMenu',
|
name: 'sottoMenu',
|
||||||
label_trans: 'pages.sottoMenu',
|
label_trans: 'pages.sottoMenu',
|
||||||
|
|||||||
@@ -3471,7 +3471,9 @@ export const tools = {
|
|||||||
) {
|
) {
|
||||||
let mystr = '';
|
let mystr = '';
|
||||||
// is same day?
|
// is same day?
|
||||||
if (tools.getstrDate(myevent.dateTimeStart) === tools.getstrDate(myevent.dateTimeEnd)) {
|
if (
|
||||||
|
tools.getstrDate(myevent.dateTimeStart) === tools.getstrDate(myevent.dateTimeEnd)
|
||||||
|
) {
|
||||||
if (withhtml) {
|
if (withhtml) {
|
||||||
mystr += `<span class="cal__where-content">${tools.getstrDateLong(myevent.dateTimeStart)}</span>
|
mystr += `<span class="cal__where-content">${tools.getstrDateLong(myevent.dateTimeStart)}</span>
|
||||||
<span class="cal__hours-content">${$t('cal.starttime')} ${tools.getstrTime(myevent.dateTimeStart)}
|
<span class="cal__hours-content">${$t('cal.starttime')} ${tools.getstrTime(myevent.dateTimeStart)}
|
||||||
@@ -5058,13 +5060,13 @@ export const tools = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
removeatIniziale(mystr: string) {
|
removeatIniziale(mystr: string) {
|
||||||
mystr = mystr.trim()
|
mystr = mystr.trim();
|
||||||
|
|
||||||
// remove @ from the beginning
|
// remove @ from the beginning
|
||||||
if (mystr.startsWith('@')) {
|
if (mystr.startsWith('@')) {
|
||||||
mystr = mystr.substring(1);
|
mystr = mystr.substring(1);
|
||||||
}
|
}
|
||||||
return mystr
|
return mystr;
|
||||||
},
|
},
|
||||||
|
|
||||||
removespaces_slash(mystr: string) {
|
removespaces_slash(mystr: string) {
|
||||||
@@ -5716,7 +5718,7 @@ export const tools = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLinkUserTelegramAportador() {
|
getLinkUserTelegramAportador() {
|
||||||
const aportador = this.getAportadorSolidario()
|
const aportador = this.getAportadorSolidario();
|
||||||
if (aportador) {
|
if (aportador) {
|
||||||
if (userprofile.profile?.username_telegram) {
|
if (userprofile.profile?.username_telegram) {
|
||||||
return 'https://t.me/' + userprofile.profile.username_telegram;
|
return 'https://t.me/' + userprofile.profile.username_telegram;
|
||||||
@@ -7782,7 +7784,6 @@ export const tools = {
|
|||||||
if (userStore.my.profile.manage_mygroups) {
|
if (userStore.my.profile.manage_mygroups) {
|
||||||
const ris = userStore.my.profile.manage_mygroups.find((grp: IMyGroup) => {
|
const ris = userStore.my.profile.manage_mygroups.find((grp: IMyGroup) => {
|
||||||
if (grp.groupname === groupname) {
|
if (grp.groupname === groupname) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -8110,7 +8111,10 @@ export const tools = {
|
|||||||
const rec = arrmultisel.find((rec) => rec.table === table);
|
const rec = arrmultisel.find((rec) => rec.table === table);
|
||||||
if (rec) {
|
if (rec) {
|
||||||
ris = tools.getCookie(
|
ris = tools.getCookie(
|
||||||
tools.COOK_SEARCH + table + '_' + tools.getCookie(tools.COOK_SEARCH + rec.join, 0),
|
tools.COOK_SEARCH +
|
||||||
|
table +
|
||||||
|
'_' +
|
||||||
|
tools.getCookie(tools.COOK_SEARCH + rec.join, 0),
|
||||||
mydef
|
mydef
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -8302,9 +8306,13 @@ export const tools = {
|
|||||||
// console.log('arrimage', arrimage)
|
// console.log('arrimage', arrimage)
|
||||||
|
|
||||||
if (shared_consts.TABLES_DIRECTORY_A_PARTE.includes(table)) {
|
if (shared_consts.TABLES_DIRECTORY_A_PARTE.includes(table)) {
|
||||||
return tools.getDirUpload() + `${table}/` + groupname + '/' + arrimage[0]?.imagefile;
|
return (
|
||||||
|
tools.getDirUpload() + `${table}/` + groupname + '/' + arrimage[0]?.imagefile
|
||||||
|
);
|
||||||
} else if (shared_consts.TABLES_DIRECTORY_SINGLE_IMG.includes(table)) {
|
} else if (shared_consts.TABLES_DIRECTORY_SINGLE_IMG.includes(table)) {
|
||||||
return tools.getDirUpload() + `${table}/` + groupname + '/' + arrimage[0]?.imagefile;
|
return (
|
||||||
|
tools.getDirUpload() + `${table}/` + groupname + '/' + arrimage[0]?.imagefile
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// console.log('username', username, 'table', table)
|
// console.log('username', username, 'table', table)
|
||||||
if (arrimage && arrimage.length > 0) {
|
if (arrimage && arrimage.length > 0) {
|
||||||
@@ -9010,11 +9018,17 @@ export const tools = {
|
|||||||
);
|
);
|
||||||
} else return '';
|
} else return '';
|
||||||
} else if (elem.type === shared_consts.ELEMTYPE.IMAGE) {
|
} else if (elem.type === shared_consts.ELEMTYPE.IMAGE) {
|
||||||
return elem.container ? tools.getDirUpload() + 'pages/' + mypath + '/' + elem.container + addtourl : '';
|
return elem.container
|
||||||
|
? tools.getDirUpload() + 'pages/' + mypath + '/' + elem.container + addtourl
|
||||||
|
: '';
|
||||||
} else if (elem.type === shared_consts.ELEMTYPE.QRCODE) {
|
} else if (elem.type === shared_consts.ELEMTYPE.QRCODE) {
|
||||||
return elem.image ? tools.getDirUpload() + 'pages/' + mypath + '/' + elem.image + addtourl : '';
|
return elem.image
|
||||||
|
? tools.getDirUpload() + 'pages/' + mypath + '/' + elem.image + addtourl
|
||||||
|
: '';
|
||||||
} else {
|
} else {
|
||||||
return elem.image ? tools.getDirUpload() + 'pages/' + mypath + '/' + elem.image + addtourl : '';
|
return elem.image
|
||||||
|
? tools.getDirUpload() + 'pages/' + mypath + '/' + elem.image + addtourl
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -10191,7 +10205,7 @@ export const tools = {
|
|||||||
indrec,
|
indrec,
|
||||||
mysubsubkey,
|
mysubsubkey,
|
||||||
specialField,
|
specialField,
|
||||||
recordFull,
|
recordFull
|
||||||
);
|
);
|
||||||
myval = newval.vers_img;
|
myval = newval.vers_img;
|
||||||
const mykey2 = 'vers_img';
|
const mykey2 = 'vers_img';
|
||||||
@@ -10207,7 +10221,7 @@ export const tools = {
|
|||||||
indrec,
|
indrec,
|
||||||
mysubsubkey,
|
mysubsubkey,
|
||||||
specialField,
|
specialField,
|
||||||
recordFull,
|
recordFull
|
||||||
);
|
);
|
||||||
|
|
||||||
eseguito = true;
|
eseguito = true;
|
||||||
@@ -11157,7 +11171,7 @@ export const tools = {
|
|||||||
// Restituisce il colore con trasparenza in formato rgba
|
// Restituisce il colore con trasparenza in formato rgba
|
||||||
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -11174,6 +11188,23 @@ export const tools = {
|
|||||||
return Math.ceil((pastDaysOfYear + startOfYear.getDay() + 1) / 7);
|
return Math.ceil((pastDaysOfYear + startOfYear.getDay() + 1) / 7);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getmenuByPath(path: string) {
|
||||||
|
const myroutes = static_data.routes;
|
||||||
|
|
||||||
|
const normalized = this.norm(path);
|
||||||
|
|
||||||
|
const mymenus = myroutes.find((menu: any) => menu.path === normalized);
|
||||||
|
|
||||||
|
return mymenus;
|
||||||
|
},
|
||||||
|
|
||||||
|
norm(path: string): string {
|
||||||
|
return path
|
||||||
|
.trim()
|
||||||
|
.replace(/^\/+|\/+$/g, '')
|
||||||
|
.toLowerCase();
|
||||||
|
},
|
||||||
|
|
||||||
// FINE !
|
// FINE !
|
||||||
|
|
||||||
// getLocale() {
|
// getLocale() {
|
||||||
|
|||||||
@@ -823,7 +823,6 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
|||||||
level_parent: page.l_par,
|
level_parent: page.l_par,
|
||||||
submenu: page.submenu,
|
submenu: page.submenu,
|
||||||
extraclass: page.extraclass,
|
extraclass: page.extraclass,
|
||||||
mainMenu: page.mainMenu,
|
|
||||||
sottoMenu: page.sottoMenu,
|
sottoMenu: page.sottoMenu,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user