portosaurus 1.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.
Files changed (57) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +116 -0
  3. package/bin/portosaurus.js +337 -0
  4. package/internal/notes/index.md +10 -0
  5. package/internal/sidebars.js +20 -0
  6. package/internal/src/components/AboutSection/index.js +67 -0
  7. package/internal/src/components/AboutSection/styles.module.css +492 -0
  8. package/internal/src/components/ContactSection/index.js +94 -0
  9. package/internal/src/components/ContactSection/styles.module.css +327 -0
  10. package/internal/src/components/ExperienceSection/index.js +25 -0
  11. package/internal/src/components/ExperienceSection/styles.module.css +180 -0
  12. package/internal/src/components/HeroSection/index.js +61 -0
  13. package/internal/src/components/HeroSection/styles.module.css +471 -0
  14. package/internal/src/components/NoteIndex/index.js +127 -0
  15. package/internal/src/components/NoteIndex/styles.module.css +143 -0
  16. package/internal/src/components/ProjectsSection/index.js +529 -0
  17. package/internal/src/components/ProjectsSection/styles.module.css +830 -0
  18. package/internal/src/components/ScrollToTop/index.js +98 -0
  19. package/internal/src/components/ScrollToTop/styles.module.css +96 -0
  20. package/internal/src/components/SocialLinks/index.js +129 -0
  21. package/internal/src/components/SocialLinks/styles.module.css +55 -0
  22. package/internal/src/components/Tooltip/index.js +30 -0
  23. package/internal/src/components/Tooltip/styles.module.css +92 -0
  24. package/internal/src/config/iconMappings.js +329 -0
  25. package/internal/src/config/metaTags.js +240 -0
  26. package/internal/src/config/prism.js +179 -0
  27. package/internal/src/config/sidebar.js +20 -0
  28. package/internal/src/css/bootstrap.css +6 -0
  29. package/internal/src/css/catppuccin.css +632 -0
  30. package/internal/src/css/custom.css +186 -0
  31. package/internal/src/css/tasks.css +868 -0
  32. package/internal/src/pages/index.js +98 -0
  33. package/internal/src/pages/notes.js +88 -0
  34. package/internal/src/pages/tasks.js +310 -0
  35. package/internal/src/utils/HashNavigation.js +250 -0
  36. package/internal/src/utils/appVersion.js +27 -0
  37. package/internal/src/utils/compileConfig.js +82 -0
  38. package/internal/src/utils/cssUtils.js +99 -0
  39. package/internal/src/utils/filterEnabledItems.js +21 -0
  40. package/internal/src/utils/generateFavicon.js +256 -0
  41. package/internal/src/utils/generateRobotsTxt.js +97 -0
  42. package/internal/src/utils/iconExtractor.js +159 -0
  43. package/internal/src/utils/imageDownloader.js +88 -0
  44. package/internal/src/utils/imageProcessor.js +134 -0
  45. package/internal/src/utils/linkShortner.js +0 -0
  46. package/internal/src/utils/updateTitle.js +107 -0
  47. package/package.json +51 -0
  48. package/template/.github/workflows/deploy.yml +57 -0
  49. package/template/README.md +70 -0
  50. package/template/blog/authors.yml +5 -0
  51. package/template/blog/welcome.md +10 -0
  52. package/template/config.js +233 -0
  53. package/template/notes/getting-started.md +7 -0
  54. package/template/static/README.md +33 -0
  55. package/utils/createConfig.js +227 -0
  56. package/utils/logger.js +19 -0
  57. package/utils/packageManager.js +88 -0
@@ -0,0 +1,492 @@
1
+
2
+ /* Animations*/
3
+
4
+ @keyframes skillAppear {
5
+ to {
6
+ opacity: 1;
7
+ transform: translateY(0);
8
+ }
9
+ }
10
+
11
+ @keyframes fadeSlideIn {
12
+ from {
13
+ opacity: 0;
14
+ transform: translateY(10px);
15
+ }
16
+ to {
17
+ opacity: 1;
18
+ transform: translateY(0);
19
+ }
20
+ }
21
+
22
+ @keyframes slideUp {
23
+ from {
24
+ opacity: 0;
25
+ transform: translateY(20px);
26
+ }
27
+ to {
28
+ opacity: 1;
29
+ transform: translateY(0);
30
+ }
31
+ }
32
+
33
+ @keyframes fadeIn {
34
+ from { opacity: 0; }
35
+ to { opacity: 1; }
36
+ }
37
+
38
+
39
+ /* Styles */
40
+
41
+ .aboutSection {
42
+ scroll-margin-top: var(--ifm-scroll-margin-top);
43
+ padding: 0.5rem 0 9.5rem;
44
+ background-color: var(--ifm-background-color);
45
+ min-height: 100vh;
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ position: relative;
50
+ width: 100%;
51
+ }
52
+
53
+ .aboutContainer {
54
+ max-width: 1200px;
55
+ margin: 0 auto;
56
+ padding: 0 2rem;
57
+ width: 100%;
58
+ position: relative;
59
+ z-index: 1;
60
+ }
61
+
62
+ .aboutHeader {
63
+ text-align: center;
64
+ margin-bottom: 4.7rem;
65
+ }
66
+
67
+ .aboutHeading {
68
+ font-size: 2.8rem;
69
+ font-weight: 600;
70
+ color: var(--ifm-color-primary);
71
+ margin-bottom: 0.6rem;
72
+ animation: slideUp 0.5s ease-out forwards;
73
+ position: relative;
74
+ display: inline-block;
75
+ }
76
+
77
+ .aboutHeading::after {
78
+ content: '';
79
+ position: absolute;
80
+ width: 30%;
81
+ height: 3px;
82
+ bottom: -0.5rem;
83
+ left: 35%;
84
+ background-color: var(--ifm-color-primary);
85
+ border-radius: 2px;
86
+ }
87
+
88
+ .aboutContent {
89
+ display: flex;
90
+ flex-direction: column;
91
+ gap: 3rem;
92
+ padding: 0;
93
+ animation: fadeIn 0.8s ease-out 0.3s both;
94
+ align-items: center;
95
+ }
96
+
97
+ .aboutBio {
98
+ display: flex;
99
+ flex-direction: row;
100
+ gap: 4rem;
101
+ width: 100%;
102
+ align-items: center;
103
+ }
104
+
105
+ .bioImageContainer {
106
+ flex: 1;
107
+ display: flex;
108
+ justify-content: center;
109
+ align-items: center;
110
+ padding-top: 0;
111
+ align-self: stretch;
112
+ margin-bottom: 1.3rem;
113
+ }
114
+
115
+ .imageWrapper {
116
+ position: relative;
117
+ border-radius: 12px;
118
+ overflow: hidden;
119
+ box-shadow: 0 10px 20px var(--ifm-shadow-color);
120
+ transform: none;
121
+ transition: transform 0.4s ease, box-shadow 0.4s ease;
122
+ max-width: 350px;
123
+ margin: auto 0;
124
+ }
125
+
126
+ .imageWrapper::before {
127
+ content: '';
128
+ position: absolute;
129
+ top: 0;
130
+ left: 0;
131
+ right: 0;
132
+ bottom: 0;
133
+ border: 2px solid var(--ifm-color-primary);
134
+ border-radius: 10px;
135
+ opacity: 0.2;
136
+ pointer-events: none;
137
+ z-index: 1;
138
+ }
139
+
140
+ .imageWrapper:hover {
141
+ transform: translateY(-8px);
142
+ box-shadow: 0 15px 30px var(--ifm-shadow-color);
143
+ }
144
+
145
+ .aboutImage {
146
+ display: block;
147
+ max-width: 100%;
148
+ height: auto;
149
+ border-radius: 8px;
150
+ object-fit: cover;
151
+ transition: filter 0.3s ease;
152
+ }
153
+
154
+ .bioTextContainer {
155
+ flex: 1.5;
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: 1.2rem;
159
+ align-self: flex-start;
160
+ }
161
+
162
+ .bioText {
163
+ display: flex;
164
+ flex-direction: column;
165
+ gap: 8px;
166
+ align-self: flex-start;
167
+ margin-top: -0.5rem;
168
+ }
169
+
170
+ .aboutParagraph {
171
+ margin-bottom: 0.2rem;
172
+ font-size: 1.05rem;
173
+ line-height: 1.8;
174
+ color: var(--ifm-font-color-base);
175
+ position: relative;
176
+ padding-left: 0.8rem;
177
+ opacity: 0;
178
+ animation: fadeSlideIn 0.5s ease-out forwards;
179
+ animation-delay: calc(0.3s + var(--paragraph-index, 0) * 0.15s);
180
+ }
181
+
182
+ .aboutParagraph:last-child {
183
+ margin-bottom: 0;
184
+ }
185
+
186
+ .aboutParagraph::before {
187
+ content: '';
188
+ position: absolute;
189
+ left: 0;
190
+ top: 0.5rem;
191
+ bottom: 0.5rem;
192
+ width: 3px;
193
+ background: linear-gradient(to bottom, var(--ifm-color-primary), transparent);
194
+ border-radius: 4px;
195
+ opacity: 0.7;
196
+ }
197
+
198
+ .resumeButtonWrapper {
199
+ margin-top: 1rem;
200
+ }
201
+
202
+ .resumeButton {
203
+ display: inline-block;
204
+ padding: 0.6rem 1.5rem;
205
+ font-size: 0.95rem;
206
+ font-weight: 500;
207
+ text-decoration: none;
208
+ color: var(--ifm-background-color);
209
+ background-color: var(--ifm-color-primary);
210
+ border-radius: 4px;
211
+ transition: all 0.3s ease, transform 0.2s ease;
212
+ border: 2px solid var(--ifm-color-primary);
213
+ position: relative;
214
+ overflow: hidden;
215
+ z-index: 1;
216
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
217
+ }
218
+
219
+ .resumeButton::before {
220
+ content: '';
221
+ position: absolute;
222
+ top: 0;
223
+ left: -100%;
224
+ width: 100%;
225
+ height: 100%;
226
+ background: linear-gradient(
227
+ 90deg,
228
+ transparent,
229
+ rgba(255, 255, 255, 0.2),
230
+ transparent
231
+ );
232
+ transition: left 0.7s ease;
233
+ z-index: -1;
234
+ }
235
+
236
+ .resumeButton:hover {
237
+ background-color: transparent;
238
+ color: var(--ifm-color-primary);
239
+ transform: translateY(-3px);
240
+ box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
241
+ text-decoration: none;
242
+ }
243
+
244
+ .resumeButton:hover::before {
245
+ left: 100%;
246
+ }
247
+
248
+ .buttonText {
249
+ position: relative;
250
+ z-index: 2;
251
+ }
252
+
253
+ .skillsContainer {
254
+ width: 100%;
255
+ padding: 0.8rem 0 0.5rem;
256
+ position: relative;
257
+ overflow: hidden;
258
+ margin-top: 0;
259
+ }
260
+
261
+ .skillsTitle {
262
+ font-size: 1.4rem;
263
+ margin-bottom: 1.2rem;
264
+ color: var(--ifm-color-primary);
265
+ font-weight: 600;
266
+ padding-left: 0;
267
+ position: relative;
268
+ display: inline-block;
269
+ }
270
+
271
+ .skillsTitle::after {
272
+ content: '';
273
+ position: absolute;
274
+ width: 40%;
275
+ height: 2px;
276
+ bottom: -0.4rem;
277
+ left: 0;
278
+ background-color: var(--ifm-color-primary);
279
+ opacity: 0.5;
280
+ border-radius: 2px;
281
+ }
282
+
283
+ .skillsGrid {
284
+ display: flex;
285
+ flex-wrap: wrap;
286
+ gap: 0.9rem;
287
+ padding-left: 0;
288
+ padding-top: 0.4rem;
289
+ margin-bottom: 0.5rem;
290
+ }
291
+
292
+ .skillBadge {
293
+ background-color: rgba(var(--ctp-lavender-rgb), 0.08);
294
+ color: var(--ctp-lavender);
295
+ border-radius: 20px;
296
+ padding: 0.5rem 1rem;
297
+ font-size: 0.95rem;
298
+ font-weight: 500;
299
+ transition: all 0.3s ease;
300
+ border: 1px solid rgba(var(--ctp-lavender-rgb), 0.15);
301
+ display: flex;
302
+ align-items: center;
303
+ justify-content: center;
304
+ opacity: 0;
305
+ animation: skillAppear 0.4s ease-out forwards;
306
+ transform: translateY(10px);
307
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
308
+ }
309
+
310
+ .skillBadge:hover {
311
+ transform: translateY(-3px);
312
+ box-shadow: 0 5px 12px rgba(0, 0, 0, 0.1);
313
+ background-color: rgba(var(--ctp-lavender-rgb), 0.15);
314
+ border-color: rgba(var(--ctp-lavender-rgb), 0.3);
315
+ }
316
+
317
+ /* Responsive styles */
318
+ @media (max-width: 992px) {
319
+ .aboutBio {
320
+ gap: 3rem;
321
+ }
322
+ }
323
+
324
+ @media (max-width: 768px) {
325
+ .aboutSection {
326
+ scroll-margin-top: var(--ifm-scroll-margin-top-mobile);
327
+ padding: 1.5rem 0 4rem;
328
+ }
329
+
330
+ .aboutContainer {
331
+ padding: 0 1.5rem;
332
+ }
333
+
334
+ .aboutHeader {
335
+ margin-bottom: 2rem;
336
+ }
337
+
338
+ .aboutHeading {
339
+ font-size: 2.4rem;
340
+ }
341
+
342
+ .aboutBio {
343
+ flex-direction: column;
344
+ gap: 2rem;
345
+ }
346
+
347
+ .bioImageContainer {
348
+ width: 100%;
349
+ padding-top: 0;
350
+ padding-bottom: 0.8rem;
351
+ margin-bottom: 0.8rem;
352
+ }
353
+
354
+ .imageWrapper {
355
+ transform: none;
356
+ max-width: 300px;
357
+ margin: 0 auto;
358
+ }
359
+
360
+ .bioTextContainer {
361
+ width: 100%;
362
+ gap: 1rem;
363
+ }
364
+
365
+ .skillsContainer {
366
+ padding: 0.6rem 0 0.5rem;
367
+ margin-top: 0;
368
+ }
369
+
370
+ .skillsTitle {
371
+ margin-bottom: 1rem;
372
+ display: block;
373
+ text-align: center;
374
+ width: 100%;
375
+ }
376
+
377
+ .skillsTitle::after {
378
+ width: 40px;
379
+ left: 50%;
380
+ transform: translateX(-50%);
381
+ }
382
+
383
+ .skillsGrid {
384
+ justify-content: center;
385
+ }
386
+ }
387
+
388
+ @media (max-width: 480px) {
389
+ .aboutSection {
390
+ scroll-margin-top: 25px;
391
+ padding: 0.5rem 0 2.5rem;
392
+ min-height: auto;
393
+ }
394
+
395
+ .aboutContainer {
396
+ padding: 0 1rem;
397
+ }
398
+
399
+ .aboutHeader {
400
+ margin-bottom: 1.4rem;
401
+ }
402
+
403
+ .aboutHeading {
404
+ font-size: 1.8rem;
405
+ }
406
+
407
+ .aboutContent {
408
+ gap: 1.5rem;
409
+ }
410
+
411
+ .aboutBio {
412
+ gap: 1.6rem;
413
+ }
414
+
415
+ .bioImageContainer {
416
+ padding-top: 0;
417
+ padding-bottom: 0.3rem;
418
+ margin-bottom: 0;
419
+ }
420
+
421
+ .imageWrapper {
422
+ max-width: 200px;
423
+ margin: 0 auto 0.5rem;
424
+ }
425
+
426
+ .aboutParagraph {
427
+ font-size: 0.95rem;
428
+ line-height: 1.6;
429
+ padding-left: 0.6rem;
430
+ }
431
+
432
+ .aboutParagraph::before {
433
+ width: 2px;
434
+ }
435
+
436
+ .skillsTitle {
437
+ font-size: 1.1rem;
438
+ margin-bottom: 0.8rem;
439
+ text-align: center;
440
+ }
441
+
442
+ .skillsGrid {
443
+ gap: 0.6rem;
444
+ justify-content: center;
445
+ padding-top: 0.3rem;
446
+ }
447
+
448
+ .skillBadge {
449
+ font-size: 0.8rem;
450
+ padding: 0.35rem 0.8rem;
451
+ border-radius: 16px;
452
+ }
453
+
454
+ .bioTextContainer {
455
+ gap: 0.6rem;
456
+ }
457
+
458
+ .skillsContainer {
459
+ padding: 0.3rem 0 0.5rem;
460
+ }
461
+ }
462
+
463
+ @media (max-width: 350px) {
464
+ .aboutHeading {
465
+ font-size: 1.6rem;
466
+ }
467
+
468
+ .imageWrapper {
469
+ max-width: 180px;
470
+ }
471
+
472
+ .skillBadge {
473
+ font-size: 0.75rem;
474
+ padding: 0.3rem 0.7rem;
475
+ }
476
+
477
+ .aboutParagraph {
478
+ font-size: 0.9rem;
479
+ line-height: 1.5;
480
+ }
481
+ }
482
+
483
+ @media (prefers-reduced-motion: reduce) {
484
+ .aboutHeading, .aboutContent, .aboutImage,
485
+ .resumeButton, .skillBadge, .imageWrapper, .resumeButton::before,
486
+ .aboutParagraph {
487
+ animation: none !important;
488
+ transition: none !important;
489
+ opacity: 1;
490
+ transform: none !important;
491
+ }
492
+ }
@@ -0,0 +1,94 @@
1
+ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
2
+ import { iconMap } from "@site/src/config/iconMappings";
3
+ import { FaQuestionCircle } from "react-icons/fa";
4
+ import styles from "./styles.module.css";
5
+
6
+ const sortEmail = (links) => {
7
+ return [...links].sort((a, b) => {
8
+ const isEmailA =
9
+ a.url?.startsWith("mailto:") ||
10
+ a.icon?.toLowerCase().includes("email") ||
11
+ a.name?.toLowerCase().includes("email");
12
+
13
+ const isEmailB =
14
+ b.url?.startsWith("mailto:") ||
15
+ b.icon?.toLowerCase().includes("email") ||
16
+ b.name?.toLowerCase().includes("email");
17
+
18
+ if (isEmailA && !isEmailB) return -1;
19
+ if (!isEmailA && isEmailB) return 1;
20
+
21
+ return 0;
22
+ });
23
+ };
24
+
25
+ export default function ContactSection({ id, className, title, subtitle }) {
26
+ const { siteConfig } = useDocusaurusContext();
27
+ const { customFields } = siteConfig;
28
+ let socialLinks = customFields.socialLinks.links || [];
29
+
30
+ socialLinks = sortEmail(socialLinks);
31
+
32
+ return (
33
+ <div
34
+ id={id}
35
+ className={`${styles.contactSection} ${className || ""}`}
36
+ role="region"
37
+ aria-label="Contact section"
38
+ >
39
+ <div className={styles.contactContainer}>
40
+ <div className={styles.contactHeader}>
41
+ <h2 className={styles.contactTitle}>{title || "Get In Touch"}</h2>
42
+ <p className={styles.contactSubtitle}>
43
+ {subtitle ||
44
+ "Feel free to reach out for collaborations, questions, or just to say hello!"}
45
+ </p>
46
+ </div>
47
+
48
+ {/* SocialCard */}
49
+ <div className={styles.gridWrapper}>
50
+ <div
51
+ className={styles.socialGrid}
52
+ role="list"
53
+ aria-label="Social media and contact links"
54
+ >
55
+ {socialLinks.map((social, index) => {
56
+ const iconData = iconMap[social.icon] || {};
57
+
58
+ const name = social.name || "?";
59
+ const Icon = iconData.icon || FaQuestionCircle;
60
+ const iconColor = iconData.color || "#3578e5";
61
+ const description =
62
+ name === "?" ? "" : social.desc || `Connect with me on ${name}`;
63
+ const url = social.url;
64
+
65
+ return (
66
+ <a
67
+ key={name}
68
+ href={url}
69
+ target="_blank"
70
+ rel="noopener noreferrer"
71
+ className={styles.socialCard}
72
+ style={{
73
+ "--card-index": index,
74
+ "--icon-hover-color": iconColor,
75
+ }}
76
+ aria-label={`Connect with me on ${name}: ${description}`}
77
+ role="listitem"
78
+ >
79
+ {Icon && (
80
+ <div className={styles.socialIcon}>
81
+ <Icon aria-hidden="true" />
82
+ </div>
83
+ )}
84
+ <h3 className={styles.socialTitle}>{name}</h3>
85
+ <p className={styles.socialDesc}>{description}</p>
86
+ </a>
87
+ );
88
+ })}
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ );
94
+ }