nitro-web 0.0.1 → 0.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.
- package/.eslintrc.json +2 -5
- package/_example/{.env-example → .env} +3 -3
- package/_example/client/config.ts +1 -5
- package/_example/client/index.ts +1 -18
- package/_example/components/auth.api.js +1 -1
- package/_example/components/index.tsx +11 -3
- package/_example/components/settings.api.js +1 -1
- package/_example/package.json +109 -0
- package/_example/server/config.js +3 -16
- package/_example/server/index.js +4 -3
- package/_example/tailwind.config.js +12 -21
- package/_example/tsconfig.json +2 -2
- package/_example/types/index.d.ts +13 -0
- package/_example/types/twin.d.ts +19 -0
- package/_example/webpack.config.js +2 -3
- package/client/index.js +42 -0
- package/components/auth/signin.jsx +9 -1
- package/components/partials/element/modal.jsx +1 -1
- package/components/partials/form/drop-handler.jsx +1 -1
- package/components/partials/form/input-currency.jsx +5 -2
- package/components/partials/form/input-date.jsx +6 -6
- package/components/partials/form/input.jsx +9 -9
- package/components/partials/layout/layout2.jsx +1 -1
- package/components/partials/styleguide.jsx +6 -7
- package/components/settings/settings-account.jsx +1 -1
- package/components/settings/settings-business.jsx +1 -4
- package/components/settings/settings-team--member.jsx +1 -1
- package/package.json +28 -97
- package/readme.md +39 -9
- package/server/email/index.js +12 -10
- package/server/index.js +23 -0
- package/server/router.js +4 -8
- package/util.js +13 -0
- package/webpack.config.js +42 -42
- package/_example/types.d.ts +0 -7
- package/client.js +0 -42
- package/server.js +0 -20
|
@@ -17,7 +17,7 @@ export function Layout2({ Logo }) {
|
|
|
17
17
|
<Outlet />
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
-
<div class="wrapper-2 w-full px-5 pb-4 flex items-center
|
|
20
|
+
<div class="wrapper-2 w-full px-5 pb-4 flex items-center text-sm text-[#1F1F1F]">
|
|
21
21
|
<ul class="flex-1 flex gap-4 list-style-none">
|
|
22
22
|
<li><Link class="underline1" to="/">Home</Link></li>
|
|
23
23
|
<li><Link class="underline1" to="/signin">About</Link></li>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/*eslint-disable*/
|
|
2
1
|
import { getCountryOptions, getCurrencyOptions, ucFirst } from '../../util.js'
|
|
3
2
|
import { CheckIcon } from '@heroicons/react/20/solid'
|
|
4
3
|
import { Input } from './form/input.jsx'
|
|
@@ -14,14 +13,13 @@ export function Styleguide({ config }) {
|
|
|
14
13
|
address: '',
|
|
15
14
|
country: 'us',
|
|
16
15
|
currency: 'nzd', // can be commented too
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
amount: 100,
|
|
17
|
+
brandColor: '#F3CA5F',
|
|
19
18
|
firstName: 'Tony',
|
|
20
19
|
date: Date.now(),
|
|
21
20
|
errors: [
|
|
22
21
|
{ title: 'address', detail: 'Address is required' },
|
|
23
22
|
{ title: 'currency', detail: 'Currency is required' },
|
|
24
|
-
// { title: 'brandColor', detail: 'Color is required' },
|
|
25
23
|
],
|
|
26
24
|
})
|
|
27
25
|
|
|
@@ -75,7 +73,8 @@ export function Styleguide({ config }) {
|
|
|
75
73
|
</div>
|
|
76
74
|
<div>
|
|
77
75
|
<label for="input1">Label</label>
|
|
78
|
-
<Checkbox name="input1" type="radio" text="Radio 1" subtext="some additional text here 1." id="input1-1" class="!mb-0"
|
|
76
|
+
<Checkbox name="input1" type="radio" text="Radio 1" subtext="some additional text here 1." id="input1-1" class="!mb-0"
|
|
77
|
+
defaultChecked />
|
|
79
78
|
<Checkbox name="input1" type="radio" text="Radio 2" subtext="some additional text here 2." id="input1-2" class="!mt-0" />
|
|
80
79
|
</div>
|
|
81
80
|
<div>
|
|
@@ -118,8 +117,8 @@ export function Styleguide({ config }) {
|
|
|
118
117
|
<div><Button color="primary-md">*-md (default)</Button></div>
|
|
119
118
|
<div><Button color="primary-lg">*-lg button</Button></div>
|
|
120
119
|
<div><Button IconLeft={<CheckIcon class="size-5 -my-5 -mx-0.5" />}>IconLeft=Element</Button></div>
|
|
121
|
-
<div><Button IconRight="v">IconRight
|
|
122
|
-
<div><Button IconRight2="v" className="w-[200px]">IconRight2
|
|
120
|
+
<div><Button IconRight="v">IconRight="v"</Button></div>
|
|
121
|
+
<div><Button IconRight2="v" className="w-[200px]">IconRight2="v"</Button></div>
|
|
123
122
|
<div><Button color="primary" isLoading>primary isLoading</Button></div>
|
|
124
123
|
</div>
|
|
125
124
|
|
|
@@ -36,7 +36,7 @@ export function SettingsBusiness({ config }) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
|
-
<div
|
|
39
|
+
<div>
|
|
40
40
|
<Topbar
|
|
41
41
|
title={<>Settings</>}
|
|
42
42
|
submenu={
|
|
@@ -116,6 +116,3 @@ export function SettingsBusiness({ config }) {
|
|
|
116
116
|
)
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
import { css } from '@emotion/react'
|
|
120
|
-
const style = (_theme) => css`
|
|
121
|
-
`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// todo: finish tailwind conversion
|
|
2
|
-
import { css } from '
|
|
2
|
+
import { css } from 'twin.macro'
|
|
3
3
|
import { Button } from '../partials/element/button.jsx'
|
|
4
4
|
import { Modal } from '../partials/element/modal.jsx'
|
|
5
5
|
import { FormError } from '../partials/form/form-error.jsx'
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "nitro-web",
|
|
3
3
|
"description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
|
|
4
4
|
"repository": "github:boycce/nitro-web",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.2",
|
|
6
6
|
"main": "client.js",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"keywords": [
|
|
@@ -14,41 +14,28 @@
|
|
|
14
14
|
"tailwind",
|
|
15
15
|
"webpack"
|
|
16
16
|
],
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
"workspaces": [
|
|
18
|
+
"_example"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./client/index.js",
|
|
22
|
+
"./server": "./server/index.js",
|
|
23
|
+
"./util": "./util.js",
|
|
24
|
+
"./.eslintrc.json": "./.eslintrc.json",
|
|
25
|
+
"./webpack.config.js": "./webpack.config.js"
|
|
25
26
|
},
|
|
26
27
|
"scripts": {
|
|
27
|
-
"
|
|
28
|
-
"dev": "clear && npm run dev:server:lint --silent & npm run dev:server --silent & npm run dev:client --silent",
|
|
29
|
-
"dev:client": "NITRO=true webpack serve --progress --config ./_example/webpack.config.js",
|
|
30
|
-
"dev:server": "NITRO=true nodemon ./_example/server -q -w ./_example/server/ -w ./_example/components/ -w ./server/ -w ./components/ -e js",
|
|
31
|
-
"dev:server:lint": "eslint ./_example/components ./_example/server ./components/ ./server/",
|
|
28
|
+
"dev": "npm run dev -w example",
|
|
32
29
|
"major": "standard-version --release-as major && npm publish",
|
|
33
30
|
"minor": "standard-version --release-as minor && npm publish",
|
|
34
|
-
"patch": "standard-version --release-as patch && npm publish"
|
|
35
|
-
"start": "node ./_example/server",
|
|
36
|
-
"stripe": "stripe listen --forward-to localhost:3001/api/stripe/webhook"
|
|
31
|
+
"patch": "standard-version --release-as patch && npm publish"
|
|
37
32
|
},
|
|
38
33
|
"dependencies": {
|
|
39
|
-
"@emotion/react": "^11.11.4",
|
|
40
|
-
"@headlessui/react": "^2.2.0",
|
|
41
|
-
"@heroicons/react": "^2.2.0",
|
|
42
|
-
"@hokify/axios": "^0.19.1",
|
|
43
|
-
"@stripe/react-stripe-js": "^1.9.0",
|
|
44
|
-
"@stripe/stripe-js": "^1.34.0",
|
|
45
34
|
"@uiw/color-convert": "^2.3.0",
|
|
46
35
|
"@uiw/react-color-hue": "^2.3.0",
|
|
47
36
|
"@uiw/react-color-saturation": "^2.3.0",
|
|
48
|
-
"axios-retry": "^3.3.1",
|
|
49
37
|
"bcrypt": "^5.0.0",
|
|
50
38
|
"body-parser": "^1.19.0",
|
|
51
|
-
"chart.js": "^4.4.3",
|
|
52
39
|
"compression": "^1.7.4",
|
|
53
40
|
"connect-mongo": "^5.1.0",
|
|
54
41
|
"date-fns": "^3.6.0",
|
|
@@ -58,98 +45,51 @@
|
|
|
58
45
|
"express-fileupload": "^1.1.6",
|
|
59
46
|
"express-session": "^1.17.0",
|
|
60
47
|
"inline-css": "^4.0.2",
|
|
61
|
-
"monastery": "~3.5.1",
|
|
62
48
|
"nanoid": "^4.0.0",
|
|
63
49
|
"nodemailer": "^6.5.0",
|
|
64
50
|
"nodemailer-mailgun-transport": "^2.0.2",
|
|
65
51
|
"nunjucks": "^3.2.2",
|
|
66
52
|
"passport": "^0.4.1",
|
|
67
|
-
"passport-jwt": "^4.0.0",
|
|
68
53
|
"passport-local": "^1.0.0",
|
|
69
|
-
"pdf-to-img": "^4.1.0",
|
|
70
|
-
"pdfmake": "0.2.7",
|
|
71
|
-
"react": "^18.3.1",
|
|
72
|
-
"react-chartjs-2": "^5.2.0",
|
|
73
54
|
"react-currency-input-field": "^3.8.0",
|
|
74
55
|
"react-day-picker": "^8.10.1",
|
|
75
|
-
"react-dom": "^18.3.1",
|
|
76
56
|
"react-number-format": "^5.4.0",
|
|
77
57
|
"react-router-dom": "6.24.1",
|
|
78
58
|
"react-select": "^5.9.0",
|
|
79
59
|
"react-tracked": "^1.3.0",
|
|
80
|
-
"sort-route-addresses-nodeps": "0.0.4"
|
|
81
|
-
|
|
60
|
+
"sort-route-addresses-nodeps": "0.0.4"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@headlessui/react": "^2.2.0",
|
|
64
|
+
"@heroicons/react": "^2.2.0",
|
|
65
|
+
"@hokify/axios": "^0.19.1",
|
|
66
|
+
"@stripe/stripe-js": "^1.34.0",
|
|
67
|
+
"axios-retry": "^3.3.1",
|
|
68
|
+
"monastery": "^3.5.2",
|
|
69
|
+
"react": "^18.3.1",
|
|
70
|
+
"react-dom": "^18.3.1",
|
|
71
|
+
"stripe": "^9.16.0",
|
|
72
|
+
"twin.macro": "^3.4.1"
|
|
82
73
|
},
|
|
83
74
|
"devDependencies": {
|
|
84
|
-
"@babel/core": "^7.8.0",
|
|
85
|
-
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
86
|
-
"@babel/plugin-transform-runtime": "^7.17.0",
|
|
87
|
-
"@babel/preset-env": "^7.8.0",
|
|
88
|
-
"@babel/preset-react": "^7.9.4",
|
|
89
|
-
"@babel/preset-typescript": "^7.24.7",
|
|
90
|
-
"@emotion/babel-plugin": "^11.11.0",
|
|
91
75
|
"@emotion/eslint-plugin": "^11.11.0",
|
|
92
|
-
"@
|
|
93
|
-
"@
|
|
76
|
+
"@emotion/react": "^11.11.4",
|
|
77
|
+
"@emotion/styled": "^11.11.4",
|
|
94
78
|
"@types/react": "^19.0.2",
|
|
95
79
|
"@types/react-dom": "^19.0.2",
|
|
96
80
|
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
97
81
|
"@typescript-eslint/parser": "^8.18.1",
|
|
98
|
-
"autoprefixer": "^9.8.8",
|
|
99
82
|
"babel-eslint": "^10.0.3",
|
|
100
|
-
"babel-loader": "^8.0.6",
|
|
101
|
-
"babel-plugin-macros": "^3.1.0",
|
|
102
|
-
"babel-plugin-react-html-attrs": "^2.1.0",
|
|
103
|
-
"clean-terminal-webpack-plugin": "https://github.com/boycce/clean-terminal-webpack-plugin.git",
|
|
104
|
-
"color": "^4.2.3",
|
|
105
|
-
"copy-webpack-plugin": "^12.0.2",
|
|
106
|
-
"core-js": "^3.12.1",
|
|
107
|
-
"css-loader": "^3.6.0",
|
|
108
|
-
"csv-loader": "^3.0.5",
|
|
109
83
|
"eslint": "^8.57.1",
|
|
110
84
|
"eslint-plugin-import": "^2.26.0",
|
|
111
|
-
"eslint-plugin-jest": "^28.9.0",
|
|
112
85
|
"eslint-plugin-react": "^7.19.0",
|
|
113
86
|
"eslint-plugin-react-hooks": "^4.0.0",
|
|
114
87
|
"eslint-webpack-plugin": "^2.7.0",
|
|
115
|
-
"
|
|
116
|
-
"html-webpack-plugin": "^5.6.0",
|
|
117
|
-
"jest": "^29.7.0",
|
|
118
|
-
"migrate-mongo": "^10.0.0",
|
|
119
|
-
"mini-css-extract-plugin": "^2.9.0",
|
|
120
|
-
"nodemon": "^2.0.1",
|
|
121
|
-
"postcss": "^8.4.49",
|
|
122
|
-
"postcss-for": "^2.1.1",
|
|
123
|
-
"postcss-import": "^16.1.0",
|
|
124
|
-
"postcss-import-resolver": "^2.0.0",
|
|
125
|
-
"postcss-loader": "^8.1.1",
|
|
126
|
-
"postcss-nested": "^7.0.2",
|
|
127
|
-
"react-refresh": "^0.14.2",
|
|
128
|
-
"standard-version": "^9.3.2",
|
|
129
|
-
"string-replace-loader": "^3.1.0",
|
|
130
|
-
"super-nunjucks-loader": "^2.0.0",
|
|
131
|
-
"tailwind-merge": "^2.6.0",
|
|
132
|
-
"tailwindcss": "^3.4.17",
|
|
133
|
-
"twin.macro": "^3.4.1",
|
|
134
|
-
"typescript": "^5.5.2",
|
|
135
|
-
"webpack": "^5.92.1",
|
|
136
|
-
"webpack-cli": "^5.1.4",
|
|
137
|
-
"webpack-dev-server": "^4.6.0",
|
|
138
|
-
"webpack-node-externals": "^1.7.2"
|
|
88
|
+
"standard-version": "^9.3.2"
|
|
139
89
|
},
|
|
140
90
|
"engines": {
|
|
141
91
|
"node": "^18"
|
|
142
92
|
},
|
|
143
|
-
"browserslist": [
|
|
144
|
-
"> 1%",
|
|
145
|
-
"last 2 versions",
|
|
146
|
-
"not ie <= 10"
|
|
147
|
-
],
|
|
148
|
-
"nodemonConfig": {
|
|
149
|
-
"events": {
|
|
150
|
-
"restart": "echo \"\\033[0;35mExpress restarting..\\033[0m\""
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
93
|
"standard-version": {
|
|
154
94
|
"releaseCommitMessageFormat": "{{currentTag}}",
|
|
155
95
|
"sign": true,
|
|
@@ -158,15 +98,6 @@
|
|
|
158
98
|
"tag": true
|
|
159
99
|
}
|
|
160
100
|
},
|
|
161
|
-
"prettier": {
|
|
162
|
-
"printWidth": 140,
|
|
163
|
-
"quoteProps": "consistent",
|
|
164
|
-
"semi": false,
|
|
165
|
-
"singleQuote": true,
|
|
166
|
-
"tabWidth": 2,
|
|
167
|
-
"trailingComma": "es5",
|
|
168
|
-
"useTabs": false
|
|
169
|
-
},
|
|
170
101
|
"jest": {
|
|
171
102
|
"transform": {}
|
|
172
103
|
},
|
package/readme.md
CHANGED
|
@@ -1,22 +1,43 @@
|
|
|
1
1
|
# Nitro
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/nitro-web)
|
|
3
|
+
[](https://www.npmjs.com/package/nitro-web)
|
|
4
4
|
|
|
5
5
|
Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀
|
|
6
6
|
|
|
7
|
-
### Install
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
8
|
npm i nitro-web
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
###
|
|
11
|
+
### Install
|
|
14
12
|
|
|
15
|
-
1. Copy
|
|
16
|
-
2.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
1. Copy `./_example` into your project
|
|
14
|
+
2. In package.json, replace `"nitro-web": "file:.."` with `"nitro-web": "^0.0.1"`
|
|
15
|
+
3. In package.json, replace `"../.eslintrc.json"` with `"./node_modules/nitro-web/.eslintrc.json"`
|
|
16
|
+
4. In tsconfig.json, remove
|
|
17
|
+
```json
|
|
18
|
+
"paths": {
|
|
19
|
+
"nitro-web": [
|
|
20
|
+
"../client/index.js",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
```
|
|
24
|
+
5. Run `npm i`
|
|
25
|
+
|
|
26
|
+
### Usage
|
|
27
|
+
|
|
28
|
+
On the client, you can import components and page-components as you would normally. See the example folder for further info.
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
import { SigninPage, Toggle, util } from 'nitro-web'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
On the server, you can import the express router, default models, and controllers. See the example folder for further info.
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
import { setupRouter, util } from 'nitro-web/server.js'
|
|
38
|
+
const server = await setupRouter(config)
|
|
39
|
+
server.listen(3001, '0.0.0.0')
|
|
40
|
+
```
|
|
20
41
|
|
|
21
42
|
### Running in development
|
|
22
43
|
|
|
@@ -41,3 +62,12 @@ npm run start
|
|
|
41
62
|
- React `^18.3`
|
|
42
63
|
- Tailwind `^3.4`
|
|
43
64
|
- Webpack `^5.92`
|
|
65
|
+
|
|
66
|
+
### Common packages
|
|
67
|
+
|
|
68
|
+
- `pdf-to-img`
|
|
69
|
+
- `pdfmake`
|
|
70
|
+
- `react-chartjs-2`
|
|
71
|
+
- `jest: ^29.7.0`
|
|
72
|
+
- `migrate-mongo: ^10.0.0`
|
|
73
|
+
- `eslint-plugin-jest: ^28.9.0`
|
package/server/email/index.js
CHANGED
|
@@ -5,12 +5,13 @@ import nunjucks from 'nunjucks'
|
|
|
5
5
|
import inlineCss from 'inline-css'
|
|
6
6
|
import { dirname, join } from 'path'
|
|
7
7
|
import { fileURLToPath } from 'url'
|
|
8
|
+
import path from 'path'
|
|
9
|
+
import { getDirectories } from '../../util.js'
|
|
8
10
|
|
|
9
11
|
let templates = {}
|
|
10
12
|
let nodemailerMailgun = undefined
|
|
11
13
|
const _dirname = dirname(fileURLToPath(import.meta.url)) + '/'
|
|
12
14
|
|
|
13
|
-
|
|
14
15
|
export async function sendEmail({ template, to, bcc, data={}, from, replyTo, recipientVariables, subject, test, skipCssInline, config }) {
|
|
15
16
|
/**
|
|
16
17
|
* Email recipient a predefined template with data and/or recipientVariables
|
|
@@ -72,7 +73,7 @@ export async function sendEmail({ template, to, bcc, data={}, from, replyTo, rec
|
|
|
72
73
|
let settings = {
|
|
73
74
|
bcc: bcc,
|
|
74
75
|
from: from,
|
|
75
|
-
isDev: config.clientUrl.match(/:/),
|
|
76
|
+
isDev: config.clientUrl.match(/:/), // possibly use config.env here
|
|
76
77
|
recipientVariables: recipientVariables,
|
|
77
78
|
replyTo: replyTo,
|
|
78
79
|
skipCssInline: skipCssInline,
|
|
@@ -81,34 +82,35 @@ export async function sendEmail({ template, to, bcc, data={}, from, replyTo, rec
|
|
|
81
82
|
test: config.emailTestMode || test,
|
|
82
83
|
to: to,
|
|
83
84
|
url: config.clientUrl,
|
|
85
|
+
emailTemplateDir: getDirectories(path, config.pwd).emailTemplateDir,
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
// Grab html and send
|
|
87
|
-
let html = template.match('<') ? template : await getTemplate(settings
|
|
89
|
+
let html = template.match('<') ? template : await getTemplate(settings)
|
|
88
90
|
if (!html) throw new Error('Sendmail: No template returned from getTemplate(..)')
|
|
89
91
|
return await sendWithMailgun(settings, html) // note, mailgun errors are resolved
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
async function getTemplate(settings
|
|
94
|
+
async function getTemplate(settings) {
|
|
93
95
|
try {
|
|
94
96
|
var templateName = settings.template
|
|
95
97
|
if (!templates[templateName] || settings.isDev) {
|
|
96
|
-
nunjucks.configure({ noCache:
|
|
98
|
+
nunjucks.configure({ noCache: settings.isDev })
|
|
97
99
|
// Setup the nunjucks environment
|
|
98
|
-
let
|
|
99
|
-
new nunjucks.FileSystemLoader(`${
|
|
100
|
+
let nunjucksEnv = new nunjucks.Environment([
|
|
101
|
+
new nunjucks.FileSystemLoader(`${settings.emailTemplateDir}`), // user templates take precedence
|
|
100
102
|
new nunjucks.FileSystemLoader(`${_dirname}`), // then fallback to nitro default templates
|
|
101
103
|
])
|
|
102
104
|
// Get the template
|
|
103
|
-
let template =
|
|
105
|
+
let template = nunjucksEnv.getTemplate(templateName + '.html', true)
|
|
104
106
|
// Render the template
|
|
105
107
|
let html = template.render({})
|
|
106
108
|
if (settings.skipCssInline && settings.test) {
|
|
107
109
|
templates[templateName] = html
|
|
108
110
|
} else {
|
|
109
111
|
try {
|
|
110
|
-
// First try to inline the CSS from the user templates directory
|
|
111
|
-
templates[templateName] = await inlineCssForPath(html,
|
|
112
|
+
// First try to inline the CSS from the user templates directory
|
|
113
|
+
templates[templateName] = await inlineCssForPath(html, settings.emailTemplateDir)
|
|
112
114
|
} catch (e) {
|
|
113
115
|
// If the CSS is not found, use default nitro CSS file
|
|
114
116
|
if (templateName == 'reset-password' || templateName == 'welcome') {
|
package/server/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export * from '../util.js'
|
|
2
|
+
export * as util from '../util.js'
|
|
3
|
+
|
|
4
|
+
// Export models
|
|
5
|
+
import userModel from './models/user.js'
|
|
6
|
+
import companyModel from './models/company.js'
|
|
7
|
+
async function setupDefaultModels(db) {
|
|
8
|
+
// Load default nitro models, if they don't exist already
|
|
9
|
+
if (!db.models.user) await db.model('user', userModel)
|
|
10
|
+
if (!db.models.company) await db.model('company', companyModel)
|
|
11
|
+
}
|
|
12
|
+
export { userModel, companyModel, setupDefaultModels }
|
|
13
|
+
|
|
14
|
+
// Export router
|
|
15
|
+
export { setupRouter } from './router.js'
|
|
16
|
+
|
|
17
|
+
// Export email utility
|
|
18
|
+
export { sendEmail } from './email/index.js'
|
|
19
|
+
|
|
20
|
+
// Export api default controllers
|
|
21
|
+
export { default as auth } from '../components/auth/auth.api.js'
|
|
22
|
+
export { default as settings } from '../components/settings/settings.api.js'
|
|
23
|
+
export { default as stripe } from '../components/billing/stripe.api.js'
|
package/server/router.js
CHANGED
|
@@ -14,19 +14,16 @@ import * as util from '../util.js'
|
|
|
14
14
|
const _dirname = dirname(fileURLToPath(import.meta.url)) + '/'
|
|
15
15
|
|
|
16
16
|
export async function setupRouter (config) {
|
|
17
|
-
const {
|
|
17
|
+
const { env, middleware, version } = config
|
|
18
|
+
const { componentsDir, distDir, emailTemplateDir } = util.getDirectories(path, config.pwd)
|
|
18
19
|
const expressApp = express()
|
|
19
20
|
const server = http.createServer(expressApp)
|
|
20
21
|
const apiRoutes = {}
|
|
21
22
|
const controllers = {}
|
|
22
23
|
const allMiddleware = { ...defaultMiddleware, ...(middleware || {}) }
|
|
23
24
|
|
|
24
|
-
if (!
|
|
25
|
-
throw new Error('setupRouter: `config.componentsDir` missing')
|
|
26
|
-
} else if (!env) {
|
|
25
|
+
if (!env) {
|
|
27
26
|
throw new Error('setupRouter: `config.env` missing')
|
|
28
|
-
} else if (!emailTemplateDir) {
|
|
29
|
-
throw new Error('setupRouter: `config.emailTemplateDir` missing')
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
// Extend request/response with our custom error responses
|
|
@@ -95,8 +92,7 @@ export async function setupRouter (config) {
|
|
|
95
92
|
expressApp.get('/email/partials/email.css', (req, res) => {
|
|
96
93
|
// first check if there is a custom email.css in the emailTemplateDir
|
|
97
94
|
// if not, return the default nitro email.css
|
|
98
|
-
|
|
99
|
-
if (fs.existsSync(emailTemplateDir + '/partials/email.css')) res.sendFile(emailTemplateDir + '/partials/email.css')
|
|
95
|
+
if (fs.existsSync(emailTemplateDir + 'partials/email.css')) res.sendFile(emailTemplateDir + 'partials/email.css')
|
|
100
96
|
else res.sendFile(_dirname + 'email/partials/email.css')
|
|
101
97
|
})
|
|
102
98
|
expressApp.get('/email/:name', async (req, res) => {
|
package/util.js
CHANGED
|
@@ -490,6 +490,19 @@ export function getCurrencyPrefixWidth (prefix, paddingRight=0) {
|
|
|
490
490
|
return width
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
+
export function getDirectories (path, pwd) {
|
|
494
|
+
const _pwd = pwd || process.env.PWD
|
|
495
|
+
return {
|
|
496
|
+
clientDir: path.join(_pwd, process.env.clientDir || 'client', '/'),
|
|
497
|
+
componentsDir: path.join(_pwd, process.env.componentsDir || 'components', '/'),
|
|
498
|
+
distDir: path.join(_pwd, process.env.distDir || ((process.env.clientDir || 'client') + '/dist'), '/'),
|
|
499
|
+
emailTemplateDir: path.join(_pwd, process.env.emailTemplateDir || 'server/email', '/'),
|
|
500
|
+
fontsDir: path.join(_pwd, (process.env.clientDir || 'client'), 'fonts', '/'),
|
|
501
|
+
imgsDir: path.join(_pwd, (process.env.clientDir || 'client'), 'imgs', '/'),
|
|
502
|
+
tmpDir: path.join(_pwd, process.env.tmpDir || 'tmp', '/'),
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
493
506
|
export function getLink (obj, query) {
|
|
494
507
|
/**
|
|
495
508
|
* @param {object} obj - new query object
|
package/webpack.config.js
CHANGED
|
@@ -7,7 +7,7 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'
|
|
|
7
7
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
|
|
8
8
|
import webpackNodeExternals from 'webpack-node-externals'
|
|
9
9
|
import path from 'path'
|
|
10
|
-
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'
|
|
10
|
+
// import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'
|
|
11
11
|
import tailwindcss from 'tailwindcss'
|
|
12
12
|
import webpack from 'webpack'
|
|
13
13
|
import ESLintPlugin from 'eslint-webpack-plugin'
|
|
@@ -15,31 +15,27 @@ import postcssImport from 'postcss-import'
|
|
|
15
15
|
import postcssNested from 'postcss-nested'
|
|
16
16
|
import postcssFor from 'postcss-for'
|
|
17
17
|
import { createRequire } from 'module'
|
|
18
|
-
import
|
|
19
|
-
const _require = createRequire(import.meta.url)
|
|
18
|
+
import { getDirectories } from './util.js'
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const imgsDir = path.join(clientDir, 'imgs/')
|
|
25
|
-
const fontsDir = path.join(clientDir, 'fonts/')
|
|
26
|
-
const build = process.env.NODE_ENV == 'production'
|
|
20
|
+
const _require = createRequire(import.meta.url)
|
|
21
|
+
const pick = (object, list) => list.reduce((o, e) => ((o[e] = object[e]), o), {})
|
|
22
|
+
const isBuild = process.env.NODE_ENV == 'production'
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
axiosRetry(axios, {
|
|
25
|
+
retries: 10,
|
|
26
|
+
retryDelay: () => 150,
|
|
27
|
+
retryCondition: (e) => e.code == 'ECONNREFUSED',
|
|
28
|
+
})
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
retryCondition: (e) => e.code == 'ECONNREFUSED',
|
|
34
|
-
})
|
|
30
|
+
// process.traceDeprecation = true
|
|
31
|
+
export const getConfig = (config) => {
|
|
32
|
+
const { clientDir, componentsDir, distDir, imgsDir, fontsDir } = getDirectories(path, config.pwd)
|
|
35
33
|
|
|
36
|
-
// process.traceDeprecation = true
|
|
37
|
-
// eslint-disable-next-line
|
|
38
34
|
return (env, argv) => [{
|
|
39
|
-
devtool:
|
|
35
|
+
devtool: isBuild ? false : 'source-map',
|
|
40
36
|
entry: clientDir + 'index.ts',
|
|
41
|
-
// entry:
|
|
42
|
-
mode:
|
|
37
|
+
// entry: isBuild ? './client/index.tsx' : ['webpack-plugin-serve/client', './client/index.tsx'], // check this
|
|
38
|
+
mode: isBuild ? 'production' : 'development',
|
|
43
39
|
// target=node ignores node_modules
|
|
44
40
|
externals: argv.target?.[0] == 'node' ? [webpackNodeExternals()] : [],
|
|
45
41
|
// target=node ignores builtin modules
|
|
@@ -94,17 +90,18 @@ export function getWebpackConfig(config) {
|
|
|
94
90
|
{ loader: 'postcss-loader', options: {
|
|
95
91
|
postcssOptions: {
|
|
96
92
|
plugins: [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}),
|
|
93
|
+
postcssImport,
|
|
94
|
+
// postcssImport({
|
|
95
|
+
// resolve: postcssImportResolver({
|
|
96
|
+
// alias: {
|
|
97
|
+
// 'nitro-web/client/css/components.css': path.resolve(nitroDir, 'client/css/components.css'),
|
|
98
|
+
// 'nitro-web/client/css/fonts.css': path.resolve(nitroDir, 'client/css/fonts.css'),
|
|
99
|
+
// },
|
|
100
|
+
// }),
|
|
101
|
+
// }),
|
|
105
102
|
postcssNested,
|
|
106
103
|
postcssFor,
|
|
107
|
-
tailwindcss({ config:
|
|
104
|
+
tailwindcss({ config: path.resolve(config.pwd, 'tailwind.config.js') }),
|
|
108
105
|
autoprefixer,
|
|
109
106
|
],
|
|
110
107
|
},
|
|
@@ -127,19 +124,25 @@ export function getWebpackConfig(config) {
|
|
|
127
124
|
options: {
|
|
128
125
|
presets: [
|
|
129
126
|
['@babel/preset-env', { debug: false }],
|
|
130
|
-
['@babel/preset-react', { runtime: 'automatic', importSource: '@emotion/react' }],
|
|
131
127
|
['@babel/preset-typescript', { allowNamespaces: true }],
|
|
128
|
+
['@babel/preset-react', { runtime: 'automatic', importSource: '@emotion/react', development: !isBuild }],
|
|
132
129
|
],
|
|
133
130
|
plugins: [
|
|
134
131
|
'react-html-attrs',
|
|
135
132
|
'@babel/plugin-syntax-dynamic-import',
|
|
136
133
|
'@babel/plugin-transform-runtime',
|
|
137
134
|
'@emotion/babel-plugin',
|
|
138
|
-
// Below allows us to reference tailwindcss theme variables in emotion
|
|
135
|
+
// Below allows us to reference tailwindcss theme variables in emotion blocks
|
|
136
|
+
// https://github.com/ben-rogerson/twin.macro/blob/master/docs/options.md
|
|
139
137
|
// https://medium.com/fredwong-it/emotion-tailwind-twin-macro-7fdc5f2ae5f9
|
|
140
|
-
// https://github.com/ben-rogerson/twin.examples/tree/master/
|
|
141
|
-
'babel-plugin-macros',
|
|
142
|
-
|
|
138
|
+
// https://github.com/ben-rogerson/twin.examples/tree/master/react-emotion-typescript#complete-the-typescript-setup
|
|
139
|
+
['babel-plugin-macros', {
|
|
140
|
+
'twin': {
|
|
141
|
+
preset: 'emotion',
|
|
142
|
+
config: path.resolve(config.pwd, 'tailwind.config.js'),
|
|
143
|
+
},
|
|
144
|
+
}],
|
|
145
|
+
// 'react-refresh/babel', // !isBuild && _require.resolve('react-refresh/babel'),
|
|
143
146
|
].filter(Boolean),
|
|
144
147
|
},
|
|
145
148
|
},
|
|
@@ -231,7 +234,7 @@ export function getWebpackConfig(config) {
|
|
|
231
234
|
// We are outputing assets into a handy subdir to allow for easier asset cache control. We can't
|
|
232
235
|
// simply use `path` because webpack-dev-server won't work when writeFiles=false (in memory).
|
|
233
236
|
// Because of this we manually need to prefix all output filenames with `assets/`.
|
|
234
|
-
filename: `assets/bundle.[name]${
|
|
237
|
+
filename: `assets/bundle.[name]${isBuild ? '.[contenthash]' : ''}.js`,
|
|
235
238
|
path: distDir,
|
|
236
239
|
publicPath: '/',
|
|
237
240
|
},
|
|
@@ -249,7 +252,7 @@ export function getWebpackConfig(config) {
|
|
|
249
252
|
},
|
|
250
253
|
},
|
|
251
254
|
},
|
|
252
|
-
minimize:
|
|
255
|
+
minimize: isBuild,
|
|
253
256
|
},
|
|
254
257
|
plugins: [
|
|
255
258
|
// new (require('webpack-bundle-analyzer').BundleAnalyzerPlugin)(),
|
|
@@ -270,10 +273,10 @@ export function getWebpackConfig(config) {
|
|
|
270
273
|
extensions: ['js', 'mjs', 'jsx'],
|
|
271
274
|
exclude: ['node_modules'],
|
|
272
275
|
}),
|
|
273
|
-
new MiniCssExtractPlugin({ filename: `assets/bundle.[name]${
|
|
276
|
+
new MiniCssExtractPlugin({ filename: `assets/bundle.[name]${isBuild ? '.[contenthash]' : ''}.css` }),
|
|
274
277
|
new HtmlWebpackPlugin({ template: clientDir + 'index.html', filename: distDir + 'index.html' }),
|
|
275
278
|
new CleanTerminalPlugin({ skipFirstRun: true }),
|
|
276
|
-
!
|
|
279
|
+
// !isBuild && new ReactRefreshWebpackPlugin({ overlay: false }),
|
|
277
280
|
].filter(Boolean),
|
|
278
281
|
resolve: {
|
|
279
282
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
@@ -281,8 +284,6 @@ export function getWebpackConfig(config) {
|
|
|
281
284
|
alias: {
|
|
282
285
|
// required for auto-importing page components into nitro app.js router
|
|
283
286
|
'componentsDir': componentsDir,
|
|
284
|
-
// needed only for only the example app. There are also css aliases above in postcss plugins
|
|
285
|
-
'nitro-web': isNitro ? path.resolve(nitroDir, 'client.js') : undefined,
|
|
286
287
|
},
|
|
287
288
|
},
|
|
288
289
|
stats: {
|
|
@@ -298,5 +299,4 @@ export function getWebpackConfig(config) {
|
|
|
298
299
|
ignored: new RegExp(`(${componentsDir}.*\\.api\\.js$|node_modules/(?!cherry))`),
|
|
299
300
|
},
|
|
300
301
|
}]
|
|
301
|
-
|
|
302
|
-
}
|
|
302
|
+
}
|