Tee Widget Launcher
A persistent launcher to manage and execute your widgets.
Code Snippet
1// ==============================================
2// 🚀 TEE WIDGET LAUNCHER
3// ==============================================
4
5const logoBase64 = "data:image/png;base64,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";
6
7// --- STATE & STORAGE ---
8let apps = await storage.get("launcher_apps");
9if (!apps) {
10 apps = [{ name: "Page Chatbot", id: "default-page-chatbot" }];
11 await storage.set("launcher_apps", apps);
12}
13let viewMode = "minimized"; // Can be "main", "add", "minimized", or "delete"
14let deletingIndex = -1;
15
16async function saveApps() {
17 await storage.set("launcher_apps", apps);
18}
19
20// --- UI VIEWS ---
21/** @returns {WidgetComponent[]} */
22function minimizedView() {
23 return [
24 { type: "image", id: "openBtn", src: logoBase64, width: "45px", height: "45px" }
25 ];
26}
27
28/** @returns {WidgetComponent[]} */
29function mainView() {
30 /** @type {WidgetComponent[]} */
31 const appCards = apps.length > 0 ? apps.map((app, idx) => ({
32 type: "row", bg: "card2", padding: "md", rounded: true, align: "center", justify: "between",
33 components: [
34 {
35 type: "column", gap: "sm",
36 components: [
37 { type: "text", text: app.name, size: "md", weight: "bold" },
38 { type: "text", text: app.id.substring(0, 20) + "…", size: "xs", color: "muted" }
39 ]
40 },
41 {
42 type: "row", gap: "sm", align: "center",justify:"end",
43 components: [
44 { type: "button", icon: "Power", id: `launch_${idx}`, variant: "ghost" },
45 { type: "button", icon: "Trash2", id: `delete_${idx}`, variant: "danger" }
46 ]
47 }
48 ]
49 })) : [
50 {
51 type: "column", align: "center", padding: "lg", gap: "sm",
52 components: [
53 { type: "image", src: logoBase64, width: "32px", height: "32px", rounded: true },
54 { type: "text", text: "No widgets yet", size: "md", weight: "medium", color: "muted", align: "center" },
55 { type: "text", text: "Add your first widget to get started.", size: "xs", color: "muted", align: "center" }
56 ]
57 }
58 ];
59
60 return [
61 {
62 type: "row", justify: "between", align: "center",
63 components: [
64 {
65 type: "row", gap: "sm", align: "center",
66 components: [
67 { type: "image", src: logoBase64, width: "24px", height: "24px", rounded: true },
68 ]
69 },
70 { type: "button", icon: "Minimize", id: "closeBtn", variant: "ghost" }
71 ]
72 },
73 { type: "divider" },
74 { type: "column", gap: "sm", scroll: true, maxHeight: "320px", components: appCards },
75 { type: "divider" },
76 { type: "button", text: "Add Widget", id: "addBtn", variant: "primary" }
77 ];
78}
79
80/** @returns {WidgetComponent[]} */
81function addView() {
82 return [
83 {
84 type: "row", align: "center", justify: "between",
85 components: [
86 { type: "image", src: logoBase64, width: "24px", height: "24px", rounded: true },
87 { type: "text", text: "Add Widget", size: "lg", weight: "bold" }
88 ]
89 },
90 { type: "divider" },
91 {
92 type: "column", gap: "md",
93 components: [
94 {
95 type: "column", gap: "sm",
96 components: [
97 { type: "text", text: "Widget Name", size: "sm", weight: "medium", color: "muted" },
98 { type: "input", id: "appName", placeholder: "e.g. Gmail Client" }
99 ]
100 },
101 {
102 type: "column", gap: "md",
103 components: [
104 { type: "text", text: "Action ID", size: "sm", weight: "medium", color: "muted" },
105 { type: "input", id: "appId", placeholder: "Paste action ID here..." }
106 ]
107 }
108 ]
109 },
110 { type: "divider" },
111 {
112 type: "row", gap: "sm", justify: "end",
113 components: [
114 { type: "button", text: "Cancel", id: "cancelAdd", variant: "ghost" },
115 { type: "button", text: "Save Widget", id: "saveApp", variant: "primary" }
116 ]
117 }
118 ];
119}
120
121/** @returns {WidgetComponent[]} */
122function deleteView() {
123 const app = apps[deletingIndex];
124 return [
125 {
126 type: "column", align: "center", padding: "lg", gap: "md",
127 components: [
128 { type: "icon", icon: "AlertTriangle", size: "lg", color: "error" },
129 { type: "text", text: "Delete Widget?", size: "lg", weight: "bold", align: "center" },
130 { type: "text", text: `Are you sure you want to remove "${app?.name}" from your launcher?`, size: "md", color: "muted", align: "center" }
131 ]
132 },
133 { type: "divider" },
134 {
135 type: "row", gap: "sm", justify: "end",
136 components: [
137 { type: "button", text: "Cancel", id: "cancelDelete", variant: "ghost" },
138 { type: "button", text: "Delete", id: "confirmDelete", variant: "danger" }
139 ]
140 }
141 ];
142}
143
144function render() {
145 if (viewMode === "minimized") {
146 widget.show(minimizedView(), "bottom-right", { hideCloseButton: true, transparent: true });
147 } else if (viewMode === "add") {
148 widget.show(addView(), "bottom-right", { hideCloseButton: true });
149 } else if (viewMode === "delete") {
150 widget.show(deleteView(), "bottom-right", { hideCloseButton: true });
151 } else {
152 widget.show(mainView(), "bottom-right", { hideCloseButton: true });
153 }
154}
155
156// --- EVENT ROUTING ---
157function bindAppListeners() {
158 apps.forEach((app, idx) => {
159 widget.on(`launch_${idx}`, "click", async () => {
160 widget.hide();
161 await actions.run(app.id);
162 render();
163 bindAppListeners();
164 });
165
166 widget.on(`delete_${idx}`, "click", async () => {
167 deletingIndex = idx;
168 viewMode = "delete";
169 render();
170 });
171 });
172}
173
174// Add/Cancel views
175widget.on("addBtn", "click", () => { viewMode = "add"; render(); });
176widget.on("cancelAdd", "click", () => { viewMode = "main"; render(); });
177
178// Delete Confirm views
179widget.on("cancelDelete", "click", () => { viewMode = "main"; render(); });
180widget.on("confirmDelete", "click", async () => {
181 if (deletingIndex >= 0 && deletingIndex < apps.length) {
182 apps.splice(deletingIndex, 1);
183 await saveApps();
184 }
185 viewMode = "main";
186 render();
187 bindAppListeners();
188});
189
190// Minimizing and Re-opening
191widget.on("closeBtn", "click", () => { viewMode = "minimized"; render(); });
192widget.on("openBtn", "click", () => { viewMode = "main"; render(); });
193
194widget.on("saveApp", "click", async (data) => {
195 const name = data.appName?.trim();
196 const id = data.appId?.trim();
197 if (name && id) {
198 apps.push({ name, id });
199 await saveApps();
200 viewMode = "main";
201 render();
202 bindAppListeners();
203 } else {
204 notify.error("Please enter both a Name and an Action ID.");
205 }
206});
207
208// --- BOOT ---
209render();
210bindAppListeners();
211await widget.waitForEvent("FOREVER_EVENT", "click");Submitted on 7/6/2026