Melissa: paginas nativas cfg-* + temas + textos com fundo + drawer WA

CHROME COMPARTILHADO + 18 PAGINAS NATIVAS
- MelissaConfigPage: chrome unico (header, drawer mobile, sidebar com Configuracoes
  + FAQ slot, main com Suspense). Replica fake-dialog right rule e fica flush
  com o config-aside global.
- 18 wrappers finos (~25 linhas cada): cfg-precificacao, cfg-descontos,
  cfg-excecoes, cfg-convenios, cfg-wa, cfg-wa-pessoal, cfg-wa-oficial,
  cfg-wa-templates, cfg-conversas-tags/autoreply/optouts/sla/bots,
  cfg-lembretes, cfg-creditos-wa, cfg-sms, cfg-email-templates,
  cfg-recursos-extras, cfg-recursos-extras-extrato, cfg-auditoria.
- Cada wrapper usa defineAsyncComponent + Suspense pra evitar race com
  tenantStore no boot (loading travado em alguns chooser-style pages).
- MelissaLayout: imports + SECOES + MELISSA_NON_CONFIG_SLUGS + render
  conditions atualizados pra cobrir os 18 slugs.

PAGINAS LEGADAS DETECTAM CONTEXTO MELISSA
- ConfiguracoesWhatsappChooserPage, WhatsappPage, TwilioWhatsappPage,
  SmsPage, RecursosExtrasPage, EmailTemplatesPage, AddonsExtratoPage,
  AgendadorPage, ConversasAutoreplyPage: route.startsWith('/melissa')
  decide se router.push vai pro slug Melissa ou /configuracoes legado.
- Anchors <a href="/configuracoes/..."> (que recarregavam pagina e
  vazavam o usuario do Melissa) trocados por RouterLink context-aware.
- MelissaAgenda.goSettings agora vai pra /melissa/agenda-config.

PERSONALIZAR > TEMAS
- melissaThemes.js: catalogo Freud/Klein/Jung (wallpaper + cor primaria
  + preset Lara/Nora + surface).
- Toggle de tema aplica tudo de uma vez; persistido em melissa_prefs.themeName.
- Boot resolve themeName -> imagem via fetch + data URL (sem guardar
  data URL gigante no DB).
- onCustomFileChange/onClearBg invalidam themeName quando user mexe no bg.

PERSONALIZAR > FUNDO NOS TEXTOS
- Pref textBgEnabled em melissa_prefs.
- MelissaHeroClock: prop textBg envolve relogio/data/saudacao/resumo
  em <span class="hero-text"> que ganha bg branco/preto 60% + borda
  + padding + radius quando o toggle esta on.
- Vars --m-hero-text-bg / --m-hero-text-border flipam com light/dark.

TOP + DOCK COM GRADIENT HORIZONTAL
- Var --m-band: preto 80% (dark) / branco 80% (light).
- .melissa-topbar-band: gradiente cor->transparente (right->left) atras
  dos botoes do topo.
- .melissa-dock: gradiente cor->transparente (left->right) atras dos pins.

MELISSANEGOCIO ABSORVE MINHA EMPRESA
- Adiciona logo upload + preview "cartao de visita" (computeds
  enderecoLinhas/redesValidas/temDados/logoDisplay + redeIcon helper).
- Normaliza dados legados do cfg-empresa: redes_sociais.{rede} virou {name}.
- Preview teleporta entre 3 destinos baseado no viewport:
  mobile -> drawer; mid-desktop -> sidebar; wide-desktop (>=1340px) ->
  painel flutuante FORA do fake dialog (ancora no right edge + 14px gap,
  altura segue conteudo, header alinhado com header do dialog).
- Remove cfg-empresa de melissaConfigGrupos.js + COMPONENT_MAP do
  MelissaConfiguracoes; grupo "Empresa & Plataforma" -> "Plataforma".

CRONOMETRO -> SESSAO AGENDADA
- MelissaCronometro emite session-end ao parar com paciente selecionado
  (threshold 5s pra ignorar start/stop acidental).
- MelissaLayout.onCronometroSessionEnd busca agenda_eventos do paciente
  no dia (tipo='sessao'), pega o mais recente e grava em
  extra_fields.cronometro_duracao_seg + cronometro_parado_em.
- Toast: sucesso ("X min salvos") ou warn ("sessao nao encontrada").

CONVERSATIONDRAWER WHATSAPP-LIKE
- Nova imagem whatsapp-bg.jpg (renomeada de hash random) usada como
  tile (380px) no .cd-msgs.
- Light: bege #efeae2 + multiply blend.
- Dark: #0b141a + camada 78% sobre o doodle.
- Bubbles WA-style (verde out / branco-dark in com tails) ja existiam.

EXTRATO RECURSOS EXTRAS
- Filtros 2-por-linha em Melissa (vs 1/4 no /configuracoes).
- Cards de Resumo teleportam pro #cfg-page-side em Melissa
  (1-col empilhado no drawer; 4-col inline no /configuracoes).
- Botoes de exportar com flex-1 distribuidos em uma unica linha em
  desktop, wrap no mobile.
- DataTable scrollable em ambos os layouts.

OUTROS AJUSTES MENORES
- Cfg-conversas-autoreply: dias semana 4-cols em Melissa (vs 7-cols
  no /configuracoes).
- Cfg-creditos-wa: 1/2 por linha (vs 1/2/4) em Melissa.
- Cfg-recursos-extras: pacotes 1/2 (vs 1/2/4); "Em breve" 1-col.
- WhatsAppPage aba Templates: guia de formatacao teleporta pro side
  drawer em Melissa, deixando textareas full-width.
- ConfigPage chrome agora tem #cfg-page-actions target pros Teleport
  de acoes (refresh button etc).
- Imagens renomeadas em src/assets/themes/ (freudwebp/melainewebp/
  jungwebp.webp) e src/assets/whatsapp-bg.jpg.
- JoditTextEditor.vue novo (wrapper Jodit generico, sem features de email).
- MelissaConfigList.vue novo (lista compartilhada de configs pro drawer).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-07 23:48:18 -03:00
parent cc7841bd1f
commit 9966b5f175
60 changed files with 4785 additions and 713 deletions
@@ -1262,14 +1262,28 @@ function insertEmoji(emoji) {
/* Light: bege esverdeado clássico do WA. Dark: cinza profundo tipo
wallpaper de modo escuro. Adapta via CSS variable `--p-content-background`
pra harmonizar com o tema do app. */
/* Background do chat estilo WhatsApp.
Light: cor bege classica (#efeae2) com a imagem doodle por cima usando
mix-blend multiply pra integrar.
Dark: cor #0b141a (mesma do WhatsApp Web dark) + camada escura translucida
por cima da imagem pra dimming. */
.cd-msgs {
background-color: color-mix(in srgb, var(--p-content-background) 85%, #efeae2);
background-image:
radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--p-text-color) 4%, transparent) 1px, transparent 0);
background-size: 18px 18px;
background-color: #efeae2;
background-image: url('../../assets/whatsapp-bg.jpg');
background-size: 380px auto;
background-repeat: repeat;
background-blend-mode: multiply;
border-radius: 8px;
margin: 0 -2px;
}
:where(.p-dark, html.dark, [data-theme="dark"]) .cd-msgs,
.cd-msgs:where(.p-dark *, html.dark *, [data-theme="dark"] *) {
background-color: #0b141a;
background-image:
linear-gradient(rgba(11, 20, 26, 0.78), rgba(11, 20, 26, 0.78)),
url('../../assets/whatsapp-bg.jpg');
background-blend-mode: normal;
}
/* ─── Bolha (wrapper + content + meta) ─── */
.cd-bubble-wrap {
+118
View File
@@ -0,0 +1,118 @@
<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/components/ui/JoditTextEditor.vue
| Data: 2026
| Local: São Carlos/SP Brasil
|--------------------------------------------------------------------------
| © 2026 Todos os direitos reservados
|--------------------------------------------------------------------------
JoditTextEditor wrapper genérico do Jodit pra rich text simples
(bold/italic/underline + listas + link + eraser). Substitui o PrimeVue
<Editor> (Quill) em pontos onde a medição via JS do Quill colapsa
em flex layouts (ex: 3 editores empilhados num mesmo card).
Pra editor de e-mail com snippets de logo header/footer, use
JoditEmailEditor.vue (componente irmão, dedicado).
-->
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import { Jodit } from 'jodit/esm/index.js';
import 'jodit/es2021/jodit.min.css';
const props = defineProps({
modelValue: { type: String, default: '' },
minHeight: { type: Number, default: 120 },
placeholder: { type: String, default: '' }
});
const emit = defineEmits(['update:modelValue']);
const container = ref(null);
let jodit = null;
let _ignoreChange = false;
let _themeObserver = null;
function isDark() {
return document.documentElement.classList.contains('app-dark');
}
function buildConfig() {
return {
height: props.minHeight,
language: 'pt_br',
theme: isDark() ? 'dark' : 'default',
toolbarAdaptive: false,
toolbarSticky: false,
showCharsCounter: false,
showWordsCounter: false,
showXPathInStatusbar: false,
disablePlugins: ['about', 'stat'],
placeholder: props.placeholder,
// Toolbar enxuta — espelha o Quill que estava antes
// (bold/italic/underline + listas ordered/bullet + link).
buttons: [
'bold', 'italic', 'underline', '|',
'ul', 'ol', '|',
'link'
],
uploader: { insertImageAsBase64URI: false },
filebrowser: { ajax: { url: '' } }
};
}
function initJodit() {
if (jodit) {
jodit.destruct();
jodit = null;
}
jodit = Jodit.make(container.value, buildConfig());
if (props.modelValue) jodit.value = props.modelValue;
jodit.events.on('change', (content) => {
if (!_ignoreChange) emit('update:modelValue', content);
});
}
onMounted(() => {
initJodit();
// Re-cria o editor quando o tema muda (Jodit nao re-tema dinamicamente).
_themeObserver = new MutationObserver(() => {
const current = isDark() ? 'dark' : 'default';
if (jodit && jodit.o?.theme !== current) {
const saved = jodit.value;
initJodit();
if (saved) jodit.value = saved;
}
});
_themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
});
onBeforeUnmount(() => {
_themeObserver?.disconnect();
_themeObserver = null;
jodit?.destruct();
jodit = null;
});
watch(
() => props.modelValue,
(val) => {
if (!jodit) return;
if (jodit.value !== (val ?? '')) {
_ignoreChange = true;
jodit.value = val ?? '';
_ignoreChange = false;
}
}
);
</script>
<template>
<div ref="container" />
</template>