一键导入
admin-ui-component
Build admin UI components and pages using @deenruv/react-ui-devkit (shadcn/Tailwind-based)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Build admin UI components and pages using @deenruv/react-ui-devkit (shadcn/Tailwind-based)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
How to add, update, and manage i18n translations in Deenruv plugins and admin UI
Step-by-step guide to create a new Deenruv plugin with server and UI components
Write E2E tests for Deenruv plugins using Vitest and @deenruv/testing utilities
How to extend the Deenruv GraphQL API with new types, queries, mutations, and resolvers
基于 SOC 职业分类
| name | admin-ui-component |
| description | Build admin UI components and pages using @deenruv/react-ui-devkit (shadcn/Tailwind-based) |
Use this skill when building React components for the Deenruv admin panel using @deenruv/react-ui-devkit.
Plugin UI code lives in plugins/<name>-plugin/src/plugin-ui/. Each plugin registers extensions via createDeenruvUIPlugin() exported from its plugin-ui/index.tsx.
All UI imports come from @deenruv/react-ui-devkit — never import raw shadcn components or react-i18next directly.
Accordion, AspectRatio, Badge, Breadcrumb, Button, Calendar, Card (Card, CardContent, CardHeader, CardTitle, CardDescription), Command, Checkbox, Dialog, DropdownMenu, Form, HoverCard, Input, Label, Pagination, Popover, ScrollArea, Select, Sheet, Switch, Table, Tabs (Tabs, TabsContent, TabsList, TabsTrigger), Textarea, Timeline, Tooltip, Sonner (toasts), AlertDialog, Toggle, ToggleGroup, Skeleton, Chart, Spinner, ImagePlaceholder, AssetUploadButton, RadioGroup, Separator, MultipleSelector, Drawer, LanguagePicker, FacetedFilter, Progress
PaymentMethodImage, OrderStateBadge, SimpleSelect, SimpleTooltip, SortButton, TranslationSelect, ListTable, SearchInput, CustomFieldsModal, ImageWithPreview, ErrorMessage, ListBadge, ContextMenu
DetailList, DetailView
DetailViewMarker, ListViewMarker, Renderer, EntityCustomFields
PageBlock, DateTimeInput, SimpleTimePicker, DraggableSelect, FacetIdsSelector, CustomCardHeader, CustomCard, EmptyState, DateTimePicker, CustomerSearch, DialogProductPicker, RichTextEditor, ConfirmationDialog, AssetsModalInput, EntityChannelManager
| Hook | Purpose |
|---|---|
useTranslation(ns) | i18n — NEVER import from react-i18next |
useQuery(query, opts) | Fetch GraphQL data (Zeus-based) |
useLazyQuery(query) | Lazy GraphQL query |
useMutation(mutation) | Execute GraphQL mutation |
useLocalStorage(key, default) | Persistent local state |
useDebounce(value, delay) | Debounced value |
useGFFLP() | Form field label/placeholder helpers |
useRouteGuard() | Unsaved changes guard |
useAssets() | Asset management |
useErrorHandler() | Error handling |
useValidators() | Form validation |
useList() | Paginated list management |
useCustomFields() | Custom field input state (value, setValue, label, description) |
useSettings, useGlobalState, useServerState, useGuardState, useOrderState, useGlobalSearch
| Enum Value | ID String | Area |
|---|---|---|
BASE_GROUP_ID.SHOP | shop-group | Shop |
BASE_GROUP_ID.ASSORTMENT | assortment-group | Products, Collections, Facets |
BASE_GROUP_ID.USERS | users-group | Customers, Admins |
BASE_GROUP_ID.PROMOTIONS | promotions-group | Promotions |
BASE_GROUP_ID.SHIPPING | shipping-group | Shipping, Payment methods |
BASE_GROUP_ID.SETTINGS | settings-group | Settings area |
components and tabs)products-detail-view, orders-detail-view, customers-detail-view, collections-detail-view, facets-detail-view, promotions-detail-view, channels-detail-view, admins-detail-view, roles-detail-view, sellers-detail-view, zones-detail-view, countries-detail-view, taxRates-detail-view, taxCategories-detail-view, shippingMethods-detail-view, paymentMethods-detail-view, customerGroups-detail-view, stockLocations-detail-view, globalSettings-detail-view, orders-summary
Append -sidebar to inject into the sidebar area (e.g. products-detail-view-sidebar).
// plugin-ui/components/FeaturePage.tsx
import React from 'react';
import { Card, CardContent, CardHeader, Button, Badge, Spinner, useTranslation, useQuery } from '@deenruv/react-ui-devkit';
import { translationNS } from '../translation-ns';
import { FeaturesQuery } from '../graphql/queries';
export const FeaturePage = () => {
const { t } = useTranslation(translationNS);
const { data, loading } = useQuery(FeaturesQuery, { initialVariables: { take: 20 } });
if (loading) return <Spinner />;
return (
<div className="space-y-6 p-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">{t('heading')}</h1>
<Button>{t('form.create')}</Button>
</div>
<Card>
<CardContent className="p-0">
{/* Use ListTable or DetailList for tabular data */}
</CardContent>
</Card>
</div>
);
};
// plugin-ui/components/CustomColorInput.tsx
import React from 'react';
import { Input, Label, useCustomFields, CardDescription } from '@deenruv/react-ui-devkit';
export const CustomColorInput = () => {
const { setValue, description, label, value } = useCustomFields<string>();
return (
<div>
<Label>{label}</Label>
<CardDescription>{description}</CardDescription>
<Input type="color" value={value ?? '#000000'} onChange={(e) => setValue(e.target.value)} />
</div>
);
};
import React from 'react';
import { BASE_GROUP_ID, createDeenruvUIPlugin } from '@deenruv/react-ui-devkit';
import { SettingsIcon } from 'lucide-react';
import { FeaturePage } from './components/FeaturePage';
import { CustomColorInput } from './components/CustomColorInput';
import { SidebarWidget } from './components/SidebarWidget';
import { translationNS } from './translation-ns';
import en from './locales/en';
import pl from './locales/pl';
export const UIPlugin = createDeenruvUIPlugin({
version: '1.0.0',
name: 'Feature Plugin',
pages: [{ path: 'feature', element: <FeaturePage /> }],
inputs: [{ id: 'color-custom-field-input', component: CustomColorInput }],
components: [{ component: SidebarWidget, id: 'products-detail-view-sidebar', tab: 'product' }],
tabs: [{ id: 'customers-detail-view', name: 'feature', label: 'Feature', component: <FeaturePage /> }],
widgets: [{ id: 'feature-widget', name: 'Feature', component: <div />, visible: true, size: { width: 6, height: 8 }, sizes: [{ width: 6, height: 8 }] }],
navMenuGroups: [{ id: 'feature-settings', labelId: 'nav.group', placement: { groupId: BASE_GROUP_ID.SETTINGS } }],
navMenuLinks: [{ id: 'feature', href: 'feature', labelId: 'nav.link', groupId: 'feature-settings', icon: SettingsIcon }],
translations: { ns: translationNS, data: { en, pl } },
});
p-6 for page padding, space-y-6 for vertical sectionsCard / CardContentBadge for status indicators, Spinner for loadingtoast from sonner for notificationslucide-react@deenruv/react-ui-devkit (not raw shadcn)useTranslation from devkit (NOT react-i18next)t()SpinnercreateDeenruvUIPlugin in plugin-ui/index.tsxns + data: { en, pl }lucide-react