6868 .gallery-item {
6969 position : relative;
7070 width : 300px ;
71- /* Fixed width for the image container */
7271 height : 300px ;
73- /* Fixed height for the image container */
7472 gap : 1px ;
7573 overflow : hidden;
7674 border-radius : 8px ;
7775 box-shadow : 0 4px 8px rgba (0 , 0 , 0 , 0.2 );
7876 display : flex;
7977 flex-direction : column;
80- /* Stack the image and description vertically */
8178 justify-content : flex-start;
8279 align-items : center;
8380 background-color : # ffffff00 ;
107104 }
108105
109106 .certificate-list {
110- display : flex ;
111- flex-wrap : nowrap ;
112- /* Keep items in a single row */
107+ position : relative ;
108+ display : grid ;
109+ grid-template-columns : repeat (auto-fit , minmax ( 300 px , 1 fr ));
113110 gap : 20px ;
114- /* Space between certificates */
115- justify-content : flex-start;
116- /* Left-aligned initially */
117- overflow-x : auto;
118- /* Allow horizontal scrolling */
119111 padding : 20px ;
120- margin-top : 20px ;
121- max-width : 100% ;
122- scroll-behavior : smooth;
123- /* Smooth scrolling for navigation */
124- }
125-
126- .certificate-item {
127- width : 300px ;
128- height : 300px ;
129- border-radius : 8px ;
112+ justify-items : center;
130113 overflow : hidden;
131- background-color : rgba ( 255 , 255 , 255 , 0.1 ) ;
114+ border-radius : 8 px ;
132115 box-shadow : 0 4px 8px rgba (0 , 0 , 0 , 0.2 );
133- display : flex;
134- flex-direction : column;
116+ background-color : # ffffff00 ;
117+ margin-right : 1px ;
118+ /* Center the certificate list */
135119 justify-content : center;
136120 align-items : center;
137- text-align : center;
138- transition : transform 0.3s ease;
139- }
140-
141- .certificate-item img {
142- width : 100% ;
143- height : 80% ;
144- object-fit : contain;
145- margin-bottom : 8px ;
146- }
147-
148- .certificate-item : hover {
149- transform : scale (1.1 );
150- }
151-
152- .nav-buttons {
153- display : flex;
154- justify-content : center;
155- gap : 10px ;
156- margin-top : 10px ;
157- }
158-
159- .nav-buttons button {
160- padding : 10px 20px ;
161- border : none;
162- border-radius : 5px ;
163- background-color : # 555 ;
164- color : white;
165- cursor : pointer;
166- font-size : 16px ;
167- transition : background-color 0.3s ease;
168- }
169-
170- .nav-buttons button : hover {
171- background-color : # 777 ;
172- }
173- </ style >
174- < style >
175- .certificate-list {
176- display : grid;
177- grid-template-columns : repeat (auto-fit, minmax (300px , 1fr ));
178- gap : 20px ;
179- padding : 20px ;
180- justify-items : center;
181121 }
182122
183123 .certificate-item {
184- width : 300px ;
185- height : 300px ;
186- border-radius : 8px ;
124+ position : relative;
125+ width : 400px ;
126+ height : 400px ;
127+ gap : 1px ;
187128 overflow : hidden;
188- background-color : rgba ( 255 , 255 , 255 , 0.1 ) ;
129+ border-radius : 8 px ;
189130 box-shadow : 0 4px 8px rgba (0 , 0 , 0 , 0.2 );
190131 display : flex;
191132 flex-direction : column;
192133 justify-content : center;
193134 align-items : center;
135+ background-color : rgba (255 , 255 , 255 , 0.1 );
194136 text-align : center;
195137 transition : transform 0.3s ease;
196138 }
197139
140+ .certificate-item canvas {
141+ width : 100% ;
142+ /* Make canvas width fully match the container */
143+
144+ height : 100% ;
145+ /* Adjust height to maintain aspect ratio */
146+ object-fit : contain;
147+ /* Ensure the content fits inside without cropping */
148+ display : block;
149+ /* Removes unwanted inline gaps */
150+ }
151+
198152 .certificate-item img {
199153 width : 100% ;
200- height : 80 % ;
154+ height : 100 % ;
201155 object-fit : contain;
202156 margin-bottom : 8px ;
203157 }
204158
159+ .certificate-item p {
160+ font-size : 16px ;
161+ color : white;
162+ padding : 8px ;
163+ background-color : rgba (0 , 0 , 0 , 0.5 );
164+ width : 100% ;
165+ }
166+
205167 .certificate-item : hover {
206168 transform : scale (1.1 );
207169 }
@@ -310,7 +272,7 @@ <h2>Certificates</h2>
310272 photos : "1U1PiyXsOYeS3BEj58un29f2XMtYb5RhA" , // Photos folder ID
311273 certificates : "1zJPPsZIjU11ZOx7yzGPDKFZXPeGgjHSW" , // Certificates folder ID
312274 } ;
313- const folderId = "1U1PiyXsOYeS3BEj58un29f2XMtYb5RhA" ; // Photos folder ID
275+
314276 const apiKey = "AIzaSyB8P_hvbRkqHa4ijc8sxD9WSjN1o1kryfs" ; // API Key
315277
316278 // Fetch files from Google Drive
@@ -360,18 +322,14 @@ <h2>Certificates</h2>
360322 } ) ;
361323 }
362324
363- // Initialize gallery display
364-
365325 // Convert PDF to image using PDF.js and display one image at a time
366326 pdfjsLib . GlobalWorkerOptions . workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.worker.min.js' ;
367327
368-
369328 async function displayCertificates ( ) {
370329 const data = await fetchFiles ( folderIds . certificates ) ;
371330 const certificateListDiv = document . getElementById ( "certificateList" ) ;
372331 const prevButton = document . getElementById ( "prevPage" ) ;
373332 const nextButton = document . getElementById ( "nextPage" ) ;
374-
375333 let currentIndex = 0 ; // Index of the currently displayed certificate
376334 const certificateItems = [ ] ; // Store certificate elements for navigation
377335
@@ -387,30 +345,44 @@ <h2>Certificates</h2>
387345 const canvas = document . createElement ( "canvas" ) ;
388346 certificateItem . appendChild ( canvas ) ;
389347
390- // Fetch the PDF file from Google Drive
348+ // Use the Google Drive API URL to get the PDF file
391349 const pdfUrl = `https://www.googleapis.com/drive/v3/files/${ file . id } ?alt=media&key=${ apiKey } ` ;
350+
392351 try {
352+ // Fetch the PDF
393353 const response = await fetch ( pdfUrl ) ;
394354 if ( ! response . ok ) throw new Error ( "Failed to fetch PDF" ) ;
395355
356+ // Get the PDF blob
396357 const blob = await response . blob ( ) ;
397358 const objectURL = URL . createObjectURL ( blob ) ;
398359
399- // Load and render the PDF using PDF.js
360+ // Use PDF.js to load and render the PDF
400361 const pdf = await pdfjsLib . getDocument ( objectURL ) . promise ;
401- const page = await pdf . getPage ( 1 ) ; // Get the first page
362+ const page = await pdf . getPage ( 1 ) ; // Render only the first page
363+
402364 const viewport = page . getViewport ( { scale : 1 } ) ;
403365 const context = canvas . getContext ( "2d" ) ;
366+
367+ // Set canvas size to match PDF page size
404368 canvas . width = viewport . width ;
405369 canvas . height = viewport . height ;
406370
371+ // Render the page on the canvas
407372 await page . render ( {
408373 canvasContext : context ,
409374 viewport : viewport ,
410375 } ) . promise ;
376+ certificateListDiv . innerHTML = "" ;
411377
412378 // Add the completed certificate item to the list
413379 certificateItems . push ( certificateItem ) ;
380+ if ( certificateItems [ currentIndex ] ) {
381+ certificateListDiv . appendChild ( certificateItems [ currentIndex ] ) ;
382+ }
383+ // Update button states
384+ prevButton . disabled = currentIndex === 0 ;
385+ nextButton . disabled = currentIndex === certificateItems . length - 1 ;
414386 } catch ( error ) {
415387 console . error ( "Error loading PDF:" , error ) ;
416388 }
@@ -421,12 +393,10 @@ <h2>Certificates</h2>
421393 function updateDisplay ( ) {
422394 // Clear the certificate list container
423395 certificateListDiv . innerHTML = "" ;
424-
425396 // Add only the current certificate to the display
426397 if ( certificateItems [ currentIndex ] ) {
427398 certificateListDiv . appendChild ( certificateItems [ currentIndex ] ) ;
428399 }
429-
430400 // Update button states
431401 prevButton . disabled = currentIndex === 0 ;
432402 nextButton . disabled = currentIndex === certificateItems . length - 1 ;
@@ -439,7 +409,6 @@ <h2>Certificates</h2>
439409 updateDisplay ( ) ;
440410 }
441411 } ) ;
442-
443412 nextButton . addEventListener ( "click" , ( ) => {
444413 if ( currentIndex < certificateItems . length - 1 ) {
445414 currentIndex ++ ;
@@ -451,8 +420,6 @@ <h2>Certificates</h2>
451420 updateDisplay ( ) ;
452421 }
453422
454-
455- // Initialize both displays
456423 displayGallery ( ) ;
457424 displayCertificates ( ) ;
458425 </ script >
0 commit comments