Skip to content

Commit eb1735e

Browse files
committed
feat(overlay-widgets): Static Image Overlay Widget Type
1 parent 4e2dd5f commit eb1735e

File tree

4 files changed

+96
-3
lines changed

4 files changed

+96
-3
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { OverlayWidgetType, IOverlayWidgetEventUtils, WidgetOverlayEvent } from "../../../../types/overlay-widgets";
2+
3+
type Settings = {
4+
filepath: string;
5+
};
6+
7+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
8+
type State = {};
9+
10+
export const image: OverlayWidgetType<Settings, State> = {
11+
id: "firebot:image",
12+
name: "Image",
13+
description: "A simple image widget that displays a static image in the overlay.",
14+
icon: "fa-image",
15+
settingsSchema: [
16+
{
17+
name: "filepath",
18+
title: "Image File",
19+
type: "filepath",
20+
default: "",
21+
fileOptions: {
22+
title: "Select an Image File",
23+
buttonLabel: "Select Image",
24+
directoryOnly: false,
25+
filters: [
26+
{ name: 'Image', extensions: ['bmp', 'gif', 'jpg', 'jpeg', 'png', 'apng', 'svg', 'webp'] },
27+
{ name: 'All Files', extensions: ['*'] }
28+
]
29+
},
30+
validation: {
31+
required: true
32+
}
33+
}
34+
],
35+
initialAspectRatio: { width: 3, height: 2 },
36+
initialState: {},
37+
supportsLivePreview: true,
38+
livePreviewState: {},
39+
resourceKeys: ["filepath"],
40+
overlayExtension: {
41+
eventHandler: (event: WidgetOverlayEvent<Settings, State>, utils: IOverlayWidgetEventUtils) => {
42+
const generateWidgetHtml = (config: typeof event["data"]["widgetConfig"]) => {
43+
const containerStyles = {
44+
"width": "100%",
45+
"height": "100%",
46+
"display": "flex",
47+
"justify-content": "center",
48+
"align-items": "center"
49+
};
50+
51+
const imageStyles = {
52+
"max-width": "100%",
53+
"max-height": "100%",
54+
"object-fit": "contain"
55+
};
56+
57+
return `
58+
<div id="image-container" style="${utils.stylesToString(containerStyles)}">
59+
${config.resourceTokens.filepath ? `<img src="http://${window.location.hostname}:7472/resource/${config.resourceTokens.filepath}" style="${utils.stylesToString(imageStyles)}" />` : ''}
60+
</div>
61+
`;
62+
};
63+
64+
utils.handleOverlayEvent(generateWidgetHtml);
65+
}
66+
}
67+
};

src/backend/overlay-widgets/builtin-types/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { counterDisplay } from "./counter-display/counter-display";
66
import { text } from "./text/text";
77
import { currentDateTime } from "./current-date-time/current-date-time";
88
import { countdownToDate } from "./countdown-to-date/countdown-to-date";
9+
import { image } from "./image/image";
910

1011
export default [
1112
progressbar,
@@ -15,5 +16,6 @@ export default [
1516
custom,
1617
customAdvanced,
1718
currentDateTime,
18-
text
19+
text,
20+
image
1921
];

src/backend/overlay-widgets/overlay-widgets-manager.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import overlayWidgetConfigManager from "./overlay-widget-config-manager";
55
import websocketServerManager from "../../server/websocket-server-manager";
66
import { wait } from "../utils";
77
import logger from "../logwrapper";
8+
import { ResourceTokenManager } from "../resource-token-manager";
89

910
type Events = {
1011
"overlay-widget-type-registered": (overlayWidgetType: OverlayWidgetType) => void;
@@ -80,10 +81,23 @@ class OverlayWidgetsManager extends TypedEmitter<Events> {
8081
await handleWidgetEvent(widgetType.onRemove);
8182
}
8283

84+
const resourceTokens = {} as Record<string, string>;
85+
if (!!widgetType.resourceKeys?.length) {
86+
for (const key of widgetType.resourceKeys) {
87+
const value = widgetConfig.settings[key];
88+
if (typeof value === "string") {
89+
resourceTokens[key] = ResourceTokenManager.storeResourcePath(value, 30);
90+
}
91+
}
92+
}
93+
8394
websocketServerManager.sendWidgetEventToOverlay({
8495
name: eventName,
8596
data: {
86-
widgetConfig,
97+
widgetConfig: {
98+
...widgetConfig,
99+
resourceTokens
100+
},
87101
widgetType,
88102
previewMode,
89103
...messageInfo

src/types/overlay-widgets.d.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ export type OverlayWidgetType<
110110
* State that is used when the widget is shown in live preview mode.
111111
*/
112112
livePreviewState?: State;
113+
114+
/**
115+
* Array of setting keys that reference local resource paths.
116+
* These properties will be automatically converted to resource tokens when sent to the overlay,
117+
*/
118+
resourceKeys?: Array<keyof Settings>;
113119
/**
114120
* Function that returns a short string representing the current state of the widget.
115121
* This is shown in the overlay widget list to give the user a quick overview of the widget's state.
@@ -185,7 +191,11 @@ type OverlayWidgetConfig<Settings = Record<string, unknown>, State = Record<stri
185191
export type WidgetOverlayEvent<Settings = Record<string, unknown>, State = Record<string, unknown>> = {
186192
name: "show" | "settings-update" | "state-update" | "message" | "remove";
187193
data: {
188-
widgetConfig: Pick<OverlayWidgetConfig<Settings, State>, "id" | "name" | "type" | "position" | "entryAnimation" | "exitAnimation" | "settings" | "state" | "overlayInstance" | "zIndex">;
194+
widgetConfig: Pick<OverlayWidgetConfig<Settings, State>, "id" | "name" | "type" | "position" | "entryAnimation" | "exitAnimation" | "settings" | "state" | "overlayInstance" | "zIndex"> & {
195+
resourceTokens: {
196+
[K in keyof Settings]: string;
197+
};
198+
};
189199
widgetType: Pick<OverlayWidgetType, "id" | "userCanConfigure">;
190200
previewMode: boolean;
191201
/**

0 commit comments

Comments
 (0)