@portosaur/theme 0.1.4 → 0.2.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.
Files changed (31) hide show
  1. package/package.json +10 -3
  2. package/src/plugins/theme.mjs +2 -0
  3. package/theme/DocCategoryGeneratedIndexPage/index.jsx +4 -10
  4. package/theme/MDXComponents.jsx +1 -1
  5. package/theme/Root.jsx +1 -1
  6. package/theme/components/AboutSection/index.jsx +89 -249
  7. package/theme/components/ContactSection/index.jsx +72 -153
  8. package/theme/components/ExperienceSection/index.jsx +35 -106
  9. package/theme/components/HeroSection/index.jsx +64 -186
  10. package/theme/components/NavArrow/index.jsx +38 -55
  11. package/theme/components/NoteIndex/index.jsx +50 -116
  12. package/theme/components/Preview/components/FeedbackStates.jsx +45 -190
  13. package/theme/components/Preview/components/FileTabs.jsx +17 -24
  14. package/theme/components/Preview/components/PreviewContent.jsx +37 -62
  15. package/theme/components/Preview/components/PreviewHeader.jsx +146 -380
  16. package/theme/components/Preview/components/Triggers/Pv.jsx +50 -78
  17. package/theme/components/Preview/components/Triggers/SrcPv.jsx +16 -47
  18. package/theme/components/Preview/components/Triggers/index.jsx +2 -2
  19. package/theme/components/Preview/components/ViewerWindow.jsx +160 -268
  20. package/theme/components/Preview/index.jsx +3 -3
  21. package/theme/components/Preview/renderers/CodeRenderer.jsx +81 -109
  22. package/theme/components/Preview/renderers/ImageRenderer.jsx +30 -67
  23. package/theme/components/Preview/renderers/PdfRenderer.jsx +31 -52
  24. package/theme/components/Preview/renderers/WebRenderer.jsx +18 -32
  25. package/theme/components/Preview/state/index.jsx +46 -30
  26. package/theme/components/ProjectsSection/index.jsx +278 -573
  27. package/theme/components/SocialLinks/index.jsx +43 -55
  28. package/theme/components/Tooltip/index.jsx +28 -39
  29. package/theme/pages/index.jsx +23 -87
  30. package/theme/pages/notes.jsx +26 -104
  31. package/theme/pages/tasks.jsx +220 -903
@@ -4,6 +4,8 @@ import { FaQuestionCircle } from "react-icons/fa";
4
4
  import useScrollReveal from "../../hooks/useScrollReveal";
5
5
  import useBrokenLinks from "@docusaurus/useBrokenLinks";
6
6
  import styles from "./styles.module.css";
7
+
8
+ // Sort so email links appear first in the contact grid
7
9
  const sortEmail = (links) => {
8
10
  return [...links].sort((a, b) => {
9
11
  const isEmailA =
@@ -19,170 +21,87 @@ const sortEmail = (links) => {
19
21
  return 0;
20
22
  });
21
23
  };
24
+
22
25
  export default function ContactSection({ id, className }) {
23
26
  const { siteConfig } = useDocusaurusContext();
24
27
  const brokenLinks = useBrokenLinks();
28
+
25
29
  if (id) {
26
30
  brokenLinks.collectAnchor(id);
27
31
  }
32
+
28
33
  const { customFields } = siteConfig;
29
- const socialLinksConfig = customFields.socialLinks || {};
30
- if (socialLinksConfig.enable === false) return null;
34
+ const socialLinksConfig = customFields.socialSection || {};
35
+
36
+ if (socialLinksConfig.enable === false) {
37
+ return null;
38
+ }
39
+
31
40
  let socialLinks = socialLinksConfig.links || [];
32
41
  const displayHeading = socialLinksConfig.heading;
33
42
  const displaySubheading = socialLinksConfig.subheading;
34
43
  const [sectionRef, isVisible] = useScrollReveal();
44
+
35
45
  socialLinks = sortEmail(socialLinks);
36
- return jsxDEV_7x81h0kn(
37
- "div",
38
- {
39
- id,
40
- ref: sectionRef,
41
- className: `${styles.contactSection} ${isVisible ? "is-visible" : ""} ${className || ""}`,
42
- role: "region",
43
- "aria-label": "Contact section",
44
- children: jsxDEV_7x81h0kn(
45
- "div",
46
- {
47
- className: styles.contactContainer,
48
- children: [
49
- jsxDEV_7x81h0kn(
50
- "div",
51
- {
52
- className: styles.contactHeader,
53
- children: [
54
- jsxDEV_7x81h0kn(
55
- "h2",
56
- {
57
- className: styles.contactTitle,
58
- children: displayHeading,
59
- },
60
- undefined,
61
- false,
62
- undefined,
63
- this,
64
- ),
65
- jsxDEV_7x81h0kn(
66
- "p",
67
- {
68
- className: styles.contactSubtitle,
69
- children: displaySubheading,
70
- },
71
- undefined,
72
- false,
73
- undefined,
74
- this,
75
- ),
76
- ],
77
- },
78
- undefined,
79
- true,
80
- undefined,
81
- this,
82
- ),
83
- jsxDEV_7x81h0kn(
84
- "div",
85
- {
86
- className: styles.gridWrapper,
87
- children: jsxDEV_7x81h0kn(
88
- "div",
89
- {
90
- className: styles.socialGrid,
91
- role: "list",
92
- "aria-label": "Social media and contact links",
93
- children: socialLinks.map((social, index) => {
94
- const iconKey = (
95
- social.icon ||
96
- social.name ||
97
- ""
98
- ).toLowerCase();
99
- const iconData = iconMap[iconKey] || {};
100
- const name = social.name;
101
- const Icon = iconData.icon || FaQuestionCircle;
102
- const iconColor =
103
- iconData.color || "var(--ifm-color-primary)";
104
- const desc = social.desc || `Connect with me on ${name}`;
105
- const url = social.url;
106
- return jsxDEV_7x81h0kn(
107
- "a",
108
- {
109
- href: url,
110
- target: "_blank",
111
- rel: "noopener noreferrer",
112
- className: styles.socialCard,
113
- style: {
114
- "--card-index": index,
115
- "--icon-hover-color": iconColor,
116
- },
117
- "aria-label": `Connect with me on ${name}: ${desc}`,
118
- role: "listitem",
119
- children: [
120
- Icon &&
121
- jsxDEV_7x81h0kn(
122
- "div",
123
- {
124
- className: styles.socialIcon,
125
- children: jsxDEV_7x81h0kn(
126
- Icon,
127
- { "aria-hidden": "true" },
128
- undefined,
129
- false,
130
- undefined,
131
- this,
132
- ),
133
- },
134
- undefined,
135
- false,
136
- undefined,
137
- this,
138
- ),
139
- jsxDEV_7x81h0kn(
140
- "h3",
141
- { className: styles.socialTitle, children: name },
142
- undefined,
143
- false,
144
- undefined,
145
- this,
146
- ),
147
- jsxDEV_7x81h0kn(
148
- "p",
149
- { className: styles.socialDesc, children: desc },
150
- undefined,
151
- false,
152
- undefined,
153
- this,
154
- ),
155
- ],
156
- },
157
- name,
158
- true,
159
- undefined,
160
- this,
161
- );
162
- }),
163
- },
164
- undefined,
165
- false,
166
- undefined,
167
- this,
168
- ),
169
- },
170
- undefined,
171
- false,
172
- undefined,
173
- this,
174
- ),
175
- ],
176
- },
177
- undefined,
178
- true,
179
- undefined,
180
- this,
181
- ),
182
- },
183
- undefined,
184
- false,
185
- undefined,
186
- this,
46
+
47
+ return (
48
+ <div
49
+ id={id}
50
+ ref={sectionRef}
51
+ className={`${styles.contactSection} ${isVisible ? "is-visible" : ""} ${className || ""}`}
52
+ role="region"
53
+ aria-label="Contact section"
54
+ >
55
+ <div className={styles.contactContainer}>
56
+ {/* Heading */}
57
+ <div className={styles.contactHeader}>
58
+ <h2 className={styles.contactTitle}>{displayHeading}</h2>
59
+ <p className={styles.contactSubtitle}>{displaySubheading}</p>
60
+ </div>
61
+
62
+ {/* Social cards grid */}
63
+ <div className={styles.gridWrapper}>
64
+ <div
65
+ className={styles.socialGrid}
66
+ role="list"
67
+ aria-label="Social media and contact links"
68
+ >
69
+ {socialLinks.map((social, index) => {
70
+ const iconKey = (social.icon || social.name || "").toLowerCase();
71
+ const iconData = iconMap[iconKey] || {};
72
+ const name = social.name;
73
+ const Icon = iconData.icon || FaQuestionCircle;
74
+ const iconColor = iconData.color || "var(--ifm-color-primary)";
75
+ const desc = social.desc || `Connect with me on ${name}`;
76
+ const url = social.url;
77
+
78
+ return (
79
+ <a
80
+ key={name}
81
+ href={url}
82
+ target="_blank"
83
+ rel="noopener noreferrer"
84
+ className={styles.socialCard}
85
+ style={{
86
+ "--card-index": index,
87
+ "--icon-hover-color": iconColor,
88
+ }}
89
+ aria-label={`Connect with me on ${name}: ${desc}`}
90
+ role="listitem"
91
+ >
92
+ {Icon && (
93
+ <div className={styles.socialIcon}>
94
+ <Icon aria-hidden="true" />
95
+ </div>
96
+ )}
97
+ <h3 className={styles.socialTitle}>{name}</h3>
98
+ <p className={styles.socialDesc}>{desc}</p>
99
+ </a>
100
+ );
101
+ })}
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
187
106
  );
188
107
  }
@@ -1,119 +1,48 @@
1
1
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
2
2
  import useBrokenLinks from "@docusaurus/useBrokenLinks";
3
3
  import styles from "./styles.module.css";
4
+
4
5
  export default function ExperienceSection({ id, className }) {
5
6
  const { siteConfig } = useDocusaurusContext();
6
7
  const brokenLinks = useBrokenLinks();
8
+
7
9
  if (id) {
8
10
  brokenLinks.collectAnchor(id);
9
11
  }
10
- const experience = siteConfig.customFields?.experience || {};
11
- if (experience.enable === false) return null;
12
+
13
+ const experience = siteConfig.customFields?.experienceSection || {};
14
+
15
+ if (experience.enable === false) {
16
+ return null;
17
+ }
18
+
12
19
  const displayHeading = experience.heading;
13
20
  const displaySubheading = experience.subheading;
14
- return jsxDEV_7x81h0kn(
15
- "div",
16
- {
17
- id,
18
- className: `${styles.experienceSection} ${className || ""}`,
19
- role: "region",
20
- "aria-label": "Experience section",
21
- children: jsxDEV_7x81h0kn(
22
- "div",
23
- {
24
- className: styles.experienceContainer,
25
- children: [
26
- jsxDEV_7x81h0kn(
27
- "div",
28
- {
29
- className: styles.experienceHeader,
30
- children: [
31
- jsxDEV_7x81h0kn(
32
- "h2",
33
- {
34
- className: styles.experienceTitle,
35
- children: displayHeading,
36
- },
37
- undefined,
38
- false,
39
- undefined,
40
- this,
41
- ),
42
- jsxDEV_7x81h0kn(
43
- "p",
44
- {
45
- className: styles.experienceSubtitle,
46
- children: displaySubheading,
47
- },
48
- undefined,
49
- false,
50
- undefined,
51
- this,
52
- ),
53
- ],
54
- },
55
- undefined,
56
- true,
57
- undefined,
58
- this,
59
- ),
60
- jsxDEV_7x81h0kn(
61
- "div",
62
- {
63
- className: styles.noticeWrapper,
64
- children: jsxDEV_7x81h0kn(
65
- "div",
66
- {
67
- className: styles.noticeBox,
68
- role: "status",
69
- "aria-live": "polite",
70
- children: [
71
- jsxDEV_7x81h0kn(
72
- "p",
73
- {
74
- className: styles.noticeText,
75
- children: "Coming Soon!",
76
- },
77
- undefined,
78
- false,
79
- undefined,
80
- this,
81
- ),
82
- jsxDEV_7x81h0kn(
83
- "p",
84
- {
85
- className: styles.noticeDesc,
86
- children: "This section is under construction.",
87
- },
88
- undefined,
89
- false,
90
- undefined,
91
- this,
92
- ),
93
- ],
94
- },
95
- undefined,
96
- true,
97
- undefined,
98
- this,
99
- ),
100
- },
101
- undefined,
102
- false,
103
- undefined,
104
- this,
105
- ),
106
- ],
107
- },
108
- undefined,
109
- true,
110
- undefined,
111
- this,
112
- ),
113
- },
114
- undefined,
115
- false,
116
- undefined,
117
- this,
21
+
22
+ return (
23
+ <div
24
+ id={id}
25
+ className={`${styles.experienceSection} ${className || ""}`}
26
+ role="region"
27
+ aria-label="Experience section"
28
+ >
29
+ <div className={styles.experienceContainer}>
30
+ {/* Heading */}
31
+ <div className={styles.experienceHeader}>
32
+ <h2 className={styles.experienceTitle}>{displayHeading}</h2>
33
+ <p className={styles.experienceSubtitle}>{displaySubheading}</p>
34
+ </div>
35
+
36
+ {/* Placeholder */}
37
+ <div className={styles.noticeWrapper}>
38
+ <div className={styles.noticeBox} role="status" aria-live="polite">
39
+ <p className={styles.noticeText}>Coming Soon!</p>
40
+ <p className={styles.noticeDesc}>
41
+ This section is under construction.
42
+ </p>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
118
47
  );
119
48
  }
@@ -1,198 +1,76 @@
1
1
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
2
2
  import useBrokenLinks from "@docusaurus/useBrokenLinks";
3
- import SocialLinks from "../SocialLinks/index.js";
3
+ import SocialLinks from "../SocialLinks/index.jsx";
4
4
  import styles from "./styles.module.css";
5
+
5
6
  export default function HeroSection({ id, className }) {
6
7
  const { siteConfig } = useDocusaurusContext();
7
8
  const brokenLinks = useBrokenLinks();
9
+
8
10
  if (id) {
9
11
  brokenLinks.collectAnchor(id);
10
12
  }
13
+
11
14
  const { customFields } = siteConfig;
12
- const intro = customFields.heroSection.intro;
13
- const title = customFields.heroSection.title;
14
- const subtitle = customFields.heroSection.subtitle;
15
- const profession = customFields.heroSection.profession;
16
- const desc = customFields.heroSection.desc;
17
- const profilePic = customFields.heroSection.profilePic;
18
- const learnMoreButtonText = customFields.heroSection.learnMoreButtonTxt;
19
- return jsxDEV_7x81h0kn(
20
- "div",
21
- {
22
- id,
23
- className: `${styles.hero} ${className || ""}`,
24
- role: "region",
25
- "aria-label": "Hero section",
26
- children: jsxDEV_7x81h0kn(
27
- "div",
28
- {
29
- className: styles.container,
30
- children: [
31
- jsxDEV_7x81h0kn(
32
- "div",
33
- {
34
- className: styles.leftSection,
35
- children: [
36
- jsxDEV_7x81h0kn(
37
- "p",
38
- { className: styles.intro, children: intro },
39
- undefined,
40
- false,
41
- undefined,
42
- this,
43
- ),
44
- jsxDEV_7x81h0kn(
45
- "h1",
46
- {
47
- className: styles.title,
48
- children: [
49
- title,
50
- jsxDEV_7x81h0kn(
51
- "span",
52
- { className: styles.titleComma, children: "," },
53
- undefined,
54
- false,
55
- undefined,
56
- this,
57
- ),
58
- ],
59
- },
60
- undefined,
61
- true,
62
- undefined,
63
- this,
64
- ),
65
- jsxDEV_7x81h0kn(
66
- "div",
67
- {
68
- className: styles.subtitleWrapper,
69
- children: [
70
- jsxDEV_7x81h0kn(
71
- "span",
72
- { className: styles.subtitle, children: subtitle },
73
- undefined,
74
- false,
75
- undefined,
76
- this,
77
- ),
78
- jsxDEV_7x81h0kn(
79
- "h2",
80
- {
81
- className: styles.profession,
82
- children: profession,
83
- },
84
- undefined,
85
- false,
86
- undefined,
87
- this,
88
- ),
89
- jsxDEV_7x81h0kn(
90
- "span",
91
- { className: styles.subtitle, children: "." },
92
- undefined,
93
- false,
94
- undefined,
95
- this,
96
- ),
97
- ],
98
- },
99
- undefined,
100
- true,
101
- undefined,
102
- this,
103
- ),
104
- jsxDEV_7x81h0kn(
105
- "p",
106
- { className: styles.description, children: desc },
107
- undefined,
108
- false,
109
- undefined,
110
- this,
111
- ),
112
- jsxDEV_7x81h0kn(
113
- "div",
114
- {
115
- className: styles.actionRow,
116
- children: [
117
- jsxDEV_7x81h0kn(
118
- "div",
119
- {
120
- className: styles.cta,
121
- children: jsxDEV_7x81h0kn(
122
- "a",
123
- {
124
- href: "#about",
125
- className: styles.ctaButton,
126
- "aria-label": "Learn more about me",
127
- children: learnMoreButtonText,
128
- },
129
- undefined,
130
- false,
131
- undefined,
132
- this,
133
- ),
134
- },
135
- undefined,
136
- false,
137
- undefined,
138
- this,
139
- ),
140
- jsxDEV_7x81h0kn(
141
- SocialLinks,
142
- { links: customFields.heroSection.social },
143
- undefined,
144
- false,
145
- undefined,
146
- this,
147
- ),
148
- ],
149
- },
150
- undefined,
151
- true,
152
- undefined,
153
- this,
154
- ),
155
- ],
156
- },
157
- undefined,
158
- true,
159
- undefined,
160
- this,
161
- ),
162
- jsxDEV_7x81h0kn(
163
- "div",
164
- {
165
- className: styles.rightSection,
166
- children: jsxDEV_7x81h0kn(
167
- "img",
168
- {
169
- src: `${profilePic}`,
170
- alt: "profile",
171
- className: styles.profilePic,
172
- loading: "lazy",
173
- },
174
- undefined,
175
- false,
176
- undefined,
177
- this,
178
- ),
179
- },
180
- undefined,
181
- false,
182
- undefined,
183
- this,
184
- ),
185
- ],
186
- },
187
- undefined,
188
- true,
189
- undefined,
190
- this,
191
- ),
192
- },
193
- undefined,
194
- false,
195
- undefined,
196
- this,
15
+ const { heroSection } = customFields;
16
+
17
+ const intro = heroSection.intro;
18
+ const title = heroSection.title;
19
+ const subtitle = heroSection.subtitle;
20
+ const profession = heroSection.profession;
21
+ const desc = heroSection.desc;
22
+ const profilePic = heroSection.profilePic;
23
+ const learnMoreButtonText = heroSection.learnMoreButtonTxt;
24
+
25
+ return (
26
+ <div
27
+ id={id}
28
+ className={`${styles.hero} ${className || ""}`}
29
+ role="region"
30
+ aria-label="Hero section"
31
+ >
32
+ <div className={styles.container}>
33
+ {/* Left: text content */}
34
+ <div className={styles.leftSection}>
35
+ <p className={styles.intro}>{intro}</p>
36
+
37
+ <h1 className={styles.title}>
38
+ {title}
39
+ <span className={styles.titleComma}>,</span>
40
+ </h1>
41
+
42
+ <div className={styles.subtitleWrapper}>
43
+ <span className={styles.subtitle}>{subtitle}</span>
44
+ <h2 className={styles.profession}>{profession}</h2>
45
+ <span className={styles.subtitle}>.</span>
46
+ </div>
47
+
48
+ <p className={styles.description}>{desc}</p>
49
+
50
+ <div className={styles.actionRow}>
51
+ <div className={styles.cta}>
52
+ <a
53
+ href="#about"
54
+ className={styles.ctaButton}
55
+ aria-label="Learn more about me"
56
+ >
57
+ {learnMoreButtonText}
58
+ </a>
59
+ </div>
60
+ <SocialLinks links={heroSection.social} />
61
+ </div>
62
+ </div>
63
+
64
+ {/* Right: profile picture */}
65
+ <div className={styles.rightSection}>
66
+ <img
67
+ src={`${profilePic}`}
68
+ alt="profile"
69
+ className={styles.profilePic}
70
+ loading="lazy"
71
+ />
72
+ </div>
73
+ </div>
74
+ </div>
197
75
  );
198
76
  }