pinokiod 3.91.0 → 3.93.0
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/package.json +1 -1
- package/server/public/common.js +142 -1
package/package.json
CHANGED
package/server/public/common.js
CHANGED
|
@@ -29,6 +29,43 @@ async function uploadCapture(blob, filename) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
class ScreenCaptureModal {
|
|
32
|
+
static ensureSavedModalStyles() {
|
|
33
|
+
if (document.querySelector('link[href="/urldropdown.css"]')) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (document.querySelector('style[data-capture-modal-styles="true"]')) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const style = document.createElement('style');
|
|
40
|
+
style.type = 'text/css';
|
|
41
|
+
style.dataset.captureModalStyles = 'true';
|
|
42
|
+
style.textContent = `
|
|
43
|
+
.modal-overlay{position:fixed;inset:0;padding:24px;display:flex;align-items:center;justify-content:center;z-index:9999;opacity:0;visibility:hidden;pointer-events:none;transition:opacity 160ms ease,visibility 0s linear 160ms;}
|
|
44
|
+
.modal-overlay.is-visible{opacity:1;visibility:visible;pointer-events:auto;transition-delay:0s;}
|
|
45
|
+
@media (prefers-reduced-motion: reduce){.modal-overlay{transition:none;}.capture-modal{animation:none;}}
|
|
46
|
+
.capture-modal-overlay{background:rgba(15,23,42,0.45);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);}
|
|
47
|
+
.capture-modal{width:min(360px,calc(100% - 32px));padding:28px 26px;border-radius:18px;background:rgba(255,255,255,0.92);border:1px solid rgba(15,23,42,0.08);box-shadow:0 30px 80px rgba(15,23,42,0.35);display:flex;flex-direction:column;gap:18px;text-align:center;}
|
|
48
|
+
body.dark .capture-modal{background:rgba(15,23,42,0.9);border-color:rgba(148,163,184,0.24);color:rgba(226,232,240,0.96);box-shadow:0 34px 88px rgba(2,6,20,0.82);}
|
|
49
|
+
.capture-modal-title{font-size:20px;font-weight:600;letter-spacing:-0.01em;color:rgba(15,23,42,0.92);}
|
|
50
|
+
body.dark .capture-modal-title{color:inherit;}
|
|
51
|
+
.capture-modal-description{font-size:14px;line-height:1.5;color:rgba(71,85,105,0.82);}
|
|
52
|
+
body.dark .capture-modal-description{color:rgba(203,213,225,0.88);}
|
|
53
|
+
.capture-modal-actions{display:flex;justify-content:center;gap:12px;}
|
|
54
|
+
.capture-modal-button{padding:10px 20px;border-radius:999px;border:1px solid transparent;font-size:14px;font-weight:600;cursor:pointer;transition:background 0.18s ease,color 0.18s ease,box-shadow 0.18s ease,transform 0.12s ease;}
|
|
55
|
+
.capture-modal-button.primary{background:linear-gradient(135deg,rgba(127,91,243,0.95),rgba(84,63,196,0.95));color:#fff;box-shadow:0 16px 36px rgba(111,76,242,0.3);}
|
|
56
|
+
.capture-modal-button.primary:hover{box-shadow:0 20px 42px rgba(111,76,242,0.38);transform:translateY(-1px);}
|
|
57
|
+
.capture-modal-button.secondary{background:rgba(148,163,184,0.18);color:rgba(15,23,42,0.78);}
|
|
58
|
+
.capture-modal-button.secondary:hover{background:rgba(148,163,184,0.28);box-shadow:0 12px 28px rgba(15,23,42,0.12);}
|
|
59
|
+
body.dark .capture-modal-button.secondary{background:rgba(148,163,184,0.2);color:rgba(226,232,240,0.92);}
|
|
60
|
+
.capture-modal-button:active{transform:translateY(1px);}
|
|
61
|
+
.capture-modal-button:focus-visible{outline:2px solid rgba(127,91,243,0.8);outline-offset:2px;}
|
|
62
|
+
.modal-overlay.is-visible .capture-modal{animation:captureModalPop 160ms ease-out;}
|
|
63
|
+
@media (max-width: 640px){.modal-overlay{padding:16px;}.capture-modal{width:calc(100% - 24px);padding:24px 20px;}.capture-modal-actions{flex-direction:column;}.capture-modal-button{width:100%;}}
|
|
64
|
+
@keyframes captureModalPop{from{opacity:0;transform:scale(0.97) translateY(12px);}to{opacity:1;transform:scale(1) translateY(0);}}
|
|
65
|
+
`;
|
|
66
|
+
document.head.appendChild(style);
|
|
67
|
+
}
|
|
68
|
+
|
|
32
69
|
constructor(stream = null, opts = {}) {
|
|
33
70
|
this.stream = stream;
|
|
34
71
|
this.opts = opts;
|
|
@@ -68,6 +105,11 @@ class ScreenCaptureModal {
|
|
|
68
105
|
this.overlayHidden = false;
|
|
69
106
|
this.floatingControls = null;
|
|
70
107
|
this.floatingStatus = null;
|
|
108
|
+
this.floatingDrag = null;
|
|
109
|
+
this.onFloatingPointerDown = this.startFloatingDrag.bind(this);
|
|
110
|
+
this.onFloatingPointerMove = this.handleFloatingPointerMove.bind(this);
|
|
111
|
+
this.onFloatingPointerUp = (event) => this.stopFloatingDrag(event);
|
|
112
|
+
this.onFloatingWindowResize = this.handleFloatingResize.bind(this);
|
|
71
113
|
this.resolveFn = null;
|
|
72
114
|
this.rejectFn = null;
|
|
73
115
|
this.colorDefault = '#ddd';
|
|
@@ -954,7 +996,7 @@ class ScreenCaptureModal {
|
|
|
954
996
|
color:#fff; padding:10px 14px; border-radius:12px;
|
|
955
997
|
box-shadow:0 8px 24px rgba(0,0,0,0.35);
|
|
956
998
|
font-size:14px; font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
|
|
957
|
-
pointer-events:auto;
|
|
999
|
+
pointer-events:auto; cursor:grab; touch-action:none;
|
|
958
1000
|
`;
|
|
959
1001
|
|
|
960
1002
|
const status = document.createElement('div');
|
|
@@ -975,11 +1017,25 @@ class ScreenCaptureModal {
|
|
|
975
1017
|
|
|
976
1018
|
controls.append(status, stopBtn);
|
|
977
1019
|
document.body.appendChild(controls);
|
|
1020
|
+
const rect = controls.getBoundingClientRect();
|
|
1021
|
+
const initial = this.clampFloatingPosition(rect);
|
|
1022
|
+
controls.style.left = `${initial.left}px`;
|
|
1023
|
+
controls.style.top = `${initial.top}px`;
|
|
1024
|
+
controls.style.right = 'auto';
|
|
1025
|
+
controls.style.bottom = 'auto';
|
|
978
1026
|
this.floatingControls = controls;
|
|
979
1027
|
this.floatingStatus = status;
|
|
1028
|
+
|
|
1029
|
+
controls.addEventListener('pointerdown', this.onFloatingPointerDown);
|
|
1030
|
+
window.addEventListener('resize', this.onFloatingWindowResize, { passive: true });
|
|
980
1031
|
}
|
|
981
1032
|
|
|
982
1033
|
removeFloatingControls() {
|
|
1034
|
+
this.stopFloatingDrag();
|
|
1035
|
+
if (this.floatingControls) {
|
|
1036
|
+
this.floatingControls.removeEventListener('pointerdown', this.onFloatingPointerDown);
|
|
1037
|
+
}
|
|
1038
|
+
window.removeEventListener('resize', this.onFloatingWindowResize);
|
|
983
1039
|
if (this.floatingControls && this.floatingControls.parentNode) {
|
|
984
1040
|
this.floatingControls.parentNode.removeChild(this.floatingControls);
|
|
985
1041
|
}
|
|
@@ -987,6 +1043,90 @@ class ScreenCaptureModal {
|
|
|
987
1043
|
this.floatingStatus = null;
|
|
988
1044
|
}
|
|
989
1045
|
|
|
1046
|
+
clampFloatingPosition(rect) {
|
|
1047
|
+
const margin = 8;
|
|
1048
|
+
const maxLeft = Math.max(margin, window.innerWidth - rect.width - margin);
|
|
1049
|
+
const maxTop = Math.max(margin, window.innerHeight - rect.height - margin);
|
|
1050
|
+
const left = Math.min(Math.max(rect.left, margin), maxLeft);
|
|
1051
|
+
const top = Math.min(Math.max(rect.top, margin), maxTop);
|
|
1052
|
+
return { left, top };
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
startFloatingDrag(event) {
|
|
1056
|
+
if (!this.floatingControls || event.button !== 0) return;
|
|
1057
|
+
if (event.target && event.target.closest('button')) return;
|
|
1058
|
+
const rect = this.floatingControls.getBoundingClientRect();
|
|
1059
|
+
const { left, top } = this.clampFloatingPosition(rect);
|
|
1060
|
+
this.floatingControls.style.left = `${left}px`;
|
|
1061
|
+
this.floatingControls.style.top = `${top}px`;
|
|
1062
|
+
this.floatingControls.style.right = 'auto';
|
|
1063
|
+
this.floatingControls.style.bottom = 'auto';
|
|
1064
|
+
|
|
1065
|
+
this.floatingDrag = {
|
|
1066
|
+
pointerId: event.pointerId,
|
|
1067
|
+
startX: event.clientX,
|
|
1068
|
+
startY: event.clientY,
|
|
1069
|
+
baseLeft: left,
|
|
1070
|
+
baseTop: top
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
if (this.floatingControls.setPointerCapture) {
|
|
1074
|
+
try {
|
|
1075
|
+
this.floatingControls.setPointerCapture(event.pointerId);
|
|
1076
|
+
} catch (_) {
|
|
1077
|
+
// Ignore inability to capture pointer (e.g., already captured).
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
this.floatingControls.style.cursor = 'grabbing';
|
|
1081
|
+
window.addEventListener('pointermove', this.onFloatingPointerMove);
|
|
1082
|
+
window.addEventListener('pointerup', this.onFloatingPointerUp);
|
|
1083
|
+
window.addEventListener('pointercancel', this.onFloatingPointerUp);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
handleFloatingPointerMove(event) {
|
|
1087
|
+
if (!this.floatingDrag || event.pointerId !== this.floatingDrag.pointerId || !this.floatingControls) return;
|
|
1088
|
+
const dx = event.clientX - this.floatingDrag.startX;
|
|
1089
|
+
const dy = event.clientY - this.floatingDrag.startY;
|
|
1090
|
+
const proposed = {
|
|
1091
|
+
left: this.floatingDrag.baseLeft + dx,
|
|
1092
|
+
top: this.floatingDrag.baseTop + dy,
|
|
1093
|
+
width: this.floatingControls.offsetWidth,
|
|
1094
|
+
height: this.floatingControls.offsetHeight
|
|
1095
|
+
};
|
|
1096
|
+
const clamped = this.clampFloatingPosition(proposed);
|
|
1097
|
+
this.floatingControls.style.left = `${clamped.left}px`;
|
|
1098
|
+
this.floatingControls.style.top = `${clamped.top}px`;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
stopFloatingDrag(event) {
|
|
1102
|
+
if (!this.floatingDrag) return;
|
|
1103
|
+
if (event && this.floatingDrag.pointerId !== event.pointerId) return;
|
|
1104
|
+
window.removeEventListener('pointermove', this.onFloatingPointerMove);
|
|
1105
|
+
window.removeEventListener('pointerup', this.onFloatingPointerUp);
|
|
1106
|
+
window.removeEventListener('pointercancel', this.onFloatingPointerUp);
|
|
1107
|
+
if (this.floatingControls && this.floatingControls.releasePointerCapture && this.floatingDrag.pointerId != null) {
|
|
1108
|
+
try {
|
|
1109
|
+
this.floatingControls.releasePointerCapture(this.floatingDrag.pointerId);
|
|
1110
|
+
} catch (_) {
|
|
1111
|
+
// Ignore release errors (e.g., pointer already released).
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (this.floatingControls) {
|
|
1115
|
+
this.floatingControls.style.cursor = 'grab';
|
|
1116
|
+
}
|
|
1117
|
+
this.floatingDrag = null;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
handleFloatingResize() {
|
|
1121
|
+
if (!this.floatingControls) return;
|
|
1122
|
+
const rect = this.floatingControls.getBoundingClientRect();
|
|
1123
|
+
const clamped = this.clampFloatingPosition(rect);
|
|
1124
|
+
this.floatingControls.style.left = `${clamped.left}px`;
|
|
1125
|
+
this.floatingControls.style.top = `${clamped.top}px`;
|
|
1126
|
+
this.floatingControls.style.right = 'auto';
|
|
1127
|
+
this.floatingControls.style.bottom = 'auto';
|
|
1128
|
+
}
|
|
1129
|
+
|
|
990
1130
|
formatDuration(ms) {
|
|
991
1131
|
const totalSeconds = Math.floor(ms / 1000);
|
|
992
1132
|
const minutes = String(Math.floor(totalSeconds / 60)).padStart(2, '0');
|
|
@@ -1128,6 +1268,7 @@ class ScreenCaptureModal {
|
|
|
1128
1268
|
}
|
|
1129
1269
|
|
|
1130
1270
|
showCaptureSavedModal(kind) {
|
|
1271
|
+
this.constructor.ensureSavedModalStyles();
|
|
1131
1272
|
const overlay = document.createElement('div');
|
|
1132
1273
|
overlay.className = 'modal-overlay capture-modal-overlay';
|
|
1133
1274
|
|