@omg-dev/sdk 0.4.29 → 0.4.31

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.
@@ -1,5 +1,4 @@
1
- import { useEffect, useId, useState, type CSSProperties } from "react"
2
- import { VibesFeedback } from "../feedback/VibesFeedback"
1
+ import { useId, useState, type CSSProperties } from "react"
3
2
 
4
3
  export interface OmgBadgeProps {
5
4
  /** Link used by the dialog CTA. Default: https://omg.dev */
@@ -13,169 +12,29 @@ const BRAND = "#FF5530"
13
12
  const Z_BADGE = 2147482000
14
13
  const Z_DIALOG = 2147483100
15
14
 
16
- // Cross-process signal the brand badge dispatches to summon the (button-less)
17
- // feedback sheet it mounts. Bundling feedback INTO this badge is deliberate:
18
- // one floating control in the corner, not three.
19
- export const FEEDBACK_OPEN_EVENT = "vibes:feedback:open"
20
-
21
- // Build-time gate (set by @omg-dev/vite-plugin via `define`). True when the app
22
- // has feedback enabled AND the brand badge owns it. Falls back to true when the
23
- // badge is used outside the plugin (it's only auto-injected by the plugin, so
24
- // in practice the define is always present in published bundles).
25
- declare const __VIBES_BRAND_FEEDBACK__: boolean | undefined
26
- function feedbackBundled(): boolean {
27
- try {
28
- return typeof __VIBES_BRAND_FEEDBACK__ === "undefined" ? true : __VIBES_BRAND_FEEDBACK__
29
- } catch {
30
- return true
31
- }
32
- }
33
-
34
- // ── Remix ("Make it mine") gating ────────────────────────────────────────────
35
- // The badge's first job on a PUBLIC Explore-listed app is the recipient→creator
36
- // hinge: a visitor who only has the shared link can fork the app back on
37
- // omg.dev. Private (not listed) apps keep the plain branding badge only —
38
- // remixBySlug rejects them, so the CTA must never appear. Once dismissed, the
39
- // SAME badge collapses to branding — the omg mark never leaves, only the CTA.
40
- const DISMISS_KEY = "vibes-remix:dismissed"
41
- const REMIX_ORIGIN =
42
- (typeof import.meta !== "undefined" &&
43
- (import.meta as { env?: Record<string, string | undefined> }).env?.VITE_REMIX_ORIGIN) ||
44
- "https://omg.dev"
45
- // Control-plane host for the unauthenticated isRemixable probe. Overridable for
46
- // self-host; defaults to production. CORS is open for this path only (Caddy).
47
- const CONTROLPLANE_URL = (
48
- (typeof import.meta !== "undefined" &&
49
- (import.meta as { env?: Record<string, string | undefined> }).env?.VITE_CONTROLPLANE_URL) ||
50
- "https://backend.omg.dev"
51
- ).replace(/\/$/, "")
52
-
53
- function appSlug(): string | null {
54
- if (typeof import.meta === "undefined") return null
55
- const env = (import.meta as { env?: Record<string, string | undefined> }).env
56
- const slug = env?.VITE_APP_SLUG?.trim()
57
- if (!slug || !/^[a-z0-9-]+$/.test(slug)) return null
58
- return slug
59
- }
60
-
61
- function isDismissed(): boolean {
62
- try {
63
- return localStorage.getItem(DISMISS_KEY) === "1"
64
- } catch {
65
- return false
66
- }
67
- }
68
-
69
- function setDismissedFlag() {
70
- try {
71
- localStorage.setItem(DISMISS_KEY, "1")
72
- } catch {
73
- /* private mode */
74
- }
75
- }
76
-
77
- /** Live check: only Explore-listed public apps may show "Make it mine". Fail closed. */
78
- async function fetchRemixable(slug: string): Promise<boolean> {
79
- try {
80
- const res = await fetch(`${CONTROLPLANE_URL}/api/projects/isRemixable`, {
81
- method: "POST",
82
- headers: { "content-type": "application/json" },
83
- body: JSON.stringify({ slug }),
84
- // Public boolean; no credentials. Avoid caching a stale private→public flip.
85
- cache: "no-store",
86
- })
87
- if (!res.ok) return false
88
- const data = (await res.json()) as { remixable?: unknown }
89
- return data?.remixable === true
90
- } catch {
91
- return false
92
- }
93
- }
94
-
95
15
  export function OmgBadge({
96
16
  href = "https://omg.dev",
97
17
  label = "What is omg?",
98
18
  }: OmgBadgeProps) {
99
19
  const [open, setOpen] = useState(false)
100
- // Fail closed: start as branding. Promote to remix only after the public
101
- // catalog confirms this slug is listed — never flash "Make it mine" on a
102
- // private published app while the probe is in flight.
103
- const slug = appSlug()
104
- const [remix, setRemix] = useState(false)
105
20
  const titleId = useId()
106
21
  const descriptionId = useId()
107
22
  const markId = useId().replace(/[^a-zA-Z0-9_-]/g, "")
108
23
 
109
- useEffect(() => {
110
- if (!slug || isDismissed()) return
111
- let cancelled = false
112
- void fetchRemixable(slug).then((ok) => {
113
- if (!cancelled && ok && !isDismissed()) setRemix(true)
114
- })
115
- return () => {
116
- cancelled = true
117
- }
118
- }, [slug])
119
-
120
- function dismissRemix() {
121
- setDismissedFlag()
122
- setRemix(false)
123
- }
124
-
125
- function summonFeedback() {
126
- setOpen(false)
127
- if (typeof window !== "undefined") {
128
- window.dispatchEvent(new CustomEvent(FEEDBACK_OPEN_EVENT))
129
- }
130
- }
131
-
132
24
  return (
133
25
  <>
134
- {remix && slug ? (
135
- // Remix state: the omg mark + "Make it mine" CTA. Tapping the pill body
136
- // navigates to the dashboard to fork the app; the ✕ collapses to the
137
- // branding badge. ?ref=pwa attributes the click on /remix.
138
- <a
139
- href={`${REMIX_ORIGIN}/remix/${slug}?ref=pwa`}
140
- aria-label="Make this app mine"
141
- data-vibes-feedback=""
142
- style={badgeStyle}
143
- >
144
- <OmgMark size={18} id={`remix-${markId}`} />
145
- <span style={badgeTextStyle}>Make it mine</span>
146
- <button
147
- type="button"
148
- aria-label="Dismiss"
149
- onClick={(event) => {
150
- event.preventDefault()
151
- event.stopPropagation()
152
- dismissRemix()
153
- }}
154
- style={dismissStyle}
155
- >
156
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none">
157
- <path d="M6 6l12 12M18 6 6 18" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" />
158
- </svg>
159
- </button>
160
- </a>
161
- ) : (
162
- // Branding state: the omg mark + "omg". Opens the "Built with omg"
163
- // dialog, which also hosts the feedback entry.
164
- <button
165
- type="button"
166
- aria-label={label}
167
- data-vibes-feedback=""
168
- onClick={() => setOpen(true)}
169
- style={badgeStyle}
170
- >
171
- <OmgMark size={18} id={`badge-${markId}`} />
172
- <span style={badgeTextStyle}>omg</span>
173
- </button>
174
- )}
26
+ <button
27
+ type="button"
28
+ aria-label={label}
29
+ onClick={() => setOpen(true)}
30
+ style={badgeStyle}
31
+ >
32
+ <OmgMark size={18} id={`badge-${markId}`} />
33
+ <span style={badgeTextStyle}>omg</span>
34
+ </button>
175
35
 
176
36
  {open && (
177
37
  <div
178
- data-vibes-feedback=""
179
38
  role="presentation"
180
39
  style={backdropStyle}
181
40
  onMouseDown={(event) => {
@@ -213,20 +72,9 @@ export function OmgBadge({
213
72
  <a href={href} target="_blank" rel="noopener noreferrer" style={ctaStyle}>
214
73
  Learn about omg
215
74
  </a>
216
- {feedbackBundled() && (
217
- <button type="button" onClick={summonFeedback} style={secondaryStyle}>
218
- Send feedback
219
- </button>
220
- )}
221
75
  </div>
222
76
  </div>
223
77
  )}
224
-
225
- {/* Feedback is bundled into the badge — a button-less sheet summoned from
226
- the dialog (or by gesture), so there's no second floating control. */}
227
- {feedbackBundled() && (
228
- <VibesFeedback showButton={false} accent={BRAND} title="Send feedback" />
229
- )}
230
78
  </>
231
79
  )
232
80
  }
@@ -288,20 +136,6 @@ const badgeTextStyle: CSSProperties = {
288
136
  padding: "0 3px",
289
137
  }
290
138
 
291
- const dismissStyle: CSSProperties = {
292
- width: 22,
293
- height: 22,
294
- flex: "0 0 auto",
295
- borderRadius: 999,
296
- border: "none",
297
- background: "rgba(20, 16, 12, 0.06)",
298
- color: "#6b6459",
299
- display: "grid",
300
- placeItems: "center",
301
- cursor: "pointer",
302
- padding: 0,
303
- }
304
-
305
139
  const backdropStyle: CSSProperties = {
306
140
  position: "fixed",
307
141
  inset: 0,
@@ -383,21 +217,3 @@ const ctaStyle: CSSProperties = {
383
217
  textDecoration: "none",
384
218
  letterSpacing: 0,
385
219
  }
386
-
387
- const secondaryStyle: CSSProperties = {
388
- display: "inline-flex",
389
- alignItems: "center",
390
- justifyContent: "center",
391
- width: "100%",
392
- height: 44,
393
- marginTop: 8,
394
- borderRadius: 12,
395
- background: "transparent",
396
- border: "1px solid rgba(21, 17, 13, 0.14)",
397
- color: "#15110d",
398
- fontSize: 15,
399
- fontWeight: 650,
400
- cursor: "pointer",
401
- fontFamily: font,
402
- letterSpacing: 0,
403
- }
@@ -4,13 +4,6 @@
4
4
  // app's React tree so it survives user app rewrites and does not require each
5
5
  // generated app to carry attribution code in its source.
6
6
  //
7
- // One control, not three: this badge is the "Make it mine" remix CTA on a fresh
8
- // visit to a PUBLIC (Explore-listed) app (same omg mark), collapses to the plain
9
- // branding badge on dismiss or when the app is private, and bundles the
10
- // (button-less) feedback sheet, summoned from its dialog. The vite-plugin
11
- // therefore skips the standalone feedback/auto + remix-cta imports whenever
12
- // this badge is enabled (the default).
13
-
14
7
  import { createRoot } from "react-dom/client"
15
8
  import { OmgBadge } from "./OmgBadge"
16
9
 
@@ -21,8 +14,6 @@ function mount() {
21
14
  if (document.getElementById(HOST_ID)) return
22
15
  const host = document.createElement("div")
23
16
  host.id = HOST_ID
24
- // Feedback screenshots should capture the app, not platform chrome.
25
- host.setAttribute("data-vibes-feedback", "")
26
17
  document.body.appendChild(host)
27
18
  createRoot(host).render(<OmgBadge />)
28
19
  }
package/src/index.ts CHANGED
@@ -14,9 +14,6 @@ export * from "./auth/index"
14
14
  // Storage surface — useUpload() + <VibesUpload />. Re-exported here for
15
15
  // the same publish-workflow reason as auth (only "." subpath survives).
16
16
  export * from "./storage/index"
17
- // Feedback surface — <VibesFeedback /> gesture widget + trace capture.
18
- // Re-exported here for the same publish-workflow reason (only "." survives).
19
- export * from "./feedback/index"
20
17
  // Brand surface — <OmgBadge /> platform attribution badge.
21
18
  export * from "./brand/index"
22
19
  // Notifications surface — durable in-app inbox + Web Push registration.
@@ -1,6 +1,10 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { createSandbox, forkSandbox, runtimeClaims } from "./sandbox";
3
3
 
4
+ it("exports the funded transcription capability", () => {
5
+ expect(runtimeClaims.speechTranscribe).toBe("speech.transcribe");
6
+ });
7
+
4
8
  describe("sandbox SDK", () => {
5
9
  it("posts create requests to the sandbox router", async () => {
6
10
  const calls: Array<{ url: string; body: unknown }> = [];
package/src/sandbox.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export const runtimeClaims = {
2
2
  llmInvoke: "llm.invoke",
3
3
  mediaInvoke: "media.invoke",
4
+ speechTranscribe: "speech.transcribe",
4
5
  browserUse: "browser.use",
5
6
  sandboxCreate: "sandbox.create",
6
7
  sandboxDelegate: "sandbox.delegate",
@@ -1,371 +0,0 @@
1
- import { t as VibesFeedback } from "./VibesFeedback-BF2Vf6FK.mjs";
2
- import { useEffect, useId, useState } from "react";
3
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- //#region src/brand/OmgBadge.tsx
5
- const BRAND = "#FF5530";
6
- const Z_BADGE = 2147482e3;
7
- const Z_DIALOG = 2147483100;
8
- const FEEDBACK_OPEN_EVENT = "vibes:feedback:open";
9
- function feedbackBundled() {
10
- try {
11
- return typeof __VIBES_BRAND_FEEDBACK__ === "undefined" ? true : __VIBES_BRAND_FEEDBACK__;
12
- } catch {
13
- return true;
14
- }
15
- }
16
- const DISMISS_KEY = "vibes-remix:dismissed";
17
- const REMIX_ORIGIN = typeof import.meta !== "undefined" && import.meta.env?.VITE_REMIX_ORIGIN || "https://omg.dev";
18
- const CONTROLPLANE_URL = (typeof import.meta !== "undefined" && import.meta.env?.VITE_CONTROLPLANE_URL || "https://backend.omg.dev").replace(/\/$/, "");
19
- function appSlug() {
20
- if (typeof import.meta === "undefined") return null;
21
- const slug = import.meta.env?.VITE_APP_SLUG?.trim();
22
- if (!slug || !/^[a-z0-9-]+$/.test(slug)) return null;
23
- return slug;
24
- }
25
- function isDismissed() {
26
- try {
27
- return localStorage.getItem(DISMISS_KEY) === "1";
28
- } catch {
29
- return false;
30
- }
31
- }
32
- function setDismissedFlag() {
33
- try {
34
- localStorage.setItem(DISMISS_KEY, "1");
35
- } catch {}
36
- }
37
- /** Live check: only Explore-listed public apps may show "Make it mine". Fail closed. */
38
- async function fetchRemixable(slug) {
39
- try {
40
- const res = await fetch(`${CONTROLPLANE_URL}/api/projects/isRemixable`, {
41
- method: "POST",
42
- headers: { "content-type": "application/json" },
43
- body: JSON.stringify({ slug }),
44
- cache: "no-store"
45
- });
46
- if (!res.ok) return false;
47
- return (await res.json())?.remixable === true;
48
- } catch {
49
- return false;
50
- }
51
- }
52
- function OmgBadge({ href = "https://omg.dev", label = "What is omg?" }) {
53
- const [open, setOpen] = useState(false);
54
- const slug = appSlug();
55
- const [remix, setRemix] = useState(false);
56
- const titleId = useId();
57
- const descriptionId = useId();
58
- const markId = useId().replace(/[^a-zA-Z0-9_-]/g, "");
59
- useEffect(() => {
60
- if (!slug || isDismissed()) return;
61
- let cancelled = false;
62
- fetchRemixable(slug).then((ok) => {
63
- if (!cancelled && ok && !isDismissed()) setRemix(true);
64
- });
65
- return () => {
66
- cancelled = true;
67
- };
68
- }, [slug]);
69
- function dismissRemix() {
70
- setDismissedFlag();
71
- setRemix(false);
72
- }
73
- function summonFeedback() {
74
- setOpen(false);
75
- if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent(FEEDBACK_OPEN_EVENT));
76
- }
77
- return /* @__PURE__ */ jsxs(Fragment, { children: [
78
- remix && slug ? /* @__PURE__ */ jsxs("a", {
79
- href: `${REMIX_ORIGIN}/remix/${slug}?ref=pwa`,
80
- "aria-label": "Make this app mine",
81
- "data-vibes-feedback": "",
82
- style: badgeStyle,
83
- children: [
84
- /* @__PURE__ */ jsx(OmgMark, {
85
- size: 18,
86
- id: `remix-${markId}`
87
- }),
88
- /* @__PURE__ */ jsx("span", {
89
- style: badgeTextStyle,
90
- children: "Make it mine"
91
- }),
92
- /* @__PURE__ */ jsx("button", {
93
- type: "button",
94
- "aria-label": "Dismiss",
95
- onClick: (event) => {
96
- event.preventDefault();
97
- event.stopPropagation();
98
- dismissRemix();
99
- },
100
- style: dismissStyle,
101
- children: /* @__PURE__ */ jsx("svg", {
102
- "aria-hidden": "true",
103
- width: "13",
104
- height: "13",
105
- viewBox: "0 0 24 24",
106
- fill: "none",
107
- children: /* @__PURE__ */ jsx("path", {
108
- d: "M6 6l12 12M18 6 6 18",
109
- stroke: "currentColor",
110
- strokeWidth: "2.4",
111
- strokeLinecap: "round"
112
- })
113
- })
114
- })
115
- ]
116
- }) : /* @__PURE__ */ jsxs("button", {
117
- type: "button",
118
- "aria-label": label,
119
- "data-vibes-feedback": "",
120
- onClick: () => setOpen(true),
121
- style: badgeStyle,
122
- children: [/* @__PURE__ */ jsx(OmgMark, {
123
- size: 18,
124
- id: `badge-${markId}`
125
- }), /* @__PURE__ */ jsx("span", {
126
- style: badgeTextStyle,
127
- children: "omg"
128
- })]
129
- }),
130
- open && /* @__PURE__ */ jsx("div", {
131
- "data-vibes-feedback": "",
132
- role: "presentation",
133
- style: backdropStyle,
134
- onMouseDown: (event) => {
135
- if (event.target === event.currentTarget) setOpen(false);
136
- },
137
- children: /* @__PURE__ */ jsxs("div", {
138
- role: "dialog",
139
- "aria-modal": "true",
140
- "aria-labelledby": titleId,
141
- "aria-describedby": descriptionId,
142
- style: dialogStyle,
143
- children: [
144
- /* @__PURE__ */ jsx("button", {
145
- type: "button",
146
- "aria-label": "Close",
147
- onClick: () => setOpen(false),
148
- style: closeButtonStyle,
149
- children: /* @__PURE__ */ jsx("svg", {
150
- "aria-hidden": "true",
151
- width: "18",
152
- height: "18",
153
- viewBox: "0 0 24 24",
154
- fill: "none",
155
- children: /* @__PURE__ */ jsx("path", {
156
- d: "M6 6l12 12M18 6 6 18",
157
- stroke: "currentColor",
158
- strokeWidth: "2",
159
- strokeLinecap: "round"
160
- })
161
- })
162
- }),
163
- /* @__PURE__ */ jsx("div", {
164
- style: markWrapStyle,
165
- children: /* @__PURE__ */ jsx(OmgMark, {
166
- size: 34,
167
- id: `dialog-${markId}`
168
- })
169
- }),
170
- /* @__PURE__ */ jsx("h2", {
171
- id: titleId,
172
- style: titleStyle,
173
- children: "Built with omg"
174
- }),
175
- /* @__PURE__ */ jsx("p", {
176
- id: descriptionId,
177
- style: bodyStyle,
178
- children: "omg turns a plain-language idea into a real app, then hosts it with sign-in, data storage, and publishing already handled."
179
- }),
180
- /* @__PURE__ */ jsx("a", {
181
- href,
182
- target: "_blank",
183
- rel: "noopener noreferrer",
184
- style: ctaStyle,
185
- children: "Learn about omg"
186
- }),
187
- feedbackBundled() && /* @__PURE__ */ jsx("button", {
188
- type: "button",
189
- onClick: summonFeedback,
190
- style: secondaryStyle,
191
- children: "Send feedback"
192
- })
193
- ]
194
- })
195
- }),
196
- feedbackBundled() && /* @__PURE__ */ jsx(VibesFeedback, {
197
- showButton: false,
198
- accent: BRAND,
199
- title: "Send feedback"
200
- })
201
- ] });
202
- }
203
- function OmgMark({ size, id }) {
204
- const maskId = `omg-mark-cut-${id}`;
205
- return /* @__PURE__ */ jsxs("svg", {
206
- "aria-hidden": "true",
207
- width: size,
208
- height: size,
209
- viewBox: "0 0 100 100",
210
- fill: "none",
211
- style: {
212
- display: "block",
213
- flex: "0 0 auto"
214
- },
215
- children: [/* @__PURE__ */ jsxs("mask", {
216
- id: maskId,
217
- children: [/* @__PURE__ */ jsx("rect", {
218
- width: "100",
219
- height: "100",
220
- fill: "white"
221
- }), /* @__PURE__ */ jsx("circle", {
222
- cx: "71",
223
- cy: "29",
224
- r: size <= 16 ? 16.5 : size <= 20 ? 15.2 : size <= 32 ? 14 : 13.2,
225
- fill: "black"
226
- })]
227
- }), /* @__PURE__ */ jsx("circle", {
228
- cx: "50",
229
- cy: "50",
230
- r: "44",
231
- fill: BRAND,
232
- mask: `url(#${maskId})`
233
- })]
234
- });
235
- }
236
- const font = "system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif";
237
- const badgeStyle = {
238
- position: "fixed",
239
- right: "max(14px, env(safe-area-inset-right))",
240
- bottom: "calc(16px + env(safe-area-inset-bottom))",
241
- zIndex: Z_BADGE,
242
- height: 38,
243
- padding: "0 8px 0 10px",
244
- border: "1px solid rgba(20, 16, 12, 0.12)",
245
- borderRadius: 999,
246
- background: "rgba(255, 255, 255, 0.94)",
247
- color: "#15110d",
248
- boxShadow: "0 8px 28px rgba(0, 0, 0, 0.16)",
249
- display: "inline-flex",
250
- alignItems: "center",
251
- gap: 7,
252
- fontFamily: font,
253
- cursor: "pointer",
254
- textDecoration: "none",
255
- WebkitTapHighlightColor: "transparent",
256
- backdropFilter: "blur(10px)"
257
- };
258
- const badgeTextStyle = {
259
- fontSize: 13,
260
- lineHeight: "18px",
261
- fontWeight: 700,
262
- letterSpacing: 0,
263
- padding: "0 3px"
264
- };
265
- const dismissStyle = {
266
- width: 22,
267
- height: 22,
268
- flex: "0 0 auto",
269
- borderRadius: 999,
270
- border: "none",
271
- background: "rgba(20, 16, 12, 0.06)",
272
- color: "#6b6459",
273
- display: "grid",
274
- placeItems: "center",
275
- cursor: "pointer",
276
- padding: 0
277
- };
278
- const backdropStyle = {
279
- position: "fixed",
280
- inset: 0,
281
- zIndex: Z_DIALOG,
282
- display: "grid",
283
- placeItems: "center",
284
- padding: "24px 16px calc(24px + env(safe-area-inset-bottom))",
285
- background: "rgba(15, 13, 11, 0.34)",
286
- boxSizing: "border-box"
287
- };
288
- const dialogStyle = {
289
- position: "relative",
290
- width: "min(100%, 360px)",
291
- borderRadius: 18,
292
- padding: "26px 22px 20px",
293
- background: "#fffaf4",
294
- color: "#15110d",
295
- boxShadow: "0 24px 70px rgba(0, 0, 0, 0.28)",
296
- border: "1px solid rgba(21, 17, 13, 0.08)",
297
- fontFamily: font,
298
- boxSizing: "border-box"
299
- };
300
- const closeButtonStyle = {
301
- position: "absolute",
302
- top: 10,
303
- right: 10,
304
- width: 34,
305
- height: 34,
306
- borderRadius: 999,
307
- border: "none",
308
- background: "transparent",
309
- color: "#6b6459",
310
- display: "grid",
311
- placeItems: "center",
312
- cursor: "pointer"
313
- };
314
- const markWrapStyle = {
315
- width: 52,
316
- height: 52,
317
- borderRadius: 16,
318
- display: "grid",
319
- placeItems: "center",
320
- background: "#fff",
321
- boxShadow: "inset 0 0 0 1px rgba(21, 17, 13, 0.08)",
322
- marginBottom: 16
323
- };
324
- const titleStyle = {
325
- margin: 0,
326
- color: "#15110d",
327
- fontSize: 23,
328
- lineHeight: "28px",
329
- fontWeight: 750,
330
- letterSpacing: 0
331
- };
332
- const bodyStyle = {
333
- margin: "10px 0 18px",
334
- color: "#5f574d",
335
- fontSize: 15,
336
- lineHeight: "22px",
337
- letterSpacing: 0
338
- };
339
- const ctaStyle = {
340
- display: "inline-flex",
341
- alignItems: "center",
342
- justifyContent: "center",
343
- width: "100%",
344
- height: 44,
345
- borderRadius: 12,
346
- background: "#15110d",
347
- color: "#fffaf4",
348
- fontSize: 15,
349
- fontWeight: 700,
350
- textDecoration: "none",
351
- letterSpacing: 0
352
- };
353
- const secondaryStyle = {
354
- display: "inline-flex",
355
- alignItems: "center",
356
- justifyContent: "center",
357
- width: "100%",
358
- height: 44,
359
- marginTop: 8,
360
- borderRadius: 12,
361
- background: "transparent",
362
- border: "1px solid rgba(21, 17, 13, 0.14)",
363
- color: "#15110d",
364
- fontSize: 15,
365
- fontWeight: 650,
366
- cursor: "pointer",
367
- fontFamily: font,
368
- letterSpacing: 0
369
- };
370
- //#endregion
371
- export { OmgBadge as t };