@undp/create-app 0.0.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.
- package/bin/generateFiles.js +65 -0
- package/bin/generateTemplates/copyTemplate.js +18 -0
- package/bin/generateTemplates/generateIndexHtml.js +15 -0
- package/bin/generateTemplates/generatePackageJson.js +105 -0
- package/bin/generateTemplates/generateReadme.js +143 -0
- package/bin/generateTemplates/generateStyleCss.js +6 -0
- package/bin/generateTemplates/index.js +6 -0
- package/bin/generateTemplates/templates/basic/App.txt +32 -0
- package/bin/generateTemplates/templates/basic/AppWithContainer.txt +32 -0
- package/bin/generateTemplates/templates/basic/main.txt +10 -0
- package/bin/generateTemplates/templates/configFiles/.prettierrc +10 -0
- package/bin/generateTemplates/templates/configFiles/eslint.config.js +97 -0
- package/bin/generateTemplates/templates/configFiles/icon.txt +1 -0
- package/bin/generateTemplates/templates/configFiles/staticwebapp.config.json +44 -0
- package/bin/generateTemplates/templates/configFiles/tailwind.config.js +7 -0
- package/bin/generateTemplates/templates/configFiles/tsconfig.json +29 -0
- package/bin/generateTemplates/templates/configFiles/tsconfig.node.json +9 -0
- package/bin/generateTemplates/templates/configFiles/vite-env.txt +1 -0
- package/bin/generateTemplates/templates/configFiles/vite.config.ts.txt +109 -0
- package/bin/generateTemplates/templates/configFiles/viteWithoutPostCss.config.ts.txt +58 -0
- package/bin/generateTemplates/templates/css/fonts.css +213 -0
- package/bin/generateTemplates/templates/query/App.txt +57 -0
- package/bin/generateTemplates/templates/query/AppWithContainer.txt +67 -0
- package/bin/generateTemplates/templates/query/main.txt +29 -0
- package/bin/generateTemplates/templates/router/App.txt +30 -0
- package/bin/generateTemplates/templates/router/components/Footer.txt +20 -0
- package/bin/generateTemplates/templates/router/components/Header.txt +29 -0
- package/bin/generateTemplates/templates/router/main.txt +60 -0
- package/bin/generateTemplates/templates/router/routes/About.txt +28 -0
- package/bin/generateTemplates/templates/router+query/App.txt +30 -0
- package/bin/generateTemplates/templates/router+query/components/Footer.txt +20 -0
- package/bin/generateTemplates/templates/router+query/components/Header.txt +29 -0
- package/bin/generateTemplates/templates/router+query/integration/tanstack-query.txt +27 -0
- package/bin/generateTemplates/templates/router+query/main.txt +69 -0
- package/bin/generateTemplates/templates/router+query/routes/queryDemo.txt +56 -0
- package/bin/index.js +57 -0
- package/bin/promptUser.js +96 -0
- package/bin/utils/createFolders.js +11 -0
- package/bin/utils/index.js +2 -0
- package/bin/utils/printSuccess.js +23 -0
- package/package.json +32 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
import react from '@vitejs/plugin-react';
|
|
5
|
+
import eslint from '@nabla/vite-plugin-eslint';
|
|
6
|
+
import { AtRule } from 'postcss';
|
|
7
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
8
|
+
import postcssNested from 'postcss-nested';
|
|
9
|
+
import tailwindcss from '@tailwindcss/postcss';
|
|
10
|
+
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
plugins: [
|
|
14
|
+
react({
|
|
15
|
+
babel: {
|
|
16
|
+
plugins: ['babel-plugin-react-compiler'],
|
|
17
|
+
},
|
|
18
|
+
}),
|
|
19
|
+
eslint(),
|
|
20
|
+
visualizer({ filename: 'stats.html', open: true }),
|
|
21
|
+
viteStaticCopy({
|
|
22
|
+
targets: [{ src: 'staticwebapp.config.json', dest: '' }],
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
css: {
|
|
26
|
+
postcss: {
|
|
27
|
+
plugins: [
|
|
28
|
+
postcssNested(),
|
|
29
|
+
tailwindcss(),
|
|
30
|
+
{
|
|
31
|
+
postcssPlugin: 'remove-layers', // If you want to flatten layers except base layer
|
|
32
|
+
AtRule: {
|
|
33
|
+
layer(rule) {
|
|
34
|
+
if (rule.params !== 'base') {
|
|
35
|
+
rule.each(child => {
|
|
36
|
+
rule.parent.insertAfter(rule, child);
|
|
37
|
+
});
|
|
38
|
+
rule.remove();
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
postcssPlugin: 'wrap-with-undp-container', // If you want to wrap all the class in .undp-container
|
|
45
|
+
OnceExit(root) {
|
|
46
|
+
const skipSelectors = ['html', 'body', ':root', ':host'];
|
|
47
|
+
root.walkRules(rule => {
|
|
48
|
+
if (rule.parent && rule.parent.type === 'atrule') {
|
|
49
|
+
const parent = rule.parent as AtRule;
|
|
50
|
+
if (parent.name === 'keyframes' || parent.name === 'supports') {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
rule.selectors = rule.selectors.map(selector => {
|
|
55
|
+
if (selector.startsWith('.undp-container')) return selector;
|
|
56
|
+
if (skipSelectors.some(skip => selector.startsWith(skip)))
|
|
57
|
+
return selector;
|
|
58
|
+
return `.undp-container ${selector}`;
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
postcssPlugin: 'move-media-queries-last', // If you want to reorder media queries to the end
|
|
65
|
+
OnceExit(root) {
|
|
66
|
+
const mediaQueries = [];
|
|
67
|
+
|
|
68
|
+
// Collect all media queries
|
|
69
|
+
root.walkAtRules('media', mediaRule => {
|
|
70
|
+
mediaQueries.push(mediaRule.clone());
|
|
71
|
+
mediaRule.remove();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Append them at the end
|
|
75
|
+
mediaQueries.forEach(mediaQuery => {
|
|
76
|
+
root.append(mediaQuery);
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
build: {
|
|
84
|
+
manifest: true,
|
|
85
|
+
cssCodeSplit: false,
|
|
86
|
+
rollupOptions: {
|
|
87
|
+
output: {
|
|
88
|
+
manualChunks(id) {
|
|
89
|
+
if (id.includes('node_modules/react')) return 'react';
|
|
90
|
+
if (id.includes('@undp/design-system-react')) return 'undp';
|
|
91
|
+
if (id.includes('@undp/data-viz')) return 'undp';
|
|
92
|
+
},
|
|
93
|
+
chunkFileNames: '[name]-[hash].js',
|
|
94
|
+
assetFileNames: '[name].[ext]',
|
|
95
|
+
entryFileNames: '[name].js',
|
|
96
|
+
},
|
|
97
|
+
treeshake: true,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
server: {
|
|
101
|
+
cors: {
|
|
102
|
+
origin: '*',
|
|
103
|
+
methods: ['GET'],
|
|
104
|
+
preflightContinue: false,
|
|
105
|
+
optionsSuccessStatus: 204,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
resolve: { alias: { '@': path.resolve(__dirname, './src') } },
|
|
109
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
import react from '@vitejs/plugin-react';
|
|
5
|
+
import eslint from '@nabla/vite-plugin-eslint';
|
|
6
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
7
|
+
import postcssNested from 'postcss-nested';
|
|
8
|
+
import tailwindcss from '@tailwindcss/postcss';
|
|
9
|
+
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
10
|
+
|
|
11
|
+
export default defineConfig({
|
|
12
|
+
plugins: [
|
|
13
|
+
react({
|
|
14
|
+
babel: {
|
|
15
|
+
plugins: ['babel-plugin-react-compiler'],
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
eslint(),
|
|
19
|
+
visualizer({ filename: 'stats.html', open: true }),
|
|
20
|
+
viteStaticCopy({
|
|
21
|
+
targets: [{ src: 'staticwebapp.config.json', dest: '' }],
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
css: {
|
|
25
|
+
postcss: {
|
|
26
|
+
plugins: [
|
|
27
|
+
postcssNested(),
|
|
28
|
+
tailwindcss(),
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
build: {
|
|
33
|
+
manifest: true,
|
|
34
|
+
cssCodeSplit: false,
|
|
35
|
+
rollupOptions: {
|
|
36
|
+
output: {
|
|
37
|
+
manualChunks(id) {
|
|
38
|
+
if (id.includes('node_modules/react')) return 'react';
|
|
39
|
+
if (id.includes('@undp/design-system-react')) return 'undp';
|
|
40
|
+
if (id.includes('@undp/data-viz')) return 'undp';
|
|
41
|
+
},
|
|
42
|
+
chunkFileNames: '[name]-[hash].js',
|
|
43
|
+
assetFileNames: '[name].[ext]',
|
|
44
|
+
entryFileNames: '[name].js',
|
|
45
|
+
},
|
|
46
|
+
treeshake: true,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
server: {
|
|
50
|
+
cors: {
|
|
51
|
+
origin: '*',
|
|
52
|
+
methods: ['GET'],
|
|
53
|
+
preflightContinue: false,
|
|
54
|
+
optionsSuccessStatus: 204,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
resolve: { alias: { '@': path.resolve(__dirname, './src') } },
|
|
58
|
+
});
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-display: swap;
|
|
3
|
+
font-family: 'ProximaNova';
|
|
4
|
+
font-style: normal;
|
|
5
|
+
font-weight: 100;
|
|
6
|
+
src: url('./fonts/proximanova-thin-webfont.woff2') format('woff2');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@font-face {
|
|
10
|
+
font-display: swap;
|
|
11
|
+
font-family: 'ProximaNova';
|
|
12
|
+
font-style: italic;
|
|
13
|
+
font-weight: 100;
|
|
14
|
+
src: url('./fonts/proximanova-thinit-webfont.woff2') format('woff2');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@font-face {
|
|
18
|
+
font-display: swap;
|
|
19
|
+
font-family: 'ProximaNova';
|
|
20
|
+
font-style: normal;
|
|
21
|
+
font-weight: 200;
|
|
22
|
+
src: url('./fonts/proximanova-light-webfont.woff2') format('woff2');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@font-face {
|
|
26
|
+
font-display: swap;
|
|
27
|
+
font-family: 'ProximaNova';
|
|
28
|
+
font-style: italic;
|
|
29
|
+
font-weight: 200 300;
|
|
30
|
+
src: url('./fonts/proximanova-lightit-webfont.woff2') format('woff2');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@font-face {
|
|
34
|
+
font-display: swap;
|
|
35
|
+
font-family: 'ProximaNova';
|
|
36
|
+
font-style: normal;
|
|
37
|
+
font-weight: 400;
|
|
38
|
+
src: url('./fonts/proximanova-regular-webfont.woff2') format('woff2');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@font-face {
|
|
42
|
+
font-display: swap;
|
|
43
|
+
font-family: 'ProximaNova';
|
|
44
|
+
font-style: italic;
|
|
45
|
+
font-weight: 400;
|
|
46
|
+
src: url('./fonts/proximanova-regularit-webfont.woff2') format('woff2');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@font-face {
|
|
50
|
+
font-display: swap;
|
|
51
|
+
font-family: 'ProximaNova';
|
|
52
|
+
font-style: normal;
|
|
53
|
+
font-weight: 500;
|
|
54
|
+
src: url('./fonts/proximanova-medium-webfont.woff2') format('woff2');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@font-face {
|
|
58
|
+
font-display: swap;
|
|
59
|
+
font-family: 'ProximaNova';
|
|
60
|
+
font-style: italic;
|
|
61
|
+
font-weight: 500;
|
|
62
|
+
src: url('./fonts/proximanova-mediumit-webfont.woff2') format('woff2');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@font-face {
|
|
66
|
+
font-display: swap;
|
|
67
|
+
font-family: 'ProximaNova';
|
|
68
|
+
font-style: normal;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
src: url('./fonts/proximanova-semibold-webfont-2.woff2') format('woff2');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@font-face {
|
|
74
|
+
font-display: swap;
|
|
75
|
+
font-family: 'ProximaNova';
|
|
76
|
+
font-style: italic;
|
|
77
|
+
font-weight: 600;
|
|
78
|
+
src: url('./fonts/proximanova-semiboldit-webfont-2.woff2') format('woff2');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@font-face {
|
|
82
|
+
font-display: swap;
|
|
83
|
+
font-family: 'ProximaNova';
|
|
84
|
+
font-style: normal;
|
|
85
|
+
font-weight: 700;
|
|
86
|
+
src: url('./fonts/proximanova-bold-webfont.woff2') format('woff2');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@font-face {
|
|
90
|
+
font-display: swap;
|
|
91
|
+
font-family: 'ProximaNova';
|
|
92
|
+
font-style: italic;
|
|
93
|
+
font-weight: 700;
|
|
94
|
+
src: url('./fonts/proximanova-boldit-webfont.woff2') format('woff2');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@font-face {
|
|
98
|
+
font-display: swap;
|
|
99
|
+
font-family: 'ProximaNova';
|
|
100
|
+
font-style: normal;
|
|
101
|
+
font-weight: 800;
|
|
102
|
+
src: url('./fonts/proximanova-extrabold-webfont.woff2') format('woff2');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@font-face {
|
|
106
|
+
font-display: swap;
|
|
107
|
+
font-family: 'ProximaNova';
|
|
108
|
+
font-style: italic;
|
|
109
|
+
font-weight: 800;
|
|
110
|
+
src: url('./fonts/proximanova-extraboldit-webfont.woff2') format('woff2');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@font-face {
|
|
114
|
+
font-display: swap;
|
|
115
|
+
font-family: 'ProximaNova';
|
|
116
|
+
font-style: normal;
|
|
117
|
+
font-weight: 900;
|
|
118
|
+
src: url('./fonts/proximanova-black-webfont.woff2') format('woff2');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@font-face {
|
|
122
|
+
font-display: swap;
|
|
123
|
+
font-family: 'ProximaNova';
|
|
124
|
+
font-style: italic;
|
|
125
|
+
font-weight: 900;
|
|
126
|
+
src: url('./fonts/proximanova-blackit-webfont.woff2') format('woff2');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* SohneBreit */
|
|
130
|
+
@font-face {
|
|
131
|
+
font-display: swap;
|
|
132
|
+
font-family: 'SohneBreit';
|
|
133
|
+
font-style: normal;
|
|
134
|
+
font-weight: 100 700;
|
|
135
|
+
src: url('./fonts/soehne-breit-web-dreiviertelfett.woff2') format('woff2');
|
|
136
|
+
unicode-range: U+0000-024F, U+1E00-1EFF, U+2000-206F, U+2070-209F;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@font-face {
|
|
140
|
+
font-display: swap;
|
|
141
|
+
font-family: 'SohneBreit';
|
|
142
|
+
font-style: italic;
|
|
143
|
+
font-weight: 100 700;
|
|
144
|
+
src: url('./fonts/soehne-breit-web-dreiviertelfett-kursiv.woff2')
|
|
145
|
+
format('woff2');
|
|
146
|
+
unicode-range: U+0000-024F, U+1E00-1EFF, U+2000-206F, U+2070-209F;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@font-face {
|
|
150
|
+
font-display: swap;
|
|
151
|
+
font-family: 'SohneBreit';
|
|
152
|
+
font-style: normal;
|
|
153
|
+
font-weight: 800 900;
|
|
154
|
+
src: url('./fonts/soehne-breit-web-fett.woff2') format('woff2');
|
|
155
|
+
unicode-range: U+0000-024F, U+1E00-1EFF, U+2000-206F, U+2070-209F;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@font-face {
|
|
159
|
+
font-display: swap;
|
|
160
|
+
font-family: 'SohneBreit';
|
|
161
|
+
font-style: italic;
|
|
162
|
+
font-weight: 800 900;
|
|
163
|
+
src: url('./fonts/soehne-breit-web-fett-kursiv.woff2') format('woff2');
|
|
164
|
+
unicode-range: U+0000-024F, U+1E00-1EFF, U+2000-20CF;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@font-face {
|
|
168
|
+
font-display: swap;
|
|
169
|
+
font-family: 'UNBangla';
|
|
170
|
+
font-style: normal;
|
|
171
|
+
font-weight: 100 300;
|
|
172
|
+
src: url('./fonts/UNBangla-Thin.woff2') format('woff2');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@font-face {
|
|
176
|
+
font-display: swap;
|
|
177
|
+
font-family: 'UNBangla';
|
|
178
|
+
font-style: italic;
|
|
179
|
+
font-weight: 100 300;
|
|
180
|
+
src: url('./fonts/UNBangla-ThinItalic.woff2') format('woff2');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@font-face {
|
|
184
|
+
font-display: swap;
|
|
185
|
+
font-family: 'UNBangla';
|
|
186
|
+
font-style: normal;
|
|
187
|
+
font-weight: 400;
|
|
188
|
+
src: url('./fonts/UNBangla-Regular.woff2') format('woff2');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@font-face {
|
|
192
|
+
font-display: swap;
|
|
193
|
+
font-family: 'UNBangla';
|
|
194
|
+
font-style: italic;
|
|
195
|
+
font-weight: 400;
|
|
196
|
+
src: url('./fonts/UNBangla-Italic.woff2') format('woff2');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@font-face {
|
|
200
|
+
font-display: swap;
|
|
201
|
+
font-family: 'UNBangla';
|
|
202
|
+
font-style: normal;
|
|
203
|
+
font-weight: 500 900;
|
|
204
|
+
src: url('./fonts/UNBangla-Bold.woff2') format('woff2');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@font-face {
|
|
208
|
+
font-display: swap;
|
|
209
|
+
font-family: 'UNBangla';
|
|
210
|
+
font-style: italic;
|
|
211
|
+
font-weight: 500 900;
|
|
212
|
+
src: url('./fonts/UNBangla-BoldItalic.woff2') format('woff2');
|
|
213
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { H3 } from '@undp/design-system-react';
|
|
2
|
+
import { useQuery } from '@tanstack/react-query';
|
|
3
|
+
|
|
4
|
+
import '@/styles/fonts.css';
|
|
5
|
+
import '@/styles/style.css';
|
|
6
|
+
import undpLogo from './assets/undp-logo-blue.svg';
|
|
7
|
+
|
|
8
|
+
function useTodoData() {
|
|
9
|
+
return useQuery({
|
|
10
|
+
queryKey: ['todos'],
|
|
11
|
+
queryFn: () =>
|
|
12
|
+
Promise.resolve([
|
|
13
|
+
{ id: 1, name: 'Alice' },
|
|
14
|
+
{ id: 2, name: 'Bob' },
|
|
15
|
+
{ id: 3, name: 'Charlie' },
|
|
16
|
+
]),
|
|
17
|
+
initialData: [],
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function App() {
|
|
22
|
+
const { data, isLoading, isError } = useTodoData();
|
|
23
|
+
|
|
24
|
+
if (isLoading) return <Spinner size='lg' className='my-20 m-auto' />;
|
|
25
|
+
|
|
26
|
+
if (isError)
|
|
27
|
+
return (
|
|
28
|
+
<div className='px-4 mx-auto'>
|
|
29
|
+
<div>Error</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
return (
|
|
33
|
+
<div className='m-5'>
|
|
34
|
+
<div>
|
|
35
|
+
<img
|
|
36
|
+
src={undpLogo}
|
|
37
|
+
className='logo react mb-8'
|
|
38
|
+
alt='React logo'
|
|
39
|
+
width='72px'
|
|
40
|
+
style={{ marginLeft: 'auto', marginRight: 'auto' }}
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
<H3 className='text-center'>
|
|
44
|
+
This is template for building visualization and frontend project
|
|
45
|
+
maintained by UNDP's DAI Hub.
|
|
46
|
+
<br />
|
|
47
|
+
<br />
|
|
48
|
+
Contact us at data@undp.org if you have any feedback or questions.
|
|
49
|
+
<br />
|
|
50
|
+
<br />
|
|
51
|
+
{data.length} elements in the query
|
|
52
|
+
</H3>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default App;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { H3 } from '@undp/design-system-react';
|
|
2
|
+
import { useQuery } from '@tanstack/react-query';
|
|
3
|
+
|
|
4
|
+
import '@/styles/fonts.css';
|
|
5
|
+
import '@/styles/style.css';
|
|
6
|
+
import undpLogo from './assets/undp-logo-blue.svg';
|
|
7
|
+
|
|
8
|
+
function useTodoData() {
|
|
9
|
+
return useQuery({
|
|
10
|
+
queryKey: ['todos'],
|
|
11
|
+
queryFn: () =>
|
|
12
|
+
Promise.resolve([
|
|
13
|
+
{ id: 1, name: 'Alice' },
|
|
14
|
+
{ id: 2, name: 'Bob' },
|
|
15
|
+
{ id: 3, name: 'Charlie' },
|
|
16
|
+
]),
|
|
17
|
+
initialData: [],
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function App() {
|
|
22
|
+
const { data, isLoading, isError } = useTodoData();
|
|
23
|
+
|
|
24
|
+
if (isLoading)
|
|
25
|
+
return (
|
|
26
|
+
<div className='undp-container'>
|
|
27
|
+
<Spinner size='lg' className='my-20 m-auto' />
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (isError)
|
|
32
|
+
return (
|
|
33
|
+
<div className='undp-container'>
|
|
34
|
+
<div className='px-4 mx-auto'>
|
|
35
|
+
<div>Error</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className='undp-container'>
|
|
42
|
+
<div className='m-5'>
|
|
43
|
+
<div>
|
|
44
|
+
<img
|
|
45
|
+
src={undpLogo}
|
|
46
|
+
className='logo react mb-8'
|
|
47
|
+
alt='React logo'
|
|
48
|
+
width='72px'
|
|
49
|
+
style={{ marginLeft: 'auto', marginRight: 'auto' }}
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
<H3 className='text-center'>
|
|
53
|
+
This is template for building visualization and frontend project
|
|
54
|
+
maintained by UNDP's DAI Hub.
|
|
55
|
+
<br />
|
|
56
|
+
<br />
|
|
57
|
+
Contact us at data@undp.org if you have any feedback or questions.
|
|
58
|
+
<br />
|
|
59
|
+
<br />
|
|
60
|
+
{data.length} elements in the query
|
|
61
|
+
</H3>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default App;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { StrictMode } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
4
|
+
|
|
5
|
+
import './styles/fonts.css';
|
|
6
|
+
import './styles/style.css';
|
|
7
|
+
|
|
8
|
+
import App from './App';
|
|
9
|
+
|
|
10
|
+
const queryClient = new QueryClient({
|
|
11
|
+
defaultOptions: {
|
|
12
|
+
queries: {
|
|
13
|
+
staleTime: 1000 * 60 * 60 * 24, // how long fetched data is considered “fresh” before it becomes “stale” 🡢 24 hrs
|
|
14
|
+
gcTime: 1000 * 60 * 60 * 24, // how long inactive (unused) query data stays in memory before being deleted 🡢 24 hrs
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const rootElement = document.getElementById('app');
|
|
20
|
+
if (rootElement && !rootElement.innerHTML) {
|
|
21
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
22
|
+
root.render(
|
|
23
|
+
<StrictMode>
|
|
24
|
+
<QueryClientProvider client={queryClient}>
|
|
25
|
+
<App />
|
|
26
|
+
</QueryClientProvider>
|
|
27
|
+
</StrictMode>,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { H3 } from '@undp/design-system-react';
|
|
2
|
+
|
|
3
|
+
import '@/styles/fonts.css';
|
|
4
|
+
import '@/styles/style.css';
|
|
5
|
+
import undpLogo from './assets/undp-logo-blue.svg';
|
|
6
|
+
|
|
7
|
+
function App() {
|
|
8
|
+
return (
|
|
9
|
+
<div className='m-5'>
|
|
10
|
+
<div>
|
|
11
|
+
<img
|
|
12
|
+
src={undpLogo}
|
|
13
|
+
className='logo react mb-8'
|
|
14
|
+
alt='React logo'
|
|
15
|
+
width='72px'
|
|
16
|
+
style={{ marginLeft: 'auto', marginRight: 'auto' }}
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
<H3 className='text-center'>
|
|
20
|
+
This is template for building visualization and frontend project
|
|
21
|
+
maintained by UNDP's DAI Hub.
|
|
22
|
+
<br />
|
|
23
|
+
<br />
|
|
24
|
+
Contact us at data@undp.org if you have any feedback or questions.
|
|
25
|
+
</H3>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default App;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Footer,
|
|
3
|
+
FooterLogoUnit,
|
|
4
|
+
FooterCopyrightUnit,
|
|
5
|
+
} from '@undp/design-system-react/Footer';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default function Header() {
|
|
10
|
+
return (
|
|
11
|
+
<Footer>
|
|
12
|
+
<FooterLogoUnit>
|
|
13
|
+
subscribe to email
|
|
14
|
+
</FooterLogoUnit>
|
|
15
|
+
<FooterCopyrightUnit>
|
|
16
|
+
Footnote can be added here
|
|
17
|
+
</FooterCopyrightUnit>
|
|
18
|
+
</Footer>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Header,
|
|
3
|
+
HeaderLogoUnit,
|
|
4
|
+
HeaderMainNavUnit,
|
|
5
|
+
HeaderMenuUnit,
|
|
6
|
+
} from '@undp/design-system-react/Header';
|
|
7
|
+
import { Link } from '@tanstack/react-router';
|
|
8
|
+
|
|
9
|
+
export default function Header() {
|
|
10
|
+
return (
|
|
11
|
+
<Header>
|
|
12
|
+
<HeaderLogoUnit
|
|
13
|
+
hyperlink="./"
|
|
14
|
+
siteName="Site name"
|
|
15
|
+
siteSubName="Sub-site name"
|
|
16
|
+
/>
|
|
17
|
+
<HeaderMainNavUnit>
|
|
18
|
+
<HeaderMenuUnit>
|
|
19
|
+
<Link to='/'>
|
|
20
|
+
Home
|
|
21
|
+
</Link>
|
|
22
|
+
<Link to='/about'>
|
|
23
|
+
About
|
|
24
|
+
</Link>
|
|
25
|
+
</HeaderMenuUnit>
|
|
26
|
+
</HeaderMainNavUnit>
|
|
27
|
+
</Header>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { StrictMode } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import {
|
|
4
|
+
Outlet,
|
|
5
|
+
RouterProvider,
|
|
6
|
+
createRootRoute,
|
|
7
|
+
createRoute,
|
|
8
|
+
createRouter,
|
|
9
|
+
} from '@tanstack/react-router';
|
|
10
|
+
|
|
11
|
+
import About from './routes/About.tsx';
|
|
12
|
+
import Header from './components/Header';
|
|
13
|
+
import Footer from './components/Footer';
|
|
14
|
+
|
|
15
|
+
import './styles/fonts.css';
|
|
16
|
+
import './styles/style.css';
|
|
17
|
+
|
|
18
|
+
import App from './App';
|
|
19
|
+
|
|
20
|
+
const rootRoute = createRootRoute({
|
|
21
|
+
component: () => (
|
|
22
|
+
<>
|
|
23
|
+
<Header />
|
|
24
|
+
<Outlet />
|
|
25
|
+
<Footer />
|
|
26
|
+
</>
|
|
27
|
+
),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const indexRoute = createRoute({
|
|
31
|
+
getParentRoute: () => rootRoute,
|
|
32
|
+
path: '/',
|
|
33
|
+
component: App,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const routeTree = rootRoute.addChildren([indexRoute, About(rootRoute)]);
|
|
37
|
+
|
|
38
|
+
const router = createRouter({
|
|
39
|
+
routeTree,
|
|
40
|
+
defaultPreload: 'intent',
|
|
41
|
+
scrollRestoration: true,
|
|
42
|
+
defaultStructuralSharing: true,
|
|
43
|
+
defaultPreloadStaleTime: 0,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
declare module '@tanstack/react-router' {
|
|
47
|
+
interface Register {
|
|
48
|
+
router: typeof router;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const rootElement = document.getElementById('app');
|
|
53
|
+
if (rootElement && !rootElement.innerHTML) {
|
|
54
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
55
|
+
root.render(
|
|
56
|
+
<StrictMode>
|
|
57
|
+
<RouterProvider router={router} />
|
|
58
|
+
</StrictMode>,
|
|
59
|
+
);
|
|
60
|
+
}
|