viewlogic 1.2.3 → 1.2.4

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 CHANGED
@@ -12,64 +12,36 @@
12
12
  </a>
13
13
  </p>
14
14
 
15
- > **Complete Vue 3 Framework**: Routing + State Management + Authentication + i18n + Caching + API + Forms
15
+ > **Complete Vue 3 Framework**: All-in-one solution for modern web development
16
16
 
17
- ## 🎯 Core Philosophy: Simplicity Through Design
17
+ ## 🎯 Core Philosophy
18
18
 
19
- ViewLogic Router revolutionizes Vue development with two fundamental core principles:
19
+ ViewLogic Router revolutionizes Vue development with two fundamental principles:
20
20
 
21
21
  ### 🎭 View-Logic Separation
22
- **Complete separation between View (presentation) and Logic (business logic)**. Views are pure HTML templates, logic is pure JavaScript components, making your code more maintainable, testable, and scalable.
22
+ **Complete separation between View (presentation) and Logic (business logic)**. Views are pure HTML templates, logic is pure JavaScript components. This separation makes your code more maintainable, testable, and scalable.
23
23
 
24
24
  ### 🚀 Zero Build Development
25
25
  **Zero build step required in development mode**. Work directly with source files, see changes instantly without any compilation, bundling, or build processes. True real-time development experience.
26
26
 
27
- ## 🚀 Why Choose ViewLogic Router?
27
+ ## What Makes ViewLogic Special
28
28
 
29
- **All-in-One Solution** - Replace 7+ libraries with one unified framework:
30
- - 🔀 **Vue Router** ViewLogic Routing
31
- - 📦 **Pinia/Vuex** StateHandler
32
- - 🔐 **Auth Libraries** AuthManager
33
- - 🌐 **Vue I18n** I18nManager
34
- - 💾 **Cache Libraries** CacheManager
35
- - 🌐 **API Libraries** ApiHandler
36
- - 📝 **Form Libraries** FormHandler
29
+ **All-in-One Solution** - Replace multiple libraries with one unified framework:
30
+ - 🔀 **Routing** - File-based routing with zero configuration
31
+ - 📦 **State Management** - Built-in reactive state without external dependencies
32
+ - 🔐 **Authentication** - JWT auth with multiple storage options
33
+ - 🌐 **Internationalization** - Multi-language support with lazy loading
34
+ - 💾 **Caching** - Smart caching with TTL and LRU eviction
35
+ - 🌐 **API Client** - HTTP client with automatic token injection
36
+ - 📝 **Form Handling** - Revolutionary form processing with parameter substitution
37
37
 
38
- **Tiny Bundle Size** - Complete framework in just 51KB minified / 17KB gzipped!
38
+ **Tiny Bundle Size** - Complete framework in just **51KB minified / 17KB gzipped**!
39
39
 
40
40
  **Easy Integration** - Drop-in UMD build available for instant usage without build tools.
41
41
 
42
- ## ✨ Key Features
43
-
44
- - 🚀 **Ultra-Lightweight** - Complete routing system with zero dependencies and optimized codebase
45
- - 🔄 **Multiple API Support** - Parallel data fetching from multiple APIs with named data storage
46
- - 📝 **Automatic Form Handling** - Revolutionary form submission with `{paramName}` variable parameters
47
- - 🛠️ **Built-in Components** - Preloaded UI components including revolutionary DynamicInclude & HtmlInclude
48
- - 🔗 **Query-Based Parameter System** - Simple query-only parameters (`/users?id=123`) instead of complex path parameters
49
- - ⚡ **Optimized Production** - Pre-built individual route bundles for lightning-fast production
50
- - 📁 **Intuitive Structure** - Organized folder structure for views, logic, styles, layouts, and components
51
- - 💾 **Smart Caching** - Intelligent route and component caching with TTL and LRU eviction
52
- - 🔐 **Authentication** - Built-in JWT auth management with multiple storage options
53
- - 🌐 **i18n Ready** - Built-in internationalization support with lazy loading
54
- - 📊 **State Management** - Reactive state management without external dependencies
55
-
56
- ### What's Included
57
- - ✅ Complete routing system with hash/history mode
58
- - ✅ Advanced caching with TTL and size limits
59
- - ✅ Built-in authentication with multiple storage options
60
- - ✅ Internationalization system with lazy loading
61
- - ✅ Form handling with automatic validation
62
- - ✅ RESTful API client with parameter substitution
63
- - ✅ Component loading and management
64
- - ✅ Error handling and logging system
65
- - ✅ Query parameter management
66
- - ✅ Layout system with slot-based composition
67
- - ✅ Global state management with reactivity
68
- - ✅ Event system for component communication
69
-
70
42
  ## 🏗️ Project Structure
71
43
 
72
- ViewLogic Router follows a clean, intuitive folder structure that promotes maintainability:
44
+ ViewLogic Router follows a clean, intuitive folder structure:
73
45
 
74
46
  ```
75
47
  project/
@@ -88,58 +60,81 @@ project/
88
60
  │ ├── layouts/ # Layout templates
89
61
  │ │ ├── default.html
90
62
  │ │ └── admin.html
91
- ├── styles/ # CSS files
92
- ├── home.css
93
- └── global.css
94
- │ └── locales/ # i18n files (optional)
95
- ├── en.json
96
- │ └── ko.json
63
+ └── styles/ # Page-specific CSS files
64
+ ├── home.css
65
+ └── user-profile.css
66
+ ├── css/ # Global CSS files
67
+ └── base.css # Base styles
68
+ ├── js/ # JavaScript library files
69
+ │ ├── viewlogic-router.js # Development version
70
+ │ ├── viewlogic-router.min.js # Minified version
71
+ │ └── viewlogic-router.umd.js # UMD bundle
72
+ ├── i18n/ # Internationalization files
73
+ │ ├── en.json # English translations
74
+ │ ├── ko.json # Korean translations
75
+ │ └── ja.json # Japanese translations
76
+ ├── routes/ # Auto-generated after building
77
+ │ ├── home.js # Built route bundles
78
+ │ ├── user-profile.js
79
+ │ └── dashboard.js
97
80
  ├── index.html # Main entry point
98
- ├── package.json
99
- └── config.json # Optional configuration
81
+ └── package.json
100
82
  ```
101
83
 
102
84
  ## 🚀 Quick Start
103
85
 
104
- ### Method 1: ES6 Modules (Recommended)
86
+ ### Method 1: Create New Project (Recommended)
105
87
 
106
88
  ```bash
107
- npm install viewlogic
89
+ npm create viewlogic myapp
90
+ cd myapp
91
+ npm run dev
108
92
  ```
109
93
 
94
+ This creates a complete project with examples and starts the development server.
95
+
96
+ ### Method 2: UMD Build (No Build Tools)
97
+
110
98
  ```html
111
99
  <!DOCTYPE html>
112
100
  <html>
113
101
  <head>
114
102
  <title>My ViewLogic App</title>
103
+ <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
104
+ <script src="https://cdn.jsdelivr.net/npm/viewlogic/dist/viewlogic-router.umd.js"></script>
115
105
  </head>
116
106
  <body>
117
107
  <div id="app"></div>
118
- <script type="module">
119
- import { ViewLogicRouter } from 'viewlogic';
120
- const router = new ViewLogicRouter({
121
- authEnabled: true,
122
- useI18n: true
108
+ <script>
109
+ ViewLogicRouter({
110
+ environment: 'development'
123
111
  });
124
112
  </script>
125
113
  </body>
126
114
  </html>
127
115
  ```
128
116
 
129
- ### Method 2: UMD Build (No Build Tools)
117
+ ### Method 3: ES6 Modules
118
+
119
+ ```bash
120
+ npm install viewlogic
121
+ ```
130
122
 
131
123
  ```html
132
124
  <!DOCTYPE html>
133
125
  <html>
134
126
  <head>
135
127
  <title>My ViewLogic App</title>
136
- <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
137
- <script src="https://cdn.jsdelivr.net/npm/viewlogic/dist/viewlogic-router.umd.js"></script>
138
128
  </head>
139
129
  <body>
140
130
  <div id="app"></div>
141
- <script>
142
- const router = new ViewLogicRouter();
131
+ <script type="module">
132
+ import { ViewLogicRouter } from 'viewlogic';
133
+ const router = new ViewLogicRouter({
134
+ environment: 'production',
135
+ authEnabled: true,
136
+ useI18n: true
137
+ });
143
138
  </script>
144
139
  </body>
145
140
  </html>
@@ -151,83 +146,204 @@ npm install viewlogic
151
146
  ```html
152
147
  <div class="home">
153
148
  <h1>{{ message }}</h1>
154
- <p>Counter: {{ count }} | Global Count: {{ globalCount }}</p>
155
- <button @click="increment">Local +1</button>
156
- <button @click="incrementGlobal">Global +1</button>
157
- <button @click="saveUser" :disabled="loading">
158
- {{ loading ? 'Saving...' : 'Save User' }}
159
- </button>
160
- <div v-if="user">
161
- <h3>{{ $t('welcome.message', { name: user.name }) }}</h3>
162
- </div>
149
+ <button @click="increment">Click me: {{ count }}</button>
163
150
  </div>
164
151
  ```
165
152
 
166
153
  **src/logic/home.js**
167
154
  ```javascript
168
155
  export default {
156
+ // Optional: specify layout (defaults to 'default')
157
+ layout: 'default', // Use layouts/default.html
158
+ // layout: 'admin', // Use layouts/admin.html
159
+ // layout: null, // No layout (page-only content)
160
+
169
161
  data() {
170
162
  return {
171
163
  message: 'Welcome to ViewLogic!',
172
- count: 0,
173
- loading: false
164
+ count: 0
174
165
  };
175
166
  },
167
+ methods: {
168
+ increment() {
169
+ this.count++;
170
+ }
171
+ }
172
+ };
173
+ ```
174
+
175
+ **src/styles/home.css** (optional)
176
+ ```css
177
+ .home {
178
+ padding: 2rem;
179
+ text-align: center;
180
+ }
181
+
182
+ .home h1 {
183
+ color: #2c3e50;
184
+ margin-bottom: 1rem;
185
+ }
186
+ ```
187
+
188
+ **src/layouts/default.html** (optional)
189
+ ```html
190
+ <!DOCTYPE html>
191
+ <html>
192
+ <head>
193
+ <title>My ViewLogic App</title>
194
+ <meta charset="utf-8">
195
+ <meta name="viewport" content="width=device-width, initial-scale=1">
196
+ </head>
197
+ <body>
198
+ <header class="navbar">
199
+ <h1>My App</h1>
200
+ <nav>
201
+ <a href="#/home">Home</a>
202
+ <a href="#/about">About</a>
203
+ </nav>
204
+ </header>
205
+
206
+ <main class="main-content">
207
+ <div class="container">
208
+ {{ content }}
209
+ </div>
210
+ </main>
211
+
212
+ <footer>
213
+ <p>&copy; 2024 My ViewLogic App</p>
214
+ </footer>
215
+ </body>
216
+ </html>
217
+ ```
218
+
219
+ ### Query Parameter Example
220
+
221
+ **src/views/user-profile.html**
222
+ ```html
223
+ <div class="user-profile">
224
+ <h1>User Profile</h1>
225
+ <p>User ID: {{ userId }}</p>
226
+ <p>Tab: {{ activeTab }}</p>
227
+ <button @click="switchTab('settings')">Settings</button>
228
+ <button @click="switchTab('posts')">Posts</button>
229
+ </div>
230
+ ```
231
+
232
+ **src/logic/user-profile.js**
233
+ ```javascript
234
+ export default {
176
235
  computed: {
177
- globalCount() {
178
- return this.$state.get('globalCounter', 0);
236
+ userId() {
237
+ return this.getParam('userId', 'No ID');
179
238
  },
180
- user() {
181
- return this.$state.get('currentUser');
239
+ activeTab() {
240
+ return this.getParam('tab', 'profile');
182
241
  }
183
242
  },
184
243
  methods: {
185
- increment() {
186
- this.count++;
187
- },
188
- incrementGlobal() {
189
- const current = this.$state.get('globalCounter', 0);
190
- this.$state.set('globalCounter', current + 1);
191
- },
192
- async saveUser() {
193
- this.loading = true;
194
- try {
195
- const userData = {
196
- name: 'John Doe',
197
- email: 'john@example.com'
198
- };
244
+ switchTab(tab) {
245
+ // Navigate with query parameters
246
+ this.navigateTo('user-profile', {
247
+ userId: this.userId,
248
+ tab: tab
249
+ });
250
+ }
251
+ }
252
+ };
253
+ ```
199
254
 
200
- const savedUser = await this.$api.post('/api/users', userData);
201
- this.$state.set('currentUser', savedUser);
255
+ **Usage:** Navigate to `/user-profile?userId=123&tab=settings` or `#/user-profile?userId=123&tab=settings` (hash mode)
202
256
 
203
- this.$toast?.success?.('User saved successfully!');
204
- } catch (error) {
205
- this.$toast?.error?.('Failed to save user');
206
- } finally {
207
- this.loading = false;
208
- }
257
+ **Multiple ways to access parameters:**
258
+ ```javascript
259
+ // Direct parameter access
260
+ const userId = this.$params.userId; // Route parameter (direct access)
261
+ const tab = this.$query.tab; // Query parameter (direct access)
262
+ const search = this.getParam('search'); // Either route or query param
263
+ const allParams = this.getParams(); // Get all parameters
264
+
265
+ // With default values
266
+ const page = this.getParam('page', 1); // Default to 1 if not found
267
+ const sort = this.$query.sort || 'asc'; // Manual default for query params
268
+ ```
269
+
270
+ ### Reusable Components
271
+
272
+ ViewLogic automatically loads components from the `components/` folder:
273
+
274
+ **src/components/UserCard.js**
275
+ ```javascript
276
+ export default {
277
+ name: 'UserCard',
278
+ template: `
279
+ <div class="user-card">
280
+ <img :src="user.avatar" :alt="user.name" class="avatar">
281
+ <div class="info">
282
+ <h3>{{ user.name }}</h3>
283
+ <p>{{ user.email }}</p>
284
+ <button @click="$emit('edit', user)" class="btn-edit">
285
+ Edit User
286
+ </button>
287
+ </div>
288
+ </div>
289
+ `,
290
+ emits: ['edit'],
291
+ props: {
292
+ user: {
293
+ type: Object,
294
+ required: true
209
295
  }
296
+ }
297
+ };
298
+ ```
299
+
300
+ **Using components in views:**
301
+
302
+ **src/views/users.html**
303
+ ```html
304
+ <div class="users-page">
305
+ <h1>Users</h1>
306
+ <UserCard
307
+ v-for="user in users"
308
+ :key="user.id"
309
+ :user="user"
310
+ @edit="editUser"
311
+ />
312
+ </div>
313
+ ```
314
+
315
+ **src/logic/users.js**
316
+ ```javascript
317
+ export default {
318
+ data() {
319
+ return {
320
+ users: []
321
+ };
210
322
  },
211
- mounted() {
212
- // Watch for global state changes
213
- this.$state.watch('currentUser', (newUser) => {
214
- console.log('User changed globally:', newUser);
215
- });
323
+ methods: {
324
+ editUser(user) {
325
+ this.navigateTo('user-edit', { userId: user.id });
326
+ }
216
327
  }
217
328
  };
218
329
  ```
219
330
 
331
+ **Dynamic Component Loading:**
332
+ - Just add `.js` files to `src/components/` folder
333
+ - Components are automatically discovered and loaded
334
+ - No import statements needed - ViewLogic handles everything
335
+ - Components are available instantly in all views
336
+
220
337
  ## 🎯 Core APIs
221
338
 
222
339
  ### State Management
223
340
 
224
- ViewLogic Router includes a powerful built-in state management system:
341
+ Built-in reactive state management system:
225
342
 
226
343
  ```javascript
227
344
  // Set state (any component can access)
228
345
  this.$state.set('user', { name: 'John', age: 30 });
229
346
  this.$state.set('theme', 'dark');
230
- this.$state.set('shoppingCart', []);
231
347
 
232
348
  // Get state with optional default
233
349
  const user = this.$state.get('user');
@@ -244,9 +360,6 @@ this.$state.watch('user', (newValue, oldValue) => {
244
360
  this.updateUI();
245
361
  });
246
362
 
247
- // Stop watching
248
- this.$state.unwatch('user', callbackFunction);
249
-
250
363
  // Bulk updates
251
364
  this.$state.update({
252
365
  theme: 'dark',
@@ -263,42 +376,33 @@ this.$state.delete('temporaryData');
263
376
 
264
377
  ### Authentication System
265
378
 
266
- Complete authentication management with multiple storage options:
379
+ Complete authentication management:
267
380
 
268
381
  ```javascript
269
382
  // Check authentication status
270
- if (this.$isAuthenticated()) {
383
+ if (this.isAuth()) {
271
384
  console.log('User is logged in');
272
385
  }
273
386
 
274
387
  // Login with token
275
- this.$setToken('jwt-token-here');
388
+ this.setToken('jwt-token-here');
276
389
 
277
390
  // Login with options
278
- this.$setToken('jwt-token', {
391
+ this.setToken('jwt-token', {
279
392
  storage: 'localStorage', // 'localStorage', 'sessionStorage', 'cookie'
280
393
  skipValidation: false // Skip JWT validation
281
394
  });
282
395
 
283
396
  // Get current token
284
- const token = this.$getToken();
285
-
286
- // Login success handling (redirects to protected route or default)
287
- this.$loginSuccess('/dashboard');
397
+ const token = this.getToken();
288
398
 
289
399
  // Logout (clears token and redirects to login)
290
- this.$logout();
291
-
292
- // Manual auth check for specific route
293
- const authResult = await this.$checkAuth('admin-panel');
294
- if (authResult.allowed) {
295
- // User can access admin panel
296
- }
400
+ this.logout();
297
401
  ```
298
402
 
299
403
  ### API Management
300
404
 
301
- Built-in HTTP client with automatic token injection and parameter substitution:
405
+ Built-in HTTP client with automatic token injection:
302
406
 
303
407
  ```javascript
304
408
  // GET request
@@ -324,11 +428,6 @@ await this.$api.delete('/api/users/{userId}');
324
428
  // If current route is /users?userId=123, this becomes /api/users/123
325
429
  const user = await this.$api.get('/api/users/{userId}');
326
430
 
327
- // Custom headers
328
- const response = await this.$api.post('/api/secure-endpoint', data, {
329
- headers: { 'X-Custom-Header': 'value' }
330
- });
331
-
332
431
  // Automatic data loading in components
333
432
  export default {
334
433
  // Single API endpoint
@@ -344,13 +443,48 @@ export default {
344
443
  mounted() {
345
444
  // Data automatically loaded and available as:
346
445
  // this.profile, this.posts, this.notifications
446
+ },
447
+
448
+ methods: {
449
+ // Manual data refresh - reuses dataURL configuration
450
+ async refreshData() {
451
+ await this.fetchData();
452
+ // All dataURL endpoints are called again
453
+ },
454
+
455
+ // Refresh when filters change
456
+ async applyFilter(filterType) {
457
+ this.$query.filter = filterType;
458
+ await this.fetchData(); // Refetch with new filter parameter
459
+ },
460
+
461
+ // Refresh when user changes
462
+ async switchUser(newUserId) {
463
+ this.$params.userId = newUserId;
464
+ await this.fetchData(); // Refetch with new userId parameter
465
+ },
466
+
467
+ // Pagination
468
+ async changePage(page) {
469
+ this.$query.page = page;
470
+ await this.fetchData(); // Load new page data
471
+ },
472
+
473
+ // Custom data loading
474
+ async loadSpecificData() {
475
+ const customData = await this.fetchData({
476
+ profile: '/api/admin/profile',
477
+ stats: '/api/stats?period={period}'
478
+ });
479
+ // Override default dataURL temporarily
480
+ }
347
481
  }
348
482
  };
349
483
  ```
350
484
 
351
485
  ### Internationalization
352
486
 
353
- Comprehensive i18n system with lazy loading and pluralization:
487
+ Comprehensive i18n system:
354
488
 
355
489
  ```javascript
356
490
  // Simple translation
@@ -362,30 +496,57 @@ const greeting = this.$t('hello.user', { name: 'John', role: 'admin' });
362
496
  // Nested keys
363
497
  const errorMsg = this.$t('errors.validation.email.required');
364
498
 
365
- // Plural forms
366
- const itemCount = this.$plural('items.count', count, { count });
367
- // items.count.singular: "{count} item"
368
- // items.count.plural: "{count} items"
369
-
370
499
  // Check current language
371
- const currentLang = this.$i18n.getCurrentLanguage();
500
+ const currentLang = this.getLanguage();
372
501
 
373
502
  // Change language (automatically reloads interface)
374
- await this.$i18n.setLanguage('ko');
503
+ await this.setLanguage('ko');
504
+ ```
375
505
 
376
- // Format dates/numbers according to locale
377
- const date = this.$i18n.formatDate(new Date(), {
378
- year: 'numeric',
379
- month: 'long',
380
- day: 'numeric'
381
- });
506
+ ### Logging & Error Handling
382
507
 
383
- const price = this.$i18n.formatNumber(1234.56, {
384
- style: 'currency',
385
- currency: 'USD'
386
- });
508
+ Built-in logging system for debugging and error tracking:
509
+
510
+ ```javascript
511
+ export default {
512
+ async mounted() {
513
+ this.log('info', 'Component mounted successfully');
514
+ },
515
+
516
+ methods: {
517
+ async handleUserAction() {
518
+ this.log('debug', 'User action started', { action: 'submit' });
519
+
520
+ try {
521
+ const result = await this.$api.post('/api/users', userData);
522
+ this.log('info', 'User created successfully', result);
523
+ } catch (error) {
524
+ this.log('error', 'Failed to create user:', error);
525
+ }
526
+ },
527
+
528
+ async loadData() {
529
+ this.log('debug', 'Loading user data...');
530
+
531
+ try {
532
+ const data = await this.fetchData();
533
+ this.log('info', 'Data loaded', { count: data.length });
534
+ } catch (error) {
535
+ this.log('warn', 'Data loading failed, using cache', error);
536
+ }
537
+ }
538
+ }
539
+ };
387
540
  ```
388
541
 
542
+ **Log Levels:**
543
+ - `debug` - Development debugging information
544
+ - `info` - General information and success messages
545
+ - `warn` - Warning messages for recoverable issues
546
+ - `error` - Error messages for failures
547
+
548
+ All logs include the component name automatically: `[routeName] Your message`
549
+
389
550
  ### Navigation & Routing
390
551
 
391
552
  Simple yet powerful routing system:
@@ -403,76 +564,93 @@ this.navigateTo({
403
564
  params: { query: 'vue', category: 'tutorials' }
404
565
  });
405
566
 
406
- // Get current route information
407
- const currentRoute = this.$route.current;
408
- const routeParams = this.$route.params;
409
- const queryParams = this.$route.query;
410
-
411
- // Access specific parameters
412
- const userId = this.$params.userId; // Route parameter
413
- const tab = this.$query.tab; // Query parameter
414
- const searchTerm = this.$param('search'); // Either route or query param
415
-
416
- // Check if route is protected
417
- const isProtected = this.$route.isProtected('admin-dashboard');
418
-
419
- // Navigate with state preservation
420
- this.navigateTo('dashboard', {
421
- preserveState: true,
422
- scrollTop: false
423
- });
424
567
  ```
425
568
 
569
+
426
570
  ### Form Handling
427
571
 
428
- Revolutionary form processing with automatic parameter substitution:
572
+ Revolutionary automatic form processing with parameter substitution:
429
573
 
430
574
  ```html
431
- <!-- Basic form with automatic handling -->
432
- <form action="/api/users" method="POST">
575
+ <!-- Basic form - automatically handled on submit -->
576
+ <form action="/api/users" method="POST"
577
+ data-success="onUserCreated"
578
+ data-error="onUserError"
579
+ data-loading="setLoading">
433
580
  <input name="name" v-model="userData.name" required>
434
581
  <input name="email" v-model="userData.email" type="email" required>
435
582
  <button type="submit">Create User</button>
436
583
  </form>
437
584
 
438
585
  <!-- Form with parameter substitution -->
439
- <form action="/api/users/{userId}" method="PUT">
586
+ <form action="/api/users/{userId}" method="PUT"
587
+ data-success="onUserUpdated"
588
+ data-redirect="user-profile">
440
589
  <input name="name" v-model="user.name">
441
590
  <input name="email" v-model="user.email">
442
591
  <button type="submit">Update User</button>
443
592
  </form>
444
593
 
445
594
  <!-- File upload form -->
446
- <form action="/api/upload" method="POST" enctype="multipart/form-data">
595
+ <form action="/api/upload" method="POST" enctype="multipart/form-data"
596
+ data-success="onFileUploaded">
447
597
  <input name="avatar" type="file" accept="image/*">
448
598
  <input name="description" v-model="description">
449
599
  <button type="submit">Upload</button>
450
600
  </form>
601
+
602
+ <!-- Form with custom validation -->
603
+ <form action="/api/contact" method="POST">
604
+ <input name="email" type="email" data-validation="validateEmail" required>
605
+ <textarea name="message" data-validation="validateMessage" required></textarea>
606
+ <button type="submit">Send Message</button>
607
+ </form>
451
608
  ```
452
609
 
453
610
  ```javascript
454
- // Programmatic form submission
611
+ // Component logic with form handlers
455
612
  export default {
613
+ data() {
614
+ return {
615
+ userData: { name: '', email: '' },
616
+ user: { name: 'John', email: 'john@example.com' },
617
+ loading: false
618
+ };
619
+ },
456
620
  methods: {
457
- async submitForm() {
458
- const formData = {
459
- name: this.userData.name,
460
- email: this.userData.email
461
- };
621
+ // Success handlers
622
+ onUserCreated(response, form) {
623
+ this.$state.set('newUser', response);
624
+ this.navigateTo('user-profile', { userId: response.id });
625
+ },
462
626
 
463
- try {
464
- const result = await this.$form.submit('/api/users', formData, {
465
- method: 'POST',
466
- onProgress: (progress) => {
467
- this.uploadProgress = progress;
468
- }
469
- });
470
-
471
- this.$state.set('newUser', result);
472
- this.navigateTo('user-profile', { userId: result.id });
473
- } catch (error) {
474
- this.handleError(error);
475
- }
627
+ onUserUpdated(response, form) {
628
+ this.$state.set('currentUser', response);
629
+ // Auto redirect via data-redirect="user-profile"
630
+ },
631
+
632
+ onFileUploaded(response, form) {
633
+ this.$state.set('uploadedFile', response.file);
634
+ },
635
+
636
+ // Error handler
637
+ onUserError(error, form) {
638
+ console.error('User operation failed:', error);
639
+ },
640
+
641
+ // Loading handler
642
+ setLoading(isLoading, form) {
643
+ this.loading = isLoading;
644
+ },
645
+
646
+ // Custom validation functions
647
+ validateEmail(value, input) {
648
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
649
+ return emailRegex.test(value);
650
+ },
651
+
652
+ validateMessage(value, input) {
653
+ return value.length >= 10;
476
654
  }
477
655
  }
478
656
  };
@@ -488,9 +666,6 @@ const router = new ViewLogicRouter({
488
666
  basePath: '/', // Base path for the application
489
667
  mode: 'hash', // 'hash' or 'history'
490
668
 
491
- // State management (always enabled)
492
- // No configuration needed - StateHandler is always available
493
-
494
669
  // Authentication settings
495
670
  authEnabled: true, // Enable authentication system
496
671
  loginRoute: 'login', // Route name for login page
@@ -502,10 +677,10 @@ const router = new ViewLogicRouter({
502
677
  // Internationalization
503
678
  useI18n: true, // Enable i18n system
504
679
  defaultLanguage: 'en', // Default language
505
- i18nPath: '/src/locales', // Path to language files
680
+ i18nPath: '/i18n', // Path to language files
506
681
 
507
682
  // Caching system
508
- cacheMode: 'memory', // 'memory' only (others removed for simplicity)
683
+ cacheMode: 'memory', // Memory caching only
509
684
  cacheTTL: 300000, // Cache TTL in milliseconds (5 minutes)
510
685
  maxCacheSize: 100, // Maximum number of cached items
511
686
 
@@ -525,165 +700,20 @@ const router = new ViewLogicRouter({
525
700
  const router = new ViewLogicRouter({
526
701
  // Custom authentication function
527
702
  authEnabled: true,
528
- checkAuthFunction: async (routeName) => {
529
- const token = localStorage.getItem('authToken');
530
- if (!token) return false;
531
-
703
+ checkAuthFunction: async (route) => {
532
704
  try {
533
- const response = await fetch('/api/auth/verify', {
534
- method: 'POST',
535
- headers: {
536
- 'Authorization': `Bearer ${token}`,
537
- 'Content-Type': 'application/json'
538
- }
539
- });
540
-
541
- if (response.ok) {
542
- const userData = await response.json();
543
- // Store user data in global state
544
- router.stateHandler.set('currentUser', userData);
545
- return true;
546
- }
547
- return false;
705
+ // Use ViewLogic APIs like in components
706
+ const userData = await route.$api.get('/api/auth/verify');
707
+ route.$state.set('currentUser', userData);
708
+ return true;
548
709
  } catch (error) {
549
710
  console.error('Auth verification failed:', error);
550
711
  return false;
551
712
  }
552
- },
553
-
554
- // Custom route loading
555
- routeResolver: (routeName) => {
556
- // Custom logic for resolving route files
557
- if (routeName.startsWith('admin/')) {
558
- return {
559
- viewPath: `/admin/views/${routeName.slice(6)}.html`,
560
- logicPath: `/admin/logic/${routeName.slice(6)}.js`
561
- };
562
- }
563
- return null; // Use default resolution
564
- },
565
-
566
- // Global error handler
567
- onError: (error, context) => {
568
- console.error('ViewLogic Error:', error, context);
569
- // Send to error tracking service
570
- if (window.errorTracker) {
571
- window.errorTracker.log(error, context);
572
- }
573
- },
574
-
575
- // Global route change handler
576
- onRouteChange: (newRoute, oldRoute) => {
577
- // Analytics tracking
578
- if (window.analytics) {
579
- window.analytics.track('page_view', {
580
- route: newRoute,
581
- previous_route: oldRoute
582
- });
583
- }
584
713
  }
585
714
  });
586
715
  ```
587
716
 
588
- ## 📦 Bundle Size Comparison
589
-
590
- | Solution | Minified | Gzipped |
591
- |----------|----------|---------|
592
- | **ViewLogic Router** (Complete) | **51KB** | **17KB** |
593
- | Vue Router + Pinia + Vue I18n | 150KB+ | 45KB+ |
594
- | React Router + Redux + i18next | 200KB+ | 60KB+ |
595
- | Next.js (Runtime) | 300KB+ | 85KB+ |
596
-
597
- *ViewLogic Router provides the functionality of 7+ libraries in a package smaller than most single-purpose libraries.*
598
-
599
- ## 🎯 Migration Guide
600
-
601
- ### From Vue Router + Pinia
602
-
603
- **Before:**
604
- ```javascript
605
- // main.js - Multiple library setup
606
- import { createApp } from 'vue';
607
- import { createRouter, createWebHistory } from 'vue-router';
608
- import { createPinia } from 'pinia';
609
- import { createI18n } from 'vue-i18n';
610
- import App from './App.vue';
611
-
612
- const router = createRouter({
613
- history: createWebHistory(),
614
- routes: [/* complex route config */]
615
- });
616
-
617
- const pinia = createPinia();
618
- const i18n = createI18n({/* complex i18n config */});
619
-
620
- const app = createApp(App);
621
- app.use(router).use(pinia).use(i18n);
622
- app.mount('#app');
623
- ```
624
-
625
- **After:**
626
- ```javascript
627
- // index.html - Single setup
628
- import { ViewLogicRouter } from 'viewlogic';
629
-
630
- const router = new ViewLogicRouter({
631
- mode: 'history',
632
- useI18n: true,
633
- authEnabled: true
634
- });
635
- // Everything is auto-configured and ready to use!
636
- ```
637
-
638
- ### State Management Migration
639
-
640
- **Before (Pinia):**
641
- ```javascript
642
- // stores/user.js
643
- import { defineStore } from 'pinia';
644
-
645
- export const useUserStore = defineStore('user', {
646
- state: () => ({
647
- currentUser: null,
648
- preferences: {}
649
- }),
650
- getters: {
651
- isLoggedIn: (state) => !!state.currentUser,
652
- userName: (state) => state.currentUser?.name || 'Guest'
653
- },
654
- actions: {
655
- setUser(userData) {
656
- this.currentUser = userData;
657
- },
658
- updatePreferences(prefs) {
659
- this.preferences = { ...this.preferences, ...prefs };
660
- }
661
- }
662
- });
663
-
664
- // In components
665
- import { useUserStore } from '@/stores/user';
666
- const userStore = useUserStore();
667
- userStore.setUser(userData);
668
- ```
669
-
670
- **After (ViewLogic):**
671
- ```javascript
672
- // In any component - no store files needed!
673
- this.$state.set('currentUser', userData);
674
- this.$state.update({ preferences: newPrefs });
675
-
676
- // Computed properties work naturally
677
- computed: {
678
- isLoggedIn() {
679
- return !!this.$state.get('currentUser');
680
- },
681
- userName() {
682
- return this.$state.get('currentUser')?.name || 'Guest';
683
- }
684
- }
685
- ```
686
-
687
717
  ## 🔧 Production Build
688
718
 
689
719
  ```bash
@@ -695,9 +725,6 @@ npm run build
695
725
 
696
726
  # Preview production build
697
727
  npm run serve
698
-
699
- # Build with custom config
700
- npm run build -- --config custom.config.js
701
728
  ```
702
729
 
703
730
  ### Production Optimizations
@@ -710,102 +737,6 @@ ViewLogic Router automatically optimizes for production:
710
737
  - **Caching**: Aggressive caching for static assets
711
738
  - **Lazy loading**: Routes and components load on demand
712
739
 
713
- ## 🌟 Advanced Examples
714
-
715
- ### E-commerce Dashboard
716
-
717
- ```javascript
718
- // logic/dashboard.js
719
- export default {
720
- dataURL: {
721
- overview: '/api/dashboard/overview',
722
- sales: '/api/sales/recent',
723
- products: '/api/products/trending'
724
- },
725
-
726
- computed: {
727
- totalRevenue() {
728
- return this.sales?.reduce((sum, sale) => sum + sale.amount, 0) || 0;
729
- },
730
- cartItems() {
731
- return this.$state.get('shoppingCart', []);
732
- }
733
- },
734
-
735
- methods: {
736
- async addToCart(product) {
737
- const cart = this.$state.get('shoppingCart', []);
738
- const existingItem = cart.find(item => item.id === product.id);
739
-
740
- if (existingItem) {
741
- existingItem.quantity += 1;
742
- } else {
743
- cart.push({ ...product, quantity: 1 });
744
- }
745
-
746
- this.$state.set('shoppingCart', cart);
747
-
748
- // Sync with backend
749
- await this.$api.post('/api/cart/sync', { items: cart });
750
- },
751
-
752
- async checkout() {
753
- const items = this.$state.get('shoppingCart', []);
754
- try {
755
- const order = await this.$api.post('/api/orders', { items });
756
- this.$state.set('shoppingCart', []);
757
- this.$state.set('lastOrder', order);
758
- this.navigateTo('order-confirmation', { orderId: order.id });
759
- } catch (error) {
760
- this.$toast?.error?.('Checkout failed. Please try again.');
761
- }
762
- }
763
- }
764
- };
765
- ```
766
-
767
- ### Multi-tenant Application
768
-
769
- ```javascript
770
- // Handle different tenants with state management
771
- export default {
772
- async mounted() {
773
- const tenantId = this.$params.tenantId || this.$query.tenant;
774
-
775
- if (tenantId !== this.$state.get('currentTenant')?.id) {
776
- await this.switchTenant(tenantId);
777
- }
778
- },
779
-
780
- methods: {
781
- async switchTenant(tenantId) {
782
- try {
783
- const tenant = await this.$api.get('/api/tenants/{tenantId}', {
784
- params: { tenantId }
785
- });
786
-
787
- // Update global state
788
- this.$state.update({
789
- currentTenant: tenant,
790
- userPermissions: tenant.permissions,
791
- theme: tenant.branding.theme
792
- });
793
-
794
- // Update language if tenant has preference
795
- if (tenant.defaultLanguage) {
796
- await this.$i18n.setLanguage(tenant.defaultLanguage);
797
- }
798
-
799
- // Update API base URL for tenant
800
- this.$api.setBaseURL(`/api/tenants/${tenantId}`);
801
-
802
- } catch (error) {
803
- this.navigateTo('tenant-not-found');
804
- }
805
- }
806
- }
807
- };
808
- ```
809
740
 
810
741
  ## 🤝 Contributing
811
742