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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.91.0",
3
+ "version": "3.93.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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