نافذة معاينة الموضوع

:information_source: الملخص نافذة معاينة الموضوعات – افتح وتفاعل مع الموضوعات دون مغادرة قائمة الموضوعات
:eyeglasses: المعاينة Theme Creator
:hammer_and_wrench: المستودع GitHub - VaperinaDEV/discourse-topic-preview-modal: Open a topic directly from the topic list in a native Discourse modal, read and interact with the topic, and then continue browsing the list without navigating away from it. · GitHub
:heart: وجدتها مفيدة؟ > ./support --coffee
:question: دليل التثبيت كيفية تثبيت موضوع أو مكوّن موضوع
:open_book: جديد على مواضيع Discourse؟ دليل المبتدئين لاستخدام مواضيع Discourse

ثبّت هذا المكوّن

نافذة معاينة الموضوعات – افتح وتفاعل مع الموضوعات دون مغادرة قائمة الموضوعات

لقد قمت بإنشاء مكوّن موضوع جديد لـ Discourse يُسمى Topic Preview Modal.

الفكرة بسيطة إلى حد ما:

افتح موضوعًا مباشرة من قائمة الموضوعات في نافذة حوارية أصلية لـ Discourse، واقرأ وتفاعل مع الموضوع، ثم واصل تصفح القائمة دون التنقل بعيدًا عنها.

بدأ الأمر من Facebook-style Topic Modal - Is it better? ، لكن الأمر انتهى بأن يتطلب قدرًا كبيرًا من التكامل مع أنظمة الموضوعات، وتدفق الرسائل، والمحرر، والنوافذ الحوارية، والإشارات المرجعية، والتوجيه، والحضور، وتتبع القراءة، والتحميل المسبق في Discourse.


لماذا؟

التدفق العادي في Discourse هو:

  1. أنت تتصفح قائمة موضوعات.
  2. تنقر على موضوع.
  3. ينتقل Discourse إلى /t/....
  4. تقرأ/ترد/تتفاعل مع الموضوع.
  5. تعود إلى قائمة الموضوعات.

بالنسبة للعديد من سير العمل، هذا أمر مثالي تمامًا.

ومع ذلك، عند تصفح قائمة موضوعات مزدحمة، أحيانًا أريد فقط فحص موضوع بسرعة، وقراءة بعض الرسائل، والتحقق من آخر الردود، أو التفاعل مع شيء ما، أو الإجابة على سؤال سريع.

بالنسبة لحالة الاستخدام هذه، يبدو مغادرة قائمة الموضوعات مكلفًا بشكل غير ضروري.

لذلك كانت هدف هذا المكوّن هو جعل قائمة الموضوعات تتصرف بشكل أكثر تشابهًا مع صندوق الوارد:

قائمة الموضوعات → معاينة → تفاعل → إغلاق → المتابعة من حيث توقفت تمامًا.


ما الذي يفعله

المعاينة ليست مجرد مقتطف ثابت.

إنها تعرض مكوّنات رسائل Discourse الفعلية داخل نافذة DModal أصلية.

هذا يعني أن المستخدمين يمكنهم:

  • قراءة الرسائل
  • التمرير عبر الموضوع
  • تحميل رسائل سابقة
  • تحميل المزيد من الرسائل بالأسفل
  • التفاعل مع الرسائل
  • وضع إشارات مرجعية للرسائل
  • اقتباس النص
  • الرد على الموضوع
  • الرد على رسائل فردية
  • تعديل الرسائل عند السماح بذلك
  • حذف/استعادة الرسائل عند السماح بذلك
  • وضع علامات على الرسائل
  • عرض سجل الرسائل
  • تنفيذ إجراءات الرسائل العادية المختلفة
  • رؤية حضور الموضوع
  • اتباع الروابط إلى رسائل أخرى ضمن نفس الموضوع
  • القفز مباشرة إلى الرسالة ذات الصلة
  • فتح الموضوع الكامل عند الحاجة

النية هي أن تكون المعاينة قريبة قدر الإمكان من فتح الموضوع فعليًا.


وضعان للتشغيل

هناك طريقتان لفتح المعاينة.

1. صف قائمة الموضوعات بأكمله

هذا هو الوضع الافتراضي.

يصبح صف قائمة الموضوعات بأكمله قابلًا للنقر، بينما يتم استبعاد العناصر التفاعلية الشائعة مثل:

  • بطاقات المستخدمين
  • المشاركون
  • روابط التصنيفات
  • الوسوم
  • روابط حالة الموضوع
  • التحديد الجماعي

من محفز النافذة الحوارية.

يجعل هذا التجربة سريعة جدًا عند تصفح قائمة الموضوعات.

2. زر توسيع صريح

بشكل بديل، يمكن للمكوّن عرض أيقونة توسيع صغيرة عبر منفذ إضافة Discourse. يمكن لمواضيع المخصصة إنشاء <PluginOutlet /> جديد ببساطة لعرض المحفز.

في هذا الوضع، يبقى سلوك قائمة الموضوعات العادي غير منسجم تمامًا.

ينقر المستخدم على أيقونة التوسيع لفتح المعاينة، بينما يؤدي النقر على عنوان الموضوع إلى تنفيذ تنقل Discourse العادي.

هذا مفيد إذا أرادت المواقع الحفاظ على نموذج تفاعل قائمة الموضوعات القياسي.

الإعداد هو:

trigger_style:
  row

أو:

trigger_style:
  button

عند استخدام وضع الزر، يمكن تكوين المنفذ أيضًا.


تبدأ المعاينة من موضع غير المقروء للمستخدم

أحد التفاصيل المهمة هو أن النافذة الحوارية لا تحمّل الرسالة الأولى ببساطة.

عندما يكون الموضوع قد قُرئ جزئيًا بالفعل، تحسب المعاينة:

last_read_post_number + 1

وتفتح حول تلك الرسالة.

لذا، إذا كان للموضوع 200 رسالة وكان المستخدم قد قرأ حتى الرسالة رقم 165، فإن فتح المعاينة يبدأ حول رقم 166.

يجعل هذا المعاينة أكثر فائدة بكثير للتصفح في العالم الحقيقي.

كما يعني ذلك أن على المكوّن التعامل مع كلا الجانبين من تدفق الرسائل:

  • تحميل الرسائل السابقة عند الضرورة
  • تحميل الرسائل الأحدث بالأسفل

تظهر زر الرسائل السابقة عندما تكون هناك رسائل فوق النطاق المحمّل حاليًا، بينما يقوم مراقب تقاطع (IntersectionObserver) sentinel بتحميل المزيد من الرسائل تلقائيًا عندما يصل المستخدم إلى القاع.


التحميل المسبق

أحد أكبر أجزاء المكوّن هو نظام التحميل المسبق الخاص به.

المشكلة مع نافذة حوارية كهذه هي أن المستخدم يتوقع أن تبدو فورية.

إذا بدأنا تحميل الموضوع فقط بعد أن ينقر المستخدم، فقد تقضي النافذة الحوارية وقتًا ملحوظًا في الانتظار على الشبكة.

بدلًا من ذلك، يمكن للمكوّن أن يقوم بالتحميل المسبق للموضوعات بشكل استباقي أثناء تصفح المستخدم للقائمة.

عندما يقترب صف موضوع من نافذة العرض، يمكن لمراقب التقاطع (IntersectionObserver) جدولة تحميل مسبق.

هناك عدة ضوابط للتحديد لمنع هذا من أن يتحول إلى حركة خلفية غير مسيطر عليها.

إزالة الارتعاش (Debouncing)

لا يحفز الموضوع طلبًا فوريًا لمجرد أنه ظهر لفترة وجيزة في نافذة العرض.

ينتظر المكوّن فترة إزالة الارتعاش المحددة.

الافتراضي:

400 ms

هذا مفيد بشكل خاص عند التمرير السريع عبر قائمة موضوعات طويلة.

هامش الجذر (Root margin)

يمكن أن يبدأ التحميل المسبق قليلاً قبل أن يدخل الموضوع فعليًا إلى نافذة العرض.

الافتراضي:

50 px

يمنح هذا الطلب بداية صغيرة.

حد الطلبات المتزامنة

يتم تحديد عدد التحميلات المسبقة المتزامنة.

الافتراضي:

2

يسمح الإعداد بين 1 و 6 تحميلات مسبقة متزامنة.

ميزانية لكل دقيقة

هناك أيضًا آلية حماية ثانية:

max_prefetches_per_minute

الافتراضي هو:

15

لذا، حتى إذا واصل المستخدم التمرير عبر مئات الموضوعات، لن يولد المكوّن طلبات استكشافية بشكل مستمر.

0 يعطّل الحد.

يمكن تعطيل التحميل المسبق بالكامل

إذا لم ترغب المواقع في أي حركة شبكة استكشافية:

enable_prefetch = false

يستمر المكوّن في العمل بشكل طبيعي. يتم ببساطة تحميل الموضوعات عند فتح المعاينة.


يتم الاحتفاظ ببيانات التحميل المسبق منفصلة عن تنقل الموضوعات العادي

هناك تفصيل تنفيذي مهم هنا.

الاستجابة المحملة مسبقًا لا تُكتب فورًا إلى مفتاح التحميل المسبق العادي topic_<id> لـ Discourse.

بدلًا من ذلك، يستخدم المكوّن نطاقه الخاص:

topic-preview-modal:prefetch:<topicId>

فقط عندما يفتح المستخدم المعاينة فعليًا، يتم ترقية وعد التحميل المسبق إلى مفتاح التحميل المسبق الأساسي للموضوع.

هذا مقصود.

قد تكون المعاينة تقوم بتحميل موضوع يبدأ من last_read_post_number + 1، ولا أريد أن تتسرب استجابة المعاينة الخاصة هذه إلى تنقل مسار الموضوع العادي.

لذا، دورة الحياة هي في الأساس:

يدخل الموضوع نافذة العرض
        ↓
تحميل مسبق
        ↓
تخزين تحميل مسبق خاص
        ↓
يفتح المستخدم المعاينة
        ↓
ترقية التحميل المسبق
        ↓
Topic.find()/PostStream تستخدم نفس الوعد

هذا يعني أيضًا أن النافذة الحوارية لا تحتاج إلى انتظار اكتمال طلب التحميل المسبق قبل الفتح.

يمكن للنافذة الحوارية أن تفتح فورًا بهيكلها العظمي (skeleton) بينما يستمر نفس الوعد في الحل.


دعم الجوال

كان هذا في الواقع أحد الأسباب التي جعلتني أقضي وقتًا أطول بكثير في التنفيذ.

عملت الفكرة الأولية بشكل معقول على سطح المكتب، لكن الجوال كشف عن عدة مشاكل تتعلق بـ:

  • التفاعل باللمس
  • التمرير في النافذة الحوارية
  • التركيز
  • القوائم المتداخلة
  • المحرر
  • ظهور الرسائل
  • تحميل الصور
  • الأداء

لذلك يتجنب التنفيذ النهائي معاملة النافذة الحوارية كمنتدى مصغر منفصل تمامًا.

بدلًا من ذلك، يعيد استخدام أكبر قدر ممكن من البنية التحتية الحالية لـ Discourse.


مكوّنات رسائل Discourse الفعلية

لا تعيد النافذة الحوارية إنشاء الرسائل باستخدام قالب مخصص مبسط.

إنها تعرض مكوّنات:

Post
PostSmallAction

الفعلية من Discourse.

هذا مهم لأن المعاينة ستصبح وإلا تنفيذًا ثانيًا لواجهة الرسائل.

يمرر المكوّن الإجراءات ذات الصلة إلى مكوّنات الرسائل العادية، بما في ذلك أشياء مثل:

  • الرد
  • التعديل
  • الحذف
  • الاستعادة
  • وضع علامة
  • السجل
  • الإشارة المرجعية
  • ويكي
  • القفل/فك القفل
  • نوع الرسالة
  • تغييرات الملكية
  • الشارات
  • الرسائل المخفية
  • الاقتباس
  • وما إلى ذلك

النتيجة هي أن المعاينة يمكن أن تتصرف بشكل أكثر تشابهًا مع موضوع عادي مقارنة بمكوّن “معاينة” تقليدي.


الردود والمحرر

المحرر هو أحد الأجزاء الأكثر تعقيدًا.

يمكن للمعاينة فتح محرر Discourse العادي لـ:

الرد على الموضوع

يُفتح محرر الموضوع مع نموذج الموضوع ومعلومات المسودة الصحيحة.

الرد على رسالة محددة

تُمرر الرسالة إلى المحرر بحيث يتصرف الرد كرد عادي على رسالة.

اقتباس النص المحدد

يتكامل المكوّن أيضًا مع PostTextSelection.

هذا يعني أن المستخدمين يمكنهم تحديد النص داخل المعاينة واستخدام تدفق الاقتباس/الرد العادي في Discourse.


النوافذ الحوارية المتداخلة

كان جزءًا آخر صعبًا هو نظام النوافذ الحوارية في Discourse.

يمكن للرسائل فتح نوافذ حوارية ومربعات حوار أخرى:

  • وضع علامة
  • السجل
  • مربعات الحوار المتعلقة بالشارات
  • تغييرات الملكية
  • تأكيدات الحذف
  • وما إلى ذلك

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

لتجنب ذلك، ينشئ المكوّن آلية نافذة حوارية فرعية محلية.

مفاهيميًا:

نافذة معاينة الموضوع
        │
        ├── نافذة وضع علامة
        ├── نافذة السجل
        ├── تأكيد الحذف
        ├── نافذة الشارة
        └── نافذة حوار أخرى متعلقة بالرسالة

تبقى المعاينة مثبتة في الأسفل.

يقوم المكوّن بتدبيج طرق خدمة النوافذ الحوارية ذات الصلة مؤقتًا أثناء نشاطه ويعيدها عند تدميره.


التوجيه داخل النافذة الحوارية

تفصيل مهم آخر هو الروابط إلى الرسائل داخل نفس الموضوع.

على سبيل المثال، إذا احتوت رسالة على رابط إلى:

/t/my-topic/123

فلا تحتاج المعاينة إلى الإغلاق والتنقل بعيدًا.

بدلًا من ذلك، يعترض المكوّن تنقل نفس الموضوع ويقفز إلى الرسالة المطلوبة داخل النافذة الحوارية.

ينطبق الشيء نفسه على الروابط المستهدفة للموضوع دون رقم رسالة محدد.

هذا يبقي المستخدم داخل المعاينة.

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

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


تتبع القراءة وتتبع الوقت

أردت أيضًا أن تتصرف المعاينة بشكل صحيح من منظور Discourse.

لا ينبغي أن يعني فتح معاينة أن تتبع القراءة يتم تجاوزه بالكامل.

لذلك يتعامل المكوّن مع:

  • تتبع زيارات الموضوع
  • تتبع الرسائل المرئية
  • توقيت الموضوع
  • تحديثات آخر رسالة مقروءة

يستخدم مؤقت التوقيت مراقب تقاطع (IntersectionObserver) لتحديد الرسائل المرئية فعليًا.

كل 5 ثوانٍ، يتم تفريغ توقيت الرسائل المرئية إلى:

/topics/timings

عند إغلاق النافذة الحوارية، يتم تنفيذ تفريغ نهائي واحد حتى لا تضيع الثواني الأخيرة.

يقيد التنفيذ أيضًا فترة توقيت واحدة بحد أقصى 60 ثانية.


إبقاء حالة غير المقروء في قائمة الموضوعات متزامنة

كانت هناك مشكلة خفية أخرى هنا.

تحديث حالة تتبع الموضوعات في Discourse وحدها غير كافية لتحديث شارة غير المقروء المعروضة مباشرة على صف قائمة الموضوعات.

لذلك يقوم المكوّن بتحديث كائن الموضوع الفعلي المرتبط بالصف بعد تفريغ معلومات التوقيت.

يقوم بتحديث قيم مثل:

last_read_post_number
unread_posts
unread
new_posts

عند الاقتضاء.

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


ظهور الرسائل

تستخدم المعاينة مراقب تقاطع (IntersectionObserver) مشتركًا لتحديد متى تصبح الرسائل الفردية مرئية.

هناك أيضًا فحص مزامنة للظهور عند إرفاق المراقب.

يتعامل هذا مع حالة حافة حيث تكون الرسالة مرئية بالفعل عند تثبيتها، لكن أول استدعاء غير متزامن لمراقب التقاطع لم يتم تشغيله بعد.

هذا ذو صلة خاصة بالمواضيع القصيرة جدًا حيث قد يكون الموضوع بأكمله مرئيًا بالفعل عند فتح النافذة الحوارية.


اعتبارات الأداء

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

يتم تنفيذ عدة أشياء خصيصًا لذلك.

العرض التدريجي

لا يعرض التحميل الأولي كل رسالة فورًا.

يعرض المكوّن أولًا ما يكفي من الرسائل للوصول إلى الموضع المستهدف.

ثم يتم عرض الرسائل المتبقية تدريجيًا باستخدام:

requestIdleCallback

عند التوفر، مع بديل إلى setTimeout.

هذا مفيد بشكل خاص عند فتح موضوع طويل حول رسالة بعيدة في أسفل التدفق.

احتواء CSS

تستخدم الرسائل:

contain: layout;
content-visibility: auto;
contain-intrinsic-size: 1px 180px;

يسمح هذا للمتصفح بتجنب القيام بعمل عرض غير ضروري للرسائل غير المرئية حاليًا.

الصور الكسولة

تُعطى الصور التي لم تحدد وضع تحميل بعد تلقائيًا:

loading="lazy"
decoding="async"

يمنع هذا موضوعًا طويلًا يحتوي على العديد من الصور من تحميل كل شيء فورًا.


حالة التحميل

لا تعرض النافذة الحوارية مجرد منطقة بيضاء/فارغة بينما يتم تنفيذ الطلب.

لديها واجهة هيكلية (skeleton UI) مع:

  • عناصر نائبة للصور الرمزية
  • عناصر نائبة لأسماء المستخدمين/الأسماء
  • عناصر نائبة لجسم الرسالة
  • حركة لمعان (shimmer animation)

تحترم حركة اللمعان:

prefers-reduced-motion

لذلك يتم تعطيل الحركة للمستخدمين الذين طلبوا تقليل الحركة.


إبقاء موضع التمرير مستقرًا

هناك عدة أماكن يحتاج فيها المكوّن إلى التلاعب بموضع التمرير يدويًا.

على سبيل المثال، عند تحميل رسائل سابقة، يزيد المحتوى المُدرج الجديد من ارتفاع التمرير.

سيؤدي مجرد إدراج الرسائل في المقدمة إلى جعل الموضع الحالي للمستخدم يقفز.

لذلك يسجل المكوّن ارتفاع التمرير السابق ويعوض الفرق بعد إدراج الرسائل.

هذا يبقي المحتوى المرئي حاليًا في نفس المكان تقريبًا.

ينطبق الشيء نفسه عند القفز إلى رسالة معينة.

يؤدي المكوّن خطوة تموضع بعد العرض ويتحقق من الموضع مرة أخرى في الإطارات اللاحقة لمراعاة المحتوى الذي قد يستقر بعد.


حضور الموضوع

عندما تكون بيانات الموضوع ذات الصلة متاحة، يمكن للمعاينة أيضًا عرض معلومات حضور الموضوع في Discourse في أسفل النافذة الحوارية.

لذا يمكن للمستخدمين رؤية من هو آخر يشاهد الموضوع حاليًا دون الحاجة إلى مغادرة المعاينة.


التفاعل مع قوائم الجوال والتركيز

أدخل الجوال فئة أخرى من المشاكل.

تستخدم بعض عناصر واجهة Discourse خدمات النوافذ/القوائم المشتركة، وهذه الخدمات لا تعرف بالضرورة أن معاينة الموضوع تعمل حاليًا كسياق تصفح متداخل.

لذلك يحتوي المكوّن على معالجة إضافية حول:

  • modal.close()
  • قوائم Float Kit
  • استعادة التركيز
  • المحرر
  • عناصر التحكم بلوحة المفاتيح في عارض الصور (lightbox)
  • أقفال تمرير الجسم

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

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


التكوين

يعرض المكوّن حاليًا الإعدادات التالية:

الإعداد الافتراضي الوصف
trigger_style row اجعل الصف بأكمله قابلًا للنقر أو استخدم زرًا صريحًا
plugin_outlet topic-list-after-title المنفذ المستخدم بواسطة محفز الزر
enable_prefetch true تفعيل/تعطيل التحميل المسبق الخلفي للموضوعات
max_concurrent_prefetches 2 الحد الأقصى لطلبات التحميل المسبق المتزامنة
prefetch_debounce_ms 400 التأخير قبل بدء التحميل المسبق
prefetch_root_margin_px 50 ابدأ التحميل المسبق بهذا العدد من البكسلات قبل دخول الصف إلى نافذة العرض
max_prefetches_per_minute 15 الحد الأقصى لطلبات الاستكشاف لكل دقيقة

تم تصميم ضوابط التحميل المسبق لتكون قابلة للتكوين عمدًا لأن المجتمعات المختلفة يمكن أن يكون لديها أنماط حركة وخصائص استضافة/شبكة مختلفة جدًا.


أحد الأهداف التصميمية الرئيسية: لا تكسر Discourse العادي

حاولت إبقاء المكوّن قريبًا قدر الإمكان من البنية الحالية لـ Discourse.

لا ينفذ مكوّن رسائل خاصًا به، أو محررًا خاصًا به، أو نموذج موضوع خاصًا به، أو تدفق رسائل منفصلًا تمامًا.

بدلًا من ذلك، يبني سياق تصفح مؤقتًا حول مكوّنات وخدمات Discourse الحالية.

هذا هو السبب أيضًا في أن بعض أجزاء التنفيذ أكثر تعقيدًا مما قد يبدو في البداية.

كان التحدي الأكثر إثارة للاهتمام هو:

هل يمكن لموضوع أن يتصرف تقريبًا كموضوع عادي في Discourse بينما يتم عرضه فعليًا داخل سياق واجهة أخرى؟

تطلب ذلك التعامل مع الحدود بين الخدمات العالمية لـ Discourse والمعاينة المحلية.

18 إعجابًا

لمعلوماتك:

يوجد به مشاكل في الرياضيات. لكن هذا يمكن أن يكون حالة حدية أخرى، رغم ذلك.

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

أسطورة مطلقة :slight_smile: الآن لا بد من معرفة كيفية جعل هذا يعمل مع إعدادي :slight_smile: @awesomerobot ما الذي يعتمد عليه سماتك لنقرة السطر بالكامل

api.renderInOutlet("topic-list-before-link", TopicListItemClick);
إعجابَين (2)

بالنسبة لأي شخص يستخدم سمة Reddit-ish، إليك حل نجحت في تطبيقه.

توافق سمة Reddit-ish

ملاحظة سريعة لأي شخص يستخدم سمة Reddit-ish: زر النافذة المنبثقة (modal) نفسه يعمل، لكن مُفعّل الصف (row trigger) الافتراضي لا يعمل.

تكمن المشكلة في أن سمة Reddit-ish تحل محل سلوك صف قائمة المواضيع القياسي، وتتعامل مع النقرات على بطاقة الموضوع بأكملها. وبسبب ذلك، لا يعمل التعامل العادي مع نقرات الصف في النافذة المنبثقة كما هو مقصود.

تغيير إعداد “نافذة معاينة الموضوع” (Topic Preview Modal) إلى:

نوع المُفعّل: زر
منفذ الإضافة: topic-list-after-title

يعمل بشكل صحيح، لأن سمة Reddit-ish تتضمن بالفعل منفذ topic-list-after-title.

للحفاظ على سلوك النقر على البطاقة بأكملها، تركت نافذة معاينة الموضوع في وضع الزر، وقمت بتغيير إجراء openTopic() الموجود في سمة Reddit-ish بحيث يُفعّل زر المعاينة العامل.

إجراء Reddit-ish الأصلي هو:

@action
openTopic(event) {
  if (
    (event.target.nodeName === "A" && !event.target.closest(".raw-link")) ||
    event.target.closest(".badge-wrapper")
  ) {
    return;
  }

  const { navigateToTopic, topic } = this.args.outletArgs;

  if (wantsNewWindow(event)) {
    window.open(topic.lastUnreadUrl, "_blank");
  } else {
    navigateToTopic(topic, topic.lastUnreadUrl);
  }
}

قمت بتغييره إلى:

@action
openTopic(event) {
  if (
    (event.target.nodeName === "A" && !event.target.closest(".raw-link")) ||
    event.target.closest(".badge-wrapper") ||
    event.target.closest(".topic-preview-modal__trigger-wrapper")
  ) {
    return;
  }

  const { navigateToTopic, topic } = this.args.outletArgs;

  if (wantsNewWindow(event)) {
    window.open(topic.lastUnreadUrl, "_blank");
    return;
  }

  const previewButton = event.currentTarget.querySelector(
    ".topic-preview-modal__trigger-wrapper--button"
  );

  if (previewButton) {
    event.preventDefault();
    event.stopPropagation();
    previewButton.click();
    return;
  }

  navigateToTopic(topic, topic.lastUnreadUrl);
}

يتم عرض مُفعّل زر النافذة المنبثقة كالتالي:

<div class="topic-preview-modal__trigger-wrapper">
  <span
    role="button"
    class="topic-preview-modal__trigger-wrapper--button"
  >

لذلك، لا يعيد هذا أي منطق للنافذة المنبثقة. إنه ببساطة يجعل نقر بطاقة Reddit-ish يُفعّل زر المعاينة العامل الموجود مسبقًا.

النتيجة هي:

  • يفتح نقر بطاقة الموضوع نافذة المعاينة المنبثقة.

  • يفتح نقر عنوان الموضوع نافذة المعاينة المنبثقة.

  • لا يزال زر المعاينة يعمل.

  • لا يزال النقر مع Cmd/Ctrl يفتح الموضوع العادي في علامة تبويب جديدة.

  • تستمر الروابط العادية مثل الفئة وغيرها في العمل بشكل طبيعي.

  • إذا لم يكن زر المعاينة موجودًا، تعود سمة Reddit-ish إلى التنقل العادي في المواضيع.

لذلك، تعمل النافذة المنبثقة الأساسية بشكل جيد مع سمة Reddit-ish؛ عدم التوافق محدد مع مُفعّل الصف الافتراضي.

كما قمت بإخفاء الزر باستخدام

.topic-preview-modal__trigger-wrapper {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
3 إعجابات

الآن سأحاول جعل الردود المتداخلة تعمل في النافذة المنبثقة :slight_smile:

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

أنت يا صديقي رائع. هذا يجب أن يكون أكثر مكونات الثيمات روعة التي رأيتها منذ فترة طويلة.

الشيء الوحيد الذي ينقصني هو عرض أكبر / قابل للتكوين، سيكون من الرائع لو يمكننا جعله بنفس عرض المنشورات في عرض الموضوع.

إعجابَين (2)

لقد قمت بضبط العرض الأقصى إلى 800px

    .d-modal {
        --modal-max-width: 600px;
        --modal-width: 30em;
        --modal-min-width: 400px;
    }
إعجاب واحد (1)

هذا ينطبق على جميع النوافذ المنبثقة…
فعلت هذا أيضاً لجعل الأيقونة أقل بروزاً

.topic-preview-modal__trigger-wrapper--button .d-icon {
    fill: #888;
}

@media (width >= 40rem) {
  .d-modal.topic-preview-modal {
      --modal-max-width: 800px;
  }
}
إعجابَين (2)

@Don أنا فضولي: لماذا لم تعيد استخدام مكون <PostList> الخاص بالنواة؟

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

مرحباً @Jagster، شكراً لك على الإبلاغ! إليك الإصلاح: FIX: Replace visibility:hidden to allow MathJax rendering · VaperinaDEV/discourse-topic-preview-modal@f9eb70f · GitHub


شكراً لك @RGJ، لقد أضفت إعداداً لهذا الغرض.


هذا سؤال جيد.

PostList/PostListItem مصمم لقوائم الملخصات القائمة على المقتطفات (المسودات، الإشارات المرجعية، feeds النشاط)، وليس لعرض تدوينة الموضوع التفاعلية الفعلية.

يقوم بتصيير @post.excerpt/expandedExcerpt عبر DDecodedHtml، بالإضافة إلى رأس الصورة الرمزية/العنوان وزر التوسيع إلى المقتطف. لا توجد أي إجراءات للإعجاب، الاقتباس، الرد، التعديل، أو الإبلاغ - أي أن آلية المنشور التفاعلية التي يحتاجها النافذة المنبثقة غير موجودة.

كما أن ترقيم صفحات PostList أحادي الاتجاه (فقط fetchMorePosts يضيف المزيد عند التمرير لأسفل)، بينما يجب أن تفتح النافذة المنبثقة عند آخر منشور مقروء وتحميل المنشورات السابقة واللاحقة حوله - وهذا يتطلب تحميل الفجوات الخاص بخدمة postStream الحقيقية، وليس مجرد استدعاء لجلب المزيد.

لذلك، كان إعادة استخدام PostList يعني إعادة تنفيذ معظم السلوك التفاعلي لـ Post وتحميل الاتجاهين الخاص بـ postStream فوق مكون مصمم لمهمة مختلفة. استخدام مكون Post الأساسي الفعلي + postStream مباشرة بدلاً من ذلك يضمن أن يتصرف النافذة المنبثقة بشكل مطابق لصفحة الموضوع الحقيقية.

3 إعجابات

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

4 إعجابات

أجري الاختبار الآن! تحسينات مبهرة جداً في واجهة المستخدم

إعجابَين (2)

نحن بحاجة ماسة إلى تعزيزات هنا، لكن مع وقت الاستجابة هذا، أصبحت قلقًا بعض الشيء الآن — هل لديكم حياة :laughing:

شكرًا :sign_of_the_horns:

3 إعجابات

سؤال: لماذا يظهر border-top الخاص بـ .topic-avatar كفاصل بين الجزء المرئي من المنشور السابق أثناء التمرير وبداية المنشور الحالي؟ هل هذا هو الهدف المقصود من هذا border-top، أم أن هناك قاعدة تنسيق/تجاوز (overflow) تجعله يتصرف بهذه الطريقة؟

@media (width >= 40rem) {
    .topic-avatar {
        border-top: 1px solid var(--content-border-color);
        padding-top: var(--space-4);
        width: var(--topic-avatar-width);
        float: left;
        z-index: 2;
        height: 100%;
        overflow-anchor: none;
    }
}
إعجاب واحد (1)

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

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

مرحباً @Don، بعد تجربة هذا المكوّن الرائع لمدة 24 ساعة، كان الشيء الذي أعجبني هو السحب للأسفل لإغلاقه، إذ وجدت أنني لا أحتاج إلى تحريك إبهامي أو يدي، مما جعل استخدام الموقع سهلاً للغاية. ومع ذلك، لم يكن التمرير لأعلى في المواضيع الأطول أمراً مثالياً.

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

رابط للاختبار هو https://www.carptalk-online.co.uk/، وبطبيعة الحال يعمل فقط على الهواتف المحمولة.

3 إعجابات

جربت منتداك يا ديميان، وإجراء السحب هذا مثالي حقًا. عمل رائع، كعادتك دائمًا!

أتساءل هل يجب أن يعمل مكوّن هذا السمة في Horizon؟ جربته على نسختين مختلفتين، لكنه يعرض خطأً للمشرفين في الأعلى. يبدو أنه غير متوافق؟

آمل أن يعمل؛ فأنا أعجب حقًا بهذه المنظور الجديد للتجربة.

إعجابَين (2)

ما الخطأ الذي تواجهه؟

إعجابَين (2)

مرحباً :waving_hand:

أضفت إعدادًا جديدًا باسم: open_all_topic_links.

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

5 إعجابات

أنت الأفضل على الإطلاق (GOAT) في عالم النوافذ المنبثقة :slight_smile: هل هناك إمكانية لإضافة خاصية السحب إلى اليمين للإغلاق على الأجهزة المحمولة إلى النسخة الأساسية، ودعم العروض المتداخلة :eyes:

إعجابَين (2)