canx-starter-admin 1.0.0 → 1.1.1

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.
@@ -1,49 +1,11 @@
1
- import { BaseController, Controller, Get, Post } from 'canxjs';
2
- import { renderPage, jsx } from 'canxjs';
1
+ import { BaseController, Controller, Get, Post, View } from 'canxjs';
2
+ import { Login } from '../views/auth/Login';
3
3
 
4
4
  @Controller('/auth')
5
5
  export class AuthController extends BaseController {
6
6
  @Get('/login')
7
7
  login() {
8
- const html = renderPage(
9
- jsx('div', { className: 'min-h-screen bg-gray-100 flex items-center justify-center p-4' },
10
- jsx('div', { className: 'bg-white rounded-2xl shadow-xl p-8 w-full max-w-md' },
11
- jsx('div', { className: 'text-center mb-8' },
12
- jsx('h1', { className: 'text-2xl font-bold text-gray-900' }, 'Admin Login'),
13
- jsx('p', { className: 'text-gray-500 mt-2' }, 'Sign in to access the dashboard')
14
- ),
15
- jsx('form', { action: '/auth/login', method: 'POST', className: 'space-y-4' },
16
- jsx('div', {},
17
- jsx('label', { className: 'block text-sm font-medium text-gray-700 mb-2' }, 'Email'),
18
- jsx('input', {
19
- type: 'email',
20
- name: 'email',
21
- className: 'w-full px-4 py-3 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500',
22
- placeholder: 'admin@example.com',
23
- required: true
24
- })
25
- ),
26
- jsx('div', {},
27
- jsx('label', { className: 'block text-sm font-medium text-gray-700 mb-2' }, 'Password'),
28
- jsx('input', {
29
- type: 'password',
30
- name: 'password',
31
- className: 'w-full px-4 py-3 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500',
32
- placeholder: '••••••••',
33
- required: true
34
- })
35
- ),
36
- jsx('button', {
37
- type: 'submit',
38
- className: 'w-full py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium'
39
- }, 'Sign In')
40
- )
41
- )
42
- ),
43
- { title: 'Login - Admin' }
44
- );
45
-
46
- return this.response.html(html);
8
+ return View(Login);
47
9
  }
48
10
 
49
11
  @Post('/login')
@@ -1,5 +1,5 @@
1
- import { BaseController, Controller, Get } from 'canxjs';
2
- import { adminLayout } from '../views/layouts/admin';
1
+ import { BaseController, Controller, Get, View } from 'canxjs';
2
+ import { Dashboard } from '../views/Dashboard';
3
3
 
4
4
  @Controller('/')
5
5
  export class DashboardController extends BaseController {
@@ -12,99 +12,9 @@ export class DashboardController extends BaseController {
12
12
  growth: '+12.5%'
13
13
  };
14
14
 
15
- const recentActivity = [
16
- { id: 1, action: 'New user registered', user: 'john@example.com', time: '5 min ago' },
17
- { id: 2, action: 'Order completed', user: 'jane@example.com', time: '12 min ago' },
18
- { id: 3, action: 'Payment received', user: 'bob@example.com', time: '1 hour ago' },
19
- ];
15
+ // User mock - in real app would come from auth
16
+ const user = { name: "Admin", email: "admin@canx.app" };
20
17
 
21
- const html = adminLayout({
22
- title: 'Dashboard',
23
- content: `
24
- <div class="mb-8">
25
- <h1 class="text-3xl font-bold text-gray-900">Dashboard</h1>
26
- <p class="text-gray-500">Welcome back, Admin!</p>
27
- </div>
28
-
29
- <!-- Stats Grid -->
30
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
31
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
32
- <div class="flex items-center justify-between">
33
- <div>
34
- <p class="text-sm font-medium text-gray-500">Total Users</p>
35
- <p class="text-2xl font-bold text-gray-900">${stats.users}</p>
36
- </div>
37
- <div class="p-3 bg-blue-100 rounded-lg">
38
- <svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
39
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
40
- </svg>
41
- </div>
42
- </div>
43
- </div>
44
-
45
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
46
- <div class="flex items-center justify-between">
47
- <div>
48
- <p class="text-sm font-medium text-gray-500">Total Orders</p>
49
- <p class="text-2xl font-bold text-gray-900">${stats.orders}</p>
50
- </div>
51
- <div class="p-3 bg-green-100 rounded-lg">
52
- <svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
53
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
54
- </svg>
55
- </div>
56
- </div>
57
- </div>
58
-
59
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
60
- <div class="flex items-center justify-between">
61
- <div>
62
- <p class="text-sm font-medium text-gray-500">Revenue</p>
63
- <p class="text-2xl font-bold text-gray-900">${stats.revenue}</p>
64
- </div>
65
- <div class="p-3 bg-purple-100 rounded-lg">
66
- <svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
67
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
68
- </svg>
69
- </div>
70
- </div>
71
- </div>
72
-
73
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
74
- <div class="flex items-center justify-between">
75
- <div>
76
- <p class="text-sm font-medium text-gray-500">Growth</p>
77
- <p class="text-2xl font-bold text-green-600">${stats.growth}</p>
78
- </div>
79
- <div class="p-3 bg-emerald-100 rounded-lg">
80
- <svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
81
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
82
- </svg>
83
- </div>
84
- </div>
85
- </div>
86
- </div>
87
-
88
- <!-- Recent Activity -->
89
- <div class="bg-white rounded-xl shadow-sm border border-gray-100">
90
- <div class="p-6 border-b border-gray-100">
91
- <h2 class="text-lg font-semibold text-gray-900">Recent Activity</h2>
92
- </div>
93
- <div class="divide-y divide-gray-100">
94
- ${recentActivity.map(item => `
95
- <div class="p-4 flex items-center justify-between hover:bg-gray-50">
96
- <div>
97
- <p class="font-medium text-gray-900">${item.action}</p>
98
- <p class="text-sm text-gray-500">${item.user}</p>
99
- </div>
100
- <span class="text-sm text-gray-400">${item.time}</span>
101
- </div>
102
- `).join('')}
103
- </div>
104
- </div>
105
- `
106
- });
107
-
108
- return this.response.html(html);
18
+ return View(Dashboard, { user, stats });
109
19
  }
110
20
  }
@@ -0,0 +1,28 @@
1
+ import { BaseController, Controller, Get, View } from 'canxjs';
2
+ import { Placeholder } from '../views/Placeholder';
3
+
4
+ const user = { name: "Admin", email: "admin@canx.app" };
5
+
6
+ @Controller('/products')
7
+ export class ProductsController extends BaseController {
8
+ @Get('/')
9
+ index() { return View(Placeholder, { title: 'Products', user }); }
10
+ }
11
+
12
+ @Controller('/orders')
13
+ export class OrdersController extends BaseController {
14
+ @Get('/')
15
+ index() { return View(Placeholder, { title: 'Orders', user }); }
16
+ }
17
+
18
+ @Controller('/analytics')
19
+ export class AnalyticsController extends BaseController {
20
+ @Get('/')
21
+ index() { return View(Placeholder, { title: 'Analytics', user }); }
22
+ }
23
+
24
+ @Controller('/settings')
25
+ export class SettingsController extends BaseController {
26
+ @Get('/')
27
+ index() { return View(Placeholder, { title: 'Settings', user }); }
28
+ }
@@ -0,0 +1,22 @@
1
+ import { BaseController, Controller, Get, Post, View } from 'canxjs';
2
+ import { Profile } from '../views/Profile';
3
+
4
+ @Controller('/profile')
5
+ export class ProfileController extends BaseController {
6
+ @Get('/')
7
+ edit() {
8
+ // Mock user for admin
9
+ const user = { name: "Admin User", email: "admin@canx.app" };
10
+ return View(Profile, { user });
11
+ }
12
+
13
+ @Post('/')
14
+ update() {
15
+ return this.response.redirect('/profile');
16
+ }
17
+
18
+ @Post('/password')
19
+ updatePassword() {
20
+ return this.response.redirect('/profile');
21
+ }
22
+ }
@@ -1,5 +1,5 @@
1
- import { BaseController, Controller, Get, Post } from 'canxjs';
2
- import { adminLayout } from '../views/layouts/admin';
1
+ import { BaseController, Controller, Get, Post, View } from 'canxjs';
2
+ import { Users } from '../views/Users';
3
3
 
4
4
  // Mock users data
5
5
  const users = [
@@ -14,165 +14,13 @@ const users = [
14
14
  export class UserController extends BaseController {
15
15
  @Get('/')
16
16
  index() {
17
- const html = adminLayout({
18
- title: 'Users',
19
- content: `
20
- <div class="flex items-center justify-between mb-8">
21
- <div>
22
- <h1 class="text-3xl font-bold text-gray-900">Users</h1>
23
- <p class="text-gray-500">Manage your users and their roles</p>
24
- </div>
25
- <a href="/users/create" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center gap-2">
26
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
27
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
28
- </svg>
29
- Add User
30
- </a>
31
- </div>
32
-
33
- <!-- Data Table -->
34
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
35
- <div class="p-4 border-b border-gray-100 flex items-center justify-between">
36
- <div class="relative">
37
- <input type="text" placeholder="Search users..." class="pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent w-64">
38
- <svg class="w-5 h-5 text-gray-400 absolute left-3 top-2.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
39
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
40
- </svg>
41
- </div>
42
- <div class="flex items-center gap-2">
43
- <select class="px-3 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
44
- <option>All Roles</option>
45
- <option>Admin</option>
46
- <option>Editor</option>
47
- <option>User</option>
48
- </select>
49
- </div>
50
- </div>
51
-
52
- <table class="w-full">
53
- <thead class="bg-gray-50">
54
- <tr>
55
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
56
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
57
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
58
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Created</th>
59
- <th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
60
- </tr>
61
- </thead>
62
- <tbody class="divide-y divide-gray-100">
63
- ${users.map(user => `
64
- <tr class="hover:bg-gray-50">
65
- <td class="px-6 py-4 whitespace-nowrap">
66
- <div class="flex items-center">
67
- <div class="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white font-medium">
68
- ${user.name.charAt(0)}
69
- </div>
70
- <div class="ml-3">
71
- <p class="font-medium text-gray-900">${user.name}</p>
72
- <p class="text-sm text-gray-500">${user.email}</p>
73
- </div>
74
- </div>
75
- </td>
76
- <td class="px-6 py-4 whitespace-nowrap">
77
- <span class="px-2 py-1 text-xs font-medium rounded-full ${
78
- user.role === 'Admin' ? 'bg-purple-100 text-purple-700' :
79
- user.role === 'Editor' ? 'bg-blue-100 text-blue-700' :
80
- 'bg-gray-100 text-gray-700'
81
- }">${user.role}</span>
82
- </td>
83
- <td class="px-6 py-4 whitespace-nowrap">
84
- <span class="flex items-center gap-1.5">
85
- <span class="w-2 h-2 rounded-full ${user.status === 'Active' ? 'bg-green-500' : 'bg-gray-400'}"></span>
86
- <span class="text-sm text-gray-600">${user.status}</span>
87
- </span>
88
- </td>
89
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${user.createdAt}</td>
90
- <td class="px-6 py-4 whitespace-nowrap text-right">
91
- <div class="flex items-center justify-end gap-2">
92
- <a href="/users/${user.id}/edit" class="p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-colors">
93
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
94
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
95
- </svg>
96
- </a>
97
- <button class="p-2 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors">
98
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
99
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
100
- </svg>
101
- </button>
102
- </div>
103
- </td>
104
- </tr>
105
- `).join('')}
106
- </tbody>
107
- </table>
108
-
109
- <!-- Pagination -->
110
- <div class="px-6 py-4 border-t border-gray-100 flex items-center justify-between">
111
- <p class="text-sm text-gray-500">Showing 1 to 5 of 5 results</p>
112
- <div class="flex items-center gap-1">
113
- <button class="px-3 py-1 text-sm text-gray-500 hover:bg-gray-100 rounded-lg">Previous</button>
114
- <button class="px-3 py-1 text-sm bg-blue-600 text-white rounded-lg">1</button>
115
- <button class="px-3 py-1 text-sm text-gray-500 hover:bg-gray-100 rounded-lg">Next</button>
116
- </div>
117
- </div>
118
- </div>
119
- `
120
- });
121
-
122
- return this.response.html(html);
17
+ return View(Users, { users });
123
18
  }
124
19
 
125
20
  @Get('/create')
126
21
  create() {
127
- const html = adminLayout({
128
- title: 'Add User',
129
- content: `
130
- <div class="mb-8">
131
- <a href="/users" class="text-blue-600 hover:text-blue-700 flex items-center gap-1 text-sm mb-2">
132
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
133
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
134
- </svg>
135
- Back to Users
136
- </a>
137
- <h1 class="text-3xl font-bold text-gray-900">Add New User</h1>
138
- </div>
139
-
140
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 max-w-2xl">
141
- <form action="/users" method="POST" class="space-y-6">
142
- <div>
143
- <label class="block text-sm font-medium text-gray-700 mb-2">Full Name</label>
144
- <input type="text" name="name" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" required>
145
- </div>
146
-
147
- <div>
148
- <label class="block text-sm font-medium text-gray-700 mb-2">Email</label>
149
- <input type="email" name="email" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" required>
150
- </div>
151
-
152
- <div>
153
- <label class="block text-sm font-medium text-gray-700 mb-2">Role</label>
154
- <select name="role" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
155
- <option value="User">User</option>
156
- <option value="Editor">Editor</option>
157
- <option value="Admin">Admin</option>
158
- </select>
159
- </div>
160
-
161
- <div>
162
- <label class="block text-sm font-medium text-gray-700 mb-2">Password</label>
163
- <input type="password" name="password" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" required>
164
- </div>
165
-
166
- <div class="flex items-center justify-end gap-4 pt-4 border-t border-gray-100">
167
- <a href="/users" class="px-4 py-2 text-gray-600 hover:text-gray-800">Cancel</a>
168
- <button type="submit" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Create User</button>
169
- </div>
170
- </form>
171
- </div>
172
- `
173
- });
174
-
175
- return this.response.html(html);
22
+ // Placeholder for create view
23
+ return this.response.html("<h1>Create User (Coming Soon)</h1>");
176
24
  }
177
25
 
178
26
  @Post('/')