feat(agenda): layout em 2 colunas no desktop + sidebar recolhível
- AgendaView: controles migrados do header horizontal para uma coluna lateral esquerda (AGENDAR, ícones de ação em faixa horizontal de tamanho igual, presença, legenda de dentistas); calendário em flex-1 ocupando a altura toda - Mobile revisto: cabeçalho compacto (título + AGENDAR) e calendário flex-1 - Sidebar do sistema recolhível no desktop (App: estado persistido + botão flutuante para reexibir); toggle fica ao lado do título "AGENDA CLÍNICA" - Toolbar do FullCalendar compactada (título/botões/cabeçalhos menores) - Título da agenda responsivo (não gera scroll horizontal na coluna estreita) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+23
-3
@@ -4,7 +4,7 @@ import { HybridBackend } from './services/backend.ts';
|
|||||||
import { Sidebar } from './components/Sidebar.tsx';
|
import { Sidebar } from './components/Sidebar.tsx';
|
||||||
import {
|
import {
|
||||||
Menu, LayoutDashboard, Users, Calendar as CalendarIcon,
|
Menu, LayoutDashboard, Users, Calendar as CalendarIcon,
|
||||||
DollarSign, Activity, ClipboardList, Bell, Settings, MoreHorizontal, Eye, X
|
DollarSign, Activity, ClipboardList, Bell, Settings, MoreHorizontal, Eye, X, PanelLeftOpen
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
import { ToastContainer } from './components/Toast.tsx';
|
import { ToastContainer } from './components/Toast.tsx';
|
||||||
@@ -315,6 +315,14 @@ const MobileBottomNav: React.FC<{
|
|||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const ver = useAppVersion();
|
const ver = useAppVersion();
|
||||||
const [isSidebarOpen, setSidebarOpen] = useState(false);
|
const [isSidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
// Recolher a sidebar no DESKTOP (persistente) — dá largura ao conteúdo (ex.: agenda).
|
||||||
|
const [isSidebarCollapsed, setSidebarCollapsed] = useState<boolean>(() => {
|
||||||
|
try { return localStorage.getItem('scoreodonto:sidebar-collapsed') === '1'; } catch { return false; }
|
||||||
|
});
|
||||||
|
const toggleSidebarCollapsed = (v: boolean) => {
|
||||||
|
setSidebarCollapsed(v);
|
||||||
|
try { localStorage.setItem('scoreodonto:sidebar-collapsed', v ? '1' : '0'); } catch { /* ignore */ }
|
||||||
|
};
|
||||||
const [, forcePwRerender] = useState(0); // re-avalia o modal de troca obrigatória de senha
|
const [, forcePwRerender] = useState(0); // re-avalia o modal de troca obrigatória de senha
|
||||||
const currentRole = HybridBackend.getCurrentRole();
|
const currentRole = HybridBackend.getCurrentRole();
|
||||||
const activeWorkspace = HybridBackend.getActiveWorkspace();
|
const activeWorkspace = HybridBackend.getActiveWorkspace();
|
||||||
@@ -500,7 +508,7 @@ const App: React.FC = () => {
|
|||||||
case 'leads': return <LeadsView />;
|
case 'leads': return <LeadsView />;
|
||||||
case 'public': return <PublicContactForm />;
|
case 'public': return <PublicContactForm />;
|
||||||
case 'pacientes': return <PatientsView />;
|
case 'pacientes': return <PatientsView />;
|
||||||
case 'agenda': return <AgendaView onNavigate={handleNavigate} />;
|
case 'agenda': return <AgendaView onNavigate={handleNavigate} sidebarCollapsed={isSidebarCollapsed} onToggleSidebar={() => toggleSidebarCollapsed(!isSidebarCollapsed)} />;
|
||||||
case 'ortodontia': return <OrthoView />;
|
case 'ortodontia': return <OrthoView />;
|
||||||
case 'financeiro': return <FinanceiroView />;
|
case 'financeiro': return <FinanceiroView />;
|
||||||
case 'dentistas': return <DentistasView />;
|
case 'dentistas': return <DentistasView />;
|
||||||
@@ -591,7 +599,7 @@ const App: React.FC = () => {
|
|||||||
></div>
|
></div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={`fixed inset-y-0 left-0 z-30 transform transition-transform duration-300 md:relative md:translate-x-0 ${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}`}>
|
<div className={`fixed inset-y-0 left-0 z-30 transform transition-transform duration-300 ${isSidebarCollapsed ? 'md:hidden' : 'md:relative md:translate-x-0'} ${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}`}>
|
||||||
<Sidebar
|
<Sidebar
|
||||||
activeTab={currentView}
|
activeTab={currentView}
|
||||||
setActiveTab={(t) => handleNavigate(t as ViewKey)}
|
setActiveTab={(t) => handleNavigate(t as ViewKey)}
|
||||||
@@ -600,6 +608,18 @@ const App: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Botão flutuante para reexibir a sidebar (desktop, quando recolhida).
|
||||||
|
Na agenda NÃO aparece — ela já tem o próprio toggle ao lado do título. */}
|
||||||
|
{!isStandaloneView && isSidebarCollapsed && currentView !== 'agenda' && (
|
||||||
|
<button
|
||||||
|
onClick={() => toggleSidebarCollapsed(false)}
|
||||||
|
title="Mostrar menu"
|
||||||
|
className="hidden md:flex fixed top-3 left-3 z-40 items-center justify-center w-9 h-9 bg-white border border-gray-200 rounded-lg text-gray-500 hover:text-gray-800 hover:border-gray-300 shadow-sm transition-colors"
|
||||||
|
>
|
||||||
|
<PanelLeftOpen size={18} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<main className={`flex-1 h-full relative flex flex-col min-w-0`}>
|
<main className={`flex-1 h-full relative flex flex-col min-w-0`}>
|
||||||
{HybridBackend.isPreviewMode() && (
|
{HybridBackend.isPreviewMode() && (
|
||||||
<div className="bg-red-600 text-white px-4 py-2 flex items-center justify-between gap-3 shadow-md z-30">
|
<div className="bg-red-600 text-white px-4 py-2 flex items-center justify-between gap-3 shadow-md z-30">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import FullCalendar from '@fullcalendar/react';
|
|||||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||||
import interactionPlugin from '@fullcalendar/interaction';
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
import { Calendar as CalendarIcon, Plus, X, Loader2, GripVertical, Settings as GearIcon, Edit, Trash2, CalendarRange, Clock, User, Stethoscope, AlertCircle, CheckCircle2, Bell, CalendarClock, History, Download } from 'lucide-react';
|
import { Calendar as CalendarIcon, Plus, X, Loader2, GripVertical, Settings as GearIcon, Edit, Trash2, CalendarRange, Clock, User, Stethoscope, AlertCircle, CheckCircle2, Bell, CalendarClock, History, Download, PanelLeftClose, PanelLeftOpen } from 'lucide-react';
|
||||||
import { AgendaSettingsModal } from '../components/AgendaSettingsModal.tsx';
|
import { AgendaSettingsModal } from '../components/AgendaSettingsModal.tsx';
|
||||||
import { AgendaDetailModal, ScoreBadge, FamiliaChips } from '../components/AgendaDetailModal.tsx';
|
import { AgendaDetailModal, ScoreBadge, FamiliaChips } from '../components/AgendaDetailModal.tsx';
|
||||||
import { WhatsChatDrawer } from './newwhats/WhatsChatDrawer.tsx';
|
import { WhatsChatDrawer } from './newwhats/WhatsChatDrawer.tsx';
|
||||||
@@ -15,7 +15,6 @@ import { Dentista, Agendamento, Paciente, DentistaHorario } from '../types.ts';
|
|||||||
import { useGTOStore } from './LancarGTO.tsx';
|
import { useGTOStore } from './LancarGTO.tsx';
|
||||||
import { useHybridBackend } from '../hooks/useHybridBackend.ts';
|
import { useHybridBackend } from '../hooks/useHybridBackend.ts';
|
||||||
import { useToast } from '../contexts/ToastContext.tsx';
|
import { useToast } from '../contexts/ToastContext.tsx';
|
||||||
import { PageHeader } from '../components/PageHeader.tsx';
|
|
||||||
|
|
||||||
// --- Reusable Debounce Hook ---
|
// --- Reusable Debounce Hook ---
|
||||||
function useDebounce(value: string, delay: number) {
|
function useDebounce(value: string, delay: number) {
|
||||||
@@ -344,7 +343,7 @@ const AppointmentModal: React.FC<{
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AgendaView: React.FC<{ onNavigate?: (view: string) => void }> = ({ onNavigate }) => {
|
export const AgendaView: React.FC<{ onNavigate?: (view: string) => void; sidebarCollapsed?: boolean; onToggleSidebar?: () => void }> = ({ onNavigate, sidebarCollapsed, onToggleSidebar }) => {
|
||||||
const { data: agendamentos, refresh } = useHybridBackend<Agendamento[]>(HybridBackend.getAgendamentos);
|
const { data: agendamentos, refresh } = useHybridBackend<Agendamento[]>(HybridBackend.getAgendamentos);
|
||||||
const { data: dentists, refresh: refreshDentists } = useHybridBackend<Dentista[]>(HybridBackend.getDentistas);
|
const { data: dentists, refresh: refreshDentists } = useHybridBackend<Dentista[]>(HybridBackend.getDentistas);
|
||||||
const { data: googleEvents, refresh: refreshGoogle } = useHybridBackend<any[]>(HybridBackend.getGoogleEvents);
|
const { data: googleEvents, refresh: refreshGoogle } = useHybridBackend<any[]>(HybridBackend.getGoogleEvents);
|
||||||
@@ -600,13 +599,78 @@ export const AgendaView: React.FC<{ onNavigate?: (view: string) => void }> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="flex flex-col lg:flex-row lg:gap-4 h-full">
|
||||||
<PageHeader title="AGENDA CLÍNICA">
|
{/* Coluna de controles (desktop: lateral esquerda vertical; mobile: topo compacto) */}
|
||||||
<div className="flex gap-2 sm:gap-3 items-center flex-wrap justify-end">
|
<aside className="shrink-0 mb-3 lg:mb-0 lg:w-56 lg:overflow-y-auto lg:pr-3 lg:border-r lg:border-gray-100">
|
||||||
|
{/* Título + recolher menu (desktop, ao lado) + AGENDAR (mobile, à direita) */}
|
||||||
|
<div className="flex items-center gap-2 mb-3">
|
||||||
|
{onToggleSidebar && (
|
||||||
|
<button onClick={onToggleSidebar} title={sidebarCollapsed ? 'Mostrar menu lateral' : 'Recolher menu lateral'}
|
||||||
|
className="hidden lg:flex items-center justify-center w-8 h-8 shrink-0 rounded-lg text-gray-400 hover:text-gray-700 hover:bg-gray-100 transition-colors">
|
||||||
|
{sidebarCollapsed ? <PanelLeftOpen size={18} /> : <PanelLeftClose size={18} />}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<h2 className="text-xl lg:text-base font-bold text-gray-900 uppercase flex-1 min-w-0 leading-tight break-words">AGENDA CLÍNICA</h2>
|
||||||
|
{(currentRole !== 'paciente' && !souDentista) && (
|
||||||
|
<button onClick={() => { setReagendarPatient(null); setSelectedAppointment(null); setSelectedDateInfo({ dateStr: new Date().toISOString() }); setIsModalOpen(true); }} title="Agendar"
|
||||||
|
className="lg:hidden shrink-0 bg-teal-600 text-white px-3 py-2 rounded-lg text-xs font-bold uppercase flex items-center gap-1.5 hover:bg-teal-700 shadow-sm">
|
||||||
|
<Plus size={16} /> AGENDAR
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2 sm:gap-3 items-center flex-wrap lg:flex-col lg:items-stretch">
|
||||||
|
{/* AGENDAR (desktop, full-width no topo da coluna) */}
|
||||||
|
{(currentRole !== 'paciente' && !souDentista) && (
|
||||||
|
<button onClick={() => { setReagendarPatient(null); setSelectedAppointment(null); setSelectedDateInfo({ dateStr: new Date().toISOString() }); setIsModalOpen(true); }} title="Agendar"
|
||||||
|
className="hidden lg:flex w-full bg-teal-600 text-white px-4 py-2.5 rounded-lg text-sm font-bold uppercase items-center justify-center gap-2 hover:bg-teal-700 shadow-sm transition-colors">
|
||||||
|
<Plus size={18} /> AGENDAR
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{/* ícones de ação — mesmo tamanho, distribuídos horizontalmente */}
|
||||||
|
<div className="flex gap-2 w-full">
|
||||||
|
{(currentRole !== 'paciente') && (
|
||||||
|
<button onClick={() => { setShowAtividade(true); loadAtividade(); }} title="Atividade da equipe hoje"
|
||||||
|
className="flex-1 flex items-center justify-center py-2.5 bg-white text-gray-400 hover:text-teal-600 border border-gray-200 rounded-xl transition-all hover:border-teal-200 hover:shadow-sm">
|
||||||
|
<History size={20} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{(currentRole === 'admin' || currentRole === 'donoclinica' || currentRole === 'donoconsultorio') && (
|
||||||
|
<button onClick={handleImportarGoogle} disabled={importando} title="Importar agendamentos do Google para o sistema"
|
||||||
|
className="flex-1 flex items-center justify-center py-2.5 bg-white text-gray-400 hover:text-emerald-600 border border-gray-200 rounded-xl transition-all hover:border-emerald-200 hover:shadow-sm disabled:opacity-50">
|
||||||
|
{importando ? <Loader2 size={20} className="animate-spin" /> : <Download size={20} />}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{(currentRole === 'admin' || currentRole === 'donoclinica') && (
|
||||||
|
<button onClick={() => setIsSettingsOpen(true)} title="Configurações da agenda"
|
||||||
|
className="flex-1 flex items-center justify-center py-2.5 bg-white text-gray-400 hover:text-teal-600 border border-gray-200 rounded-xl transition-all hover:border-teal-200 hover:shadow-sm">
|
||||||
|
<GearIcon size={20} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{souDentista && (
|
||||||
|
<button onClick={() => { setShowInteresses(true); loadInteresses(); }} title="Pedidos de interesse na sua agenda"
|
||||||
|
className="relative flex-1 flex items-center justify-center py-2.5 bg-white text-gray-400 hover:text-teal-600 border border-gray-200 rounded-xl transition-all hover:border-teal-200 hover:shadow-sm">
|
||||||
|
<Bell size={20} />
|
||||||
|
{interessesAguardando > 0 && (
|
||||||
|
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-[9px] font-black rounded-full w-4 h-4 flex items-center justify-center">{interessesAguardando}</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{(currentRole !== 'paciente' && !souDentista) && (
|
||||||
|
<button onClick={() => { setShowPendencias(true); loadPendencias(); }} title="Pacientes a reagendar"
|
||||||
|
className="relative flex-1 flex items-center justify-center py-2.5 bg-white text-gray-400 hover:text-amber-600 border border-gray-200 rounded-xl transition-all hover:border-amber-200 hover:shadow-sm">
|
||||||
|
<CalendarClock size={20} />
|
||||||
|
{pendencias.length > 0 && (
|
||||||
|
<span className="absolute -top-1 -right-1 bg-amber-500 text-white text-[9px] font-black rounded-full w-4 h-4 flex items-center justify-center">{pendencias.length}</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="w-full"><AgendaPresence /></div>
|
||||||
|
{/* Legenda de dentistas (desktop, no rodapé da coluna) */}
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
<Droppable droppableId="dentists-legend" direction="horizontal">
|
<Droppable droppableId="dentists-legend" direction="horizontal">
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
<div {...provided.droppableProps} ref={provided.innerRef} className="hidden lg:flex gap-2 items-center">
|
<div {...provided.droppableProps} ref={provided.innerRef} className="hidden lg:flex lg:flex-wrap gap-2 items-center lg:w-full lg:mt-1">
|
||||||
{filteredDentists?.map((d, index) => (
|
{filteredDentists?.map((d, index) => (
|
||||||
<Draggable key={d.id} draggableId={d.id} index={index} isDragDisabled={currentRole === 'dentista'}>
|
<Draggable key={d.id} draggableId={d.id} index={index} isDragDisabled={currentRole === 'dentista'}>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
@@ -628,50 +692,9 @@ export const AgendaView: React.FC<{ onNavigate?: (view: string) => void }> = ({
|
|||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
<AgendaPresence />
|
|
||||||
{(currentRole !== 'paciente') && (
|
|
||||||
<button onClick={() => { setShowAtividade(true); loadAtividade(); }} title="Atividade da equipe hoje"
|
|
||||||
className="p-2.5 bg-white text-gray-400 hover:text-teal-600 border border-gray-200 rounded-xl transition-all hover:border-teal-200 hover:shadow-sm">
|
|
||||||
<History size={20} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{(currentRole === 'admin' || currentRole === 'donoclinica' || currentRole === 'donoconsultorio') && (
|
|
||||||
<button onClick={handleImportarGoogle} disabled={importando} title="Importar agendamentos do Google para o sistema"
|
|
||||||
className="p-2.5 bg-white text-gray-400 hover:text-emerald-600 border border-gray-200 rounded-xl transition-all hover:border-emerald-200 hover:shadow-sm disabled:opacity-50">
|
|
||||||
{importando ? <Loader2 size={20} className="animate-spin" /> : <Download size={20} />}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{(currentRole === 'admin' || currentRole === 'donoclinica') && (
|
|
||||||
<button onClick={() => setIsSettingsOpen(true)} className="p-2.5 bg-white text-gray-400 hover:text-teal-600 border border-gray-200 rounded-xl transition-all hover:border-teal-200 hover:shadow-sm">
|
|
||||||
<GearIcon size={20} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{souDentista && (
|
|
||||||
<button onClick={() => { setShowInteresses(true); loadInteresses(); }} title="Pedidos de interesse na sua agenda"
|
|
||||||
className="relative p-2.5 bg-white text-gray-400 hover:text-teal-600 border border-gray-200 rounded-xl transition-all hover:border-teal-200 hover:shadow-sm">
|
|
||||||
<Bell size={20} />
|
|
||||||
{interessesAguardando > 0 && (
|
|
||||||
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-[9px] font-black rounded-full w-4 h-4 flex items-center justify-center">{interessesAguardando}</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{(currentRole !== 'paciente' && !souDentista) && (
|
|
||||||
<button onClick={() => { setShowPendencias(true); loadPendencias(); }} title="Pacientes a reagendar"
|
|
||||||
className="relative p-2.5 bg-white text-gray-400 hover:text-amber-600 border border-gray-200 rounded-xl transition-all hover:border-amber-200 hover:shadow-sm">
|
|
||||||
<CalendarClock size={20} />
|
|
||||||
{pendencias.length > 0 && (
|
|
||||||
<span className="absolute -top-1 -right-1 bg-amber-500 text-white text-[9px] font-black rounded-full w-4 h-4 flex items-center justify-center">{pendencias.length}</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{(currentRole !== 'paciente' && !souDentista) && (
|
|
||||||
<button onClick={() => { setReagendarPatient(null); setSelectedAppointment(null); setSelectedDateInfo({ dateStr: new Date().toISOString() }); setIsModalOpen(true); }} title="Novo agendamento" className="bg-teal-600 text-white px-3 sm:px-4 py-2 rounded-lg text-sm font-bold uppercase flex items-center gap-2 hover:bg-teal-700 shadow-sm transition-colors">
|
|
||||||
<Plus size={18} /> <span className="hidden sm:inline">NOVO AGENDAMENTO</span>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</aside>
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-2 sm:p-4 relative h-[calc(100dvh-220px)] sm:h-[750px] min-h-[420px]">
|
<div className="flex-1 min-w-0 bg-white rounded-xl shadow-sm border border-gray-200 p-2 sm:p-4 relative min-h-[420px] lg:min-h-0">
|
||||||
<FullCalendar
|
<FullCalendar
|
||||||
key={isMobile ? 'mobile' : 'desktop'}
|
key={isMobile ? 'mobile' : 'desktop'}
|
||||||
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
|
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
|
||||||
@@ -810,6 +833,12 @@ export const AgendaView: React.FC<{ onNavigate?: (view: string) => void }> = ({
|
|||||||
.custom-scrollbar::-webkit-scrollbar { width: 4px; }
|
.custom-scrollbar::-webkit-scrollbar { width: 4px; }
|
||||||
.custom-scrollbar::-webkit-scrollbar-track { background: #f1f1f1; }
|
.custom-scrollbar::-webkit-scrollbar-track { background: #f1f1f1; }
|
||||||
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
|
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
|
||||||
|
/* FullCalendar — toolbar/controles compactos (todas as telas) */
|
||||||
|
.fc .fc-toolbar.fc-header-toolbar { margin-bottom: .6rem; }
|
||||||
|
.fc .fc-toolbar-title { font-size: 1.05rem; font-weight: 700; }
|
||||||
|
.fc .fc-button { padding: .3rem .65rem; font-size: .8rem; box-shadow: none !important; }
|
||||||
|
.fc .fc-button-group { gap: 0; }
|
||||||
|
.fc .fc-col-header-cell-cushion { font-size: .72rem; padding: 4px 2px; }
|
||||||
/* FullCalendar — responsividade mobile */
|
/* FullCalendar — responsividade mobile */
|
||||||
@media (max-width: 639px) {
|
@media (max-width: 639px) {
|
||||||
.fc .fc-toolbar.fc-header-toolbar { margin-bottom: .5rem; flex-wrap: wrap; gap: .4rem; }
|
.fc .fc-toolbar.fc-header-toolbar { margin-bottom: .5rem; flex-wrap: wrap; gap: .4rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user