@aref-shojaei/router 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,205 +1,332 @@
1
- ![SPA (1)](https://github.com/user-attachments/assets/7e76a68b-84f0-4fa7-b961-26319d3ed3bc)
2
-
3
-
4
- <h1 align='center'>Router - SPA Application</h1>
5
-
6
-
7
- > app.js
8
- ```js
9
- import { Router, Route } from "@aref-shojaei/router"
10
-
11
-
12
- // Confgiure router system
13
- Router.configure({ window, document })
14
-
15
-
16
- // Single Route
17
- Route.addRoute("/", () => "Welcome Page")
18
-
19
- // Group Routes
20
- Route.group("/auth", () => {
21
- Route.addRoute("/login", () => "Login Page")
22
- Route.addRoute("/register", () => "Register Page")
23
- })
24
-
25
- // Dynamic Route
26
- Route.addRoute("/users/{id}", ({ params : { name } }) => `User#${id} Page`)
27
-
28
-
29
- // Redirect Routes
30
- Route.addRoute("/redirection", () => Route.redirect("/"))
31
-
32
-
33
- // Initialize the router
34
- Router.run()
35
- ```
36
-
37
- > index.html
38
- ```html
39
- <html>
40
- <head>
41
- <title>SPA App</title>
42
- </head>
43
- <body>
44
- <ul>
45
- <!-- Redirect to local links -->
46
- <li><a href="/">Home</a></li>
47
- <li><a href="/auth/login">Login</a></li>
48
- <li><a href="/auth/register">Register</a></li>
49
- <li><a href="/users/2904152">Admin Page</a></li>
50
- <li><a href="/redirection">Redirect to a page</a></li>
51
-
52
- <!-- Redirect to external resources -->
53
- <li><a href="https://github.com/ArefShojaei/Router" data-link>Github</a></li>
54
- </ul>
55
-
56
- <div id="root"></div>
57
-
58
- <script src="app.js"></script>
59
- </body>
60
- </html>
61
- ```
62
-
63
-
64
- ## Guide :
65
- 1. [Introduction](#introduction)
66
- * [What is this library ?](#what-is-this-library)
67
- * [Why should I use it ?](#why-should-i-use-it)
68
- * [Is it work like SPA ?](#is-it-work-like-spa)
69
- 2. [installation](#installation)
70
- 3. [tutorial](#tutorial)
71
-
72
- <br/>
73
-
74
- ## Introduction
75
-
76
- <br/>
77
-
78
- ### What is this library ?
79
- > This library is for handling routes in the browser env by HTTP requests!
80
-
81
- ```bash
82
- * Back-end:
83
- [Request] GET /blog => [Response] HTML | JSON
84
-
85
-
86
- * Front-end:
87
- Page -> [Route] /blog -> Update content -> without refereshing -> Render template
88
- ```
89
-
90
- <br>
91
-
92
- ### Why should I use it ?
93
- > If you like to have application or pages not to need to referesh again for every action | request + high performance for loading content (SPA)
94
-
95
- <br>
96
-
97
- ### Is it work like SPA ?
98
- > Sure You can get this options to use the library:
99
- * Add Signle Route
100
- * Add the group routes
101
- * Add middleware to every routes (back-end concept)
102
- * Add route redirection
103
- * Add pages as component or template files to specific route
104
- * More ...
105
-
106
- <br>
107
-
108
- ## Installation
109
-
110
- > NPM
111
- ```bash
112
- npm i @aref-shojaei/router
113
- ```
114
-
115
- > Yarn
116
- ```bash
117
- yarn add @aref-shojaei/router
118
- ```
119
-
120
- <br/>
121
-
122
- > Setup - app.js
123
-
124
- ```js
125
- import { Router , Route } from "@aref-shojaei/router"
126
-
127
- Route.addRoute("/", () => "Welcome Page")
128
-
129
- Router.run()
130
- ```
131
- **Note: Don't forget to read guides again!**
132
-
133
- <br/>
134
-
135
- ## Tutorial
136
-
137
- > Route
138
- * Single type
139
- * Group type
140
- * Dynamic type
141
-
142
- ```js
143
- import { Route } from "@aref-shojaei/router"
144
-
145
- // Single route
146
- Route.addRoute("/", () => "Welcome Page")
147
-
148
- // Group routes
149
- Route.group("/auth", () => {
150
- Route.addRoute("/login", () => "Welcome Page")
151
- Route.addRoute("/register", () => "Welcome Page")
152
- })
153
-
154
- // Dynamic route with params
155
- Route.addRoute("/users/{id}", ({ params : { id } }) => `User #{id} Page`)
156
-
157
- Route.addRoute("/courses/{category}/{name}", ({ params : { category, name } }) => `Course Detail: '${category}/${name}' Page`)
158
- ```
159
-
160
- <br/>
161
-
162
- > Middleware
163
-
164
- * Note: Midddleware is a function to call before every routes
165
-
166
- ```js
167
- import { Route } from "@aref-shojaei/router"
168
-
169
-
170
- // Middleware
171
- const logger = () => console.log("[LOG] my custom middleware")
172
-
173
-
174
- // Single route with middleware
175
- Route.addRoute("/", () => "Welcome Page").middleware([logger])
176
-
177
- // Group routes with middleware
178
- Route.group("/auth", () => {
179
- Route.addRoute("/login", () => "Welcome Page")
180
- Route.addRoute("/register", () => "Welcome Page")
181
- }).middleware([logger])
182
- ```
183
-
184
- <br/>
185
-
186
- > Route Redirection
187
-
188
- ```js
189
- import { Route } from "@aref-shojaei/router"
190
-
191
- Route.addRoute("/auth/login", () => "Welcome Page")
192
- Route.addRoute("/dashboard", () => Route.redirect("/auth/login"))
193
- ```
194
-
195
- <br/>
196
-
197
- > Route page title
198
-
199
- * Note: If I don't use it, page title is applied from document.title by default!
200
-
201
- ```js
202
- import { Route } from "@aref-shojaei/router"
203
-
204
- Route.addRoute("/", () => "Welcome Page").title("Custom Page Title | SPA")
205
- ```
1
+ <div align="center">
2
+
3
+ # 🚀 Router - Lightweight JavaScript SPA Router
4
+
5
+ A lightweight and powerful client-side routing library for building Single Page Applications (SPA) with pure JavaScript.
6
+
7
+ Define routes, manage navigation, handle dynamic parameters, apply middleware, and create seamless page transitions without refreshing the browser.
8
+
9
+ <img src="https://github.com/user-attachments/assets/f1831dc5-f72e-4d7a-806d-b9c01b4be29a" alt="Router SPA Banner" />
10
+
11
+ </div>
12
+
13
+ ---
14
+
15
+ ## ✨ Features
16
+
17
+ * 🚀 Client-side SPA routing
18
+ * 🔗 Browser History API support
19
+ * 📄 Single and grouped routes
20
+ * 🔥 Dynamic route parameters
21
+ * 🛡 Route middleware system
22
+ * 🔀 Route redirection
23
+ * 🏷 Dynamic page titles
24
+ * ⚡ No page refresh navigation
25
+ * 🪶 Lightweight and dependency-free
26
+ * 🧩 Simple and expressive API
27
+
28
+ ---
29
+
30
+ # 📦 Installation
31
+
32
+ ## Using NPM
33
+
34
+ ```bash
35
+ npm install @aref-shojaei/router
36
+ ```
37
+
38
+ ## Using Yarn
39
+
40
+ ```bash
41
+ yarn add @aref-shojaei/router
42
+ ```
43
+
44
+ ---
45
+
46
+ # 🚀 Quick Start
47
+
48
+ Create your `app.js` file:
49
+
50
+ ```javascript
51
+ import { Router, Route } from "@aref-shojaei/router";
52
+
53
+ // Configure browser environment
54
+ Router.configure({
55
+ window,
56
+ document
57
+ });
58
+
59
+ // Create routes
60
+ Route.add("/", () => "Home Page");
61
+
62
+ Route.group("/auth", () => {
63
+ Route.add("/login", () => "Login Page");
64
+ Route.add("/register", () => "Register Page");
65
+ });
66
+
67
+ // Dynamic routes
68
+ Route.add("/users/{id}", ({ params: { id } }) => {
69
+ return `User #${id}`;
70
+ });
71
+
72
+ // Start the router
73
+ Router.run();
74
+ ```
75
+
76
+ ---
77
+
78
+ # 🌐 HTML Integration
79
+
80
+ The router automatically intercepts internal links and updates the page without refreshing the browser.
81
+
82
+ ```html
83
+ <body>
84
+ <nav>
85
+ <a href="/">Home</a>
86
+ <a href="/auth/login">Login</a>
87
+ <a href="/auth/register">Register</a>
88
+ <a href="/users/10">User Profile</a>
89
+ </nav>
90
+
91
+ <div id="root"></div>
92
+
93
+ <script src="app.js"></script>
94
+ </body>
95
+ ```
96
+
97
+ ---
98
+
99
+ # 🏗 Router Workflow
100
+
101
+ ```txt
102
+ User Click
103
+ |
104
+ |
105
+ Browser Event
106
+ |
107
+ |
108
+ Router Engine
109
+ |
110
+ |
111
+ Route Matching
112
+ |
113
+ |
114
+ Middleware
115
+ |
116
+ |
117
+ Component Rendering
118
+ |
119
+ |
120
+ DOM Update
121
+ ```
122
+
123
+ ---
124
+
125
+ # 📚 Routing Guide
126
+
127
+ ## Basic Routes
128
+
129
+ Create simple routes:
130
+
131
+ ```javascript
132
+ Route.add("/", () => "Welcome Page");
133
+
134
+ Route.add("/about", () => "About Page");
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Route Groups
140
+
141
+ Organize related routes together.
142
+
143
+ ```javascript
144
+ Route.group("/auth", () => {
145
+ Route.add("/login", () => "Login Page");
146
+ Route.add("/register", () => "Register Page");
147
+ });
148
+ ```
149
+
150
+ Generated routes:
151
+
152
+ ```txt
153
+ /auth/login
154
+ /auth/register
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Dynamic Routes
160
+
161
+ Capture values directly from the URL.
162
+
163
+ ```javascript
164
+ Route.add("/users/{id}", ({ params: { id } }) => {
165
+ return `User ID: ${id}`;
166
+ });
167
+ ```
168
+
169
+ Multiple parameters:
170
+
171
+ ```javascript
172
+ Route.add(
173
+ "/courses/{category}/{name}",
174
+ ({ params: { category, name } }) => {
175
+ return `${category} / ${name}`;
176
+ }
177
+ );
178
+ ```
179
+
180
+ ---
181
+
182
+ # 🛡 Middleware
183
+
184
+ Middleware allows you to execute custom logic before rendering a route.
185
+
186
+ Common use cases:
187
+
188
+ * Authentication checks
189
+ * Logging
190
+ * Analytics
191
+ * Permissions
192
+ * Data preparation
193
+
194
+ Example:
195
+
196
+ ```javascript
197
+ const logger = () => {
198
+ console.log("[LOG] Route visited");
199
+ };
200
+
201
+ Route.add(
202
+ "/dashboard",
203
+ () => "Dashboard"
204
+ ).middleware([logger]);
205
+ ```
206
+
207
+ Group middleware:
208
+
209
+ ```javascript
210
+ Route.group("/admin", () => {
211
+ Route.add("/users", () => "Users");
212
+ Route.add("/settings", () => "Settings");
213
+ }).middleware([logger]);
214
+ ```
215
+
216
+ ---
217
+
218
+ # 🔀 Route Redirection
219
+
220
+ Redirect users to another route.
221
+
222
+ ```javascript
223
+ Route.add("/login", () => "Login Page");
224
+
225
+ Route.add("/dashboard", () => {
226
+ return Route.redirect("/login");
227
+ });
228
+ ```
229
+
230
+ ---
231
+
232
+ # 🏷 Page Titles
233
+
234
+ Change the browser tab title dynamically.
235
+
236
+ ```javascript
237
+ Route.add("/", () => "Home")
238
+ .title("My Awesome SPA");
239
+ ```
240
+
241
+ If no title is specified, the router uses the default `document.title`.
242
+
243
+ ---
244
+
245
+ # 📂 Example Project Structure
246
+
247
+ ```txt
248
+ my-spa/
249
+ |
250
+ ├── index.html
251
+ |
252
+ ├── app.js
253
+ |
254
+ └── node_modules/
255
+ ```
256
+
257
+ ---
258
+
259
+ # 💡 Use Cases
260
+
261
+ Router can be used for:
262
+
263
+ * Single Page Applications (SPA)
264
+ * Dashboard interfaces
265
+ * Admin panels
266
+ * Personal websites
267
+ * Progressive Web Applications
268
+ * Educational projects to learn routing concepts
269
+
270
+ ---
271
+
272
+ # 🔥 Why Router?
273
+
274
+ Traditional websites require a full page reload for every navigation.
275
+
276
+ With Router:
277
+
278
+ ```txt
279
+ Traditional Website
280
+
281
+ Click Link
282
+ |
283
+ HTTP Request
284
+ |
285
+ Server Response
286
+ |
287
+ Reload Entire Page
288
+
289
+
290
+ SPA Router
291
+
292
+ Click Link
293
+ |
294
+ JavaScript Router
295
+ |
296
+ Change Route
297
+ |
298
+ Update DOM
299
+ ```
300
+
301
+ This results in a faster and smoother user experience.
302
+
303
+ ---
304
+
305
+ # 🧠 Concepts You Will Learn
306
+
307
+ By studying this project, you can understand:
308
+
309
+ * Browser History API
310
+ * URL parsing
311
+ * Route matching algorithms
312
+ * Dynamic parameters
313
+ * Middleware patterns
314
+ * Event handling
315
+ * Client-side rendering
316
+ * SPA architecture
317
+
318
+ ---
319
+
320
+ # 👨‍💻 Author
321
+
322
+ **Aref Shojaei**
323
+ - 📧 Email: [arefshojaei82@gmail.com](mailto:arefshojaei82@gmail.com)
324
+ - 🐙 GitHub: [@ArefShojaei](https://github.com/ArefShojaei)
325
+
326
+ ---
327
+
328
+ # ⭐ Show Your Support
329
+
330
+ If this project helps you understand SPA architecture and client-side routing, consider giving it a **Star ⭐ on GitHub**.
331
+
332
+ Your support helps the project grow.
@@ -1 +1 @@
1
- (()=>{"use strict";class t extends Error{constructor(t){super(t),this.name="Invalid argument error"}}class e{static#t="";static#e="";static#s;constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static setDocument(e){if("object"!=typeof e)throw new t("'document' must be a Document object!");this.#s=e}static _getDocument(){return this.#s}static setTitle(e){if("string"!=typeof e)throw new t("'title' must be a string!");this.#e=e,this.#i()}static getTitle(){return this.#e||this.#t}static setRootTitle(e){if("string"!=typeof e)throw new t("'value' must be a string!");this.#t=e,this.#i()}static getRootTitle(){return this.#t}static#i(){const t=this._getDocument();this.getTitle()?t.title=this.getTitle():t.title=this.getRootTitle()}}class s{constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static render(e,s={}){if("function"!=typeof e)throw new t("'template' must be a function!");try{return e(s)}catch(t){console.error("Error during template rendering: ",t)}}}class i{static#o=[];constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static findAll(e,s){if("string"!=typeof e)throw new t("'element' must be an HTMLElement object!");if("object"!=typeof s)throw new t("'document' must be a Document object!");const i=s.querySelectorAll(e);return this._setElements(i),this}static each(e){if("function"!=typeof e)throw new t("'callback' must be a function!");const s=this._getElements();this.#o.length&&s.forEach(e)}static _setElements(t){this.#o.push(...t)}static _getElements(){return this.#o}}class o{constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static onClick(e,s){if("object"!=typeof e)throw new t("'element' must be an HTMLElement object!");if("function"!=typeof s)throw new t("'callback' must be a function!");e.addEventListener("click",s)}}class r{title="";template;middlewares=[];meta={params:{},query:{}};constructor({title:t,template:e}){this.title=t??this.title,this.template=e}}class n{static _window;static _document;static _rootElement="#root";static _routes={};static _currentRoute="";static _routePrefix="";static _defaultRoute=new r({title:"404",template:()=>"404 | Page not found!"});constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static configure({window:e,document:s,selector:i}){if("object"!=typeof e)throw new t("'window' must be a Window object!");if("object"!=typeof s)throw new t("'document' must be a Document object!");if(i&&"string"!=typeof i)throw new t("'selector' must be a string!");i&&(this._rootElement=i),this._window=e,this._document=s}static#r(t){for(const e in this._routes){const s=new RegExp(`^${e.replace(/\{(\w+)\}/g,"(?<$1>[^/{}]+)")}$`);if(!s.test(t))continue;const{groups:i}=s.exec(t);return this.#n(e),this.#a(e,i),this._routes[e]}}static#n(t){const e={},{search:s}=location;if(!s.length)return!1;s.slice(1).split("&").forEach((t=>{const[s,i]=t.split("=");e[s]=i})),this._routes[t].meta.query={...e}}static#a(t,e){this._routes[t].meta.params={...e}}static _setRouteToURL(e){if("string"!=typeof e||!e.startsWith("/"))throw new t("'route' must be a string starting with \"/\"!");this._window.history.pushState({},"",e)}static#c(t){try{const{title:i,template:o,middlewares:r,meta:n}=this.#r(t)??this._defaultRoute;e.setTitle(i),this.#u(r),this._document.querySelector(this._rootElement).innerHTML=s.render(o,n)}catch(e){console.error("Error to inject route template:",t,e)}}static#l(){this._window.addEventListener("popstate",(t=>{const e=t.target.location.pathname;this.#c(e)}))}static#h(){const{pathname:t}=this._window.location;this.#c(t)}static#w(){i.findAll("a",this._document).each((t=>{o.onClick(t,(t=>{if(t.target.hasAttribute("data-link"))return!1;t.preventDefault();const e=t.target.getAttribute("href");this._setRouteToURL(e),this.#c(e)}))}))}static#u(t){try{t.length&&t.forEach((t=>t()))}catch(t){console.error("Error executing middleware:",t)}}static run(s=(()=>{})){if("function"!=typeof s)throw new t("'callback' must be a function!");e.setDocument(this._document),e.setRootTitle(this._document.title),this.#l(),this.#h(),this.#w(),s()}}window.Router=n,window.Route=class extends n{constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static addRoute(e,s){if("string"!=typeof e)throw new t("'route' must be a string!");if("function"!=typeof s)throw new t("'callback' must be a function!");return this._routes[this._routePrefix+e]=new r({template:s}),this._currentRoute=e,this}static group(e,s){if("string"!=typeof e||!e.startsWith("/"))throw new t("'prefix' must be a string!");if("function"!=typeof s)throw new t("'callback' must be a function!");const i=this._routePrefix;return this._routePrefix=e,s(),this._routePrefix=i,this}static middleware(e){if(!Array.isArray(e))throw new t("'middlewares' must be an array!");if(this._routePrefix)for(const t in this._routes)t.startsWith(this._routePrefix)&&this._routes[t].middlewares.push(...e);else this._routes[this._routePrefix+this._currentRoute].middlewares.push(...e)}static title(e){if("string"!=typeof e)throw new t("'value' must be a string!");this._routes[this._routePrefix+this._currentRoute].title=e}static redirect(e){if("string"!=typeof e||!e.startsWith("/"))throw new t("'to' must be a string starting route with \"/\"!");this._setRouteToURL(e);const{template:i,meta:o}=this._routes[e]??this._defaultRoute;return s.render(i,o)}}})();
1
+ (()=>{"use strict";class t extends Error{constructor(t){super(t),this.name="Invalid argument error"}}class e{static#t="";static#e="";static#s;constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static setDocument(e){if("object"!=typeof e)throw new t("'document' must be a Document object!");this.#s=e}static _getDocument(){return this.#s}static setTitle(e){if("string"!=typeof e)throw new t("'title' must be a string!");this.#e=e,this.#i()}static getTitle(){return this.#e||this.#t}static setRootTitle(e){if("string"!=typeof e)throw new t("'value' must be a string!");this.#t=e,this.#i()}static getRootTitle(){return this.#t}static#i(){const t=this._getDocument();this.getTitle()?t.title=this.getTitle():t.title=this.getRootTitle()}}class s{constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static render(e,s={}){if("function"!=typeof e)throw new t("'template' must be a function!");try{return e(s)}catch(t){console.error("Error during template rendering: ",t)}}}class i{static#o=[];constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static findAll(e,s){if("string"!=typeof e)throw new t("'element' must be an HTMLElement object!");if("object"!=typeof s)throw new t("'document' must be a Document object!");const i=s.querySelectorAll(e);return this._setElements(i),this}static each(e){if("function"!=typeof e)throw new t("'callback' must be a function!");const s=this._getElements();this.#o.length&&s.forEach(e)}static _setElements(t){this.#o.push(...t)}static _getElements(){return this.#o}}class o{constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static onClick(e,s){if("object"!=typeof e)throw new t("'element' must be an HTMLElement object!");if("function"!=typeof s)throw new t("'callback' must be a function!");e.addEventListener("click",s)}}class r{title="";template;middlewares=[];meta={params:{},query:{}};constructor({title:t,template:e}){this.title=t??this.title,this.template=e}}class n{static _window;static _document;static _rootElement="#root";static _routes={};static _currentRoute="";static _routePrefix="";static _defaultRoute=new r({title:"404",template:()=>"404 | Page not found!"});constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static configure({window:e,document:s,selector:i}){if("object"!=typeof e)throw new t("'window' must be a Window object!");if("object"!=typeof s)throw new t("'document' must be a Document object!");if(i&&"string"!=typeof i)throw new t("'selector' must be a string!");i&&(this._rootElement=i),this._window=e,this._document=s}static#r(t){for(const e in this._routes){const s=new RegExp(`^${e.replace(/\{(\w+)\}/g,"(?<$1>[^/{}]+)")}$`);if(!s.test(t))continue;const{groups:i}=s.exec(t);return this.#n(e),this.#a(e,i),this._routes[e]}}static#n(t){const e={},{search:s}=location;if(!s.length)return!1;s.slice(1).split("&").forEach((t=>{const[s,i]=t.split("=");e[s]=i})),this._routes[t].meta.query={...e}}static#a(t,e){this._routes[t].meta.params={...e}}static _setRouteToURL(e){if("string"!=typeof e||!e.startsWith("/"))throw new t("'route' must be a string starting with \"/\"!");this._window.history.pushState({},"",e)}static#c(t){try{const{title:i,template:o,middlewares:r,meta:n}=this.#r(t)??this._defaultRoute;e.setTitle(i),this.#u(r),this._document.querySelector(this._rootElement).innerHTML=s.render(o,n)}catch(e){console.error("Error to inject route template:",t,e)}}static#l(){this._window.addEventListener("popstate",(t=>{const e=t.target.location.pathname;this.#c(e)}))}static#h(){const{pathname:t}=this._window.location;this.#c(t)}static#w(){i.findAll("a",this._document).each((t=>{o.onClick(t,(t=>{if(t.target.hasAttribute("data-link"))return!1;t.preventDefault();const e=t.target.getAttribute("href");this._setRouteToURL(e),this.#c(e)}))}))}static#u(t){try{t.length&&t.forEach((t=>t()))}catch(t){console.error("Error executing middleware:",t)}}static run(s=(()=>{})){if("function"!=typeof s)throw new t("'callback' must be a function!");e.setDocument(this._document),e.setRootTitle(this._document.title),this.#l(),this.#h(),this.#w(),s()}}window.Router=n,window.Route=class extends n{constructor(){throw new Error(`${new.target.name} class must not be called with "new" keyword!`)}static add(e,s){if("string"!=typeof e)throw new t("'route' must be a string!");if("function"!=typeof s)throw new t("'callback' must be a function!");return this._routes[this._routePrefix+e]=new r({template:s}),this._currentRoute=e,this}static group(e,s){if("string"!=typeof e||!e.startsWith("/"))throw new t("'prefix' must be a string!");if("function"!=typeof s)throw new t("'callback' must be a function!");const i=this._routePrefix;return this._routePrefix=e,s(),this._routePrefix=i,this}static middleware(e){if(!Array.isArray(e))throw new t("'middlewares' must be an array!");if(this._routePrefix)for(const t in this._routes)t.startsWith(this._routePrefix)&&this._routes[t].middlewares.push(...e);else this._routes[this._routePrefix+this._currentRoute].middlewares.push(...e)}static title(e){if("string"!=typeof e)throw new t("'value' must be a string!");this._routes[this._routePrefix+this._currentRoute].title=e}static redirect(e){if("string"!=typeof e||!e.startsWith("/"))throw new t("'to' must be a string starting route with \"/\"!");this._setRouteToURL(e);const{template:i,meta:o}=this._routes[e]??this._defaultRoute;return s.render(i,o)}}})();
@@ -1,46 +1,46 @@
1
- * {
2
- box-sizing: border-box;
3
- padding: 0;
4
- margin: 0;
5
- font-family: sans-serif;
6
- }
7
-
8
- body {
9
- display: flex;
10
- flex-direction: column;
11
- align-items: center;
12
- padding: 24px;
13
- }
14
-
15
- ul {
16
- display: flex;
17
- align-items: center;
18
- margin-top: 16px;
19
- }
20
-
21
- ul li {
22
- margin: 0 24px;
23
- list-style: none;
24
- }
25
-
26
- ul li a {
27
- padding: 4 8px;
28
- color: #81a6f4;
29
- text-decoration: none;
30
- }
31
-
32
- ul li a:hover {
33
- color: #2b2b2a;
34
- transition: all .5s ease;
35
- }
36
-
37
-
38
- #root {
39
- padding: 16px;
40
- text-align: center;
41
- margin-top: 40px;
42
- background: #ded7d7;
43
- width: 600px;
44
- height: 250px;
45
- border-radius: 16px;
1
+ * {
2
+ box-sizing: border-box;
3
+ padding: 0;
4
+ margin: 0;
5
+ font-family: sans-serif;
6
+ }
7
+
8
+ body {
9
+ display: flex;
10
+ flex-direction: column;
11
+ align-items: center;
12
+ padding: 24px;
13
+ }
14
+
15
+ ul {
16
+ display: flex;
17
+ align-items: center;
18
+ margin-top: 16px;
19
+ }
20
+
21
+ ul li {
22
+ margin: 0 24px;
23
+ list-style: none;
24
+ }
25
+
26
+ ul li a {
27
+ padding: 4 8px;
28
+ color: #81a6f4;
29
+ text-decoration: none;
30
+ }
31
+
32
+ ul li a:hover {
33
+ color: #2b2b2a;
34
+ transition: all .5s ease;
35
+ }
36
+
37
+
38
+ #root {
39
+ padding: 16px;
40
+ text-align: center;
41
+ margin-top: 40px;
42
+ background: #ded7d7;
43
+ width: 600px;
44
+ height: 250px;
45
+ border-radius: 16px;
46
46
  }
@@ -1,8 +1,8 @@
1
- Router.configure({ window, document })
2
-
3
- Route.addRoute("/", () => "Welcome Page")
4
- Route.addRoute("/users", () => "Users Page")
5
- Route.addRoute("/users/{name}", ({ params : { name } }) => `User #${name} Page`)
6
- Route.addRoute("/redirection", () => Route.redirect("/"))
7
-
1
+ Router.configure({ window, document })
2
+
3
+ Route.add("/", () => "Welcome Page")
4
+ Route.add("/users", () => "Users Page")
5
+ Route.add("/users/{name}", ({ params : { name } }) => `User #${name} Page`)
6
+ Route.add("/redirection", () => Route.redirect("/"))
7
+
8
8
  Router.run()