From 0514a660504f4411cf7af34b22d421326161e853 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:26:02 +0330 Subject: [PATCH] Import source: app/src/widgets/CompanyWidget Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- app/src/widgets/CompanyWidget.jsx | 133 ++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 app/src/widgets/CompanyWidget.jsx diff --git a/app/src/widgets/CompanyWidget.jsx b/app/src/widgets/CompanyWidget.jsx new file mode 100644 index 0000000..65b6cdc --- /dev/null +++ b/app/src/widgets/CompanyWidget.jsx @@ -0,0 +1,133 @@ +// Embeddable company profile card. +// Fetches from /api/companies/:slug; falls back to TeknavData static seed. +import { useEffect, useRef, useState } from 'react'; +import { TeknavData } from '../../teknav-data.js'; + +const SITE_URL = 'https://www.teknav.ir'; + +const isDark = typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches; + +const cardStyle = { + fontFamily: '\'Vazirmatn\', Tahoma, sans-serif', + direction: 'rtl', + maxWidth: 480, + border: isDark ? '1px solid rgba(255,255,255,0.1)' : '1px solid #E4DDD2', + borderRadius: 12, + overflow: 'hidden', + background: isDark ? '#0C1E22' : '#fff', +}; + +export function CompanyWidget({ slug }) { + const [company, setCompany] = useState(null); + const [loading, setLoading] = useState(true); + const lastHeight = useRef(0); + + useEffect(() => { + fetch(`/api/companies/${encodeURIComponent(slug)}`) + .then((r) => r.ok ? r.json() : null) + .then((data) => { + if (data) { setCompany(data); } + else { + // Static fallback from seed data + const fallback = (TeknavData.companies ?? []).find((c) => c.slug === slug); + if (fallback) setCompany(fallback); + } + setLoading(false); + }) + .catch(() => { + const fallback = (TeknavData.companies ?? []).find((c) => c.slug === slug); + if (fallback) setCompany(fallback); + setLoading(false); + }); + }, [slug]); + + 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(); + }, []); + + if (loading) { + return ( +
+
+
+
+
+
+
+ ); + } + + if (!company) { + return
شرکت یافت نشد.
; + } + + return ( +
+
+ {company.logoUrl && ( + {company.name} + )} +
+
{company.name}
+ {company.verified && ( + ✓ تأیید شده + )} +
+ {company.category && ( + + {company.category} + + )} +
+
+ {company.description && ( +

{company.description}

+ )} + {(company.techStack || []).length > 0 && ( +
+ {company.techStack.map((tech) => ( + {tech} + ))} +
+ )} +
+ +
+ ); +}