- migliorata la grafica dell'aggiungi elemento.
This commit is contained in:
@@ -125,6 +125,7 @@ export const shared_consts = {
|
|||||||
IMAGEUPLOAD: 35,
|
IMAGEUPLOAD: 35,
|
||||||
SEPARATOR: 40,
|
SEPARATOR: 40,
|
||||||
VIDEO: 50,
|
VIDEO: 50,
|
||||||
|
VIDEO_YOUTUBE: 52,
|
||||||
PAGE: 55,
|
PAGE: 55,
|
||||||
PAGEINTRO: 58,
|
PAGEINTRO: 58,
|
||||||
CALENDAR: 70,
|
CALENDAR: 70,
|
||||||
@@ -1816,66 +1817,82 @@ export const shared_consts = {
|
|||||||
{
|
{
|
||||||
value: 5,
|
value: 5,
|
||||||
label: 'Titolo',
|
label: 'Titolo',
|
||||||
|
icon: 'fas fa-heading',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 8,
|
value: 8,
|
||||||
label: 'ImgTitolo',
|
label: 'ImgTitolo',
|
||||||
|
icon: 'fas fa-image',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 10,
|
value: 10,
|
||||||
label: 'Testo semplice',
|
label: 'Testo semplice',
|
||||||
|
icon: 'fas fa-file-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 30,
|
value: 30,
|
||||||
label: 'Immagine (nomefile)',
|
label: 'Immagine (nomefile)',
|
||||||
|
icon: 'fas fa-image',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 130,
|
value: 130,
|
||||||
label: 'MainView',
|
label: 'MainView',
|
||||||
|
icon: 'fas fa-eye',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 140,
|
value: 140,
|
||||||
label: 'Dashboard',
|
label: 'Dashboard',
|
||||||
|
icon: 'fas fa-tachometer-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 145,
|
value: 145,
|
||||||
label: 'DashGroup',
|
label: 'DashGroup',
|
||||||
|
icon: 'fas fa-users',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 148,
|
value: 148,
|
||||||
label: 'Lista Movimenti',
|
label: 'Lista Movimenti',
|
||||||
|
icon: 'fas fa-list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 150,
|
value: 150,
|
||||||
label: 'SendCoinTo',
|
label: 'SendCoinTo',
|
||||||
|
icon: 'fas fa-wallet',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 280,
|
value: 280,
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
|
icon: 'fas fa-book',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 400,
|
value: 400,
|
||||||
label: 'Visualizzatore Tabelle',
|
label: 'Visualizzatore Tabelle',
|
||||||
|
icon: 'fas fa-table',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 410,
|
value: 410,
|
||||||
label: 'Qr Code',
|
label: 'Qr Code',
|
||||||
|
icon: 'fas fa-qrcode',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 420,
|
value: 420,
|
||||||
label: 'Lista Cataloghi',
|
label: 'Lista Cataloghi',
|
||||||
|
icon: 'fas fa-list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 450,
|
value: 450,
|
||||||
label: 'Raccolte Cataloghi',
|
label: 'Raccolte Cataloghi',
|
||||||
|
icon: 'fas fa-list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 460,
|
value: 460,
|
||||||
label: 'Statistiche Pagine',
|
label: 'Statistiche Pagine',
|
||||||
|
icon: 'fas fa-chart-pie',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 430, // SEARCHPRODUCT
|
value: 430, // SEARCHPRODUCT
|
||||||
label: 'Cerca Prodotto',
|
label: 'Cerca Prodotto',
|
||||||
|
icon: 'fas fa-search',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -1883,130 +1900,162 @@ export const shared_consts = {
|
|||||||
{
|
{
|
||||||
value: 100,
|
value: 100,
|
||||||
label: 'Check Email',
|
label: 'Check Email',
|
||||||
|
icon: 'fas fa-envelope',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 120,
|
value: 120,
|
||||||
label: 'OpenStreetMap',
|
label: 'OpenStreetMap',
|
||||||
|
icon: 'fas fa-globe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 160,
|
value: 160,
|
||||||
label: 'Stato Registrati',
|
label: 'Stato Registrati',
|
||||||
|
icon: 'fas fa-user',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 170,
|
value: 170,
|
||||||
label: 'CheckIfIsLogged',
|
label: 'CheckIfIsLogged',
|
||||||
|
icon: 'fas fa-user-lock',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 180,
|
value: 180,
|
||||||
label: 'Info Versione',
|
label: 'Info Versione',
|
||||||
|
icon: 'fas fa-info-circle',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 190,
|
value: 190,
|
||||||
label: 'Bottone Condividi',
|
label: 'Bottone Condividi',
|
||||||
|
icon: 'fas fa-share-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 192,
|
value: 192,
|
||||||
label: 'Bottone Chat Territoriale',
|
label: 'Bottone Chat Territoriale',
|
||||||
|
icon: 'fas fa-comments',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 200,
|
value: 200,
|
||||||
label: 'Presentazione',
|
label: 'Presentazione',
|
||||||
|
icon: 'fas fa-presentation',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 205,
|
value: 205,
|
||||||
label: 'Attività',
|
label: 'Attività',
|
||||||
|
icon: 'fas fa-briefcase',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 210,
|
value: 210,
|
||||||
label: 'Notifiche in Top',
|
label: 'Notifiche in Top',
|
||||||
|
icon: 'fas fa-bell',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 135,
|
value: 135,
|
||||||
label: 'Check App Running',
|
label: 'Check App Running',
|
||||||
|
icon: 'fas fa-spinner',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 258,
|
value: 258,
|
||||||
label: 'Registration',
|
label: 'Registration',
|
||||||
|
icon: 'fas fa-user-plus',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 220,
|
value: 220,
|
||||||
label: 'CHART',
|
label: 'CHART',
|
||||||
|
icon: 'fas fa-chart-pie',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 230,
|
value: 230,
|
||||||
label: 'Check New Version',
|
label: 'Check New Version',
|
||||||
|
icon: 'fas fa-sync-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 240,
|
value: 240,
|
||||||
label: 'Check Test Version',
|
label: 'Check Test Version',
|
||||||
|
icon: 'fas fa-flask',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 250,
|
value: 250,
|
||||||
label: 'Butt Registrati',
|
label: 'Butt Registrati',
|
||||||
|
icon: 'fas fa-user-plus',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 255,
|
value: 255,
|
||||||
label: 'Butt Registrati col Bot',
|
label: 'Butt Registrati col Bot',
|
||||||
|
icon: 'fas fa-user-plus',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 260,
|
value: 260,
|
||||||
label: 'Butt Login',
|
label: 'Butt Login',
|
||||||
|
icon: 'fas fa-sign-in-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 270,
|
value: 270,
|
||||||
label: 'Footer',
|
label: 'Footer',
|
||||||
|
icon: 'fas fa-copyright',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 280,
|
value: 280,
|
||||||
label: 'Visu Promo and PDF',
|
label: 'Visu Promo and PDF',
|
||||||
|
icon: 'fas fa-file-pdf',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 40,
|
value: 40,
|
||||||
label: 'Separatore',
|
label: 'Separatore',
|
||||||
|
icon: 'fas fa-minus',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 70,
|
value: 70,
|
||||||
label: 'Calendario',
|
label: 'Calendario',
|
||||||
|
icon: 'fas fa-calendar',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 300,
|
value: 300,
|
||||||
label: 'E-COMMERCE',
|
label: 'E-COMMERCE',
|
||||||
|
icon: 'fas fa-shopping-cart',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 310,
|
value: 310,
|
||||||
label: 'CATALOGO',
|
label: 'CATALOGO',
|
||||||
|
icon: 'fas fa-list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 315,
|
value: 315,
|
||||||
label: 'RACCOLTA CATALOGHI',
|
label: 'RACCOLTA CATALOGHI',
|
||||||
|
icon: 'fas fa-list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 320,
|
value: 320,
|
||||||
label: 'TOOLS AI',
|
label: 'TOOLS AI',
|
||||||
|
icon: 'fas fa-robot',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 325,
|
value: 325,
|
||||||
label: 'CHATBOT',
|
label: 'CHATBOT',
|
||||||
|
icon: 'fas fa-robot',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 350,
|
value: 350,
|
||||||
label: 'MAPPA',
|
label: 'MAPPA',
|
||||||
|
icon: 'fas fa-globe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 360,
|
value: 360,
|
||||||
label: 'MAPPAUTENTI',
|
label: 'MAPPAUTENTI',
|
||||||
|
icon: 'fas fa-globe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 370,
|
value: 370,
|
||||||
label: 'MAPPACOMUNI',
|
label: 'MAPPACOMUNI',
|
||||||
|
icon: 'fas fa-globe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 380,
|
value: 380,
|
||||||
label: 'MAPPA GET COORD',
|
label: 'MAPPA GET COORD',
|
||||||
|
icon: 'fas fa-globe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 390,
|
value: 390,
|
||||||
label: 'EDIT ADDRESS BY COORD',
|
label: 'EDIT ADDRESS BY COORD',
|
||||||
|
icon: 'fas fa-globe',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -2024,11 +2073,12 @@ export const shared_consts = {
|
|||||||
{
|
{
|
||||||
value: 35,
|
value: 35,
|
||||||
label: 'Immagine',
|
label: 'Immagine',
|
||||||
icon: '',
|
icon: 'fas fa-image',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 7,
|
value: 7,
|
||||||
label: 'Scheda (IMG + Testo)',
|
label: 'Scheda (IMG + Testo)',
|
||||||
|
icon: 'fas fa-id-card',
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
Disattivato perchè attualmente non funziona bene
|
Disattivato perchè attualmente non funziona bene
|
||||||
@@ -2039,26 +2089,37 @@ export const shared_consts = {
|
|||||||
{
|
{
|
||||||
value: 195,
|
value: 195,
|
||||||
label: 'Bottone',
|
label: 'Bottone',
|
||||||
|
icon: 'fas fa-hand-point-right',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 50,
|
value: 50,
|
||||||
label: 'Video',
|
label: 'Video',
|
||||||
|
icon: 'fas fa-video',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 52,
|
||||||
|
label: 'Video Youtube',
|
||||||
|
icon: 'fab fa-youtube',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 55,
|
value: 55,
|
||||||
label: 'Pagina',
|
label: 'Pagina',
|
||||||
|
icon: 'fas fa-file-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 58,
|
value: 58,
|
||||||
label: 'Pagina (solo Intro)',
|
label: 'Pagina (solo Intro)',
|
||||||
|
icon: 'fas fa-file-alt',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 110,
|
value: 110,
|
||||||
label: "Galleria d'Immagini",
|
label: "Galleria d'Immagini",
|
||||||
|
icon: 'fas fa-images',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 6,
|
value: 6,
|
||||||
label: 'Margine',
|
label: 'Margine',
|
||||||
|
icon: 'fas fa-arrows-alt-h',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -1097,6 +1097,53 @@
|
|||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO_YOUTUBE">
|
||||||
|
<div
|
||||||
|
v-if="enableEdit"
|
||||||
|
class="row q-col-gutter-sm"
|
||||||
|
>
|
||||||
|
<!-- Link YouTube -->
|
||||||
|
<div class="col-12">
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
label="Link YouTube"
|
||||||
|
v-model="myel.container"
|
||||||
|
@update:model-value="modifElem"
|
||||||
|
v-on:keyup.enter="saveElem"
|
||||||
|
:rules="[(v) => !!v || 'Inserisci un link YouTube']"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Titolo accessibile (facoltativo) -->
|
||||||
|
<div class="col-12">
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
label="Titolo (facoltativo)"
|
||||||
|
v-model="myel.container2"
|
||||||
|
@update:model-value="modifElem"
|
||||||
|
v-on:keyup.enter="saveElem"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Ratio -->
|
||||||
|
<div class="col-12 col-sm-6">
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
type="number"
|
||||||
|
step="any"
|
||||||
|
min="0.2"
|
||||||
|
label="Ratio (es. 1.777 per 16/9)"
|
||||||
|
v-model.number="myel.ratio"
|
||||||
|
@update:model-value="modifElem"
|
||||||
|
v-on:keyup.enter="saveElem"
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGE">
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGE">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { shared_consts } from '@src/common/shared_vuejs';
|
|||||||
import { LandingFooter } from '@src/components/LandingFooter';
|
import { LandingFooter } from '@src/components/LandingFooter';
|
||||||
import { CMyActivities } from '@src/components/CMyActivities';
|
import { CMyActivities } from '@src/components/CMyActivities';
|
||||||
import { CECommerce } from '@src/components/CECommerce';
|
import { CECommerce } from '@src/components/CECommerce';
|
||||||
|
import { CMyVideoYoutube } from '@src/components/CMyVideoYoutube';
|
||||||
import { CStatMacro } from '@src/components/CStatMacro';
|
import { CStatMacro } from '@src/components/CStatMacro';
|
||||||
import { CSearchProduct } from '@src/components/CSearchProduct';
|
import { CSearchProduct } from '@src/components/CSearchProduct';
|
||||||
import { CPageViewStats } from '@src/components/CPageViewStats';
|
import { CPageViewStats } from '@src/components/CPageViewStats';
|
||||||
@@ -117,6 +118,7 @@ export default defineComponent({
|
|||||||
CSection,
|
CSection,
|
||||||
CRow,
|
CRow,
|
||||||
CColumn,
|
CColumn,
|
||||||
|
CMyVideoYoutube,
|
||||||
// , //CMapMarker,
|
// , //CMapMarker,
|
||||||
},
|
},
|
||||||
emits: ['selElemClick'],
|
emits: ['selElemClick'],
|
||||||
|
|||||||
@@ -312,7 +312,7 @@
|
|||||||
:height="myel.heightimg ? myel.heightimg : undefined"
|
:height="myel.heightimg ? myel.heightimg : undefined"
|
||||||
></q-img>
|
></q-img>
|
||||||
<q-img
|
<q-img
|
||||||
v-else
|
v-else
|
||||||
src="images/noimg.png"
|
src="images/noimg.png"
|
||||||
:fit="myel.fit ? myel.fit : 'contain'"
|
:fit="myel.fit ? myel.fit : 'contain'"
|
||||||
class="img"
|
class="img"
|
||||||
@@ -335,6 +335,26 @@
|
|||||||
</q-video>
|
</q-video>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO_YOUTUBE">
|
||||||
|
<CMyVideoYoutube
|
||||||
|
:url="myelem.container"
|
||||||
|
:title="myelem.container2 || ''"
|
||||||
|
:ratio="myelem.ratio || 16 / 9"
|
||||||
|
:privacyMode="myelem.privacyMode ?? true"
|
||||||
|
:thumbnailClickToPlay="myelem.thumbnailClickToPlay ?? true"
|
||||||
|
:autoplay="myelem.autoplay ?? false"
|
||||||
|
:controls="myelem.controls ?? true"
|
||||||
|
:mute="myelem.mute ?? false"
|
||||||
|
:loop="myelem.loop ?? false"
|
||||||
|
:start="myelem.start || 0"
|
||||||
|
:end="myelem.end || 0"
|
||||||
|
:rel="myelem.rel ?? false"
|
||||||
|
:modestBranding="myelem.modestBranding ?? true"
|
||||||
|
:playsinline="myelem.playsinline ?? true"
|
||||||
|
:ccLang="myelem.ccLang || ''"
|
||||||
|
:ccLoad="myelem.ccLoad ?? false"
|
||||||
|
/>
|
||||||
|
</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()"
|
||||||
|
|||||||
@@ -460,3 +460,42 @@ h1 {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.elementor-btn {
|
||||||
|
border-radius: 12px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba($primary, 0.1);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migliora il look delle espansioni
|
||||||
|
.q-expansion-item {
|
||||||
|
&__content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Risposta mobile
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.elementor-btn {
|
||||||
|
q-icon {
|
||||||
|
size: 32px;
|
||||||
|
}
|
||||||
|
.text-caption {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-stacked-btn .q-btn__label {
|
||||||
|
white-space: normal;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-size: 0.85em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
@@ -31,11 +31,8 @@ import { useProducts } from '@src/store/Products';
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CMyElemAdd',
|
name: 'CMyElemAdd',
|
||||||
components: {
|
components: {},
|
||||||
},
|
emits: ['AddedNewElem'],
|
||||||
emits: [
|
|
||||||
'AddedNewElem',
|
|
||||||
],
|
|
||||||
props: {
|
props: {
|
||||||
myelem: {
|
myelem: {
|
||||||
type: Object as PropType<IMyElem>,
|
type: Object as PropType<IMyElem>,
|
||||||
@@ -76,6 +73,16 @@ export default defineComponent({
|
|||||||
const catalogStore = useCatalogStore();
|
const catalogStore = useCatalogStore();
|
||||||
const router = useRouter();
|
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 { setmeta, getsrcbyimg } = MixinMetaTags();
|
||||||
const { setValDb, getValDb } = MixinBase();
|
const { setValDb, getValDb } = MixinBase();
|
||||||
|
|
||||||
@@ -107,7 +114,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
const selectedClasses = ref(<any>[]);
|
const selectedClasses = ref(<any>[]);
|
||||||
|
|
||||||
|
|
||||||
async function addNewElem(elemsel: any, direz: number) {
|
async function addNewElem(elemsel: any, direz: number) {
|
||||||
// Nascondi la visualizzazione di aggiunta (presumo sia una variabile reattiva)
|
// Nascondi la visualizzazione di aggiunta (presumo sia una variabile reattiva)
|
||||||
visuadd.value = false;
|
visuadd.value = false;
|
||||||
@@ -148,7 +154,7 @@ export default defineComponent({
|
|||||||
let sectionId = '';
|
let sectionId = '';
|
||||||
let rowId = '';
|
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
|
// Aggiungi un nuovo elemento alla sezione o riga usando il metodo preparato
|
||||||
const newrec = await globalStore.prepareAddNewElem(
|
const newrec = await globalStore.prepareAddNewElem(
|
||||||
@@ -157,7 +163,7 @@ export default defineComponent({
|
|||||||
t,
|
t,
|
||||||
myelem,
|
myelem,
|
||||||
props.myElemParent,
|
props.myElemParent,
|
||||||
newtype.value,
|
newtype.value
|
||||||
);
|
);
|
||||||
|
|
||||||
// Emitti l'evento per la selezione del nuovo elemento
|
// Emitti l'evento per la selezione del nuovo elemento
|
||||||
@@ -167,7 +173,6 @@ export default defineComponent({
|
|||||||
// emit('updateAll', newrec);
|
// emit('updateAll', newrec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tools,
|
tools,
|
||||||
shared_consts,
|
shared_consts,
|
||||||
@@ -191,6 +196,7 @@ export default defineComponent({
|
|||||||
Products,
|
Products,
|
||||||
globalStore,
|
globalStore,
|
||||||
myel,
|
myel,
|
||||||
|
sections,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,107 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<q-card class="">
|
<q-card class="shadow-6 rounded-lg" style="overflow: hidden">
|
||||||
<q-bar
|
<!-- Barra superiore -->
|
||||||
dense
|
<q-bar class="bg-primary text-white">
|
||||||
class="bg-primary text-white"
|
|
||||||
>
|
|
||||||
Aggiungi Elemento:
|
Aggiungi Elemento:
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-btn
|
<q-btn flat round icon="close" v-close-popup />
|
||||||
flat
|
|
||||||
round
|
|
||||||
color="white"
|
|
||||||
icon="close"
|
|
||||||
v-close-popup
|
|
||||||
></q-btn>
|
|
||||||
</q-bar>
|
</q-bar>
|
||||||
|
|
||||||
<div class="q-pa-md row justify-center">
|
<!-- Contenuto principale -->
|
||||||
<div style="width: 100%; max-width: 600px">
|
<div class="q-pa-sm row justify-center">
|
||||||
<q-list
|
<div style="width: 100%; max-width: 350px">
|
||||||
padding
|
<q-list padding bordered class="rounded-borders shadow-sm">
|
||||||
bordered
|
<!-- Sezioni generate dinamicamente -->
|
||||||
class="rounded-borders"
|
|
||||||
>
|
|
||||||
<q-expansion-item
|
<q-expansion-item
|
||||||
label="Principali"
|
v-for="(sec, i) in sections"
|
||||||
icon="fas fa-eye"
|
:key="sec.label"
|
||||||
dense
|
:label="sec.label"
|
||||||
dense-toggle
|
:icon="sec.icon"
|
||||||
|
:default-opened="i === 0"
|
||||||
expand-separator
|
expand-separator
|
||||||
default-opened
|
header-class="text-subtitle1 text-weight-bold"
|
||||||
>
|
>
|
||||||
<div class="row q-pa-sm">
|
<div class="row q-pa-xs" v-if="enableAdd">
|
||||||
<div
|
<div
|
||||||
v-for="(rec, index) in shared_consts.TypesElem"
|
v-for="(rec, idx) in sec.items"
|
||||||
:key="index"
|
:key="idx"
|
||||||
class="col-6 q-pa-xs"
|
class="col-6"
|
||||||
>
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="enableAdd"
|
flat
|
||||||
|
no-caps
|
||||||
|
stack
|
||||||
|
class="elementor-btn full-width q-py-sm q-px-sm my-stacked-btn"
|
||||||
|
:icon="rec.icon"
|
||||||
:label="rec.label"
|
:label="rec.label"
|
||||||
color="primary"
|
text-color="primary"
|
||||||
class="full-width uniform-button q-px-sm"
|
|
||||||
@click="
|
@click="
|
||||||
newtype = rec.value;
|
newtype = rec.value;
|
||||||
addNewElem(myel, direzadd);
|
addNewElem(myel, direzadd);
|
||||||
"
|
"
|
||||||
>
|
/>
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-expansion-item>
|
|
||||||
<q-expansion-item
|
|
||||||
dense
|
|
||||||
dense-toggle
|
|
||||||
expand-separator
|
|
||||||
label="Gestione"
|
|
||||||
icon="fas fa-cog"
|
|
||||||
>
|
|
||||||
<div class="row q-pa-sm">
|
|
||||||
<div
|
|
||||||
v-for="(rec, index) in shared_consts.TypesElemAdmin"
|
|
||||||
:key="index"
|
|
||||||
class="col-6 q-pa-xs"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-if="enableAdd"
|
|
||||||
:label="rec.label"
|
|
||||||
color="primary"
|
|
||||||
class="full-width uniform-button q-px-sm"
|
|
||||||
@click="
|
|
||||||
newtype = rec.value;
|
|
||||||
addNewElem(myel, direzadd);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-expansion-item>
|
|
||||||
<q-expansion-item
|
|
||||||
dense
|
|
||||||
dense-toggle
|
|
||||||
expand-separator
|
|
||||||
label="Avanzati"
|
|
||||||
icon="fas fa-star"
|
|
||||||
>
|
|
||||||
<div class="row q-pa-sm">
|
|
||||||
<div
|
|
||||||
v-for="(rec, index) in shared_consts.TypesElemAdminTools"
|
|
||||||
:key="index"
|
|
||||||
class="col-6 q-pa-sm"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-if="enableAdd"
|
|
||||||
:label="rec.label"
|
|
||||||
color="primary"
|
|
||||||
class="full-width uniform-button q-px-sm"
|
|
||||||
@click="
|
|
||||||
newtype = rec.value;
|
|
||||||
addNewElem(myel, direzadd);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|||||||
@@ -115,6 +115,66 @@ export default defineComponent({
|
|||||||
|
|
||||||
const onloading = ref(false);
|
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(() => {
|
const myelems = computed(() => {
|
||||||
if (myidPage.value) return globalStore.getMyElemsByIdPage(myidPage.value);
|
if (myidPage.value) return globalStore.getMyElemsByIdPage(myidPage.value);
|
||||||
else if (mypathin.value) return globalStore.getMyElems(mypathin.value);
|
else if (mypathin.value) return globalStore.getMyElems(mypathin.value);
|
||||||
@@ -376,11 +436,9 @@ export default defineComponent({
|
|||||||
idRowToAddDown?: string,
|
idRowToAddDown?: string,
|
||||||
neword?: number
|
neword?: number
|
||||||
) {
|
) {
|
||||||
|
const section = newElem;
|
||||||
const section = newElem
|
|
||||||
// trova la section “vera” nello store (per sicurezza)
|
// trova la section “vera” nello store (per sicurezza)
|
||||||
const newRow =
|
const newRow = newElem.rows[newElem.rows.length - 1];
|
||||||
newElem.rows[newElem.rows.length - 1]
|
|
||||||
if (!section) return;
|
if (!section) return;
|
||||||
|
|
||||||
if (!Array.isArray(section.rows)) section.rows = [];
|
if (!Array.isArray(section.rows)) section.rows = [];
|
||||||
@@ -515,6 +573,13 @@ export default defineComponent({
|
|||||||
myElemSel,
|
myElemSel,
|
||||||
myElemParent,
|
myElemParent,
|
||||||
getColClasses,
|
getColClasses,
|
||||||
|
mediaBlocks,
|
||||||
|
drawerWidth,
|
||||||
|
containerStyle,
|
||||||
|
closeEditor,
|
||||||
|
openAdd,
|
||||||
|
addAtEnd,
|
||||||
|
showOrder,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,48 +8,45 @@
|
|||||||
<q-spinner-tail
|
<q-spinner-tail
|
||||||
color="primary"
|
color="primary"
|
||||||
size="4em"
|
size="4em"
|
||||||
>
|
/>
|
||||||
</q-spinner-tail>
|
|
||||||
</q-inner-loading>
|
</q-inner-loading>
|
||||||
|
|
||||||
<div v-if="!onloading">
|
<div v-if="!onloading">
|
||||||
|
<!-- Toggle edit solo manager -->
|
||||||
<q-toggle
|
<q-toggle
|
||||||
v-if="tools.isManager()"
|
v-if="tools.isManager()"
|
||||||
v-model="editOn"
|
v-model="editOn"
|
||||||
dense
|
dense
|
||||||
color="green"
|
color="green"
|
||||||
size="sm"
|
size="sm"
|
||||||
@update:model-value="changeVisuDrawer(mypathin, editOn)"
|
|
||||||
icon="fas fa-pencil-alt"
|
icon="fas fa-pencil-alt"
|
||||||
>
|
@update:model-value="changeVisuDrawer(mypathin, editOn)"
|
||||||
</q-toggle>
|
/>
|
||||||
|
|
||||||
|
<!-- Drawer Editor -->
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="visuEditor"
|
v-model="visuEditor"
|
||||||
v-if="selElem && editOn && !tools.isObjectEmpty(selElem)"
|
v-if="selElem && editOn && !tools.isObjectEmpty(selElem)"
|
||||||
show-if-above
|
show-if-above
|
||||||
:breakpoint="350"
|
|
||||||
side="right"
|
side="right"
|
||||||
:width="tools.isMobile() ? 350 : mywidthEditor"
|
:breakpoint="420"
|
||||||
|
:width="drawerWidth"
|
||||||
elevated
|
elevated
|
||||||
style="transition: 'width 0.3s ease'"
|
:style="{ transition: 'width 0.3s ease' }"
|
||||||
>
|
>
|
||||||
<q-bar
|
<q-bar
|
||||||
dense
|
dense
|
||||||
class="q-ma-xs bg-primary text-white"
|
class="q-ma-xs bg-primary text-white"
|
||||||
>
|
>
|
||||||
<q-toolbar-title> Editor </q-toolbar-title>
|
<q-toolbar-title>Editor</q-toolbar-title>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
size="md"
|
size="md"
|
||||||
color="white"
|
color="white"
|
||||||
icon="close"
|
icon="close"
|
||||||
@click="
|
@click="closeEditor"
|
||||||
visuEditor = false;
|
/>
|
||||||
selElem = {};
|
|
||||||
"
|
|
||||||
></q-btn>
|
|
||||||
</q-bar>
|
</q-bar>
|
||||||
|
|
||||||
<CMyEditElem
|
<CMyEditElem
|
||||||
@@ -61,365 +58,340 @@
|
|||||||
@deleteElem="deleteElem"
|
@deleteElem="deleteElem"
|
||||||
@toggleSize="toggleSize"
|
@toggleSize="toggleSize"
|
||||||
@dupPage="duplicatePage"
|
@dupPage="duplicatePage"
|
||||||
@expPage="showexportPage = !showexportPage"
|
@expPage="showexportPage = true"
|
||||||
@impPage="showimportPage = !showimportPage"
|
@impPage="showimportPage = true"
|
||||||
>
|
/>
|
||||||
</CMyEditElem>
|
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
|
|
||||||
|
<!-- Contenuto pagina -->
|
||||||
<div
|
<div
|
||||||
:class="{ 'q-gutter-xs': !hideHeader }"
|
:class="[{ 'q-gutter-xs': !hideHeader }, 'q-mx-auto', 'q-px-sm', 'q-pb-lg']"
|
||||||
:style="[
|
:style="containerStyle"
|
||||||
{
|
|
||||||
'margin-left': hideHeader ? 0 : 1 + 'px',
|
|
||||||
'margin-right': hideHeader ? 0 : 1 + 'px',
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
>
|
>
|
||||||
<div
|
<!-- Media/Content blocks (1..3) -->
|
||||||
v-if="!!rec.img1"
|
<section
|
||||||
class="text-center"
|
v-for="(blk, i) in mediaBlocks"
|
||||||
|
:key="`mblk-${i}`"
|
||||||
|
class="q-mb-md"
|
||||||
>
|
>
|
||||||
<q-img
|
<div
|
||||||
:src="`` + rec.img1"
|
v-if="blk.img"
|
||||||
class="img"
|
class="text-center q-mb-sm"
|
||||||
></q-img>
|
>
|
||||||
</div>
|
<q-img
|
||||||
|
:src="blk.img"
|
||||||
|
class="page-img"
|
||||||
|
:ratio="16 / 9"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="blk.html"
|
||||||
|
v-html="blk.html"
|
||||||
|
class="q-mb-sm content-html"
|
||||||
|
></div>
|
||||||
|
<q-video
|
||||||
|
v-if="blk.video"
|
||||||
|
:src="blk.video"
|
||||||
|
:ratio="blk.ratio || 16 / 9"
|
||||||
|
class="q-mb-md"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Contenuti extra HTML -->
|
||||||
<div
|
<div
|
||||||
v-if="!!rec.content"
|
v-if="rec.content4"
|
||||||
v-html="rec.content"
|
|
||||||
></div>
|
|
||||||
<q-video
|
|
||||||
v-if="!!rec.video1"
|
|
||||||
:src="rec.video1"
|
|
||||||
:ratio="rec.ratio1"
|
|
||||||
>
|
|
||||||
</q-video>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="!!rec.img2"
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
<q-img
|
|
||||||
:src="`` + rec.img2"
|
|
||||||
class="img"
|
|
||||||
></q-img>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="!!rec.content2"
|
|
||||||
v-html="rec.content2"
|
|
||||||
></div>
|
|
||||||
<q-video
|
|
||||||
v-if="!!rec.video2"
|
|
||||||
:src="rec.video2"
|
|
||||||
:ratio="rec.ratio2"
|
|
||||||
></q-video>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="!!rec.img3"
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
<q-img
|
|
||||||
:src="`` + rec.img2"
|
|
||||||
class="img"
|
|
||||||
></q-img>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="!!rec.content3"
|
|
||||||
v-html="rec.content3"
|
|
||||||
></div>
|
|
||||||
<q-video
|
|
||||||
v-if="!!rec.video3"
|
|
||||||
:src="rec.video3"
|
|
||||||
:ratio="rec.ratio3"
|
|
||||||
></q-video>
|
|
||||||
<div
|
|
||||||
v-if="!!rec.content4"
|
|
||||||
v-html="rec.content4"
|
v-html="rec.content4"
|
||||||
|
class="q-mb-md content-html"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
|
<!-- Lista elementi -->
|
||||||
<div
|
<div
|
||||||
v-for="myelem in myelems"
|
v-for="myelem in myelems"
|
||||||
:key="myelem._id"
|
:key="myelem._id"
|
||||||
|
class="q-mb-lg"
|
||||||
>
|
>
|
||||||
<div>
|
<transition
|
||||||
<transition
|
appear
|
||||||
:duration="1000"
|
:duration="300"
|
||||||
appear
|
enter-active-class="animated fadeInUp"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<CTitleBanner
|
<CTitleBanner
|
||||||
v-if="(myelem.active || editOn) && !!rec.path && myelem.titleBanner"
|
v-if="(myelem.active || editOn) && !!rec.path && myelem.titleBanner"
|
||||||
:class="`q-pa-xs`"
|
class="q-pa-xs"
|
||||||
:title="myelem.titleBanner"
|
:title="myelem.titleBanner"
|
||||||
bgcolor="bg-primary"
|
bgcolor="bg-primary"
|
||||||
:clcolor="myelem.color ? `` : `text-white`"
|
:clcolor="myelem.color ? '' : 'text-white'"
|
||||||
:mystyle="myelem.color ? `color: ${myelem.color} !important;` : ``"
|
:mystyle="myelem.color ? `color: ${myelem.color} !important;` : ''"
|
||||||
:myclass="myelem.classBanner"
|
:myclass="myelem.classBanner"
|
||||||
:canopen="true"
|
:canopen="true"
|
||||||
>
|
/>
|
||||||
</CTitleBanner>
|
<div
|
||||||
|
v-if="showOrder"
|
||||||
|
class="text-caption text-grey q-mb-xs"
|
||||||
|
>
|
||||||
order: {{ myelem.order }}
|
order: {{ myelem.order }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Sezione -->
|
<!-- Sezione -->
|
||||||
<div v-if="myelem.type === shared_consts.ELEMTYPE.SECTION">
|
<div v-if="myelem.type === shared_consts.ELEMTYPE.SECTION">
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="text-center text-caption q-mb-sm"
|
||||||
|
>
|
||||||
|
SEZIONE
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CMyElem
|
||||||
|
:myelem="myelem"
|
||||||
|
:idPage="rec._id"
|
||||||
|
:editOn="editOn"
|
||||||
|
:addOn="addOn"
|
||||||
|
:path="rec.path || ''"
|
||||||
|
:selElem="selElem"
|
||||||
|
@selElemClick="selElemClick"
|
||||||
|
>
|
||||||
|
<!-- Righe della sezione -->
|
||||||
<div
|
<div
|
||||||
v-if="editOn"
|
v-for="(row, indriga) in myelem.rows"
|
||||||
class="text-center"
|
:key="row._id"
|
||||||
|
class="q-mb-md"
|
||||||
>
|
>
|
||||||
<div v-if="editOn">SEZIONE:</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CMyElem
|
|
||||||
:myelem="myelem"
|
|
||||||
:idPage="rec._id"
|
|
||||||
:editOn="editOn"
|
|
||||||
:addOn="addOn"
|
|
||||||
:path="!!rec.path ? rec.path : ''"
|
|
||||||
:selElem="selElem"
|
|
||||||
@selElemClick="selElemClick"
|
|
||||||
>
|
|
||||||
<!-- Rendering righe dentro la sezione -->
|
|
||||||
<div
|
|
||||||
v-for="(row, indriga) in myelem.rows"
|
|
||||||
:key="row._id"
|
|
||||||
class="row-container"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="editOn"
|
|
||||||
class="text-center q-mb-md"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-if="editOn"
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
label="Riga"
|
|
||||||
size="sm"
|
|
||||||
color="positive"
|
|
||||||
icon="add"
|
|
||||||
@click="
|
|
||||||
addNewElemSectRow(
|
|
||||||
myelem.order + 1,
|
|
||||||
myelem,
|
|
||||||
shared_consts.ELEMTYPE.ROW,
|
|
||||||
row._id
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-tooltip> Aggiungi Riga </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="row.type === shared_consts.ELEMTYPE.ROW">
|
|
||||||
<div
|
|
||||||
v-if="editOn"
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
<div v-if="editOn">RIGA {{ indriga + 1 }}:</div>
|
|
||||||
</div>
|
|
||||||
<CMyElem
|
|
||||||
:myelem="row"
|
|
||||||
:idPage="rec._id"
|
|
||||||
:editOn="editOn"
|
|
||||||
:addOn="addOn"
|
|
||||||
:path="!!rec.path ? rec.path : ''"
|
|
||||||
:selElem="selElem"
|
|
||||||
@selElemClick="selElemClick"
|
|
||||||
>
|
|
||||||
<!-- Rendering colonne dentro la riga -->
|
|
||||||
<div class="row q-col-gutter-md items-stretch">
|
|
||||||
<template
|
|
||||||
v-for="(col, index) in row.columns"
|
|
||||||
:key="col._id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="col.type === shared_consts.ELEMTYPE.COLUMN"
|
|
||||||
:class="getColClasses(col, row, index)"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
:style="editOn ? `border: 2px dashed #1976d2` : ``"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="editOn"
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
Colonna {{ index + 1 }}:
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="el in col.elems"
|
|
||||||
:key="el._id"
|
|
||||||
>
|
|
||||||
<CMyElem
|
|
||||||
:myelem="el"
|
|
||||||
:idPage="rec._id"
|
|
||||||
:editOn="editOn"
|
|
||||||
:addOn="addOn"
|
|
||||||
:path="!!rec.path ? rec.path : ''"
|
|
||||||
:selElem="selElem"
|
|
||||||
@selElemClick="selElemClick"
|
|
||||||
/>
|
|
||||||
<div class="text-center q-mb-md">
|
|
||||||
<q-btn
|
|
||||||
v-if="editOn"
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
size="sm"
|
|
||||||
color="negative"
|
|
||||||
icon="delete"
|
|
||||||
@click="deleteElemento(el)"
|
|
||||||
>
|
|
||||||
<q-tooltip> Elimina Elemento </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center q-mb-md">
|
|
||||||
<q-btn
|
|
||||||
v-if="editOn"
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
size="sm"
|
|
||||||
color="positive"
|
|
||||||
icon="add"
|
|
||||||
@click="
|
|
||||||
visuadd = true;
|
|
||||||
myElemSel = col;
|
|
||||||
myElemParent = myelem;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-tooltip> Aggiungi Elemento </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center q-mb-md">
|
|
||||||
<q-btn
|
|
||||||
v-if="editOn"
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
size="sm"
|
|
||||||
label="Colonna"
|
|
||||||
color="negative"
|
|
||||||
icon="delete"
|
|
||||||
@click="deleteCol(col)"
|
|
||||||
>
|
|
||||||
<q-tooltip> Elimina Colonna </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</CMyElem>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="editOn"
|
|
||||||
class="text-center q-mb-md"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-if="editOn"
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
size="sm"
|
|
||||||
label="Colonna"
|
|
||||||
color="primary"
|
|
||||||
icon="add"
|
|
||||||
@click="
|
|
||||||
addNewElemSectRow(
|
|
||||||
row.order + 1,
|
|
||||||
row,
|
|
||||||
shared_consts.ELEMTYPE.COLUMN
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-tooltip> Aggiungi Colonna </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-center q-mb-md">
|
|
||||||
<q-btn
|
|
||||||
v-if="editOn"
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
size="sm"
|
|
||||||
label="Riga"
|
|
||||||
color="negative"
|
|
||||||
icon="delete"
|
|
||||||
@click="deleteRow(row)"
|
|
||||||
>
|
|
||||||
<q-tooltip> Elimina Riga </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
v-if="editOn"
|
v-if="editOn"
|
||||||
class="text-center q-mb-md"
|
class="text-center q-mb-sm"
|
||||||
>
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="editOn"
|
|
||||||
dense
|
dense
|
||||||
rounded
|
rounded
|
||||||
label="Riga"
|
|
||||||
size="sm"
|
size="sm"
|
||||||
color="positive"
|
color="positive"
|
||||||
icon="add"
|
icon="add"
|
||||||
|
label="Riga"
|
||||||
@click="
|
@click="
|
||||||
addNewElemSectRow(
|
addNewElemSectRow(
|
||||||
myelem.order + 1,
|
myelem.order + 1,
|
||||||
myelem,
|
myelem,
|
||||||
shared_consts.ELEMTYPE.ROW
|
shared_consts.ELEMTYPE.ROW,
|
||||||
|
row._id
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<q-tooltip> Aggiungi Riga </q-tooltip>
|
<q-tooltip>Aggiungi Riga</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</div>
|
</div>
|
||||||
</CMyElem>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Elementi senza Sezione (retrocompatibilità) -->
|
<div v-if="row.type === shared_consts.ELEMTYPE.ROW">
|
||||||
<div v-if="myelem.type !== shared_consts.ELEMTYPE.SECTION">
|
<div
|
||||||
<CMyElem
|
v-if="editOn"
|
||||||
:myelem="myelem"
|
class="text-center text-caption q-mb-xs"
|
||||||
:idPage="rec._id"
|
>
|
||||||
:editOn="editOn"
|
RIGA {{ indriga + 1 }}
|
||||||
:addOn="addOn"
|
</div>
|
||||||
:path="!!rec.path ? rec.path : ''"
|
|
||||||
:selElem="selElem"
|
|
||||||
@selElemClick="selElemClick"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center q-mb-md">
|
<CMyElem
|
||||||
<q-btn
|
:myelem="row"
|
||||||
|
:idPage="rec._id"
|
||||||
|
:editOn="editOn"
|
||||||
|
:addOn="addOn"
|
||||||
|
:path="rec.path || ''"
|
||||||
|
:selElem="selElem"
|
||||||
|
@selElemClick="selElemClick"
|
||||||
|
>
|
||||||
|
<!-- Colonne della riga -->
|
||||||
|
<div class="row q-col-gutter-md items-stretch">
|
||||||
|
<template
|
||||||
|
v-for="(col, index) in row.columns"
|
||||||
|
:key="col._id"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="col.type === shared_consts.ELEMTYPE.COLUMN"
|
||||||
|
:class="getColClasses(col, row, index)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
{ 'editor-border': editOn },
|
||||||
|
'q-pa-xs q-mb-sm',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="text-center text-caption q-mb-xs"
|
||||||
|
>
|
||||||
|
Colonna {{ index + 1 }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="el in col.elems"
|
||||||
|
:key="el._id"
|
||||||
|
class="q-mb-sm"
|
||||||
|
>
|
||||||
|
<CMyElem
|
||||||
|
:myelem="el"
|
||||||
|
:idPage="rec._id"
|
||||||
|
:editOn="editOn"
|
||||||
|
:addOn="addOn"
|
||||||
|
:path="rec.path || ''"
|
||||||
|
:selElem="selElem"
|
||||||
|
@selElemClick="selElemClick"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="text-center q-mt-xs"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="negative"
|
||||||
|
icon="delete"
|
||||||
|
@click="deleteElemento(el)"
|
||||||
|
>
|
||||||
|
<q-tooltip>Elimina Elemento</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Azioni colonna -->
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="row justify-center q-gutter-sm q-mb-sm"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="positive"
|
||||||
|
icon="add"
|
||||||
|
@click="openAdd(col, myelem)"
|
||||||
|
>
|
||||||
|
<q-tooltip>Aggiungi Elemento</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="negative"
|
||||||
|
icon="delete"
|
||||||
|
label="Colonna"
|
||||||
|
@click="deleteCol(col)"
|
||||||
|
>
|
||||||
|
<q-tooltip>Elimina Colonna</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</CMyElem>
|
||||||
|
|
||||||
|
<!-- Aggiungi colonna -->
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="text-center q-mb-sm"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
icon="add"
|
||||||
|
label="Colonna"
|
||||||
|
@click="
|
||||||
|
addNewElemSectRow(
|
||||||
|
row.order + 1,
|
||||||
|
row,
|
||||||
|
shared_consts.ELEMTYPE.COLUMN
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-tooltip>Aggiungi Colonna</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Elimina riga -->
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="text-center"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="negative"
|
||||||
|
icon="delete"
|
||||||
|
label="Riga"
|
||||||
|
@click="deleteRow(row)"
|
||||||
|
>
|
||||||
|
<q-tooltip>Elimina Riga</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Aggiungi riga -->
|
||||||
|
<div
|
||||||
v-if="editOn"
|
v-if="editOn"
|
||||||
dense
|
class="text-center q-mt-sm"
|
||||||
rounded
|
|
||||||
size="sm"
|
|
||||||
color="positive"
|
|
||||||
icon="add"
|
|
||||||
@click="
|
|
||||||
visuadd = true;
|
|
||||||
myElemSel =
|
|
||||||
myelems.length > 0 ? myelems[myelems.length - 1] : null;
|
|
||||||
myElemParent =
|
|
||||||
myelems.length > 0 ? myelems[myelems.length - 1] : null;
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<q-tooltip> Aggiungi Elemento </q-tooltip>
|
<q-btn
|
||||||
</q-btn>
|
dense
|
||||||
</div>
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="positive"
|
||||||
|
icon="add"
|
||||||
|
label="Riga"
|
||||||
|
@click="
|
||||||
|
addNewElemSectRow(
|
||||||
|
myelem.order + 1,
|
||||||
|
myelem,
|
||||||
|
shared_consts.ELEMTYPE.ROW
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-tooltip>Aggiungi Riga</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</CMyElem>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
</div>
|
<!-- Elementi fuori sezione (retrocompatibilità) -->
|
||||||
|
<div v-else>
|
||||||
|
<CMyElem
|
||||||
|
:myelem="myelem"
|
||||||
|
:idPage="rec._id"
|
||||||
|
:editOn="editOn"
|
||||||
|
:addOn="addOn"
|
||||||
|
:path="rec.path || ''"
|
||||||
|
:selElem="selElem"
|
||||||
|
@selElemClick="selElemClick"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Aggiungi elemento al fondo lista -->
|
||||||
|
<div
|
||||||
|
v-if="editOn"
|
||||||
|
class="text-center q-mt-sm"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
size="sm"
|
||||||
|
color="positive"
|
||||||
|
icon="add"
|
||||||
|
@click="addAtEnd()"
|
||||||
|
>
|
||||||
|
<q-tooltip>Aggiungi Elemento</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="myelems.length === 0">
|
<!-- Stato vuoto -->
|
||||||
|
<div v-if="myelems.length === 0 && editOn">
|
||||||
<CMyElem
|
<CMyElem
|
||||||
v-if="editOn && !!rec.path"
|
|
||||||
:myelem="myelemVoid"
|
:myelem="myelemVoid"
|
||||||
:editOn="editOn"
|
:editOn="editOn"
|
||||||
:addOn="addOn"
|
:addOn="addOn"
|
||||||
@@ -427,13 +399,15 @@
|
|||||||
:selElem="selElem"
|
:selElem="selElem"
|
||||||
:path="rec.path"
|
:path="rec.path"
|
||||||
@selElemClick="selElemClick"
|
@selElemClick="selElemClick"
|
||||||
>
|
/>
|
||||||
</CMyElem>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<LandingFooter v-if="rec.showFooter"></LandingFooter>
|
|
||||||
|
<LandingFooter v-if="rec.showFooter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Header di fallback -->
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div v-if="!!title">
|
<div v-if="!!title">
|
||||||
<CTitle
|
<CTitle
|
||||||
@@ -442,81 +416,69 @@
|
|||||||
:headtitle="title"
|
:headtitle="title"
|
||||||
:sizes="sizes"
|
:sizes="sizes"
|
||||||
:styleadd="styleadd"
|
:styleadd="styleadd"
|
||||||
></CTitle>
|
/>
|
||||||
<div v-if="!imgbackground">
|
<div v-else-if="img">
|
||||||
<CImgTitle
|
<CImgTitle
|
||||||
v-if="img"
|
|
||||||
:src="img"
|
:src="img"
|
||||||
:title="title"
|
:title="title"
|
||||||
>
|
/>
|
||||||
</CImgTitle>
|
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
<slot />
|
||||||
<div v-if="!nofooter"></div>
|
<div v-if="!nofooter"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Dialog Export/Import -->
|
||||||
<q-dialog v-model="showexportPage">
|
<q-dialog v-model="showexportPage">
|
||||||
<q-card class="dialog_card">
|
<q-card class="dialog_card">
|
||||||
<q-toolbar class="bg-primary text-white">
|
<q-toolbar class="bg-primary text-white">
|
||||||
<q-toolbar-title> Esporta Pagina </q-toolbar-title>
|
<q-toolbar-title>Esporta Pagina</q-toolbar-title>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
color="white"
|
color="white"
|
||||||
icon="close"
|
icon="close"
|
||||||
v-close-popup
|
v-close-popup
|
||||||
></q-btn>
|
/>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
<q-card-section class="q-pa-xs inset-shadow">
|
<q-card-section class="q-pa-xs inset-shadow">
|
||||||
<br />
|
|
||||||
<CExportImportPage
|
<CExportImportPage
|
||||||
:idPage="rec._id"
|
:idPage="rec._id"
|
||||||
:nomefileprop="`esporta_${rec.path}.json`"
|
:nomefileprop="`esporta_${rec.path}.json`"
|
||||||
:esporta="true"
|
:esporta="true"
|
||||||
>
|
/>
|
||||||
</CExportImportPage>
|
|
||||||
<br />
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
|
|
||||||
<q-dialog v-model="showimportPage">
|
<q-dialog v-model="showimportPage">
|
||||||
<q-card class="dialog_card">
|
<q-card class="dialog_card">
|
||||||
<q-toolbar class="bg-primary text-white">
|
<q-toolbar class="bg-primary text-white">
|
||||||
<q-toolbar-title> Esporta Pagina </q-toolbar-title>
|
<q-toolbar-title>Importa Pagina</q-toolbar-title>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
round
|
round
|
||||||
color="white"
|
color="white"
|
||||||
icon="close"
|
icon="close"
|
||||||
v-close-popup
|
v-close-popup
|
||||||
></q-btn>
|
/>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
<q-card-section class="q-pa-xs inset-shadow">
|
<q-card-section class="q-pa-xs inset-shadow">
|
||||||
<br />
|
|
||||||
<CExportImportPage
|
<CExportImportPage
|
||||||
:idPage="rec._id"
|
:idPage="rec._id"
|
||||||
:nomefileprop="`esporta_${rec.path}.json`"
|
:nomefileprop="`esporta_${rec.path}.json`"
|
||||||
>
|
/>
|
||||||
</CExportImportPage>
|
|
||||||
<br />
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
<div>
|
|
||||||
<q-dialog
|
<!-- Dialog Add Element -->
|
||||||
v-model="visuadd"
|
<q-dialog
|
||||||
style="
|
v-model="visuadd"
|
||||||
width: 600px;
|
transition-show="slide-up"
|
||||||
max-width: 100%;
|
transition-hide="slide-down"
|
||||||
position: fixed;
|
>
|
||||||
left: 0;
|
<div class="full-height-dialog">
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
"
|
|
||||||
transition-show="slide-up"
|
|
||||||
transition-hide="slide-down"
|
|
||||||
>
|
|
||||||
<CMyElemAdd
|
<CMyElemAdd
|
||||||
v-if="visuadd"
|
v-if="visuadd"
|
||||||
:myelem="myElemSel"
|
:myelem="myElemSel"
|
||||||
@@ -527,10 +489,9 @@
|
|||||||
:addonlyinMem="true"
|
:addonlyinMem="true"
|
||||||
@AddedNewElem="AddedNewElem"
|
@AddedNewElem="AddedNewElem"
|
||||||
@close="visuadd = false"
|
@close="visuadd = false"
|
||||||
>
|
/>
|
||||||
</CMyElemAdd>
|
</div>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
72
src/components/CMyVideoYoutube/CMyVideoYoutube.scss
Executable file
72
src/components/CMyVideoYoutube/CMyVideoYoutube.scss
Executable file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
134
src/components/CMyVideoYoutube/CMyVideoYoutube.ts
Executable file
134
src/components/CMyVideoYoutube/CMyVideoYoutube.ts
Executable file
@@ -0,0 +1,134 @@
|
|||||||
|
import { defineComponent, computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
type Nullable<T> = T | null | undefined;
|
||||||
|
|
||||||
|
function extractYouTubeId(url: string): string | null {
|
||||||
|
if (!url) return null;
|
||||||
|
|
||||||
|
// URL normalizzati, rimuovi spazi
|
||||||
|
const u = url.trim();
|
||||||
|
|
||||||
|
// youtu.be/<id>
|
||||||
|
const short = u.match(/^https?:\/\/(?:www\.)?youtu\.be\/([A-Za-z0-9_-]{11})/i);
|
||||||
|
if (short?.[1]) return short[1];
|
||||||
|
|
||||||
|
// youtube.com/watch?v=<id> (&…)
|
||||||
|
const watchMatch = u.match(/[?&]v=([A-Za-z0-9_-]{11})/i);
|
||||||
|
if (watchMatch?.[1]) return watchMatch[1];
|
||||||
|
|
||||||
|
// youtube.com/embed/<id>
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
54
src/components/CMyVideoYoutube/CMyVideoYoutube.vue
Executable file
54
src/components/CMyVideoYoutube/CMyVideoYoutube.vue
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cmy-yt">
|
||||||
|
<!-- Stato errore URL non valido -->
|
||||||
|
<div v-if="!videoId" class="cmy-yt__error">
|
||||||
|
<q-icon name="warning" class="q-mr-sm" />
|
||||||
|
Link YouTube non valido.
|
||||||
|
<div class="text-caption text-grey-7 q-mt-xs">
|
||||||
|
Esempi accettati: https://youtu.be/ID, https://www.youtube.com/watch?v=ID
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modalità thumbnail -> click per avviare -->
|
||||||
|
<div v-else-if="thumbnailClickToPlay && !isPlaying" class="cmy-yt__thumb-wrapper">
|
||||||
|
<q-responsive :ratio="ratio">
|
||||||
|
<q-img
|
||||||
|
:src="thumbUrl"
|
||||||
|
:alt="computedTitle"
|
||||||
|
class="cmy-yt__thumb-img"
|
||||||
|
spinner-color="primary"
|
||||||
|
loading="lazy"
|
||||||
|
>
|
||||||
|
<div class="cmy-yt__overlay">
|
||||||
|
<button
|
||||||
|
class="cmy-yt__play-btn"
|
||||||
|
type="button"
|
||||||
|
:aria-label="`Riproduci video: ${computedTitle}`"
|
||||||
|
@click="startPlayback"
|
||||||
|
>
|
||||||
|
<q-icon name="play_arrow" size="40px" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</q-img>
|
||||||
|
</q-responsive>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Iframe diretto -->
|
||||||
|
<q-responsive v-else :ratio="ratio" class="cmy-yt__frame-wrapper">
|
||||||
|
<iframe
|
||||||
|
class="cmy-yt__iframe"
|
||||||
|
:title="computedTitle"
|
||||||
|
:src="embedUrl"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowfullscreen
|
||||||
|
:loading="lazy ? 'lazy' : 'eager'"
|
||||||
|
></iframe>
|
||||||
|
</q-responsive>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" src="./CMyVideoYoutube.ts"></script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './CMyVideoYoutube.scss';
|
||||||
|
</style>
|
||||||
1
src/components/CMyVideoYoutube/index.ts
Executable file
1
src/components/CMyVideoYoutube/index.ts
Executable file
@@ -0,0 +1 @@
|
|||||||
|
export {default as CMyVideoYoutube} from './CMyVideoYoutube.vue'
|
||||||
Reference in New Issue
Block a user