diff --git a/data/cv-en.json b/data/cv-en.json
index 69c80ed..d9ebe12 100644
--- a/data/cv-en.json
+++ b/data/cv-en.json
@@ -546,6 +546,7 @@
"projectDesc": "AI-Powered Photo Library MCP Server",
"url": "https://drolosoft.com/immich-photo-manager.html?lang=en",
"gitRepoUrl": "https://github.com/drolosoft/immich-photo-manager",
+ "openSource": true,
"projectLogo": "immich-photo-manager.png",
"location": "Online",
"startDate": "2026",
@@ -573,6 +574,7 @@
"projectDesc": "Terminal Session Persistence Tool",
"url": "https://drolosoft.com/cmux-resurrect.html?lang=en",
"gitRepoUrl": "https://github.com/drolosoft/cmux-resurrect",
+ "openSource": true,
"projectLogo": "cmux-resurrect.png",
"location": "Online",
"startDate": "2026",
@@ -600,6 +602,7 @@
"projectDesc": "Bidirectional Server Control Plugin",
"url": "https://github.com/drolosoft/gotify-commander",
"gitRepoUrl": "https://github.com/drolosoft/gotify-commander",
+ "openSource": true,
"projectLogo": "gotify-commander.png",
"location": "Online",
"startDate": "2026",
@@ -726,6 +729,7 @@
"projectDesc": "SAP Customer Data Cloud Demo",
"url": "https://gigyademo.com/cdc-starter-kit/",
"gitRepoUrl": "https://github.com/gigya/cdc-starter-kit",
+ "openSource": true,
"projectLogo": "sap.png",
"logoIndex": 8,
"location": "Online",
diff --git a/data/cv-es.json b/data/cv-es.json
index 202b561..215ef3d 100644
--- a/data/cv-es.json
+++ b/data/cv-es.json
@@ -546,6 +546,7 @@
"projectDesc": "Servidor MCP para Gestión de Fotos con IA",
"url": "https://drolosoft.com/immich-photo-manager.html?lang=es",
"gitRepoUrl": "https://github.com/drolosoft/immich-photo-manager",
+ "openSource": true,
"projectLogo": "immich-photo-manager.png",
"location": "Online",
"startDate": "2026",
@@ -573,6 +574,7 @@
"projectDesc": "Herramienta de Persistencia de Sesiones de Terminal",
"url": "https://drolosoft.com/cmux-resurrect.html?lang=es",
"gitRepoUrl": "https://github.com/drolosoft/cmux-resurrect",
+ "openSource": true,
"projectLogo": "cmux-resurrect.png",
"location": "Online",
"startDate": "2026",
@@ -600,6 +602,7 @@
"projectDesc": "Plugin Bidireccional de Control de Servidores",
"url": "https://github.com/drolosoft/gotify-commander",
"gitRepoUrl": "https://github.com/drolosoft/gotify-commander",
+ "openSource": true,
"projectLogo": "gotify-commander.png",
"location": "Online",
"startDate": "2026",
@@ -726,6 +729,7 @@
"projectDesc": "Demo de SAP Customer Data Cloud",
"url": "https://gigyademo.com/cdc-starter-kit/",
"gitRepoUrl": "https://github.com/gigya/cdc-starter-kit",
+ "openSource": true,
"projectLogo": "sap.png",
"logoIndex": 8,
"location": "Online",
diff --git a/internal/models/cv.go b/internal/models/cv.go
index a9d2a2d..78729e5 100644
--- a/internal/models/cv.go
+++ b/internal/models/cv.go
@@ -100,6 +100,7 @@ type Project struct {
ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename
LogoIndex *int `json:"logoIndex,omitempty"` // Sprite sheet index (nil means no sprite)
GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates
+ OpenSource bool `json:"openSource,omitempty"` // True if project is open source (shows stars badge)
Location string `json:"location"`
StartDate string `json:"startDate,omitempty"` // Optional static start date
Current bool `json:"current"`
diff --git a/internal/models/cv/cv.go b/internal/models/cv/cv.go
index 7c71c9a..572f446 100644
--- a/internal/models/cv/cv.go
+++ b/internal/models/cv/cv.go
@@ -105,6 +105,7 @@ type Project struct {
ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename
LogoIndex *int `json:"logoIndex,omitempty"` // Sprite sheet index (nil means no sprite)
GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates
+ OpenSource bool `json:"openSource,omitempty"` // True if project is open source (shows stars badge)
Location string `json:"location"`
StartDate string `json:"startDate,omitempty"` // Optional static start date
Current bool `json:"current"`
diff --git a/internal/templates/template.go b/internal/templates/template.go
index 78698dc..5ef8ab3 100644
--- a/internal/templates/template.go
+++ b/internal/templates/template.go
@@ -68,6 +68,15 @@ func (m *Manager) loadTemplatesLocked() error {
"replaceDrolosoft": func(s string) string {
return strings.Replace(s, "drolosoft", `drolosoft`, 1)
},
+ // githubRepo extracts "owner/repo" from a GitHub URL
+ "githubRepo": func(url string) string {
+ url = strings.TrimSuffix(url, "/")
+ parts := strings.Split(url, "github.com/")
+ if len(parts) == 2 {
+ return parts[1]
+ }
+ return ""
+ },
// dict creates a map from key-value pairs for passing to sub-templates
"dict": func(values ...interface{}) (map[string]interface{}, error) {
if len(values)%2 != 0 {
diff --git a/static/css/03-components/_cv-section.css b/static/css/03-components/_cv-section.css
index f5396a0..f1f69a9 100644
--- a/static/css/03-components/_cv-section.css
+++ b/static/css/03-components/_cv-section.css
@@ -194,6 +194,19 @@
font-size: 1.2em;
}
+.stars-badge {
+ display: inline-flex;
+ align-items: center;
+ margin-left: 0.3em;
+ vertical-align: middle;
+ text-decoration: none;
+}
+
+.stars-badge img {
+ height: 18px;
+ vertical-align: middle;
+}
+
.maintained-badge {
display: inline-block;
background: #3498db;
diff --git a/static/css/print.css b/static/css/print.css
index be13984..d4a5a45 100644
--- a/static/css/print.css
+++ b/static/css/print.css
@@ -105,6 +105,10 @@
text-decoration: none !important;
}
+ .stars-badge {
+ display: none !important;
+ }
+
/* ===================================
REMOVE ALL SHADOWS & BORDERS (Nuclear Option)
=================================== */
diff --git a/templates/partials/sections/projects.html b/templates/partials/sections/projects.html
index f85b8b8..ac75d64 100644
--- a/templates/partials/sections/projects.html
+++ b/templates/partials/sections/projects.html
@@ -32,6 +32,7 @@
{{if .Current}}LIVE{{end}}
{{if .GitRepoUrl}}GitHub{{end}}
+ {{if and .OpenSource .GitRepoUrl}}
{{end}}
{{if .MaintainedBy}}{{$.UI.Sections.MaintainedBy}} {{.MaintainedBy}}{{end}}
{{if .StartDate}}{{.StartDate}}{{if .Current}}{{if .DynamicDate}} / {{.DynamicDate}}{{else}} / {{$.UI.Sections.Present}}{{end}}{{end}}{{end}} - ({{.Location}})