@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.
Files changed (123) hide show
  1. package/.env.example +10 -0
  2. package/Dockerfile +36 -0
  3. package/README.MD +50 -0
  4. package/components.json +25 -0
  5. package/eslint.config.js +28 -0
  6. package/index.html +39 -0
  7. package/package.json +84 -0
  8. package/pnpm-workspace.yaml +2 -0
  9. package/public/favicon.ico +0 -0
  10. package/public/logo-dark.png +0 -0
  11. package/public/logo-mark-dark.png +0 -0
  12. package/public/logo-mark.png +0 -0
  13. package/public/logo.png +0 -0
  14. package/src/App.css +158 -0
  15. package/src/App.tsx +151 -0
  16. package/src/components/app-shell/brand.tsx +70 -0
  17. package/src/components/app-shell/breadcrumb.tsx +81 -0
  18. package/src/components/app-shell/document-title-handler.tsx +169 -0
  19. package/src/components/app-shell/error-component.tsx +134 -0
  20. package/src/components/app-shell/header.tsx +127 -0
  21. package/src/components/app-shell/layout.tsx +39 -0
  22. package/src/components/app-shell/loading-overlay.tsx +36 -0
  23. package/src/components/app-shell/sidebar.tsx +351 -0
  24. package/src/components/app-shell/user-avatar.tsx +42 -0
  25. package/src/components/app-shell/user-info.tsx +53 -0
  26. package/src/components/auth/auth-layout.tsx +82 -0
  27. package/src/components/auth/forgot-password-form.tsx +58 -0
  28. package/src/components/auth/input-password.tsx +38 -0
  29. package/src/components/auth/sign-in-form.tsx +111 -0
  30. package/src/components/auth/sign-up-form.tsx +127 -0
  31. package/src/components/data-table/data-table-filter.tsx +994 -0
  32. package/src/components/data-table/data-table-pagination.tsx +146 -0
  33. package/src/components/data-table/data-table-sorter.tsx +47 -0
  34. package/src/components/data-table/data-table.tsx +321 -0
  35. package/src/components/notifications/toaster.tsx +23 -0
  36. package/src/components/notifications/undoable-notification.tsx +84 -0
  37. package/src/components/notifications/use-notification-provider.tsx +62 -0
  38. package/src/components/resources/buttons/clone.tsx +81 -0
  39. package/src/components/resources/buttons/create.tsx +70 -0
  40. package/src/components/resources/buttons/delete.tsx +113 -0
  41. package/src/components/resources/buttons/edit.tsx +81 -0
  42. package/src/components/resources/buttons/list.tsx +70 -0
  43. package/src/components/resources/buttons/refresh.tsx +81 -0
  44. package/src/components/resources/buttons/show.tsx +81 -0
  45. package/src/components/resources/status-badge.tsx +37 -0
  46. package/src/components/resources/views/create-view.tsx +81 -0
  47. package/src/components/resources/views/edit-view.tsx +104 -0
  48. package/src/components/resources/views/list-view.tsx +86 -0
  49. package/src/components/resources/views/show-view.tsx +108 -0
  50. package/src/components/theme/theme-provider.tsx +71 -0
  51. package/src/components/theme/theme-select.tsx +97 -0
  52. package/src/components/theme/theme-toggle.tsx +66 -0
  53. package/src/components/ui/accordion.tsx +72 -0
  54. package/src/components/ui/alert-dialog.tsx +185 -0
  55. package/src/components/ui/alert.tsx +76 -0
  56. package/src/components/ui/aspect-ratio.tsx +22 -0
  57. package/src/components/ui/avatar.tsx +107 -0
  58. package/src/components/ui/badge.tsx +52 -0
  59. package/src/components/ui/breadcrumb.tsx +125 -0
  60. package/src/components/ui/button.tsx +58 -0
  61. package/src/components/ui/calendar.tsx +221 -0
  62. package/src/components/ui/card.tsx +103 -0
  63. package/src/components/ui/carousel.tsx +240 -0
  64. package/src/components/ui/chart.tsx +373 -0
  65. package/src/components/ui/checkbox.tsx +29 -0
  66. package/src/components/ui/collapsible.tsx +19 -0
  67. package/src/components/ui/command.tsx +192 -0
  68. package/src/components/ui/context-menu.tsx +271 -0
  69. package/src/components/ui/dialog.tsx +160 -0
  70. package/src/components/ui/drawer.tsx +226 -0
  71. package/src/components/ui/dropdown-menu.tsx +268 -0
  72. package/src/components/ui/form.tsx +174 -0
  73. package/src/components/ui/hover-card.tsx +49 -0
  74. package/src/components/ui/input-group.tsx +158 -0
  75. package/src/components/ui/input-otp.tsx +87 -0
  76. package/src/components/ui/input.tsx +20 -0
  77. package/src/components/ui/label.tsx +18 -0
  78. package/src/components/ui/menubar.tsx +278 -0
  79. package/src/components/ui/navigation-menu.tsx +168 -0
  80. package/src/components/ui/pagination.tsx +130 -0
  81. package/src/components/ui/popover.tsx +91 -0
  82. package/src/components/ui/progress.tsx +81 -0
  83. package/src/components/ui/radio-group.tsx +38 -0
  84. package/src/components/ui/resizable.tsx +48 -0
  85. package/src/components/ui/scroll-area.tsx +55 -0
  86. package/src/components/ui/select.tsx +199 -0
  87. package/src/components/ui/separator.tsx +25 -0
  88. package/src/components/ui/sheet.tsx +136 -0
  89. package/src/components/ui/sidebar.tsx +723 -0
  90. package/src/components/ui/skeleton.tsx +13 -0
  91. package/src/components/ui/slider.tsx +52 -0
  92. package/src/components/ui/sonner.tsx +47 -0
  93. package/src/components/ui/switch.tsx +32 -0
  94. package/src/components/ui/table.tsx +114 -0
  95. package/src/components/ui/tabs.tsx +82 -0
  96. package/src/components/ui/textarea.tsx +18 -0
  97. package/src/components/ui/toggle-group.tsx +87 -0
  98. package/src/components/ui/toggle.tsx +43 -0
  99. package/src/components/ui/tooltip.tsx +66 -0
  100. package/src/hooks/use-mobile.ts +19 -0
  101. package/src/index.tsx +17 -0
  102. package/src/lib/utils.ts +19 -0
  103. package/src/pages/blog-posts/create.tsx +177 -0
  104. package/src/pages/blog-posts/edit.tsx +197 -0
  105. package/src/pages/blog-posts/index.ts +4 -0
  106. package/src/pages/blog-posts/list.tsx +131 -0
  107. package/src/pages/blog-posts/show.tsx +81 -0
  108. package/src/pages/categories/create.tsx +73 -0
  109. package/src/pages/categories/edit.tsx +73 -0
  110. package/src/pages/categories/index.ts +4 -0
  111. package/src/pages/categories/list.tsx +86 -0
  112. package/src/pages/categories/show.tsx +37 -0
  113. package/src/pages/forgot-password/index.tsx +6 -0
  114. package/src/pages/forgotPassword/index.tsx +5 -0
  115. package/src/pages/login/index.tsx +5 -0
  116. package/src/pages/register/index.tsx +5 -0
  117. package/src/providers/auth.ts +204 -0
  118. package/src/providers/constants.ts +75 -0
  119. package/src/providers/data.ts +232 -0
  120. package/src/vite-env.d.ts +1 -0
  121. package/tsconfig.json +25 -0
  122. package/tsconfig.node.json +21 -0
  123. 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
+ ![2026-07-22-08-48-12](https://static-docs.nocobase.com/2026-07-22-08-48-12.png)
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
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ allowBuilds:
2
+ esbuild: true
Binary file
Binary file
Binary file
Binary file
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
+ }