last_edit / frontend /recommendations.html
Moharek
Deploy Moharek GEO Platform
a74b879
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>التوصيات الذكية — منصة محرك GEO</title>
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<link rel="stylesheet" href="/theme.css">
<style>
.reveal{opacity:0;transform:translateY(20px);transition:all .6s cubic-bezier(.16,1,.3,1)}
.reveal.show{opacity:1;transform:translateY(0)}
nav{position:sticky;top:0;z-index:1000;border-bottom:1px solid var(--border);background:rgba(3,7,18,.85);backdrop-filter:blur(32px);height:80px;display:flex;align-items:center}
.nav-inner{max-width:1200px;margin:0 auto;padding:0 32px;width:100%;display:flex;justify-content:space-between;align-items:center}
.nav-logo{display:flex;align-items:center;gap:12px;text-decoration:none}
.wrap{max-width:1200px;margin:0 auto;padding:40px 24px}
.logo-box {
width: 44px;
height: 40px;
flex-shrink: 0;
position: relative;
}
.gear-motif {
position: relative;
width: 100%;
height: 100%;
}
.gear-motif i {
position: absolute;
font-size: 18px;
filter: drop-shadow(0 0 5px rgba(0,0,0,0.5));
animation: gearSpin 10s linear infinite;
}
.gear-blue {
top: 0;
left: 50%;
transform: translateX(-50%);
color: var(--blue);
z-index: 2;
}
.gear-gold {
bottom: 2px;
left: 4px;
color: var(--gold);
font-size: 14px !important;
animation-delay: -3s !important;
}
.gear-red {
bottom: 2px;
right: 4px;
color: var(--red);
font-size: 14px !important;
animation-delay: -6s !important;
}
@keyframes gearSpin {
from { transform: translateX(-50%) rotate(0deg); }
to { transform: translateX(-50%) rotate(360deg); }
}
.gear-gold, .gear-red {
animation-name: gearSpinStatic !important;
}
@keyframes gearSpinStatic {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.nav-links{display:flex;gap:28px}
.nav-link{color:var(--muted);text-decoration:none;font-weight:700;font-size:14px;transition:.3s;padding:8px;position:relative}
.nav-link:hover{color:#fff}
.nav-link.active{color:var(--text);}
.nav-link.active::after{content:'';position:absolute;bottom:-10px;left:0;right:0;height:2px;background:var(--blue);border-radius:2px}
.nav-user{display:flex;align-items:center;gap:16px}
.user-info{text-align:right}
.user-name{font-weight:900;color:#fff;font-size:14px}
.user-email{font-size:11px;color:var(--muted)}
.user-avatar{
width:40px;height:40px;border-radius:12px;
background:var(--accent-grad);
display:flex;align-items:center;justify-content:center;
font-weight:900;color:#000;font-size:18px;
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3);
}
.logout-btn{padding:8px 24px;background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);color:var(--red);border-radius:100px;font-weight:800;font-size:13px;cursor:pointer;transition:.3s}
.logout-btn:hover{background:var(--red);color:#fff}
.wrap{max-width:1200px;margin:0 auto;padding:40px 24px}
/* Header */
.page-header{margin-bottom:0;text-align:center;position:relative}
.header-card{background:var(--bg-elevated);border:1px solid var(--border);border-top:3px solid var(--purple);border-radius:20px;padding:40px;backdrop-filter:blur(16px);box-shadow:0 10px 40px rgba(0,0,0,0.3);position:relative;overflow:hidden;margin-bottom:32px}
.header-card::before{content:'';position:absolute;inset:0;background:radial-gradient(circle at top right,rgba(168,85,247,0.1),transparent);pointer-events:none}
.label{display:inline-flex;align-items:center;gap:6px;background:rgba(168,85,247,0.1);color:var(--purple);padding:6px 16px;border-radius:100px;font-size:12px;font-weight:700;margin-bottom:16px;border:1px solid rgba(168,85,247,0.25)}
.page-title{font-size:clamp(32px,6vw,54px);font-weight:900;margin-bottom:12px;background:var(--hero-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.page-subtitle{font-size:16px;color:var(--muted);max-width:700px;margin:0 auto;line-height:1.6}
/* Stats */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px;margin-bottom:32px}
.kpi{background:var(--bg-elevated);border:1px solid var(--border);padding:24px;border-radius:16px;position:relative;overflow:hidden;transition:.3s;backdrop-filter:blur(12px)}
.kpi:hover{transform:translateY(-4px);box-shadow:0 12px 30px rgba(0,0,0,0.5)}
.kpi.blue:hover{border-color:rgba(59,130,246,.4)}
.kpi.red:hover{border-color:rgba(239,68,68,.4)}
.kpi.yel:hover{border-color:rgba(251,191,36,.4)}
.kpi.pur:hover{border-color:rgba(168,85,247,.4)}
.kpi-lbl{font-size:13px;color:var(--muted);font-weight:600;margin-bottom:8px}
.kpi-val{font-size:36px;font-weight:900;background:var(--hero-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:4px}
.kpi-sub{font-size:12px;color:var(--dim)}
/* Controls Bar */
.controls-bar{display:flex;gap:12px;align-items:center;margin-bottom:32px;flex-wrap:wrap;background:var(--bg-elevated);border:1px solid var(--border);padding:16px;border-radius:16px;backdrop-filter:blur(10px)}
.filter-btn{background:transparent;border:1px solid transparent;color:var(--muted);padding:10px 24px;border-radius:100px;cursor:pointer;font-family:'Cairo',sans-serif;font-weight:700;transition:all 0.3s;font-size:13px;display:flex;align-items:center;gap:6px}
.filter-btn.active{background:var(--blue);color:#fff;border-color:var(--blue);box-shadow:0 6px 16px rgba(59,130,246,0.3)}
.filter-btn:hover:not(.active){background:rgba(255,255,255,0.05);color:#fff;border-color:rgba(255,255,255,0.1)}
.btn-secondary{background:rgba(255,255,255,.04);border:1px solid var(--border);color:#fff;padding:12px 24px;border-radius:100px;font-weight:700;font-size:13px;cursor:pointer;font-family:'Cairo',sans-serif;transition:.3s;display:inline-flex;align-items:center;gap:6px}
.btn-secondary:hover{background:rgba(255,255,255,.09);transform:scale(1.05)}
/* Recommendation Cards */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(500px,1fr));gap:24px;margin-bottom:60px}
.rec-item{background:linear-gradient(135deg,rgba(15,20,25,0.95),rgba(30,41,59,0.85));border:1px solid rgba(255,255,255,0.08);border-right:3px solid transparent;border-radius:16px;padding:28px;transition:all 0.4s cubic-bezier(.16,1,.3,1);display:flex;flex-direction:column;position:relative;overflow:hidden;backdrop-filter:blur(10px)}
.rec-item::before{content:'';position:absolute;inset:0;background:radial-gradient(circle at top right,rgba(255,255,255,0.02),transparent);pointer-events:none;transition:all 0.4s}
.rec-item:hover{transform:translateY(-6px);box-shadow:0 20px 40px rgba(0,0,0,0.3)}
.rec-item.priority-high{border-right-color:var(--red)}
.rec-item.priority-high:hover{border-color:rgba(239,68,68,0.5);box-shadow:0 20px 40px rgba(239,68,68,0.2)}
.rec-item.priority-medium{border-right-color:var(--gold)}
.rec-item.priority-medium:hover{border-color:rgba(251,191,36,0.5);box-shadow:0 20px 40px rgba(251,191,36,0.2)}
.rec-item.priority-low{border-right-color:var(--emerald)}
.rec-item.priority-low:hover{border-color:rgba(16,185,129,0.5);box-shadow:0 20px 40px rgba(16,185,129,0.2)}
.rec-head-row{display:flex;gap:16px;align-items:flex-start;margin-bottom:12px;position:relative;z-index:1}
.rec-number{display:flex;align-items:center;justify-content:center;width:44px;height:44px;background:var(--bg-elevated);border:1px solid var(--border);color:var(--text);font-weight:800;border-radius:12px;font-size:18px;flex-shrink:0;box-shadow:0 4px 12px rgba(0,0,0,0.2)}
.rec-content{flex:1}
.rec-title{font-weight:800;color:#fff;margin-bottom:6px;font-size:18px;line-height:1.4}
.rec-desc{font-size:14px;color:var(--muted);margin-bottom:20px;line-height:1.6}
.rec-meta{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:20px}
.badge{padding:6px 12px;border-radius:8px;font-weight:700;font-size:12px;border:1px solid transparent;display:inline-flex;align-items:center;gap:6px}
.badge-high{background:rgba(239,68,68,0.15);color:var(--red);border-color:rgba(239,68,68,0.3)}
.badge-medium{background:rgba(251,191,36,0.15);color:var(--gold);border-color:rgba(251,191,36,0.3)}
.badge-low{background:rgba(16,185,129,0.15);color:var(--emerald);border-color:rgba(16,185,129,0.3)}
.badge-impact{background:rgba(59,130,246,0.15);color:var(--blue);border-color:rgba(59,130,246,0.3)}
.badge-time{background:rgba(168,85,247,0.15);color:var(--purple);border-color:rgba(168,85,247,0.3)}
.progress-section{position:relative;z-index:1;margin-bottom:20px}
.progress-label{font-size:12px;color:var(--muted);margin-bottom:8px;display:flex;justify-content:space-between;font-weight:600}
.progress-bar{width:100%;height:8px;background:rgba(0,0,0,0.3);border-radius:4px;overflow:hidden;border:1px solid rgba(255,255,255,0.05)}
.progress-fill{height:100%;border-radius:4px;transition:width 1s cubic-bezier(.16,1,.3,1)}
.btn-action{background:var(--accent-grad);color:#fff;border:none;padding:12px 24px;border-radius:10px;font-weight:800;cursor:pointer;font-size:13px;font-family:'Cairo',sans-serif;transition:.3s;display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%}
.btn-action:hover{transform:translateY(-2px);box-shadow:0 12px 32px rgba(59,130,246,.4)}
.empty-state{text-align:center;padding:80px 20px;background:var(--bg-elevated);border:1px dashed var(--border);border-radius:20px;grid-column:1/-1}
.empty-state-icon{font-size:54px;margin-bottom:16px;opacity:0.8}
.empty-state-text{color:var(--muted);font-size:15px;font-weight:600;line-height:1.6}
.reveal{opacity:0;transform:translateY(30px);transition:all .7s cubic-bezier(.16,1,.3,1)}
.reveal.show{opacity:1;transform:translateY(0)}
@media(max-width:900px){
.wrap{padding:20px}
.nav-inner{padding:0 20px}
.page-title{font-size:36px}
.controls-bar{flex-direction:column;align-items:stretch}
.filter-btn{justify-content:center}
.grid{grid-template-columns:1fr}
}
</style>
</head>
<body>
<div class="bg-mesh"></div>
<div class="bg-grid"></div>
<nav>
<div class="nav-inner">
<a href="/portal.html" class="nav-logo">
<div class="logo-box" style="width:40px;height:40px;display:grid;place-items:center;overflow:hidden;border-radius:10px;background:transparent">
<img src="moharek-logo-v2.svg" alt="Moharek" style="width:100%;height:100%;object-fit:contain">
</div>
<div>
<div style="font-size:15px;font-weight:900;color:#fff">محرك GEO</div>
<div style="font-size:10px;color:var(--muted);font-weight:500">BRAND IDENTITY · AI</div>
</div>
</a>
<div class="nav-links">
<a class="nav-link" href="/portal.html">لوحة التحكم</a>
<a class="nav-link" href="/jobs.html">المهام</a>
<a class="nav-link" href="/search.html">البحث</a>
<a class="nav-link active" href="/recommendations.html">التوصيات</a>
<a class="nav-link" href="/ads.html">إدارة الإعلانات</a>
</div>
<div class="nav-user">
<div class="user-info">
<div class="user-name" id="userNameNav">مستخدم</div>
<div class="user-email" id="userEmailNav">user@mohrek.com</div>
</div>
<div class="user-avatar" id="userAvatarNav">M</div>
<button class="logout-btn" onclick="logout()">خروج</button>
</div>
</div>
</nav>
<div class="wrap">
<div class="header-card reveal">
<div class="page-header">
<div class="label"><i class="fas fa-lightbulb"></i> التوصيات الذكية</div>
<h1 class="page-title">التوصيات الاستراتيجية</h1>
<p class="page-subtitle">توصيات مرتبة حسب الأولوية وتطبيقات عملية بخطوات مبنية على الذكاء الاصطناعي لتحسين ظهورك في محركات الذكاء الاصطناعي</p>
</div>
</div>
<div class="kpis reveal" style="animation-delay:0.1s">
<div class="kpi blue">
<div class="kpi-lbl"><i class="fas fa-tasks" style="color:var(--blue);margin-left:6px"></i>إجمالي التوصيات</div>
<div class="kpi-val" id="totalRec">0</div>
<div class="kpi-sub">تطبيقات معلقة</div>
</div>
<div class="kpi red">
<div class="kpi-lbl"><i class="fas fa-exclamation-circle" style="color:var(--red);margin-left:6px"></i>عالية الأولوية</div>
<div class="kpi-val" id="highPriority" style="background:linear-gradient(135deg,#ef4444,#f97316);-webkit-background-clip:text;background-clip:text;color:transparent">0</div>
<div class="kpi-sub">تتطلب تنفيذ عاجل</div>
</div>
<div class="kpi yel">
<div class="kpi-lbl"><i class="fas fa-chart-line" style="color:var(--gold);margin-left:6px"></i>% محتمل الكسب</div>
<div class="kpi-val" id="potentialGain" style="background:var(--gold-grad);-webkit-background-clip:text;background-clip:text;color:transparent">0</div>
<div class="kpi-sub">زيادة الرؤية المقدرة</div>
</div>
<div class="kpi pur">
<div class="kpi-lbl"><i class="fas fa-clock" style="color:var(--purple);margin-left:6px"></i>أيام التنفيذ</div>
<div class="kpi-val" id="estimatedTime">0</div>
<div class="kpi-sub">متوسط وقت الإنجاز</div>
</div>
</div>
<div class="controls-bar reveal" style="animation-delay:0.2s">
<div style="display:flex;gap:4px;flex-wrap:wrap">
<button class="filter-btn active" data-priority="all" onclick="filterByPriority('all', event)"><i class="fas fa-layer-group"></i> كل التوصيات</button>
<button class="filter-btn" data-priority="high" onclick="filterByPriority('high', event)"><i class="fas fa-circle" style="color:var(--red);font-size:10px"></i> عالية</button>
<button class="filter-btn" data-priority="medium" onclick="filterByPriority('medium', event)"><i class="fas fa-circle" style="color:var(--gold);font-size:10px"></i> متوسطة</button>
<button class="filter-btn" data-priority="low" onclick="filterByPriority('low', event)"><i class="fas fa-circle" style="color:var(--emerald);font-size:10px"></i> منخفضة</button>
</div>
<div style="flex:1"></div>
<div style="display:flex;gap:12px">
<button class="btn-secondary" onclick="loadRecommendations()"><i class="fas fa-sync-alt"></i> تحديث</button>
<button class="btn-secondary" onclick="location.href='/portal.html'"><i class="fas fa-arrow-left"></i> العودة</button>
</div>
</div>
<div id="recContainer" class="grid">
<div class="empty-state reveal" style="animation-delay:0.3s">
<div class="empty-state-icon"><i class="fas fa-circle-notch fa-spin" style="color:var(--blue)"></i></div>
<p class="empty-state-text">جارٍ تحليل بيانتك وتوليد التوصيات الذكية...</p>
</div>
</div>
</div>
<section style="padding:40px 0;text-align:center;border-top:1px solid var(--border);margin-top:40px">
<p style="color:var(--dim);font-size:13px;font-weight:600">© 2025 محرك — منصة SEO &amp; GEO بالذكاء الاصطناعي</p>
</section>
<script>
const token = localStorage.getItem('token');
let allRecommendations = [];
let currentPriority = 'all';
// if (!token) window.location.href = '/login.html';
async function loadUserInfo() {
try {
const res = await fetch('http://localhost:8001/api/users/me', { headers: { 'Authorization': `Bearer ${token}` } });
if (res.ok) {
const data = await res.json();
document.getElementById('userNameNav').textContent = data.username || 'مستخدم';
document.getElementById('userEmailNav').textContent = data.email || '';
document.getElementById('userAvatarNav').textContent = (data.username || 'M')[0].toUpperCase();
}
} catch (e) { console.error(e); }
}
async function loadRecommendations() {
const container = document.getElementById('recContainer');
container.innerHTML = '<div class="empty-state"><div class="empty-state-icon"><i class="fas fa-circle-notch fa-spin" style="color:var(--blue)"></i></div><p class="empty-state-text">جارٍ مراجعة مصادر البيانات وتحليل التوصيات...</p></div>';
try {
const jobsRes = await fetch('http://localhost:8001/api/jobs', { headers: { 'Authorization': `Bearer ${token}` } });
const jobsData = await jobsRes.json();
const jobs = jobsData.jobs || [];
const params = new URLSearchParams(location.search);
const jobIdParam = params.get('job_id') ? parseInt(params.get('job_id')) : null;
const latestCompleted = jobIdParam
? jobs.find(j => j.id === jobIdParam)
: jobs.find(j => j.status === 'completed' && j.result_path);
const body = { api_keys: { groq: localStorage.getItem('geo_groq_key'), openai: localStorage.getItem('geo_openai_key') } };
if (latestCompleted) body.job_id = latestCompleted.id;
const res = await fetch('http://localhost:8001/api/recommendations', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify(body)
});
const data = await res.json();
if (!data.ok) {
container.innerHTML = `<div class="empty-state"><div class="empty-state-icon"><i class="fas fa-exclamation-triangle" style="color:var(--orange)"></i></div><p class="empty-state-text" style="color:var(--text);font-size:16px">${data.error || 'خطأ في تحميل التوصيات'}</p><p style="color:var(--muted);font-size:13px;margin-top:12px">يجب تحليل موقع أولاً من <a href="/jobs.html" style="color:var(--blue);text-decoration:underline">صفحة المهام</a></p></div>`;
return;
}
const recs = data.recommendations || {};
allRecommendations = [];
const rawActions = Array.isArray(recs) ? recs : (recs.actions || []);
const perPage = recs.per_page || [];
rawActions.forEach((a, i) => {
const text = typeof a === 'object' ? (a.text || a.title || JSON.stringify(a)) : a;
const priority = typeof a === 'object' ? (a.priority || 'medium') : 'medium';
allRecommendations.push({ title: text, desc: typeof a === 'object' ? (a.description || a.why || '') : '', priority: priority.toLowerCase(), impact: typeof a === 'object' ? (a.impact || 20) : 20, days: typeof a === 'object' ? (a.days || 3) : 3, idx: i });
});
perPage.forEach((p, i) => {
const issues = (p.issues || []).join(' • ');
const suggestions = (p.suggestions || []).map(s => typeof s === 'object' ? s.label || s.rewrite || '' : s).join(' | ');
allRecommendations.push({ title: `صفحة: ${p.title || p.url}`, desc: `${issues}${suggestions ? ' — ' + suggestions.substring(0, 120) : ''}`, priority: (p.issues && p.issues.length > 2) ? 'high' : 'medium', impact: 15, days: 2, idx: rawActions.length + i });
});
if (allRecommendations.length === 0) {
container.innerHTML = '<div class="empty-state"><div class="empty-state-icon"><i class="fas fa-check-circle" style="color:var(--emerald)"></i></div><p class="empty-state-text">موقعك في حالة جيدة جداً، لا توجد توصيات حالياً.</p></div>';
return;
}
updateStats();
// Pass undefined for event to let filterByPriority handle the fallback logically
filterByPriority('all');
} catch (e) {
console.error(e);
document.getElementById('recContainer').innerHTML = `<div class="empty-state"><div class="empty-state-icon"><i class="fas fa-times-circle" style="color:var(--red)"></i></div><p class="empty-state-text">خطأ أو فصل في الاتصال: ${e.message}</p></div>`;
}
}
function updateStats() {
const high = allRecommendations.filter(r => r.priority === 'high').length;
const totalGain = Math.round(allRecommendations.reduce((sum, r) => sum + r.impact, 0) / allRecommendations.length) || 0;
const maxDays = allRecommendations.length > 0 ? Math.max(...allRecommendations.map(r => r.days)) : 0;
document.getElementById('totalRec').textContent = allRecommendations.length;
document.getElementById('highPriority').textContent = high;
document.getElementById('potentialGain').textContent = totalGain;
document.getElementById('estimatedTime').textContent = maxDays;
}
function getPriorityClass(priority) {
if(priority === 'high') return 'badge-high';
if(priority === 'medium') return 'badge-medium';
return 'badge-low';
}
function getPriorityIcon(priority) {
if(priority === 'high') return '<i class="fas fa-circle" style="font-size:10px"></i>';
if(priority === 'medium') return '<i class="fas fa-circle" style="font-size:10px"></i>';
return '<i class="fas fa-circle" style="font-size:10px"></i>';
}
function filterByPriority(priority, event) {
currentPriority = priority;
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
if (event && event.currentTarget) {
event.currentTarget.classList.add('active');
} else {
// Fallback if called programmatically
const btn = document.querySelector(`.filter-btn[data-priority="${priority}"]`);
if(btn) btn.classList.add('active');
}
displayRecommendations();
}
function displayRecommendations() {
let filtered = allRecommendations;
if (currentPriority !== 'all') {
filtered = filtered.filter(r => r.priority === currentPriority);
}
if (filtered.length === 0) {
document.getElementById('recContainer').innerHTML = `<div class="empty-state"><div class="empty-state-icon"><i class="fas fa-check-double" style="color:var(--dim)"></i></div><p class="empty-state-text">لا توجد توصيات مطابقة لهذه الفئة</p></div>`;
return;
}
let html = '';
filtered.forEach((rec, idx) => {
const priorityLabel = rec.priority === 'high' ? 'عالية' : rec.priority === 'medium' ? 'متوسطة' : 'منخفضة';
const pColor = rec.priority === 'high' ? 'var(--red)' : rec.priority === 'medium' ? 'var(--gold)' : 'var(--emerald)';
const progressGradient = rec.priority === 'high' ? 'linear-gradient(90deg, var(--red), var(--orange))' : rec.priority === 'medium' ? 'var(--gold-grad)' : 'linear-gradient(90deg, var(--emerald), var(--cyan))';
html += `
<div class="rec-item priority-${rec.priority} reveal" style="animation-delay:${(idx%10) * 0.05}s">
<div class="rec-head-row">
<div class="rec-number" style="box-shadow:inset 0 0 0 1px ${pColor}33">${rec.idx + 1}</div>
<div class="rec-content">
<div class="rec-title">${rec.title}</div>
<div class="rec-desc">${rec.desc}</div>
</div>
</div>
<div class="rec-meta">
<span class="badge ${getPriorityClass(rec.priority)}">${getPriorityIcon(rec.priority)} أولوية ${priorityLabel}</span>
<span class="badge badge-impact"><i class="fas fa-chart-line"></i> ${rec.impact}% احتمال كسب</span>
<span class="badge badge-time"><i class="far fa-clock"></i> ${rec.days} أيام تنفيذ</span>
</div>
<div class="progress-section">
<div class="progress-label">
<span><i class="fas fa-tachometer-alt" style="margin-left:4px"></i> درجة التأثير:</span>
<span>${rec.impact}%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width:${rec.impact}%;background:${progressGradient}"></div>
</div>
</div>
<button class="btn-action" onclick="implementRecommendation('${encodeURIComponent(rec.title)}')"><i class="fas fa-cogs"></i> التطبيق والدراسة</button>
</div>
`;
});
document.getElementById('recContainer').innerHTML = html;
revealOnScroll();
}
function implementRecommendation(encodedTitle) {
window.location.href = '/content_v2.html';
}
function logout() {
localStorage.removeItem('token');
window.location.href = '/';
}
function revealOnScroll() {
const reveals = document.querySelectorAll('.reveal');
reveals.forEach(el => {
const windowHeight = window.innerHeight;
const elementTop = el.getBoundingClientRect().top;
if (elementTop < windowHeight - 50) {
el.classList.add('show');
}
});
}
window.addEventListener('scroll', revealOnScroll);
window.addEventListener('load', () => {
revealOnScroll();
loadUserInfo();
loadRecommendations();
});
</script>
</body>
</html>