Compare commits
16 Commits
93ffacb124
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d6fef8775f | |||
| 5db9856f9a | |||
| c3d748aa29 | |||
| 6376fc4a1c | |||
| 4c496eff23 | |||
| e70b13a7f4 | |||
| 18ae0deae1 | |||
| 842c10ac58 | |||
| 77d30b30f3 | |||
| ac5d571d28 | |||
| 521c4b02ad | |||
| ffa92bbee1 | |||
| fbe23f9536 | |||
| ab116e4824 | |||
| 50059bb3a5 | |||
| 0e92466fd6 |
@@ -0,0 +1,28 @@
|
||||
name: Deploy Portfolio
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build Astro
|
||||
run: npm run build
|
||||
|
||||
- name: Publish Site
|
||||
run: |
|
||||
docker exec gitea-runner sh -c 'rm -rf /sites/portfolio/*'
|
||||
docker cp dist/. gitea-runner:/sites/portfolio/
|
||||
|
||||
- name: Verify Deployment
|
||||
run: |
|
||||
docker exec gitea-runner ls -la /sites/portfolio
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.astro/
|
||||
@@ -0,0 +1,43 @@
|
||||
# Astro Starter Kit: Minimal
|
||||
|
||||
```sh
|
||||
npm create astro@latest -- --template minimal
|
||||
```
|
||||
|
||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||
|
||||
## 🚀 Project Structure
|
||||
|
||||
Inside of your Astro project, you'll see the following folders and files:
|
||||
|
||||
```text
|
||||
/
|
||||
├── public/
|
||||
├── src/
|
||||
│ └── pages/
|
||||
│ └── index.astro
|
||||
└── package.json
|
||||
```
|
||||
|
||||
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
||||
|
||||
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
||||
|
||||
Any static assets, like images, can be placed in the `public/` directory.
|
||||
|
||||
## 🧞 Commands
|
||||
|
||||
All commands are run from the root of the project, from a terminal:
|
||||
|
||||
| Command | Action |
|
||||
| :------------------------ | :----------------------------------------------- |
|
||||
| `npm install` | Installs dependencies |
|
||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
||||
| `npm run build` | Build your production site to `./dist/` |
|
||||
| `npm run preview` | Preview your build locally, before deploying |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `npm run astro -- --help` | Get help using the Astro CLI |
|
||||
|
||||
## 👀 Want to learn more?
|
||||
|
||||
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
||||
@@ -0,0 +1,13 @@
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
i18n: {
|
||||
locales: ["pt-br", "en", "es"],
|
||||
defaultLocale: "pt-br",
|
||||
routing: {
|
||||
prefixDefaultLocale: false
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 900px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="pt-BR">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Clezio Penha</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>Clezio Penha</h1>
|
||||
<p>Backend Developer | C++ | Java | Cloud</p>
|
||||
</header>
|
||||
|
||||
<section>
|
||||
<h2>Sobre</h2>
|
||||
|
||||
```
|
||||
<p>
|
||||
Desenvolvedor backend com experiência em C++, Qt e Java.
|
||||
Atuo com desenvolvimento de aplicações, APIs REST,
|
||||
Docker, Linux e Cloud.
|
||||
</p>
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Tecnologias</h2>
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li>C++</li>
|
||||
<li>Qt</li>
|
||||
<li>Java</li>
|
||||
<li>Spring Boot</li>
|
||||
<li>Quarkus</li>
|
||||
<li>Docker</li>
|
||||
<li>Linux</li>
|
||||
<li>Oracle Cloud</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Projetos</h2>
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li>Infraestrutura Oracle Cloud</li>
|
||||
<li>Servidor Git Privado com Gitea</li>
|
||||
<li>APIs Java com Spring Boot</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Contato</h2>
|
||||
|
||||
```
|
||||
<p>Email: clezio.penha@gmail.com</p>
|
||||
<p>Git: https://git.clezio.com.br</p>
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Generated
+4849
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "portfolio",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"node": ">=22.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^6.4.4"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 655 B |
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 749 B |
@@ -0,0 +1,30 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="about" class="section">
|
||||
<h2>{t.about.title}</h2>
|
||||
<p>{t.about.description}</p>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2>{t.about.workTitle}</h2>
|
||||
|
||||
<div class="cards-grid">
|
||||
{
|
||||
t.workPrinciples.map(work => (
|
||||
<article class="card">
|
||||
<h3>{work.title}</h3>
|
||||
<p>{work.description}</p>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="contact" class="section">
|
||||
|
||||
<h2>{t.contact.title}</h2>
|
||||
|
||||
<p>{t.contact.description}</p>
|
||||
|
||||
<div class="contact-links">
|
||||
|
||||
<a href={`mailto:${t.profile.email}`}>
|
||||
{t.profile.email}
|
||||
</a>
|
||||
|
||||
<a href={t.profile.linkedin} target="_blank" rel="noopener noreferrer">
|
||||
{t.contact.linkedin}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="experience" class="section">
|
||||
|
||||
<h2>{t.sections.experience}</h2>
|
||||
|
||||
<div class="timeline">
|
||||
|
||||
{
|
||||
t.timeline.map(item => (
|
||||
<article class="timeline-item">
|
||||
<h3>{item.title}</h3>
|
||||
<p>{item.description}</p>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<footer class="footer">
|
||||
|
||||
<p>
|
||||
© 2026 {t.profile.name}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{t.profile.footerRole}
|
||||
</p>
|
||||
|
||||
</footer>
|
||||
|
||||
<button id="backToTop" aria-label={t.ui.backToTop}>
|
||||
↑
|
||||
</button>
|
||||
|
||||
<script>
|
||||
const backToTopButton = document.querySelector("#backToTop");
|
||||
|
||||
const toggleBackToTop = () => {
|
||||
backToTopButton?.classList.toggle("show", window.scrollY > 500);
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", toggleBackToTop, { passive: true });
|
||||
toggleBackToTop();
|
||||
|
||||
backToTopButton?.addEventListener("click", () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: "smooth"
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
import { languageLinks, type Locale, type Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
locale: Locale;
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { locale, t } = Astro.props;
|
||||
---
|
||||
|
||||
<header class="header">
|
||||
<nav class="navbar">
|
||||
|
||||
<div class="logo">
|
||||
{t.profile.name}
|
||||
</div>
|
||||
|
||||
<ul id="primary-navigation" class="nav-links">
|
||||
<li><a href="#home">{t.nav.home}</a></li>
|
||||
<li><a href="#about">{t.nav.about}</a></li>
|
||||
<li><a href="#specialties">{t.nav.specialties}</a></li>
|
||||
<li><a href="#experience">{t.nav.experience}</a></li>
|
||||
<li><a href="#projects">{t.nav.projects}</a></li>
|
||||
<li><a href="#contact">{t.nav.contact}</a></li>
|
||||
</ul>
|
||||
|
||||
<button
|
||||
class="menu-toggle"
|
||||
type="button"
|
||||
aria-label={t.ui.menuToggle}
|
||||
aria-expanded="false"
|
||||
aria-controls="primary-navigation"
|
||||
>
|
||||
☰
|
||||
</button>
|
||||
|
||||
<div class="controls">
|
||||
|
||||
<button
|
||||
id="theme-toggle"
|
||||
type="button"
|
||||
aria-label={t.ui.themeToggle}
|
||||
aria-pressed="false"
|
||||
>◐</button>
|
||||
|
||||
<div class="language-switcher" aria-label={t.ui.languageSwitcher}>
|
||||
{
|
||||
languageLinks.map(language => (
|
||||
<a
|
||||
href={language.href}
|
||||
aria-label={language.label}
|
||||
aria-current={language.locale === locale ? "true" : undefined}
|
||||
class:list={{ active: language.locale === locale }}
|
||||
>
|
||||
{language.flag}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
const themeToggle = document.querySelector("#theme-toggle");
|
||||
const menuToggle = document.querySelector(".menu-toggle");
|
||||
const navLinks = document.querySelector(".nav-links");
|
||||
const navAnchors = document.querySelectorAll(".nav-links a");
|
||||
const themeStorageKey = "portfolio-theme";
|
||||
const themeIcons = {
|
||||
light: "☀️",
|
||||
dark: "🌙"
|
||||
};
|
||||
|
||||
const getPreferredTheme = () => {
|
||||
const storedTheme = localStorage.getItem(themeStorageKey);
|
||||
|
||||
if (storedTheme === "light" || storedTheme === "dark") {
|
||||
return storedTheme;
|
||||
}
|
||||
|
||||
return window.matchMedia("(prefers-color-scheme: light)").matches
|
||||
? "light"
|
||||
: "dark";
|
||||
};
|
||||
|
||||
const applyTheme = (theme) => {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
|
||||
if (themeToggle instanceof HTMLButtonElement) {
|
||||
const isLight = theme === "light";
|
||||
|
||||
themeToggle.textContent = isLight ? themeIcons.dark : themeIcons.light;
|
||||
themeToggle.setAttribute("aria-pressed", String(isLight));
|
||||
}
|
||||
};
|
||||
|
||||
applyTheme(getPreferredTheme());
|
||||
|
||||
themeToggle?.addEventListener("click", () => {
|
||||
const currentTheme = document.documentElement.dataset.theme === "light"
|
||||
? "light"
|
||||
: "dark";
|
||||
const nextTheme = currentTheme === "light" ? "dark" : "light";
|
||||
|
||||
localStorage.setItem(themeStorageKey, nextTheme);
|
||||
applyTheme(nextTheme);
|
||||
});
|
||||
|
||||
const closeMenu = () => {
|
||||
navLinks?.classList.remove("open");
|
||||
|
||||
if (menuToggle instanceof HTMLButtonElement) {
|
||||
menuToggle.setAttribute("aria-expanded", "false");
|
||||
menuToggle.textContent = "☰";
|
||||
}
|
||||
};
|
||||
|
||||
menuToggle?.addEventListener("click", () => {
|
||||
const isOpen = navLinks?.classList.toggle("open") ?? false;
|
||||
|
||||
if (menuToggle instanceof HTMLButtonElement) {
|
||||
menuToggle.setAttribute("aria-expanded", String(isOpen));
|
||||
menuToggle.textContent = isOpen ? "×" : "☰";
|
||||
}
|
||||
});
|
||||
|
||||
navAnchors.forEach((anchor) => {
|
||||
anchor.addEventListener("click", closeMenu);
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
closeMenu();
|
||||
}
|
||||
});
|
||||
|
||||
const sections = Array.from(navAnchors)
|
||||
.map((anchor) => document.querySelector(anchor.getAttribute("href") ?? ""))
|
||||
.filter((section) => section instanceof HTMLElement);
|
||||
|
||||
const setActiveLink = (id) => {
|
||||
navAnchors.forEach((anchor) => {
|
||||
anchor.classList.toggle("active", anchor.getAttribute("href") === `#${id}`);
|
||||
});
|
||||
};
|
||||
|
||||
const sectionObserver = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const visibleEntry = entries.find((entry) => entry.isIntersecting);
|
||||
|
||||
if (visibleEntry?.target instanceof HTMLElement) {
|
||||
setActiveLink(visibleEntry.target.id);
|
||||
}
|
||||
},
|
||||
{
|
||||
rootMargin: "-45% 0px -50% 0px",
|
||||
threshold: 0
|
||||
}
|
||||
);
|
||||
|
||||
sections.forEach((section) => sectionObserver.observe(section));
|
||||
</script>
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="home" class="hero">
|
||||
|
||||
<div class="hero-content">
|
||||
|
||||
<span class="hero-badge">{t.hero.badge}</span>
|
||||
|
||||
<h1>{t.hero.title}</h1>
|
||||
|
||||
<p>{t.hero.description}</p>
|
||||
|
||||
<div class="hero-actions">
|
||||
<a href="#projects" class="btn-primary">
|
||||
{t.hero.primaryButton}
|
||||
</a>
|
||||
|
||||
<a href="#contact" class="btn-secondary">
|
||||
{t.hero.secondaryButton}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section class="metrics">
|
||||
|
||||
{
|
||||
t.metrics.map(metric => (
|
||||
<article class="metric-card">
|
||||
<h3>{metric.value}</h3>
|
||||
<p>{metric.label}</p>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
import MainLayout from "../layouts/MainLayout.astro";
|
||||
|
||||
import Header from "./Header.astro";
|
||||
import Hero from "./Hero.astro";
|
||||
import Metrics from "./Metrics.astro";
|
||||
import About from "./About.astro";
|
||||
import Specialties from "./Specialties.astro";
|
||||
import Experience from "./Experience.astro";
|
||||
import Projects from "./Projects.astro";
|
||||
import Contact from "./Contact.astro";
|
||||
import Footer from "./Footer.astro";
|
||||
|
||||
import { translations, type Locale } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
locale: Locale;
|
||||
}
|
||||
|
||||
const { locale } = Astro.props;
|
||||
const t = translations[locale];
|
||||
---
|
||||
|
||||
<MainLayout
|
||||
title={t.meta.title}
|
||||
description={t.meta.description}
|
||||
lang={t.lang}
|
||||
canonical={t.canonical}
|
||||
ogTitle={t.meta.ogTitle}
|
||||
ogDescription={t.meta.ogDescription}
|
||||
>
|
||||
|
||||
<Header locale={locale} t={t} />
|
||||
|
||||
<main>
|
||||
<Hero t={t} />
|
||||
<Metrics t={t} />
|
||||
<About t={t} />
|
||||
<Specialties t={t} />
|
||||
<Experience t={t} />
|
||||
<Projects t={t} />
|
||||
<Contact t={t} />
|
||||
</main>
|
||||
|
||||
<Footer t={t} />
|
||||
|
||||
</MainLayout>
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="projects" class="section">
|
||||
|
||||
<h2>{t.sections.projects}</h2>
|
||||
|
||||
<div class="cards-grid">
|
||||
|
||||
{
|
||||
t.projects.map(project => (
|
||||
<article class="project-card">
|
||||
<h3>{project.title}</h3>
|
||||
|
||||
<p>{project.description}</p>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
import type { Translation } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
t: Translation;
|
||||
}
|
||||
|
||||
const { t } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="specialties" class="section">
|
||||
|
||||
<h2>{t.sections.specialties}</h2>
|
||||
|
||||
<div class="cards-grid">
|
||||
|
||||
{
|
||||
t.specialties.map(specialty => (
|
||||
<article class="card">
|
||||
<h3>{specialty}</h3>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
|
||||
<h2>{t.sections.stack}</h2>
|
||||
|
||||
<div class="tech-stack">
|
||||
|
||||
{
|
||||
t.stack.map(technology => (
|
||||
<span>{technology}</span>
|
||||
))
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,488 @@
|
||||
export const defaultLocale = "pt-br";
|
||||
|
||||
export const locales = ["pt-br", "en", "es"] as const;
|
||||
|
||||
export type Locale = (typeof locales)[number];
|
||||
|
||||
export const languageLinks = [
|
||||
{
|
||||
locale: "pt-br",
|
||||
href: "/",
|
||||
label: "Português",
|
||||
flag: "🇧🇷"
|
||||
},
|
||||
{
|
||||
locale: "en",
|
||||
href: "/en/",
|
||||
label: "English",
|
||||
flag: "🇺🇸"
|
||||
},
|
||||
{
|
||||
locale: "es",
|
||||
href: "/es/",
|
||||
label: "Español",
|
||||
flag: "🇪🇸"
|
||||
}
|
||||
] as const;
|
||||
|
||||
export const translations = {
|
||||
"pt-br": {
|
||||
lang: "pt-BR",
|
||||
canonical: "https://clezio.com.br/",
|
||||
meta: {
|
||||
title: "Clezio Penha | Senior Backend Engineer",
|
||||
description:
|
||||
"Programador Sênior Backend com mais de 15 anos de experiência em Java, C++, APIs REST, Cloud Computing, DevOps e Arquitetura de Software.",
|
||||
ogTitle: "Clezio Penha | Programador Sênior Backend",
|
||||
ogDescription: "Mais de 15 anos construindo sistemas robustos, escaláveis e seguros."
|
||||
},
|
||||
profile: {
|
||||
name: "Clezio Penha",
|
||||
role: "Senior Backend Engineer",
|
||||
footerRole: "Senior Backend Engineer",
|
||||
email: "clezio.penha@gmail.com",
|
||||
linkedin: "https://www.linkedin.com/in/clezio"
|
||||
},
|
||||
nav: {
|
||||
home: "Início",
|
||||
about: "Sobre",
|
||||
specialties: "Especialidades",
|
||||
experience: "Experiência",
|
||||
projects: "Projetos",
|
||||
contact: "Contato"
|
||||
},
|
||||
hero: {
|
||||
badge: "Programador Sênior • Backend Engineer • Tech Lead",
|
||||
title: "Transformando desafios de negócio em soluções robustas, escaláveis e seguras.",
|
||||
description:
|
||||
"Programador Sênior com mais de 15 anos de experiência em desenvolvimento backend, arquitetura de software, cloud computing e liderança técnica.",
|
||||
primaryButton: "Ver Projetos",
|
||||
secondaryButton: "Entrar em Contato"
|
||||
},
|
||||
metrics: [
|
||||
{
|
||||
value: "15+",
|
||||
label: "Anos de Experiência"
|
||||
},
|
||||
{
|
||||
value: "Tech Lead",
|
||||
label: "Liderança Técnica"
|
||||
},
|
||||
{
|
||||
value: "Cloud",
|
||||
label: "Oracle Cloud & Azure"
|
||||
},
|
||||
{
|
||||
value: "Backend",
|
||||
label: "APIs e Sistemas Corporativos"
|
||||
}
|
||||
],
|
||||
about: {
|
||||
title: "Sobre Mim",
|
||||
description:
|
||||
"Ao longo da minha carreira participei da construção e evolução de sistemas corporativos, integrações críticas, automações de processos e plataformas backend voltadas para desempenho, escalabilidade e confiabilidade.",
|
||||
workTitle: "Como Eu Trabalho"
|
||||
},
|
||||
workPrinciples: [
|
||||
{
|
||||
title: "Arquitetura",
|
||||
description: "Planejamento técnico antes da implementação."
|
||||
},
|
||||
{
|
||||
title: "Escalabilidade",
|
||||
description: "Sistemas preparados para crescimento contínuo."
|
||||
},
|
||||
{
|
||||
title: "Performance",
|
||||
description: "Eficiência operacional e otimização de recursos."
|
||||
},
|
||||
{
|
||||
title: "Segurança",
|
||||
description: "Boas práticas desde a concepção."
|
||||
},
|
||||
{
|
||||
title: "Qualidade",
|
||||
description: "Código limpo e manutenção simplificada."
|
||||
}
|
||||
],
|
||||
sections: {
|
||||
specialties: "Especialidades",
|
||||
stack: "Stack Tecnológica",
|
||||
experience: "Experiência Profissional",
|
||||
projects: "Projetos em Destaque"
|
||||
},
|
||||
specialties: [
|
||||
"APIs REST",
|
||||
"Arquitetura de Software",
|
||||
"Cloud Computing",
|
||||
"DevOps",
|
||||
"Bancos de Dados",
|
||||
"Microsserviços"
|
||||
],
|
||||
stack: [
|
||||
"Java",
|
||||
"C++",
|
||||
"Spring Boot",
|
||||
"Quarkus",
|
||||
"Docker",
|
||||
"Kubernetes",
|
||||
"Jenkins",
|
||||
"GitLab CI",
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
"SQL Server",
|
||||
"Oracle Cloud",
|
||||
"Azure"
|
||||
],
|
||||
timeline: [
|
||||
{
|
||||
title: "Programador Sênior",
|
||||
description: "Desenvolvimento de sistemas corporativos e soluções backend."
|
||||
},
|
||||
{
|
||||
title: "Tech Lead",
|
||||
description: "Liderança técnica e apoio arquitetural."
|
||||
},
|
||||
{
|
||||
title: "Cloud & DevOps",
|
||||
description: "Modernização de infraestrutura e automação."
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
title: "Sistema de Processamento SPED",
|
||||
description:
|
||||
"Plataforma responsável pela geração e processamento automatizado de arquivos fiscais SPED."
|
||||
},
|
||||
{
|
||||
title: "Infraestrutura Oracle Cloud",
|
||||
description: "Implementação e gerenciamento de infraestrutura cloud."
|
||||
},
|
||||
{
|
||||
title: "Servidor Git Privado com Gitea",
|
||||
description: "Ambiente Git privado para versionamento e colaboração."
|
||||
},
|
||||
{
|
||||
title: "APIs Corporativas",
|
||||
description: "Desenvolvimento de APIs REST utilizando Spring Boot."
|
||||
}
|
||||
],
|
||||
contact: {
|
||||
title: "Vamos Conversar",
|
||||
description: "Disponível para oportunidades profissionais e novos desafios.",
|
||||
linkedin: "LinkedIn"
|
||||
},
|
||||
ui: {
|
||||
menuToggle: "Abrir menu",
|
||||
themeToggle: "Alternar tema",
|
||||
languageSwitcher: "Selecionar idioma",
|
||||
backToTop: "Voltar ao topo"
|
||||
}
|
||||
},
|
||||
en: {
|
||||
lang: "en",
|
||||
canonical: "https://clezio.com.br/en/",
|
||||
meta: {
|
||||
title: "Clezio Penha | Senior Backend Engineer",
|
||||
description:
|
||||
"Senior Backend Engineer with 15+ years of experience in Java, C++, REST APIs, cloud computing, DevOps and software architecture.",
|
||||
ogTitle: "Clezio Penha | Backend Engineer",
|
||||
ogDescription: "15+ years building robust, scalable and secure systems."
|
||||
},
|
||||
profile: {
|
||||
name: "Clezio Penha",
|
||||
role: "Senior Backend Engineer",
|
||||
footerRole: "Senior Backend Engineer",
|
||||
email: "clezio.penha@gmail.com",
|
||||
linkedin: "https://www.linkedin.com/in/clezio"
|
||||
},
|
||||
nav: {
|
||||
home: "Home",
|
||||
about: "About",
|
||||
specialties: "Specialties",
|
||||
experience: "Experience",
|
||||
projects: "Projects",
|
||||
contact: "Contact"
|
||||
},
|
||||
hero: {
|
||||
badge: "Senior Developer • Backend Engineer • Tech Lead",
|
||||
title: "Turning business challenges into robust, scalable and secure solutions.",
|
||||
description:
|
||||
"Senior developer with 15+ years of experience in backend development, software architecture, cloud computing and technical leadership.",
|
||||
primaryButton: "View Projects",
|
||||
secondaryButton: "Get in Touch"
|
||||
},
|
||||
metrics: [
|
||||
{
|
||||
value: "15+",
|
||||
label: "Years of Experience"
|
||||
},
|
||||
{
|
||||
value: "Tech Lead",
|
||||
label: "Technical Leadership"
|
||||
},
|
||||
{
|
||||
value: "Cloud",
|
||||
label: "Oracle Cloud & Azure"
|
||||
},
|
||||
{
|
||||
value: "Backend",
|
||||
label: "APIs and Enterprise Systems"
|
||||
}
|
||||
],
|
||||
about: {
|
||||
title: "About Me",
|
||||
description:
|
||||
"Throughout my career, I have helped build and evolve enterprise systems, critical integrations, process automations and backend platforms focused on performance, scalability and reliability.",
|
||||
workTitle: "How I Work"
|
||||
},
|
||||
workPrinciples: [
|
||||
{
|
||||
title: "Architecture",
|
||||
description: "Technical planning before implementation."
|
||||
},
|
||||
{
|
||||
title: "Scalability",
|
||||
description: "Systems prepared for continuous growth."
|
||||
},
|
||||
{
|
||||
title: "Performance",
|
||||
description: "Operational efficiency and resource optimization."
|
||||
},
|
||||
{
|
||||
title: "Security",
|
||||
description: "Good practices from the design phase."
|
||||
},
|
||||
{
|
||||
title: "Quality",
|
||||
description: "Clean code and simplified maintenance."
|
||||
}
|
||||
],
|
||||
sections: {
|
||||
specialties: "Specialties",
|
||||
stack: "Technology Stack",
|
||||
experience: "Professional Experience",
|
||||
projects: "Featured Projects"
|
||||
},
|
||||
specialties: [
|
||||
"REST APIs",
|
||||
"Software Architecture",
|
||||
"Cloud Computing",
|
||||
"DevOps",
|
||||
"Databases",
|
||||
"Microservices"
|
||||
],
|
||||
stack: [
|
||||
"Java",
|
||||
"C++",
|
||||
"Spring Boot",
|
||||
"Quarkus",
|
||||
"Docker",
|
||||
"Kubernetes",
|
||||
"Jenkins",
|
||||
"GitLab CI",
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
"SQL Server",
|
||||
"Oracle Cloud",
|
||||
"Azure"
|
||||
],
|
||||
timeline: [
|
||||
{
|
||||
title: "Senior Developer",
|
||||
description: "Development of enterprise systems and backend solutions."
|
||||
},
|
||||
{
|
||||
title: "Tech Lead",
|
||||
description: "Technical leadership and architectural support."
|
||||
},
|
||||
{
|
||||
title: "Cloud & DevOps",
|
||||
description: "Infrastructure modernization and automation."
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
title: "SPED Processing System",
|
||||
description: "Platform responsible for the automated generation and processing of SPED tax files."
|
||||
},
|
||||
{
|
||||
title: "Oracle Cloud Infrastructure",
|
||||
description: "Implementation and management of cloud infrastructure."
|
||||
},
|
||||
{
|
||||
title: "Private Git Server with Gitea",
|
||||
description: "Private Git environment for version control and collaboration."
|
||||
},
|
||||
{
|
||||
title: "Enterprise APIs",
|
||||
description: "Development of REST APIs using Spring Boot."
|
||||
}
|
||||
],
|
||||
contact: {
|
||||
title: "Let's Talk",
|
||||
description: "Available for professional opportunities and new challenges.",
|
||||
linkedin: "LinkedIn"
|
||||
},
|
||||
ui: {
|
||||
menuToggle: "Open menu",
|
||||
themeToggle: "Toggle theme",
|
||||
languageSwitcher: "Select language",
|
||||
backToTop: "Back to top"
|
||||
}
|
||||
},
|
||||
es: {
|
||||
lang: "es",
|
||||
canonical: "https://clezio.com.br/es/",
|
||||
meta: {
|
||||
title: "Clezio Penha | Senior Backend Engineer",
|
||||
description:
|
||||
"Programador Backend Sénior con más de 15 años de experiencia en Java, C++, APIs REST, cloud computing, DevOps y arquitectura de software.",
|
||||
ogTitle: "Clezio Penha | Backend Engineer",
|
||||
ogDescription: "Más de 15 años construyendo sistemas robustos, escalables y seguros."
|
||||
},
|
||||
profile: {
|
||||
name: "Clezio Penha",
|
||||
role: "Senior Backend Engineer",
|
||||
footerRole: "Senior Backend Engineer",
|
||||
email: "clezio.penha@gmail.com",
|
||||
linkedin: "https://www.linkedin.com/in/clezio"
|
||||
},
|
||||
nav: {
|
||||
home: "Inicio",
|
||||
about: "Sobre mí",
|
||||
specialties: "Especialidades",
|
||||
experience: "Experiencia",
|
||||
projects: "Proyectos",
|
||||
contact: "Contacto"
|
||||
},
|
||||
hero: {
|
||||
badge: "Programador Sénior • Backend Engineer • Tech Lead",
|
||||
title: "Transformando desafíos de negocio en soluciones robustas, escalables y seguras.",
|
||||
description:
|
||||
"Programador sénior con más de 15 años de experiencia en desarrollo backend, arquitectura de software, cloud computing y liderazgo técnico.",
|
||||
primaryButton: "Ver Proyectos",
|
||||
secondaryButton: "Entrar en Contacto"
|
||||
},
|
||||
metrics: [
|
||||
{
|
||||
value: "15+",
|
||||
label: "Años de Experiencia"
|
||||
},
|
||||
{
|
||||
value: "Tech Lead",
|
||||
label: "Liderazgo Técnico"
|
||||
},
|
||||
{
|
||||
value: "Cloud",
|
||||
label: "Oracle Cloud y Azure"
|
||||
},
|
||||
{
|
||||
value: "Backend",
|
||||
label: "APIs y Sistemas Corporativos"
|
||||
}
|
||||
],
|
||||
about: {
|
||||
title: "Sobre Mí",
|
||||
description:
|
||||
"A lo largo de mi carrera he participado en la construcción y evolución de sistemas corporativos, integraciones críticas, automatizaciones de procesos y plataformas backend enfocadas en rendimiento, escalabilidad y confiabilidad.",
|
||||
workTitle: "Cómo Trabajo"
|
||||
},
|
||||
workPrinciples: [
|
||||
{
|
||||
title: "Arquitectura",
|
||||
description: "Planificación técnica antes de la implementación."
|
||||
},
|
||||
{
|
||||
title: "Escalabilidad",
|
||||
description: "Sistemas preparados para el crecimiento continuo."
|
||||
},
|
||||
{
|
||||
title: "Rendimiento",
|
||||
description: "Eficiencia operativa y optimización de recursos."
|
||||
},
|
||||
{
|
||||
title: "Seguridad",
|
||||
description: "Buenas prácticas desde la concepción."
|
||||
},
|
||||
{
|
||||
title: "Calidad",
|
||||
description: "Código limpio y mantenimiento simplificado."
|
||||
}
|
||||
],
|
||||
sections: {
|
||||
specialties: "Especialidades",
|
||||
stack: "Stack Tecnológico",
|
||||
experience: "Experiencia Profesional",
|
||||
projects: "Proyectos Destacados"
|
||||
},
|
||||
specialties: [
|
||||
"APIs REST",
|
||||
"Arquitectura de Software",
|
||||
"Cloud Computing",
|
||||
"DevOps",
|
||||
"Bases de Datos",
|
||||
"Microservicios"
|
||||
],
|
||||
stack: [
|
||||
"Java",
|
||||
"C++",
|
||||
"Spring Boot",
|
||||
"Quarkus",
|
||||
"Docker",
|
||||
"Kubernetes",
|
||||
"Jenkins",
|
||||
"GitLab CI",
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
"SQL Server",
|
||||
"Oracle Cloud",
|
||||
"Azure"
|
||||
],
|
||||
timeline: [
|
||||
{
|
||||
title: "Programador Sénior",
|
||||
description: "Desarrollo de sistemas corporativos y soluciones backend."
|
||||
},
|
||||
{
|
||||
title: "Tech Lead",
|
||||
description: "Liderazgo técnico y apoyo arquitectónico."
|
||||
},
|
||||
{
|
||||
title: "Cloud & DevOps",
|
||||
description: "Modernización de infraestructura y automatización."
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
title: "Sistema de Procesamiento SPED",
|
||||
description: "Plataforma responsable de la generación y procesamiento automatizado de archivos fiscales SPED."
|
||||
},
|
||||
{
|
||||
title: "Infraestructura Oracle Cloud",
|
||||
description: "Implementación y gestión de infraestructura cloud."
|
||||
},
|
||||
{
|
||||
title: "Servidor Git Privado con Gitea",
|
||||
description: "Entorno Git privado para versionamiento y colaboración."
|
||||
},
|
||||
{
|
||||
title: "APIs Corporativas",
|
||||
description: "Desarrollo de APIs REST utilizando Spring Boot."
|
||||
}
|
||||
],
|
||||
contact: {
|
||||
title: "Hablemos",
|
||||
description: "Disponible para oportunidades profesionales y nuevos desafíos.",
|
||||
linkedin: "LinkedIn"
|
||||
},
|
||||
ui: {
|
||||
menuToggle: "Abrir menú",
|
||||
themeToggle: "Alternar tema",
|
||||
languageSwitcher: "Seleccionar idioma",
|
||||
backToTop: "Volver arriba"
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export type Translation = (typeof translations)[Locale];
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
import "../styles/global.css";
|
||||
import { languageLinks } from "../data/translations";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
lang: "pt" | "en" | "es";
|
||||
canonical?: string;
|
||||
ogTitle?: string;
|
||||
ogDescription?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
lang,
|
||||
canonical,
|
||||
ogTitle = title,
|
||||
ogDescription = description
|
||||
} = Astro.props;
|
||||
|
||||
const schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Person",
|
||||
|
||||
name: "Clezio Penha",
|
||||
jobTitle: "Senior Software Engineer",
|
||||
description,
|
||||
email: "mailto:clezio.penha@gmail.com",
|
||||
|
||||
knowsAbout: [
|
||||
"Java",
|
||||
"C++",
|
||||
"Spring Boot",
|
||||
"Quarkus",
|
||||
"Docker",
|
||||
"Kubernetes",
|
||||
"PostgreSQL",
|
||||
"Oracle Cloud",
|
||||
"Azure"
|
||||
]
|
||||
};
|
||||
|
||||
const localeMap: Record<string, string> = {
|
||||
"pt": "pt_BR",
|
||||
"pt-BR": "pt_BR",
|
||||
"en": "en_US",
|
||||
"es": "es_ES"
|
||||
};
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang={lang}>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>{title}</title>
|
||||
|
||||
<meta name="author" content="Clezio Penha">
|
||||
<meta name="description" content={description}>
|
||||
<link rel="canonical" href={canonical}>
|
||||
<meta name="keywords" content="Java, Spring Boot, Backend, Cloud, Docker, Kubernetes, Oracle Cloud, Azure, APIs REST, DevOps">
|
||||
<meta property="og:title" content={ogTitle}>
|
||||
<meta property="og:description" content={ogDescription}>
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content={canonical}>
|
||||
<meta property="og:site_name" content="Clezio Penha">
|
||||
<meta property="og:locale" content={localeMap[lang] ?? "pt_BR"}>
|
||||
<meta property="og:image" content="https://clezio.com.br/og-image.png"/>
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="Clezio Penha Portfolio" />
|
||||
|
||||
{
|
||||
languageLinks.map(language => (
|
||||
<link rel="alternate" hreflang={language.locale} href={language.href} />
|
||||
))
|
||||
}
|
||||
|
||||
<link rel="alternate" hreflang="x-default" href="/">
|
||||
|
||||
<script type="application/ld+json" set:html={JSON.stringify(schema)} />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
import PortfolioPage from "../../components/PortfolioPage.astro";
|
||||
---
|
||||
|
||||
<PortfolioPage locale="en" />
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
import PortfolioPage from "../../components/PortfolioPage.astro";
|
||||
---
|
||||
|
||||
<PortfolioPage locale="es" />
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
import PortfolioPage from "../components/PortfolioPage.astro";
|
||||
---
|
||||
|
||||
<PortfolioPage locale="pt-br" />
|
||||
@@ -0,0 +1,691 @@
|
||||
/* =========================
|
||||
RESET
|
||||
========================= */
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
font-family: "Inter", sans-serif;
|
||||
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at top,
|
||||
rgba(59,130,246,.08),
|
||||
transparent 45%
|
||||
),
|
||||
var(--background);
|
||||
|
||||
color: var(--text-primary);
|
||||
|
||||
line-height: 1.7;
|
||||
|
||||
overflow-x: hidden;
|
||||
|
||||
transition:
|
||||
background .3s ease,
|
||||
color .3s ease;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
VARIABLES
|
||||
========================= */
|
||||
|
||||
:root {
|
||||
--background: #09090b;
|
||||
--surface: #111827;
|
||||
--surface-hover: #1f2937;
|
||||
--border: #27272a;
|
||||
--text-primary: #fafafa;
|
||||
--text-secondary: #a1a1aa;
|
||||
--accent: #3b82f6;
|
||||
--accent-hover: #2563eb;
|
||||
--header-bg: rgba(9, 9, 11, 0.75);
|
||||
--header-border: rgba(255, 255, 255, 0.05);
|
||||
--hero-title-start: #ffffff;
|
||||
--hero-title-end: #dbeafe;
|
||||
--container: 1200px;
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--background: #f8fafc;
|
||||
--surface: #ffffff;
|
||||
--surface-hover: #f1f5f9;
|
||||
--border: #e2e8f0;
|
||||
--text-primary: #0f172a;
|
||||
--text-secondary: #475569;
|
||||
--accent: #2563eb;
|
||||
--accent-hover: #1d4ed8;
|
||||
--header-bg: rgba(248, 250, 252, 0.82);
|
||||
--header-border: rgba(15, 23, 42, 0.08);
|
||||
--hero-title-start: #0f172a;
|
||||
--hero-title-end: #2563eb;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
GLOBAL
|
||||
========================= */
|
||||
|
||||
main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section {
|
||||
max-width: var(--container);
|
||||
margin: 0 auto;
|
||||
padding: 120px 24px;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 2.4rem;
|
||||
margin-bottom: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.section p {
|
||||
color: var(--text-secondary);
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
HEADER
|
||||
========================= */
|
||||
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(18px);
|
||||
background: var(--header-bg);
|
||||
border-bottom: 1px solid var(--header-border);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
max-width: var(--container);
|
||||
margin: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 18px 24px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 28px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
text-decoration: none;
|
||||
color: var(--text-secondary);
|
||||
transition: 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
HERO
|
||||
========================= */
|
||||
|
||||
.hero {
|
||||
min-height: 85vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120px 24px 60px;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
max-width: 900px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
display: inline-block;
|
||||
|
||||
margin-bottom: 24px;
|
||||
|
||||
padding: 8px 16px;
|
||||
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px;
|
||||
|
||||
background: color-mix(in srgb,
|
||||
var(--surface) 80%,
|
||||
transparent);
|
||||
|
||||
color: var(--text-secondary);
|
||||
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: clamp(2.8rem, 6vw, 4.8rem);
|
||||
|
||||
background: linear-gradient(180deg,
|
||||
var(--hero-title-start) 0%,
|
||||
var(--hero-title-end) 100%);
|
||||
|
||||
-webkit-background-clip: text;
|
||||
|
||||
-webkit-text-fill-color: transparent;
|
||||
|
||||
max-width: 1000px;
|
||||
|
||||
line-height: 1.1;
|
||||
|
||||
margin: 0 auto 28px;
|
||||
|
||||
font-weight: 800;
|
||||
|
||||
letter-spacing: -2px;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
color: var(--text-secondary);
|
||||
|
||||
font-size: 1.2rem;
|
||||
|
||||
max-width: 700px;
|
||||
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
margin-top: 40px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
BUTTONS
|
||||
========================= */
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
text-decoration: none;
|
||||
|
||||
padding: 14px 26px;
|
||||
|
||||
border-radius: 12px;
|
||||
|
||||
transition: 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
METRICS
|
||||
========================= */
|
||||
|
||||
.metrics {
|
||||
max-width: var(--container);
|
||||
|
||||
margin: auto;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
|
||||
gap: 24px;
|
||||
|
||||
padding: 0 24px 120px;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
background: var(--surface);
|
||||
|
||||
border: 1px solid var(--border);
|
||||
|
||||
padding: 32px;
|
||||
|
||||
border-radius: 20px;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.metric-card h3 {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.metric-card p {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
GRID CARDS
|
||||
========================= */
|
||||
|
||||
.cards-grid {
|
||||
display: grid;
|
||||
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
|
||||
gap: 24px;
|
||||
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.card,
|
||||
.project-card {
|
||||
background: var(--surface);
|
||||
|
||||
border: 1px solid var(--border);
|
||||
|
||||
border-radius: 20px;
|
||||
|
||||
padding: 28px;
|
||||
|
||||
transition: all .3s ease;
|
||||
}
|
||||
|
||||
.card:hover,
|
||||
.project-card:hover {
|
||||
transform: translateY(-6px);
|
||||
|
||||
border-color: rgba(59, 130, 246, .35);
|
||||
|
||||
background: var(--surface-hover);
|
||||
}
|
||||
|
||||
.card h3,
|
||||
.project-card h3 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.card p,
|
||||
.project-card p {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
TECH STACK
|
||||
========================= */
|
||||
|
||||
.tech-stack {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
gap: 14px;
|
||||
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.tech-stack span {
|
||||
padding: 10px 18px;
|
||||
|
||||
background: var(--surface);
|
||||
|
||||
border: 1px solid var(--border);
|
||||
|
||||
border-radius: 999px;
|
||||
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
TIMELINE
|
||||
========================= */
|
||||
|
||||
.timeline {
|
||||
margin-top: 40px;
|
||||
|
||||
border-left: 2px solid var(--border);
|
||||
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.timeline-item::before {
|
||||
content: "";
|
||||
|
||||
position: absolute;
|
||||
|
||||
left: -41px;
|
||||
top: 8px;
|
||||
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
||||
border-radius: 50%;
|
||||
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
.timeline-item h3 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.timeline-item p {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
CONTACT
|
||||
========================= */
|
||||
|
||||
.contact-links {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
margin-top: 30px;
|
||||
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.contact-links a {
|
||||
text-decoration: none;
|
||||
|
||||
color: var(--accent);
|
||||
|
||||
transition: 0.3s ease;
|
||||
}
|
||||
|
||||
.contact-links a:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
FOOTER
|
||||
========================= */
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid var(--border);
|
||||
|
||||
text-align: center;
|
||||
|
||||
padding: 50px 24px;
|
||||
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.footer p:first-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* ========================= BACK TO TOP ========================= */
|
||||
#backToTop {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#backToTop:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
#backToTop.show {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* ========================= SECTION ANIMATION ========================= */
|
||||
/*
|
||||
.section,
|
||||
.metric-card,
|
||||
.project-card,
|
||||
.card {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.7s ease;
|
||||
}
|
||||
|
||||
.show-element {
|
||||
opacity: 1 !important;
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
*/
|
||||
|
||||
/* ========================= ACTIVE NAV ========================= */
|
||||
.nav-links a.active {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.nav-links a.active::after {
|
||||
content: "";
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #3b82f6;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
THEME BUTTON
|
||||
========================= */
|
||||
|
||||
.controls {
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
#theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 50%;
|
||||
background: color-mix(in srgb, var(--surface) 72%, transparent);
|
||||
|
||||
color: var(--text-primary);
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
font-size: 1.05rem;
|
||||
line-height: 1;
|
||||
|
||||
transition: .3s ease;
|
||||
}
|
||||
|
||||
#theme-toggle:hover {
|
||||
|
||||
background: var(--surface-hover);
|
||||
transform: rotate(18deg);
|
||||
}
|
||||
|
||||
.language-switcher {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--surface) 72%, transparent);
|
||||
}
|
||||
|
||||
.language-switcher a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 36px;
|
||||
min-height: 32px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background .2s ease,
|
||||
color .2s ease,
|
||||
transform .2s ease;
|
||||
}
|
||||
|
||||
.language-switcher a:hover,
|
||||
.language-switcher a.active {
|
||||
background: var(--accent);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.language-switcher a.active {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
RESPONSIVE
|
||||
========================= */
|
||||
|
||||
@media (max-width: 960px) {
|
||||
|
||||
.metrics {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 90px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
|
||||
.metrics {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hero {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
#theme-toggle {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.language-switcher a {
|
||||
min-width: 32px;
|
||||
min-height: 30px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
display: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-primary);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card:hover,
|
||||
.project-card:hover {
|
||||
transform: translateY(-6px) scale(1.02);
|
||||
}
|
||||
|
||||
@media (max-width:960px) {
|
||||
.navbar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-links.open {
|
||||
display: flex !important;
|
||||
position: absolute;
|
||||
top: calc(100% + 1px);
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 18px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 18px 40px rgba(0, 0, 0, .22);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"include": [".astro/types.d.ts", "**/*"],
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user