@@ -5,7 +5,7 @@ import Footer from "../../components/Footer.astro";
55import HeroSection from " ../../components/HeroSection.astro" ;
66
77const DIRECTUS_URL = " https://directus.bounteer.com" ;
8- const READ_TOKEN = " 5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn" ;
8+ const READ_TOKEN = " 5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn" ; // must have create: files + submissions
99---
1010
1111<style is:global >
@@ -21,7 +21,7 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
2121 <HeroSection
2222 title =" Get Your Role Fit Score"
2323 highlightText =" Role Fit Score"
24- description =" Instantly analyze how well your CV matches any job description. Get detailed insights and actionable recommendations. "
24+ description =" Instantly analyze how well your CV matches any job description."
2525 badge =" ⚡ AI-Powered Career Matching"
2626 />
2727
@@ -42,10 +42,18 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
4242 fileName: '',
4343 fileObj: null,
4444 error: '',
45- step: 0, // 0 idle, 1 uploading
45+ step: 0, // 0 idle, 1 uploading
4646 buttonText: 'Analyze Role Fit now',
4747
48- // handlers
48+ // helpers
49+ autoGrow(el){
50+ // cap at 60% viewport height
51+ const max = Math.floor(window.innerHeight * 0.6);
52+ el.style.height = 'auto';
53+ el.style.height = Math.min(el.scrollHeight, max) + 'px';
54+ },
55+
56+ // file handlers
4957 handleFile(file){ this.validateFile(file); },
5058 handleDrop(ev){ const f = ev.dataTransfer.files?.[0]; this.validateFile(f); },
5159 validateFile(file){
@@ -58,14 +66,13 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
5866 },
5967
6068 async analyze(){
61- console.log('analyze');
6269 try{
6370 if(!this.fileObj){ this.error='Please select a PDF'; return; }
6471 const jdText = this.$refs.jdInput?.value?.trim();
6572 if(!jdText){ this.error='Please paste the JD'; return; }
6673 if(!this.directusUrl || !this.writeToken){ this.error='Missing Directus config'; return; }
6774
68- // STEP 1: Upload
75+ // STEP 1: Upload file
6976 this.step = 1; this.isBusy = true; this.buttonText = 'Uploading CV…';
7077 const fd = new FormData();
7178 fd.append('file', this.fileObj, this.fileName || 'cv.pdf');
@@ -79,7 +86,7 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
7986 if(!upRes.ok) throw new Error(upJson?.errors?.[0]?.message || 'Upload failed');
8087 const fileId = upJson?.data?.id;
8188
82- // Create submission
89+ // STEP 2: Create submission
8390 this.buttonText = 'Saving submission…';
8491 const subRes = await fetch(`${this.directusUrl}/items/role_fit_score_submission`, {
8592 method: 'POST',
@@ -93,12 +100,11 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
93100 if(!subRes.ok) throw new Error(subJson?.errors?.[0]?.message || 'Submission failed');
94101 const submissionId = subJson?.data?.id;
95102
96- // Redirect to report viewer (query string for static hosting )
103+ // Redirect ( static-friendly )
97104 window.location.href = `/score/report?id=${encodeURIComponent(submissionId)}`;
98-
99105 }catch(e){
100106 this.error = e?.message || 'Unexpected error';
101- this.isBusy = false; this.step = 0; this.buttonText = 'Analyze Role Fit';
107+ this.isBusy = false; this.step = 0; this.buttonText = 'Analyze Role Fit now ';
102108 }
103109 }
104110 }
@@ -112,9 +118,14 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
112118 class =" absolute inset-0 z-50 flex items-center justify-center bg-white/80 backdrop-blur-sm"
113119 aria-live =" polite"
114120 role =" status"
121+ x-cloak
115122 >
116123 <div class =" flex flex-col items-center gap-4" >
117- <svg class =" h-12 w-12 animate-spin" viewBox =" 0 0 24 24" >
124+ <svg
125+ class =" h-12 w-12 animate-spin"
126+ viewBox =" 0 0 24 24"
127+ aria-hidden =" true"
128+ >
118129 <circle
119130 cx =" 12"
120131 cy =" 12"
@@ -140,34 +151,46 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
140151 Upload JD and CV
141152 </h3 >
142153
143- <div class =" grid grid-cols-1 md:grid-cols-2 gap-10" >
144- <div >
154+ <div class =" grid grid-cols-1 md:grid-cols-2 gap-10 items-stretch" >
155+ <!-- JD (auto-grow textarea only) -->
156+ <div class =" flex flex-col" >
145157 <label
146158 for =" job-description"
147159 class =" block text-sm font-medium text-gray-700 mb-2"
148- >Job Description (Text or URL)</label
149160 >
161+ Job Description (Text or URL)
162+ </label >
163+
150164 <textarea
151165 id =" job-description"
152- class =" w-full h-56 p-4 border rounded-lg text-sm text-gray-700 focus:ring-2 focus:ring-primary-500 focus:outline-none"
153- placeholder =" Paste the JD or a JD URL…"
154166 x-ref =" jdInput"
155167 :disabled =" isBusy"
156- :class =" isBusy ? 'opacity-60 pointer-events-none' : ''"
168+ placeholder =" Paste the JD or a JD URL…"
169+ @input =" autoGrow($event.target)"
170+ x-init =" autoGrow($el)"
171+ class =" block w-full rounded-lg border-2 border-dashed border-gray-300
172+ p-8 text-sm text-gray-700 placeholder:text-gray-400
173+ focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500
174+ min-h-[260px] md:min-h-[300px] resize-none overflow-auto
175+ transition disabled:opacity-60 disabled:pointer-events-none"
157176 ></textarea >
158177 </div >
159178
179+ <!-- CV dropzone -->
160180 <div
161181 @dragover.prevent =" isDragging = true"
162182 @dragleave.prevent =" isDragging = false"
163183 @drop.prevent =" isDragging = false; handleDrop($event)"
164184 :class =" isBusy ? 'opacity-60 pointer-events-none' : ''"
185+ class =" flex flex-col"
165186 >
166- <label class =" block text-sm font-medium text-gray-700 mb-2"
167- >Upload CV (PDF only)</label
168- >
187+ <label class =" block text-sm font-medium text-gray-700 mb-2" >
188+ Upload CV (PDF only)
189+ </label >
190+
169191 <div
170- class =" border-2 border-dashed rounded-lg p-8 text-center transition"
192+ class =" border-2 border-dashed rounded-lg p-8 text-center transition
193+ min-h-[260px] md:min-h-[300px] h-full flex flex-col items-center justify-center"
171194 :class =" isDragging ? 'border-primary-500 bg-primary-50' : 'border-gray-300'"
172195 >
173196 <div class =" flex flex-col items-center justify-center" >
@@ -201,22 +224,34 @@ const READ_TOKEN = "5OTK2voWFO_vTptGVMAY2Oxz9XBCDAvn";
201224 </label >
202225 <br /> Supports PDF up to 10MB
203226 </p >
227+ </div >
204228
205- <template x-if =" fileName" >
206- <p class =" mt-3 text-sm text-blue-600 font-medium" >
207- 📄 <span x-text =" fileName" ></span >
229+ <!-- reserved rows to prevent jump -->
230+ <div class =" mt-4 w-full max-w-xs min-w-0 mx-auto" >
231+ <div class =" h-6 flex items-center justify-center" >
232+ <p
233+ x-show =" fileName"
234+ x-cloak
235+ class =" text-sm text-blue-600 font-medium truncate max-w-full"
236+ x-text =" `📄 ${fileName}`"
237+ >
208238 </p >
209- </template >
210-
211- <template x-if =" error" >
212- <p class =" mt-3 text-sm text-red-600" x-text =" error" ></p >
213- </template >
239+ </div >
240+ <div class =" h-5 flex items-center justify-center" >
241+ <p
242+ x-show =" error"
243+ x-cloak
244+ class =" text-sm text-red-600"
245+ x-text =" error"
246+ >
247+ </p >
248+ </div >
214249 </div >
215250 </div >
216251 </div >
217252 </div >
218253
219- <!-- BUTTON: visible only when not analyzing -->
254+ <!-- Primary button -->
220255 <div class =" mt-10 relative h-12" >
221256 <button
222257 x-cloak
0 commit comments