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:
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user