nextia 6.0.4 → 7.0.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.
Files changed (76) hide show
  1. package/README.md +1 -1
  2. package/biome.json +21 -0
  3. package/package.json +14 -6
  4. package/src/bin.js +240 -0
  5. package/src/lib.js +21 -29
  6. package/template/README.md +29 -0
  7. package/template/_env.dev +4 -0
  8. package/template/_env.prod +1 -0
  9. package/template/_env.test +1 -0
  10. package/template/_gitignore +10 -0
  11. package/template/package.json +35 -0
  12. package/template/public/error.html +14 -0
  13. package/template/public/logo.svg +105 -0
  14. package/template/src/assets/i18n/index.js +26 -0
  15. package/template/src/assets/img/image.jpg +0 -0
  16. package/template/src/components/Counter/index.jsx +34 -0
  17. package/template/src/components/Counter/style.css +5 -0
  18. package/template/src/components/Message/index.jsx +12 -0
  19. package/template/src/components/index.js +10 -0
  20. package/template/src/components/ui/I18n/index.jsx +23 -0
  21. package/template/src/components/ui/Icon/index.jsx +50 -0
  22. package/template/src/components/ui/Link/index.jsx +12 -0
  23. package/template/src/components/ui/Svg/index.jsx +54 -0
  24. package/template/src/components/ui/Translate/index.jsx +18 -0
  25. package/template/src/index.html +18 -0
  26. package/template/src/index.jsx +4 -0
  27. package/template/src/pages/counter/functions.js +6 -0
  28. package/template/src/pages/counter/index.jsx +51 -0
  29. package/template/src/pages/counter/style.css +2 -0
  30. package/template/src/pages/env/functions.js +3 -0
  31. package/template/src/pages/env/index.jsx +27 -0
  32. package/template/src/pages/env/style.css +2 -0
  33. package/template/src/pages/functions.js +37 -0
  34. package/template/src/pages/home/functions.js +43 -0
  35. package/template/src/pages/home/index.jsx +211 -0
  36. package/template/src/pages/home/style.css +51 -0
  37. package/template/src/pages/http/not-found/index.jsx +10 -0
  38. package/template/src/pages/http/not-found/style.css +2 -0
  39. package/template/src/pages/icons/functions.js +3 -0
  40. package/template/src/pages/icons/index.jsx +20 -0
  41. package/template/src/pages/icons/style.css +5 -0
  42. package/template/src/pages/images/functions.js +3 -0
  43. package/template/src/pages/images/index.jsx +20 -0
  44. package/template/src/pages/images/style.css +8 -0
  45. package/template/src/pages/index.jsx +114 -0
  46. package/template/src/pages/mockapi/functions.js +71 -0
  47. package/template/src/pages/mockapi/index.jsx +101 -0
  48. package/template/src/pages/mockapi/style.css +57 -0
  49. package/template/src/pages/my-context/functions.js +7 -0
  50. package/template/src/pages/my-context/index.jsx +32 -0
  51. package/template/src/pages/my-context/style.css +2 -0
  52. package/template/src/pages/resize/functions.js +3 -0
  53. package/template/src/pages/resize/index.jsx +15 -0
  54. package/template/src/pages/resize/style.css +2 -0
  55. package/template/src/pages/search-params/functions.js +3 -0
  56. package/template/src/pages/search-params/index.jsx +36 -0
  57. package/template/src/pages/search-params/style.css +2 -0
  58. package/template/src/pages/subpage/hello/functions.js +3 -0
  59. package/template/src/pages/subpage/hello/index.jsx +11 -0
  60. package/template/src/pages/subpage/hello/style.css +2 -0
  61. package/template/src/pages/translate/functions.js +5 -0
  62. package/template/src/pages/translate/index.jsx +31 -0
  63. package/template/src/pages/translate/style.css +12 -0
  64. package/template/src/services/api.js +9 -0
  65. package/template/src/services/http.js +40 -0
  66. package/template/src/theme/animations.css +72 -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/exit.svg +69 -0
  70. package/template/src/theme/icons/icons.svg +126 -0
  71. package/template/src/theme/index.css +39 -0
  72. package/template/src/theme/util.css +27 -0
  73. package/template/src/utils/hooks.js +49 -0
  74. package/template/src/utils/index.js +19 -0
  75. package/template/test/index.test.js +12 -0
  76. package/template/vite.config.js +97 -0
@@ -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,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,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,69 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="256" height="256" viewBox="0 0 48 48" fill="none"
2
+ color="currentColor" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
3
+
4
+ <style type="text/css">
5
+ svg {
6
+ transition: transform 200ms linear;
7
+
8
+ #ani {
9
+ transition:
10
+ stroke-dashoffset 400ms linear,
11
+ stroke-dasharray 400ms linear;
12
+ stroke: var(--primary-color);
13
+ stroke-dasharray: 1, 200;
14
+ stroke-dashoffset: 1;
15
+ }
16
+
17
+ #arrow {
18
+ animation: arrow 2s ease-in-out infinite;
19
+
20
+ #right,
21
+ #left {
22
+ display: none;
23
+ }
24
+ }
25
+ }
26
+
27
+ svg:hover {
28
+ transform: rotate(-90deg);
29
+
30
+ #ani {
31
+ stroke-dasharray: 200, 1;
32
+ }
33
+
34
+ #arrow {
35
+ transform: translateY(2px);
36
+ stroke: var(--primary-color);
37
+
38
+ line {
39
+ stroke-width: 6px;
40
+ }
41
+
42
+ #right,
43
+ #left {
44
+ display: block;
45
+ }
46
+ }
47
+ }
48
+
49
+ @keyframes arrow {
50
+
51
+ 0%,
52
+ 100% {
53
+ transform: translateY(2px);
54
+ }
55
+
56
+ 50% {
57
+ transform: translateY(6px);
58
+ }
59
+ }
60
+ </style>
61
+
62
+ <path id="solid" 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" />
63
+ <path id="ani" 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" />
64
+ <g id="arrow">
65
+ <line id="left" x1="24" y1="25" x2="10" y2="14" />
66
+ <line id="center" x1="24" y1="1.3" x2="24" y2="25" />
67
+ <line id="right" x1="24" y1="25" x2="35" y2="14" />
68
+ </g>
69
+ </svg>
@@ -0,0 +1,126 @@
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
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
20
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
21
+ xmlns="http://www.w3.org/2000/svg"
22
+ xmlns:svg="http://www.w3.org/2000/svg">
23
+ <title
24
+ id="title">icons</title>
25
+ <sodipodi:namedview
26
+ id="namedview"
27
+ pagecolor="#505050"
28
+ bordercolor="#ffffff"
29
+ borderopacity="1"
30
+ inkscape:showpageshadow="0"
31
+ inkscape:pageopacity="0"
32
+ inkscape:pagecheckerboard="1"
33
+ inkscape:deskcolor="#505050"
34
+ showgrid="false"
35
+ showguides="true"
36
+ inkscape:zoom="3.5672"
37
+ inkscape:cx="156.56537"
38
+ inkscape:cy="128.25185"
39
+ inkscape:current-layer="globe"
40
+ inkscape:window-width="2560"
41
+ inkscape:window-height="1080"
42
+ inkscape:window-x="2560"
43
+ inkscape:window-y="0"
44
+ inkscape:window-maximized="1" />
45
+ <defs
46
+ id="defs" />
47
+ <g
48
+ id="globe"
49
+ style="display:none">
50
+ <circle
51
+ cx="23.960287038110003"
52
+ cy="23.914597038110003"
53
+ r="18.23231994892"
54
+ id="circle1" />
55
+ <line
56
+ x1="6"
57
+ y1="24"
58
+ x2="42"
59
+ y2="24"
60
+ id="line1" />
61
+ <path
62
+ 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"
63
+ id="path1" />
64
+ </g>
65
+ <g
66
+ id="camera"
67
+ style="display:none;"
68
+ sodipodi:insensitive="true">
69
+ <path
70
+ 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"
71
+ id="path2" />
72
+ <circle
73
+ cx="24.709818"
74
+ cy="23.41984"
75
+ r="5.5424304"
76
+ id="circle2" />
77
+ </g>
78
+ <g
79
+ id="video"
80
+ style="display:none;"
81
+ sodipodi:insensitive="true">
82
+ <polygon
83
+ points="45.444025,13.035503 31.653955,23.006053 45.444025,32.976603 "
84
+ id="polygon35" />
85
+ <rect
86
+ x="2.1038051"
87
+ y="9.0472832"
88
+ width="29.55015"
89
+ height="27.91754"
90
+ rx="1.9999979"
91
+ ry="1.9999982"
92
+ id="rect35" />
93
+ </g>
94
+ <g
95
+ id="exit"
96
+ style="display:none"
97
+ sodipodi:insensitive="true">
98
+ <path
99
+ id="solid"
100
+ 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" />
101
+ <path
102
+ id="animation"
103
+ 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" />
104
+ <g
105
+ id="arrow">
106
+ <line
107
+ id="left"
108
+ x1="24"
109
+ y1="25"
110
+ x2="10"
111
+ y2="14" />
112
+ <line
113
+ id="center"
114
+ x1="24"
115
+ y1="1.3"
116
+ x2="24"
117
+ y2="25" />
118
+ <line
119
+ id="right"
120
+ x1="24"
121
+ y1="25"
122
+ x2="35"
123
+ y2="14" />
124
+ </g>
125
+ </g>
126
+ </svg>
@@ -0,0 +1,39 @@
1
+ @import "./util.css";
2
+ @import "./fonts/index.css";
3
+ @import "./animations.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,27 @@
1
+ /**
2
+ * Scrollbar
3
+ */
4
+
5
+ @media (pointer: fine) {
6
+ ::-webkit-scrollbar {
7
+ width: 14px;
8
+ height: 14px;
9
+ }
10
+
11
+ ::-webkit-scrollbar-thumb {
12
+ border-radius: 14px;
13
+ border: 3px solid transparent;
14
+ background-clip: content-box;
15
+ background-color: var(--primary-color);
16
+ }
17
+
18
+ ::-webkit-scrollbar-thumb:hover {
19
+ background-color: var(--primary-color-50);
20
+ }
21
+
22
+ ::-webkit-scrollbar,
23
+ ::-webkit-scrollbar-track,
24
+ ::-webkit-scrollbar-corner {
25
+ background-color: transparent;
26
+ }
27
+ }
@@ -0,0 +1,49 @@
1
+ import { useCallback, useEffect, useState } from 'react'
2
+
3
+ export function useQueryString() {
4
+ const getQueryString = useCallback(
5
+ () => ({
6
+ hash: window.location.hash.split('?')[0],
7
+ queryString: Object.fromEntries(
8
+ new URLSearchParams(window.location.hash.split('?')[1])
9
+ )
10
+ }),
11
+ []
12
+ )
13
+
14
+ const [queryString, setQueryString] = useState(getQueryString)
15
+
16
+ useEffect(() => {
17
+ const handlePopState = () => setQueryString(getQueryString())
18
+
19
+ window.addEventListener('popstate', handlePopState)
20
+ return () => {
21
+ window.removeEventListener('popstate', handlePopState)
22
+ }
23
+ }, [getQueryString])
24
+
25
+ return queryString
26
+ }
27
+
28
+ export function useResize() {
29
+ const getResize = useCallback(
30
+ () => ({
31
+ width: window.innerWidth,
32
+ height: window.innerHeight
33
+ }),
34
+ []
35
+ )
36
+
37
+ const [resize, setResize] = useState(getResize)
38
+
39
+ useEffect(() => {
40
+ const handleResize = () => setResize(getResize())
41
+
42
+ window.addEventListener('resize', handleResize)
43
+ return () => {
44
+ window.removeEventListener('resize', handleResize)
45
+ }
46
+ }, [getResize])
47
+
48
+ return resize
49
+ }
@@ -0,0 +1,19 @@
1
+ import { flushSync } from 'react-dom'
2
+ import { useQueryString, useResize } from './hooks'
3
+
4
+ const env = import.meta.env
5
+
6
+ async function startViewTransition(fun = () => {}, ref, animation = 'fade') {
7
+ if (!document.startViewTransition || env.PUBLIC_VIEW_TRANSITION === 'false')
8
+ return fun()
9
+
10
+ ref.style.viewTransitionName = animation
11
+ await document.startViewTransition(() => flushSync(fun)).finished
12
+ ref.style.viewTransitionName = ''
13
+ }
14
+
15
+ function sum(a, b) {
16
+ return a + b
17
+ }
18
+
19
+ export { env, startViewTransition, sum, useQueryString, useResize }
@@ -0,0 +1,12 @@
1
+ import { env, sum } from 'utils'
2
+ import { test } from 'vitest'
3
+
4
+ test('test', () => {})
5
+
6
+ test('sumTest', () => {
7
+ console.info(sum(1, 20))
8
+ })
9
+
10
+ test('envTest', () => {
11
+ console.info(`PUBLIC_TITLE : ${env.PUBLIC_TITLE}`)
12
+ })
@@ -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
+ })