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,88 @@
1
+ import React from 'react';
2
+ import Layout from '@theme/Layout';
3
+ import NoteCards from '@site/src/components/NoteIndex';
4
+ import { usePluginData } from '@docusaurus/useGlobalData';
5
+ import ScrollToTop from '../components/ScrollToTop';
6
+ import HashNavigation from '../utils/HashNavigation';
7
+
8
+ const style = {
9
+
10
+ notesContainer: {
11
+ padding: '2rem 0',
12
+ maxWidth: '1200px',
13
+ margin: '0 auto'
14
+ },
15
+
16
+ pageTitle: {
17
+ fontSize: '2.5rem',
18
+ textAlign: 'center',
19
+ marginBottom: '0.5rem',
20
+ color: 'var(--ifm-color-primary)',
21
+ animation: 'slideUp 0.5s ease-out forwards'
22
+ },
23
+
24
+ pageDescription: {
25
+ fontSize: '0.9rem',
26
+ textAlign: 'center',
27
+ color: 'var(--ifm-font-color-tertiary)',
28
+ marginBottom: '2rem',
29
+ animation: 'slideUp 0.5s ease-out 0.2s forwards',
30
+ },
31
+
32
+ '@keyframes slideUp': {
33
+ from: {
34
+ opacity: 0,
35
+ transform: 'translateY(20px)'
36
+ },
37
+ to: {
38
+ opacity: 1,
39
+ transform: 'translateY(0)'
40
+ }
41
+ },
42
+
43
+ '@media (prefers-reduced-motion: reduce)': {
44
+ notesContainer: {
45
+ animation: 'none !important'
46
+ },
47
+ pageTitle: {
48
+ animation: 'none !important'
49
+ },
50
+ pageDescription: {
51
+ animation: 'none !important',
52
+ opacity: 1
53
+ }
54
+ }
55
+ };
56
+
57
+ export default function Notes() {
58
+ const { path: docsBasePath } = usePluginData('docusaurus-plugin-content-docs');
59
+ const pathName = docsBasePath.replace('/', '');
60
+ const pageTitle = pathName.charAt(0).toUpperCase() + pathName.slice(1);
61
+
62
+ return (
63
+ <Layout
64
+ title={pageTitle}
65
+ description={`My ${pageTitle}`}
66
+ >
67
+ <main style={style.notesContainer}>
68
+ <div className="container">
69
+ <header className="text-center mb-4">
70
+ <h1 style={style.pageTitle}>
71
+ My Notes
72
+ </h1>
73
+ <p style={style.pageDescription}>
74
+ A collection of my self written notes & reference guides
75
+ </p>
76
+ </header>
77
+ <NoteCards/>
78
+ <ScrollToTop/>
79
+ <HashNavigation
80
+ elementPrefix="note-"
81
+ elementSelector=".note-card"
82
+ effectDuration={6000}
83
+ />
84
+ </div>
85
+ </main>
86
+ </Layout>
87
+ );
88
+ }
@@ -0,0 +1,251 @@
1
+ /*
2
+ __ ___ _ ____ _
3
+ \ \ / (_) |__ ___ / ___|___ __| | ___
4
+ \ \ / /| | '_ \ / _ \ | | / _ \ / _` |/ _ \
5
+ \ V / | | |_) | __/ | |__| (_) | (_| | __/
6
+ \_/ |_|_.__/ \___| \____\___/ \__,_|\___|
7
+
8
+ This Page is completely Vibe coded. No code except small tweaks is written by me.
9
+ */
10
+
11
+
12
+ import { useState } from 'react';
13
+ import Layout from '@theme/Layout';
14
+ import Head from '@docusaurus/Head';
15
+ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
16
+ import '../css/tasks.css';
17
+ import {
18
+ FaClipboardList,
19
+ FaSyncAlt,
20
+ FaClock,
21
+ FaCheckCircle,
22
+ FaFire,
23
+ FaThermometerHalf,
24
+ FaSnowflake,
25
+ FaTasks,
26
+ FaExclamationTriangle
27
+ } from 'react-icons/fa';
28
+
29
+ function TaskList({ filterStatus, taskList }) {
30
+ if (!taskList || !Array.isArray(taskList)) {
31
+ return (
32
+ <div className="task-empty-state">
33
+ <FaTasks className="task-empty-icon" />
34
+ <p>No tasks available</p>
35
+ </div>
36
+ );
37
+ }
38
+
39
+ const filteredTasks = taskList.filter(task =>
40
+ filterStatus ? task.status === filterStatus : true
41
+ );
42
+
43
+ if (filteredTasks.length === 0) {
44
+ return (
45
+ <div className="task-empty-state">
46
+ <FaTasks className="task-empty-icon" />
47
+ <p>No tasks in this category</p>
48
+ </div>
49
+ );
50
+ }
51
+
52
+ // Sort tasks by status first (with completed tasks at bottom), then by priority
53
+ const sortedTasks = [...filteredTasks].sort((a, b) => {
54
+ const statusOrder = { active: 1, pending: 2, completed: 3 };
55
+ const statusDiff = statusOrder[a.status] - statusOrder[b.status];
56
+
57
+ if (statusDiff !== 0) return statusDiff;
58
+
59
+ // Priority order: high, medium, low
60
+ const priorityOrder = { high: 1, medium: 2, low: 3 };
61
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
62
+ });
63
+
64
+ return (
65
+ <div className="task-list-container">
66
+ <div className="task-list-table">
67
+ <div className="task-list-header">
68
+ <div className="task-cell task-cell-status">Status</div>
69
+ <div className="task-cell task-cell-title">Task Details</div>
70
+ <div className="task-cell task-cell-priority">Priority</div>
71
+ </div>
72
+
73
+ <div className="task-rows">
74
+ {sortedTasks.map((task, index) => (
75
+ <div
76
+ key={index}
77
+ className={`task-row ${task.status === 'completed' ? 'task-row-completed' : ''} ${index % 2 === 1 ? 'task-row-striped' : ''}`}
78
+ >
79
+ <div className="task-cell task-cell-status">
80
+ <span className={`badge badge-status-${task.status}`}>
81
+ {task.status === 'completed' && <><FaCheckCircle className="badge-icon" /> Done</>}
82
+ {task.status === 'active' && <><FaSyncAlt className="badge-icon spin" /> In Progress</>}
83
+ {task.status === 'pending' && <><FaClock className="badge-icon" /> Planned</>}
84
+ </span>
85
+ </div>
86
+
87
+ <div className="task-cell task-cell-title">
88
+ <div className="task-title">{task.title}</div>
89
+ {task.description && (
90
+ <div className="task-description">{task.description}</div>
91
+ )}
92
+ </div>
93
+
94
+ <div className="task-cell task-cell-priority">
95
+ <span className={`badge badge-priority-${task.priority}`}>
96
+ {task.priority === 'high' && <><FaFire className="badge-icon" /> High</>}
97
+ {task.priority === 'medium' && <><FaThermometerHalf className="badge-icon" /> Medium</>}
98
+ {task.priority === 'low' && <><FaSnowflake className="badge-icon" /> Low</>}
99
+ </span>
100
+ </div>
101
+ </div>
102
+ ))}
103
+ </div>
104
+ </div>
105
+ </div>
106
+ );
107
+ }
108
+
109
+
110
+ function TaskStats({ taskList }) {
111
+ if (!taskList || !Array.isArray(taskList)) {
112
+ return null;
113
+ }
114
+
115
+ const total = taskList.length;
116
+ const completed = taskList.filter(task => task.status === 'completed').length;
117
+ const active = taskList.filter(task => task.status === 'active').length;
118
+ const pending = taskList.filter(task => task.status === 'pending').length;
119
+ const percentComplete = total > 0 ? Math.round((completed / total) * 100) : 0;
120
+
121
+ return (
122
+ <div className="stats-container">
123
+ <div className="stat-box">
124
+ <div className="stat-label">Total Tasks</div>
125
+ <div className="stat-value">{total}</div>
126
+ </div>
127
+ <div className="stat-box">
128
+ <div className="stat-label">Completed</div>
129
+ <div className="stat-value stat-value-completed">{completed}</div>
130
+ </div>
131
+ <div className="stat-box">
132
+ <div className="stat-label">In Progress</div>
133
+ <div className="stat-value stat-value-active">{active}</div>
134
+ </div>
135
+ <div className="stat-box">
136
+ <div className="stat-label">Planned</div>
137
+ <div className="stat-value stat-value-pending">{pending}</div>
138
+ </div>
139
+ <div className="stat-box">
140
+ <div className="stat-label">Progress</div>
141
+ <div className="stat-value">{percentComplete}%</div>
142
+ <div className="progress-bar-container">
143
+ <div className="progress-bar" style={{width: `${percentComplete}%`}}></div>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ );
148
+ }
149
+
150
+ function TaskTabs({ taskList }) {
151
+ const [activeTab, setActiveTab] = useState('all');
152
+
153
+ if (!taskList || !Array.isArray(taskList)) {
154
+ return null;
155
+ }
156
+
157
+ const tabData = [
158
+ { id: 'all', label: 'All Tasks', icon: <FaClipboardList />, count: taskList.length },
159
+ { id: 'active', label: 'In Progress', icon: <FaSyncAlt className="spin" />, count: taskList.filter(t => t.status === 'active').length },
160
+ { id: 'pending', label: 'Planned', icon: <FaClock />, count: taskList.filter(t => t.status === 'pending').length },
161
+ { id: 'completed', label: 'Completed', icon: <FaCheckCircle />, count: taskList.filter(t => t.status === 'completed').length },
162
+ ];
163
+
164
+ return (
165
+ <div className="task-tabs-container">
166
+ <div className="task-tabs" role="tablist" aria-label="Task categories">
167
+ {tabData.map(tab => (
168
+ <button
169
+ key={tab.id}
170
+ className={`task-tab ${activeTab === tab.id ? 'task-tab-active' : ''}`}
171
+ onClick={() => setActiveTab(tab.id)}
172
+ role="tab"
173
+ aria-selected={activeTab === tab.id}
174
+ aria-controls={`tab-content-${tab.id}`}
175
+ id={`tab-${tab.id}`}
176
+ >
177
+ <span className="task-tab-icon" aria-hidden="true">{tab.icon}</span>
178
+ <span className="task-tab-label">{tab.label}</span>
179
+ <span className="task-tab-count">{tab.count}</span>
180
+ </button>
181
+ ))}
182
+ </div>
183
+
184
+ <div
185
+ className="task-tab-content"
186
+ role="tabpanel"
187
+ id={`tab-content-${activeTab}`}
188
+ aria-labelledby={`tab-${activeTab}`}
189
+ >
190
+ {activeTab === 'all' && <TaskList taskList={taskList} />}
191
+ {activeTab === 'active' && <TaskList taskList={taskList} filterStatus="active" />}
192
+ {activeTab === 'pending' && <TaskList taskList={taskList} filterStatus="pending" />}
193
+ {activeTab === 'completed' && <TaskList taskList={taskList} filterStatus="completed" />}
194
+ </div>
195
+ </div>
196
+ );
197
+ }
198
+
199
+
200
+ export default function TasksPage() {
201
+ const { siteConfig } = useDocusaurusContext();
202
+ const { customFields } = siteConfig || {};
203
+
204
+ const tasksPage = customFields?.tasksPage;
205
+ const title = tasksPage.title;
206
+ const description = tasksPage.description;
207
+ const taskList = tasksPage.enable && tasksPage.taskList ? tasksPage.taskList : [];
208
+
209
+ // If tasks are disabled, show a notice box instead
210
+ if (!tasksPage || !tasksPage.enable) {
211
+ return (
212
+ <Layout title="Tasks are Disabled" description="Tasks are currently disabled">
213
+ <div className="tasks-container">
214
+ <div className="tasks-content">
215
+ <div className="tasks-disabled-notice">
216
+ <div className="disabled-icon">
217
+ <FaExclamationTriangle aria-hidden="true" />
218
+ </div>
219
+ <h2 className="disabled-title">Tasks are currently disabled</h2>
220
+ <p className="disabled-help">
221
+ To enable tasks, set <code>tasks_page.enable</code> to <code>true</code>
222
+ </p>
223
+ </div>
224
+ </div>
225
+ </div>
226
+ </Layout>
227
+ );
228
+ }
229
+
230
+ return (
231
+ <Layout title={title} description={description}>
232
+ <Head>
233
+ <meta property="og:title" content={title} />
234
+ <meta property="og:description" content={description} />
235
+ <meta name="twitter:title" content={title} />
236
+ <meta name="twitter:description" content={description} />
237
+ </Head>
238
+
239
+ <div className="tasks-container">
240
+ <div className="tasks-header">
241
+ <h1 className="tasks-heading">{title}</h1>
242
+ </div>
243
+
244
+ <div className="tasks-content">
245
+ <TaskStats taskList={taskList} />
246
+ <TaskTabs taskList={taskList} />
247
+ </div>
248
+ </div>
249
+ </Layout>
250
+ );
251
+ }
@@ -0,0 +1,67 @@
1
+ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
2
+ import styles from './styles.module.css';
3
+
4
+ export default function AboutSection({ id, className}) {
5
+ const { siteConfig } = useDocusaurusContext();
6
+ const { customFields } = siteConfig;
7
+ const aboutMe = customFields.aboutMe || {};
8
+
9
+ return (
10
+ <div id={id} className={`${styles.aboutSection} ${className || ''}`} role="region" aria-label="About me section">
11
+ <div className={styles.aboutContainer}>
12
+ <div className={styles.aboutHeader}>
13
+ <h2 className={styles.aboutHeading}>{"About Me"}</h2>
14
+ </div>
15
+
16
+ <div className={styles.aboutContent}>
17
+ <div className={styles.aboutBio}>
18
+ <div className={styles.bioImageContainer}>
19
+ {aboutMe.image && (
20
+ <div className={styles.imageWrapper}>
21
+ <img
22
+ src={aboutMe.image}
23
+ alt="About Me"
24
+ className={styles.aboutImage}
25
+ loading="lazy"
26
+ />
27
+ </div>
28
+ )}
29
+ </div>
30
+
31
+ <div className={styles.bioTextContainer}>
32
+ <div className={styles.bioText}>
33
+ {Array.isArray(aboutMe.description) ? (
34
+ aboutMe.description.map((paragraph, index) => (
35
+ <p key={index} className={styles.aboutParagraph}>{paragraph}</p>
36
+ ))
37
+ ) : (
38
+ <p className={styles.aboutParagraph}>
39
+ {aboutMe.description || "Information about me goes here."}
40
+ </p>
41
+ )}
42
+ </div>
43
+
44
+ {aboutMe.skills && aboutMe.skills.length > 0 && (
45
+ <div className={styles.skillsContainer}>
46
+ <h3 className={styles.skillsTitle} id="skills-heading">My Skills</h3>
47
+ <div className={styles.skillsGrid} role="list">
48
+ {aboutMe.skills.map((skill, index) => (
49
+ <div
50
+ key={index}
51
+ className={styles.skillBadge}
52
+ role="listitem"
53
+ style={{ animationDelay: `${index * 0.05}s` }}
54
+ >
55
+ {skill}
56
+ </div>
57
+ ))}
58
+ </div>
59
+ </div>
60
+ )}
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ );
67
+ }