feat: lazy load ninja-keys + HTML Invoker Commands API
- Lazy load ninja-keys only on CMD+K press (0 requests on initial load) - Use esm.sh bundled module (3 requests vs ~81 previously) - Add esm.sh to CSP whitelist - Implement HTML Invoker Commands API for modals: - commandfor="modal-id" + command="show-modal" for opening - commandfor="modal-id" + command="close" for closing - Removes need for onclick handlers on modal buttons - Refactor index.html into layout partials (head, body-scripts) - Add comprehensive tests for both features
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
{{define "head-structured-data"}}
|
||||
<!-- Structured Data (JSON-LD) - Enhanced for AI-era SEO -->
|
||||
<!-- Person Schema -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Person",
|
||||
"@id": "{{.CV.Personal.Website}}/#person",
|
||||
"name": "{{.CV.Personal.Name}}",
|
||||
"givenName": "{{.CV.Personal.FirstName}}",
|
||||
"familyName": "{{.CV.Personal.LastName}}",
|
||||
"jobTitle": "{{.CV.Personal.Title}}",
|
||||
"description": "{{.CV.Summary}}",
|
||||
"url": "{{.CV.Personal.Website}}",
|
||||
"image": "{{.CV.Personal.Website}}/static/images/profile.jpg",
|
||||
"email": "{{.CV.Personal.Email}}",
|
||||
"telephone": "{{.CV.Personal.Phone}}",
|
||||
"birthDate": "{{.CV.Personal.DateOfBirth}}",
|
||||
"birthPlace": {
|
||||
"@type": "Place",
|
||||
"name": "{{.CV.Personal.PlaceOfBirth}}"
|
||||
},
|
||||
"nationality": {
|
||||
"@type": "Country",
|
||||
"name": "{{.CV.Personal.Citizenship}}"
|
||||
},
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"addressLocality": "{{.CV.Personal.Location}}",
|
||||
"addressCountry": "ES"
|
||||
},
|
||||
"sameAs": [
|
||||
"{{.CV.Personal.LinkedIn}}",
|
||||
"{{.CV.Personal.GitHub}}",
|
||||
"{{.CV.Personal.Domestika}}"
|
||||
],
|
||||
"alumniOf": {
|
||||
"@type": "CollegeOrUniversity",
|
||||
"name": "Universidad de Extremadura",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"addressLocality": "Cáceres",
|
||||
"addressCountry": "ES"
|
||||
}
|
||||
},
|
||||
"knowsAbout": [
|
||||
"Web Development",
|
||||
"SAP Customer Data Cloud",
|
||||
"React",
|
||||
"Node.js",
|
||||
"Go",
|
||||
"HTMX",
|
||||
"AI-Assisted Development",
|
||||
"Full Stack Development",
|
||||
"Authentication Systems",
|
||||
"GDPR Compliance",
|
||||
"Identity Management"
|
||||
],
|
||||
"knowsLanguage": [
|
||||
{
|
||||
"@type": "Language",
|
||||
"name": "Spanish",
|
||||
"alternateName": "es"
|
||||
},
|
||||
{
|
||||
"@type": "Language",
|
||||
"name": "English",
|
||||
"alternateName": "en"
|
||||
},
|
||||
{
|
||||
"@type": "Language",
|
||||
"name": "Portuguese",
|
||||
"alternateName": "pt"
|
||||
}
|
||||
],
|
||||
"worksFor": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"name": "Olympic Broadcasting Services",
|
||||
"url": "https://www.obs.tv/"
|
||||
},
|
||||
{
|
||||
"@type": "Organization",
|
||||
"name": "LIV Golf",
|
||||
"url": "https://www.livgolf.com/"
|
||||
}
|
||||
],
|
||||
"hasOccupation": [
|
||||
{{- range $i, $exp := .CV.Experience}}{{if $i}},{{end}}
|
||||
{
|
||||
"@type": "Occupation",
|
||||
"name": "{{$exp.Position}}",
|
||||
"occupationLocation": {
|
||||
"@type": "Place",
|
||||
"name": "{{$exp.Location}}"
|
||||
},
|
||||
"description": "{{$exp.ShortDescription}}",
|
||||
"skills": "{{range $j, $tech := $exp.Technologies}}{{if $j}}, {{end}}{{$tech}}{{end}}"
|
||||
}
|
||||
{{- end}}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- WebSite Schema -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"@id": "{{.CV.Personal.Website}}/#website",
|
||||
"name": "{{.CV.Personal.Name}} - Professional CV",
|
||||
"url": "{{.CV.Personal.Website}}",
|
||||
"description": "Interactive curriculum vitae of {{.CV.Personal.Name}}, {{.CV.Personal.Title}}",
|
||||
"inLanguage": ["en", "es"],
|
||||
"author": {
|
||||
"@id": "{{.CV.Personal.Website}}/#person"
|
||||
},
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": "{{.CV.Personal.Website}}/?lang={search_term_string}",
|
||||
"query-input": "required name=search_term_string"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- BreadcrumbList Schema -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "Home",
|
||||
"item": "{{.CV.Personal.Website}}"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "CV {{if eq .Lang "es"}}(Español){{else}}(English){{end}}",
|
||||
"item": "{{.CV.Personal.Website}}/?lang={{.Lang}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- ProfilePage Schema (for CV/Resume) -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ProfilePage",
|
||||
"mainEntity": {
|
||||
"@id": "{{.CV.Personal.Website}}/#person"
|
||||
},
|
||||
"dateCreated": "2024-01-01",
|
||||
"dateModified": "{{.CV.Meta.LastUpdated}}",
|
||||
"name": "{{.CV.Personal.Name}} - Curriculum Vitae",
|
||||
"description": "{{.CV.SEO.MetaDescription}}",
|
||||
"inLanguage": "{{.Lang}}"
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- EducationalOccupationalCredential Schema -->
|
||||
{{range .CV.Education}}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "EducationalOccupationalCredential",
|
||||
"name": "{{.Degree}}",
|
||||
"description": "{{.Field}}",
|
||||
"educationalLevel": "Bachelor's Degree",
|
||||
"credentialCategory": "degree",
|
||||
"recognizedBy": {
|
||||
"@type": "CollegeOrUniversity",
|
||||
"name": "{{.Institution}}",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"addressLocality": "{{.Location}}"
|
||||
}
|
||||
},
|
||||
"dateCreated": "{{.EndDate}}"
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
|
||||
<!-- Course Schemas -->
|
||||
{{range .CV.Courses}}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Course",
|
||||
"name": "{{.Title}}",
|
||||
"description": "{{if .ShortDescription}}{{.ShortDescription}}{{else}}{{.Description}}{{end}}",
|
||||
"provider": {
|
||||
"@type": "Organization",
|
||||
"name": "{{.Institution}}"
|
||||
},
|
||||
"hasCourseInstance": {
|
||||
"@type": "CourseInstance",
|
||||
"courseMode": "onsite",
|
||||
"location": {
|
||||
"@type": "Place",
|
||||
"name": "{{.Location}}"
|
||||
}
|
||||
},
|
||||
"timeRequired": "{{.Duration}}"
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user