nextia 6.1.1 → 7.0.2

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 (76) hide show
  1. package/README.md +1 -1
  2. package/biome.json +21 -0
  3. package/package.json +13 -8
  4. package/src/bin.js +239 -0
  5. package/src/{lib.js → lib/fx.js} +18 -33
  6. package/src/lib/index.js +32 -0
  7. package/src/lib/ui.js +112 -0
  8. package/src/lib/utils.js +107 -0
  9. package/template/README.md +29 -0
  10. package/template/_env.dev +4 -0
  11. package/template/_env.prod +1 -0
  12. package/template/_env.test +1 -0
  13. package/template/_gitignore +10 -0
  14. package/template/biome.json +21 -0
  15. package/template/package.json +35 -0
  16. package/template/public/error.html +14 -0
  17. package/template/public/logo.svg +105 -0
  18. package/template/src/assets/i18n/index.js +26 -0
  19. package/template/src/assets/img/image.svg +6 -0
  20. package/template/src/assets/img/image.webp +0 -0
  21. package/template/src/components/Counter/index.jsx +33 -0
  22. package/template/src/components/Counter/style.css +5 -0
  23. package/template/src/components/Message/index.jsx +12 -0
  24. package/template/src/components/index.js +6 -0
  25. package/template/src/components/ui/Translate/index.jsx +20 -0
  26. package/template/src/index.html +18 -0
  27. package/template/src/index.jsx +4 -0
  28. package/template/src/pages/env/functions.js +3 -0
  29. package/template/src/pages/env/index.jsx +26 -0
  30. package/template/src/pages/env/style.css +2 -0
  31. package/template/src/pages/functions.js +37 -0
  32. package/template/src/pages/home/functions.js +43 -0
  33. package/template/src/pages/home/index.jsx +211 -0
  34. package/template/src/pages/home/style.css +51 -0
  35. package/template/src/pages/http/not-found/index.jsx +10 -0
  36. package/template/src/pages/http/not-found/style.css +2 -0
  37. package/template/src/pages/icons/functions.js +3 -0
  38. package/template/src/pages/icons/index.jsx +21 -0
  39. package/template/src/pages/icons/style.css +8 -0
  40. package/template/src/pages/images/functions.js +3 -0
  41. package/template/src/pages/images/index.jsx +25 -0
  42. package/template/src/pages/images/style.css +27 -0
  43. package/template/src/pages/index.jsx +124 -0
  44. package/template/src/pages/mockapi/functions.js +71 -0
  45. package/template/src/pages/mockapi/index.jsx +101 -0
  46. package/template/src/pages/mockapi/style.css +57 -0
  47. package/template/src/pages/my-context/functions.js +7 -0
  48. package/template/src/pages/my-context/index.jsx +32 -0
  49. package/template/src/pages/my-context/style.css +2 -0
  50. package/template/src/pages/resize/functions.js +3 -0
  51. package/template/src/pages/resize/index.jsx +15 -0
  52. package/template/src/pages/resize/style.css +2 -0
  53. package/template/src/pages/search-params/functions.js +3 -0
  54. package/template/src/pages/search-params/index.jsx +35 -0
  55. package/template/src/pages/search-params/style.css +2 -0
  56. package/template/src/pages/subpage/hello/functions.js +3 -0
  57. package/template/src/pages/subpage/hello/index.jsx +11 -0
  58. package/template/src/pages/subpage/hello/style.css +2 -0
  59. package/template/src/pages/translate/functions.js +5 -0
  60. package/template/src/pages/translate/index.jsx +31 -0
  61. package/template/src/pages/translate/style.css +12 -0
  62. package/template/src/pages/view-transition/functions.js +6 -0
  63. package/template/src/pages/view-transition/index.jsx +30 -0
  64. package/template/src/pages/view-transition/style.css +2 -0
  65. package/template/src/services/api.js +9 -0
  66. package/template/src/services/http.js +40 -0
  67. package/template/src/theme/fonts/Roboto-Regular.ttf +0 -0
  68. package/template/src/theme/fonts/index.css +7 -0
  69. package/template/src/theme/icons/icons.svg +125 -0
  70. package/template/src/theme/icons/index.css +55 -0
  71. package/template/src/theme/index.css +39 -0
  72. package/template/src/theme/utils/index.css +29 -0
  73. package/template/src/theme/utils/view-transition.css +72 -0
  74. package/template/src/utils/index.js +5 -0
  75. package/template/test/index.test.js +11 -0
  76. package/template/vite.config.js +97 -0
@@ -0,0 +1,31 @@
1
+ import { css, I18n, useFx } from 'nextia'
2
+ import functions from './functions'
3
+ import './style.css'
4
+ import { Message } from 'components'
5
+
6
+ export default function TranslatePage() {
7
+ const { state, fx } = useFx(functions)
8
+
9
+ return (
10
+ <section className={css('TranslatePage', '')}>
11
+ <I18n value="page.name" args={['Sinuhe', 'Maceda', 'Bouchan']} />
12
+
13
+ <ul>
14
+ <li>
15
+ <I18n value="ui.ok" />
16
+ </li>
17
+ <li>
18
+ <I18n value="ui.back" />
19
+ </li>
20
+ <li>
21
+ <I18n value="page.user.family" />
22
+ </li>
23
+ <li>
24
+ <I18n value="page.module.block.docker" />
25
+ </li>
26
+ </ul>
27
+
28
+ <Message />
29
+ </section>
30
+ )
31
+ }
@@ -0,0 +1,12 @@
1
+ .TranslatePage {
2
+ margin: 20px;
3
+
4
+ h3 {
5
+ color: gray;
6
+ }
7
+
8
+ button {
9
+ width: 40px;
10
+ margin: 15px;
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ const initialState = {
2
+ count: 1,
3
+ count2: 1
4
+ }
5
+
6
+ export default { initialState }
@@ -0,0 +1,30 @@
1
+ import { Counter } from 'components'
2
+ import { css, useFx } from 'nextia'
3
+ import functions from './functions'
4
+ import './style.css'
5
+
6
+ export default function ViewTransitionPage() {
7
+ const { state, fx } = useFx(functions)
8
+
9
+ return (
10
+ <section className={css('ViewTransitionPage')}>
11
+ Counters
12
+ <Counter
13
+ value={state.count}
14
+ animation="count"
15
+ onChange={() => {
16
+ fx.set({ count: state.count + 1 })
17
+ }}
18
+ />
19
+ <br />
20
+ <br />
21
+ <Counter
22
+ value={state.count2}
23
+ animation="count2"
24
+ onChange={() => {
25
+ fx.set({ count2: state.count2 + 10 })
26
+ }}
27
+ />
28
+ </section>
29
+ )
30
+ }
@@ -0,0 +1,2 @@
1
+ .ViewTransitionPage {
2
+ }
@@ -0,0 +1,9 @@
1
+ import { env } from 'nextia'
2
+ import { DELETE, GET, POST, PUT } from './http'
3
+
4
+ const API = env.PUBLIC_API
5
+
6
+ export const getUser = (p) => GET(`${API}/user/:id`, p.path, p.body)
7
+ export const createUser = (p) => POST(`${API}/user`, p.path, p.body)
8
+ export const updateUser = (p) => PUT(`${API}/user/:id`, p.path, p.body)
9
+ export const deleteUser = (p) => DELETE(`${API}/user/:id`, p.path, p.body)
@@ -0,0 +1,40 @@
1
+ function urlTemplate(url, path) {
2
+ const params = url.match(/:\w+/g) ?? []
3
+
4
+ return params.reduce((acc, e) => {
5
+ const key = e.split(':')[1]
6
+ return acc.replaceAll(e, path[key] ?? '')
7
+ }, url)
8
+ }
9
+
10
+ async function request(method, url, path, body, headers) {
11
+ url = urlTemplate(url, path)
12
+
13
+ if (method === 'GET') {
14
+ url += Object.keys(body).length ? `?${new URLSearchParams(body)}` : ''
15
+ }
16
+
17
+ const response = await fetch(url, {
18
+ method,
19
+ headers: { 'Content-Type': 'application/json', ...headers },
20
+ ...(method !== 'GET' && {
21
+ body: JSON.stringify(body)
22
+ })
23
+ })
24
+
25
+ const { ok, status, statusText } = response
26
+
27
+ if (ok) return { ok, status, statusText, data: await response.json() }
28
+
29
+ throw new Error(`ok: ${ok} , status: ${status} , statusText: ${statusText}`)
30
+ }
31
+
32
+ const factory =
33
+ (method) =>
34
+ (url = '', path = {}, body = {}, headers = {}) =>
35
+ request(method, url, path, body, headers)
36
+
37
+ export const GET = factory('GET')
38
+ export const POST = factory('POST')
39
+ export const PUT = factory('PUT')
40
+ export const DELETE = factory('DELETE')
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ font-family: Roboto;
3
+ font-style: normal;
4
+ font-display: swap;
5
+ font-weight: bold;
6
+ src: url("./Roboto-Regular.ttf");
7
+ }
@@ -0,0 +1,125 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg
3
+ width="256"
4
+ height="256"
5
+ viewBox="0 0 48 48"
6
+ fill="none"
7
+ color="white"
8
+ stroke="currentColor"
9
+ stroke-width="1"
10
+ stroke-linecap="round"
11
+ stroke-linejoin="round"
12
+ version="1.1"
13
+ id="icons"
14
+ sodipodi:docname="icons.svg"
15
+ inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
16
+ inkscape:export-filename="icons.svg"
17
+ inkscape:export-xdpi="96"
18
+ inkscape:export-ydpi="96"
19
+ aria-hidden="true"
20
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
21
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
22
+ xmlns="http://www.w3.org/2000/svg"
23
+ xmlns:svg="http://www.w3.org/2000/svg">
24
+ <sodipodi:namedview
25
+ id="namedview"
26
+ pagecolor="#505050"
27
+ bordercolor="#ffffff"
28
+ borderopacity="1"
29
+ inkscape:showpageshadow="0"
30
+ inkscape:pageopacity="0"
31
+ inkscape:pagecheckerboard="1"
32
+ inkscape:deskcolor="#505050"
33
+ showgrid="false"
34
+ showguides="true"
35
+ inkscape:zoom="3.5672"
36
+ inkscape:cx="156.56537"
37
+ inkscape:cy="128.25185"
38
+ inkscape:current-layer="globe"
39
+ inkscape:window-width="2560"
40
+ inkscape:window-height="1080"
41
+ inkscape:window-x="2560"
42
+ inkscape:window-y="0"
43
+ inkscape:window-maximized="1" />
44
+ <defs
45
+ id="defs" />
46
+ <g
47
+ id="globe"
48
+ style="display:none">
49
+ <circle
50
+ cx="23.960287038110003"
51
+ cy="23.914597038110003"
52
+ r="18.23231994892"
53
+ id="circle1" />
54
+ <line
55
+ x1="6"
56
+ y1="24"
57
+ x2="42"
58
+ y2="24"
59
+ id="line1" />
60
+ <path
61
+ d="m 23.9603,5.6822471 c 4.4192,4.9926549 6.9306,11.4718789 7.0671,18.2323589 -0.1365,6.760478 -2.6479,13.23962 -7.0671,18.232339 -4.4193,-4.992719 -6.9307,-11.471861 -7.0672,-18.232339 0.1365,-6.76048 2.6479,-13.239704 7.0672,-18.2323589 z"
62
+ id="path1" />
63
+ </g>
64
+ <g
65
+ id="camera"
66
+ style="display:none;"
67
+ sodipodi:insensitive="true">
68
+ <path
69
+ d="m 44.2234,35.0688 c 0,1.9822 -1.6079,3.5891 -3.5913,3.5891 h -32.32145 c -1.98338,0 -3.59123,-1.6069 -3.59125,-3.5891 v -19.7405 c 0,-1.9822 1.60786,-3.5891 3.59125,-3.5891 h 7.18255 l 3.5913,-5.38381 h 10.7738 l 3.5913,5.38381 h 7.1825 c 1.9834,0 3.5913,1.6069 3.5913,3.5891 z"
70
+ id="path2" />
71
+ <circle
72
+ cx="24.709818"
73
+ cy="23.41984"
74
+ r="5.5424304"
75
+ id="circle2" />
76
+ </g>
77
+ <g
78
+ id="video"
79
+ style="display:none;"
80
+ sodipodi:insensitive="true">
81
+ <polygon
82
+ points="45.444025,13.035503 31.653955,23.006053 45.444025,32.976603 "
83
+ id="polygon35" />
84
+ <rect
85
+ x="2.1038051"
86
+ y="9.0472832"
87
+ width="29.55015"
88
+ height="27.91754"
89
+ rx="1.9999979"
90
+ ry="1.9999982"
91
+ id="rect35" />
92
+ </g>
93
+ <g
94
+ id="exit"
95
+ style="display:none"
96
+ sodipodi:insensitive="true">
97
+ <path
98
+ id="background"
99
+ d="M 12,3.4 C 5.8,7.2 1.8,14 1.8,22 1.8,35 12,45 24,45 36,45 46,35 46,22 46,14 42,7.2 36,3.4" />
100
+ <path
101
+ id="ring"
102
+ d="M 12,3.4 C 5.8,7.2 1.8,14 1.8,22 1.8,35 12,45 24,45 36,45 46,35 46,22 46,14 42,7.2 36,3.4" />
103
+ <g
104
+ id="arrow">
105
+ <line
106
+ id="left"
107
+ x1="24"
108
+ y1="25"
109
+ x2="10"
110
+ y2="14" />
111
+ <line
112
+ id="center"
113
+ x1="24"
114
+ y1="1.3"
115
+ x2="24"
116
+ y2="25" />
117
+ <line
118
+ id="right"
119
+ x1="24"
120
+ y1="25"
121
+ x2="35"
122
+ y2="14" />
123
+ </g>
124
+ </g>
125
+ </svg>
@@ -0,0 +1,55 @@
1
+ #exit.nextia-animate-icon {
2
+ transition: transform 200ms linear;
3
+
4
+ #ring {
5
+ stroke-dasharray: 1, 200;
6
+ stroke-dashoffset: 1;
7
+ transition:
8
+ stroke-dashoffset 400ms linear,
9
+ stroke-dasharray 400ms linear;
10
+ }
11
+
12
+ #arrow {
13
+ animation: exit_arrow 2s ease-in-out infinite;
14
+
15
+ #right,
16
+ #left {
17
+ display: none;
18
+ }
19
+ }
20
+
21
+ &:hover {
22
+ transform: rotate(-90deg);
23
+
24
+ #ring {
25
+ stroke-dasharray: 200, 1;
26
+ stroke: var(--primary-color);
27
+ stroke-width: 4px;
28
+ }
29
+
30
+ #arrow {
31
+ transform: translateY(2px);
32
+ stroke: var(--primary-color);
33
+
34
+ line {
35
+ stroke-width: 4px;
36
+ }
37
+
38
+ #right,
39
+ #left {
40
+ display: block;
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ @keyframes exit_arrow {
47
+ 0%,
48
+ 100% {
49
+ transform: translateY(2px);
50
+ }
51
+
52
+ 50% {
53
+ transform: translateY(6px);
54
+ }
55
+ }
@@ -0,0 +1,39 @@
1
+ @import "./fonts/index.css";
2
+ @import "./icons/index.css";
3
+ @import "./utils/index.css";
4
+
5
+ :root {
6
+ --primary-color: #344188;
7
+ --primary-color-50: #3441887a;
8
+ --link: #5fac9f;
9
+ --body-bg: #282c34;
10
+ --body-color: #a8a8a8;
11
+ --font-family: "Roboto";
12
+ }
13
+
14
+ /**
15
+ * html
16
+ */
17
+
18
+ html,
19
+ body {
20
+ background-color: var(--body-bg);
21
+ color: var(--body-color);
22
+ font-family: var(--font-family);
23
+ }
24
+
25
+ a {
26
+ color: var(--link);
27
+ }
28
+
29
+ .mr-2 {
30
+ margin-right: 20px;
31
+ }
32
+
33
+ .m-2 {
34
+ margin: 20px;
35
+ }
36
+
37
+ .p-2 {
38
+ padding: 20px;
39
+ }
@@ -0,0 +1,29 @@
1
+ @import "./view-transition.css";
2
+
3
+ /**
4
+ * Scrollbar
5
+ */
6
+
7
+ @media (pointer: fine) {
8
+ ::-webkit-scrollbar {
9
+ width: 14px;
10
+ height: 14px;
11
+ }
12
+
13
+ ::-webkit-scrollbar-thumb {
14
+ border-radius: 14px;
15
+ border: 3px solid transparent;
16
+ background-clip: content-box;
17
+ background-color: var(--primary-color);
18
+ }
19
+
20
+ ::-webkit-scrollbar-thumb:hover {
21
+ background-color: var(--primary-color-50);
22
+ }
23
+
24
+ ::-webkit-scrollbar,
25
+ ::-webkit-scrollbar-track,
26
+ ::-webkit-scrollbar-corner {
27
+ background-color: transparent;
28
+ }
29
+ }
@@ -0,0 +1,72 @@
1
+ :root {
2
+ view-transition-name: none;
3
+ }
4
+
5
+ /* fade */
6
+
7
+ @keyframes fade-in {
8
+ from {
9
+ opacity: 0;
10
+ }
11
+ to {
12
+ opacity: 1;
13
+ }
14
+ }
15
+ @keyframes fade-out {
16
+ from {
17
+ opacity: 1;
18
+ }
19
+ to {
20
+ opacity: 0;
21
+ }
22
+ }
23
+
24
+ ::view-transition-old(fade) {
25
+ animation: fade-out ease 0.3s forwards;
26
+ }
27
+
28
+ ::view-transition-new(fade) {
29
+ animation: fade-in ease 0.3s forwards;
30
+ }
31
+
32
+ /* count */
33
+
34
+ @keyframes count-in {
35
+ from {
36
+ scale: 1 0;
37
+ }
38
+ to {
39
+ scale: 1 1;
40
+ }
41
+ }
42
+
43
+ @keyframes count-out {
44
+ from {
45
+ scale: 1 1;
46
+ }
47
+ to {
48
+ scale: 1 0;
49
+ }
50
+ }
51
+
52
+ ::view-transition-new(count) {
53
+ animation: count-in 0.25s forwards;
54
+ transform-origin: 50% 0;
55
+ }
56
+
57
+ ::view-transition-old(count) {
58
+ animation: count-out 0.25s forwards;
59
+ transform-origin: 50% 100%;
60
+ }
61
+
62
+ /* count2 */
63
+
64
+ ::view-transition-new(count2) {
65
+ animation: count-in 0.25s forwards;
66
+ transform-origin: 10% 100%;
67
+ }
68
+
69
+ ::view-transition-old(count2) {
70
+ animation: count-out 0.25s forwards;
71
+ transform-origin: 10% 0%;
72
+ }
@@ -0,0 +1,5 @@
1
+ function sum(a, b) {
2
+ return a + b
3
+ }
4
+
5
+ export { sum }
@@ -0,0 +1,11 @@
1
+ import { env } from 'nextia'
2
+ import { sum } from 'utils'
3
+ import { test } from 'vitest'
4
+
5
+ test('sumTest', () => {
6
+ console.info(sum(1, 20))
7
+ })
8
+
9
+ test('envTest', () => {
10
+ console.info(`PUBLIC_TITLE : ${env.PUBLIC_TITLE}`)
11
+ })
@@ -0,0 +1,97 @@
1
+ import { execSync } from 'node:child_process'
2
+ import { readFile } from 'node:fs/promises'
3
+ import react from '@vitejs/plugin-react'
4
+ import { defineConfig } from 'vite'
5
+ import { version } from './package.json'
6
+
7
+ export default defineConfig(({ mode }) => {
8
+ const CWD = process.cwd()
9
+ const host = '0.0.0.0'
10
+ const port = 3000
11
+
12
+ return {
13
+ server: {
14
+ host,
15
+ port
16
+ },
17
+
18
+ preview: {
19
+ host,
20
+ port
21
+ },
22
+
23
+ base: '',
24
+ envDir: CWD,
25
+ envPrefix: 'PUBLIC_',
26
+ root: `${CWD}/src`,
27
+ publicDir: `${CWD}/public`,
28
+
29
+ resolve: {
30
+ alias: Object.fromEntries(
31
+ ['assets', 'components', 'services', 'theme', 'utils'].map((dir) => [
32
+ dir,
33
+ `${CWD}/src/${dir}`
34
+ ])
35
+ )
36
+ },
37
+
38
+ build: {
39
+ outDir: '../out',
40
+ assetsDir: 'assets',
41
+ emptyOutDir: true
42
+ },
43
+
44
+ css: {
45
+ postcss: {}
46
+ },
47
+
48
+ plugins: [
49
+ react(),
50
+ {
51
+ name: 'html',
52
+ transformIndexHtml(html) {
53
+ let gitHash = ''
54
+ try {
55
+ gitHash = execSync('git rev-parse --short HEAD 2> /dev/null')
56
+ .toString()
57
+ .trim()
58
+ } catch {}
59
+
60
+ html.replaceAll(
61
+ '%VERSION%',
62
+ `version=${version}, env=${mode}, release-date=${new Date()}, git-hash=${gitHash}`
63
+ )
64
+
65
+ return html
66
+ }
67
+ },
68
+ {
69
+ name: 'svg',
70
+ async transform(_src, id) {
71
+ const [path, query] = id.split('?')
72
+ if (query !== 'raw') return
73
+
74
+ let code = await readFile(path, 'utf8')
75
+ code = code
76
+ .replace(/\s{2,}/g, ' ') // multiple spaces to single space
77
+ .replace(/\n/g, '') // remove newlines
78
+ .replace(/\t/g, '') // remove tabs
79
+ .replace(/>\s+</g, '><') // remove space between tags
80
+ .trim()
81
+ return `export default ${JSON.stringify(code)};`
82
+ }
83
+ }
84
+ ],
85
+
86
+ test: {
87
+ root: './',
88
+ environment: 'jsdom',
89
+ include: ['test/**/*.test.{js,jsx,ts,tsx}'],
90
+ coverage: {
91
+ reportsDirectory: '.coverage',
92
+ exclude: ['src/assets', 'src/components/index.js', 'src/index.jsx'],
93
+ include: ['src/**/*.{js,jsx,ts,tsx}']
94
+ }
95
+ }
96
+ }
97
+ })