portosaurus 0.14.0

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.

Potentially problematic release.


This version of portosaurus might be problematic. Click here for more details.

Files changed (64) hide show
  1. package/.vscode/snippets.code-snippets +79 -0
  2. package/AGENTS.md +37 -0
  3. package/GG/config.js +233 -0
  4. package/GG/package.json +14 -0
  5. package/GG/static/.nojekyll +0 -0
  6. package/GG/static/docusaurus-snippet.css +3 -0
  7. package/GG/static/img/icon-bg.png +0 -0
  8. package/GG/static/img/icon-old.png +0 -0
  9. package/GG/static/img/icon.png +0 -0
  10. package/GG/static/img/project-blank.png +0 -0
  11. package/GG/static/img/social-card.jpeg +0 -0
  12. package/LICENSE +674 -0
  13. package/README.md +57 -0
  14. package/bin/portosaurus.js +136 -0
  15. package/package.json +36 -0
  16. package/src/config/iconMappings.js +329 -0
  17. package/src/config/metaTags.js +240 -0
  18. package/src/config/prism.js +179 -0
  19. package/src/config/sidebar.js +20 -0
  20. package/src/configLoader.js +99 -0
  21. package/src/index.js +79 -0
  22. package/src/pages/index.js +98 -0
  23. package/src/pages/notes.js +88 -0
  24. package/src/pages/tasks.js +251 -0
  25. package/src/theme/components/AboutSection/index.js +67 -0
  26. package/src/theme/components/AboutSection/styles.module.css +492 -0
  27. package/src/theme/components/ContactSection/index.js +87 -0
  28. package/src/theme/components/ContactSection/styles.module.css +327 -0
  29. package/src/theme/components/ExperienceSection/index.js +25 -0
  30. package/src/theme/components/ExperienceSection/styles.module.css +180 -0
  31. package/src/theme/components/HeroSection/index.js +63 -0
  32. package/src/theme/components/HeroSection/styles.module.css +471 -0
  33. package/src/theme/components/NoteIndex/index.js +119 -0
  34. package/src/theme/components/NoteIndex/styles.module.css +143 -0
  35. package/src/theme/components/ProjectsSection/index.js +529 -0
  36. package/src/theme/components/ProjectsSection/styles.module.css +830 -0
  37. package/src/theme/components/ScrollToTop/index.js +98 -0
  38. package/src/theme/components/ScrollToTop/styles.module.css +96 -0
  39. package/src/theme/components/SocialLinks/index.js +129 -0
  40. package/src/theme/components/SocialLinks/styles.module.css +55 -0
  41. package/src/theme/components/Tooltip/index.js +30 -0
  42. package/src/theme/components/Tooltip/styles.module.css +92 -0
  43. package/src/theme/css/bootstrap.css +6 -0
  44. package/src/theme/css/catppuccin.css +632 -0
  45. package/src/theme/css/custom.css +186 -0
  46. package/src/theme/css/tasks.css +868 -0
  47. package/src/theme/staticLink/.nojekyll +0 -0
  48. package/src/theme/staticLink/docusaurus-snippet.css +3 -0
  49. package/src/theme/staticLink/img/icon-bg.png +0 -0
  50. package/src/theme/staticLink/img/icon-old.png +0 -0
  51. package/src/theme/staticLink/img/icon.png +0 -0
  52. package/src/theme/staticLink/img/project-blank.png +0 -0
  53. package/src/theme/staticLink/img/social-card.jpeg +0 -0
  54. package/src/utils/HashNavigation.js +250 -0
  55. package/src/utils/appVersion.js +27 -0
  56. package/src/utils/cssUtils.js +99 -0
  57. package/src/utils/filterEnabledItems.js +21 -0
  58. package/src/utils/generateFavicon.js +256 -0
  59. package/src/utils/generateRobotsTxt.js +97 -0
  60. package/src/utils/iconExtractor.js +159 -0
  61. package/src/utils/imageDownloader.js +88 -0
  62. package/src/utils/imageProcessor.js +134 -0
  63. package/src/utils/linkShortner.js +0 -0
  64. package/src/utils/updateTitle.js +107 -0
@@ -0,0 +1,98 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import { IoIosArrowUp } from 'react-icons/io';
3
+ import styles from './styles.module.css';
4
+
5
+ export default function ScrollToTop({ hideDelay = 1500 }) {
6
+ const [isVisible, setIsVisible] = useState(false);
7
+ const [isHovering, setIsHovering] = useState(false);
8
+ const timeoutRef = useRef(null);
9
+ const lastScrollTopRef = useRef(0);
10
+
11
+ const startHideTimer = () => {
12
+
13
+ // Clear any existing timeout
14
+ if (timeoutRef.current) {
15
+ clearTimeout(timeoutRef.current);
16
+ }
17
+
18
+ // Only start timer if not hovering
19
+ if (!isHovering) {
20
+ timeoutRef.current = setTimeout(() => {
21
+ setIsVisible(false);
22
+ }, hideDelay);
23
+ }
24
+ };
25
+
26
+ useEffect(() => {
27
+
28
+ const handleScroll = () => {
29
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
30
+ const isScrollingUp = scrollTop < lastScrollTopRef.current;
31
+
32
+ // Save the current scroll position
33
+ lastScrollTopRef.current = scrollTop;
34
+
35
+ // Show button when scrolling up past threshold
36
+ if (isScrollingUp && scrollTop > 300) {
37
+
38
+ setIsVisible(true);
39
+ startHideTimer();
40
+ } else {
41
+
42
+ setIsVisible(false);
43
+
44
+ if (timeoutRef.current) {
45
+ clearTimeout(timeoutRef.current);
46
+ }
47
+ }
48
+ };
49
+
50
+ // Set up event listener
51
+ window.addEventListener('scroll', handleScroll, { passive: true });
52
+
53
+ // Clean up
54
+ return () => {
55
+ window.removeEventListener('scroll', handleScroll);
56
+ if (timeoutRef.current) {
57
+ clearTimeout(timeoutRef.current);
58
+ }
59
+ };
60
+ }, [hideDelay, isHovering]);
61
+
62
+ const handleMouseEnter = () => {
63
+
64
+ setIsHovering(true);
65
+
66
+ if (timeoutRef.current) {
67
+ clearTimeout(timeoutRef.current);
68
+ }
69
+ };
70
+
71
+ const handleMouseLeave = () => {
72
+
73
+ setIsHovering(false);
74
+ startHideTimer();
75
+ };
76
+
77
+ const scrollToTop = () => {
78
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
79
+
80
+ window.scrollTo({
81
+ top: 0,
82
+ behavior: prefersReducedMotion ? 'auto' : 'smooth'
83
+ });
84
+ };
85
+
86
+ return (
87
+ <button
88
+ className={`${styles.scrollToTop} ${isVisible ? styles.visible : ''}`}
89
+ onClick={scrollToTop}
90
+ onMouseEnter={handleMouseEnter}
91
+ onMouseLeave={handleMouseLeave}
92
+ aria-label="Scroll to top"
93
+ title="Scroll to top"
94
+ >
95
+ <IoIosArrowUp />
96
+ </button>
97
+ );
98
+ }
@@ -0,0 +1,96 @@
1
+ .scrollToTop {
2
+ position: fixed;
3
+ bottom: 30px;
4
+ right: 30px;
5
+ background-color: var(--ifm-color-primary);
6
+ color: var(--ifm-background-color);
7
+ width: 50px;
8
+ height: 50px;
9
+ border-radius: 50%;
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ cursor: pointer;
14
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
15
+ border: none;
16
+ z-index: 100;
17
+ opacity: 0;
18
+ transform: translateY(20px) scale(0.9);
19
+ pointer-events: none;
20
+ transition: opacity 0.3s ease, transform 0.3s ease, background-color 0.3s ease;
21
+ }
22
+
23
+ .scrollToTop.visible {
24
+ opacity: 1;
25
+ transform: translateY(0) scale(1);
26
+ pointer-events: auto;
27
+ }
28
+
29
+ .scrollToTop:hover {
30
+ background-color: var(--ifm-color-primary-dark);
31
+ transform: translateY(-3px) scale(1.05);
32
+ }
33
+
34
+ .scrollToTop:active {
35
+ transform: translateY(-1px) scale(1.02);
36
+ }
37
+
38
+ .scrollToTop svg {
39
+ width: 28px;
40
+ height: 28px;
41
+ }
42
+
43
+ .scrollToTop:hover svg {
44
+ transform: scale(1.1);
45
+ }
46
+
47
+ /* Responsive adjustments */
48
+ @media (max-width: 768px) {
49
+
50
+ .scrollToTop {
51
+ width: 45px;
52
+ height: 45px;
53
+ bottom: 25px;
54
+ right: 25px;
55
+ }
56
+
57
+ .scrollToTop svg {
58
+ width: 24px;
59
+ height: 24px;
60
+ }
61
+ }
62
+
63
+ @media (max-width: 480px) {
64
+
65
+ .scrollToTop {
66
+ width: 40px;
67
+ height: 40px;
68
+ bottom: 20px;
69
+ right: 50%;
70
+ transform: translateX(50%) translateY(20px) scale(0.9);
71
+ }
72
+
73
+ .scrollToTop.visible {
74
+ transform: translateX(50%) scale(1);
75
+ }
76
+
77
+ .scrollToTop:hover {
78
+ transform: translateX(50%) translateY(-3px) scale(1.05);
79
+ }
80
+
81
+ .scrollToTop:active {
82
+ transform: translateX(50%) translateY(-1px) scale(1.02);
83
+ }
84
+
85
+ .scrollToTop svg {
86
+ width: 22px;
87
+ height: 22px;
88
+ }
89
+ }
90
+
91
+ /* Accessibility preferences */
92
+ @media (prefers-reduced-motion: reduce) {
93
+ .scrollToTop {
94
+ transition: none;
95
+ }
96
+ }
@@ -0,0 +1,129 @@
1
+ import { useState, useEffect, useMemo, useCallback } from 'react';
2
+ import styles from './styles.module.css';
3
+ import { FaQuestionCircle } from 'react-icons/fa';
4
+
5
+ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
6
+ import useIsBrowser from '@docusaurus/useIsBrowser';
7
+
8
+ import Tooltip from '@site/src/components/Tooltip';
9
+ import { iconMap } from '@site/src/config/iconMappings';
10
+
11
+
12
+ // Default icon & icon
13
+ const DEFAULT_ICON = FaQuestionCircle;
14
+ const DEFAULT_COLOR = 'var(--ifm-color-primary)';
15
+
16
+
17
+ export default function SocialIcons({ showAll = false }) {
18
+ const { siteConfig } = useDocusaurusContext();
19
+ const { customFields } = siteConfig;
20
+ const isBrowser = useIsBrowser();
21
+
22
+ const [animationDelays, setAnimationDelays] = useState({});
23
+
24
+ const allSocialLinks = customFields.socialLinks.links || [];
25
+
26
+ // FIX: `to prevent unnecessary recalculations`
27
+ const socialLinks = useMemo(() => {
28
+ return showAll
29
+ ? allSocialLinks
30
+ : allSocialLinks.filter(link => link.pin);
31
+ }, [allSocialLinks, showAll]);
32
+
33
+ // Calculate delays based on screen size
34
+ const calculateDelays = useCallback(() => {
35
+ if (!isBrowser) return {};
36
+
37
+ const isTablet = window.innerWidth <= 768;
38
+ const isMobile = window.innerWidth <= 480;
39
+ const delays = {};
40
+
41
+ const baseDelay = isMobile ? 0.7 : (isTablet ? 0.9 : 1.3);
42
+ const incrementDelay = 0.1;
43
+
44
+ socialLinks.forEach((_, index) => {
45
+ delays[index] = `${baseDelay + (index * incrementDelay)}s`;
46
+ });
47
+
48
+ return delays;
49
+ }, [isBrowser, socialLinks]);
50
+
51
+ useEffect(() => {
52
+ if (!isBrowser) return;
53
+
54
+ // Set initial delays
55
+ setAnimationDelays(calculateDelays());
56
+
57
+ const handleResize = () => {
58
+ setAnimationDelays(calculateDelays());
59
+ };
60
+
61
+ window.addEventListener('resize', handleResize);
62
+ return () => window.removeEventListener('resize', handleResize);
63
+ }, [isBrowser, calculateDelays]);
64
+
65
+
66
+ // Get icon component and color
67
+ const getIconDetails = (iconName) => {
68
+
69
+ if (!iconName) {
70
+ return {
71
+ icon: DEFAULT_ICON,
72
+ color: DEFAULT_COLOR
73
+ };
74
+ }
75
+
76
+ const formattedIconName = iconName.toLowerCase();
77
+ const iconDetails = iconMap[formattedIconName];
78
+
79
+ if (!iconDetails) {
80
+ return {
81
+ icon: DEFAULT_ICON,
82
+ color: DEFAULT_COLOR
83
+ };
84
+ }
85
+
86
+ return {
87
+ icon: iconDetails.icon,
88
+ color: iconDetails.color || DEFAULT_COLOR
89
+ };
90
+ };
91
+
92
+ if (socialLinks.length === 0) {
93
+ return null;
94
+ }
95
+
96
+ return (
97
+ <div className={styles.socialIcons}>
98
+ {
99
+ socialLinks.map((social, index) => {
100
+ const { icon: IconComponent, color: iconColor } = getIconDetails(social.icon);
101
+ const href = social.url || '#';
102
+ const displayColor = social.color || iconColor;
103
+
104
+ return (
105
+ <Tooltip
106
+ key={index}
107
+ content={social.desc || social.icon || 'Link'}
108
+ position="top"
109
+ color={displayColor}
110
+ >
111
+ <a
112
+ href={href}
113
+ target="_blank"
114
+ rel="noopener noreferrer"
115
+ className={styles.socialLink}
116
+ style={{
117
+ '--hover-color': displayColor,
118
+ animationDelay: animationDelays[index] || '0s'
119
+ }}
120
+ aria-label={social.icon || 'social link'}
121
+ >
122
+ <IconComponent size={24} />
123
+ </a>
124
+ </Tooltip>
125
+ );
126
+ })}
127
+ </div>
128
+ );
129
+ }
@@ -0,0 +1,55 @@
1
+
2
+ /* Animation */
3
+ @keyframes fadeIn {
4
+ from { opacity: 0; }
5
+ to { opacity: 1; }
6
+ }
7
+
8
+
9
+ .socialIcons {
10
+ display: flex;
11
+ align-items: center;
12
+ gap: 18px;
13
+ height: 38px;
14
+ }
15
+
16
+ .socialLink {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ color: var(--ifm-color-primary);
21
+ transition: color 0.3s, transform 0.2s;
22
+ position: relative;
23
+ animation: fadeIn 0.3s ease-out forwards;
24
+ opacity: 0;
25
+ }
26
+
27
+ .socialLink:hover {
28
+ opacity: 0.9;
29
+ transform: translateY(-4px) scale(1.15);
30
+ text-decoration: none;
31
+ color: var(--hover-color, var(--ifm-color-primary-dark));
32
+ }
33
+
34
+
35
+ /* Responsive */
36
+ @media (max-width: 768px) {
37
+ .socialIcons {
38
+ justify-content: center;
39
+ width: 100%;
40
+ }
41
+
42
+ .socialLink {
43
+ margin: 0 9px;
44
+ }
45
+
46
+ }
47
+
48
+ /* Accessibility */
49
+ @media (prefers-reduced-motion: reduce) {
50
+ .socialLink {
51
+ animation: none !important;
52
+ opacity: 1;
53
+ transition: none;
54
+ }
55
+ }
@@ -0,0 +1,30 @@
1
+ import React, { useState } from 'react';
2
+ import styles from './styles.module.css';
3
+
4
+ export default function Tooltip({ children, content, position = 'top', color }) {
5
+ const [isVisible, setIsVisible] = useState(false);
6
+
7
+ const tooltipStyle = color ? { '--tooltip-color': color } : {};
8
+
9
+ return (
10
+ <div
11
+ className={styles.tooltipContainer}
12
+ onMouseEnter={() => setIsVisible(true)}
13
+ onMouseLeave={() => setIsVisible(false)}
14
+ onFocus={() => setIsVisible(true)}
15
+ onBlur={() => setIsVisible(false)}
16
+ >
17
+ {children}
18
+ {isVisible && (
19
+ <div
20
+ className={`${styles.tooltip} ${styles[position]}`}
21
+ style={tooltipStyle}
22
+ role="tooltip"
23
+ >
24
+ {content}
25
+ <div className={styles.arrow} />
26
+ </div>
27
+ )}
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,92 @@
1
+ .tooltipContainer {
2
+ position: relative;
3
+ display: inline-flex;
4
+ cursor: pointer;
5
+ }
6
+
7
+ .tooltip {
8
+ position: absolute;
9
+ background-color: var(--tooltip-color, var(--ifm-background-surface-color));
10
+ color: var(--ifm-font-color-base);
11
+ padding: 6px 10px;
12
+ border-radius: 4px;
13
+ font-size: 0.8rem;
14
+ font-weight: 400;
15
+ white-space: nowrap;
16
+ z-index: 10;
17
+ opacity: 0;
18
+ animation: tooltipFadeIn 0.15s ease-out forwards;
19
+ box-shadow: none;
20
+ pointer-events: none;
21
+ }
22
+
23
+ .arrow {
24
+ position: absolute;
25
+ width: 8px;
26
+ height: 8px;
27
+ background-color: inherit;
28
+ }
29
+
30
+ /* Positioning variations */
31
+ .top {
32
+ bottom: 100%;
33
+ left: 50%;
34
+ transform: translateX(-50%) translateY(-10px);
35
+ margin-bottom: 4px;
36
+ }
37
+
38
+ .top .arrow {
39
+ top: 100%;
40
+ left: 50%;
41
+ transform: translateX(-50%) rotate(45deg);
42
+ margin-top: -4px;
43
+ }
44
+
45
+ .bottom {
46
+ top: 100%;
47
+ left: 50%;
48
+ transform: translateX(-50%) translateY(6px);
49
+ }
50
+
51
+ .bottom .arrow {
52
+ bottom: 100%;
53
+ left: 50%;
54
+ transform: translateX(-50%) rotate(45deg);
55
+ margin-bottom: -4px;
56
+ }
57
+
58
+ .left {
59
+ right: 100%;
60
+ top: 50%;
61
+ transform: translateY(-50%) translateX(-6px);
62
+ }
63
+
64
+ .left .arrow {
65
+ right: -4px;
66
+ top: 50%;
67
+ transform: translateY(-50%) rotate(45deg);
68
+ }
69
+
70
+ .right {
71
+ left: 100%;
72
+ top: 50%;
73
+ transform: translateY(-50%) translateX(6px);
74
+ }
75
+
76
+ .right .arrow {
77
+ left: -4px;
78
+ top: 50%;
79
+ transform: translateY(-50%) rotate(45deg);
80
+ }
81
+
82
+ @keyframes tooltipFadeIn {
83
+ from { opacity: 0; }
84
+ to { opacity: 1; }
85
+ }
86
+
87
+ /* Accessibility */
88
+ @media (prefers-reduced-motion: reduce) {
89
+ .tooltip {
90
+ animation: none;
91
+ }
92
+ }
@@ -0,0 +1,6 @@
1
+ .center {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ }
6
+