281 lines
10 KiB
HTML
281 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>N8N Workflow Chat - H3R7Tech</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Syne:wght@400;700;800&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--bg: #0d0f1a;
|
|
--bg2: #13162a;
|
|
--bg3: #1a1f38;
|
|
--accent: #e94560;
|
|
--cyan: #00d9ff;
|
|
--green: #2ec4b6;
|
|
--yellow: #f4c542;
|
|
--muted: #4a5080;
|
|
--text: #e8eaf6;
|
|
--text2: #8892b0;
|
|
}
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: 'Syne', sans-serif;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
min-height: 100vh;
|
|
}
|
|
.header {
|
|
background: linear-gradient(135deg, #0d0f1a 0%, #1a1f38 100%);
|
|
border-bottom: 1px solid var(--muted);
|
|
padding: 16px 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
}
|
|
.header h1 { font-size: 20px; font-weight: 800; color: var(--cyan); }
|
|
.header .status { margin-left: auto; font-family: 'Space Mono', monospace; font-size: 12px; color: var(--text2); }
|
|
.status-dot {
|
|
display: inline-block; width: 8px; height: 8px; border-radius: 50%;
|
|
background: var(--accent); margin-right: 6px;
|
|
}
|
|
.status-dot.connected { background: var(--green); }
|
|
|
|
.content { max-width: 800px; margin: 0 auto; padding: 20px; }
|
|
|
|
.card {
|
|
background: var(--bg2);
|
|
border: 1px solid var(--bg3);
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.chat-container {
|
|
height: 400px;
|
|
overflow-y: auto;
|
|
background: var(--bg);
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.message {
|
|
margin-bottom: 12px;
|
|
padding: 12px 16px;
|
|
border-radius: 12px;
|
|
max-width: 85%;
|
|
}
|
|
.message.user {
|
|
background: rgba(0, 217, 255, 0.15);
|
|
border: 1px solid rgba(0, 217, 255, 0.3);
|
|
margin-left: auto;
|
|
}
|
|
.message.system {
|
|
background: rgba(46, 196, 182, 0.15);
|
|
border: 1px solid rgba(46, 196, 182, 0.3);
|
|
}
|
|
.message.error {
|
|
background: rgba(233, 69, 96, 0.15);
|
|
border: 1px solid rgba(233, 69, 96, 0.3);
|
|
color: var(--accent);
|
|
}
|
|
.message .role {
|
|
font-size: 10px; font-weight: 700; text-transform: uppercase;
|
|
color: var(--text2); margin-bottom: 4px;
|
|
}
|
|
.message .content { padding: 0; max-width: 100%; }
|
|
|
|
.input-row {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
.input-row input {
|
|
flex: 1;
|
|
padding: 14px 18px;
|
|
border-radius: 8px;
|
|
border: 1px solid var(--muted);
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
font-family: 'Syne', sans-serif;
|
|
font-size: 14px;
|
|
}
|
|
.input-row input:focus {
|
|
outline: none;
|
|
border-color: var(--cyan);
|
|
}
|
|
.input-row button {
|
|
padding: 14px 24px;
|
|
border-radius: 8px;
|
|
border: none;
|
|
background: var(--cyan);
|
|
color: #000;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
font-family: 'Syne', sans-serif;
|
|
transition: all .2s;
|
|
}
|
|
.input-row button:hover { transform: translateY(-2px); }
|
|
.input-row button:disabled { background: var(--muted); cursor: not-allowed; }
|
|
|
|
.loader {
|
|
display: flex; align-items: center; gap: 8px; padding: 20px;
|
|
}
|
|
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--cyan); animation: bounce .8s infinite; }
|
|
.dot:nth-child(2) { animation-delay: .15s; }
|
|
.dot:nth-child(3) { animation-delay: .3s; }
|
|
@keyframes bounce {
|
|
0%,100% { transform: translateY(0); opacity: .4; }
|
|
50% { transform: translateY(-8px); opacity: 1; }
|
|
}
|
|
|
|
.quick-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 16px;
|
|
}
|
|
.quick-actions button {
|
|
padding: 8px 14px;
|
|
border-radius: 20px;
|
|
border: 1px solid var(--muted);
|
|
background: var(--bg2);
|
|
color: var(--text2);
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
transition: all .2s;
|
|
}
|
|
.quick-actions button:hover {
|
|
border-color: var(--cyan);
|
|
color: var(--cyan);
|
|
}
|
|
|
|
.home-btn{position:fixed;top:10px;left:10px;z-index:9999;background:linear-gradient(135deg,#00d9ff,#7b2cbf);color:#fff;border:none;border-radius:8px;padding:10px 15px;font-size:14px;cursor:pointer;text-decoration:none;display:flex;align-items:center;gap:8px;box-shadow:0 2px 10px rgba(0,217,255,0.3);transition:all 0.3s;font-family:-apple-system,BlinkMacSystemFont,sans-serif}.home-btn:hover{transform:translateY(-2px);box-shadow:0 4px 15px rgba(0,217,255,0.5)}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<a href="https://portal-kolifee.duckdns.org/" class="home-btn" title="Retour au portail"><span style="font-size:18px">🏠</span><span>Accueil</span></a>
|
|
<div class="header">
|
|
<h1>🤖 N8N Workflow Chat</h1>
|
|
<div class="status">
|
|
<span class="status-dot" id="status-dot"></span>
|
|
<span id="status-text">Connecting...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<div class="card">
|
|
<div class="quick-actions">
|
|
<button onclick="sendQuick('Quelle est la date du jour?')">📅 Date</button>
|
|
<button onclick="sendQuick('Liste les 5 derniers workflows actifs')">📋 Workflows</button>
|
|
<button onclick="sendQuick('Affiche les statistiques du système')">📊 Stats</button>
|
|
<button onclick="sendQuick('Test de connexion')">✅ Test</button>
|
|
</div>
|
|
|
|
<div class="chat-container" id="chat-container">
|
|
<div class="message system">
|
|
<div class="role">Système</div>
|
|
<div class="content">👋 Bienvenue! Posez vos questions au workflow n8n.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="input-row">
|
|
<input type="text" id="message-input" placeholder="Votre message..."
|
|
onkeypress="if(event.key==='Enter')sendMessage()">
|
|
<button id="send-btn" onclick="sendMessage()">Envoyer</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const WEBHOOK_URL = '/turf/api/n8n-proxy';
|
|
const CHAT_CONTAINER = document.getElementById('chat-container');
|
|
const MESSAGE_INPUT = document.getElementById('message-input');
|
|
const SEND_BTN = document.getElementById('send-btn');
|
|
|
|
function addMessage(role, content, isError = false) {
|
|
const div = document.createElement('div');
|
|
div.className = `message ${role}${isError ? ' error' : ''}`;
|
|
div.innerHTML = `<div class="role">${role}</div><div class="content">${content}</div>`;
|
|
CHAT_CONTAINER.appendChild(div);
|
|
CHAT_CONTAINER.scrollTop = CHAT_CONTAINER.scrollHeight;
|
|
}
|
|
|
|
function showLoader() {
|
|
const div = document.createElement('div');
|
|
div.id = 'loader';
|
|
div.className = 'message system';
|
|
div.innerHTML = `<div class="loader"><div class="dot"></div><div class="dot"></div><div class="dot"></div></div>`;
|
|
CHAT_CONTAINER.appendChild(div);
|
|
CHAT_CONTAINER.scrollTop = CHAT_CONTAINER.scrollHeight;
|
|
}
|
|
|
|
function hideLoader() {
|
|
const loader = document.getElementById('loader');
|
|
if (loader) loader.remove();
|
|
}
|
|
|
|
async function sendQuick(msg) {
|
|
MESSAGE_INPUT.value = msg;
|
|
sendMessage();
|
|
}
|
|
|
|
async function sendMessage() {
|
|
const msg = MESSAGE_INPUT.value.trim();
|
|
if (!msg) return;
|
|
|
|
addMessage('user', msg);
|
|
MESSAGE_INPUT.value = '';
|
|
SEND_BTN.disabled = true;
|
|
showLoader();
|
|
|
|
try {
|
|
const response = await fetch(WEBHOOK_URL, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
query: msg,
|
|
timestamp: Date.now(),
|
|
source: 'n8n-chat-web'
|
|
})
|
|
});
|
|
|
|
hideLoader();
|
|
|
|
try {
|
|
const data = await response.json();
|
|
let msg = data.message || 'Message envoyé';
|
|
addMessage('system', msg);
|
|
} catch(e) {
|
|
const text = await response.text();
|
|
addMessage('system', text || 'Message envoyé');
|
|
}
|
|
} catch (e) {
|
|
hideLoader();
|
|
addMessage('system', `Erreur de connexion: ${e.message}`, true);
|
|
}
|
|
|
|
SEND_BTN.disabled = false;
|
|
MESSAGE_INPUT.focus();
|
|
}
|
|
|
|
// Test connection on load
|
|
async function testConnection() {
|
|
try {
|
|
const resp = await fetch(WEBHOOK_URL, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ query: 'ping', timestamp: Date.now() })
|
|
});
|
|
|
|
document.getElementById('status-dot').classList.add('connected');
|
|
document.getElementById('status-text').textContent = 'Connecté';
|
|
} catch (e) {
|
|
document.getElementById('status-text').textContent = 'Erreur: ' + e.message;
|
|
}
|
|
}
|
|
|
|
testConnection();
|
|
</script>
|
|
</body>
|
|
</html> |