hh-shipments 0.3.1 → 0.3.2

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
@@ -18,7 +18,7 @@
18
18
  "test": "node test/run-tests.js && node test/run-carriers-tests.js"
19
19
  },
20
20
  "type": "commonjs",
21
- "version": "0.3.1",
21
+ "version": "0.3.2",
22
22
  "bin": {
23
23
  "hh-shipments": "server.js"
24
24
  },
package/public/app.js CHANGED
@@ -196,19 +196,48 @@ function pastedImageFiles(e) {
196
196
 
197
197
  // Paste-text tab: pasting a screenshot runs OCR and extracts tracking numbers;
198
198
  // pasting plain text behaves normally
199
+ async function handlePastedImageFile(f) {
200
+ try {
201
+ const text = await ocrFile(f, $('ocr-status-paste'));
202
+ const fd = new FormData();
203
+ fd.append('image', f);
204
+ const up = await fetch('/api/intake/image', { method: 'POST', body: fd });
205
+ if (!up.ok) throw new Error('upload failed');
206
+ await runQuick(text, $('quick-result'));
207
+ } catch (err) { $('ocr-status-paste').textContent = ''; $('quick-result').innerHTML = `<p class="error">${esc(err.message)}</p>`; }
208
+ }
209
+
199
210
  $('tab-paste').addEventListener('paste', async (e) => {
200
211
  const files = pastedImageFiles(e);
201
212
  if (!files.length) return; // text paste — let it land in the textarea
202
213
  e.preventDefault();
203
- for (const f of files) {
204
- try {
205
- const text = await ocrFile(f, $('ocr-status-paste'));
206
- const fd = new FormData();
207
- fd.append('image', f);
208
- const up = await fetch('/api/intake/image', { method: 'POST', body: fd });
209
- if (!up.ok) throw new Error('upload failed');
210
- await runQuick(text, $('quick-result'));
211
- } catch (err) { $('quick-result').innerHTML = `<p class="error">${esc(err.message)}</p>`; }
214
+ $('paste-box').innerHTML = '📋 <span class="muted">or tap here, then paste a screenshot</span>';
215
+ for (const f of files) await handlePastedImageFile(f);
216
+ });
217
+
218
+ // Fallback: read the image straight off the clipboard on tap (iOS sometimes
219
+ // won't offer image-paste inside a plain text box)
220
+ $('btn-clipboard').addEventListener('click', async () => {
221
+ if (!navigator.clipboard || !navigator.clipboard.read) {
222
+ $('quick-result').innerHTML = '<p class="error">This browser can\'t read the clipboard — copy the screenshot, tap the dashed box above, long-press → Paste.</p>';
223
+ return;
224
+ }
225
+ try {
226
+ $('ocr-status-paste').textContent = 'Reading clipboard…';
227
+ const items = await navigator.clipboard.read();
228
+ const files = [];
229
+ for (const item of items) for (const type of item.types) {
230
+ if (type.startsWith('image/')) {
231
+ const blob = await item.getType(type);
232
+ files.push(new File([blob], 'clipboard.' + type.split('/')[1], { type }));
233
+ }
234
+ }
235
+ $('ocr-status-paste').textContent = '';
236
+ if (!files.length) { $('quick-result').innerHTML = '<p class="muted">No image on the clipboard — copy a screenshot first, then tap this again.</p>'; return; }
237
+ for (const f of files) await handlePastedImageFile(f);
238
+ } catch (err) {
239
+ $('ocr-status-paste').textContent = '';
240
+ $('quick-result').innerHTML = `<p class="error">Couldn't read the clipboard (${esc(err.message)}). Tap the dashed box above, long-press → Paste instead.</p>`;
212
241
  }
213
242
  });
214
243
 
package/public/index.html CHANGED
@@ -61,7 +61,9 @@
61
61
  <button class="tab" data-tab="manual">Manual</button>
62
62
  </div>
63
63
  <div id="tab-paste" class="tabpanel">
64
- <textarea id="paste-text" rows="6" placeholder="Paste the seller's message or a tracking-number screenshot here…"></textarea>
64
+ <textarea id="paste-text" rows="6" placeholder="Paste the seller's message here…"></textarea>
65
+ <div id="paste-box" class="pastebox" contenteditable="true" spellcheck="false">📋 <span class="muted">or tap here, then paste a screenshot</span></div>
66
+ <div class="row" style="margin-top:8px"><button id="btn-clipboard" class="secondary">📋 Grab screenshot from clipboard</button></div>
65
67
  <div id="ocr-status-paste" class="muted"></div>
66
68
  <button id="btn-quick" class="primary">Extract &amp; add</button>
67
69
  <div id="quick-result"></div>
package/public/styles.css CHANGED
@@ -42,6 +42,8 @@ h2 { font-size: 17px; margin: 18px 0 8px; }
42
42
  .tab.active { background: var(--blue); color: #fff; }
43
43
  .tabpanel { margin-bottom: 12px; }
44
44
  .filebtn { display: block; text-align: center; background: #e5e5ea; border-radius: 12px; padding: 16px; font-weight: 600; cursor: pointer; }
45
+ .pastebox { margin-top: 8px; border: 2px dashed #c7c7cc; border-radius: 12px; padding: 14px; text-align: center; outline: none; caret-color: transparent; min-height: 20px; }
46
+ .pastebox:focus { border-color: #007aff; background: #f2f8ff; }
45
47
  .statusline { font-size: 17px; font-weight: 600; margin: 8px 0; }
46
48
  .timeline { border-left: 2px solid #d1d1d6; margin-left: 6px; padding-left: 14px; }
47
49
  .timeline .ev { margin-bottom: 12px; font-size: 14px; }