entekhab-page-components
v1.0.29
Published
Reusable page components for dynamic page rendering - Persian/RTL support
Maintainers
Readme
entekhab-page-components
کامپوننتهای مستقل و قابل استفاده مجدد برای رندر صفحات داینامیک با پشتیبانی کامل از RTL و فارسی.
نصب
npm install entekhab-page-componentsیا اگر از git استفاده میکنید:
npm install git+https://github.com/your-org/page-components.gitوابستگیهای مورد نیاز
این package به وابستگیهای زیر نیاز دارد که باید در پروژه شما نصب باشند:
react^19.2.0react-dom^19.2.0
✅ نیازی به نصب Tailwind CSS یا shadcn/ui نیست! این پکیج شامل فایل CSS آماده Tailwind است که تمام استایلهای مورد نیاز را شامل میشود.
تمام dependencies دیگر (Radix UI، lucide-react، و غیره) به صورت خودکار با نصب پکیج نصب میشوند.
راهاندازی
1. Import کردن فایل CSS
در Next.js (App Router):
فایل CSS پکیج را در app/layout.tsx import کنید:
// app/layout.tsx
import 'entekhab-page-components/style/style.css';
export default function RootLayout({ children }) {
return (
<html lang="fa" dir="rtl">
<body>{children}</body>
</html>
);
}در Next.js (Pages Router):
در pages/_app.tsx:
import 'entekhab-page-components/style/style.css';
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}در Create React App یا Vite:
در فایل اصلی (مثلاً src/index.tsx یا src/main.tsx):
import 'entekhab-page-components/style/style.css';2. استفاده از کامپوننتها
'use client';
import { PageRenderer, PageComponent } from 'entekhab-page-components';
export default function MyPage() {
const components: PageComponent[] = [
// ... کامپوننتهای شما
];
return (
<div className="min-h-screen">
<PageRenderer components={components} viewport="desktop" />
</div>
);
}استفاده سریع
1. دریافت JSON از API و رندر کردن
'use client';
import React, { useState, useEffect } from 'react';
import { PageRenderer, PageComponent } from 'entekhab-page-components';
export default function DynamicPage({ screenId }: { screenId: string }) {
const [components, setComponents] = useState<PageComponent[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchPageData = async () => {
try {
setLoading(true);
const response = await fetch(`/api/screens/${screenId}`);
if (!response.ok) {
throw new Error('Failed to fetch page data');
}
const data = await response.json();
setComponents(data.components || []);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
};
fetchPageData();
}, [screenId]);
if (loading) {
return <div>در حال بارگذاری...</div>;
}
if (error) {
return <div>خطا: {error}</div>;
}
return (
<div className="min-h-screen">
<PageRenderer components={components} viewport="desktop" />
</div>
);
}2. استفاده مستقیم از کامپوننتها
import { Heading, Text, Button, ContentCard3 } from 'entekhab-page-components';
export default function MyPage() {
return (
<div dir="rtl">
<Heading
text="عنوان صفحه"
level="1"
align="center"
marginTop="lg"
marginBottom="md"
/>
<Text
text="این یک متن نمونه است"
size="md"
align="right"
/>
<Button
text="کلیک کنید"
variant="default"
size="default"
/>
<ContentCard3
cards={[
{
id: '1',
icon: 'Users',
metric: '1000+',
title: 'کاربران',
description: 'تعداد کاربران فعال'
}
]}
/>
</div>
);
}3. استفاده از renderComponent
import { renderComponent, PageComponentProps } from 'entekhab-page-components';
const headingProps: PageComponentProps = {
text: 'عنوان من',
level: '1',
align: 'center',
marginTop: 'md',
marginBottom: 'md',
} as const;
const element = renderComponent('Heading', headingProps);نمونه کاملتر با ساختار خروجی Page Builder:
import { renderComponent, PageComponent } from 'entekhab-page-components';
const component: PageComponent = {
id: 'f1cee4fe-710a-4bcf-8b85-621954120d81',
type: 'ContentCard2',
props: {
card1Image: '/CardContentImage.PNG',
card1Text: 'نشان دهنده میزان ارائه خدمات حمایتی مانند بیمه، وام تسهیلات درمانی و امکانات فرهنگی',
card1ButtonText: 'مطالب بیشتر',زمس
card2Image: '/CardContentImage.PNG',
card2Text: 'نشان دهنده میزان ارائه خدمات حمایتی مانند بیمه، وام تسهیلات درمانی و امکانات فرهنگی',
card2ButtonText: 'مطالب بیشتر',
card3Image: '/CardContentImage.PNG',
card3Text: 'نشان دهنده میزان ارائه خدمات حمایتی مانند بیمه، وام تسهیلات درمانی و امکانات فرهنگی',
card3ButtonText: 'مطالب بیشتر',
card4Image: '/CardContentImage.PNG',
card4Text: 'نشان دهنده میزان ارائه خدمات حمایتی مانند بیمه، وام تسهیلات درمانی و امکانات فرهنگی',
card4ButtonText: 'مطالب بیشتر',
shadow: true,
shadowIntensity: 'md',
marginTop: 'none',
marginRight: 'none',
marginBottom: 'none',
marginLeft: 'none',
backgroundColor: '',
componentName: 'contentcard2-f1cee4fe',
},
};
const element = renderComponent(component.type, component.props);تنظیم پسزمینه صفحه
در خروجی Page Builder و همچنین هنگام استفاده مستقیم از PageRenderer میتوانید برای کل صفحه یک رنگ یا گرادیانت تعریف کنید. کافی است در JSON خروجی، فیلد pageBackground را اضافه کنید:
{
"name": "صفحه فرم",
"pageBackground": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
"components": [
{
"id": "hero-1",
"type": "HeroSection",
"props": {
"title": "فرم تماس",
"mediaType": "none",
"showButton": false
}
}
]
}- اگر مقدار
pageBackgroundیک رشتهی شاملgradientباشد، به عنوانbackgroundاعمال میشود. - در غیر این صورت به عنوان
backgroundColor(برای رنگهای ساده مثل#ffffff) اعمال میشود. - مقدار پیشفرض این فیلد
#ffffffاست.
ساختار JSON
JSON که از API دریافت میکنید باید این ساختار را داشته باشد:
{
"screenId": "123",
"name": "صفحه اصلی",
"components": [
{
"id": "1",
"type": "Heading",
"props": {
"text": "خوش آمدید",
"level": "1",
"align": "center",
"marginTop": "lg",
"marginBottom": "md"
},
"children": []
},
{
"id": "2",
"type": "ContentCard3",
"props": {
"cards": [
{
"id": "1",
"icon": "Users",
"metric": "1000+",
"title": "کاربران",
"description": "تعداد کاربران فعال"
}
],
"backgroundColor": "#ffffff"
},
"children": []
}
],
"viewport": "desktop"
}کامپوننتهای موجود
کامپوننتهای پایه
Heading- عنوان با سطوح مختلف (H1-H6)Text- متن با اندازه و تراز قابل تنظیمButton- دکمه با انواع مختلفImage- تصویر با تنظیمات responsiveDivider- خط جداکنندهSpacer- فاصلهدهنده
کامپوننتهای فرم
FormRenderer- رندر کننده فرمهای داینامیک بر اساس JSON
کامپوننتهای پیشرفته
کارتهای محتوا (Content Cards)
این کامپوننتها برای نمایش محتوا در قالب کارت استفاده میشوند:
ContentCard- کارت محتوا ساده با تصویر/ویدیو، عنوان، متن و دکمهContentCard2- کارت محتوا با 4 کارت در یک ردیف (مناسب برای نمایش خدمات یا ویژگیها)ContentCard3- کارت محتوا با متریکها (مناسب برای نمایش آمار و KPI)ContentCard4- کارت محتوا با آیکون و توضیحات (مناسب برای نمایش مزایا)
نکته: در Page Builder، این کامپوننتها به صورت یک منو گروهبندی شده نمایش داده میشوند تا انتخاب و استفاده از آنها راحتتر باشد.
سایر کامپوننتهای پیشرفته
HeroSection- بخش قهرمان (Hero Section) برای صفحات اصلیSlider- اسلایدر تصاویر با قابلیت پخش خودکارNavigation- منوی ناوبری با قابلیت لینکدهی داخلی و خارجیContainer- کانتینر با تنظیمات responsive برای گروهبندی کامپوننتهاTabs- تبها برای نمایش محتوای دستهبندی شدهFAQ- سوالات متداول با قابلیت باز و بسته شدن
قالبهای آماده
این پکیج شامل قالبهای آماده و مدرن برای شروع سریع است. تمام قالبها با طراحی زیبا و کاربرپسند ایجاد شدهاند:
1. لندینگ پیج مدرن ⭐
قالب لندینگ پیج مدرن با طراحی جذاب که شامل:
- Hero Section با gradient زیبا
- کارتهای KPI برای نمایش آمار و متریکها
- بخش خدمات با کارتهای زیبا
- بخش CTA (Call to Action) با gradient برای دعوت به اقدام
این قالب مناسب برای صفحات اصلی و لندینگ پیجها است.
2. داشبورد مدرن 📊
قالب داشبورد مدرن با طراحی حرفهای که شامل:
- هدر با gradient زیبا
- کارتهای KPI برای نمایش آمار و گزارشها
- بخش محتوا برای نمایش گزارشهای مختلف
این قالب مناسب برای صفحات مدیریتی و داشبوردها است.
3. صفحه خدمات مدرن 🛠️
قالب صفحه خدمات با طراحی مدرن که شامل:
- Hero Section با gradient صورتی-قرمز
- بخش ویژگیهای خدمات
- کارتهای خدمات با سایههای زیبا
این قالب مناسب برای نمایش خدمات و محصولات است.
4. پورتفولیو مدرن 🎨
قالب پورتفولیو مدرن با طراحی جذاب که شامل:
- هدر با gradient آبی-فیروزهای
- کارتهای آمار و موفقیت
- گالری نمونه کارها با کارتهای تصویری
این قالب مناسب برای نمایش نمونه کارها و پروژهها است.
5. درباره ما مدرن 👥
قالب درباره ما با طراحی مدرن که شامل:
- Hero Section با gradient صورتی-زرد
- بخش ارزشهای شرکت
- کارتهای آمار و موفقیت
- بخش سوالات متداول
این قالب مناسب برای صفحات معرفی و درباره ما است.
6. قالب مینیمال و مدرن
قالبی تمیز و کاربرپسند با طراحی مدرن که شامل:
- Hero Section جذاب
- کارتهای KPI برای نمایش آمار
- کارتهای محتوا برای نمایش خدمات
- بخش CTA (Call to Action) برای دعوت به اقدام
7. قالب با منوی ناوبری
قالب کامل با:
- منوی ناوبری در بالا
- اسلایدر تصاویر
- کارتهای KPI
- بخش سوالات متداول
8. قالب اسلایدر و محتوا
قالب مناسب برای صفحات خدماتی با:
- اسلایدر تصاویر
- کارتهای KPI
- کارتهای محتوا برای نمایش خدمات
9. قالب مزایا و کارتها
قالب مناسب برای صفحات معرفی با:
- کارتهای مزایا
- بخش سوالات متداول
10. قالب فرم جذاب با فاصلههای زیبا ✨
قالب جدیدی که برای صفحههای فرم طراحی شده و شامل:
- Hero Section مدرن برای معرفی فرم
- کانتینر فرم با Heading و توضیحات
- فاصلهگذاریهای متعدد (
Spacer) برای ایجاد تنفس بین بخشها - کارتهای اطلاعات و ویژگیها
- بخش CTA با گرادیانت و دکمه بزرگ
این قالب برای ساخت فرمهای جذاب و مدرن با فاصلهگذاری منظم آماده شده است.
نکته: تمام قالبها به صورت مستقل هستند و میتوانید آنها را به راحتی ویرایش و سفارشیسازی کنید. تمام کامپوننتها قابل drag & drop هستند و میتوانید ترتیب و محتوای آنها را تغییر دهید.
استفاده از فرمها
این پکیج شامل قابلیت نمایش فرمهای داینامیک است که از JSON ساخته شدهاند.
1. تنظیم API برای فرمها
قبل از استفاده از FormRenderer یا PageRenderer با فرمها، باید API endpoint خود را تنظیم کنید:
import { setFormApiConfig } from 'entekhab-page-components';
import axios from 'axios';
// روش 1: استفاده از baseUrl (سادهترین روش)
setFormApiConfig({
baseUrl: 'https://your-api.com',
});
// روش 2: استفاده از axios instance (توصیه میشود)
const axiosInstance = axios.create({
baseURL: 'https://your-api.com',
// میتوانید headers، interceptors و غیره را اضافه کنید
});
setFormApiConfig({
axiosInstance,
});
// روش 3: استفاده از custom function (برای کنترل کامل)
setFormApiConfig({
getFormById: async (formId: string) => {
const response = await axios.get(`https://your-api.com/api/v1/forms/GetFormById/${formId}`);
// اگر ساختار response شما { result: "ok", data: { form: {...} } } است:
return response.data.data.form;
},
});نکته مهم: این تنظیمات باید یک بار در فایل اصلی برنامه (مثلاً app/layout.tsx یا _app.tsx) انجام شود.
2. استفاده از FormRenderer
import { FormRenderer } from 'entekhab-page-components';
export default function FormPage({ formId }: { formId: string }) {
return (
<div className="min-h-screen p-8">
<FormRenderer
formId={formId}
onFormLoad={(formData) => {
console.log('Form loaded:', formData);
}}
onFormError={(error) => {
console.error('Form error:', error);
}}
/>
</div>
);
}3. استفاده از formModal در رویدادهای onClick
برای استفاده از فرمها در رویداد onClick کامپوننتها، باید دو مرحله را انجام دهید:
مرحله 1: تنظیم API endpoint برای دریافت فرمها
import { setFormApiConfig } from 'entekhab-page-components';
// در فایل اصلی برنامه (مثلاً _app.tsx یا layout.tsx)
setFormApiConfig({
baseUrl: 'https://your-api.com', // یا
getFormById: async (formId: string) => {
const response = await fetch(`https://your-api.com/api/v1/forms/GetFormById/${formId}`);
const data = await response.json();
// اگر ساختار response شما { data: { form: {...} } } است:
return data.data.form;
// یا اگر ساختار دیگری دارد، آن را برگردانید
},
});مرحله 2: تنظیم handler برای باز کردن مودال فرم
'use client';
import { useState, useEffect } from 'react';
import { setFormModalOpener, FormRenderer, PageRenderer } from 'entekhab-page-components';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Loader2, Info } from 'lucide-react';
export default function App({ pageData }: { pageData: any }) {
const [formModalOpen, setFormModalOpen] = useState(false);
const [selectedFormId, setSelectedFormId] = useState<string | null>(null);
const [selectedFormTitle, setSelectedFormTitle] = useState<string>('');
// ⚠️ مهم: setFormModalOpener باید در useEffect فراخوانی شود
useEffect(() => {
setFormModalOpener((payload) => {
if (payload?.formId) {
setSelectedFormId(payload.formId);
setSelectedFormTitle(payload.formTitle || 'فرم');
setFormModalOpen(true);
}
});
}, []); // فقط یک بار در mount اجرا میشود
return (
<>
{/* کامپوننتهای صفحه */}
<PageRenderer
components={pageData.components}
pageBackground={pageData.pageBackground}
/>
{/* مودال فرم */}
<Dialog open={formModalOpen} onOpenChange={setFormModalOpen}>
<DialogContent className="w-[95vw] sm:w-full sm:max-w-2xl h-[90vh] sm:h-[85vh] max-h-[95vh] flex flex-col p-0 gap-0">
<DialogHeader className="flex-shrink-0 border-b border-gray-200/60 dark:border-gray-700/60 pb-3 px-4 sm:px-6">
<DialogTitle className="text-lg font-bold text-gray-800 dark:text-gray-100">
{selectedFormTitle}
</DialogTitle>
</DialogHeader>
<ScrollArea className="flex-1 min-h-0">
<div className="p-4 sm:p-6">
{selectedFormId && (
<FormRenderer
formId={selectedFormId}
formTitle={selectedFormTitle}
/>
)}
</div>
</ScrollArea>
</DialogContent>
</Dialog>
</>
);
}مثال کامل با استفاده از axios:
'use client';
import { useState, useEffect } from 'react';
import { setFormApiConfig, setFormModalOpener, FormRenderer, PageRenderer } from 'entekhab-page-components';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import axios from 'axios';
// تنظیم API config (یک بار در فایل اصلی برنامه)
setFormApiConfig({
getFormById: async (formId: string) => {
const response = await axios.get(`https://your-api.com/api/v1/forms/GetFormById/${formId}`);
// اگر ساختار response شما { data: { form: {...} } } است:
return response.data.data.form;
},
});
export default function PageView({ pageData }: { pageData: any }) {
const [formModalOpen, setFormModalOpen] = useState(false);
const [selectedFormId, setSelectedFormId] = useState<string | null>(null);
const [selectedFormTitle, setSelectedFormTitle] = useState<string>('');
useEffect(() => {
setFormModalOpener((payload) => {
console.log('Form modal opened with:', payload); // برای debug
if (payload?.formId) {
setSelectedFormId(payload.formId);
setSelectedFormTitle(payload.formTitle || 'فرم');
setFormModalOpen(true);
}
});
}, []);
return (
<>
<PageRenderer
components={pageData.components}
pageBackground={pageData.pageBackground}
/>
<Dialog open={formModalOpen} onOpenChange={setFormModalOpen}>
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>{selectedFormTitle}</DialogTitle>
</DialogHeader>
{selectedFormId && (
<FormRenderer formId={selectedFormId} />
)}
</DialogContent>
</Dialog>
</>
);
}ساختار JSON فرم
JSON فرم باید این ساختار را داشته باشد:
{
"fields": [
{
"id": "1",
"type": "input",
"label": "نام",
"name": "name",
"placeholder": "نام خود را وارد کنید",
"required": true
},
{
"id": "2",
"type": "textarea",
"label": "پیام",
"name": "message",
"placeholder": "پیام خود را بنویسید"
},
{
"id": "3",
"type": "select",
"label": "دستهبندی",
"name": "category",
"options": [
{ "id": "1", "label": "پشتیبانی", "value": "support" },
{ "id": "2", "label": "فروش", "value": "sales" }
]
},
{
"id": "4",
"type": "radio",
"label": "اولویت",
"name": "priority",
"options": [
{ "id": "1", "label": "کم", "value": "low" },
{ "id": "2", "label": "متوسط", "value": "medium" },
{ "id": "3", "label": "زیاد", "value": "high" }
]
},
{
"id": "5",
"type": "checkbox",
"label": "گزینهها",
"name": "options",
"options": [
{ "id": "1", "label": "گزینه 1", "value": "opt1" },
{ "id": "2", "label": "گزینه 2", "value": "opt2" }
]
},
{
"id": "6",
"type": "date",
"label": "تاریخ",
"name": "date"
},
{
"id": "7",
"type": "time",
"label": "زمان",
"name": "time"
},
{
"id": "8",
"type": "divider"
},
{
"id": "9",
"type": "button",
"text": "ارسال"
}
]
}انواع فیلدهای فرم
input- فیلد متنی یک خطیtextarea- فیلد متنی چند خطیselect- لیست انتخاب (dropdown)radio- دکمههای رادیویی (انتخاب یک گزینه)checkbox- چکباکسها (انتخاب چند گزینه)date- انتخاب تاریخtime- انتخاب زمانdivider- خط جداکنندهbutton- دکمه ارسال
TypeScript
این package به صورت کامل با TypeScript نوشته شده و type definitions را شامل میشود.
import { PageComponent, PageComponentProps, FormField, FormData } from 'entekhab-page-components';
const component: PageComponent = {
id: '1',
type: 'Heading',
props: {
text: 'عنوان',
level: '1',
},
children: [],
};
const formField: FormField = {
id: '1',
type: 'input',
label: 'نام',
name: 'name',
placeholder: 'نام خود را وارد کنید',
required: true,
};پشتیبانی
برای سوالات و مشکلات، لطفاً issue ایجاد کنید یا با تیم توسعه تماس بگیرید.
License
MIT
