Layout 100%, Notificações, SetupWizard
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
:style="{ width: '1000px', maxWidth: '96vw' }"
|
||||
:breakpoints="{ '960px': '96vw', '640px': '98vw' }"
|
||||
class="agenda-event-composer"
|
||||
pt:mask:class="backdrop-blur-xs"
|
||||
>
|
||||
<template #header>
|
||||
<div class="w-full flex items-center justify-between gap-3">
|
||||
@@ -24,47 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<Button
|
||||
v-if="step === 2 && !isEdit && allowBack"
|
||||
label="Voltar"
|
||||
icon="pi pi-arrow-left"
|
||||
severity="secondary"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full"
|
||||
@click="goBack"
|
||||
/>
|
||||
<Button
|
||||
v-if="step === 2 && isEdit && hasSerie"
|
||||
label="Encerrar série"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full text-xs h-8"
|
||||
@click="onEncerrarSerie"
|
||||
/>
|
||||
<Button
|
||||
v-if="step === 2 && isEdit && !hasSerie"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full h-9 w-9"
|
||||
v-tooltip.bottom="'Remover'"
|
||||
@click="onDelete"
|
||||
/>
|
||||
<Button
|
||||
v-if="step === 2"
|
||||
label="Salvar"
|
||||
icon="pi pi-check"
|
||||
size="small"
|
||||
class="rounded-full"
|
||||
:disabled="!canSave"
|
||||
@click="onSave"
|
||||
/>
|
||||
</div>
|
||||
<!-- actions moved to footer -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -924,7 +885,7 @@
|
||||
:style="{ width: '560px', maxWidth: '96vw' }"
|
||||
:breakpoints="{ '640px': '98vw' }"
|
||||
>
|
||||
<div class="flex flex-col gap-4 p-1">
|
||||
<div class="flex flex-col gap-4">
|
||||
<!-- Data -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-2">Data</label>
|
||||
@@ -1060,6 +1021,53 @@
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
|
||||
<!-- Footer -->
|
||||
<template v-if="step === 2" #footer>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
v-if="!isEdit && allowBack"
|
||||
label="Voltar"
|
||||
icon="pi pi-arrow-left"
|
||||
severity="secondary"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full"
|
||||
@click="goBack"
|
||||
/>
|
||||
<Button
|
||||
v-if="isEdit && hasSerie"
|
||||
label="Encerrar série"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full text-xs h-8"
|
||||
@click="onEncerrarSerie"
|
||||
/>
|
||||
<Button
|
||||
v-if="isEdit && !hasSerie"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full h-9 w-9"
|
||||
v-tooltip.bottom="'Remover'"
|
||||
@click="onDelete"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
label="Salvar"
|
||||
icon="pi pi-check"
|
||||
size="small"
|
||||
class="rounded-full"
|
||||
:disabled="!canSave"
|
||||
@click="onSave"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ══════════════════════════════════════════════ -->
|
||||
<!-- Cadastro Rápido de Paciente -->
|
||||
<!-- ══════════════════════════════════════════════ -->
|
||||
@@ -2662,7 +2670,7 @@ function statusSeverity (v) {
|
||||
.commitment-card {
|
||||
width: 100%; text-align: left;
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 1.25rem;
|
||||
border-radius: 6px;
|
||||
background: color-mix(in srgb, var(--surface-card), transparent 10%);
|
||||
transition: box-shadow .12s ease, transform .12s ease, border-color .12s;
|
||||
overflow: hidden;
|
||||
@@ -2704,7 +2712,7 @@ function statusSeverity (v) {
|
||||
/* ── paciente hero ──────────────────────────────── */
|
||||
.patient-hero {
|
||||
border: 1.5px solid var(--surface-border);
|
||||
border-radius: 1.25rem;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: color-mix(in srgb, var(--surface-card), transparent 10%);
|
||||
}
|
||||
@@ -2736,7 +2744,7 @@ function statusSeverity (v) {
|
||||
|
||||
/* Card genérico para seções (data/horário, etc.) */
|
||||
.field-card {
|
||||
border-radius: 1rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--surface-border);
|
||||
background: var(--surface-card);
|
||||
overflow: hidden;
|
||||
@@ -2848,7 +2856,7 @@ function statusSeverity (v) {
|
||||
}
|
||||
.side-card {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 1.25rem;
|
||||
border-radius: 6px;
|
||||
padding: .9rem 1rem;
|
||||
background: color-mix(in srgb, var(--surface-card), transparent 10%);
|
||||
}
|
||||
@@ -2879,7 +2887,7 @@ function statusSeverity (v) {
|
||||
|
||||
/* ── serie banner ───────────────────────────────── */
|
||||
.serie-banner {
|
||||
border-radius: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: .75rem .9rem;
|
||||
background: color-mix(in srgb, var(--blue-500, #3b82f6) 8%, var(--surface-card));
|
||||
border: 1px solid color-mix(in srgb, var(--blue-400, #60a5fa) 30%, transparent);
|
||||
@@ -2922,7 +2930,7 @@ function statusSeverity (v) {
|
||||
.recorrencia-preview {
|
||||
display: flex; align-items: center; gap: .5rem;
|
||||
padding: .5rem .75rem;
|
||||
border-radius: .75rem;
|
||||
border-radius: 6px;
|
||||
background: color-mix(in srgb, var(--p-primary-500) 8%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--p-primary-400) 25%, transparent);
|
||||
}
|
||||
@@ -2994,7 +3002,7 @@ function statusSeverity (v) {
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 16px;
|
||||
border-radius: 0.75rem;
|
||||
border-radius: 6px;
|
||||
background: color-mix(in srgb, var(--primary-500, #6366f1) 8%, var(--surface-card));
|
||||
border: 1px solid color-mix(in srgb, var(--primary-400, #818cf8) 25%, transparent);
|
||||
}
|
||||
@@ -3125,7 +3133,7 @@ function statusSeverity (v) {
|
||||
.rec-startdate-row {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: .5rem;
|
||||
padding: .45rem .65rem;
|
||||
border-radius: .75rem;
|
||||
border-radius: 6px;
|
||||
background: color-mix(in srgb, var(--surface-ground), transparent 30%);
|
||||
border: 1px solid var(--surface-border);
|
||||
}
|
||||
@@ -3177,7 +3185,7 @@ function statusSeverity (v) {
|
||||
/* ── personalizar box ───────────────────────────── */
|
||||
.personalizar-box {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: .85rem;
|
||||
border-radius: 6px;
|
||||
padding: .75rem;
|
||||
background: color-mix(in srgb, var(--surface-ground), transparent 40%);
|
||||
display: flex;
|
||||
@@ -3190,7 +3198,7 @@ function statusSeverity (v) {
|
||||
.patient-item {
|
||||
width: 100%; display: flex; align-items: center; justify-content: space-between;
|
||||
gap: 1rem; text-align: left; padding: .85rem .95rem;
|
||||
border: 1px solid var(--surface-border); border-radius: 1.25rem;
|
||||
border: 1px solid var(--surface-border); border-radius: 6px;
|
||||
background: color-mix(in srgb, var(--surface-card), transparent 10%);
|
||||
transition: box-shadow .12s ease, transform .12s ease;
|
||||
}
|
||||
@@ -3199,7 +3207,7 @@ function statusSeverity (v) {
|
||||
/* ── serie panel (Recorrências Aplicadas) ─────────── */
|
||||
.serie-panel {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 1.1rem;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.serie-panel__header {
|
||||
@@ -3273,7 +3281,7 @@ function statusSeverity (v) {
|
||||
flex-direction: column;
|
||||
gap: .35rem;
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: .5rem;
|
||||
border-radius: 6px;
|
||||
padding: .5rem;
|
||||
}
|
||||
.commitment-item-row {
|
||||
|
||||
@@ -6,14 +6,15 @@
|
||||
:closable="!saving"
|
||||
:dismissableMask="!saving"
|
||||
class="dc-dialog w-[96vw] max-w-2xl"
|
||||
:pt="{ content: { class: 'p-0' }, header: { class: 'pb-0' } }"
|
||||
:pt="{ content: { class: 'p-0' }, header: { class: 'pb-0' }, footer: { class: 'pt-0' } }"
|
||||
pt:mask:class="backdrop-blur-xs"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex w-full items-center justify-between gap-3 px-1">
|
||||
<div class="flex items-center gap-3 min-w-0">
|
||||
<!-- Dot de cor -->
|
||||
<span
|
||||
class="dc-header-dot shrink-0"
|
||||
class="shrink-0 w-3.5 h-3.5 rounded-full border-2 border-white/30 shadow-[0_0_0_3px_rgba(0,0,0,0.08)] transition-colors duration-200"
|
||||
:style="{ backgroundColor: previewBgColor }"
|
||||
/>
|
||||
<div class="min-w-0">
|
||||
@@ -37,33 +38,17 @@
|
||||
v-tooltip.top="'Excluir'"
|
||||
@click="emitDelete"
|
||||
/>
|
||||
<Button
|
||||
label="Cancelar"
|
||||
severity="secondary"
|
||||
outlined
|
||||
class="rounded-full"
|
||||
:disabled="saving"
|
||||
@click="close"
|
||||
/>
|
||||
<Button
|
||||
label="Salvar"
|
||||
icon="pi pi-check"
|
||||
class="rounded-full"
|
||||
:loading="saving"
|
||||
:disabled="!canSubmit"
|
||||
@click="submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Banner de preview -->
|
||||
<div
|
||||
class="dc-banner"
|
||||
class="h-[72px] flex items-center justify-center transition-colors duration-[250ms] rounded-[6px]"
|
||||
:style="{ backgroundColor: previewBgColor }"
|
||||
>
|
||||
<span
|
||||
class="dc-banner__pill"
|
||||
class="text-base font-bold tracking-[-0.02em] px-[1.1rem] py-[0.35rem] bg-black/15 rounded-full backdrop-blur-sm transition-colors duration-200"
|
||||
:style="{ color: form.text_color || '#ffffff' }"
|
||||
>
|
||||
{{ form.name || 'Nome do compromisso' }}
|
||||
@@ -71,7 +56,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Corpo -->
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
<div class="flex flex-col gap-4 mt-4">
|
||||
|
||||
<!-- Nome + Ativo -->
|
||||
<div class="flex items-center gap-3">
|
||||
@@ -91,68 +76,15 @@
|
||||
<label for="cr-nome">Nome *</label>
|
||||
</FloatLabel>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 shrink-0 pt-1">
|
||||
|
||||
<!-- Toggle Ativo -->
|
||||
<div class="shrink-0 flex items-center gap-2">
|
||||
<span class="text-sm font-medium">Ativo</span>
|
||||
<InputSwitch v-model="form.active" :disabled="saving || isActiveLocked" />
|
||||
<ToggleSwitch v-model="form.active" :disabled="saving || isActiveLocked" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seção Cor -->
|
||||
<div class="dc-section">
|
||||
<div class="dc-section__label">Cor</div>
|
||||
|
||||
<!-- Paleta predefinida -->
|
||||
<div class="dc-palette">
|
||||
<button
|
||||
v-for="p in presetColors"
|
||||
:key="p.bg"
|
||||
class="dc-swatch"
|
||||
:class="{ 'dc-swatch--active': form.bg_color === p.bg }"
|
||||
:style="{ backgroundColor: `#${p.bg}` }"
|
||||
:title="p.name"
|
||||
:disabled="saving || isEditLocked"
|
||||
@click="applyPreset(p)"
|
||||
>
|
||||
<i v-if="form.bg_color === p.bg" class="pi pi-check dc-swatch__check" />
|
||||
</button>
|
||||
|
||||
<!-- Custom ColorPicker -->
|
||||
<div class="dc-swatch dc-swatch--custom" title="Cor personalizada">
|
||||
<ColorPicker
|
||||
v-model="form.bg_color"
|
||||
format="hex"
|
||||
:disabled="saving || isEditLocked"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Texto -->
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<span class="text-xs font-medium opacity-60 uppercase tracking-wide">Texto</span>
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="dc-text-opt"
|
||||
:class="{ 'dc-text-opt--active': form.text_color === '#ffffff' }"
|
||||
:disabled="saving || isEditLocked"
|
||||
@click="form.text_color = '#ffffff'"
|
||||
>
|
||||
<span class="dc-text-opt__dot" style="background:#ffffff; border: 1px solid #ccc;" />
|
||||
Branco
|
||||
</button>
|
||||
<button
|
||||
class="dc-text-opt"
|
||||
:class="{ 'dc-text-opt--active': form.text_color === '#000000' }"
|
||||
:disabled="saving || isEditLocked"
|
||||
@click="form.text_color = '#000000'"
|
||||
>
|
||||
<span class="dc-text-opt__dot" style="background:#000000;" />
|
||||
Preto
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Descrição -->
|
||||
|
||||
<!-- Descrição -->
|
||||
<FloatLabel variant="on">
|
||||
<Textarea
|
||||
id="cr-descricao"
|
||||
@@ -166,10 +98,83 @@
|
||||
<label for="cr-descricao">Descrição</label>
|
||||
</FloatLabel>
|
||||
|
||||
<!-- Seção Cor -->
|
||||
<div class="border border-[var(--surface-border)] rounded-[6px] bg-[var(--surface-card)] p-4">
|
||||
<div class="text-[1rem] font-bold uppercase tracking-[0.06em] opacity-45 mb-3">Cor</div>
|
||||
|
||||
<!-- Paleta predefinida -->
|
||||
<div class="flex flex-wrap gap-[0.45rem]">
|
||||
<button
|
||||
v-for="p in presetColors"
|
||||
:key="p.bg"
|
||||
class="w-7 h-7 rounded-full grid place-items-center cursor-pointer relative transition-transform duration-[120ms] ease-in-out hover:scale-[1.18] hover:shadow-[0_3px_10px_rgba(0,0,0,0.2)] disabled:cursor-not-allowed"
|
||||
:class="form.bg_color === p.bg ? 'shadow-[0_0_0_2px_var(--text-color)] border-2 border-[var(--surface-0,#fff)]' : 'border-0'"
|
||||
:style="{ backgroundColor: `#${p.bg}` }"
|
||||
:title="p.name"
|
||||
:disabled="saving || isEditLocked"
|
||||
@click="applyPreset(p)"
|
||||
>
|
||||
<i v-if="form.bg_color === p.bg" class="pi pi-check !text-[13px] text-white font-black p-1" />
|
||||
</button>
|
||||
|
||||
<!-- Custom ColorPicker -->
|
||||
<div
|
||||
class="w-7 h-7 rounded-full grid place-items-center cursor-pointer overflow-hidden relative transition-transform duration-[120ms] ease-in-out hover:scale-[1.18] hover:shadow-[0_3px_10px_rgba(0,0,0,0.2)]"
|
||||
:class="isCustomColor ? 'shadow-[0_0_0_2px_var(--text-color)]' : ''"
|
||||
style="background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red);"
|
||||
title="Cor personalizada"
|
||||
>
|
||||
<i
|
||||
v-if="isCustomColor"
|
||||
class="pi pi-check !text-[13px] text-white font-black absolute z-10 pointer-events-none drop-shadow-[0_1px_2px_rgba(0,0,0,0.6)]"
|
||||
/>
|
||||
<ColorPicker
|
||||
v-model="form.bg_color"
|
||||
format="hex"
|
||||
:disabled="saving || isEditLocked"
|
||||
class="absolute inset-0 [&_.p-colorpicker-preview]:w-full [&_.p-colorpicker-preview]:h-full [&_.p-colorpicker-preview]:border-0 [&_.p-colorpicker-preview]:rounded-full [&_.p-colorpicker-preview]:opacity-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Texto -->
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<span class="text-xs font-medium opacity-60 uppercase tracking-wide">Texto</span>
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="inline-flex items-center gap-[0.4rem] px-3 py-1 rounded-full border text-sm font-medium cursor-pointer transition-colors duration-[120ms] disabled:cursor-not-allowed"
|
||||
:class="
|
||||
form.text_color === '#ffffff'
|
||||
? 'bg-[var(--surface-section,var(--surface-100))] border-[var(--primary-color)] text-[var(--primary-color)] font-bold'
|
||||
: 'bg-transparent border-[var(--surface-border)] text-[var(--text-color)] hover:bg-[var(--surface-hover)]'
|
||||
"
|
||||
:disabled="saving || isEditLocked"
|
||||
@click="form.text_color = '#ffffff'"
|
||||
>
|
||||
<span class="w-2.5 h-2.5 rounded-full inline-block border border-[#ccc]" style="background:#ffffff;" />
|
||||
Branco
|
||||
</button>
|
||||
<button
|
||||
class="inline-flex items-center gap-[0.4rem] px-3 py-1 rounded-full border text-sm font-medium cursor-pointer transition-colors duration-[120ms] disabled:cursor-not-allowed"
|
||||
:class="
|
||||
form.text_color === '#000000'
|
||||
? 'bg-[var(--surface-section,var(--surface-100))] border-[var(--primary-color)] text-[var(--primary-color)] font-bold'
|
||||
: 'bg-transparent border-[var(--surface-border)] text-[var(--text-color)] hover:bg-[var(--surface-hover)]'
|
||||
"
|
||||
:disabled="saving || isEditLocked"
|
||||
@click="form.text_color = '#000000'"
|
||||
>
|
||||
<span class="w-2.5 h-2.5 rounded-full inline-block" style="background:#000000;" />
|
||||
Preto
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Campos adicionais -->
|
||||
<div class="dc-section">
|
||||
<div class="border border-[var(--surface-border)] rounded-[6px] bg-[var(--surface-card)] p-4">
|
||||
<div class="flex items-center justify-between gap-2 mb-3">
|
||||
<div class="dc-section__label mb-0">Campos adicionais</div>
|
||||
<div class="text-[1rem] font-bold uppercase tracking-[0.06em] opacity-45">Campos adicionais</div>
|
||||
<Button
|
||||
label="Adicionar campo"
|
||||
icon="pi pi-plus"
|
||||
@@ -190,7 +195,7 @@
|
||||
<div
|
||||
v-for="(f, idx) in form.fields"
|
||||
:key="f.key"
|
||||
class="grid grid-cols-1 gap-2 rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-0)] p-3 md:grid-cols-12"
|
||||
class="grid grid-cols-1 gap-2 rounded-[6px] border border-[var(--surface-border)] bg-[var(--surface-0)] p-3 md:grid-cols-12"
|
||||
>
|
||||
<div class="md:col-span-6">
|
||||
<FloatLabel variant="on">
|
||||
@@ -233,14 +238,32 @@
|
||||
@click="removeField(idx)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-12 text-xs opacity-40 font-mono">
|
||||
key: {{ f.key }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer com botões Cancelar / Salvar -->
|
||||
<template #footer>
|
||||
<div class="flex items-center justify-end gap-2 pt-2">
|
||||
<Button
|
||||
label="Cancelar"
|
||||
severity="secondary"
|
||||
outlined
|
||||
class="rounded-full"
|
||||
:disabled="saving"
|
||||
@click="close"
|
||||
/>
|
||||
<Button
|
||||
label="Salvar"
|
||||
icon="pi pi-check"
|
||||
class="rounded-full"
|
||||
:loading="saving"
|
||||
:disabled="!canSubmit"
|
||||
@click="submit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
@@ -249,8 +272,9 @@ import { computed, reactive, watch } from 'vue'
|
||||
|
||||
import Textarea from 'primevue/textarea'
|
||||
import Dropdown from 'primevue/dropdown'
|
||||
import InputSwitch from 'primevue/inputswitch'
|
||||
import ColorPicker from 'primevue/colorpicker'
|
||||
import ToggleSwitch from 'primevue/toggleswitch'
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
@@ -281,6 +305,16 @@ const presetColors = [
|
||||
{ bg: '292524', text: '#ffffff', name: 'Escuro' },
|
||||
]
|
||||
|
||||
// bg_colors dos presets (sem #) para comparação
|
||||
const presetBgValues = presetColors.map(p => p.bg)
|
||||
|
||||
// Verdadeiro quando a cor atual não bate com nenhum preset
|
||||
const isCustomColor = computed(() => {
|
||||
if (!form.bg_color) return false
|
||||
const clean = String(form.bg_color).replace('#', '').toLowerCase()
|
||||
return !presetBgValues.includes(clean)
|
||||
})
|
||||
|
||||
function applyPreset (p) {
|
||||
if (props.saving) return
|
||||
form.bg_color = p.bg
|
||||
@@ -350,9 +384,9 @@ function hydrate () {
|
||||
}
|
||||
}
|
||||
|
||||
const isActiveLocked = computed(() => !!form.locked) // nativo+locked → sempre ativo, nunca pode desativar
|
||||
const isEditLocked = computed(() => false) // edição sempre permitida
|
||||
const isFieldsLocked = computed(() => false) // campos sempre editáveis
|
||||
const isActiveLocked = computed(() => !!form.locked)
|
||||
const isEditLocked = computed(() => false)
|
||||
const isFieldsLocked = computed(() => false)
|
||||
const canDelete = computed(() => !form.native)
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
@@ -408,13 +442,11 @@ function removeField (idx) {
|
||||
}
|
||||
|
||||
function syncKey (field) {
|
||||
// se o user renomear, a key acompanha (sem quebrar: simples por enquanto)
|
||||
const next = makeKey(field.label)
|
||||
field.key = next
|
||||
}
|
||||
|
||||
function makeKey (label) {
|
||||
|
||||
const k = String(label || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
@@ -424,100 +456,4 @@ function makeKey (label) {
|
||||
.replace(/(^_|_$)/g, '') || `field_${Math.random().toString(16).slice(2, 8)}`
|
||||
return k
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* ── Header ─────────────────────────────── */
|
||||
.dc-header-dot {
|
||||
width: 14px; height: 14px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255,255,255,0.3);
|
||||
box-shadow: 0 0 0 3px rgba(0,0,0,0.08);
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
/* ── Banner de preview ───────────────────── */
|
||||
.dc-banner {
|
||||
height: 72px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
transition: background-color 0.25s ease;
|
||||
}
|
||||
.dc-banner__pill {
|
||||
font-size: 1rem; font-weight: 700; letter-spacing: -0.02em;
|
||||
padding: 0.35rem 1.1rem;
|
||||
background: rgba(0,0,0,0.15);
|
||||
border-radius: 999px;
|
||||
backdrop-filter: blur(4px);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
/* ── Section ─────────────────────────────── */
|
||||
.dc-section {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 1.25rem;
|
||||
background: var(--surface-card);
|
||||
padding: 1rem;
|
||||
}
|
||||
.dc-section__label {
|
||||
font-size: 0.7rem; font-weight: 700;
|
||||
text-transform: uppercase; letter-spacing: 0.06em;
|
||||
opacity: 0.45; margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
/* ── Paleta ──────────────────────────────── */
|
||||
.dc-palette {
|
||||
display: flex; flex-wrap: wrap; gap: 0.45rem;
|
||||
}
|
||||
.dc-swatch {
|
||||
width: 28px; height: 28px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid transparent;
|
||||
display: grid; place-items: center;
|
||||
cursor: pointer;
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
|
||||
position: relative;
|
||||
}
|
||||
.dc-swatch:hover:not(:disabled) {
|
||||
transform: scale(1.18);
|
||||
box-shadow: 0 3px 10px rgba(0,0,0,0.2);
|
||||
}
|
||||
.dc-swatch--active {
|
||||
border-color: var(--surface-0, #fff);
|
||||
box-shadow: 0 0 0 2px var(--text-color);
|
||||
}
|
||||
.dc-swatch__check {
|
||||
font-size: 0.6rem; color: #fff; font-weight: 900;
|
||||
}
|
||||
.dc-swatch--custom {
|
||||
background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red);
|
||||
overflow: hidden;
|
||||
}
|
||||
.dc-swatch--custom :deep(.p-colorpicker-preview) {
|
||||
width: 100%; height: 100%;
|
||||
border: none; border-radius: 50%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ── Texto toggle ────────────────────────── */
|
||||
.dc-text-opt {
|
||||
display: inline-flex; align-items: center; gap: 0.4rem;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--surface-border);
|
||||
font-size: 0.8rem; font-weight: 500;
|
||||
cursor: pointer;
|
||||
color: var(--text-color);
|
||||
background: transparent;
|
||||
transition: background 0.12s, border-color 0.12s;
|
||||
}
|
||||
.dc-text-opt:hover:not(:disabled) { background: var(--surface-hover); }
|
||||
.dc-text-opt--active {
|
||||
background: var(--surface-section, var(--surface-100));
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
font-weight: 700;
|
||||
}
|
||||
.dc-text-opt__dot {
|
||||
width: 10px; height: 10px; border-radius: 50%; display: inline-block;
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
@@ -3,141 +3,102 @@
|
||||
<Toast />
|
||||
<ConfirmDialog />
|
||||
|
||||
<!-- Sentinel para detecção de sticky -->
|
||||
<!-- Sentinel -->
|
||||
<div ref="headerSentinelRef" class="ag-sentinel" />
|
||||
|
||||
<!-- Hero Header sticky -->
|
||||
<div ref="headerEl" class="ag-hero mx-3 md:mx-5 mb-3" :class="{ 'ag-hero--stuck': headerStuck }">
|
||||
<!-- Blobs decorativos -->
|
||||
<div class="ag-hero__blobs" aria-hidden="true">
|
||||
<div class="ag-hero__blob ag-hero__blob--1" />
|
||||
<div class="ag-hero__blob ag-hero__blob--2" />
|
||||
<div class="ag-hero__blob ag-hero__blob--3" />
|
||||
<!-- Topbar compacta sticky -->
|
||||
<div ref="headerEl" class="ag-topbar mx-3 md:mx-4 mb-3" :class="{ 'ag-topbar--stuck': headerStuck }">
|
||||
<div class="ag-topbar__blobs" aria-hidden="true">
|
||||
<div class="ag-topbar__blob ag-topbar__blob--1" />
|
||||
<div class="ag-topbar__blob ag-topbar__blob--2" />
|
||||
</div>
|
||||
<div class="ag-topbar__inner">
|
||||
|
||||
<!-- Linha 1: brand + controles -->
|
||||
<div class="ag-hero__row1">
|
||||
<!-- Brand -->
|
||||
<div class="ag-hero__brand">
|
||||
<div class="ag-hero__icon">
|
||||
<i class="pi pi-calendar text-lg" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<div class="ag-hero__title">Agenda</div>
|
||||
<div class="ag-hero__sub">{{ subtitleText }}</div>
|
||||
<div class="ag-topbar__brand">
|
||||
<div class="ag-topbar__icon"><i class="pi pi-calendar text-base" /></div>
|
||||
<div class="min-w-0 hidden xl:block">
|
||||
<div class="ag-topbar__title">Agenda · Clínica</div>
|
||||
<div class="ag-topbar__sub">{{ subtitleText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Controles desktop (≥1200px) -->
|
||||
<div class="ag-hero__desktop-controls">
|
||||
<!-- Navegação (sempre visível) -->
|
||||
<div class="flex items-center gap-1">
|
||||
<Button label="Hoje" severity="secondary" outlined size="small" class="rounded-full" @click="goToday" />
|
||||
<Button icon="pi pi-chevron-left" severity="secondary" outlined class="h-8 w-8 rounded-full" @click="goPrev" />
|
||||
<Button icon="pi pi-chevron-right" severity="secondary" outlined class="h-8 w-8 rounded-full" @click="goNext" />
|
||||
<Button :label="visibleTitle" icon="pi pi-calendar" severity="secondary" outlined size="small" class="rounded-full" @click="toggleMonthPicker" />
|
||||
</div>
|
||||
<!-- Navegação -->
|
||||
<div class="ag-topbar__nav">
|
||||
<Button label="Hoje" severity="secondary" outlined size="small" class="rounded-full hidden lg:flex" @click="goToday" />
|
||||
<Button icon="pi pi-chevron-left" severity="secondary" outlined class="h-8 w-8 rounded-full" @click="goPrev" />
|
||||
<span class="ag-topbar__date-pill" @click="toggleMonthPicker">
|
||||
<i class="pi pi-calendar text-xs opacity-60" />
|
||||
{{ subtitleText }}
|
||||
</span>
|
||||
<Button icon="pi pi-chevron-right" severity="secondary" outlined class="h-8 w-8 rounded-full" @click="goNext" />
|
||||
</div>
|
||||
|
||||
<!-- Busca (oculta quando colado) -->
|
||||
<div v-if="!headerStuck" class="w-[260px]">
|
||||
<!-- Filtros (desktop) -->
|
||||
<div class="ag-topbar__filters hidden xl:flex items-center gap-1.5">
|
||||
<SelectButton v-model="calendarView" :options="viewOptions" optionLabel="label" optionValue="value" :allowEmpty="false" size="small" />
|
||||
<SelectButton v-model="timeMode" :options="timeModeOptions" optionLabel="label" optionValue="value" :allowEmpty="false" size="small" />
|
||||
<SelectButton v-model="onlySessions" :options="onlySessionsOptions" optionLabel="label" optionValue="value" :allowEmpty="false" size="small" />
|
||||
<SelectButton v-model="mosaicMode" :options="mosaicModeOptions" optionLabel="label" optionValue="value" :allowEmpty="false" size="small" />
|
||||
</div>
|
||||
|
||||
<!-- Ações -->
|
||||
<div class="ag-topbar__actions">
|
||||
<!-- Busca desktop -->
|
||||
<div class="hidden xl:block w-44">
|
||||
<FloatLabel variant="on">
|
||||
<IconField>
|
||||
<InputIcon class="pi pi-search" />
|
||||
<InputText id="agendaSearch" v-model="search" class="w-full" autocomplete="off" @keyup.enter="openSearchModal" />
|
||||
</IconField>
|
||||
<label for="agendaSearch">Buscar paciente...</label>
|
||||
<label for="agendaSearch">Buscar...</label>
|
||||
</FloatLabel>
|
||||
</div>
|
||||
|
||||
<!-- Ações rápidas -->
|
||||
<div class="flex items-center gap-1">
|
||||
<!-- Badge: feriados próximos sem bloqueio -->
|
||||
<div v-if="feriadosTodosProximos.length" class="relative">
|
||||
<Button
|
||||
icon="pi pi-bell"
|
||||
:severity="feriadosSemBloqueio.length ? 'danger' : 'secondary'"
|
||||
outlined
|
||||
class="h-9 w-9 rounded-full"
|
||||
v-tooltip.bottom="feriadosSemBloqueio.length
|
||||
? `${feriadosSemBloqueio.length} feriado(s) sem bloqueio nos próximos 30 dias`
|
||||
: `${feriadosTodosProximos.length} feriado(s) gerenciados`"
|
||||
@click="feriadosAlertaOpen = true"
|
||||
/>
|
||||
<span v-if="feriadosSemBloqueio.length" class="ag-badge">{{ feriadosSemBloqueio.length }}</span>
|
||||
</div>
|
||||
<Button v-if="!headerStuck" label="Bloquear" icon="pi pi-lock" size="small" class="rounded-full" severity="danger" outlined @click="(e) => blockMenuRef.toggle(e)" />
|
||||
<Menu ref="blockMenuRef" :model="blockMenuItems" :popup="true" />
|
||||
<Button icon="pi pi-plus" class="h-9 w-9 rounded-full" title="Novo compromisso" @click="onCreateFromButton" />
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Recarregar" @click="refetch" />
|
||||
<Button icon="pi pi-sync" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Recorrências" @click="goRecorrencias" />
|
||||
<Button icon="pi pi-cog" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Configurações" @click="goSettings" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Menu mobile (<1200px) -->
|
||||
<div class="ag-hero__mobile-controls">
|
||||
<!-- Sino: feriados próximos -->
|
||||
<!-- Sino feriados -->
|
||||
<div v-if="feriadosTodosProximos.length" class="relative">
|
||||
<Button
|
||||
icon="pi pi-bell"
|
||||
:severity="feriadosSemBloqueio.length ? 'danger' : 'secondary'"
|
||||
outlined
|
||||
class="h-9 w-9 rounded-full"
|
||||
@click="feriadosAlertaOpen = true"
|
||||
/>
|
||||
<Button icon="pi pi-bell" :severity="feriadosSemBloqueio.length ? 'danger' : 'secondary'" outlined class="h-9 w-9 rounded-full" @click="feriadosAlertaOpen = true" />
|
||||
<span v-if="feriadosSemBloqueio.length" class="ag-badge">{{ feriadosSemBloqueio.length }}</span>
|
||||
</div>
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => headerMenuRef.toggle(e)" />
|
||||
<Menu ref="headerMenuRef" :model="headerMenuItems" :popup="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Divisor -->
|
||||
<Divider class="ag-hero__divider my-2" />
|
||||
<Button icon="pi pi-plus" class="h-9 w-9 rounded-full" title="Novo compromisso" @click="onCreateFromButton" />
|
||||
|
||||
<!-- Linha 2: filtros -->
|
||||
<div class="ag-hero__row2">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm opacity-60">Exibir:</span>
|
||||
<SelectButton v-model="onlySessions" :options="onlySessionsOptions" optionLabel="label" optionValue="value" :allowEmpty="false" />
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1">
|
||||
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="searchModalOpen = true" />
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => headerMenuRef.toggle(e)" />
|
||||
<Menu ref="headerMenuRef" :model="headerMenuItems" :popup="true" />
|
||||
</div>
|
||||
<SelectButton v-model="calendarView" :options="viewOptions" optionLabel="label" optionValue="value" :allowEmpty="false" />
|
||||
<SelectButton v-model="timeMode" :options="timeModeOptions" optionLabel="label" optionValue="value" :allowEmpty="false" />
|
||||
</div>
|
||||
|
||||
<div v-if="searchTrim" class="flex items-center gap-2">
|
||||
<Tag :value="`Busca: ${searchTrim}`" severity="secondary" />
|
||||
<Button label="Limpar" icon="pi pi-times" text severity="secondary" size="small" @click="clearSearch" />
|
||||
<Button v-if="searchResults.length" :label="`Ver resultados (${searchResults.length})`" icon="pi pi-list" severity="secondary" outlined size="small" class="rounded-full" @click="openSearchModal" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Aviso: eventos fora da jornada de trabalho -->
|
||||
<div
|
||||
v-if="hasEventsOutsideWorkHours"
|
||||
class="mx-3 md:mx-5 mb-3 rounded-2xl p-3"
|
||||
style="background: color-mix(in srgb, var(--yellow-400, #facc15) 10%, var(--surface-card)); border: 1px solid color-mix(in srgb, var(--yellow-400, #facc15) 35%, transparent);"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<i class="pi pi-exclamation-triangle shrink-0 mt-0.5" style="color: var(--yellow-600, #ca8a04);" />
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="font-semibold text-sm">Existem compromissos fora da jornada de trabalho</div>
|
||||
<div class="text-xs opacity-70 mt-0.5">A exibição foi ajustada para <b>24h</b> automaticamente. Caso queira visualizar com horário reduzido (e aceite não ver alguns compromissos), escolha abaixo:</div>
|
||||
<div class="flex gap-2 mt-2 flex-wrap">
|
||||
<Button label="Meu Horário" size="small" severity="secondary" outlined class="rounded-full" @click="timeMode = 'my'" />
|
||||
<Button label="12h" size="small" severity="secondary" outlined class="rounded-full" @click="timeMode = '12'" />
|
||||
<!-- Desktop: extras -->
|
||||
<div class="hidden xl:flex items-center gap-1">
|
||||
<Button label="Bloquear" icon="pi pi-lock" size="small" class="rounded-full" severity="danger" outlined @click="(e) => blockMenuRef.toggle(e)" />
|
||||
<Menu ref="blockMenuRef" :model="blockMenuItems" :popup="true" />
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="refetch" />
|
||||
<Button icon="pi pi-sync" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Recorrências" @click="goRecorrencias" />
|
||||
<Button icon="pi pi-cog" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="goSettings" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout: 2 colunas -->
|
||||
<div class="flex flex-col lg:flex-row gap-4 px-3 md:px-5 pb-5">
|
||||
<!-- Coluna maior -->
|
||||
<div class="w-full lg:flex-1 lg:order-2 min-w-0">
|
||||
<div class="overflow-hidden rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-card)] shadow-sm">
|
||||
<!-- Aviso: fora da jornada -->
|
||||
<div v-if="hasEventsOutsideWorkHours" class="mx-3 md:mx-4 mb-3 rounded-[6px] p-3" style="background:color-mix(in srgb,var(--yellow-400,#facc15) 10%,var(--surface-card));border:1px solid color-mix(in srgb,var(--yellow-400,#facc15) 35%,transparent);">
|
||||
<div class="flex items-center gap-3">
|
||||
<i class="pi pi-exclamation-triangle shrink-0" style="color:var(--yellow-600,#ca8a04);" />
|
||||
<div class="font-semibold text-sm flex-1">Compromissos fora da jornada</div>
|
||||
<div class="flex gap-1 shrink-0">
|
||||
<Button label="Meu Horário" size="small" severity="secondary" outlined class="rounded-full" @click="timeMode = 'my'" />
|
||||
<Button label="12h" size="small" severity="secondary" outlined class="rounded-full" @click="timeMode = '12'" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout 2 colunas: calendário + sidebar -->
|
||||
<div class="flex flex-col xl:flex-row gap-3 px-3 md:px-4 pb-5 items-start">
|
||||
<!-- Col centro: calendário mosaic -->
|
||||
<div class="w-full xl:flex-1 min-w-0">
|
||||
<div class="ag-cal-wrap">
|
||||
<div class="p-2">
|
||||
<AgendaClinicMosaic
|
||||
ref="calendarRef"
|
||||
@@ -169,12 +130,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="w-full lg:basis-[24%] lg:max-w-[24%] lg:order-1">
|
||||
<!-- Resultados (DESKTOP) -->
|
||||
<div
|
||||
v-if="searchTrim"
|
||||
class="hidden sm:block mb-3 rounded-3xl border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 shadow-sm"
|
||||
>
|
||||
<div class="hidden xl:flex flex-col gap-3 w-full xl:w-[280px] shrink-0">
|
||||
<!-- Resultados -->
|
||||
<div v-if="searchTrim" class="ag-card">
|
||||
<div class="mb-2 flex items-center justify-between gap-2">
|
||||
<div class="min-w-0">
|
||||
<div class="font-semibold truncate">Resultados</div>
|
||||
@@ -220,40 +178,38 @@
|
||||
</div>
|
||||
|
||||
<!-- Mini calendário -->
|
||||
<div class="mb-3 rounded-3xl border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 shadow-sm">
|
||||
<div class="mb-2 flex items-center justify-between">
|
||||
<span class="font-semibold">Calendário</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<Button label="Hoje" severity="secondary" text class="h-9 rounded-full" @click="miniGoToday" />
|
||||
<Button icon="pi pi-chevron-left" severity="secondary" text class="h-9 w-9 rounded-full" @click="miniPrevMonth" />
|
||||
<Button icon="pi pi-chevron-right" severity="secondary" text class="h-9 w-9 rounded-full" @click="miniNextMonth" />
|
||||
<div class="ag-card">
|
||||
<div class="ag-card__head mb-1">
|
||||
<span class="ag-card__title"><i class="pi pi-calendar" />{{ visibleTitle }}</span>
|
||||
<div class="flex items-center gap-0.5">
|
||||
<Button icon="pi pi-home" severity="secondary" text class="h-7 w-7 rounded-full" v-tooltip.top="'Hoje'" @click="miniGoToday" />
|
||||
<Button icon="pi pi-chevron-left" severity="secondary" text class="h-7 w-7 rounded-full" @click="miniPrevMonth" />
|
||||
<Button icon="pi pi-chevron-right" severity="secondary" text class="h-7 w-7 rounded-full" @click="miniNextMonth" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Calendar
|
||||
v-model="miniDate"
|
||||
inline
|
||||
showWeek
|
||||
class="w-full"
|
||||
class="ag-mini-cal"
|
||||
@update:modelValue="onMiniPick"
|
||||
:pt="{ day: ({ context }) => ({ class: miniDayClass(context.date) }) }"
|
||||
>
|
||||
<template #date="{ date }">
|
||||
<span class="mini-day-num">{{ date.day }}</span>
|
||||
<span v-if="hasMiniEvent(date)" class="mini-day-dot" />
|
||||
</template>
|
||||
</Calendar>
|
||||
<template #date="{ date }">
|
||||
<span class="mini-day-num">{{ date.day }}</span>
|
||||
<span v-if="hasMiniEvent(date)" class="mini-day-dot" />
|
||||
</template>
|
||||
</Calendar>
|
||||
</div>
|
||||
|
||||
<ProximosFeriadosCard
|
||||
class="mb-3"
|
||||
:ownerId="clinicOwnerId"
|
||||
:tenantId="tenantId || ''"
|
||||
:workRules="workRules"
|
||||
@bloqueado="refetch"
|
||||
/>
|
||||
:ownerId="clinicOwnerId"
|
||||
:tenantId="tenantId || ''"
|
||||
:workRules="workRules"
|
||||
@bloqueado="refetch"
|
||||
/>
|
||||
|
||||
<div class="rounded-3xl border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 shadow-sm">
|
||||
<div class="ag-card">
|
||||
<Button label="Novo Compromisso" icon="pi pi-plus" class="w-full rounded-full" @click="onCreateFromButton" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -2452,76 +2408,92 @@ function goRecorrencias () { router.push({ name: 'admin-agenda-recorrencias' })
|
||||
:deep(.evt-private) { opacity: 0.9; filter: saturate(0.25); }
|
||||
:deep(.evt-private.fc-event) { border-style: dashed; }
|
||||
|
||||
/* ── Hero Header ─────────────────────────────────── */
|
||||
/* ── Topbar ─────────────────────────────────────────── */
|
||||
.ag-sentinel { height: 1px; }
|
||||
|
||||
.ag-hero {
|
||||
.ag-topbar {
|
||||
position: sticky;
|
||||
top: var(--layout-sticky-top, 56px);
|
||||
z-index: 20;
|
||||
overflow: hidden;
|
||||
border-radius: 1.75rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--surface-border);
|
||||
background: var(--surface-card);
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
.ag-hero--stuck {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
.ag-topbar--stuck { border-top-left-radius: 0; border-top-right-radius: 0; }
|
||||
.ag-topbar__blobs { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
|
||||
.ag-topbar__blob { position: absolute; border-radius: 50%; filter: blur(60px); }
|
||||
.ag-topbar__blob--1 { width: 16rem; height: 16rem; top: -4rem; right: -2rem; background: rgba(99,102,241,0.10); }
|
||||
.ag-topbar__blob--2 { width: 18rem; height: 18rem; top: 0; left: -4rem; background: rgba(52,211,153,0.07); }
|
||||
|
||||
/* Blobs */
|
||||
.ag-hero__blobs { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
|
||||
.ag-hero__blob { position: absolute; border-radius: 50%; filter: blur(70px); }
|
||||
.ag-hero__blob--1 { width: 18rem; height: 18rem; top: -4rem; right: -3rem; background: rgba(99,102,241,0.12); }
|
||||
.ag-hero__blob--2 { width: 20rem; height: 20rem; top: 0.5rem; left: -5rem; background: rgba(52,211,153,0.09); }
|
||||
.ag-hero__blob--3 { width: 14rem; height: 14rem; bottom: -2rem; right: 22%; background: rgba(217,70,239,0.08); }
|
||||
|
||||
/* Linha 1 */
|
||||
.ag-hero__row1 {
|
||||
.ag-topbar__inner {
|
||||
position: relative; z-index: 1;
|
||||
display: flex; align-items: center; gap: 1rem;
|
||||
display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;
|
||||
}
|
||||
.ag-hero__brand {
|
||||
display: flex; align-items: center; gap: 0.75rem;
|
||||
flex-shrink: 0; min-width: 0;
|
||||
}
|
||||
.ag-hero__icon {
|
||||
.ag-topbar__brand { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
|
||||
.ag-topbar__icon {
|
||||
display: grid; place-items: center;
|
||||
width: 2.5rem; height: 2.5rem; border-radius: 0.875rem;
|
||||
flex-shrink: 0;
|
||||
width: 2.25rem; height: 2.25rem; border-radius: 6px; flex-shrink: 0;
|
||||
background: color-mix(in srgb, var(--p-primary-500, #6366f1) 12%, transparent);
|
||||
color: var(--p-primary-500, #6366f1);
|
||||
}
|
||||
.ag-hero__title {
|
||||
font-size: 1.1rem; font-weight: 700; letter-spacing: -0.02em;
|
||||
color: var(--text-color); white-space: nowrap;
|
||||
.ag-topbar__title { font-size: 1rem; font-weight: 700; letter-spacing: -0.02em; color: var(--text-color); }
|
||||
.ag-topbar__sub { font-size: 0.75rem; color: var(--text-color-secondary); }
|
||||
.ag-topbar__nav { display: flex; align-items: center; gap: 0.25rem; }
|
||||
.ag-topbar__date-pill {
|
||||
display: inline-flex; align-items: center; gap: 0.35rem;
|
||||
padding: 0.25rem 0.75rem; border-radius: 999px;
|
||||
border: 1px solid var(--surface-border); background: var(--surface-ground);
|
||||
font-size: 0.8rem; font-weight: 600; color: var(--text-color);
|
||||
cursor: pointer; white-space: nowrap; transition: border-color 0.15s;
|
||||
}
|
||||
.ag-hero__sub {
|
||||
font-size: 0.78rem; color: var(--text-color-secondary); margin-top: 2px;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
.ag-topbar__date-pill:hover { border-color: var(--p-primary-400); }
|
||||
.ag-topbar__filters { flex-shrink: 0; }
|
||||
.ag-topbar__actions { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }
|
||||
|
||||
/* ── Badge ────────────────────────────────────────────── */
|
||||
.ag-badge {
|
||||
position: absolute; top: -4px; right: -4px;
|
||||
min-width: 16px; height: 16px; border-radius: 999px; padding: 0 4px;
|
||||
background: var(--red-500, #ef4444); color: #fff;
|
||||
font-size: 0.65rem; font-weight: 700;
|
||||
display: flex; align-items: center; justify-content: center; pointer-events: none;
|
||||
}
|
||||
|
||||
.ag-hero__desktop-controls {
|
||||
flex: 1; display: flex; align-items: center;
|
||||
justify-content: flex-end; gap: 0.75rem; flex-wrap: wrap;
|
||||
}
|
||||
.ag-hero__mobile-controls { display: none; }
|
||||
|
||||
/* Linha 2 */
|
||||
.ag-hero__row2 {
|
||||
display: flex; flex-wrap: wrap; align-items: center;
|
||||
justify-content: space-between; gap: 0.75rem;
|
||||
/* ── Calendar wrap ──────────────────────────────────── */
|
||||
.ag-cal-wrap {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 6px; background: var(--surface-card); overflow: hidden;
|
||||
}
|
||||
|
||||
/* Mobile < 1200px */
|
||||
@media (max-width: 1199px) {
|
||||
.ag-hero__desktop-controls { display: none; }
|
||||
.ag-hero__mobile-controls { display: flex; margin-left: auto; }
|
||||
.ag-hero__divider,
|
||||
.ag-hero__row2 { display: none; }
|
||||
/* ── Sidebar cards ──────────────────────────────────── */
|
||||
.ag-card {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 6px; background: var(--surface-card); padding: 0.75rem;
|
||||
}
|
||||
.ag-card__head { display: flex; align-items: center; justify-content: space-between; }
|
||||
.ag-card__title {
|
||||
display: flex; align-items: center; gap: 0.35rem;
|
||||
font-size: 0.7rem; font-weight: 700;
|
||||
text-transform: uppercase; letter-spacing: 0.06em;
|
||||
color: var(--text-color-secondary); opacity: 0.65;
|
||||
}
|
||||
|
||||
/* ── Mini calendário ────────────────────────────────── */
|
||||
:deep(.ag-mini-cal .p-datepicker) { width: 100%; border: none; padding: 0; background: transparent; box-shadow: none; }
|
||||
:deep(.ag-mini-cal .p-datepicker-header) { padding: 0 0 0.5rem; border: none; background: transparent; }
|
||||
:deep(.ag-mini-cal .p-datepicker-calendar) { width: 100%; font-size: 0.78rem; }
|
||||
:deep(.ag-mini-cal .p-datepicker-calendar td) { padding: 1px; }
|
||||
:deep(.ag-mini-cal .p-datepicker-calendar td > span) {
|
||||
width: 100%; min-width: unset; border-radius: 6px;
|
||||
position: relative; display: flex; align-items: center; justify-content: center; aspect-ratio: 1;
|
||||
}
|
||||
.mini-day-num { display: block; text-align: center; line-height: 1; }
|
||||
.mini-day-dot {
|
||||
position: absolute; bottom: 2px; right: 2px;
|
||||
width: 4px; height: 4px; border-radius: 50%;
|
||||
background: var(--primary-color, #6366f1);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user