feat(campaigns/editor): "Variables" button — visible merge-tag reference

The previous discoverability path was clic-text → floating toolbar → {}
icon, which assumes the user already knows how to invoke Unlayer's merge
tag UI. A direct "Variables" button now opens a dialog listing all 9
placeholders grouped by category (Client / Offre / Système) with their
sample value and a click-to-copy action. Reads from the same mergeTags
config Unlayer consumes — single source of truth, no drift risk.

Banner inside hints at the upcoming CSV-driven custom variable feature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-05-22 09:14:56 -04:00
parent bf1253ac58
commit 10d3745b31

View File

@ -13,12 +13,9 @@
<q-chip v-if="lastSavedTs" dense size="sm" color="grey-2" text-color="grey-9" class="q-ml-sm" icon="cloud_done"> <q-chip v-if="lastSavedTs" dense size="sm" color="grey-2" text-color="grey-9" class="q-ml-sm" icon="cloud_done">
Sauvegardé · {{ lastSavedLabel }} Sauvegardé · {{ lastSavedLabel }}
</q-chip> </q-chip>
<q-btn flat dense icon="code" class="q-ml-sm" color="grey-7"> <q-btn flat dense icon="data_object" label="Variables" color="grey-8"
<q-tooltip max-width="320px"> class="q-ml-sm" @click="variablesOpen = true">
<strong>9 variables disponibles</strong> (Client / Offre / Système). <q-tooltip>Voir toutes les variables Mustache disponibles et leur exemple</q-tooltip>
Insertion : clic dans un texte barre flottante icône <code>{}</code> Merge Tags.
Marche aussi dans les champs URL (boutons, images, mailto).
</q-tooltip>
</q-btn> </q-btn>
<q-space /> <q-space />
<q-btn flat color="primary" icon="visibility" label="Aperçu inbox" class="q-mr-sm" @click="openPreview"> <q-btn flat color="primary" icon="visibility" label="Aperçu inbox" class="q-mr-sm" @click="openPreview">
@ -178,6 +175,57 @@
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</q-dialog> </q-dialog>
<!-- Variables dialog reference card showing every Mustache placeholder
the worker recognises, with its sample value and a click-to-copy
button so the user can paste it into any field that doesn't surface
Unlayer's Merge Tags icon (e.g. the email subject in the campaign
wizard, or a custom href). Source of truth is the same mergeTags
array passed to Unlayer below kept in sync via computed. -->
<q-dialog v-model="variablesOpen">
<q-card style="min-width: 540px; max-width: 720px">
<q-card-section class="row items-center q-pb-none">
<div class="text-h6"><q-icon name="data_object" class="q-mr-sm" />Variables disponibles</div>
<q-space />
<q-btn flat dense round icon="close" v-close-popup />
</q-card-section>
<q-card-section>
<div class="text-caption text-grey-7 q-mb-md">
Le worker du hub substitue ces variables dans le HTML au moment de l'envoi
(moteur Mustache). Tu peux les insérer dans n'importe quel texte ou champ URL.
Dans l'éditeur Unlayer, le moyen le plus rapide est : clique dans un texte
barre flottante icône <code>{ }</code>.
</div>
<div v-for="cat in editorOptions.mergeTags" :key="cat.name" class="q-mb-md">
<div class="text-subtitle2 text-grey-9 q-mb-xs">{{ cat.name }}</div>
<q-list dense bordered class="rounded-borders">
<q-item v-for="tag in cat.mergeTags" :key="tag.value" clickable
@click="copyVariable(tag.value)">
<q-item-section avatar>
<code style="background:#F1F5F9;padding:2px 8px;border-radius:4px;font-size:13px">{{ tag.value }}</code>
</q-item-section>
<q-item-section>
<q-item-label>{{ tag.name }}</q-item-label>
<q-item-label caption>exemple : {{ tag.sample }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-btn flat dense round icon="content_copy" size="sm" color="grey-7"
@click.stop="copyVariable(tag.value)">
<q-tooltip>Copier {{ tag.value }}</q-tooltip>
</q-btn>
</q-item-section>
</q-item>
</q-list>
</div>
<q-banner class="bg-blue-1 text-blue-9 q-mt-md" rounded dense>
<template v-slot:avatar><q-icon name="lightbulb" /></template>
<span v-pre><strong>Bientôt :</strong> à l'importation CSV, on pourra mapper chaque colonne
comme variable additionnelle (ex. <code>{{plan_name}}</code>,
<code>{{renewal_date}}</code>) sans toucher au code.</span>
</q-banner>
</q-card-section>
</q-card>
</q-dialog>
</q-page> </q-page>
</template> </template>
@ -279,6 +327,18 @@ async function loadAvailableTemplates () {
// AI translation (Gemini via hub) // AI translation (Gemini via hub)
// Auto-detect source language from the template name suffix (-fr / -en) and // Auto-detect source language from the template name suffix (-fr / -en) and
// compute the target name with the OPPOSITE suffix. // compute the target name with the OPPOSITE suffix.
// Reference card showing every Mustache variable. Read-only the variables
// list lives in editorOptions.mergeTags above (same source Unlayer uses).
const variablesOpen = ref(false)
async function copyVariable (val) {
try {
await navigator.clipboard.writeText(val)
$q.notify({ type: 'positive', message: `${val} copié`, timeout: 1200 })
} catch {
$q.notify({ type: 'negative', message: 'Impossible de copier — sélectionne et copie manuellement' })
}
}
const aiTranslateOpen = ref(false) const aiTranslateOpen = ref(false)
const aiTranslating = ref(false) const aiTranslating = ref(false)
const aiTranslateOverride = ref(false) const aiTranslateOverride = ref(false)