portosaurus 0.14.0 → 0.16.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/README.md +36 -45
- package/bin/cli.ts +60 -0
- package/docusaurus.config.ts +221 -0
- package/lib/bin/cli.js +49 -0
- package/lib/docusaurus.config.js +204 -0
- package/lib/src/cli/commands/build.js +26 -0
- package/lib/src/cli/commands/init.js +134 -0
- package/lib/src/cli/commands/serve.js +22 -0
- package/lib/src/cli/commands/start.js +37 -0
- package/lib/src/cli/utils/config-loader.js +28 -0
- package/lib/src/cli/utils/logger.js +18 -0
- package/lib/src/components/AboutSection/index.js +9 -0
- package/lib/src/components/ContactSection/index.js +38 -0
- package/lib/src/components/ExperienceSection/index.js +5 -0
- package/lib/src/components/HeroSection/index.js +17 -0
- package/lib/src/components/NoteIndex/index.js +65 -0
- package/lib/src/components/ProjectsSection/index.js +289 -0
- package/lib/src/components/ScrollToTop/index.js +68 -0
- package/lib/src/components/SocialLinks/index.js +82 -0
- package/lib/src/components/Tooltip/index.js +8 -0
- package/lib/src/config/iconMappings.js +266 -0
- package/lib/src/config/metaTags.js +233 -0
- package/lib/src/config/prism.js +177 -0
- package/lib/src/config/sidebar.js +16 -0
- package/lib/src/index.js +1 -0
- package/lib/src/pages/index.js +31 -0
- package/lib/src/pages/notes.js +57 -0
- package/lib/src/pages/tasks.js +74 -0
- package/lib/src/types/config.js +1 -0
- package/lib/src/utils/HashNavigation.js +177 -0
- package/lib/src/utils/UpdateTitle.js +76 -0
- package/lib/src/utils/appVersion.js +19 -0
- package/lib/src/utils/compileConfig.js +66 -0
- package/lib/src/utils/cssUtils.js +85 -0
- package/lib/src/utils/filterEnabledItems.js +19 -0
- package/lib/src/utils/generateFavicon.js +179 -0
- package/lib/src/utils/generateRobotsTxt.js +74 -0
- package/lib/src/utils/iconExtractor.js +135 -0
- package/lib/src/utils/imageDownloader.js +63 -0
- package/lib/src/utils/imageProcessor.js +91 -0
- package/lib/templates/config.js +100 -0
- package/package.json +73 -13
- package/src/cli/commands/build.ts +31 -0
- package/src/cli/commands/init.ts +151 -0
- package/src/cli/commands/serve.ts +26 -0
- package/src/cli/commands/start.ts +44 -0
- package/src/cli/utils/config-loader.ts +26 -0
- package/src/cli/utils/logger.ts +23 -0
- package/src/{theme/components/AboutSection/index.js → components/AboutSection/index.tsx} +14 -3
- package/src/{theme/components/ContactSection/index.js → components/ContactSection/index.tsx} +23 -8
- package/src/{theme/components/ExperienceSection/index.js → components/ExperienceSection/index.tsx} +8 -1
- package/src/{theme/components/HeroSection/index.js → components/HeroSection/index.tsx} +15 -9
- package/src/{theme/components/NoteIndex/index.js → components/NoteIndex/index.tsx} +35 -15
- package/src/{theme/components/ProjectsSection/index.js → components/ProjectsSection/index.tsx} +49 -27
- package/src/{theme/components/ScrollToTop/index.js → components/ScrollToTop/index.tsx} +6 -2
- package/src/{theme/components/SocialLinks/index.js → components/SocialLinks/index.tsx} +23 -11
- package/src/{theme/components/Tooltip/index.js → components/Tooltip/index.tsx} +10 -3
- package/src/config/{iconMappings.js → iconMappings.ts} +7 -3
- package/src/config/{prism.js → prism.ts} +2 -2
- package/src/config/{sidebar.js → sidebar.ts} +4 -3
- package/src/index.ts +1 -0
- package/src/pages/{index.js → index.tsx} +14 -15
- package/src/pages/{notes.js → notes.tsx} +11 -9
- package/src/pages/{tasks.js → tasks.tsx} +25 -12
- package/src/types/config.ts +99 -0
- package/src/types.d.ts +1 -0
- package/src/utils/{HashNavigation.js → HashNavigation.tsx} +25 -20
- package/src/utils/{updateTitle.js → UpdateTitle.tsx} +10 -10
- package/src/utils/{appVersion.js → appVersion.ts} +6 -10
- package/src/{configLoader.js → utils/compileConfig.ts} +27 -39
- package/src/utils/{cssUtils.js → cssUtils.ts} +12 -12
- package/src/utils/{filterEnabledItems.js → filterEnabledItems.ts} +12 -5
- package/src/utils/{generateFavicon.js → generateFavicon.ts} +60 -90
- package/src/utils/{generateRobotsTxt.js → generateRobotsTxt.ts} +19 -7
- package/src/utils/{iconExtractor.js → iconExtractor.ts} +44 -28
- package/src/utils/{imageDownloader.js → imageDownloader.ts} +19 -37
- package/src/utils/{imageProcessor.js → imageProcessor.ts} +5 -24
- package/templates/README.md +29 -0
- package/templates/_tsconfig.json +7 -0
- package/templates/blog/welcome.md +17 -0
- package/templates/config.js +110 -0
- package/templates/notes/intro.md +9 -0
- package/tsconfig.json +28 -0
- package/.vscode/snippets.code-snippets +0 -79
- package/AGENTS.md +0 -37
- package/GG/config.js +0 -233
- package/GG/package.json +0 -14
- package/GG/static/.nojekyll +0 -0
- package/GG/static/docusaurus-snippet.css +0 -3
- 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 +0 -674
- package/bin/portosaurus.js +0 -136
- package/src/index.js +0 -79
- package/src/theme/staticLink/.nojekyll +0 -0
- package/src/theme/staticLink/docusaurus-snippet.css +0 -3
- 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/linkShortner.js +0 -0
- /package/src/{theme/components → components}/AboutSection/styles.module.css +0 -0
- /package/src/{theme/components → components}/ContactSection/styles.module.css +0 -0
- /package/src/{theme/components → components}/ExperienceSection/styles.module.css +0 -0
- /package/src/{theme/components → components}/HeroSection/styles.module.css +0 -0
- /package/src/{theme/components → components}/NoteIndex/styles.module.css +0 -0
- /package/src/{theme/components → components}/ProjectsSection/styles.module.css +0 -0
- /package/src/{theme/components → components}/ScrollToTop/styles.module.css +0 -0
- /package/src/{theme/components → components}/SocialLinks/styles.module.css +0 -0
- /package/src/{theme/components → components}/Tooltip/styles.module.css +0 -0
- /package/src/config/{metaTags.js → metaTags.ts} +0 -0
- /package/src/{theme/css → css}/bootstrap.css +0 -0
- /package/src/{theme/css → css}/catppuccin.css +0 -0
- /package/src/{theme/css → css}/custom.css +0 -0
- /package/src/{theme/css → css}/tasks.css +0 -0
package/README.md
CHANGED
|
@@ -1,57 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="./static/img/icon.png" width=150>
|
|
3
|
-
<h1>Postosaurus</h1>
|
|
4
|
-
<p>Complete portfolio cum personal website solution for your digital personality.</p>
|
|
5
|
-
</div>
|
|
1
|
+
# Portosaurus
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
> COMPLETE portfolio cum personal website solution for your digital personality.
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
Portosaurus is a Docusaurus-based portfolio generator. It allows you to create a beautiful, developer-focused portfolio with a blog and notes section in minutes, using a simple configuration file.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
## Features
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
│ │ ├── index.js - entry point
|
|
28
|
-
│ │ └── holds standalone pages
|
|
29
|
-
│ └── ...
|
|
30
|
-
├── static/
|
|
31
|
-
│ ├── img/
|
|
32
|
-
│ ├── ...
|
|
33
|
-
│ └── static files
|
|
34
|
-
├── config.js
|
|
35
|
-
├── docusaurus.config.js
|
|
36
|
-
└── package.json
|
|
9
|
+
- **Zero Config Setup**: Scaffolds a complete project with one command.
|
|
10
|
+
- **Config Driven**: Customize everything via `config.ts` or `config.js`.
|
|
11
|
+
- **Blog & Notes**: Built-in support for technical blogging and taking notes.
|
|
12
|
+
- **Themes**: Dark mode support and customizable themes.
|
|
13
|
+
- **Fast**: Built on Docusaurus/React.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
Create a new project:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx portosaurus init my-portfolio
|
|
21
|
+
cd my-portfolio
|
|
22
|
+
npm start
|
|
37
23
|
```
|
|
38
24
|
|
|
39
|
-
|
|
25
|
+
This will start a local development server at `http://localhost:3000`.
|
|
40
26
|
|
|
41
|
-
|
|
27
|
+
## Commands
|
|
42
28
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
- `npm start`: Start the development server (aliased to `portosaurus start`).
|
|
30
|
+
- `npm run build`: Build the static site for production (aliased to `portosaurus build`).
|
|
31
|
+
- `npm run serve`: Serve the built site locally (aliased to `portosaurus serve`).
|
|
46
32
|
|
|
47
|
-
|
|
33
|
+
## Project Structure
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
35
|
+
Your project will look like this:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
my-portfolio/
|
|
39
|
+
├── config.ts # Main configuration
|
|
40
|
+
├── blog/ # Your blog posts (MDX)
|
|
41
|
+
├── notes/ # Your notes (MDX)
|
|
42
|
+
├── src/ # Static assets (images, etc.)
|
|
43
|
+
└── package.json # Dependency management
|
|
44
|
+
```
|
|
52
45
|
|
|
53
|
-
|
|
46
|
+
## Documentation
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
npm run serve
|
|
57
|
-
```
|
|
48
|
+
For full documentation, visit [Portosaurus Docs](https://github.com/StartSomethingStudio/portosaurus).
|
package/bin/cli.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const cliRequire = createRequire(import.meta.url);
|
|
10
|
+
|
|
11
|
+
// prefix removed as per previous step logic, just keep the declaration once
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
// Resolve package.json path (handles both dev tsx and prod lib execution)
|
|
15
|
+
const devPkgPath = path.resolve(__dirname, '../package.json');
|
|
16
|
+
const prodPkgPath = path.resolve(__dirname, '../../package.json');
|
|
17
|
+
const packageJsonPath = fs.existsSync(devPkgPath) ? devPkgPath : prodPkgPath;
|
|
18
|
+
const packageJson = cliRequire(packageJsonPath);
|
|
19
|
+
|
|
20
|
+
const program = new Command();
|
|
21
|
+
|
|
22
|
+
program
|
|
23
|
+
.name('portosaurus')
|
|
24
|
+
.description('Complete portfolio cum personal website solution for your digital personality')
|
|
25
|
+
.version(packageJson.version);
|
|
26
|
+
|
|
27
|
+
program
|
|
28
|
+
.command('init')
|
|
29
|
+
.description('Initialize a new Portosaurus project')
|
|
30
|
+
.argument('[directory]', 'Directory to initialize in', '.')
|
|
31
|
+
.action(async (directory) => {
|
|
32
|
+
const { initCommand } = await import('../src/cli/commands/init.js');
|
|
33
|
+
await initCommand(directory);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.command('start')
|
|
38
|
+
.description('Start the development server')
|
|
39
|
+
.action(async () => {
|
|
40
|
+
const { startCommand } = await import('../src/cli/commands/start.js');
|
|
41
|
+
await startCommand();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
program
|
|
45
|
+
.command('build')
|
|
46
|
+
.description('Build the website for production')
|
|
47
|
+
.action(async () => {
|
|
48
|
+
const { buildCommand } = await import('../src/cli/commands/build.js');
|
|
49
|
+
await buildCommand();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
program
|
|
53
|
+
.command('serve')
|
|
54
|
+
.description('Serve the built website')
|
|
55
|
+
.action(async () => {
|
|
56
|
+
const { serveCommand } = await import('../src/cli/commands/serve.js');
|
|
57
|
+
await serveCommand();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import type { Config } from '@docusaurus/types';
|
|
2
|
+
import type * as Preset from '@docusaurus/preset-classic';
|
|
3
|
+
import { loadUserConfig } from './src/cli/utils/config-loader.js';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
|
|
8
|
+
import generateFaviconPlugin from './src/utils/generateFavicon.js';
|
|
9
|
+
import generateRobotsTxtPlugin from './src/utils/generateRobotsTxt.js';
|
|
10
|
+
import { metaTags } from './src/config/metaTags.js';
|
|
11
|
+
import { catppuccinMocha, catppuccinLatte } from './src/config/prism.js';
|
|
12
|
+
|
|
13
|
+
// Helper to filter enabled items
|
|
14
|
+
const useEnabled = (items: any[]) => {
|
|
15
|
+
return items.flatMap(item => {
|
|
16
|
+
if (item && typeof item === 'object' && 'enable' in item && 'value' in item) {
|
|
17
|
+
return item.enable === true ? [item.value] : [];
|
|
18
|
+
}
|
|
19
|
+
return [item];
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default async function createConfig(): Promise<Config> {
|
|
24
|
+
const userConfig = await loadUserConfig();
|
|
25
|
+
|
|
26
|
+
if (!userConfig) {
|
|
27
|
+
throw new Error('Config file not found! Please create config.ts or config.js');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// --- Map Portosaurus Config to Docusaurus Config ---
|
|
31
|
+
|
|
32
|
+
const siteConfig: Config = {
|
|
33
|
+
headTags: metaTags,
|
|
34
|
+
title: userConfig.hero_section.title,
|
|
35
|
+
tagline: userConfig.hero_section.description,
|
|
36
|
+
favicon: 'img/favicon.ico', // TODO: Make dynamic/configurable
|
|
37
|
+
|
|
38
|
+
// Set the production url of your site here
|
|
39
|
+
url: userConfig.site_url === 'auto' ? 'https://example.com' : userConfig.site_url,
|
|
40
|
+
baseUrl: userConfig.site_path === 'auto' ? '/' : userConfig.site_path,
|
|
41
|
+
|
|
42
|
+
onBrokenLinks: 'throw',
|
|
43
|
+
onBrokenMarkdownLinks: 'warn',
|
|
44
|
+
|
|
45
|
+
i18n: {
|
|
46
|
+
defaultLocale: 'en',
|
|
47
|
+
locales: ['en'],
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
presets: [
|
|
51
|
+
[
|
|
52
|
+
'classic',
|
|
53
|
+
{
|
|
54
|
+
docs: {
|
|
55
|
+
routeBasePath: 'notes',
|
|
56
|
+
path: 'notes',
|
|
57
|
+
sidebarPath: './src/config/sidebar.ts',
|
|
58
|
+
admonitions: {
|
|
59
|
+
keywords: ["note", "tip", "info", "warning", "danger", "question"],
|
|
60
|
+
extendDefaults: true,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
blog: {
|
|
64
|
+
showReadingTime: true,
|
|
65
|
+
path: 'blog',
|
|
66
|
+
routeBasePath: 'blog',
|
|
67
|
+
feedOptions: userConfig.rss ? {
|
|
68
|
+
type: 'all',
|
|
69
|
+
copyright: `Copyright © ${new Date().getFullYear()} ${userConfig.hero_section.title}`,
|
|
70
|
+
} : undefined,
|
|
71
|
+
onInlineTags: 'warn',
|
|
72
|
+
onInlineAuthors: 'warn',
|
|
73
|
+
onUntruncatedBlogPosts: 'warn',
|
|
74
|
+
},
|
|
75
|
+
theme: {
|
|
76
|
+
customCss: './src/css/custom.css',
|
|
77
|
+
},
|
|
78
|
+
} satisfies Preset.Options,
|
|
79
|
+
],
|
|
80
|
+
],
|
|
81
|
+
|
|
82
|
+
plugins: [
|
|
83
|
+
generateFaviconPlugin as any, // TODO: strict plugin types
|
|
84
|
+
generateRobotsTxtPlugin as any,
|
|
85
|
+
[
|
|
86
|
+
require.resolve('@easyops-cn/docusaurus-search-local'),
|
|
87
|
+
{
|
|
88
|
+
hashed: true,
|
|
89
|
+
indexDocs: true,
|
|
90
|
+
docsDir: "notes",
|
|
91
|
+
docsRouteBasePath: "notes",
|
|
92
|
+
highlightSearchTermsOnTargetPage: true,
|
|
93
|
+
explicitSearchResultPath: true,
|
|
94
|
+
hideSearchBarWithNoSearchContext: true,
|
|
95
|
+
searchContextByPaths: ["notes", "blog"],
|
|
96
|
+
language: ["en"],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
require.resolve('plugin-image-zoom'),
|
|
100
|
+
],
|
|
101
|
+
|
|
102
|
+
customFields: {
|
|
103
|
+
version: '1.0.0', // TODO: dynamic
|
|
104
|
+
heroSection: {
|
|
105
|
+
profilePic: userConfig.hero_section.profile_pic,
|
|
106
|
+
intro: "Hi, I am",
|
|
107
|
+
title: userConfig.hero_section.title,
|
|
108
|
+
subtitle: "I am a",
|
|
109
|
+
profession: userConfig.hero_section.profession,
|
|
110
|
+
description: userConfig.hero_section.description,
|
|
111
|
+
learnMoreButtonTxt: "Learn More",
|
|
112
|
+
},
|
|
113
|
+
aboutMe: userConfig.about_me,
|
|
114
|
+
projects: userConfig.project_shelf,
|
|
115
|
+
experience: userConfig.experience,
|
|
116
|
+
socialLinks: userConfig.social_links,
|
|
117
|
+
robotsTxt: { enable: userConfig.rebots_txt, rules: [{ disallow: ["/notes/", "/tasks/"] }], customLines: [] },
|
|
118
|
+
tasksPage: userConfig.tasks_page,
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
themeConfig: {
|
|
122
|
+
image: userConfig.social_card || "img/social-card.jpeg",
|
|
123
|
+
docs: {
|
|
124
|
+
sidebar: {
|
|
125
|
+
hideable: userConfig.colapsable_sidebar,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
imageZoom: {
|
|
129
|
+
options: {
|
|
130
|
+
margin: 2,
|
|
131
|
+
background: "rgba(var(--ifm-background-color-rgb), 0.9)",
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
colorMode: {
|
|
135
|
+
defaultMode: userConfig.dark_mode ? "dark" : "light",
|
|
136
|
+
disableSwitch: userConfig.disable_theme_switch,
|
|
137
|
+
},
|
|
138
|
+
navbar: {
|
|
139
|
+
title: userConfig.hero_section.title,
|
|
140
|
+
hideOnScroll: userConfig.hide_navbar_on_scroll,
|
|
141
|
+
logo: {
|
|
142
|
+
alt: 'Site Logo',
|
|
143
|
+
src: userConfig.hero_section.profile_pic, // Using profile pic as logo per original config
|
|
144
|
+
},
|
|
145
|
+
items: useEnabled([
|
|
146
|
+
{
|
|
147
|
+
type: "search",
|
|
148
|
+
position: "right",
|
|
149
|
+
className: "navbar-search-bar",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
enable: userConfig.about_me?.enable,
|
|
153
|
+
value: {
|
|
154
|
+
label: "About Me",
|
|
155
|
+
to: "/#about",
|
|
156
|
+
position: "right",
|
|
157
|
+
activeBaseRegex: "^/#about",
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
enable: userConfig.project_shelf?.enable,
|
|
162
|
+
value: {
|
|
163
|
+
label: "Projects",
|
|
164
|
+
to: "/#projects",
|
|
165
|
+
position: "right",
|
|
166
|
+
activeBaseRegex: "^/#projects",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
enable: userConfig.experience?.enable,
|
|
171
|
+
value: {
|
|
172
|
+
label: "Experience",
|
|
173
|
+
to: "/#experience",
|
|
174
|
+
position: "right",
|
|
175
|
+
activeBaseRegex: "^/#experience",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
enable: userConfig.social_links?.enable,
|
|
180
|
+
value: {
|
|
181
|
+
label: "Contact",
|
|
182
|
+
to: "/#contact",
|
|
183
|
+
position: "right",
|
|
184
|
+
activeBaseRegex: "^/$contact",
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
type: "dropdown",
|
|
189
|
+
label: "More",
|
|
190
|
+
position: "right",
|
|
191
|
+
className: "_navbar-more-items",
|
|
192
|
+
items: useEnabled([
|
|
193
|
+
{ label: "Notes", to: "/notes" },
|
|
194
|
+
{ label: "Blog", to: "/blog" },
|
|
195
|
+
{ label: "Tasks", to: "/tasks" },
|
|
196
|
+
{
|
|
197
|
+
enable: true,
|
|
198
|
+
value: {
|
|
199
|
+
label: `Portosaurus`,
|
|
200
|
+
className: "_nav-protosaurus-version",
|
|
201
|
+
href: "https://github.com/soymadip/portosaurus",
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
]),
|
|
205
|
+
}
|
|
206
|
+
]),
|
|
207
|
+
},
|
|
208
|
+
footer: {
|
|
209
|
+
// Empty footer per original config
|
|
210
|
+
},
|
|
211
|
+
// tableOfContents: { minHeadingLevel: 2, maxHeadingLevel: 4 }, // Add if needed
|
|
212
|
+
prism: {
|
|
213
|
+
theme: catppuccinLatte as any,
|
|
214
|
+
darkTheme: catppuccinMocha as any,
|
|
215
|
+
additionalLanguages: ["java", "php", "bash"],
|
|
216
|
+
},
|
|
217
|
+
} satisfies Preset.ThemeConfig,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
return siteConfig;
|
|
221
|
+
}
|
package/lib/bin/cli.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
const cliRequire = createRequire(import.meta.url);
|
|
8
|
+
// prefix removed as per previous step logic, just keep the declaration once
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
// Resolve package.json path (handles both dev tsx and prod lib execution)
|
|
11
|
+
const devPkgPath = path.resolve(__dirname, '../package.json');
|
|
12
|
+
const prodPkgPath = path.resolve(__dirname, '../../package.json');
|
|
13
|
+
const packageJsonPath = fs.existsSync(devPkgPath) ? devPkgPath : prodPkgPath;
|
|
14
|
+
const packageJson = cliRequire(packageJsonPath);
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('portosaurus')
|
|
18
|
+
.description('Complete portfolio cum personal website solution for your digital personality')
|
|
19
|
+
.version(packageJson.version);
|
|
20
|
+
program
|
|
21
|
+
.command('init')
|
|
22
|
+
.description('Initialize a new Portosaurus project')
|
|
23
|
+
.argument('[directory]', 'Directory to initialize in', '.')
|
|
24
|
+
.action(async (directory) => {
|
|
25
|
+
const { initCommand } = await import('../src/cli/commands/init.js');
|
|
26
|
+
await initCommand(directory);
|
|
27
|
+
});
|
|
28
|
+
program
|
|
29
|
+
.command('start')
|
|
30
|
+
.description('Start the development server')
|
|
31
|
+
.action(async () => {
|
|
32
|
+
const { startCommand } = await import('../src/cli/commands/start.js');
|
|
33
|
+
await startCommand();
|
|
34
|
+
});
|
|
35
|
+
program
|
|
36
|
+
.command('build')
|
|
37
|
+
.description('Build the website for production')
|
|
38
|
+
.action(async () => {
|
|
39
|
+
const { buildCommand } = await import('../src/cli/commands/build.js');
|
|
40
|
+
await buildCommand();
|
|
41
|
+
});
|
|
42
|
+
program
|
|
43
|
+
.command('serve')
|
|
44
|
+
.description('Serve the built website')
|
|
45
|
+
.action(async () => {
|
|
46
|
+
const { serveCommand } = await import('../src/cli/commands/serve.js');
|
|
47
|
+
await serveCommand();
|
|
48
|
+
});
|
|
49
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { loadUserConfig } from './src/cli/utils/config-loader.js';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
import generateFaviconPlugin from './src/utils/generateFavicon.js';
|
|
5
|
+
import generateRobotsTxtPlugin from './src/utils/generateRobotsTxt.js';
|
|
6
|
+
import { metaTags } from './src/config/metaTags.js';
|
|
7
|
+
import { catppuccinMocha, catppuccinLatte } from './src/config/prism.js';
|
|
8
|
+
// Helper to filter enabled items
|
|
9
|
+
const useEnabled = (items) => {
|
|
10
|
+
return items.flatMap(item => {
|
|
11
|
+
if (item && typeof item === 'object' && 'enable' in item && 'value' in item) {
|
|
12
|
+
return item.enable === true ? [item.value] : [];
|
|
13
|
+
}
|
|
14
|
+
return [item];
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
export default async function createConfig() {
|
|
18
|
+
const userConfig = await loadUserConfig();
|
|
19
|
+
if (!userConfig) {
|
|
20
|
+
throw new Error('Config file not found! Please create config.ts or config.js');
|
|
21
|
+
}
|
|
22
|
+
// --- Map Portosaurus Config to Docusaurus Config ---
|
|
23
|
+
const siteConfig = {
|
|
24
|
+
headTags: metaTags,
|
|
25
|
+
title: userConfig.hero_section.title,
|
|
26
|
+
tagline: userConfig.hero_section.description,
|
|
27
|
+
favicon: 'img/favicon.ico', // TODO: Make dynamic/configurable
|
|
28
|
+
// Set the production url of your site here
|
|
29
|
+
url: userConfig.site_url === 'auto' ? 'https://example.com' : userConfig.site_url,
|
|
30
|
+
baseUrl: userConfig.site_path === 'auto' ? '/' : userConfig.site_path,
|
|
31
|
+
onBrokenLinks: 'throw',
|
|
32
|
+
onBrokenMarkdownLinks: 'warn',
|
|
33
|
+
i18n: {
|
|
34
|
+
defaultLocale: 'en',
|
|
35
|
+
locales: ['en'],
|
|
36
|
+
},
|
|
37
|
+
presets: [
|
|
38
|
+
[
|
|
39
|
+
'classic',
|
|
40
|
+
{
|
|
41
|
+
docs: {
|
|
42
|
+
routeBasePath: 'notes',
|
|
43
|
+
path: 'notes',
|
|
44
|
+
sidebarPath: './src/config/sidebar.ts',
|
|
45
|
+
admonitions: {
|
|
46
|
+
keywords: ["note", "tip", "info", "warning", "danger", "question"],
|
|
47
|
+
extendDefaults: true,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
blog: {
|
|
51
|
+
showReadingTime: true,
|
|
52
|
+
path: 'blog',
|
|
53
|
+
routeBasePath: 'blog',
|
|
54
|
+
feedOptions: userConfig.rss ? {
|
|
55
|
+
type: 'all',
|
|
56
|
+
copyright: `Copyright © ${new Date().getFullYear()} ${userConfig.hero_section.title}`,
|
|
57
|
+
} : undefined,
|
|
58
|
+
onInlineTags: 'warn',
|
|
59
|
+
onInlineAuthors: 'warn',
|
|
60
|
+
onUntruncatedBlogPosts: 'warn',
|
|
61
|
+
},
|
|
62
|
+
theme: {
|
|
63
|
+
customCss: './src/css/custom.css',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
],
|
|
68
|
+
plugins: [
|
|
69
|
+
generateFaviconPlugin, // TODO: strict plugin types
|
|
70
|
+
generateRobotsTxtPlugin,
|
|
71
|
+
[
|
|
72
|
+
require.resolve('@easyops-cn/docusaurus-search-local'),
|
|
73
|
+
{
|
|
74
|
+
hashed: true,
|
|
75
|
+
indexDocs: true,
|
|
76
|
+
docsDir: "notes",
|
|
77
|
+
docsRouteBasePath: "notes",
|
|
78
|
+
highlightSearchTermsOnTargetPage: true,
|
|
79
|
+
explicitSearchResultPath: true,
|
|
80
|
+
hideSearchBarWithNoSearchContext: true,
|
|
81
|
+
searchContextByPaths: ["notes", "blog"],
|
|
82
|
+
language: ["en"],
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
require.resolve('plugin-image-zoom'),
|
|
86
|
+
],
|
|
87
|
+
customFields: {
|
|
88
|
+
version: '1.0.0', // TODO: dynamic
|
|
89
|
+
heroSection: {
|
|
90
|
+
profilePic: userConfig.hero_section.profile_pic,
|
|
91
|
+
intro: "Hi, I am",
|
|
92
|
+
title: userConfig.hero_section.title,
|
|
93
|
+
subtitle: "I am a",
|
|
94
|
+
profession: userConfig.hero_section.profession,
|
|
95
|
+
description: userConfig.hero_section.description,
|
|
96
|
+
learnMoreButtonTxt: "Learn More",
|
|
97
|
+
},
|
|
98
|
+
aboutMe: userConfig.about_me,
|
|
99
|
+
projects: userConfig.project_shelf,
|
|
100
|
+
experience: userConfig.experience,
|
|
101
|
+
socialLinks: userConfig.social_links,
|
|
102
|
+
robotsTxt: { enable: userConfig.rebots_txt, rules: [{ disallow: ["/notes/", "/tasks/"] }], customLines: [] },
|
|
103
|
+
tasksPage: userConfig.tasks_page,
|
|
104
|
+
},
|
|
105
|
+
themeConfig: {
|
|
106
|
+
image: userConfig.social_card || "img/social-card.jpeg",
|
|
107
|
+
docs: {
|
|
108
|
+
sidebar: {
|
|
109
|
+
hideable: userConfig.colapsable_sidebar,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
imageZoom: {
|
|
113
|
+
options: {
|
|
114
|
+
margin: 2,
|
|
115
|
+
background: "rgba(var(--ifm-background-color-rgb), 0.9)",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
colorMode: {
|
|
119
|
+
defaultMode: userConfig.dark_mode ? "dark" : "light",
|
|
120
|
+
disableSwitch: userConfig.disable_theme_switch,
|
|
121
|
+
},
|
|
122
|
+
navbar: {
|
|
123
|
+
title: userConfig.hero_section.title,
|
|
124
|
+
hideOnScroll: userConfig.hide_navbar_on_scroll,
|
|
125
|
+
logo: {
|
|
126
|
+
alt: 'Site Logo',
|
|
127
|
+
src: userConfig.hero_section.profile_pic, // Using profile pic as logo per original config
|
|
128
|
+
},
|
|
129
|
+
items: useEnabled([
|
|
130
|
+
{
|
|
131
|
+
type: "search",
|
|
132
|
+
position: "right",
|
|
133
|
+
className: "navbar-search-bar",
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
enable: userConfig.about_me?.enable,
|
|
137
|
+
value: {
|
|
138
|
+
label: "About Me",
|
|
139
|
+
to: "/#about",
|
|
140
|
+
position: "right",
|
|
141
|
+
activeBaseRegex: "^/#about",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
enable: userConfig.project_shelf?.enable,
|
|
146
|
+
value: {
|
|
147
|
+
label: "Projects",
|
|
148
|
+
to: "/#projects",
|
|
149
|
+
position: "right",
|
|
150
|
+
activeBaseRegex: "^/#projects",
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
enable: userConfig.experience?.enable,
|
|
155
|
+
value: {
|
|
156
|
+
label: "Experience",
|
|
157
|
+
to: "/#experience",
|
|
158
|
+
position: "right",
|
|
159
|
+
activeBaseRegex: "^/#experience",
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
enable: userConfig.social_links?.enable,
|
|
164
|
+
value: {
|
|
165
|
+
label: "Contact",
|
|
166
|
+
to: "/#contact",
|
|
167
|
+
position: "right",
|
|
168
|
+
activeBaseRegex: "^/$contact",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
type: "dropdown",
|
|
173
|
+
label: "More",
|
|
174
|
+
position: "right",
|
|
175
|
+
className: "_navbar-more-items",
|
|
176
|
+
items: useEnabled([
|
|
177
|
+
{ label: "Notes", to: "/notes" },
|
|
178
|
+
{ label: "Blog", to: "/blog" },
|
|
179
|
+
{ label: "Tasks", to: "/tasks" },
|
|
180
|
+
{
|
|
181
|
+
enable: true,
|
|
182
|
+
value: {
|
|
183
|
+
label: `Portosaurus`,
|
|
184
|
+
className: "_nav-protosaurus-version",
|
|
185
|
+
href: "https://github.com/soymadip/portosaurus",
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
]),
|
|
189
|
+
}
|
|
190
|
+
]),
|
|
191
|
+
},
|
|
192
|
+
footer: {
|
|
193
|
+
// Empty footer per original config
|
|
194
|
+
},
|
|
195
|
+
// tableOfContents: { minHeadingLevel: 2, maxHeadingLevel: 4 }, // Add if needed
|
|
196
|
+
prism: {
|
|
197
|
+
theme: catppuccinLatte,
|
|
198
|
+
darkTheme: catppuccinMocha,
|
|
199
|
+
additionalLanguages: ["java", "php", "bash"],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
return siteConfig;
|
|
204
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
export async function buildCommand() {
|
|
10
|
+
logger.info('Building for production...');
|
|
11
|
+
// Resolve path to docusaurus command
|
|
12
|
+
const docusaurusCorePath = path.dirname(require.resolve('@docusaurus/core/package.json'));
|
|
13
|
+
const docusaurusBin = path.join(docusaurusCorePath, 'bin', 'docusaurus.mjs');
|
|
14
|
+
const sourceConfigPath = path.resolve(__dirname, '../../../docusaurus.config.ts');
|
|
15
|
+
const compiledConfigPath = path.resolve(__dirname, '../../../docusaurus.config.js');
|
|
16
|
+
const configPath = fs.existsSync(sourceConfigPath) ? sourceConfigPath : compiledConfigPath;
|
|
17
|
+
try {
|
|
18
|
+
execSync(`node "${docusaurusBin}" build --config "${configPath}"`, {
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
logger.error(`Build failed: ${error}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
}
|