Mohamadzadeh 4ec530906e
All checks were successful
Build and Deploy Next.js + Nginx Docker Image / build-and-deploy (push) Successful in 52s
Build and Deploy Next.js + Nginx Docker Image / deploy (push) Successful in 7s
update sidebar icons
2026-08-22 16:24:40 +03:30
2026-07-09 13:34:48 +03:30
2026-08-22 16:24:40 +03:30
2026-08-22 16:24:40 +03:30
2026-06-11 18:49:00 +03:30
2026-07-09 16:33:43 +03:30
2026-07-09 17:15:59 +03:30
2026-08-19 17:19:15 +03:30
2026-08-20 07:28:42 +00:00
2026-08-20 10:49:25 +03:30
2026-08-19 13:41:17 +03:30

uikit

Shared library for BI next.js projects.


Install

yarn add git+https://git.d.aiengines.ir/bi/uikit.git

Update

yarn upgrade uikit

or

rm -rf .next
rm -rf node_modules/.vite
rm -rf node_modules/.cache
rm -rf node_modules/uikit

yarn upgrade uikit

imports

مسیر کاربرد dependency اضافی
uikit utility functions -
uikit/utils utility functions -
uikit/pagination pagination Chakra + React + react-icons
uikit/layout Header, Sidebar Chakra + React + React Icons
uikit/core API، BiProvider، Keycloak، Permission Chakra + React Query + Axios + Keycloak + Query Params
uikit/table DataTable Chakra + TanStack Table + Pagination
uikit/remote/ui Remote UI components مثل GBadge Chakra + React + remote static file

utils

import { toFaDigits, toEnDigits, toFaNumber } from "uikit/utils";

toFaDigits(123456);
toEnDigits("۱۲۳۴۵۶");
toFaNumber(123456);

or

import { toFaDigits } from "uikit";

pagination

required dependencies

yarn add @chakra-ui/react@2
yarn add @chakra-ui/icons@2
yarn add @emotion/react@11
yarn add @emotion/styled@11
yarn add chakra-react-select@5
yarn add react-select@5
yarn add framer-motion@10
yarn add react-icons

using

import { Pagination, LightPagination, SimplePagination } from "uikit/pagination";

function Page() {
  return (
    <Pagination
      currentPage={1}
      totalCount={100}
      totalPages={5}
      onPageChange={(page) => console.log(page)}
    />
  );
}

Header

required dependencies:

yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion

using:

import { Header } from "uikit/layout";

function AppHeader() {
  return (
    <Header>
      <Header.BrandSection>
        <Header.Logo src="/logo.png" />

        <Header.Brand>
          <Header.Title>عنوان سامانه</Header.Title>
          <Header.Description>توضیح کوتاه سامانه</Header.Description>
        </Header.Brand>
      </Header.BrandSection>

      <Header.Bi />
    </Header>
  );
}

Sidebar

required dependencies:

yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion react-icons
yarn add @tanstack/react-query axios keycloak-js
yarn add next-query-params@^5.1.0 use-query-params@^2.2.2

Sidebar همان UI ناوبری سامانه را برای دسکتاپ و موبایل ارائه می‌دهد. در دسکتاپ به صورت نوار آیکون کناری و در موبایل به صورت bottom navigation + drawer «بیشتر» نمایش داده می‌شود.

آیتم‌ها به صورت config به کامپوننت داده می‌شوند:

import { SlUserFollowing } from "react-icons/sl";

const navigationItems = [
  {
    title: "آنالیز شبکه متعارف - فالوور/فالووینگ",
    mobileTitle: "ارتباط کاربران",
    icon: SlUserFollowing,
    path: "/user-connections/analyze",
    perm: ["analyze"],
  },
];

نمونه استفاده در Next.js Pages Router:

import NextLink from "next/link";
import { useRouter } from "next/router";
import { Sidebar } from "uikit/layout";

function AppSidebar() {
  const router = useRouter();

  return (
    <Sidebar
      items={navigationItems}
      currentPath={router.asPath}
      linkComponent={NextLink}
    />
  );
}

Sidebar باید داخل BiProvider استفاده شود. Permission هر آیتم از perm توسط خود UI Kit بررسی می‌شود و خروج با Keycloak توسط خود UI Kit انجام می‌شود. سامانه مقصد نیازی به usePermission یا logoutKeycloak برای Sidebar ندارد.

کنترل دسترسی کلی panel_access عمداً داخل Sidebar انجام نمی‌شود تا navigation هنگام render باعث redirect و لغو route در Next.js نشود. اگر سامانه به این guard نیاز دارد، از PanelAccessGuard موجود در uikit/core در سطح Layout/App استفاده کنید.

aliases نیز پشتیبانی می‌شود و برای تشخیص آیتم active استفاده می‌شود:

{
  title: "آنالیز شبکه های اجتماعی خارجی",
  mobileTitle: "شبکه خارجی",
  icon: TbAnalyze,
  path: "/posts/final_analyze",
  aliases: ["/posts/analyze"],
  perm: ["analyze"],
}

اگر perm آرایه باشد، همه permissionهای داخل آرایه برای فعال بودن آیتم لازم هستند. آیتم بدون perm محدودیت permission ندارد.


Core

required dependencies:

yarn add @chakra-ui/react@^2
yarn add @emotion/react@^11
yarn add @emotion/styled@^11
yarn add framer-motion@^12
yarn add @tanstack/react-query@^5
yarn add axios@^1
yarn add keycloak-js
yarn add next-query-params@^5.1.0
yarn add use-query-params@^2.2.2

BiProvider

import { BiProvider } from "uikit/core";

export default function App() {
  return (
    <BiProvider
      apiBaseUrl="https://api.example.com"
      keycloakClientId="front-client"
      permissionClientId="permission-client"
    >
      <YourApp />
    </BiProvider>
  );
}

BiProvider props

Prop
apiBaseUrl
keycloakClientId
permissionClientId
loading
updateChecker
updateCheckerProps
keycloakUrl
keycloakRealm
permissionUrl
keycloakEnabled
permissionEnabled
remoteUiEnabled
remoteUiUrl
remoteUiChakraProviderProps

BiProvider defaults

keycloakUrl = "https://auth.ibagher.ir";
keycloakRealm = "bi";
permissionUrl = "https://api.d.aiengines.ir/user_api/v1/permissions/list";
updateChecker = false;
remoteUiEnabled = true;
remoteUiUrl = "https://uikit.d.aiengines.ir/GBadge.js";

BiProvider with Remote UI

BiProvider به صورت خودکار dependencyهای لازم برای کامپوننت‌های remote/ui را setup می‌کند.

پس اگر سامانه مقصد از BiProvider استفاده می‌کند، برای استفاده از GBadge کار اضافه‌ای لازم نیست.

import { BiProvider } from "uikit/core";
import { GBadge } from "uikit/remote/ui";

export default function App() {
  return (
    <BiProvider
      apiBaseUrl="https://api.example.com"
      keycloakClientId="front-client"
      permissionClientId="permission-client"
    >
      <GBadge colorScheme="blue" py={1} px={2} borderRadius="full">
        فعال
      </GBadge>
    </BiProvider>
  );
}

در این حالت GBadge همچنان از Chakra استفاده می‌کند، ولی فایل remote آن، یعنی GBadge.js، خودش Chakra و React و font را داخل bundle نمی‌آورد.

dependencyهای لازم از خود سامانه مقصد گرفته می‌شوند.


Change Remote UI URL

اگر فایل remote روی آدرس دیگری deploy شده باشد:

import { BiProvider } from "uikit/core";

export default function App() {
  return (
    <BiProvider
      apiBaseUrl="https://api.example.com"
      keycloakClientId="front-client"
      permissionClientId="permission-client"
      remoteUiUrl="https://static.example.com/uikit/GBadge.js"
    >
      <YourApp />
    </BiProvider>
  );
}

Disable Remote UI setup in BiProvider

اگر نمی‌خواهید BiProvider به صورت خودکار remote ui را setup کند:

import { BiProvider } from "uikit/core";

export default function App() {
  return (
    <BiProvider
      apiBaseUrl="https://api.example.com"
      keycloakClientId="front-client"
      permissionClientId="permission-client"
      remoteUiEnabled={false}
    >
      <YourApp />
    </BiProvider>
  );
}

To enable updateChecker you should have a script write-version.js in the root of the project and in the package.json of the target project, run before the build:

{
  "scripts": {
    "prebuild": "node write-version.js",
    "build": "next build"
  }
}

API

import { api, fetcher, configureApi, getApi } from "uikit/core";
import { api } from "uikit/core";

const response = await api.get("/users");

or

import { fetcher } from "uikit/core";

const data = await fetcher("/users");

createApi

import { createApi } from "uikit/core";

export const sampleApi = createApi({
  key: "sample",
  url: "/...",

  actions: {
    create: {
      method: "post",
      url: "/...",
    },

    update: {
      method: "patch",
      url: (id) => `/.../${id}`,
    },

    delete: {
      method: "delete",
      url: (id) => `/.../${id}`,
    },

    confirm: {
      method: "post",
      url: "/...",
    },

    updateImage: {
      method: "post",
      url: (id) => `/.../${id}/image`,
      body: ({ formData }) => formData,
    },
  },
});

Keycloak

import {
  getKeycloakToken,
  loginKeycloak,
  logoutKeycloak,
} from "uikit/core";

const token = getKeycloakToken();

loginKeycloak();

logoutKeycloak({
  redirectUri: window.location.origin,
});

Permission

import { Can, usePermission } from "uikit/core";

function Page() {
  const { can, cannot, permissions } = usePermission();

  return (
    <>
      {can("users:list") && <div>لیست کاربران</div>}

      <Can perm="users:create" fallback={null}>
        <button>ایجاد کاربر</button>
      </Can>
    </>
  );
}

Remote UI

remote/ui برای کامپوننت‌هایی است که باید بدون build مجدد سامانه مقصد، از طریق فایل remote به‌روزرسانی شوند.

مثلاً GBadge از این مسیر استفاده می‌شود:

import { GBadge } from "uikit/remote/ui";

function Page() {
  return (
    <GBadge colorScheme="blue" py={1} px={2} borderRadius="full">
      فعال
    </GBadge>
  );
}

GBadge

required dependencies:

yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion

using:

import { GBadge } from "uikit/remote/ui";

function Page({ item }) {
  return (
    <GBadge colorScheme="blue" py={1} px={2} borderRadius="full">
      {item}
    </GBadge>
  );
}

GBadge از Chakra Badge استفاده می‌کند.

اما برای کم شدن حجم فایل remote، این موارد داخل GBadge.js bundle نمی‌شوند:

React
ReactDOM
Chakra
Emotion
theme
Fonts
font files

این موارد باید در سامانه مقصد وجود داشته باشند.


GBadge with BiProvider

اگر سامانه مقصد از BiProvider استفاده می‌کند، نیازی به setup دستی نیست:

import { BiProvider } from "uikit/core";
import { GBadge } from "uikit/remote/ui";

function App() {
  return (
    <BiProvider
      apiBaseUrl="https://api.example.com"
      keycloakClientId="front-client"
      permissionClientId="permission-client"
    >
      <GBadge colorScheme="blue" py={1} px={2} borderRadius="full">
        فعال
      </GBadge>
    </BiProvider>
  );
}

GBadge without BiProvider

اگر سامانه مقصد از BiProvider استفاده نمی‌کند، دو حالت وجود دارد.

حالت ساده

اگر theme خاصی ندارید، فقط استفاده از GBadge کافی است:

import { GBadge } from "uikit/remote/ui";

function Page() {
  return (
    <GBadge colorScheme="blue" py={1} px={2} borderRadius="full">
      فعال
    </GBadge>
  );
}

در این حالت wrapper مربوط به GBadge خودش dependencyهای لازم را setup می‌کند.


حالت با theme اختصاصی

اگر سامانه مقصد theme اختصاصی Chakra دارد، بهتر است در entry اصلی پروژه یک بار setup انجام شود.

مثلاً در main.jsx، App.jsx یا _app.jsx:

import React from "react";
import { createRoot } from "react-dom/client";
import { ChakraProvider } from "@chakra-ui/react";
import { setupUikitRemoteDeps } from "uikit/remote/ui";
import { theme } from "./theme";
import App from "./App";

setupUikitRemoteDeps({
  theme,
});

createRoot(document.getElementById("root")).render(
  <ChakraProvider theme={theme}>
    <App />
  </ChakraProvider>,
);

برای Next.js:

import { ChakraProvider } from "@chakra-ui/react";
import { setupUikitRemoteDeps } from "uikit/remote/ui";
import { theme } from "@/theme";

setupUikitRemoteDeps({
  theme,
});

export default function App({ Component, pageProps }) {
  return (
    <ChakraProvider theme={theme}>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

Remote URL without BiProvider

اگر سامانه مقصد از BiProvider استفاده نمی‌کند و آدرس فایل remote متفاوت است:

import { setupUikitRemoteDeps } from "uikit/remote/ui";
import { theme } from "./theme";

setupUikitRemoteDeps({
  theme,
  remoteUrl: "https://static.example.com/uikit/GBadge.js",
});

یا مستقیم روی خود کامپوننت:

import { GBadge } from "uikit/remote/ui";

function Page() {
  return (
    <GBadge
      remoteUrl="https://static.example.com/uikit/GBadge.js"
      colorScheme="blue"
      py={1}
      px={2}
      borderRadius="full"
    >
      فعال
    </GBadge>
  );
}

Font

فونت داخل فایل remote باندل نمی‌شود.

اگر سامانه مقصد از BiProvider استفاده می‌کند، فونت و theme اصلی از همان BiProvider می‌آید.

اگر سامانه مقصد BiProvider ندارد، فونت را در خود سامانه مقصد ست کنید:

@font-face {
  font-family: Estedad;
  src: url("/fonts/estedad.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --uikit-font-family: Estedad, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

body {
  font-family: var(--uikit-font-family);
}

GBadge از این مقدار استفاده می‌کند:

var(--uikit-font-family, inherit)

Build Remote UI

برای ساخت فایل remote:

yarn build:remote

خروجی remote:

dist/remote/GBadge.js

این فایل باید روی static server یا CDN داخلی deploy شود.

مثلاً:

https://uikit.d.aiengines.ir/GBadge.js

Deploy Remote UI

بعد از تغییر در GBadge.remote.jsx یا کامپوننت‌های remote:

yarn build:remote

سپس فایل زیر را deploy کنید:

dist/remote/GBadge.js

سامانه‌های مقصد بعد از reload صفحه، نسخه جدید remote را دریافت می‌کنند.

اگر cache سمت browser یا CDN فعال است، باید cache فایل remote کنترل شود.


Important Notes

اگر از مسیر زیر استفاده شود:

import { GBadge } from "uikit/remote/ui";

خود کامپوننت از فایل remote استفاده می‌کند.

اما اگر کامپوننتی از مسیر معمولی package import شود، مثل:

import { SomeComponent } from "uikit";

یا:

import { SomeComponent } from "uikit/table";

آن کامپوننت داخل build سامانه مقصد bundle می‌شود و برای آپدیت شدن نیاز به rebuild یا yarn upgrade دارد.

پس:

uikit/remote/ui  => update by remote file
uikit/table      => update by package upgrade
uikit/core       => update by package upgrade
uikit/layout     => update by package upgrade

DataTable

required dependencies:

yarn add @tanstack/react-table

using:

import { DataTable } from "uikit/table";

function UsersTable({ data, columns }) {
  return (
    <DataTable
      data={data}
      columns={columns}
      page={1}
      size={20}
      pagination={{
        totalCount: 100,
        totalPages: 5,
      }}
      onPageChange={(page) => console.log(page)}
      getRowId={(row) => String(row.id)}
      enableSelection
      showIndex
    >
      <DataTable.Topbar>
        <DataTable.Title>لیست کاربران</DataTable.Title>
        <DataTable.Spacer />
        <DataTable.Actions>
          <DataTable.SelectAll />
        </DataTable.Actions>
      </DataTable.Topbar>

      <DataTable.Content>
        <DataTable.Table />
        <DataTable.Pagination />
      </DataTable.Content>
    </DataTable>
  );
}

Sidebar.Exit

Sidebar به‌صورت پیش‌فرض گزینه خروج را نمایش نمی‌دهد. برای فعال‌کردن خروج Keycloak داخلی UI Kit، آن را به‌صورت compound component اضافه کنید:

<Sidebar
  items={items}
  currentPath={router.asPath}
  linkComponent={NextLink}
>
  <Sidebar.Exit />
</Sidebar>

عنوان و آیکون خروج قابل تغییر هستند:

<Sidebar.Exit title="خروج از سامانه" icon={MyExitIcon} />

Sidebar.Exit از logoutKeycloak داخلی UI Kit استفاده می‌کند و callback خروج از سامانه مقصد نیاز ندارد.

Sidebar active route notes

Sidebar compares currentPath with each item's path and aliases, ignoring query strings, hashes, and trailing slashes. Use the actual application route as path; use aliases only for alternate routes that should keep the same item active.

Active sidebar items are rendered as non-links to avoid redundant same-route navigations. This is especially useful on pages that synchronize URL query params.

Description
No description provided
Readme 6.6 MiB
Languages
JavaScript 99.2%
Python 0.6%
Dockerfile 0.2%