| 1 |
document.addEventListener("DOMContentLoaded", () => { |
| 2 |
const form = document.getElementById("aibui-settings-form"); |
| 3 |
const toast = document.getElementById("aibui-settings-toast"); |
| 4 |
|
| 5 |
// Descriptions for Design Style options |
| 6 |
const designStyleDescriptions = { |
| 7 |
minimalist: "Priority on white space and readability. Few graphic elements, very airy and quiet design.", |
| 8 |
"tech-modern": "A 'Startup' style with soft drop shadows, subtle gradients, and a very clean appearance.", |
| 9 |
corporate: "A structured and reassuring design, ideal for B2B companies, firms, and consultants.", |
| 10 |
brutalist: "Strong contrasts, bold typography, thick black borders. A style that dares and stands out.", |
| 11 |
luxury: "Sophisticated, monochrome or gold palettes, often associated with serif fonts.", |
| 12 |
organic: "Pastel colors, natural shapes, no pure black, for a wellness or nature ambiance.", |
| 13 |
}; |
| 14 |
|
| 15 |
// Descriptions for Block Shapes options |
| 16 |
const blockShapesDescriptions = { |
| 17 |
sharp: "Right angles (0px). Gives a rigorous, solid, and technical look.", |
| 18 |
soft: "Soft angles (4px - 8px). The current web standard, neutral and pleasant.", |
| 19 |
rounded: "Pronounced curves (12px - 20px). Brings modernity and fluidity.", |
| 20 |
pill: "Very rounded buttons and cards (Full radius). Friendly, young, and playful style.", |
| 21 |
}; |
| 22 |
|
| 23 |
// Descriptions for Copywriting Tone options |
| 24 |
const copywritingToneDescriptions = { |
| 25 |
professional: "An expert tone, formal address, precise vocabulary. Inspires trust and authority.", |
| 26 |
friendly: "A conversational, warm tone, close to the reader. Ideal for blogs or lifestyle brands.", |
| 27 |
persuasive: "Short sentences, action-oriented (CTA), focused on customer benefits. For selling.", |
| 28 |
educational: "A neutral, pedagogical, and detailed tone. Perfect for explaining complex services.", |
| 29 |
enthusiastic: "Many positive adjectives, exclamation points, dynamic style to motivate.", |
| 30 |
}; |
| 31 |
|
| 32 |
function showToast(message, isError = false) { |
| 33 |
if (!toast) return; |
| 34 |
toast.textContent = message; |
| 35 |
toast.style.display = "block"; |
| 36 |
toast.style.background = isError ? "#b00020" : "#23272f"; |
| 37 |
toast.style.color = "#fff"; |
| 38 |
toast.style.padding = "10px 14px"; |
| 39 |
toast.style.borderRadius = "8px"; |
| 40 |
setTimeout(() => { |
| 41 |
toast.style.display = "none"; |
| 42 |
}, 4000); |
| 43 |
} |
| 44 |
|
| 45 |
// Limite et compteur pour "Site description & context" |
| 46 |
const SITE_DESCRIPTION_MAX = 1000; |
| 47 |
const siteDescriptionTextarea = document.getElementById("siteDescription"); |
| 48 |
const siteDescriptionCounter = document.getElementById("siteDescription-counter"); |
| 49 |
|
| 50 |
function updateSiteDescriptionCounter() { |
| 51 |
if (!siteDescriptionTextarea || !siteDescriptionCounter) return; |
| 52 |
let value = siteDescriptionTextarea.value || ""; |
| 53 |
if (value.length > SITE_DESCRIPTION_MAX) { |
| 54 |
value = value.slice(0, SITE_DESCRIPTION_MAX); |
| 55 |
siteDescriptionTextarea.value = value; |
| 56 |
} |
| 57 |
siteDescriptionCounter.textContent = `${value.length}/${SITE_DESCRIPTION_MAX}`; |
| 58 |
} |
| 59 |
|
| 60 |
if (siteDescriptionTextarea && siteDescriptionCounter) { |
| 61 |
siteDescriptionTextarea.addEventListener("input", updateSiteDescriptionCounter); |
| 62 |
// Initialiser l'affichage au chargement |
| 63 |
updateSiteDescriptionCounter(); |
| 64 |
} |
| 65 |
|
| 66 |
// Update description when select changes |
| 67 |
function updateDescription(selectId, descriptions) { |
| 68 |
const select = document.getElementById(selectId); |
| 69 |
const descriptionEl = document.getElementById(selectId + "-description"); |
| 70 |
if (!select || !descriptionEl) return; |
| 71 |
|
| 72 |
select.addEventListener("change", () => { |
| 73 |
const value = select.value; |
| 74 |
descriptionEl.textContent = descriptions[value] || ""; |
| 75 |
}); |
| 76 |
|
| 77 |
// Set initial description |
| 78 |
const initialValue = select.value; |
| 79 |
descriptionEl.textContent = descriptions[initialValue] || ""; |
| 80 |
} |
| 81 |
|
| 82 |
async function getJwtToken() { |
| 83 |
const res = await fetch(aiBuilderVars.ajaxurl, { |
| 84 |
method: "POST", |
| 85 |
headers: { "Content-Type": "application/x-www-form-urlencoded" }, |
| 86 |
body: `action=aibui_get_token&nonce=${aiBuilderVars.nonce}`, |
| 87 |
}); |
| 88 |
const data = await res.json(); |
| 89 |
if (data.success && data.data.token) return data.data.token; |
| 90 |
throw new Error("Missing token"); |
| 91 |
} |
| 92 |
|
| 93 |
async function loadSettings() { |
| 94 |
try { |
| 95 |
const jwt = await getJwtToken(); |
| 96 |
const res = await fetch(window.config.apiUrl + "/settings", { |
| 97 |
method: "GET", |
| 98 |
headers: { Authorization: `Bearer ${jwt}` }, |
| 99 |
}); |
| 100 |
if (!res.ok) throw new Error("Failed to load settings"); |
| 101 |
const data = await res.json(); |
| 102 |
|
| 103 |
// Expect shape: { primaryColor, secondaryColor, siteName, siteDescription, designStyle, blockShapes, copywritingTone } |
| 104 |
const { |
| 105 |
primaryColor = "#2f80ed", |
| 106 |
secondaryColor = "#00b87c", |
| 107 |
siteName = "", |
| 108 |
siteDescription = "", |
| 109 |
designStyle = "", |
| 110 |
blockShapes = "", |
| 111 |
copywritingTone = "", |
| 112 |
} = data || {}; |
| 113 |
|
| 114 |
document.getElementById("primaryColor").value = primaryColor; |
| 115 |
document.getElementById("secondaryColor").value = secondaryColor; |
| 116 |
document.getElementById("siteName").value = siteName; |
| 117 |
const siteDescriptionEl = document.getElementById("siteDescription"); |
| 118 |
if (siteDescriptionEl) { |
| 119 |
siteDescriptionEl.value = siteDescription; |
| 120 |
// Mettre à jour le compteur si déjà chargé |
| 121 |
if (typeof updateSiteDescriptionCounter === "function") { |
| 122 |
updateSiteDescriptionCounter(); |
| 123 |
} |
| 124 |
} |
| 125 |
|
| 126 |
if (designStyle) { |
| 127 |
document.getElementById("designStyle").value = designStyle; |
| 128 |
} |
| 129 |
if (blockShapes) { |
| 130 |
document.getElementById("blockShapes").value = blockShapes; |
| 131 |
} |
| 132 |
if (copywritingTone) { |
| 133 |
document.getElementById("copywritingTone").value = copywritingTone; |
| 134 |
} |
| 135 |
|
| 136 |
// Update descriptions for loaded values |
| 137 |
updateDescription("designStyle", designStyleDescriptions); |
| 138 |
updateDescription("blockShapes", blockShapesDescriptions); |
| 139 |
updateDescription("copywritingTone", copywritingToneDescriptions); |
| 140 |
} catch (e) { |
| 141 |
// Silent load error; user can still save |
| 142 |
console.warn("AI Builder Settings: load failed", e); |
| 143 |
// Still initialize description handlers even if load fails |
| 144 |
updateDescription("designStyle", designStyleDescriptions); |
| 145 |
updateDescription("blockShapes", blockShapesDescriptions); |
| 146 |
updateDescription("copywritingTone", copywritingToneDescriptions); |
| 147 |
} |
| 148 |
} |
| 149 |
|
| 150 |
form?.addEventListener("submit", async (e) => { |
| 151 |
e.preventDefault(); |
| 152 |
try { |
| 153 |
const jwt = await getJwtToken(); |
| 154 |
const body = { |
| 155 |
primaryColor: document.getElementById("primaryColor").value, |
| 156 |
secondaryColor: document.getElementById("secondaryColor").value, |
| 157 |
siteName: document.getElementById("siteName").value.trim(), |
| 158 |
siteDescription: document |
| 159 |
.getElementById("siteDescription") |
| 160 |
.value.trim(), |
| 161 |
designStyle: document.getElementById("designStyle").value, |
| 162 |
blockShapes: document.getElementById("blockShapes").value, |
| 163 |
copywritingTone: document.getElementById("copywritingTone").value, |
| 164 |
}; |
| 165 |
|
| 166 |
const res = await fetch(window.config.apiUrl + "/settings", { |
| 167 |
method: "POST", |
| 168 |
headers: { |
| 169 |
"Content-Type": "application/json", |
| 170 |
Authorization: `Bearer ${jwt}`, |
| 171 |
}, |
| 172 |
body: JSON.stringify(body), |
| 173 |
}); |
| 174 |
if (!res.ok) throw new Error("Save failed"); |
| 175 |
showToast("Settings saved"); |
| 176 |
} catch (err) { |
| 177 |
showToast("Error saving settings", true); |
| 178 |
} |
| 179 |
}); |
| 180 |
|
| 181 |
loadSettings(); |
| 182 |
}); |
| 183 |
|