diff --git a/src/common/shared_vuejs.ts b/src/common/shared_vuejs.ts
index a44937f5..478ca853 100755
--- a/src/common/shared_vuejs.ts
+++ b/src/common/shared_vuejs.ts
@@ -125,6 +125,7 @@ export const shared_consts = {
IMAGEUPLOAD: 35,
SEPARATOR: 40,
VIDEO: 50,
+ VIDEO_YOUTUBE: 52,
PAGE: 55,
PAGEINTRO: 58,
CALENDAR: 70,
@@ -1816,66 +1817,82 @@ export const shared_consts = {
{
value: 5,
label: 'Titolo',
+ icon: 'fas fa-heading',
},
{
value: 8,
label: 'ImgTitolo',
+ icon: 'fas fa-image',
},
{
value: 10,
label: 'Testo semplice',
+ icon: 'fas fa-file-alt',
},
{
value: 30,
label: 'Immagine (nomefile)',
+ icon: 'fas fa-image',
},
{
value: 130,
label: 'MainView',
+ icon: 'fas fa-eye',
},
{
value: 140,
label: 'Dashboard',
+ icon: 'fas fa-tachometer-alt',
},
{
value: 145,
label: 'DashGroup',
+ icon: 'fas fa-users',
},
{
value: 148,
label: 'Lista Movimenti',
+ icon: 'fas fa-list',
},
{
value: 150,
label: 'SendCoinTo',
+ icon: 'fas fa-wallet',
},
{
value: 280,
label: 'Tutorial',
+ icon: 'fas fa-book',
},
{
value: 400,
label: 'Visualizzatore Tabelle',
+ icon: 'fas fa-table',
},
{
value: 410,
label: 'Qr Code',
+ icon: 'fas fa-qrcode',
},
{
value: 420,
label: 'Lista Cataloghi',
+ icon: 'fas fa-list',
},
{
value: 450,
label: 'Raccolte Cataloghi',
+ icon: 'fas fa-list',
},
{
value: 460,
label: 'Statistiche Pagine',
+ icon: 'fas fa-chart-pie',
},
{
value: 430, // SEARCHPRODUCT
label: 'Cerca Prodotto',
+ icon: 'fas fa-search',
},
],
@@ -1883,130 +1900,162 @@ export const shared_consts = {
{
value: 100,
label: 'Check Email',
+ icon: 'fas fa-envelope',
},
{
value: 120,
label: 'OpenStreetMap',
+ icon: 'fas fa-globe',
},
{
value: 160,
label: 'Stato Registrati',
+ icon: 'fas fa-user',
},
{
value: 170,
label: 'CheckIfIsLogged',
+ icon: 'fas fa-user-lock',
},
{
value: 180,
label: 'Info Versione',
+ icon: 'fas fa-info-circle',
},
{
value: 190,
label: 'Bottone Condividi',
+ icon: 'fas fa-share-alt',
},
{
value: 192,
label: 'Bottone Chat Territoriale',
+ icon: 'fas fa-comments',
},
{
value: 200,
label: 'Presentazione',
+ icon: 'fas fa-presentation',
},
{
value: 205,
label: 'Attività',
+ icon: 'fas fa-briefcase',
},
{
value: 210,
label: 'Notifiche in Top',
+ icon: 'fas fa-bell',
},
{
value: 135,
label: 'Check App Running',
+ icon: 'fas fa-spinner',
},
{
value: 258,
label: 'Registration',
+ icon: 'fas fa-user-plus',
},
{
value: 220,
label: 'CHART',
+ icon: 'fas fa-chart-pie',
},
{
value: 230,
label: 'Check New Version',
+ icon: 'fas fa-sync-alt',
},
{
value: 240,
label: 'Check Test Version',
+ icon: 'fas fa-flask',
},
{
value: 250,
label: 'Butt Registrati',
+ icon: 'fas fa-user-plus',
},
{
value: 255,
label: 'Butt Registrati col Bot',
+ icon: 'fas fa-user-plus',
},
{
value: 260,
label: 'Butt Login',
+ icon: 'fas fa-sign-in-alt',
},
{
value: 270,
label: 'Footer',
+ icon: 'fas fa-copyright',
},
{
value: 280,
label: 'Visu Promo and PDF',
+ icon: 'fas fa-file-pdf',
},
{
value: 40,
label: 'Separatore',
+ icon: 'fas fa-minus',
},
{
value: 70,
label: 'Calendario',
+ icon: 'fas fa-calendar',
},
{
value: 300,
label: 'E-COMMERCE',
+ icon: 'fas fa-shopping-cart',
},
{
value: 310,
label: 'CATALOGO',
+ icon: 'fas fa-list',
},
{
value: 315,
label: 'RACCOLTA CATALOGHI',
+ icon: 'fas fa-list',
},
{
value: 320,
label: 'TOOLS AI',
+ icon: 'fas fa-robot',
},
{
value: 325,
label: 'CHATBOT',
+ icon: 'fas fa-robot',
},
{
value: 350,
label: 'MAPPA',
+ icon: 'fas fa-globe',
},
{
value: 360,
label: 'MAPPAUTENTI',
+ icon: 'fas fa-globe',
},
{
value: 370,
label: 'MAPPACOMUNI',
+ icon: 'fas fa-globe',
},
{
value: 380,
label: 'MAPPA GET COORD',
+ icon: 'fas fa-globe',
},
{
value: 390,
label: 'EDIT ADDRESS BY COORD',
+ icon: 'fas fa-globe',
},
],
@@ -2024,11 +2073,12 @@ export const shared_consts = {
{
value: 35,
label: 'Immagine',
- icon: '',
+ icon: 'fas fa-image',
},
{
value: 7,
label: 'Scheda (IMG + Testo)',
+ icon: 'fas fa-id-card',
},
/*
Disattivato perchè attualmente non funziona bene
@@ -2039,26 +2089,37 @@ export const shared_consts = {
{
value: 195,
label: 'Bottone',
+ icon: 'fas fa-hand-point-right',
},
{
value: 50,
label: 'Video',
+ icon: 'fas fa-video',
+ },
+ {
+ value: 52,
+ label: 'Video Youtube',
+ icon: 'fab fa-youtube',
},
{
value: 55,
label: 'Pagina',
+ icon: 'fas fa-file-alt',
},
{
value: 58,
label: 'Pagina (solo Intro)',
+ icon: 'fas fa-file-alt',
},
{
value: 110,
label: "Galleria d'Immagini",
+ icon: 'fas fa-images',
},
{
value: 6,
label: 'Margine',
+ icon: 'fas fa-arrows-alt-h',
},
],
diff --git a/src/components/CMyEditElem/CMyEditElem.vue b/src/components/CMyEditElem/CMyEditElem.vue
index 2755f370..ea049298 100755
--- a/src/components/CMyEditElem/CMyEditElem.vue
+++ b/src/components/CMyEditElem/CMyEditElem.vue
@@ -1097,6 +1097,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
,
@@ -76,6 +73,16 @@ export default defineComponent({
const catalogStore = useCatalogStore();
const router = useRouter();
+ const sections = computed(() => [
+ { label: 'Principali', icon: 'fas fa-eye', items: shared_consts.TypesElem },
+ { label: 'Gestione', icon: 'fas fa-cog', items: shared_consts.TypesElemAdmin },
+ {
+ label: 'Avanzati',
+ icon: 'fas fa-star',
+ items: shared_consts.TypesElemAdminTools,
+ },
+ ]);
+
const { setmeta, getsrcbyimg } = MixinMetaTags();
const { setValDb, getValDb } = MixinBase();
@@ -107,7 +114,6 @@ export default defineComponent({
const selectedClasses = ref(
[]);
-
async function addNewElem(elemsel: any, direz: number) {
// Nascondi la visualizzazione di aggiunta (presumo sia una variabile reattiva)
visuadd.value = false;
@@ -148,7 +154,7 @@ export default defineComponent({
let sectionId = '';
let rowId = '';
- console.log('sectionId', sectionId, 'rowId', rowId)
+ console.log('sectionId', sectionId, 'rowId', rowId);
// Aggiungi un nuovo elemento alla sezione o riga usando il metodo preparato
const newrec = await globalStore.prepareAddNewElem(
@@ -157,7 +163,7 @@ export default defineComponent({
t,
myelem,
props.myElemParent,
- newtype.value,
+ newtype.value
);
// Emitti l'evento per la selezione del nuovo elemento
@@ -167,7 +173,6 @@ export default defineComponent({
// emit('updateAll', newrec);
}
-
return {
tools,
shared_consts,
@@ -191,6 +196,7 @@ export default defineComponent({
Products,
globalStore,
myel,
+ sections,
};
},
});
diff --git a/src/components/CMyElemAdd/CMyElemAdd.vue b/src/components/CMyElemAdd/CMyElemAdd.vue
index 5b1a9a96..b784224b 100755
--- a/src/components/CMyElemAdd/CMyElemAdd.vue
+++ b/src/components/CMyElemAdd/CMyElemAdd.vue
@@ -1,107 +1,46 @@
-
-
+
+
+
Aggiungi Elemento:
-
+
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
-
diff --git a/src/components/CMyPageElem/CMyPageElem.ts b/src/components/CMyPageElem/CMyPageElem.ts
index 0ad612f1..16e43376 100755
--- a/src/components/CMyPageElem/CMyPageElem.ts
+++ b/src/components/CMyPageElem/CMyPageElem.ts
@@ -115,6 +115,66 @@ export default defineComponent({
const onloading = ref(false);
+ // Blocchi media DRY (img/content/video x 1..3) + fix img3
+ const mediaBlocks = computed(() => {
+ if (!rec.value) return [];
+ const r = rec.value;
+ return [
+ {
+ img: r.img1 || null,
+ html: r.content || null,
+ video: r.video1 || null,
+ ratio: r.ratio1 || null,
+ },
+ {
+ img: r.img2 || null,
+ html: r.content2 || null,
+ video: r.video2 || null,
+ ratio: r.ratio2 || null,
+ },
+ {
+ img: r.img3 || null,
+ html: r.content3 || null,
+ video: r.video3 || null,
+ ratio: r.ratio3 || null,
+ },
+ ];
+ });
+
+ // Larghezza drawer responsiva (usa mobile/tablet/desktop)
+ const drawerWidth = computed(() => {
+ // se hai $q disponibile: const s = $q.screen;
+ // fallback semplice:
+ return tools.isMobile() ? 340 : Math.min(mywidthEditor.value || 420, 560);
+ });
+
+ const containerStyle = computed(() => ({
+ maxWidth: '980px', // comodo per lettura
+ marginLeft: 0,
+ marginRight: 0,
+ }));
+
+ const closeEditor = () => {
+ visuEditor.value = false;
+ selElem.value = {};
+ };
+
+ const openAdd = (col: any, parent: any) => {
+ visuadd.value = true;
+ myElemSel.value = col;
+ myElemParent.value = parent;
+ };
+
+ const addAtEnd = () => {
+ visuadd.value = true;
+ const last =
+ myelems.value.length > 0 ? myelems.value[myelems.value.length - 1] : null;
+ myElemSel.value = last;
+ myElemParent.value = last;
+ };
+
+ const showOrder = ref(false)
+
const myelems = computed(() => {
if (myidPage.value) return globalStore.getMyElemsByIdPage(myidPage.value);
else if (mypathin.value) return globalStore.getMyElems(mypathin.value);
@@ -376,11 +436,9 @@ export default defineComponent({
idRowToAddDown?: string,
neword?: number
) {
-
- const section = newElem
+ const section = newElem;
// trova la section “vera” nello store (per sicurezza)
- const newRow =
- newElem.rows[newElem.rows.length - 1]
+ const newRow = newElem.rows[newElem.rows.length - 1];
if (!section) return;
if (!Array.isArray(section.rows)) section.rows = [];
@@ -515,6 +573,13 @@ export default defineComponent({
myElemSel,
myElemParent,
getColClasses,
+ mediaBlocks,
+ drawerWidth,
+ containerStyle,
+ closeEditor,
+ openAdd,
+ addAtEnd,
+ showOrder,
};
},
});
diff --git a/src/components/CMyPageElem/CMyPageElem.vue b/src/components/CMyPageElem/CMyPageElem.vue
index 19f3e7e7..7bcd87e2 100755
--- a/src/components/CMyPageElem/CMyPageElem.vue
+++ b/src/components/CMyPageElem/CMyPageElem.vue
@@ -8,48 +8,45 @@
-
+ />
+
-
+ @update:model-value="changeVisuDrawer(mypathin, editOn)"
+ />
+
- Editor
+ Editor
+ @click="closeEditor"
+ />
-
+ @expPage="showexportPage = true"
+ @impPage="showimportPage = true"
+ />
+
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
order: {{ myelem.order }}
+
-
-
+
+
+
+ SEZIONE
+
+
+
+
-
-
-
-
-
-
- Aggiungi Riga
-
-
-
-
-
-
RIGA {{ indriga + 1 }}:
-
-
-
-
-
-
-
-
- Colonna {{ index + 1 }}:
-
-
-
-
-
- Elimina Elemento
-
-
-
-
-
-
-
- Aggiungi Elemento
-
-
-
-
-
- Elimina Colonna
-
-
-
-
-
-
-
-
-
- Aggiungi Colonna
-
-
-
-
-
- Elimina Riga
-
-
-
- Aggiungi Riga
+ Aggiungi Riga
-
-
-
-
-
-
+
+
+ RIGA {{ indriga + 1 }}
+
-
-
+
+
+
+
+
+
+ Colonna {{ index + 1 }}
+
+
+
+
+
+
+ Elimina Elemento
+
+
+
+
+
+
+
+
+ Aggiungi Elemento
+
+
+ Elimina Colonna
+
+
+
+
+
+
+
+
+
+
+ Aggiungi Colonna
+
+
+
+
+
+
+
+ Elimina Riga
+
+
+
+
+
+
0 ? myelems[myelems.length - 1] : null;
- myElemParent =
- myelems.length > 0 ? myelems[myelems.length - 1] : null;
- "
+ class="text-center q-mt-sm"
>
- Aggiungi Elemento
-
-
+
+ Aggiungi Riga
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+ Aggiungi Elemento
+
+
+
+
-
-
+
+
+
+
+
- Esporta Pagina
+ Esporta Pagina
+ />
-
-
-
+ />
+
- Esporta Pagina
+ Importa Pagina
+ />
-
-
-
+ />
-
+
diff --git a/src/components/CMyVideoYoutube/CMyVideoYoutube.scss b/src/components/CMyVideoYoutube/CMyVideoYoutube.scss
new file mode 100755
index 00000000..06ca867e
--- /dev/null
+++ b/src/components/CMyVideoYoutube/CMyVideoYoutube.scss
@@ -0,0 +1,72 @@
+.cmy-yt {
+ width: 100%;
+}
+
+.cmy-yt__error {
+ display: flex;
+ align-items: center;
+ padding: 8px 12px;
+ border-radius: 8px;
+ background: rgba(255, 171, 0, 0.12);
+ color: #7a4f01;
+}
+
+.cmy-yt__frame-wrapper {
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);
+}
+
+.cmy-yt__iframe {
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+
+.cmy-yt__thumb-wrapper {
+ position: relative;
+}
+
+.cmy-yt__thumb-img {
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);
+}
+
+.cmy-yt__overlay {
+ position: absolute;
+ inset: 0;
+ display: grid;
+ place-items: center;
+ background: linear-gradient(0deg, rgba(0,0,0,0.35), rgba(0,0,0,0.15));
+}
+
+.cmy-yt__play-btn {
+ appearance: none;
+ border: none;
+ border-radius: 999px;
+ padding: 14px 16px;
+ background: rgba(255, 255, 255, 0.92);
+ color: #111;
+ cursor: pointer;
+ transform: scale(1);
+ transition: transform .15s ease, box-shadow .15s ease, background .2s ease;
+ box-shadow: 0 6px 20px rgba(0,0,0,.18);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.cmy-yt__play-btn:hover,
+.cmy-yt__play-btn:focus-visible {
+ transform: scale(1.05);
+ box-shadow: 0 10px 28px rgba(0,0,0,.22);
+ background: #fff;
+}
+
+@media (max-width: 599px) {
+ .cmy-yt__frame-wrapper,
+ .cmy-yt__thumb-img {
+ border-radius: 10px;
+ }
+}
diff --git a/src/components/CMyVideoYoutube/CMyVideoYoutube.ts b/src/components/CMyVideoYoutube/CMyVideoYoutube.ts
new file mode 100755
index 00000000..d8c38f64
--- /dev/null
+++ b/src/components/CMyVideoYoutube/CMyVideoYoutube.ts
@@ -0,0 +1,134 @@
+import { defineComponent, computed, ref, watch } from 'vue';
+
+type Nullable
= T | null | undefined;
+
+function extractYouTubeId(url: string): string | null {
+ if (!url) return null;
+
+ // URL normalizzati, rimuovi spazi
+ const u = url.trim();
+
+ // youtu.be/
+ const short = u.match(/^https?:\/\/(?:www\.)?youtu\.be\/([A-Za-z0-9_-]{11})/i);
+ if (short?.[1]) return short[1];
+
+ // youtube.com/watch?v= (&…)
+ const watchMatch = u.match(/[?&]v=([A-Za-z0-9_-]{11})/i);
+ if (watchMatch?.[1]) return watchMatch[1];
+
+ // youtube.com/embed/
+ const embed = u.match(/\/embed\/([A-Za-z0-9_-]{11})/i);
+ if (embed?.[1]) return embed[1];
+
+ // shorts
+ const shorts = u.match(/\/shorts\/([A-Za-z0-9_-]{11})/i);
+ if (shorts?.[1]) return shorts[1];
+
+ // fallback debole: sequenza di 11 char nel path o query
+ const loose = u.match(/([A-Za-z0-9_-]{11})/);
+ return loose?.[1] ?? null;
+}
+
+export default defineComponent({
+ name: 'CMyVideoYoutube',
+ props: {
+ /** Link completo YouTube (watch, youtu.be, embed, shorts) */
+ url: { type: String, required: true },
+
+ /** Rapporto d'aspetto (es. 16/9) */
+ ratio: { type: Number, default: 16 / 9 },
+
+ /** Modalità privacy (usa youtube-nocookie.com) */
+ privacyMode: { type: Boolean, default: true },
+
+ /** Caricamento lazy dell'iframe */
+ lazy: { type: Boolean, default: true },
+
+ /** Mostra thumbnail e avvia iframe solo al click */
+ thumbnailClickToPlay: { type: Boolean, default: true },
+
+ /** Titolo accessibile (fallback al titolo standard) */
+ title: { type: String, default: '' },
+
+ // ---- Parametri player utili ----
+ autoplay: { type: Boolean, default: false },
+ controls: { type: Boolean, default: true },
+ mute: { type: Boolean, default: false },
+ loop: { type: Boolean, default: false },
+ start: { type: Number, default: 0 },
+ end: { type: Number, default: 0 }, // 0 = nessun end
+ rel: { type: Boolean, default: false }, // video correlati (false = solo stesso canale)
+ modestBranding: { type: Boolean, default: true },
+ playsinline: { type: Boolean, default: true },
+ /** Lingua sottotitoli ("it", "en", ...) */
+ ccLang: { type: String, default: '' },
+ /** Forza sottotitoli abilitati */
+ ccLoad: { type: Boolean, default: false }
+ },
+ emits: ['started'],
+ setup(props, { emit }) {
+ const isPlaying = ref(false);
+
+ const videoId = computed(() => extractYouTubeId(props.url));
+
+ const computedTitle = computed(() => {
+ if (props.title) return props.title;
+ return 'Video YouTube';
+ });
+
+ const baseDomain = computed(() =>
+ props.privacyMode ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com'
+ );
+
+ const thumbUrl = computed(() => {
+ if (!videoId.value) return '';
+ // hqdefault.jpg è un buon compromesso tra qualità e peso
+ return `https://i.ytimg.com/vi/${videoId.value}/hqdefault.jpg`;
+ });
+
+ const embedUrl = computed(() => {
+ if (!videoId.value) return '';
+ const params = new URLSearchParams();
+
+ params.set('autoplay', (isPlaying.value || props.autoplay) ? '1' : '0');
+ params.set('controls', props.controls ? '1' : '0');
+ params.set('mute', props.mute ? '1' : '0');
+ params.set('modestbranding', props.modestBranding ? '1' : '0');
+ params.set('playsinline', props.playsinline ? '1' : '0');
+ params.set('rel', props.rel ? '1' : '0');
+
+ if (props.start > 0) params.set('start', String(props.start));
+ if (props.end > 0) params.set('end', String(props.end));
+ if (props.ccLang) params.set('cc_lang_pref', props.ccLang);
+ if (props.ccLoad) params.set('cc_load_policy', '1');
+
+ // Loop su singolo video: serve anche playlist=id
+ if (props.loop) {
+ params.set('loop', '1');
+ params.set('playlist', videoId.value);
+ }
+
+ const path = `/embed/${videoId.value}`;
+ return `${baseDomain.value}${path}?${params.toString()}`;
+ });
+
+ function startPlayback() {
+ isPlaying.value = true;
+ emit('started');
+ }
+
+ // Se cambia URL, resetta stato play
+ watch(() => props.url, () => {
+ isPlaying.value = false;
+ });
+
+ return {
+ videoId,
+ computedTitle,
+ embedUrl,
+ thumbUrl,
+ isPlaying,
+ startPlayback
+ };
+ }
+});
diff --git a/src/components/CMyVideoYoutube/CMyVideoYoutube.vue b/src/components/CMyVideoYoutube/CMyVideoYoutube.vue
new file mode 100755
index 00000000..b7aa0cd0
--- /dev/null
+++ b/src/components/CMyVideoYoutube/CMyVideoYoutube.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+ Link YouTube non valido.
+
+ Esempi accettati: https://youtu.be/ID, https://www.youtube.com/watch?v=ID
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/CMyVideoYoutube/index.ts b/src/components/CMyVideoYoutube/index.ts
new file mode 100755
index 00000000..b98dd5f4
--- /dev/null
+++ b/src/components/CMyVideoYoutube/index.ts
@@ -0,0 +1 @@
+export {default as CMyVideoYoutube} from './CMyVideoYoutube.vue'