From 71a82fe0623b42669bca35a31024765a66c79af4 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:26:05 +0330 Subject: [PATCH] Import source: app/src/widgets/GlossaryWidget Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- app/src/widgets/GlossaryWidget.jsx | 101 +++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 app/src/widgets/GlossaryWidget.jsx diff --git a/app/src/widgets/GlossaryWidget.jsx b/app/src/widgets/GlossaryWidget.jsx new file mode 100644 index 0000000..c666e55 --- /dev/null +++ b/app/src/widgets/GlossaryWidget.jsx @@ -0,0 +1,101 @@ +// Embeddable glossary definition card. +// Rendered in an iframe; sends postMessage resize to parent only when height changes. +import { useEffect, useRef } from 'react'; +import { TeknavData } from '../../teknav-data.js'; + +const SITE_URL = 'https://www.teknav.ir'; + +const light = { + card: { background: '#fff', border: '1px solid #E4DDD2', color: '#263238' }, + header: { background: '#0C1E22' }, + footer: { background: '#F8F5F0', borderTop: '1px solid #E4DDD2' }, + summary: { color: '#263238' }, + faqQ: { color: '#0F6B73' }, + faqA: { color: '#5F6B6D' }, + link: { color: '#0F6B73' }, +}; +const dark = { + card: { background: '#0C1E22', border: '1px solid rgba(255,255,255,0.1)', color: '#E4DDD2' }, + header: { background: '#061014' }, + footer: { background: '#061014', borderTop: '1px solid rgba(255,255,255,0.08)' }, + summary: { color: 'rgba(255,255,255,0.85)' }, + faqQ: { color: '#D49A2A' }, + faqA: { color: 'rgba(255,255,255,0.6)' }, + link: { color: '#D49A2A' }, +}; + +function useTheme() { + const darkMq = typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)'); + return darkMq?.matches ? dark : light; +} + +export function GlossaryWidget({ slug }) { + const term = (TeknavData.glossary ?? []).find((g) => g.slug === slug); + const theme = useTheme(); + const lastHeight = useRef(0); + + useEffect(() => { + const el = document.getElementById('widget-root'); + if (!el) return; + const observer = new ResizeObserver((entries) => { + for (const entry of entries) { + const h = entry.target.offsetHeight || 0; + if (h !== lastHeight.current) { + lastHeight.current = h; + window.parent?.postMessage({ type: 'resize', height: h }, '*'); + } + } + }); + observer.observe(el); + return () => observer.disconnect(); + }, []); + + const cardBase = { + fontFamily: '\'Vazirmatn\', Tahoma, sans-serif', + direction: 'rtl', + maxWidth: 480, + borderRadius: 12, + overflow: 'hidden', + ...theme.card, + }; + + if (!term) { + return ( +
+ اصطلاح یافت نشد. +
+ ); + } + + return ( +
+
+ {term.term} + {term.english} +
+
+

{term.summary}

+ {(term.faqs || []).length > 0 && ( +
+ {term.faqs.map(([q, a], i) => ( +
+ {q} +

{a}

+
+ ))} +
+ )} +
+
+ + منبع: تکناو ↗ + +
+
+ ); +}