@nocobase/portal-template-default 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +10 -0
- package/Dockerfile +36 -0
- package/README.MD +50 -0
- package/components.json +25 -0
- package/eslint.config.js +28 -0
- package/index.html +39 -0
- package/package.json +84 -0
- package/pnpm-workspace.yaml +2 -0
- package/public/favicon.ico +0 -0
- package/public/logo-dark.png +0 -0
- package/public/logo-mark-dark.png +0 -0
- package/public/logo-mark.png +0 -0
- package/public/logo.png +0 -0
- package/src/App.css +158 -0
- package/src/App.tsx +151 -0
- package/src/components/app-shell/brand.tsx +70 -0
- package/src/components/app-shell/breadcrumb.tsx +81 -0
- package/src/components/app-shell/document-title-handler.tsx +169 -0
- package/src/components/app-shell/error-component.tsx +134 -0
- package/src/components/app-shell/header.tsx +127 -0
- package/src/components/app-shell/layout.tsx +39 -0
- package/src/components/app-shell/loading-overlay.tsx +36 -0
- package/src/components/app-shell/sidebar.tsx +351 -0
- package/src/components/app-shell/user-avatar.tsx +42 -0
- package/src/components/app-shell/user-info.tsx +53 -0
- package/src/components/auth/auth-layout.tsx +82 -0
- package/src/components/auth/forgot-password-form.tsx +58 -0
- package/src/components/auth/input-password.tsx +38 -0
- package/src/components/auth/sign-in-form.tsx +111 -0
- package/src/components/auth/sign-up-form.tsx +127 -0
- package/src/components/data-table/data-table-filter.tsx +994 -0
- package/src/components/data-table/data-table-pagination.tsx +146 -0
- package/src/components/data-table/data-table-sorter.tsx +47 -0
- package/src/components/data-table/data-table.tsx +321 -0
- package/src/components/notifications/toaster.tsx +23 -0
- package/src/components/notifications/undoable-notification.tsx +84 -0
- package/src/components/notifications/use-notification-provider.tsx +62 -0
- package/src/components/resources/buttons/clone.tsx +81 -0
- package/src/components/resources/buttons/create.tsx +70 -0
- package/src/components/resources/buttons/delete.tsx +113 -0
- package/src/components/resources/buttons/edit.tsx +81 -0
- package/src/components/resources/buttons/list.tsx +70 -0
- package/src/components/resources/buttons/refresh.tsx +81 -0
- package/src/components/resources/buttons/show.tsx +81 -0
- package/src/components/resources/status-badge.tsx +37 -0
- package/src/components/resources/views/create-view.tsx +81 -0
- package/src/components/resources/views/edit-view.tsx +104 -0
- package/src/components/resources/views/list-view.tsx +86 -0
- package/src/components/resources/views/show-view.tsx +108 -0
- package/src/components/theme/theme-provider.tsx +71 -0
- package/src/components/theme/theme-select.tsx +97 -0
- package/src/components/theme/theme-toggle.tsx +66 -0
- package/src/components/ui/accordion.tsx +72 -0
- package/src/components/ui/alert-dialog.tsx +185 -0
- package/src/components/ui/alert.tsx +76 -0
- package/src/components/ui/aspect-ratio.tsx +22 -0
- package/src/components/ui/avatar.tsx +107 -0
- package/src/components/ui/badge.tsx +52 -0
- package/src/components/ui/breadcrumb.tsx +125 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/calendar.tsx +221 -0
- package/src/components/ui/card.tsx +103 -0
- package/src/components/ui/carousel.tsx +240 -0
- package/src/components/ui/chart.tsx +373 -0
- package/src/components/ui/checkbox.tsx +29 -0
- package/src/components/ui/collapsible.tsx +19 -0
- package/src/components/ui/command.tsx +192 -0
- package/src/components/ui/context-menu.tsx +271 -0
- package/src/components/ui/dialog.tsx +160 -0
- package/src/components/ui/drawer.tsx +226 -0
- package/src/components/ui/dropdown-menu.tsx +268 -0
- package/src/components/ui/form.tsx +174 -0
- package/src/components/ui/hover-card.tsx +49 -0
- package/src/components/ui/input-group.tsx +158 -0
- package/src/components/ui/input-otp.tsx +87 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/label.tsx +18 -0
- package/src/components/ui/menubar.tsx +278 -0
- package/src/components/ui/navigation-menu.tsx +168 -0
- package/src/components/ui/pagination.tsx +130 -0
- package/src/components/ui/popover.tsx +91 -0
- package/src/components/ui/progress.tsx +81 -0
- package/src/components/ui/radio-group.tsx +38 -0
- package/src/components/ui/resizable.tsx +48 -0
- package/src/components/ui/scroll-area.tsx +55 -0
- package/src/components/ui/select.tsx +199 -0
- package/src/components/ui/separator.tsx +25 -0
- package/src/components/ui/sheet.tsx +136 -0
- package/src/components/ui/sidebar.tsx +723 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/slider.tsx +52 -0
- package/src/components/ui/sonner.tsx +47 -0
- package/src/components/ui/switch.tsx +32 -0
- package/src/components/ui/table.tsx +114 -0
- package/src/components/ui/tabs.tsx +82 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/toggle-group.tsx +87 -0
- package/src/components/ui/toggle.tsx +43 -0
- package/src/components/ui/tooltip.tsx +66 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/index.tsx +17 -0
- package/src/lib/utils.ts +19 -0
- package/src/pages/blog-posts/create.tsx +177 -0
- package/src/pages/blog-posts/edit.tsx +197 -0
- package/src/pages/blog-posts/index.ts +4 -0
- package/src/pages/blog-posts/list.tsx +131 -0
- package/src/pages/blog-posts/show.tsx +81 -0
- package/src/pages/categories/create.tsx +73 -0
- package/src/pages/categories/edit.tsx +73 -0
- package/src/pages/categories/index.ts +4 -0
- package/src/pages/categories/list.tsx +86 -0
- package/src/pages/categories/show.tsx +37 -0
- package/src/pages/forgot-password/index.tsx +6 -0
- package/src/pages/forgotPassword/index.tsx +5 -0
- package/src/pages/login/index.tsx +5 -0
- package/src/pages/register/index.tsx +5 -0
- package/src/providers/auth.ts +204 -0
- package/src/providers/constants.ts +75 -0
- package/src/providers/data.ts +232 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
- package/tsconfig.node.json +21 -0
- package/vite.config.ts +74 -0
package/.env.example
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# NocoBase REST API root (the /api suffix is required)
|
|
2
|
+
NOCOBASE_API_URL=/api
|
|
3
|
+
NOCOBASE_AUTHENTICATOR=basic
|
|
4
|
+
|
|
5
|
+
# Public base path for Vite assets and React Router when deployed under NocoBase.
|
|
6
|
+
# Use / for root-local development, or /x/admin/ when building for storage/dist-client/x/admin.
|
|
7
|
+
NOCOBASE_PORTAL_BASE=/x/admin/
|
|
8
|
+
|
|
9
|
+
# Optional for local development. Do not commit real access tokens.
|
|
10
|
+
# NOCOBASE_API_TOKEN=
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# This Dockerfile uses `serve` npm package to serve the static files with node process.
|
|
2
|
+
# You can find the Dockerfile for nginx in the following link:
|
|
3
|
+
# https://github.com/refinedev/dockerfiles/blob/main/vite/Dockerfile.nginx
|
|
4
|
+
FROM refinedev/node:18 AS base
|
|
5
|
+
|
|
6
|
+
FROM base as deps
|
|
7
|
+
|
|
8
|
+
RUN corepack enable
|
|
9
|
+
|
|
10
|
+
COPY package.json pnpm-lock.yaml .npmrc ./
|
|
11
|
+
|
|
12
|
+
RUN pnpm install --frozen-lockfile
|
|
13
|
+
|
|
14
|
+
FROM base as builder
|
|
15
|
+
|
|
16
|
+
ENV NODE_ENV production
|
|
17
|
+
|
|
18
|
+
COPY --from=deps /app/refine/node_modules ./node_modules
|
|
19
|
+
|
|
20
|
+
COPY . .
|
|
21
|
+
|
|
22
|
+
RUN pnpm run build
|
|
23
|
+
|
|
24
|
+
FROM base as runner
|
|
25
|
+
|
|
26
|
+
ENV NODE_ENV production
|
|
27
|
+
ENV PNPM_HOME=/pnpm
|
|
28
|
+
ENV PATH=$PNPM_HOME:$PATH
|
|
29
|
+
|
|
30
|
+
RUN corepack enable && pnpm add --global serve
|
|
31
|
+
|
|
32
|
+
COPY --from=builder /app/refine/dist ./
|
|
33
|
+
|
|
34
|
+
USER refine
|
|
35
|
+
|
|
36
|
+
CMD ["serve"]
|
package/README.MD
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# nocobase-admin-starter
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
## NocoBase configuration
|
|
6
|
+
|
|
7
|
+
Copy `.env.example` to `.env.local` and set the NocoBase API URL. The default `basic` authenticator uses the NocoBase username or email and password login. For local development, a temporary access token can be supplied through `NOCOBASE_API_TOKEN`; do not commit it. The data provider sends it as `Authorization: Bearer <token>`.
|
|
8
|
+
|
|
9
|
+
If you call a remote NocoBase instance from `http://localhost:*`, the browser may block `auth:signIn` because NocoBase requires the `X-Authenticator` request header and the remote server must explicitly allow it in CORS preflight responses. In local Vite development, prefer using the built-in dev proxy:
|
|
10
|
+
|
|
11
|
+
```env
|
|
12
|
+
NOCOBASE_API_URL=https://develop.v2.test.nocobase.com/nocobase/api/__app/cms
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
In development, the app auto-detects the proxy target from `NOCOBASE_API_URL` when that value is an absolute URL. The configured API URL can stay on the original sub-app path such as `/nocobase/api/__app/cms`.
|
|
16
|
+
|
|
17
|
+
Refine resource names must match NocoBase collection names. For example, the supplied Swagger document exposes `collectionCategories`, so use that name when registering a corresponding Refine resource.
|
|
18
|
+
|
|
19
|
+
## Available Scripts
|
|
20
|
+
|
|
21
|
+
### Running the development server.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Building for production.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Running the production server.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pnpm start
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Learn More
|
|
40
|
+
|
|
41
|
+
To learn more about **Refine**, please check out the [Documentation](https://refine.dev/docs)
|
|
42
|
+
|
|
43
|
+
- **REST Data Provider** [Docs](https://refine.dev/docs/core/providers/data-provider/#overview)
|
|
44
|
+
- **shadcn/ui** [Docs](https://refine.dev/docs/guides-concepts/general-concepts/#headless-concept)
|
|
45
|
+
- **React Router** [Docs](https://refine.dev/docs/core/providers/router-provider/)
|
|
46
|
+
- **Custom Auth Provider** [Docs](https://refine.dev/docs/core/providers/auth-provider/)
|
|
47
|
+
|
|
48
|
+
## License
|
|
49
|
+
|
|
50
|
+
MIT
|
package/components.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "base-nova",
|
|
4
|
+
"rsc": false,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "",
|
|
8
|
+
"css": "src/App.css",
|
|
9
|
+
"baseColor": "neutral",
|
|
10
|
+
"cssVariables": true,
|
|
11
|
+
"prefix": ""
|
|
12
|
+
},
|
|
13
|
+
"iconLibrary": "lucide",
|
|
14
|
+
"rtl": false,
|
|
15
|
+
"aliases": {
|
|
16
|
+
"components": "@/components",
|
|
17
|
+
"utils": "@/lib/utils",
|
|
18
|
+
"ui": "@/components/ui",
|
|
19
|
+
"lib": "@/lib",
|
|
20
|
+
"hooks": "@/hooks"
|
|
21
|
+
},
|
|
22
|
+
"menuColor": "default",
|
|
23
|
+
"menuAccent": "subtle",
|
|
24
|
+
"registries": {}
|
|
25
|
+
}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
import reactHooks from "eslint-plugin-react-hooks";
|
|
3
|
+
import reactRefresh from "eslint-plugin-react-refresh";
|
|
4
|
+
import globals from "globals";
|
|
5
|
+
import tseslint from "typescript-eslint";
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{ ignores: ["dist"] },
|
|
9
|
+
{
|
|
10
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
+
files: ["**/*.{ts,tsx}"],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
ecmaVersion: 2020,
|
|
14
|
+
globals: globals.browser,
|
|
15
|
+
},
|
|
16
|
+
plugins: {
|
|
17
|
+
"react-hooks": reactHooks,
|
|
18
|
+
"react-refresh": reactRefresh,
|
|
19
|
+
},
|
|
20
|
+
rules: {
|
|
21
|
+
...reactHooks.configs.recommended.rules,
|
|
22
|
+
"react-refresh/only-export-components": [
|
|
23
|
+
"warn",
|
|
24
|
+
{ allowConstantExport: true },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
);
|
package/index.html
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<meta name="theme-color" content="#171717" />
|
|
8
|
+
<meta
|
|
9
|
+
name="description"
|
|
10
|
+
content="NocoBase administration console"
|
|
11
|
+
/>
|
|
12
|
+
<meta
|
|
13
|
+
data-rh="true"
|
|
14
|
+
property="og:image"
|
|
15
|
+
content="/logo-mark.png"
|
|
16
|
+
/>
|
|
17
|
+
<meta
|
|
18
|
+
data-rh="true"
|
|
19
|
+
name="twitter:image"
|
|
20
|
+
content="/logo-mark.png"
|
|
21
|
+
/>
|
|
22
|
+
<title>NocoBase</title>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
26
|
+
<div id="root"></div>
|
|
27
|
+
<script type="module" src="/src/index.tsx"></script>
|
|
28
|
+
<!--
|
|
29
|
+
This HTML file is a template.
|
|
30
|
+
If you open it directly in the browser, you will see an empty page.
|
|
31
|
+
|
|
32
|
+
You can add webfonts, meta tags, or analytics to this file.
|
|
33
|
+
The build step will place the bundled scripts into the <body> tag.
|
|
34
|
+
|
|
35
|
+
To begin development, run `pnpm dev`.
|
|
36
|
+
To create a production bundle, run `pnpm build`.
|
|
37
|
+
-->
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nocobase/portal-template-default",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@base-ui/react": "^1.6.0",
|
|
7
|
+
"@fontsource-variable/geist": "^5.3.0",
|
|
8
|
+
"@hookform/resolvers": "^5.0.1",
|
|
9
|
+
"@refinedev/cli": "^2.16.48",
|
|
10
|
+
"@refinedev/core": "^5.0.8",
|
|
11
|
+
"@refinedev/devtools": "^2.0.1",
|
|
12
|
+
"@refinedev/react-hook-form": "^5.0.0",
|
|
13
|
+
"@refinedev/react-router": "^2.0.0",
|
|
14
|
+
"@refinedev/react-table": "^6.0.0",
|
|
15
|
+
"@refinedev/rest": "^2.1.0",
|
|
16
|
+
"@refinedev/simple-rest": "^6.0.0",
|
|
17
|
+
"@tailwindcss/vite": "^4.1.8",
|
|
18
|
+
"@tanstack/react-table": "^8.2.6",
|
|
19
|
+
"class-variance-authority": "^0.7.1",
|
|
20
|
+
"clsx": "^2.1.1",
|
|
21
|
+
"date-fns": "^4.1.0",
|
|
22
|
+
"dayjs": "^1.10.7",
|
|
23
|
+
"embla-carousel-react": "^8.6.0",
|
|
24
|
+
"input-otp": "^1.4.2",
|
|
25
|
+
"lucide-react": "^0.487.0",
|
|
26
|
+
"next-themes": "^0.4.6",
|
|
27
|
+
"postcss": "^8.5.3",
|
|
28
|
+
"react": "19.1.0",
|
|
29
|
+
"react-day-picker": "10.0.1",
|
|
30
|
+
"react-dom": "19.1.0",
|
|
31
|
+
"react-hook-form": "^7.57.0",
|
|
32
|
+
"react-resizable-panels": "^4.12.2",
|
|
33
|
+
"react-router": "^7.0.2",
|
|
34
|
+
"recharts": "^3.8.0",
|
|
35
|
+
"shadcn": "^4.13.1",
|
|
36
|
+
"sonner": "^2.0.3",
|
|
37
|
+
"tailwind-merge": "^3.2.0",
|
|
38
|
+
"tw-animate-css": "^1.2.5",
|
|
39
|
+
"zod": "^3.24.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@eslint/js": "^9.25.0",
|
|
43
|
+
"@tailwindcss/postcss": "^4.1.4",
|
|
44
|
+
"@types/node": "^20",
|
|
45
|
+
"@types/react": "^19.1.0",
|
|
46
|
+
"@types/react-dom": "^19.1.0",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
|
48
|
+
"@typescript-eslint/parser": "^5.57.1",
|
|
49
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
50
|
+
"eslint": "^9.25.0",
|
|
51
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
52
|
+
"eslint-plugin-react-refresh": "^0.4.19",
|
|
53
|
+
"globals": "^16.0.0",
|
|
54
|
+
"tailwindcss": "^4.1.4",
|
|
55
|
+
"typescript": "^5.8.3",
|
|
56
|
+
"typescript-eslint": "^8.30.1",
|
|
57
|
+
"vite": "^6.3.5"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
61
|
+
},
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "git+https://github.com/nocobase/portal-template-default.git"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"dev": "vite",
|
|
68
|
+
"build": "tsc && refine build",
|
|
69
|
+
"start": "refine start",
|
|
70
|
+
"refine": "refine"
|
|
71
|
+
},
|
|
72
|
+
"browserslist": {
|
|
73
|
+
"production": [
|
|
74
|
+
">0.2%",
|
|
75
|
+
"not dead",
|
|
76
|
+
"not op_mini all"
|
|
77
|
+
],
|
|
78
|
+
"development": [
|
|
79
|
+
"last 1 chrome version",
|
|
80
|
+
"last 1 firefox version",
|
|
81
|
+
"last 1 safari version"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/public/logo.png
ADDED
|
Binary file
|
package/src/App.css
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
@import "shadcn/tailwind.css";
|
|
4
|
+
|
|
5
|
+
@custom-variant dark (&:is(.dark *));
|
|
6
|
+
|
|
7
|
+
@theme inline {
|
|
8
|
+
--color-background: var(--background);
|
|
9
|
+
--color-foreground: var(--foreground);
|
|
10
|
+
--font-sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
11
|
+
"PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;
|
|
12
|
+
--font-mono: var(--font-geist-mono);
|
|
13
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
14
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
15
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
16
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
17
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
18
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
19
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
20
|
+
--color-sidebar: var(--sidebar);
|
|
21
|
+
--color-chart-5: var(--chart-5);
|
|
22
|
+
--color-chart-4: var(--chart-4);
|
|
23
|
+
--color-chart-3: var(--chart-3);
|
|
24
|
+
--color-chart-2: var(--chart-2);
|
|
25
|
+
--color-chart-1: var(--chart-1);
|
|
26
|
+
--color-ring: var(--ring);
|
|
27
|
+
--color-input: var(--input);
|
|
28
|
+
--color-border: var(--border);
|
|
29
|
+
--color-destructive: var(--destructive);
|
|
30
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
31
|
+
--color-accent: var(--accent);
|
|
32
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
33
|
+
--color-muted: var(--muted);
|
|
34
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
35
|
+
--color-secondary: var(--secondary);
|
|
36
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
37
|
+
--color-primary: var(--primary);
|
|
38
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
39
|
+
--color-popover: var(--popover);
|
|
40
|
+
--color-card-foreground: var(--card-foreground);
|
|
41
|
+
--color-card: var(--card);
|
|
42
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
43
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
44
|
+
--radius-lg: var(--radius);
|
|
45
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
46
|
+
|
|
47
|
+
--font-heading: var(--font-sans);
|
|
48
|
+
|
|
49
|
+
--radius-2xl: calc(var(--radius) * 1.8);
|
|
50
|
+
|
|
51
|
+
--radius-3xl: calc(var(--radius) * 2.2);
|
|
52
|
+
|
|
53
|
+
--radius-4xl: calc(var(--radius) * 2.6);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:root {
|
|
57
|
+
--radius: 0.5rem;
|
|
58
|
+
--background: oklch(0.985 0 0);
|
|
59
|
+
--foreground: oklch(0.16 0 0);
|
|
60
|
+
--card: oklch(1 0 0);
|
|
61
|
+
--card-foreground: oklch(0.16 0 0);
|
|
62
|
+
--popover: oklch(1 0 0);
|
|
63
|
+
--popover-foreground: oklch(0.16 0 0);
|
|
64
|
+
--primary: oklch(0.18 0 0);
|
|
65
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
66
|
+
--secondary: oklch(0.96 0 0);
|
|
67
|
+
--secondary-foreground: oklch(0.22 0 0);
|
|
68
|
+
--muted: oklch(0.96 0 0);
|
|
69
|
+
--muted-foreground: oklch(0.52 0 0);
|
|
70
|
+
--accent: oklch(0.94 0 0);
|
|
71
|
+
--accent-foreground: oklch(0.22 0 0);
|
|
72
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
73
|
+
--border: oklch(0.9 0 0);
|
|
74
|
+
--input: oklch(0.9 0 0);
|
|
75
|
+
--ring: oklch(0.55 0 0);
|
|
76
|
+
--chart-1: oklch(0.87 0 0);
|
|
77
|
+
--chart-2: oklch(0.556 0 0);
|
|
78
|
+
--chart-3: oklch(0.439 0 0);
|
|
79
|
+
--chart-4: oklch(0.371 0 0);
|
|
80
|
+
--chart-5: oklch(0.269 0 0);
|
|
81
|
+
--sidebar: oklch(0.995 0 0);
|
|
82
|
+
--sidebar-foreground: oklch(0.16 0 0);
|
|
83
|
+
--sidebar-primary: oklch(0.18 0 0);
|
|
84
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
85
|
+
--sidebar-accent: oklch(0.95 0 0);
|
|
86
|
+
--sidebar-accent-foreground: oklch(0.2 0 0);
|
|
87
|
+
--sidebar-border: oklch(0.91 0 0);
|
|
88
|
+
--sidebar-ring: oklch(0.55 0 0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.dark {
|
|
92
|
+
--background: oklch(0.13 0 0);
|
|
93
|
+
--foreground: oklch(0.96 0 0);
|
|
94
|
+
--card: oklch(0.18 0 0);
|
|
95
|
+
--card-foreground: oklch(0.985 0 0);
|
|
96
|
+
--popover: oklch(0.18 0 0);
|
|
97
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
98
|
+
--primary: oklch(0.94 0 0);
|
|
99
|
+
--primary-foreground: oklch(0.16 0 0);
|
|
100
|
+
--secondary: oklch(0.24 0 0);
|
|
101
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
102
|
+
--muted: oklch(0.23 0 0);
|
|
103
|
+
--muted-foreground: oklch(0.7 0 0);
|
|
104
|
+
--accent: oklch(0.27 0 0);
|
|
105
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
106
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
107
|
+
--border: oklch(1 0 0 / 10%);
|
|
108
|
+
--input: oklch(1 0 0 / 15%);
|
|
109
|
+
--ring: oklch(0.62 0 0);
|
|
110
|
+
--chart-1: oklch(0.87 0 0);
|
|
111
|
+
--chart-2: oklch(0.556 0 0);
|
|
112
|
+
--chart-3: oklch(0.439 0 0);
|
|
113
|
+
--chart-4: oklch(0.371 0 0);
|
|
114
|
+
--chart-5: oklch(0.269 0 0);
|
|
115
|
+
--sidebar: oklch(0.155 0 0);
|
|
116
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
117
|
+
--sidebar-primary: oklch(0.94 0 0);
|
|
118
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
119
|
+
--sidebar-accent: oklch(0.24 0 0);
|
|
120
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
121
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
122
|
+
--sidebar-ring: oklch(0.62 0 0);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@layer base {
|
|
126
|
+
* {
|
|
127
|
+
@apply antialiased border-border outline-ring/50;
|
|
128
|
+
}
|
|
129
|
+
body {
|
|
130
|
+
@apply min-h-svh bg-background font-sans text-foreground;
|
|
131
|
+
}
|
|
132
|
+
html {
|
|
133
|
+
@apply font-sans;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
::selection {
|
|
138
|
+
background: color-mix(in oklch, var(--foreground) 18%, transparent);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@layer components {
|
|
142
|
+
.resource-form {
|
|
143
|
+
@apply max-w-3xl space-y-6 rounded-xl border bg-card p-6 shadow-[0_1px_2px_rgba(0,0,0,0.04)] sm:p-8;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.resource-form [data-slot="input"],
|
|
147
|
+
.resource-form [data-slot="select-trigger"] {
|
|
148
|
+
@apply h-10;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.resource-form [data-slot="textarea"] {
|
|
152
|
+
@apply min-h-56;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.resource-detail-card {
|
|
156
|
+
@apply shadow-[0_1px_2px_rgba(0,0,0,0.04)];
|
|
157
|
+
}
|
|
158
|
+
}
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Refine,
|
|
3
|
+
Authenticated,
|
|
4
|
+
} from "@refinedev/core";
|
|
5
|
+
|
|
6
|
+
import { BrowserRouter, Route, Routes, Outlet } from "react-router";
|
|
7
|
+
import routerProvider, {
|
|
8
|
+
NavigateToResource,
|
|
9
|
+
CatchAllNavigate,
|
|
10
|
+
UnsavedChangesNotifier,
|
|
11
|
+
} from "@refinedev/react-router";
|
|
12
|
+
import {
|
|
13
|
+
BlogPostList,
|
|
14
|
+
BlogPostCreate,
|
|
15
|
+
BlogPostEdit,
|
|
16
|
+
BlogPostShow,
|
|
17
|
+
} from "./pages/blog-posts";
|
|
18
|
+
import {
|
|
19
|
+
CategoryList,
|
|
20
|
+
CategoryCreate,
|
|
21
|
+
CategoryEdit,
|
|
22
|
+
CategoryShow,
|
|
23
|
+
} from "./pages/categories";
|
|
24
|
+
import { dataProvider } from "./providers/data";
|
|
25
|
+
import { Login } from "./pages/login";
|
|
26
|
+
import { Register } from "./pages/register";
|
|
27
|
+
import { ForgotPassword } from "./pages/forgot-password";
|
|
28
|
+
import { ErrorComponent } from "./components/app-shell/error-component";
|
|
29
|
+
import { Layout } from "./components/app-shell/layout";
|
|
30
|
+
import { DocumentTitleHandler } from "./components/app-shell/document-title-handler";
|
|
31
|
+
import { useNotificationProvider } from "./components/notifications/use-notification-provider";
|
|
32
|
+
import { Toaster } from "./components/notifications/toaster";
|
|
33
|
+
import { ThemeProvider } from "./components/theme/theme-provider";
|
|
34
|
+
import { TooltipProvider } from "./components/ui/tooltip";
|
|
35
|
+
import { BrandLogo } from "./components/app-shell/brand";
|
|
36
|
+
import "./App.css";
|
|
37
|
+
import { authProvider } from "./providers/auth";
|
|
38
|
+
import { FileText, Tags } from "lucide-react";
|
|
39
|
+
|
|
40
|
+
const basename = import.meta.env.BASE_URL.replace(/\/+$/, "");
|
|
41
|
+
|
|
42
|
+
function App() {
|
|
43
|
+
return (
|
|
44
|
+
<BrowserRouter basename={basename || undefined}>
|
|
45
|
+
<ThemeProvider>
|
|
46
|
+
<TooltipProvider>
|
|
47
|
+
<Refine
|
|
48
|
+
dataProvider={dataProvider}
|
|
49
|
+
notificationProvider={useNotificationProvider()}
|
|
50
|
+
routerProvider={routerProvider}
|
|
51
|
+
authProvider={authProvider}
|
|
52
|
+
resources={[
|
|
53
|
+
{
|
|
54
|
+
name: "blog_posts",
|
|
55
|
+
list: "/blog-posts",
|
|
56
|
+
create: "/blog-posts/create",
|
|
57
|
+
edit: "/blog-posts/edit/:id",
|
|
58
|
+
show: "/blog-posts/show/:id",
|
|
59
|
+
meta: {
|
|
60
|
+
label: "Blog posts",
|
|
61
|
+
icon: <FileText />,
|
|
62
|
+
description:
|
|
63
|
+
"Create and publish content on a reliable NocoBase data foundation.",
|
|
64
|
+
canCreate: true,
|
|
65
|
+
canDelete: true,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "categories",
|
|
70
|
+
list: "/categories",
|
|
71
|
+
create: "/categories/create",
|
|
72
|
+
edit: "/categories/edit/:id",
|
|
73
|
+
show: "/categories/show/:id",
|
|
74
|
+
meta: {
|
|
75
|
+
label: "Categories",
|
|
76
|
+
icon: <Tags />,
|
|
77
|
+
description:
|
|
78
|
+
"Organize reusable structures while NocoBase keeps the underlying data consistent.",
|
|
79
|
+
canCreate: true,
|
|
80
|
+
canDelete: true,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
]}
|
|
84
|
+
options={{
|
|
85
|
+
syncWithLocation: true,
|
|
86
|
+
warnWhenUnsavedChanges: true,
|
|
87
|
+
disableTelemetry: true,
|
|
88
|
+
title: {
|
|
89
|
+
text: "NocoBase",
|
|
90
|
+
icon: <BrandLogo className="size-14 rounded-2xl" />,
|
|
91
|
+
},
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
<Routes>
|
|
95
|
+
<Route
|
|
96
|
+
element={
|
|
97
|
+
<Authenticated
|
|
98
|
+
key="authenticated-inner"
|
|
99
|
+
fallback={<CatchAllNavigate to="/login" />}
|
|
100
|
+
>
|
|
101
|
+
<Layout>
|
|
102
|
+
<Outlet />
|
|
103
|
+
</Layout>
|
|
104
|
+
</Authenticated>
|
|
105
|
+
}
|
|
106
|
+
>
|
|
107
|
+
<Route
|
|
108
|
+
index
|
|
109
|
+
element={<NavigateToResource resource="blog_posts" />}
|
|
110
|
+
/>
|
|
111
|
+
<Route path="/blog-posts">
|
|
112
|
+
<Route index element={<BlogPostList />} />
|
|
113
|
+
<Route path="create" element={<BlogPostCreate />} />
|
|
114
|
+
<Route path="edit/:id" element={<BlogPostEdit />} />
|
|
115
|
+
<Route path="show/:id" element={<BlogPostShow />} />
|
|
116
|
+
</Route>
|
|
117
|
+
<Route path="/categories">
|
|
118
|
+
<Route index element={<CategoryList />} />
|
|
119
|
+
<Route path="create" element={<CategoryCreate />} />
|
|
120
|
+
<Route path="edit/:id" element={<CategoryEdit />} />
|
|
121
|
+
<Route path="show/:id" element={<CategoryShow />} />
|
|
122
|
+
</Route>
|
|
123
|
+
<Route path="*" element={<ErrorComponent />} />
|
|
124
|
+
</Route>
|
|
125
|
+
<Route
|
|
126
|
+
element={
|
|
127
|
+
<Authenticated
|
|
128
|
+
key="authenticated-outer"
|
|
129
|
+
fallback={<Outlet />}
|
|
130
|
+
>
|
|
131
|
+
<NavigateToResource />
|
|
132
|
+
</Authenticated>
|
|
133
|
+
}
|
|
134
|
+
>
|
|
135
|
+
<Route path="/login" element={<Login />} />
|
|
136
|
+
<Route path="/register" element={<Register />} />
|
|
137
|
+
<Route path="/forgot-password" element={<ForgotPassword />} />
|
|
138
|
+
</Route>
|
|
139
|
+
</Routes>
|
|
140
|
+
|
|
141
|
+
<Toaster />
|
|
142
|
+
<UnsavedChangesNotifier />
|
|
143
|
+
<DocumentTitleHandler appName="NocoBase" />
|
|
144
|
+
</Refine>
|
|
145
|
+
</TooltipProvider>
|
|
146
|
+
</ThemeProvider>
|
|
147
|
+
</BrowserRouter>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default App;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { assetUrl, cn } from "@/lib/utils";
|
|
2
|
+
|
|
3
|
+
type BrandLogoProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function BrandLogo({ className }: BrandLogoProps) {
|
|
8
|
+
return (
|
|
9
|
+
<span
|
|
10
|
+
className={cn(
|
|
11
|
+
"inline-flex size-10 shrink-0 items-center justify-center overflow-hidden",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
>
|
|
15
|
+
<img
|
|
16
|
+
src={assetUrl("/logo-mark.png")}
|
|
17
|
+
alt=""
|
|
18
|
+
className="size-full object-contain dark:hidden"
|
|
19
|
+
/>
|
|
20
|
+
<img
|
|
21
|
+
src={assetUrl("/logo-mark-dark.png")}
|
|
22
|
+
alt=""
|
|
23
|
+
className="hidden size-full object-contain dark:block"
|
|
24
|
+
/>
|
|
25
|
+
</span>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function BrandWordmark({ className }: BrandLogoProps) {
|
|
30
|
+
return (
|
|
31
|
+
<span
|
|
32
|
+
className={cn(
|
|
33
|
+
"inline-flex h-8 shrink-0 items-center overflow-hidden",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
<img
|
|
38
|
+
src={assetUrl("/logo.png")}
|
|
39
|
+
alt="NocoBase"
|
|
40
|
+
className="h-full w-auto object-contain dark:hidden"
|
|
41
|
+
/>
|
|
42
|
+
<img
|
|
43
|
+
src={assetUrl("/logo-dark.png")}
|
|
44
|
+
alt="NocoBase"
|
|
45
|
+
className="hidden h-full w-auto object-contain dark:block"
|
|
46
|
+
/>
|
|
47
|
+
</span>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
type BrandProps = {
|
|
51
|
+
className?: string;
|
|
52
|
+
logoClassName?: string;
|
|
53
|
+
showText?: boolean;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export function Brand({
|
|
57
|
+
className,
|
|
58
|
+
logoClassName,
|
|
59
|
+
showText = true,
|
|
60
|
+
}: BrandProps) {
|
|
61
|
+
return (
|
|
62
|
+
<div className={cn("flex min-w-0 items-center", className)}>
|
|
63
|
+
{showText ? (
|
|
64
|
+
<BrandWordmark className={logoClassName} />
|
|
65
|
+
) : (
|
|
66
|
+
<BrandLogo className={logoClassName} />
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|