create-foliokit 0.0.0-stage → 1.0.1
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.
- package/LICENSE +21 -0
- package/README.md +111 -2
- package/bin/index.js +6 -0
- package/package.json +50 -4
- package/src/cli.js +111 -0
- package/src/generator.js +133 -0
- package/src/prompts.js +44 -0
- package/src/utils/errors.js +7 -0
- package/src/utils/paths.js +12 -0
- package/src/utils/progress.js +5 -0
- package/src/utils/project-name.js +30 -0
- package/templates/default/data.ts +169 -0
- package/templates/default/index.html +23 -0
- package/templates/default/package-lock.json +1280 -0
- package/templates/default/package.json +28 -0
- package/templates/default/public/avatar-placeholder.png +0 -0
- package/templates/default/public/experience-logo-placeholder.png +0 -0
- package/templates/default/public/project-placeholder.png +0 -0
- package/templates/default/public/robots.txt +2 -0
- package/templates/default/scripts/generate-seo.mjs +34 -0
- package/templates/default/src/App.tsx +582 -0
- package/templates/default/src/BrandIcon.tsx +36 -0
- package/templates/default/src/ProjectMagazineGallery.css +90 -0
- package/templates/default/src/ProjectMagazineGallery.tsx +218 -0
- package/templates/default/src/main.tsx +28 -0
- package/templates/default/src/styles.css +501 -0
- package/templates/default/src/utils.ts +2 -0
- package/templates/default/src/vite-env.d.ts +1 -0
- package/templates/default/tests/portfolio.test.js +96 -0
- package/templates/default/tsconfig.app.json +21 -0
- package/templates/default/tsconfig.json +7 -0
- package/templates/default/tsconfig.node.json +16 -0
- package/templates/default/types.ts +73 -0
- package/templates/default/vite.config.ts +38 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"lib": ["ES2023", "DOM"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"strict": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["vite.config.ts"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface Skill {
|
|
2
|
+
name: string
|
|
3
|
+
icon: string
|
|
4
|
+
category?: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface Project {
|
|
8
|
+
name: string
|
|
9
|
+
category?: string
|
|
10
|
+
description: string
|
|
11
|
+
image?: string
|
|
12
|
+
imageAlt?: string
|
|
13
|
+
technologies: Skill[]
|
|
14
|
+
liveUrl?: string
|
|
15
|
+
githubUrl?: string
|
|
16
|
+
featured?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ContentItem {
|
|
20
|
+
title: string
|
|
21
|
+
organization?: string
|
|
22
|
+
organizationUrl?: string
|
|
23
|
+
date?: string
|
|
24
|
+
location?: string
|
|
25
|
+
description?: string
|
|
26
|
+
image?: string
|
|
27
|
+
imageAlt?: string
|
|
28
|
+
imagePlaceholder?: string
|
|
29
|
+
links?: { label: string; url: string }[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Testimonial {
|
|
33
|
+
name: string
|
|
34
|
+
role: string
|
|
35
|
+
company?: string
|
|
36
|
+
message: string
|
|
37
|
+
image?: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SocialIcon {
|
|
41
|
+
label: string
|
|
42
|
+
icon: string
|
|
43
|
+
url?: string
|
|
44
|
+
color?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface PortfolioConfig {
|
|
48
|
+
profile: {
|
|
49
|
+
name: string
|
|
50
|
+
headline: string
|
|
51
|
+
introduction: string
|
|
52
|
+
about: string
|
|
53
|
+
location?: string
|
|
54
|
+
timeZone?: string
|
|
55
|
+
timeZoneLabel?: string
|
|
56
|
+
profileImage?: string
|
|
57
|
+
resumeUrl?: string
|
|
58
|
+
quote?: string
|
|
59
|
+
}
|
|
60
|
+
socialIcons: SocialIcon[]
|
|
61
|
+
experience: ContentItem[]
|
|
62
|
+
education: ContentItem[]
|
|
63
|
+
skills: Skill[]
|
|
64
|
+
projects: Project[]
|
|
65
|
+
testimonials: Testimonial[]
|
|
66
|
+
contact: { email?: string }
|
|
67
|
+
seo: {
|
|
68
|
+
title: string
|
|
69
|
+
description: string
|
|
70
|
+
siteUrl?: string
|
|
71
|
+
image?: string
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
import { portfolioConfig } from './data.ts'
|
|
4
|
+
|
|
5
|
+
function escapeHtml(value: string) {
|
|
6
|
+
return value.replace(/[&<>"']/g, (character) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[character]!)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function portfolioMetadata() {
|
|
10
|
+
return {
|
|
11
|
+
name: 'portfolio-metadata',
|
|
12
|
+
transformIndexHtml(html: string) {
|
|
13
|
+
const personalize = (value: string) => value
|
|
14
|
+
.replaceAll('{{name}}', portfolioConfig.profile.name)
|
|
15
|
+
.replaceAll('{{username}}', portfolioConfig.profile.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''))
|
|
16
|
+
.replaceAll('{{headline}}', portfolioConfig.profile.headline)
|
|
17
|
+
const title = escapeHtml(personalize(portfolioConfig.seo.title))
|
|
18
|
+
const description = escapeHtml(personalize(portfolioConfig.seo.description))
|
|
19
|
+
let result = html
|
|
20
|
+
.replace(/<title>.*?<\/title>/s, `<title>${title}</title>`)
|
|
21
|
+
.replace(/(<meta name="description" content=")[^"]*("\s*\/>)/, (_match, prefix, suffix) => `${prefix}${description}${suffix}`)
|
|
22
|
+
.replace(/(<meta property="og:title" content=")[^"]*("\s*\/>)/, (_match, prefix, suffix) => `${prefix}${title}${suffix}`)
|
|
23
|
+
.replace(/(<meta property="og:description" content=")[^"]*("\s*\/>)/, (_match, prefix, suffix) => `${prefix}${description}${suffix}`)
|
|
24
|
+
.replace(/(<meta name="twitter:title" content=")[^"]*("\s*\/>)/, (_match, prefix, suffix) => `${prefix}${title}${suffix}`)
|
|
25
|
+
.replace(/(<meta name="twitter:description" content=")[^"]*("\s*\/>)/, (_match, prefix, suffix) => `${prefix}${description}${suffix}`)
|
|
26
|
+
const tags = [
|
|
27
|
+
portfolioConfig.seo.siteUrl && `<meta property="og:url" content="${escapeHtml(portfolioConfig.seo.siteUrl)}" />`,
|
|
28
|
+
portfolioConfig.seo.image && `<meta property="og:image" content="${escapeHtml(portfolioConfig.seo.image)}" />`,
|
|
29
|
+
portfolioConfig.seo.image && `<meta name="twitter:image" content="${escapeHtml(portfolioConfig.seo.image)}" />`,
|
|
30
|
+
portfolioConfig.seo.image && `<link rel="icon" href="${escapeHtml(portfolioConfig.seo.image)}" />`,
|
|
31
|
+
].filter(Boolean).join('\n ')
|
|
32
|
+
if (tags) result = result.replace('</head>', ` ${tags}\n </head>`)
|
|
33
|
+
return result
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default defineConfig({ plugins: [react(), portfolioMetadata()] })
|