44 < head >
55 < meta charset ="UTF-8 " />
66 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 " />
7- < title > Show Case</ title >
87 < link rel ="stylesheet "
98 href ="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css " />
109 < link rel ="stylesheet " href ="style.css " />
11- <!-- box icons -->
12- < link href ="
https://unpkg.com/[email protected] /css/boxicons.min.css "
rel ="
stylesheet "
/> 10+ < title > Show Case</ title >
11+ < link rel ="icon " href ="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
12+ <text y='.9em' font-size='90'>🖼️</text></svg> ">
1313 < style >
1414 body {
1515 font-family : 'Montserrat' , sans-serif;
3737 transition : all 1000ms linear;
3838 }
3939
40+ html {
41+ font-size : 62.5% ;
42+ }
43+
4044 h1 {
4145 text-align : center;
4246 color : white;
97101 text-align : center;
98102 font-size : 14px ;
99103 color : # ffffff ;
100- /* margin-top: 10px; */
101104 background-color : # 9790ff5e ;
105+ border : # 0056b3 ;
106+ border-radius : 5px ;
102107 width : 100% ;
103- /* border-top: 1px solid #ddd; */
104108 }
105109
106110
107111 # certificateList {
108112 margin : 20px auto;
109- width : 90 % ;
110- /* Adjust container width as needed */
113+ width : 100 % ;
114+ height : auto;
111115 max-width : 800px ;
112116 text-align : center;
113117 }
114118
115- .certificate-item {
119+ .certificate-container {
120+ text-align : center;
116121 margin-bottom : 20px ;
117- position : relative;
118- padding-top : 56.25% ;
119- /* 16:9 aspect ratio */
120- border : 1px solid # ccc ;
121- border-radius : 8px ;
122- overflow : hidden;
123- box-shadow : 0 4px 6px rgba (0 , 0 , 0 , 0.1 );
124122 }
125123
126- .certificate-item iframe {
127- position : absolute;
128- top : 0 ;
129- left : 0 ;
124+ .certificate-frame {
130125 width : 100% ;
131- height : 100% ;
132- border : none;
126+ max-width : 700px ;
127+ height : 400px ;
128+ border : 1px solid # ccc ;
129+ border-radius : 8px ;
130+ box-shadow : 0 4px 8px rgba (0 , 0 , 0 , 0.1 );
131+ margin-bottom : 10px ;
133132 }
134133
135- .certificate-item p {
136- margin : 10px 0 ;
137- font-weight : bold;
134+ .certificate-description {
135+ font-size : 2rem ;
136+ color : # e6e6e6 ;
137+ padding : 10px ;
138+ border-radius : 5px ;
139+ width : 80% ;
140+ margin : 0 auto;
141+ box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.1 );
138142 }
139143
140144 # navigation {
166170
167171 @media screen and (max-width : 576px ) {
168172
169- /* Center the header elements properly */
170- .cd-header {
171- position : relative;
172- /* Allow header to scroll with content */
173- width : 100% ;
174- text-align : center;
175- }
176-
177- .logo-wrap a {
178- position : relative;
179- font-size : 1.5rem ;
180- /* Smaller logo size */
181-
182- }
183-
184173 /* Gallery Layout Adjustments */
185174 .gallery {
186175 padding : 10px ;
208197 max-width : 100% ;
209198 }
210199
200+ .certificate-description {
201+ text-align : center;
202+ margin-top : 15px ;
203+ font-size : 13px ;
204+ color : white;
205+ background : rgba (0 , 0 , 0 , 0.5 );
206+ padding : 10px ;
207+ border-radius : 5px ;
208+ }
209+
211210 .certificate-item {
212211 padding-top : 75% ;
213- /* Maintain aspect ratio */
214212 }
215213
216214 /* Button adjustments for better spacing */
232230 font-size : 1.5rem ;
233231 }
234232
235- /* Reduce gallery item size further for small screens */
236233 .gallery-item {
237234 max-width : 100% ;
238235 }
269266 < div class ="nav ">
270267 < div class ="nav__content ">
271268 < ul class ="nav__list ">
272- < li class ="nav__list-item active-nav ">
269+ < li class ="nav__list-item ">
273270 < a href ="index.html " class ="hover-target "> Home</ a >
274271 </ li >
275272 < li class ="nav__list-item ">
276273 < a href ="projects.html " class ="hover-target "> Projects</ a >
277274 </ li >
278275 < li class ="nav__list-item ">
279- < a href ="# " class ="hover-target "> About</ a >
276+ < a href ="about.html " class ="hover-target "> About</ a >
280277 </ li >
281- < li class ="nav__list-item ">
278+ < li class ="nav__list-item active-nav ">
282279 < a href ="ShowCase.html " class ="hover-target "> Show Case</ a >
283280 </ li >
284281 < li class ="nav__list-item ">
@@ -297,16 +294,13 @@ <h1>My Portfolio Gallery</h1>
297294 < div class ="gallery " id ="gallery "> </ div >
298295 </ div >
299296
300-
301297 <!-- Certificates Section -->
302- < h2 > Certificates</ h2 >
298+ < h1 > Certificates</ h1 >
303299 < div id ="certificateList "> </ div >
304300 < div id ="navigation ">
305301 < button id ="prevPage "> Previous</ button >
306302 < button id ="nextPage "> Next</ button >
307303 </ div >
308-
309-
310304 </ div >
311305
312306 < div class ="cursor " id ="cursor "> </ div >
@@ -327,29 +321,42 @@ <h2>Certificates</h2>
327321
328322 const apiKey = "AIzaSyB8P_hvbRkqHa4ijc8sxD9WSjN1o1kryfs" ; // API Key
329323
330- // Fetch files from Google Drive
331- async function fetchFiles ( folderId ) {
332- const url = `https://www.googleapis.com/drive/v3/files?q='${ folderId } '+in+parents&key=${ apiKey } ` ;
333- const response = await fetch ( url ) ;
334- if ( ! response . ok ) throw new Error ( "Failed to fetch files" ) ;
335- const data = await response . json ( ) ;
336- return data ;
324+ async function fetchFiles ( url ) {
325+ try {
326+ const response = await fetch ( url ) ;
327+ if ( ! response . ok ) throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
328+
329+ const data = await response . json ( ) ;
330+
331+ // Check if 'files' property exists and is an array
332+ if ( ! data . files || ! Array . isArray ( data . files ) ) {
333+ throw new Error ( "Invalid response structure: 'files' field is missing." ) ;
334+ }
335+
336+ return data . files ;
337+ } catch ( error ) {
338+ console . error ( "Error fetching files:" , error . message ) ;
339+ return [ ] ; // Return an empty array to avoid further issues
340+ }
337341 }
338342
339- // Dynamically create the gallery
340343 async function displayGallery ( ) {
341- const data = await fetchFiles ( folderIds . photos ) ;
344+ const url = `https://www.googleapis.com/drive/v3/files?q='${ folderIds . photos } '+in+parents+and+mimeType+contains+'image/'&fields=files(id,name,mimeType,description)&key=${ apiKey } ` ;
345+ const files = await fetchFiles ( url ) ;
342346 const galleryDiv = document . getElementById ( "gallery" ) ;
343347
344- const images = data . files . filter ( file => file . mimeType . startsWith ( "image/" ) ) ;
345- const rows = [ ] ; // This will hold each row of gallery items
348+ if ( files . length === 0 ) {
349+ galleryDiv . innerHTML = "<p>No photos found.</p>" ;
350+ return ;
351+ }
352+
353+ const images = files . filter ( file => file . mimeType . startsWith ( "image/" ) ) ;
354+ const rows = [ ] ;
346355
347- // Group images into rows (3 items per row)
348356 for ( let i = 0 ; i < images . length ; i += 3 ) {
349357 rows . push ( images . slice ( i , i + 3 ) ) ;
350358 }
351359
352- // Create gallery rows dynamically
353360 rows . forEach ( row => {
354361 const galleryRow = document . createElement ( "div" ) ;
355362 galleryRow . className = "gallery-row" ;
@@ -359,51 +366,59 @@ <h2>Certificates</h2>
359366 galleryItem . className = "gallery-item" ;
360367
361368 const img = document . createElement ( "img" ) ;
362- img . src = `https://lh3.googleusercontent.com/d/${ file . id } ` ;
363- img . alt = file . name ;
364369
365- galleryItem . appendChild ( img ) ;
370+ img . src = `https://drive.google.com/thumbnail?id=${ file . id } ` ;
371+ img . alt = file . name ;
366372
367- // Add description if available
368373 const description = document . createElement ( "p" ) ;
369- description . innerText = file . description || `No description available for ${ file . name } ` ;
370- galleryItem . appendChild ( description ) ;
374+ // Check if description is available, if not, fallback to file name
375+ description . innerText = file . description ? file . description : file . name ;
371376
377+ galleryItem . appendChild ( img ) ;
378+ galleryItem . appendChild ( description ) ;
372379 galleryRow . appendChild ( galleryItem ) ;
373380 } ) ;
374381
375382 galleryDiv . appendChild ( galleryRow ) ;
376383 } ) ;
377384 }
378385
379- // Convert PDF to image using PDF.js and display one image at a time
380- pdfjsLib . GlobalWorkerOptions . workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.worker.min.js' ;
381-
382386 async function displayCertificates ( ) {
383- const data = await fetchFiles ( folderIds . certificates ) ;
387+ const url = `https://www.googleapis.com/drive/v3/files?q='${ folderIds . certificates } '+in+parents&fields=files(id,name,mimeType,description)&key=${ apiKey } ` ;
388+ const files = await fetchFiles ( url ) ;
384389 const certificateListDiv = document . getElementById ( "certificateList" ) ;
385390 const prevButton = document . getElementById ( "prevPage" ) ;
386391 const nextButton = document . getElementById ( "nextPage" ) ;
387- let currentIndex = 0 ; // Index of the currently displayed certificate
388- const certificateItems = [ ] ; // Store certificate elements for navigation
389392
390- for ( const file of data . files ) {
391- if ( file . mimeType === "application/pdf" ) {
392- const certificateItem = document . createElement ( "div" ) ;
393- certificateItem . className = "certificate-item" ;
393+ if ( files . length === 0 ) {
394+ certificateListDiv . innerHTML = "<p>No certificates found.</p>" ;
395+ return ;
396+ }
394397
395- const certificateTitle = document . createElement ( "p" ) ;
396- certificateTitle . innerText = file . name ;
397- certificateItem . appendChild ( certificateTitle ) ;
398+ let currentIndex = 0 ;
399+ const certificateItems = [ ] ;
398400
399- // Embed the PDF using Google Drive Viewer
401+ files . forEach ( file => {
402+ if ( file . mimeType === "application/pdf" ) {
403+ const certificateContainer = document . createElement ( "div" ) ;
404+ certificateContainer . className = "certificate-container" ;
405+
406+ // Create iframe for certificate preview
400407 const iframe = document . createElement ( "iframe" ) ;
401408 iframe . src = `https://drive.google.com/file/d/${ file . id } /preview` ;
402- certificateItem . appendChild ( iframe ) ;
409+ iframe . className = "certificate-frame" ;
410+
411+ // Description section
412+ const description = document . createElement ( "div" ) ;
413+ description . className = "certificate-description" ;
414+ description . innerText = file . description ? file . description : "No description available." ;
403415
404- certificateItems . push ( certificateItem ) ;
416+ certificateContainer . appendChild ( iframe ) ;
417+ certificateContainer . appendChild ( description ) ;
418+
419+ certificateItems . push ( certificateContainer ) ;
405420 }
406- }
421+ } ) ;
407422
408423 function updateDisplay ( ) {
409424 certificateListDiv . innerHTML = "" ;
@@ -432,9 +447,7 @@ <h2>Certificates</h2>
432447 }
433448
434449 displayGallery ( ) ;
435- displayCertificates ( ) . catch ( error => {
436- console . error ( "Error:" , error ) ;
437- } ) ;
450+ displayCertificates ( ) ;
438451 </ script >
439452 </ body >
440453
0 commit comments