koin.js 1.0.10 → 1.0.11
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.d.mts +1 -13
- package/dist/index.d.ts +1 -13
- package/dist/index.js +279 -216
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +282 -218
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +0 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var React2 = require('react');
|
|
4
4
|
var lucideReact = require('lucide-react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var reactDom = require('react-dom');
|
|
6
7
|
var nostalgist = require('nostalgist');
|
|
7
8
|
|
|
8
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -61,18 +62,43 @@ var ControlButton = React2.memo(function ControlButton2({
|
|
|
61
62
|
);
|
|
62
63
|
});
|
|
63
64
|
var SPEED_OPTIONS = [1, 2];
|
|
64
|
-
|
|
65
|
+
var SpeedMenu = React2.memo(function SpeedMenu2({ speed, onSpeedChange, disabled = false }) {
|
|
65
66
|
const [showMenu, setShowMenu] = React2.useState(false);
|
|
66
67
|
const buttonRef = React2__default.default.useRef(null);
|
|
67
|
-
const
|
|
68
|
-
|
|
68
|
+
const menuRef = React2__default.default.useRef(null);
|
|
69
|
+
const [menuPosition, setMenuPosition] = React2.useState({ bottom: "0px", left: "0px", transform: "translateX(-50%)" });
|
|
70
|
+
const updateMenuPosition = () => {
|
|
71
|
+
if (!buttonRef.current) return;
|
|
69
72
|
const rect = buttonRef.current.getBoundingClientRect();
|
|
70
|
-
|
|
73
|
+
setMenuPosition({
|
|
71
74
|
bottom: `${window.innerHeight - rect.top + 8}px`,
|
|
72
75
|
left: `${rect.left + rect.width / 2}px`,
|
|
73
76
|
transform: "translateX(-50%)"
|
|
74
|
-
};
|
|
77
|
+
});
|
|
75
78
|
};
|
|
79
|
+
React2.useEffect(() => {
|
|
80
|
+
if (showMenu) {
|
|
81
|
+
updateMenuPosition();
|
|
82
|
+
window.addEventListener("resize", updateMenuPosition);
|
|
83
|
+
window.addEventListener("scroll", updateMenuPosition);
|
|
84
|
+
return () => {
|
|
85
|
+
window.removeEventListener("resize", updateMenuPosition);
|
|
86
|
+
window.removeEventListener("scroll", updateMenuPosition);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}, [showMenu]);
|
|
90
|
+
React2.useEffect(() => {
|
|
91
|
+
if (!showMenu) return;
|
|
92
|
+
const handleClickOutside = (e) => {
|
|
93
|
+
const target = e.target;
|
|
94
|
+
if (buttonRef.current?.contains(target) || menuRef.current?.contains(target)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
setShowMenu(false);
|
|
98
|
+
};
|
|
99
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
100
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
101
|
+
}, [showMenu]);
|
|
76
102
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
77
103
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
78
104
|
"button",
|
|
@@ -103,36 +129,41 @@ function SpeedMenu({ speed, onSpeedChange, disabled = false }) {
|
|
|
103
129
|
]
|
|
104
130
|
}
|
|
105
131
|
),
|
|
106
|
-
showMenu &&
|
|
107
|
-
/* @__PURE__ */ jsxRuntime.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
132
|
+
showMenu && typeof document !== "undefined" && reactDom.createPortal(
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
134
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[9998]", onClick: () => setShowMenu(false) }),
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
136
|
+
"div",
|
|
137
|
+
{
|
|
138
|
+
ref: menuRef,
|
|
139
|
+
className: "fixed z-[9999] bg-black/90 backdrop-blur-md border border-white/20 rounded-lg p-1.5 shadow-xl flex flex-col gap-1 min-w-[80px]",
|
|
140
|
+
style: menuPosition,
|
|
141
|
+
children: SPEED_OPTIONS.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
142
|
+
"button",
|
|
143
|
+
{
|
|
144
|
+
onClick: () => {
|
|
145
|
+
onSpeedChange(s);
|
|
146
|
+
setShowMenu(false);
|
|
147
|
+
},
|
|
148
|
+
className: `
|
|
121
149
|
px-3 py-2 rounded text-xs font-mono font-bold text-center transition-colors
|
|
122
150
|
${speed === s ? "bg-white/20 text-white" : "hover:bg-white/10 text-gray-400 hover:text-white"}
|
|
123
151
|
`,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
152
|
+
children: [
|
|
153
|
+
s,
|
|
154
|
+
"x"
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
s
|
|
158
|
+
))
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
] }),
|
|
162
|
+
document.body
|
|
163
|
+
)
|
|
134
164
|
] });
|
|
135
|
-
}
|
|
165
|
+
});
|
|
166
|
+
var SpeedMenu_default = SpeedMenu;
|
|
136
167
|
function VolumeControl({
|
|
137
168
|
volume,
|
|
138
169
|
isMuted,
|
|
@@ -191,13 +222,72 @@ function VolumeControl({
|
|
|
191
222
|
] })
|
|
192
223
|
] });
|
|
193
224
|
}
|
|
194
|
-
|
|
195
|
-
|
|
225
|
+
var PortalTooltip = React2.memo(function PortalTooltip2({
|
|
226
|
+
content,
|
|
227
|
+
children,
|
|
228
|
+
className = "",
|
|
229
|
+
show = true,
|
|
230
|
+
tooltipClassName = "bg-black/90 text-white"
|
|
231
|
+
}) {
|
|
232
|
+
const [isHovered, setIsHovered] = React2.useState(false);
|
|
233
|
+
const containerRef = React2.useRef(null);
|
|
234
|
+
const [tooltipPosition, setTooltipPosition] = React2.useState({ bottom: "0px", left: "0px" });
|
|
235
|
+
React2.useEffect(() => {
|
|
236
|
+
if (!isHovered || !show) return;
|
|
237
|
+
const updatePosition = () => {
|
|
238
|
+
if (!containerRef.current) return;
|
|
239
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
240
|
+
setTooltipPosition({
|
|
241
|
+
bottom: `${window.innerHeight - rect.top + 8}px`,
|
|
242
|
+
left: `${rect.left + rect.width / 2}px`
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
updatePosition();
|
|
246
|
+
window.addEventListener("resize", updatePosition);
|
|
247
|
+
window.addEventListener("scroll", updatePosition);
|
|
248
|
+
return () => {
|
|
249
|
+
window.removeEventListener("resize", updatePosition);
|
|
250
|
+
window.removeEventListener("scroll", updatePosition);
|
|
251
|
+
};
|
|
252
|
+
}, [isHovered, show]);
|
|
253
|
+
if (!show) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
196
254
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
197
|
-
|
|
198
|
-
|
|
255
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
256
|
+
"div",
|
|
257
|
+
{
|
|
258
|
+
ref: containerRef,
|
|
259
|
+
onMouseEnter: () => setIsHovered(true),
|
|
260
|
+
onMouseLeave: () => setIsHovered(false),
|
|
261
|
+
className,
|
|
262
|
+
children
|
|
263
|
+
}
|
|
264
|
+
),
|
|
265
|
+
isHovered && typeof document !== "undefined" && reactDom.createPortal(
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
267
|
+
"div",
|
|
268
|
+
{
|
|
269
|
+
className: `fixed px-2 py-1 text-xs rounded whitespace-nowrap z-[9999] ${tooltipClassName}`,
|
|
270
|
+
style: { ...tooltipPosition, transform: "translateX(-50%)" },
|
|
271
|
+
children: content
|
|
272
|
+
}
|
|
273
|
+
),
|
|
274
|
+
document.body
|
|
275
|
+
)
|
|
199
276
|
] });
|
|
200
|
-
}
|
|
277
|
+
});
|
|
278
|
+
var HardcoreTooltip = React2.memo(function HardcoreTooltip2({ show, message = "Disabled in Hardcore mode", children }) {
|
|
279
|
+
if (!show) return children ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children }) : null;
|
|
280
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
281
|
+
PortalTooltip,
|
|
282
|
+
{
|
|
283
|
+
content: message,
|
|
284
|
+
show,
|
|
285
|
+
tooltipClassName: "bg-amber-500/90 text-black",
|
|
286
|
+
children
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
var HardcoreTooltip_default = HardcoreTooltip;
|
|
201
291
|
|
|
202
292
|
// src/locales/en.ts
|
|
203
293
|
var en = {
|
|
@@ -495,33 +585,40 @@ var PlaybackControls = React2.memo(function PlaybackControls2({
|
|
|
495
585
|
systemColor
|
|
496
586
|
}
|
|
497
587
|
),
|
|
498
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
499
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
588
|
+
/* @__PURE__ */ jsxRuntime.jsx(SpeedMenu_default, { speed, onSpeedChange, disabled }),
|
|
589
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
590
|
+
PortalTooltip,
|
|
591
|
+
{
|
|
592
|
+
content: t.common.playToEnableRewind,
|
|
593
|
+
show: hardcoreRestrictions?.canUseRewind !== false && !hasRewindHistory,
|
|
594
|
+
className: "relative group",
|
|
595
|
+
children: [
|
|
596
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
597
|
+
ControlButton,
|
|
598
|
+
{
|
|
599
|
+
onMouseDown: hasRewindHistory && hardcoreRestrictions?.canUseRewind !== false ? onRewindStart : void 0,
|
|
600
|
+
onMouseUp: hasRewindHistory && hardcoreRestrictions?.canUseRewind !== false ? onRewindStop : void 0,
|
|
601
|
+
onMouseLeave: hasRewindHistory && hardcoreRestrictions?.canUseRewind !== false ? onRewindStop : void 0,
|
|
602
|
+
onTouchStart: hasRewindHistory && hardcoreRestrictions?.canUseRewind !== false ? onRewindStart : void 0,
|
|
603
|
+
onTouchEnd: hasRewindHistory && hardcoreRestrictions?.canUseRewind !== false ? onRewindStop : void 0,
|
|
604
|
+
icon: lucideReact.Rewind,
|
|
605
|
+
label: t.controls.rewind,
|
|
606
|
+
active: isRewinding,
|
|
607
|
+
disabled: disabled || !hasRewindHistory || hardcoreRestrictions?.canUseRewind === false,
|
|
608
|
+
systemColor
|
|
609
|
+
}
|
|
610
|
+
),
|
|
611
|
+
hasRewindHistory && !isRewinding && hardcoreRestrictions?.canUseRewind !== false && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 rounded-lg animate-pulse pointer-events-none", style: { backgroundColor: `${systemColor}20` } }),
|
|
612
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
613
|
+
HardcoreTooltip_default,
|
|
614
|
+
{
|
|
615
|
+
show: hardcoreRestrictions?.canUseRewind === false,
|
|
616
|
+
message: hardcoreRestrictions?.isHardcore ? t.common.disabledInHardcore : t.common.notSupported
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
),
|
|
525
622
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-8 bg-white/10 mx-1" }),
|
|
526
623
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
527
624
|
VolumeControl,
|
|
@@ -747,7 +844,7 @@ var SaveLoadControls = React2.memo(function SaveLoadControls2({
|
|
|
747
844
|
}
|
|
748
845
|
),
|
|
749
846
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
750
|
-
|
|
847
|
+
HardcoreTooltip_default,
|
|
751
848
|
{
|
|
752
849
|
show: hardcoreRestrictions?.canUseSaveStates === false,
|
|
753
850
|
message: hardcoreRestrictions?.isHardcore ? t.common.disabledInHardcore : t.common.notSupported
|
|
@@ -766,7 +863,7 @@ var SaveLoadControls = React2.memo(function SaveLoadControls2({
|
|
|
766
863
|
}
|
|
767
864
|
),
|
|
768
865
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
769
|
-
|
|
866
|
+
HardcoreTooltip_default,
|
|
770
867
|
{
|
|
771
868
|
show: hardcoreRestrictions?.canUseSaveStates === false,
|
|
772
869
|
message: hardcoreRestrictions?.isHardcore ? t.common.disabledInHardcore : t.common.notSupported
|
|
@@ -824,17 +921,41 @@ var ShaderDropdown = React2.memo(function ShaderDropdown2({
|
|
|
824
921
|
}) {
|
|
825
922
|
const [isOpen, setIsOpen] = React2.useState(false);
|
|
826
923
|
const [pendingShader, setPendingShader] = React2.useState(null);
|
|
827
|
-
const
|
|
924
|
+
const buttonRef = React2.useRef(null);
|
|
925
|
+
const menuRef = React2.useRef(null);
|
|
926
|
+
const [dropdownPosition, setDropdownPosition] = React2.useState({ bottom: "0px", left: "0px" });
|
|
927
|
+
const updateDropdownPosition = () => {
|
|
928
|
+
if (!buttonRef.current) return;
|
|
929
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
930
|
+
setDropdownPosition({
|
|
931
|
+
bottom: `${window.innerHeight - rect.top + 8}px`,
|
|
932
|
+
left: `${rect.left}px`
|
|
933
|
+
});
|
|
934
|
+
};
|
|
828
935
|
React2.useEffect(() => {
|
|
936
|
+
if (isOpen) {
|
|
937
|
+
updateDropdownPosition();
|
|
938
|
+
window.addEventListener("resize", updateDropdownPosition);
|
|
939
|
+
window.addEventListener("scroll", updateDropdownPosition);
|
|
940
|
+
return () => {
|
|
941
|
+
window.removeEventListener("resize", updateDropdownPosition);
|
|
942
|
+
window.removeEventListener("scroll", updateDropdownPosition);
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
}, [isOpen]);
|
|
946
|
+
React2.useEffect(() => {
|
|
947
|
+
if (!isOpen) return;
|
|
829
948
|
const handleClickOutside = (e) => {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
949
|
+
const target = e.target;
|
|
950
|
+
if (buttonRef.current?.contains(target) || menuRef.current?.contains(target)) {
|
|
951
|
+
return;
|
|
833
952
|
}
|
|
953
|
+
setIsOpen(false);
|
|
954
|
+
setPendingShader(null);
|
|
834
955
|
};
|
|
835
956
|
document.addEventListener("mousedown", handleClickOutside);
|
|
836
957
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
837
|
-
}, []);
|
|
958
|
+
}, [isOpen]);
|
|
838
959
|
const currentLabel = QUICK_PRESETS.find((p) => p.id === currentShader)?.label || "Custom";
|
|
839
960
|
if (!onShaderChange) return null;
|
|
840
961
|
const handleSelect = (id) => {
|
|
@@ -859,10 +980,11 @@ var ShaderDropdown = React2.memo(function ShaderDropdown2({
|
|
|
859
980
|
const cancelRestart = () => {
|
|
860
981
|
setPendingShader(null);
|
|
861
982
|
};
|
|
862
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
983
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative hidden sm:block", children: [
|
|
863
984
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
864
985
|
"button",
|
|
865
986
|
{
|
|
987
|
+
ref: buttonRef,
|
|
866
988
|
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
867
989
|
disabled,
|
|
868
990
|
className: `flex items-center gap-1.5 px-2 py-1.5 rounded-lg transition-all duration-200 hover:bg-white/10 ${disabled ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
@@ -874,52 +996,60 @@ var ShaderDropdown = React2.memo(function ShaderDropdown2({
|
|
|
874
996
|
]
|
|
875
997
|
}
|
|
876
998
|
),
|
|
877
|
-
isOpen &&
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
] }),
|
|
890
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-white/60", children: "Shader change requires game restart. Your progress since last save will be lost." }),
|
|
891
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 pt-1", children: [
|
|
892
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
893
|
-
"button",
|
|
894
|
-
{
|
|
895
|
-
onClick: confirmRestart,
|
|
896
|
-
className: "flex-1 px-2 py-1 text-xs font-bold rounded bg-orange-500/20 text-orange-400 hover:bg-orange-500/30",
|
|
897
|
-
children: "Restart"
|
|
898
|
-
}
|
|
899
|
-
),
|
|
900
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
901
|
-
"button",
|
|
902
|
-
{
|
|
903
|
-
onClick: cancelRestart,
|
|
904
|
-
className: "flex-1 px-2 py-1 text-xs font-bold rounded bg-white/10 text-white/60 hover:bg-white/20",
|
|
905
|
-
children: "Cancel"
|
|
906
|
-
}
|
|
907
|
-
)
|
|
908
|
-
] })
|
|
909
|
-
] }) : (
|
|
910
|
-
// Shader list
|
|
911
|
-
QUICK_PRESETS.map(({ id, label }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
912
|
-
"button",
|
|
913
|
-
{
|
|
914
|
-
onClick: () => handleSelect(id),
|
|
915
|
-
className: `w-full px-3 py-1.5 text-left text-xs font-medium transition-colors ${currentShader === id ? "text-white" : "text-white/70 hover:bg-white/10"}`,
|
|
916
|
-
style: currentShader === id ? { backgroundColor: `${systemColor}30`, color: systemColor } : void 0,
|
|
917
|
-
children: label
|
|
999
|
+
isOpen && typeof document !== "undefined" && reactDom.createPortal(
|
|
1000
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1001
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[9998]", onClick: () => setIsOpen(false) }),
|
|
1002
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1003
|
+
"div",
|
|
1004
|
+
{
|
|
1005
|
+
ref: menuRef,
|
|
1006
|
+
className: "fixed py-1 rounded-lg shadow-xl z-[9999] min-w-[160px]",
|
|
1007
|
+
style: {
|
|
1008
|
+
backgroundColor: "rgba(0, 0, 0, 0.95)",
|
|
1009
|
+
border: `1px solid ${systemColor}40`,
|
|
1010
|
+
...dropdownPosition
|
|
918
1011
|
},
|
|
919
|
-
|
|
920
|
-
|
|
1012
|
+
children: pendingShader !== null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 space-y-2", children: [
|
|
1013
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-orange-400", children: [
|
|
1014
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { size: 14 }),
|
|
1015
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold", children: "Restart Required" })
|
|
1016
|
+
] }),
|
|
1017
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-white/60", children: "Shader change requires game restart. Your progress since last save will be lost." }),
|
|
1018
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 pt-1", children: [
|
|
1019
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1020
|
+
"button",
|
|
1021
|
+
{
|
|
1022
|
+
onClick: confirmRestart,
|
|
1023
|
+
className: "flex-1 px-2 py-1 text-xs font-bold rounded bg-orange-500/20 text-orange-400 hover:bg-orange-500/30",
|
|
1024
|
+
children: "Restart"
|
|
1025
|
+
}
|
|
1026
|
+
),
|
|
1027
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
|
+
"button",
|
|
1029
|
+
{
|
|
1030
|
+
onClick: cancelRestart,
|
|
1031
|
+
className: "flex-1 px-2 py-1 text-xs font-bold rounded bg-white/10 text-white/60 hover:bg-white/20",
|
|
1032
|
+
children: "Cancel"
|
|
1033
|
+
}
|
|
1034
|
+
)
|
|
1035
|
+
] })
|
|
1036
|
+
] }) : (
|
|
1037
|
+
// Shader list
|
|
1038
|
+
QUICK_PRESETS.map(({ id, label }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1039
|
+
"button",
|
|
1040
|
+
{
|
|
1041
|
+
onClick: () => handleSelect(id),
|
|
1042
|
+
className: `w-full px-3 py-1.5 text-left text-xs font-medium transition-colors ${currentShader === id ? "text-white" : "text-white/70 hover:bg-white/10"}`,
|
|
1043
|
+
style: currentShader === id ? { backgroundColor: `${systemColor}30`, color: systemColor } : void 0,
|
|
1044
|
+
children: label
|
|
1045
|
+
},
|
|
1046
|
+
id
|
|
1047
|
+
))
|
|
1048
|
+
)
|
|
1049
|
+
}
|
|
921
1050
|
)
|
|
922
|
-
}
|
|
1051
|
+
] }),
|
|
1052
|
+
document.body
|
|
923
1053
|
)
|
|
924
1054
|
] });
|
|
925
1055
|
});
|
|
@@ -936,41 +1066,48 @@ function RAButton({
|
|
|
936
1066
|
const t = useKoinTranslation();
|
|
937
1067
|
const title = isGameFound ? `${t.retroAchievements.title} (${achievementCount} achievements)` : isConnected ? t.retroAchievements.connected : t.retroAchievements.title;
|
|
938
1068
|
const tooltip = isIdentifying ? t.retroAchievements.identifying : isGameFound ? t.retroAchievements.achievementsAvailable.replace("{{count}}", achievementCount.toString()) : isConnected ? t.retroAchievements.gameNotSupported : t.retroAchievements.connect;
|
|
939
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1069
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1070
|
+
PortalTooltip,
|
|
1071
|
+
{
|
|
1072
|
+
content: tooltip,
|
|
1073
|
+
className: `relative group ${className}`,
|
|
1074
|
+
tooltipClassName: "bg-gray-900/95 text-white border border-white/10",
|
|
1075
|
+
children: [
|
|
1076
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1077
|
+
"button",
|
|
1078
|
+
{
|
|
1079
|
+
onClick,
|
|
1080
|
+
disabled,
|
|
1081
|
+
className: `
|
|
946
1082
|
group relative flex flex-col items-center gap-1 px-3 py-2 rounded-lg
|
|
947
1083
|
transition-all duration-200 disabled:opacity-40 disabled:cursor-not-allowed
|
|
948
1084
|
select-none
|
|
949
1085
|
${isGameFound ? "bg-gradient-to-b from-yellow-500/30 to-orange-500/20 text-yellow-400 ring-1 ring-yellow-500/50 shadow-[0_0_12px_rgba(234,179,8,0.3)]" : isConnected ? "bg-yellow-500/10 text-yellow-400/70 ring-1 ring-yellow-500/30" : "hover:bg-white/10 text-gray-400 hover:text-white"}
|
|
950
1086
|
`,
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1087
|
+
title,
|
|
1088
|
+
children: [
|
|
1089
|
+
isIdentifying ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 20, className: "animate-spin text-yellow-400" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1090
|
+
lucideReact.Trophy,
|
|
1091
|
+
{
|
|
1092
|
+
size: 20,
|
|
1093
|
+
className: `
|
|
958
1094
|
transition-all group-hover:scale-110
|
|
959
1095
|
${isGameFound ? "drop-shadow-[0_0_8px_rgba(234,179,8,0.7)] text-yellow-400" : ""}
|
|
960
1096
|
${isConnected && !isGameFound ? "opacity-70" : ""}
|
|
961
1097
|
`
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1098
|
+
}
|
|
1099
|
+
),
|
|
1100
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] font-bold uppercase tracking-wider opacity-70", children: isIdentifying ? "..." : isGameFound ? achievementCount : "RA" })
|
|
1101
|
+
]
|
|
1102
|
+
}
|
|
1103
|
+
),
|
|
1104
|
+
isConnected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `
|
|
969
1105
|
absolute -top-1 -right-1 w-3 h-3 rounded-full border-2 border-black
|
|
970
1106
|
${isGameFound ? "bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.8)]" : "bg-yellow-500 shadow-[0_0_6px_rgba(234,179,8,0.6)]"}
|
|
971
|
-
`, children: isGameFound && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-green-400 rounded-full animate-ping opacity-50" }) })
|
|
972
|
-
|
|
973
|
-
|
|
1107
|
+
`, children: isGameFound && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-green-400 rounded-full animate-ping opacity-50" }) })
|
|
1108
|
+
]
|
|
1109
|
+
}
|
|
1110
|
+
);
|
|
974
1111
|
}
|
|
975
1112
|
var SettingsControls = React2.memo(function SettingsControls2({
|
|
976
1113
|
onFullscreen,
|
|
@@ -1062,7 +1199,7 @@ var SettingsControls = React2.memo(function SettingsControls2({
|
|
|
1062
1199
|
}
|
|
1063
1200
|
),
|
|
1064
1201
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1065
|
-
|
|
1202
|
+
HardcoreTooltip_default,
|
|
1066
1203
|
{
|
|
1067
1204
|
show: hardcoreRestrictions?.canUseCheats === false,
|
|
1068
1205
|
message: hardcoreRestrictions?.isHardcore ? t.common.disabledInHardcore : t.common.notSupported
|
|
@@ -9340,6 +9477,8 @@ function AchievementPopup({
|
|
|
9340
9477
|
}
|
|
9341
9478
|
);
|
|
9342
9479
|
}
|
|
9480
|
+
|
|
9481
|
+
// src/lib/shader-presets.ts
|
|
9343
9482
|
var SHADER_PRESETS = [
|
|
9344
9483
|
{ id: "", name: "None", description: "No shader - sharp pixels" },
|
|
9345
9484
|
{ id: "crt/crt-lottes", name: "CRT Lottes", description: "High-quality arcade monitor look" },
|
|
@@ -9352,81 +9491,6 @@ var SHADER_PRESETS = [
|
|
|
9352
9491
|
{ id: "handheld/lcd-grid-v2", name: "LCD Grid", description: "Game Boy style LCD effect" },
|
|
9353
9492
|
{ id: "scanlines", name: "Scanlines", description: "Simple horizontal scanlines" }
|
|
9354
9493
|
];
|
|
9355
|
-
var ShaderSelector = React2.memo(function ShaderSelector2({
|
|
9356
|
-
currentShader,
|
|
9357
|
-
onShaderChange,
|
|
9358
|
-
disabled = false,
|
|
9359
|
-
systemColor = "#00FF41"
|
|
9360
|
-
}) {
|
|
9361
|
-
const [isOpen, setIsOpen] = React2.useState(false);
|
|
9362
|
-
const dropdownRef = React2.useRef(null);
|
|
9363
|
-
React2.useEffect(() => {
|
|
9364
|
-
const handleClickOutside = (e) => {
|
|
9365
|
-
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
9366
|
-
setIsOpen(false);
|
|
9367
|
-
}
|
|
9368
|
-
};
|
|
9369
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
9370
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
9371
|
-
}, []);
|
|
9372
|
-
const currentPreset = SHADER_PRESETS.find((p) => p.id === currentShader) || SHADER_PRESETS[0];
|
|
9373
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: dropdownRef, className: "relative", children: [
|
|
9374
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9375
|
-
"button",
|
|
9376
|
-
{
|
|
9377
|
-
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
9378
|
-
disabled,
|
|
9379
|
-
className: "flex items-center gap-2 px-3 py-2 rounded text-sm font-medium transition-all",
|
|
9380
|
-
style: {
|
|
9381
|
-
backgroundColor: currentShader ? `${systemColor}20` : "rgba(255,255,255,0.1)",
|
|
9382
|
-
color: currentShader ? systemColor : "rgba(255,255,255,0.7)",
|
|
9383
|
-
border: `1px solid ${currentShader ? systemColor : "rgba(255,255,255,0.2)"}`
|
|
9384
|
-
},
|
|
9385
|
-
children: [
|
|
9386
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { size: 16 }),
|
|
9387
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: currentPreset.name }),
|
|
9388
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 14, className: `transition-transform ${isOpen ? "rotate-180" : ""}` })
|
|
9389
|
-
]
|
|
9390
|
-
}
|
|
9391
|
-
),
|
|
9392
|
-
isOpen && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9393
|
-
"div",
|
|
9394
|
-
{
|
|
9395
|
-
className: "absolute bottom-full left-0 mb-2 w-56 bg-black/95 border border-white/20 rounded-lg shadow-xl overflow-hidden z-50",
|
|
9396
|
-
style: { backdropFilter: "blur(8px)" },
|
|
9397
|
-
children: [
|
|
9398
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b border-white/10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-bold text-white/60 uppercase tracking-wide", children: "Video Shader" }) }),
|
|
9399
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-64 overflow-y-auto", children: SHADER_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9400
|
-
"button",
|
|
9401
|
-
{
|
|
9402
|
-
onClick: () => {
|
|
9403
|
-
onShaderChange(preset.id);
|
|
9404
|
-
setIsOpen(false);
|
|
9405
|
-
},
|
|
9406
|
-
className: "w-full px-3 py-2 text-left hover:bg-white/10 transition-colors flex flex-col gap-0.5",
|
|
9407
|
-
style: {
|
|
9408
|
-
backgroundColor: currentShader === preset.id ? `${systemColor}20` : void 0
|
|
9409
|
-
},
|
|
9410
|
-
children: [
|
|
9411
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9412
|
-
"span",
|
|
9413
|
-
{
|
|
9414
|
-
className: "text-sm font-medium",
|
|
9415
|
-
style: { color: currentShader === preset.id ? systemColor : "white" },
|
|
9416
|
-
children: preset.name
|
|
9417
|
-
}
|
|
9418
|
-
),
|
|
9419
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-white/50", children: preset.description })
|
|
9420
|
-
]
|
|
9421
|
-
},
|
|
9422
|
-
preset.id
|
|
9423
|
-
)) })
|
|
9424
|
-
]
|
|
9425
|
-
}
|
|
9426
|
-
)
|
|
9427
|
-
] });
|
|
9428
|
-
});
|
|
9429
|
-
var ShaderSelector_default = ShaderSelector;
|
|
9430
9494
|
var SHORTCUTS = [
|
|
9431
9495
|
{ key: "F1", description: "Help" },
|
|
9432
9496
|
{ key: "F3", description: "FPS Overlay" },
|
|
@@ -9508,7 +9572,6 @@ exports.STICK_BUTTONS = STICK_BUTTONS;
|
|
|
9508
9572
|
exports.SUPPORTED_EXTENSIONS = SUPPORTED_EXTENSIONS;
|
|
9509
9573
|
exports.SYSTEMS = SYSTEMS;
|
|
9510
9574
|
exports.SYSTEM_BUTTONS = SYSTEM_BUTTONS;
|
|
9511
|
-
exports.ShaderSelector = ShaderSelector_default;
|
|
9512
9575
|
exports.ShortcutsReference = ShortcutsReference_default;
|
|
9513
9576
|
exports.TRIGGER_BUTTONS = TRIGGER_BUTTONS;
|
|
9514
9577
|
exports.ToastContainer = ToastContainer;
|