create-flowdular 0.2.2 → 0.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-flowdular",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Scaffold a Flowdular application: the platform, one example module and the secrets a fresh install needs.",
6
6
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  "dependencies": {
17
17
  "octane": "0.1.51",
18
18
  "segment-state": "0.2.0",
19
- "@flowdular/sdk": "0.2.2"
19
+ "@flowdular/sdk": "0.2.3"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@tsrx/typescript-plugin": "0.3.120",
@@ -195,30 +195,34 @@ export function NotesView(props: NotesViewProps) @{
195
195
  onSubmit={submit}
196
196
  >
197
197
  <div class="ui-drawer__body">
198
- @if (error) {
199
- <Alert>{error}</Alert>
200
- }
201
- <FormField label={t('example.field.title')}>
202
- <input
203
- class="ui-input"
204
- id="title"
205
- name="title"
198
+ <div class="ui-form">
199
+ @if (error) {
200
+ <Alert>{error}</Alert>
201
+ }
202
+ <FormField label={t('example.field.title')} required>
203
+ <input
204
+ class="ui-input"
205
+ id="title"
206
+ name="title"
207
+ required
208
+ maxLength={120}
209
+ />
210
+ </FormField>
211
+ <FormField
212
+ label={t('example.field.body')}
206
213
  required
207
- maxLength={120}
208
- />
209
- </FormField>
210
- <FormField
211
- label={t('example.field.body')}
212
- help={t('example.field.body.help')}
213
- >
214
- <textarea
215
- class="ui-textarea"
216
- id="body"
217
- required
218
- rows={6}
219
- maxLength={4000}
220
- ></textarea>
221
- </FormField>
214
+ help={t('example.field.body.help')}
215
+ >
216
+ <textarea
217
+ class="ui-textarea"
218
+ id="body"
219
+ name="body"
220
+ required
221
+ rows={6}
222
+ maxLength={4000}
223
+ ></textarea>
224
+ </FormField>
225
+ </div>
222
226
  </div>
223
227
  <div class="ui-drawer__foot">
224
228
  <Button type="button" onClick={closeForm}>{t(
@@ -21,6 +21,6 @@
21
21
  "devDependencies": {
22
22
  "@tsrx/prettier-plugin": "0.3.120",
23
23
  "prettier": "3.6.2",
24
- "flowdular": "0.2.2"
24
+ "flowdular": "0.2.3"
25
25
  }
26
26
  }
@@ -1,13 +1,168 @@
1
1
  <!doctype html>
2
- <html lang="en">
2
+ <html lang="en" class="flowdular-booting">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="theme-color" content="#141B2E" />
7
7
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
+ <style id="flowdular-critical-splash">
9
+ html,
10
+ body,
11
+ #root {
12
+ min-height: 100%;
13
+ margin: 0;
14
+ background: #0c1222;
15
+ }
16
+ .flowdular-splash {
17
+ position: fixed;
18
+ inset: 0;
19
+ z-index: 2147483647;
20
+ display: grid;
21
+ place-items: center;
22
+ background: #0c1222;
23
+ color: #f4f6fa;
24
+ transition: opacity 180ms ease;
25
+ }
26
+ .flowdular-splash__content {
27
+ display: grid;
28
+ justify-items: center;
29
+ gap: 16px;
30
+ font:
31
+ 600 13px/1.2 ui-sans-serif,
32
+ system-ui,
33
+ sans-serif;
34
+ letter-spacing: 0.14em;
35
+ text-transform: uppercase;
36
+ }
37
+ .flowdular-splash__stage {
38
+ min-width: 190px;
39
+ font-size: 10px;
40
+ font-weight: 500;
41
+ color: #8794ab;
42
+ letter-spacing: 0.08em;
43
+ text-align: center;
44
+ text-transform: none;
45
+ }
46
+ .flowdular-splash__mark {
47
+ display: block;
48
+ width: 44px;
49
+ height: 44px;
50
+ animation: flowdular-pulse 1.4s ease-in-out infinite alternate;
51
+ }
52
+ .flowdular-splash--leaving {
53
+ opacity: 0;
54
+ pointer-events: none;
55
+ }
56
+ @keyframes flowdular-pulse {
57
+ to {
58
+ opacity: 0.45;
59
+ }
60
+ }
61
+ @media (prefers-reduced-motion: reduce) {
62
+ .flowdular-splash__mark {
63
+ animation: none;
64
+ }
65
+ }
66
+ </style>
8
67
  <!--ssr-head-->
9
68
  </head>
10
- <body>
69
+ <body aria-busy="true">
70
+ <div
71
+ id="flowdular-splash"
72
+ class="flowdular-splash"
73
+ role="status"
74
+ aria-live="polite"
75
+ >
76
+ <div class="flowdular-splash__content">
77
+ <svg
78
+ class="flowdular-splash__mark"
79
+ viewBox="0 0 24 24"
80
+ aria-hidden="true"
81
+ >
82
+ <g fill="#ffffff">
83
+ <circle cx="7.9" cy="3.4" r="1.7" />
84
+ <rect x="6.2" y="3.4" width="3.4" height="1.6" />
85
+ <rect x="6.2" y="10.8" width="3.4" height="9.8" />
86
+ <circle cx="7.9" cy="20.6" r="1.7" />
87
+ <circle cx="16.1" cy="3.4" r="1.7" />
88
+ <rect x="14.4" y="3.4" width="3.4" height="9.8" />
89
+ <rect x="14.4" y="19" width="3.4" height="1.6" />
90
+ <circle cx="16.1" cy="20.6" r="1.7" />
91
+ </g>
92
+ <g fill="#e08a45">
93
+ <circle cx="3.4" cy="7.9" r="1.7" />
94
+ <rect x="3.4" y="6.2" width="9.8" height="3.4" />
95
+ <rect x="19" y="6.2" width="1.6" height="3.4" />
96
+ <circle cx="20.6" cy="7.9" r="1.7" />
97
+ <circle cx="3.4" cy="16.1" r="1.7" />
98
+ <rect x="3.4" y="14.4" width="1.6" height="3.4" />
99
+ <rect x="10.8" y="14.4" width="9.8" height="3.4" />
100
+ <circle cx="20.6" cy="16.1" r="1.7" />
101
+ </g>
102
+ </svg>
103
+ <span>Flowdular</span>
104
+ <small id="flowdular-splash-stage" class="flowdular-splash__stage"
105
+ >Starting workspace</small
106
+ >
107
+ </div>
108
+ </div>
11
109
  <div id="root"><!--ssr-body--></div>
110
+ <script nonce="__FLOWDULAR_CSP_NONCE__">
111
+ (() => {
112
+ if (document.getElementById('flowdular-web-data')) {
113
+ document.getElementById('flowdular-splash')?.remove();
114
+ document.documentElement.classList.remove('flowdular-booting');
115
+ document.body.removeAttribute('aria-busy');
116
+ return;
117
+ }
118
+ const startedAt = performance.now();
119
+ const stages = [
120
+ 'Securing session',
121
+ 'Selecting workspace',
122
+ 'Loading modules',
123
+ 'Preparing workspace',
124
+ ];
125
+ let stageIndex = 0;
126
+ let ready = false;
127
+ let stageTimer;
128
+ const stage = document.getElementById('flowdular-splash-stage');
129
+ const advance = () => {
130
+ if (!stage || ready) return;
131
+ stage.textContent = stages[Math.min(stageIndex, stages.length - 1)];
132
+ stageIndex += 1;
133
+ };
134
+ const finish = () => {
135
+ if (ready) return;
136
+ ready = true;
137
+ clearInterval(stageTimer);
138
+ const splash = document.getElementById('flowdular-splash');
139
+ if (!splash) return;
140
+ const leave = () => {
141
+ splash.classList.add('flowdular-splash--leaving');
142
+ document.documentElement.classList.remove('flowdular-booting');
143
+ document.body.setAttribute('aria-busy', 'false');
144
+ setTimeout(() => splash.remove(), 200);
145
+ };
146
+ const remaining = Math.max(0, 850 - (performance.now() - startedAt));
147
+ setTimeout(leave, remaining);
148
+ };
149
+ window.addEventListener('DOMContentLoaded', () => {
150
+ advance();
151
+ stageTimer = setInterval(advance, 320);
152
+ /* The server-rendered page is already visible underneath; hydration
153
+ in development can take seconds, so the splash never blocks longer
154
+ than this. */
155
+ setTimeout(finish, 2500);
156
+ });
157
+ window.addEventListener('flowdular:ready', finish, { once: true });
158
+ })();
159
+ </script>
160
+ <noscript
161
+ ><style>
162
+ .flowdular-splash {
163
+ display: none;
164
+ }
165
+ </style></noscript
166
+ >
12
167
  </body>
13
168
  </html>
@@ -14,7 +14,7 @@
14
14
  "@octanejs/vite-plugin": "0.1.51",
15
15
  "octane": "0.1.51",
16
16
  "pg": "8.23.0",
17
- "@flowdular/sdk": "0.2.2"
17
+ "@flowdular/sdk": "0.2.3"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@octanejs/app-core": "0.0.47",
@@ -1,18 +1,51 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import { createServer } from 'vite';
4
+ import {
5
+ createOctaneLogger,
6
+ installOctaneConsoleBridge,
7
+ shouldUseColor,
8
+ createTheme,
9
+ printReady,
10
+ } from '@flowdular/sdk/dev-console';
4
11
 
5
12
  const appRoot = resolve(fileURLToPath(new URL('..', import.meta.url)));
13
+ const verbose =
14
+ process.argv.includes('--verbose') ||
15
+ process.argv.includes('-v') ||
16
+ process.env.FD_DEV_VERBOSE === 'true';
17
+ const color = shouldUseColor();
18
+ const restoreConsole = installOctaneConsoleBridge(verbose, color);
6
19
 
7
- const server = await createServer({
8
- root: appRoot,
9
- configFile: resolve(appRoot, 'vite.config.ts'),
20
+ let server;
21
+ try {
22
+ server = await createServer({
23
+ root: appRoot,
24
+ configFile: resolve(appRoot, 'vite.config.ts'),
25
+ customLogger: createOctaneLogger(verbose, color),
26
+ clearScreen: false,
27
+ });
28
+ await server.listen();
29
+ } catch (error) {
30
+ restoreConsole();
31
+ throw error;
32
+ }
33
+ printReady({
34
+ title: 'FLOWDULAR',
35
+ subtitle: 'development workspace',
36
+ theme: createTheme(color),
37
+ lines: [
38
+ [
39
+ 'local',
40
+ server.resolvedUrls?.local?.[0] ?? 'http://localhost:4310/',
41
+ 'info',
42
+ ],
43
+ ['diagnostics', verbose ? 'verbose' : 'quiet · use --verbose', 'muted'],
44
+ ],
10
45
  });
11
- await server.listen();
12
- server.printUrls();
13
46
 
14
47
  /* Closing without exiting lets octane.config.ts release the database on the
15
48
  same signal; the process ends once both have drained. */
16
- const stop = () => void server.close();
49
+ const stop = () => void server.close().finally(restoreConsole);
17
50
  process.once('SIGINT', stop);
18
51
  process.once('SIGTERM', stop);