@מ.ל.ל
קח לא בדקתי יותר מידי
קוד סקריפט
function doGet(e) {
try {
var tid = e && e.parameter && e.parameter.tid ? e.parameter.tid : '';
var cid = e && e.parameter && e.parameter.cid ? e.parameter.cid : '';
var page = e && e.parameter && e.parameter.page ? e.parameter.page : '';
var recent = e && e.parameter && (e.parameter.recent || e.parameter.action === 'recent' || e.parameter.q === 'recent' || e.parameter.sort === 'recent');
var top = e && e.parameter && (e.parameter.top || e.parameter.action === 'top' || e.parameter.sort === 'top' || e.parameter.popular);
var term = e && e.parameter ? (e.parameter.term || e.parameter.q || e.parameter.search || e.parameter.query) : '';
var path = '';
var queryParams = [];
if (tid) {
path = 'topic/' + tid;
} else if (cid) {
path = 'category/' + cid;
} else if (recent) {
path = 'recent';
} else if (top) {
path = 'top';
} else if (term) {
path = 'search';
queryParams.push('term=' + encodeURIComponent(term));
}
// כתובת ה-API של פורום מתמחים טופ
var url = 'https://mitmachim.top/api/' + path;
if (page) {
queryParams.push('page=' + page);
}
if (queryParams.length > 0) {
url += '?' + queryParams.join('&');
}
var cache = CacheService.getScriptCache();
var cacheKey = (tid ? 'topic_' + tid : (cid ? 'category_' + cid : (recent ? 'recent' : (top ? 'top' : (term ? 'search_' + term : 'home'))))) + '_p' + (page || 1);
var cachedData = cache.get(cacheKey);
if (cachedData) {
return ContentService.createTextOutput(cachedData)
.setMimeType(ContentService.MimeType.JSON);
}
var options = {
'muteHttpExceptions': true,
'headers': {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}
};
var response = UrlFetchApp.fetch(url, options);
var responseCode = response.getResponseCode();
var jsonText = response.getContentText();
if (responseCode !== 200) {
jsonText = JSON.stringify({ error: "שגיאת שרת חיצוני (HTTP " + responseCode + ")" });
} else {
try {
if (jsonText.length < 90000) {
var cacheTime = tid ? 600 : (recent || top ? 120 : 300);
cache.put(cacheKey, jsonText, cacheTime);
}
} catch (cacheErr) {}
}
return ContentService.createTextOutput(jsonText)
.setMimeType(ContentService.MimeType.JSON);
} catch(err) {
return ContentService.createTextOutput(JSON.stringify({error: err.message}))
.setMimeType(ContentService.MimeType.JSON);
}
}
קוד דף
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>פורום מתמחים טופ - ממשק מתקדם</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style>
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: var(--bg-color, #f8fafc);
color: var(--text-color, #1e293b);
transition: background-color 0.3s, color 0.3s;
}
pre, code {
font-family: Consolas, Monaco, 'Courier New', Courier, monospace;
direction: ltr;
text-align: left;
}
pre {
background-color: #0f172a;
color: #e2e8f0;
border-radius: 12px;
padding: 20px;
padding-top: 45px;
overflow-x: auto;
margin: 16px 0;
font-size: 0.92rem;
position: relative;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.2);
}
code {
background-color: #f1f5f9;
border: 1px solid #e2e8f0;
padding: 2px 6px;
border-radius: 6px;
font-size: 0.88rem;
color: #0f172a;
}
pre code {
background-color: transparent;
border: none;
padding: 0;
color: inherit;
}
.post-content a {
color: #6366f1;
text-decoration: underline;
font-weight: 500;
}
.post-content a:hover {
color: #4f46e5;
}
html {
scroll-behavior: smooth;
}
/* Dark Mode Variables & Overrides */
body.dark-mode {
--bg-color: #0f172a;
--text-color: #f1f5f9;
--card-bg: #1e293b;
--border-color: #334155;
--hover-bg: #26334d;
}
body.dark-mode .bg-white {
background-color: #1e293b !important;
color: #f1f5f9 !important;
border-color: #334155 !important;
}
body.dark-mode .text-slate-800,
body.dark-mode .text-slate-900,
body.dark-mode .text-slate-700 {
color: #f1f5f9 !important;
}
body.dark-mode .text-slate-500,
body.dark-mode .text-slate-400 {
color: #94a3b8 !important;
}
body.dark-mode .border-slate-200,
body.dark-mode .border-slate-100 {
border-color: #334155 !important;
}
body.dark-mode .bg-slate-50,
body.dark-mode .bg-slate-100 {
background-color: #0f172a !important;
color: #cbd5e1 !important;
}
@media print {
header, footer, button, .no-print, #tabs-bar {
display: none !important;
}
body {
background: white !important;
color: black !important;
}
main {
max-width: 100% !important;
padding: 0 !important;
margin: 0 !important;
}
.bg-white {
box-shadow: none !important;
border: none !important;
padding: 0 !important;
margin-bottom: 20px !important;
}
}
</style>
</head>
<body class="min-h-screen flex flex-col justify-between">
<div>
<!-- Modern Header -->
<header class="bg-gradient-to-r from-blue-900 via-indigo-900 to-slate-900 text-white shadow-xl py-6 px-6 mb-8 border-b border-indigo-700/50">
<div class="max-w-5xl mx-auto flex flex-col md:flex-row justify-between items-center gap-4">
<div class="flex items-center gap-3 cursor-pointer" onclick="loadHome()">
<div class="w-10 h-10 rounded-xl bg-gradient-to-tr from-blue-500 to-indigo-500 flex items-center justify-center shadow-lg font-bold text-xl text-white">
מ
</div>
<div>
<h1 class="text-2xl font-extrabold tracking-tight hover:text-blue-200 transition">
מתמחים טופ
</h1>
<p class="text-xs text-blue-200/80 font-medium">ממשק גלישה מתקדם ומהיר</p>
</div>
</div>
<!-- Top Quick Actions -->
<div class="flex flex-wrap items-center gap-2">
<button onclick="loadHome()" class="bg-white/10 hover:bg-white/20 text-white border border-white/20 px-3.5 py-2 rounded-xl text-xs font-semibold transition backdrop-blur-md cursor-pointer flex items-center gap-1.5">
🏠 הבית
</button>
<button onclick="loadRecentPosts()" class="bg-white/10 hover:bg-white/20 text-white border border-white/20 px-3.5 py-2 rounded-xl text-xs font-semibold transition backdrop-blur-md cursor-pointer flex items-center gap-1.5">
🔥 פוסטים אחרונים
</button>
<button onclick="loadPopularPosts()" class="bg-white/10 hover:bg-white/20 text-white border border-white/20 px-3.5 py-2 rounded-xl text-xs font-semibold transition backdrop-blur-md cursor-pointer flex items-center gap-1.5">
⭐ פופולריים
</button>
<button onclick="loadBookmarks()" class="bg-white/10 hover:bg-white/20 text-white border border-white/20 px-3.5 py-2 rounded-xl text-xs font-semibold transition backdrop-blur-md cursor-pointer flex items-center gap-1.5">
📌 מועדפים (<span id="bm-count">0</span>)
</button>
<button onclick="loadHistory()" class="bg-white/10 hover:bg-white/20 text-white border border-white/20 px-3.5 py-2 rounded-xl text-xs font-semibold transition backdrop-blur-md cursor-pointer flex items-center gap-1.5">
📜 היסטוריה
</button>
<!-- Dark Mode Toggle -->
<button onclick="toggleDarkMode()" id="dark-mode-btn" class="bg-white/10 hover:bg-white/20 text-white border border-white/20 p-2 rounded-xl text-xs transition backdrop-blur-md cursor-pointer" title="מצב לילה / בהיר">
🌙
</button>
<!-- Font Size Controls -->
<div class="flex items-center bg-white/10 border border-white/20 rounded-xl overflow-hidden backdrop-blur-md">
<button onclick="changeFontSize('decrease')" class="px-2.5 py-2 hover:bg-white/20 text-xs font-bold transition cursor-pointer" title="הקטן טקסט">A-</button>
<button onclick="changeFontSize('increase')" class="px-2.5 py-2 hover:bg-white/20 text-xs font-bold transition cursor-pointer" title="הגדל טקסט">A+</button>
</div>
</div>
</div>
<!-- Advanced Controls Bar (Search & Custom URL) -->
<div class="max-w-5xl mx-auto mt-6 pt-6 border-t border-indigo-700/60 grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Search Box -->
<div class="flex items-center gap-2 bg-white/10 backdrop-blur-md p-2 rounded-2xl border border-white/20">
<input type="text" id="search-input" placeholder="חיפוש נושאים בפורום..." onkeydown="if(event.key==='Enter') handleSearch()" class="bg-transparent text-white placeholder-blue-200 px-3 py-1.5 text-sm w-full focus:outline-none">
<button onclick="handleSearch()" class="bg-white text-blue-900 px-4 py-2 rounded-xl text-xs font-bold hover:bg-blue-50 transition shrink-0 cursor-pointer shadow-sm">
🔍 חיפוש
</button>
</div>
<!-- Custom URL Loader Box -->
<div class="flex items-center gap-2 bg-white/10 backdrop-blur-md p-2 rounded-2xl border border-white/20">
<input type="text" id="url-input" placeholder="הדבק קישור לפורום כאן (לדוגמה: /topic/1234)..." onkeydown="if(event.key==='Enter') handleCustomUrl()" class="bg-transparent text-white placeholder-blue-200 px-3 py-1.5 text-sm w-full focus:outline-none" dir="ltr">
<button onclick="handleCustomUrl()" class="bg-indigo-500 text-white px-4 py-2 rounded-xl text-xs font-bold hover:bg-indigo-600 transition shrink-0 cursor-pointer shadow-sm">
🔗 טען קישור
</button>
</div>
</div>
</header>
<!-- Main Container -->
<main class="max-w-5xl mx-auto px-4 sm:px-6 pb-16">
<!-- Open Tabs Bar -->
<div id="tabs-bar" class="hidden flex items-center gap-2 overflow-x-auto pb-3 mb-4 no-print"></div>
<div id="main-container">
<!-- Loading State -->
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="relative w-14 h-14">
<div class="absolute inset-0 rounded-full border-4 border-blue-200 animate-pulse"></div>
<div class="absolute inset-0 rounded-full border-4 border-blue-600 border-t-transparent animate-spin"></div>
</div>
<span class="text-slate-500 font-medium text-sm tracking-wide">טוען את נתוני המערכת...</span>
</div>
</div>
</main>
</div>
<!-- Footer -->
<footer class="bg-white border-t border-slate-200 py-6 text-center text-xs text-slate-400">
<p>ממשק מותאם אישית לקהילת מתמחים טופ • נבנה בעיצוב מודרני מהיר ונוח</p>
</footer>
<script>
const scriptUrl = 'פריסה הדבק';
let currentCid = '';
let currentCatPage = 1;
let currentFontSizeLevel = parseInt(localStorage.getItem('forum_font_size') || '16');
let openTabs = [];
let activeTabId = null;
let currentMainView = { type: 'home', data: null };
document.addEventListener('DOMContentLoaded', () => {
if (localStorage.getItem('forum_dark_mode') === 'true') {
document.body.classList.add('dark-mode');
document.getElementById('dark-mode-btn').innerHTML = '☀️';
}
updateBookmarkCount();
applyFontSize();
});
function toggleDarkMode() {
document.body.classList.toggle('dark-mode');
const isDark = document.body.classList.contains('dark-mode');
localStorage.setItem('forum_dark_mode', isDark);
document.getElementById('dark-mode-btn').innerHTML = isDark ? '☀️' : '🌙';
}
function changeFontSize(action) {
if (action === 'increase' && currentFontSizeLevel < 22) {
currentFontSizeLevel += 2;
} else if (action === 'decrease' && currentFontSizeLevel > 12) {
currentFontSizeLevel -= 2;
}
localStorage.setItem('forum_font_size', currentFontSizeLevel);
applyFontSize();
}
function applyFontSize() {
const contents = document.querySelectorAll('.post-content');
contents.forEach(el => {
el.style.fontSize = currentFontSizeLevel + 'px';
});
}
function getBookmarks() {
try {
return JSON.parse(localStorage.getItem('forum_bookmarks') || '[]');
} catch (e) {
return [];
}
}
function toggleBookmark(tid, title) {
let bookmarks = getBookmarks();
const index = bookmarks.findIndex(b => b.tid === tid);
if (index > -1) {
bookmarks.splice(index, 1);
} else {
bookmarks.unshift({ tid, title: title || 'נושא ללא כותרת', date: new Date().toLocaleDateString('he-IL') });
}
localStorage.setItem('forum_bookmarks', JSON.stringify(bookmarks));
updateBookmarkCount();
}
function isBookmarked(tid) {
return getBookmarks().some(b => b.tid === tid);
}
function updateBookmarkCount() {
const count = getBookmarks().length;
const badge = document.getElementById('bm-count');
if (badge) badge.innerText = count;
}
function loadBookmarks() {
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'bookmarks' };
const container = document.getElementById('main-container');
const bookmarks = getBookmarks();
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<button onclick="loadHome()" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer">
← חזרה לדף הבית
</button>
<h2 class="text-xl font-bold text-slate-800">הנושאים השמורים שלי (מועדפים)</h2>
</div>
`;
if (bookmarks.length > 0) {
html += `<div class="bg-white rounded-2xl shadow-sm border border-slate-200 divide-y divide-slate-100 overflow-hidden mb-6">`;
bookmarks.forEach(bm => {
html += `
<div class="p-4 sm:p-5 hover:bg-blue-50/40 transition flex flex-col sm:flex-row sm:items-center justify-between gap-4 group">
<div onclick="loadTopic('${bm.tid}', '', 1, 1, false)" class="flex items-start gap-3 flex-1 cursor-pointer">
<div class="w-9 h-9 rounded-xl bg-amber-50 text-amber-600 flex items-center justify-center shrink-0 font-bold text-xs shadow-sm">
📌
</div>
<div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-700 text-base transition leading-snug">${escapeHtml(bm.title)}</h4>
<span class="text-xs text-slate-400">נשמר בתאריך: ${bm.date}</span>
</div>
</div>
<div class="flex items-center gap-2 self-start sm:self-center">
<button onclick="openInTab('${bm.tid}', '${escapeHtml(bm.title)}', '', 1, 1)" class="bg-blue-50 hover:bg-blue-100 text-blue-700 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
📑 פתח בטאב
</button>
<button onclick="toggleBookmark('${bm.tid}'); loadBookmarks();" class="bg-rose-50 hover:bg-rose-100 text-rose-600 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
הסר
</button>
</div>
</div>
`;
});
html += `</div>`;
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">אין עדיין נושאים שמורים במועדפים.</div>`;
}
container.innerHTML = html;
}
function addHistory(tid, title) {
if (!tid) return;
try {
let history = JSON.parse(localStorage.getItem('forum_history') || '[]');
history = history.filter(h => h.tid !== tid);
history.unshift({ tid, title: title || 'נושא ללא כותרת', time: new Date().toLocaleTimeString('he-IL', {hour: '2-digit', minute:'2-digit'}) });
if (history.length > 15) history.pop();
localStorage.setItem('forum_history', JSON.stringify(history));
} catch (e) {}
}
function loadHistory() {
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'history' };
const container = document.getElementById('main-container');
let history = [];
try {
history = JSON.parse(localStorage.getItem('forum_history') || '[]');
} catch (e) {}
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<button onclick="loadHome()" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer">
← חזרה לדף הבית
</button>
<div class="flex items-center gap-3">
<button onclick="localStorage.removeItem('forum_history'); loadHistory();" class="bg-rose-50 hover:bg-rose-100 text-rose-600 border border-rose-200 px-3.5 py-2 rounded-xl text-xs font-bold transition cursor-pointer">
🗑️ נקה היסטוריה
</button>
<h2 class="text-xl font-bold text-slate-800">היסטוריית צפייה</h2>
</div>
</div>
`;
if (history.length > 0) {
html += `<div class="bg-white rounded-2xl shadow-sm border border-slate-200 divide-y divide-slate-100 overflow-hidden mb-6">`;
history.forEach(item => {
html += `
<div class="p-4 sm:p-5 hover:bg-blue-50/40 transition flex flex-col sm:flex-row sm:items-center justify-between gap-4 group">
<div onclick="loadTopic('${item.tid}', '', 1, 1, false)" class="flex items-start gap-3 flex-1 cursor-pointer">
<div class="w-9 h-9 rounded-xl bg-slate-100 group-hover:bg-blue-600 group-hover:text-white text-slate-500 flex items-center justify-center shrink-0 transition font-bold text-xs shadow-sm">
📜
</div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-700 text-base transition leading-snug">${escapeHtml(item.title)}</h4>
</div>
<div class="flex items-center gap-2 self-start sm:self-center">
<button onclick="openInTab('${item.tid}', '${escapeHtml(item.title)}', '', 1, 1)" class="bg-blue-50 hover:bg-blue-100 text-blue-700 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
📑 פתח בטאב
</button>
<span class="bg-slate-100 text-slate-600 px-3 py-1.5 rounded-lg text-xs font-medium">🕒 ${item.time}</span>
</div>
</div>
`;
});
html += `</div>`;
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">אין היסטוריית גלישה זמינה.</div>`;
}
container.innerHTML = html;
}
async function loadRecentPosts() {
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'recent' };
const container = document.getElementById('main-container');
container.innerHTML = `
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="w-12 h-12 rounded-full border-4 border-blue-600 border-t-transparent animate-spin"></div>
<span class="text-slate-500 font-medium text-sm">טוען פוסטים אחרונים...</span>
</div>
`;
try {
const response = await fetch(`${scriptUrl}?recent=true`);
const data = await response.json();
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<button onclick="loadHome()" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer">
← חזרה לדף הבית
</button>
<h2 class="text-xl font-bold text-slate-800">🔥 פוסטים ודיונים אחרונים</h2>
</div>
`;
const topicsList = data.topics || data.posts || (Array.isArray(data) ? data : []);
if (topicsList.length > 0) {
html += `<div class="bg-white rounded-2xl shadow-sm border border-slate-200 divide-y divide-slate-100 overflow-hidden mb-6">`;
topicsList.forEach(topic => {
const tid = topic.tid || topic.topic_id;
const title = topic.title || 'נושא ללא כותרת';
html += `
<div class="p-4 sm:p-5 hover:bg-blue-50/40 transition flex flex-col sm:flex-row sm:items-center justify-between gap-4 group">
<div onclick="loadTopic('${tid}', '', 1, 1, true)" class="flex items-start gap-3 flex-1 cursor-pointer">
<div class="w-9 h-9 rounded-xl bg-blue-50 text-blue-600 flex items-center justify-center shrink-0 font-bold text-xs shadow-sm">
🔥
</div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-700 text-base transition leading-snug">${escapeHtml(title)}</h4>
</div>
<div class="flex items-center gap-2 self-start sm:self-center shrink-0">
<button onclick="openInTab('${tid}', '${escapeHtml(title)}', '', 1, 1)" class="bg-blue-50 hover:bg-blue-100 text-blue-700 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
📑 פתח בטאב
</button>
<span class="bg-slate-100 text-slate-600 px-3 py-1.5 rounded-lg text-xs font-medium">👁️ ${topic.viewcount || 0}</span>
</div>
</div>
`;
});
html += `</div>`;
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">לא נמצאו פוסטים אחרונים.</div>`;
}
container.innerHTML = html;
} catch (err) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה בטעינת פוסטים אחרונים.</div>`;
}
}
async function loadPopularPosts() {
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'popular' };
const container = document.getElementById('main-container');
container.innerHTML = `
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="w-12 h-12 rounded-full border-4 border-amber-500 border-t-transparent animate-spin"></div>
<span class="text-slate-500 font-medium text-sm">טוען נושאים פופולרים...</span>
</div>
`;
try {
const response = await fetch(`${scriptUrl}?top=true`);
const data = await response.json();
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<button onclick="loadHome()" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer">
← חזרה לדף הבית
</button>
<h2 class="text-xl font-bold text-slate-800">⭐ נושאים פופולרים וחמים</h2>
</div>
`;
const topicsList = data.topics || data.posts || (Array.isArray(data) ? data : []);
if (topicsList.length > 0) {
html += `<div class="bg-white rounded-2xl shadow-sm border border-slate-200 divide-y divide-slate-100 overflow-hidden mb-6">`;
topicsList.forEach(topic => {
const tid = topic.tid || topic.topic_id;
const title = topic.title || 'נושא ללא כותרת';
html += `
<div class="p-4 sm:p-5 hover:bg-amber-50/40 transition flex flex-col sm:flex-row sm:items-center justify-between gap-4 group">
<div onclick="loadTopic('${tid}', '', 1, 1, true)" class="flex items-start gap-3 flex-1 cursor-pointer">
<div class="w-9 h-9 rounded-xl bg-amber-50 text-amber-600 flex items-center justify-center shrink-0 font-bold text-xs shadow-sm">
⭐
</div>
<h4 class="font-bold text-slate-800 group-hover:text-amber-700 text-base transition leading-snug">${escapeHtml(title)}</h4>
</div>
<div class="flex items-center gap-2 self-start sm:self-center shrink-0">
<button onclick="openInTab('${tid}', '${escapeHtml(title)}', '', 1, 1)" class="bg-amber-50 hover:bg-amber-100 text-amber-700 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
📑 פתח בטאב
</button>
<span class="bg-slate-100 text-slate-600 px-3 py-1.5 rounded-lg text-xs font-medium">👁️ ${topic.viewcount || 0}</span>
</div>
</div>
`;
});
html += `</div>`;
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">לא נמצאו נושאים פופולרים.</div>`;
}
container.innerHTML = html;
} catch (err) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה בטעינת נושאים פופולרים.</div>`;
}
}
function openInTab(tid, title, cid, catPage, postPage) {
const existingTab = openTabs.find(t => t.tid === tid);
if (existingTab) {
activeTabId = tid;
renderTopicData(existingTab.data, existingTab.cid, existingTab.catPage, existingTab.postPage);
renderTabsBar();
return;
}
fetch(`${scriptUrl}?tid=${tid}&page=${postPage || 1}`).then(res => res.json()).then(data => {
if (data && !data.error) {
const newTab = { tid, title: data.title || title, data, cid, catPage, postPage: postPage || 1 };
openTabs.push(newTab);
activeTabId = tid;
renderTabsBar();
renderTopicData(data, cid, catPage, postPage || 1);
addHistory(tid, data.title);
} else {
alert('שגיאה בטעינת הנושא לטאב.');
}
}).catch(err => console.error(err));
}
function switchTab(tid) {
const tab = openTabs.find(t => t.tid === tid);
if (tab) {
activeTabId = tid;
renderTabsBar();
renderTopicData(tab.data, tab.cid, tab.catPage, tab.postPage);
}
}
function closeTab(event, tid) {
event.stopPropagation();
openTabs = openTabs.filter(t => t.tid !== tid);
if (activeTabId === tid) {
if (openTabs.length > 0) {
const lastTab = openTabs[openTabs.length - 1];
switchTab(lastTab.tid);
} else {
activeTabId = null;
renderTabsBar();
if (currentMainView.type === 'category') {
loadCategory(currentMainView.cid, currentMainView.page);
} else if (currentMainView.type === 'bookmarks') {
loadBookmarks();
} else if (currentMainView.type === 'history') {
loadHistory();
} else if (currentMainView.type === 'recent') {
loadRecentPosts();
} else if (currentMainView.type === 'popular') {
loadPopularPosts();
} else {
loadHome();
}
}
} else {
renderTabsBar();
}
}
function renderTabsBar() {
const bar = document.getElementById('tabs-bar');
if (openTabs.length === 0) {
bar.classList.add('hidden');
bar.innerHTML = '';
return;
}
bar.classList.remove('hidden');
let html = `<span class="text-xs font-bold text-slate-400 shrink-0 pl-1">טאבים פתוחים:</span>`;
openTabs.forEach(tab => {
const isActive = tab.tid === activeTabId;
html += `
<div onclick="switchTab('${tab.tid}')" class="flex items-center gap-2 px-3 py-1.5 rounded-xl text-xs font-semibold cursor-pointer transition shadow-xs shrink-0 ${isActive ? 'bg-blue-600 text-white' : 'bg-white hover:bg-slate-100 text-slate-700 border border-slate-200'}">
<span class="max-w-[140px] truncate">${escapeHtml(tab.title)}</span>
<span onclick="closeTab(event, '${tab.tid}')" class="hover:bg-black/20 rounded-full w-4 h-4 flex items-center justify-center text-[10px]">✕</span>
</div>
`;
});
bar.innerHTML = html;
}
document.addEventListener('click', function(e) {
const anchor = e.target.closest('a');
if (!anchor) return;
const href = anchor.getAttribute('href');
if (!href) return;
const tidMatch = href.match(/(?:\/|^)topic\/([^\/\?#]+)/);
const cidMatch = href.match(/(?:\/|^)category\/([^\/\?#]+)/);
if (tidMatch) {
e.preventDefault();
loadTopic(tidMatch[1], currentCid, currentCatPage, 1, true);
} else if (cidMatch) {
e.preventDefault();
loadCategory(cidMatch[1], 1);
}
});
function handleCustomUrl() {
const urlInput = document.getElementById('url-input').value.trim();
if (!urlInput) return;
const tidMatch = urlInput.match(/(?:\/|^)topic\/([^\/\?#]+)/);
const cidMatch = urlInput.match(/(?:\/|^)category\/([^\/\?#]+)/);
if (tidMatch) {
loadTopic(tidMatch[1], '', 1, 1, true);
} else if (cidMatch) {
loadCategory(cidMatch[1], 1);
} else {
alert('הקישור שהוזן אינו זוהה כמועמד תקני לנושא או קטגוריה.');
}
}
async function handleSearch() {
const query = document.getElementById('search-input').value.trim();
if (!query) return;
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'search' };
const container = document.getElementById('main-container');
container.innerHTML = `
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="w-12 h-12 rounded-full border-4 border-blue-600 border-t-transparent animate-spin"></div>
<span class="text-slate-500 font-medium text-sm">מחפש "${escapeHtml(query)}"...</span>
</div>
`;
try {
const response = await fetch(`${scriptUrl}?term=${encodeURIComponent(query)}`);
const data = await response.json();
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<button onclick="loadHome()" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer">
← חזרה לדף הבית
</button>
<h2 class="text-xl font-bold text-slate-800">תוצאות חיפוש: "${escapeHtml(query)}"</h2>
</div>
`;
const results = data.topics || data.posts || (Array.isArray(data) ? data : []);
if (results.length > 0) {
html += `<div class="bg-white rounded-2xl shadow-sm border border-slate-200 divide-y divide-slate-100 overflow-hidden mb-6">`;
results.forEach(topic => {
const tid = topic.tid || topic.topic_id;
const title = topic.title || 'נושא ללא כותרת';
html += `
<div class="p-4 sm:p-5 hover:bg-blue-50/40 transition flex flex-col sm:flex-row sm:items-center justify-between gap-4 group">
<div onclick="loadTopic('${tid}', '', 1, 1, true)" class="flex items-start gap-3 flex-1 cursor-pointer">
<div class="w-9 h-9 rounded-xl bg-slate-100 group-hover:bg-blue-600 group-hover:text-white text-slate-500 flex items-center justify-center shrink-0 transition font-bold text-xs shadow-sm">
🔍
</div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-700 text-base transition leading-snug">${escapeHtml(title)}</h4>
</div>
<div class="flex items-center gap-2 self-start sm:self-center shrink-0">
<button onclick="openInTab('${tid}', '${escapeHtml(title)}', '', 1, 1)" class="bg-blue-50 hover:bg-blue-100 text-blue-700 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
📑 פתח בטאב
</button>
<span class="bg-slate-100 text-slate-600 px-3 py-1.5 rounded-lg text-xs font-medium">👁️ ${topic.viewcount || 0}</span>
</div>
</div>
`;
});
html += `</div>`;
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">לא נמצאו תוצאות חיפוש.</div>`;
}
container.innerHTML = html;
} catch (err) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה בביצוע החיפוש.</div>`;
}
}
async function loadHome() {
currentCid = '';
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'home' };
const container = document.getElementById('main-container');
container.innerHTML = `
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="w-12 h-12 rounded-full border-4 border-blue-600 border-t-transparent animate-spin"></div>
<span class="text-slate-500 font-medium text-sm">טוען את דף הבית...</span>
</div>
`;
try {
const response = await fetch(scriptUrl);
const data = await response.json();
if (data && data.categories && Array.isArray(data.categories) && data.categories.length > 0) {
let html = `
<div class="mb-6">
<h2 class="text-xl font-bold text-slate-800 tracking-tight">קטגוריות ראשיות</h2>
<p class="text-sm text-slate-500">בחר קטגוריה לצפייה בנושאים ודיונים</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
`;
data.categories.forEach(cat => {
html += `
<div onclick="loadCategory('${cat.cid}', 1)" class="group bg-white p-5 rounded-2xl shadow-sm hover:shadow-xl border border-slate-200/80 hover:border-blue-500/50 transition-all duration-300 cursor-pointer flex flex-col justify-between gap-4 relative overflow-hidden">
<div class="absolute top-0 right-0 w-1.5 h-full bg-blue-500 opacity-0 group-hover:opacity-100 transition-opacity"></div>
<div class="flex items-start justify-between gap-3">
<h3 class="font-bold text-slate-800 group-hover:text-blue-600 text-lg transition line-clamp-2">${escapeHtml(cat.name)}</h3>
<span class="p-2.5 rounded-xl bg-blue-50 text-blue-600 group-hover:bg-blue-600 group-hover:text-white transition-all shadow-sm">
📁
</span>
</div>
<div class="flex items-center gap-2 pt-2 border-t border-slate-100 text-xs font-medium">
<span class="bg-slate-100 text-slate-600 px-3 py-1 rounded-lg">נושאים: <strong class="text-slate-800">${cat.topic_count || 0}</strong></span>
<span class="bg-blue-50/70 text-blue-700 px-3 py-1 rounded-lg">הודעות: <strong class="text-blue-900">${cat.post_count || 0}</strong></span>
</div>
</div>
`;
});
html += `</div>`;
container.innerHTML = html;
} else {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-500 font-medium border border-slate-200">לא נמצאו קטגוריות להצגה.</div>`;
}
} catch (error) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה בטעינת דף הבית.</div>`;
}
}
async function loadCategory(cid, page = 1) {
currentCid = cid;
currentCatPage = page;
activeTabId = null;
renderTabsBar();
currentMainView = { type: 'category', cid, page };
const container = document.getElementById('main-container');
container.innerHTML = `
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="w-12 h-12 rounded-full border-4 border-blue-600 border-t-transparent animate-spin"></div>
<span class="text-slate-500 font-medium text-sm">טוען נתונים מהקטגוריה...</span>
</div>
`;
try {
const response = await fetch(`${scriptUrl}?cid=${cid}&page=${page}`);
const data = await response.json();
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<button onclick="loadHome()" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer flex items-center gap-2">
← חזרה לדף הבית
</button>
<div class="bg-white border border-slate-200 px-4 py-2 rounded-xl text-xs font-semibold text-slate-500 shadow-sm">
עמוד ${page}
</div>
</div>
<div class="bg-gradient-to-br from-white to-slate-50 rounded-2xl shadow-sm border border-slate-200 p-6 sm:p-8 mb-6">
<h2 class="text-2xl font-black text-slate-900 tracking-tight">${escapeHtml(data.name || 'קטגוריה')}</h2>
</div>
`;
if (data && data.topics && Array.isArray(data.topics) && data.topics.length > 0) {
html += `<h3 class="text-base font-bold text-slate-700 mb-3 px-1">נושאים בקטגוריה</h3>`;
html += `<div class="bg-white rounded-2xl shadow-sm border border-slate-200 divide-y divide-slate-100 overflow-hidden mb-6">`;
data.topics.forEach(topic => {
html += `
<div class="p-4 sm:p-5 hover:bg-blue-50/40 transition flex flex-col sm:flex-row sm:items-center justify-between gap-4 group">
<div onclick="loadTopic('${topic.tid}', '${cid}', ${page}, 1, true)" class="flex items-start gap-3 flex-1 cursor-pointer">
<div class="w-9 h-9 rounded-xl bg-slate-100 group-hover:bg-blue-600 group-hover:text-white text-slate-500 flex items-center justify-center shrink-0 transition font-bold text-xs shadow-sm">
💬
</div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-700 text-base transition leading-snug">${escapeHtml(topic.title)}</h4>
</div>
<div class="flex items-center gap-2 self-start sm:self-center shrink-0">
<button onclick="openInTab('${topic.tid}', '${escapeHtml(topic.title)}', '${cid}', ${page}, 1)" class="bg-blue-50 hover:bg-blue-100 text-blue-700 px-3 py-1.5 rounded-lg text-xs font-bold transition cursor-pointer">
📑 פתח בטאב
</button>
<span class="bg-slate-100 text-slate-600 px-3 py-1.5 rounded-lg text-xs font-medium">👁️ ${topic.viewcount || 0}</span>
<span class="bg-blue-50 text-blue-700 px-3 py-1.5 rounded-lg text-xs font-medium">💬 ${topic.postcount || 0}</span>
</div>
</div>
`;
});
html += `</div>`;
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">אין נושאים להצגה בקטגוריה זו.</div>`;
}
container.innerHTML = html;
} catch (error) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה בטעינת הקטגוריה.</div>`;
}
}
async function loadTopic(tid, cid, catPage, postPage = 1, openAsMain = false) {
currentCid = cid;
currentCatPage = catPage;
if (openAsMain) {
activeTabId = null;
renderTabsBar();
}
const container = document.getElementById('main-container');
container.innerHTML = `
<div class="flex flex-col justify-center items-center py-28 gap-4">
<div class="w-12 h-12 rounded-full border-4 border-blue-600 border-t-transparent animate-spin"></div>
<span class="text-slate-500 font-medium text-sm">טוען תוכן הפוסט...</span>
</div>
`;
try {
const response = await fetch(`${scriptUrl}?tid=${tid}&page=${postPage}`);
const data = await response.json();
if (data && data.error) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה: ${escapeHtml(data.error)}</div>`;
return;
}
addHistory(tid, data.title);
renderTopicData(data, cid, catPage, postPage);
} catch (error) {
container.innerHTML = `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-red-500 font-medium border border-slate-200">שגיאה בטעינת תוכן הפוסט.</div>`;
}
}
function renderTopicData(data, cid, catPage, postPage) {
const container = document.getElementById('main-container');
let backAction = cid ? `loadCategory('${cid}', ${catPage})` : `loadHome()`;
const tid = data.tid || '';
const title = data.title || 'תוכן הפוסט';
const bookmarked = isBookmarked(tid);
let html = `
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 no-print">
<button onclick="${backAction}" class="self-start bg-white hover:bg-slate-50 text-slate-700 border border-slate-200 px-4 py-2.5 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer flex items-center gap-2">
← חזרה אחורה
</button>
<div class="flex flex-wrap items-center gap-2">
<button onclick="window.print()" class="bg-blue-50 hover:bg-blue-100 text-blue-700 border border-blue-200 px-3.5 py-2 rounded-xl text-xs font-bold transition shadow-sm cursor-pointer">
🖨️ הדפסה נקייה
</button>
<button onclick="toggleBookmark('${tid}', '${escapeHtml(title)}'); renderTopicData(dataForRender, '${cid}', ${catPage}, ${postPage});" class="bg-white hover:bg-slate-50 ${bookmarked ? 'text-amber-500 border-amber-300' : 'text-slate-600 border-slate-200'} px-3.5 py-2 rounded-xl text-xs font-bold transition shadow-sm cursor-pointer">
${bookmarked ? '📌 מוסר ממועדפים' : '📍 שמור במועדפים'}
</button>
</div>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-6 sm:p-8 mb-6">
<h2 class="text-2xl font-black text-slate-900 tracking-tight leading-snug">${escapeHtml(title)}</h2>
</div>
`;
window.dataForRender = data;
if (data && data.posts && Array.isArray(data.posts) && data.posts.length > 0) {
data.posts.forEach((post, index) => {
const authorName = (post.user && post.user.username) ? post.user.username : 'משתמש אנונימי';
const likesCount = (post.upvotes !== undefined) ? post.upvotes : (post.votes || 0);
const initial = authorName.charAt(0).toUpperCase();
html += `
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-6 sm:p-8 mb-4 relative overflow-hidden">
<div class="flex items-center justify-between mb-6 pb-4 border-b border-slate-100">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-gradient-to-tr from-blue-600 to-indigo-600 text-white font-bold flex items-center justify-center shadow-md text-sm">
${escapeHtml(initial)}
</div>
<div>
<h4 class="font-bold text-slate-800 text-sm">${escapeHtml(authorName)}</h4>
<span class="text-xs text-slate-400">תגובה מספר #${index + 1}</span>
</div>
</div>
<div class="bg-rose-50 text-rose-600 border border-rose-100 text-xs px-3.5 py-1.5 rounded-xl font-bold flex items-center gap-1.5 shadow-xs">
❤️ ${likesCount} לייקים
</div>
</div>
<div class="post-content text-slate-700 leading-relaxed space-y-4 text-base" style="font-size: ${currentFontSizeLevel}px;">
${post.content || ''}
</div>
</div>
`;
});
} else {
html += `<div class="bg-white p-12 rounded-2xl shadow-sm text-center text-slate-400 font-medium border border-slate-200">אין תגובות זמינות להצגה.</div>`;
}
container.innerHTML = html;
setupCopyButtons();
}
function setupCopyButtons() {
const pres = document.querySelectorAll('main pre');
pres.forEach(pre => {
if (pre.querySelector('.copy-code-btn')) return;
const button = document.createElement('button');
button.className = 'copy-code-btn absolute top-3 left-3 bg-slate-700 hover:bg-slate-600 text-slate-200 text-xs px-3 py-1.5 rounded-lg font-medium transition shadow-sm cursor-pointer no-print';
button.innerHTML = '📋 העתק';
button.addEventListener('click', () => {
const code = pre.querySelector('code') || pre;
navigator.clipboard.writeText(code.innerText).then(() => {
button.innerHTML = '✅ הועתק!';
setTimeout(() => { button.innerHTML = '📋 העתק'; }, 2000);
});
});
pre.appendChild(button);
});
}
function escapeHtml(text) {
if (!text) return '';
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}
loadHome();
</script>
</body>
</html>