Compare commits

...

2 Commits

10 changed files with 1655 additions and 407 deletions

View File

@ -0,0 +1,271 @@
/* Utilitários responsivos para melhorar a experiência em diferentes dispositivos */
/* Breakpoints personalizados */
$mobile: 576px;
$tablet: 768px;
$desktop-small: 992px;
$desktop: 1200px;
$desktop-large: 1400px;
/* Utilitários de texto responsivo */
.text-responsive {
@media screen and (max-width: $tablet - 1) {
font-size: 0.9rem !important;
}
@media screen and (max-width: $mobile - 1) {
font-size: 0.85rem !important;
}
}
.heading-responsive {
@media screen and (max-width: $desktop - 1) {
font-size: 1.5rem !important;
}
@media screen and (max-width: $tablet - 1) {
font-size: 1.3rem !important;
}
@media screen and (max-width: $mobile - 1) {
font-size: 1.1rem !important;
}
}
/* Cards responsivos */
.card-responsive {
@media screen and (max-width: $tablet - 1) {
margin-bottom: 1rem;
}
.card-body {
@media screen and (max-width: $tablet - 1) {
padding: 1rem;
}
@media screen and (max-width: $mobile - 1) {
padding: 0.75rem;
}
}
}
/* Botões responsivos */
.btn-responsive {
@media screen and (max-width: $tablet - 1) {
padding: 0.5rem 1rem;
font-size: 0.9rem;
}
@media screen and (max-width: $mobile - 1) {
padding: 0.6rem 1.2rem;
font-size: 0.85rem;
width: 100%;
max-width: 200px;
}
}
/* Tabelas responsivas */
.table-responsive-custom {
@media screen and (max-width: $desktop - 1) {
font-size: 0.9rem;
}
@media screen and (max-width: $tablet - 1) {
font-size: 0.8rem;
th, td {
padding: 0.5rem !important;
}
}
@media screen and (max-width: $mobile - 1) {
font-size: 0.75rem;
th, td {
padding: 0.3rem !important;
}
}
}
/* Formulários responsivos */
.form-responsive {
.form-control {
@media screen and (max-width: $tablet - 1) {
font-size: 0.9rem;
padding: 0.5rem 0.75rem;
}
@media screen and (max-width: $mobile - 1) {
font-size: 0.85rem;
padding: 0.6rem 0.8rem;
}
}
.form-label {
@media screen and (max-width: $tablet - 1) {
font-size: 0.9rem;
margin-bottom: 0.3rem;
}
@media screen and (max-width: $mobile - 1) {
font-size: 0.85rem;
margin-bottom: 0.25rem;
}
}
}
/* Navegação responsiva */
.nav-responsive {
@media screen and (max-width: $tablet - 1) {
.nav-link {
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
}
}
@media screen and (max-width: $mobile - 1) {
.nav-link {
padding: 0.6rem 0.8rem;
font-size: 0.85rem;
}
}
}
/* Modais responsivos */
.modal-responsive {
@media screen and (max-width: $tablet - 1) {
.modal-dialog {
margin: 1rem;
max-width: calc(100% - 2rem);
}
.modal-header {
padding: 1rem;
.modal-title {
font-size: 1.1rem;
}
}
.modal-body {
padding: 1rem;
font-size: 0.9rem;
}
.modal-footer {
padding: 0.75rem 1rem;
}
}
@media screen and (max-width: $mobile - 1) {
.modal-dialog {
margin: 0.5rem;
max-width: calc(100% - 1rem);
}
.modal-header {
padding: 0.75rem;
.modal-title {
font-size: 1rem;
}
}
.modal-body {
padding: 0.75rem;
font-size: 0.85rem;
}
.modal-footer {
padding: 0.5rem 0.75rem;
}
}
}
/* Utilitários de espaçamento responsivo */
.spacing-responsive {
@media screen and (max-width: $desktop - 1) {
margin: 1.5rem 0 !important;
}
@media screen and (max-width: $tablet - 1) {
margin: 1rem 0 !important;
}
@media screen and (max-width: $mobile - 1) {
margin: 0.75rem 0 !important;
}
}
/* Container responsivo personalizado */
.container-responsive {
@media screen and (min-width: $desktop-large) {
max-width: 1320px;
}
@media screen and (min-width: $desktop) and (max-width: $desktop-large - 1) {
max-width: 1140px;
}
@media screen and (min-width: $desktop-small) and (max-width: $desktop - 1) {
max-width: 960px;
}
@media screen and (min-width: $tablet) and (max-width: $desktop-small - 1) {
max-width: 720px;
}
@media screen and (max-width: $tablet - 1) {
padding: 0 1rem;
}
@media screen and (max-width: $mobile - 1) {
padding: 0 0.5rem;
}
}
/* Ocultar/mostrar elementos por breakpoint */
.hide-mobile {
@media screen and (max-width: $tablet - 1) {
display: none !important;
}
}
.hide-tablet {
@media screen and (min-width: $tablet) and (max-width: $desktop - 1) {
display: none !important;
}
}
.hide-desktop {
@media screen and (min-width: $desktop) {
display: none !important;
}
}
.show-mobile-only {
display: none !important;
@media screen and (max-width: $tablet - 1) {
display: block !important;
}
}
.show-tablet-only {
display: none !important;
@media screen and (min-width: $tablet) and (max-width: $desktop - 1) {
display: block !important;
}
}
/* Ajustes específicos para touch devices */
@media (hover: none) and (pointer: coarse) {
.btn, .sidebar-link, .nav-link {
min-height: 44px; /* Tamanho mínimo recomendado para touch */
}
.form-control {
min-height: 44px;
}
}

View File

@ -1,9 +1,10 @@
@mixin sidebar-active { @mixin sidebar-active($sidebar-width: 300px) {
.sidebar-wrapper { .sidebar-wrapper {
left: 0; left: 0;
width: $sidebar-width;
} }
& ~ #main { & ~ #main {
margin-left: 300px; margin-left: $sidebar-width;
} }
} }
@mixin sidebar-inactive { @mixin sidebar-inactive {
@ -18,8 +19,36 @@
#sidebar { #sidebar {
@include sidebar-inactive(); @include sidebar-inactive();
@media screen and (min-width: 1200px) { // Desktop grande (1920px+)
@include sidebar-active(); @media screen and (min-width: 1400px) {
@include sidebar-active(300px);
}
// Desktop padrão (1200px-1399px)
@media screen and (min-width: 1200px) and (max-width: 1399px) {
@include sidebar-active(280px);
}
// Tablet grande (992px-1199px)
@media screen and (min-width: 992px) and (max-width: 1199px) {
@include sidebar-active(260px);
}
// Tablet (768px-991px) - sidebar colapsada por padrão
@media screen and (min-width: 768px) and (max-width: 991px) {
@include sidebar-inactive();
&.active {
.sidebar-wrapper {
left: 0;
width: 280px;
z-index: 1050;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
}
& ~ #main {
margin-left: 0;
}
}
} }
&.inactive { &.inactive {
@ -42,21 +71,56 @@
overflow-y: auto; overflow-y: auto;
background-color: $sidebar-bg; background-color: $sidebar-bg;
bottom: 0; bottom: 0;
transition: left .7s cubic-bezier(0.22, 1, 0.36, 1); transition: left .7s cubic-bezier(0.22, 1, 0.36, 1), width .3s ease;
// Responsividade da largura
@media screen and (min-width: 1200px) and (max-width: 1399px) {
width: 280px;
}
@media screen and (min-width: 992px) and (max-width: 1199px) {
width: 260px;
}
@media screen and (max-width: 991px) {
width: 280px;
z-index: 1050;
}
.sidebar-header { .sidebar-header {
padding: 2rem 2rem 1rem; padding: 2rem 1.5rem 1rem;
font-size: 2rem; font-size: 1.8rem;
font-weight: bold; font-weight: bold;
// Responsividade do header
@media screen and (max-width: 1199px) {
padding: 1.5rem 1rem 0.5rem;
font-size: 1.6rem;
}
@media screen and (max-width: 767px) {
padding: 1rem 1rem 0.5rem;
font-size: 1.4rem;
}
img { img {
height: 1.2rem; height: 1.2rem;
@media screen and (max-width: 767px) {
height: 1rem;
}
} }
} }
.sidebar-toggler.x { .sidebar-toggler.x {
position: absolute; position: absolute;
right: 1.75rem; right: 1.75rem;
top: .25rem; top: .25rem;
display:none; display: none;
@media screen and (max-width: 991px) {
right: 1rem;
top: 0.5rem;
}
} }
.menu { .menu {
@ -64,6 +128,18 @@
margin-top: 2rem; margin-top: 2rem;
padding: 0 2rem; padding: 0 2rem;
font-weight: 600; font-weight: 600;
// Responsividade do menu
@media screen and (max-width: 1199px) {
padding: 0 1.5rem;
margin-top: 1.5rem;
}
@media screen and (max-width: 767px) {
padding: 0 1rem;
margin-top: 1rem;
}
.sidebar-title { .sidebar-title {
padding: 0 1rem; padding: 0 1rem;
margin: 1.5rem 0 1rem; margin: 1.5rem 0 1rem;
@ -71,6 +147,18 @@
list-style: none; list-style: none;
font-weight: 600; font-weight: 600;
color: $sidebar-link-color; color: $sidebar-link-color;
@media screen and (max-width: 1199px) {
margin: 1rem 0 0.5rem;
font-size: 0.9rem;
padding: 0 0.5rem;
}
@media screen and (max-width: 767px) {
margin: 0.8rem 0 0.4rem;
font-size: 0.85rem;
padding: 0 0.3rem;
}
} }
.sidebar-link { .sidebar-link {
@ -83,14 +171,39 @@
transition: all .5s; transition: all .5s;
text-decoration: none; text-decoration: none;
color: $sidebar-link-color; color: $sidebar-link-color;
// Responsividade dos links
@media screen and (max-width: 1199px) {
padding: 0.6rem 0.8rem;
font-size: 0.9rem;
}
@media screen and (max-width: 767px) {
padding: 0.8rem 0.6rem;
font-size: 0.85rem;
}
svg,i { svg,i {
color:#7c8db5; color:#7c8db5;
flex-shrink: 0;
@media screen and (max-width: 767px) {
font-size: 1.1em;
}
} }
i:before { i:before {
vertical-align: top; vertical-align: top;
} }
span { span {
margin-left: 1rem; margin-left: 1rem;
@media screen and (max-width: 1199px) {
margin-left: 0.8rem;
}
@media screen and (max-width: 767px) {
margin-left: 0.6rem;
}
} }
&:hover { &:hover {
background-color: $sidebar-link-hover-bg; background-color: $sidebar-link-hover-bg;
@ -192,15 +305,80 @@
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
z-index: 9; z-index: 9;
} }
// Media queries para diferentes dispositivos
@media screen and (max-width: 1199px) { @media screen and (max-width: 1199px) {
.sidebar-wrapper { .sidebar-wrapper {
position: fixed; position: fixed;
left: -300px; left: -300px;
.sidebar-toggler.x { .sidebar-toggler.x {
display:block; display: block;
} }
} }
} }
// Tablet específico
@media screen and (min-width: 768px) and (max-width: 991px) {
.sidebar-wrapper {
left: -280px;
.menu {
.sidebar-link {
padding: 0.7rem 0.8rem;
}
}
}
#sidebar.active ~ #main {
margin-left: 0 !important;
}
}
// Mobile específico
@media screen and (max-width: 767px) {
.sidebar-wrapper {
left: -280px;
width: 280px !important;
.sidebar-header {
.logo h1 {
font-size: 1.3rem;
}
}
.menu {
.sidebar-link {
padding: 0.9rem 0.7rem;
span {
font-size: 0.9rem;
}
}
.submenu {
.submenu-item a {
padding: 0.6rem 1.5rem;
font-size: 0.8rem;
}
}
}
}
#sidebar.active ~ #main {
margin-left: 0 !important;
}
// Backdrop para mobile
#sidebar.active::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1040;
}
}
@keyframes slideDown { @keyframes slideDown {
from { from {
max-height: 0; max-height: 0;

View File

@ -0,0 +1,338 @@
/* Melhorias de responsividade para tabelas e componentes de dados */
/* Tabelas responsivas melhoradas */
.table-responsive-enhanced {
@media screen and (max-width: 1199px) {
font-size: 0.9rem;
th, td {
padding: 0.6rem 0.5rem !important;
}
}
@media screen and (max-width: 991px) {
font-size: 0.85rem;
th, td {
padding: 0.5rem 0.4rem !important;
}
/* Ocultar colunas menos importantes em tablet */
.hide-tablet {
display: none !important;
}
}
@media screen and (max-width: 767px) {
font-size: 0.8rem;
th, td {
padding: 0.4rem 0.3rem !important;
}
/* Ocultar mais colunas em mobile */
.hide-mobile {
display: none !important;
}
/* Estilo de card para mobile */
&.table-card-mobile {
thead {
display: none;
}
tbody tr {
display: block;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
margin-bottom: 1rem;
padding: 0.75rem;
background: white;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}
tbody td {
display: block;
border: none;
padding: 0.25rem 0 !important;
text-align: left !important;
&:before {
content: attr(data-label) ": ";
font-weight: bold;
color: #495057;
}
&:last-child {
border-bottom: none;
}
}
}
}
@media screen and (max-width: 576px) {
font-size: 0.75rem;
th, td {
padding: 0.3rem 0.2rem !important;
}
}
}
/* Cards responsivos para dados */
.data-card-responsive {
@media screen and (max-width: 991px) {
margin-bottom: 1rem;
.card-header {
padding: 0.75rem 1rem;
h5, h6 {
font-size: 1rem;
margin-bottom: 0;
}
}
.card-body {
padding: 1rem;
}
}
@media screen and (max-width: 767px) {
.card-header {
padding: 0.5rem 0.75rem;
h5, h6 {
font-size: 0.9rem;
}
}
.card-body {
padding: 0.75rem;
font-size: 0.9rem;
}
}
@media screen and (max-width: 576px) {
.card-header {
padding: 0.5rem;
h5, h6 {
font-size: 0.85rem;
}
}
.card-body {
padding: 0.5rem;
font-size: 0.85rem;
}
}
}
/* Paginação responsiva */
.pagination-responsive {
@media screen and (max-width: 767px) {
.page-item {
&:not(.active):not(.disabled) {
&:nth-child(n+4):nth-last-child(n+4) {
display: none;
}
}
}
.page-link {
padding: 0.5rem 0.75rem;
font-size: 0.875rem;
}
}
@media screen and (max-width: 576px) {
justify-content: center;
.page-item {
&:not(.active):not(.disabled) {
&:nth-child(n+3):nth-last-child(n+3) {
display: none;
}
}
}
.page-link {
padding: 0.4rem 0.6rem;
font-size: 0.8rem;
}
}
}
/* Filtros e controles responsivos */
.filters-responsive {
@media screen and (max-width: 991px) {
.row {
margin-bottom: 1rem;
}
.col-md-3, .col-md-4, .col-md-6 {
margin-bottom: 0.5rem;
}
}
@media screen and (max-width: 767px) {
.form-control, .form-select {
font-size: 0.9rem;
padding: 0.5rem 0.75rem;
}
.btn {
font-size: 0.9rem;
padding: 0.5rem 1rem;
width: 100%;
margin-bottom: 0.5rem;
}
}
@media screen and (max-width: 576px) {
.form-control, .form-select {
font-size: 0.85rem;
padding: 0.6rem 0.8rem;
}
.btn {
font-size: 0.85rem;
padding: 0.6rem 1rem;
}
}
}
/* Stats cards responsivos */
.stats-card-responsive {
@media screen and (max-width: 1199px) {
.card-body {
padding: 1.25rem 1rem;
}
h3, h4 {
font-size: 1.5rem;
}
.stats-icon {
width: 3rem;
height: 3rem;
}
}
@media screen and (max-width: 991px) {
margin-bottom: 1rem;
.card-body {
padding: 1rem 0.75rem;
}
h3, h4 {
font-size: 1.3rem;
}
.stats-icon {
width: 2.5rem;
height: 2.5rem;
}
}
@media screen and (max-width: 767px) {
.card-body {
padding: 0.75rem;
text-align: center;
}
h3, h4 {
font-size: 1.2rem;
}
.stats-icon {
width: 2rem;
height: 2rem;
margin: 0 auto 0.5rem;
}
p, small {
font-size: 0.85rem;
}
}
@media screen and (max-width: 576px) {
.card-body {
padding: 0.5rem;
}
h3, h4 {
font-size: 1.1rem;
}
.stats-icon {
width: 1.8rem;
height: 1.8rem;
}
p, small {
font-size: 0.8rem;
}
}
}
/* Breadcrumb responsivo */
.breadcrumb-responsive {
@media screen and (max-width: 767px) {
font-size: 0.85rem;
padding: 0.5rem 0;
.breadcrumb-item {
&:not(:last-child) {
&:nth-child(n+2):nth-last-child(n+2) {
display: none;
}
&:nth-last-child(2):before {
content: "... / ";
}
}
}
}
@media screen and (max-width: 576px) {
font-size: 0.8rem;
.breadcrumb-item {
&:not(:last-child):not(:first-child) {
display: none;
}
&:first-child:not(:last-child):after {
content: " / ...";
}
}
}
}
/* Alertas responsivos */
.alert-responsive {
@media screen and (max-width: 767px) {
padding: 0.75rem;
font-size: 0.9rem;
.alert-heading {
font-size: 1.1rem;
}
}
@media screen and (max-width: 576px) {
padding: 0.5rem;
font-size: 0.85rem;
.alert-heading {
font-size: 1rem;
}
.btn-close {
padding: 0.25rem;
}
}
}

View File

@ -2,12 +2,41 @@
margin-left: 300px; margin-left: 300px;
padding: 2rem; padding: 2rem;
min-height: 100vh; min-height: 100vh;
@media screen and (max-width: 1199px) { transition: margin-left .7s cubic-bezier(0.22, 1, 0.36, 1);
margin-left: 0;
// Responsividade do layout principal
@media screen and (min-width: 1400px) {
margin-left: 300px;
padding: 2rem;
} }
@media screen and (min-width: 1200px) and (max-width: 1399px) {
margin-left: 280px;
padding: 1.5rem;
}
@media screen and (min-width: 992px) and (max-width: 1199px) {
margin-left: 260px;
padding: 1.5rem;
}
@media screen and (min-width: 768px) and (max-width: 991px) {
margin-left: 0;
padding: 1rem;
}
@media screen and (max-width: 767px) {
margin-left: 0;
padding: 1rem 0.5rem;
}
&.layout-navbar { &.layout-navbar {
padding: 0; padding: 0;
transition: margin-left .7s cubic-bezier(0.22, 1, 0.36, 1) transition: margin-left .7s cubic-bezier(0.22, 1, 0.36, 1);
@media screen and (max-width: 767px) {
padding: 0;
}
} }
&.layout-horizontal { &.layout-horizontal {
padding: 0; padding: 0;
@ -15,6 +44,14 @@
} }
#main-content { #main-content {
padding: 2rem; padding: 2rem;
@media screen and (max-width: 1199px) {
padding: 1.5rem;
}
@media screen and (max-width: 767px) {
padding: 1rem;
}
} }
} }
#main, #main-content { #main, #main-content {
@ -25,9 +62,26 @@
flex-grow: 1; flex-grow: 1;
} }
.page-heading { .page-heading {
margin: 0 0 2rem; margin: 0 0 2rem;
@media screen and (max-width: 1199px) {
margin: 0 0 1.5rem;
}
@media screen and (max-width: 767px) {
margin: 0 0 1rem;
}
h3 { h3 {
font-weight: bold; font-weight: bold;
@media screen and (max-width: 1199px) {
font-size: 1.5rem;
}
@media screen and (max-width: 767px) {
font-size: 1.3rem;
}
} }
} }
.page-title-headings { .page-title-headings {
@ -35,12 +89,28 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: .5rem; margin-bottom: .5rem;
@media screen and (max-width: 767px) {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
h3 { h3 {
margin-bottom: 0; margin-bottom: 0;
margin-right: 1rem; margin-right: 1rem;
@media screen and (max-width: 767px) {
margin-right: 0;
font-size: 1.2rem;
}
} }
.breadcrumb { .breadcrumb {
margin-bottom: 0; margin-bottom: 0;
@media screen and (max-width: 767px) {
font-size: 0.85rem;
}
} }
} }
a { a {

View File

@ -38,6 +38,8 @@
@import 'components/progress'; @import 'components/progress';
@import 'components/sidebar'; @import 'components/sidebar';
@import 'components/table'; @import 'components/table';
@import 'components/responsive';
@import 'components/tables-responsive';
// Layout (se tiver arquivos, mas você mencionou que tem main.scss aqui) // Layout (se tiver arquivos, mas você mencionou que tem main.scss aqui)
@import 'layouts/main'; @import 'layouts/main';

View File

@ -30,13 +30,60 @@ body {
} }
} }
@media screen and (max-width: 1399.9px) { @media screen and (max-width: 1399.9px) {
padding: 3rem ; padding: 3rem;
.auth-title {
font-size: 3rem;
}
.auth-subtitle {
font-size: 1.4rem;
line-height: 2rem;
}
.auth-logo {
margin-bottom: 5rem;
}
}
@media screen and (max-width: 991px) {
padding: 2.5rem;
.auth-title {
font-size: 2.5rem;
}
.auth-subtitle {
font-size: 1.2rem;
line-height: 1.8rem;
}
.auth-logo {
margin-bottom: 3rem;
}
} }
@media screen and (max-width: 767px) { @media screen and (max-width: 767px) {
padding: 5rem ; padding: 2rem;
.auth-title {
font-size: 2rem;
}
.auth-subtitle {
font-size: 1rem;
line-height: 1.5rem;
}
.auth-logo {
margin-bottom: 2rem;
}
} }
@media screen and (max-width: 576px) { @media screen and (max-width: 576px) {
padding: 5rem 3rem; padding: 1.5rem 1rem;
.auth-title {
font-size: 1.8rem;
}
.auth-subtitle {
font-size: 0.9rem;
line-height: 1.4rem;
}
.auth-logo {
margin-bottom: 1.5rem;
}
} }
} }
} }
@ -61,3 +108,60 @@ html[data-bs-theme="dark"] {
} }
} }
} }
/* Melhorias específicas para responsividade do login */
.card-position {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 1rem;
@media screen and (max-width: 768px) {
padding: 0.5rem;
align-items: flex-start;
padding-top: 2rem;
}
@media screen and (max-width: 576px) {
padding: 0.25rem;
padding-top: 1rem;
}
.card {
width: 100%;
max-width: 500px;
@media screen and (max-width: 576px) {
margin: 0;
border-radius: 0.5rem;
}
}
}
/* Melhorias para formulários de autenticação */
.form-control-xl {
@media screen and (max-width: 768px) {
padding: 0.75rem 1rem;
font-size: 1rem;
}
@media screen and (max-width: 576px) {
padding: 0.8rem 1rem;
font-size: 0.9rem;
}
}
.btn-block {
@media screen and (max-width: 576px) {
padding: 0.8rem 1rem;
font-size: 1rem;
}
}
/* Ajustes para ícones em campos de formulário */
.form-control-icon {
@media screen and (max-width: 576px) {
left: 0.8rem;
}
}

View File

@ -0,0 +1,86 @@
import React from 'react';
const MobileMenuToggle = ({ isOpen, onToggle, className = '' }) => {
return (
<button
type="button"
className={`mobile-menu-toggle btn btn-outline-primary d-lg-none ${className}`}
onClick={onToggle}
aria-label={isOpen ? 'Fechar menu' : 'Abrir menu'}
aria-expanded={isOpen}
style={{
position: 'fixed',
top: '1rem',
left: '1rem',
zIndex: 1060,
width: '3rem',
height: '3rem',
padding: 0,
border: '2px solid #435ebe',
borderRadius: '0.375rem',
backgroundColor: 'white',
boxShadow: '0 0.125rem 0.25rem rgba(0, 0, 0, 0.075)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.3s ease'
}}
>
<div
className="hamburger-icon"
style={{
width: '1.5rem',
height: '1.2rem',
position: 'relative',
transform: isOpen ? 'rotate(45deg)' : 'none',
transition: 'transform 0.3s ease'
}}
>
<span
style={{
display: 'block',
position: 'absolute',
height: '2px',
width: '100%',
backgroundColor: '#435ebe',
borderRadius: '1px',
opacity: isOpen ? 0 : 1,
left: 0,
top: '0.25rem',
transition: 'all 0.3s ease'
}}
/>
<span
style={{
display: 'block',
position: 'absolute',
height: '2px',
width: '100%',
backgroundColor: '#435ebe',
borderRadius: '1px',
left: 0,
top: '0.5rem',
transform: isOpen ? 'rotate(90deg)' : 'none',
transition: 'all 0.3s ease'
}}
/>
<span
style={{
display: 'block',
position: 'absolute',
height: '2px',
width: '100%',
backgroundColor: '#435ebe',
borderRadius: '1px',
opacity: isOpen ? 0 : 1,
left: 0,
top: '0.75rem',
transition: 'all 0.3s ease'
}}
/>
</div>
</button>
);
};
export default MobileMenuToggle;

View File

@ -1,271 +1,287 @@
import React, { useState } from "react"; import React, { useState, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import menuItems from "../data/sidebar-items-medico.json";
import TrocardePerfis from "./TrocardePerfis"; import TrocardePerfis from "./TrocardePerfis";
import MobileMenuToggle from "./MobileMenuToggle";
function Sidebar({ menuItems }) { function Sidebar({ menuItems }) {
const [isActive, setIsActive] = useState(true); const [isActive, setIsActive] = useState(true);
const [openSubmenu, setOpenSubmenu] = useState(null); const [openSubmenu, setOpenSubmenu] = useState(null);
const [showLogoutModal, setShowLogoutModal] = useState(false); const [isMobile, setIsMobile] = useState(false);
const navigate = useNavigate(); const [showLogoutModal, setShowLogoutModal] = useState(false);
const navigate = useNavigate();
const toggleSidebar = () => { // Detecta se é mobile/tablet
setIsActive(!isActive); useEffect(() => {
const checkScreenSize = () => {
const mobile = window.innerWidth < 992;
setIsMobile(mobile);
setIsActive(!mobile);
}; };
const handleSubmenuClick = (submenuName) => { checkScreenSize();
setOpenSubmenu(openSubmenu === submenuName ? null : submenuName); window.addEventListener("resize", checkScreenSize);
}; return () => window.removeEventListener("resize", checkScreenSize);
}, []);
const handleLogoutClick = () => { const toggleSidebar = () => setIsActive(!isActive);
setShowLogoutModal(true); const handleSubmenuClick = (submenuName) =>
}; setOpenSubmenu(openSubmenu === submenuName ? null : submenuName);
const handleLogoutConfirm = async () => { const handleLogoutClick = () => setShowLogoutModal(true);
try {
const token = localStorage.getItem('token') ||
localStorage.getItem('authToken') ||
localStorage.getItem('userToken') ||
localStorage.getItem('access_token') ||
sessionStorage.getItem('token') ||
sessionStorage.getItem('authToken');
if (token) { const handleLogoutConfirm = async () => {
const response = await fetch('https://mock.apidog.com/m1/1053378-0-default/auth/v1/logout', { try {
method: 'POST', const token =
headers: { localStorage.getItem("token") ||
'Content-Type': 'application/json', localStorage.getItem("authToken") ||
'Authorization': `Bearer ${token}` localStorage.getItem("userToken") ||
} localStorage.getItem("access_token") ||
}); sessionStorage.getItem("token") ||
sessionStorage.getItem("authToken");
if (response.status === 204) { if (token) {
console.log('Logout realizado com sucesso'); const response = await fetch(
} else if (response.status === 401) { "https://mock.apidog.com/m1/1053378-0-default/auth/v1/logout",
console.log('Token inválido ou expirado'); {
} else { method: "POST",
try { headers: {
const errorData = await response.json(); "Content-Type": "application/json",
console.error('Erro no logout:', errorData); Authorization: `Bearer ${token}`,
} catch { },
console.error('Erro no logout - status:', response.status); }
}
}
}
clearAuthData();
navigate('/login');
} catch (error) {
console.error('Erro durante logout:', error);
clearAuthData();
navigate('/login');
} finally {
setShowLogoutModal(false);
}
};
const clearAuthData = () => {
localStorage.removeItem('token');
localStorage.removeItem('authToken');
localStorage.removeItem('userToken');
localStorage.removeItem('access_token');
localStorage.removeItem('user');
localStorage.removeItem('auth');
localStorage.removeItem('userData');
sessionStorage.removeItem('token');
sessionStorage.removeItem('authToken');
sessionStorage.removeItem('userToken');
sessionStorage.removeItem('access_token');
sessionStorage.removeItem('user');
sessionStorage.removeItem('auth');
sessionStorage.removeItem('userData');
if (window.caches) {
caches.keys().then(names => {
names.forEach(name => {
if (name.includes('auth') || name.includes('api')) {
caches.delete(name);
}
});
});
}
};
const handleLogoutCancel = () => {
setShowLogoutModal(false);
};
const renderLink = (item) => {
if (item.url && item.url.startsWith("/")) {
return (
<Link to={item.url} className="sidebar-link">
{item.icon && <i className={`bi bi-${item.icon}`}></i>}
<span>{item.name}</span>
</Link>
);
}
return (
<a
href={item.url}
className="sidebar-link"
target="_blank"
rel="noreferrer"
>
{item.icon && <i className={`bi bi-${item.icon}`}></i>}
<span>{item.name}</span>
</a>
); );
};
if (response.status === 204) console.log("Logout realizado com sucesso");
else if (response.status === 401) console.log("Token inválido ou expirado");
else {
try {
const errorData = await response.json();
console.error("Erro no logout:", errorData);
} catch {
console.error("Erro no logout - status:", response.status);
}
}
}
clearAuthData();
navigate("/login");
} catch (error) {
console.error("Erro durante logout:", error);
clearAuthData();
navigate("/login");
} finally {
setShowLogoutModal(false);
}
};
const clearAuthData = () => {
["token","authToken","userToken","access_token","user","auth","userData"].forEach(key => {
localStorage.removeItem(key);
sessionStorage.removeItem(key);
});
if (window.caches) {
caches.keys().then(names => {
names.forEach(name => {
if (name.includes("auth") || name.includes("api")) caches.delete(name);
});
});
}
};
const handleLogoutCancel = () => setShowLogoutModal(false);
const renderLink = (item) => {
if (item.url && item.url.startsWith("/")) {
return (
<Link to={item.url} className="sidebar-link">
{item.icon && <i className={`bi bi-${item.icon}`}></i>}
<span>{item.name}</span>
</Link>
);
}
return ( return (
<> <a href={item.url} className="sidebar-link" target="_blank" rel="noreferrer">
{showLogoutModal && ( {item.icon && <i className={`bi bi-${item.icon}`}></i>}
<div className="modal-overlay" style={{ <span>{item.name}</span>
position: 'fixed', </a>
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
zIndex: 9999
}}>
<div className="modal-content" style={{
backgroundColor: 'white',
padding: '2rem',
borderRadius: '8px',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
maxWidth: '400px',
width: '90%'
}}>
<h3 style={{ marginBottom: '1rem' }}>Confirmar Logout</h3>
<p style={{ marginBottom: '2rem' }}>Tem certeza que deseja encerrar a sessão?</p>
<div style={{ display: 'flex', gap: '1rem', justifyContent: 'flex-end' }}>
<button
onClick={handleLogoutCancel}
style={{
padding: '0.5rem 1rem',
border: '1px solid #ccc',
borderRadius: '4px',
backgroundColor: 'transparent',
cursor: 'pointer'
}}
>
Cancelar
</button>
<button
onClick={handleLogoutConfirm}
style={{
padding: '0.5rem 1rem',
border: 'none',
borderRadius: '4px',
backgroundColor: '#dc3545',
color: 'white',
cursor: 'pointer'
}}
>
Sair
</button>
</div>
</div>
</div>
)}
<div id="sidebar" className={isActive ? "active" : ""}>
<div className="sidebar-wrapper active">
<div className="sidebar-header">
<div className="d-flex justify-content-between">
<div className="logo">
<Link to="/">
<h1>MediConnect</h1>
</Link>
</div>
<div className="toggler">
<button
type="button"
className="sidebar-hide d-xl-none d-block btn"
onClick={toggleSidebar}
>
<i className="bi bi-x bi-middle"></i>
</button>
</div>
</div>
</div>
<div className="sidebar-menu">
<ul className="menu">
{menuItems && menuItems.map((item, index) => {
if (item.isTitle) {
return (
<li key={index} className="sidebar-title">
{item.name}
</li>
);
}
if (item.submenu) {
return (
<li
key={index}
className={`sidebar-item has-sub ${openSubmenu === item.key ? "active" : ""
}`}
>
<button
type="button"
className="sidebar-link btn"
onClick={() => handleSubmenuClick(item.key)}
>
<i className={`bi bi-${item.icon}`}></i>
<span>{item.name}</span>
</button>
<ul
className={`submenu ${openSubmenu === item.key ? "active" : ""
}`}
>
{item.submenu.map((subItem, subIndex) => (
<li key={subIndex} className="submenu-item">
{renderLink(subItem)}
</li>
))}
</ul>
</li>
);
}
return (
<li key={index} className="sidebar-item">
{renderLink(item)}
</li>
);
})}
<li className="sidebar-item">
<button
type="button"
className="sidebar-link btn"
onClick={handleLogoutClick}
>
<i className="bi bi-box-arrow-right"></i>
<span>Sair (Logout)</span>
</button>
</li>
<TrocardePerfis />
</ul>
</div>
<button className="sidebar-toggler btn x" onClick={toggleSidebar}>
<i data-feather="x"></i>
</button>
</div>
</div>
</>
); );
};
return (
<>
{/* Toggle e backdrop para mobile */}
{isMobile && <MobileMenuToggle isOpen={isActive} onToggle={toggleSidebar} />}
{isMobile && isActive && (
<div
className="sidebar-backdrop"
onClick={toggleSidebar}
style={{
position: "fixed",
top: 0,
left: 0,
width: "100vw",
height: "100vh",
backgroundColor: "rgba(0,0,0,0.5)",
zIndex: 1040,
}}
/>
)}
{/* Modal de Logout */}
{showLogoutModal && (
<div
className="modal-overlay"
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(0,0,0,0.5)",
display: "flex",
justifyContent: "center",
alignItems: "center",
zIndex: 9999,
}}
>
<div
className="modal-content"
style={{
backgroundColor: "white",
padding: "2rem",
borderRadius: "8px",
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
maxWidth: "400px",
width: "90%",
}}
>
<h3 style={{ marginBottom: "1rem" }}>Confirmar Logout</h3>
<p style={{ marginBottom: "2rem" }}>Tem certeza que deseja encerrar a sessão?</p>
<div style={{ display: "flex", gap: "1rem", justifyContent: "flex-end" }}>
<button
onClick={handleLogoutCancel}
style={{
padding: "0.5rem 1rem",
border: "1px solid #ccc",
borderRadius: "4px",
backgroundColor: "transparent",
cursor: "pointer",
}}
>
Cancelar
</button>
<button
onClick={handleLogoutConfirm}
style={{
padding: "0.5rem 1rem",
border: "none",
borderRadius: "4px",
backgroundColor: "#dc3545",
color: "white",
cursor: "pointer",
}}
>
Sair
</button>
</div>
</div>
</div>
)}
{/* Sidebar */}
<div id="sidebar" className={isActive ? "active" : ""}>
<div className="sidebar-wrapper active">
<div className="sidebar-header">
<div className="d-flex justify-content-between">
<div className="logo">
<Link to="/">
<h1>MediConnect</h1>
</Link>
</div>
<div className="toggler">
<button
type="button"
className="sidebar-hide d-xl-none d-block btn"
onClick={toggleSidebar}
>
<i className="bi bi-x bi-middle"></i>
</button>
</div>
</div>
</div>
<div className="sidebar-menu">
<ul className="menu">
{menuItems &&
menuItems.map((item, index) => {
if (item.isTitle)
return (
<li key={index} className="sidebar-title">
{item.name}
</li>
);
if (item.submenu)
return (
<li
key={index}
className={`sidebar-item has-sub ${
openSubmenu === item.key ? "active" : ""
}`}
>
<button
type="button"
className="sidebar-link btn"
onClick={() => handleSubmenuClick(item.key)}
>
<i className={`bi bi-${item.icon}`}></i>
<span>{item.name}</span>
</button>
<ul
className={`submenu ${
openSubmenu === item.key ? "active" : ""
}`}
>
{item.submenu.map((subItem, subIndex) => (
<li key={subIndex} className="submenu-item">
{renderLink(subItem)}
</li>
))}
</ul>
</li>
);
return (
<li key={index} className="sidebar-item">
{renderLink(item)}
</li>
);
})}
{/* Logout */}
<li className="sidebar-item">
<button
type="button"
className="sidebar-link btn"
onClick={handleLogoutClick}
>
<i className="bi bi-box-arrow-right"></i>
<span>Sair (Logout)</span>
</button>
</li>
<TrocardePerfis />
</ul>
</div>
<button className="sidebar-toggler btn x" onClick={toggleSidebar}>
<i data-feather="x"></i>
</button>
</div>
</div>
</>
);
} }
export default Sidebar; export default Sidebar;

View File

@ -1,19 +1,19 @@
import React, { useState, useEffect, use } from 'react'; import React, { useState, useEffect, use } from "react";
import {Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { useAuth } from '../components/utils/AuthProvider'; import { useAuth } from "../components/utils/AuthProvider";
import API_KEY from '../components/utils/apiKeys'; import API_KEY from "../components/utils/apiKeys";
import { UserInfos } from '../components/utils/Functions-Endpoints/General'; import { UserInfos } from "../components/utils/Functions-Endpoints/General";
function Login({ onEnterSystem }) { function Login({ onEnterSystem }) {
const {setAuthTokens } = useAuth(); const { setAuthTokens } = useAuth();
const navigate = useNavigate(); const navigate = useNavigate();
const [form, setForm] = useState({ const [form, setForm] = useState({
username: "", username: "",
password: "" password: "",
}); });
const [alert, setAlert] = useState(""); const [alert, setAlert] = useState("");
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
/* /*
useEffect(async () => { useEffect(async () => {
var myHeaders = new Headers(); var myHeaders = new Headers();
@ -64,7 +64,7 @@ function Login({ onEnterSystem }) {
.then(result => console.log(result)) .then(result => console.log(result))
.catch(error => console.log('error', error));*/ .catch(error => console.log('error', error));*/
/* var myHeaders = new Headers(); /* var myHeaders = new Headers();
myHeaders.append("Authorization", `Bearer ${data.access_token}`); myHeaders.append("Authorization", `Bearer ${data.access_token}`);
myHeaders.append("apikey", API_KEY); myHeaders.append("apikey", API_KEY);
var requestOptions = { var requestOptions = {
@ -80,83 +80,82 @@ function Login({ onEnterSystem }) {
} }
}, []);*/ }, []);*/
const handleChange = (e) => { const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value }); setForm({ ...form, [e.target.name]: e.target.value });
}; };
const handleLogin = async (e) => { const handleLogin = async (e) => {
e.preventDefault(); e.preventDefault();
console.log("Tentando logar com:", form); console.log("Tentando logar com:", form);
if (form.username && form.password) { if (form.username && form.password) {
var myHeaders = new Headers(); var myHeaders = new Headers();
myHeaders.append("apikey", API_KEY); myHeaders.append("apikey", API_KEY);
myHeaders.append("Content-Type", "application/json"); myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({ var raw = JSON.stringify({
"email": form.username, email: form.username,
"password": form.password password: form.password,
}); });
var requestOptions = { var requestOptions = {
method: 'POST', method: "POST",
headers: myHeaders, headers: myHeaders,
body: raw, body: raw,
redirect: 'follow' redirect: "follow",
}; };
const response = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/auth/v1/token?grant_type=password", requestOptions); const response = await fetch(
const data = await response.json(); "https://yuanqfswhberkoevtmfr.supabase.co/auth/v1/token?grant_type=password",
setAuthTokens(data); requestOptions
console.log(data); );
const data = await response.json();
setAuthTokens(data);
console.log(data);
if (data.access_token) {
const UserData = await UserInfos(`bearer ${data.access_token}`);
console.log(UserData, "Dados do usuário");
if (data.access_token){ if (UserData?.roles?.includes("admin")) {
navigate(`/admin/`);
} else if (UserData?.roles?.includes("secretaria")) {
const UserData = await UserInfos(`bearer ${data.access_token}`); navigate(`/secretaria/`);
console.log(UserData, 'Dados do usuário'); } else if (UserData?.roles?.includes("medico")) {
navigate(`/medico/`);
if(UserData?.roles?.includes('admin')){ } else if (UserData?.roles?.includes("financeiro")) {
navigate(`/admin/`); navigate(`/financeiro/`);
} else if(UserData?.roles?.includes('secretaria')){
navigate(`/secretaria/`);
} else if(UserData?.roles?.includes('medico')){
navigate(`/medico/`);
} else if(UserData?.roles?.includes('financeiro')){
navigate(`/financeiro/`);
}
} }
}
} else {
setAlert("Preencha todos os campos!");
}
};
} else { return (
setAlert("Preencha todos os campos!");
}
};
return (
<> <>
<div className="mt-3 card-position"> <div className="mt-3 card-position">
<div className="col-lg-5 col-12"> <div className="col-lg-5 col-md-7 col-sm-9 col-12 mx-auto">
<div className="card shadow-sm d-flex justify-content-between align-items-center"> <div className="card shadow-sm d-flex justify-content-between align-items-center">
<div id="auth-left"> <div id="auth-left" className="w-100">
<div className="auth-logo"> <div className="auth-logo">
<br /> <br />
<Link to="/"> <Link to="/">
<h1 className="mb-4 text-center">MediConnect</h1> <h1 className="mb-4 text-center">MediConnect</h1>
</Link> </Link>
</div> </div>
<h3 className="auth-title">Entrar</h3> <h3 className="auth-title">Entrar</h3>
<p className="auth-subtitle mb-5"> <p className="auth-subtitle mb-5">
Entre com os dados que você inseriu durante o registro. Entre com os dados que você inseriu durante o registro.
</p> </p>
{alert && ( {alert && (
<div className="alert alert-info" role="alert"> <div className="alert alert-info" role="alert">
{alert} {alert}
</div> </div>
)} )}
<form onSubmit={handleLogin}> <form onSubmit={handleLogin}>
<div className="form-group position-relative has-icon-left mb-4"> <div className="form-group position-relative has-icon-left mb-4">
<input <input
type="text" type="text"
name="username" name="username"
className="form-control form-control-xl" className="form-control form-control-xl"
@ -164,13 +163,13 @@ function Login({ onEnterSystem }) {
value={form.username} value={form.username}
onChange={handleChange} onChange={handleChange}
required required
/> />
<div className="form-control-icon"> <div className="form-control-icon">
<i className="bi bi-person" /> <i className="bi bi-person" />
</div> </div>
</div> </div>
<div className="form-group position-relative has-icon-left mb-4"> <div className="form-group position-relative has-icon-left mb-4">
<input <input
type={showPassword ? "text" : "password"} type={showPassword ? "text" : "password"}
name="password" name="password"
className="form-control form-control-xl" className="form-control form-control-xl"
@ -178,62 +177,75 @@ function Login({ onEnterSystem }) {
value={form.password} value={form.password}
onChange={handleChange} onChange={handleChange}
required required
/> />
<div className="form-control-icon"> <div className="form-control-icon">
<i className="bi bi-shield-lock" /> <i className="bi bi-shield-lock" />
</div> </div>
<button <button
type="button" type="button"
className="btn btn-sm" className="btn btn-sm"
style={{ position: "absolute", right: "10px", top: "10px", background: "none", border: "none" }} style={{
onClick={() => setShowPassword(!showPassword)} position: "absolute",
tabIndex={-1} right: "10px",
> top: "10px",
<i className={`bi ${showPassword ? "bi-eye-slash" : "bi-eye"}`}></i> background: "none",
</button> border: "none",
}}
onClick={() => setShowPassword(!showPassword)}
tabIndex={-1}
>
<i
className={`bi ${
showPassword ? "bi-eye-slash" : "bi-eye"
}`}
></i>
</button>
</div> </div>
<div className="form-check form-check-lg d-flex align-items-end"> <div className="form-check form-check-lg d-flex align-items-end">
<input <input
className="form-check-input me-2" className="form-check-input me-2"
type="checkbox" type="checkbox"
defaultValue="" defaultValue=""
id="flexCheckDefault" id="flexCheckDefault"
/> />
<label <label
className="form-check-label text-gray-600" className="form-check-label text-gray-600"
htmlFor="flexCheckDefault" htmlFor="flexCheckDefault"
> >
Manter-me conectado Manter-me conectado
</label> </label>
</div> </div>
<button type="submit" className="btn btn-primary btn-block btn-lg shadow-lg mt-5" > <button
Entrar type="submit"
className="btn btn-primary btn-block btn-lg shadow-lg mt-5"
>
Entrar
</button> </button>
</form> </form>
<div className="text-center mt-5 text-lg fs-4"> <div className="text-center mt-5 text-lg fs-4">
<p className="text-gray-600"> <p className="text-gray-600">
Não tem uma conta? Não tem uma conta?
<Link className="font-bold" to={'/register'}> <Link className="font-bold" to={"/register"}>
Cadastre-se Cadastre-se
</Link> </Link>
. .
</p> </p>
<p> <p>
<Link className="font-bold" to={'/forgotPassword'}> <Link className="font-bold" to={"/forgotPassword"}>
Esqueceu a senha? Esqueceu a senha?
</Link> </Link>
. .
</p> </p>
</div> </div>
</div> </div>
<div className="col-lg-7 d-none d-lg-block"> <div className="col-lg-7 d-none d-lg-block">
<div id="auth-right"></div> <div id="auth-right"></div>
</div> </div>
</div>
</div> </div>
</div> </div>
</div>
</> </>
); );
} }
export default Login; export default Login;

View File

@ -21,6 +21,31 @@
z-index: 1000; z-index: 1000;
} }
/* Responsividade do cabeçalho */
@media screen and (max-width: 1199px) {
.landing-header {
padding: 12px 30px;
}
}
@media screen and (max-width: 768px) {
.landing-header {
padding: 10px 20px;
flex-wrap: wrap;
gap: 10px;
}
}
@media screen and (max-width: 576px) {
.landing-header {
padding: 8px 15px;
flex-direction: column;
gap: 15px;
position: relative;
padding-bottom: 15px;
}
}
/* Estilo para a logo DENTRO do cabeçalho da Landing Page */ /* Estilo para a logo DENTRO do cabeçalho da Landing Page */
.landing-header .logo h1 { .landing-header .logo h1 {
font-size: 1.8em; font-size: 1.8em;
@ -30,6 +55,38 @@
padding: 0; /* Remove padding */ padding: 0; /* Remove padding */
} }
@media screen and (max-width: 768px) {
.landing-header .logo h1 {
font-size: 1.5em;
}
}
@media screen and (max-width: 576px) {
.landing-header .logo h1 {
font-size: 1.3em;
}
}
.nav-menu {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
@media screen and (max-width: 768px) {
.nav-menu {
gap: 15px;
}
}
@media screen and (max-width: 576px) {
.nav-menu {
justify-content: center;
width: 100%;
}
}
.nav-menu a { .nav-menu a {
text-decoration: none; text-decoration: none;
color: #333; color: #333;
@ -38,6 +95,19 @@
transition: color 0.2s; transition: color 0.2s;
} }
@media screen and (max-width: 768px) {
.nav-menu a {
margin-left: 0;
font-size: 0.9em;
}
}
@media screen and (max-width: 576px) {
.nav-menu a {
font-size: 0.85em;
}
}
.nav-menu a:hover { .nav-menu a:hover {
color: #5b56f8; color: #5b56f8;
} }
@ -56,6 +126,21 @@
font-weight: 600; font-weight: 600;
} }
@media screen and (max-width: 768px) {
.access-button {
margin-left: 0;
padding: 8px 15px;
font-size: 0.9em;
}
}
@media screen and (max-width: 576px) {
.access-button {
padding: 10px 20px;
font-size: 0.85em;
}
}
/* --- Área de Destaque (Hero Section) --- */ /* --- Área de Destaque (Hero Section) --- */
.hero-section { .hero-section {
display: flex; display: flex;
@ -68,11 +153,45 @@
padding-top: 100px; padding-top: 100px;
} }
/* Responsividade da hero section */
@media screen and (max-width: 1199px) {
.hero-section {
padding: 80px 30px;
min-height: 500px;
padding-top: 80px;
}
}
@media screen and (max-width: 768px) {
.hero-section {
padding: 60px 20px;
min-height: 400px;
padding-top: 80px;
justify-content: center;
text-align: center;
}
}
@media screen and (max-width: 576px) {
.hero-section {
padding: 40px 15px;
min-height: 350px;
padding-top: 100px;
}
}
.hero-content { .hero-content {
max-width: 700px; max-width: 700px;
text-align: left; text-align: left;
} }
@media screen and (max-width: 768px) {
.hero-content {
max-width: 100%;
text-align: center;
}
}
/* Título Branco e Legível */ /* Título Branco e Legível */
.hero-content .hero-title { .hero-content .hero-title {
font-size: 3.5em; font-size: 3.5em;
@ -82,12 +201,48 @@
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
} }
@media screen and (max-width: 1199px) {
.hero-content .hero-title {
font-size: 3em;
}
}
@media screen and (max-width: 768px) {
.hero-content .hero-title {
font-size: 2.5em;
margin-bottom: 15px;
}
}
@media screen and (max-width: 576px) {
.hero-content .hero-title {
font-size: 2em;
margin-bottom: 12px;
line-height: 1.2;
}
}
.hero-content p { .hero-content p {
font-size: 1.2em; font-size: 1.2em;
margin-bottom: 30px; margin-bottom: 30px;
color: #ddd; color: #ddd;
} }
@media screen and (max-width: 768px) {
.hero-content p {
font-size: 1.1em;
margin-bottom: 25px;
}
}
@media screen and (max-width: 576px) {
.hero-content p {
font-size: 1em;
margin-bottom: 20px;
line-height: 1.4;
}
}
.main-action-button { .main-action-button {
background-color: #5b56f8; background-color: #5b56f8;
color: white; color: white;
@ -100,6 +255,22 @@
transition: background-color 0.3s; transition: background-color 0.3s;
} }
@media screen and (max-width: 768px) {
.main-action-button {
padding: 12px 25px;
font-size: 1em;
}
}
@media screen and (max-width: 576px) {
.main-action-button {
padding: 12px 20px;
font-size: 0.9em;
width: 100%;
max-width: 250px;
}
}
.main-action-button:hover { .main-action-button:hover {
background-color: #4540d6; background-color: #4540d6;
} }