create-eventus-app 0.1.3 → 0.1.5
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
package/template/src/App.tsx
CHANGED
|
@@ -1,169 +1,65 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
1
|
import manifest from "virtual:eventus-manifest";
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
type EventusContext,
|
|
8
|
-
type EventusRuntimeSource,
|
|
9
|
-
} from "@eventusgo/sdk";
|
|
3
|
+
EventusContextProvider,
|
|
4
|
+
useEventusContext,
|
|
5
|
+
} from "@eventusgo/sdk/react";
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
| { status: "ready"; context: EventusContext }
|
|
14
|
-
| {
|
|
15
|
-
status: "bridge-unavailable";
|
|
16
|
-
previewHtml: string | null;
|
|
17
|
-
}
|
|
18
|
-
| { status: "error"; message: string };
|
|
7
|
+
import logoDark from "./assets/logo_black_transparent.png";
|
|
8
|
+
import logoLight from "./assets/logo_white_transparent.png";
|
|
19
9
|
|
|
20
10
|
export default function App() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let cancelled = false;
|
|
28
|
-
let receivedReadyEvent = false;
|
|
29
|
-
|
|
30
|
-
const unsubscribeReady = eventus.on("ready", ({ context, source }) => {
|
|
31
|
-
receivedReadyEvent = true;
|
|
32
|
-
if (!cancelled) {
|
|
33
|
-
setRuntimeSource(source);
|
|
34
|
-
setState({ status: "ready", context });
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const unsubscribe = eventus.on("themeChange", ({ context }) => {
|
|
39
|
-
if (!cancelled) {
|
|
40
|
-
setState({ status: "ready", context });
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
void (async () => {
|
|
45
|
-
try {
|
|
46
|
-
await eventus.ready();
|
|
47
|
-
const context = await eventus.getContext();
|
|
48
|
-
|
|
49
|
-
if (!cancelled && !receivedReadyEvent) {
|
|
50
|
-
setRuntimeSource(window.Eventus ? "native" : "mock");
|
|
51
|
-
setState({ status: "ready", context });
|
|
52
|
-
}
|
|
53
|
-
} catch (error) {
|
|
54
|
-
if (receivedReadyEvent || cancelled) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (isBridgeUnavailableError(error)) {
|
|
59
|
-
const previewHtml = await getLivePreviewHtml();
|
|
60
|
-
if (!cancelled && !receivedReadyEvent) {
|
|
61
|
-
setRuntimeSource("bridge-unavailable");
|
|
62
|
-
setState({
|
|
63
|
-
status: "bridge-unavailable",
|
|
64
|
-
previewHtml,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!cancelled) {
|
|
71
|
-
setState({
|
|
72
|
-
status: "error",
|
|
73
|
-
message:
|
|
74
|
-
error instanceof Error
|
|
75
|
-
? error.message
|
|
76
|
-
: "Unable to initialize the Eventus client.",
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
})();
|
|
81
|
-
|
|
82
|
-
return () => {
|
|
83
|
-
cancelled = true;
|
|
84
|
-
unsubscribeReady();
|
|
85
|
-
unsubscribe();
|
|
86
|
-
};
|
|
87
|
-
}, []);
|
|
11
|
+
return (
|
|
12
|
+
<EventusContextProvider>
|
|
13
|
+
<WelcomeScreen />
|
|
14
|
+
</EventusContextProvider>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
88
17
|
|
|
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;
|
|
89
26
|
const runtimeLabel =
|
|
90
|
-
runtimeSource === "native"
|
|
91
|
-
? "Native bridge detected"
|
|
92
|
-
: runtimeSource === "mock"
|
|
93
|
-
? "Explicit mock mode active"
|
|
94
|
-
: runtimeSource === "bridge-unavailable"
|
|
95
|
-
? "Open this mini app inside Eventus X"
|
|
96
|
-
: "Detecting runtime…";
|
|
27
|
+
runtimeSource === "native" ? "Connected to Eventus X" : "Mock preview";
|
|
97
28
|
|
|
98
29
|
return (
|
|
99
|
-
<main className="
|
|
100
|
-
<section className=
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
</p>
|
|
133
|
-
</div>
|
|
134
|
-
)
|
|
135
|
-
) : null}
|
|
136
|
-
|
|
137
|
-
{state.status === "ready" ? (
|
|
138
|
-
<dl className="details-grid">
|
|
139
|
-
<div>
|
|
140
|
-
<dt>Theme</dt>
|
|
141
|
-
<dd>{state.context.theme}</dd>
|
|
142
|
-
</div>
|
|
143
|
-
<div>
|
|
144
|
-
<dt>Locale</dt>
|
|
145
|
-
<dd>{state.context.locale}</dd>
|
|
146
|
-
</div>
|
|
147
|
-
<div>
|
|
148
|
-
<dt>User</dt>
|
|
149
|
-
<dd>
|
|
150
|
-
{state.context.user?.name ??
|
|
151
|
-
state.context.user?.id ??
|
|
152
|
-
"Anonymous"}
|
|
153
|
-
</dd>
|
|
154
|
-
</div>
|
|
155
|
-
<div>
|
|
156
|
-
<dt>Manifest Permissions</dt>
|
|
157
|
-
<dd>{manifest.permissions?.join(", ") ?? "None"}</dd>
|
|
158
|
-
</div>
|
|
159
|
-
</dl>
|
|
160
|
-
) : null}
|
|
161
|
-
|
|
162
|
-
{state.status === "ready" ? (
|
|
163
|
-
<pre className="context-preview">
|
|
164
|
-
{JSON.stringify(state.context, null, 2)}
|
|
165
|
-
</pre>
|
|
166
|
-
) : null}
|
|
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>
|
|
53
|
+
</div>
|
|
54
|
+
<div className="welcome-chip">
|
|
55
|
+
<span>Locale</span>
|
|
56
|
+
<strong>{context.locale}</strong>
|
|
57
|
+
</div>
|
|
58
|
+
<div className="welcome-chip">
|
|
59
|
+
<span>App ID</span>
|
|
60
|
+
<strong>{manifest.appId}</strong>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
167
63
|
</section>
|
|
168
64
|
</main>
|
|
169
65
|
);
|
|
Binary file
|
|
Binary file
|
package/template/src/styles.css
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
|
|
3
3
|
color: #102347;
|
|
4
|
-
background:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
background:
|
|
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%);
|
|
10
16
|
line-height: 1.5;
|
|
11
17
|
font-weight: 400;
|
|
12
18
|
}
|
|
@@ -26,103 +32,162 @@ pre {
|
|
|
26
32
|
font-family: "IBM Plex Mono", "SFMono-Regular", monospace;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
.
|
|
35
|
+
.welcome-shell {
|
|
30
36
|
min-height: 100vh;
|
|
31
37
|
display: grid;
|
|
32
38
|
place-items: center;
|
|
33
39
|
padding: 24px;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
.card {
|
|
37
|
-
|
|
42
|
+
.welcome-card {
|
|
43
|
+
position: relative;
|
|
44
|
+
isolation: isolate;
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
width: min(760px, 100%);
|
|
38
47
|
padding: 32px;
|
|
39
|
-
border-radius:
|
|
40
|
-
background: rgba(255, 255, 255, 0.84);
|
|
48
|
+
border-radius: 32px;
|
|
41
49
|
border: 1px solid rgba(16, 35, 71, 0.08);
|
|
42
|
-
box-shadow: 0 24px 80px rgba(38, 73, 134, 0.
|
|
43
|
-
backdrop-filter: blur(
|
|
50
|
+
box-shadow: 0 24px 80px rgba(38, 73, 134, 0.16);
|
|
51
|
+
backdrop-filter: blur(18px);
|
|
44
52
|
}
|
|
45
53
|
|
|
46
|
-
.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
letter-spacing: 0.12em;
|
|
50
|
-
text-transform: uppercase;
|
|
51
|
-
color: #3f6ea8;
|
|
54
|
+
.theme-light {
|
|
55
|
+
background: rgba(255, 255, 255, 0.86);
|
|
56
|
+
color: #102347;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.welcome-glow {
|
|
67
|
+
position: absolute;
|
|
68
|
+
border-radius: 999px;
|
|
69
|
+
filter: blur(12px);
|
|
70
|
+
opacity: 0.85;
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
z-index: -1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.welcome-glow-primary {
|
|
76
|
+
top: -80px;
|
|
77
|
+
right: -40px;
|
|
78
|
+
width: 220px;
|
|
79
|
+
height: 220px;
|
|
80
|
+
background: rgba(84, 169, 255, 0.24);
|
|
57
81
|
}
|
|
58
82
|
|
|
59
|
-
.
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
.welcome-glow-secondary {
|
|
84
|
+
bottom: -90px;
|
|
85
|
+
left: -80px;
|
|
86
|
+
width: 260px;
|
|
87
|
+
height: 260px;
|
|
88
|
+
background: rgba(0, 229, 214, 0.16);
|
|
62
89
|
}
|
|
63
90
|
|
|
64
|
-
.
|
|
65
|
-
|
|
91
|
+
.welcome-brand {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: space-between;
|
|
95
|
+
gap: 16px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.welcome-logo {
|
|
99
|
+
height: 34px;
|
|
100
|
+
width: auto;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.welcome-badge {
|
|
66
104
|
display: inline-flex;
|
|
67
|
-
|
|
105
|
+
align-items: center;
|
|
106
|
+
gap: 8px;
|
|
107
|
+
padding: 10px 14px;
|
|
68
108
|
border-radius: 999px;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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;
|
|
72
115
|
}
|
|
73
116
|
|
|
74
|
-
.
|
|
75
|
-
margin:
|
|
76
|
-
|
|
77
|
-
gap: 20px;
|
|
117
|
+
.welcome-copy {
|
|
118
|
+
margin-top: 32px;
|
|
119
|
+
max-width: 560px;
|
|
78
120
|
}
|
|
79
121
|
|
|
80
|
-
.
|
|
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;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
h1 {
|
|
132
|
+
margin: 0;
|
|
133
|
+
font-size: clamp(2.4rem, 5vw, 4.4rem);
|
|
134
|
+
line-height: 0.96;
|
|
135
|
+
letter-spacing: -0.04em;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.welcome-subtitle {
|
|
139
|
+
margin: 18px 0 0;
|
|
140
|
+
font-size: 1.05rem;
|
|
141
|
+
line-height: 1.75;
|
|
142
|
+
opacity: 0.82;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.welcome-chips {
|
|
81
146
|
display: grid;
|
|
82
147
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
83
148
|
gap: 16px;
|
|
84
|
-
margin:
|
|
149
|
+
margin-top: 28px;
|
|
85
150
|
}
|
|
86
151
|
|
|
87
|
-
.
|
|
88
|
-
padding: 16px;
|
|
89
|
-
border-radius:
|
|
90
|
-
background: #f8fbff;
|
|
152
|
+
.welcome-chip {
|
|
153
|
+
padding: 16px 18px;
|
|
154
|
+
border-radius: 20px;
|
|
91
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);
|
|
92
158
|
}
|
|
93
159
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
text-transform: uppercase;
|
|
99
|
-
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;
|
|
100
164
|
}
|
|
101
165
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
padding: 16px;
|
|
110
|
-
border-radius: 16px;
|
|
111
|
-
overflow: auto;
|
|
112
|
-
background: #0d1d3a;
|
|
113
|
-
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;
|
|
114
173
|
}
|
|
115
174
|
|
|
116
|
-
.
|
|
117
|
-
|
|
175
|
+
.welcome-chip strong {
|
|
176
|
+
font-size: 1rem;
|
|
177
|
+
font-weight: 700;
|
|
118
178
|
}
|
|
119
179
|
|
|
120
180
|
@media (max-width: 640px) {
|
|
121
|
-
.
|
|
181
|
+
.welcome-shell {
|
|
182
|
+
padding: 18px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.welcome-card {
|
|
122
186
|
padding: 24px;
|
|
123
187
|
}
|
|
124
188
|
|
|
125
|
-
.
|
|
126
|
-
|
|
189
|
+
.welcome-brand {
|
|
190
|
+
align-items: flex-start;
|
|
191
|
+
flex-direction: column;
|
|
127
192
|
}
|
|
128
193
|
}
|