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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-eventus-app",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Scaffold an Eventus mini app.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,169 +1,65 @@
1
- import { useEffect, useState } from "react";
2
1
  import manifest from "virtual:eventus-manifest";
3
2
  import {
4
- eventus,
5
- getLivePreviewHtml,
6
- isBridgeUnavailableError,
7
- type EventusContext,
8
- type EventusRuntimeSource,
9
- } from "@eventusgo/sdk";
3
+ EventusContextProvider,
4
+ useEventusContext,
5
+ } from "@eventusgo/sdk/react";
10
6
 
11
- type LoadState =
12
- | { status: "idle" | "loading" }
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
- const [state, setState] = useState<LoadState>({ status: "loading" });
22
- const [runtimeSource, setRuntimeSource] = useState<
23
- EventusRuntimeSource | "bridge-unavailable" | "loading"
24
- >("loading");
25
-
26
- useEffect(() => {
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="app-shell">
100
- <section className="card">
101
- <p className="eyebrow">Eventus Mini App Toolkit</p>
102
- <h1>{manifest.name}</h1>
103
- <p className="subtitle">
104
- App ID <code>{manifest.appId}</code> · Version{" "}
105
- <code>{manifest.version}</code>
106
- </p>
107
-
108
- <div className="status-banner">{runtimeLabel}</div>
109
-
110
- {state.status === "loading" ? (
111
- <p>Connecting to the Eventus client…</p>
112
- ) : null}
113
-
114
- {state.status === "error" ? (
115
- <p className="error-text">{state.message}</p>
116
- ) : null}
117
-
118
- {state.status === "bridge-unavailable" ? (
119
- state.previewHtml ? (
120
- <div
121
- dangerouslySetInnerHTML={{
122
- __html: state.previewHtml,
123
- }}
124
- />
125
- ) : (
126
- <div className="handoff-panel">
127
- <h2>Open inside Eventus X</h2>
128
- <p>
129
- This mini app needs the Eventus bridge to access the real
130
- runtime. Open it from Eventus X to test it with production-like
131
- behavior.
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
  );
@@ -1,12 +1,18 @@
1
1
  :root {
2
2
  font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
3
3
  color: #102347;
4
- background: radial-gradient(
5
- circle at top,
6
- #d8f2ff 0%,
7
- #f3f9ff 35%,
8
- #eef3ff 100%
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
- .app-shell {
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
- width: min(720px, 100%);
42
+ .welcome-card {
43
+ position: relative;
44
+ isolation: isolate;
45
+ overflow: hidden;
46
+ width: min(760px, 100%);
38
47
  padding: 32px;
39
- border-radius: 24px;
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.14);
43
- backdrop-filter: blur(16px);
50
+ box-shadow: 0 24px 80px rgba(38, 73, 134, 0.16);
51
+ backdrop-filter: blur(18px);
44
52
  }
45
53
 
46
- .eyebrow {
47
- margin: 0 0 8px;
48
- font-size: 0.85rem;
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
- h1 {
55
- margin: 0;
56
- font-size: clamp(2rem, 4vw, 3rem);
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
- .subtitle {
60
- margin: 12px 0 0;
61
- 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);
62
89
  }
63
90
 
64
- .status-banner {
65
- margin: 24px 0;
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
- padding: 8px 12px;
105
+ align-items: center;
106
+ gap: 8px;
107
+ padding: 10px 14px;
68
108
  border-radius: 999px;
69
- background: #eef6ff;
70
- color: #22548d;
71
- font-weight: 600;
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
- .handoff-panel {
75
- margin: 24px 0;
76
- display: grid;
77
- gap: 20px;
117
+ .welcome-copy {
118
+ margin-top: 32px;
119
+ max-width: 560px;
78
120
  }
79
121
 
80
- .details-grid {
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: 24px 0;
149
+ margin-top: 28px;
85
150
  }
86
151
 
87
- .details-grid div {
88
- padding: 16px;
89
- border-radius: 16px;
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
- dt {
95
- margin-bottom: 6px;
96
- font-size: 0.85rem;
97
- color: #6880a6;
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
- dd {
103
- margin: 0;
104
- font-weight: 600;
105
- }
106
-
107
- .context-preview {
108
- margin: 0;
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
- .error-text {
117
- color: #b42318;
175
+ .welcome-chip strong {
176
+ font-size: 1rem;
177
+ font-weight: 700;
118
178
  }
119
179
 
120
180
  @media (max-width: 640px) {
121
- .card {
181
+ .welcome-shell {
182
+ padding: 18px;
183
+ }
184
+
185
+ .welcome-card {
122
186
  padding: 24px;
123
187
  }
124
188
 
125
- .handoff-panel {
126
- grid-template-columns: 1fr;
189
+ .welcome-brand {
190
+ align-items: flex-start;
191
+ flex-direction: column;
127
192
  }
128
193
  }