@kyro-cms/admin 0.1.6 → 0.1.8
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/README.md +149 -51
- package/package.json +54 -5
- package/src/collections/auth/index.ts +2 -2
- package/src/collections/portfolio/index.ts +343 -0
- package/src/components/ActionBar.tsx +153 -16
- package/src/components/Admin.tsx +137 -28
- package/src/components/ApiExplorer.tsx +325 -0
- package/src/components/ApiKeysManager.tsx +563 -0
- package/src/components/AuditLogsPage.tsx +664 -0
- package/src/components/AutoForm.tsx +2155 -770
- package/src/components/BrandingHub.tsx +267 -0
- package/src/components/BulkActionsBar.tsx +3 -3
- package/src/components/CreateView.tsx +4 -4
- package/src/components/Dashboard.tsx +393 -0
- package/src/components/DetailView.tsx +200 -58
- package/src/components/DeveloperCenter.tsx +403 -0
- package/src/components/EnhancedListView.tsx +890 -0
- package/src/components/GraphQLExplorer.tsx +675 -0
- package/src/components/GraphQLPlayground.tsx +627 -0
- package/src/components/ListView.tsx +192 -54
- package/src/components/MediaGallery.tsx +1569 -0
- package/src/components/Modal.tsx +206 -0
- package/src/components/RestPlayground.tsx +951 -0
- package/src/components/Sidebar.astro +237 -0
- package/src/components/ThemeProvider.tsx +8 -2
- package/src/components/UserManagement.tsx +204 -0
- package/src/components/VersionHistoryPanel.tsx +3 -3
- package/src/components/WebhookManager.tsx +608 -0
- package/src/components/blocks/AccordionBlock.tsx +65 -0
- package/src/components/blocks/ArrayBlock.tsx +84 -0
- package/src/components/blocks/BlockEditModal.tsx +363 -0
- package/src/components/blocks/ButtonBlock.tsx +64 -0
- package/src/components/blocks/ChildBlocksTree.tsx +551 -0
- package/src/components/blocks/CodeBlock.tsx +114 -0
- package/src/components/blocks/ColumnsBlock.tsx +93 -0
- package/src/components/blocks/DividerBlock.tsx +43 -0
- package/src/components/blocks/FileBlock.tsx +63 -0
- package/src/components/blocks/HeadingBlock.tsx +59 -0
- package/src/components/blocks/HeroBlock.tsx +99 -0
- package/src/components/blocks/ImageBlock.tsx +82 -0
- package/src/components/blocks/LinkBlock.tsx +65 -0
- package/src/components/blocks/ListBlock.tsx +60 -0
- package/src/components/blocks/ParagraphBlock.tsx +61 -0
- package/src/components/blocks/RelationshipBlock.tsx +72 -0
- package/src/components/blocks/RichTextBlock.tsx +66 -0
- package/src/components/blocks/VStackBlock.tsx +61 -0
- package/src/components/blocks/VideoBlock.tsx +65 -0
- package/src/components/blocks/index.ts +10 -0
- package/src/components/fields/AccordionField.tsx +213 -0
- package/src/components/fields/ArrayField.tsx +241 -0
- package/src/components/fields/BlocksField.tsx +323 -0
- package/src/components/fields/ButtonField.tsx +53 -0
- package/src/components/fields/CheckboxField.tsx +18 -8
- package/src/components/fields/ChildrenField.tsx +48 -0
- package/src/components/fields/CodeField.tsx +294 -0
- package/src/components/fields/ColumnsField.tsx +137 -0
- package/src/components/fields/DateField.tsx +24 -12
- package/src/components/fields/EditorClient.tsx +537 -0
- package/src/components/fields/HeadingField.tsx +31 -0
- package/src/components/fields/HeroField.tsx +101 -0
- package/src/components/fields/JSONField.tsx +341 -0
- package/src/components/fields/LinkField.tsx +81 -0
- package/src/components/fields/ListField.tsx +74 -0
- package/src/components/fields/MarkdownField.tsx +260 -0
- package/src/components/fields/NumberField.tsx +25 -13
- package/src/components/fields/PortableTextField.tsx +155 -0
- package/src/components/fields/PortableTextRenderer.tsx +68 -0
- package/src/components/fields/RelationshipBlockField.tsx +233 -0
- package/src/components/fields/RelationshipField.tsx +278 -60
- package/src/components/fields/SelectField.tsx +28 -16
- package/src/components/fields/TextField.tsx +31 -15
- package/src/components/fields/UploadField.tsx +613 -0
- package/src/components/fields/VideoField.tsx +73 -0
- package/src/components/fields/extensions/blockComponents.tsx +247 -0
- package/src/components/fields/extensions/blocksStore.ts +273 -0
- package/src/components/fields/index.ts +24 -0
- package/src/components/index.ts +1 -2
- package/src/components/layout/Header.tsx +2 -2
- package/src/components/layout/Layout.tsx +3 -3
- package/src/components/ui/Badge.tsx +9 -4
- package/src/components/ui/BlockDrawer.tsx +79 -0
- package/src/components/ui/Button.tsx +1 -1
- package/src/components/ui/CommandPalette.tsx +362 -0
- package/src/components/ui/CommandPaletteWrapper.tsx +97 -0
- package/src/components/ui/Dropdown.tsx +1 -1
- package/src/components/ui/Modal.tsx +37 -12
- package/src/components/ui/PromptModal.tsx +94 -0
- package/src/components/ui/SlidePanel.tsx +43 -16
- package/src/components/ui/Toast.tsx +80 -14
- package/src/env.d.ts +16 -0
- package/src/env.ts +20 -0
- package/src/index.ts +0 -1
- package/src/layouts/AdminLayout.astro +164 -170
- package/src/layouts/AuthLayout.astro +23 -6
- package/src/lib/MediaService.ts +541 -0
- package/src/lib/api.ts +163 -0
- package/src/lib/auth/sqlite-adapter.ts +319 -0
- package/src/lib/config.ts +23 -7
- package/src/lib/dataStore.ts +188 -73
- package/src/lib/date-utils.ts +69 -0
- package/src/lib/db/adapter.ts +54 -0
- package/src/lib/db/drizzle-mysql-adapter.ts +194 -0
- package/src/lib/db/drizzle-mysql-auth-adapter.ts +327 -0
- package/src/lib/db/drizzle-postgres-adapter.ts +202 -0
- package/src/lib/db/drizzle-postgres-auth-adapter.ts +304 -0
- package/src/lib/db/drizzle-sqlite-adapter.ts +227 -0
- package/src/lib/db/drizzle-sqlite-auth-adapter.ts +548 -0
- package/src/lib/db/index.ts +449 -0
- package/src/lib/db/mongodb-adapter.ts +207 -0
- package/src/lib/db/mongodb-auth-adapter.ts +305 -0
- package/src/lib/db/schema/mysql-auth.ts +113 -0
- package/src/lib/db/schema/mysql-content.ts +20 -0
- package/src/lib/db/schema/postgres-auth.ts +116 -0
- package/src/lib/db/schema/postgres-content.ts +35 -0
- package/src/lib/db/schema/postgres-media.ts +52 -0
- package/src/lib/db/schema/postgres-settings.ts +11 -0
- package/src/lib/db/schema/sqlite-auth.ts +112 -0
- package/src/lib/db/schema/sqlite-content.ts +20 -0
- package/src/lib/db/version-adapter.ts +248 -0
- package/src/lib/graphql/index.ts +1 -0
- package/src/lib/graphql/schema.ts +443 -0
- package/src/lib/i18n.tsx +353 -0
- package/src/lib/rate-limit.ts +267 -0
- package/src/lib/slugify.ts +15 -0
- package/src/lib/storage.ts +374 -0
- package/src/lib/store.ts +85 -0
- package/src/lib/validation.ts +250 -0
- package/src/middleware.ts +70 -11
- package/src/pages/[collection]/[id].astro +178 -122
- package/src/pages/[collection]/index.astro +24 -156
- package/src/pages/admin/api-explorer.astro +98 -0
- package/src/pages/admin/graphql-explorer.astro +40 -0
- package/src/pages/admin/graphql.astro +97 -0
- package/src/pages/admin/index.astro +200 -139
- package/src/pages/admin/keys.astro +8 -0
- package/src/pages/admin/rest-playground.astro +44 -0
- package/src/pages/admin/webhooks.astro +8 -0
- package/src/pages/api/[collection]/[id]/publish.ts +52 -0
- package/src/pages/api/[collection]/[id]/unpublish.ts +42 -0
- package/src/pages/api/[collection]/[id]/versions.ts +66 -0
- package/src/pages/api/[collection]/[id].ts +114 -159
- package/src/pages/api/[collection]/index.ts +150 -230
- package/src/pages/api/auth/[id].ts +48 -69
- package/src/pages/api/auth/audit-logs.ts +20 -43
- package/src/pages/api/auth/login.ts +159 -45
- package/src/pages/api/auth/logout.ts +42 -24
- package/src/pages/api/auth/refresh.ts +119 -0
- package/src/pages/api/auth/register.ts +110 -40
- package/src/pages/api/auth/users.ts +22 -97
- package/src/pages/api/collections.ts +59 -0
- package/src/pages/api/globals/[slug]/test.ts +172 -0
- package/src/pages/api/globals/[slug].ts +42 -0
- package/src/pages/api/graphql.ts +90 -0
- package/src/pages/api/health.ts +417 -40
- package/src/pages/api/keys/[id].ts +26 -0
- package/src/pages/api/keys/index.ts +75 -0
- package/src/pages/api/media/[id].ts +309 -0
- package/src/pages/api/media/folders.ts +609 -0
- package/src/pages/api/media/index.ts +146 -0
- package/src/pages/api/media/resize.ts +267 -0
- package/src/pages/api/search.ts +82 -0
- package/src/pages/api/slug-availability.ts +70 -0
- package/src/pages/api/storage-config.ts +20 -0
- package/src/pages/api/storage-status.ts +206 -0
- package/src/pages/api/upload.ts +334 -0
- package/src/pages/api/webhooks/index.ts +71 -0
- package/src/pages/audit/index.astro +2 -104
- package/src/pages/login.astro +11 -11
- package/src/pages/media.astro +10 -0
- package/src/pages/preview/[collection]/[id].astro +178 -0
- package/src/pages/register.astro +13 -13
- package/src/pages/roles/index.astro +21 -21
- package/src/pages/settings/[slug].astro +162 -0
- package/src/pages/settings/index.astro +9 -0
- package/src/pages/users/[id].astro +29 -21
- package/src/pages/users/index.astro +22 -17
- package/src/pages/users/new.astro +18 -17
- package/src/styles/main.css +563 -128
- package/src/components/layout/Sidebar.tsx +0 -497
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@ Admin dashboard for Kyro CMS — a React-based admin interface built with Astro.
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
7
|
+
- **Multi-Database Support** — SQLite, PostgreSQL, MySQL, MongoDB
|
|
8
|
+
- **Authentication** — JWT-based login/logout with auto-selecting auth adapter
|
|
8
9
|
- **Collection Management** — Create, edit, and manage content collections
|
|
9
10
|
- **User Management** — Manage users, roles, and permissions
|
|
10
11
|
- **Settings** — Configure CMS settings, globals, and plugins
|
|
@@ -34,6 +35,9 @@ npm run preview
|
|
|
34
35
|
|
|
35
36
|
# Type check
|
|
36
37
|
npm run check
|
|
38
|
+
|
|
39
|
+
# Run tests
|
|
40
|
+
npm run test:run
|
|
37
41
|
```
|
|
38
42
|
|
|
39
43
|
### Integration with Kyro CMS
|
|
@@ -78,9 +82,85 @@ The admin dashboard is designed to work alongside a Kyro CMS project. In your As
|
|
|
78
82
|
});
|
|
79
83
|
```
|
|
80
84
|
|
|
85
|
+
## Database Configuration
|
|
86
|
+
|
|
87
|
+
The admin supports multiple database backends. The auth system automatically uses the same database as your content data.
|
|
88
|
+
|
|
89
|
+
### SQLite (Default)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# No configuration needed - uses ./data/kyro.db
|
|
93
|
+
DB_TYPE=sqlite
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### PostgreSQL
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
DB_TYPE=postgres
|
|
100
|
+
DB_HOST=localhost
|
|
101
|
+
DB_PORT=5432
|
|
102
|
+
DB_NAME=kyro
|
|
103
|
+
DB_USER=admin
|
|
104
|
+
DB_PASSWORD=secret
|
|
105
|
+
# Or use connection string
|
|
106
|
+
DB_CONNECTION_STRING=postgresql://admin:secret@localhost:5432/kyro
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### MySQL
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
DB_TYPE=mysql
|
|
113
|
+
DB_HOST=localhost
|
|
114
|
+
DB_PORT=3306
|
|
115
|
+
DB_NAME=kyro
|
|
116
|
+
DB_USER=root
|
|
117
|
+
DB_PASSWORD=secret
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### MongoDB
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
DB_TYPE=mongodb
|
|
124
|
+
DB_HOST=localhost
|
|
125
|
+
DB_PORT=27017
|
|
126
|
+
DB_NAME=kyro
|
|
127
|
+
# Or use connection string
|
|
128
|
+
DB_CONNECTION_STRING=mongodb://admin:secret@localhost:27017/kyro
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Connection Pooling
|
|
132
|
+
|
|
133
|
+
For PostgreSQL and MySQL, configure connection pool:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
DB_POOL_MIN=5
|
|
137
|
+
DB_POOL_MAX=20
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Environment Variables
|
|
141
|
+
|
|
142
|
+
| Variable | Description | Default |
|
|
143
|
+
| ------------------------- | --------------------------------------------- | ------------------------- |
|
|
144
|
+
| `DB_TYPE` | Database type (sqlite/postgres/mysql/mongodb) | `sqlite` |
|
|
145
|
+
| `DB_CONNECTION_STRING` | Full connection URI | - |
|
|
146
|
+
| `DB_HOST` | Database host | `localhost` |
|
|
147
|
+
| `DB_PORT` | Database port | 5432/3306/27017 |
|
|
148
|
+
| `DB_NAME` | Database name | `kyro` |
|
|
149
|
+
| `DB_USER` | Database username | - |
|
|
150
|
+
| `DB_PASSWORD` | Database password | - |
|
|
151
|
+
| `DB_POOL_MIN` | Minimum pool connections | 5 |
|
|
152
|
+
| `DB_POOL_MAX` | Maximum pool connections | 20 |
|
|
153
|
+
| `JWT_SECRET` | Secret for signing JWT tokens | `change-me-in-production` |
|
|
154
|
+
| `JWT_EXPIRES_IN` | Token expiration time | `24h` |
|
|
155
|
+
| `KYRO_ALLOW_REGISTRATION` | Allow public registration | `true` |
|
|
156
|
+
|
|
81
157
|
## Authentication
|
|
82
158
|
|
|
83
|
-
|
|
159
|
+
Auth is automatically handled by the adapter matching your `DB_TYPE`:
|
|
160
|
+
|
|
161
|
+
- **SQLite** → Uses SQLiteAuthAdapter (local file-based)
|
|
162
|
+
- **Postgres** → Uses PostgresAuthAdapter (same DB)
|
|
163
|
+
- **MongoDB** → Uses MongoDBAuthAdapter (same DB)
|
|
84
164
|
|
|
85
165
|
### Creating Your First Admin User
|
|
86
166
|
|
|
@@ -89,15 +169,6 @@ The admin uses SQLite for auth by default (stored at `./data/auth.db`). No Redis
|
|
|
89
169
|
3. Register with your email and password
|
|
90
170
|
4. The first user automatically gets the `super_admin` role
|
|
91
171
|
|
|
92
|
-
### Environment Variables
|
|
93
|
-
|
|
94
|
-
| Variable | Description | Default |
|
|
95
|
-
| ------------------------- | ------------------------------------------ | ------------------------- |
|
|
96
|
-
| `JWT_SECRET` | Secret for signing JWT tokens | `change-me-in-production` |
|
|
97
|
-
| `JWT_EXPIRES_IN` | Token expiration time | `24h` |
|
|
98
|
-
| `KYRO_AUTH_DB_PATH` | Path to auth SQLite database | `./data/auth.db` |
|
|
99
|
-
| `KYRO_ALLOW_REGISTRATION` | Allow public registration after first user | `true` |
|
|
100
|
-
|
|
101
172
|
### Auth API Endpoints
|
|
102
173
|
|
|
103
174
|
| Endpoint | Method | Description |
|
|
@@ -114,58 +185,85 @@ The admin uses SQLite for auth by default (stored at `./data/auth.db`). No Redis
|
|
|
114
185
|
```
|
|
115
186
|
admin/
|
|
116
187
|
├── src/
|
|
117
|
-
│ ├──
|
|
118
|
-
│ ├──
|
|
119
|
-
│ │
|
|
120
|
-
│ │
|
|
121
|
-
│ ├──
|
|
122
|
-
│
|
|
123
|
-
├──
|
|
124
|
-
|
|
188
|
+
│ ├── lib/
|
|
189
|
+
│ │ ├── db/ # Database adapters
|
|
190
|
+
│ │ │ ├── adapter.ts # DatabaseAdapter interface
|
|
191
|
+
│ │ │ ├── index.ts # Factory & config
|
|
192
|
+
│ │ │ ├── sqlite-adapter.ts
|
|
193
|
+
│ │ │ ├── postgres-adapter.ts
|
|
194
|
+
│ │ │ ├── mysql-adapter.ts
|
|
195
|
+
│ │ │ ├── mongodb-adapter.ts
|
|
196
|
+
│ │ │ └── mongodb-auth-adapter.ts
|
|
197
|
+
│ │ ├── auth/ # Auth adapter
|
|
198
|
+
│ │ │ └── sqlite-adapter.ts
|
|
199
|
+
│ │ ├── dataStore.ts # Content data wrapper
|
|
200
|
+
│ │ └── config.ts # Collection/global config
|
|
201
|
+
│ ├── components/ # React UI components
|
|
202
|
+
│ ├── pages/ # Astro pages + API routes
|
|
203
|
+
│ │ └── api/ # REST API endpoints
|
|
204
|
+
│ │ └── auth/ # Authentication endpoints
|
|
205
|
+
│ └── collections/ # Auth collection config
|
|
206
|
+
├── test/ # Vitest tests
|
|
207
|
+
├── public/ # Static assets
|
|
208
|
+
└── astro.config.mjs # Astro configuration
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Adapter Architecture
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
215
|
+
│ Application Code │
|
|
216
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
217
|
+
│
|
|
218
|
+
▼
|
|
219
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
220
|
+
│ dataStore.ts (Wrapper) │
|
|
221
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
222
|
+
│
|
|
223
|
+
▼
|
|
224
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
225
|
+
│ db/index.ts (Factory/Registry) │
|
|
226
|
+
│ - Reads DB_TYPE from env │
|
|
227
|
+
│ - Lazy-loads appropriate adapter │
|
|
228
|
+
│ - Auto-selects matching auth adapter │
|
|
229
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
230
|
+
│
|
|
231
|
+
▼
|
|
232
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
233
|
+
│ adapter.ts (DatabaseAdapter Interface) │
|
|
234
|
+
│ - find, findById, create, update, delete │
|
|
235
|
+
│ - findGlobal, updateGlobal, seedGlobal │
|
|
236
|
+
│ - seed, isSeeded, count │
|
|
237
|
+
└─────────────────────────┬───────────────────────────────────┘
|
|
238
|
+
│
|
|
239
|
+
┌─────────────────────┼─────────────────────┐
|
|
240
|
+
▼ ▼ ▼
|
|
241
|
+
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
242
|
+
│ SQLite │ │ PG │ │ MySQL │
|
|
243
|
+
└─────────┘ └─────────┘ └─────────┘
|
|
244
|
+
┌─────────┐
|
|
245
|
+
│ MongoDB │
|
|
246
|
+
└─────────┘
|
|
125
247
|
```
|
|
126
248
|
|
|
127
249
|
## Security
|
|
128
250
|
|
|
129
|
-
- **Password Hashing** — bcryptjs with
|
|
251
|
+
- **Password Hashing** — bcryptjs with 10 salt rounds
|
|
130
252
|
- **JWT Tokens** — Signed tokens with configurable expiration
|
|
131
|
-
- **Session Management** — Server-side session tracking via
|
|
253
|
+
- **Session Management** — Server-side session tracking via DB adapter
|
|
132
254
|
- **Middleware Protection** — All non-auth routes require valid JWT
|
|
133
|
-
- **Password Policy** — Minimum
|
|
255
|
+
- **Password Policy** — Minimum 8 characters
|
|
134
256
|
|
|
135
|
-
##
|
|
136
|
-
|
|
137
|
-
### Default Setup (Single Instance)
|
|
138
|
-
|
|
139
|
-
SQLite auth adapter handles everything in a single `./data/auth.db` file. Perfect for:
|
|
140
|
-
|
|
141
|
-
- Development
|
|
142
|
-
- Small to medium projects
|
|
143
|
-
- Single-server deployments
|
|
144
|
-
|
|
145
|
-
### Multi-Instance / Horizontal Scaling
|
|
146
|
-
|
|
147
|
-
When running multiple Kyro CMS instances behind a load balancer, configure:
|
|
257
|
+
## Testing
|
|
148
258
|
|
|
149
259
|
```bash
|
|
150
|
-
#
|
|
151
|
-
|
|
260
|
+
# Run all tests
|
|
261
|
+
npm run test:run
|
|
152
262
|
|
|
153
|
-
#
|
|
154
|
-
|
|
263
|
+
# Run tests with watch mode
|
|
264
|
+
npm run test
|
|
155
265
|
```
|
|
156
266
|
|
|
157
|
-
### High-Scale Production
|
|
158
|
-
|
|
159
|
-
For high-traffic deployments with many concurrent users:
|
|
160
|
-
|
|
161
|
-
1. **Connection Pooling** — SQLite handles concurrent reads well, but writes are serialized. For write-heavy workloads, consider PostgreSQL with the Drizzle auth adapter.
|
|
162
|
-
|
|
163
|
-
2. **Session Caching** — JWT tokens are self-contained, so session validation doesn't require database reads on every request.
|
|
164
|
-
|
|
165
|
-
3. **Rate Limiting** — Currently in-memory per instance. For distributed rate limiting, use Redis or a shared SQLite file on fast storage.
|
|
166
|
-
|
|
167
|
-
4. **Audit Logs** — Stored in SQLite. For high-volume audit logging, consider exporting to a dedicated log store.
|
|
168
|
-
|
|
169
267
|
## License
|
|
170
268
|
|
|
171
269
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kyro-cms/admin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Admin dashboard for Kyro CMS",
|
|
@@ -20,23 +20,72 @@
|
|
|
20
20
|
"dev": "astro dev",
|
|
21
21
|
"build": "astro build",
|
|
22
22
|
"preview": "astro preview",
|
|
23
|
-
"check": "astro check"
|
|
23
|
+
"check": "astro check",
|
|
24
|
+
"test": "vitest",
|
|
25
|
+
"test:run": "vitest run"
|
|
24
26
|
},
|
|
25
27
|
"dependencies": {
|
|
26
28
|
"@astrojs/node": "^9.5.5",
|
|
27
29
|
"@astrojs/react": "^4.2.0",
|
|
28
|
-
"@
|
|
30
|
+
"@codemirror/lang-cpp": "^6.0.3",
|
|
31
|
+
"@codemirror/lang-css": "^6.3.1",
|
|
32
|
+
"@codemirror/lang-html": "^6.4.11",
|
|
33
|
+
"@codemirror/lang-java": "^6.0.2",
|
|
34
|
+
"@codemirror/lang-javascript": "^6.2.5",
|
|
35
|
+
"@codemirror/lang-json": "^6.0.2",
|
|
36
|
+
"@codemirror/lang-markdown": "^6.5.0",
|
|
37
|
+
"@codemirror/lang-php": "^6.0.2",
|
|
38
|
+
"@codemirror/lang-python": "^6.2.1",
|
|
39
|
+
"@codemirror/lang-rust": "^6.0.2",
|
|
40
|
+
"@codemirror/lang-sql": "^6.10.0",
|
|
41
|
+
"@codemirror/state": "^6.6.0",
|
|
42
|
+
"@codemirror/view": "^6.41.0",
|
|
43
|
+
"@dnd-kit/core": "^6.3.1",
|
|
44
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
45
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
46
|
+
"@graphiql/react": "^0.37.3",
|
|
47
|
+
"@kyro-cms/core": "workspace:*",
|
|
48
|
+
"@kyro-cms/utils": "workspace:*",
|
|
49
|
+
"@platejs/dnd": "^53.0.0",
|
|
50
|
+
"@portabletext/editor": "^6.6.3",
|
|
51
|
+
"@portabletext/react": "^6.0.3",
|
|
52
|
+
"@portabletext/schema": "^2.1.1",
|
|
53
|
+
"@portabletext/toolbar": "^7.0.26",
|
|
54
|
+
"@portabletext/types": "^4.0.2",
|
|
29
55
|
"@tailwindcss/vite": "^4.0.0",
|
|
56
|
+
"@types/pg": "^8.20.0",
|
|
57
|
+
"@udecode/plate-dnd": "^49.0.0",
|
|
58
|
+
"@uiw/codemirror-theme-aura": "^4.25.9",
|
|
59
|
+
"@uiw/codemirror-theme-dracula": "^4.25.9",
|
|
60
|
+
"@uiw/codemirror-theme-github": "^4.25.9",
|
|
61
|
+
"@uiw/react-codemirror": "^4.25.9",
|
|
30
62
|
"astro": "^5.4.0",
|
|
63
|
+
"better-sqlite3": "^11.10.0",
|
|
64
|
+
"drizzle-orm": "^0.45.2",
|
|
65
|
+
"graphiql": "^5.2.2",
|
|
31
66
|
"lucide-react": "^0.475.0",
|
|
67
|
+
"mongodb": "^7.1.1",
|
|
68
|
+
"mysql2": "^3.21.0",
|
|
69
|
+
"pg": "^8.20.0",
|
|
70
|
+
"platejs": "^53.0.0",
|
|
32
71
|
"react": "^19.0.0",
|
|
33
72
|
"react-dom": "^19.0.0",
|
|
34
|
-
"
|
|
73
|
+
"react-image-crop": "^11.0.10",
|
|
74
|
+
"sharp": "^0.34.5",
|
|
75
|
+
"slate": "^0.124.1",
|
|
76
|
+
"slate-history": "^0.113.1",
|
|
77
|
+
"slate-react": "^0.124.0",
|
|
78
|
+
"tailwindcss": "^4.0.0",
|
|
79
|
+
"zustand": "^5.0.3"
|
|
35
80
|
},
|
|
36
81
|
"devDependencies": {
|
|
37
82
|
"@types/react": "^19.0.0",
|
|
38
83
|
"@types/react-dom": "^19.0.0",
|
|
39
|
-
"
|
|
84
|
+
"dotenv": "^17.4.2",
|
|
85
|
+
"dotenv-cli": "^11.0.0",
|
|
86
|
+
"drizzle-kit": "^0.31.10",
|
|
87
|
+
"typescript": "^5.7.0",
|
|
88
|
+
"vitest": "^4.1.4"
|
|
40
89
|
},
|
|
41
90
|
"peerDependencies": {
|
|
42
91
|
"@kyro-cms/core": "^0.1.2"
|
|
@@ -73,7 +73,7 @@ export const rolesCollection: CollectionConfig = {
|
|
|
73
73
|
items: { type: "text" },
|
|
74
74
|
label: "Inherits From",
|
|
75
75
|
},
|
|
76
|
-
{ name: "description", type: "
|
|
76
|
+
{ name: "description", type: "richtext" },
|
|
77
77
|
{
|
|
78
78
|
name: "permissions",
|
|
79
79
|
type: "array",
|
|
@@ -124,7 +124,7 @@ export const auditLogsCollection: CollectionConfig = {
|
|
|
124
124
|
{ name: "ipAddress", type: "text", label: "IP Address" },
|
|
125
125
|
{ name: "userAgent", type: "text", label: "User Agent" },
|
|
126
126
|
{ name: "success", type: "boolean" },
|
|
127
|
-
{ name: "error", type: "
|
|
127
|
+
{ name: "error", type: "richtext" },
|
|
128
128
|
{ name: "metadata", type: "json", label: "Metadata" },
|
|
129
129
|
{ name: "timestamp", type: "datetime", required: true, readonly: true },
|
|
130
130
|
],
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import type { CollectionConfig } from "@kyro-cms/core";
|
|
2
|
+
|
|
3
|
+
export const portfolioCollections: Record<string, CollectionConfig> = {
|
|
4
|
+
projects: {
|
|
5
|
+
slug: "projects",
|
|
6
|
+
label: "Projects",
|
|
7
|
+
labelPlural: "Projects",
|
|
8
|
+
singularLabel: "Project",
|
|
9
|
+
admin: {
|
|
10
|
+
useAsTitle: "title",
|
|
11
|
+
defaultColumns: ["title", "featured", "status", "createdAt"],
|
|
12
|
+
description: "Portfolio projects and case studies",
|
|
13
|
+
},
|
|
14
|
+
fields: [
|
|
15
|
+
{
|
|
16
|
+
name: "title",
|
|
17
|
+
type: "text",
|
|
18
|
+
required: true,
|
|
19
|
+
label: "Title",
|
|
20
|
+
admin: { description: "Project title" },
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "slug",
|
|
24
|
+
type: "text",
|
|
25
|
+
required: true,
|
|
26
|
+
label: "Slug",
|
|
27
|
+
admin: { description: "URL-friendly identifier" },
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "client",
|
|
31
|
+
type: "text",
|
|
32
|
+
label: "Client",
|
|
33
|
+
admin: { description: "Client name" },
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "description",
|
|
37
|
+
type: "richtext",
|
|
38
|
+
label: "Description",
|
|
39
|
+
admin: { description: "Project description" },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "featuredImage",
|
|
43
|
+
type: "upload",
|
|
44
|
+
label: "Featured Image",
|
|
45
|
+
relationTo: "media",
|
|
46
|
+
admin: { description: "Main project image" },
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "gallery",
|
|
50
|
+
type: "array",
|
|
51
|
+
label: "Gallery",
|
|
52
|
+
fields: [
|
|
53
|
+
{
|
|
54
|
+
name: "image",
|
|
55
|
+
type: "upload",
|
|
56
|
+
label: "Image",
|
|
57
|
+
relationTo: "media",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "caption",
|
|
61
|
+
type: "text",
|
|
62
|
+
label: "Caption",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
admin: { description: "Additional project images" },
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "technologies",
|
|
69
|
+
type: "array",
|
|
70
|
+
label: "Technologies",
|
|
71
|
+
fields: [
|
|
72
|
+
{
|
|
73
|
+
name: "name",
|
|
74
|
+
type: "text",
|
|
75
|
+
label: "Technology",
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
admin: { description: "Tools and technologies used" },
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "link",
|
|
82
|
+
type: "text",
|
|
83
|
+
label: "Project URL",
|
|
84
|
+
admin: { description: "Live project link" },
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "github",
|
|
88
|
+
type: "text",
|
|
89
|
+
label: "GitHub URL",
|
|
90
|
+
admin: { description: "Repository link" },
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "featured",
|
|
94
|
+
type: "checkbox",
|
|
95
|
+
label: "Featured",
|
|
96
|
+
defaultValue: false,
|
|
97
|
+
admin: { description: "Show on homepage" },
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "status",
|
|
101
|
+
type: "select",
|
|
102
|
+
label: "Status",
|
|
103
|
+
options: [
|
|
104
|
+
{ label: "Draft", value: "draft" },
|
|
105
|
+
{ label: "Published", value: "published" },
|
|
106
|
+
{ label: "Archived", value: "archived" },
|
|
107
|
+
],
|
|
108
|
+
defaultValue: "draft",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "order",
|
|
112
|
+
type: "number",
|
|
113
|
+
label: "Display Order",
|
|
114
|
+
defaultValue: 0,
|
|
115
|
+
admin: { description: "Sort order" },
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "completedAt",
|
|
119
|
+
type: "date",
|
|
120
|
+
label: "Completed At",
|
|
121
|
+
admin: { description: "Project completion date" },
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
timestamps: true,
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
team: {
|
|
128
|
+
slug: "team",
|
|
129
|
+
label: "Team Members",
|
|
130
|
+
labelPlural: "Team Members",
|
|
131
|
+
singularLabel: "Team Member",
|
|
132
|
+
admin: {
|
|
133
|
+
useAsTitle: "name",
|
|
134
|
+
defaultColumns: ["name", "role", "order", "createdAt"],
|
|
135
|
+
description: "Team members and staff",
|
|
136
|
+
},
|
|
137
|
+
fields: [
|
|
138
|
+
{
|
|
139
|
+
name: "name",
|
|
140
|
+
type: "text",
|
|
141
|
+
required: true,
|
|
142
|
+
label: "Name",
|
|
143
|
+
admin: { description: "Full name" },
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "role",
|
|
147
|
+
type: "text",
|
|
148
|
+
required: true,
|
|
149
|
+
label: "Role",
|
|
150
|
+
admin: { description: "Job title or role" },
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "bio",
|
|
154
|
+
type: "markdown",
|
|
155
|
+
label: "Bio",
|
|
156
|
+
admin: { description: "Short biography" },
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "photo",
|
|
160
|
+
type: "upload",
|
|
161
|
+
label: "Photo",
|
|
162
|
+
relationTo: "media",
|
|
163
|
+
admin: { description: "Profile photo" },
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: "gallery",
|
|
167
|
+
type: "array",
|
|
168
|
+
label: "Gallery",
|
|
169
|
+
fields: [
|
|
170
|
+
{
|
|
171
|
+
name: "image",
|
|
172
|
+
type: "upload",
|
|
173
|
+
label: "Image",
|
|
174
|
+
relationTo: "media",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "caption",
|
|
178
|
+
type: "text",
|
|
179
|
+
label: "Caption",
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
admin: { description: "Additional photos" },
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "email",
|
|
186
|
+
type: "email",
|
|
187
|
+
label: "Email",
|
|
188
|
+
admin: { description: "Contact email" },
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "phone",
|
|
192
|
+
type: "text",
|
|
193
|
+
label: "Phone",
|
|
194
|
+
admin: { description: "Contact phone" },
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "linkedin",
|
|
198
|
+
type: "text",
|
|
199
|
+
label: "LinkedIn",
|
|
200
|
+
admin: { description: "LinkedIn profile URL" },
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: "twitter",
|
|
204
|
+
type: "text",
|
|
205
|
+
label: "Twitter",
|
|
206
|
+
admin: { description: "Twitter handle" },
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "github",
|
|
210
|
+
type: "text",
|
|
211
|
+
label: "GitHub",
|
|
212
|
+
admin: { description: "GitHub profile URL" },
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "website",
|
|
216
|
+
type: "text",
|
|
217
|
+
label: "Website",
|
|
218
|
+
admin: { description: "Personal website" },
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: "order",
|
|
222
|
+
type: "number",
|
|
223
|
+
label: "Display Order",
|
|
224
|
+
defaultValue: 0,
|
|
225
|
+
admin: { description: "Sort order" },
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "status",
|
|
229
|
+
type: "select",
|
|
230
|
+
label: "Status",
|
|
231
|
+
options: [
|
|
232
|
+
{ label: "Active", value: "active" },
|
|
233
|
+
{ label: "Inactive", value: "inactive" },
|
|
234
|
+
],
|
|
235
|
+
defaultValue: "active",
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
timestamps: true,
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
menus: {
|
|
242
|
+
slug: "menus",
|
|
243
|
+
label: "Menus",
|
|
244
|
+
labelPlural: "Menus",
|
|
245
|
+
singularLabel: "Menu",
|
|
246
|
+
admin: {
|
|
247
|
+
useAsTitle: "name",
|
|
248
|
+
defaultColumns: ["name", "location", "createdAt"],
|
|
249
|
+
description: "Navigation menus",
|
|
250
|
+
},
|
|
251
|
+
fields: [
|
|
252
|
+
{
|
|
253
|
+
name: "name",
|
|
254
|
+
type: "text",
|
|
255
|
+
required: true,
|
|
256
|
+
label: "Name",
|
|
257
|
+
admin: { description: "Menu name" },
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: "location",
|
|
261
|
+
type: "select",
|
|
262
|
+
label: "Location",
|
|
263
|
+
required: true,
|
|
264
|
+
options: [
|
|
265
|
+
{ label: "Header", value: "header" },
|
|
266
|
+
{ label: "Footer", value: "footer" },
|
|
267
|
+
{ label: "Mobile", value: "mobile" },
|
|
268
|
+
{ label: "Sidebar", value: "sidebar" },
|
|
269
|
+
],
|
|
270
|
+
admin: { description: "Where to display this menu" },
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: "items",
|
|
274
|
+
type: "array",
|
|
275
|
+
label: "Menu Items",
|
|
276
|
+
admin: { description: "Navigation items" },
|
|
277
|
+
fields: [
|
|
278
|
+
{
|
|
279
|
+
name: "label",
|
|
280
|
+
type: "text",
|
|
281
|
+
label: "Label",
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "url",
|
|
285
|
+
type: "text",
|
|
286
|
+
label: "URL",
|
|
287
|
+
admin: { description: "Link address" },
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: "target",
|
|
291
|
+
type: "select",
|
|
292
|
+
label: "Target",
|
|
293
|
+
options: [
|
|
294
|
+
{ label: "Same tab", value: "_self" },
|
|
295
|
+
{ label: "New tab", value: "_blank" },
|
|
296
|
+
],
|
|
297
|
+
defaultValue: "_self",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "icon",
|
|
301
|
+
type: "text",
|
|
302
|
+
label: "Icon",
|
|
303
|
+
admin: { description: "Icon name" },
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: "order",
|
|
307
|
+
type: "number",
|
|
308
|
+
label: "Order",
|
|
309
|
+
defaultValue: 0,
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: "children",
|
|
313
|
+
type: "array",
|
|
314
|
+
label: "Sub-items",
|
|
315
|
+
fields: [
|
|
316
|
+
{
|
|
317
|
+
name: "label",
|
|
318
|
+
type: "text",
|
|
319
|
+
label: "Label",
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
name: "url",
|
|
323
|
+
type: "text",
|
|
324
|
+
label: "URL",
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
name: "target",
|
|
328
|
+
type: "select",
|
|
329
|
+
label: "Target",
|
|
330
|
+
options: [
|
|
331
|
+
{ label: "Same tab", value: "_self" },
|
|
332
|
+
{ label: "New tab", value: "_blank" },
|
|
333
|
+
],
|
|
334
|
+
defaultValue: "_self",
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
timestamps: true,
|
|
342
|
+
},
|
|
343
|
+
};
|