@inglorious/create-app 1.9.1 → 1.11.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.
- package/bin/lib/app-jsx.js +22 -7
- package/bin/lib/app-lit.js +23 -7
- package/bin/lib/app-vue.js +14 -6
- package/bin/lib/app.js +85 -23
- package/bin/lib/prompts.js +17 -11
- package/bin/lib/source.js +26 -0
- package/package.json +1 -1
- package/templates/js/src/store/index.js +1 -1
- package/templates/js-jsx/src/{app.jsx → app/index.jsx} +1 -1
- package/templates/js-jsx/src/store/index.js +1 -1
- package/templates/{ts-vue/src/app.vue → js-vue/src/app/index.vue} +1 -1
- package/templates/js-vue/src/main.js +1 -1
- package/templates/js-vue/src/store/index.js +1 -1
- package/templates/minimal/src/main.js +1 -1
- package/templates/minimal/src/store/index.js +1 -1
- package/templates/ssx-ts/types/index.d.ts +10 -2
- package/templates/ssx-ts-jsx/types/index.d.ts +10 -2
- package/templates/ts/src/{app.ts → app/index.ts} +2 -2
- package/templates/ts/src/{types/message.ts → app/message/index.ts} +1 -1
- package/templates/ts/src/main.ts +6 -1
- package/templates/ts/src/store/index.ts +3 -3
- package/templates/ts/types/index.d.ts +11 -3
- package/templates/ts-jsx/src/{app.tsx → app/index.tsx} +2 -3
- package/templates/ts-jsx/src/{types/message.tsx → app/message/index.tsx} +1 -1
- package/templates/ts-jsx/src/main.ts +1 -1
- package/templates/ts-jsx/src/store/index.ts +3 -3
- package/templates/ts-jsx/types/index.d.ts +11 -3
- package/templates/{js-vue/src/app.vue → ts-vue/src/app/index.vue} +1 -1
- package/templates/ts-vue/src/main.ts +7 -2
- package/templates/ts-vue/src/store/index.ts +1 -1
- package/templates/ts-vue/types/index.d.ts +1 -1
- /package/templates/js/src/{app.js → app/index.js} +0 -0
- /package/templates/js/src/{types/message.js → app/message/index.js} +0 -0
- /package/templates/js-jsx/src/{types/message.jsx → app/message/index.jsx} +0 -0
- /package/templates/js-vue/src/{types/message.vue → app/message/index.vue} +0 -0
- /package/templates/minimal/src/{app.js → app/index.js} +0 -0
- /package/templates/minimal/src/{types/message.js → app/message/index.js} +0 -0
- /package/templates/ts/types/{vite-end.d.ts → vite-env.d.ts} +0 -0
- /package/templates/ts-jsx/types/{vite-end.d.ts → vite-env.d.ts} +0 -0
- /package/templates/ts-vue/src/{types/message.vue → app/message/index.vue} +0 -0
- /package/templates/ts-vue/types/{vite-end.d.ts → vite-env.d.ts} +0 -0
package/bin/lib/app-jsx.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { renderLocals, selectChange } from "./app-lit.js"
|
|
2
2
|
import { importBlock } from "./imports.js"
|
|
3
|
+
import { relative } from "./source.js"
|
|
3
4
|
|
|
4
5
|
export const extension = (app) => (app.isTypeScript ? "tsx" : "jsx")
|
|
5
6
|
|
|
@@ -27,8 +28,12 @@ export function appSource(app, { pages, navIcons }) {
|
|
|
27
28
|
if (app.links) imports.push('import { Link } from "@inglorious/ui/link"')
|
|
28
29
|
if (app.i18n) imports.push('import { Select } from "@inglorious/ui/select"')
|
|
29
30
|
}
|
|
30
|
-
if (app.isTypeScript)
|
|
31
|
-
|
|
31
|
+
if (app.isTypeScript)
|
|
32
|
+
imports.push(
|
|
33
|
+
`import type { AppApi } from "${relative(app.layout.app, "types")}"`,
|
|
34
|
+
)
|
|
35
|
+
if (app.i18n)
|
|
36
|
+
imports.push(`import { t } from "${relative(app.layout.app, "src/i18n")}"`)
|
|
32
37
|
|
|
33
38
|
const signature = app.isTypeScript
|
|
34
39
|
? "render(props: Record<string, unknown> | null, api: AppApi)"
|
|
@@ -56,14 +61,17 @@ ${shell}
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
export function homeSource(app, { showcase }) {
|
|
59
|
-
const imports = [
|
|
64
|
+
const imports = [
|
|
65
|
+
`import { Message } from "${relative(app.layout.home, app.layout.message)}"`,
|
|
66
|
+
]
|
|
60
67
|
for (const icon of showcase) {
|
|
61
68
|
imports.push(`import ${icon.name} from "${icon.from}"`)
|
|
62
69
|
}
|
|
63
70
|
if (showcase.length) {
|
|
64
71
|
imports.push('import { Icon } from "@inglorious/ui/icon"')
|
|
65
72
|
}
|
|
66
|
-
if (app.i18n)
|
|
73
|
+
if (app.i18n)
|
|
74
|
+
imports.push(`import { t } from "${relative(app.layout.home, "src/i18n")}"`)
|
|
67
75
|
|
|
68
76
|
const text = (key, fallback) => (app.i18n ? `{t("${key}")}` : fallback)
|
|
69
77
|
const icons = showcase.length
|
|
@@ -98,7 +106,9 @@ ${expectError(app, " ")} <Message entityId="message3" />!
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
export function aboutSource(app) {
|
|
101
|
-
const head = app.i18n
|
|
109
|
+
const head = app.i18n
|
|
110
|
+
? `import { t } from "${relative(app.layout.about, "src/i18n")}"\n\n`
|
|
111
|
+
: ""
|
|
102
112
|
const text = (key, fallback) => (app.i18n ? `{t("${key}")}` : fallback)
|
|
103
113
|
|
|
104
114
|
return `${head}export const About = {
|
|
@@ -117,9 +127,14 @@ export function aboutSource(app) {
|
|
|
117
127
|
export function messageSource(app) {
|
|
118
128
|
const imports = []
|
|
119
129
|
if (app.isTypeScript) {
|
|
120
|
-
imports.push(
|
|
130
|
+
imports.push(
|
|
131
|
+
`import type { MessageType } from "${relative(app.layout.message, "types")}"`,
|
|
132
|
+
)
|
|
121
133
|
}
|
|
122
|
-
if (app.i18n)
|
|
134
|
+
if (app.i18n)
|
|
135
|
+
imports.push(
|
|
136
|
+
`import { t } from "${relative(app.layout.message, "src/i18n")}"`,
|
|
137
|
+
)
|
|
123
138
|
const greeting = app.i18n ? '{t("message.hello", { who })}' : "Hello {who}"
|
|
124
139
|
const annotation = app.isTypeScript ? ": MessageType" : ""
|
|
125
140
|
|
package/bin/lib/app-lit.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { importBlock } from "./imports.js"
|
|
2
|
+
import { relative } from "./source.js"
|
|
2
3
|
|
|
3
4
|
export const extension = (app) => (app.isTypeScript ? "ts" : "js")
|
|
4
5
|
|
|
@@ -23,8 +24,12 @@ export function appSource(app, { pages, navIcons }) {
|
|
|
23
24
|
if (app.links) imports.push('import { Link } from "@inglorious/ui/link"')
|
|
24
25
|
if (app.i18n) imports.push('import { Select } from "@inglorious/ui/select"')
|
|
25
26
|
}
|
|
26
|
-
if (app.isTypeScript)
|
|
27
|
-
|
|
27
|
+
if (app.isTypeScript)
|
|
28
|
+
imports.push(
|
|
29
|
+
`import type { AppApi } from "${relative(app.layout.app, "types")}"`,
|
|
30
|
+
)
|
|
31
|
+
if (app.i18n)
|
|
32
|
+
imports.push(`import { t } from "${relative(app.layout.app, "src/i18n")}"`)
|
|
28
33
|
|
|
29
34
|
const label = (key, text) => (app.i18n ? `t("${key}")` : `"${text}"`)
|
|
30
35
|
const signature = app.isTypeScript
|
|
@@ -82,9 +87,12 @@ export function homeSource(app, { showcase }) {
|
|
|
82
87
|
imports.push('import { Icon } from "@inglorious/ui/icon"')
|
|
83
88
|
}
|
|
84
89
|
if (app.isTypeScript) {
|
|
85
|
-
imports.push(
|
|
90
|
+
imports.push(
|
|
91
|
+
`import type { HomeType } from "${relative(app.layout.home, "types")}"`,
|
|
92
|
+
)
|
|
86
93
|
}
|
|
87
|
-
if (app.i18n)
|
|
94
|
+
if (app.i18n)
|
|
95
|
+
imports.push(`import { t } from "${relative(app.layout.home, "src/i18n")}"`)
|
|
88
96
|
|
|
89
97
|
const text = (key, fallback) => (app.i18n ? `\${t("${key}")}` : fallback)
|
|
90
98
|
const icons = showcase.length
|
|
@@ -123,7 +131,10 @@ export const Home${annotation} = {
|
|
|
123
131
|
|
|
124
132
|
export function aboutSource(app) {
|
|
125
133
|
const imports = ['import { html } from "@inglorious/web"']
|
|
126
|
-
if (app.i18n)
|
|
134
|
+
if (app.i18n)
|
|
135
|
+
imports.push(
|
|
136
|
+
`import { t } from "${relative(app.layout.about, "src/i18n")}"`,
|
|
137
|
+
)
|
|
127
138
|
const text = (key, fallback) => (app.i18n ? `\${t("${key}")}` : fallback)
|
|
128
139
|
|
|
129
140
|
return `${importBlock(imports)}
|
|
@@ -142,9 +153,14 @@ export const About = {
|
|
|
142
153
|
export function messageSource(app) {
|
|
143
154
|
const imports = ['import { html } from "@inglorious/web"']
|
|
144
155
|
if (app.isTypeScript) {
|
|
145
|
-
imports.push(
|
|
156
|
+
imports.push(
|
|
157
|
+
`import type { MessageType } from "${relative(app.layout.message, "types")}"`,
|
|
158
|
+
)
|
|
146
159
|
}
|
|
147
|
-
if (app.i18n)
|
|
160
|
+
if (app.i18n)
|
|
161
|
+
imports.push(
|
|
162
|
+
`import { t } from "${relative(app.layout.message, "src/i18n")}"`,
|
|
163
|
+
)
|
|
148
164
|
const greeting = app.i18n ? '${t("message.hello", { who })}' : "Hello ${who}"
|
|
149
165
|
const annotation = app.isTypeScript ? ": MessageType" : ""
|
|
150
166
|
|
package/bin/lib/app-vue.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { importBlock } from "./imports.js"
|
|
2
|
-
import { LINE_WIDTH } from "./source.js"
|
|
2
|
+
import { LINE_WIDTH, relative } from "./source.js"
|
|
3
3
|
|
|
4
4
|
export const extension = () => "vue"
|
|
5
5
|
|
|
@@ -24,7 +24,8 @@ export function appSource(app, { pages, navIcons }) {
|
|
|
24
24
|
if (app.links) imports.push('import { Link } from "@inglorious/ui/link"')
|
|
25
25
|
if (app.i18n) imports.push('import { Select } from "@inglorious/ui/select"')
|
|
26
26
|
}
|
|
27
|
-
if (app.i18n)
|
|
27
|
+
if (app.i18n)
|
|
28
|
+
imports.push(`import { t } from "${relative(app.layout.app, "src/i18n")}"`)
|
|
28
29
|
|
|
29
30
|
const locals = []
|
|
30
31
|
if (app.routing) locals.push('const router = api.getEntity("router")')
|
|
@@ -47,14 +48,17 @@ ${template}
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
export function homeSource(app, { showcase }) {
|
|
50
|
-
const imports = [
|
|
51
|
+
const imports = [
|
|
52
|
+
`import { Message } from "${relative(app.layout.home, app.layout.message)}/index.vue"`,
|
|
53
|
+
]
|
|
51
54
|
for (const icon of showcase) {
|
|
52
55
|
imports.push(`import ${icon.name} from "${icon.from}"`)
|
|
53
56
|
}
|
|
54
57
|
if (showcase.length) {
|
|
55
58
|
imports.push('import { Icon } from "@inglorious/ui/icon"')
|
|
56
59
|
}
|
|
57
|
-
if (app.i18n)
|
|
60
|
+
if (app.i18n)
|
|
61
|
+
imports.push(`import { t } from "${relative(app.layout.home, "src/i18n")}"`)
|
|
58
62
|
|
|
59
63
|
const text = (key, fallback) => (app.i18n ? `{{ t("${key}") }}` : fallback)
|
|
60
64
|
const icons = showcase.length
|
|
@@ -81,7 +85,9 @@ ${showcase
|
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
export function aboutSource(app) {
|
|
84
|
-
const imports = app.i18n
|
|
88
|
+
const imports = app.i18n
|
|
89
|
+
? [`import { t } from "${relative(app.layout.about, "src/i18n")}"`]
|
|
90
|
+
: []
|
|
85
91
|
const text = (key, fallback) => (app.i18n ? `{{ t("${key}") }}` : fallback)
|
|
86
92
|
return `${script(imports, [])}<template>
|
|
87
93
|
<h1>${text("about.title", "About")}</h1>
|
|
@@ -91,7 +97,9 @@ export function aboutSource(app) {
|
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
export function messageSource(app) {
|
|
94
|
-
const imports = app.i18n
|
|
100
|
+
const imports = app.i18n
|
|
101
|
+
? [`import { t } from "${relative(app.layout.message, "src/i18n")}"`]
|
|
102
|
+
: []
|
|
95
103
|
const who = "entity.isUpperCase ? entity.who.toUpperCase() : entity.who"
|
|
96
104
|
const span = app.i18n
|
|
97
105
|
? ` <span @click="click">{{
|
package/bin/lib/app.js
CHANGED
|
@@ -15,7 +15,14 @@ import {
|
|
|
15
15
|
import { ICON_PACKS, LANGUAGES, PROMPT_TEXTS } from "./features.js"
|
|
16
16
|
import { importBlock } from "./imports.js"
|
|
17
17
|
import { envExample, promptFiles } from "./prompts.js"
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
appModel,
|
|
20
|
+
call,
|
|
21
|
+
layout,
|
|
22
|
+
LINE_WIDTH,
|
|
23
|
+
relative,
|
|
24
|
+
union,
|
|
25
|
+
} from "./source.js"
|
|
19
26
|
|
|
20
27
|
const COMPONENTS = {
|
|
21
28
|
"lit-html": litComponents,
|
|
@@ -53,6 +60,7 @@ export function addAppFeatures(targetDir, pkg, options) {
|
|
|
53
60
|
app.links = app.routing && !app.tabs
|
|
54
61
|
app.isVue = app.renderer === "vue"
|
|
55
62
|
app.hasPrompts = app.analytics || app.push
|
|
63
|
+
app.layout = layout(app)
|
|
56
64
|
|
|
57
65
|
const components = COMPONENTS[app.renderer]
|
|
58
66
|
const componentExt = components.extension(app)
|
|
@@ -60,17 +68,18 @@ export function addAppFeatures(targetDir, pkg, options) {
|
|
|
60
68
|
|
|
61
69
|
addDependencies(pkg, app)
|
|
62
70
|
|
|
71
|
+
const { layout: at } = app
|
|
63
72
|
const files = {
|
|
64
73
|
[`src/main.${app.ext}`]: mainSource(app),
|
|
65
|
-
[
|
|
66
|
-
|
|
67
|
-
[
|
|
68
|
-
[
|
|
74
|
+
[`${at.app}/index.${componentExt}`]: components.appSource(app, model),
|
|
75
|
+
[`${at.app}/style.css`]: appStyles(app),
|
|
76
|
+
[`${at.home}/index.${componentExt}`]: components.homeSource(app, model),
|
|
77
|
+
[`${at.message}/index.${componentExt}`]: components.messageSource(app),
|
|
69
78
|
[`src/store/index.${app.ext}`]: storeSource(app),
|
|
70
79
|
[`src/store/entities.${app.ext}`]: entitiesSource(app),
|
|
71
80
|
}
|
|
72
81
|
if (app.routing) {
|
|
73
|
-
files[
|
|
82
|
+
files[`${at.about}/index.${componentExt}`] = components.aboutSource(app)
|
|
74
83
|
files[`src/store/routes.${app.ext}`] = routesSource(app)
|
|
75
84
|
}
|
|
76
85
|
if (app.i18n) {
|
|
@@ -88,6 +97,10 @@ export function addAppFeatures(targetDir, pkg, options) {
|
|
|
88
97
|
files["types/index.d.ts"] = typesSource(app)
|
|
89
98
|
}
|
|
90
99
|
|
|
100
|
+
// The template's hello world keeps its messages in the shell; here they move
|
|
101
|
+
// to the home screen that renders them.
|
|
102
|
+
removeTemplateMessages(targetDir, app)
|
|
103
|
+
|
|
91
104
|
for (const [file, source] of Object.entries(files)) {
|
|
92
105
|
const filePath = path.join(targetDir, file)
|
|
93
106
|
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
@@ -97,6 +110,15 @@ export function addAppFeatures(targetDir, pkg, options) {
|
|
|
97
110
|
if (app.ui) applyTheme(targetDir, app)
|
|
98
111
|
}
|
|
99
112
|
|
|
113
|
+
function removeTemplateMessages(targetDir, app) {
|
|
114
|
+
const templateMessages = "src/app/message"
|
|
115
|
+
if (app.layout.message === templateMessages) return
|
|
116
|
+
fs.rmSync(path.join(targetDir, templateMessages), {
|
|
117
|
+
recursive: true,
|
|
118
|
+
force: true,
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
100
122
|
function addDependencies(pkg, app) {
|
|
101
123
|
pkg.dependencies ??= {}
|
|
102
124
|
if (app.ui) pkg.dependencies["@inglorious/ui"] = "workspace:*"
|
|
@@ -141,9 +163,10 @@ function applyTheme(targetDir, app) {
|
|
|
141
163
|
|
|
142
164
|
// An import of one of the app's components: Vue's name their file, and
|
|
143
165
|
// TypeScript cannot read .vue files, so it is told to expect that.
|
|
166
|
+
/** Imports a component from its folder: its index, which a .vue file names. */
|
|
144
167
|
function componentImport(app, names, from) {
|
|
145
168
|
if (!app.isVue) return `import { ${names} } from "${from}"`
|
|
146
|
-
const line = `import { ${names} } from "${from}.vue"`
|
|
169
|
+
const line = `import { ${names} } from "${from}/index.vue"`
|
|
147
170
|
return app.isTypeScript
|
|
148
171
|
? `// @ts-expect-error - Handled by @inglorious/vite-plugin-vue\n${line}`
|
|
149
172
|
: line
|
|
@@ -161,10 +184,10 @@ function mainSource(app) {
|
|
|
161
184
|
imports.push('import "@inglorious/ui/view-transitions.css"')
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
|
-
imports.push(
|
|
187
|
+
imports.push(`import "${relative("src", app.layout.app)}/style.css"`)
|
|
165
188
|
imports.push(
|
|
166
189
|
`import { ${app.hasPrompts ? "html, mount" : "mount"} } from "@inglorious/web"`,
|
|
167
|
-
componentImport(app, "App", "
|
|
190
|
+
componentImport(app, "App", relative("src", app.layout.app)),
|
|
168
191
|
'import { store } from "./store"',
|
|
169
192
|
)
|
|
170
193
|
if (app.i18n) imports.push('import { ready } from "./i18n"')
|
|
@@ -292,8 +315,8 @@ main {
|
|
|
292
315
|
function storeSource(app) {
|
|
293
316
|
const imports = [
|
|
294
317
|
'import { createStore } from "@inglorious/store"',
|
|
295
|
-
componentImport(app, "Home", "
|
|
296
|
-
componentImport(app, "Message", "
|
|
318
|
+
componentImport(app, "Home", relative("src/store", app.layout.home)),
|
|
319
|
+
componentImport(app, "Message", relative("src/store", app.layout.message)),
|
|
297
320
|
'import { entities } from "./entities"',
|
|
298
321
|
'import { middlewares } from "./middlewares"',
|
|
299
322
|
]
|
|
@@ -305,19 +328,25 @@ function storeSource(app) {
|
|
|
305
328
|
if (app.routing) {
|
|
306
329
|
imports.push(
|
|
307
330
|
'import { Router, setRoutes } from "@inglorious/web/router"',
|
|
308
|
-
componentImport(app, "About", "
|
|
331
|
+
componentImport(app, "About", relative("src/store", app.layout.about)),
|
|
309
332
|
'import { routes } from "./routes"',
|
|
310
333
|
)
|
|
311
334
|
}
|
|
312
335
|
if (app.isTypeScript) {
|
|
313
|
-
imports.push(
|
|
336
|
+
imports.push(
|
|
337
|
+
'import type { AppEntity, AppEvents, AppState } from "../../types"',
|
|
338
|
+
)
|
|
314
339
|
}
|
|
315
340
|
if (app.i18n) imports.push('import { I18n } from "../i18n"')
|
|
316
341
|
if (app.analytics) {
|
|
317
|
-
imports.push(
|
|
342
|
+
imports.push(
|
|
343
|
+
`import { Analytics } from "${relative("src/store", app.layout.analytics)}"`,
|
|
344
|
+
)
|
|
318
345
|
}
|
|
319
346
|
if (app.push) {
|
|
320
|
-
imports.push(
|
|
347
|
+
imports.push(
|
|
348
|
+
`import { PushPrompt } from "${relative("src/store", app.layout.pushPrompt)}"`,
|
|
349
|
+
)
|
|
321
350
|
}
|
|
322
351
|
|
|
323
352
|
const types = ["Message", "Home"]
|
|
@@ -332,7 +361,7 @@ function storeSource(app) {
|
|
|
332
361
|
: ` types: {
|
|
333
362
|
${types.map((type) => ` ${type},`).join("\n")}
|
|
334
363
|
},`
|
|
335
|
-
const generics = app.isTypeScript ? "<AppEntity, AppState>" : ""
|
|
364
|
+
const generics = app.isTypeScript ? "<AppEntity, AppState, AppEvents>" : ""
|
|
336
365
|
|
|
337
366
|
return `${importBlock(imports)}
|
|
338
367
|
${app.routing ? "\nsetRoutes(routes)\n" : ""}
|
|
@@ -398,13 +427,35 @@ export const { I18n, t, ready } = createI18n({
|
|
|
398
427
|
`
|
|
399
428
|
}
|
|
400
429
|
|
|
430
|
+
/**
|
|
431
|
+
* `export type AppEvents = EventsOf<...>`, wrapped as Prettier would: on one
|
|
432
|
+
* line if it fits, then with the types on a line of their own, then one per
|
|
433
|
+
* line.
|
|
434
|
+
*/
|
|
435
|
+
function eventsOf(types) {
|
|
436
|
+
const head = "export type AppEvents = EventsOf<"
|
|
437
|
+
const oneLine = `${head}${types.join(" | ")}>`
|
|
438
|
+
if (oneLine.length <= LINE_WIDTH) return oneLine
|
|
439
|
+
const inner = ` ${types.join(" | ")}`
|
|
440
|
+
if (inner.length <= LINE_WIDTH) return `${head}\n${inner}\n>`
|
|
441
|
+
return `${head}\n${types.map((type) => ` | ${type}`).join("\n")}\n>`
|
|
442
|
+
}
|
|
443
|
+
|
|
401
444
|
function typesSource(app) {
|
|
402
445
|
const imports = [
|
|
403
|
-
'import "./vite-
|
|
404
|
-
|
|
446
|
+
'import "./vite-env"',
|
|
447
|
+
`import type {
|
|
448
|
+
BaseEntity,
|
|
449
|
+
EntitiesState,
|
|
450
|
+
EntityType,
|
|
451
|
+
EventsOf,
|
|
452
|
+
} from "@inglorious/store"`,
|
|
405
453
|
'import type { Api, TemplateResult } from "@inglorious/web"',
|
|
406
454
|
]
|
|
407
455
|
const entities = ["MessageEntity", "HomeEntity"]
|
|
456
|
+
// The types whose events the app sends: its own, then the libraries'.
|
|
457
|
+
const eventTypes = ["MessageType"]
|
|
458
|
+
if (app.renderer === "lit-html") eventTypes.push("HomeType")
|
|
408
459
|
const declarations = [
|
|
409
460
|
`export interface MessageEntity extends BaseEntity {
|
|
410
461
|
type: "Message"
|
|
@@ -423,7 +474,10 @@ function typesSource(app) {
|
|
|
423
474
|
]
|
|
424
475
|
|
|
425
476
|
if (app.routing) {
|
|
426
|
-
imports.push(
|
|
477
|
+
imports.push(
|
|
478
|
+
'import type { RouterEntity, RouterType } from "@inglorious/web/router"',
|
|
479
|
+
)
|
|
480
|
+
eventTypes.push("RouterType")
|
|
427
481
|
entities.push("AboutEntity", "AppRouterEntity")
|
|
428
482
|
declarations.push(
|
|
429
483
|
`export interface AboutEntity extends BaseEntity {
|
|
@@ -437,7 +491,8 @@ function typesSource(app) {
|
|
|
437
491
|
state.push(" about: AboutEntity")
|
|
438
492
|
}
|
|
439
493
|
if (app.i18n) {
|
|
440
|
-
imports.push('import type { I18nEntity } from "@inglorious/i18n"')
|
|
494
|
+
imports.push('import type { I18nEntity, I18nType } from "@inglorious/i18n"')
|
|
495
|
+
eventTypes.push("I18nType")
|
|
441
496
|
entities.push("AppI18nEntity")
|
|
442
497
|
declarations.push(
|
|
443
498
|
`export interface AppI18nEntity extends I18nEntity {
|
|
@@ -448,8 +503,9 @@ function typesSource(app) {
|
|
|
448
503
|
}
|
|
449
504
|
if (app.analytics) {
|
|
450
505
|
imports.push(
|
|
451
|
-
'import type { AnalyticsEntity } from "@inglorious/web/analytics"',
|
|
506
|
+
'import type { AnalyticsEntity, AnalyticsType } from "@inglorious/web/analytics"',
|
|
452
507
|
)
|
|
508
|
+
eventTypes.push("AnalyticsType")
|
|
453
509
|
entities.push("AppAnalyticsEntity")
|
|
454
510
|
declarations.push(
|
|
455
511
|
`export interface AppAnalyticsEntity extends AnalyticsEntity {
|
|
@@ -459,7 +515,10 @@ function typesSource(app) {
|
|
|
459
515
|
state.push(" analytics: AppAnalyticsEntity")
|
|
460
516
|
}
|
|
461
517
|
if (app.push) {
|
|
462
|
-
imports.push(
|
|
518
|
+
imports.push(
|
|
519
|
+
'import type { PushPromptEntity, PushPromptType } from "@inglorious/web/push"',
|
|
520
|
+
)
|
|
521
|
+
eventTypes.push("PushPromptType")
|
|
463
522
|
entities.push("AppPushPromptEntity")
|
|
464
523
|
declarations.push(
|
|
465
524
|
`export interface AppPushPromptEntity extends PushPromptEntity {
|
|
@@ -481,7 +540,10 @@ export interface AppState extends EntitiesState<AppEntity> {
|
|
|
481
540
|
${state.join("\n")}
|
|
482
541
|
}
|
|
483
542
|
|
|
484
|
-
|
|
543
|
+
// The events the app's types answer, so that \`notify\` checks them.
|
|
544
|
+
${eventsOf(eventTypes)}
|
|
545
|
+
|
|
546
|
+
export type AppApi = Api<AppEntity, AppState, AppEvents>
|
|
485
547
|
|
|
486
548
|
// Each type's events and their payloads. Declare types with \`type\`, not
|
|
487
549
|
// \`interface\`: an interface does not fit the store's \`types\`.
|
package/bin/lib/prompts.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { importBlock } from "./imports.js"
|
|
2
|
-
import { LINE_WIDTH } from "./source.js"
|
|
2
|
+
import { LINE_WIDTH, relative } from "./source.js"
|
|
3
3
|
|
|
4
4
|
const FIREBASE_CONFIG_KEYS = {
|
|
5
5
|
apiKey: "VITE_FIREBASE_API_KEY",
|
|
@@ -22,12 +22,12 @@ export function promptFiles(app) {
|
|
|
22
22
|
[`src/common/prompt.${app.ext}`]: promptSource(app),
|
|
23
23
|
}
|
|
24
24
|
if (app.analytics) {
|
|
25
|
-
files[
|
|
25
|
+
files[`${app.layout.analytics}/index.${app.ext}`] = analyticsSource(app)
|
|
26
26
|
}
|
|
27
27
|
if (app.push) {
|
|
28
28
|
files[`src/api/supabase.${app.ext}`] = supabaseSource()
|
|
29
29
|
files[`src/api/push.${app.ext}`] = pushSource(app)
|
|
30
|
-
files[
|
|
30
|
+
files[`${app.layout.pushPrompt}/index.${app.ext}`] = pushPromptSource(app)
|
|
31
31
|
}
|
|
32
32
|
return files
|
|
33
33
|
}
|
|
@@ -172,13 +172,16 @@ function analyticsSource(app) {
|
|
|
172
172
|
'import { firebaseAnalytics } from "@inglorious/firebase/analytics"',
|
|
173
173
|
'import { createAnalytics } from "@inglorious/web/analytics"',
|
|
174
174
|
'import { when } from "@inglorious/web/directives/when"',
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
`import { firebaseConfig } from "${relative(app.layout.analytics, "src/api/firebase")}"`,
|
|
176
|
+
`import { Prompt } from "${relative(app.layout.analytics, "src/common/prompt")}"`,
|
|
177
177
|
]
|
|
178
|
-
if (app.i18n)
|
|
178
|
+
if (app.i18n)
|
|
179
|
+
imports.push(
|
|
180
|
+
`import { t } from "${relative(app.layout.analytics, "src/i18n")}"`,
|
|
181
|
+
)
|
|
179
182
|
if (app.isTypeScript) {
|
|
180
183
|
imports.push(
|
|
181
|
-
|
|
184
|
+
`import type { AppAnalyticsEntity, AppApi } from "${relative(app.layout.analytics, "types")}"`,
|
|
182
185
|
)
|
|
183
186
|
}
|
|
184
187
|
const label = labelFor(app)
|
|
@@ -263,13 +266,16 @@ function pushPromptSource(app) {
|
|
|
263
266
|
const imports = [
|
|
264
267
|
'import { when } from "@inglorious/web/directives/when"',
|
|
265
268
|
'import { createPushPrompt } from "@inglorious/web/push"',
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
`import { push } from "${relative(app.layout.pushPrompt, "src/api/push")}"`,
|
|
270
|
+
`import { Prompt } from "${relative(app.layout.pushPrompt, "src/common/prompt")}"`,
|
|
268
271
|
]
|
|
269
|
-
if (app.i18n)
|
|
272
|
+
if (app.i18n)
|
|
273
|
+
imports.push(
|
|
274
|
+
`import { t } from "${relative(app.layout.pushPrompt, "src/i18n")}"`,
|
|
275
|
+
)
|
|
270
276
|
if (app.isTypeScript) {
|
|
271
277
|
imports.push(
|
|
272
|
-
|
|
278
|
+
`import type { AppApi, AppPushPromptEntity } from "${relative(app.layout.pushPrompt, "types")}"`,
|
|
273
279
|
)
|
|
274
280
|
}
|
|
275
281
|
const label = labelFor(app)
|
package/bin/lib/source.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
|
|
1
3
|
import { ICON_PACKS } from "./features.js"
|
|
2
4
|
|
|
3
5
|
export const LINE_WIDTH = 80
|
|
@@ -25,6 +27,30 @@ export function appModel(app) {
|
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Where each part of a generated app lives. The shell and its own pieces are
|
|
32
|
+
* in src/app; routed screens are in src/views, and without routing the one
|
|
33
|
+
* screen is a piece of the shell. A piece lives with what renders it, so the
|
|
34
|
+
* messages live in the home screen's folder.
|
|
35
|
+
*/
|
|
36
|
+
export function layout(app) {
|
|
37
|
+
const screens = app.routing ? "src/views" : "src/app"
|
|
38
|
+
return {
|
|
39
|
+
app: "src/app",
|
|
40
|
+
home: `${screens}/home`,
|
|
41
|
+
about: "src/views/about",
|
|
42
|
+
message: `${screens}/home/message`,
|
|
43
|
+
analytics: "src/app/analytics",
|
|
44
|
+
pushPrompt: "src/app/push-prompt",
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The import specifier from a folder to a path, both relative to the project. */
|
|
49
|
+
export function relative(fromDir, to) {
|
|
50
|
+
const specifier = path.posix.relative(fromDir, to)
|
|
51
|
+
return specifier.startsWith(".") ? specifier : `./${specifier}`
|
|
52
|
+
}
|
|
53
|
+
|
|
28
54
|
export function call(name, args, indent, trailing) {
|
|
29
55
|
const line = `${indent}${name}(${args.join(", ")})${trailing}`
|
|
30
56
|
if (line.length <= LINE_WIDTH) return line
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/create-app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "A scaffolding tool to quickly create a new app with Inglorious Web.",
|
|
5
5
|
"author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
BaseEntity,
|
|
3
|
+
EntitiesState,
|
|
4
|
+
EntityType,
|
|
5
|
+
EventsOf,
|
|
6
|
+
} from "@inglorious/store"
|
|
2
7
|
import type { Api, TemplateResult } from "@inglorious/web"
|
|
3
8
|
|
|
4
9
|
export interface AboutEntity extends BaseEntity {
|
|
@@ -12,7 +17,10 @@ export interface AppState extends EntitiesState<AppEntity> {
|
|
|
12
17
|
about: AboutEntity
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
// The events the types below answer, so that `notify` checks them.
|
|
21
|
+
export type AppEvents = EventsOf<AboutType>
|
|
22
|
+
|
|
23
|
+
export type AppApi = Api<AppEntity, AppState, AppEvents>
|
|
16
24
|
|
|
17
25
|
export type AboutType = {
|
|
18
26
|
click: (entity: AboutEntity) => void
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/// <reference types="@inglorious/jsx/jsx-runtime" />
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
BaseEntity,
|
|
5
|
+
EntitiesState,
|
|
6
|
+
EntityType,
|
|
7
|
+
EventsOf,
|
|
8
|
+
} from "@inglorious/store"
|
|
4
9
|
import type { Api, TemplateResult } from "@inglorious/web"
|
|
5
10
|
|
|
6
11
|
export interface AboutEntity extends BaseEntity {
|
|
@@ -14,7 +19,10 @@ export interface AppState extends EntitiesState<AppEntity> {
|
|
|
14
19
|
about: AboutEntity
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
// The events the types below answer, so that `notify` checks them.
|
|
23
|
+
export type AppEvents = EventsOf<AboutType>
|
|
24
|
+
|
|
25
|
+
export type AppApi = Api<AppEntity, AppState, AppEvents>
|
|
18
26
|
|
|
19
27
|
export type AboutType = {
|
|
20
28
|
click: (entity: AboutEntity) => void
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { html } from "@inglorious/web"
|
|
2
2
|
|
|
3
|
-
import type { AppApi } from "
|
|
3
|
+
import type { AppApi } from "../../types"
|
|
4
4
|
|
|
5
5
|
export const App = {
|
|
6
|
-
render(
|
|
6
|
+
render(_props: Record<string, unknown> | null, api: AppApi) {
|
|
7
7
|
return html`<h1>
|
|
8
8
|
${api.render("message1")}, ${api.render("message2")},
|
|
9
9
|
${api.render("message3")}!
|
package/templates/ts/src/main.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { mount } from "@inglorious/web"
|
|
2
2
|
|
|
3
|
+
import type { AppApi } from "../types"
|
|
3
4
|
import { App } from "./app"
|
|
4
5
|
import { store } from "./store"
|
|
5
6
|
|
|
6
|
-
mount(
|
|
7
|
+
mount(
|
|
8
|
+
store,
|
|
9
|
+
(api: AppApi) => App.render(null, api),
|
|
10
|
+
document.getElementById("root")!,
|
|
11
|
+
)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createStore } from "@inglorious/store"
|
|
2
2
|
|
|
3
|
-
import type { AppEntity, AppState } from "../../types"
|
|
4
|
-
import { Message } from "../
|
|
3
|
+
import type { AppEntity, AppEvents, AppState } from "../../types"
|
|
4
|
+
import { Message } from "../app/message"
|
|
5
5
|
import { entities } from "./entities"
|
|
6
6
|
import { middlewares } from "./middlewares"
|
|
7
7
|
|
|
8
|
-
export const store = createStore<AppEntity, AppState>({
|
|
8
|
+
export const store = createStore<AppEntity, AppState, AppEvents>({
|
|
9
9
|
types: { Message },
|
|
10
10
|
entities,
|
|
11
11
|
middlewares,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import "./vite-
|
|
1
|
+
import "./vite-env"
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
BaseEntity,
|
|
5
|
+
EntitiesState,
|
|
6
|
+
EntityType,
|
|
7
|
+
EventsOf,
|
|
8
|
+
} from "@inglorious/store"
|
|
4
9
|
import type { Api, TemplateResult } from "@inglorious/web"
|
|
5
10
|
|
|
6
11
|
export interface MessageEntity extends BaseEntity {
|
|
@@ -17,7 +22,10 @@ export interface AppState extends EntitiesState<AppEntity> {
|
|
|
17
22
|
message3: MessageEntity
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
// The events the types below answer, so that `notify` checks them.
|
|
26
|
+
export type AppEvents = EventsOf<MessageType>
|
|
27
|
+
|
|
28
|
+
export type AppApi = Api<AppEntity, AppState, AppEvents>
|
|
21
29
|
|
|
22
30
|
export type MessageType = {
|
|
23
31
|
click: (entity: MessageEntity) => void
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Message } from "./types/message"
|
|
1
|
+
import { Message } from "./message"
|
|
3
2
|
|
|
4
3
|
export const App = {
|
|
5
|
-
render(
|
|
4
|
+
render() {
|
|
6
5
|
return (
|
|
7
6
|
<h1>
|
|
8
7
|
{/* @ts-expect-error - JSX components are entity type names, not imports */}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createStore } from "@inglorious/store"
|
|
2
2
|
|
|
3
|
-
import type { AppEntity, AppState } from "../../types"
|
|
4
|
-
import { Message } from "../
|
|
3
|
+
import type { AppEntity, AppEvents, AppState } from "../../types"
|
|
4
|
+
import { Message } from "../app/message"
|
|
5
5
|
import { entities } from "./entities"
|
|
6
6
|
import { middlewares } from "./middlewares"
|
|
7
7
|
|
|
8
|
-
export const store = createStore<AppEntity, AppState>({
|
|
8
|
+
export const store = createStore<AppEntity, AppState, AppEvents>({
|
|
9
9
|
types: { Message },
|
|
10
10
|
entities,
|
|
11
11
|
middlewares,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import "./vite-
|
|
1
|
+
import "./vite-env"
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
BaseEntity,
|
|
5
|
+
EntitiesState,
|
|
6
|
+
EntityType,
|
|
7
|
+
EventsOf,
|
|
8
|
+
} from "@inglorious/store"
|
|
4
9
|
import type { Api, TemplateResult } from "@inglorious/web"
|
|
5
10
|
|
|
6
11
|
export interface MessageEntity extends BaseEntity {
|
|
@@ -17,7 +22,10 @@ export interface AppState extends EntitiesState<AppEntity> {
|
|
|
17
22
|
message3: MessageEntity
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
// The events the types below answer, so that `notify` checks them.
|
|
26
|
+
export type AppEvents = EventsOf<MessageType>
|
|
27
|
+
|
|
28
|
+
export type AppApi = Api<AppEntity, AppState, AppEvents>
|
|
21
29
|
|
|
22
30
|
export type MessageType = {
|
|
23
31
|
click: (entity: MessageEntity) => void
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { mount } from "@inglorious/web"
|
|
2
2
|
|
|
3
|
+
import type { AppApi } from "../types"
|
|
3
4
|
// @ts-expect-error - Handled by @inglorious/vite-plugin-vue
|
|
4
|
-
import { App } from "./app.vue"
|
|
5
|
+
import { App } from "./app/index.vue"
|
|
5
6
|
import { store } from "./store"
|
|
6
7
|
|
|
7
|
-
mount(
|
|
8
|
+
mount(
|
|
9
|
+
store,
|
|
10
|
+
(api: AppApi) => App.render(null, api),
|
|
11
|
+
document.getElementById("root")!,
|
|
12
|
+
)
|
|
@@ -2,7 +2,7 @@ import { createStore } from "@inglorious/store"
|
|
|
2
2
|
|
|
3
3
|
import type { AppEntity, AppState } from "../../types"
|
|
4
4
|
// @ts-expect-error - Handled by @inglorious/vite-plugin-vue
|
|
5
|
-
import { Message } from "../
|
|
5
|
+
import { Message } from "../app/message/index.vue"
|
|
6
6
|
import { entities } from "./entities"
|
|
7
7
|
import { middlewares } from "./middlewares"
|
|
8
8
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|