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 +376 -445
- package/dist/viewlogic-router.js +26 -26
- package/dist/viewlogic-router.js.map +2 -2
- package/dist/viewlogic-router.min.js +3 -3
- package/dist/viewlogic-router.min.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,64 +12,36 @@
|
|
|
12
12
|
</a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
> **Complete Vue 3 Framework**:
|
|
15
|
+
> **Complete Vue 3 Framework**: All-in-one solution for modern web development
|
|
16
16
|
|
|
17
|
-
## 🎯 Core Philosophy
|
|
17
|
+
## 🎯 Core Philosophy
|
|
18
18
|
|
|
19
|
-
ViewLogic Router revolutionizes Vue development with two fundamental
|
|
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
|
|
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
|
-
##
|
|
27
|
+
## ✨ What Makes ViewLogic Special
|
|
28
28
|
|
|
29
|
-
**All-in-One Solution** - Replace
|
|
30
|
-
- 🔀 **
|
|
31
|
-
- 📦 **
|
|
32
|
-
- 🔐 **
|
|
33
|
-
- 🌐 **
|
|
34
|
-
- 💾 **
|
|
35
|
-
- 🌐 **API
|
|
36
|
-
- 📝 **Form
|
|
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
|
|
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
|
-
│
|
|
92
|
-
│
|
|
93
|
-
│
|
|
94
|
-
|
|
95
|
-
│
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
└── config.json # Optional configuration
|
|
81
|
+
└── package.json
|
|
100
82
|
```
|
|
101
83
|
|
|
102
84
|
## 🚀 Quick Start
|
|
103
85
|
|
|
104
|
-
### Method 1:
|
|
86
|
+
### Method 1: Create New Project (Recommended)
|
|
105
87
|
|
|
106
88
|
```bash
|
|
107
|
-
npm
|
|
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
|
|
119
|
-
|
|
120
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
<
|
|
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>© 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
|
-
|
|
178
|
-
return this
|
|
236
|
+
userId() {
|
|
237
|
+
return this.getParam('userId', 'No ID');
|
|
179
238
|
},
|
|
180
|
-
|
|
181
|
-
return this
|
|
239
|
+
activeTab() {
|
|
240
|
+
return this.getParam('tab', 'profile');
|
|
182
241
|
}
|
|
183
242
|
},
|
|
184
243
|
methods: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
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
|
|
379
|
+
Complete authentication management:
|
|
267
380
|
|
|
268
381
|
```javascript
|
|
269
382
|
// Check authentication status
|
|
270
|
-
if (this
|
|
383
|
+
if (this.isAuth()) {
|
|
271
384
|
console.log('User is logged in');
|
|
272
385
|
}
|
|
273
386
|
|
|
274
387
|
// Login with token
|
|
275
|
-
this
|
|
388
|
+
this.setToken('jwt-token-here');
|
|
276
389
|
|
|
277
390
|
// Login with options
|
|
278
|
-
this
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
500
|
+
const currentLang = this.getLanguage();
|
|
372
501
|
|
|
373
502
|
// Change language (automatically reloads interface)
|
|
374
|
-
await this
|
|
503
|
+
await this.setLanguage('ko');
|
|
504
|
+
```
|
|
375
505
|
|
|
376
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
|
572
|
+
Revolutionary automatic form processing with parameter substitution:
|
|
429
573
|
|
|
430
574
|
```html
|
|
431
|
-
<!-- Basic form
|
|
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
|
-
//
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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: '/
|
|
680
|
+
i18nPath: '/i18n', // Path to language files
|
|
506
681
|
|
|
507
682
|
// Caching system
|
|
508
|
-
cacheMode: 'memory', //
|
|
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 (
|
|
529
|
-
const token = localStorage.getItem('authToken');
|
|
530
|
-
if (!token) return false;
|
|
531
|
-
|
|
703
|
+
checkAuthFunction: async (route) => {
|
|
532
704
|
try {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
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
|
|