-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
157 lines (133 loc) · 19.8 KB
/
index.html
File metadata and controls
157 lines (133 loc) · 19.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v5.11.0"><title>Ornithop.fyi</title><meta name="description" content="Personal Showcase - Tech writing and projects"><meta name="theme-color" content="#8c5cf5"><link rel="canonical" href="https://33j33.github.io/"><meta name="og:title" content="Ornithop.fyi"><meta name="og:description" content="Personal Showcase - Tech writing and projects"><meta name="og:image" content="/img/og.png"><meta name="og:url" content="https://33j33.github.io/"><meta name="og:type" content="website"><meta name="og:locale" content="en"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="Ornithop.fyi"><meta name="twitter:description" content="Personal Showcase - Tech writing and projects"><meta name="twitter:image" content="/img/og.png"><style>.layout-grid-left,.layout-grid-right{display:flex;flex-direction:column;width:100%;gap:2rem}@media screen and (max-width: 640px){.layout-grid-left,.layout-grid-right{gap:1rem}}.flex-col-card{display:flex;flex-direction:column}.flex-row-card{display:flex;justify-content:center;align-items:center}.header-container{display:flex;flex-direction:row;align-items:center;gap:1rem;margin-bottom:1rem}.header-container *{margin:0}.prose{line-height:1.6}.work-experience-duration{color:var(--secondary)}.work-experience-container{display:flex;flex-direction:column;gap:1rem}.work-experience-entry:not(:last-of-type){border-bottom:1px solid #353535;padding-bottom:1rem}.work-experience-duration{font-size:.925rem}.work-experience-company{margin-top:.25rem;margin-bottom:.5rem}.work-experience-role{margin-bottom:.75rem}.socials-link{color:#fff;display:flex;flex-direction:row;gap:.75rem;align-items:center}
.card[data-astro-cid-dohjnao5]{width:100%;height:auto;background-color:#121212;border:1px solid #353535;padding:1.5rem;overflow:hidden}.no-padding[data-astro-cid-dohjnao5]{padding:0}
.chip[data-astro-cid-b4zvghpy]{display:inline-block;padding:.2rem .5rem;border-radius:.2rem;color:var(--secondary);box-shadow:inset 0 0 5px 0 var(--primary-dark);white-space:nowrap;text-decoration:none;border:1px solid var(--primary-dark)}.post-container[data-astro-cid-iyiqi2so]{display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid #353535;color:#fff;text-decoration:none;transition:background-color .15s ease,border .15s ease}.post-container[data-astro-cid-iyiqi2so]:hover,.post-container[data-astro-cid-iyiqi2so]:focus-visible{background-color:rgba(var(--primary-rgb),.125);border:1px solid var(--primary);color:#fff;text-decoration:none}.post-container[data-astro-cid-iyiqi2so]:focus-visible{outline:none}.post-header[data-astro-cid-iyiqi2so]{display:flex;flex-direction:column;justify-content:space-between;gap:.5rem}.post-description[data-astro-cid-iyiqi2so]{margin-top:.6rem}@media screen and (max-width: 640px){.post-header[data-astro-cid-iyiqi2so]{flex-direction:column;gap:.5rem}}.post-date[data-astro-cid-iyiqi2so]{color:var(--secondary);white-space:nowrap}.tags[data-astro-cid-iyiqi2so]{display:flex;gap:.4rem;flex-wrap:wrap}
</style>
<link rel="stylesheet" href="/_astro/index.DGEM5TYP.css"></head> <body> <main data-pagefind-ignore="true"> <nav data-astro-cid-5blmo7yk> <a class="site-title" href="/" data-astro-cid-5blmo7yk>Ornithop.fyi</a> <ul data-astro-cid-5blmo7yk> <li data-astro-cid-5blmo7yk> <a href="/posts" data-astro-cid-5blmo7yk>Posts</a> </li> <li class="nav-separator" data-astro-cid-5blmo7yk>|</li> <li data-astro-cid-5blmo7yk> <a href="/projects" data-astro-cid-5blmo7yk>Projects</a> </li> <li class="nav-separator" data-astro-cid-5blmo7yk>|</li> <li data-astro-cid-5blmo7yk> <input id="search" type="text" placeholder="Search (Ctrl+K)" data-astro-cid-5blmo7yk> <div id="search-results" data-astro-cid-5blmo7yk></div> </li> </ul> <button class="mobile-nav-toggle" data-astro-cid-5blmo7yk> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="menu-closed" data-astro-cid-5blmo7yk="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16M4 6h16M4 18h16"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="menu-open" data-astro-cid-5blmo7yk="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6L6 18M6 6l12 12"/></svg> </button> </nav> <script>
const searchElement = document.querySelector('#search');
const results = document.querySelector('#search-results');
const navToggle = document.querySelector('.mobile-nav-toggle');
let focusIndex = -1;
document.addEventListener('keydown', (e) => {
if (e.key === 'k' && e.ctrlKey) {
searchElement.focus();
}
if (e.key === 'Escape') {
searchElement.blur();
results.classList.remove('active');
focusIndex = -1;
}
if (e.key === 'ArrowDown') {
e.preventDefault();
focusIndex++;
const results = document.querySelectorAll('#search-results a');
if (focusIndex >= results.length) {
focusIndex = 0;
}
results[focusIndex]?.focus();
}
if (e.key === 'ArrowUp') {
e.preventDefault();
focusIndex--;
const results = document.querySelectorAll('#search-results a');
if (focusIndex < 0) {
focusIndex = results.length - 1;
}
results[focusIndex]?.focus();
}
});
let pagefindInitialized = false;
searchElement?.addEventListener('focus', async () => {
searchElement.placeholder = '';
results.classList.add('active');
// initialize pagefind on first focus
if (!pagefindInitialized) {
try {
window.pagefind = await import("/pagefind/pagefind.js");
await window.pagefind.init();
pagefindInitialized = true;
} catch (error) {
console.error('Failed to initialize Pagefind:', error);
}
}
});
searchElement?.addEventListener('blur', () => {
handleTabletChange()
setTimeout(() => {
if (!document.activeElement?.closest('#search-results')) {
results.classList.remove('active');
focusIndex = -1;
}
}, 1);
});
results?.addEventListener('focusout', (e) => {
if (!e.relatedTarget?.closest('#search-results')) {
results.classList.remove('active');
focusIndex = -1;
}
});
searchElement?.addEventListener('input', async (e) => {
// only search if Pagefind is ready
if (!pagefindInitialized) {
return;
}
results.innerHTML = '';
let searchResultHtml = '';
const search = await window.pagefind.search(e.target.value);
let i = 0;
for (const result of search.results) {
i++;
const data = await result.data();
searchResultHtml += `
<a href="${data.url}">
<h5 class="no-mt">${data.meta.title}</h5>
<p>${data.excerpt}</p>
</a>
${i < search.results.length ? '<hr class="separator">' : ''}
`;
}
if (search.results.length === 0 && e.target.value.length > 0) {
results.innerHTML = '<p style="margin-top: 0;">No results found</p>';
} else {
results.innerHTML = searchResultHtml;
}
results.classList.add('active');
});
navToggle?.addEventListener('click', () => {
navToggle.classList.toggle('active');
document.querySelector('nav').classList.toggle('active');
});
const handleTabletChange = () => {
if (window.matchMedia('(max-width: 640px)').matches) {
searchElement.placeholder = 'Search';
} else {
searchElement.placeholder = 'Search (Ctrl+K)';
}
}
document.addEventListener('DOMContentLoaded', handleTabletChange);
document.addEventListener('resize', handleTabletChange);
</script> <div class="layout-grid" data-astro-cid-cgyg4spe> <div class="layout-grid-left"> <div class="card flex-col-card" data-astro-cid-dohjnao5> <div class="card flex-row-card no-padding" data-astro-cid-dohjnao5> <img src="/_astro/openpeepofme.D9RUv1_z_ZeUq5e.webp" alt="Avatar of the author" loading="eager" decoding="async" fetchpriority="auto" width="200" height="200"> </div> <h3>Jai A</h3> <ul class="overview-list"> <!-- {quickInfo.map((info) => (
<li>
<Icon type={info.data.icon.type} name={info.data.icon.name as any} width={24} height={24} class='glow-icon' />
<span>{info.data.text}</span>
</li>
))} --> <li> <a href="https://github.com/33j33" class="socials-link"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="glow-icon"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5c.08-1.25-.27-2.48-1-3.5c.28-1.15.28-2.35 0-3.5c0 0-1 0-3 1.5c-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 4 9c0 3.5 3 5.5 6 5.5c-.39.49-.68 1.05-.85 1.65S8.93 17.38 9 18v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></g></svg> <span>GitHub</span> </a> </li> </ul> </div> <div class="card flex-col-card" data-astro-cid-dohjnao5> <div class="header-container"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="glow-icon"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></g></svg> <h5>About me</h5> </div> <div class="prose"> <p>I’m a software developer with over 4 years of experience working across the stack, from building robust backend services to performant frontend apps. I’ve worked extensively in the JavaScript ecosystem. Besides that, I have hands-on experience with Python, Go, Ruby on Rails, and serverless tech.</p>
<p>I’m driven by the pursuit of excellence, a passion for learning new technologies and building systems that scale. Trying to find my footing in the post-LLM world. Rethinking how we build, learn, and collaborate in a landscape that’s changing fast. This blog is my space to explore those ideas. I write to sharpen my own craft, share what I’ve learned, and hopefully contribute something useful to other folks navigating similar paths.</p> </div> </div> <!-- <Card>
<h3 class="no-mt">Socials</h3>
<ul class="overview-list">
</ul>
</Card> --> </div> <div class="layout-grid-right"> <div class="card" data-astro-cid-dohjnao5> <div class="header-container"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="glow-icon"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1"/></g></svg> <h5>Posts</h5> </div> <div class="content-container"> <a href="/posts/aws-s3-sam-cloudfront" class="post-container" data-tags="aws,sam,cloudfront,s3,infrastructure-as-code" data-astro-cid-iyiqi2so> <div class="post-header" data-astro-cid-iyiqi2so> <h6 class="no-mt no-mb" data-pagefind-meta="title" data-astro-cid-iyiqi2so>Set up S3 and CloudFront with SAM for your frontend</h6> <span class="post-date small" data-pagefind-ignore data-astro-cid-iyiqi2so>Published | 15th February 2025</span> </div> <div class="tags" data-astro-cid-iyiqi2so><span class="chip" data-astro-cid-b4zvghpy>aws</span> <span class="chip" data-astro-cid-b4zvghpy>sam</span> <span class="chip" data-astro-cid-b4zvghpy>cloudfront</span> <span class="chip" data-astro-cid-b4zvghpy>s3</span> <span class="chip" data-astro-cid-b4zvghpy>infrastructure-as-code</span> </div> <p class="post-description" data-astro-cid-iyiqi2so>Learn how to quickly deploy your SPAs or websites to a secure S3 bucket with CloudFront distribution using SAM template</p> </a> <a href="/posts/react-state-shallow" class="post-container" data-tags="react,javascript,immutability" data-astro-cid-iyiqi2so> <div class="post-header" data-astro-cid-iyiqi2so> <h6 class="no-mt no-mb" data-pagefind-meta="title" data-astro-cid-iyiqi2so>Why shallow copying nested state objects in React can cause bugs?</h6> <span class="post-date small" data-pagefind-ignore data-astro-cid-iyiqi2so>Published | 14th May 2022</span> </div> <div class="tags" data-astro-cid-iyiqi2so><span class="chip" data-astro-cid-b4zvghpy>react</span> <span class="chip" data-astro-cid-b4zvghpy>javascript</span> <span class="chip" data-astro-cid-b4zvghpy>immutability</span> </div> <p class="post-description" data-astro-cid-iyiqi2so>Learn how copying nested state objects affect state changes, and how to prevent bugs by ensuring state immutability</p> </a> </div> </div> <div class="card" data-astro-cid-dohjnao5> <div class="header-container"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="glow-icon"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><circle cx="12" cy="13" r="2"/><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Zm-6-7h3M7 13h3"/></g></svg> <h5>Projects</h5> </div> <div class="content-container"> <a href="https://github.com/33j33/Slack-Privacy-Extension" class="post-container" data-tags="browser-extension,javascript,slack" data-astro-cid-iyiqi2so> <div class="post-header" data-astro-cid-iyiqi2so> <h6 class="no-mt no-mb" data-pagefind-meta="title" data-astro-cid-iyiqi2so>Slack Privacy Extension</h6> </div> <div class="tags" data-astro-cid-iyiqi2so><span class="chip" data-astro-cid-b4zvghpy>browser-extension</span> <span class="chip" data-astro-cid-b4zvghpy>javascript</span> <span class="chip" data-astro-cid-b4zvghpy>slack</span> </div> <p class="post-description" data-astro-cid-iyiqi2so>Browser extension for Slack which blurs messages, media, and other content until you need to view them. Perfect for those who work in public spaces or frequently share their screen during meetings.</p> </a> <a href="https://github.com/33j33/buffered-event-emitter" class="post-container" data-tags="event-emitter,javascript,node" data-astro-cid-iyiqi2so> <div class="post-header" data-astro-cid-iyiqi2so> <h6 class="no-mt no-mb" data-pagefind-meta="title" data-astro-cid-iyiqi2so>buffered-event-emitter</h6> </div> <div class="tags" data-astro-cid-iyiqi2so><span class="chip" data-astro-cid-b4zvghpy>event-emitter</span> <span class="chip" data-astro-cid-b4zvghpy>javascript</span> <span class="chip" data-astro-cid-b4zvghpy>node</span> </div> <p class="post-description" data-astro-cid-iyiqi2so>A tiny (2.4kb) library with Typescript support to handle events. Buffer and flush events with configurable buffer capacity. Pause, queue and resume events. Log event emission, adding and removing listeners. Works for both node and browser.</p> </a> <a href="https://github.com/33j33/10-Layouts-in-10-CSS-Lines" class="post-container" data-tags="css,layouts,grid,flexbox" data-astro-cid-iyiqi2so> <div class="post-header" data-astro-cid-iyiqi2so> <h6 class="no-mt no-mb" data-pagefind-meta="title" data-astro-cid-iyiqi2so>10-Layouts-in-10-CSS-Lines</h6> </div> <div class="tags" data-astro-cid-iyiqi2so><span class="chip" data-astro-cid-b4zvghpy>css</span> <span class="chip" data-astro-cid-b4zvghpy>layouts</span> <span class="chip" data-astro-cid-b4zvghpy>grid</span> <span class="chip" data-astro-cid-b4zvghpy>flexbox</span> </div> <p class="post-description" data-astro-cid-iyiqi2so>Collection of common layout patterns and their implementation with few lines of minimal, modern CSS</p> </a> </div> </div> <!-- <Card>
<div class="header-container">
<Icon type='lucide' name="briefcase-business" width={24} height={24} class='glow-icon' />
<h5>Work Experience</h5>
</div>
<div class="work-experience-container">
{workExperience.reverse().map((entry) => (
<div class="work-experience-entry">
<span class="work-experience-duration">{entry.data.duration}</span>
<h3 class="work-experience-company">{entry.data.company}</h3>
<span class="work-experience-role">{entry.data.title}</span>
<p class="work-experience-desc">{entry.data.description}</p>
</div>
))}
</div>
</Card> --> </div> </div> </main> <canvas id="overlay-canvas"></canvas> <script type="module">class a extends Error{type="AstroUserError";hint;name="AstroUserError";constructor(t,e){super(),this.message=t,this.hint=e}static is(t){return t.type==="AstroUserError"}}class l{LETTER_FADE_DURATION=[2,7];overlayCanvas;overlayCtx;width=document.body.clientWidth;height=Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.offsetHeight);animationFrameId=null;letterPositions=[];letterInstances=[];primaryRgb;constructor(t){const e=t.getContext("2d");if(!e)throw new a("Unable to get 2D context.");this.overlayCanvas=t,this.overlayCtx=e,t.width=this.width,t.height=this.height,this.primaryRgb=window.getComputedStyle(document.documentElement).getPropertyValue("--primary-rgb").trim(),this.initBackground(),this.animationFrameId=requestAnimationFrame(this.redrawBackground)}configureContext=()=>{this.overlayCtx.font="bold 28px Geist Mono",this.overlayCtx.textAlign="start",this.overlayCtx.textBaseline="top",this.overlayCtx.shadowBlur=16};initBackground=()=>{const t=document.title.toLowerCase().split(" | ")[0]||"spectre",e=Math.ceil(this.width/17),n=Math.ceil(this.height/35);for(let o=0;o<n;o++)for(let i=0;i<e;i++)this.letterPositions.push({x:i*17,y:o*35,letter:t[i%t.length]});const r=this.getRandomAmountFromArray(this.letterPositions,Number.parseInt((n*.75).toFixed()));this.configureContext();for(const o of r){this.overlayCtx.fillStyle=`rgba(${this.primaryRgb}, 0)`,this.overlayCtx.shadowColor=`rgba(${this.primaryRgb}, 0)`,this.overlayCtx.fillText(o.letter,o.x,o.y);const i=this.LETTER_FADE_DURATION[0]+Math.random()*(this.LETTER_FADE_DURATION[1]-this.LETTER_FADE_DURATION[0]);this.letterInstances.push({x:o.x,y:o.y,letter:o.letter,timestamp:Date.now(),fadeout:Date.now()+i*1e3})}};easeInOutSine=(t,e,n)=>{const r=n-e;if(t<e)return 0;if(t>n){const h=(t-n)/(r/2);return Math.sin(h*Math.PI)}const o=(t-e)/r;return Math.max(0,.5-.5*Math.cos(o*Math.PI))};getRandomAmountFromArray=(t,e=20)=>{let n=t.length;const r=new Array(e),o=new Array(n);if(e>n)throw new a("getRandomAmountFromArray: more elements taken than available");for(;e--;){const i=Math.floor(Math.random()*n);r[e]=t[i in o?o[i]:i],o[i]=--n in o?o[n]:n}return r};redrawBackground=()=>{this.overlayCtx.clearRect(0,0,this.overlayCanvas.width,this.overlayCanvas.height);const t=Date.now();for(const e of this.letterInstances){if(e.fadeout>t)continue;const n=this.easeInOutSine(t,e.timestamp,e.fadeout);if(n<=0&&t>e.fadeout){this.letterInstances.splice(this.letterInstances.indexOf(e),1);const r=this.getRandomAmountFromArray(this.letterPositions,1);this.letterInstances.push({x:r[0].x,y:r[0].y,letter:r[0].letter,timestamp:t,fadeout:t+(this.LETTER_FADE_DURATION[0]+Math.random()*(this.LETTER_FADE_DURATION[1]-this.LETTER_FADE_DURATION[0]))*1e3})}this.overlayCtx.fillStyle=`rgba(${this.primaryRgb}, ${n})`,this.overlayCtx.shadowColor=`rgba(${this.primaryRgb}, ${n})`,this.overlayCtx.fillText(e.letter,e.x,e.y)}this.animationFrameId=requestAnimationFrame(this.redrawBackground)};resizeBackground=()=>{this.width=document.body.clientWidth,this.height=Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.offsetHeight),this.overlayCanvas.width=this.width,this.overlayCanvas.height=this.height,this.overlayCtx.clearRect(0,0,this.overlayCanvas.width,this.overlayCanvas.height),this.letterInstances=[],this.letterPositions=[],this.initBackground()};destroy=()=>{this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}}async function d(){const s=new FontFace("Geist Mono","url(/fonts/GeistMono.woff2)");await s.load(),document.fonts.add(s)}async function c(){await d();const s=document.getElementById("overlay-canvas"),t=new l(s),e=new ResizeObserver(()=>{t.resizeBackground()});e.observe(document.body),window.addEventListener("beforeunload",()=>{t.destroy(),e.disconnect()})}c();</script> </body></html>