nextia 6.0.2 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -15
  3. package/package.json +13 -11
  4. package/src/lib.js +57 -77
  5. package/src/bin.js +0 -233
  6. package/src/template/README.md +0 -30
  7. package/src/template/_env.dev +0 -1
  8. package/src/template/_env.prod +0 -1
  9. package/src/template/_env.test +0 -1
  10. package/src/template/_gitignore +0 -9
  11. package/src/template/biome.json +0 -43
  12. package/src/template/package.json +0 -37
  13. package/src/template/public/error.html +0 -14
  14. package/src/template/public/logo.svg +0 -865
  15. package/src/template/src/assets/i18n/index.js +0 -8
  16. package/src/template/src/assets/img/image.jpg +0 -0
  17. package/src/template/src/components/I18n/index.jsx +0 -23
  18. package/src/template/src/components/Icon/index.jsx +0 -48
  19. package/src/template/src/components/Link/index.jsx +0 -14
  20. package/src/template/src/components/Translate/index.jsx +0 -31
  21. package/src/template/src/components/Translate/style.css +0 -2
  22. package/src/template/src/components/index.js +0 -6
  23. package/src/template/src/index.html +0 -18
  24. package/src/template/src/index.jsx +0 -5
  25. package/src/template/src/pages/demo/functions.js +0 -3
  26. package/src/template/src/pages/demo/index.jsx +0 -10
  27. package/src/template/src/pages/demo/style.css +0 -2
  28. package/src/template/src/pages/functions.js +0 -9
  29. package/src/template/src/pages/home/functions.js +0 -43
  30. package/src/template/src/pages/home/index.jsx +0 -10
  31. package/src/template/src/pages/home/style.css +0 -2
  32. package/src/template/src/pages/http/not-found/index.jsx +0 -19
  33. package/src/template/src/pages/http/not-found/style.css +0 -2
  34. package/src/template/src/pages/index.jsx +0 -65
  35. package/src/template/src/theme/animations.css +0 -30
  36. package/src/template/src/theme/fonts/Roboto-Regular.ttf +0 -0
  37. package/src/template/src/theme/fonts/index.css +0 -7
  38. package/src/template/src/theme/icons/icons.svg +0 -121
  39. package/src/template/src/theme/icons/index.css +0 -1
  40. package/src/template/src/theme/index.css +0 -40
  41. package/src/template/src/theme/util.css +0 -27
  42. package/src/template/src/utils/hooks.js +0 -23
  43. package/src/template/src/utils/index.js +0 -14
  44. package/src/template/vite.config.js +0 -97
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Sinuhe Dev. https://sinuhe.dev
3
+ Copyright (c) 2025 Sinuhe Maceda https://sinuhe.dev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,26 +1,16 @@
1
1
  # nextia
2
+
2
3
  Create fast web applications
3
4
 
4
5
  ### To start
5
- ```sh
6
- npm install
7
- pnpm install
8
- #
9
- cd test
10
- ```
11
6
 
12
- ### To test
13
7
  ```sh
14
8
  npm install
15
- pnpm install
16
- #
17
- node --run test:my-app
9
+ cd test-webapp
10
+ npm install
11
+ node --run dev
18
12
  ```
19
13
 
20
- ### To create project
21
- ```sh
22
- pnpm i -g nextia
23
- nextia my-app
24
- ```
14
+ ### npmjs
25
15
 
26
16
  [npmjs.com/package/nextia](https://www.npmjs.com/package/nextia)
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "nextia",
3
3
  "description": "Create fast web applications",
4
- "version": "6.0.2",
4
+ "version": "6.1.1",
5
5
  "engines": {
6
6
  "node": ">22"
7
7
  },
8
8
  "type": "module",
9
9
  "license": "MIT",
10
10
  "author": {
11
- "name": "Sinuhe Dev.",
11
+ "name": "Sinuhe Maceda",
12
12
  "email": "sinuhe.dev@gmail.com",
13
13
  "url": "https://sinuhe.dev"
14
14
  },
@@ -20,23 +20,25 @@
20
20
  "keywords": [
21
21
  "react"
22
22
  ],
23
- "bin": {
24
- "nextia": "src/bin.js"
25
- },
26
23
  "main": "src/lib.js",
27
24
  "scripts": {
28
- "clean": "rm -fr node_modules package-lock.json pnpm-lock.yaml .coverage out my-app",
25
+ "clean": "rm -fr node_modules package-lock.json pnpm-lock.yaml .coverage target",
29
26
  "format": "biome format",
30
- "lint": "biome lint",
31
- "check": "biome check --reporter=summary",
32
- "test": "node src/bin.js",
33
- "test:my-app": "node src/bin.js my-app"
27
+ "lint": "biome lint src",
28
+ "check": "biome check --reporter=summary src",
29
+ "test": "vitest run",
30
+ "test:name": "vitest run --testNamePattern",
31
+ "test:silent": "vitest run --silent",
32
+ "test:coverage": "vitest run --silent --coverage"
34
33
  },
35
34
  "peerDependencies": {
36
35
  "react": "^19.2.3",
37
36
  "react-dom": "^19.2.3"
38
37
  },
39
38
  "devDependencies": {
40
- "@biomejs/biome": "^2.3.14"
39
+ "@vitejs/plugin-react": "^6.0.1",
40
+ "@vitest/coverage-v8": "^4.0.18",
41
+ "jsdom": "^29.0.0",
42
+ "vitest": "^4.0.18"
41
43
  }
42
44
  }
package/src/lib.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) 2025 Sinuhe Dev. https://sinuhe.dev
2
+ * Copyright (c) 2025 Sinuhe Maceda https://sinuhe.dev
3
3
  *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -7,36 +7,34 @@
7
7
  * https://github.com/sinuhedev/nextia
8
8
  */
9
9
 
10
- import { createContext, use, useReducer, useCallback } from 'react'
10
+ import { createContext, use, useReducer } from 'react'
11
11
 
12
- const Context = createContext()
12
+ const PagesContext = createContext()
13
+ const isLogger = import.meta.env.DEV
13
14
 
14
15
  /**
15
- * css
16
+ * util
16
17
  */
18
+
17
19
  function css(...classNames) {
18
- classNames = classNames
19
- .filter((e) => e)
20
+ return classNames
20
21
  .reduce((accumulator, currentValue) => {
21
22
  if (typeof currentValue === 'string') {
22
- accumulator.push(currentValue)
23
+ accumulator.push(currentValue.trim())
23
24
  } else if (
24
25
  !Array.isArray(currentValue) &&
25
26
  typeof currentValue === 'object'
26
27
  ) {
27
28
  for (const e in currentValue) {
28
- if (currentValue[e]) accumulator.push(e)
29
+ if (currentValue[e]) accumulator.push(e.trim())
29
30
  }
30
31
  }
31
32
  return accumulator
32
33
  }, [])
33
-
34
- return [...new Set(classNames)].join(' ')
34
+ .filter((e) => e)
35
+ .join(' ')
35
36
  }
36
37
 
37
- /**
38
- * values
39
- */
40
38
  function values(state, payload, value) {
41
39
  const paths = payload.split('.')
42
40
 
@@ -63,9 +61,6 @@ function values(state, payload, value) {
63
61
  return stateClone
64
62
  }
65
63
 
66
- /**
67
- * merge
68
- */
69
64
  function merge(target, source) {
70
65
  // in array return all source
71
66
  if (Array.isArray(target)) return source
@@ -83,60 +78,10 @@ function merge(target, source) {
83
78
  return output
84
79
  }
85
80
 
86
- /**
87
- * logger
88
- */
89
-
90
- const logger = () => {
91
- if (import.meta?.env) {
92
- return import.meta.env.DEV && import.meta.env.VITE_LOGGER !== 'false'
93
- }
94
- }
95
-
96
- const log = (reducer) => {
97
- const getPayload = (action) => {
98
- const { type, payload } = action
99
-
100
- if (type === 'change') {
101
- const { name, type, checked, value } = payload.target
102
- return {
103
- name,
104
- type,
105
- checked,
106
- value
107
- }
108
- }
109
-
110
- if (typeof payload !== 'object') {
111
- return `(${payload ?? ''})`
112
- }
113
-
114
- return payload
115
- }
116
-
117
- const reducerWithLogger = useCallback(
118
- (state, action) => {
119
- const newState = reducer(state, action)
120
-
121
- console.log(
122
- `%c${action.isContext ? 'Context' : 'Page '} %c${action.type}`,
123
- 'color: #90b1d1',
124
- 'color: #6592c8',
125
- getPayload(action),
126
- { state, new_state: newState }
127
- )
128
-
129
- return newState
130
- },
131
- [reducer]
132
- )
133
-
134
- return reducerWithLogger
135
- }
136
-
137
81
  /**
138
82
  * reducer
139
83
  */
84
+
140
85
  const reducer = (state, action) => {
141
86
  const { type, payload, initialState } = action
142
87
 
@@ -182,14 +127,49 @@ const reducer = (state, action) => {
182
127
  }
183
128
  }
184
129
 
130
+ const reducerLogger = (state, action) => {
131
+ const newState = reducer(state, action)
132
+
133
+ const payloadLog = (action) => {
134
+ const { type, payload } = action
135
+
136
+ if (type === 'change') {
137
+ const { name, type, checked, value } = payload.target
138
+ return {
139
+ name,
140
+ type,
141
+ checked,
142
+ value
143
+ }
144
+ }
145
+
146
+ if (typeof payload !== 'object') {
147
+ return `(${payload ?? ''})`
148
+ }
149
+
150
+ return payload
151
+ }
152
+
153
+ console.log(
154
+ `%c${action.isContext ? 'Pages Context' : 'Page'} %c${action.type}`,
155
+ 'color: #90b1d1',
156
+ 'color: #6592c8',
157
+ payloadLog(action),
158
+ { state, new_state: newState }
159
+ )
160
+
161
+ return newState
162
+ }
163
+
185
164
  /**
186
165
  * useFx
187
166
  */
167
+
188
168
  function useFx(functions = { initialState: {} }) {
189
- const context = use(Context)
169
+ const pageContext = use(PagesContext)
190
170
  const { initialState } = functions
191
171
  const [state, dispatch] = useReducer(
192
- logger() ? log(reducer) : reducer,
172
+ isLogger ? reducerLogger : reducer,
193
173
  initialState
194
174
  )
195
175
 
@@ -197,7 +177,7 @@ function useFx(functions = { initialState: {} }) {
197
177
  const commonActions = ['set', 'show', 'hide', 'change', 'reset'].reduce(
198
178
  (acc, e) => {
199
179
  acc[e] = (payload) =>
200
- dispatch({ type: e, payload, initialState, isContext: !context })
180
+ dispatch({ type: e, payload, initialState, isContext: !pageContext })
201
181
  return acc
202
182
  },
203
183
  {}
@@ -207,16 +187,16 @@ function useFx(functions = { initialState: {} }) {
207
187
  const actions = Object.keys(functions).reduce((ac, e) => {
208
188
  if (functions[e] instanceof Function) {
209
189
  ac[e] = (payload) => {
210
- const props = {
190
+ const actionsProps = {
211
191
  ...commonActions,
212
192
  state,
213
193
  payload
214
194
  }
215
- if (context) {
216
- props.context = context
195
+ if (pageContext) {
196
+ actionsProps.context = pageContext
217
197
  }
218
198
 
219
- return functions[e](Object.freeze(props))
199
+ return functions[e](Object.freeze(actionsProps))
220
200
  }
221
201
  }
222
202
  return ac
@@ -228,11 +208,11 @@ function useFx(functions = { initialState: {} }) {
228
208
  state,
229
209
  fx: { ...commonActions, ...actions }
230
210
  }
231
- if (context) {
232
- props.context = context
211
+ if (pageContext) {
212
+ props.context = pageContext
233
213
  }
234
214
 
235
215
  return Object.freeze(props)
236
216
  }
237
217
 
238
- export { css, Context, useFx }
218
+ export { css, PagesContext, useFx }
package/src/bin.js DELETED
@@ -1,233 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Copyright (c) 2025 Sinuhe Dev. https://sinuhe.dev
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file in the root directory of this source tree.
8
- *
9
- * https://github.com/sinuhedev/nextia
10
- */
11
-
12
- import pkg from '../package.json' with { type: 'json' }
13
- import { fileURLToPath } from 'node:url'
14
- import { dirname } from 'node:path'
15
- import {
16
- mkdir,
17
- writeFile,
18
- readFile,
19
- cp,
20
- rename,
21
- access
22
- } from 'node:fs/promises'
23
-
24
- async function createPage(name) {
25
- const toPascalCase = (str) =>
26
- str
27
- .toLowerCase()
28
- .replace(/[^a-zA-Z0-9 ]/g, ' ') // replace special characters
29
- .split(/\s+/) // split by spaces
30
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
31
- .join('')
32
-
33
- const dirName = `./src/pages/${name}`
34
-
35
- try {
36
- await mkdir(dirName)
37
-
38
- const pageName = toPascalCase(name) + 'Page'
39
-
40
- // index.jsx
41
- writeFile(
42
- `${dirName}/index.jsx`,
43
- `import React, { useEffect } from 'react'
44
- import { useFx, css } from 'nextia'
45
- import functions from './functions'
46
- import './style.css'
47
-
48
- export default function ${pageName} () {
49
- const { state, fx } = useFx(functions)
50
-
51
- return (
52
- <section className={css('${pageName}', '')}>
53
- ${pageName}
54
- </section>
55
- )
56
- }
57
- `
58
- )
59
-
60
- // style.sss
61
- writeFile(
62
- `${dirName}/style.css`,
63
- `.${pageName} {
64
- }`
65
- )
66
-
67
- // function.js
68
- writeFile(
69
- `${dirName}/functions.js`,
70
- `const initialState = {
71
- }
72
-
73
- export default { initialState }
74
- `
75
- )
76
- } catch (err) {
77
- console.error(err)
78
- }
79
- }
80
-
81
- async function createComponent(name) {
82
- const dirName = `./src/components/${name}`
83
-
84
- try {
85
- await mkdir(dirName)
86
- const componentName = name.replaceAll('/', '') + '-component'
87
-
88
- // index.jsx
89
- writeFile(
90
- `${dirName}/index.jsx`,
91
- `import React, { useEffect } from 'react'
92
- import { css } from 'nextia'
93
- import './style.css'
94
-
95
- export default function ${name} ({ className, style }) {
96
- return (
97
- <article className={css('${componentName}', className)} style={style}>
98
- ${componentName}
99
- </article>
100
- )
101
- }
102
- `
103
- )
104
-
105
- // style.css
106
- writeFile(
107
- `${dirName}/style.css`,
108
- `.${componentName} {
109
- }`
110
- )
111
- } catch (err) {
112
- console.error(err)
113
- }
114
- }
115
-
116
- async function createComponentFx(name) {
117
- const dirName = `./src/components/${name}`
118
-
119
- try {
120
- await mkdir(dirName)
121
- const containerName = name.replaceAll('/', '') + '-component'
122
-
123
- // index.jsx
124
- writeFile(
125
- `${dirName}/index.jsx`,
126
- `import React, { useEffect } from 'react'
127
- import { useFx, css } from 'nextia'
128
- import functions from './functions'
129
- import './style.css'
130
-
131
- export default function ${name} ({ className, style }) {
132
- const { state, fx } = useFx(functions)
133
-
134
- return (
135
- <article className={css('${containerName}', className, '')} style={style}>
136
- ${containerName}
137
- </article>
138
- )
139
- }
140
- `
141
- )
142
-
143
- // style.css
144
- writeFile(
145
- `${dirName}/style.css`,
146
- `.${containerName} {
147
- }`
148
- )
149
-
150
- // function.js
151
- writeFile(
152
- `${dirName}/functions.js`,
153
- `const initialState = {
154
- }
155
-
156
- export default { initialState }
157
- `
158
- )
159
- } catch (err) {
160
- console.error(err)
161
- }
162
- }
163
-
164
- async function createProject(name) {
165
- let projectPath
166
-
167
- try {
168
- projectPath = process.cwd() + `/${name}/`
169
- await access(projectPath)
170
- console.error(`The "${name}" already exists.`)
171
- return
172
- } catch (error) {}
173
-
174
- const template = dirname(fileURLToPath(import.meta.url)) + '/template/'
175
-
176
- // Create new project
177
- try {
178
- const mv = (fileName) =>
179
- rename(projectPath + `_${fileName}`, projectPath + `.${fileName}`)
180
- await cp(template, projectPath, { recursive: true })
181
- const replaceToken = async (filename, token, value) => {
182
- const content = await readFile(projectPath + filename, 'utf8')
183
- const updated = content.replaceAll(token, value)
184
- await writeFile(projectPath + filename, updated, 'utf8')
185
- }
186
-
187
- await mv('env.dev')
188
- await mv('env.prod')
189
- await mv('env.test')
190
- await mv('gitignore')
191
-
192
- // replace tokens
193
- await replaceToken('README.md', 'TEMPLATE', name)
194
- await replaceToken('package.json', 'TEMPLATE', name)
195
- await replaceToken('package.json', 'VERSION', pkg.version)
196
- } catch (err) {
197
- console.error(err)
198
- }
199
- }
200
-
201
- /**
202
- * main
203
- */
204
-
205
- const ARG1 = process.argv[2]
206
- const ARG2 = process.argv[3]
207
-
208
- switch (ARG1) {
209
- case 'page':
210
- if (ARG2) createPage(ARG2)
211
- else console.warn('node --run page <page-name>')
212
- break
213
-
214
- case 'component':
215
- if (ARG2) createComponent(ARG2)
216
- else console.warn('node --run component <ComponentName>')
217
- break
218
-
219
- case 'container':
220
- if (ARG2) createComponentFx(ARG2)
221
- else console.warn('node --run container <ContainerName>')
222
- break
223
-
224
- default:
225
- if (ARG1) createProject(ARG1)
226
- else
227
- console.info(`
228
- Version ${pkg.version}
229
-
230
- npx nextia@latest <ProjectName>
231
- `)
232
- break
233
- }
@@ -1,30 +0,0 @@
1
- # TEMPLATE
2
-
3
- # To start
4
- Open http://localhost:3000 to view it in the browser.
5
-
6
- ```sh
7
- npm install
8
- pnpm install
9
- #
10
- node --run dev
11
- node --run test
12
- node --run build <ENV>
13
- node --run preview
14
- ```
15
-
16
- # env
17
- ```.env
18
- .env # loaded in all cases
19
- .env.[ENV] # only loaded in specified ENV [ dev, test, prod ]
20
- ```
21
-
22
- * .env.dev
23
- * .env.prod
24
- * .env.test
25
-
26
- ```env
27
- VITE_TITLE=TITLE
28
- VITE_LOGGER=false
29
- VITE_VIEW_TRANSITION=false
30
- ```
@@ -1 +0,0 @@
1
- VITE_TITLE=dev
@@ -1 +0,0 @@
1
- VITE_TITLE=prod
@@ -1 +0,0 @@
1
- VITE_TITLE=test
@@ -1,9 +0,0 @@
1
- node_modules
2
- out
3
-
4
- .coverage
5
- .env
6
- .env.*
7
-
8
- deploy
9
- deploy-variables
@@ -1,43 +0,0 @@
1
- {
2
- "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
3
- "assist": {
4
- "actions": {
5
- "source": {
6
- "organizeImports": "off"
7
- }
8
- }
9
- },
10
- "linter": {
11
- "enabled": true,
12
- "rules": {
13
- "recommended": true,
14
- "correctness": {
15
- "noUnusedVariables": "error"
16
- }
17
- }
18
- },
19
- "formatter": {
20
- "enabled": true,
21
- "formatWithErrors": false,
22
- "indentStyle": "space",
23
- "indentWidth": 2
24
- },
25
- "javascript": {
26
- "formatter": {
27
- "semicolons": "asNeeded",
28
- "quoteStyle": "single",
29
- "jsxQuoteStyle": "double",
30
- "trailingCommas": "none"
31
- }
32
- },
33
- "css": {
34
- "formatter": {
35
- "enabled": true
36
- }
37
- },
38
- "json": {
39
- "formatter": {
40
- "enabled": true
41
- }
42
- }
43
- }
@@ -1,37 +0,0 @@
1
- {
2
- "name": "TEMPLATE",
3
- "description": "description",
4
- "version": "0.0.0",
5
- "type": "module",
6
- "private": true,
7
- "scripts": {
8
- "dev": "vite --mode dev",
9
- "clean": "rm -fr node_modules package-lock.json pnpm-lock.yaml .coverage out",
10
- "build": "vite build --mode",
11
- "preview": "vite preview",
12
- "format": "biome format",
13
- "lint": "biome lint",
14
- "check": "biome check --reporter=summary",
15
- "page": "nextia page",
16
- "component": "nextia component",
17
- "componentFx": "nextia componentFx",
18
- "test": "vitest",
19
- "test:name": "vitest run --testNamePattern",
20
- "test:silent": "vitest run --silent",
21
- "test:coverage": "vitest run --silent --coverage"
22
- },
23
- "devDependencies": {
24
- "@biomejs/biome": "^2.3.14",
25
- "@vitejs/plugin-react": "^5.1.3",
26
- "@vitest/coverage-v8": "4.0.18",
27
- "autoprefixer": "^10.4.24",
28
- "jsdom": "^28.0.0",
29
- "vite": "^7.3.1",
30
- "vitest": "4.0.18"
31
- },
32
- "dependencies": {
33
- "nextia": "^VERSION",
34
- "react": "^19.2.4",
35
- "react-dom": "^19.2.4"
36
- }
37
- }
@@ -1,14 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
-
4
- <head>
5
- <meta charset="UTF-8" />
6
- <title>Error</title>
7
- <link rel="shortcut icon" href="logo.svg" />
8
- </head>
9
-
10
- <body>
11
- Error ...
12
- </body>
13
-
14
- </html>