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.
- package/.vscode/snippets.code-snippets +79 -0
- package/AGENTS.md +37 -0
- package/GG/config.js +233 -0
- package/GG/package.json +14 -0
- package/GG/static/.nojekyll +0 -0
- package/GG/static/docusaurus-snippet.css +3 -0
- package/GG/static/img/icon-bg.png +0 -0
- package/GG/static/img/icon-old.png +0 -0
- package/GG/static/img/icon.png +0 -0
- package/GG/static/img/project-blank.png +0 -0
- package/GG/static/img/social-card.jpeg +0 -0
- package/LICENSE +674 -0
- package/README.md +57 -0
- package/bin/portosaurus.js +136 -0
- package/package.json +36 -0
- package/src/config/iconMappings.js +329 -0
- package/src/config/metaTags.js +240 -0
- package/src/config/prism.js +179 -0
- package/src/config/sidebar.js +20 -0
- package/src/configLoader.js +99 -0
- package/src/index.js +79 -0
- package/src/pages/index.js +98 -0
- package/src/pages/notes.js +88 -0
- package/src/pages/tasks.js +251 -0
- package/src/theme/components/AboutSection/index.js +67 -0
- package/src/theme/components/AboutSection/styles.module.css +492 -0
- package/src/theme/components/ContactSection/index.js +87 -0
- package/src/theme/components/ContactSection/styles.module.css +327 -0
- package/src/theme/components/ExperienceSection/index.js +25 -0
- package/src/theme/components/ExperienceSection/styles.module.css +180 -0
- package/src/theme/components/HeroSection/index.js +63 -0
- package/src/theme/components/HeroSection/styles.module.css +471 -0
- package/src/theme/components/NoteIndex/index.js +119 -0
- package/src/theme/components/NoteIndex/styles.module.css +143 -0
- package/src/theme/components/ProjectsSection/index.js +529 -0
- package/src/theme/components/ProjectsSection/styles.module.css +830 -0
- package/src/theme/components/ScrollToTop/index.js +98 -0
- package/src/theme/components/ScrollToTop/styles.module.css +96 -0
- package/src/theme/components/SocialLinks/index.js +129 -0
- package/src/theme/components/SocialLinks/styles.module.css +55 -0
- package/src/theme/components/Tooltip/index.js +30 -0
- package/src/theme/components/Tooltip/styles.module.css +92 -0
- package/src/theme/css/bootstrap.css +6 -0
- package/src/theme/css/catppuccin.css +632 -0
- package/src/theme/css/custom.css +186 -0
- package/src/theme/css/tasks.css +868 -0
- package/src/theme/staticLink/.nojekyll +0 -0
- package/src/theme/staticLink/docusaurus-snippet.css +3 -0
- package/src/theme/staticLink/img/icon-bg.png +0 -0
- package/src/theme/staticLink/img/icon-old.png +0 -0
- package/src/theme/staticLink/img/icon.png +0 -0
- package/src/theme/staticLink/img/project-blank.png +0 -0
- package/src/theme/staticLink/img/social-card.jpeg +0 -0
- package/src/utils/HashNavigation.js +250 -0
- package/src/utils/appVersion.js +27 -0
- package/src/utils/cssUtils.js +99 -0
- package/src/utils/filterEnabledItems.js +21 -0
- package/src/utils/generateFavicon.js +256 -0
- package/src/utils/generateRobotsTxt.js +97 -0
- package/src/utils/iconExtractor.js +159 -0
- package/src/utils/imageDownloader.js +88 -0
- package/src/utils/imageProcessor.js +134 -0
- package/src/utils/linkShortner.js +0 -0
- package/src/utils/updateTitle.js +107 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { getCssVar } from "../utils/cssUtils.js";
|
|
2
|
+
|
|
3
|
+
const backgroundColor = getCssVar('--ifm-background-color');
|
|
4
|
+
|
|
5
|
+
export const metaTags = [
|
|
6
|
+
|
|
7
|
+
// Theme color meta tags
|
|
8
|
+
{
|
|
9
|
+
tagName: 'meta',
|
|
10
|
+
attributes: {
|
|
11
|
+
name: 'msapplication-TileColor',
|
|
12
|
+
content: backgroundColor,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
tagName: 'meta',
|
|
17
|
+
attributes: {
|
|
18
|
+
name: 'theme-color',
|
|
19
|
+
content: backgroundColor,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Android Chrome icons
|
|
24
|
+
{
|
|
25
|
+
tagName: 'link',
|
|
26
|
+
attributes: {
|
|
27
|
+
rel: 'icon',
|
|
28
|
+
type: 'image/png',
|
|
29
|
+
sizes: '36x36',
|
|
30
|
+
href: '/favicon/android-chrome-36x36.png',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
tagName: 'link',
|
|
35
|
+
attributes: {
|
|
36
|
+
rel: 'icon',
|
|
37
|
+
type: 'image/png',
|
|
38
|
+
sizes: '48x48',
|
|
39
|
+
href: '/favicon/android-chrome-48x48.png',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
tagName: 'link',
|
|
44
|
+
attributes: {
|
|
45
|
+
rel: 'icon',
|
|
46
|
+
type: 'image/png',
|
|
47
|
+
sizes: '72x72',
|
|
48
|
+
href: '/favicon/android-chrome-72x72.png',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
tagName: 'link',
|
|
53
|
+
attributes: {
|
|
54
|
+
rel: 'icon',
|
|
55
|
+
type: 'image/png',
|
|
56
|
+
sizes: '96x96',
|
|
57
|
+
href: '/favicon/android-chrome-96x96.png',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
tagName: 'link',
|
|
62
|
+
attributes: {
|
|
63
|
+
rel: 'icon',
|
|
64
|
+
type: 'image/png',
|
|
65
|
+
sizes: '144x144',
|
|
66
|
+
href: '/favicon/android-chrome-144x144.png',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
tagName: 'link',
|
|
71
|
+
attributes: {
|
|
72
|
+
rel: 'icon',
|
|
73
|
+
type: 'image/png',
|
|
74
|
+
sizes: '192x192',
|
|
75
|
+
href: '/favicon/android-chrome-192x192.png',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
tagName: 'link',
|
|
80
|
+
attributes: {
|
|
81
|
+
rel: 'icon',
|
|
82
|
+
type: 'image/png',
|
|
83
|
+
sizes: '256x256',
|
|
84
|
+
href: '/favicon/android-chrome-256x256.png',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
tagName: 'link',
|
|
89
|
+
attributes: {
|
|
90
|
+
rel: 'icon',
|
|
91
|
+
type: 'image/png',
|
|
92
|
+
sizes: '384x384',
|
|
93
|
+
href: '/favicon/android-chrome-384x384.png',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
tagName: 'link',
|
|
98
|
+
attributes: {
|
|
99
|
+
rel: 'icon',
|
|
100
|
+
type: 'image/png',
|
|
101
|
+
sizes: '512x512',
|
|
102
|
+
href: '/favicon/android-chrome-512x512.png',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
// Apple touch icons
|
|
107
|
+
{
|
|
108
|
+
tagName: 'link',
|
|
109
|
+
attributes: {
|
|
110
|
+
rel: 'apple-touch-icon',
|
|
111
|
+
sizes: '57x57',
|
|
112
|
+
href: '/favicon/apple-touch-icon-57x57.png',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
tagName: 'link',
|
|
117
|
+
attributes: {
|
|
118
|
+
rel: 'apple-touch-icon',
|
|
119
|
+
sizes: '60x60',
|
|
120
|
+
href: '/favicon/apple-touch-icon-60x60.png',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
tagName: 'link',
|
|
125
|
+
attributes: {
|
|
126
|
+
rel: 'apple-touch-icon',
|
|
127
|
+
sizes: '72x72',
|
|
128
|
+
href: '/favicon/apple-touch-icon-72x72.png',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
tagName: 'link',
|
|
133
|
+
attributes: {
|
|
134
|
+
rel: 'apple-touch-icon',
|
|
135
|
+
sizes: '76x76',
|
|
136
|
+
href: '/favicon/apple-touch-icon-76x76.png',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
tagName: 'link',
|
|
141
|
+
attributes: {
|
|
142
|
+
rel: 'apple-touch-icon',
|
|
143
|
+
sizes: '114x114',
|
|
144
|
+
href: '/favicon/apple-touch-icon-114x114.png',
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
tagName: 'link',
|
|
149
|
+
attributes: {
|
|
150
|
+
rel: 'apple-touch-icon',
|
|
151
|
+
sizes: '120x120',
|
|
152
|
+
href: '/favicon/apple-touch-icon-120x120.png',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
tagName: 'link',
|
|
157
|
+
attributes: {
|
|
158
|
+
rel: 'apple-touch-icon',
|
|
159
|
+
sizes: '144x144',
|
|
160
|
+
href: '/favicon/apple-touch-icon-144x144.png',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
tagName: 'link',
|
|
165
|
+
attributes: {
|
|
166
|
+
rel: 'apple-touch-icon',
|
|
167
|
+
sizes: '152x152',
|
|
168
|
+
href: '/favicon/apple-touch-icon-152x152.png',
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
tagName: 'link',
|
|
173
|
+
attributes: {
|
|
174
|
+
rel: 'apple-touch-icon',
|
|
175
|
+
sizes: '167x167',
|
|
176
|
+
href: '/favicon/apple-touch-icon-167x167.png',
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
tagName: 'link',
|
|
181
|
+
attributes: {
|
|
182
|
+
rel: 'apple-touch-icon',
|
|
183
|
+
sizes: '180x180',
|
|
184
|
+
href: '/favicon/apple-touch-icon-180x180.png',
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
tagName: 'link',
|
|
189
|
+
attributes: {
|
|
190
|
+
rel: 'apple-touch-icon',
|
|
191
|
+
sizes: '1024x1024',
|
|
192
|
+
href: '/favicon/apple-touch-icon-1024x1024.png',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
tagName: 'link',
|
|
197
|
+
attributes: {
|
|
198
|
+
rel: 'apple-touch-icon-precomposed',
|
|
199
|
+
href: '/favicon/apple-touch-icon-precomposed.png',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
// Standard favicons
|
|
204
|
+
{
|
|
205
|
+
tagName: 'link',
|
|
206
|
+
attributes: {
|
|
207
|
+
rel: 'icon',
|
|
208
|
+
type: 'image/png',
|
|
209
|
+
sizes: '16x16',
|
|
210
|
+
href: '/favicon/favicon-16x16.png',
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
tagName: 'link',
|
|
215
|
+
attributes: {
|
|
216
|
+
rel: 'icon',
|
|
217
|
+
type: 'image/png',
|
|
218
|
+
sizes: '32x32',
|
|
219
|
+
href: '/favicon/favicon-32x32.png',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
tagName: 'link',
|
|
224
|
+
attributes: {
|
|
225
|
+
rel: 'icon',
|
|
226
|
+
type: 'image/png',
|
|
227
|
+
sizes: '48x48',
|
|
228
|
+
href: '/favicon/favicon-48x48.png',
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
// Web manifest
|
|
233
|
+
{
|
|
234
|
+
tagName: 'link',
|
|
235
|
+
attributes: {
|
|
236
|
+
rel: 'manifest',
|
|
237
|
+
href: '/favicon/manifest.webmanifest',
|
|
238
|
+
},
|
|
239
|
+
}
|
|
240
|
+
];
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catppuccin theme for Prism.js
|
|
3
|
+
**/
|
|
4
|
+
|
|
5
|
+
// Catppuccin Mocha (dark theme)
|
|
6
|
+
export const catppuccinMocha = {
|
|
7
|
+
plain: {
|
|
8
|
+
color: '#cdd6f4',
|
|
9
|
+
backgroundColor: '#181825',
|
|
10
|
+
},
|
|
11
|
+
styles: [
|
|
12
|
+
{
|
|
13
|
+
types: ['comment', 'prolog', 'doctype', 'cdata'],
|
|
14
|
+
style: {
|
|
15
|
+
color: '#6c7086',
|
|
16
|
+
fontStyle: 'italic',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
types: ['namespace'],
|
|
21
|
+
style: {
|
|
22
|
+
opacity: 0.7,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
types: ['string', 'char', 'attr-value'],
|
|
27
|
+
style: {
|
|
28
|
+
color: '#a6e3a1',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
types: ['punctuation', 'operator'],
|
|
33
|
+
style: {
|
|
34
|
+
color: '#a6adc8',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
types: [
|
|
39
|
+
'entity',
|
|
40
|
+
'url',
|
|
41
|
+
'symbol',
|
|
42
|
+
'number',
|
|
43
|
+
'boolean',
|
|
44
|
+
'variable',
|
|
45
|
+
'constant',
|
|
46
|
+
'property',
|
|
47
|
+
'regex',
|
|
48
|
+
'inserted',
|
|
49
|
+
],
|
|
50
|
+
style: {
|
|
51
|
+
color: '#fab387',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
types: ['atrule', 'keyword', 'attr-name', 'selector'],
|
|
56
|
+
style: {
|
|
57
|
+
color: '#cba6f7',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
types: ['function', 'deleted', 'tag'],
|
|
62
|
+
style: {
|
|
63
|
+
color: '#f38ba8',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
types: ['function-variable'],
|
|
68
|
+
style: {
|
|
69
|
+
color: '#89b4fa',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
types: ['class-name'],
|
|
74
|
+
style: {
|
|
75
|
+
color: '#f9e2af',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
types: ['important', 'bold'],
|
|
80
|
+
style: {
|
|
81
|
+
fontWeight: 'bold',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
types: ['italic'],
|
|
86
|
+
style: {
|
|
87
|
+
fontStyle: 'italic',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Catppuccin Latte (light theme)
|
|
94
|
+
export const catppuccinLatte = {
|
|
95
|
+
plain: {
|
|
96
|
+
color: '#4c4f69',
|
|
97
|
+
backgroundColor: '#FAF9F6',
|
|
98
|
+
},
|
|
99
|
+
styles: [
|
|
100
|
+
{
|
|
101
|
+
types: ['comment', 'prolog', 'doctype', 'cdata'],
|
|
102
|
+
style: {
|
|
103
|
+
color: '#8c8fa1',
|
|
104
|
+
fontStyle: 'italic',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
types: ['namespace'],
|
|
109
|
+
style: {
|
|
110
|
+
opacity: 0.7,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
types: ['string', 'char', 'attr-value'],
|
|
115
|
+
style: {
|
|
116
|
+
color: '#40a02b',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
types: ['punctuation', 'operator'],
|
|
121
|
+
style: {
|
|
122
|
+
color: '#8c8fa1',
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
types: [
|
|
127
|
+
'entity',
|
|
128
|
+
'url',
|
|
129
|
+
'symbol',
|
|
130
|
+
'number',
|
|
131
|
+
'boolean',
|
|
132
|
+
'variable',
|
|
133
|
+
'constant',
|
|
134
|
+
'property',
|
|
135
|
+
'regex',
|
|
136
|
+
'inserted',
|
|
137
|
+
],
|
|
138
|
+
style: {
|
|
139
|
+
color: '#fe640b',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
types: ['atrule', 'keyword', 'attr-name', 'selector'],
|
|
144
|
+
style: {
|
|
145
|
+
color: '#8839ef',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
types: ['function', 'deleted', 'tag'],
|
|
150
|
+
style: {
|
|
151
|
+
color: '#d20f39',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
types: ['function-variable'],
|
|
156
|
+
style: {
|
|
157
|
+
color: '#1e66f5',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
types: ['class-name'],
|
|
162
|
+
style: {
|
|
163
|
+
color: '#df8e1d',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
types: ['important', 'bold'],
|
|
168
|
+
style: {
|
|
169
|
+
fontWeight: 'bold',
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
types: ['italic'],
|
|
174
|
+
style: {
|
|
175
|
+
fontStyle: 'italic',
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
function resolvePath(obj, path) {
|
|
5
|
+
const parts = path.split('.');
|
|
6
|
+
let current = obj;
|
|
7
|
+
|
|
8
|
+
for (const part of parts) {
|
|
9
|
+
if (current === null || current === undefined || typeof current !== 'object') {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
current = current[part];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseStringValue(value, config) {
|
|
19
|
+
if (typeof value !== 'string') {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Find all ${...} references
|
|
24
|
+
return value.replace(/\${([^}]+)}/g, (match, path) => {
|
|
25
|
+
const resolvedValue = resolvePath(config, path);
|
|
26
|
+
|
|
27
|
+
if (resolvedValue === undefined) {
|
|
28
|
+
console.warn(`Warning: Could not resolve reference "${path}" in config value "${value}"`);
|
|
29
|
+
return match;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (typeof resolvedValue === 'string' && resolvedValue.includes('${')) {
|
|
33
|
+
return parseStringValue(resolvedValue, config);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return resolvedValue;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseConfigObject(obj, config) {
|
|
41
|
+
if (Array.isArray(obj)) {
|
|
42
|
+
return obj.map(item => parseConfigObject(item, config));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (obj !== null && typeof obj === 'object') {
|
|
46
|
+
const result = {};
|
|
47
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
48
|
+
result[key] = parseConfigObject(value, config);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof obj === 'string') {
|
|
54
|
+
return parseStringValue(obj, config);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return obj;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function parseConfig(config) {
|
|
61
|
+
const parsedConfig = JSON.parse(JSON.stringify(config));
|
|
62
|
+
return parseConfigObject(parsedConfig, config);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function loadUserConfig() {
|
|
66
|
+
const configPath = path.resolve(process.cwd(), 'config.js');
|
|
67
|
+
|
|
68
|
+
if (!fs.existsSync(configPath)) {
|
|
69
|
+
console.warn(`\n⚠️ No config.js found at ${configPath}. Using empty config.\n`);
|
|
70
|
+
return {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const rawConfig = require(configPath);
|
|
75
|
+
// Support both `module.exports = { usrConf: ... }` and direct object
|
|
76
|
+
const rootConfig = rawConfig.usrConf || rawConfig;
|
|
77
|
+
|
|
78
|
+
// Parse the config (resolve variables)
|
|
79
|
+
const parsedExports = {};
|
|
80
|
+
for (const key in rootConfig) {
|
|
81
|
+
parsedExports[key] = parseConfig(rootConfig[key]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
...parsedExports,
|
|
86
|
+
// Helper methods attached if needed, but mostly we just return the object
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(`\n❌ Error loading config.js:`, err);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
loadUserConfig,
|
|
97
|
+
parseConfig,
|
|
98
|
+
resolvePath
|
|
99
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { loadUserConfig } = require('./configLoader');
|
|
3
|
+
|
|
4
|
+
module.exports = function preset(context, options) {
|
|
5
|
+
// 1. Load User Configuration
|
|
6
|
+
const userConfig = loadUserConfig();
|
|
7
|
+
|
|
8
|
+
// 2. Resolve Paths
|
|
9
|
+
const customCss = [
|
|
10
|
+
require.resolve('./theme/css/catppuccin.css'),
|
|
11
|
+
require.resolve('./theme/css/custom.css'),
|
|
12
|
+
require.resolve('./theme/css/tasks.css') // Globally available
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// 3. Define the Preset
|
|
16
|
+
return {
|
|
17
|
+
themes: [
|
|
18
|
+
// In Docusaurus 3, we can't easily "inject" a theme folder without a proper theme definition.
|
|
19
|
+
// But since we are packaging components, we can add a local plugin that performs `addRoute`
|
|
20
|
+
// or we just trust the user to rely on our components?
|
|
21
|
+
// Actually, standard way is to return a theme from options.
|
|
22
|
+
// We will assume `preset-classic` handles the heavy lifting, and we just override CSS.
|
|
23
|
+
// EXCEPT: We likely have swizzled components in `src/theme/components`.
|
|
24
|
+
// To use them, we need to register a theme plugin that points to `src/theme`.
|
|
25
|
+
|
|
26
|
+
// Let's define a simple inline theme plugin to expose our components
|
|
27
|
+
function (context, options) {
|
|
28
|
+
return {
|
|
29
|
+
name: 'docusaurus-theme-portosaurus-components',
|
|
30
|
+
getThemePath() {
|
|
31
|
+
return path.resolve(__dirname, './theme');
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
plugins: [
|
|
37
|
+
// Search Plugin
|
|
38
|
+
[
|
|
39
|
+
require.resolve('@easyops-cn/docusaurus-search-local'),
|
|
40
|
+
{
|
|
41
|
+
hashed: true,
|
|
42
|
+
indexDocs: true,
|
|
43
|
+
docsDir: "notes",
|
|
44
|
+
docsRouteBasePath: "notes",
|
|
45
|
+
highlightSearchTermsOnTargetPage: true,
|
|
46
|
+
searchContextByPaths: ["notes", "blog"],
|
|
47
|
+
...((userConfig.usrConf && userConfig.usrConf.search) || {})
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
// Image Zoom
|
|
51
|
+
require.resolve('plugin-image-zoom'),
|
|
52
|
+
],
|
|
53
|
+
presets: [
|
|
54
|
+
[
|
|
55
|
+
require.resolve('@docusaurus/preset-classic'),
|
|
56
|
+
{
|
|
57
|
+
docs: {
|
|
58
|
+
path: 'notes',
|
|
59
|
+
routeBasePath: 'notes',
|
|
60
|
+
sidebarPath: require.resolve('./config/sidebar.js'),
|
|
61
|
+
// Pass through any user overrides if needed
|
|
62
|
+
...((userConfig.usrConf && userConfig.usrConf.docs) || {})
|
|
63
|
+
},
|
|
64
|
+
blog: {
|
|
65
|
+
path: 'blog',
|
|
66
|
+
showReadingTime: false,
|
|
67
|
+
// Pass through
|
|
68
|
+
...((userConfig.usrConf && userConfig.usrConf.blog) || {})
|
|
69
|
+
},
|
|
70
|
+
theme: {
|
|
71
|
+
customCss: customCss,
|
|
72
|
+
},
|
|
73
|
+
// Pages??
|
|
74
|
+
// If we want to support user pages in `src/pages` (root), it works by default.
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import Layout from "@theme/Layout";
|
|
2
|
+
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
|
3
|
+
import UpdateTitle from '@site/src/utils/updateTitle';
|
|
4
|
+
|
|
5
|
+
// Import components
|
|
6
|
+
import HeroSection from "@site/src/components/HeroSection";
|
|
7
|
+
import AboutSection from "@site/src/components/AboutSection";
|
|
8
|
+
import ProjectsSection from "@site/src/components/ProjectsSection";
|
|
9
|
+
import ContactSection from "@site/src/components/ContactSection";
|
|
10
|
+
import ExperienceSection from "@site/src/components/ExperienceSection";
|
|
11
|
+
import ScrollToTop from "@site/src/components/ScrollToTop";
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export default function Home() {
|
|
15
|
+
const { siteConfig } = useDocusaurusContext();
|
|
16
|
+
const { customFields } = siteConfig;
|
|
17
|
+
|
|
18
|
+
const aboutMe = customFields.aboutMe || {};
|
|
19
|
+
const projects = customFields.projects || {};
|
|
20
|
+
const socialLinks = customFields.socialLinks || {};
|
|
21
|
+
const experience = customFields.experience || {};
|
|
22
|
+
|
|
23
|
+
const sectionTitles = {
|
|
24
|
+
'me': `Home | ${siteConfig.title}`,
|
|
25
|
+
'about': `About Me | ${siteConfig.title}`,
|
|
26
|
+
'projects': `Projects | ${siteConfig.title}`,
|
|
27
|
+
'experience': `Experience | ${siteConfig.title}`,
|
|
28
|
+
'contact': `Contact | ${siteConfig.title}`
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const customStyles = `
|
|
32
|
+
/* For future */
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Layout
|
|
38
|
+
title="Me"
|
|
39
|
+
description="My portfolio website"
|
|
40
|
+
>
|
|
41
|
+
{/* Custom styles */}
|
|
42
|
+
<style>{customStyles}</style>
|
|
43
|
+
|
|
44
|
+
<UpdateTitle
|
|
45
|
+
sections={sectionTitles}
|
|
46
|
+
defaultTitle={siteConfig.title}
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
<main>
|
|
50
|
+
|
|
51
|
+
{/* Hero Section */}
|
|
52
|
+
<HeroSection
|
|
53
|
+
id="me"
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
{/* About Section */}
|
|
57
|
+
{(aboutMe.enable !== false) && (
|
|
58
|
+
<AboutSection
|
|
59
|
+
id="about"
|
|
60
|
+
title="About Me"
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
|
|
64
|
+
{/* Projects Section */}
|
|
65
|
+
{(projects.enable !== false) && (
|
|
66
|
+
<ProjectsSection
|
|
67
|
+
id="projects"
|
|
68
|
+
title="My Projects"
|
|
69
|
+
subtitle="A collection of all my works, with featured projects highlighted"
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
|
|
73
|
+
{/* Experience Section */}
|
|
74
|
+
{(experience.enable !== false) && (
|
|
75
|
+
<ExperienceSection
|
|
76
|
+
id="experience"
|
|
77
|
+
title="Experience"
|
|
78
|
+
subtitle="My professional journey and work experience"
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
|
|
82
|
+
{/* Contact Section */}
|
|
83
|
+
{(socialLinks.enable !== false) && (
|
|
84
|
+
<ContactSection
|
|
85
|
+
id="contact"
|
|
86
|
+
title="Get In Touch"
|
|
87
|
+
subtitle="Feel free to reach out for collaborations, questions, or just to say hello!"
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{/* Scroll to top button */}
|
|
92
|
+
<ScrollToTop
|
|
93
|
+
hideDelay={3500}
|
|
94
|
+
/>
|
|
95
|
+
</main>
|
|
96
|
+
</Layout>
|
|
97
|
+
);
|
|
98
|
+
}
|