الفئة التي تقوم بتحميل مواضيع عشوائية؟

لقد حاولت البحث في جوجل، لكنني لم أجد شيئًا متعلقًا بهذا.
أعتقد أن بعض المواضيع يمكن أن تكون ذات قيمة كبيرة، لكن المستخدمين يميلون إلى التركيز أكثر على أحدث المواضيع (إلا إذا وصلوا إلى منتدى من بحث جوجل، على سبيل المثال).

هل من الممكن، ربما من خلال مكون/إضافة، وجود فئة أو شيء من هذا القبيل، حيث يتم تحميل مواضيع عشوائية تلقائيًا؟ هذا من شأنه أن يحيي بعض المشاركات القديمة التي ربما لم تحظ بالكثير من التفاعل قبل 3 سنوات، ولكنها كانت لا تزال ذات قيمة، وربما الآن مع المزيد من المستخدمين يمكن أن تحظى بالاهتمام الذي تستحقه.

للتوضيح، لا أريد أن تقتصر المواضيع العشوائية على فئة واحدة، على الرغم من أن ذلك قد يكون جيدًا أيضًا. كنت أفكر في ميزة عامة حيث يمكن تحميل أي موضوع من أي فئة في هذا القسم. بشكل أساسي بنفس الطريقة التي عندما أذهب إلى الصفحة الرئيسية لـ https://meta.discourse.org/ يمكنني رؤية قائمة بجميع أحدث المواضيع، بغض النظر عن الفئة، ولكن في حالتي، سيتم تحميل مواضيع عشوائية أيضًا من أي فئة، ولكنها غير مركزة على تاريخ المواضيع أو حتى أحدث الردود.

آمل أن يكون هذا منطقيًا…

إعجابَين (2)

أنا أحب فكرة المواضيع العشوائية، ولكن أفترض أنه يجب إجراء تعديلات.
منتدى الخاص بي عمره أكثر من 20 عامًا وسيكون من الغريب أن تكون هناك صفحة تحتوي على مجموعة من المواضيع العشوائية التي يزيد عمرها عن عقد من الزمان.

إذا كنت ترغب في استهداف المواضيع ذات المشاركة المنخفضة، فيجب أن يكون هناك معلمة مثل الحد الأقصى لعدد الردود التي تظهر.

حتى مع ذلك، هذا لا يعني أن كل هذه المواضيع ذات المشاركة المنخفضة مثيرة للاهتمام.

هل تريد استهداف المواضيع بناءً على بعض المعايير، أم مجرد… عشوائية؟

أقرب شيء موجود يكمن في إعدادات الفئة:

تم استخدامه (ربما لا يزال؟) هنا في #support، حيث أن الحالة المثالية لمواضيع Support هي محلولة/مغلقة. المواضيع المفتوحة هنا تعني عادةً أنه لم يتم تقديم حل، لذا فهي تمنح فرصة للمواضيع ذات المشاركة المنخفضة ليتم النظر فيها، حتى لو كان ذلك بعد شهور أو سنوات - يمكن أن تكون دائمًا ذات قيمة.

إعجاب واحد (1)

عشوائية.

يمكن أن تكون فئة معينة، على سبيل المثال، أو حتى زر لـ “عشوائي”.
أو ربما مجرد قسم في أسفل أحدث المشاركات يتم تحميله مثل 3 أو 4 مشاركات قديمة عشوائية؟

حتى المشاركات من منتدى عمره 20 عامًا أو أكثر يمكن أن تكون ذات صلة اليوم، ولكن ربما عندما تم إنشاؤها، لم يهتم بها أحد حقًا ويمكن أن تحصل على بعض “الحب” الآن :wink:

إعجابَين (2)

اليوم قررت أن أطلب المساعدة من كلود في هذا الأمر.
هذا ما توصلنا إليه، بعد الكثير من الاختبارات والتصحيحات (إنه يقوم بتحميل المواضيع المفتوحة فقط، وهو ما يبدو منطقيًا بالنسبة لي):

عند النقر على “تحميل المزيد من المواضيع العشوائية”، يتم تحميل 5 مواضيع إضافية أسفل المواضيع الحالية. النقر على الزر مرة أخرى يضيف 5 أخرى، حتى لا يتبقى المزيد من المواضيع:

لتحميل المواضيع العشوائية، ما عليك سوى زيارة:
yourwebsite.com/?random


إليك كيفية التنفيذ:

1 - إنشاء مكون (component)
2 - أضف هذا إلى علامة التبويب JS:

import { apiInitializer } from "discourse/lib/api";
// إخفاء المحتوى فورًا إذا كان ?random موجودًا في عنوان URL
if (new URLSearchParams(window.location.search).has('random')) {
  const style = document.createElement('style');
  style.textContent = '#main-outlet { display: none; }';
  document.head.appendChild(style);
}

let loadedTopicIds = new Set();

function addRandomTopics(listDiv, button) {
  // إخفاء الزر وإظهار التحميل
  button.style.display = 'none';
  const loadingDiv = document.createElement('div');
  loadingDiv.className = 'loading-more';
  loadingDiv.textContent = 'Loading...';
  listDiv.appendChild(loadingDiv);
  
  const query = `status:open`;
  
  fetch(`/search.json?q=${encodeURIComponent(query)}`)
    .then((response) => response.json())
    .then((data) => {
      loadingDiv.remove();
      
      if (!data || !data.topics || data.topics.length === 0) {
        button.remove();
        const noMoreDiv = document.createElement('div');
        noMoreDiv.className = 'no-more-topics';
        noMoreDiv.textContent = 'No more topics to load';
        listDiv.appendChild(noMoreDiv);
        return;
      }
      
      // تصفية المواضيع التي تم تحميلها بالفعل
      const unloadedTopics = data.topics.filter(topic => !loadedTopicIds.has(topic.id));
      
      if (unloadedTopics.length === 0) {
        button.remove();
        const noMoreDiv = document.createElement('div');
        noMoreDiv.className = 'no-more-topics';
        noMoreDiv.textContent = 'No more topics to load';
        listDiv.appendChild(noMoreDiv);
        return;
      }
      
      // خلط واختيار ما يصل إلى 5 مواضيع عشوائية
      const shuffled = unloadedTopics.sort(() => 0.5 - Math.random());
      const selected = shuffled.slice(0, Math.min(5, unloadedTopics.length));
      
      // الحصول على الفئة من بيانات موقع Discourse
      const site = Discourse.__container__.lookup('site:main');
      
      selected.forEach(topic => {
        loadedTopicIds.add(topic.id);
        
        const date = new Date(topic.created_at);
        const formattedDate = date.toLocaleDateString('en-US', { 
          year: 'numeric', 
          month: 'short', 
          day: 'numeric' 
        });
        
        const itemDiv = document.createElement('div');
        itemDiv.className = 'random-topic-item';
        
        const linkDiv = document.createElement('div');
        linkDiv.className = 'random-topic-link';
        
        const link = document.createElement('a');
        link.href = `/t/${topic.slug}/${topic.id}`;
        link.textContent = topic.unicode_title || topic.title;
        
        linkDiv.appendChild(link);
        
        const metaDiv = document.createElement('div');
        metaDiv.className = 'random-topic-meta';
        
        const category = site.categories.find(cat => cat.id === topic.category_id);
        const categoryName = category?.name || 'Uncategorized';
        
        metaDiv.textContent = `${categoryName} • ${formattedDate}`;
        
        itemDiv.appendChild(linkDiv);
        itemDiv.appendChild(metaDiv);
        
        // الإدراج قبل الزر
        listDiv.insertBefore(itemDiv, button);
      });
      
      // التحقق مما إذا كنا قد قمنا بتحميل جميع المواضيع المتاحة
      if (selected.length < 5 || loadedTopicIds.size >= data.topics.length) {
        button.remove();
        const noMoreDiv = document.createElement('div');
        noMoreDiv.className = 'no-more-topics';
        noMoreDiv.textContent = 'No more topics to load';
        listDiv.appendChild(noMoreDiv);
      } else {
        button.style.display = 'block';
      }
    })
    .catch((err) => {
      console.error("Fetch error:", err);
      loadingDiv.remove();
      button.style.display = 'block';
    });
}

function loadRandomTopics(container) {
  // إعادة تعيين المواضيع المحملة
  loadedTopicIds = new Set();
  
  container.innerHTML = '<div class="spinner"></div>';
  
  const query = `status:open`;
  
  fetch(`/search.json?q=${encodeURIComponent(query)}`)
    .then((response) => response.json())
    .then((data) => {
      if (!data || !data.topics || data.topics.length === 0) {
        container.innerHTML = '<p>No topics found</p>';
        return;
      }
      
      // خلط واختيار 5 مواضيع عشوائية
      const shuffled = data.topics.sort(() => 0.5 - Math.random());
      const selected = shuffled.slice(0, 5);
      
      // بناء HTML
      const listDiv = document.createElement('div');
      listDiv.className = 'random-topics-list';
      
      const heading = document.createElement('h2');
      heading.textContent = 'Random Open Topics';
      listDiv.appendChild(heading);
      
      // الحصول على الفئة من بيانات موقع Discourse
      const site = Discourse.__container__.lookup('site:main');
      
      selected.forEach(topic => {
        loadedTopicIds.add(topic.id);
        
        const date = new Date(topic.created_at);
        const formattedDate = date.toLocaleDateString('en-US', { 
          year: 'numeric', 
          month: 'short', 
          day: 'numeric' 
        });
        
        const itemDiv = document.createElement('div');
        itemDiv.className = 'random-topic-item';
        
        const linkDiv = document.createElement('div');
        linkDiv.className = 'random-topic-link';
        
        const link = document.createElement('a');
        link.href = `/t/${topic.slug}/${topic.id}`;
        link.textContent = topic.unicode_title || topic.title;
        
        linkDiv.appendChild(link);
        
        const metaDiv = document.createElement('div');
        metaDiv.className = 'random-topic-meta';
        
        const category = site.categories.find(cat => cat.id === topic.category_id);
        const categoryName = category?.name || 'Uncategorized';
        
        metaDiv.textContent = `${categoryName} • ${formattedDate}`;
        
        itemDiv.appendChild(linkDiv);
        itemDiv.appendChild(metaDiv);
        listDiv.appendChild(itemDiv);
      });
      
      const button = document.createElement('button');
      button.className = 'btn btn-primary load-more-random';
      button.textContent = 'Load more random topics';
      button.addEventListener('click', () => {
        addRandomTopics(listDiv, button);
      });
      
      listDiv.appendChild(button);
      container.innerHTML = '';
      container.appendChild(listDiv);
    })
    .catch((err) => {
      console.error("Fetch error:", err);
      container.innerHTML = '<p>Error loading topics</p>';
    });
}

export default apiInitializer("1.8.0", (api) => {
  let wasOnRandomPage = new URLSearchParams(window.location.search).has('random');
  
  api.onPageChange(() => {
    const urlParams = new URLSearchParams(window.location.search);
    const isOnRandomPage = urlParams.has('random');
    
    // إذا كنا في صفحة عشوائية والآن لسنا كذلك، فرض إعادة تحميل
    if (wasOnRandomPage && !isOnRandomPage) {
      window.location.reload();
      return;
    }
    
    wasOnRandomPage = isOnRandomPage;
    
    if (!isOnRandomPage) {
      return;
    }
    
    // إظهار واستبدال المحتوى
    const mainContent = document.querySelector('#main-outlet');
    if (mainContent) {
      mainContent.style.display = 'block';
      mainContent.innerHTML = '<div id="random-topics-container"></div>';
      
      const container = document.querySelector('#random-topics-container');
      loadRandomTopics(container);
    }
  });
});

3 - أضف هذا إلى علامة التبويب CSS:

.random-topics-list {
  max-width: 800px;
  margin: 40px auto;
  padding: 20px;
}

.random-topics-list h2 {
  margin-bottom: 30px;
  font-size: 2em;
}

.random-topic-item {
  margin-bottom: 25px;
}

.random-topic-link a {
  color: #E9E9E9;
  text-decoration: underline;
  font-size: 1.1em;
}

.random-topic-link a:hover {
  color: #229ED7;
}

.random-topic-meta {
  color: #808080;
  font-size: 0.85em;
  margin-top: 4px;
}

.load-more-random {
  margin-top: 30px;
}

.loading-more {
  text-align: center;
  margin-top: 20px;
  color: #808080;
}

.no-more-topics {
  text-align: center;
  margin-top: 30px;
  color: #808080;
  font-style: italic;
}

.spinner {
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
  margin: 100px auto;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

إذا كان أي شخص يعرف كيفية استخدام عرض Discourse العادي بدلاً من استخدام صفحة HTML مخصصة، فسيكون ذلك رائعًا! أنا سعيد بالميزة نفسها، ولكن وجود التخطيط الافتراضي سيكون أفضل، إذا كان بإمكان شخص ما مشاركة كيفية القيام بذلك؟