@lumiastream/ui 0.2.8-alpha.25 → 0.2.8-alpha.27
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/dist/index.js +86 -54
- package/dist/se-import.js +86 -54
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3226,9 +3226,17 @@ var YOUTUBE_CONTEXTS = {
|
|
|
3226
3226
|
"subscriber-week": { amount: "youtube_week_member_count", count: "youtube_week_member_count" },
|
|
3227
3227
|
"subscriber-month": { amount: "youtube_month_member_count", count: "youtube_month_member_count" }
|
|
3228
3228
|
};
|
|
3229
|
+
var RECENT_TO_LATEST_LISTENER = {
|
|
3230
|
+
"follower-recent": "follower-latest",
|
|
3231
|
+
"subscriber-recent": "subscriber-latest",
|
|
3232
|
+
"cheer-recent": "cheer-latest",
|
|
3233
|
+
"tip-recent": "tip-latest",
|
|
3234
|
+
"raid-recent": "raid-latest"
|
|
3235
|
+
};
|
|
3229
3236
|
function listenerPlaceholderContext(listener, provider = "twitch") {
|
|
3237
|
+
const resolved = RECENT_TO_LATEST_LISTENER[listener] ?? listener;
|
|
3230
3238
|
const platformTable = provider === "kick" ? KICK_CONTEXTS : provider === "youtube" ? YOUTUBE_CONTEXTS : null;
|
|
3231
|
-
return platformTable?.[
|
|
3239
|
+
return platformTable?.[resolved] ?? TWITCH_CONTEXTS[resolved] ?? {};
|
|
3232
3240
|
}
|
|
3233
3241
|
var SE_WIDGET_TYPE_LABELS = {
|
|
3234
3242
|
"subscriber-latest": "Latest subscriber",
|
|
@@ -3313,8 +3321,9 @@ var YOUTUBE_LISTENER_VARS = {
|
|
|
3313
3321
|
};
|
|
3314
3322
|
function listenerToLumiaVariable(listener, provider = "twitch") {
|
|
3315
3323
|
if (typeof listener !== "string" || !listener) return "username";
|
|
3316
|
-
|
|
3317
|
-
if (provider === "
|
|
3324
|
+
const resolvedListener = RECENT_TO_LATEST_LISTENER[listener] ?? listener;
|
|
3325
|
+
if (provider === "kick" && KICK_LISTENER_VARS[resolvedListener]) return KICK_LISTENER_VARS[resolvedListener];
|
|
3326
|
+
if (provider === "youtube" && YOUTUBE_LISTENER_VARS[resolvedListener]) return YOUTUBE_LISTENER_VARS[resolvedListener];
|
|
3318
3327
|
const m = {
|
|
3319
3328
|
// Latest events
|
|
3320
3329
|
"follower-latest": "twitch_last_follower",
|
|
@@ -3371,7 +3380,7 @@ function listenerToLumiaVariable(listener, provider = "twitch") {
|
|
|
3371
3380
|
"cheer-alltime-top-donation": "twitch_alltime_top_cheerer_amount",
|
|
3372
3381
|
"cheer-alltime-top-donator": "twitch_alltime_top_cheerer"
|
|
3373
3382
|
};
|
|
3374
|
-
return m[
|
|
3383
|
+
return m[resolvedListener] ?? resolvedListener.replace(/-/g, "_");
|
|
3375
3384
|
}
|
|
3376
3385
|
function seCssToBounds(css, defaults = { width: 600, height: 200 }, canvas) {
|
|
3377
3386
|
let widthIsAuto = false;
|
|
@@ -3502,6 +3511,25 @@ function seLayoutUsesPushText(seLayout) {
|
|
|
3502
3511
|
|
|
3503
3512
|
// src/se-import/mappers/build.ts
|
|
3504
3513
|
import { nanoid } from "nanoid";
|
|
3514
|
+
function mapSeTextCssToModuleCss(widget, defaults = {}) {
|
|
3515
|
+
const seTextCss = widget.text?.css ?? {};
|
|
3516
|
+
const asStr = (v, fallback) => typeof v === "string" && v.length > 0 ? v : fallback;
|
|
3517
|
+
const asNumOrStr = (v, fallback) => {
|
|
3518
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
3519
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
3520
|
+
return fallback;
|
|
3521
|
+
};
|
|
3522
|
+
return {
|
|
3523
|
+
lineHeight: asNumOrStr(seTextCss["line-height"], defaults.lineHeight ?? 1),
|
|
3524
|
+
fontSize: asNumOrStr(seTextCss["font-size"], defaults.fontSize ?? 24),
|
|
3525
|
+
textAlign: asStr(seTextCss["text-align"], defaults.textAlign ?? "center"),
|
|
3526
|
+
fontFamily: asStr(seTextCss["font-family"], defaults.fontFamily ?? "Roboto"),
|
|
3527
|
+
fontWeight: asStr(seTextCss["font-weight"], defaults.fontWeight ?? "bold"),
|
|
3528
|
+
color: asStr(seTextCss.color, defaults.color ?? "#ffffff"),
|
|
3529
|
+
textShadow: asStr(seTextCss["text-shadow"], defaults.textShadow ?? "rgb(0, 0, 0) 1px 1px 1px"),
|
|
3530
|
+
background: defaults.background ?? "transparent"
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3505
3533
|
function buildUnit(widget, lumiaType, moduleExtras, ctx) {
|
|
3506
3534
|
const id = nanoid();
|
|
3507
3535
|
const defaults = LUMIA_DEFAULT_SIZES[lumiaType] ?? { width: 400, height: 400 };
|
|
@@ -3998,7 +4026,6 @@ function mapGoal(widget, ctx) {
|
|
|
3998
4026
|
const v = widget.variables ?? {};
|
|
3999
4027
|
const listener = v.goalListener ?? (typeof widget.listener === "string" ? widget.listener : null);
|
|
4000
4028
|
const charity = charityGoalVariables(widget.type);
|
|
4001
|
-
const seTextCss = widget.text?.css ?? {};
|
|
4002
4029
|
return buildUnit(widget, "goal", {
|
|
4003
4030
|
content: {
|
|
4004
4031
|
version: 1,
|
|
@@ -4041,23 +4068,16 @@ function mapGoal(widget, ctx) {
|
|
|
4041
4068
|
simpleDesign: !!v.simpleDesign
|
|
4042
4069
|
})
|
|
4043
4070
|
},
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
textAlign: seTextCss["text-align"] ?? "center",
|
|
4055
|
-
fontFamily: seTextCss["font-family"] ?? "Roboto",
|
|
4056
|
-
fontWeight: seTextCss["font-weight"] ?? "bold",
|
|
4057
|
-
color: seTextCss.color ?? "#ffffff",
|
|
4058
|
-
textShadow: seTextCss["text-shadow"] ?? "rgb(0, 0, 0) 1px 1px 1px",
|
|
4059
|
-
background: "transparent"
|
|
4060
|
-
}
|
|
4071
|
+
// `borderRadius` / `borderStyle` / `borderWidth` / `borderColor`
|
|
4072
|
+
// used to be set on `css` too, but the Goal renderer applies its
|
|
4073
|
+
// own border + borderRadius via inline `style={…}` on the .goal-bar
|
|
4074
|
+
// div (see Goal/index.tsx:123,127,155) sourced from
|
|
4075
|
+
// `content.border` and `content.borderRadius`. Writing them to
|
|
4076
|
+
// module.css just plopped useless transparent-0px rules on the
|
|
4077
|
+
// outer .overlay-module wrapper. SE charity goals commonly use
|
|
4078
|
+
// 24-30px Nunito/Roboto — fontSize default of 30 mirrors the
|
|
4079
|
+
// previous hardcoded fallback.
|
|
4080
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 30 })
|
|
4061
4081
|
}, ctx);
|
|
4062
4082
|
}
|
|
4063
4083
|
|
|
@@ -4331,6 +4351,9 @@ function mapEventList(widget, ctx) {
|
|
|
4331
4351
|
const filters = computeListenerFilters(widget.listeners, widget.listener);
|
|
4332
4352
|
const maxItems = v.visibleEvents ?? v.visibleItems ?? 5;
|
|
4333
4353
|
return buildUnit(widget, "eventlist", {
|
|
4354
|
+
// SE event-list widgets style per-event lines via widget.text.css; the
|
|
4355
|
+
// Lumia eventlist reads font/size/color from module.css.
|
|
4356
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 18 }),
|
|
4334
4357
|
content: {
|
|
4335
4358
|
theme: v.theme ?? "simple",
|
|
4336
4359
|
direction: v.direction ?? "top",
|
|
@@ -4542,16 +4565,11 @@ function mapCredits(widget, ctx) {
|
|
|
4542
4565
|
amount: v.amount
|
|
4543
4566
|
})
|
|
4544
4567
|
},
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
color: "#ffffff",
|
|
4551
|
-
textShadow: "",
|
|
4552
|
-
textAlign: "center",
|
|
4553
|
-
background: "transparent"
|
|
4554
|
-
}
|
|
4568
|
+
// Credits renders scrolling section headers + per-event lines; the
|
|
4569
|
+
// renderer reads font/size/weight/color from module.css. Pull from SE's
|
|
4570
|
+
// text.css so an imported credits widget keeps the streamer's chosen
|
|
4571
|
+
// font and weight — defaults match the prior hardcoded fallbacks.
|
|
4572
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 30, fontWeight: "normal", textShadow: "" })
|
|
4555
4573
|
}, ctx);
|
|
4556
4574
|
}
|
|
4557
4575
|
function inferSlideshowMediaType(mime, url) {
|
|
@@ -4678,21 +4696,10 @@ function mapTimer(widget, ctx) {
|
|
|
4678
4696
|
if (v.seconds !== false) clockBits.push("{{seconds}}");
|
|
4679
4697
|
if (clockBits.length) parts.push(clockBits.join(":"));
|
|
4680
4698
|
}
|
|
4681
|
-
const seTextCss = widget.text?.css ?? {};
|
|
4682
|
-
const asStr = (v2, fallback) => typeof v2 === "string" && v2.length > 0 ? v2 : fallback;
|
|
4683
|
-
const asNum = (v2, fallback) => typeof v2 === "number" && Number.isFinite(v2) ? v2 : typeof v2 === "string" && v2.length > 0 ? v2 : fallback;
|
|
4684
|
-
const moduleCss = {
|
|
4685
|
-
lineHeight: asNum(seTextCss["line-height"], 1),
|
|
4686
|
-
fontSize: asNum(seTextCss["font-size"], 24),
|
|
4687
|
-
textAlign: asStr(seTextCss["text-align"], "center"),
|
|
4688
|
-
fontFamily: asStr(seTextCss["font-family"], "Roboto"),
|
|
4689
|
-
fontWeight: asStr(seTextCss["font-weight"], "bold"),
|
|
4690
|
-
color: asStr(seTextCss.color, "#ffffff"),
|
|
4691
|
-
textShadow: asStr(seTextCss["text-shadow"], "rgb(0, 0, 0) 1px 1px 1px"),
|
|
4692
|
-
background: "transparent"
|
|
4693
|
-
};
|
|
4694
4699
|
return buildUnit(widget, "timer", {
|
|
4695
|
-
|
|
4700
|
+
// Carry the streamer's SE text styling (font/size/color/shadow) so an
|
|
4701
|
+
// imported countdown doesn't render in Lumia's default Roboto/24px.
|
|
4702
|
+
css: mapSeTextCssToModuleCss(widget),
|
|
4696
4703
|
content: {
|
|
4697
4704
|
version: 1,
|
|
4698
4705
|
type: "countdown",
|
|
@@ -4780,14 +4787,10 @@ function mapMediaShare(widget, ctx) {
|
|
|
4780
4787
|
// `durationSeconds + grace`).
|
|
4781
4788
|
importMeta: buildImportMeta(widget, { timeLeft: v.timeLeft === true })
|
|
4782
4789
|
},
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
textShadow: "rgb(0, 0, 0) 1px 1px 1px",
|
|
4788
|
-
background: "transparent",
|
|
4789
|
-
fontSize: 18
|
|
4790
|
-
}
|
|
4790
|
+
// Lumia songrequest renders the queue list as styled text; pull SE's
|
|
4791
|
+
// widget.text.css so font/size/color carry across (defaults match the
|
|
4792
|
+
// previous hardcoded fallbacks for this widget specifically).
|
|
4793
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 18 })
|
|
4791
4794
|
}, ctx);
|
|
4792
4795
|
}
|
|
4793
4796
|
function mapKappagen(widget, ctx) {
|
|
@@ -4855,6 +4858,9 @@ function mapLeaderboardFromVariables(widget, currency, ctx) {
|
|
|
4855
4858
|
const window = v.period === "weekly" ? "week" : v.period === "monthly" ? "month" : "alltime";
|
|
4856
4859
|
const title = currency === "tips" ? "Top Tippers" : currency === "cheers" ? "Top Cheerers" : "Top Gifters";
|
|
4857
4860
|
return buildUnit(widget, "loyaltyleaderboard", {
|
|
4861
|
+
// Carry SE text styling so the leaderboard list keeps the streamer's
|
|
4862
|
+
// chosen font / size / color.
|
|
4863
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 18 }),
|
|
4858
4864
|
content: {
|
|
4859
4865
|
source: "variables",
|
|
4860
4866
|
currency,
|
|
@@ -4881,6 +4887,8 @@ function mapGiveaway(widget, ctx) {
|
|
|
4881
4887
|
const primary = v.colors?.primary ?? "#393853";
|
|
4882
4888
|
const accent = v.colors?.accent ?? "#FF4076";
|
|
4883
4889
|
return buildUnit(widget, "raffle", {
|
|
4890
|
+
// Raffle renders entrants/winner text via module.css.
|
|
4891
|
+
css: mapSeTextCssToModuleCss(widget),
|
|
4884
4892
|
content: {
|
|
4885
4893
|
version: 1,
|
|
4886
4894
|
type: "basic",
|
|
@@ -4965,6 +4973,9 @@ function isHypetrainCustomWidget(widget) {
|
|
|
4965
4973
|
function mapHypetrain(widget, ctx) {
|
|
4966
4974
|
const v = widget.variables ?? {};
|
|
4967
4975
|
return buildUnit(widget, "hypetrain", {
|
|
4976
|
+
// Hypetrain renders level / progress / contributor text — carry SE
|
|
4977
|
+
// styling so an imported hype-train widget keeps its font + accent.
|
|
4978
|
+
css: mapSeTextCssToModuleCss(widget),
|
|
4968
4979
|
content: {
|
|
4969
4980
|
// Twitch-native is the right default — SE hype-train widgets always
|
|
4970
4981
|
// reflected the Twitch native train. Users can flip to 'synthetic'
|
|
@@ -5357,6 +5368,23 @@ var GOAL_TYPES = /* @__PURE__ */ new Set([
|
|
|
5357
5368
|
"se-widget-merch-goal"
|
|
5358
5369
|
]);
|
|
5359
5370
|
var EVENTLIST_TYPES = /* @__PURE__ */ new Set(["se-widget-event-list", "se-widget-follower-recent", "se-widget-subscriber-recent", "se-widget-cheer-recent", "se-widget-tip-recent"]);
|
|
5371
|
+
var SCROLLING_RECENT_TYPES = /* @__PURE__ */ new Set([
|
|
5372
|
+
"se-widget-follower-recent",
|
|
5373
|
+
"se-widget-subscriber-recent",
|
|
5374
|
+
"se-widget-cheer-recent",
|
|
5375
|
+
"se-widget-tip-recent"
|
|
5376
|
+
]);
|
|
5377
|
+
var RECENT_TO_LATEST_FALLBACK_VAR = {
|
|
5378
|
+
"se-widget-follower-recent": "twitch_last_follower",
|
|
5379
|
+
"se-widget-subscriber-recent": "twitch_last_subscriber",
|
|
5380
|
+
"se-widget-cheer-recent": "twitch_last_bit",
|
|
5381
|
+
"se-widget-tip-recent": "latest_donator"
|
|
5382
|
+
};
|
|
5383
|
+
function isScrollingRecentWidget(widget) {
|
|
5384
|
+
if (!SCROLLING_RECENT_TYPES.has(widget.type)) return false;
|
|
5385
|
+
const scrolling = widget.text?.scrolling;
|
|
5386
|
+
return !!(scrolling && typeof scrolling === "object" && scrolling.enabled === true);
|
|
5387
|
+
}
|
|
5360
5388
|
function dispatch(widget, ctx) {
|
|
5361
5389
|
const t = widget.type;
|
|
5362
5390
|
console.log("[SE-IMPORT] dispatch widget", {
|
|
@@ -5385,6 +5413,10 @@ function dispatch(widget, ctx) {
|
|
|
5385
5413
|
if (t === "se-widget-donor-drive-alert") return { unit: mapSingleAlert(widget, "donordrive-donation", ctx), status: "direct", lumiaType: "alert" };
|
|
5386
5414
|
if (t === "se-widget-extralife-alert") return { unit: mapSingleAlert(widget, "extralife-donation", ctx), status: "direct", lumiaType: "alert" };
|
|
5387
5415
|
if (t === "se-widget-tiltify-alert") return { unit: mapSingleAlert(widget, "tiltify-campaignDonation", ctx), status: "direct", lumiaType: "alert" };
|
|
5416
|
+
if (isScrollingRecentWidget(widget)) {
|
|
5417
|
+
const fallbackVar = RECENT_TO_LATEST_FALLBACK_VAR[t] ?? "username";
|
|
5418
|
+
return { unit: mapReadout(widget, fallbackVar, ctx), status: "direct", lumiaType: "text" };
|
|
5419
|
+
}
|
|
5388
5420
|
if (EVENTLIST_TYPES.has(t)) return { unit: mapEventList(widget, ctx), status: "direct", lumiaType: "eventlist" };
|
|
5389
5421
|
if (t === "se-widget-top-tippers-list") return { unit: mapLeaderboardFromVariables(widget, "tips", ctx), status: "direct", lumiaType: "loyaltyleaderboard" };
|
|
5390
5422
|
if (t === "se-widget-top-cheerers-list") return { unit: mapLeaderboardFromVariables(widget, "cheers", ctx), status: "direct", lumiaType: "loyaltyleaderboard" };
|
package/dist/se-import.js
CHANGED
|
@@ -111,9 +111,17 @@ var YOUTUBE_CONTEXTS = {
|
|
|
111
111
|
"subscriber-week": { amount: "youtube_week_member_count", count: "youtube_week_member_count" },
|
|
112
112
|
"subscriber-month": { amount: "youtube_month_member_count", count: "youtube_month_member_count" }
|
|
113
113
|
};
|
|
114
|
+
var RECENT_TO_LATEST_LISTENER = {
|
|
115
|
+
"follower-recent": "follower-latest",
|
|
116
|
+
"subscriber-recent": "subscriber-latest",
|
|
117
|
+
"cheer-recent": "cheer-latest",
|
|
118
|
+
"tip-recent": "tip-latest",
|
|
119
|
+
"raid-recent": "raid-latest"
|
|
120
|
+
};
|
|
114
121
|
function listenerPlaceholderContext(listener, provider = "twitch") {
|
|
122
|
+
const resolved = RECENT_TO_LATEST_LISTENER[listener] ?? listener;
|
|
115
123
|
const platformTable = provider === "kick" ? KICK_CONTEXTS : provider === "youtube" ? YOUTUBE_CONTEXTS : null;
|
|
116
|
-
return platformTable?.[
|
|
124
|
+
return platformTable?.[resolved] ?? TWITCH_CONTEXTS[resolved] ?? {};
|
|
117
125
|
}
|
|
118
126
|
var SE_WIDGET_TYPE_LABELS = {
|
|
119
127
|
"subscriber-latest": "Latest subscriber",
|
|
@@ -198,8 +206,9 @@ var YOUTUBE_LISTENER_VARS = {
|
|
|
198
206
|
};
|
|
199
207
|
function listenerToLumiaVariable(listener, provider = "twitch") {
|
|
200
208
|
if (typeof listener !== "string" || !listener) return "username";
|
|
201
|
-
|
|
202
|
-
if (provider === "
|
|
209
|
+
const resolvedListener = RECENT_TO_LATEST_LISTENER[listener] ?? listener;
|
|
210
|
+
if (provider === "kick" && KICK_LISTENER_VARS[resolvedListener]) return KICK_LISTENER_VARS[resolvedListener];
|
|
211
|
+
if (provider === "youtube" && YOUTUBE_LISTENER_VARS[resolvedListener]) return YOUTUBE_LISTENER_VARS[resolvedListener];
|
|
203
212
|
const m = {
|
|
204
213
|
// Latest events
|
|
205
214
|
"follower-latest": "twitch_last_follower",
|
|
@@ -256,7 +265,7 @@ function listenerToLumiaVariable(listener, provider = "twitch") {
|
|
|
256
265
|
"cheer-alltime-top-donation": "twitch_alltime_top_cheerer_amount",
|
|
257
266
|
"cheer-alltime-top-donator": "twitch_alltime_top_cheerer"
|
|
258
267
|
};
|
|
259
|
-
return m[
|
|
268
|
+
return m[resolvedListener] ?? resolvedListener.replace(/-/g, "_");
|
|
260
269
|
}
|
|
261
270
|
function seCssToBounds(css, defaults = { width: 600, height: 200 }, canvas) {
|
|
262
271
|
let widthIsAuto = false;
|
|
@@ -387,6 +396,25 @@ function seLayoutUsesPushText(seLayout) {
|
|
|
387
396
|
|
|
388
397
|
// src/se-import/mappers/build.ts
|
|
389
398
|
import { nanoid } from "nanoid";
|
|
399
|
+
function mapSeTextCssToModuleCss(widget, defaults = {}) {
|
|
400
|
+
const seTextCss = widget.text?.css ?? {};
|
|
401
|
+
const asStr = (v, fallback) => typeof v === "string" && v.length > 0 ? v : fallback;
|
|
402
|
+
const asNumOrStr = (v, fallback) => {
|
|
403
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
404
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
405
|
+
return fallback;
|
|
406
|
+
};
|
|
407
|
+
return {
|
|
408
|
+
lineHeight: asNumOrStr(seTextCss["line-height"], defaults.lineHeight ?? 1),
|
|
409
|
+
fontSize: asNumOrStr(seTextCss["font-size"], defaults.fontSize ?? 24),
|
|
410
|
+
textAlign: asStr(seTextCss["text-align"], defaults.textAlign ?? "center"),
|
|
411
|
+
fontFamily: asStr(seTextCss["font-family"], defaults.fontFamily ?? "Roboto"),
|
|
412
|
+
fontWeight: asStr(seTextCss["font-weight"], defaults.fontWeight ?? "bold"),
|
|
413
|
+
color: asStr(seTextCss.color, defaults.color ?? "#ffffff"),
|
|
414
|
+
textShadow: asStr(seTextCss["text-shadow"], defaults.textShadow ?? "rgb(0, 0, 0) 1px 1px 1px"),
|
|
415
|
+
background: defaults.background ?? "transparent"
|
|
416
|
+
};
|
|
417
|
+
}
|
|
390
418
|
function buildUnit(widget, lumiaType, moduleExtras, ctx) {
|
|
391
419
|
const id = nanoid();
|
|
392
420
|
const defaults = LUMIA_DEFAULT_SIZES[lumiaType] ?? { width: 400, height: 400 };
|
|
@@ -883,7 +911,6 @@ function mapGoal(widget, ctx) {
|
|
|
883
911
|
const v = widget.variables ?? {};
|
|
884
912
|
const listener = v.goalListener ?? (typeof widget.listener === "string" ? widget.listener : null);
|
|
885
913
|
const charity = charityGoalVariables(widget.type);
|
|
886
|
-
const seTextCss = widget.text?.css ?? {};
|
|
887
914
|
return buildUnit(widget, "goal", {
|
|
888
915
|
content: {
|
|
889
916
|
version: 1,
|
|
@@ -926,23 +953,16 @@ function mapGoal(widget, ctx) {
|
|
|
926
953
|
simpleDesign: !!v.simpleDesign
|
|
927
954
|
})
|
|
928
955
|
},
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
textAlign: seTextCss["text-align"] ?? "center",
|
|
940
|
-
fontFamily: seTextCss["font-family"] ?? "Roboto",
|
|
941
|
-
fontWeight: seTextCss["font-weight"] ?? "bold",
|
|
942
|
-
color: seTextCss.color ?? "#ffffff",
|
|
943
|
-
textShadow: seTextCss["text-shadow"] ?? "rgb(0, 0, 0) 1px 1px 1px",
|
|
944
|
-
background: "transparent"
|
|
945
|
-
}
|
|
956
|
+
// `borderRadius` / `borderStyle` / `borderWidth` / `borderColor`
|
|
957
|
+
// used to be set on `css` too, but the Goal renderer applies its
|
|
958
|
+
// own border + borderRadius via inline `style={…}` on the .goal-bar
|
|
959
|
+
// div (see Goal/index.tsx:123,127,155) sourced from
|
|
960
|
+
// `content.border` and `content.borderRadius`. Writing them to
|
|
961
|
+
// module.css just plopped useless transparent-0px rules on the
|
|
962
|
+
// outer .overlay-module wrapper. SE charity goals commonly use
|
|
963
|
+
// 24-30px Nunito/Roboto — fontSize default of 30 mirrors the
|
|
964
|
+
// previous hardcoded fallback.
|
|
965
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 30 })
|
|
946
966
|
}, ctx);
|
|
947
967
|
}
|
|
948
968
|
|
|
@@ -1216,6 +1236,9 @@ function mapEventList(widget, ctx) {
|
|
|
1216
1236
|
const filters = computeListenerFilters(widget.listeners, widget.listener);
|
|
1217
1237
|
const maxItems = v.visibleEvents ?? v.visibleItems ?? 5;
|
|
1218
1238
|
return buildUnit(widget, "eventlist", {
|
|
1239
|
+
// SE event-list widgets style per-event lines via widget.text.css; the
|
|
1240
|
+
// Lumia eventlist reads font/size/color from module.css.
|
|
1241
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 18 }),
|
|
1219
1242
|
content: {
|
|
1220
1243
|
theme: v.theme ?? "simple",
|
|
1221
1244
|
direction: v.direction ?? "top",
|
|
@@ -1427,16 +1450,11 @@ function mapCredits(widget, ctx) {
|
|
|
1427
1450
|
amount: v.amount
|
|
1428
1451
|
})
|
|
1429
1452
|
},
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
color: "#ffffff",
|
|
1436
|
-
textShadow: "",
|
|
1437
|
-
textAlign: "center",
|
|
1438
|
-
background: "transparent"
|
|
1439
|
-
}
|
|
1453
|
+
// Credits renders scrolling section headers + per-event lines; the
|
|
1454
|
+
// renderer reads font/size/weight/color from module.css. Pull from SE's
|
|
1455
|
+
// text.css so an imported credits widget keeps the streamer's chosen
|
|
1456
|
+
// font and weight — defaults match the prior hardcoded fallbacks.
|
|
1457
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 30, fontWeight: "normal", textShadow: "" })
|
|
1440
1458
|
}, ctx);
|
|
1441
1459
|
}
|
|
1442
1460
|
function inferSlideshowMediaType(mime, url) {
|
|
@@ -1563,21 +1581,10 @@ function mapTimer(widget, ctx) {
|
|
|
1563
1581
|
if (v.seconds !== false) clockBits.push("{{seconds}}");
|
|
1564
1582
|
if (clockBits.length) parts.push(clockBits.join(":"));
|
|
1565
1583
|
}
|
|
1566
|
-
const seTextCss = widget.text?.css ?? {};
|
|
1567
|
-
const asStr = (v2, fallback) => typeof v2 === "string" && v2.length > 0 ? v2 : fallback;
|
|
1568
|
-
const asNum = (v2, fallback) => typeof v2 === "number" && Number.isFinite(v2) ? v2 : typeof v2 === "string" && v2.length > 0 ? v2 : fallback;
|
|
1569
|
-
const moduleCss = {
|
|
1570
|
-
lineHeight: asNum(seTextCss["line-height"], 1),
|
|
1571
|
-
fontSize: asNum(seTextCss["font-size"], 24),
|
|
1572
|
-
textAlign: asStr(seTextCss["text-align"], "center"),
|
|
1573
|
-
fontFamily: asStr(seTextCss["font-family"], "Roboto"),
|
|
1574
|
-
fontWeight: asStr(seTextCss["font-weight"], "bold"),
|
|
1575
|
-
color: asStr(seTextCss.color, "#ffffff"),
|
|
1576
|
-
textShadow: asStr(seTextCss["text-shadow"], "rgb(0, 0, 0) 1px 1px 1px"),
|
|
1577
|
-
background: "transparent"
|
|
1578
|
-
};
|
|
1579
1584
|
return buildUnit(widget, "timer", {
|
|
1580
|
-
|
|
1585
|
+
// Carry the streamer's SE text styling (font/size/color/shadow) so an
|
|
1586
|
+
// imported countdown doesn't render in Lumia's default Roboto/24px.
|
|
1587
|
+
css: mapSeTextCssToModuleCss(widget),
|
|
1581
1588
|
content: {
|
|
1582
1589
|
version: 1,
|
|
1583
1590
|
type: "countdown",
|
|
@@ -1665,14 +1672,10 @@ function mapMediaShare(widget, ctx) {
|
|
|
1665
1672
|
// `durationSeconds + grace`).
|
|
1666
1673
|
importMeta: buildImportMeta(widget, { timeLeft: v.timeLeft === true })
|
|
1667
1674
|
},
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
textShadow: "rgb(0, 0, 0) 1px 1px 1px",
|
|
1673
|
-
background: "transparent",
|
|
1674
|
-
fontSize: 18
|
|
1675
|
-
}
|
|
1675
|
+
// Lumia songrequest renders the queue list as styled text; pull SE's
|
|
1676
|
+
// widget.text.css so font/size/color carry across (defaults match the
|
|
1677
|
+
// previous hardcoded fallbacks for this widget specifically).
|
|
1678
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 18 })
|
|
1676
1679
|
}, ctx);
|
|
1677
1680
|
}
|
|
1678
1681
|
function mapKappagen(widget, ctx) {
|
|
@@ -1740,6 +1743,9 @@ function mapLeaderboardFromVariables(widget, currency, ctx) {
|
|
|
1740
1743
|
const window = v.period === "weekly" ? "week" : v.period === "monthly" ? "month" : "alltime";
|
|
1741
1744
|
const title = currency === "tips" ? "Top Tippers" : currency === "cheers" ? "Top Cheerers" : "Top Gifters";
|
|
1742
1745
|
return buildUnit(widget, "loyaltyleaderboard", {
|
|
1746
|
+
// Carry SE text styling so the leaderboard list keeps the streamer's
|
|
1747
|
+
// chosen font / size / color.
|
|
1748
|
+
css: mapSeTextCssToModuleCss(widget, { fontSize: 18 }),
|
|
1743
1749
|
content: {
|
|
1744
1750
|
source: "variables",
|
|
1745
1751
|
currency,
|
|
@@ -1766,6 +1772,8 @@ function mapGiveaway(widget, ctx) {
|
|
|
1766
1772
|
const primary = v.colors?.primary ?? "#393853";
|
|
1767
1773
|
const accent = v.colors?.accent ?? "#FF4076";
|
|
1768
1774
|
return buildUnit(widget, "raffle", {
|
|
1775
|
+
// Raffle renders entrants/winner text via module.css.
|
|
1776
|
+
css: mapSeTextCssToModuleCss(widget),
|
|
1769
1777
|
content: {
|
|
1770
1778
|
version: 1,
|
|
1771
1779
|
type: "basic",
|
|
@@ -1850,6 +1858,9 @@ function isHypetrainCustomWidget(widget) {
|
|
|
1850
1858
|
function mapHypetrain(widget, ctx) {
|
|
1851
1859
|
const v = widget.variables ?? {};
|
|
1852
1860
|
return buildUnit(widget, "hypetrain", {
|
|
1861
|
+
// Hypetrain renders level / progress / contributor text — carry SE
|
|
1862
|
+
// styling so an imported hype-train widget keeps its font + accent.
|
|
1863
|
+
css: mapSeTextCssToModuleCss(widget),
|
|
1853
1864
|
content: {
|
|
1854
1865
|
// Twitch-native is the right default — SE hype-train widgets always
|
|
1855
1866
|
// reflected the Twitch native train. Users can flip to 'synthetic'
|
|
@@ -2242,6 +2253,23 @@ var GOAL_TYPES = /* @__PURE__ */ new Set([
|
|
|
2242
2253
|
"se-widget-merch-goal"
|
|
2243
2254
|
]);
|
|
2244
2255
|
var EVENTLIST_TYPES = /* @__PURE__ */ new Set(["se-widget-event-list", "se-widget-follower-recent", "se-widget-subscriber-recent", "se-widget-cheer-recent", "se-widget-tip-recent"]);
|
|
2256
|
+
var SCROLLING_RECENT_TYPES = /* @__PURE__ */ new Set([
|
|
2257
|
+
"se-widget-follower-recent",
|
|
2258
|
+
"se-widget-subscriber-recent",
|
|
2259
|
+
"se-widget-cheer-recent",
|
|
2260
|
+
"se-widget-tip-recent"
|
|
2261
|
+
]);
|
|
2262
|
+
var RECENT_TO_LATEST_FALLBACK_VAR = {
|
|
2263
|
+
"se-widget-follower-recent": "twitch_last_follower",
|
|
2264
|
+
"se-widget-subscriber-recent": "twitch_last_subscriber",
|
|
2265
|
+
"se-widget-cheer-recent": "twitch_last_bit",
|
|
2266
|
+
"se-widget-tip-recent": "latest_donator"
|
|
2267
|
+
};
|
|
2268
|
+
function isScrollingRecentWidget(widget) {
|
|
2269
|
+
if (!SCROLLING_RECENT_TYPES.has(widget.type)) return false;
|
|
2270
|
+
const scrolling = widget.text?.scrolling;
|
|
2271
|
+
return !!(scrolling && typeof scrolling === "object" && scrolling.enabled === true);
|
|
2272
|
+
}
|
|
2245
2273
|
function dispatch(widget, ctx) {
|
|
2246
2274
|
const t = widget.type;
|
|
2247
2275
|
console.log("[SE-IMPORT] dispatch widget", {
|
|
@@ -2270,6 +2298,10 @@ function dispatch(widget, ctx) {
|
|
|
2270
2298
|
if (t === "se-widget-donor-drive-alert") return { unit: mapSingleAlert(widget, "donordrive-donation", ctx), status: "direct", lumiaType: "alert" };
|
|
2271
2299
|
if (t === "se-widget-extralife-alert") return { unit: mapSingleAlert(widget, "extralife-donation", ctx), status: "direct", lumiaType: "alert" };
|
|
2272
2300
|
if (t === "se-widget-tiltify-alert") return { unit: mapSingleAlert(widget, "tiltify-campaignDonation", ctx), status: "direct", lumiaType: "alert" };
|
|
2301
|
+
if (isScrollingRecentWidget(widget)) {
|
|
2302
|
+
const fallbackVar = RECENT_TO_LATEST_FALLBACK_VAR[t] ?? "username";
|
|
2303
|
+
return { unit: mapReadout(widget, fallbackVar, ctx), status: "direct", lumiaType: "text" };
|
|
2304
|
+
}
|
|
2273
2305
|
if (EVENTLIST_TYPES.has(t)) return { unit: mapEventList(widget, ctx), status: "direct", lumiaType: "eventlist" };
|
|
2274
2306
|
if (t === "se-widget-top-tippers-list") return { unit: mapLeaderboardFromVariables(widget, "tips", ctx), status: "direct", lumiaType: "loyaltyleaderboard" };
|
|
2275
2307
|
if (t === "se-widget-top-cheerers-list") return { unit: mapLeaderboardFromVariables(widget, "cheers", ctx), status: "direct", lumiaType: "loyaltyleaderboard" };
|