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

@wikex/admin-kit

v0.12.0

Published

Reusable Payload CMS admin shell, visual editor and typography tools for Wikex projects

Downloads

2,602

Readme

@wikex/admin-kit

Admin shell dùng chung cho các website Payload CMS của Wikex.

Package sở hữu:

  • navigation, header, đăng nhập, account menu, đổi theme và branding động bằng MUI;
  • Minimal UI skin và các bản vá layout Payload;
  • Live Preview editor, drawer thuộc tính, block picker và resize text;
  • font family, line-height và runtime áp dụng typography;
  • chuẩn hóa tiếng Việt và hướng dẫn kích thước upload ảnh.

Schema, block catalog, route registry, dashboard và seed data vẫn thuộc ứng dụng sử dụng package vì chúng thay đổi theo từng dự án.

@wikex/admin-kit phụ thuộc @wikex/content-kit, nên chỉ cần cài Admin Kit là có luôn schema Page/Post/Media, SEO, redirects, robots và sitemap chuẩn. Schema, block catalog và frontend renderer cụ thể vẫn thuộc dự án consumer.

Dùng trong workspace

{
  "dependencies": {
    "@wikex/admin-kit": "workspace:*"
  }
}
// next.config.ts
const nextConfig = {
  transpilePackages: ['@wikex/admin-kit'],
}
// Payload custom.scss
@use '@wikex/admin-kit/styles';
// Payload plugins
import { adminExperiencePlugin, wikexAdminPlugin } from '@wikex/admin-kit'

export const plugins = [
  adminExperiencePlugin,
  wikexAdminPlugin({
    components: {
      beforeDashboard: '@/components/BeforeDashboard',
      provider: '@/components/LivePreviewResizer',
    },
  }),
]

wikexAdminPlugin tự đăng ký MUI/Emotion provider của Admin Kit và đồng bộ light/dark mode với Payload. Các màn hình custom có thể dùng trực tiếp các primitive Minimal thật:

'use client'

import { MinimalBlockCard, MinimalDataTable, MinimalSelect } from '@wikex/admin-kit/minimal'

export const ProductPanel = () => (
  <MinimalBlockCard label="Catalog" title="Hàng hóa">
    <MinimalSelect
      label="Trạng thái"
      onChange={(value) => console.log(value)}
      options={[{ label: 'Đang bán', value: 'active' }]}
      value="active"
    />
    <MinimalDataTable
      caption="Danh sách hàng hóa"
      columns={[{ id: 'name', header: 'Tên', render: (row) => row.name }]}
      rowKey="id"
      rows={[{ id: 'gold', name: 'Vàng' }]}
    />
  </MinimalBlockCard>
)

Theme dùng palette gốc của Minimal UI (primary.main = #00A76F) và không chèn CssBaseline, nhờ vậy không reset CSS form/document có sẵn của Payload. Admin shell dùng trực tiếp component MUI của Minimal; các control nội bộ của Payload (table, filter, select, block, editor) được ánh xạ sang cùng token và kích thước để giữ nguyên sorting, permission, localization và Live Preview.

Live Preview provider của dự án là adapter khai báo route và component khả dụng:

'use client'

import { configureAdminBrand } from '@wikex/admin-kit/admin/brand'
import LivePreviewEditor, { configureLivePreview } from '@wikex/admin-kit/live-preview'

configureLivePreview({
  getVisualEditorRoute,
  pageBlocks,
  postBlocks,
})

configureAdminBrand({
  logo: { alt: projectName, height: 64, url: '/logo.svg', width: 64 },
  siteName: projectName,
})

export default LivePreviewEditor

Trong frontend, dùng useTargetedLivePreview cho từng Page/Header/Footer để các message chung một iframe không ghi đè dữ liệu của nhau:

import { useTargetedLivePreview } from '@wikex/admin-kit/live-preview'

const page = useTargetedLivePreview(initialPage, { collectionSlug: 'pages' })
const header = useTargetedLivePreview(initialHeader, { globalSlug: 'header' })

Trong visual editor, nhấp đúp text sẽ mở ô nội dung trong inspector. Admin Kit không đặt contentEditable lên DOM của website, vì field có thể nằm trên wrapper chứa markup/style con. Thay đổi được gửi qua field Payload thật và Live Preview chịu trách nhiệm render lại component.

Tự động hóa component, text và ảnh

Khai báo nội dung editable ngay trong component. Không cần tạo file *.wikex.ts riêng:

import { defineWikexComponent, wikex } from '@wikex/admin-kit/content'

export default defineWikexComponent({
  slug: 'hero',
  label: 'Hero',
  description: 'Hero của trang chủ',
  image: '/thumbnails/hero.webp',
  fields: {
    eyebrow: wikex.text({ defaultValue: 'Wikex', label: 'Nhãn nhỏ' }),
    title: wikex.text({ defaultValue: 'Nền tảng hàng hóa', label: 'Tiêu đề' }),
    artwork: wikex.image({
      defaultSrc: '/images/hero.webp',
      label: 'Ảnh hero',
      alt: { defaultValue: 'Biểu đồ hàng hóa' },
    }),
    actions: wikex.list({
      label: 'Nút hành động',
      fields: {
        label: wikex.text({ required: true }),
        url: wikex.text({ required: true }),
      },
      defaultValue: [{ label: 'Bắt đầu', url: '/register' }],
    }),
  },
})(({ content, bind }) => (
  <section {...bind.component()}>
    <p {...bind.text('eyebrow')}>{content.eyebrow}</p>
    <h1 {...bind.text('title')}>{content.title}</h1>
    <img {...bind.image('artwork')} src={content.artwork.url} alt={content.artwork.alt} />
    {content.actions.map((action, index) => (
      <a key={action.url} href={action.url} {...bind.text(`actions.${index}.label`)}>
        {action.label}
      </a>
    ))}
  </section>
))

wikex.image() tự sinh ba phần dữ liệu: Media upload, đường dẫn asset mặc định và alt. Khi editor chọn ảnh mới, content.artwork.url ưu tiên URL Media; nếu chưa chọn thì dùng defaultSrc. Các factory hiện có gồm text, textarea, richText, number, boolean, select, relationship, link, group, listimage.

Thêm generator vào lifecycle của project:

{
  "scripts": {
    "predev": "wikex generate",
    "prebuild": "wikex generate"
  }
}

Lệnh này scan src/**/*.tsx bằng TypeScript AST mà không chạy/import component, sau đó sinh theo convention:

  • src/cms/wikexBlocks.generated.ts — Payload schema, Add Layout catalog và defaults;
  • src/cms/wikexBlockRenderers.generated.ts — mapping blockType sang component frontend.

Metadata phải là object tĩnh; có thể dùng literal, array, as const và local const tĩnh. Không dùng giá trị lấy từ API, hook hoặc function runtime bên trong object annotation.

Đưa registry vào starter để không phải khai báo block lần hai:

import { createWikexStarter } from '@wikex/admin-kit/starter'
import { wikexBlockRegistry } from './cms/wikexBlocks.generated'

export const admin = createWikexStarter({
  blocks: wikexBlockRegistry,
  brand,
  content: { page: { previewURL: '/' } },
  id: 'acme',
  provider: '@/cms/LivePreviewAdapter',
})

Starter tự dùng pageBlocks, metadata Add Layout và hydrateLayout() cho Page cũ chưa có field mới. Giá trị editor đã lưu không bị ghi đè. Scanner cũng đánh dấu component annotated là editable và liệt kê các route đang import trực tiếp hoặc gián tiếp component.

Quy trình scaffold và import 0.12

Với dự án mới, có thể dựng trước một sườn admin độc lập rồi đưa page/component vào sau:

pnpm exec wikex init --full
cp .env.example .env
pnpm exec wikex generate
pnpm exec payload generate:importmap

init --full tạo các file còn thiếu cho Payload Admin tại /admin, REST API tại /api, Users, Settings, Header/Footer, SQLite config và adapter Live Preview. Lệnh không ghi đè source có sẵn. Cài các peer cần cho sườn Payload, tối thiểu @payloadcms/db-sqlite, @payloadcms/next, payload, Next và React. Nếu project đang có src/app/layout.tsx, giữ layout đó và tích hợp Payload RootLayout theo cấu trúc route group hiện tại của project thay vì tạo root layout thứ hai.

Discovery dựa trên cấu trúc thư mục, không ghi database:

pnpm exec wikex discover
pnpm exec wikex discover --apply
  • route lấy từ src/app/**/page.tsx; route group được bỏ khỏi URL và dynamic route được đánh dấu để xử lý riêng;
  • component lấy từ export trong src/components/**/*.{tsx,jsx};
  • catalog phân biệt registeredneeds-mapping.

Import là một bước tường minh. Chọn component theo tên, file hoặc catalog id:

pnpm exec wikex import-component Hero
pnpm exec wikex import-component components:Hero.tsx#default --apply
pnpm exec wikex generate

Sidecar mới giữ nguyên component React làm renderer và bắt đầu với fields: []. Hãy khai báo các field Payload tương ứng text/ảnh/list rồi chạy lại wikex generate. Admin Kit không đoán ý nghĩa prop từ JSX, vì đoán sai sẽ làm Live Preview hiển thị được nhưng lưu dữ liệu sai. Component chỉ được xem là sẵn sàng bàn giao khi field mapping đã được khai báo.

Sau khi registry đã sẵn sàng, import các route tĩnh vào collection pages:

pnpm exec wikex import-pages
pnpm exec wikex import-pages --apply
pnpm exec wikex import-pages --apply --overwrite

import-pages mặc định dry-run. --apply chỉ tạo page còn thiếu; record editor đang có được giữ nguyên. --overwrite là lựa chọn riêng để cập nhật title/layout từ source. Có thể dùng --collection <slug>--config <payload-config> cho project khác convention. Dynamic route không được tự tạo vì cần nguồn dữ liệu/slug cụ thể.

React component vẫn thuộc source code; Payload DB chỉ giữ metadata, content và layout. Để Live Preview hoạt động như editor hiện tại, frontend route phải đọc Page từ Payload và render layout bằng src/cms/WikexLayout.tsx do init --full tạo; mỗi component cần sidecar field mapping hoặc defineWikexComponent().

Quy trình tự động hóa 0.11

Khởi tạo dự án mới bằng một lệnh. init chỉ tạo file còn thiếu, giữ nguyên source đã tồn tại và bổ sung lifecycle script trong package.json:

pnpm exec wikex init
pnpm exec wikex generate
pnpm exec wikex doctor

Trong lúc phát triển có thể generate liên tục và quét inventory dưới dạng dễ đọc hoặc JSON:

pnpm exec wikex generate --watch
pnpm exec wikex scan
pnpm exec wikex scan --json

Đồng bộ Page và content luôn là dry-run mặc định. sync-pages --apply chỉ ghi manifest local để review/import, không tự kết nối hay ghi database Payload. Dynamic route được bỏ qua và phải cấu hình thủ công:

pnpm exec wikex sync-pages
pnpm exec wikex sync-pages --apply

sync-content hydrate default vào Page JSON đã export, không ghi đè field có nội dung. Khi dùng --apply, CLI tạo backup trước khi ghi và có thể restore bằng --rollback:

pnpm exec wikex sync-content --input ./pages.json
pnpm exec wikex sync-content --input ./pages.json --apply
pnpm exec wikex sync-content --input ./pages.json --rollback ./pages.json.backup-... --apply

doctor kiểm tra dependency, lifecycle scripts, Next transpilation, Payload styles, generated registry và block slug trùng. Lỗi bắt buộc trả exit code 1 để dùng trong CI.

API defineWikexBlock() cùng sidecar *.wikex.ts vẫn được hỗ trợ để migrate dần các dự án cũ.

Project config và route resolver cũng dùng API chung, nhưng tên module/collection vẫn do từng website quyết định:

import { createVisualEditorRouteResolver, defineWikexProject } from '@wikex/admin-kit/project'

export const project = defineWikexProject({
  brand: {
    description: 'Website doanh nghiệp',
    logo: { height: 64, url: '/logo.svg', width: 64 },
    name: 'Wikex Corporate',
  },
  id: 'wikex-corporate',
  modules: ['website', 'services'],
})

export const getVisualEditorRoute = createVisualEditorRouteResolver({
  collections: ['pages'],
  globals: { footer: 'footer', header: 'header', homepage: 'content' },
})

Xem consumer không thuộc lĩnh vực bất động sản tại examples/corporate-demo.

Ứng dụng cần cung cấp các file font tại public/fonts/google, hoặc ghi đè các biến --font-* nếu dùng font riêng.

Cài vào dự án khác — một package, một cấu hình

pnpm add @wikex/[email protected]

Không cần .npmrc, GitLab token hay npm token ở dự án consumer. Các peer dependency Payload/Next/React phải đã có trong dự án.

// src/wikex.ts — server-only config, dùng một lần trong Payload config
import { createWikexStarter } from '@wikex/admin-kit/starter'
import { pageBlocks, postBlocks } from './blocks'

export const wikex = createWikexStarter({
  brand: {
    description: 'Website công ty Acme',
    logo: { height: 64, url: '/logo.svg', width: 64 },
    name: 'Acme',
  },
  content: {
    page: { blocks: pageBlocks, previewURL: '/' },
    post: { blocks: postBlocks, previewURL: '/news' },
    seo: {
      siteName: 'Acme',
      pathFor: ({ collection, slug }) =>
        collection === 'pages' ? (slug === 'home' ? '/' : `/${slug}`) : `/news/${slug}`,
    },
  },
  globals: { footer: 'footer', header: 'header' },
  id: 'acme',
  provider: '@/LivePreviewAdapter',
})
// payload.config.ts
import { wikex } from './src/wikex'

export default buildConfig({
  collections: [Users, ...wikex.collections, ...projectCollections],
  globals: projectGlobals,
  plugins: wikex.plugins,
})

Giữ LivePreviewAdapter.tsx nhỏ ở client vì block renderer của mỗi website là riêng. Adapter gọi createWikexLivePreviewAdapter từ @wikex/admin-kit/starter/client với branding, block picker và route resolver tương ứng; xem implementation hoàn chỉnh tại examples/corporate-demo.

Phát hành npm public

Khi phát hành:

  1. tăng version theo SemVer và cập nhật CHANGELOG.md;
  2. chạy test/typecheck/build trong starter;
  3. tạo tag admin-kit-v<version> để GitLab CI publish npm;
  4. ở từng dự án consumer đổi workspace:* thành version cố định, ví dụ 0.2.0;
  5. nâng version có chủ đích, không dùng latest trong production.

GitLab CI cần một CI/CD variable bảo mật NPM_TOKEN có quyền publish scope @wikex. Đây là credential duy nhất của phía phát hành; người dùng package công khai không cần credential nào.