Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
19c1c0d
refactor(admin): migrate admin app to React
Innei May 24, 2026
dbcabc7
feat: update dependencies and add new packages
Innei May 24, 2026
1a7e5f9
refactor: update pnpm workspace configuration to remove redundant pac…
Innei May 25, 2026
0c993c1
refactor(admin): flatten src/app/* into src/ root
Innei May 25, 2026
0da0971
refactor(admin): extract Drawer UI and align write-page header
Innei May 25, 2026
abf48d1
feat(admin): add headless DateTimePicker built on @rehookify/datepicker
Innei May 25, 2026
dc01b70
docs: add imperative modal system design spec
Innei May 25, 2026
41ffa18
feat(admin): redesign write-page editing canvas to Notion-style
Innei May 25, 2026
60a1a60
feat(admin): replace haklex ToolbarPlugin with custom Notion-style ed…
Innei May 25, 2026
6fd0429
docs: address codex review findings in imperative modal spec
Innei May 25, 2026
1516802
feat(admin): add imperative modal system and migrate DraftRecoveryDialog
Innei May 25, 2026
78e1528
docs: add admin mobile layout design spec
Innei May 25, 2026
f4a60c1
chore(admin): snapshot in-progress UI/modal/portal work before mobile…
Innei May 25, 2026
9466617
feat(admin/ui): add BottomSheet primitive
Innei May 25, 2026
557111c
feat(admin): mobile sidebar drawer + ShellNavContext
Innei May 25, 2026
8f9b976
feat(admin/ui): PageHeader hamburger trigger + typed actions API
Innei May 25, 2026
8fe8791
feat(admin/ui): ContentLayout mobile branch via BottomSheet
Innei May 25, 2026
5f9bc56
feat(admin/ui): ResponsiveDataTable + DefaultRowCard primitives
Innei May 25, 2026
a95db8f
fix(admin/ui): page-layout review feedback
Innei May 25, 2026
2ca518e
refactor(admin/ui): extract useMediaQuery; address T4/T5 review feedback
Innei May 25, 2026
c28e932
fix(admin): shell mobile top bar; wire write-page onCloseAside
Innei May 25, 2026
bb32003
feat(admin): smart shell top bar fallback + MobileHamburger primitive
Innei May 25, 2026
7a14fc9
refactor(admin): split route pages into feature domains
Innei May 26, 2026
57203ae
fix(admin): tolerate null/empty timestamps in i18n + draft tag
Innei May 26, 2026
ad25d58
feat(admin): port CodeMirror markdown editor + write panel polish
Innei May 26, 2026
dd281d7
refactor(admin): reorganize src/ui by category; extract vendor + feat…
Innei May 26, 2026
68eb020
docs: spec for convention-based admin routing
Innei May 26, 2026
0885358
refactor(admin): convention-based file-system routing
Innei May 26, 2026
a09cc1f
docs(spec): /posts /notes row redesign + singleton ContextMenu
Innei May 26, 2026
a9fab9a
feat(admin): /posts /notes row redesign + ContextMenu primitive
Innei May 26, 2026
eff042b
feat(admin): focus scope + keyboard navigation for content lists
Innei May 26, 2026
b419ed9
refactor(admin): migrate ad-hoc stores to Zustand + Jotai
Innei May 26, 2026
be75d26
chore(admin): drop the old codemirror/editor-store.ts shim
Innei May 26, 2026
f48262f
docs(spec): ContentListToolbar layout rebalance
Innei May 26, 2026
b08c824
refactor(admin): rebalance ContentListToolbar layout
Innei May 26, 2026
23fdf24
feat(admin): i18n migration — extract hardcoded zh-CN strings via tra…
Innei May 27, 2026
f390be3
refactor(admin): dashboard block spacing & stats grid hairline
Innei May 27, 2026
adcfc03
feat: enhance button component with icon-only variant and refactor cl…
Innei May 27, 2026
24b7dea
Refactor topic and webhook forms to use modals
Innei May 27, 2026
8ac2311
feat: redesign files management routes with new components and hooks
Innei May 27, 2026
e15d5d6
feat(admin): redesign /assets/template page with master-detail layout
Innei May 27, 2026
eebfd69
feat(admin): redesign /ai/{summary,translation,insights} with article…
Innei May 27, 2026
1c23798
feat(admin): delete /ai/slug-backfill and redesign /ai/translation-en…
Innei May 27, 2026
3a6cba4
feat(admin): redesign /ai, /analyze, /markdown with decomposed blocks
Innei May 28, 2026
9a62a31
feat(admin): flatten /setting/:type detail layout and consolidate modals
Innei May 28, 2026
323b9a8
feat(admin): redesign snippets master-detail with collapsible groups …
Innei May 28, 2026
d071e9e
feat(admin): redesign sidebar chrome and tighten page header typography
Innei May 28, 2026
a7bf5a7
feat(admin): sync master changes — thumbhash migration and translatio…
Innei May 28, 2026
c8a0a6f
feat(admin): redesign /readers as master-detail with search, role tab…
Innei May 28, 2026
9ef8aec
feat(admin): redesign write AI agent panel into a focused module
Innei May 28, 2026
616c376
docs(claude): mark repo archived; admin code moved to mx-core/apps/admin
Innei May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
41 changes: 15 additions & 26 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,40 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

MX Admin (admin-vue3) is the dashboard for MX Space, a personal blog management system. Built with Vue 3, Naive UI, and UnoCSS. This is the v4.0 admin interface for Mix Space Server v5.0.
MX Admin is the dashboard for MX Space, a personal blog management system. The active admin app is a React application built with Base UI primitives, React Router, TanStack Query, Sonner, and UnoCSS.

## Development Commands

```bash
pnpm install # Install dependencies
pnpm dev # Start development server (opens browser automatically)
pnpm build # Build for production
pnpm lint # Lint code with Biome
pnpm lint # Lint code with oxlint
pnpm lint:fix # Lint and auto-fix
npx tsc --noEmit # Type check (use this instead of build for validation)
pnpm -C apps/admin exec tsc --noEmit --pretty false
```

## Architecture Overview

### Technology Stack

- **Vue 3** with Composition API and TSX (JSX via `@vitejs/plugin-vue-jsx`)
- **Naive UI** - Component library with Vercel-style neutral theme
- **React** with TSX
- **Base UI** - Headless component primitives
- **React Router** - Route rendering and shell navigation
- **UnoCSS** (preset-wind4) - Tailwind-compatible utility classes
- **Pinia** - State management
- **TanStack Query** (`@tanstack/vue-query`) - Server state management with localStorage persistence
- **TanStack Query** (`@tanstack/react-query`) - Server state management
- **Sonner** - Toast notifications
- **Socket.IO** - Real-time WebSocket updates
- **CodeMirror/Monaco** - Code editors

### Path Aliases

```typescript
import { something } from '~/utils/...' // ~ maps to ./src
```

### API Layer (`src/api/`)
### API Layer (`src/app/api/`)

API services use the custom request layer built on `ofetch`. The backend wraps array responses as `{ data: [...] }`, which is automatically unwrapped by the request layer.
React app API services use the fetch-based helpers in `src/app/api/http.ts`.

When using TanStack Query, extract arrays with:
```typescript
Expand All @@ -48,14 +48,6 @@ select: (res: any) => Array.isArray(res) ? res : res?.data ?? []
- `BusinessError` - Application-level errors (4xx responses)
- `SystemError` - Network/server errors (5xx responses, network failures)

### State Management

**Pinia Stores (`src/stores/`):**
- `useUIStore` - Theme mode (light/dark/system), viewport dimensions, sidebar state
- `useUserStore` - User authentication state
- `useAppStore` - Global application state
- `useCategoryStore` - Category data

### Responsive Breakpoints (UnoCSS)

- `phone:` - max-width: 768px
Expand All @@ -66,7 +58,7 @@ select: (res: any) => Array.isArray(res) ? res : res?.data ?? []

### Validation

After modifying code, run type check only (`npx tsc --noEmit`). Do not run `pnpm build` for validation.
After modifying code, run focused type checking and linting. Run production build before reporting completion for broad application changes.

### Gray Scale Colors

Expand All @@ -92,8 +84,8 @@ See `docs/typography.md` for full guidelines.
## Configuration Files

- `uno.config.ts` - UnoCSS configuration with custom breakpoints and theme colors
- `src/utils/color.ts` - Naive UI theme overrides (Vercel-style neutral gray palette)
- `biome.json` - Linter/formatter configuration with Vue globals
- `src/app/theme.ts` - CSS token installation for the React shell
- `src/app/` - React routes, shell, API helpers, UI primitives, and migrated views
- `.env` - Local dev API endpoint (`VITE_APP_BASE_API`)

## Related Projects
Expand All @@ -102,9 +94,6 @@ See `docs/typography.md` for full guidelines.
- **Shiroi** — Next.js frontend (blog), located at `../Shiroi`
- **haklex** — Rich editor packages (`@haklex/*`), located at `../haklex` (standalone) or `../Shiroi/haklex` (original host)

### Rich Editor Integration (React-in-Vue)
### Rich Editor Integration

admin-vue3 is a Vue 3 project but embeds the React-based haklex editor via a bridge pattern in `src/components/editor/rich/RichEditor.tsx`:
- Uses `createRoot()` from `react-dom/client` inside Vue `defineComponent` to mount the local `ShiroEditor` (`packages/rich-react/src/shiro/`)
- Local Shiro lives in `packages/rich-react/src/shiro/` — composes `@haklex/rich-editor` + per-feature `@haklex/rich-ext-*` / `@haklex/rich-renderer-*` packages directly
- All `@haklex/*` packages are pinned npm versions (not workspace links). After haklex releases, update versions here.
The admin app no longer mounts rich editor surfaces through a framework bridge. React editor work should be integrated as ordinary React components and kept out of compatibility shims.
10 changes: 5 additions & 5 deletions apps/admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
link.href = favicon
document.head.appendChild(link)
</script>
<title>Mx Space Admin Vue 3 v2</title>
<title>Mx Space Admin</title>
<script>
window.injectData = {}
window.version = 'N/A'
Expand Down Expand Up @@ -98,15 +98,15 @@
</div>
<noscript>
<strong
>We're sorry but MX Space Admin Vue 3 doesn't work properly without
JavaScript enabled. Please enable it to continue.</strong
>We're sorry but MX Space Admin doesn't work properly without JavaScript
enabled. Please enable it to continue.</strong
>
<strong>
It may be a network problem that caused the failure to load the JS file.
</strong>
</noscript>
<script>
// Initialize theme before Vue loads to prevent flash
// Initialize theme before the application loads to prevent flash
;(function () {
var themeMode = localStorage.getItem('theme-mode')
// Remove quotes if stored as JSON string
Expand All @@ -124,6 +124,6 @@
}
})()
</script>
<script type="module" src="/src/main.ts"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
98 changes: 46 additions & 52 deletions apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,100 +12,95 @@
},
"dependencies": {
"@antv/g2": "^5.4.8",
"@base-ui/react": "1.5.0",
"@better-auth/passkey": "1.4.18",
"@bytebase/vue-kbar": "0.1.8",
"@codemirror/commands": "6.10.3",
"@codemirror/lang-markdown": "6.5.0",
"@codemirror/language": "6.12.3",
"@codemirror/language-data": "6.5.2",
"@codemirror/search": "6.7.0",
"@codemirror/state": "6.6.0",
"@codemirror/theme-one-dark": "6.1.3",
"@codemirror/view": "6.42.1",
"@ddietr/codemirror-themes": "1.5.2",
"@emoji-mart/data": "1.2.1",
"@excalidraw/excalidraw": "^0.18.0",
"@haklex/rich-agent-chat": "0.8.0",
"@haklex/rich-agent-core": "0.8.0",
"@haklex/rich-diff": "0.8.0",
"@haklex/rich-editor": "0.8.0",
"@haklex/rich-ext-ai-agent": "0.8.0",
"@haklex/rich-ext-nested-doc": "0.8.0",
"@haklex/rich-style-token": "0.8.0",
"@lexical/code-core": "^0.44.0",
"@haklex/rich-agent-core": "0.15.4",
"@haklex/rich-compose": "0.15.4",
"@haklex/rich-diff": "0.15.4",
"@haklex/rich-editor": "0.15.4",
"@haklex/rich-editor-ui": "0.15.4",
"@haklex/rich-ext-ai-agent": "0.15.4",
"@haklex/rich-ext-chat": "0.15.4",
"@haklex/rich-ext-code-snippet": "0.15.4",
"@haklex/rich-ext-embed": "0.15.4",
"@haklex/rich-ext-excalidraw": "0.15.4",
"@haklex/rich-ext-gallery": "0.15.4",
"@haklex/rich-ext-nested-doc": "0.15.4",
"@haklex/rich-plugin-block-handle": "0.15.4",
"@haklex/rich-plugin-floating-toolbar": "0.15.4",
"@haklex/rich-plugin-link-edit": "0.15.4",
"@haklex/rich-plugin-litexml-paste": "0.15.4",
"@haklex/rich-plugin-mention": "0.15.4",
"@haklex/rich-plugin-slash-menu": "0.15.4",
"@haklex/rich-plugin-table": "0.15.4",
"@haklex/rich-plugin-toolbar": "0.15.4",
"@haklex/rich-renderer-alert": "0.15.4",
"@haklex/rich-renderer-banner": "0.15.4",
"@haklex/rich-renderer-codeblock": "0.15.4",
"@haklex/rich-renderer-image": "0.15.4",
"@haklex/rich-renderer-katex": "0.15.4",
"@haklex/rich-renderer-linkcard": "0.15.4",
"@haklex/rich-renderer-mention": "0.15.4",
"@haklex/rich-renderer-mermaid": "0.15.4",
"@haklex/rich-renderer-ruby": "0.15.4",
"@haklex/rich-renderer-video": "0.15.4",
"@lexical/markdown": "^0.44.0",
"@lezer/highlight": "1.2.3",
"@mx-admin/rich-react": "workspace:*",
"@lexical/react": "^0.44.0",
"@monaco-editor/react": "4.7.0",
"@pierre/diffs": "1.1.3",
"@simplewebauthn/browser": "13.3.0",
"@tanstack/query-async-storage-persister": "5.95.0",
"@tanstack/query-persist-client-core": "5.95.0",
"@tanstack/vue-query": "5.95.0",
"@tanstack/react-query": "5.100.13",
"@types/canvas-confetti": "1.9.0",
"@typescript/ata": "0.9.8",
"@vicons/utils": "0.1.4",
"@vueuse/core": "14.2.1",
"@xterm/addon-fit": "0.11.0",
"@xterm/xterm": "6.0.0",
"ansi_up": "6.0.6",
"better-auth": "1.4.18",
"blurhash": "2.0.5",
"buffer": "6.0.3",
"canvas-confetti": "1.9.4",
"date-fns": "4.1.0",
"ejs": "4.0.1",
"emoji-mart": "5.6.0",
"ejs": "5.0.2",
"es-toolkit": "1.45.1",
"event-source-polyfill": "1.0.31",
"fuse.js": "7.1.0",
"highlight.js": "11.11.1",
"js-cookie": "3.0.5",
"js-yaml": "4.1.1",
"json5": "2.2.3",
"jsondiffpatch": "0.7.3",
"katex": "0.16.40",
"katex": "^0.16.45",
"lexical": "^0.44.0",
"lit": "3.3.2",
"lodash.transform": "4.6.0",
"lucide-vue-next": "0.574.0",
"markdown-escape": "2.0.0",
"lucide-react": "1.8.0",
"marked": "17.0.5",
"monaco-editor": "0.55.1",
"naive-ui": "2.44.1",
"octokit": "5.0.5",
"ofetch": "1.5.1",
"openai": "6.32.0",
"os-browserify": "0.3.0",
"path-browserify": "1.0.1",
"pinia": "3.0.4",
"qier-progress": "1.0.4",
"qs": "6.15.0",
"shiki": "3.21.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-resizable-panels": "4.11.1",
"react-router": "7.15.1",
"socket.io-client": "4.8.3",
"sortablejs": "1.15.7",
"umi-request": "1.4.0",
"sonner": "2.0.7",
"validator": "13.15.26",
"vue": "3.5.30",
"vue-router": "4.6.4",
"vue-sonner": "2.0.9",
"xss": "1.0.15",
"xterm-theme": "1.1.0",
"zod": "4.3.6"
},
"devDependencies": {
"@types/ejs": "3.1.5",
"@types/event-source-polyfill": "1.0.5",
"@types/js-yaml": "4.0.9",
"@types/markdown-escape": "1.1.3",
"@types/qs": "6.15.0",
"@types/sortablejs": "1.15.9",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@types/validator": "13.15.10",
"@unocss/postcss": "^66.6.8",
"@unocss/preset-typography": "66.6.7",
"@vitejs/plugin-vue": "6.0.5",
"@vitejs/plugin-vue-jsx": "5.1.5",
"@vue/compiler-sfc": "3.5.30",
"@vue/test-utils": "^2.4.0",
"@vitejs/plugin-react": "6.0.2",
"code-inspector-plugin": "1.5.1",
"cors": "2.8.6",
"happy-dom": "^15.11.0",
"postcss": "8.5.8",
Expand All @@ -117,7 +112,6 @@
"vite": "8.0.1",
"vite-plugin-checker": "0.12.0",
"vite-plugin-mkcert": "1.17.10",
"vite-plugin-vue-inspector": "5.4.0",
"vitest": "^4.1.5"
}
}
Loading
Loading