portosaurus 1.18.13 → 1.18.15

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portosaurus",
3
- "version": "1.18.13",
3
+ "version": "1.18.15",
4
4
  "author": "soymadip",
5
5
  "license": "GPL-3.0-only",
6
6
  "description": "Complete portfolio cum personal website solution for your digital personality.",
@@ -1,6 +1,6 @@
1
1
  import { FaQuestionCircle } from "react-icons/fa";
2
2
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
3
- import { iconMap as defaultIconMap } from "#config/iconMappings";
3
+ import { iconMap as defaultIconMap } from "../../config/iconMappings.js";
4
4
  import styles from "./styles.module.css";
5
5
 
6
6
  const sortEmail = (links) => {
@@ -1,5 +1,5 @@
1
1
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
2
- import SocialLinks from "#components/SocialLinks/index.js";
2
+ import SocialLinks from "../SocialLinks/index.js";
3
3
  import styles from "./styles.module.css";
4
4
 
5
5
  export default function HeroSection({ id, className }) {
@@ -4,7 +4,7 @@ import { usePluginData } from "@docusaurus/useGlobalData";
4
4
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
5
5
  import DocCardList from "@theme/DocCardList";
6
6
 
7
- import { iconMap } from "#config/iconMappings";
7
+ import { iconMap } from "../../config/iconMappings.js";
8
8
 
9
9
  import { FaBook } from "react-icons/fa";
10
10
  import styles from "./styles.module.css";
@@ -1,8 +1,16 @@
1
- import { useRef, useState, useEffect, useCallback, useMemo } from 'react';
2
- import Slider from "react-slick";
3
- import { FaGithub, FaGlobe, FaPlay, FaChevronLeft, FaChevronRight, FaStar } from 'react-icons/fa';
1
+ import { useRef, useState, useEffect, useCallback, useMemo } from "react";
2
+ import SliderImport from "react-slick";
3
+ const Slider = SliderImport.default || SliderImport;
4
+ import {
5
+ FaGithub,
6
+ FaGlobe,
7
+ FaPlay,
8
+ FaChevronLeft,
9
+ FaChevronRight,
10
+ FaStar,
11
+ } from "react-icons/fa";
4
12
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
5
- import styles from './styles.module.css';
13
+ import styles from "./styles.module.css";
6
14
 
7
15
  // Import slick carousel css
8
16
  import "slick-carousel/slick/slick.css";
@@ -23,102 +31,119 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
23
31
  const activeDotRef = useRef(null);
24
32
  const dotsContainerRef = useRef(null);
25
33
 
26
- // Default Settings
34
+ // Default Settings
27
35
  const projectDefaults = {
28
36
  title: "Future Project",
29
- desc: "Coming soon...",
37
+ desc: "Coming soon...",
30
38
  image: "img/project-blank.png",
31
39
  state: "active",
32
- tags: ["planned"]
40
+ tags: ["planned"],
33
41
  };
34
42
 
43
+ const createPlaceholders = useCallback(
44
+ (count, existingProjects) => {
45
+ if (existingProjects.length === 0) return [];
35
46
 
36
- const createPlaceholders = useCallback((count, existingProjects) => {
37
- if (existingProjects.length === 0) return [];
38
-
39
- return [
40
- ...existingProjects,
41
- ...Array.from({ length: count }, (_, i) => ({
42
- ...projectDefaults,
43
-
44
- // Dummy card config
45
- state: "n/a",
46
- title: `Project ${existingProjects.length + i + 1}`,
47
- description: projectDefaults.desc,
48
- image: projectDefaults.image,
49
- id: `placeholder-${i}`,
50
- tags: null
51
- }))
52
- ];
53
- }, [projectDefaults]);
47
+ return [
48
+ ...existingProjects,
49
+ ...Array.from({ length: count }, (_, i) => ({
50
+ ...projectDefaults,
51
+
52
+ // Dummy card config
53
+ state: "n/a",
54
+ title: `Project ${existingProjects.length + i + 1}`,
55
+ description: projectDefaults.desc,
56
+ image: projectDefaults.image,
57
+ id: `placeholder-${i}`,
58
+ tags: null,
59
+ })),
60
+ ];
61
+ },
62
+ [projectDefaults],
63
+ );
54
64
 
55
65
  // Get current slidesToShow based on screen width
56
66
  const getVisibleSlidesPerView = useCallback(() => {
57
- if (typeof window === 'undefined') return 3;
58
-
67
+ if (typeof window === "undefined") return 3;
68
+
59
69
  const width = window.innerWidth;
60
70
  if (width <= 600) return 1;
61
71
  if (width <= 1024) return 2;
62
72
  return 3;
63
73
  }, []);
64
-
65
- const prepareProjects = useCallback((projectList, slides) => {
66
- if (!projectList?.length) return { projects: [], totalPages: 0 };
67
-
68
- // Sort featured first
69
- const sortedProjects = [...projectList].sort((a, b) =>
70
- (a.featured ? -1 : 0) - (b.featured ? -1 : 0)
71
- ).map(project => {
72
-
73
- // Apply defaults if value not null
74
- const processedProject = {
75
- ...project,
76
- description: project.desc === undefined ? projectDefaults.desc : project.desc,
77
- image: project.image === undefined ? projectDefaults.image : project.image,
78
- tags: project.tags === undefined ? [...projectDefaults.tags] : project.tags,
79
- state: project.state === undefined ? projectDefaults.state : project.state
74
+
75
+ const prepareProjects = useCallback(
76
+ (projectList, slides) => {
77
+ if (!projectList?.length) return { projects: [], totalPages: 0 };
78
+
79
+ // Sort featured first
80
+ const sortedProjects = [...projectList]
81
+ .sort((a, b) => (a.featured ? -1 : 0) - (b.featured ? -1 : 0))
82
+ .map((project) => {
83
+ // Apply defaults if value not null
84
+ const processedProject = {
85
+ ...project,
86
+ description:
87
+ project.desc === undefined ? projectDefaults.desc : project.desc,
88
+ image:
89
+ project.image === undefined
90
+ ? projectDefaults.image
91
+ : project.image,
92
+ tags:
93
+ project.tags === undefined
94
+ ? [...projectDefaults.tags]
95
+ : project.tags,
96
+ state:
97
+ project.state === undefined
98
+ ? projectDefaults.state
99
+ : project.state,
100
+ };
101
+
102
+ // Add ID
103
+ if (!processedProject.id) {
104
+ processedProject.id = processedProject.title
105
+ .toLowerCase()
106
+ .replace(/[^\w\s-]/g, "")
107
+ .replace(/\s+/g, "-")
108
+ .replace(/-+/g, "-");
109
+ }
110
+
111
+ return processedProject;
112
+ });
113
+
114
+ // Calculate pagination and placeholder needs
115
+ const totalPages = Math.ceil(sortedProjects.length / slides);
116
+ const slotsPerPage = slides;
117
+ const totalSlots = totalPages * slotsPerPage;
118
+ const placeholderCount = totalSlots - sortedProjects.length;
119
+
120
+ // Return prepared data
121
+ return {
122
+ projects:
123
+ placeholderCount > 0
124
+ ? createPlaceholders(placeholderCount, sortedProjects)
125
+ : sortedProjects,
126
+ totalPages,
80
127
  };
81
-
82
- // Add ID
83
- if (!processedProject.id) {
84
- processedProject.id = processedProject.title
85
- .toLowerCase()
86
- .replace(/[^\w\s-]/g, '')
87
- .replace(/\s+/g, '-')
88
- .replace(/-+/g, '-');
89
- }
90
-
91
- return processedProject;
92
- });
93
-
94
- // Calculate pagination and placeholder needs
95
- const totalPages = Math.ceil(sortedProjects.length / slides);
96
- const slotsPerPage = slides;
97
- const totalSlots = totalPages * slotsPerPage;
98
- const placeholderCount = totalSlots - sortedProjects.length;
99
-
100
- // Return prepared data
101
- return {
102
- projects: placeholderCount > 0
103
- ? createPlaceholders(placeholderCount, sortedProjects)
104
- : sortedProjects,
105
- totalPages
106
- };
107
- }, [createPlaceholders, projectDefaults]);
128
+ },
129
+ [createPlaceholders, projectDefaults],
130
+ );
108
131
 
109
132
  // Load and set up projects on initial load and on resize
110
133
  useEffect(() => {
111
134
  const projectShelf = siteConfig.customFields?.projects;
112
- const configuredProjects = projectShelf?.enable ? projectShelf?.projects || [] : [];
113
-
135
+ const configuredProjects = projectShelf?.enable
136
+ ? projectShelf?.projects || []
137
+ : [];
138
+
114
139
  const handleLayout = () => {
115
140
  const newSlidesToShow = getVisibleSlidesPerView();
116
-
141
+
117
142
  if (newSlidesToShow !== slidesToShow || !projects.length) {
118
143
  setSlidesToShow(newSlidesToShow);
119
- const { projects: newProjects, totalPages: newTotalPages } =
144
+ const { projects: newProjects, totalPages: newTotalPages } =
120
145
  prepareProjects(configuredProjects, newSlidesToShow);
121
-
146
+
122
147
  setProjects(newProjects);
123
148
  setTotalPages(newTotalPages);
124
149
  setAtEnd(newProjects.length <= newSlidesToShow);
@@ -127,124 +152,135 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
127
152
 
128
153
  // Initial setup
129
154
  handleLayout();
130
-
155
+
131
156
  // Resize handler
132
- window.addEventListener('resize', handleLayout);
133
- return () => window.removeEventListener('resize', handleLayout);
134
- }, [siteConfig, getVisibleSlidesPerView, prepareProjects, slidesToShow, projects.length]);
157
+ window.addEventListener("resize", handleLayout);
158
+ return () => window.removeEventListener("resize", handleLayout);
159
+ }, [
160
+ siteConfig,
161
+ getVisibleSlidesPerView,
162
+ prepareProjects,
163
+ slidesToShow,
164
+ projects.length,
165
+ ]);
135
166
 
136
167
  // Method to go to a specific slide
137
- const goToSlide = useCallback((index) => {
138
- if (sliderRef.current) {
139
-
140
- sliderRef.current.slickGoTo(index * slidesToShow);
141
- setCurrentSlide(index);
142
-
143
- }
144
- }, [slidesToShow]);
168
+ const goToSlide = useCallback(
169
+ (index) => {
170
+ if (sliderRef.current) {
171
+ sliderRef.current.slickGoTo(index * slidesToShow);
172
+ setCurrentSlide(index);
173
+ }
174
+ },
175
+ [slidesToShow],
176
+ );
145
177
 
146
178
  useEffect(() => {
147
179
  const scrollTimeout = setTimeout(() => {
148
-
149
180
  if (activeDotRef.current && dotsContainerRef.current) {
150
181
  const container = dotsContainerRef.current;
151
182
  const activeDot = activeDotRef.current;
152
-
153
- try {
154
183
 
184
+ try {
155
185
  // For first few
156
186
  const adaptiveThreshold = Math.max(1, Math.floor(totalPages * 0.1));
157
187
  if (currentSlide <= adaptiveThreshold) {
158
188
  container.scrollTo({
159
189
  left: 0,
160
- behavior: 'smooth'
190
+ behavior: "smooth",
161
191
  });
162
192
  return;
163
193
  }
164
-
194
+
165
195
  // For last few
166
196
  if (currentSlide >= totalPages - 2) {
167
197
  const scrollMax = container.scrollWidth - container.clientWidth;
168
198
  container.scrollTo({
169
199
  left: scrollMax,
170
- behavior: 'smooth'
200
+ behavior: "smooth",
171
201
  });
172
202
  return;
173
203
  }
174
-
204
+
175
205
  // Center the active dot at mobile
176
206
  const dotRect = activeDot.getBoundingClientRect();
177
207
  const containerRect = container.getBoundingClientRect();
178
-
208
+
179
209
  // Check if dot is within visible area with margins
180
210
  const isOutsideLeft = dotRect.left < containerRect.left + 20;
181
211
  const isOutsideRight = dotRect.right > containerRect.right - 20;
182
-
212
+
183
213
  if (isOutsideLeft || isOutsideRight) {
184
214
  const dotPosition = activeDot.offsetLeft;
185
215
  const dotWidth = activeDot.clientWidth;
186
216
  const containerWidth = container.clientWidth;
187
- const scrollPosition = dotPosition - (containerWidth / 2) + (dotWidth / 2);
188
-
217
+ const scrollPosition =
218
+ dotPosition - containerWidth / 2 + dotWidth / 2;
219
+
189
220
  // Disable smooth scroll if not supported
190
- if ('scrollBehavior' in document.documentElement.style) {
221
+ if ("scrollBehavior" in document.documentElement.style) {
191
222
  container.scrollTo({
192
223
  left: Math.max(0, scrollPosition),
193
- behavior: 'smooth'
224
+ behavior: "smooth",
194
225
  });
195
226
  } else {
196
227
  container.scrollLeft = Math.max(0, scrollPosition);
197
228
  }
198
229
  }
199
230
  } catch (error) {
200
- console.warn('Dot scrolling error:', error);
231
+ console.warn("Dot scrolling error:", error);
201
232
  }
202
233
  }
203
234
  }, 50);
204
-
235
+
205
236
  return () => clearTimeout(scrollTimeout);
206
237
  }, [currentSlide, totalPages]);
207
238
 
208
239
  // Carousel settings
209
- const settings = useMemo(() => ({
210
- dots: false,
211
- infinite: false,
212
- speed: 600,
213
- slidesToShow: Math.min(projects.length, slidesToShow),
214
- slidesToScroll: slidesToShow,
215
- autoplay: false,
216
- adaptiveHeight: false,
217
- centerPadding: '20px',
218
- centerMode: false,
219
- variableWidth: false,
220
- swipeToSlide: false,
221
- focusOnSelect: false,
222
- responsive: [
223
- {
224
- breakpoint: 1024,
225
- settings: {
226
- slidesToShow: Math.min(projects.length, 2),
227
- slidesToScroll: 2,
228
- dots: false,
229
- }
240
+ const settings = useMemo(
241
+ () => ({
242
+ dots: false,
243
+ infinite: false,
244
+ speed: 600,
245
+ slidesToShow: Math.min(projects.length, slidesToShow),
246
+ slidesToScroll: slidesToShow,
247
+ autoplay: false,
248
+ adaptiveHeight: false,
249
+ centerPadding: "20px",
250
+ centerMode: false,
251
+ variableWidth: false,
252
+ swipeToSlide: false,
253
+ focusOnSelect: false,
254
+ responsive: [
255
+ {
256
+ breakpoint: 1024,
257
+ settings: {
258
+ slidesToShow: Math.min(projects.length, 2),
259
+ slidesToScroll: 2,
260
+ dots: false,
261
+ },
262
+ },
263
+ {
264
+ breakpoint: 600,
265
+ settings: {
266
+ slidesToShow: 1,
267
+ slidesToScroll: 1,
268
+ dots: false,
269
+ arrows: false,
270
+ },
271
+ },
272
+ ],
273
+ className: styles.projectsCarousel,
274
+ beforeChange: (current, next) => {
275
+ setAtBeginning(next === 0);
276
+ setCurrentSlide(Math.floor(next / slidesToShow));
277
+ setAtEnd(
278
+ next + Math.min(projects.length, slidesToShow) >= projects.length,
279
+ );
230
280
  },
231
- {
232
- breakpoint: 600,
233
- settings: {
234
- slidesToShow: 1,
235
- slidesToScroll: 1,
236
- dots: false,
237
- arrows: false,
238
- }
239
- }
240
- ],
241
- className: styles.projectsCarousel,
242
- beforeChange: (current, next) => {
243
- setAtBeginning(next === 0);
244
- setCurrentSlide(Math.floor(next / slidesToShow));
245
- setAtEnd(next + Math.min(projects.length, slidesToShow) >= projects.length);
246
- },
247
- }), [projects, slidesToShow]);
281
+ }),
282
+ [projects, slidesToShow],
283
+ );
248
284
 
249
285
  // Navigation handlers
250
286
  const goToNext = useCallback(() => {
@@ -264,10 +300,10 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
264
300
  if (!url) return null;
265
301
 
266
302
  return (
267
- <a
268
- href={url}
269
- target="_blank"
270
- rel="noopener noreferrer"
303
+ <a
304
+ href={url}
305
+ target="_blank"
306
+ rel="noopener noreferrer"
271
307
  className={styles.projectLink}
272
308
  aria-label={ariaLabel}
273
309
  >
@@ -279,48 +315,48 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
279
315
 
280
316
  // Get state label and class
281
317
  const getProjectStateInfo = useCallback((state) => {
282
- switch(state?.toLowerCase()) {
318
+ switch (state?.toLowerCase()) {
283
319
  // For projects currently in active development
284
- case 'active':
285
- return {
286
- label: 'Active',
320
+ case "active":
321
+ return {
322
+ label: "Active",
287
323
  className: styles.stateActive,
288
324
  };
289
325
  // For finished projects
290
- case 'completed':
291
- return {
292
- label: 'Completed',
326
+ case "completed":
327
+ return {
328
+ label: "Completed",
293
329
  className: styles.stateCompleted,
294
330
  };
295
331
  // For projects receiving updates/maintenance
296
- case 'maintenance':
297
- return {
298
- label: 'Maintenance',
332
+ case "maintenance":
333
+ return {
334
+ label: "Maintenance",
299
335
  className: styles.stateMaintenance,
300
336
  };
301
337
  // For temporarily paused development
302
- case 'paused':
303
- return {
304
- label: 'Paused',
338
+ case "paused":
339
+ return {
340
+ label: "Paused",
305
341
  className: styles.statePaused,
306
342
  };
307
343
  // For projects no longer maintained
308
- case 'archived':
309
- return {
310
- label: 'Archived',
344
+ case "archived":
345
+ return {
346
+ label: "Archived",
311
347
  className: styles.stateArchived,
312
348
  };
313
349
  // For future projects in planning stage
314
- case 'planned':
315
- return {
316
- label: 'Planned',
350
+ case "planned":
351
+ return {
352
+ label: "Planned",
317
353
  className: styles.statePlanned,
318
354
  };
319
355
  // Default state when not specified
320
- case 'n/a':
356
+ case "n/a":
321
357
  default:
322
- return {
323
- label: 'N/A',
358
+ return {
359
+ label: "N/A",
324
360
  className: styles.stateNA,
325
361
  };
326
362
  }
@@ -332,9 +368,9 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
332
368
 
333
369
  // Determine if we should use scrollable or centered layout
334
370
  const fewDots = totalPages <= 5;
335
-
371
+
336
372
  return (
337
- <div
373
+ <div
338
374
  className={`${styles.navDotsContainer} ${fewDots ? styles.centerDots : styles.scrollDots}`}
339
375
  role="tablist"
340
376
  aria-label="Project carousel navigation"
@@ -342,7 +378,7 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
342
378
  {Array.from({ length: totalPages }, (_, i) => (
343
379
  <button
344
380
  key={i}
345
- className={`${styles.navDot} ${currentSlide === i ? styles.activeDot : ''}`}
381
+ className={`${styles.navDot} ${currentSlide === i ? styles.activeDot : ""}`}
346
382
  onClick={() => goToSlide(i)}
347
383
  aria-label={`Go to slide ${i + 1} of ${totalPages}`}
348
384
  aria-selected={currentSlide === i}
@@ -356,17 +392,21 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
356
392
  }, [currentSlide, totalPages, goToSlide]);
357
393
 
358
394
  return (
359
- <div id={id} className={`${styles.projectsSection} ${className || ''}`} role="region" aria-label="Projects section">
395
+ <div
396
+ id={id}
397
+ className={`${styles.projectsSection} ${className || ""}`}
398
+ role="region"
399
+ aria-label="Projects section"
400
+ >
360
401
  <div className={styles.projectsContainer}>
361
402
  <div className={styles.projectsHeader}>
362
- <h2 className={styles.projectsTitle}>
363
- {title || "My Projects"}
364
- </h2>
403
+ <h2 className={styles.projectsTitle}>{title || "My Projects"}</h2>
365
404
  <p className={styles.projectsSubtitle}>
366
- {subtitle || "A collection of all my works, with featured projects highlighted"}
405
+ {subtitle ||
406
+ "A collection of all my works, with featured projects highlighted"}
367
407
  </p>
368
408
  </div>
369
-
409
+
370
410
  {projects.length === 0 ? (
371
411
  <div className={styles.noProjects}>
372
412
  <p>No projects to display.</p>
@@ -374,8 +414,8 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
374
414
  ) : (
375
415
  <div className={styles.carouselContainer}>
376
416
  {/* Desktop navigation buttons (sides) */}
377
- <button
378
- className={`${styles.carouselControl} ${styles.prevButton} ${styles.desktopOnly} ${atBeginning ? styles.disabledButton : ''}`}
417
+ <button
418
+ className={`${styles.carouselControl} ${styles.prevButton} ${styles.desktopOnly} ${atBeginning ? styles.disabledButton : ""}`}
379
419
  onClick={goToPrev}
380
420
  aria-label="View previous projects"
381
421
  aria-disabled={atBeginning}
@@ -384,25 +424,33 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
384
424
  >
385
425
  <FaChevronLeft aria-hidden="true" />
386
426
  </button>
387
-
388
- <div className={styles.carouselWrapper} aria-roledescription="carousel" aria-label="Projects carousel">
427
+
428
+ <div
429
+ className={styles.carouselWrapper}
430
+ aria-roledescription="carousel"
431
+ aria-label="Projects carousel"
432
+ >
389
433
  <Slider ref={sliderRef} {...settings}>
390
434
  {projects.map((project, index) => (
391
- <div
392
- key={project.id || project.title + index}
393
- className={styles.carouselSlide}
435
+ <div
436
+ key={project.id || project.title + index}
437
+ className={styles.carouselSlide}
394
438
  data-project-id={project.id}
395
- aria-roledescription="slide"
439
+ aria-roledescription="slide"
396
440
  aria-label={`Project ${index + 1} of ${projects.length}: ${project.title}`}
397
441
  >
398
- <div className={`${styles.carouselCard} ${project.featured ? styles.featuredCard : ''}`}>
442
+ <div
443
+ className={`${styles.carouselCard} ${project.featured ? styles.featuredCard : ""}`}
444
+ >
399
445
  {/* Project state badge */}
400
446
  {project.state && (
401
- <div
447
+ <div
402
448
  className={styles.projectStateBadge}
403
449
  title={`Project status: ${getProjectStateInfo(project.state).label}`}
404
450
  >
405
- <span className={`${styles.projectStateLabel} ${getProjectStateInfo(project.state).className}`}>
451
+ <span
452
+ className={`${styles.projectStateLabel} ${getProjectStateInfo(project.state).className}`}
453
+ >
406
454
  {getProjectStateInfo(project.state).label}
407
455
  </span>
408
456
  </div>
@@ -410,74 +458,82 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
410
458
 
411
459
  <div className={styles.projectImageContainer}>
412
460
  {project.image && (
413
- <img
414
- src={project.image}
415
- alt={project.title}
416
- className={styles.projectImage}
461
+ <img
462
+ src={project.image}
463
+ alt={project.title}
464
+ className={styles.projectImage}
417
465
  loading="lazy"
418
466
  />
419
467
  )}
420
-
468
+
421
469
  {/* Featured badge */}
422
470
  {project.featured && (
423
- <div className={styles.featuredBadge} title="Featured Project" aria-label="Featured project">
471
+ <div
472
+ className={styles.featuredBadge}
473
+ title="Featured Project"
474
+ aria-label="Featured project"
475
+ >
424
476
  <FaStar aria-hidden="true" />
425
477
  </div>
426
478
  )}
427
479
  </div>
428
-
480
+
429
481
  <div className={styles.projectContent}>
430
482
  <h3 className={styles.projectTitle}>{project.title}</h3>
431
-
483
+
432
484
  {project.tags?.length > 0 && (
433
485
  <div className={styles.projectTags}>
434
- {project.tags.map(tag => (
435
- <span key={tag} className={styles.projectTag}>{tag}</span>
486
+ {project.tags.map((tag) => (
487
+ <span key={tag} className={styles.projectTag}>
488
+ {tag}
489
+ </span>
436
490
  ))}
437
491
  </div>
438
492
  )}
439
-
440
- <p className={styles.projectDescription}>{project.description}</p>
493
+
494
+ <p className={styles.projectDescription}>
495
+ {project.description}
496
+ </p>
441
497
  </div>
442
-
498
+
443
499
  <div className={styles.projectLinks}>
444
500
  {renderProjectLink(
445
- project.website,
446
- FaGlobe,
447
- "Website",
448
- `Visit ${project.title} website`
501
+ project.website,
502
+ FaGlobe,
503
+ "Website",
504
+ `Visit ${project.title} website`,
449
505
  )}
450
-
506
+
451
507
  {renderProjectLink(
452
- project.github,
453
- FaGithub,
454
- "Source",
455
- `Repository with source code`
508
+ project.github,
509
+ FaGithub,
510
+ "Source",
511
+ `Repository with source code`,
456
512
  )}
457
-
513
+
458
514
  {renderProjectLink(
459
- project.Demo,
460
- FaPlay,
461
- "Demo",
462
- `Live demo for ${project.title}`
515
+ project.Demo,
516
+ FaPlay,
517
+ "Demo",
518
+ `Live demo for ${project.title}`,
463
519
  )}
464
520
  </div>
465
521
  </div>
466
522
  </div>
467
523
  ))}
468
524
  </Slider>
469
-
525
+
470
526
  {/* Desktop navigation dots */}
471
527
  <div className={styles.desktopDotsContainer}>
472
528
  {renderNavigationDots()}
473
529
  </div>
474
-
530
+
475
531
  {/* Mobile navigation controls (bottom) */}
476
532
  <div className={styles.mobileNavigationControls}>
477
533
  {totalPages > 1 && (
478
534
  <>
479
- <button
480
- className={`${styles.carouselControl} ${styles.prevButton} ${atBeginning ? styles.disabledButton : ''}`}
535
+ <button
536
+ className={`${styles.carouselControl} ${styles.prevButton} ${atBeginning ? styles.disabledButton : ""}`}
481
537
  onClick={goToPrev}
482
538
  aria-label="View previous projects"
483
539
  aria-disabled={atBeginning}
@@ -486,17 +542,17 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
486
542
  >
487
543
  <FaChevronLeft aria-hidden="true" />
488
544
  </button>
489
-
545
+
490
546
  {/* Mobile navigation dots */}
491
- <div
547
+ <div
492
548
  className={styles.dotsScrollContainer}
493
549
  ref={dotsContainerRef}
494
550
  >
495
551
  {renderNavigationDots()}
496
552
  </div>
497
-
498
- <button
499
- className={`${styles.carouselControl} ${styles.nextButton} ${atEnd ? styles.disabledButton : ''}`}
553
+
554
+ <button
555
+ className={`${styles.carouselControl} ${styles.nextButton} ${atEnd ? styles.disabledButton : ""}`}
500
556
  onClick={goToNext}
501
557
  aria-label="View next projects"
502
558
  aria-disabled={atEnd}
@@ -509,10 +565,10 @@ export default function ProjectsSection({ id, className, title, subtitle }) {
509
565
  )}
510
566
  </div>
511
567
  </div>
512
-
568
+
513
569
  {/* Desktop navigation button (right side) */}
514
- <button
515
- className={`${styles.carouselControl} ${styles.nextButton} ${styles.desktopOnly} ${atEnd ? styles.disabledButton : ''}`}
570
+ <button
571
+ className={`${styles.carouselControl} ${styles.nextButton} ${styles.desktopOnly} ${atEnd ? styles.disabledButton : ""}`}
516
572
  onClick={goToNext}
517
573
  aria-label="View next projects"
518
574
  aria-disabled={atEnd}
@@ -5,13 +5,13 @@ import { FaQuestionCircle } from "react-icons/fa";
5
5
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
6
6
  import useIsBrowser from "@docusaurus/useIsBrowser";
7
7
 
8
- import Tooltip from "#components/Tooltip/index.js";
8
+ import Tooltip from "../Tooltip/index.js";
9
9
 
10
10
  // Default icon & icon
11
11
  const DEFAULT_ICON = FaQuestionCircle;
12
12
  const DEFAULT_COLOR = "var(--ifm-color-primary)";
13
13
 
14
- import { iconMap } from "#config/iconMappings";
14
+ import { iconMap } from "../../config/iconMappings.js";
15
15
 
16
16
  export default function SocialIcons({ showAll = false }) {
17
17
  const { siteConfig } = useDocusaurusContext();
package/src/pages/Home.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Docusaurus Utils
2
2
  import Layout from "@theme/Layout";
3
3
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
4
- import UpdateTitle from "#utils/updateTitle";
4
+ import UpdateTitle from "../utils/updateTitle.js";
5
5
 
6
6
  // Import components
7
7
  import HeroSection from "#components/HeroSection/index.js";
@@ -3,7 +3,7 @@ import Layout from "@theme/Layout";
3
3
  import NoteCards from "#components/NoteIndex/index.js";
4
4
  import { usePluginData } from "@docusaurus/useGlobalData";
5
5
  import ScrollToTop from "#components/ScrollToTop/index.js";
6
- import HashNavigation from "#utils/HashNavigation";
6
+ import HashNavigation from "../utils/HashNavigation.js";
7
7
 
8
8
  const style = {
9
9
  notesContainer: {
@@ -12,7 +12,7 @@ import { useState } from "react";
12
12
  import Layout from "@theme/Layout";
13
13
  import Head from "@docusaurus/Head";
14
14
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
15
- import "#css/tasks.css";
15
+ import "../css/tasks.css";
16
16
  import {
17
17
  FaClipboardList,
18
18
  FaSyncAlt,