From 6527410cc8fc01153b221bca39b02ba36569381b Mon Sep 17 00:00:00 2001 From: mibali Date: Mon, 4 May 2026 18:59:18 +0100 Subject: [PATCH] fix: apply rateLimitError to CALL_API and CALL_API_STREAM handlers The previous fix only covered TAILOR_CV and ANALYZE_CV_MATCH. The answer generation modal uses CALL_API_STREAM (handleStreamingAPICall) and CALL_API (handleAPICall) which still showed the generic message. Patch both. Co-Authored-By: Claude Sonnet 4.6 --- extension-ready/background.js | 2 + extension-ready/popup.html | 227 ++++++++++++++++++++-------------- 2 files changed, 135 insertions(+), 94 deletions(-) diff --git a/extension-ready/background.js b/extension-ready/background.js index 3b437a0..801dbb4 100644 --- a/extension-ready/background.js +++ b/extension-ready/background.js @@ -602,6 +602,7 @@ async function handleStreamingAPICall(payload, requestId, tabId, frameId) { response = await doRequest(); } + if (response.status === 429) throw new Error(rateLimitError(response)); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.error || `Proxy error: ${response.status}`); @@ -707,6 +708,7 @@ async function handleAPICall(payload, requestId) { response = await doRequest(); } + if (response.status === 429) throw new Error(rateLimitError(response)); if (!response.ok) { const error = await response.json().catch(() => ({})); const msg = error.error || `Proxy error: ${response.status}`; diff --git a/extension-ready/popup.html b/extension-ready/popup.html index ee1a67b..ae3a3e5 100644 --- a/extension-ready/popup.html +++ b/extension-ready/popup.html @@ -9,25 +9,30 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - width: 360px; - background: #f8fafc; - color: #1e293b; + width: 376px; + background: #f6f8fb; + color: #172033; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; } /* ── Header ── */ .da-header { - background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%); - padding: 14px 16px; + background: + linear-gradient(135deg, rgba(37, 99, 235, 0.96) 0%, rgba(124, 58, 237, 0.96) 100%); + padding: 15px 16px; display: flex; align-items: center; - gap: 10px; + gap: 11px; + border-bottom: 1px solid rgba(255, 255, 255, 0.16); } .da-header-logo { - width: 32px; - height: 32px; - background: rgba(255, 255, 255, 0.18); - border-radius: 9px; + width: 34px; + height: 34px; + background: rgba(255, 255, 255, 0.16); + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 8px; display: flex; align-items: center; justify-content: center; @@ -44,26 +49,26 @@ .da-header-text { flex: 1; } .da-header-title { - font-size: 15px; + font-size: 15.5px; font-weight: 700; color: white; - letter-spacing: -0.2px; + letter-spacing: 0; line-height: 1.2; } .da-header-sub { - font-size: 11px; - color: rgba(255, 255, 255, 0.65); - margin-top: 1px; + font-size: 11.5px; + color: rgba(255, 255, 255, 0.78); + margin-top: 2px; } /* ── Status row ── */ .da-status-row { display: flex; - gap: 6px; - padding: 10px 14px; + gap: 8px; + padding: 12px 14px; background: white; - border-bottom: 1px solid #f1f5f9; + border-bottom: 1px solid #e7edf5; } .da-status-chip { @@ -71,9 +76,9 @@ align-items: center; gap: 6px; flex: 1; - padding: 5px 10px; + padding: 6px 9px; background: #f8fafc; - border-radius: 20px; + border-radius: 8px; border: 1px solid #e2e8f0; min-width: 0; } @@ -92,32 +97,32 @@ .da-status-label { font-size: 11.5px; - color: #475569; + color: #40506a; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ── Body ── */ - .da-body { padding: 14px; } + .da-body { padding: 15px; } .da-section-label { font-size: 10.5px; - font-weight: 600; + font-weight: 700; text-transform: uppercase; - letter-spacing: 0.5px; - color: #94a3b8; + letter-spacing: 0.7px; + color: #8493aa; margin-bottom: 8px; } /* ── Upload area ── */ .upload-area { - border: 1.5px dashed #cbd5e1; - border-radius: 10px; - padding: 16px; + border: 1px dashed #c6d0df; + border-radius: 8px; + padding: 15px; text-align: center; cursor: pointer; - transition: border-color 0.2s, background 0.2s; + transition: border-color 0.2s, background 0.2s, box-shadow 0.2s; background: white; } @@ -125,6 +130,7 @@ .upload-area.dragover { border-color: #2563eb; background: #eff6ff; + box-shadow: 0 1px 0 rgba(37, 99, 235, 0.08); } .upload-area.has-file { @@ -136,10 +142,10 @@ display: flex; align-items: center; justify-content: center; - width: 38px; - height: 38px; + width: 36px; + height: 36px; background: #f1f5f9; - border-radius: 10px; + border-radius: 8px; margin: 0 auto 9px; transition: background 0.2s; } @@ -150,7 +156,7 @@ .upload-text { font-size: 13px; - color: #475569; + color: #40506a; line-height: 1.4; } @@ -161,7 +167,7 @@ .upload-hint { font-size: 11px; - color: #94a3b8; + color: #8795aa; margin-top: 3px; } @@ -188,15 +194,17 @@ textarea { width: 100%; padding: 10px 12px; - border: 1.5px solid #e2e8f0; + border: 1px solid #dbe3ee; border-radius: 8px; font-size: 13px; font-family: inherit; resize: vertical; min-height: 90px; - color: #1e293b; + color: #172033; + background: white; outline: none; transition: border-color 0.2s, box-shadow 0.2s; + line-height: 1.45; } textarea:focus { @@ -216,19 +224,19 @@ font-weight: 600; cursor: pointer; margin-top: 8px; - transition: opacity 0.2s, transform 0.15s, box-shadow 0.15s; - letter-spacing: -0.1px; + transition: background 0.2s, color 0.2s, border-color 0.2s, transform 0.15s, box-shadow 0.15s; + letter-spacing: 0; } .btn-primary { background: linear-gradient(135deg, #2563eb, #7c3aed); color: white; + box-shadow: 0 1px 2px rgba(30, 41, 59, 0.12); } .btn-primary:hover { - opacity: 0.92; transform: translateY(-1px); - box-shadow: 0 4px 14px rgba(37, 99, 235, 0.35); + box-shadow: 0 7px 18px rgba(37, 99, 235, 0.24); } .btn-primary:active { @@ -238,7 +246,7 @@ .btn-secondary { background: #f1f5f9; - color: #475569; + color: #40506a; } .btn-secondary:hover { background: #e2e8f0; } @@ -246,9 +254,10 @@ /* ── CV Loaded card ── */ .cv-loaded-card { background: white; - border: 1.5px solid #e2e8f0; - border-radius: 10px; + border: 1px solid #dbe3ee; + border-radius: 8px; overflow: hidden; + box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); } .cv-loaded-header { @@ -256,14 +265,14 @@ align-items: center; gap: 10px; padding: 11px 14px; - border-bottom: 1px solid #f1f5f9; + border-bottom: 1px solid #edf2f7; } .cv-check-icon { width: 26px; height: 26px; background: #dcfce7; - border-radius: 50%; + border-radius: 8px; display: flex; align-items: center; justify-content: center; @@ -284,7 +293,7 @@ padding: 4px 11px; font-size: 12px; font-weight: 500; - border: 1.5px solid #e2e8f0; + border: 1px solid #dbe3ee; border-radius: 6px; background: white; color: #64748b; @@ -305,7 +314,7 @@ max-height: 52px; overflow: hidden; line-height: 1.5; - background: #fafafa; + background: #fbfcfe; } /* ── Productivity stats ── */ @@ -404,9 +413,10 @@ gap: 8px; padding: 9px 12px; background: white; - border: 1.5px solid #e2e8f0; + border: 1px solid #dbe3ee; border-radius: 8px; margin-bottom: 8px; + box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); } /* ── Message ── */ @@ -431,7 +441,7 @@ .da-footer { padding: 8px 14px 14px; font-size: 11px; - color: #94a3b8; + color: #8795aa; text-align: center; line-height: 1.5; } @@ -443,8 +453,8 @@ display: flex; align-items: center; gap: 10px; - padding-bottom: 12px; - border-bottom: 1px solid #f1f5f9; + padding-bottom: 13px; + border-bottom: 1px solid #e7edf5; margin-bottom: 14px; } @@ -454,7 +464,7 @@ color: #64748b; font-size: 13px; cursor: pointer; - padding: 4px 0; + padding: 5px 0; font-family: inherit; line-height: 1; } @@ -462,8 +472,8 @@ .tailor-view-title { font-size: 13px; - font-weight: 600; - color: #1e293b; + font-weight: 700; + color: #172033; } .tailor-inputs-row { @@ -475,16 +485,19 @@ .tailor-input { flex: 1; padding: 8px 10px; - border: 1.5px solid #e2e8f0; + border: 1px solid #dbe3ee; border-radius: 8px; font-size: 12.5px; outline: none; font-family: inherit; - color: #1e293b; + color: #172033; background: white; - transition: border-color 0.2s; + transition: border-color 0.2s, box-shadow 0.2s; + } + .tailor-input:focus { + border-color: #2563eb; + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08); } - .tailor-input:focus { border-color: #2563eb; } .tailor-input::placeholder { color: #94a3b8; } @keyframes tailor-spin { to { transform: rotate(360deg); } } @@ -520,95 +533,119 @@ /* Match report */ .match-report { background: white; - border: 1.5px solid #e2e8f0; - border-radius: 10px; - padding: 12px 14px; + border: 1px solid #dbe3ee; + border-radius: 8px; + padding: 13px 14px; margin-top: 14px; + box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); } .match-report-header { display: flex; align-items: center; justify-content: space-between; - margin-bottom: 10px; + margin-bottom: 11px; } .match-report-title { font-size: 11px; - font-weight: 600; + font-weight: 700; text-transform: uppercase; - letter-spacing: 0.5px; - color: #94a3b8; + letter-spacing: 0.7px; + color: #8493aa; } .match-score-badge { - font-size: 20px; + font-size: 18px; font-weight: 700; color: #2563eb; + padding: 3px 8px; + border-radius: 8px; + background: #eff6ff; } - .match-score-badge.score-high { color: #16a34a; } - .match-score-badge.score-mid { color: #d97706; } - .match-score-badge.score-low { color: #94a3b8; } + .match-score-badge.score-high { color: #166534; background: #f0fdf4; } + .match-score-badge.score-mid { color: #92400e; background: #fffbeb; } + .match-score-badge.score-low { color: #64748b; background: #f8fafc; } .match-group { margin-top: 8px; } .match-group-label { font-size: 10px; - font-weight: 600; + font-weight: 700; text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 5px; + letter-spacing: 0.6px; + margin-bottom: 6px; } .match-label-green { color: #16a34a; } .match-label-blue { color: #2563eb; } .match-label-gray { color: #94a3b8; } - .match-chips { display: flex; flex-wrap: wrap; gap: 4px; } + .match-chips { display: flex; flex-wrap: wrap; gap: 6px; } .match-chip { - padding: 3px 8px; - border-radius: 12px; + padding: 4px 8px; + border-radius: 8px; font-size: 11px; font-weight: 500; + line-height: 1.25; } - .match-chip-strong { background: #dcfce7; color: #166534; } - .match-chip-confirmed { background: #dbeafe; color: #1e40af; } - .match-chip-missing { background: #f1f5f9; color: #64748b; } - .match-chip-domain { background: #f5f3ff; color: #6d28d9; } + .match-chip-strong { background: #f0fdf4; color: #166534; border: 1px solid #bbf7d0; } + .match-chip-confirmed { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; } + .match-chip-missing { background: #f8fafc; color: #475569; border: 1px solid #e2e8f0; } + .match-chip-domain { background: #f5f3ff; color: #6d28d9; border: 1px solid #ddd6fe; } .match-label-purple { color: #7c3aed; } .missing-skill-check { display: inline-flex; align-items: center; - gap: 5px; - padding: 4px 8px; - border-radius: 12px; + gap: 6px; + padding: 6px 9px; + border-radius: 8px; background: #f8fafc; color: #475569; font-size: 11px; font-weight: 500; border: 1px solid #e2e8f0; cursor: pointer; + line-height: 1.2; + transition: background 0.2s, border-color 0.2s, color 0.2s; + } + + .missing-skill-check:hover { + background: #eff6ff; + border-color: #bfdbfe; + color: #1e40af; } .missing-skill-check input { - width: 12px; - height: 12px; + width: 13px; + height: 13px; margin: 0; accent-color: #2563eb; } .missing-skill-help { - margin: 3px 0 7px; + margin: 3px 0 8px; color: #64748b; font-size: 11px; line-height: 1.35; } + .trust-note { + margin-top: 8px; + padding: 7px 9px; + border-radius: 8px; + background: #f8fafc; + border: 1px solid #e2e8f0; + color: #64748b; + font-size: 10.8px; + line-height: 1.35; + } + .tailor-warning-box { margin-top: 10px; padding: 10px 12px; @@ -626,6 +663,7 @@ max-height: 280px; font-size: 12px; line-height: 1.55; + background: #fbfcfe; } .tailor-action-row { @@ -648,7 +686,7 @@ flex: 1; background: #f1f5f9; color: #475569; - border: 1.5px solid #e2e8f0; + border: 1px solid #dbe3ee; font-size: 13px; } .tailor-action-secondary .btn-copy:hover { background: #e2e8f0; } @@ -658,7 +696,7 @@ padding: 10px 14px; background: #f1f5f9; color: #475569; - border: 1.5px solid #e2e8f0; + border: 1px solid #dbe3ee; font-size: 13px; } .tailor-action-secondary .btn-redo:hover { background: #e2e8f0; } @@ -667,8 +705,8 @@ #tailor-open-btn { margin-top: 8px; background: white; - border: 1.5px solid #e2e8f0; - color: #475569; + border: 1px solid #dbe3ee; + color: #40506a; } #tailor-open-btn:hover { background: #f8fafc; border-color: #7c3aed; color: #7c3aed; } @@ -677,8 +715,8 @@ display: flex; align-items: center; gap: 0; - margin-bottom: 14px; - padding: 10px 0 4px; + margin-bottom: 15px; + padding: 10px 0 5px; } .tailor-step { @@ -695,7 +733,7 @@ top: 10px; left: 55%; width: 90%; - height: 1.5px; + height: 1px; background: #e2e8f0; transition: background 0.3s; } @@ -706,9 +744,9 @@ .tailor-step-dot { width: 20px; height: 20px; - border-radius: 50%; + border-radius: 8px; background: #f1f5f9; - border: 1.5px solid #cbd5e1; + border: 1px solid #cbd5e1; display: flex; align-items: center; justify-content: center; @@ -997,6 +1035,7 @@
Not found in your CV
Tick any skills you genuinely have — they'll be included in the tailored CV.
+
Only used for this tailored CV. Not saved for training.