- aggiornati form registrazione

- Login
- Password dimenticata
- Aggiorna password.
- Email registrazione
- Ammetti Utente
This commit is contained in:
Surya Paolo
2025-11-24 17:42:26 +01:00
parent 9faaa1a4c3
commit e9fa53a637
25 changed files with 4440 additions and 1051 deletions

View File

@@ -0,0 +1,667 @@
// ========================================
// VARIABILI (Sincronizzate con CSignUp)
// ========================================
$primary-color: #1976d2;
$primary-light: #42a5f5;
$primary-dark: #1565c0;
$accent-color: #26a69a;
$positive-color: #21ba45;
$negative-color: #c10015;
$info-color: #31ccec;
$border-radius: 16px;
$border-radius-sm: 12px;
$border-radius-lg: 24px;
$transition-speed: 0.3s;
$shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
$shadow-md: 0 4px 16px rgba(0, 0, 0, 0.12);
$shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.16);
$mobile-breakpoint: 768px;
// ========================================
// CONTAINER PRINCIPALE
// ========================================
.registration-container {
width: 100%;
min-height: 60vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
@media (max-width: $mobile-breakpoint) {
padding: 6px;
min-height: 100vh;
align-items: flex-start;
}
}
// ========================================
// BOTTONE INIZIALE
// ========================================
.start-button-wrapper {
text-align: center;
animation: fadeInUp 0.6s ease;
}
.start-btn {
min-width: 200px;
height: 56px;
border-radius: $border-radius;
font-size: 1.125rem;
font-weight: 600;
text-transform: none;
box-shadow: $shadow-lg;
background: linear-gradient(135deg, $primary-color, $primary-light);
transition: all $transition-speed ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(25, 118, 210, 0.4);
}
&:active {
transform: translateY(-2px);
}
@media (max-width: $mobile-breakpoint) {
min-width: 180px;
height: 52px;
font-size: 1rem;
}
}
// ========================================
// CARD PRINCIPALE
// ========================================
.registration-card {
width: 100%;
max-width: 700px;
border-radius: $border-radius-lg;
box-shadow: $shadow-lg;
overflow: hidden;
background: white;
animation: fadeInUp 0.6s ease;
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
border-radius: $border-radius;
}
}
// ========================================
// CAROUSEL
// ========================================
.modern-carousel {
background: transparent;
@media (max-width: $mobile-breakpoint) {
height: auto !important;
}
}
.carousel-slide {
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
// ========================================
// SLIDE CONTENT
// ========================================
.slide-content {
width: 100%;
padding: 10px 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
animation: fadeIn 0.4s ease;
@media (max-width: $mobile-breakpoint) {
padding: 10px 8px;
gap: 16px;
}
}
.slide-icon-wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, rgba(25, 118, 210, 0.1), rgba(38, 166, 154, 0.1));
margin-bottom: 8px;
animation: scaleIn 0.6s ease;
@media (max-width: $mobile-breakpoint) {
width: 100px;
height: 100px;
.q-icon {
font-size: 48px !important;
}
}
}
.slide-title {
font-size: 1.75rem;
font-weight: 600;
color: #1a1a1a;
text-align: center;
margin: 0;
line-height: 1.3;
@media (max-width: $mobile-breakpoint) {
font-size: 1.375rem;
}
}
// ========================================
// ACTION BUTTONS (Yes/No)
// ========================================
.action-buttons {
display: flex;
flex-direction: column;
gap: 16px;
width: 100%;
max-width: 400px;
@media (max-width: $mobile-breakpoint) {
gap: 12px;
max-width: 100%;
}
}
.action-btn {
width: 100%;
height: 56px;
border-radius: $border-radius;
font-size: 1.125rem;
font-weight: 600;
text-transform: none;
box-shadow: $shadow-md;
transition: all $transition-speed ease;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-lg;
}
&:active {
transform: translateY(0);
}
@media (max-width: $mobile-breakpoint) {
height: 52px;
font-size: 1rem;
}
}
.yes-btn {
background: linear-gradient(135deg, $positive-color, #26a69a);
}
.no-btn {
background: linear-gradient(135deg, $negative-color, #e91e63);
}
// ========================================
// LINKS LIST
// ========================================
.links-list {
width: 100%;
max-width: 500px;
display: flex;
flex-direction: column;
gap: 12px;
@media (max-width: $mobile-breakpoint) {
gap: 8px;
}
}
.link-item {
background: linear-gradient(to right, rgba(25, 118, 210, 0.05), transparent);
border-radius: $border-radius-sm;
padding: 12px;
border: 1px solid rgba(0, 0, 0, 0.08);
transition: all $transition-speed ease;
&:hover {
transform: translateX(4px);
box-shadow: $shadow-sm;
background: linear-gradient(to right, rgba(25, 118, 210, 0.1), transparent);
}
@media (max-width: $mobile-breakpoint) {
padding: 8px;
}
}
.custom-link {
margin-top: 16px;
padding: 16px;
text-align: center;
@media (max-width: $mobile-breakpoint) {
margin-top: 12px;
padding: 12px;
}
}
.custom-link-text {
display: inline-flex;
align-items: center;
gap: 8px;
color: $primary-color;
font-size: 1.125rem;
font-weight: 600;
text-decoration: none;
transition: all $transition-speed ease;
&:hover {
color: $primary-dark;
transform: translateX(4px);
}
@media (max-width: $mobile-breakpoint) {
font-size: 1rem;
}
}
// ========================================
// NO INVITED CONTENT
// ========================================
.no-invited-content {
width: 100%;
max-width: 550px;
}
.instructions {
display: flex;
flex-direction: column;
gap: 24px;
margin-top: 24px;
@media (max-width: $mobile-breakpoint) {
gap: 16px;
margin-top: 16px;
}
}
.instruction-item {
display: flex;
gap: 16px;
align-items: flex-start;
@media (max-width: $mobile-breakpoint) {
gap: 12px;
}
}
.instruction-number {
flex-shrink: 0;
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, $primary-color, $accent-color);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
font-weight: 700;
box-shadow: $shadow-sm;
@media (max-width: $mobile-breakpoint) {
width: 36px;
height: 36px;
font-size: 1.125rem;
}
}
.instruction-content {
flex: 1;
p {
margin: 0 0 12px;
font-size: 1rem;
line-height: 1.6;
color: #333;
@media (max-width: $mobile-breakpoint) {
font-size: 0.9375rem;
margin: 0 0 8px;
}
}
}
.instruction-note {
font-size: 0.9375rem;
color: #666;
font-style: italic;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
}
}
.telegram-btn {
margin-top: 12px;
border-radius: $border-radius-sm;
text-transform: none;
font-weight: 600;
box-shadow: $shadow-sm;
transition: all $transition-speed ease;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-md;
}
@media (max-width: $mobile-breakpoint) {
margin-top: 8px;
width: 100%;
}
}
// ========================================
// WITH INVITED CONTENT
// ========================================
.with-invited-content {
width: 100%;
max-width: 800px;
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
}
}
.registration-options {
width: 100%;
display: flex;
flex-direction: column;
gap: 20px;
margin-top: 24px;
@media (max-width: $mobile-breakpoint) {
gap: 16px;
margin-top: 16px;
}
}
.option-btn {
width: 100%;
height: 64px;
border-radius: $border-radius;
font-size: 1.125rem;
font-weight: 600;
text-transform: none;
box-shadow: $shadow-md;
transition: all $transition-speed ease;
position: relative;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-lg;
}
@media (max-width: $mobile-breakpoint) {
height: 76px;
font-size: 1rem;
}
}
.telegram-option {
background: linear-gradient(135deg, $primary-color, $primary-light);
}
.email-option {
border-width: 2px;
&:hover {
background: rgba(25, 118, 210, 0.08);
}
}
.recommended-badge {
top: -8px;
right: -8px;
padding: 4px 12px;
font-size: 0.75rem;
font-weight: 700;
border-radius: 12px;
box-shadow: $shadow-sm;
@media (max-width: $mobile-breakpoint) {
font-size: 0.6875rem;
padding: 3px 10px;
}
}
.divider {
position: relative;
text-align: center;
margin: 8px 0;
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
width: calc(50% - 40px);
height: 1px;
background: linear-gradient(to right, transparent, rgba(0, 0, 0, 0.12));
}
&::before {
left: 0;
}
&::after {
right: 0;
background: linear-gradient(to left, transparent, rgba(0, 0, 0, 0.12));
}
span {
display: inline-block;
padding: 4px 12px;
background: white;
color: #666;
font-size: 0.875rem;
font-weight: 500;
border-radius: 12px;
border: 1px solid rgba(0, 0, 0, 0.08);
}
}
// ========================================
// SINGLE REGISTRATION
// ========================================
.single-registration {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
margin-top: 24px;
@media (max-width: $mobile-breakpoint) {
margin-top: 16px;
gap: 12px;
}
}
.registration-text {
font-size: 1.125rem;
color: #666;
margin: 0;
@media (max-width: $mobile-breakpoint) {
font-size: 1rem;
}
}
.register-btn {
width: 100%;
max-width: 300px;
height: 56px;
border-radius: $border-radius;
font-size: 1.125rem;
font-weight: 600;
text-transform: none;
background: linear-gradient(135deg, $primary-color, $primary-light);
box-shadow: $shadow-md;
transition: all $transition-speed ease;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-lg;
}
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
height: 52px;
font-size: 1rem;
}
}
// ========================================
// BACK BUTTON
// ========================================
.back-btn {
margin-top: 24px;
border-radius: $border-radius-sm;
text-transform: none;
font-weight: 500;
transition: all $transition-speed ease;
&:hover {
background: rgba(0, 0, 0, 0.04);
}
@media (max-width: $mobile-breakpoint) {
margin-top: 16px;
width: 100%;
}
}
// ========================================
// NAVIGATION DOTS
// ========================================
.navigation-dots {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
padding: 16px;
background: linear-gradient(to top, rgba(0, 0, 0, 0.02), transparent);
@media (max-width: $mobile-breakpoint) {
padding: 12px;
gap: 6px;
}
}
.nav-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #d0d0d0;
cursor: pointer;
transition: all $transition-speed ease;
opacity: 0;
pointer-events: none;
&.visible {
opacity: 1;
pointer-events: auto;
}
&.active {
width: 24px;
border-radius: 5px;
background: $primary-color;
}
&:hover:not(.active) {
background: #a0a0a0;
transform: scale(1.2);
}
@media (max-width: $mobile-breakpoint) {
width: 8px;
height: 8px;
&.active {
width: 20px;
}
}
}
// ========================================
// ANIMAZIONI
// ========================================
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.5);
}
to {
opacity: 1;
transform: scale(1);
}
}
// ========================================
// RESPONSIVE UTILITIES
// ========================================
@media (max-width: $mobile-breakpoint) {
// Fix per iOS Safari
.registration-container {
min-height: -webkit-fill-available;
}
}
// ========================================
// UTILITY CLASSES (Legacy)
// ========================================
.centermydiv2 {
display: flex;
justify-content: center;
align-items: center;
}
.dialog_card {
background: white;
border-radius: $border-radius;
}
.my-custom-border {
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: $border-radius-sm;
}

View File

@@ -5,6 +5,7 @@ import { useQuasar } from 'quasar'
import { useI18n } from 'vue-i18n'
import { CContactUser } from '@src/components/CContactUser'
import { CMyUser } from '@src/components/CMyUser'
import { Logo } from '@src/components/logo'
import { DefaultProfile, useUserStore } from '@store/UserStore'
import { useRoute, useRouter } from 'vue-router'
@@ -14,7 +15,7 @@ import { useGlobalStore } from '@store/globalStore'
export default defineComponent({
name: 'CRegistration',
emits: ['regEventEmail'],
components: { CMyUser, CContactUser },
components: { CMyUser, CContactUser, Logo },
props: {
slide: {
type: String,
@@ -57,14 +58,18 @@ export default defineComponent({
const actionType = ref(costanti.ACTIONTYPE.LINK_REG)
function clickToRegister() {
// Responsive detection
const isMobile = ref(false)
const checkMobile = () => {
isMobile.value = window.innerWidth <= 768
}
function clickToRegister() {
//if (site.value.confpages.enableRegByBot) {
//$router.push('/bot')
//} else {
$router.push('/registrati/' + tools.getInvitante())
//}
}
function mounted() {
@@ -76,6 +81,10 @@ export default defineComponent({
chooseReg.value = true
slide.value = 'second'
}
// Check mobile on mount
checkMobile()
window.addEventListener('resize', checkMobile)
}
function regEventEmail() {
@@ -91,16 +100,29 @@ export default defineComponent({
if (invitante) {
start.value = true
slide.value = 'second';
noInvited.value = false;
chooseReg.value = true;
slide.value = 'second'
noInvited.value = false
chooseReg.value = true
} else {
start.value = true
}
}
// Determina se mostrare un dot specifico
function shouldShowDot(slideName: string) {
// Non mostrare 'sceglilink' se non ci sono link
if (slideName === 'sceglilink' && listlinksreg.value.length === 0) {
return false
}
return true
}
onMounted(mounted)
onUnmounted(() => {
window.removeEventListener('resize', checkMobile)
})
return {
tools,
site,
@@ -115,6 +137,8 @@ export default defineComponent({
listlinksreg,
actionType,
t,
isMobile,
shouldShowDot,
}
},
})

View File

@@ -1,223 +1,275 @@
<template>
<div
v-if="site.confpages?.enableReg"
class="row q-ma-sm centermydiv2 q-pa-sm justify-center align-center"
class="registration-container"
>
<div v-if="!start">
<!-- Bottone Iniziale -->
<div
v-if="!start"
class="start-button-wrapper"
>
<q-btn
rounded
glossy
icon="fas fa-user-plus"
size="md"
unelevated
size="lg"
color="primary"
icon="person_add"
@click="buttRegistrati()"
:label="$t('reg.submit')"
>
</q-btn>
class="start-btn"
/>
</div>
<q-carousel
<!-- Carousel Registrazione -->
<q-card
v-if="start"
v-model="slide"
transition-prev="scale"
transition-next="scale"
animated
control-color="white"
navigation
padding
height="500px"
:class="`text-white bg-primary shadow-1 rounded-borders`"
class="registration-card"
>
<q-carousel-slide
name="start"
class="column no-wrap flex-center"
<q-carousel
v-model="slide"
transition-prev="slide-right"
transition-next="slide-left"
animated
swipeable
class="modern-carousel"
:height="isMobile ? 'auto' : '500px'"
>
<q-icon
name="fas fa-user-plus"
size="56px"
/>
<div class="q-mt-md text-center">
<span class="text-h6 text-white"> {{ t('reg.invitante') }}</span>
<q-card class="dialog_card q-mb-lg">
<q-card-section class="column q-ma-sm q-pa-sm q-col-gutter-sm">
<!-- Slide 1: Hai un Invitante? -->
<q-carousel-slide
name="start"
class="carousel-slide"
>
<div class="slide-content">
<div class="slide-icon-wrapper">
<q-icon
name="person_add"
size="64px"
color="primary"
/>
</div>
<h2 class="slide-title">{{ t('reg.invitante') }}</h2>
<div class="action-buttons">
<q-btn
rounded
glossy
unelevated
size="lg"
color="positive"
icon="check"
@click="
listlinksreg.length > 0 ? (slide = 'sceglilink') : (slide = 'second');
noInvited = false;
chooseReg = true;
"
:label="$t('dialog.yes')"
>
</q-btn>
class="action-btn yes-btn"
/>
<q-btn
rounded
glossy
unelevated
size="lg"
color="negative"
icon="close"
@click="
slide = 'second';
noInvited = true;
chooseReg = false;
"
:label="$t('dialog.no')"
class="action-btn no-btn"
/>
</div>
</div>
</q-carousel-slide>
<!-- Slide 2: Scegli Link (se disponibile) -->
<q-carousel-slide
name="sceglilink"
class="carousel-slide"
>
<div class="slide-content">
<h2 class="slide-title">{{ t('reg.title_reg_con_link') }}</h2>
<div class="links-list">
<div
v-for="(rec, i) in listlinksreg"
:key="i"
class="link-item"
>
</q-btn>
</q-card-section>
</q-card>
</div>
</q-carousel-slide>
<q-carousel-slide name="sceglilink">
<q-card class="dialog_card q-mb-lg">
<div class="q-ma-sm q-pa-sm text-h6 text-blue text-bold">{{ t('reg.title_reg_con_link') }}</div>
<q-card-section class="column q-ma-sm q-pa-sm q-col-gutter-sm text-black">
<div
v-for="(rec, i) in listlinksreg"
:key="i"
>
<div class="q-pa-xs q-ma-xs q-border q-rounded my-custom-border">
<CMyUser
:mycontact="rec"
:visu="costanti.FIND_PEOPLE"
@setCmd="tools.setCmd"
:actionType="actionType"
:hideellipses="true"
>
</CMyUser>
<!--<CContactUser
:myuser="rec"
:showBtnActivities="false"
:sendRIS="false"
:actionType="actionType"
/>
</div>-->
</div>
<div class="q-ma-md q-pa-md">
<div class="custom-link">
<a
href="/registrati"
target="_blank"
>👉🏻 {{ t('reg.scelgo_l_invitante') }}</a
class="custom-link-text"
>
</div>
<div class="text-center">
<q-btn
rounded
glossy
size="md"
color="primary"
@click="slide = 'start'"
:label="$t('dialog.indietro')"
>
</q-btn>
<q-icon
name="arrow_forward"
size="20px"
/>
{{ t('reg.scelgo_l_invitante') }}
</a>
</div>
</div>
</q-card-section>
</q-card>
</q-carousel-slide>
<q-carousel-slide name="second">
<div
v-if="noInvited"
class="text-h7"
>
<div class="text-center text-bold text-h6">Se ancora non sei stato invitato:</div>
<br />
1 👉🏻 Entra nei gruppi Territoriali su Telegram:<br />
<div class="text-center">
<q-btn
type="a"
rounded
icon="fab fa-telegram"
color="positive"
href="https://t.me/riso_canale/3"
target="_blank"
label="Progetto RISO"
>
</q-btn>
</div>
<br />
2 👉🏻 sul post del canale fissato in alto, troverai tutte le info sul progetto e su come entrare nel gruppo
della tua provincia.<br />
Potrai cosi richiedere il link una volta entrato nella chat di gruppo.<br />
</div>
<div v-else-if="chooseReg">
<div class="row justify-center items-center">
<q-icon
name="fas fa-user-plus"
size="27px"
class="q-mx-md"
<q-btn
flat
color="grey-7"
icon="arrow_back"
@click="slide = 'start'"
:label="$t('dialog.indietro')"
class="back-btn"
/>
<span class="text-h6 text-white"> {{ t('reg.page_title') }}</span>
<q-card class="q-mt-sm dialog_card q-mb-sm">
<q-card-section>
<div
v-if="site.confpages?.enableRegMultiChoice"
style=""
class="column q-ma-sm centermydiv2 q-pa-sm justify-center"
>
<q-btn
rounded
type="a"
class="col-xs-12 col-sm-6 flex-item-btn items-center q-my-md"
icon="fab fa-telegram"
size="md"
color="primary"
:href="invited ? tools.getLinkBotTelegram(invited, regexpire) : `/bot`"
:label="$t('reg.bytelegram')"
>
<q-badge
color="red"
align="bottom"
floating
>Consigliato</q-badge
>
</q-btn>
<br />
<div :class="$q.dark.isActive ? `text-white` : `text-black` + ` col-12 text-center`">
<div class="bg-grey-4">
<br />
se non hai Telegram puoi registrarti con solo l'email ma
<span style="text-decoration: underline">non potrai contattare gli iscritti</span>.
<q-btn
rounded
class="flex-item-btn col-xs-12 col-sm-6"
outline
icon="fas fa-envelope"
size="0.75rem"
:color="$q.dark.isActive ? `black` : `white`"
:text-color="$q.dark.isActive ? `white` : `black`"
@click="regEventEmail"
:label="$t('reg.byemail')"
>
</q-btn>
</div>
</div>
</q-carousel-slide>
<!-- Slide 3: Scelta Registrazione -->
<q-carousel-slide
name="second"
class="carousel-slide"
>
<div class="slide-content">
<!-- Caso: Non Invitato -->
<div
v-if="noInvited"
class="no-invited-content"
>
<div class="slide-icon-wrapper">
<q-icon
name="info"
size="56px"
color="info"
/>
</div>
<h2 class="slide-title">Se ancora non sei stato invitato:</h2>
<div class="instructions">
<div class="instruction-item">
<div class="instruction-number">1</div>
<div class="instruction-content">
<p>Entra nei gruppi Territoriali su Telegram</p>
<q-btn
unelevated
color="positive"
icon="fab fa-telegram"
href="https://t.me/riso_canale/3"
target="_blank"
label="Progetto RISO"
class="telegram-btn"
/>
</div>
</div>
<div
v-else
style="margin-top: 10px; text-align: center"
>
Registrati<br />
<q-btn
rounded
size="md"
color="primary"
@click="clickToRegister"
:label="$t('reg.submit')"
>
</q-btn>
<div class="instruction-item">
<div class="instruction-number">2</div>
<div class="instruction-content">
<p>
Sul post del canale fissato in alto, troverai tutte le info sul
progetto e su come entrare nel gruppo della tua provincia.
</p>
<p class="instruction-note">
Potrai così richiedere il link una volta entrato nella chat di
gruppo.
</p>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
<!-- Caso: Con Invitante -->
<div
v-else-if="chooseReg"
class="with-invited-content"
>
<div class="flex justify-center">
<logo
class="signup-logo "
mystyle="width: 50px !important; height: 50px !important;"
/>
</div>
<!-- Multi Choice: Telegram vs Email -->
<div
v-if="site.confpages?.enableRegMultiChoice"
class="registration-options"
>
<q-btn
unelevated
size="lg"
color="primary"
icon="fab fa-telegram"
type="a"
:href="invited ? tools.getLinkBotTelegram(invited, regexpire) : `/bot`"
:label="$t('reg.bytelegram')"
class="option-btn telegram-option"
>
<q-badge
color="positive"
floating
class="recommended-badge"
>
Consigliato
</q-badge>
</q-btn>
<div class="divider">
<span>oppure</span>
</div>
<q-btn
outline
size="lg"
color="primary"
icon="email"
@click="regEventEmail"
:label="$t('reg.byemail')"
class="option-btn email-option"
/>
</div>
<!-- Single Choice: Solo Registrati -->
<div
v-else
class="single-registration"
>
<p class="registration-text">Registrati</p>
<q-btn
unelevated
size="lg"
color="primary"
icon="person_add"
@click="clickToRegister"
:label="$t('reg.submit')"
class="register-btn"
/>
</div>
</div>
</div>
</div>
</q-carousel-slide>
</q-carousel>
</q-carousel-slide>
</q-carousel>
<!-- Navigation Indicators -->
<div
v-if="start"
class="navigation-dots"
>
<div
v-for="(s, i) in ['start', 'sceglilink', 'second']"
:key="i"
class="nav-dot"
:class="{ active: slide === s, visible: shouldShowDot(s) }"
@click="slide = s"
></div>
</div>
</q-card>
</div>
</template>

View File

@@ -1,5 +1,414 @@
// ========================================
// VARIABILI (Sincronizzate con CSignUp)
// ========================================
$primary-color: #1976d2;
$primary-light: #42a5f5;
$primary-dark: #1565c0;
$accent-color: #26a69a;
$positive-color: #21ba45;
$negative-color: #c10015;
$border-radius: 16px;
$border-radius-sm: 12px;
$border-radius-lg: 24px;
$transition-speed: 0.3s;
$shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
$shadow-md: 0 4px 16px rgba(0, 0, 0, 0.12);
$shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.16);
$mobile-breakpoint: 768px;
// ========================================
// CONTAINER PRINCIPALE
// ========================================
.signin-container {
width: 100%;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
background-attachment: fixed;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
@media (max-width: $mobile-breakpoint) {
padding: 12px;
align-items: flex-start;
padding-top: 40px;
}
}
// ========================================
// PWA CHECK
// ========================================
.pwa-check {
position: absolute;
top: 20px;
right: 20px;
z-index: 10;
@media (max-width: $mobile-breakpoint) {
top: 12px;
right: 12px;
}
}
// ========================================
// CARD PRINCIPALE
// ========================================
.signin-card {
width: 100%;
max-width: 450px;
border-radius: $border-radius-lg;
box-shadow: $shadow-lg;
overflow: hidden;
background: white;
animation: fadeInUp 0.6s ease;
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
border-radius: $border-radius;
}
}
// ========================================
// HEADER
// ========================================
.signin-header {
text-align: center;
padding: 32px 24px 24px;
background: linear-gradient(to bottom, rgba(103, 126, 234, 0.05), transparent);
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
@media (max-width: $mobile-breakpoint) {
padding: 24px 16px 16px;
}
}
.signin-logo {
margin: 0 auto 16px;
animation: scaleIn 0.6s ease;
@media (max-width: $mobile-breakpoint) {
margin: 0 auto 12px;
}
}
.signin-title {
font-size: 2rem;
font-weight: 600;
margin: 0 0 8px;
background: linear-gradient(135deg, $primary-color, $accent-color);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@media (max-width: $mobile-breakpoint) {
font-size: 1.5rem;
margin: 0 0 6px;
}
}
.signin-subtitle {
font-size: 1rem;
color: #666;
margin: 0;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
}
}
// ========================================
// FORM
// ========================================
.signin-form {
padding: 32px 24px;
@media (max-width: $mobile-breakpoint) {
padding: 20px 16px;
}
}
.form-fields {
display: flex;
flex-direction: column;
gap: 20px;
@media (max-width: $mobile-breakpoint) {
gap: 16px;
}
}
// ========================================
// INPUT FIELDS
// ========================================
.modern-input {
:deep(.q-field__control) {
border-radius: $border-radius-sm;
min-height: 56px;
transition: all $transition-speed ease;
@media (max-width: $mobile-breakpoint) {
min-height: 52px;
border-radius: 10px;
}
&:before {
border-color: rgba(0, 0, 0, 0.12);
}
&:hover:before {
border-color: $primary-light;
}
}
:deep(.q-field__label) {
font-size: 1rem;
@media (max-width: $mobile-breakpoint) {
font-size: 0.9375rem;
}
}
:deep(.q-field__prepend) {
.q-icon {
font-size: 24px;
@media (max-width: $mobile-breakpoint) {
font-size: 20px;
}
}
}
&.q-field--focused {
:deep(.q-field__control) {
box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.2);
}
}
&.q-field--error {
animation: shake 0.4s ease;
}
}
// ========================================
// SUBMIT BUTTON
// ========================================
.submit-btn {
width: 100%;
height: 56px;
border-radius: $border-radius;
font-size: 1.125rem;
font-weight: 600;
text-transform: none;
background: linear-gradient(135deg, $primary-color, $primary-light);
box-shadow: $shadow-md;
transition: all $transition-speed ease;
margin-top: 8px;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-lg;
background: linear-gradient(135deg, $primary-dark, $primary-color);
}
&:active {
transform: translateY(0);
}
@media (max-width: $mobile-breakpoint) {
height: 52px;
font-size: 1rem;
}
}
// ========================================
// FORGOT PASSWORD
// ========================================
.forgot-password {
text-align: center;
margin-top: -8px;
@media (max-width: $mobile-breakpoint) {
margin-top: -4px;
}
}
.forgot-link {
display: inline-flex;
align-items: center;
gap: 6px;
color: #666;
text-decoration: none;
font-size: 0.9375rem;
transition: all $transition-speed ease;
padding: 8px 12px;
border-radius: $border-radius-sm;
&:hover {
color: $primary-color;
background: rgba(25, 118, 210, 0.06);
}
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
padding: 6px 10px;
}
}
// ========================================
// DIVIDER
// ========================================
.divider {
position: relative;
text-align: center;
margin: 8px 0;
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
width: calc(50% - 80px);
height: 1px;
background: linear-gradient(to right, transparent, rgba(0, 0, 0, 0.12));
}
&::before {
left: 0;
}
&::after {
right: 0;
background: linear-gradient(to left, transparent, rgba(0, 0, 0, 0.12));
}
span {
display: inline-block;
padding: 4px 16px;
background: white;
color: #666;
font-size: 0.875rem;
font-weight: 500;
border-radius: 12px;
border: 1px solid rgba(0, 0, 0, 0.08);
@media (max-width: $mobile-breakpoint) {
font-size: 0.8125rem;
padding: 3px 12px;
}
}
}
// ========================================
// REGISTRATION SECTION
// ========================================
.register-section {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 16px;
background: linear-gradient(to bottom, rgba(33, 186, 69, 0.05), transparent);
border-radius: $border-radius;
border: 1px solid rgba(33, 186, 69, 0.15);
@media (max-width: $mobile-breakpoint) {
padding: 12px;
gap: 10px;
}
}
.register-text {
margin: 0;
font-size: 0.9375rem;
color: #666;
text-align: center;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
}
}
.register-btn {
width: 100%;
max-width: 300px;
height: 52px;
border-radius: $border-radius;
font-size: 1.0625rem;
font-weight: 600;
text-transform: none;
background: linear-gradient(135deg, $positive-color, #26a69a);
box-shadow: $shadow-sm;
transition: all $transition-speed ease;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-md;
background: linear-gradient(135deg, #1e8e3e, $positive-color);
}
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
height: 48px;
font-size: 1rem;
}
}
// ========================================
// ANIMAZIONI
// ========================================
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.5);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
25% {
transform: translateX(-10px);
}
75% {
transform: translateX(10px);
}
}
// ========================================
// RESPONSIVE UTILITIES
// ========================================
@media (max-width: $mobile-breakpoint) {
// Fix per iOS Safari
.signin-container {
min-height: -webkit-fill-available;
}
}
// ========================================
// LEGACY CLASS (per compatibilità)
// ========================================
.signin {
width: 100%;
margin: 0 auto;
max-width: 450px;
}
}

View File

@@ -1,127 +1,151 @@
<template>
<div>
<div v-if="enablePwa"><CCheckAppRunning :login="true"/></div>
<div class="text-center">
<p>
<logo></logo>
</p>
<div class="signin-container">
<!-- PWA Check -->
<div v-if="enablePwa" class="pwa-check">
<CCheckAppRunning :login="true" />
</div>
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<div class="q-gutter-xs">
<q-input
ref="refUsername"
v-model="signin.username"
rounded
outlined
dense
lazy-rules
:label="$t('reg.username_login')"
:rules="[
(val) => !!val || t('reg.err.required'),
(val) =>
val.length >= 4 ||
t('reg.err.atleast') + ' 4 ' + t('reg.err.char'),
]"
>
<template v-slot:prepend>
<q-icon name="person" />
</template>
</q-input>
<q-input
ref="refPassword"
v-model="signin.password"
:type="typePassword"
rounded
outlined
dense
debounce="500"
@update:model-value="checkAutoCompletion"
v-on:keyup.enter="onSubmit()"
:label="$t('reg.password')"
:rules="[
(val) => !!val || t('reg.err.required'),
(val) =>
val.length >= 8 ||
t('reg.err.atleast') + ' 8 ' + t('reg.err.char'),
]"
>
<template v-slot:append>
<q-btn
v-if="!autoCompleteTriggered"
tabindex="-1"
:icon="
typePassword === `password` ? `fas fa-eye-slash` : `fas fa-eye`
"
@click="showPassword"
>
</q-btn>
</template>
<template v-slot:prepend>
<q-icon name="vpn_key" />
</template>
</q-input>
<div style="text-align: center">
<q-btn
type="submit"
rounded
size="md"
color="primary"
:label="$t('login.enter')"
>
</q-btn>
</div>
<br />
<div class="text-center" style="margin-bottom: 10px">
<a :href="getlinkforgetpwd()" style="color: gray">{{
t('reg.forgetpassword')
}}</a>
</div>
<div
v-if="
site.confpages &&
site.confpages?.enableReg &&
showregbutt &&
site.confpages?.enableRegByBot
"
style="margin-top: 10px; text-align: center"
>
Se non sei ancora Registrato:<br />
<q-btn
type="a"
rounded
size="md"
color="primary"
href="/bot"
:label="$t('reg.submit')"
>
</q-btn>
</div>
<div
v-else-if="site.confpages && site.confpages?.enableReg && showregbutt"
style="margin-top: 10px; text-align: center"
>
Se non sei ancora Registrato:<br />
<q-btn
rounded
size="md"
color="primary"
to="/registrati"
:label="$t('reg.submit')"
>
</q-btn>
</div>
<!-- Login Card -->
<q-card class="signin-card">
<!-- Header con Logo -->
<div class="signin-header">
<logo class="signin-logo" mystyle="width: 60px !important; height: 60px !important;" />
<h1 class="signin-title">{{ t('login.enter') }}</h1>
<p class="signin-subtitle">Accedi al tuo account</p>
</div>
</q-form>
<!-- Form -->
<q-card-section class="signin-form">
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<div class="form-fields">
<!-- Username Input -->
<q-input
ref="refUsername"
v-model="signin.username"
filled
class="modern-input"
:label="$t('reg.username_login')"
tabindex="1"
lazy-rules
:rules="[
(val) => !!val || t('reg.err.required'),
(val) =>
val.length >= 4 ||
t('reg.err.atleast') + ' 4 ' + t('reg.err.char'),
]"
>
<template v-slot:prepend>
<q-icon name="person" color="primary" />
</template>
</q-input>
<!-- Password Input -->
<q-input
ref="refPassword"
v-model="signin.password"
:type="typePassword"
filled
class="modern-input"
:label="$t('reg.password')"
tabindex="2"
debounce="500"
@update:model-value="checkAutoCompletion"
v-on:keyup.enter="onSubmit()"
lazy-rules
:rules="[
(val) => !!val || t('reg.err.required'),
(val) =>
val.length >= 8 ||
t('reg.err.atleast') + ' 8 ' + t('reg.err.char'),
]"
>
<template v-slot:prepend>
<q-icon name="lock" color="primary" />
</template>
<template v-slot:append>
<q-btn
v-if="!autoCompleteTriggered"
flat
round
dense
tabindex="-1"
:icon="typePassword === 'password' ? 'visibility_off' : 'visibility'"
@click="showPassword"
/>
</template>
</q-input>
<!-- Submit Button -->
<q-btn
type="submit"
unelevated
size="lg"
color="primary"
:label="$t('login.enter')"
class="submit-btn"
tabindex="3"
/>
<!-- Forgot Password Link -->
<div class="forgot-password">
<a :href="getlinkforgetpwd()" class="forgot-link">
<q-icon name="help_outline" size="18px" />
{{ t('reg.forgetpassword') }}
</a>
</div>
<!-- Divider -->
<div v-if="site.confpages && site.confpages?.enableReg && showregbutt" class="divider">
<span>Non hai un account?</span>
</div>
<!-- Registration Button (Bot) -->
<div
v-if="
site.confpages &&
site.confpages?.enableReg &&
showregbutt &&
site.confpages?.enableRegByBot
"
class="register-section"
>
<p class="register-text">Se non sei ancora registrato:</p>
<q-btn
type="a"
unelevated
size="lg"
color="positive"
icon="person_add"
href="/bot"
:label="$t('reg.submit')"
class="register-btn"
/>
</div>
<!-- Registration Button (Standard) -->
<div
v-else-if="site.confpages && site.confpages?.enableReg && showregbutt"
class="register-section"
>
<p class="register-text">Se non sei ancora registrato:</p>
<q-btn
unelevated
size="lg"
color="positive"
icon="person_add"
to="/registrati"
:label="$t('reg.submit')"
class="register-btn"
/>
</div>
</div>
</q-form>
</q-card-section>
</q-card>
</div>
</template>
<script lang="ts" src="./CSignIn.ts">
</script>
<script lang="ts" src="./CSignIn.ts"></script>
<style lang="scss" scoped>
@import './CSignIn.scss';

View File

@@ -1,46 +1,843 @@
// ========================================
// VARIABILI E CONFIGURAZIONE
// ========================================
$primary-color: #1976d2;
$primary-light: #42a5f5;
$primary-dark: #1565c0;
$accent-color: #26a69a;
$positive-color: #21ba45;
$negative-color: #c10015;
$warning-color: #f2c037;
$border-radius: 16px;
$border-radius-sm: 12px;
$border-radius-lg: 24px;
$transition-speed: 0.3s;
$shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
$shadow-md: 0 4px 16px rgba(0, 0, 0, 0.12);
$shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.16);
$mobile-breakpoint: 768px;
$mobile-footer-height: 80px;
// ========================================
// CONTAINER PRINCIPALE
// ========================================
.signup-container {
width: 100%;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
background-attachment: fixed;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
position: relative;
@media (max-width: $mobile-breakpoint) {
padding: 0;
align-items: flex-start;
background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
}
}
// ========================================
// CARDS DI SISTEMA (Success, Error, Warning)
// ========================================
.already-logged,
.already-registered {
width: 100%;
max-width: 500px;
animation: fadeInUp 0.5s ease;
}
.success-card,
.error-card,
.warning-card,
.telegram-card {
border-radius: $border-radius-lg;
box-shadow: $shadow-lg;
overflow: hidden;
background: white;
.q-icon {
animation: scaleIn 0.5s ease;
}
}
.success-card {
border-top: 4px solid $positive-color;
}
.error-card {
border-top: 4px solid $negative-color;
}
.warning-card {
border-top: 4px solid $warning-color;
}
.action-btn {
min-width: 140px;
border-radius: $border-radius-sm;
text-transform: none;
font-weight: 500;
transition: all $transition-speed ease;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-md;
}
}
// ========================================
// FORM PRINCIPALE
// ========================================
.signup-form {
width: 100%;
max-width: 800px;
animation: fadeInUp 0.5s ease;
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
}
}
// ========================================
// HEADER
// ========================================
.signup-header {
text-align: center;
padding: 0 10px 10px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: $border-radius-lg $border-radius-lg 0 0;
box-shadow: $shadow-sm;
@media (max-width: $mobile-breakpoint) {
padding: 6px 8px;
border-radius: 0;
margin: 8px;
background: white;
}
}
.signup-logo {
margin: 2px auto 2px;
animation: rotateIn 0.6s ease;
@media (max-width: $mobile-breakpoint) {
margin: 2px auto;
}
}
.signup-title {
h1 {
margin: 0;
background: linear-gradient(135deg, $primary-color, $accent-color);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-size: 2rem;
@media (max-width: $mobile-breakpoint) {
font-size: 1.5rem;
}
}
p {
margin: 8px 0 0;
font-size: 1rem;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
margin: 4px 0 0;
}
}
}
// ========================================
// FORM CONTENT
// ========================================
.form-content {
background: white;
border-radius: $border-radius-lg;
box-shadow: $shadow-lg;
overflow: hidden;
@media (max-width: $mobile-breakpoint) {
border-radius: 0;
flex: 1;
display: flex;
flex-direction: column;
}
}
// ========================================
// PROGRESS STEPPER
// ========================================
.progress-stepper {
display: flex;
justify-content: center;
align-items: center;
padding: 24px 20px;
background: linear-gradient(to bottom, rgba(103, 126, 234, 0.05), transparent);
@media (max-width: $mobile-breakpoint) {
padding: 12px 16px;
}
}
.step-item {
display: flex;
align-items: center;
position: relative;
&.active .step-circle {
background: $primary-color;
color: white;
transform: scale(1.15);
box-shadow: 0 4px 12px rgba(25, 118, 210, 0.4);
}
&.completed .step-circle {
background: $positive-color;
color: white;
}
}
.step-circle {
width: 36px;
height: 36px;
border-radius: 50%;
background: #e0e0e0;
color: #757575;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.875rem;
transition: all $transition-speed ease;
position: relative;
z-index: 2;
@media (max-width: $mobile-breakpoint) {
width: 32px;
height: 32px;
font-size: 0.75rem;
}
}
.step-line {
width: 60px;
height: 3px;
background: linear-gradient(to right, #e0e0e0, #bdbdbd);
margin: 0 4px;
transition: all $transition-speed ease;
@media (max-width: $mobile-breakpoint) {
width: 40px;
}
.completed + & {
background: linear-gradient(to right, $positive-color, $primary-color);
}
}
// ========================================
// CAROUSEL
// ========================================
.carousel-wrapper {
@media (max-width: $mobile-breakpoint) {
flex: 1;
display: flex;
flex-direction: column;
padding-bottom: $mobile-footer-height;
}
}
.modern-carousel {
background: transparent;
@media (max-width: $mobile-breakpoint) {
flex: 1;
height: auto !important;
}
}
.carousel-slide {
padding: 0;
@media (max-width: $mobile-breakpoint) {
padding: 0;
}
}
// ========================================
// SLIDE CONTENT
// ========================================
.slide-content {
padding: 5px 16px 16px;
display: flex;
flex-direction: column;
gap: 12px;
animation: fadeIn 0.4s ease;
@media (max-width: $mobile-breakpoint) {
padding: 0px 16px 16px;
gap: 12px;
min-height: calc(100vh - 280px);
}
&.final-slide {
@media (max-width: $mobile-breakpoint) {
min-height: auto;
}
}
}
.slide-header {
text-align: center;
padding-bottom: 16px;
border-bottom: 2px solid rgba(0, 0, 0, 0.05);
@media (max-width: $mobile-breakpoint) {
padding-bottom: 12px;
}
.q-icon {
margin-bottom: 12px;
animation: bounceIn 0.6s ease;
@media (max-width: $mobile-breakpoint) {
font-size: 32px !important;
margin-bottom: 8px;
}
}
}
.slide-title {
font-size: 1.75rem;
font-weight: 600;
margin: 12px 0 8px;
color: #1a1a1a;
@media (max-width: $mobile-breakpoint) {
font-size: 1.25rem;
margin: 8px 0 4px;
}
}
.slide-subtitle {
font-size: 1rem;
color: #666;
margin: 0;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
}
}
// ========================================
// FORM FIELDS
// ========================================
.form-fields {
display: flex;
flex-direction: column;
gap: 16px;
@media (max-width: $mobile-breakpoint) {
gap: 10px;
}
}
.modern-input {
:deep(.q-field__control) {
border-radius: $border-radius-sm;
min-height: 56px;
transition: all $transition-speed ease;
@media (max-width: $mobile-breakpoint) {
min-height: 48px;
border-radius: 10px;
}
&:before {
border-color: rgba(0, 0, 0, 0.12);
}
&:hover:before {
border-color: $primary-light;
}
}
:deep(.q-field__label) {
font-size: 1rem;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
}
}
:deep(.q-field__prepend) {
.q-icon {
font-size: 24px;
@media (max-width: $mobile-breakpoint) {
font-size: 20px;
}
}
}
&.q-field--focused {
:deep(.q-field__control) {
box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.2);
}
}
}
.password-hint {
display: flex;
align-items: center;
gap: 8px;
padding: 12px;
background: rgba(103, 126, 234, 0.08);
border-radius: $border-radius-sm;
font-size: 0.875rem;
color: #666;
margin-top: 8px;
@media (max-width: $mobile-breakpoint) {
padding: 8px;
font-size: 0.8125rem;
margin-top: 4px;
}
}
// ========================================
// SUMMARY CARD (Slide 4)
// ========================================
.summary-card {
background: linear-gradient(135deg, rgba(103, 126, 234, 0.08), rgba(118, 75, 162, 0.08));
padding: 20px;
border-radius: $border-radius;
display: flex;
flex-direction: column;
gap: 12px;
@media (max-width: $mobile-breakpoint) {
padding: 12px;
gap: 8px;
}
}
.summary-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: white;
border-radius: $border-radius-sm;
font-size: 1rem;
color: #333;
box-shadow: $shadow-sm;
transition: all $transition-speed ease;
@media (max-width: $mobile-breakpoint) {
padding: 10px;
gap: 10px;
font-size: 0.875rem;
}
&:hover {
transform: translateX(4px);
box-shadow: $shadow-md;
}
.q-icon {
font-size: 24px;
flex-shrink: 0;
@media (max-width: $mobile-breakpoint) {
font-size: 20px;
}
}
span {
font-weight: 500;
word-break: break-word;
}
}
// ========================================
// POLICY SECTION
// ========================================
.policy-section {
display: flex;
flex-direction: column;
gap: 16px;
padding-top: 16px;
@media (max-width: $mobile-breakpoint) {
gap: 12px;
padding-top: 3px;
}
}
.policy-btn {
text-transform: none;
font-weight: 500;
align-self: center;
border-radius: $border-radius-sm;
padding: 8px 16px;
transition: all $transition-speed ease;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
padding: 4px 16px;
}
&:hover {
background: rgba(25, 118, 210, 0.08);
}
}
.terms-checkbox {
padding: 16px;
background: rgba(0, 0, 0, 0.02);
border-radius: $border-radius-sm;
transition: all $transition-speed ease;
@media (max-width: $mobile-breakpoint) {
padding: 0px 12px;
}
&:hover {
background: rgba(0, 0, 0, 0.04);
}
:deep(.q-checkbox__label) {
font-size: 0.9375rem;
line-height: 1.5;
@media (max-width: $mobile-breakpoint) {
font-size: 0.875rem;
}
}
}
.terms-text {
color: #333;
font-weight: 500;
}
// ========================================
// NAVIGATION BUTTONS
// ========================================
.navigation-buttons {
display: flex;
justify-content: space-between;
gap: 12px;
padding: 20px 32px;
background: linear-gradient(to top, rgba(0, 0, 0, 0.02), transparent);
@media (max-width: $mobile-breakpoint) {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 12px 16px;
background: white;
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.1);
z-index: 1000;
border-top: 1px solid rgba(0, 0, 0, 0.08);
}
&.mobile {
.nav-btn {
flex: 1;
max-width: none;
}
.back-btn {
flex: 0 0 auto;
min-width: 48px;
padding: 0 12px;
}
}
}
.nav-btn {
min-height: 48px;
border-radius: $border-radius-sm;
font-weight: 600;
text-transform: none;
font-size: 1rem;
transition: all $transition-speed ease;
box-shadow: $shadow-sm;
@media (max-width: $mobile-breakpoint) {
min-height: 44px;
font-size: 0.9375rem;
}
&:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: $shadow-md;
}
&:active:not(:disabled) {
transform: translateY(0);
}
&:disabled {
opacity: 0.5;
}
}
.back-btn {
min-width: 120px;
@media (max-width: $mobile-breakpoint) {
min-width: auto;
}
}
.next-btn,
.submit-btn {
flex: 1;
max-width: 300px;
background: linear-gradient(135deg, $primary-color, $primary-light);
&:hover:not(:disabled) {
background: linear-gradient(135deg, $primary-dark, $primary-color);
}
@media (max-width: $mobile-breakpoint) {
max-width: none;
}
}
.submit-btn {
background: linear-gradient(135deg, $positive-color, #26a69a);
&:hover:not(:disabled) {
background: linear-gradient(135deg, #1e8e3e, $positive-color);
}
}
// ========================================
// DEBUG STEPPER
// ========================================
.debug-stepper {
padding: 16px 32px;
@media (max-width: $mobile-breakpoint) {
padding: 12px 16px;
margin-bottom: $mobile-footer-height;
}
}
// ========================================
// TELEGRAM SECTION
// ========================================
.telegram-section {
padding: 20px;
@media (max-width: $mobile-breakpoint) {
padding: 16px;
}
}
// ========================================
// ANIMAZIONI
// ========================================
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.5);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.3);
}
50% {
transform: scale(1.05);
}
70% {
transform: scale(0.9);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes rotateIn {
from {
opacity: 0;
transform: rotate(-180deg);
}
to {
opacity: 1;
transform: rotate(0);
}
}
// ========================================
// UTILITY CLASSES
// ========================================
.signup {
width: 100%;
margin: 0 auto;
max-width: 450px;
max-width: 800px;
@media (max-width: $mobile-breakpoint) {
max-width: 100%;
}
}
.wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.clCellCode {
border-radius: 32px;
border-right: #2d2260;
height: 50px;
font-size: 1rem;
padding: 8px;
}
// Legacy classes (mantenute per compatibilità)
.clCellCode,
.clCell {
border-radius: 32px;
border-right: #2d2260;
height: 50px;
font-size: 1rem;
padding: 8px;
}
.vue-country-select{
.vue-country-select {
border-radius: 32px;
}
.myuserinvitante{
.myuserinvitante {
font-weight: bold;
color: red;
color: $negative-color;
font-size: 1.5rem;
}
.cosa_chiedere{
font-weight: bold;
color: blue;
font-size: 1rem;
padding: 10px;
// ========================================
// RESPONSIVE UTILITIES
// ========================================
@media (max-width: $mobile-breakpoint) {
// Assicura che il body non scrolli quando necessario
body.signup-open {
overflow: hidden;
position: fixed;
width: 100%;
}
// Fix per iOS Safari
.signup-container {
min-height: -webkit-fill-available;
}
}
// ========================================
// DARK MODE SUPPORT (opzionale)
// ========================================
// @media (prefers-color-scheme: dark) {
// .signup-container {
// background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
// }
// .signup-header,
// .form-content {
// background: #2a2a3e;
// color: #ffffff;
// }
// .slide-title {
// color: #ffffff;
// }
// .slide-subtitle {
// color: #b0b0b0;
// }
// .summary-card {
// background: linear-gradient(135deg, rgba(103, 126, 234, 0.15), rgba(118, 75, 162, 0.15));
// }
// .summary-item {
// background: #3a3a4e;
// color: #ffffff;
// }
// .modern-input {
// :deep(.q-field__control) {
// background: #3a3a4e;
// color: #ffffff;
// }
// :deep(.q-field__label) {
// color: #b0b0b0;
// }
// }
// }
.signup-header {
position: relative;
}
.header-content {
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.signup-logo {
position: absolute;
left: 0;
margin: 0 !important;
}
.signup-title {
text-align: center;
h1 {
margin: 0;
font-size: 1.5rem;
@media (max-width: $mobile-breakpoint) {
font-size: 1.25rem;
}
}
}

View File

@@ -10,7 +10,16 @@ import { CTitleBanner } from '../CTitleBanner';
import { CCopyBtn } from '../CCopyBtn';
import { CRegistration } from '../CRegistration';
import { PagePolicy } from '../PagePolicy';
import { computed, defineComponent, onMounted, reactive, ref, watch } from 'vue';
import {
computed,
defineComponent,
nextTick,
onMounted,
onUnmounted,
reactive,
ref,
watch,
} from 'vue';
import { CSignIn } from '@src/components/CSignIn';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
@@ -123,6 +132,14 @@ export default defineComponent({
const inputPassword = ref(<any>null);
const inputPassword2 = ref(<any>null);
const submitBtn = ref(<any>null); // AGGIUNGI QUESTA RIGA
// Responsive detection
const isMobile = ref(false);
const checkMobile = () => {
isMobile.value = window.innerWidth <= 768;
};
const invitaStore = useInvitaAmicoStore();
const checkifDisabled = computed(() => {
@@ -132,7 +149,7 @@ export default defineComponent({
ret =
!signup.email ||
(tools.getAskToVerifyReg() &&
(!signup.aportador_solidario || inputAportador.value.hasError)) ||
(!signup.aportador_solidario || inputAportador.value?.hasError)) ||
(inputEmail.value && inputEmail.value.hasError);
} else if (slide.value === '2') {
// Username
@@ -158,6 +175,37 @@ export default defineComponent({
return ret;
});
// Auto-focus sul primo campo quando cambia slide
watch(
() => slide.value,
async (newSlide) => {
await nextTick();
if (newSlide === '1') {
// Step 1: Focus su aportador o email
if (inputAportador.value && props.showaportador) {
inputAportador.value.focus();
} else if (inputEmail.value) {
inputEmail.value.focus();
}
} else if (newSlide === '2') {
// Step 2: Focus su username
if (inputUsername.value) {
inputUsername.value.focus();
}
} else if (newSlide === '3') {
// Step 3: Focus su password
if (inputPassword.value) {
inputPassword.value.focus();
}
} else if (newSlide === '4') {
if (submitBtn.value) {
submitBtn.value.$el.focus();
}
}
}
);
const typePassword = ref('password');
const ap_iniziale = ref('');
@@ -452,20 +500,27 @@ export default defineComponent({
onMounted(async () => {
const token = props.token;
// Check mobile on mount
checkMobile();
window.addEventListener('resize', checkMobile);
if (token) {
// carica le info della registrazione
const risinvite = await invitaStore.ottieniInvitoByToken(token);
if (risinvite && risinvite.email) {
signup.email = risinvite.email;
if (risinvite.usernameInvitante)
signup.aportador_solidario = risinvite.usernameInvitante
slide.value = '2'
signup.aportador_solidario = risinvite.usernameInvitante;
slide.value = '2';
}
}
});
onUnmounted(() => {
window.removeEventListener('resize', checkMobile);
});
created();
return {
@@ -502,6 +557,8 @@ export default defineComponent({
inputPassword,
inputPassword2,
shared_consts,
isMobile,
submitBtn,
};
},
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,68 @@
// ========================================
// VARIABILI
// ========================================
$transition-speed: 0.3s;
$mobile-breakpoint: 768px;
.svgclass {
color: white;
transform: translateY(0px);
}
.svgclass_animate {
transform: translateY(-70px);
color: red;
}
#sun {
animation: gravity 5s infinite;
}
#logoimg {
height: 100px;
width: auto;
@media screen and (max-width: 600px) {
// ========================================
// LOGO WRAPPER
// ========================================
.logo-wrapper {
display: inline-flex;
align-items: center;
justify-content: center;
transition: all $transition-speed ease;
// Hover effect subtile
&:hover {
.logo-image {
transform: scale(1.05);
}
}
}
@keyframes gravity {
// ========================================
// LOGO IMAGE
// ========================================
.logo-image {
height: 100px;
width: auto;
max-width: 100%;
object-fit: contain;
transition: all $transition-speed ease;
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.1));
// Animazione ingresso
animation: logoEntrance 0.8s ease;
@media (max-width: $mobile-breakpoint) {
height: 80px;
}
// Animazione hover
&:hover {
filter: drop-shadow(0 4px 16px rgba(0, 0, 0, 0.15));
}
}
// ========================================
// ANIMAZIONI
// ========================================
// Animazione ingresso logo
@keyframes logoEntrance {
from {
opacity: 0;
transform: scale(0.8) translateY(-10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
// Animazione rotazione 3D (per elementi speciali)
@keyframes rotate3D {
0% {
transform: rotateY(0deg);
}
@@ -32,8 +71,161 @@
}
}
// ========================================
// CLASSI UTILITY (per animazioni personalizzate)
// ========================================
// Rotazione continua
.logo-rotate {
.logo-image {
animation: rotate3D 10s linear infinite;
}
}
// Pulsazione
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
.logo-pulse {
.logo-image {
animation: pulse 2s ease-in-out infinite;
}
}
// Flottante
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
.logo-float {
.logo-image {
animation: float 3s ease-in-out infinite;
}
}
// ========================================
// LEGACY SUPPORT (per compatibilità)
// ========================================
// Supporto per ID legacy
#logo {
display: inline-flex;
align-items: center;
justify-content: center;
}
#logoimg {
height: 100px;
width: auto;
max-width: 100%;
object-fit: contain;
transition: all $transition-speed ease;
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.1));
@media (max-width: $mobile-breakpoint) {
height: 80px;
}
}
// Classi SVG legacy
.svgclass {
color: white;
transform: translateY(0);
transition: all $transition-speed ease;
}
.svgclass_animate {
transform: translateY(-70px);
color: red;
}
// Animazione legacy per elementi specifici
#sun {
animation: rotate3D 10s linear infinite;
}
#smile {
opacity: 0.1 !important;
fill: red;
}
// ========================================
// TEMI SPECIALI
// ========================================
// Logo con glow effect
.logo-glow {
.logo-image {
filter: drop-shadow(0 0 20px rgba(103, 126, 234, 0.5));
animation: glowPulse 2s ease-in-out infinite;
}
}
@keyframes glowPulse {
0%, 100% {
filter: drop-shadow(0 0 20px rgba(103, 126, 234, 0.5));
}
50% {
filter: drop-shadow(0 0 30px rgba(103, 126, 234, 0.8));
}
}
// Logo con effetto rainbow (opzionale)
.logo-rainbow {
.logo-image {
animation: rainbowFilter 3s linear infinite;
}
}
@keyframes rainbowFilter {
0% {
filter: hue-rotate(0deg) drop-shadow(0 2px 8px rgba(0, 0, 0, 0.1));
}
100% {
filter: hue-rotate(360deg) drop-shadow(0 2px 8px rgba(0, 0, 0, 0.1));
}
}
// ========================================
// DARK MODE SUPPORT
// ========================================
@media (prefers-color-scheme: dark) {
.logo-image {
filter: drop-shadow(0 2px 8px rgba(255, 255, 255, 0.15));
&:hover {
filter: drop-shadow(0 4px 16px rgba(255, 255, 255, 0.25));
}
}
#logoimg {
filter: drop-shadow(0 2px 8px rgba(255, 255, 255, 0.15));
}
}
// ========================================
// PRINT STYLES
// ========================================
@media print {
.logo-wrapper,
#logo {
page-break-inside: avoid;
}
.logo-image,
#logoimg {
max-height: 60px;
filter: none;
}
}

View File

@@ -1,11 +1,16 @@
<template>
<div id="logo">
<img id="logoimg" :alt="logoalt()" :src=logoimg() :style="mystyle">
</div>
<div class="logo-wrapper">
<img
class="logo-image"
:alt="logoalt()"
:src="logoimg()"
:style="mystyle"
>
</div>
</template>
<script lang="ts" src="./logo.ts">
</script>
<script lang="ts" src="./logo.ts"></script>
<style lang="scss" scoped>
@import './logo.scss';
@import './logo.scss';
</style>