Skip to content

Commit 89b2c5a

Browse files
committed
Add analytics, JSON-LD, data & GitHub lib
Introduce site instrumentation, structured data and centralized content/data libraries. Adds a client-side Analytics component (GA4 via NEXT_PUBLIC_GA_ID) and a JsonLd component for schema.org Person data. Introduces app/lib/data.ts (profile, skills, experiences, socials) and app/lib/github.ts (GraphQL pinned repos fetch with token + fallback). Revamps globals.css with a new dark theme, UI utilities (cards, code blocks, tags, cursor, reveal animations, scrollbar, noise texture), and styling improvements. Update layout.tsx to include improved metadata, fonts, manifest, JsonLd and Analytics injection. Replace large page.tsx with a Portfolio import and wire up GitHub fetch. Add workflow env vars (GITHUB_TOKEN, NEXT_PUBLIC_GA_ID) and new public assets (apple-touch-icon, manifest.json, robots.txt, sitemap.xml). These changes improve SEO, analytics, theming and make profile/project data reusable across the app.
1 parent 0d0b772 commit 89b2c5a

17 files changed

Lines changed: 1130 additions & 695 deletions

.github/workflows/deploy.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ jobs:
3535

3636
- name: Build
3737
run: npm run build
38+
env:
39+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
NEXT_PUBLIC_GA_ID: G-GFK73008MT
3841

3942
- name: Upload artifact
4043
uses: actions/upload-pages-artifact@v3

app/components/analytics.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"use client";
2+
import Script from "next/script";
3+
4+
const GA_ID = process.env.NEXT_PUBLIC_GA_ID;
5+
6+
export default function Analytics() {
7+
if (!GA_ID) return null;
8+
return (
9+
<>
10+
<Script src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`} strategy="afterInteractive" />
11+
<Script id="ga4" strategy="afterInteractive">
12+
{`window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','${GA_ID}');`}
13+
</Script>
14+
</>
15+
);
16+
}

app/components/json-ld.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { PROFILE, SKILLS, SOCIALS, EDUCATION } from "../lib/data";
2+
3+
export default function JsonLd() {
4+
const structuredData = {
5+
"@context": "https://schema.org",
6+
"@type": "Person",
7+
name: PROFILE.name,
8+
jobTitle: PROFILE.title,
9+
worksFor: {
10+
"@type": "Organization",
11+
name: "Derivative Path",
12+
},
13+
url: "https://jonathanperis.github.io",
14+
sameAs: SOCIALS.map((s) => s.href),
15+
email: PROFILE.email,
16+
address: {
17+
"@type": "PostalAddress",
18+
addressLocality: "Itanhaem",
19+
addressRegion: "Sao Paulo",
20+
addressCountry: "BR",
21+
},
22+
knowsAbout: [
23+
...SKILLS.languages,
24+
...SKILLS.backend,
25+
...SKILLS.architecture,
26+
...SKILLS.cloud,
27+
...SKILLS.databases,
28+
...SKILLS.frontend,
29+
],
30+
alumniOf: {
31+
"@type": "EducationalOrganization",
32+
name: EDUCATION.institution,
33+
},
34+
};
35+
36+
return (
37+
<script
38+
type="application/ld+json"
39+
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
40+
/>
41+
);
42+
}

app/globals.css

Lines changed: 142 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,161 @@
11
@import "tailwindcss";
22

33
@theme {
4-
--color-navy: #0a192f;
5-
--color-navy-light: #112240;
6-
--color-navy-lightest: #233554;
7-
--color-slate: #8892b0;
8-
--color-slate-light: #a8b2d1;
9-
--color-slate-lightest: #ccd6f6;
10-
--color-white: #e6f1ff;
11-
--color-green: #64ffda;
12-
--color-green-tint: rgba(100, 255, 218, 0.1);
13-
--font-sans: "Inter", "San Francisco", "SF Pro Text", -apple-system, system-ui, sans-serif;
14-
--font-mono: "SF Mono", "Fira Code", "Fira Mono", "Roboto Mono", monospace;
4+
--color-bg: #09090b;
5+
--color-surface: #111113;
6+
--color-elevated: #1a1a1e;
7+
--color-border: #1f1f23;
8+
--color-border-hover: #2e2e35;
9+
--color-text: #ededed;
10+
--color-muted: #888888;
11+
--color-dim: #555555;
12+
--color-green: #4ade80;
13+
--color-green-dim: #22c55e;
14+
--color-green-tint: rgba(74, 222, 128, 0.08);
15+
--color-green-glow: rgba(74, 222, 128, 0.12);
16+
--color-purple: #c084fc;
17+
--color-cyan: #22d3ee;
18+
--color-yellow: #fbbf24;
19+
--color-rose: #fb7185;
20+
--font-sans: "Inter", -apple-system, system-ui, sans-serif;
21+
--font-mono: "JetBrains Mono", "Fira Code", monospace;
1522
}
1623

17-
html {
18-
scroll-behavior: smooth;
19-
}
24+
html { scroll-behavior: smooth; }
2025

2126
body {
22-
background-color: var(--color-navy);
23-
color: var(--color-slate);
27+
background-color: var(--color-bg);
28+
color: var(--color-muted);
2429
font-family: var(--font-sans);
2530
-webkit-font-smoothing: antialiased;
26-
-moz-osx-font-smoothing: grayscale;
2731
}
2832

2933
::selection {
30-
background-color: var(--color-navy-lightest);
31-
color: var(--color-slate-lightest);
34+
background-color: rgba(74, 222, 128, 0.2);
35+
color: var(--color-text);
36+
}
37+
38+
::-webkit-scrollbar { width: 6px; }
39+
::-webkit-scrollbar-track { background: transparent; }
40+
::-webkit-scrollbar-thumb { background-color: var(--color-border-hover); border-radius: 3px; }
41+
42+
/* ── Noise texture ── */
43+
body::before {
44+
content: '';
45+
position: fixed;
46+
inset: 0;
47+
opacity: 0.02;
48+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
49+
pointer-events: none;
50+
z-index: 0;
51+
}
52+
53+
/* ── Scroll progress ── */
54+
.scroll-bar {
55+
transform-origin: left;
56+
background: linear-gradient(90deg, var(--color-green), var(--color-green-dim));
57+
}
58+
59+
/* ── Blinking cursor ── */
60+
@keyframes blink {
61+
0%, 100% { opacity: 1; }
62+
50% { opacity: 0; }
63+
}
64+
.typing-cursor {
65+
display: inline-block;
66+
width: 2px;
67+
height: 1.15em;
68+
background: var(--color-green);
69+
margin-left: 1px;
70+
animation: blink 0.75s step-end infinite;
71+
vertical-align: text-bottom;
72+
}
73+
74+
/* ── Fade in ── */
75+
.reveal {
76+
opacity: 0;
77+
transform: translateY(24px);
78+
transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
79+
}
80+
.reveal.shown {
81+
opacity: 1;
82+
transform: none;
83+
}
84+
85+
/* ── Card ── */
86+
.card {
87+
background: var(--color-surface);
88+
border: 1px solid var(--color-border);
89+
border-radius: 12px;
90+
transition: border-color 0.3s, box-shadow 0.3s, background-color 0.3s;
91+
}
92+
.card:hover, .card-glow:hover {
93+
border-color: rgba(74, 222, 128, 0.25);
94+
box-shadow: 0 0 40px rgba(74, 222, 128, 0.04);
95+
background: var(--color-elevated);
3296
}
3397

34-
::-webkit-scrollbar {
35-
width: 12px;
98+
/* ── Code block ── */
99+
.code-block {
100+
background: var(--color-surface);
101+
border: 1px solid var(--color-border);
102+
border-radius: 12px;
103+
overflow: hidden;
104+
}
105+
.code-block .titlebar {
106+
background: var(--color-elevated);
107+
border-bottom: 1px solid var(--color-border);
108+
padding: 10px 16px;
109+
display: flex;
110+
align-items: center;
111+
gap: 8px;
36112
}
113+
.code-block .dots { display: flex; gap: 6px; }
114+
.code-block .dot { width: 10px; height: 10px; border-radius: 50%; }
115+
.code-block .dot-red { background: #ff5f57; }
116+
.code-block .dot-yellow { background: #febc2e; }
117+
.code-block .dot-green { background: #28c840; }
37118

38-
::-webkit-scrollbar-track {
39-
background: var(--color-navy);
119+
/* ── Tag ── */
120+
.tag {
121+
font-family: var(--font-mono);
122+
font-size: 11px;
123+
padding: 3px 10px;
124+
border-radius: 6px;
125+
background: var(--color-green-tint);
126+
color: var(--color-green);
127+
border: 1px solid rgba(74, 222, 128, 0.12);
128+
transition: all 0.2s;
129+
white-space: nowrap;
40130
}
41131

42-
::-webkit-scrollbar-thumb {
43-
background-color: var(--color-navy-lightest);
44-
border: 3px solid var(--color-navy);
45-
border-radius: 10px;
132+
/* ── Experience entry ── */
133+
.exp-entry {
134+
border-left: 2px solid var(--color-border);
135+
transition: border-color 0.3s;
136+
}
137+
.exp-entry:hover {
138+
border-left-color: var(--color-green);
139+
}
140+
141+
/* ── Terminal ── */
142+
.terminal-backdrop {
143+
background: rgba(0, 0, 0, 0.8);
144+
backdrop-filter: blur(24px);
145+
}
146+
.terminal-body::-webkit-scrollbar { width: 4px; }
147+
.terminal-body::-webkit-scrollbar-thumb { background-color: var(--color-border-hover); border-radius: 2px; }
148+
149+
/* ── Glow dot ── */
150+
@keyframes pulse-ring {
151+
0% { transform: scale(1); opacity: 0.6; }
152+
100% { transform: scale(2.5); opacity: 0; }
153+
}
154+
.glow-dot::before {
155+
content: '';
156+
position: absolute;
157+
inset: 0;
158+
border-radius: 50%;
159+
background: var(--color-green);
160+
animation: pulse-ring 2s ease-out infinite;
46161
}

app/layout.tsx

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
11
import type { Metadata } from "next";
22
import "./globals.css";
3+
import Analytics from "./components/analytics";
4+
import JsonLd from "./components/json-ld";
35

46
export const metadata: Metadata = {
5-
title: "Jonathan Peris | Software Engineer",
7+
metadataBase: new URL("https://jonathanperis.github.io"),
8+
title: "Jonathan Peris — Software Engineer",
69
description:
7-
"Jonathan Peris is a software engineer specializing in .NET and Fintech solutions, architecting and delivering high-impact, enterprise-grade software with modern cloud-native technologies.",
10+
"Software Engineer specializing in .NET and Fintech. 12+ years building enterprise-grade systems with modern cloud-native technologies.",
11+
alternates: {
12+
canonical: "/",
13+
},
14+
keywords: [
15+
"Jonathan Peris",
16+
"Software Engineer",
17+
".NET",
18+
"C#",
19+
"Fintech",
20+
"Azure",
21+
"Microservices",
22+
"CQRS",
23+
"DDD",
24+
"Clean Architecture",
25+
"Backend Developer",
26+
"Cloud-Native",
27+
],
828
openGraph: {
9-
title: "Jonathan Peris | Software Engineer",
29+
title: "Jonathan Peris Software Engineer",
1030
description:
11-
"Jonathan Peris is a software engineer specializing in .NET and Fintech solutions, architecting and delivering high-impact, enterprise-grade software with modern cloud-native technologies.",
31+
"Software Engineer specializing in .NET and Fintech. 12+ years building enterprise-grade systems with modern cloud-native technologies.",
1232
url: "https://jonathanperis.github.io",
1333
siteName: "Jonathan Peris",
1434
images: [
@@ -21,31 +41,40 @@ export const metadata: Metadata = {
2141
locale: "en_US",
2242
type: "website",
2343
},
44+
twitter: {
45+
card: "summary_large_image",
46+
title: "Jonathan Peris — Software Engineer",
47+
description:
48+
"Software Engineer specializing in .NET and Fintech. 12+ years building enterprise-grade systems with modern cloud-native technologies.",
49+
creator: "@jperis_silva",
50+
},
2451
icons: {
2552
icon: "/favicon.svg",
53+
apple: "/apple-touch-icon.png",
2654
},
2755
};
2856

2957
export default function RootLayout({
3058
children,
31-
}: Readonly<{
32-
children: React.ReactNode;
33-
}>) {
59+
}: Readonly<{ children: React.ReactNode }>) {
3460
return (
3561
<html lang="en" className="scroll-smooth">
3662
<head>
63+
<meta name="theme-color" content="#09090b" />
3764
<link rel="preconnect" href="https://fonts.googleapis.com" />
65+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
3866
<link
39-
rel="preconnect"
40-
href="https://fonts.gstatic.com"
41-
crossOrigin="anonymous"
42-
/>
43-
<link
44-
href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
67+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:ital,wght@0,400;0,500;0,700;1,400&display=swap"
4568
rel="stylesheet"
4669
/>
70+
<link rel="alternate" hrefLang="en" href="https://jonathanperis.github.io/" />
71+
<link rel="manifest" href="/manifest.json" />
72+
<JsonLd />
4773
</head>
48-
<body className="antialiased">{children}</body>
74+
<body className="antialiased">
75+
{children}
76+
<Analytics />
77+
</body>
4978
</html>
5079
);
5180
}

0 commit comments

Comments
 (0)