@moraby/app-launcher 2.0.1 → 2.0.3
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/README.md +6 -0
- package/dist/index.css +1 -754
- package/dist/index.js +1 -775
- package/dist/index.mjs +1 -785
- package/package.json +1 -1
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,775 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
AppLauncher: () => AppLauncher,
|
|
24
|
-
AppSettings: () => AppSettings,
|
|
25
|
-
LocalAppLauncher: () => LocalAppLauncher,
|
|
26
|
-
default: () => AppLauncher,
|
|
27
|
-
getIcon: () => getIcon,
|
|
28
|
-
iconMap: () => iconMap
|
|
29
|
-
});
|
|
30
|
-
module.exports = __toCommonJS(index_exports);
|
|
31
|
-
|
|
32
|
-
// src/AppLauncher.tsx
|
|
33
|
-
var import_react = require("react");
|
|
34
|
-
var import_io52 = require("react-icons/io5");
|
|
35
|
-
|
|
36
|
-
// src/icons.ts
|
|
37
|
-
var import_fa = require("react-icons/fa");
|
|
38
|
-
var import_fa6 = require("react-icons/fa6");
|
|
39
|
-
var import_gr = require("react-icons/gr");
|
|
40
|
-
var import_io5 = require("react-icons/io5");
|
|
41
|
-
var import_md = require("react-icons/md");
|
|
42
|
-
var import_si = require("react-icons/si");
|
|
43
|
-
var import_ai = require("react-icons/ai");
|
|
44
|
-
var iconMap = {
|
|
45
|
-
// Business & Work
|
|
46
|
-
FaBriefcase: import_fa.FaBriefcase,
|
|
47
|
-
IoBusinessSharp: import_io5.IoBusinessSharp,
|
|
48
|
-
MdWork: import_md.MdWork,
|
|
49
|
-
FaGraduationCap: import_fa.FaGraduationCap,
|
|
50
|
-
// Security
|
|
51
|
-
MdOutlineSecurity: import_md.MdOutlineSecurity,
|
|
52
|
-
FaLock: import_fa.FaLock,
|
|
53
|
-
FaKey: import_fa.FaKey,
|
|
54
|
-
AiOutlineSecurityScan: import_ai.AiOutlineSecurityScan,
|
|
55
|
-
// Communication
|
|
56
|
-
FaEnvelope: import_fa.FaEnvelope,
|
|
57
|
-
MdEmail: import_md.MdEmail,
|
|
58
|
-
FaBell: import_fa.FaBell,
|
|
59
|
-
// Media
|
|
60
|
-
FaYoutube: import_fa.FaYoutube,
|
|
61
|
-
FaMusic: import_fa.FaMusic,
|
|
62
|
-
FaCamera: import_fa.FaCamera,
|
|
63
|
-
FaImage: import_fa.FaImage,
|
|
64
|
-
FaGamepad: import_fa.FaGamepad,
|
|
65
|
-
// Productivity
|
|
66
|
-
FaCalendarAlt: import_fa.FaCalendarAlt,
|
|
67
|
-
FaClipboard: import_fa.FaClipboard,
|
|
68
|
-
FaCalculator: import_fa.FaCalculator,
|
|
69
|
-
FaFolder: import_fa.FaFolder,
|
|
70
|
-
FaFile: import_fa.FaFile,
|
|
71
|
-
FaBookmark: import_fa.FaBookmark,
|
|
72
|
-
FaTable: import_fa.FaTable,
|
|
73
|
-
FaNewspaper: import_fa.FaNewspaper,
|
|
74
|
-
// Navigation
|
|
75
|
-
FaMapMarkerAlt: import_fa.FaMapMarkerAlt,
|
|
76
|
-
FaGlobe: import_fa.FaGlobe,
|
|
77
|
-
FaHome: import_fa.FaHome,
|
|
78
|
-
// Google
|
|
79
|
-
FaGoogle: import_fa.FaGoogle,
|
|
80
|
-
SiGoogledrive: import_si.SiGoogledrive,
|
|
81
|
-
SiGooglemeet: import_si.SiGooglemeet,
|
|
82
|
-
// Development
|
|
83
|
-
FaCode: import_fa.FaCode,
|
|
84
|
-
FaTerminal: import_fa.FaTerminal,
|
|
85
|
-
FaDatabase: import_fa.FaDatabase,
|
|
86
|
-
FaPuzzlePiece: import_fa.FaPuzzlePiece,
|
|
87
|
-
// Analytics
|
|
88
|
-
FaChartBar: import_fa.FaChartBar,
|
|
89
|
-
MdDashboard: import_md.MdDashboard,
|
|
90
|
-
MdAnalytics: import_md.MdAnalytics,
|
|
91
|
-
// Shopping
|
|
92
|
-
FaShoppingCart: import_fa.FaShoppingCart,
|
|
93
|
-
FaGift: import_fa.FaGift,
|
|
94
|
-
FaTicketSimple: import_fa6.FaTicketSimple,
|
|
95
|
-
// Travel
|
|
96
|
-
FaPlane: import_fa.FaPlane,
|
|
97
|
-
FaCar: import_fa.FaCar,
|
|
98
|
-
FaBicycle: import_fa.FaBicycle,
|
|
99
|
-
GrDeliver: import_gr.GrDeliver,
|
|
100
|
-
// Food
|
|
101
|
-
FaUtensils: import_fa.FaUtensils,
|
|
102
|
-
FaCoffee: import_fa.FaCoffee,
|
|
103
|
-
// General
|
|
104
|
-
FaRocket: import_fa.FaRocket,
|
|
105
|
-
FaUser: import_fa.FaUser,
|
|
106
|
-
FaCog: import_fa.FaCog,
|
|
107
|
-
FaHeart: import_fa.FaHeart,
|
|
108
|
-
FaStar: import_fa.FaStar,
|
|
109
|
-
IoApps: import_io5.IoApps
|
|
110
|
-
};
|
|
111
|
-
function getIcon(name) {
|
|
112
|
-
return iconMap[name] || import_fa.FaRocket;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/AppLauncher.tsx
|
|
116
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
117
|
-
function AppLauncher({
|
|
118
|
-
configUrl,
|
|
119
|
-
apps: propApps,
|
|
120
|
-
className,
|
|
121
|
-
onAppClick,
|
|
122
|
-
renderFooter
|
|
123
|
-
}) {
|
|
124
|
-
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
125
|
-
const [apps, setApps] = (0, import_react.useState)([]);
|
|
126
|
-
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
127
|
-
const [error, setError] = (0, import_react.useState)(null);
|
|
128
|
-
const containerRef = (0, import_react.useRef)(null);
|
|
129
|
-
(0, import_react.useEffect)(() => {
|
|
130
|
-
if (propApps) {
|
|
131
|
-
setApps(propApps.map(resolveApp));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
if (configUrl) {
|
|
135
|
-
setLoading(true);
|
|
136
|
-
setError(null);
|
|
137
|
-
fetch(configUrl).then((res) => {
|
|
138
|
-
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
|
139
|
-
return res.json();
|
|
140
|
-
}).then((config) => {
|
|
141
|
-
setApps(config.apps.map(resolveApp));
|
|
142
|
-
}).catch((err) => {
|
|
143
|
-
setError(err.message);
|
|
144
|
-
console.error("AppLauncher: Failed to load config", err);
|
|
145
|
-
}).finally(() => setLoading(false));
|
|
146
|
-
}
|
|
147
|
-
}, [configUrl, propApps]);
|
|
148
|
-
(0, import_react.useEffect)(() => {
|
|
149
|
-
function handleClickOutside(event) {
|
|
150
|
-
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
151
|
-
setIsOpen(false);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (isOpen) {
|
|
155
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
156
|
-
}
|
|
157
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
158
|
-
}, [isOpen]);
|
|
159
|
-
(0, import_react.useEffect)(() => {
|
|
160
|
-
function handleEscape(event) {
|
|
161
|
-
if (event.key === "Escape") setIsOpen(false);
|
|
162
|
-
}
|
|
163
|
-
if (isOpen) {
|
|
164
|
-
document.addEventListener("keydown", handleEscape);
|
|
165
|
-
}
|
|
166
|
-
return () => document.removeEventListener("keydown", handleEscape);
|
|
167
|
-
}, [isOpen]);
|
|
168
|
-
function isCustomIconUrl(icon) {
|
|
169
|
-
return icon.startsWith("/") || icon.startsWith("http");
|
|
170
|
-
}
|
|
171
|
-
function resolveApp(app) {
|
|
172
|
-
const isCustom = isCustomIconUrl(app.icon);
|
|
173
|
-
return {
|
|
174
|
-
id: app.id,
|
|
175
|
-
name: app.name,
|
|
176
|
-
url: app.url,
|
|
177
|
-
icon: isCustom ? null : getIcon(app.icon),
|
|
178
|
-
customIconUrl: isCustom ? app.icon : null,
|
|
179
|
-
color: app.color,
|
|
180
|
-
description: app.description
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
function handleAppClick(app) {
|
|
184
|
-
if (onAppClick) {
|
|
185
|
-
onAppClick({
|
|
186
|
-
id: app.id,
|
|
187
|
-
name: app.name,
|
|
188
|
-
url: app.url,
|
|
189
|
-
icon: app.customIconUrl || (app.icon?.name ?? "FaRocket"),
|
|
190
|
-
color: app.color,
|
|
191
|
-
description: app.description
|
|
192
|
-
});
|
|
193
|
-
} else {
|
|
194
|
-
window.open(app.url, "_blank", "noopener,noreferrer");
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `app-launcher ${className || ""}`, ref: containerRef, children: [
|
|
198
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
199
|
-
"button",
|
|
200
|
-
{
|
|
201
|
-
className: "app-launcher__trigger",
|
|
202
|
-
onClick: () => setIsOpen(!isOpen),
|
|
203
|
-
"aria-label": "Open app launcher",
|
|
204
|
-
"aria-expanded": isOpen,
|
|
205
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_io52.IoApps, { className: "app-launcher__trigger-icon" })
|
|
206
|
-
}
|
|
207
|
-
),
|
|
208
|
-
isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "app-launcher__dropdown", children: [
|
|
209
|
-
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "app-launcher__loading", children: "Loading..." }),
|
|
210
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "app-launcher__error", children: error }),
|
|
211
|
-
!loading && !error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "app-launcher__grid", children: apps.map((app) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
212
|
-
"button",
|
|
213
|
-
{
|
|
214
|
-
className: "app-launcher__item",
|
|
215
|
-
onClick: () => handleAppClick(app),
|
|
216
|
-
title: app.description || app.name,
|
|
217
|
-
children: [
|
|
218
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "app-launcher__icon-wrapper", children: app.customIconUrl ? (
|
|
219
|
-
// Check if it's an SVG - use mask-image for color support
|
|
220
|
-
app.customIconUrl.endsWith(".svg") ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
221
|
-
"div",
|
|
222
|
-
{
|
|
223
|
-
className: "app-launcher__icon app-launcher__icon--svg",
|
|
224
|
-
style: {
|
|
225
|
-
maskImage: `url(${app.customIconUrl})`,
|
|
226
|
-
WebkitMaskImage: `url(${app.customIconUrl})`,
|
|
227
|
-
backgroundColor: app.color === "transparent" ? "#5f6368" : app.color
|
|
228
|
-
},
|
|
229
|
-
"aria-label": app.name
|
|
230
|
-
}
|
|
231
|
-
) : (
|
|
232
|
-
// Regular image for PNG, JPG, etc.
|
|
233
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
234
|
-
"img",
|
|
235
|
-
{
|
|
236
|
-
src: app.customIconUrl,
|
|
237
|
-
alt: app.name,
|
|
238
|
-
className: "app-launcher__icon app-launcher__icon--custom"
|
|
239
|
-
}
|
|
240
|
-
)
|
|
241
|
-
)
|
|
242
|
-
) : app.icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(app.icon, { className: "app-launcher__icon", style: { color: app.color } }) : null }),
|
|
243
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "app-launcher__name", children: app.name })
|
|
244
|
-
]
|
|
245
|
-
},
|
|
246
|
-
app.id
|
|
247
|
-
)) }),
|
|
248
|
-
renderFooter && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "app-launcher__footer", children: renderFooter() })
|
|
249
|
-
] })
|
|
250
|
-
] });
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// src/AppSettings.tsx
|
|
254
|
-
var import_react4 = require("react");
|
|
255
|
-
var import_fa2 = require("react-icons/fa");
|
|
256
|
-
|
|
257
|
-
// src/AddAppForm.tsx
|
|
258
|
-
var import_react3 = require("react");
|
|
259
|
-
|
|
260
|
-
// src/IconPicker.tsx
|
|
261
|
-
var import_react2 = require("react");
|
|
262
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
263
|
-
var allIcons = Object.keys(iconMap);
|
|
264
|
-
function IconPicker({ selectedIcon, onSelect }) {
|
|
265
|
-
const [searchTerm, setSearchTerm] = (0, import_react2.useState)("");
|
|
266
|
-
const filteredIcons = allIcons.filter(
|
|
267
|
-
(name) => name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
268
|
-
);
|
|
269
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "app-launcher-icon-picker", children: [
|
|
270
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
271
|
-
"input",
|
|
272
|
-
{
|
|
273
|
-
type: "text",
|
|
274
|
-
placeholder: "Search icons...",
|
|
275
|
-
value: searchTerm,
|
|
276
|
-
onChange: (e) => setSearchTerm(e.target.value),
|
|
277
|
-
className: "app-launcher-icon-picker__search"
|
|
278
|
-
}
|
|
279
|
-
),
|
|
280
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "app-launcher-icon-picker__grid", children: filteredIcons.map((iconName) => {
|
|
281
|
-
const Icon = iconMap[iconName];
|
|
282
|
-
const isSelected = selectedIcon === iconName;
|
|
283
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
284
|
-
"button",
|
|
285
|
-
{
|
|
286
|
-
className: `app-launcher-icon-picker__button ${isSelected ? "app-launcher-icon-picker__button--selected" : ""}`,
|
|
287
|
-
onClick: () => onSelect(iconName),
|
|
288
|
-
title: iconName,
|
|
289
|
-
type: "button",
|
|
290
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { className: "app-launcher-icon-picker__icon" })
|
|
291
|
-
},
|
|
292
|
-
iconName
|
|
293
|
-
);
|
|
294
|
-
}) }),
|
|
295
|
-
filteredIcons.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "app-launcher-icon-picker__empty", children: "No icons found" })
|
|
296
|
-
] });
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// src/AddAppForm.tsx
|
|
300
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
301
|
-
var presetColors = [
|
|
302
|
-
"#4285F4",
|
|
303
|
-
// Blue
|
|
304
|
-
"#EA4335",
|
|
305
|
-
// Red
|
|
306
|
-
"#FBBC04",
|
|
307
|
-
// Yellow
|
|
308
|
-
"#34A853",
|
|
309
|
-
// Green
|
|
310
|
-
"#FF6D01",
|
|
311
|
-
// Orange
|
|
312
|
-
"#46BDC6",
|
|
313
|
-
// Teal
|
|
314
|
-
"#7B1FA2",
|
|
315
|
-
// Purple
|
|
316
|
-
"#E91E63",
|
|
317
|
-
// Pink
|
|
318
|
-
"#607D8B",
|
|
319
|
-
// Gray
|
|
320
|
-
"#795548"
|
|
321
|
-
// Brown
|
|
322
|
-
];
|
|
323
|
-
function AddAppForm({
|
|
324
|
-
initialData,
|
|
325
|
-
onSubmit,
|
|
326
|
-
onCancel,
|
|
327
|
-
submitLabel = "Add App"
|
|
328
|
-
}) {
|
|
329
|
-
const [name, setName] = (0, import_react3.useState)(initialData?.name || "");
|
|
330
|
-
const [url, setUrl] = (0, import_react3.useState)(initialData?.url || "");
|
|
331
|
-
const initialIcon = initialData?.icon || "FaRocket";
|
|
332
|
-
const isInitialCustom = initialIcon.startsWith("/") || initialIcon.startsWith("http");
|
|
333
|
-
const [iconName, setIconName] = (0, import_react3.useState)(isInitialCustom ? "FaRocket" : initialIcon);
|
|
334
|
-
const [customIconUrl, setCustomIconUrl] = (0, import_react3.useState)(isInitialCustom ? initialIcon : "");
|
|
335
|
-
const [iconMode, setIconMode] = (0, import_react3.useState)(isInitialCustom ? "custom" : "picker");
|
|
336
|
-
const [color, setColor] = (0, import_react3.useState)(initialData?.color || "#4285F4");
|
|
337
|
-
const [description, setDescription] = (0, import_react3.useState)(initialData?.description || "");
|
|
338
|
-
const [errors, setErrors] = (0, import_react3.useState)({});
|
|
339
|
-
const SelectedIcon = iconMap[iconName] || iconMap["FaRocket"];
|
|
340
|
-
const validate = () => {
|
|
341
|
-
const newErrors = {};
|
|
342
|
-
if (!name.trim()) {
|
|
343
|
-
newErrors.name = "Name is required";
|
|
344
|
-
}
|
|
345
|
-
if (!url.trim()) {
|
|
346
|
-
newErrors.url = "URL is required";
|
|
347
|
-
} else if (!url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("/")) {
|
|
348
|
-
newErrors.url = "URL must start with http://, https://, or /";
|
|
349
|
-
}
|
|
350
|
-
if (iconMode === "custom" && customIconUrl.trim()) {
|
|
351
|
-
if (!customIconUrl.startsWith("http://") && !customIconUrl.startsWith("https://") && !customIconUrl.startsWith("/")) {
|
|
352
|
-
newErrors.customIconUrl = "Icon URL must start with http://, https://, or /";
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
setErrors(newErrors);
|
|
356
|
-
return Object.keys(newErrors).length === 0;
|
|
357
|
-
};
|
|
358
|
-
const handleSubmit = (e) => {
|
|
359
|
-
e.preventDefault();
|
|
360
|
-
if (!validate()) return;
|
|
361
|
-
const finalIcon = iconMode === "custom" && customIconUrl.trim() ? customIconUrl.trim() : iconName;
|
|
362
|
-
onSubmit({
|
|
363
|
-
name: name.trim(),
|
|
364
|
-
url: url.trim(),
|
|
365
|
-
icon: finalIcon,
|
|
366
|
-
color,
|
|
367
|
-
description: description.trim() || void 0
|
|
368
|
-
});
|
|
369
|
-
};
|
|
370
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleSubmit, className: "app-launcher-form", children: [
|
|
371
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__preview", children: [
|
|
372
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "app-launcher-form__preview-icon", style: { backgroundColor: color + "20" }, children: iconMode === "custom" && customIconUrl ? customIconUrl.endsWith(".svg") ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
373
|
-
"div",
|
|
374
|
-
{
|
|
375
|
-
className: "app-launcher-form__preview-svg",
|
|
376
|
-
style: {
|
|
377
|
-
maskImage: `url(${customIconUrl})`,
|
|
378
|
-
WebkitMaskImage: `url(${customIconUrl})`,
|
|
379
|
-
backgroundColor: color === "transparent" ? "#5f6368" : color
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
383
|
-
"img",
|
|
384
|
-
{
|
|
385
|
-
src: customIconUrl,
|
|
386
|
-
alt: "Icon preview",
|
|
387
|
-
className: "app-launcher-form__preview-img"
|
|
388
|
-
}
|
|
389
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SelectedIcon, { style: { color, fontSize: 32 } }) }),
|
|
390
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "app-launcher-form__preview-name", children: name || "App Name" })
|
|
391
|
-
] }),
|
|
392
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__field", children: [
|
|
393
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { htmlFor: "app-name", className: "app-launcher-form__label", children: "Name *" }),
|
|
394
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
395
|
-
"input",
|
|
396
|
-
{
|
|
397
|
-
id: "app-name",
|
|
398
|
-
type: "text",
|
|
399
|
-
value: name,
|
|
400
|
-
onChange: (e) => setName(e.target.value),
|
|
401
|
-
placeholder: "My App",
|
|
402
|
-
className: `app-launcher-form__input ${errors.name ? "app-launcher-form__input--error" : ""}`
|
|
403
|
-
}
|
|
404
|
-
),
|
|
405
|
-
errors.name && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "app-launcher-form__error", children: errors.name })
|
|
406
|
-
] }),
|
|
407
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__field", children: [
|
|
408
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { htmlFor: "app-url", className: "app-launcher-form__label", children: "URL *" }),
|
|
409
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
410
|
-
"input",
|
|
411
|
-
{
|
|
412
|
-
id: "app-url",
|
|
413
|
-
type: "text",
|
|
414
|
-
value: url,
|
|
415
|
-
onChange: (e) => setUrl(e.target.value),
|
|
416
|
-
placeholder: "https://myapp.com or /dashboard",
|
|
417
|
-
className: `app-launcher-form__input ${errors.url ? "app-launcher-form__input--error" : ""}`
|
|
418
|
-
}
|
|
419
|
-
),
|
|
420
|
-
errors.url && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "app-launcher-form__error", children: errors.url })
|
|
421
|
-
] }),
|
|
422
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__field", children: [
|
|
423
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { htmlFor: "app-description", className: "app-launcher-form__label", children: "Description" }),
|
|
424
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
425
|
-
"input",
|
|
426
|
-
{
|
|
427
|
-
id: "app-description",
|
|
428
|
-
type: "text",
|
|
429
|
-
value: description,
|
|
430
|
-
onChange: (e) => setDescription(e.target.value),
|
|
431
|
-
placeholder: "Optional description (shown on hover)",
|
|
432
|
-
className: "app-launcher-form__input"
|
|
433
|
-
}
|
|
434
|
-
)
|
|
435
|
-
] }),
|
|
436
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__field", children: [
|
|
437
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "app-launcher-form__label", children: "Color" }),
|
|
438
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__color-picker", children: [
|
|
439
|
-
presetColors.map((presetColor) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
440
|
-
"button",
|
|
441
|
-
{
|
|
442
|
-
type: "button",
|
|
443
|
-
className: `app-launcher-form__color-button ${color === presetColor ? "app-launcher-form__color-button--selected" : ""}`,
|
|
444
|
-
style: { backgroundColor: presetColor },
|
|
445
|
-
onClick: () => setColor(presetColor),
|
|
446
|
-
title: presetColor
|
|
447
|
-
},
|
|
448
|
-
presetColor
|
|
449
|
-
)),
|
|
450
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
451
|
-
"input",
|
|
452
|
-
{
|
|
453
|
-
type: "color",
|
|
454
|
-
value: color,
|
|
455
|
-
onChange: (e) => setColor(e.target.value),
|
|
456
|
-
className: "app-launcher-form__color-input",
|
|
457
|
-
title: "Custom color"
|
|
458
|
-
}
|
|
459
|
-
)
|
|
460
|
-
] })
|
|
461
|
-
] }),
|
|
462
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__field", children: [
|
|
463
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "app-launcher-form__label", children: "Icon" }),
|
|
464
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__icon-mode", children: [
|
|
465
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
466
|
-
"button",
|
|
467
|
-
{
|
|
468
|
-
type: "button",
|
|
469
|
-
className: `app-launcher-form__mode-button ${iconMode === "picker" ? "app-launcher-form__mode-button--active" : ""}`,
|
|
470
|
-
onClick: () => setIconMode("picker"),
|
|
471
|
-
children: "Icon Picker"
|
|
472
|
-
}
|
|
473
|
-
),
|
|
474
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
475
|
-
"button",
|
|
476
|
-
{
|
|
477
|
-
type: "button",
|
|
478
|
-
className: `app-launcher-form__mode-button ${iconMode === "custom" ? "app-launcher-form__mode-button--active" : ""}`,
|
|
479
|
-
onClick: () => setIconMode("custom"),
|
|
480
|
-
children: "Custom URL"
|
|
481
|
-
}
|
|
482
|
-
)
|
|
483
|
-
] }),
|
|
484
|
-
iconMode === "picker" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IconPicker, { selectedIcon: iconName, onSelect: setIconName }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__custom-icon", children: [
|
|
485
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
486
|
-
"input",
|
|
487
|
-
{
|
|
488
|
-
id: "app-custom-icon",
|
|
489
|
-
type: "text",
|
|
490
|
-
value: customIconUrl,
|
|
491
|
-
onChange: (e) => setCustomIconUrl(e.target.value),
|
|
492
|
-
placeholder: "/icons/my-icon.svg or https://cdn.example.com/icon.svg",
|
|
493
|
-
className: `app-launcher-form__input ${errors.customIconUrl ? "app-launcher-form__input--error" : ""}`
|
|
494
|
-
}
|
|
495
|
-
),
|
|
496
|
-
errors.customIconUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "app-launcher-form__error", children: errors.customIconUrl }),
|
|
497
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "app-launcher-form__hint", children: "Enter a path from your public folder (e.g., /icons/logo.svg) or a full URL" })
|
|
498
|
-
] })
|
|
499
|
-
] }),
|
|
500
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "app-launcher-form__actions", children: [
|
|
501
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
502
|
-
"button",
|
|
503
|
-
{
|
|
504
|
-
type: "button",
|
|
505
|
-
onClick: onCancel,
|
|
506
|
-
className: "app-launcher-form__button app-launcher-form__button--cancel",
|
|
507
|
-
children: "Cancel"
|
|
508
|
-
}
|
|
509
|
-
),
|
|
510
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
511
|
-
"button",
|
|
512
|
-
{
|
|
513
|
-
type: "submit",
|
|
514
|
-
className: "app-launcher-form__button app-launcher-form__button--submit",
|
|
515
|
-
children: submitLabel
|
|
516
|
-
}
|
|
517
|
-
)
|
|
518
|
-
] })
|
|
519
|
-
] });
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// src/AppSettings.tsx
|
|
523
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
524
|
-
function AppSettings({
|
|
525
|
-
isOpen,
|
|
526
|
-
onClose,
|
|
527
|
-
apps,
|
|
528
|
-
defaultApps = [],
|
|
529
|
-
onAdd,
|
|
530
|
-
onUpdate,
|
|
531
|
-
onDelete
|
|
532
|
-
}) {
|
|
533
|
-
const [showAddForm, setShowAddForm] = (0, import_react4.useState)(false);
|
|
534
|
-
const [editingApp, setEditingApp] = (0, import_react4.useState)(null);
|
|
535
|
-
if (!isOpen) return null;
|
|
536
|
-
const handleAddSubmit = (data) => {
|
|
537
|
-
onAdd(data);
|
|
538
|
-
setShowAddForm(false);
|
|
539
|
-
};
|
|
540
|
-
const handleEditSubmit = (data) => {
|
|
541
|
-
if (editingApp) {
|
|
542
|
-
onUpdate(editingApp.id, data);
|
|
543
|
-
setEditingApp(null);
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
const handleDelete = (id) => {
|
|
547
|
-
if (confirm("Are you sure you want to delete this app?")) {
|
|
548
|
-
onDelete(id);
|
|
549
|
-
}
|
|
550
|
-
};
|
|
551
|
-
const handleExportConfig = () => {
|
|
552
|
-
const exportedApps = [
|
|
553
|
-
// User apps first (they appear at top)
|
|
554
|
-
...apps,
|
|
555
|
-
// Then default apps
|
|
556
|
-
...defaultApps.filter((da) => !apps.some((ua) => ua.id === da.id))
|
|
557
|
-
// Avoid duplicates if any
|
|
558
|
-
];
|
|
559
|
-
const config = {
|
|
560
|
-
version: "1.0",
|
|
561
|
-
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
562
|
-
apps: exportedApps
|
|
563
|
-
};
|
|
564
|
-
const blob = new Blob([JSON.stringify(config, null, 2)], { type: "application/json" });
|
|
565
|
-
const url = URL.createObjectURL(blob);
|
|
566
|
-
const a = document.createElement("a");
|
|
567
|
-
a.href = url;
|
|
568
|
-
a.download = "app-launcher-config.json";
|
|
569
|
-
document.body.appendChild(a);
|
|
570
|
-
a.click();
|
|
571
|
-
document.body.removeChild(a);
|
|
572
|
-
URL.revokeObjectURL(url);
|
|
573
|
-
};
|
|
574
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "app-settings__overlay", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__modal", onClick: (e) => e.stopPropagation(), children: [
|
|
575
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__header", children: [
|
|
576
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "app-settings__title", children: showAddForm ? "Add New App" : editingApp ? "Edit App" : "Settings" }),
|
|
577
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "app-settings__close-button", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa2.FaTimes, {}) })
|
|
578
|
-
] }),
|
|
579
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "app-settings__content", children: showAddForm ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
580
|
-
AddAppForm,
|
|
581
|
-
{
|
|
582
|
-
onSubmit: handleAddSubmit,
|
|
583
|
-
onCancel: () => setShowAddForm(false),
|
|
584
|
-
submitLabel: "Add App"
|
|
585
|
-
}
|
|
586
|
-
) : editingApp ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
587
|
-
AddAppForm,
|
|
588
|
-
{
|
|
589
|
-
initialData: editingApp,
|
|
590
|
-
onSubmit: handleEditSubmit,
|
|
591
|
-
onCancel: () => setEditingApp(null),
|
|
592
|
-
submitLabel: "Save Changes"
|
|
593
|
-
}
|
|
594
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
595
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: "app-settings__add-button", onClick: () => setShowAddForm(true), children: [
|
|
596
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa2.FaPlus, { className: "app-settings__add-icon" }),
|
|
597
|
-
"Add New App"
|
|
598
|
-
] }),
|
|
599
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__list", children: [
|
|
600
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "app-settings__section-title", children: "My Custom Apps" }),
|
|
601
|
-
apps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "app-settings__empty-message", children: 'No custom apps yet. Click "Add New App" to get started.' }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "app-settings__grid", children: apps.map((app) => {
|
|
602
|
-
const isCustom = app.icon.startsWith("/") || app.icon.startsWith("http");
|
|
603
|
-
const Icon = !isCustom ? iconMap[app.icon] || iconMap["FaRocket"] : null;
|
|
604
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__card", children: [
|
|
605
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__card-info", children: [
|
|
606
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
607
|
-
"div",
|
|
608
|
-
{
|
|
609
|
-
className: "app-settings__card-icon",
|
|
610
|
-
style: { backgroundColor: app.color + "20" },
|
|
611
|
-
children: isCustom ? app.icon.endsWith(".svg") ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
612
|
-
"div",
|
|
613
|
-
{
|
|
614
|
-
style: {
|
|
615
|
-
width: 20,
|
|
616
|
-
height: 20,
|
|
617
|
-
maskImage: `url(${app.icon})`,
|
|
618
|
-
WebkitMaskImage: `url(${app.icon})`,
|
|
619
|
-
maskSize: "contain",
|
|
620
|
-
maskRepeat: "no-repeat",
|
|
621
|
-
maskPosition: "center",
|
|
622
|
-
WebkitMaskSize: "contain",
|
|
623
|
-
WebkitMaskRepeat: "no-repeat",
|
|
624
|
-
WebkitMaskPosition: "center",
|
|
625
|
-
backgroundColor: app.color === "transparent" ? "#5f6368" : app.color
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
629
|
-
"img",
|
|
630
|
-
{
|
|
631
|
-
src: app.icon,
|
|
632
|
-
alt: app.name,
|
|
633
|
-
style: { width: 20, height: 20, objectFit: "contain" }
|
|
634
|
-
}
|
|
635
|
-
) : Icon && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { style: { color: app.color } })
|
|
636
|
-
}
|
|
637
|
-
),
|
|
638
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__card-details", children: [
|
|
639
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "app-settings__card-name", children: app.name }),
|
|
640
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "app-settings__card-url", children: app.url })
|
|
641
|
-
] })
|
|
642
|
-
] }),
|
|
643
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "app-settings__card-actions", children: [
|
|
644
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
645
|
-
"button",
|
|
646
|
-
{
|
|
647
|
-
className: "app-settings__action-button",
|
|
648
|
-
onClick: () => setEditingApp(app),
|
|
649
|
-
title: "Edit",
|
|
650
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa2.FaEdit, {})
|
|
651
|
-
}
|
|
652
|
-
),
|
|
653
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
654
|
-
"button",
|
|
655
|
-
{
|
|
656
|
-
className: "app-settings__action-button app-settings__action-button--delete",
|
|
657
|
-
onClick: () => handleDelete(app.id),
|
|
658
|
-
title: "Delete",
|
|
659
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa2.FaTrash, {})
|
|
660
|
-
}
|
|
661
|
-
)
|
|
662
|
-
] })
|
|
663
|
-
] }, app.id);
|
|
664
|
-
}) })
|
|
665
|
-
] }),
|
|
666
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: "app-settings__export-button", onClick: handleExportConfig, children: [
|
|
667
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa2.FaDownload, { className: "app-settings__export-icon" }),
|
|
668
|
-
"Export Configuration"
|
|
669
|
-
] }),
|
|
670
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "app-settings__info", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: 'Custom apps are saved in your browser. Use "Export Configuration" to share with other apps.' }) })
|
|
671
|
-
] }) })
|
|
672
|
-
] }) });
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// src/LocalAppLauncher.tsx
|
|
676
|
-
var import_react5 = require("react");
|
|
677
|
-
var import_fa3 = require("react-icons/fa");
|
|
678
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
679
|
-
var STORAGE_KEY = "app-launcher-user-apps";
|
|
680
|
-
function LocalAppLauncher({
|
|
681
|
-
defaultApps = [],
|
|
682
|
-
className,
|
|
683
|
-
mergeDefaultApps = true
|
|
684
|
-
}) {
|
|
685
|
-
const [showSettings, setShowSettings] = (0, import_react5.useState)(false);
|
|
686
|
-
const [userApps, setUserApps] = (0, import_react5.useState)([]);
|
|
687
|
-
const [isLoaded, setIsLoaded] = (0, import_react5.useState)(false);
|
|
688
|
-
(0, import_react5.useEffect)(() => {
|
|
689
|
-
if (typeof window !== "undefined") {
|
|
690
|
-
try {
|
|
691
|
-
const stored = localStorage.getItem(STORAGE_KEY);
|
|
692
|
-
if (stored) {
|
|
693
|
-
setUserApps(JSON.parse(stored));
|
|
694
|
-
}
|
|
695
|
-
} catch (e) {
|
|
696
|
-
console.error("Failed to load apps from localStorage", e);
|
|
697
|
-
}
|
|
698
|
-
setIsLoaded(true);
|
|
699
|
-
}
|
|
700
|
-
}, []);
|
|
701
|
-
const saveApps = (apps) => {
|
|
702
|
-
setUserApps(apps);
|
|
703
|
-
if (typeof window !== "undefined") {
|
|
704
|
-
localStorage.setItem(STORAGE_KEY, JSON.stringify(apps));
|
|
705
|
-
}
|
|
706
|
-
};
|
|
707
|
-
const handleAddApp = (data) => {
|
|
708
|
-
const newApp = {
|
|
709
|
-
...data,
|
|
710
|
-
id: `custom-${Date.now()}`
|
|
711
|
-
};
|
|
712
|
-
saveApps([...userApps, newApp]);
|
|
713
|
-
};
|
|
714
|
-
const handleUpdateApp = (id, updates) => {
|
|
715
|
-
saveApps(userApps.map((app) => app.id === id ? { ...app, ...updates } : app));
|
|
716
|
-
};
|
|
717
|
-
const handleDeleteApp = (id) => {
|
|
718
|
-
saveApps(userApps.filter((app) => app.id !== id));
|
|
719
|
-
};
|
|
720
|
-
const displayApps = isLoaded ? mergeDefaultApps ? [...userApps, ...defaultApps.filter((da) => !userApps.some((ua) => ua.id === da.id))] : userApps.length > 0 ? userApps : defaultApps : [];
|
|
721
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
722
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
723
|
-
AppLauncher,
|
|
724
|
-
{
|
|
725
|
-
apps: displayApps,
|
|
726
|
-
className,
|
|
727
|
-
renderFooter: () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
728
|
-
"button",
|
|
729
|
-
{
|
|
730
|
-
className: "app-launcher__footer-button",
|
|
731
|
-
style: {
|
|
732
|
-
display: "flex",
|
|
733
|
-
alignItems: "center",
|
|
734
|
-
gap: "8px",
|
|
735
|
-
width: "100%",
|
|
736
|
-
justifyContent: "center",
|
|
737
|
-
border: "none",
|
|
738
|
-
background: "transparent",
|
|
739
|
-
cursor: "pointer",
|
|
740
|
-
color: "var(--al-text-secondary)",
|
|
741
|
-
fontSize: "14px",
|
|
742
|
-
fontWeight: 500
|
|
743
|
-
},
|
|
744
|
-
onClick: () => setShowSettings(true),
|
|
745
|
-
children: [
|
|
746
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_fa3.FaCog, { style: { fontSize: "16px" } }),
|
|
747
|
-
"Settings"
|
|
748
|
-
]
|
|
749
|
-
}
|
|
750
|
-
)
|
|
751
|
-
}
|
|
752
|
-
),
|
|
753
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
754
|
-
AppSettings,
|
|
755
|
-
{
|
|
756
|
-
isOpen: showSettings,
|
|
757
|
-
onClose: () => setShowSettings(false),
|
|
758
|
-
apps: userApps,
|
|
759
|
-
defaultApps,
|
|
760
|
-
onAdd: handleAddApp,
|
|
761
|
-
onUpdate: handleUpdateApp,
|
|
762
|
-
onDelete: handleDeleteApp
|
|
763
|
-
}
|
|
764
|
-
)
|
|
765
|
-
] });
|
|
766
|
-
}
|
|
767
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
768
|
-
0 && (module.exports = {
|
|
769
|
-
AppLauncher,
|
|
770
|
-
AppSettings,
|
|
771
|
-
LocalAppLauncher,
|
|
772
|
-
getIcon,
|
|
773
|
-
iconMap
|
|
774
|
-
});
|
|
775
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";var D=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var te=Object.prototype.hasOwnProperty;var oe=(i,l)=>{for(var u in l)D(i,u,{get:l[u],enumerable:!0})},ne=(i,l,u,b)=>{if(l&&typeof l=="object"||typeof l=="function")for(let c of re(l))!te.call(i,c)&&c!==u&&D(i,c,{get:()=>l[c],enumerable:!(b=ae(l,c))||b.enumerable});return i};var ie=i=>ne(D({},"__esModule",{value:!0}),i);var le={};oe(le,{AppLauncher:()=>P,AppSettings:()=>W,LocalAppLauncher:()=>Q,default:()=>P,getIcon:()=>O,iconMap:()=>k});module.exports=ie(le);var w=require("react"),Y=require("react-icons/io5");var e=require("react-icons/fa"),$=require("react-icons/fa6"),G=require("react-icons/gr"),M=require("react-icons/io5"),A=require("react-icons/md"),U=require("react-icons/si"),q=require("react-icons/ai"),k={FaBriefcase:e.FaBriefcase,IoBusinessSharp:M.IoBusinessSharp,MdWork:A.MdWork,FaGraduationCap:e.FaGraduationCap,MdOutlineSecurity:A.MdOutlineSecurity,FaLock:e.FaLock,FaKey:e.FaKey,AiOutlineSecurityScan:q.AiOutlineSecurityScan,FaEnvelope:e.FaEnvelope,MdEmail:A.MdEmail,FaBell:e.FaBell,FaYoutube:e.FaYoutube,FaMusic:e.FaMusic,FaCamera:e.FaCamera,FaImage:e.FaImage,FaGamepad:e.FaGamepad,FaCalendarAlt:e.FaCalendarAlt,FaClipboard:e.FaClipboard,FaCalculator:e.FaCalculator,FaFolder:e.FaFolder,FaFile:e.FaFile,FaBookmark:e.FaBookmark,FaTable:e.FaTable,FaNewspaper:e.FaNewspaper,FaMapMarkerAlt:e.FaMapMarkerAlt,FaGlobe:e.FaGlobe,FaHome:e.FaHome,FaGoogle:e.FaGoogle,SiGoogledrive:U.SiGoogledrive,SiGooglemeet:U.SiGooglemeet,FaCode:e.FaCode,FaTerminal:e.FaTerminal,FaDatabase:e.FaDatabase,FaPuzzlePiece:e.FaPuzzlePiece,FaChartBar:e.FaChartBar,MdDashboard:A.MdDashboard,MdAnalytics:A.MdAnalytics,FaShoppingCart:e.FaShoppingCart,FaGift:e.FaGift,FaTicketSimple:$.FaTicketSimple,FaPlane:e.FaPlane,FaCar:e.FaCar,FaBicycle:e.FaBicycle,GrDeliver:G.GrDeliver,FaUtensils:e.FaUtensils,FaCoffee:e.FaCoffee,FaRocket:e.FaRocket,FaUser:e.FaUser,FaCog:e.FaCog,FaHeart:e.FaHeart,FaStar:e.FaStar,IoApps:M.IoApps};function O(i){return k[i]||e.FaRocket}var f=require("react/jsx-runtime");function P({configUrl:i,apps:l,className:u,onAppClick:b,renderFooter:c}){let[n,g]=(0,w.useState)(!1),[I,_]=(0,w.useState)([]),[h,x]=(0,w.useState)(!1),[F,d]=(0,w.useState)(null),C=(0,w.useRef)(null);(0,w.useEffect)(()=>{if(l){_(l.map(r));return}i&&(x(!0),d(null),fetch(i).then(a=>{if(!a.ok)throw new Error(`Failed to fetch: ${a.status}`);return a.json()}).then(a=>{_(a.apps.map(r))}).catch(a=>{d(a.message),console.error("AppLauncher: Failed to load config",a)}).finally(()=>x(!1)))},[i,l]),(0,w.useEffect)(()=>{function a(v){C.current&&!C.current.contains(v.target)&&g(!1)}return n&&document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[n]),(0,w.useEffect)(()=>{function a(v){v.key==="Escape"&&g(!1)}return n&&document.addEventListener("keydown",a),()=>document.removeEventListener("keydown",a)},[n]);function p(a){return a.startsWith("/")||a.startsWith("http")}function r(a){let v=p(a.icon);return{id:a.id,name:a.name,url:a.url,icon:v?null:O(a.icon),customIconUrl:v?a.icon:null,color:a.color,description:a.description}}function m(a){b?b({id:a.id,name:a.name,url:a.url,icon:a.customIconUrl||(a.icon?.name??"FaRocket"),color:a.color,description:a.description}):window.open(a.url,"_blank","noopener,noreferrer")}return(0,f.jsxs)("div",{className:`app-launcher ${u||""}`,ref:C,children:[(0,f.jsx)("button",{className:"app-launcher__trigger",onClick:()=>g(!n),"aria-label":"Open app launcher","aria-expanded":n,children:(0,f.jsx)(Y.IoApps,{className:"app-launcher__trigger-icon"})}),n&&(0,f.jsxs)("div",{className:"app-launcher__dropdown",children:[h&&(0,f.jsx)("div",{className:"app-launcher__loading",children:"Loading..."}),F&&(0,f.jsx)("div",{className:"app-launcher__error",children:F}),!h&&!F&&(0,f.jsx)("div",{className:"app-launcher__grid",children:I.map(a=>(0,f.jsxs)("button",{className:"app-launcher__item",onClick:()=>m(a),title:a.description||a.name,children:[(0,f.jsx)("div",{className:"app-launcher__icon-wrapper",children:a.customIconUrl?a.customIconUrl.endsWith(".svg")?(0,f.jsx)("div",{className:"app-launcher__icon app-launcher__icon--svg",style:{maskImage:`url(${a.customIconUrl})`,WebkitMaskImage:`url(${a.customIconUrl})`,backgroundColor:a.color==="transparent"?"#5f6368":a.color},"aria-label":a.name}):(0,f.jsx)("img",{src:a.customIconUrl,alt:a.name,className:"app-launcher__icon app-launcher__icon--custom"}):a.icon?(0,f.jsx)(a.icon,{className:"app-launcher__icon",style:{color:a.color}}):null}),(0,f.jsx)("span",{className:"app-launcher__name",children:a.name})]},a.id))}),c&&(0,f.jsx)("div",{className:"app-launcher__footer",children:c()})]})]})}var B=require("react"),N=require("react-icons/fa");var S=require("react");var H=require("react");var z=require("react/jsx-runtime"),pe=Object.keys(k);function J({selectedIcon:i,onSelect:l}){let[u,b]=(0,H.useState)(""),c=pe.filter(n=>n.toLowerCase().includes(u.toLowerCase()));return(0,z.jsxs)("div",{className:"app-launcher-icon-picker",children:[(0,z.jsx)("input",{type:"text",placeholder:"Search icons...",value:u,onChange:n=>b(n.target.value),className:"app-launcher-icon-picker__search"}),(0,z.jsx)("div",{className:"app-launcher-icon-picker__grid",children:c.map(n=>{let g=k[n];return(0,z.jsx)("button",{className:`app-launcher-icon-picker__button ${i===n?"app-launcher-icon-picker__button--selected":""}`,onClick:()=>l(n),title:n,type:"button",children:(0,z.jsx)(g,{className:"app-launcher-icon-picker__icon"})},n)})}),c.length===0&&(0,z.jsx)("div",{className:"app-launcher-icon-picker__empty",children:"No icons found"})]})}var t=require("react/jsx-runtime"),se=["#4285F4","#EA4335","#FBBC04","#34A853","#FF6D01","#46BDC6","#7B1FA2","#E91E63","#607D8B","#795548"];function T({initialData:i,onSubmit:l,onCancel:u,submitLabel:b="Add App"}){let[c,n]=(0,S.useState)(i?.name||""),[g,I]=(0,S.useState)(i?.url||""),_=i?.icon||"FaRocket",h=_.startsWith("/")||_.startsWith("http"),[x,F]=(0,S.useState)(h?"FaRocket":_),[d,C]=(0,S.useState)(h?_:""),[p,r]=(0,S.useState)(h?"custom":"picker"),[m,a]=(0,S.useState)(i?.color||"#4285F4"),[v,R]=(0,S.useState)(i?.description||""),[y,j]=(0,S.useState)({}),X=k[x]||k.FaRocket,Z=()=>{let s={};return c.trim()||(s.name="Name is required"),g.trim()?!g.startsWith("http://")&&!g.startsWith("https://")&&!g.startsWith("/")&&(s.url="URL must start with http://, https://, or /"):s.url="URL is required",p==="custom"&&d.trim()&&!d.startsWith("http://")&&!d.startsWith("https://")&&!d.startsWith("/")&&(s.customIconUrl="Icon URL must start with http://, https://, or /"),j(s),Object.keys(s).length===0};return(0,t.jsxs)("form",{onSubmit:s=>{if(s.preventDefault(),!Z())return;let ee=p==="custom"&&d.trim()?d.trim():x;l({name:c.trim(),url:g.trim(),icon:ee,color:m,description:v.trim()||void 0})},className:"app-launcher-form",children:[(0,t.jsxs)("div",{className:"app-launcher-form__preview",children:[(0,t.jsx)("div",{className:"app-launcher-form__preview-icon",style:{backgroundColor:m+"20"},children:p==="custom"&&d?d.endsWith(".svg")?(0,t.jsx)("div",{className:"app-launcher-form__preview-svg",style:{maskImage:`url(${d})`,WebkitMaskImage:`url(${d})`,backgroundColor:m==="transparent"?"#5f6368":m}}):(0,t.jsx)("img",{src:d,alt:"Icon preview",className:"app-launcher-form__preview-img"}):(0,t.jsx)(X,{style:{color:m,fontSize:32}})}),(0,t.jsx)("span",{className:"app-launcher-form__preview-name",children:c||"App Name"})]}),(0,t.jsxs)("div",{className:"app-launcher-form__field",children:[(0,t.jsx)("label",{htmlFor:"app-name",className:"app-launcher-form__label",children:"Name *"}),(0,t.jsx)("input",{id:"app-name",type:"text",value:c,onChange:s=>n(s.target.value),placeholder:"My App",className:`app-launcher-form__input ${y.name?"app-launcher-form__input--error":""}`}),y.name&&(0,t.jsx)("span",{className:"app-launcher-form__error",children:y.name})]}),(0,t.jsxs)("div",{className:"app-launcher-form__field",children:[(0,t.jsx)("label",{htmlFor:"app-url",className:"app-launcher-form__label",children:"URL *"}),(0,t.jsx)("input",{id:"app-url",type:"text",value:g,onChange:s=>I(s.target.value),placeholder:"https://myapp.com or /dashboard",className:`app-launcher-form__input ${y.url?"app-launcher-form__input--error":""}`}),y.url&&(0,t.jsx)("span",{className:"app-launcher-form__error",children:y.url})]}),(0,t.jsxs)("div",{className:"app-launcher-form__field",children:[(0,t.jsx)("label",{htmlFor:"app-description",className:"app-launcher-form__label",children:"Description"}),(0,t.jsx)("input",{id:"app-description",type:"text",value:v,onChange:s=>R(s.target.value),placeholder:"Optional description (shown on hover)",className:"app-launcher-form__input"})]}),(0,t.jsxs)("div",{className:"app-launcher-form__field",children:[(0,t.jsx)("label",{className:"app-launcher-form__label",children:"Color"}),(0,t.jsxs)("div",{className:"app-launcher-form__color-picker",children:[se.map(s=>(0,t.jsx)("button",{type:"button",className:`app-launcher-form__color-button ${m===s?"app-launcher-form__color-button--selected":""}`,style:{backgroundColor:s},onClick:()=>a(s),title:s},s)),(0,t.jsx)("input",{type:"color",value:m,onChange:s=>a(s.target.value),className:"app-launcher-form__color-input",title:"Custom color"})]})]}),(0,t.jsxs)("div",{className:"app-launcher-form__field",children:[(0,t.jsx)("label",{className:"app-launcher-form__label",children:"Icon"}),(0,t.jsxs)("div",{className:"app-launcher-form__icon-mode",children:[(0,t.jsx)("button",{type:"button",className:`app-launcher-form__mode-button ${p==="picker"?"app-launcher-form__mode-button--active":""}`,onClick:()=>r("picker"),children:"Icon Picker"}),(0,t.jsx)("button",{type:"button",className:`app-launcher-form__mode-button ${p==="custom"?"app-launcher-form__mode-button--active":""}`,onClick:()=>r("custom"),children:"Custom URL"})]}),p==="picker"?(0,t.jsx)(J,{selectedIcon:x,onSelect:F}):(0,t.jsxs)("div",{className:"app-launcher-form__custom-icon",children:[(0,t.jsx)("input",{id:"app-custom-icon",type:"text",value:d,onChange:s=>C(s.target.value),placeholder:"/icons/my-icon.svg or https://cdn.example.com/icon.svg",className:`app-launcher-form__input ${y.customIconUrl?"app-launcher-form__input--error":""}`}),y.customIconUrl&&(0,t.jsx)("span",{className:"app-launcher-form__error",children:y.customIconUrl}),(0,t.jsx)("p",{className:"app-launcher-form__hint",children:"Enter a path from your public folder (e.g., /icons/logo.svg) or a full URL"})]})]}),(0,t.jsxs)("div",{className:"app-launcher-form__actions",children:[(0,t.jsx)("button",{type:"button",onClick:u,className:"app-launcher-form__button app-launcher-form__button--cancel",children:"Cancel"}),(0,t.jsx)("button",{type:"submit",className:"app-launcher-form__button app-launcher-form__button--submit",children:b})]})]})}var o=require("react/jsx-runtime");function W({isOpen:i,onClose:l,apps:u,defaultApps:b=[],onAdd:c,onUpdate:n,onDelete:g}){let[I,_]=(0,B.useState)(!1),[h,x]=(0,B.useState)(null);if(!i)return null;let F=r=>{c(r),_(!1)},d=r=>{h&&(n(h.id,r),x(null))},C=r=>{confirm("Are you sure you want to delete this app?")&&g(r)},p=()=>{let r=[...u,...b.filter(y=>!u.some(j=>j.id===y.id))],m={version:"1.0",exportedAt:new Date().toISOString(),apps:r},a=new Blob([JSON.stringify(m,null,2)],{type:"application/json"}),v=URL.createObjectURL(a),R=document.createElement("a");R.href=v,R.download="app-launcher-config.json",document.body.appendChild(R),R.click(),document.body.removeChild(R),URL.revokeObjectURL(v)};return(0,o.jsx)("div",{className:"app-settings__overlay",children:(0,o.jsxs)("div",{className:"app-settings__modal",onClick:r=>r.stopPropagation(),children:[(0,o.jsxs)("div",{className:"app-settings__header",children:[(0,o.jsx)("h2",{className:"app-settings__title",children:I?"Add New App":h?"Edit App":"Settings"}),(0,o.jsx)("button",{className:"app-settings__close-button",onClick:l,"aria-label":"Close",children:(0,o.jsx)(N.FaTimes,{})})]}),(0,o.jsx)("div",{className:"app-settings__content",children:I?(0,o.jsx)(T,{onSubmit:F,onCancel:()=>_(!1),submitLabel:"Add App"}):h?(0,o.jsx)(T,{initialData:h,onSubmit:d,onCancel:()=>x(null),submitLabel:"Save Changes"}):(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)("button",{className:"app-settings__add-button",onClick:()=>_(!0),children:[(0,o.jsx)(N.FaPlus,{className:"app-settings__add-icon"}),"Add New App"]}),(0,o.jsxs)("div",{className:"app-settings__list",children:[(0,o.jsx)("h3",{className:"app-settings__section-title",children:"My Custom Apps"}),u.length===0?(0,o.jsx)("p",{className:"app-settings__empty-message",children:'No custom apps yet. Click "Add New App" to get started.'}):(0,o.jsx)("div",{className:"app-settings__grid",children:u.map(r=>{let m=r.icon.startsWith("/")||r.icon.startsWith("http"),a=m?null:k[r.icon]||k.FaRocket;return(0,o.jsxs)("div",{className:"app-settings__card",children:[(0,o.jsxs)("div",{className:"app-settings__card-info",children:[(0,o.jsx)("div",{className:"app-settings__card-icon",style:{backgroundColor:r.color+"20"},children:m?r.icon.endsWith(".svg")?(0,o.jsx)("div",{style:{width:20,height:20,maskImage:`url(${r.icon})`,WebkitMaskImage:`url(${r.icon})`,maskSize:"contain",maskRepeat:"no-repeat",maskPosition:"center",WebkitMaskSize:"contain",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",backgroundColor:r.color==="transparent"?"#5f6368":r.color}}):(0,o.jsx)("img",{src:r.icon,alt:r.name,style:{width:20,height:20,objectFit:"contain"}}):a&&(0,o.jsx)(a,{style:{color:r.color}})}),(0,o.jsxs)("div",{className:"app-settings__card-details",children:[(0,o.jsx)("span",{className:"app-settings__card-name",children:r.name}),(0,o.jsx)("span",{className:"app-settings__card-url",children:r.url})]})]}),(0,o.jsxs)("div",{className:"app-settings__card-actions",children:[(0,o.jsx)("button",{className:"app-settings__action-button",onClick:()=>x(r),title:"Edit",children:(0,o.jsx)(N.FaEdit,{})}),(0,o.jsx)("button",{className:"app-settings__action-button app-settings__action-button--delete",onClick:()=>C(r.id),title:"Delete",children:(0,o.jsx)(N.FaTrash,{})})]})]},r.id)})})]}),(0,o.jsxs)("button",{className:"app-settings__export-button",onClick:p,children:[(0,o.jsx)(N.FaDownload,{className:"app-settings__export-icon"}),"Export Configuration"]}),(0,o.jsx)("div",{className:"app-settings__info",children:(0,o.jsx)("p",{children:'Custom apps are saved in your browser. Use "Export Configuration" to share with other apps.'})})]})})]})})}var E=require("react"),V=require("react-icons/fa");var L=require("react/jsx-runtime"),K="app-launcher-user-apps";function Q({defaultApps:i=[],className:l,mergeDefaultApps:u=!0}){let[b,c]=(0,E.useState)(!1),[n,g]=(0,E.useState)([]),[I,_]=(0,E.useState)(!1);(0,E.useEffect)(()=>{if(typeof window<"u"){try{let p=localStorage.getItem(K);p&&g(JSON.parse(p))}catch(p){console.error("Failed to load apps from localStorage",p)}_(!0)}},[]);let h=p=>{g(p),typeof window<"u"&&localStorage.setItem(K,JSON.stringify(p))},x=p=>{let r={...p,id:`custom-${Date.now()}`};h([...n,r])},F=(p,r)=>{h(n.map(m=>m.id===p?{...m,...r}:m))},d=p=>{h(n.filter(r=>r.id!==p))},C=I?u?[...n,...i.filter(p=>!n.some(r=>r.id===p.id))]:n.length>0?n:i:[];return(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(P,{apps:C,className:l,renderFooter:()=>(0,L.jsxs)("button",{className:"app-launcher__footer-button",style:{display:"flex",alignItems:"center",gap:"8px",width:"100%",justifyContent:"center",border:"none",background:"transparent",cursor:"pointer",color:"var(--al-text-secondary)",fontSize:"14px",fontWeight:500},onClick:()=>c(!0),children:[(0,L.jsx)(V.FaCog,{style:{fontSize:"16px"}}),"Settings"]})}),(0,L.jsx)(W,{isOpen:b,onClose:()=>c(!1),apps:n,defaultApps:i,onAdd:x,onUpdate:F,onDelete:d})]})}0&&(module.exports={AppLauncher,AppSettings,LocalAppLauncher,getIcon,iconMap});
|