From 7aed0eca7e62f6950cab85486d30b8f894f268c0 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 26 Mar 2026 11:02:48 +0100 Subject: added new version of the danix.me hugo site, coauthored by claude-code --- themes/danixme/assets/css/main.css | 1750 ++++++++++++++++++++++++ themes/danixme/assets/js/main.js | 374 +++++ themes/danixme/i18n/en.toml | 149 ++ themes/danixme/i18n/it.toml | 149 ++ themes/danixme/layouts/_default/baseof.html | 11 + themes/danixme/layouts/index.html | 10 + themes/danixme/layouts/partials/about.html | 37 + themes/danixme/layouts/partials/certs.html | 67 + themes/danixme/layouts/partials/contact.html | 49 + themes/danixme/layouts/partials/education.html | 28 + themes/danixme/layouts/partials/footer.html | 22 + themes/danixme/layouts/partials/head.html | 77 ++ themes/danixme/layouts/partials/hero.html | 60 + themes/danixme/layouts/partials/nav.html | 45 + themes/danixme/layouts/partials/projects.html | 93 ++ themes/danixme/layouts/partials/scripts.html | 11 + themes/danixme/layouts/partials/services.html | 24 + themes/danixme/layouts/partials/skills.html | 24 + themes/danixme/layouts/robots.txt | 4 + themes/danixme/theme.toml | 5 + 20 files changed, 2989 insertions(+) create mode 100644 themes/danixme/assets/css/main.css create mode 100644 themes/danixme/assets/js/main.js create mode 100644 themes/danixme/i18n/en.toml create mode 100644 themes/danixme/i18n/it.toml create mode 100644 themes/danixme/layouts/_default/baseof.html create mode 100644 themes/danixme/layouts/index.html create mode 100644 themes/danixme/layouts/partials/about.html create mode 100644 themes/danixme/layouts/partials/certs.html create mode 100644 themes/danixme/layouts/partials/contact.html create mode 100644 themes/danixme/layouts/partials/education.html create mode 100644 themes/danixme/layouts/partials/footer.html create mode 100644 themes/danixme/layouts/partials/head.html create mode 100644 themes/danixme/layouts/partials/hero.html create mode 100644 themes/danixme/layouts/partials/nav.html create mode 100644 themes/danixme/layouts/partials/projects.html create mode 100644 themes/danixme/layouts/partials/scripts.html create mode 100644 themes/danixme/layouts/partials/services.html create mode 100644 themes/danixme/layouts/partials/skills.html create mode 100644 themes/danixme/layouts/robots.txt create mode 100644 themes/danixme/theme.toml (limited to 'themes') diff --git a/themes/danixme/assets/css/main.css b/themes/danixme/assets/css/main.css new file mode 100644 index 0000000..649adae --- /dev/null +++ b/themes/danixme/assets/css/main.css @@ -0,0 +1,1750 @@ +/* ── Reset & Variables ──────────────────────────── */ +*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } + +:root { + --bg: #060b10; + --bg2: #0c1520; + --surface: #101e2d; + --border: #182840; + --accent: #a855f7; + --accent2: #00ff88; + --accent-glow: rgba(168, 85, 247, 0.12); + --text: #c4d6e8; + --text-dim: #7a9bb8; + --muted: #304860; + --font-mono: 'JetBrains Mono', 'Courier New', monospace; + --font-head: 'Oxanium', sans-serif; +} + +html { scroll-behavior: smooth; font-size: 17px; overflow-x: hidden; } + +body { + background-color: var(--bg); + color: var(--text); + font-family: var(--font-mono); + font-size: 1rem; + line-height: 1.8; + overflow-x: hidden; + -webkit-font-smoothing: antialiased; + overflow-wrap: break-word; +} + +/* Dot grid */ +body::before { + content: ''; + position: fixed; + inset: 0; + background-image: radial-gradient(circle, rgba(168,85,247,0.07) 1px, transparent 1px); + background-size: 30px 30px; + pointer-events: none; + z-index: 0; +} + +/* ── Light Theme ────────────────────────────────── */ +/* Class applied by inline script before CSS renders — no flash. */ +/* Media query block is a no-JS fallback only. */ + +html.theme-light { + --bg: #f0f4f8; + --bg2: #e2eaf4; + --surface: #d4dff0; + --border: #a8bdd8; + --accent: #7c3aed; + --accent2: #008f5a; + --accent-glow: rgba(124, 58, 237, 0.1); + --text: #0d1b2a; + --text-dim: #2e4a6a; + --muted: #6888a8; +} +html.theme-light body::before { + background-image: radial-gradient(circle, rgba(124,58,237,0.07) 1px, transparent 1px); +} +html.theme-light nav { + background: rgba(240, 244, 248, 0.92); + border-bottom-color: rgba(168, 189, 216, 0.6); +} +html.theme-light #matrix-canvas { opacity: 0.18; } +html.theme-light #hero::after { + background: radial-gradient(ellipse, rgba(124,58,237,0.06) 0%, transparent 65%); +} +html.theme-light .hero-name { + text-shadow: 0 0 80px rgba(124,58,237,0.12), 0 0 120px rgba(124,58,237,0.05); +} +html.theme-light .hero-term { + background: rgba(10, 20, 35, 0.95); + border-color: rgba(124, 58, 237, 0.35); + box-shadow: 0 0 40px rgba(124,58,237,0.08), inset 0 0 30px rgba(0,0,0,0.5); + /* Reset colour variables to dark values so text is legible on dark bg */ + --text: #c4d6e8; + --text-dim: #7a9bb8; + --muted: #304860; + --accent: #a855f7; + --accent2: #00ff88; + /* Re-apply color so it resolves against the local --text above */ + color: var(--text); +} +html.theme-light #scroll-progress { + box-shadow: 0 0 8px rgba(124,58,237,0.45); +} + +/* No-JS fallback via media query */ +@media (prefers-color-scheme: light) { + :root { + --bg: #f0f4f8; + --bg2: #e2eaf4; + --surface: #d4dff0; + --border: #a8bdd8; + --accent: #7c3aed; + --accent2: #008f5a; + --accent-glow: rgba(124, 58, 237, 0.1); + --text: #0d1b2a; + --text-dim: #2e4a6a; + --muted: #6888a8; + } + body::before { + background-image: radial-gradient(circle, rgba(124,58,237,0.07) 1px, transparent 1px); + } + nav { background: rgba(240,244,248,0.92); border-bottom-color: rgba(168,189,216,0.6); } + #matrix-canvas { opacity: 0.18; } + #hero::after { background: radial-gradient(ellipse, rgba(124,58,237,0.06) 0%, transparent 65%); } + .hero-name { text-shadow: 0 0 80px rgba(124,58,237,0.12), 0 0 120px rgba(124,58,237,0.05); } + .hero-term { background: rgba(10,20,35,0.95); border-color: rgba(124,58,237,0.35); box-shadow: 0 0 40px rgba(124,58,237,0.08), inset 0 0 30px rgba(0,0,0,0.5); --text: #c4d6e8; --text-dim: #7a9bb8; --muted: #304860; --accent: #a855f7; --accent2: #00ff88; color: var(--text); } + #scroll-progress { box-shadow: 0 0 8px rgba(124,58,237,0.45); } +} + +/* Force dark even when system preference is light */ +html.theme-dark { + --bg: #060b10; + --bg2: #0c1520; + --surface: #101e2d; + --border: #182840; + --accent: #a855f7; + --accent2: #00ff88; + --accent-glow: rgba(168, 85, 247, 0.12); + --text: #c4d6e8; + --text-dim: #7a9bb8; + --muted: #304860; +} +html.theme-dark nav { + background: rgba(6,11,16,0.88); + border-bottom-color: rgba(24,40,64,0.5); +} +html.theme-dark body::before { + background-image: radial-gradient(circle, rgba(168,85,247,0.07) 1px, transparent 1px); +} +html.theme-dark #matrix-canvas { opacity: 0.13; } +html.theme-dark #hero::after { + background: radial-gradient(ellipse, rgba(168,85,247,0.07) 0%, transparent 65%); +} +html.theme-dark .hero-name { + text-shadow: 0 0 80px rgba(168,85,247,0.18), 0 0 120px rgba(168,85,247,0.08); +} +html.theme-dark .hero-term { + background: rgba(6, 11, 16, 0.85); + border-color: rgba(168,85,247,0.3); + box-shadow: 0 0 40px rgba(168,85,247,0.1), inset 0 0 30px rgba(0,0,0,0.4); +} +html.theme-dark #scroll-progress { + box-shadow: 0 0 8px rgba(168,85,247,0.6); +} + +/* ── Container ──────────────────────────────────── */ +.container { + max-width: 1080px; + margin: 0 auto; + padding: 0 1.2rem; + position: relative; + z-index: 1; +} + +@media (min-width: 768px) { + .container { padding: 0 2rem; } +} + +/* ── Scroll Progress ─────────────────────────────── */ +#scroll-progress { + position: fixed; + top: 0; + left: 0; + height: 2px; + width: 0%; + background: linear-gradient(to right, var(--accent), var(--accent2)); + box-shadow: 0 0 8px rgba(168,85,247,0.6); + z-index: 9999; + pointer-events: none; +} + +/* ── Navbar ─────────────────────────────────────── */ +nav { + position: fixed; + inset-block-start: 0; + inset-inline: 0; + z-index: 100; + padding: 1rem 1.2rem; + display: flex; + align-items: center; + justify-content: space-between; + background: rgba(6,11,16,0.88); + backdrop-filter: blur(14px); + border-bottom: 1px solid rgba(24,40,64,0.5); + transition: border-color 0.3s; +} + +@media (min-width: 768px) { + nav { padding: 1.1rem 2rem; } +} + +.nav-logo { + display: flex; + align-items: center; + gap: 0.55rem; + text-decoration: none; +} +.nav-logo-img { + height: 28px; + width: auto; + display: block; + flex-shrink: 0; +} +.nav-logo-text { + font-family: var(--font-head); + font-size: 1.05rem; + font-weight: 800; + color: var(--accent); + letter-spacing: -0.02em; +} +.nav-logo-tld { color: var(--muted); font-size: 0.85rem; } +@media (max-width: 767px) { + .nav-logo-text { display: none; } +} + +.nav-right { + display: flex; + align-items: center; + gap: 1rem; +} + +@media (min-width: 768px) { + .nav-right { gap: 2rem; } +} + +/* Nav links: hidden on mobile, shown on desktop */ +.nav-links { + display: none; + list-style: none; +} + +@media (min-width: 768px) { + .nav-links { + display: flex; + gap: 1.75rem; + } +} + +.nav-links a { + color: var(--text-dim); + text-decoration: none; + font-size: 0.8rem; + letter-spacing: 0.08em; + text-transform: uppercase; + transition: color 0.2s; + position: relative; +} +.nav-links a::after { + content: ''; + position: absolute; + bottom: -2px; + inset-inline: 0; + height: 1px; + background: var(--accent); + transform: scaleX(0); + transition: transform 0.2s; +} +.nav-links a:hover { color: var(--accent); } +.nav-links a:hover::after { transform: scaleX(1); } + +/* Lang toggle */ +.lang-toggle { + display: flex; + background: var(--surface); + border: 1px solid var(--border); + overflow: hidden; +} +.lang-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + cursor: pointer; + background: transparent; + border: 2px solid transparent; + border-radius: 4px; + transition: border-color 0.2s, opacity 0.2s; + line-height: 1; +} +.lang-btn .fi { + width: 1.4em; + height: 1.4em; + border-radius: 2px; + display: block; +} +.lang-btn.active { + border-color: var(--accent); +} +.lang-btn:not(.active) { opacity: 0.65; } +.lang-btn:not(.active):hover { opacity: 1; } +span.lang-btn { cursor: default; } +a.lang-btn { text-decoration: none; } + +/* Theme toggle */ +.theme-toggle { + background: none; + border: none; + cursor: pointer; + color: var(--text-dim); + font-size: 1rem; + padding: 0.25rem; + display: flex; + align-items: center; + gap: 0.5rem; + transition: color 0.2s; + line-height: 1; +} +.theme-toggle:hover { color: var(--accent); } + +/* Desktop toggle: hide on mobile */ +.theme-toggle--desktop { + display: none; +} +@media (min-width: 768px) { + .theme-toggle--desktop { display: flex; } +} + +/* Mobile toggle item: hide on desktop */ +.nav-theme-item { display: none; } +.nav-theme-item .theme-toggle { + font-size: 0.8rem; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 0; +} + +/* Hamburger: shown on mobile, hidden on desktop */ +.hamburger { + display: flex; + flex-direction: column; + gap: 5px; + cursor: pointer; + background: none; + border: none; + padding: 4px; +} +.hamburger span { + display: block; + width: 22px; + height: 2px; + background: var(--text-dim); + transition: all 0.3s; +} + +@media (min-width: 768px) { + .hamburger { display: none; } +} + +/* ── Hero ───────────────────────────────────────── */ +#hero { + min-height: 100svh; + display: flex; + align-items: center; + padding-top: 60px; + position: relative; + overflow: hidden; + background: var(--bg); +} + +@media (min-width: 768px) { + #hero { padding-top: 70px; } +} + +/* Matrix canvas */ +#matrix-canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + opacity: 0.13; + pointer-events: none; +} + +/* Scanlines overlay */ +#hero::before { + content: ''; + position: absolute; + inset: 0; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 2px, + rgba(0,0,0,0.07) 2px, + rgba(0,0,0,0.07) 3px + ); + pointer-events: none; + z-index: 1; +} + +/* Ambient radial glow */ +#hero::after { + content: ''; + position: absolute; + top: 35%; + left: 30%; + transform: translate(-50%, -50%); + width: 900px; + height: 600px; + background: radial-gradient(ellipse, rgba(168,85,247,0.07) 0%, transparent 65%); + pointer-events: none; + z-index: 0; +} + +/* Hero inner: flex column — name full-width, then bottom row */ +.hero-inner { + padding: 3rem 0; + display: flex; + flex-direction: column; + gap: 1.5rem; + position: relative; + z-index: 2; +} + +@media (min-width: 768px) { + .hero-inner { padding: 4rem 0; } +} + +/* Bottom row: content + terminal side-by-side on desktop */ +.hero-bottom { + display: flex; + align-items: center; + gap: 3rem; +} + +.hero-content { flex: 1; min-width: 0; } + +/* ── Prompt ── */ +.hero-prompt { + font-size: 0.8rem; + color: var(--accent2); + letter-spacing: 0.1em; + margin-bottom: 1.25rem; + opacity: 0; + animation: fadeUp 0.6s ease forwards 0.2s; +} +.hero-prompt::before { content: '$ '; color: var(--muted); } + +/* ── Name with glitch ── */ +.hero-name { + font-family: var(--font-head); + font-size: clamp(3rem, 12vw, 7rem); + font-weight: 800; + line-height: 0.95; + letter-spacing: -0.04em; + color: var(--text); + margin-bottom: 0; + opacity: 0; + animation: fadeUp 0.6s ease forwards 0.4s; + display: inline-block; + position: relative; + text-shadow: 0 0 80px rgba(168,85,247,0.18), 0 0 120px rgba(168,85,247,0.08); +} + +/* Chromatic aberration layers */ +.hero-name::before, +.hero-name::after { + content: attr(data-text); + position: absolute; + top: 0; left: 0; + width: 100%; + height: 100%; + opacity: 0; + pointer-events: none; + overflow: hidden; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + letter-spacing: inherit; + line-height: inherit; +} +.hero-name::before { color: #ff2b6d; } +.hero-name::after { color: #00e5ff; } + +.hero-name.is-glitching::before { + opacity: 0.8; + animation: glitch-red 0.45s steps(3) forwards; +} +.hero-name.is-glitching::after { + opacity: 0.8; + animation: glitch-cyn 0.45s steps(3) forwards; +} + +/* ── Role ── */ +.hero-role { + font-size: clamp(0.85rem, 3vw, 1rem); + color: var(--accent); + margin-bottom: 1.5rem; + opacity: 0; + animation: fadeUp 0.6s ease forwards 0.6s; + min-height: 1.75em; +} + +.cursor { + display: inline-block; + width: 2px; + height: 1em; + background: var(--accent); + margin-left: 1px; + vertical-align: text-bottom; + animation: blink 1s step-end infinite; +} + +/* ── Tagline ── */ +.hero-tagline { + font-size: 0.93rem; + color: var(--text-dim); + max-width: 500px; + margin-bottom: 2.5rem; + opacity: 0; + animation: fadeUp 0.6s ease forwards 0.8s; + line-height: 1.95; +} + +/* ── CTA buttons ── */ +.hero-cta { + display: flex; + flex-direction: column; + gap: 1rem; + opacity: 0; + animation: fadeUp 0.6s ease forwards 1s; +} + +@media (min-width: 480px) { + .hero-cta { flex-direction: row; flex-wrap: wrap; } +} + +/* ── Terminal panel ── */ +.hero-term { + display: none; +} + +@media (min-width: 900px) { + .hero-term { + display: flex; + flex-direction: column; + width: 320px; + flex-shrink: 0; + background: rgba(6, 11, 16, 0.85); + border: 1px solid rgba(168,85,247,0.3); + border-radius: 10px; + overflow: hidden; + box-shadow: 0 0 40px rgba(168,85,247,0.1), inset 0 0 30px rgba(0,0,0,0.4); + opacity: 0; + animation: fadeUp 0.6s ease forwards 0.5s; + backdrop-filter: blur(8px); + } +} + +.hero-term-bar { + display: flex; + align-items: center; + gap: 0.4rem; + padding: 0.6rem 0.9rem; + background: rgba(255,255,255,0.04); + border-bottom: 1px solid rgba(168,85,247,0.15); +} + +.hero-term-dot { + width: 11px; + height: 11px; + border-radius: 50%; + background: var(--c, #888); + flex-shrink: 0; +} + +.hero-term-title { + margin-left: 0.4rem; + font-size: 0.65rem; + color: var(--muted); + letter-spacing: 0.06em; + font-family: var(--font-mono); +} + +.hero-term-body { + padding: 1rem 1.1rem; + font-family: var(--font-mono); + font-size: 0.78rem; + line-height: 1.7; + display: flex; + flex-direction: column; + gap: 0.1rem; +} + +/* Terminal line fade-in sequence */ +.tl { + opacity: 0; + animation: fadeIn 0.25s ease forwards; +} +.hero-term-body .tl { white-space: nowrap; } +.tl-d1 { animation-delay: 0.9s; } +.tl-d2 { animation-delay: 1.5s; } +.tl-d3 { animation-delay: 1.9s; } +.tl-d4 { animation-delay: 2.1s; } +.tl-d5 { animation-delay: 2.3s; } +.tl-d6 { animation-delay: 2.5s; } +.tl-d7 { animation-delay: 2.7s; } +.tl-d8 { animation-delay: 2.9s; } +.tl-d9 { animation-delay: 3.1s; } + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.tc-dim { color: var(--muted); } +.tc-ok { color: var(--accent2); } +.tc-val { color: var(--text); } +.tc-key { color: var(--muted); } +.tc-blink { animation: blink 1s step-end infinite; color: var(--accent2); } + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.65rem 1.4rem; + font-family: var(--font-mono); + font-size: 0.8rem; + letter-spacing: 0.1em; + text-transform: uppercase; + text-decoration: none; + cursor: pointer; + border: none; + transition: all 0.22s; +} + +@media (min-width: 480px) { + .btn { justify-content: flex-start; } +} + +.btn-primary { + background: var(--accent); + color: var(--bg); + font-weight: 700; +} +.btn-primary:hover { + background: #fff; + box-shadow: 0 0 24px rgba(168,85,247,0.45); +} +.btn-outline { + background: transparent; + color: var(--text); + border: 1px solid var(--border); +} +.btn-outline:hover { + border-color: var(--accent); + color: var(--accent); + box-shadow: inset 0 0 16px rgba(168,85,247,0.06); +} +.btn-cv { + background: transparent; + color: var(--muted); + border: 1px dashed var(--border); + gap: 0.45rem; +} +.btn-cv:hover { + border-color: var(--accent); + border-style: solid; + color: var(--accent); +} + +.scroll-indicator { + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + color: var(--muted); + font-size: 0.7rem; + letter-spacing: 0.12em; + text-transform: uppercase; + opacity: 0; + animation: fadeUp 0.6s ease forwards 1.4s; +} +.scroll-line { + width: 1px; + height: 44px; + background: linear-gradient(to bottom, var(--accent), transparent); + animation: scanDown 2s ease-in-out infinite; +} + +/* ── Sections ───────────────────────────────────── */ +section { + padding: 4rem 0; + position: relative; + z-index: 1; +} + +@media (min-width: 768px) { + section { padding: 6rem 0; } +} + +.section-eyebrow { + font-size: 0.75rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--accent); + margin-bottom: 0.6rem; + display: flex; + align-items: center; + gap: 0.7rem; +} +.section-eyebrow::before { content: '//'; color: var(--muted); } + +.section-title { + font-family: var(--font-head); + font-size: clamp(1.7rem, 6vw, 3rem); + font-weight: 800; + color: var(--text); + letter-spacing: -0.035em; + margin-bottom: 2rem; + line-height: 1.05; +} + +@media (min-width: 768px) { + .section-title { margin-bottom: 3rem; } +} + +/* ── About ──────────────────────────────────────── */ + +/* Mobile: single column */ +.about-grid { + display: grid; + grid-template-columns: 1fr; + gap: 2.5rem; + align-items: start; +} + +/* Desktop: two columns */ +@media (min-width: 768px) { + .about-grid { + grid-template-columns: 1.1fr 0.9fr; + gap: 4rem; + } +} + +.about-bio p { + color: var(--text-dim); + font-size: 0.95rem; + line-height: 1.95; + margin-bottom: 1rem; + hyphens: auto; +} +.about-bio p:last-child { margin-bottom: 0; } + +/* About photo (floated inside bio column) */ +.about-photo { + float: left; + width: 120px; + height: 120px; + object-fit: cover; + object-position: center top; + border: 1px solid var(--border); + margin: 0.2rem 1.25rem 0.75rem 0; + filter: grayscale(15%); + transition: filter 0.4s; + flex-shrink: 0; +} + +.about-photo:hover { + filter: grayscale(0%); +} + +.about-bio { overflow: hidden; } + +/* Terminal window */ +.terminal { + background: var(--bg2); + border: 1px solid var(--border); +} +.terminal-bar { + padding: 0.55rem 1rem; + background: var(--surface); + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + gap: 0.45rem; +} +.dot { width: 10px; height: 10px; border-radius: 50%; } +.dot-r { background: #ff5f57; } +.dot-y { background: #ffbd2e; } +.dot-g { background: #28c840; } +.t-file { font-size: 0.68rem; color: var(--muted); margin-left: 0.4rem; } + +.terminal-body { + padding: 1.4rem 1.5rem; + font-size: 0.84rem; + line-height: 1.9; + overflow-x: auto; +} +.tl { display: flex; gap: 0.6rem; } +.t-ps { color: var(--accent2); user-select: none; flex-shrink: 0; } +.t-cm { color: var(--accent); } +.t-out { color: var(--text-dim); padding-left: 1rem; } +.t-k { color: var(--muted); } +.t-v { color: var(--text); } +.t-s { color: var(--accent2); } + +/* ── Services ───────────────────────────────────── */ +.services-grid { + display: grid; + grid-template-columns: 1fr; + gap: 1.5rem; +} + +@media (min-width: 600px) { + .services-grid { grid-template-columns: repeat(2, 1fr); } +} + +.service-card { + border: 1px solid var(--border); + background: var(--bg2); + padding: 1.75rem; + position: relative; + overflow: hidden; + transition: border-color 0.3s, background 0.2s; +} +.service-card::before { + content: ''; + position: absolute; + top: 0; inset-inline: 0; + height: 2px; + background: linear-gradient(90deg, var(--accent), var(--accent2)); +} +.service-card:hover { + border-color: rgba(168,85,247,0.28); + background: var(--surface); +} + +.service-icon { + font-size: 1.6rem; + margin-bottom: 1rem; + color: var(--accent); + display: block; +} +.service-title { + font-family: var(--font-head); + font-size: 1.1rem; + font-weight: 800; + color: var(--text); + letter-spacing: -0.02em; + margin-bottom: 0.2rem; +} +.service-subtitle { + font-size: 0.76rem; + color: var(--accent); + letter-spacing: 0.06em; + margin-bottom: 0.9rem; +} +.service-desc { + font-size: 0.88rem; + color: var(--text-dim); + line-height: 1.85; +} + +/* ── Education ──────────────────────────────────── */ +#education { background: var(--bg2); } + +.edu-list { + position: relative; + display: flex; + flex-direction: column; + padding-left: 1rem; +} +.edu-list::before { + content: ''; + position: absolute; + left: 0.44rem; + top: 0.75rem; + bottom: 0; + width: 1px; + background: linear-gradient(to bottom, var(--accent), transparent); +} + +.edu-item { + display: grid; + grid-template-columns: 1.5rem 1fr; + gap: 1.5rem; + padding-bottom: 2.5rem; +} +.edu-item:last-child { padding-bottom: 0; } + +.edu-dot { + width: 0.9rem; + height: 0.9rem; + border-radius: 50%; + border: 2px solid var(--accent); + background: var(--bg2); + flex-shrink: 0; + margin-top: 0.3rem; + position: relative; + z-index: 1; + transition: background 0.2s; +} +.edu-dot.current { + background: var(--accent); + box-shadow: 0 0 10px rgba(168,85,247,0.5); +} + +.edu-period { + font-size: 0.72rem; + color: var(--accent); + letter-spacing: 0.1em; + text-transform: uppercase; + margin-bottom: 0.35rem; +} +.edu-degree { + font-family: var(--font-head); + font-size: 1.05rem; + font-weight: 800; + color: var(--text); + letter-spacing: -0.02em; + margin-bottom: 0.2rem; +} +.edu-institution { + font-size: 0.78rem; + color: var(--muted); + letter-spacing: 0.03em; + margin-bottom: 0.6rem; +} +.edu-desc { + font-size: 0.88rem; + color: var(--text-dim); + line-height: 1.85; +} + +/* ── Skills ─────────────────────────────────────── */ +#skills { background: var(--bg2); } +#skills::before { + content: ''; + position: absolute; + inset: 0; + background-image: radial-gradient(circle, rgba(168,85,247,0.04) 1px, transparent 1px); + background-size: 28px 28px; +} + +/* Mobile: single column; wider: auto-fill grid */ +.skills-grid { + display: grid; + grid-template-columns: 1fr; + background: var(--border); + gap: 1px; + border: 1px solid var(--border); +} + +@media (min-width: 480px) { + .skills-grid { grid-template-columns: repeat(2, 1fr); } +} + +@media (min-width: 900px) { + .skills-grid { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); } +} + +.skill-card { + background: var(--bg2); + padding: 1.5rem; + transition: background 0.2s; +} +.skill-card:hover { background: var(--surface); } + +.skill-head { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 0.6rem; +} +.skill-icon { + width: 34px; + height: 34px; + display: flex; + align-items: center; + justify-content: center; + background: var(--accent-glow); + border: 1px solid rgba(168,85,247,0.18); + font-size: 1rem; + flex-shrink: 0; + color: var(--accent); +} +.skill-name { + font-size: 0.85rem; + font-weight: 700; + color: var(--text); + letter-spacing: 0.01em; +} +.skill-track { + height: 2px; + background: var(--border); + margin-top: 0.75rem; + overflow: hidden; +} +.skill-fill { + height: 100%; + background: linear-gradient(90deg, var(--accent), var(--accent2)); + transform-origin: left; + transform: scaleX(0); + transition: transform 1.1s cubic-bezier(0.16,1,0.3,1); +} +.skill-fill.go { transform: scaleX(var(--w, 1)); } + +.skill-tags { + display: flex; + flex-wrap: wrap; + gap: 0.35rem; + margin-top: 0.75rem; +} +.tag { + font-size: 0.7rem; + padding: 0.18rem 0.45rem; + background: rgba(168,85,247,0.05); + border: 1px solid rgba(168,85,247,0.13); + color: var(--text-dim); + letter-spacing: 0.04em; +} + +/* ── Certifications ─────────────────────────────── */ + +/* Mobile: single column; wider: auto-fill */ +.cert-grid { + display: grid; + grid-template-columns: 1fr; + gap: 1.5rem; +} + +@media (min-width: 640px) { + .cert-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } +} + +.cert-card { + border: 1px solid var(--border); + background: var(--bg2); + padding: 1.5rem; + position: relative; + overflow: hidden; + transition: border-color 0.3s, box-shadow 0.3s; +} + +.cert-date { + position: absolute; + top: 1.5rem; + right: 1.5rem; + font-size: 0.72rem; + color: var(--muted); + letter-spacing: 0.06em; +} + +.cert-wip { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 0.2rem 0.55rem; + border-radius: 999px; + background: color-mix(in srgb, var(--accent2, #00ff88) 12%, transparent); + color: var(--accent2, #00ff88); + border: 1px solid color-mix(in srgb, var(--accent2, #00ff88) 35%, transparent); + margin-bottom: 0.75rem; +} + +.cert-wip::before { + content: ""; + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent2, #00ff88); + animation: pulse-dot 1.4s ease-in-out infinite; +} + +@keyframes pulse-dot { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.4; transform: scale(0.7); } +} + +@media (min-width: 640px) { + .cert-card { padding: 2rem; } +} + +.cert-card::before { + content: ''; + position: absolute; + top: 0; inset-inline: 0; + height: 2px; + background: linear-gradient(90deg, var(--accent), var(--accent2)); +} +.cert-card:hover { + border-color: rgba(168,85,247,0.28); + box-shadow: 0 0 40px rgba(168,85,247,0.04); +} +.cert-card.placeholder { + opacity: 0.38; + border-style: dashed; +} +.cert-card.placeholder::before { display: none; } + +.cert-badge { + width: 72px; + height: 72px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 1.2rem; + position: relative; +} +.cert-badge--img { + background: transparent; +} +.cert-badge--img img { + width: 100%; + height: 100%; + object-fit: contain; +} +.cert-badge--placeholder { + background: var(--accent-glow); + border: 2px dashed var(--muted); + font-size: 1.6rem; + color: var(--muted); + width: 52px; + height: 52px; +} + +.cert-name { + font-family: var(--font-head); + font-size: 1.35rem; + font-weight: 800; + color: var(--text); + letter-spacing: -0.02em; + margin-bottom: 0.2rem; +} +.cert-issuer { + font-size: 0.78rem; + color: var(--accent); + letter-spacing: 0.06em; + margin-bottom: 0.9rem; +} +.cert-desc { + font-size: 0.88rem; + color: var(--text-dim); + line-height: 1.85; +} +.cert-meta { + display: flex; + flex-wrap: wrap; + gap: 1rem 1.5rem; + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid var(--border); +} +.cert-meta-item { font-size: 0.76rem; } +.cert-meta-label { color: var(--muted); letter-spacing: 0.06em; display: block; margin-bottom: 0.1rem; } +.cert-meta-val { color: var(--text-dim); font-weight: 700; } + +/* ── Carousel ───────────────────────────────────── */ +.carousel-wrap { position: relative; } + +/* Use double-class specificity to beat section-level grid rules */ +.cert-grid.is-carousel, +.projects-grid.is-carousel { + display: flex; + overflow-x: auto; + scroll-snap-type: x mandatory; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + gap: 1.5rem; + padding-bottom: 0.25rem; +} +.cert-grid.is-carousel::-webkit-scrollbar, +.projects-grid.is-carousel::-webkit-scrollbar { display: none; } + +/* Card sizing — narrow: ~1 card */ +.is-carousel .cert-card, +.is-carousel .project-card { + flex: 0 0 min(300px, 80vw); + scroll-snap-align: start; +} + +/* Tablet: ~2 cards */ +@media (min-width: 640px) { + .is-carousel .cert-card, + .is-carousel .project-card { + flex: 0 0 calc(50% - 0.75rem); + } +} + +/* Wide: revert to grid if not is-wide-carousel */ +@media (min-width: 900px) { + .cert-grid.is-carousel:not(.is-wide-carousel), + .projects-grid.is-carousel:not(.is-wide-carousel) { + display: grid; + overflow: visible; + scroll-snap-type: none; + } + .cert-grid.is-carousel:not(.is-wide-carousel) .cert-card, + .projects-grid.is-carousel:not(.is-wide-carousel) .project-card { + flex: none; + scroll-snap-align: none; + } + /* Wide carousel: 3 cards per view */ + .is-wide-carousel .cert-card, + .is-wide-carousel .project-card { + flex: 0 0 calc(33.333% - 1rem); + scroll-snap-align: start; + } +} + +/* Controls: visible on narrow always, on wide only if is-wide-carousel */ +.carousel-controls { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + margin-top: 1.5rem; +} + +@media (min-width: 900px) { + .carousel-wrap:not(:has(.is-wide-carousel)) .carousel-controls { + display: none; + } +} + +.carousel-btn { + width: 36px; + height: 36px; + border-radius: 50%; + border: 1px solid var(--border); + background: var(--bg2); + color: var(--text-dim); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + flex-shrink: 0; + transition: border-color 0.2s, color 0.2s; +} +.carousel-btn:hover { border-color: var(--accent); color: var(--accent); } + +.carousel-dots { + display: flex; + gap: 0.45rem; + align-items: center; +} + +.carousel-dot { + width: 6px; + height: 6px; + border-radius: 50%; + border: none; + padding: 0; + background: var(--border); + cursor: pointer; + transition: background 0.2s, transform 0.2s; +} +.carousel-dot.active { background: var(--accent); transform: scale(1.4); } + +/* ── Projects ───────────────────────────────────── */ +.projects-grid { + display: grid; + grid-template-columns: 1fr; + gap: 1.5rem; +} + +@media (min-width: 640px) { + .projects-grid { grid-template-columns: repeat(2, 1fr); } +} + +@media (min-width: 900px) { + .projects-grid { grid-template-columns: repeat(3, 1fr); } +} + +.project-card { + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 12px; + overflow: hidden; + display: flex; + flex-direction: column; + transition: border-color 0.25s, transform 0.25s; +} + +.project-card:hover { + border-color: var(--accent); + transform: translateY(-3px); +} + +.project-img-wrap { + width: 100%; + aspect-ratio: 16 / 9; + overflow: hidden; + background: var(--bg3, var(--bg2)); +} + +.project-img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: transform 0.4s; +} + +.project-card:hover .project-img { transform: scale(1.04); } + +.project-body { + padding: 1.25rem; + display: flex; + flex-direction: column; + flex: 1; + gap: 0.6rem; +} + +.project-title { + font-size: 1rem; + font-weight: 700; + color: var(--text); + margin: 0; +} + +.project-subtitle { + font-size: 0.8rem; + color: var(--accent); + letter-spacing: 0.06em; + text-transform: uppercase; + margin: 0; +} + +.project-tags { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; +} + +.project-tag { + font-size: 0.75rem; + padding: 0.2rem 0.55rem; + border-radius: 999px; + background: color-mix(in srgb, var(--accent) 12%, transparent); + color: var(--accent); + border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); + letter-spacing: 0.04em; +} + +.project-desc { + font-size: 0.88rem; + color: var(--text-dim); + line-height: 1.7; + margin: 0; + flex: 1; +} + +.project-footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 0.6rem; + padding-top: 0.75rem; + border-top: 1px solid var(--border); + gap: 0.5rem; +} + +.project-link { + display: inline-flex; + align-items: center; + gap: 0.4rem; + font-size: 0.84rem; + font-weight: 600; + color: var(--accent); + text-decoration: none; + transition: opacity 0.2s; +} + +.project-link:hover { opacity: 0.75; } + +.project-share { + display: flex; + gap: 0.5rem; +} + +.share-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 6px; + background: color-mix(in srgb, var(--text-dim) 8%, transparent); + color: var(--text-dim); + text-decoration: none; + font-size: 0.78rem; + transition: background 0.2s, color 0.2s; +} + +.share-btn:hover { + background: color-mix(in srgb, var(--accent) 15%, transparent); + color: var(--accent); +} + +.project-card--collab { + border-style: dashed; + border-color: color-mix(in srgb, var(--accent) 35%, transparent); + background: color-mix(in srgb, var(--accent) 4%, transparent); + justify-content: center; + min-height: 220px; +} + +.project-card--collab:hover { + border-style: dashed; + border-color: var(--accent); + transform: translateY(-3px); +} + +.project-collab-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 2rem; + color: color-mix(in srgb, var(--accent) 45%, transparent); + padding: 1.5rem 1.25rem 0; + transition: color 0.25s; +} + +.project-card--collab:hover .project-collab-icon { + color: var(--accent); +} + +/* ── Contact ────────────────────────────────────── */ +#contact { background: var(--bg2); } + +.contact-sub { + font-size: 0.93rem; + color: var(--text-dim); + max-width: 520px; + margin-bottom: 2rem; + line-height: 1.95; +} + +@media (min-width: 768px) { + .contact-sub { margin-bottom: 2.5rem; } +} + +.contact-list { + border: 1px solid var(--border); + max-width: 580px; +} +.contact-row { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.9rem 1.2rem; + text-decoration: none; + cursor: pointer; + color: var(--text); + border-bottom: 1px solid var(--border); + transition: background 0.2s, color 0.2s; +} + +@media (min-width: 480px) { + .contact-row { padding: 1rem 1.4rem; } +} + +.contact-row:last-child { border-bottom: none; } +.contact-row:hover { background: var(--accent-glow); } + +.contact-ico { + width: 34px; + height: 34px; + display: flex; + align-items: center; + justify-content: center; + background: var(--surface); + border: 1px solid var(--border); + flex-shrink: 0; + font-size: 1rem; + color: var(--text-dim); + transition: border-color 0.2s, color 0.2s; +} +.contact-row:hover .contact-ico { color: var(--accent); } +.contact-row:hover .contact-ico { border-color: rgba(168,85,247,0.35); } +.contact-lbl { font-size: 0.72rem; color: var(--muted); letter-spacing: 0.06em; display: block; } +.contact-val { font-size: 0.88rem; color: var(--text); } +.contact-row:hover .contact-val { color: var(--accent); } + +/* Contact form max width when standalone */ +.contact-form { max-width: 640px; } + +/* ── Contact form ───────────────────────────────── */ +.contact-form { + flex: 1; + display: flex; + flex-direction: column; + gap: 1.1rem; +} + +/* Honeypot — visually hidden, not display:none so bots still see it */ +.cf-honey { + position: absolute; + left: -9999px; + width: 1px; + height: 1px; + overflow: hidden; +} + +.cf-row { + display: grid; + grid-template-columns: 1fr; + gap: 1.1rem; +} + +@media (min-width: 480px) { + .cf-row { grid-template-columns: 1fr 1fr; } +} + +.cf-field { + display: flex; + flex-direction: column; + gap: 0.4rem; +} + +.cf-field label { + font-size: 0.76rem; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--muted); +} + +.cf-req { color: var(--accent); } + +.cf-field input, +.cf-field textarea { + background: var(--surface); + border: 1px solid var(--border); + color: var(--text); + font-family: var(--font-mono); + font-size: 0.88rem; + padding: 0.65rem 0.9rem; + outline: none; + transition: border-color 0.2s, box-shadow 0.2s; + resize: vertical; + width: 100%; +} + +.cf-field input:focus, +.cf-field textarea:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px rgba(168,85,247,0.1); +} + +.cf-invalid { + border-color: #ff5f7e !important; + box-shadow: 0 0 0 3px rgba(255,95,126,0.1) !important; +} + +.cf-field input::placeholder, +.cf-field textarea::placeholder { + color: var(--muted); +} + +.cf-footer { + display: flex; + align-items: center; + gap: 1.2rem; + flex-wrap: wrap; +} + +.cf-submit { min-width: 160px; } +.cf-submit.loading ~ .cf-clear { visibility: hidden; } + +.cf-submit.loading span { display: none; } +.cf-submit.loading::after { + content: ''; + display: inline-block; + width: 14px; + height: 14px; + border: 2px solid currentColor; + border-top-color: transparent; + border-radius: 50%; + animation: spin 0.7s linear infinite; +} + +@keyframes spin { to { transform: rotate(360deg); } } + +.cf-status { + font-size: 0.84rem; + line-height: 1.4; +} + +.cf-status.ok { color: var(--accent2); } +.cf-status.err { color: #ff5f7e; } + +/* ── Footer ─────────────────────────────────────── */ +footer { + padding: 1.5rem 1.2rem; + text-align: center; + font-size: 0.75rem; + color: var(--muted); + letter-spacing: 0.07em; + border-top: 1px solid var(--border); + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + gap: 0.4rem; +} + +@media (min-width: 768px) { + footer { padding: 2rem; } +} + +.footer-top { color: var(--text-dim); } +.footer-copy { color: var(--muted); font-size: 0.7rem; } + +.footer-social { + display: flex; + align-items: center; + justify-content: center; + gap: 0.6rem; +} + +.footer-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid var(--border); + color: var(--muted); + font-size: 0.8rem; + text-decoration: none; + cursor: pointer; + transition: border-color 0.2s, color 0.2s; +} + +.footer-icon:hover { + border-color: var(--accent); + color: var(--accent); +} + +/* ── Scroll Reveal ──────────────────────────────── */ +.reveal { + opacity: 0; + transform: translateY(28px); + transition: opacity 0.75s cubic-bezier(0.16,1,0.3,1), + transform 0.75s cubic-bezier(0.16,1,0.3,1); +} +.reveal.visible { opacity: 1; transform: translateY(0); } + +/* ── Keyframes ──────────────────────────────────── */ +@keyframes fadeUp { + from { opacity: 0; transform: translateY(22px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0; } +} + +@keyframes scanDown { + 0%, 100% { opacity: 0.25; transform: scaleY(0.5); transform-origin: top; } + 50% { opacity: 1; transform: scaleY(1); } +} + +@keyframes glitch { + 0% { transform: translate(0); clip-path: none; } + 20% { transform: translate(-3px, 2px); clip-path: inset(25% 0 35% 0); } + 40% { transform: translate(3px, -2px); clip-path: inset(55% 0 15% 0); } + 60% { transform: translate(-2px, 1px); clip-path: inset(10% 0 65% 0); } + 80% { transform: translate(2px, -1px); clip-path: inset(75% 0 8% 0); } + 100% { transform: translate(0); clip-path: none; } +} + +@keyframes glitch-red { + 0% { transform: translate(-5px, 1px); clip-path: inset(8% 0 78% 0); } + 33% { transform: translate(4px, -2px); clip-path: inset(42% 0 38% 0); } + 66% { transform: translate(-3px, 2px); clip-path: inset(68% 0 12% 0); } + 100% { transform: translate(0); clip-path: inset(0 0 100% 0); opacity: 0; } +} + +@keyframes glitch-cyn { + 0% { transform: translate(5px, -1px); clip-path: inset(22% 0 62% 0); } + 33% { transform: translate(-4px, 2px); clip-path: inset(55% 0 28% 0); } + 66% { transform: translate(3px, -2px); clip-path: inset(15% 0 70% 0); } + 100% { transform: translate(0); clip-path: inset(0 0 100% 0); opacity: 0; } +} + +/* ── Accessibility: Focus Styles ────────────────── */ +.nav-links a:focus-visible, +.btn:focus-visible, +.lang-btn:focus-visible, +.footer-icon:focus-visible, +.carousel-btn:focus-visible, +.carousel-dot:focus-visible, +.hamburger:focus-visible, +.project-link:focus-visible, +.share-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; +} + +/* ── Accessibility: Reduced Motion ─────────────── */ +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + /* Reveal elements should be visible immediately */ + .reveal { + opacity: 1; + transform: none; + transition: none; + } + + /* Hero animated elements should start visible */ + .hero-prompt, + .hero-name, + .hero-role, + .hero-tagline, + .hero-cta, + .hero-term, + .scroll-indicator { + opacity: 1; + animation: none; + } + + /* Terminal lines should be visible immediately */ + .tl { opacity: 1; animation: none; } + + /* Stop blinking cursors */ + .cursor, + .tc-blink { animation: none; opacity: 1; } + + /* Hide matrix canvas */ + #matrix-canvas { display: none; } +} diff --git a/themes/danixme/assets/js/main.js b/themes/danixme/assets/js/main.js new file mode 100644 index 0000000..7d28689 --- /dev/null +++ b/themes/danixme/assets/js/main.js @@ -0,0 +1,374 @@ +/* ── Matrix Rain ─────────────────────────────────── */ +(function () { + const canvas = document.getElementById('matrix-canvas'); + if (!canvas) return; + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; + + const ctx = canvas.getContext('2d'); + const CHARS = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789ABCDEF<>/\\|{}[]$#@!'; + const FS = 14; + let cols, drops, raf; + + function init() { + canvas.width = canvas.offsetWidth; + canvas.height = canvas.offsetHeight; + cols = Math.floor(canvas.width / FS) + 1; + drops = Array.from({ length: cols }, () => Math.random() * -(canvas.height / FS)); + } + + function tick() { + const light = document.documentElement.classList.contains('theme-light'); + ctx.fillStyle = light ? 'rgba(240,244,248,0.07)' : 'rgba(6,11,16,0.055)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.font = `${FS}px "JetBrains Mono", monospace`; + + for (let i = 0; i < cols; i++) { + const char = CHARS[Math.floor(Math.random() * CHARS.length)]; + // Occasional bright green "head", otherwise purple + ctx.fillStyle = Math.random() > 0.96 + ? (light ? '#008f5a' : '#00ff88') + : (light ? '#7c3aed' : '#a855f7'); + ctx.fillText(char, i * FS, drops[i] * FS); + + if (drops[i] * FS > canvas.height && Math.random() > 0.975) { + drops[i] = Math.random() * -20; + } + drops[i] += 0.5; + } + raf = requestAnimationFrame(tick); + } + + init(); + window.addEventListener('resize', () => { cancelAnimationFrame(raf); init(); tick(); }, { passive: true }); + document.addEventListener('visibilitychange', () => { + if (document.hidden) cancelAnimationFrame(raf); else tick(); + }); + tick(); +})(); + +/* ── Hero Glitch ─────────────────────────────────── */ +(function () { + const name = document.querySelector('.hero-name'); + if (!name) return; + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; + + function glitch() { + name.classList.add('is-glitching'); + setTimeout(() => name.classList.remove('is-glitching'), 500); + setTimeout(glitch, 4000 + Math.random() * 7000); + } + setTimeout(glitch, 3500); +})(); + +/* ── CV Download ─────────────────────────────────── */ +document.querySelectorAll('[data-cv]').forEach(el => { + const trigger = (e) => { + e.preventDefault(); + const a = document.createElement('a'); + a.href = atob(el.dataset.cv); + a.download = ''; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + el.addEventListener('click', trigger); + el.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') trigger(e); }); +}); + +/* ── Email Assembly ──────────────────────────────── */ +document.querySelectorAll('[data-eu]').forEach(el => { + const addr = el.dataset.eu + '@' + el.dataset.ed; + el.href = 'mailto:' + addr; + const val = el.querySelector('.contact-val'); + if (val) val.textContent = addr; +}); + +/* ── Typing Animation ────────────────────────────── */ +const typedEl = document.getElementById('typed'); +const phrases = window.SITE_PHRASES || []; + +let pIdx = 0, cIdx = 0, deleting = false, timer; + +function type() { + const word = phrases[pIdx % phrases.length]; + if (!word) return; + + if (!deleting) { + typedEl.textContent = word.slice(0, ++cIdx); + if (cIdx === word.length) { deleting = true; timer = setTimeout(type, 2200); return; } + } else { + typedEl.textContent = word.slice(0, --cIdx); + if (cIdx === 0) { deleting = false; pIdx++; timer = setTimeout(type, 350); return; } + } + timer = setTimeout(type, deleting ? 38 : 68); +} + +function resetTyping() { + clearTimeout(timer); + pIdx = 0; cIdx = 0; deleting = false; + typedEl.textContent = ''; + type(); +} + +resetTyping(); + +/* ── Scroll Reveal ───────────────────────────────── */ +const revealObs = new IntersectionObserver((entries) => { + entries.forEach((e, i) => { + if (e.isIntersecting) { + setTimeout(() => e.target.classList.add('visible'), i * 90); + revealObs.unobserve(e.target); + } + }); +}, { threshold: 0.1 }); + +document.querySelectorAll('.reveal').forEach(el => revealObs.observe(el)); + +/* ── Skill Bar Animation ─────────────────────────── */ +const skillsObs = new IntersectionObserver((entries) => { + entries.forEach(e => { + if (e.isIntersecting) { + e.target.querySelectorAll('.skill-fill').forEach((bar, i) => + setTimeout(() => bar.classList.add('go'), i * 110) + ); + skillsObs.unobserve(e.target); + } + }); +}, { threshold: 0.2 }); + +const sg = document.getElementById('skillsGrid'); +if (sg) skillsObs.observe(sg); + +/* ── Carousel ────────────────────────────────────── */ +document.querySelectorAll('[data-carousel]').forEach(wrap => { + const track = wrap.querySelector('.is-carousel'); + const prevBtn = wrap.querySelector('.carousel-btn--prev'); + const nextBtn = wrap.querySelector('.carousel-btn--next'); + const dotsWrap = wrap.querySelector('.carousel-dots'); + if (!track) return; + + const cards = Array.from(track.children); + + // Scroll position of card i relative to the track's scrollable content + function cardScrollLeft(i) { + const trackRect = track.getBoundingClientRect(); + const cardRect = cards[i].getBoundingClientRect(); + return track.scrollLeft + (cardRect.left - trackRect.left); + } + + // Build dots + const dots = cards.map((_, i) => { + const dot = document.createElement('button'); + dot.className = 'carousel-dot'; + dot.setAttribute('aria-label', `${i + 1}`); + dot.addEventListener('click', () => { + track.scrollTo({ left: cardScrollLeft(i), behavior: 'smooth' }); + }); + dotsWrap.appendChild(dot); + return dot; + }); + + function activeDot() { + const trackLeft = track.getBoundingClientRect().left; + let closest = 0, minDist = Infinity; + cards.forEach((card, i) => { + const dist = Math.abs(card.getBoundingClientRect().left - trackLeft); + if (dist < minDist) { minDist = dist; closest = i; } + }); + dots.forEach((d, i) => d.classList.toggle('active', i === closest)); + } + + function cardWidth() { + const gap = parseFloat(getComputedStyle(track).columnGap) || 24; + return cards[0].offsetWidth + gap; + } + + prevBtn.addEventListener('click', () => track.scrollBy({ left: -cardWidth(), behavior: 'smooth' })); + nextBtn.addEventListener('click', () => track.scrollBy({ left: cardWidth(), behavior: 'smooth' })); + + track.addEventListener('scroll', activeDot, { passive: true }); + activeDot(); +}); + +/* ── Contact Form ────────────────────────────────── */ +(function () { + const form = document.getElementById('contact-form'); + if (!form) return; + + // Stamp load time into hidden field — used by PHP timing check + const timeField = document.getElementById('cf-time'); + if (timeField) timeField.value = Math.floor(Date.now() / 1000); + + const btn = form.querySelector('.cf-submit'); + const status = form.querySelector('.cf-status'); + const i18n = window.FORM_I18N || {}; + + form.addEventListener('submit', async (e) => { + e.preventDefault(); + + // Basic client-side required check + const required = form.querySelectorAll('[required]'); + let valid = true; + required.forEach(el => { + el.classList.toggle('cf-invalid', !el.value.trim()); + if (!el.value.trim()) valid = false; + }); + if (!valid) { + setStatus('err', i18n.error_fields); + return; + } + + btn.classList.add('loading'); + btn.disabled = true; + setStatus('', ''); + + try { + const res = await fetch('/api/contact.php', { + method: 'POST', + body: new FormData(form), + }); + const data = await res.json(); + + if (data.success) { + setStatus('ok', i18n.success); + form.reset(); + // Re-stamp time after reset + if (timeField) timeField.value = Math.floor(Date.now() / 1000); + } else { + setStatus('err', i18n.error); + } + } catch { + setStatus('err', i18n.error); + } finally { + btn.classList.remove('loading'); + btn.disabled = false; + } + }); + + // Clear invalid state on input + form.querySelectorAll('input, textarea').forEach(el => { + el.addEventListener('input', () => el.classList.remove('cf-invalid')); + }); + + // On reset: clear status message, invalid states, and re-stamp time + form.addEventListener('reset', () => { + setStatus('', ''); + form.querySelectorAll('.cf-invalid').forEach(el => el.classList.remove('cf-invalid')); + if (timeField) setTimeout(() => { timeField.value = Math.floor(Date.now() / 1000); }, 0); + }); + + function setStatus(type, msg) { + status.className = 'cf-status' + (type ? ' ' + type : ''); + status.textContent = msg; + } +})(); + +/* ── Scroll Progress Bar ─────────────────────────── */ +(function () { + const bar = document.getElementById('scroll-progress'); + if (!bar) return; + window.addEventListener('scroll', () => { + const scrolled = document.documentElement.scrollTop; + const total = document.documentElement.scrollHeight - document.documentElement.clientHeight; + const pct = total > 0 ? (scrolled / total) * 100 : 0; + bar.style.width = pct + '%'; + bar.setAttribute('aria-valuenow', Math.round(pct)); + }, { passive: true }); +})(); + +/* ── Nav Border on Scroll ────────────────────────── */ +const navEl = document.getElementById('nav'); +const isLight = () => document.documentElement.classList.contains('theme-light'); +window.addEventListener('scroll', () => { + navEl.style.borderBottomColor = scrollY > 60 + ? (isLight() ? 'rgba(168,189,216,0.9)' : 'rgba(24,40,64,0.9)') + : (isLight() ? 'rgba(168,189,216,0.5)' : 'rgba(24,40,64,0.5)'); +}, { passive: true }); + +/* ── Mobile Menu ─────────────────────────────────── */ +const burger = document.querySelector('.hamburger'); +const navLinks = document.querySelector('.nav-links'); +let menuOpen = false; + +function menuBg() { + return isLight() + ? { bg: 'rgba(240,244,248,0.97)', border: '1px solid rgba(168,189,216,0.8)' } + : { bg: 'rgba(6,11,16,0.97)', border: '1px solid rgba(24,40,64,0.9)' }; +} + +function openMenu() { + menuOpen = true; + burger.setAttribute('aria-expanded', true); + const { bg, border } = menuBg(); + Object.assign(navLinks.style, { + display: 'flex', + flexDirection: 'column', + position: 'absolute', + top: '100%', + left: '0', + right: '0', + background: bg, + padding: '1rem 2rem', + borderBottom: border, + gap: '1rem' + }); + navLinks.querySelector('.nav-theme-item').style.display = 'flex'; +} + +function closeMenu() { + menuOpen = false; + burger.setAttribute('aria-expanded', false); + navLinks.style.display = 'none'; + navLinks.querySelector('.nav-theme-item').style.display = ''; +} + +burger.addEventListener('click', (e) => { + e.stopPropagation(); + menuOpen ? closeMenu() : openMenu(); +}); + +document.addEventListener('click', (e) => { + if (menuOpen && !navEl.contains(e.target)) closeMenu(); +}); + +document.addEventListener('touchstart', (e) => { + if (menuOpen && !navEl.contains(e.target)) closeMenu(); +}, { passive: true }); + +/* ── Theme Toggle ────────────────────────────────── */ +(function () { + const html = document.documentElement; + const toggles = document.querySelectorAll('.theme-toggle'); + + function currentTheme() { + return html.classList.contains('theme-light') ? 'light' : 'dark'; + } + + function applyTheme(theme) { + html.classList.remove('theme-light', 'theme-dark'); + html.classList.add('theme-' + theme); + localStorage.setItem('theme', theme); + updateIcons(); + // Refresh open mobile menu background + if (menuOpen) { + const { bg, border } = menuBg(); + navLinks.style.background = bg; + navLinks.style.borderBottom = border; + } + } + + function updateIcons() { + const light = currentTheme() === 'light'; + toggles.forEach(btn => { + btn.querySelector('i').className = light ? 'fa-solid fa-moon' : 'fa-solid fa-sun'; + const lbl = btn.querySelector('.theme-toggle-label'); + if (lbl) lbl.textContent = light ? 'Dark mode' : 'Light mode'; + }); + } + + toggles.forEach(btn => btn.addEventListener('click', () => { + applyTheme(currentTheme() === 'light' ? 'dark' : 'light'); + })); + + updateIcons(); +})(); diff --git a/themes/danixme/i18n/en.toml b/themes/danixme/i18n/en.toml new file mode 100644 index 0000000..8a7ffd8 --- /dev/null +++ b/themes/danixme/i18n/en.toml @@ -0,0 +1,149 @@ +[nav_about] +other = "About" + +[nav_services] +other = "Services" + +[nav_education] +other = "Education" + +[nav_skills] +other = "Skills" + +[nav_certs] +other = "Certs" + +[nav_contact] +other = "Contact" + +[btn_contact] +other = "↗ Get in Touch" + +[btn_cv] +other = "Download CV" + +[btn_more] +other = "→ Learn More" + +[scroll] +other = "scroll" + +[hero_prompt] +other = "whoami" + +[section_about] +other = "About" + +[section_skills] +other = "Skills" + +[section_certs] +other = "Certifications" + +[section_contact] +other = "Contact" + +[about_title] +other = "Background" + +[section_services] +other = "Services" + +[services_title] +other = "What I Do" + +[section_education] +other = "Education" + +[education_title] +other = "Academic Path" + +[skills_title] +other = "Toolkit" + +[certs_title] +other = "Credentials" + +[contact_title] +other = "Let's Connect" + +[terminal_role] +other = "CyberSecurity Specialist" + +[terminal_status] +other = "open to work" + +[cert_in_progress] +other = "Studying" + +[cert_issuer_label] +other = "Issuer" + +[cert_level_label] +other = "Level" + +[cert_type_label] +other = "Type" + +[cert_date_label] +other = "Obtained" + +[nav_projects] +other = "Projects" + +[section_projects] +other = "Projects" + +[projects_title] +other = "My Work" + +[project_visit] +other = "View Project" + +[carousel_prev] +other = "Previous" + +[carousel_next] +other = "Next" + +[project_collab_title] +other = "Next Project" + +[project_collab_desc] +other = "Got an exciting idea? I'm always open to collaborating on something new. Let's build something great together." + +[project_collab_cta] +other = "Get in Touch" + +[form_name] +other = "Name" + +[form_email] +other = "Email" + +[form_subject] +other = "Subject" + +[form_message] +other = "Message" + +[form_send] +other = "Send Message" + +[form_clear] +other = "Clear" + +[form_success] +other = "Message sent! I'll get back to you soon." + +[form_error] +other = "Something went wrong. Please try again." + +[form_error_fields] +other = "Please fill in all required fields." + +[footer1] +other = 'Made with a mix of and a general lack of , plus some mad skills' + +[footer2] +other = "This site is what my 15 years old self wanted to build" diff --git a/themes/danixme/i18n/it.toml b/themes/danixme/i18n/it.toml new file mode 100644 index 0000000..943119d --- /dev/null +++ b/themes/danixme/i18n/it.toml @@ -0,0 +1,149 @@ +[nav_about] +other = "Chi Sono" + +[nav_services] +other = "Servizi" + +[nav_education] +other = "Formazione" + +[nav_skills] +other = "Competenze" + +[nav_certs] +other = "Certificazioni" + +[nav_contact] +other = "Contatti" + +[btn_contact] +other = "↗ Contattami" + +[btn_cv] +other = "Scarica CV" + +[btn_more] +other = "→ Scopri di Più" + +[scroll] +other = "scorri" + +[hero_prompt] +other = "chi_sono" + +[section_about] +other = "Chi Sono" + +[section_skills] +other = "Competenze" + +[section_certs] +other = "Certificazioni" + +[section_contact] +other = "Contatti" + +[about_title] +other = "Background" + +[section_services] +other = "Servizi" + +[services_title] +other = "di cosa mi occupo" + +[section_education] +other = "Formazione" + +[education_title] +other = "Percorso Accademico" + +[skills_title] +other = "Strumenti" + +[certs_title] +other = "Credenziali" + +[contact_title] +other = "Connettiti" + +[terminal_role] +other = "Specialista Cybersecurity" + +[terminal_status] +other = "disponibile" + +[cert_in_progress] +other = "In corso" + +[cert_issuer_label] +other = "Ente" + +[cert_level_label] +other = "Livello" + +[cert_type_label] +other = "Tipo" + +[cert_date_label] +other = "Ottenuta" + +[nav_projects] +other = "Progetti" + +[section_projects] +other = "Progetti" + +[projects_title] +other = "I Miei Lavori" + +[project_visit] +other = "Vedi Progetto" + +[carousel_prev] +other = "Precedente" + +[carousel_next] +other = "Successivo" + +[project_collab_title] +other = "Prossimo Progetto" + +[project_collab_desc] +other = "Hai un'idea interessante? Sono sempre aperto a collaborare su qualcosa di nuovo. Costruiamo qualcosa di grande insieme." + +[project_collab_cta] +other = "Contattami" + +[form_name] +other = "Nome" + +[form_email] +other = "Email" + +[form_subject] +other = "Oggetto" + +[form_message] +other = "Messaggio" + +[form_send] +other = "Invia Messaggio" + +[form_clear] +other = "Cancella" + +[form_success] +other = "Messaggio inviato! Ti risponderò presto." + +[form_error] +other = "Qualcosa è andato storto. Riprova." + +[form_error_fields] +other = "Compila tutti i campi obbligatori." + +[footer1] +other = 'Realizzato con un misto di e una mancanza di , oltre alle mie capacità da ' + +[footer2] +other = "Questo è il sito che sognavo a 15 anni." diff --git a/themes/danixme/layouts/_default/baseof.html b/themes/danixme/layouts/_default/baseof.html new file mode 100644 index 0000000..f01a9f2 --- /dev/null +++ b/themes/danixme/layouts/_default/baseof.html @@ -0,0 +1,11 @@ + + +{{ partial "head.html" . }} + +
+{{ partial "nav.html" . }} +{{ block "main" . }}{{ end }} +{{ partial "footer.html" . }} +{{ partial "scripts.html" . }} + + diff --git a/themes/danixme/layouts/index.html b/themes/danixme/layouts/index.html new file mode 100644 index 0000000..01e2f90 --- /dev/null +++ b/themes/danixme/layouts/index.html @@ -0,0 +1,10 @@ +{{ define "main" }} +{{ partial "hero.html" . }} +{{ partial "about.html" . }} +{{ partial "services.html" . }} +{{ partial "skills.html" . }} +{{ partial "education.html" . }} +{{ partial "certs.html" . }} +{{ partial "projects.html" . }} +{{ partial "contact.html" . }} +{{ end }} diff --git a/themes/danixme/layouts/partials/about.html b/themes/danixme/layouts/partials/about.html new file mode 100644 index 0000000..68cb6e8 --- /dev/null +++ b/themes/danixme/layouts/partials/about.html @@ -0,0 +1,37 @@ +
+
+
{{ i18n "section_about" }}
+

{{ i18n "about_title" }}

+ +
+
+ {{ with .Params.about_photo }} + {{ $.Site.Params.name }} + {{ end }} +
{{ .Params.bio | markdownify }}
+
+ +
+
+
+
+
+ profile.json +
+
+
~cat profile.json
+
+
{
+
  "name": "{{ .Site.Params.name }}",
+
  "role": "{{ i18n "terminal_role" }}",
+
  "cert": "{{ .Site.Params.cert }}",
+
  "focus": "{{ .Site.Params.focus }}",
+
  "location": "{{ .Site.Params.location }}",
+
  "status": "{{ i18n "terminal_status" }}"
+
}
+
+
+
+
+
+
diff --git a/themes/danixme/layouts/partials/certs.html b/themes/danixme/layouts/partials/certs.html new file mode 100644 index 0000000..41e672a --- /dev/null +++ b/themes/danixme/layouts/partials/certs.html @@ -0,0 +1,67 @@ +
+
+
{{ i18n "section_certs" }}
+

{{ i18n "certs_title" }}

+ + {{ $lang := .Site.Language.Lang }} + {{ $count := len hugo.Data.certs }} + {{ $wide := gt $count 3 }} + + {{/* end carousel-wrap */}} +
+
diff --git a/themes/danixme/layouts/partials/contact.html b/themes/danixme/layouts/partials/contact.html new file mode 100644 index 0000000..9584c74 --- /dev/null +++ b/themes/danixme/layouts/partials/contact.html @@ -0,0 +1,49 @@ +
+
+
{{ i18n "section_contact" }}
+

{{ i18n "contact_title" }}

+ +

{{ .Params.contact_sub }}

+ +
+ + + + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ + +
+
+
diff --git a/themes/danixme/layouts/partials/education.html b/themes/danixme/layouts/partials/education.html new file mode 100644 index 0000000..74b1374 --- /dev/null +++ b/themes/danixme/layouts/partials/education.html @@ -0,0 +1,28 @@ +
+
+
{{ i18n "section_education" }}
+

{{ i18n "education_title" }}

+ +
+ {{ $lang := .Site.Language.Lang }} + {{ range hugo.Data.education }} + {{ $current := index . "current" }} +
+
+
+
{{ .period }}
+
+ {{ if eq $lang "it" }}{{ .degree_it }}{{ else }}{{ .degree_en }}{{ end }} +
+
+ {{ if eq $lang "it" }}{{ .institution_it }}{{ else }}{{ .institution_en }}{{ end }} +
+
+ {{ if eq $lang "it" }}{{ .desc_it | markdownify }}{{ else }}{{ .desc_en | markdownify }}{{ end }} +
+
+
+ {{ end }} +
+
+
diff --git a/themes/danixme/layouts/partials/footer.html b/themes/danixme/layouts/partials/footer.html new file mode 100644 index 0000000..ad9d015 --- /dev/null +++ b/themes/danixme/layouts/partials/footer.html @@ -0,0 +1,22 @@ + diff --git a/themes/danixme/layouts/partials/head.html b/themes/danixme/layouts/partials/head.html new file mode 100644 index 0000000..ce87286 --- /dev/null +++ b/themes/danixme/layouts/partials/head.html @@ -0,0 +1,77 @@ + + + + + + {{/* ── Primary Meta ──────────────────────────────── */}} + {{ .Site.Title }} + {{ $desc := .Params.description | default .Site.Params.description }} + + + + + + {{/* ── Hreflang (multilingual) ───────────────────── */}} + {{ range .Site.Home.AllTranslations }} + + {{ end }} + + + {{/* ── Open Graph ───────────────────────────────── */}} + {{ $ogImage := .Params.og_image | default .Site.Params.og_image }} + + + + + {{ with $ogImage }}{{ end }} + + {{ range .Site.Home.AllTranslations }}{{ if ne .Language.Lang $.Site.Language.Lang }} + + {{ end }}{{ end }} + + {{/* ── Twitter / X Card ────────────────────────── */}} + + + + {{ with $ogImage }}{{ end }} + + {{/* ── Geo (local SEO — Italy) ────────────────── */}} + + + + {{/* ── Favicon & icons ─────────────────────────── */}} + {{ with .Site.Params.favicon }}{{ end }} + + + + + {{/* ── JSON-LD: Person schema ───────────────────── */}} + {{- $photo := .Params.about_photo | default "/img/Danilo_profile.jpg" -}} + {{- $links := slice -}} + {{- range hugo.Data.contact -}}{{- with .href -}}{{- $links = $links | append . -}}{{- end -}}{{- end -}} + + + {{/* ── Preconnect ───────────────────────────────── */}} + + + + + {{/* ── Stylesheets ──────────────────────────────── */}} + + + + {{ $css := resources.Get "css/main.css" }} + {{ if hugo.IsProduction }}{{ $css = $css | minify | fingerprint }}{{ end }} + + diff --git a/themes/danixme/layouts/partials/hero.html b/themes/danixme/layouts/partials/hero.html new file mode 100644 index 0000000..aa5ab0f --- /dev/null +++ b/themes/danixme/layouts/partials/hero.html @@ -0,0 +1,60 @@ +
+ + +
+
+ +
{{ i18n "hero_prompt" }}
+

{{ .Site.Params.name }}

+ +
+
+
+ +
+ +
{{ .Params.tagline | markdownify }}
+ +
+ {{ i18n "btn_contact" }} + {{ i18n "btn_more" }} + {{ with .Site.Language.Params.cv }} + + + {{ i18n "btn_cv" }} + + {{ end }} +
+
+ + + +
{{/* end hero-bottom */}} + +
{{/* end hero-inner */}} +
+ +
+ {{ i18n "scroll" }} +
+
+
diff --git a/themes/danixme/layouts/partials/nav.html b/themes/danixme/layouts/partials/nav.html new file mode 100644 index 0000000..8a045d0 --- /dev/null +++ b/themes/danixme/layouts/partials/nav.html @@ -0,0 +1,45 @@ + diff --git a/themes/danixme/layouts/partials/projects.html b/themes/danixme/layouts/partials/projects.html new file mode 100644 index 0000000..d9bc7d4 --- /dev/null +++ b/themes/danixme/layouts/partials/projects.html @@ -0,0 +1,93 @@ +
+
+
{{ i18n "section_projects" }}
+

{{ i18n "projects_title" }}

+ + {{ $lang := .Site.Language.Lang }} + {{ $count := add (len hugo.Data.projects) 1 }}{{/* +1 for the collab card */}} + {{ $wide := gt $count 3 }} + + {{/* end carousel-wrap */}} +
+
diff --git a/themes/danixme/layouts/partials/scripts.html b/themes/danixme/layouts/partials/scripts.html new file mode 100644 index 0000000..77e4583 --- /dev/null +++ b/themes/danixme/layouts/partials/scripts.html @@ -0,0 +1,11 @@ + +{{ $js := resources.Get "js/main.js" }} +{{ if hugo.IsProduction }}{{ $js = $js | minify | fingerprint }}{{ end }} + diff --git a/themes/danixme/layouts/partials/services.html b/themes/danixme/layouts/partials/services.html new file mode 100644 index 0000000..538fb29 --- /dev/null +++ b/themes/danixme/layouts/partials/services.html @@ -0,0 +1,24 @@ +
+
+
{{ i18n "section_services" }}
+

{{ i18n "services_title" }}

+ +
+ {{ $lang := .Site.Language.Lang }} + {{ range hugo.Data.services }} +
+
+
+ {{ if eq $lang "it" }}{{ .title_it }}{{ else }}{{ .title_en }}{{ end }} +
+
+ {{ if eq $lang "it" }}{{ .subtitle_it }}{{ else }}{{ .subtitle_en }}{{ end }} +
+
+ {{ if eq $lang "it" }}{{ .desc_it | markdownify }}{{ else }}{{ .desc_en | markdownify }}{{ end }} +
+
+ {{ end }} +
+
+
diff --git a/themes/danixme/layouts/partials/skills.html b/themes/danixme/layouts/partials/skills.html new file mode 100644 index 0000000..790bea3 --- /dev/null +++ b/themes/danixme/layouts/partials/skills.html @@ -0,0 +1,24 @@ +
+
+
{{ i18n "section_skills" }}
+

{{ i18n "skills_title" }}

+ +
+ {{ $lang := .Site.Language.Lang }} + {{ range hugo.Data.skills }} +
+
+
+
+ {{ if eq $lang "it" }}{{ .name_it }}{{ else }}{{ .name_en }}{{ end }} +
+
+
+
+ {{ range .tags }}{{ . }}{{ end }} +
+
+ {{ end }} +
+
+
diff --git a/themes/danixme/layouts/robots.txt b/themes/danixme/layouts/robots.txt new file mode 100644 index 0000000..da0727f --- /dev/null +++ b/themes/danixme/layouts/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: {{ .Site.BaseURL }}sitemap.xml diff --git a/themes/danixme/theme.toml b/themes/danixme/theme.toml new file mode 100644 index 0000000..738686a --- /dev/null +++ b/themes/danixme/theme.toml @@ -0,0 +1,5 @@ +name = "danixme" +license = "MIT" +description = "Personal portfolio theme for danix.me" +tags = ["portfolio", "cybersecurity", "minimal"] +min_version = "0.120.0" -- cgit v1.2.3