templates/editor: layout 3-col + tabs cabecalho/corpo/rodape
Refatora DocumentTemplateEditor em 3 colunas seguindo padrao
MelissaAgendaConfig:
- COL 1 (esquerda, 240-280px): form de metadados — nome, tipo,
descricao (Textarea com autoResize), URL do logo
- COL 2 (centro, flex 1): sub-tabs Cabecalho/Corpo/Rodape, 1
editor visivel por vez. Cada editor com minHeight: 450px (era
120/350/120). Tab ativa destacada com border-bottom primary +
background sutil.
- COL 3 (direita, 220-260px): variaveis agrupadas por categoria,
hint dinamico mostrando qual sub-tab esta ativa ("Clique para
inserir no Cabecalho/Corpo/Rodape"). Botoes com {{ }} braces
em monospace + cor primary.
Scroll interno:
- .dte-page flex column, gap 12, min-height 0, padding 12
- Cada coluna eh card (border + radius) com header sticky + body
scrollable interno (overflow-y: auto, scrollbar-width: thin)
- Variaveis com max-height proprio + scroll interno
Mobile (<1024px):
- 3-col vira 1-col stacked
- Container do .dte-cols ganha overflow-y auto (scroll da pagina
inteira em vez de scroll interno em cada coluna)
- Variaveis ganha max-height 320px pra nao ocupar a tela toda
Preview (toggle no topo):
- Documento A4-like centralizado (max-width 794px ≈ 96dpi)
- Padding 48/56px, shadow sutil
- Mobile: padding reduzido pra max width disponivel
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,8 @@ const emit = defineEmits(['update:modelValue', 'save', 'cancel'])
|
||||
const { TIPOS_TEMPLATE, TEMPLATE_VARIABLES, variablesGrouped, previewHtml } = useDocumentTemplates()
|
||||
|
||||
const activeTab = ref('editor') // editor | preview
|
||||
// Sub-tab do editor (centro do layout 3-col): qual seção renderiza
|
||||
const editorTab = ref('corpo') // cabecalho | corpo | rodape
|
||||
|
||||
// ── Form reativo synced com modelValue ──────────────────────
|
||||
|
||||
@@ -89,47 +91,339 @@ function onSave() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-3 xl:gap-4">
|
||||
<!-- ══ Card: Identificação ══════════════════════════════ -->
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<div class="flex items-center gap-2 px-4 py-3 border-b border-[var(--surface-border,#e2e8f0)]">
|
||||
<i class="pi pi-tag text-[var(--text-color-secondary)] opacity-60" />
|
||||
<span class="font-semibold text-sm">Identificação</span>
|
||||
</div>
|
||||
<div class="p-4 flex flex-col gap-3">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-[1fr_220px] gap-3">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">Nome do template</label>
|
||||
<InputText v-model="form.nome_template" placeholder="Ex: Declaração de comparecimento" class="w-full" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">Tipo</label>
|
||||
<Select v-model="form.tipo" :options="TIPOS_TEMPLATE" optionLabel="label" optionValue="value" class="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">Descrição</label>
|
||||
<InputText v-model="form.descricao" placeholder="Breve descrição do template" class="w-full" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">URL do logo (opcional)</label>
|
||||
<InputText v-model="form.logo_url" placeholder="https://..." class="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style scoped>
|
||||
/* ═══════ Page chrome (preenche o espaço do container pai) ═══════ */
|
||||
.dte-page {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
/* padding pra não grudar nas bordas do container pai (mdt-body) */
|
||||
padding: 12px;
|
||||
/* fallback pra quando o pai não é flex */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
<!-- ══ Card: Conteúdo ═══════════════════════════════════ -->
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<div class="flex items-center justify-between gap-2 px-4 py-3 border-b border-[var(--surface-border,#e2e8f0)]">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<i class="pi pi-file-edit text-[var(--text-color-secondary)] opacity-60" />
|
||||
<span class="font-semibold text-sm">Conteúdo do documento</span>
|
||||
.dte-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dte-toolbar__title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 0.92rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.dte-toolbar__title > i {
|
||||
color: var(--text-color-secondary);
|
||||
opacity: 0.7;
|
||||
}
|
||||
.dte-toolbar__tabs {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* ═══════ 3-col grid (form / editor / variáveis) ═══════ */
|
||||
.dte-cols {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(240px, 280px) minmax(0, 1fr) minmax(220px, 260px);
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
/* COL 1 — Form metadados */
|
||||
.dte-side {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dte-side__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 14px;
|
||||
border-bottom: 1px solid var(--surface-border);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dte-side__head > i {
|
||||
color: var(--text-color-secondary);
|
||||
opacity: 0.7;
|
||||
}
|
||||
.dte-side__body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.dte-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.dte-field label {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
|
||||
/* COL 2 — Editor com sub-tabs */
|
||||
.dte-main {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dte-main__tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
border-bottom: 1px solid var(--surface-border);
|
||||
background: var(--surface-ground);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dte-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 18px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
color: var(--text-color-secondary);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: color 140ms ease, border-color 140ms ease, background-color 140ms ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
.dte-tab:hover {
|
||||
color: var(--text-color);
|
||||
background: color-mix(in srgb, var(--p-primary-color) 4%, transparent);
|
||||
}
|
||||
.dte-tab.is-active {
|
||||
color: var(--p-primary-color);
|
||||
border-bottom-color: var(--p-primary-color);
|
||||
background: color-mix(in srgb, var(--p-primary-color) 6%, transparent);
|
||||
}
|
||||
.dte-tab > i { font-size: 0.82rem; }
|
||||
|
||||
.dte-main__editor {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 14px;
|
||||
background: var(--surface-card);
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.dte-editor-wrap {
|
||||
min-height: 450px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.dte-editor-wrap > * {
|
||||
flex: 1;
|
||||
min-height: 450px;
|
||||
}
|
||||
|
||||
/* COL 3 — Variáveis */
|
||||
.dte-vars {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dte-vars__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 14px 8px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dte-vars__head > i {
|
||||
color: var(--p-primary-color);
|
||||
}
|
||||
.dte-vars__hint {
|
||||
margin: 0 14px 6px;
|
||||
font-size: 0.72rem;
|
||||
color: var(--text-color-secondary);
|
||||
line-height: 1.4;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dte-vars__hint strong {
|
||||
color: var(--text-color);
|
||||
}
|
||||
.dte-vars__list {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 4px 10px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.dte-vars__group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.dte-vars__group-title {
|
||||
font-size: 0.62rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--text-color-secondary);
|
||||
opacity: 0.75;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.dte-vars__group-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
.dte-vars__btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 8px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
color: var(--text-color);
|
||||
font-size: 0.74rem;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: background-color 120ms ease, color 120ms ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
.dte-vars__btn:hover {
|
||||
background: color-mix(in srgb, var(--p-primary-color) 10%, transparent);
|
||||
color: var(--p-primary-color);
|
||||
}
|
||||
.dte-vars__btn-brace {
|
||||
font-family: 'JetBrains Mono', 'Consolas', monospace;
|
||||
font-size: 0.66rem;
|
||||
color: var(--p-primary-color);
|
||||
opacity: 0.6;
|
||||
}
|
||||
.dte-vars__btn-label {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ═══════ Preview ═══════ */
|
||||
.dte-preview {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
background: var(--surface-ground);
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.dte-preview__doc {
|
||||
background: white;
|
||||
color: #1a1a1a;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
width: 100%;
|
||||
max-width: 794px; /* ≈ A4 a 96dpi */
|
||||
padding: 48px 56px;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-size: 12pt;
|
||||
line-height: 1.6;
|
||||
min-height: 500px;
|
||||
}
|
||||
.dte-preview__header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.dte-preview__body {
|
||||
min-height: 300px;
|
||||
}
|
||||
.dte-preview__footer {
|
||||
margin-top: 32px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #ccc;
|
||||
text-align: center;
|
||||
font-size: 10pt;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* ═══════ Mobile (<1024px): empilha 1 col ═══════ */
|
||||
@media (max-width: 1023px) {
|
||||
.dte-cols {
|
||||
grid-template-columns: 1fr;
|
||||
overflow-y: auto;
|
||||
align-items: start;
|
||||
}
|
||||
.dte-side,
|
||||
.dte-main,
|
||||
.dte-vars {
|
||||
height: auto;
|
||||
}
|
||||
.dte-vars__list {
|
||||
max-height: 320px;
|
||||
}
|
||||
.dte-preview {
|
||||
padding: 12px;
|
||||
}
|
||||
.dte-preview__doc {
|
||||
padding: 24px 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="dte-page">
|
||||
<!-- ══ Toggle Editor / Preview no topo ══════════════════ -->
|
||||
<div class="dte-toolbar">
|
||||
<div class="dte-toolbar__title">
|
||||
<i class="pi pi-file-edit" />
|
||||
<span>Conteúdo do documento</span>
|
||||
</div>
|
||||
<!-- Tabs: Editor / Preview -->
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="dte-toolbar__tabs">
|
||||
<Button
|
||||
:label="'Editor'"
|
||||
label="Editor"
|
||||
icon="pi pi-pencil"
|
||||
:severity="activeTab === 'editor' ? undefined : 'secondary'"
|
||||
:outlined="activeTab !== 'editor'"
|
||||
@@ -138,7 +432,7 @@ function onSave() {
|
||||
@click="activeTab = 'editor'"
|
||||
/>
|
||||
<Button
|
||||
:label="'Preview'"
|
||||
label="Preview"
|
||||
icon="pi pi-eye"
|
||||
:severity="activeTab === 'preview' ? undefined : 'secondary'"
|
||||
:outlined="activeTab !== 'preview'"
|
||||
@@ -149,67 +443,117 @@ function onSave() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Editor -->
|
||||
<div v-show="activeTab === 'editor'" class="p-4 flex flex-col lg:flex-row gap-4">
|
||||
<!-- Campos HTML -->
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-3">
|
||||
<div class="flex flex-col gap-1" @focusin="cursorField = 'cabecalho_html'">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">Cabeçalho</label>
|
||||
<JoditEmailEditor ref="editorCabecalho" v-model="form.cabecalho_html" :minHeight="120" layoutButtons :logoUrl="form.logo_url" />
|
||||
<!-- ══ EDITOR — 3 colunas (form / editor / variáveis) ══ -->
|
||||
<div v-show="activeTab === 'editor'" class="dte-cols">
|
||||
<!-- ─── COL 1 (esquerda): Form de metadados ─── -->
|
||||
<aside class="dte-side">
|
||||
<div class="dte-side__head">
|
||||
<i class="pi pi-tag" />
|
||||
<span>Identificação</span>
|
||||
</div>
|
||||
<div class="dte-side__body">
|
||||
<div class="dte-field">
|
||||
<label>Nome do template</label>
|
||||
<InputText v-model="form.nome_template" placeholder="Ex: Declaração de comparecimento" class="w-full" />
|
||||
</div>
|
||||
<div class="dte-field">
|
||||
<label>Tipo</label>
|
||||
<Select v-model="form.tipo" :options="TIPOS_TEMPLATE" optionLabel="label" optionValue="value" class="w-full" />
|
||||
</div>
|
||||
<div class="dte-field">
|
||||
<label>Descrição</label>
|
||||
<Textarea v-model="form.descricao" placeholder="Breve descrição do template" class="w-full" rows="3" autoResize />
|
||||
</div>
|
||||
<div class="dte-field">
|
||||
<label>URL do logo (opcional)</label>
|
||||
<InputText v-model="form.logo_url" placeholder="https://..." class="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- ─── COL 2 (centro): Tabs Cabeçalho/Corpo/Rodapé + editor ─── -->
|
||||
<main class="dte-main">
|
||||
<div class="dte-main__tabs">
|
||||
<button
|
||||
type="button"
|
||||
class="dte-tab"
|
||||
:class="{ 'is-active': editorTab === 'cabecalho' }"
|
||||
@click="editorTab = 'cabecalho'"
|
||||
>
|
||||
<i class="pi pi-align-left" />
|
||||
<span>Cabeçalho</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dte-tab"
|
||||
:class="{ 'is-active': editorTab === 'corpo' }"
|
||||
@click="editorTab = 'corpo'"
|
||||
>
|
||||
<i class="pi pi-align-justify" />
|
||||
<span>Corpo</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dte-tab"
|
||||
:class="{ 'is-active': editorTab === 'rodape' }"
|
||||
@click="editorTab = 'rodape'"
|
||||
>
|
||||
<i class="pi pi-align-center" />
|
||||
<span>Rodapé</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1" @focusin="cursorField = 'corpo_html'">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">Corpo do documento</label>
|
||||
<JoditEmailEditor ref="editorCorpo" v-model="form.corpo_html" :minHeight="350" />
|
||||
<div class="dte-main__editor">
|
||||
<div v-show="editorTab === 'cabecalho'" class="dte-editor-wrap" @focusin="cursorField = 'cabecalho_html'">
|
||||
<JoditEmailEditor ref="editorCabecalho" v-model="form.cabecalho_html" :minHeight="450" layoutButtons :logoUrl="form.logo_url" />
|
||||
</div>
|
||||
<div v-show="editorTab === 'corpo'" class="dte-editor-wrap" @focusin="cursorField = 'corpo_html'">
|
||||
<JoditEmailEditor ref="editorCorpo" v-model="form.corpo_html" :minHeight="450" />
|
||||
</div>
|
||||
<div v-show="editorTab === 'rodape'" class="dte-editor-wrap" @focusin="cursorField = 'rodape_html'">
|
||||
<JoditEmailEditor ref="editorRodape" v-model="form.rodape_html" :minHeight="450" layoutButtons :logoUrl="form.logo_url" />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="flex flex-col gap-1" @focusin="cursorField = 'rodape_html'">
|
||||
<label class="text-xs font-semibold text-[var(--text-color-secondary)]">Rodapé</label>
|
||||
<JoditEmailEditor ref="editorRodape" v-model="form.rodape_html" :minHeight="120" layoutButtons :logoUrl="form.logo_url" />
|
||||
<!-- ─── COL 3 (direita): Variáveis disponíveis ─── -->
|
||||
<aside class="dte-vars">
|
||||
<div class="dte-vars__head">
|
||||
<i class="pi pi-code" />
|
||||
<span>Variáveis</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Painel de variáveis -->
|
||||
<div class="w-full lg:w-[240px] shrink-0">
|
||||
<div class="lg:sticky lg:top-3 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)]/50 overflow-hidden">
|
||||
<div class="flex items-center gap-2 px-3 py-2 border-b border-[var(--surface-border,#e2e8f0)]">
|
||||
<i class="pi pi-code text-[var(--text-color-secondary)] opacity-60 text-xs" />
|
||||
<span class="font-semibold text-xs">Variáveis</span>
|
||||
</div>
|
||||
<div class="px-3 pt-2 text-[0.68rem] text-[var(--text-color-secondary)] opacity-75 italic">Clique para inserir no campo ativo</div>
|
||||
<div class="flex flex-col gap-3 p-3 max-h-[500px] overflow-y-auto">
|
||||
<div v-for="(vars, grupo) in variablesGrouped" :key="grupo">
|
||||
<div class="text-[0.62rem] font-semibold uppercase tracking-wider text-[var(--text-color-secondary)] mb-1">{{ grupo }}</div>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<p class="dte-vars__hint">
|
||||
Clique para inserir no
|
||||
<strong>{{ editorTab === 'cabecalho' ? 'Cabeçalho' : editorTab === 'rodape' ? 'Rodapé' : 'Corpo' }}</strong>.
|
||||
</p>
|
||||
<div class="dte-vars__list">
|
||||
<div v-for="(vars, grupo) in variablesGrouped" :key="grupo" class="dte-vars__group">
|
||||
<div class="dte-vars__group-title">{{ grupo }}</div>
|
||||
<div class="dte-vars__group-items">
|
||||
<button
|
||||
v-for="v in vars"
|
||||
:key="v.key"
|
||||
class="text-left text-xs px-2 py-1 rounded-md bg-transparent border-none hover:bg-[var(--primary-color,#6366f1)]/10 hover:text-[var(--primary-color,#6366f1)] transition-colors truncate cursor-pointer"
|
||||
class="dte-vars__btn"
|
||||
:title="v.key"
|
||||
@click="insertVariable(v.key)"
|
||||
>
|
||||
<span class="font-mono text-[0.62rem] opacity-60">{{</span>
|
||||
{{ v.label }}
|
||||
<span class="font-mono text-[0.62rem] opacity-60">}}</span>
|
||||
<span class="dte-vars__btn-brace">{{</span>
|
||||
<span class="dte-vars__btn-label">{{ v.label }}</span>
|
||||
<span class="dte-vars__btn-brace">}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<!-- Preview -->
|
||||
<div v-show="activeTab === 'preview'" class="p-4">
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-white overflow-hidden">
|
||||
<div class="p-6 text-black" style="font-family: 'Segoe UI', Arial, sans-serif; font-size: 12pt; line-height: 1.6;">
|
||||
<div v-if="form.cabecalho_html" class="text-center mb-4 pb-3 border-b border-gray-300" v-html="renderedCabecalho" />
|
||||
<div class="min-h-[300px]" v-html="renderedPreview" />
|
||||
<div v-if="form.rodape_html" class="mt-8 pt-3 border-t border-gray-300 text-center text-[10pt] text-gray-500" v-html="renderedRodape" />
|
||||
<!-- ══ PREVIEW — full width ════════════════════════════ -->
|
||||
<div v-show="activeTab === 'preview'" class="dte-preview">
|
||||
<div class="dte-preview__doc">
|
||||
<div v-if="form.cabecalho_html" class="dte-preview__header" v-html="renderedCabecalho" />
|
||||
<div class="dte-preview__body" v-html="renderedPreview" />
|
||||
<div v-if="form.rodape_html" class="dte-preview__footer" v-html="renderedRodape" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user