Versão 18h39 06/03

This commit is contained in:
Thais Ferreira 2025-03-06 18:40:08 -03:00
parent 20fc4e91f5
commit 3d67602759
8 changed files with 74 additions and 680 deletions

View File

@ -1,33 +0,0 @@
<template>
<v-card
class="pa-4"
:class="{ 'striped-bg': item.striped }"
:color="item.color"
outlined
>
<v-card-text class="text-center text-white text-h6 card">
{{ item.name }}
</v-card-text>
</v-card>
</template>
<script setup>
defineProps({
item: Object,
});
</script>
<style scoped>
.card {
color: #6c00b5!important;
}
.striped-bg {
border-radius: 50px;
background: linear-gradient(145deg, #eeeded, #ffffff);
box-shadow: 20px 20px 60px #d9d9d9,
-20px -20px 60px #ffffff;
}
</style>

View File

@ -1,227 +0,0 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useChatStore
} from '../stores/chatstore';
const chatStore = useChatStore()
// Variáveis de controle do Drawer e do Mini Variant
const isDrawerOpen = ref(true)
const isMiniVariant = ref(false)
const inputMessage = ref('')
// Funções de controle do Drawer
const toggleDrawer = () => {
isDrawerOpen.value = !isDrawerOpen.value
isMiniVariant.value = !isMiniVariant.value
}
// Selecionar um chat da lista
const selectChat = (index) => {
chatStore.selectedChatIndex = index
}
// Criar um novo chat
const createNewChat = () => {
const newChatName = `Chat ${chatStore.chatList.length + 1}`
chatStore.chatList.push({ id: `chat${chatStore.chatList.length + 1}`, name: newChatName, messages: [] })
chatStore.selectedChatIndex = chatStore.chatList.length - 1
}
// Salvar nome do chat
const saveChatName = (index) => {
if (chatStore.chatList[index].name.trim() !== '') {
chatStore.chatList[index].name = chatStore.chatList[index].name.trim()
}
}
// Enviar uma mensagem
const sendMessage = () => {
if (inputMessage.value.trim() !== '') {
chatStore.chatList[chatStore.selectedChatIndex].messages.push({ text: inputMessage.value, isUser: true })
inputMessage.value = ''
setTimeout(() => {
chatStore.chatList[chatStore.selectedChatIndex].messages.push({
text: 'Esta é uma resposta automática.',
isUser: false
})
}, 1000)
}
}
// Carregar os chats do usuário no onMounted
onMounted(async () => {
const userId = 'user123' // Esse id viria do sistema de autenticação
await chatStore.loadChats(userId)
})
</script>
<template>
<v-container fluid no-gutters class="chat">
<!-- Drawer Lateral -->
<v-navigation-drawer v-model="isDrawerOpen" :mini-variant="isMiniVariant" app permanent>
<v-list>
<v-list-item v-if="!isMiniVariant">
<v-row align="center" justify="space-between" style="width: 100%">
<v-col cols="auto">
<v-list-item-title class="text-h6">Chats</v-list-item-title>
</v-col>
<v-col cols="auto">
<v-icon @click="createNewChat" style="padding-left: 25pt;">mdi-chat-plus-outline</v-icon>
</v-col>
</v-row>
</v-list-item>
<!-- Lista de chats -->
<v-list-item v-for="(chat, index) in chatStore.chatList" :key="chat.id" @click="selectChat(index)"
:class="{ 'chat-selected': chatStore.selectedChatIndex === index }" v-if="!isMiniVariant">
<v-list-item-content>
<v-list-item-title>
<v-textarea v-model="chat.name" @focus="chat.isUnderlined = true" @blur="chat.isUnderlined = false"
hide-details variant="plain" class="mr-2" :class="{ 'underline': chat.isUnderlined }"
@keyup.enter="saveChatName(index)" placeholder="Novo nome" auto-grow rows="1" max-rows="5" />
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<!-- Barra de aplicação com o título do chat selecionado -->
<v-app-bar app flat>
<template v-if="isMiniVariant">
<v-btn @click="createNewChat" icon>
<v-icon>mdi-chat-plus-outline</v-icon>
</v-btn>
<v-btn @click="toggleDrawer" icon>
<v-icon>mdi-menu</v-icon>
</v-btn>
<h2 class="text-h5 ml-2">{{ chatStore.chatList[chatStore.selectedChatIndex]?.name }}</h2>
</template>
<template v-else>
<v-btn @click="toggleDrawer" icon>
<v-icon>mdi-menu</v-icon>
</v-btn>
<h2 class="text-h5 ml-2">{{ chatStore.chatList[chatStore.selectedChatIndex]?.name }}</h2>
</template>
</v-app-bar>
<!-- Conteúdo do chat -->
<v-col cols="12" lg="6" xs="10" offset-lg="3" offset-xs="1" class="chat-container">
<div class="chat-messages flex-grow-1 overflow-y-auto">
<v-list>
<v-list-item-group>
<v-list-item v-for="(message, index) in chatStore.chatList[chatStore.selectedChatIndex]?.messages" :key="index">
<v-list-item-content>
<v-row>
<v-col cols="12" v-if="message.isUser">
<v-row justify="end">
<v-col cols="8">
<v-card class="user-message" outlined>
<v-card-text>{{ message.text }}</v-card-text>
</v-card>
</v-col>
</v-row>
</v-col>
<v-col cols="12" v-else>
<v-row justify="start">
<v-col cols="8">
<v-card class="received-message" outlined>
<v-card-text>{{ message.text }}</v-card-text>
</v-card>
</v-col>
</v-row>
</v-col>
</v-row>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</div>
</v-col>
<!-- Barra de entrada para nova mensagem -->
<v-app-bar location="bottom" flat>
<v-row align="center">
<v-col cols="10" lg="6" offset="1" offset-lg="3">
<v-textarea class="input-message" v-model="inputMessage" @keyup.enter="sendMessage"
label="Digite sua mensagem" outlined hide-details prepend-inner-icon="mdi-send"
@click:append-outer="sendMessage" rows="1" />
</v-col>
</v-row>
</v-app-bar>
</v-container>
</template>
<style scoped>
/* Estilo para as mensagens recebidas */
.input-message {
background-color: #f1f1f1;
border-top-left-radius: 16px;
border-bottom-left-radius: 0px;
border-top-right-radius: 16px;
border-bottom-right-radius: 0px;
text-align: center;
margin-bottom: 15pt;
max-width: 100%;
/* Limita para que o texto não ocupe toda a linha */
box-shadow: none;
/* Remove a sombra */
}
/* Estilo para as mensagens do usuário */
.user-message {
background-color: #e3f2fd;
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
border-top-right-radius: 16px;
border-bottom-right-radius: 0px;
text-align: end;
max-width: 100%;
/* Limita para que o texto não ocupe toda a linha */
box-shadow: none;
/* Remove a sombra */
}
/* Estilo para as mensagens recebidas */
.received-message {
background-color: #f1f1f1;
border-top-left-radius: 16px;
border-bottom-left-radius: 0px;
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
text-align: start;
max-width: 100%;
/* Limita para que o texto não ocupe toda a linha */
box-shadow: none;
/* Remove a sombra */
}
.chat-selected {
background-color: #e0f7fa;
}
.v-navigation-drawer {
max-width: 250px;
}
.chat {
padding: 0 !important;
}
.chat-container {
height: calc(80vh - 70px);
}
.chat-messages {
flex-grow: 1;
overflow-y: auto;
}
.underline {
text-decoration: underline;
}
</style>

View File

@ -1,5 +1,9 @@
<template>
<v-navigation-drawer class="body sidebar-navigation" v-model="drawer" app>
<v-navigation-drawer
class="sidebar-navigation"
v-model="drawer"
app
>
<v-list>
<v-list-item
v-for="(item, index) in filteredMenuItems"
@ -8,104 +12,94 @@
exact
class="menu-item"
>
<v-icon>{{ item.icon }}</v-icon>
<!-- Alterado para usar v-list-item-content apenas com texto -->
<v-list-item-content>
<span>{{ item.title }}</span>
</v-list-item-content>
<template v-slot:prepend>
<v-icon>{{ item.icon }}</v-icon>
</template>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-navigation-drawer>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '../stores/auth' // Importa a store de autenticação
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthStore } from '../stores/auth'; // Importa a store de autenticação
const drawer = ref(true)
const router = useRouter()
const authStore = useAuthStore()
const drawer = ref(true);
const router = useRouter();
const authStore = useAuthStore();
// A função getPermissionsByRole retorna as permissões específicas de um papel
// Aqui estamos pegando as permissões para "Dashboard"
const dashboardPermissions = authStore.getPermissionsByRole('Dashboard')
console.log('Permissões do Dashboard:', dashboardPermissions) // Log para verificar as permissões
// Debug: Verificar se a store está sendo carregada corretamente
console.log('Auth Store:', authStore);
console.log('Função getPermissionsByRole:', authStore.getPermissionsByRole);
// Itens do menu, agora com os itens atualizados: home, dashboard, analytics, reports, testing, users
// Obtém as permissões do usuário para "Dashboard"
const dashboardPermissions = authStore.getPermissionsByRole('Dashboard') || [];
console.log('Permissões do Dashboard:', dashboardPermissions); // Log para verificar as permissões
// Itens do menu
const menuItems = [
{ title: 'Home', path: '/dashboard/home', icon: 'mdi mdi-home-circle', requiredPermission: 'read' },
{ title: 'Dashboard', path: '/dashboard', icon: 'mdi mdi-view-dashboard', requiredPermission: 'read' },
{ title: 'Analytics', path: '/dashboard/analytics', icon: 'mdi-chart-box', requiredPermission: 'read' },
{ title: 'Relatórios', path: '/dashboard/reports', icon: 'mdi-file-chart', requiredPermission: 'read' },
{ title: 'Testes', path: '/dashboard/testing', icon: 'mdi-flask', requiredPermission: 'write' },
{ title: 'Gerenciamento de Usuários', path: '/dashboard/users', icon: 'mdi-account-group', requiredPermission: 'write' }
]
{ title: 'Perfil', path: '/dashboard/profile', icon: 'mdi-account', requiredPermission: 'read' },
{ title: 'Configurações', path: '/dashboard/settings', icon: 'mdi-cog', requiredPermission: 'write' },
{ title: 'Usuários', path: '/dashboard/users', icon: 'mdi-account-multiple-outline', requiredPermission: 'write' },
{ title: 'Train', path: '/dashboard/train', icon: 'mdi mdi-thought-bubble', requiredPermission: 'write' },
];
// Função para filtrar os itens de menu com base nas permissões do usuário para 'Dashboard'
// Filtra os itens de menu com base nas permissões do usuário
const filteredMenuItems = computed(() => {
const filteredItems = menuItems.filter(item => dashboardPermissions.includes(item.requiredPermission))
console.log('Itens do Menu Filtrados:', filteredItems) // Log para verificar os itens filtrados
return filteredItems
})
// Função para ativar/desativar o drawer
const toggleDrawer = () => {
drawer.value = !drawer.value
}
const filteredItems = menuItems.filter(item => dashboardPermissions.includes(item.requiredPermission));
console.log('Itens do Menu Filtrados:', filteredItems); // Log para verificar os itens filtrados
return filteredItems.length > 0 ? filteredItems : menuItems; // Exibir todos temporariamente se vazio
});
</script>
<style scoped>
/* Estilo para o menu lateral */
.sidebar-navigation {
background: linear-gradient(145deg, #1a237e 0%, #0d47a1 100%);
}
.v-navigation-drawer {
border-style: none;
border-right: none;
}
/* Estilo para os itens de menu */
.v-list-item {
color: rgba(108, 0, 181);
color: white;
transition: all 0.3s ease;
border-style: solid;
border-radius: 15px;
margin: 8px 0;
margin: 8px 16px;
padding: 10px 16px;
font-weight: 500;
}
.v-list-item:hover {
background-color: #f5f5f5;
color: rgba(76, 201, 240);
border-radius: 15px !important;
background-color: rgba(255, 255, 255, 0.1);
color: #4cc9f0;
margin-left: 25px;
border-radius: 50px;
background: linear-gradient(145deg, #eeeded, #ffffff);
margin-right: 16px;
}
/* Estilo para o item de menu ativo */
.v-list-item--active {
background-color: #4cc9f0 !important;
color: white !important;
border-radius: 15px !important;
margin-left: 25px;
margin-right: 25px;
}
/* Estilo para o conteúdo do item de menu */
.v-list-item-content {
margin-left: 16px;
letter-spacing: 0.5px;
/* Estilo para os ícones */
.v-list-item .v-icon {
margin-right: 16px;
}
/* Estilo para o botão de recolher */
/* Estilo para o botão de recolher (se adicionado futuramente) */
.v-btn {
background: linear-gradient(145deg, #2196f3 0%, #1565c0 100%);
color: white;
}
/* Estilo para o avatar */
/* Estilo para o avatar (se adicionado futuramente) */
.gradient-avatar {
background: linear-gradient(145deg, #2196f3 0%, #1565c0 100%);
}
@ -113,9 +107,11 @@ const toggleDrawer = () => {
.profile-section {
background-color: rgba(255, 255, 255, 0.05);
cursor: pointer;
padding: 16px;
margin-top: auto;
}
.profile-section:hover {
background-color: rgba(0, 0, 0, 0.05);
background-color: rgba(255, 255, 255, 0.1);
}
</style>

View File

@ -8,17 +8,13 @@ import Settings from '../views/Settings.vue'
import Users from '../views/Users.vue'
import UserEditPage from '../views/UserEditPage.vue'
import Train from '../views/Train.vue'
import DashboardView from '../views/DashboardView.vue'
import Chat from '../views/Chat.vue'
import Home from '../views/Home.vue'
import Register from '../views/Register.vue'
const routes = [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/register', component: Register},
{
path: '/dashboard',
@ -30,9 +26,6 @@ const routes = [
{ path: 'settings', name: 'settings', component: Settings },
{ path: 'users', name: 'users', component: Users },
{ path: 'train', name: 'train', component: Train},
{ path: 'dashboardview', name: 'dashboard-view', component: DashboardView},
{ path: 'chat', name: 'chat', component: Chat },
{
path: 'users/edit/:id', // Removido `/` do início para alinhar ao filho de dashboard

View File

@ -1,15 +0,0 @@
<template>
<v-container>
<ChatComponent /> <!-- Adiciona o componente de chat aqui -->
</v-container>
</template>
<script setup>
import ChatComponent from '../components/ChatComponent.vue' // Importa o componente de chat
</script>
<style scoped>
/* Adicione estilos se necessário */
</style>

View File

@ -1,16 +0,0 @@
<template>
<v-container>
<v-row>
<v-col v-for="(item, index) in dashboardStore.items" :key="index" cols="12" md="4">
<CardItem :item="item" />
</v-col>
</v-row>
</v-container>
</template>
<script setup>
import { useDashboardStore } from '../stores/useDashboardStore';
import CardItem from '../components/CardItem.vue'
const dashboardStore = useDashboardStore();
</script>

View File

@ -54,7 +54,7 @@ export default {
return {
quickStats: [
{ title: 'Câmeras Ativas', value: 0, icon: 'mdi-cctv', color: 'success' },
{ title: 'Modelos AI', value: 0, icon: 'mdi-brain', color: 'primary' },
{ title: 'Modelos', value: 0, icon: 'mdi-brain', color: 'primary' },
{ title: 'Alertas 24h', value: 0, icon: 'mdi-bell', color: 'warning' },
{ title: 'Usuários', value: 0, icon: 'mdi-account-group', color: 'info' }
],

View File

@ -1,4 +1,3 @@
<!-- src/views/Login.vue -->
<template>
<div class="login-container">
<div class="login-wrapper">
@ -11,26 +10,11 @@
/>
</div>
<!-- Right Side: Login/Register Form -->
<div class="login-card">
<div class="tab-buttons">
<button
:class="['tab-btn', { active: currentTab === 'login' }]"
@click="currentTab = 'login'"
>
Sign in
</button>
<button
:class="['tab-btn', { active: currentTab === 'register' }]"
@click="currentTab = 'register'"
>
Register
</button>
</div>
<!-- Login Form -->
<div v-if="currentTab === 'login'" class="form-container">
<h3 class="login-title">Bem-vindo</h3> <p class="login-sub-title">Faça login para continuar</p>
<!-- Login Form -->
<div class="login-card">
<div class="form-container">
<h3 class="login-title">Bem-vindo</h3>
<p class="login-sub-title">Faça login para continuar</p>
<form @submit.prevent="handleLogin" class="login-form">
<!-- Email Input -->
@ -87,92 +71,6 @@
</div>
</form>
</div>
<!-- Register Form -->
<div v-if="currentTab === 'register'" class="form-container">
<h3 class="register-title">Criar Conta</h3>
<p class="register-sub-title">Preencha os dados para se registrar</p>
<form @submit.prevent="handleRegister" class="login-form">
<!-- Name Input -->
<div class="form-group">
<label for="register-name">Nome</label>
<input
id="register-name"
v-model="name"
type="text"
placeholder="Digite seu nome completo"
:class="{'input-error': nameError}"
@blur="validateName"
/>
<span v-if="nameError" class="error-message">
{{ nameError }}
</span>
</div>
<!-- Email Input -->
<div class="form-group">
<label for="register-email">Email</label>
<input
id="register-email"
v-model="registerEmail"
type="email"
placeholder="Digite seu email"
:class="{'input-error': registerEmailError}"
@blur="validateRegisterEmail"
/>
<span v-if="registerEmailError" class="error-message">
{{ registerEmailError }}
</span>
</div>
<!-- Password and Confirm Password Inputs (side by side) -->
<div class="password-row">
<!-- Password Input -->
<div class="form-group password-field">
<label for="register-password">Senha</label>
<input
id="register-password"
v-model="registerPassword"
type="password"
placeholder="Digite sua senha"
:class="{'input-error': registerPasswordError}"
@blur="validateRegisterPassword"
/>
<span v-if="registerPasswordError" class="error-message">
{{ registerPasswordError }}
</span>
</div>
<!-- Confirm Password Input -->
<div class="form-group password-field">
<label for="confirm-password">Confirmar Senha</label>
<input
id="confirm-password"
v-model="confirmPassword"
type="password"
placeholder="Confirme sua senha"
:class="{'input-error': confirmPasswordError}"
@blur="validateConfirmPassword"
/>
<span v-if="confirmPasswordError" class="error-message">
{{ confirmPasswordError }}
</span>
</div>
</div>
<!-- Register Button -->
<div class="button-group">
<button
type="submit"
class="btn btn-primary"
:disabled="!isRegisterFormValid"
>
Registrar
</button>
</div>
</form>
</div>
</div>
</div>
</div>
@ -188,25 +86,12 @@ import { useAuthStore } from '../stores/auth'
const router = useRouter()
const authStore = useAuthStore()
// Current tab
const currentTab = ref('login')
// Login Form Fields
const email = ref('')
const password = ref('')
const emailError = ref('')
const passwordError = ref('')
// Register Form Fields
const name = ref('')
const registerEmail = ref('')
const registerPassword = ref('')
const confirmPassword = ref('')
const nameError = ref('')
const registerEmailError = ref('')
const registerPasswordError = ref('')
const confirmPasswordError = ref('')
// Validation Methods - Login
const validateEmail = () => {
const emailRegex = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$|^[a-zA-Z0-9_.-]+$/
@ -233,80 +118,15 @@ const validatePassword = () => {
}
}
// Validation Methods - Register
const validateName = () => {
if (!name.value) {
nameError.value = 'Nome é obrigatório'
return false
} else if (name.value.length < 3) {
nameError.value = 'Nome deve ter pelo menos 3 caracteres'
return false
} else {
nameError.value = ''
return true
}
}
const validateRegisterEmail = () => {
const emailRegex = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/
if (!registerEmail.value) {
registerEmailError.value = 'Email é obrigatório'
return false
} else if (!emailRegex.test(registerEmail.value)) {
registerEmailError.value = 'Formato de email inválido'
return false
} else {
registerEmailError.value = ''
return true
}
}
const validateRegisterPassword = () => {
if (!registerPassword.value) {
registerPasswordError.value = 'Senha é obrigatória'
return false
} else if (registerPassword.value.length < 6) {
registerPasswordError.value = 'Senha deve ter pelo menos 6 caracteres'
return false
} else {
registerPasswordError.value = ''
return true
}
}
const validateConfirmPassword = () => {
if (!confirmPassword.value) {
confirmPasswordError.value = 'Confirme sua senha'
return false
} else if (confirmPassword.value !== registerPassword.value) {
confirmPasswordError.value = 'As senhas não correspondem'
return false
} else {
confirmPasswordError.value = ''
return true
}
}
// Watch for changes to validate in real-time
watch(email, () => { if (email.value) validateEmail() })
watch(password, () => { if (password.value) validatePassword() })
watch(name, () => { if (name.value) validateName() })
watch(registerEmail, () => { if (registerEmail.value) validateRegisterEmail() })
watch(registerPassword, () => { if (registerPassword.value) validateRegisterPassword() })
watch(confirmPassword, () => { if (confirmPassword.value) validateConfirmPassword() })
// Form Validation
const isLoginFormValid = computed(() => {
return email.value && password.value && !emailError.value && !passwordError.value
})
const isRegisterFormValid = computed(() => {
return name.value && registerEmail.value && registerPassword.value &&
confirmPassword.value && !nameError.value && !registerEmailError.value &&
!registerPasswordError.value && !confirmPasswordError.value
})
// Login Handlers
const handleLogin = async () => {
if (isLoginFormValid.value) {
@ -329,29 +149,10 @@ const handleSSO = async () => {
}
}
}
const handleRegister = async () => {
if (isRegisterFormValid.value) {
try {
await authStore.register(name.value, registerEmail.value, registerPassword.value)
alert('Registro realizado com sucesso! Faça login para continuar.')
// Clear register form
name.value = ''
registerEmail.value = ''
registerPassword.value = ''
confirmPassword.value = ''
// Switch to login tab
currentTab.value = 'login'
} catch (error) {
alert('Falha no registro. Por favor, tente novamente.')
}
}
}
</script>
<style scoped>
/* Mantendo os estilos do login */
.login-container {
display: flex;
justify-content: center;
@ -365,7 +166,7 @@ const handleRegister = async () => {
.login-wrapper {
width: 70%;
max-width: 600px; /* Reduzido para focar na área do formulário */
max-width: 600px;
background-color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 20px;
@ -383,11 +184,11 @@ const handleRegister = async () => {
.logo-top {
display: flex;
justify-content: center;
margin-bottom: 0rem;
margin-bottom: 0px;
}
.logo-image {
max-width: 150px;
max-width: 250px;
height: auto;
}
@ -395,99 +196,28 @@ const handleRegister = async () => {
width: 100%;
}
.tab-buttons {
display: flex;
margin-bottom: 2rem;
border-bottom: 1px solid #e5e7eb;
}
.tab-btn {
flex: 1;
background: none;
border: none;
padding: 0.75rem;
cursor: pointer;
color: #6b7280;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
}
.tab-btn.active {
color: #36a8ca;
border-bottom-color: #4cc9f0;
}
.login-title {
text-align: light;
text-align: flex;
color: #2eaacf;
margin-bottom: 0px; /* Aumente esse valor se precisar de mais espaço entre o título e o subtítulo */
font-size: 20px;
text-transform: capitalize;
font-size: 23px;
}
.login-sub-title {
text-align: light;
text-align: flex;
color: #2eaacf;
margin-top: 0; /* Pode ajustar se quiser controlar o espaçamento entre título e subtítulo */
margin-bottom: 20px; /* Ajuste esse valor conforme necessário */
font-size: 15px;
text-transform: lowercase;
}
.register-title {
text-align: light;
color: #2eaacf;
margin-bottom: 0px; /* Aumente esse valor se precisar de mais espaço entre o título e o subtítulo */
font-size: 20px;
text-transform: capitalize;
}
.register-sub-title {
text-align: light;
color: #2eaacf;
margin-top: 0; /* Pode ajustar se quiser controlar o espaçamento entre título e subtítulo */
margin-bottom: 20px; /* Ajuste esse valor conforme necessário */
font-size: 15px;
text-transform: lowercase;
}
.login-form {
display: flex;
flex-direction: column;
margin-bottom: 1rem;
}
.form-group {
margin-bottom: 1rem;
}
/* Estilos para campos de senha lado a lado */
.password-row {
display: flex;
gap: 1rem;
width: 100%;
}
.password-field {
flex: 1;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
color: #4cc9f0;
}
.form-group input {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 25px;
outline: none;
transition: border-color 0.3s;
}
.form-group input:focus {
border-color: #4cc9f0;
}
.input-error {
@ -497,40 +227,27 @@ const handleRegister = async () => {
.error-message {
color: red;
font-size: 0.8rem;
margin-top: 0.25rem;
}
.button-group {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
}
.btn {
padding: 0.75rem;
border: none;
border-radius: 25px;
cursor: pointer;
transition: background-color 0.3s, transform 0.1s;
}
.btn:hover:not(:disabled) {
transform: translateY(-2px);
}
.btn:active:not(:disabled) {
transform: translateY(1px);
margin-top: 0rem;
}
.btn-primary {
padding: 3px;
background-color: #4cc9f0;
color: white;
border-radius: 10px;
}
.btn-secondary {
padding: 3px;
background-color: #f8f9fa;
color: #4cc9f0;
border-radius: 10px;
border: 1px solid #4cc9f0;
}
@ -538,25 +255,4 @@ const handleRegister = async () => {
opacity: 0.6;
cursor: not-allowed;
}
@media (max-width: 768px) {
.login-wrapper {
flex-direction: column;
width: 95%;
}
.logo-section {
padding: 1.5rem;
}
.logo-image {
max-width: 500px;
}
/* Ajuste responsivo para campos de senha em telas pequenas */
.password-row {
flex-direction: column;
gap: 1rem;
}
}
</style>