create-eventus-app 0.1.2 → 0.1.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 +1 -1
- package/template/package.json +0 -2
- package/template/src/App.tsx +50 -237
- package/template/src/assets/logo_black_transparent.png +0 -0
- package/template/src/assets/logo_white_transparent.png +0 -0
- package/template/src/styles.css +114 -116
- package/template/src/dev-preview.ts +0 -102
package/package.json
CHANGED
package/template/package.json
CHANGED
|
@@ -10,12 +10,10 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@eventusgo/sdk": "__EVENTUS_SDK_VERSION__",
|
|
13
|
-
"qrcode": "1.5.4",
|
|
14
13
|
"react": "18.3.1",
|
|
15
14
|
"react-dom": "18.3.1"
|
|
16
15
|
},
|
|
17
16
|
"devDependencies": {
|
|
18
|
-
"@types/qrcode": "1.5.5",
|
|
19
17
|
"@eventusgo/vite-plugin": "__EVENTUS_VITE_PLUGIN_VERSION__",
|
|
20
18
|
"@types/react": "18.3.28",
|
|
21
19
|
"@types/react-dom": "18.3.7",
|
package/template/src/App.tsx
CHANGED
|
@@ -1,253 +1,66 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
1
|
import manifest from "virtual:eventus-manifest";
|
|
3
|
-
import QRCode from "qrcode";
|
|
4
2
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "@eventusgo/sdk";
|
|
9
|
-
import {
|
|
10
|
-
fetchDevPreviewDescriptor,
|
|
11
|
-
isBridgeUnavailableError,
|
|
12
|
-
type EventusDevPreviewDescriptor,
|
|
13
|
-
} from "./dev-preview";
|
|
3
|
+
EventusContextProvider,
|
|
4
|
+
useEventusContext,
|
|
5
|
+
} from "@eventusgo/sdk/react";
|
|
14
6
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| { status: "ready"; context: EventusContext }
|
|
18
|
-
| {
|
|
19
|
-
status: "bridge-unavailable";
|
|
20
|
-
preview: EventusDevPreviewDescriptor | null;
|
|
21
|
-
}
|
|
22
|
-
| { status: "error"; message: string };
|
|
7
|
+
import logoDark from "./assets/logo_black_transparent.png";
|
|
8
|
+
import logoLight from "./assets/logo_white_transparent.png";
|
|
23
9
|
|
|
24
10
|
export default function App() {
|
|
25
|
-
const [state, setState] = useState<LoadState>({ status: "loading" });
|
|
26
|
-
const [runtimeSource, setRuntimeSource] = useState<
|
|
27
|
-
EventusRuntimeSource | "bridge-unavailable" | "loading"
|
|
28
|
-
>("loading");
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
let cancelled = false;
|
|
32
|
-
let receivedReadyEvent = false;
|
|
33
|
-
|
|
34
|
-
const unsubscribeReady = eventus.on("ready", ({ context, source }) => {
|
|
35
|
-
receivedReadyEvent = true;
|
|
36
|
-
if (!cancelled) {
|
|
37
|
-
setRuntimeSource(source);
|
|
38
|
-
setState({ status: "ready", context });
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const unsubscribe = eventus.on("themeChange", ({ context }) => {
|
|
43
|
-
if (!cancelled) {
|
|
44
|
-
setState({ status: "ready", context });
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
void (async () => {
|
|
49
|
-
try {
|
|
50
|
-
await eventus.ready();
|
|
51
|
-
const context = await eventus.getContext();
|
|
52
|
-
|
|
53
|
-
if (!cancelled && !receivedReadyEvent) {
|
|
54
|
-
setRuntimeSource(window.Eventus ? "native" : "mock");
|
|
55
|
-
setState({ status: "ready", context });
|
|
56
|
-
}
|
|
57
|
-
} catch (error) {
|
|
58
|
-
if (receivedReadyEvent || cancelled) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (isBridgeUnavailableError(error)) {
|
|
63
|
-
const preview = await fetchDevPreviewDescriptor();
|
|
64
|
-
if (!cancelled && !receivedReadyEvent) {
|
|
65
|
-
setRuntimeSource("bridge-unavailable");
|
|
66
|
-
setState({
|
|
67
|
-
status: "bridge-unavailable",
|
|
68
|
-
preview,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!cancelled) {
|
|
75
|
-
setState({
|
|
76
|
-
status: "error",
|
|
77
|
-
message:
|
|
78
|
-
error instanceof Error
|
|
79
|
-
? error.message
|
|
80
|
-
: "Unable to initialize the Eventus client.",
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
})();
|
|
85
|
-
|
|
86
|
-
return () => {
|
|
87
|
-
cancelled = true;
|
|
88
|
-
unsubscribeReady();
|
|
89
|
-
unsubscribe();
|
|
90
|
-
};
|
|
91
|
-
}, []);
|
|
92
|
-
|
|
93
|
-
const runtimeLabel =
|
|
94
|
-
runtimeSource === "native"
|
|
95
|
-
? "Native bridge detected"
|
|
96
|
-
: runtimeSource === "mock"
|
|
97
|
-
? "Explicit mock mode active"
|
|
98
|
-
: runtimeSource === "bridge-unavailable"
|
|
99
|
-
? "Open this mini app inside Eventus X"
|
|
100
|
-
: "Detecting runtime…";
|
|
101
|
-
|
|
102
11
|
return (
|
|
103
|
-
<
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
<h1>{manifest.name}</h1>
|
|
107
|
-
<p className="subtitle">
|
|
108
|
-
App ID <code>{manifest.appId}</code> · Version <code>{manifest.version}</code>
|
|
109
|
-
</p>
|
|
110
|
-
|
|
111
|
-
<div className="status-banner">{runtimeLabel}</div>
|
|
112
|
-
|
|
113
|
-
{state.status === "loading" ? (
|
|
114
|
-
<p>Connecting to the Eventus client…</p>
|
|
115
|
-
) : null}
|
|
116
|
-
|
|
117
|
-
{state.status === "error" ? (
|
|
118
|
-
<p className="error-text">{state.message}</p>
|
|
119
|
-
) : null}
|
|
120
|
-
|
|
121
|
-
{state.status === "bridge-unavailable" ? (
|
|
122
|
-
<DeveloperHandoff preview={state.preview} />
|
|
123
|
-
) : null}
|
|
124
|
-
|
|
125
|
-
{state.status === "ready" ? (
|
|
126
|
-
<dl className="details-grid">
|
|
127
|
-
<div>
|
|
128
|
-
<dt>Theme</dt>
|
|
129
|
-
<dd>{state.context.theme}</dd>
|
|
130
|
-
</div>
|
|
131
|
-
<div>
|
|
132
|
-
<dt>Locale</dt>
|
|
133
|
-
<dd>{state.context.locale}</dd>
|
|
134
|
-
</div>
|
|
135
|
-
<div>
|
|
136
|
-
<dt>User</dt>
|
|
137
|
-
<dd>{state.context.user?.name ?? state.context.user?.id ?? "Anonymous"}</dd>
|
|
138
|
-
</div>
|
|
139
|
-
<div>
|
|
140
|
-
<dt>Manifest Permissions</dt>
|
|
141
|
-
<dd>{manifest.permissions?.join(", ") ?? "None"}</dd>
|
|
142
|
-
</div>
|
|
143
|
-
</dl>
|
|
144
|
-
) : null}
|
|
145
|
-
|
|
146
|
-
{state.status === "ready" ? (
|
|
147
|
-
<pre className="context-preview">
|
|
148
|
-
{JSON.stringify(state.context, null, 2)}
|
|
149
|
-
</pre>
|
|
150
|
-
) : null}
|
|
151
|
-
</section>
|
|
152
|
-
</main>
|
|
12
|
+
<EventusContextProvider>
|
|
13
|
+
<WelcomeScreen />
|
|
14
|
+
</EventusContextProvider>
|
|
153
15
|
);
|
|
154
16
|
}
|
|
155
17
|
|
|
156
|
-
function
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
This mini app needs the Eventus bridge to access the real runtime.
|
|
167
|
-
Open it from Eventus X to test it with production-like behavior.
|
|
168
|
-
</p>
|
|
169
|
-
</div>
|
|
170
|
-
);
|
|
171
|
-
}
|
|
18
|
+
function WelcomeScreen() {
|
|
19
|
+
const { context, runtimeSource } = useEventusContext();
|
|
20
|
+
const userName =
|
|
21
|
+
context.user?.name ??
|
|
22
|
+
context.user?.displayName ??
|
|
23
|
+
context.user?.id ??
|
|
24
|
+
"there";
|
|
25
|
+
const logo = context.theme === "dark" ? logoLight : logoDark;
|
|
26
|
+
const runtimeLabel =
|
|
27
|
+
runtimeSource === "native" ? "Connected to Eventus X" : "Mock preview";
|
|
172
28
|
|
|
173
29
|
return (
|
|
174
|
-
<
|
|
175
|
-
<
|
|
176
|
-
<
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
30
|
+
<main className="welcome-shell">
|
|
31
|
+
<section className={`welcome-card theme-${context.theme}`}>
|
|
32
|
+
<div className="welcome-glow welcome-glow-primary" />
|
|
33
|
+
<div className="welcome-glow welcome-glow-secondary" />
|
|
34
|
+
|
|
35
|
+
<div className="welcome-brand">
|
|
36
|
+
<img src={logo} alt="Eventus" className="welcome-logo" />
|
|
37
|
+
<span className="welcome-badge">{runtimeLabel}</span>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div className="welcome-copy">
|
|
41
|
+
<p className="welcome-eyebrow">{manifest.name}</p>
|
|
42
|
+
<h1>Welcome back, {userName}</h1>
|
|
43
|
+
<p className="welcome-subtitle">
|
|
44
|
+
Your mini app is ready inside Eventus. Start building a polished
|
|
45
|
+
experience for real users with the live bridge, theme, and locale.
|
|
46
|
+
</p>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div className="welcome-chips">
|
|
50
|
+
<div className="welcome-chip">
|
|
51
|
+
<span>Theme</span>
|
|
52
|
+
<strong>{context.theme}</strong>
|
|
187
53
|
</div>
|
|
188
|
-
<div>
|
|
189
|
-
<
|
|
190
|
-
<
|
|
191
|
-
<code>{preview.urls.local}</code>
|
|
192
|
-
</dd>
|
|
54
|
+
<div className="welcome-chip">
|
|
55
|
+
<span>Locale</span>
|
|
56
|
+
<strong>{context.locale}</strong>
|
|
193
57
|
</div>
|
|
194
|
-
|
|
195
|
-
<
|
|
196
|
-
|
|
197
|
-
<dd>
|
|
198
|
-
<code>{preview.urls.network}</code>
|
|
199
|
-
</dd>
|
|
200
|
-
</div>
|
|
201
|
-
) : null}
|
|
202
|
-
<div>
|
|
203
|
-
<dt>Permissions</dt>
|
|
204
|
-
<dd>{preview.manifest.permissions?.join(", ") ?? "None"}</dd>
|
|
58
|
+
<div className="welcome-chip">
|
|
59
|
+
<span>App ID</span>
|
|
60
|
+
<strong>{manifest.appId}</strong>
|
|
205
61
|
</div>
|
|
206
|
-
</
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
</p>
|
|
210
|
-
</div>
|
|
211
|
-
<QrPanel payload={preview} />
|
|
212
|
-
</div>
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function QrPanel({
|
|
217
|
-
payload,
|
|
218
|
-
}: {
|
|
219
|
-
payload: EventusDevPreviewDescriptor;
|
|
220
|
-
}) {
|
|
221
|
-
const [svg, setSvg] = useState("");
|
|
222
|
-
|
|
223
|
-
useEffect(() => {
|
|
224
|
-
let cancelled = false;
|
|
225
|
-
|
|
226
|
-
void (async () => {
|
|
227
|
-
const nextSvg = await QRCode.toString(JSON.stringify(payload), {
|
|
228
|
-
type: "svg",
|
|
229
|
-
width: 220,
|
|
230
|
-
margin: 1,
|
|
231
|
-
});
|
|
232
|
-
if (!cancelled) {
|
|
233
|
-
setSvg(nextSvg);
|
|
234
|
-
}
|
|
235
|
-
})();
|
|
236
|
-
|
|
237
|
-
return () => {
|
|
238
|
-
cancelled = true;
|
|
239
|
-
};
|
|
240
|
-
}, [payload]);
|
|
241
|
-
|
|
242
|
-
return (
|
|
243
|
-
<div className="qr-panel">
|
|
244
|
-
<div
|
|
245
|
-
className="qr-code"
|
|
246
|
-
aria-label="Eventus live preview QR code"
|
|
247
|
-
dangerouslySetInnerHTML={{
|
|
248
|
-
__html: svg || "<div class='qr-placeholder'>Generating QR…</div>",
|
|
249
|
-
}}
|
|
250
|
-
/>
|
|
251
|
-
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</section>
|
|
64
|
+
</main>
|
|
252
65
|
);
|
|
253
66
|
}
|
|
Binary file
|
|
Binary file
|
package/template/src/styles.css
CHANGED
|
@@ -2,7 +2,17 @@
|
|
|
2
2
|
font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
|
|
3
3
|
color: #102347;
|
|
4
4
|
background:
|
|
5
|
-
radial-gradient(
|
|
5
|
+
radial-gradient(
|
|
6
|
+
circle at top left,
|
|
7
|
+
rgba(97, 180, 255, 0.28),
|
|
8
|
+
transparent 34%
|
|
9
|
+
),
|
|
10
|
+
radial-gradient(
|
|
11
|
+
circle at 82% 18%,
|
|
12
|
+
rgba(58, 115, 255, 0.16),
|
|
13
|
+
transparent 26%
|
|
14
|
+
),
|
|
15
|
+
linear-gradient(180deg, #e9f5ff 0%, #eef3ff 44%, #f8fbff 100%);
|
|
6
16
|
line-height: 1.5;
|
|
7
17
|
font-weight: 400;
|
|
8
18
|
}
|
|
@@ -22,174 +32,162 @@ pre {
|
|
|
22
32
|
font-family: "IBM Plex Mono", "SFMono-Regular", monospace;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
.
|
|
35
|
+
.welcome-shell {
|
|
26
36
|
min-height: 100vh;
|
|
27
37
|
display: grid;
|
|
28
38
|
place-items: center;
|
|
29
39
|
padding: 24px;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
.card {
|
|
33
|
-
|
|
42
|
+
.welcome-card {
|
|
43
|
+
position: relative;
|
|
44
|
+
isolation: isolate;
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
width: min(760px, 100%);
|
|
34
47
|
padding: 32px;
|
|
35
|
-
border-radius:
|
|
36
|
-
background: rgba(255, 255, 255, 0.84);
|
|
48
|
+
border-radius: 32px;
|
|
37
49
|
border: 1px solid rgba(16, 35, 71, 0.08);
|
|
38
|
-
box-shadow: 0 24px 80px rgba(38, 73, 134, 0.
|
|
39
|
-
backdrop-filter: blur(
|
|
50
|
+
box-shadow: 0 24px 80px rgba(38, 73, 134, 0.16);
|
|
51
|
+
backdrop-filter: blur(18px);
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
letter-spacing: 0.12em;
|
|
46
|
-
text-transform: uppercase;
|
|
47
|
-
color: #3f6ea8;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
h1 {
|
|
51
|
-
margin: 0;
|
|
52
|
-
font-size: clamp(2rem, 4vw, 3rem);
|
|
54
|
+
.theme-light {
|
|
55
|
+
background: rgba(255, 255, 255, 0.86);
|
|
56
|
+
color: #102347;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
color: #
|
|
59
|
+
.theme-dark {
|
|
60
|
+
background: rgba(10, 24, 54, 0.9);
|
|
61
|
+
color: #f2f6ff;
|
|
62
|
+
border-color: rgba(182, 211, 255, 0.12);
|
|
63
|
+
box-shadow: 0 28px 96px rgba(6, 14, 30, 0.42);
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
display: inline-flex;
|
|
63
|
-
padding: 8px 12px;
|
|
66
|
+
.welcome-glow {
|
|
67
|
+
position: absolute;
|
|
64
68
|
border-radius: 999px;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
filter: blur(12px);
|
|
70
|
+
opacity: 0.85;
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
z-index: -1;
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
.welcome-glow-primary {
|
|
76
|
+
top: -80px;
|
|
77
|
+
right: -40px;
|
|
78
|
+
width: 220px;
|
|
79
|
+
height: 220px;
|
|
80
|
+
background: rgba(84, 169, 255, 0.24);
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
margin: 0;
|
|
83
|
-
color: #465d82;
|
|
83
|
+
.welcome-glow-secondary {
|
|
84
|
+
bottom: -90px;
|
|
85
|
+
left: -80px;
|
|
86
|
+
width: 260px;
|
|
87
|
+
height: 260px;
|
|
88
|
+
background: rgba(0, 229, 214, 0.16);
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.preview-grid div {
|
|
93
|
-
padding: 14px 16px;
|
|
94
|
-
border-radius: 16px;
|
|
95
|
-
background: #f8fbff;
|
|
96
|
-
border: 1px solid rgba(16, 35, 71, 0.08);
|
|
91
|
+
.welcome-brand {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: space-between;
|
|
95
|
+
gap: 16px;
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
.
|
|
100
|
-
|
|
98
|
+
.welcome-logo {
|
|
99
|
+
height: 34px;
|
|
100
|
+
width: auto;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
.
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
.welcome-badge {
|
|
104
|
+
display: inline-flex;
|
|
105
|
+
align-items: center;
|
|
106
|
+
gap: 8px;
|
|
107
|
+
padding: 10px 14px;
|
|
108
|
+
border-radius: 999px;
|
|
109
|
+
font-size: 0.82rem;
|
|
110
|
+
font-weight: 700;
|
|
111
|
+
letter-spacing: 0.04em;
|
|
112
|
+
text-transform: uppercase;
|
|
113
|
+
background: rgba(82, 137, 255, 0.12);
|
|
114
|
+
color: inherit;
|
|
106
115
|
}
|
|
107
116
|
|
|
108
|
-
.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
padding: 20px;
|
|
112
|
-
border-radius: 24px;
|
|
113
|
-
background: linear-gradient(180deg, #fefefe 0%, #f3f7ff 100%);
|
|
114
|
-
border: 1px solid rgba(16, 35, 71, 0.08);
|
|
117
|
+
.welcome-copy {
|
|
118
|
+
margin-top: 32px;
|
|
119
|
+
max-width: 560px;
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
.welcome-eyebrow {
|
|
123
|
+
margin: 0 0 10px;
|
|
124
|
+
font-size: 0.82rem;
|
|
125
|
+
letter-spacing: 0.16em;
|
|
126
|
+
text-transform: uppercase;
|
|
127
|
+
color: inherit;
|
|
128
|
+
opacity: 0.7;
|
|
122
129
|
}
|
|
123
130
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
h1 {
|
|
132
|
+
margin: 0;
|
|
133
|
+
font-size: clamp(2.4rem, 5vw, 4.4rem);
|
|
134
|
+
line-height: 0.96;
|
|
135
|
+
letter-spacing: -0.04em;
|
|
127
136
|
}
|
|
128
137
|
|
|
129
|
-
.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
border-radius: 20px;
|
|
135
|
-
background: #eef6ff;
|
|
136
|
-
color: #22548d;
|
|
137
|
-
font-weight: 600;
|
|
138
|
+
.welcome-subtitle {
|
|
139
|
+
margin: 18px 0 0;
|
|
140
|
+
font-size: 1.05rem;
|
|
141
|
+
line-height: 1.75;
|
|
142
|
+
opacity: 0.82;
|
|
138
143
|
}
|
|
139
144
|
|
|
140
|
-
.
|
|
145
|
+
.welcome-chips {
|
|
141
146
|
display: grid;
|
|
142
147
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
143
148
|
gap: 16px;
|
|
144
|
-
margin:
|
|
149
|
+
margin-top: 28px;
|
|
145
150
|
}
|
|
146
151
|
|
|
147
|
-
.
|
|
148
|
-
padding: 16px;
|
|
149
|
-
border-radius:
|
|
150
|
-
background: #f8fbff;
|
|
152
|
+
.welcome-chip {
|
|
153
|
+
padding: 16px 18px;
|
|
154
|
+
border-radius: 20px;
|
|
151
155
|
border: 1px solid rgba(16, 35, 71, 0.08);
|
|
156
|
+
background: rgba(255, 255, 255, 0.36);
|
|
157
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
|
|
152
158
|
}
|
|
153
159
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
text-transform: uppercase;
|
|
159
|
-
letter-spacing: 0.06em;
|
|
160
|
+
.theme-dark .welcome-chip {
|
|
161
|
+
background: rgba(255, 255, 255, 0.06);
|
|
162
|
+
border-color: rgba(182, 211, 255, 0.12);
|
|
163
|
+
box-shadow: none;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
padding: 16px;
|
|
170
|
-
border-radius: 16px;
|
|
171
|
-
overflow: auto;
|
|
172
|
-
background: #0d1d3a;
|
|
173
|
-
color: #eef5ff;
|
|
166
|
+
.welcome-chip span {
|
|
167
|
+
display: block;
|
|
168
|
+
margin-bottom: 8px;
|
|
169
|
+
font-size: 0.8rem;
|
|
170
|
+
text-transform: uppercase;
|
|
171
|
+
letter-spacing: 0.06em;
|
|
172
|
+
opacity: 0.65;
|
|
174
173
|
}
|
|
175
174
|
|
|
176
|
-
.
|
|
177
|
-
|
|
175
|
+
.welcome-chip strong {
|
|
176
|
+
font-size: 1rem;
|
|
177
|
+
font-weight: 700;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
@media (max-width: 640px) {
|
|
181
|
-
.
|
|
182
|
-
padding:
|
|
181
|
+
.welcome-shell {
|
|
182
|
+
padding: 18px;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
.
|
|
186
|
-
|
|
185
|
+
.welcome-card {
|
|
186
|
+
padding: 24px;
|
|
187
187
|
}
|
|
188
|
-
}
|
|
189
188
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
align-items: start;
|
|
189
|
+
.welcome-brand {
|
|
190
|
+
align-items: flex-start;
|
|
191
|
+
flex-direction: column;
|
|
194
192
|
}
|
|
195
193
|
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
export type EventusDevPreviewDescriptor = {
|
|
2
|
-
type: "eventus-dev-preview";
|
|
3
|
-
version: 1;
|
|
4
|
-
manifest: {
|
|
5
|
-
name: string;
|
|
6
|
-
appId: string;
|
|
7
|
-
version: string;
|
|
8
|
-
permissions?: string[];
|
|
9
|
-
};
|
|
10
|
-
urls: {
|
|
11
|
-
local: string;
|
|
12
|
-
network: string | null;
|
|
13
|
-
preview: string;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export function isBridgeUnavailableError(error: unknown): boolean {
|
|
18
|
-
return (
|
|
19
|
-
error instanceof Error && error.name === "EventusBridgeUnavailableError"
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function fetchDevPreviewDescriptor(): Promise<EventusDevPreviewDescriptor | null> {
|
|
24
|
-
if (typeof fetch !== "function") {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
const response = await fetch("/__eventus__/preview.json", {
|
|
30
|
-
headers: {
|
|
31
|
-
Accept: "application/json",
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
if (!response.ok) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const json = (await response.json()) as unknown;
|
|
39
|
-
return parseDevPreviewDescriptor(json);
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function parseDevPreviewDescriptor(
|
|
46
|
-
value: unknown,
|
|
47
|
-
): EventusDevPreviewDescriptor | null {
|
|
48
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const descriptor = value as Record<string, unknown>;
|
|
53
|
-
const manifest = descriptor.manifest;
|
|
54
|
-
const urls = descriptor.urls;
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
descriptor.type !== "eventus-dev-preview" ||
|
|
58
|
-
descriptor.version !== 1 ||
|
|
59
|
-
!manifest ||
|
|
60
|
-
typeof manifest !== "object" ||
|
|
61
|
-
Array.isArray(manifest) ||
|
|
62
|
-
!urls ||
|
|
63
|
-
typeof urls !== "object" ||
|
|
64
|
-
Array.isArray(urls)
|
|
65
|
-
) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const nextManifest = manifest as Record<string, unknown>;
|
|
70
|
-
const nextUrls = urls as Record<string, unknown>;
|
|
71
|
-
const permissions = nextManifest.permissions;
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
typeof nextManifest.name !== "string" ||
|
|
75
|
-
typeof nextManifest.appId !== "string" ||
|
|
76
|
-
typeof nextManifest.version !== "string" ||
|
|
77
|
-
typeof nextUrls.local !== "string" ||
|
|
78
|
-
(nextUrls.network !== null && typeof nextUrls.network !== "string") ||
|
|
79
|
-
typeof nextUrls.preview !== "string" ||
|
|
80
|
-
(permissions !== undefined &&
|
|
81
|
-
(!Array.isArray(permissions) ||
|
|
82
|
-
permissions.some((permission) => typeof permission !== "string")))
|
|
83
|
-
) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
type: "eventus-dev-preview",
|
|
89
|
-
version: 1,
|
|
90
|
-
manifest: {
|
|
91
|
-
name: nextManifest.name,
|
|
92
|
-
appId: nextManifest.appId,
|
|
93
|
-
version: nextManifest.version,
|
|
94
|
-
...(permissions ? { permissions: permissions as string[] } : {}),
|
|
95
|
-
},
|
|
96
|
-
urls: {
|
|
97
|
-
local: nextUrls.local,
|
|
98
|
-
network: nextUrls.network as string | null,
|
|
99
|
-
preview: nextUrls.preview,
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|