npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

entekhab-page-components

v1.0.29

Published

Reusable page components for dynamic page rendering - Persian/RTL support

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.0
  • react-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 - تصویر با تنظیمات responsive
  • Divider - خط جداکننده
  • 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