Split repo into noo and portfolio workers
- noo: moved from nextcloud_client/website, deploys to noo.ayushya.dev - portfolio: moved root site into portfolio/, deploys to ayushya.dev - separate path-filtered Gitea workflows per worker
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
wrangler.toml
|
||||
README.md
|
||||
.assetsignore
|
||||
node_modules
|
||||
.wrangler
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<rect x="2" y="2" width="60" height="60" rx="16" fill="#2563eb"/>
|
||||
<rect x="10" y="2" width="2" height="10" fill="#ffffff"/>
|
||||
<circle cx="11" cy="2" r="3" fill="#ffffff"/>
|
||||
<circle cx="22" cy="34" r="9" fill="#ffffff"/>
|
||||
<circle cx="22" cy="34" r="3.4" fill="#2563eb"/>
|
||||
<circle cx="42" cy="34" r="9" fill="#ffffff"/>
|
||||
<circle cx="42" cy="34" r="3.4" fill="#2563eb"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 453 B |
@@ -0,0 +1,399 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Ayushya.dev</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
--bg:#fafaf9; --fg:#141414; --muted:#6b6b68; --accent:#2563eb;
|
||||
--border:#141414; --card-bg:#ffffff; --divider:#dcdcd8; --limb:#c7c7c2;
|
||||
}
|
||||
@media (prefers-color-scheme: dark){
|
||||
:root{
|
||||
--bg:#0b0d0f; --fg:#f2f2f0; --muted:#9a9a95; --accent:#64a1fb;
|
||||
--border:#f2f2f0; --card-bg:#141719; --divider:#2b2e31; --limb:#33373b;
|
||||
}
|
||||
}
|
||||
*{box-sizing:border-box;}
|
||||
html,body{margin:0;padding:0;}
|
||||
body{background:var(--bg);color:var(--fg);font-family:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;}
|
||||
a{color:inherit;text-decoration:none;}
|
||||
h1,h2,h3,p{margin:0;}
|
||||
button{font-family:inherit;}
|
||||
|
||||
.page{width:100%;min-height:100vh;display:flex;flex-direction:column;}
|
||||
.layout-grid{display:grid;grid-template-columns:1fr 190px 1fr;gap:48px;max-width:1180px;width:100%;margin:0 auto;padding:72px 32px 56px;align-items:start;}
|
||||
|
||||
.name-box{border:1px solid var(--border);border-radius:14px;padding:26px 30px;width:100%;}
|
||||
.name-box h1{font-size:26px;font-weight:700;letter-spacing:0.03em;text-align:center;}
|
||||
|
||||
.left-col{display:flex;flex-direction:column;gap:32px;min-width:0;}
|
||||
.projects-block{display:flex;flex-direction:column;gap:16px;margin-top:48px;}
|
||||
.stack-row{display:flex;align-items:center;gap:14px;position:relative;}
|
||||
|
||||
.link-btn{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--accent);color:var(--accent);border-radius:8px;padding:11px 20px;font-size:13px;font-weight:600;letter-spacing:0.06em;font-family:inherit;background:transparent;cursor:pointer;transition:background .15s ease,color .15s ease;}
|
||||
.link-btn:hover{background:var(--accent);color:var(--card-bg);}
|
||||
|
||||
.card-link{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--accent);color:var(--accent);border-radius:8px;padding:9px 18px;font-size:12px;font-weight:700;letter-spacing:0.06em;transition:background .15s ease,color .15s ease;align-self:flex-start;}
|
||||
.card-link:hover{background:var(--accent);color:var(--card-bg);}
|
||||
|
||||
.nav-btn{width:40px;height:40px;min-width:40px;min-height:40px;border-radius:50%;border:1px solid var(--border);background:var(--card-bg);color:var(--fg);display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0;transition:background .15s ease,color .15s ease;}
|
||||
.nav-btn:hover{background:var(--fg);color:var(--bg);}
|
||||
.nav-btn:hover .tri{border-bottom-color:var(--bg);}
|
||||
.nav-btn:hover .tri-down{border-top-color:var(--bg);}
|
||||
.nav-btn[data-disabled="true"]{opacity:0.32;pointer-events:none;}
|
||||
.tri{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:8px solid var(--accent);transition:border-color .15s ease;}
|
||||
.tri-down{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:8px solid var(--accent);transition:border-color .15s ease;}
|
||||
.nav-col{position:absolute;right:-58px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:10px;flex-shrink:0;}
|
||||
|
||||
.stack-scroll{scrollbar-width:none;-ms-overflow-style:none;}
|
||||
.stack-scroll::-webkit-scrollbar{display:none;width:0;height:0;}
|
||||
.stack-card-top{display:flex;flex-direction:column;gap:14px;}
|
||||
.avatar{width:52px;height:52px;border-radius:50%;border:1px solid var(--accent);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;color:var(--accent);flex-shrink:0;}
|
||||
.card-text{display:flex;flex-direction:column;gap:6px;}
|
||||
.card-text h3{font-size:15px;font-weight:700;letter-spacing:0.02em;}
|
||||
.desc-clamp{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;font-size:13px;line-height:1.5;color:var(--muted);}
|
||||
|
||||
.projects-label{text-align:center;font-size:11px;letter-spacing:0.14em;color:var(--muted);}
|
||||
|
||||
.mid-col{display:flex;flex-direction:column;align-items:stretch;gap:16px;height:100%;align-self:stretch;}
|
||||
.divider-v{width:1px;flex:1 1 auto;background:var(--divider);margin:8px auto;}
|
||||
.email-link{font-size:12px;letter-spacing:0.06em;color:var(--muted);text-align:center;}
|
||||
|
||||
.robot-col{display:flex;flex-direction:column;align-items:center;gap:28px;padding-top:6px;}
|
||||
.marquee-wrap{overflow:hidden;-webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);width:100%;max-width:260px;font-size:12px;letter-spacing:0.08em;color:var(--muted);}
|
||||
.marquee-track{display:inline-block;white-space:nowrap;animation:scrollLeft 16s linear infinite;}
|
||||
@keyframes scrollLeft{from{transform:translateX(0);}to{transform:translateX(-50%);}}
|
||||
|
||||
.robot{display:flex;flex-direction:column;align-items:center;}
|
||||
.antenna-wire{width:2px;height:20px;background:var(--fg);}
|
||||
.antenna-seg-1{width:2px;height:12px;background:var(--fg);transform:rotate(28deg) translateX(3px);}
|
||||
.antenna-seg-2{width:2px;height:12px;background:var(--fg);transform:rotate(-28deg) translateX(-3px);margin-top:-2px;}
|
||||
.antenna-tip{width:10px;height:10px;border-radius:50%;background:var(--fg);margin-top:2px;}
|
||||
.head{width:140px;height:118px;margin-top:14px;border:2px solid var(--fg);border-radius:30px;background:var(--card-bg);display:flex;align-items:center;justify-content:center;gap:20px;}
|
||||
.eye-ball{width:34px;height:34px;border-radius:50%;background:var(--card-bg);border:2px solid var(--fg);position:relative;flex-shrink:0;}
|
||||
.pupil{position:absolute;top:50%;left:50%;width:13px;height:13px;border-radius:50%;background:var(--fg);margin-top:-6.5px;margin-left:-6.5px;transition:transform .06s linear;}
|
||||
.neck-gap{height:16px;}
|
||||
.body-row{display:flex;align-items:flex-start;gap:10px;}
|
||||
.arm{width:16px;height:118px;border-radius:10px;background:var(--limb);margin-top:10px;}
|
||||
.torso{width:150px;height:150px;border:2px solid var(--fg);border-radius:26px;background:var(--card-bg);}
|
||||
.leg-gap{height:10px;}
|
||||
.legs-row{display:flex;gap:26px;}
|
||||
.leg{width:20px;height:78px;border-radius:10px;background:var(--limb);}
|
||||
|
||||
@media (max-width: 880px){
|
||||
.layout-grid{grid-template-columns:1fr !important;}
|
||||
.divider-v{display:none !important;}
|
||||
.robot-col{padding-top:0 !important;}
|
||||
.stack-row{flex-direction:column;align-items:stretch;}
|
||||
.nav-col{flex-direction:row !important;justify-content:center;position:static;transform:none;right:auto;top:auto;}
|
||||
.tri{transform:rotate(-90deg);}
|
||||
.tri-down{transform:rotate(-90deg);}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="layout-grid">
|
||||
|
||||
<div class="left-col">
|
||||
<div class="name-box"><h1>AYUSHYA.DEV</h1></div>
|
||||
|
||||
<div class="projects-block">
|
||||
<div class="stack-row">
|
||||
<div class="stack-scroll" id="stackScroll">
|
||||
<div class="spacer" id="spacer" style="position:relative;">
|
||||
<div class="layer" id="layer" style="position:absolute;top:0;left:0;">
|
||||
<!-- cards injected by JS -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-col">
|
||||
<button class="nav-btn" id="prevBtn" aria-label="Show previous project" type="button">
|
||||
<span class="tri"></span>
|
||||
</button>
|
||||
<button class="nav-btn" id="nextBtn" aria-label="Show next project" type="button">
|
||||
<span class="tri-down"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="projects-label">PROJECTS</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mid-col">
|
||||
<a class="link-btn" href="https://github.com/ayushyamitabh/" target="_blank" rel="noopener noreferrer">GITHUB</a>
|
||||
<a class="link-btn" href="https://linkedin.com/in/ayushyamitabh" target="_blank" rel="noopener noreferrer">LINKEDIN</a>
|
||||
<div class="divider-v"></div>
|
||||
<a class="email-link" href="mailto:hello@ayushya.dev">HELLO@AYUSHYA.DEV</a>
|
||||
</div>
|
||||
|
||||
<div class="robot-col">
|
||||
<div class="marquee-wrap">
|
||||
<span class="marquee-track" id="marquee"></span>
|
||||
</div>
|
||||
|
||||
<div class="robot">
|
||||
<div class="antenna-wire"></div>
|
||||
<div class="antenna-seg-1"></div>
|
||||
<div class="antenna-seg-2"></div>
|
||||
<div class="antenna-tip"></div>
|
||||
|
||||
<div class="head">
|
||||
<div class="eye-ball" id="eyeLeft"><div class="pupil" id="pupilLeft"></div></div>
|
||||
<div class="eye-ball" id="eyeRight"><div class="pupil" id="pupilRight"></div></div>
|
||||
</div>
|
||||
|
||||
<div class="neck-gap"></div>
|
||||
|
||||
<div class="body-row">
|
||||
<div class="arm"></div>
|
||||
<div class="torso"></div>
|
||||
<div class="arm"></div>
|
||||
</div>
|
||||
|
||||
<div class="leg-gap"></div>
|
||||
|
||||
<div class="legs-row">
|
||||
<div class="leg"></div>
|
||||
<div class="leg"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var PROJECTS = [
|
||||
{ initials: 'N', name: 'NOO', desc: 'A fast, native Nextcloud client built with Flutter and Material You \u2014 files, photos, activity, shares, and trash in one themed app.', link: 'https://noo.ayushya.dev' },
|
||||
{ initials: 'WP', name: 'CHROME WATCH PARTY', desc: 'Syncs streamed video across devices so you can watch with your favorite people, with chat, GIFs, and free group calls.', link: 'https://watchparty-archive.web.app/' },
|
||||
{ initials: 'V&M', name: 'VAX & ME', desc: 'Explains the expected side effects of COVID-19 vaccines, built from FDA data on Pfizer, Moderna, and J&J.', link: 'https://vaxandme-archive.web.app/' },
|
||||
];
|
||||
|
||||
var COUNT = PROJECTS.length;
|
||||
var PEEK_SCALE = 0.9;
|
||||
var MOBILE_BREAKPOINT = 880;
|
||||
var MOBILE_CONTAINER_HEIGHT = 260;
|
||||
var DESKTOP_STEP = 160;
|
||||
var DESKTOP_VIEW = 318;
|
||||
var DESKTOP_CARD = 250;
|
||||
|
||||
var stackScroll = document.getElementById('stackScroll');
|
||||
var spacer = document.getElementById('spacer');
|
||||
var layer = document.getElementById('layer');
|
||||
var prevBtn = document.getElementById('prevBtn');
|
||||
var nextBtn = document.getElementById('nextBtn');
|
||||
|
||||
var cardEls = [];
|
||||
var isMobile = window.matchMedia('(max-width: ' + MOBILE_BREAKPOINT + 'px)').matches;
|
||||
var containerWidth = 320;
|
||||
var scrollPos = 0;
|
||||
|
||||
function escapeHtml(str) {
|
||||
var div = document.createElement('div');
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function buildCards() {
|
||||
PROJECTS.forEach(function (proj) {
|
||||
var card = document.createElement('div');
|
||||
card.innerHTML =
|
||||
'<div class="stack-card-top">' +
|
||||
'<div class="avatar">' + escapeHtml(proj.initials) + '</div>' +
|
||||
'<div class="card-text">' +
|
||||
'<h3>' + escapeHtml(proj.name) + '</h3>' +
|
||||
'<p class="desc-clamp">' + escapeHtml(proj.desc) + '</p>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<a class="card-link" href="' + proj.link + '" target="_blank" rel="noopener noreferrer">LINK</a>';
|
||||
layer.appendChild(card);
|
||||
cardEls.push(card);
|
||||
});
|
||||
}
|
||||
|
||||
function getGeometry() {
|
||||
if (isMobile) {
|
||||
var cw = containerWidth;
|
||||
var peek = Math.max(16, Math.round(cw * 0.1));
|
||||
var cardSize = Math.round(Math.max(cw - peek * 2, 120));
|
||||
var step = Math.round(cardSize * 0.64);
|
||||
return { axisProp: 'left', sizeProp: 'width', crossSizeProp: 'height', peek: peek, cardSize: cardSize, step: step, viewSize: cw };
|
||||
}
|
||||
return { axisProp: 'top', sizeProp: 'height', crossSizeProp: 'width', peek: 34, cardSize: DESKTOP_CARD, step: DESKTOP_STEP, viewSize: DESKTOP_VIEW };
|
||||
}
|
||||
|
||||
function lerp(a, b, t) { return a + (b - a) * t; }
|
||||
var EPS = 1.05;
|
||||
|
||||
function render() {
|
||||
var g = getGeometry();
|
||||
var maxScroll = (COUNT - 1) * g.step;
|
||||
var clampedPos = Math.max(0, Math.min(scrollPos, maxScroll));
|
||||
var progress = clampedPos / g.step;
|
||||
|
||||
if (isMobile) {
|
||||
stackScroll.style.cssText = 'position:relative;height:' + MOBILE_CONTAINER_HEIGHT + 'px;width:100%;overflow-x:auto;overflow-y:hidden;min-width:0;-webkit-overflow-scrolling:touch;';
|
||||
spacer.style.cssText = 'position:relative;width:' + (g.viewSize + maxScroll) + 'px;height:100%;';
|
||||
layer.style.cssText = 'position:absolute;top:0;left:0;width:' + g.viewSize + 'px;height:100%;transform:translateX(' + clampedPos + 'px);';
|
||||
} else {
|
||||
stackScroll.style.cssText = 'position:relative;height:' + g.viewSize + 'px;flex:1 1 auto;min-width:0;overflow-y:auto;overflow-x:hidden;';
|
||||
spacer.style.cssText = 'position:relative;height:' + (g.viewSize + maxScroll) + 'px;width:100%;';
|
||||
layer.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:' + g.viewSize + 'px;transform:translateY(' + clampedPos + 'px);';
|
||||
}
|
||||
|
||||
for (var i = 0; i < COUNT; i++) {
|
||||
var delta = i - progress;
|
||||
var pos, scale, opacity;
|
||||
if (delta < -EPS || delta > EPS) {
|
||||
pos = g.peek; scale = PEEK_SCALE; opacity = 0;
|
||||
} else if (delta <= 0) {
|
||||
var t1 = Math.min(-delta, 1);
|
||||
pos = lerp(g.peek, 0, t1);
|
||||
scale = lerp(1, PEEK_SCALE, t1);
|
||||
opacity = lerp(1, 0.55, t1);
|
||||
} else {
|
||||
var t2 = Math.min(delta, 1);
|
||||
pos = lerp(g.peek, g.peek * 2, t2);
|
||||
scale = lerp(1, PEEK_SCALE, t2);
|
||||
opacity = lerp(1, 0.55, t2);
|
||||
}
|
||||
var zIndex = Math.round((1 - Math.min(Math.abs(delta), 1)) * 100);
|
||||
var pointerEvents = Math.abs(delta) < 0.05 ? 'auto' : 'none';
|
||||
var otherAxis = isMobile ? 'top:0;' : 'left:0;';
|
||||
var sizeStyle = g.sizeProp + ':' + g.cardSize + 'px; ' + g.crossSizeProp + ':100%;';
|
||||
|
||||
cardEls[i].style.cssText =
|
||||
'position:absolute; ' + g.axisProp + ':' + pos + 'px; ' + otherAxis + ' ' + sizeStyle +
|
||||
' z-index:' + zIndex + '; opacity:' + opacity + '; pointer-events:' + pointerEvents + '; transform: scale(' + scale + ');' +
|
||||
' padding:24px; background:var(--card-bg); border:1px solid var(--border); border-radius:16px; display:flex; flex-direction:column; justify-content:space-between; gap:14px; box-shadow:0 10px 24px rgba(0,0,0,0.12);';
|
||||
}
|
||||
|
||||
var activeIndex = Math.round(progress);
|
||||
prevBtn.setAttribute('data-disabled', activeIndex <= 0 ? 'true' : 'false');
|
||||
nextBtn.setAttribute('data-disabled', activeIndex >= COUNT - 1 ? 'true' : 'false');
|
||||
}
|
||||
|
||||
function getStep() {
|
||||
return getGeometry().step;
|
||||
}
|
||||
|
||||
function nextCard() {
|
||||
var step = getStep();
|
||||
var active = Math.round(scrollPos / step);
|
||||
var target = Math.min(active + 1, COUNT - 1) * step;
|
||||
if (isMobile) stackScroll.scrollTo({ left: target, behavior: 'smooth' });
|
||||
else stackScroll.scrollTo({ top: target, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function prevCard() {
|
||||
var step = getStep();
|
||||
var active = Math.round(scrollPos / step);
|
||||
var target = Math.max(active - 1, 0) * step;
|
||||
if (isMobile) stackScroll.scrollTo({ left: target, behavior: 'smooth' });
|
||||
else stackScroll.scrollTo({ top: target, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function measure() {
|
||||
var rect = stackScroll.getBoundingClientRect();
|
||||
if (rect.width > 0) containerWidth = rect.width;
|
||||
render();
|
||||
}
|
||||
|
||||
buildCards();
|
||||
measure();
|
||||
|
||||
prevBtn.addEventListener('click', prevCard);
|
||||
nextBtn.addEventListener('click', nextCard);
|
||||
|
||||
var scrollRafPending = false;
|
||||
var snapTimer = null;
|
||||
|
||||
function snapToNearest() {
|
||||
var step = getStep();
|
||||
var maxIndex = COUNT - 1;
|
||||
var nearest = Math.max(0, Math.min(Math.round(scrollPos / step), maxIndex));
|
||||
var target = nearest * step;
|
||||
if (Math.abs(scrollPos - target) > 1) {
|
||||
if (isMobile) stackScroll.scrollTo({ left: target, behavior: 'smooth' });
|
||||
else stackScroll.scrollTo({ top: target, behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
|
||||
stackScroll.addEventListener('scroll', function () {
|
||||
if (scrollRafPending) return;
|
||||
scrollRafPending = true;
|
||||
requestAnimationFrame(function () {
|
||||
scrollRafPending = false;
|
||||
scrollPos = isMobile ? stackScroll.scrollLeft : stackScroll.scrollTop;
|
||||
render();
|
||||
});
|
||||
|
||||
clearTimeout(snapTimer);
|
||||
snapTimer = setTimeout(snapToNearest, 130);
|
||||
});
|
||||
|
||||
var mq = window.matchMedia('(max-width: ' + MOBILE_BREAKPOINT + 'px)');
|
||||
function handleMqChange(e) {
|
||||
stackScroll.scrollTo({ top: 0, left: 0 });
|
||||
isMobile = e.matches;
|
||||
scrollPos = 0;
|
||||
measure();
|
||||
}
|
||||
if (mq.addEventListener) mq.addEventListener('change', handleMqChange);
|
||||
else if (mq.addListener) mq.addListener(handleMqChange);
|
||||
|
||||
window.addEventListener('resize', measure);
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
new ResizeObserver(measure).observe(stackScroll);
|
||||
}
|
||||
|
||||
var binary = (function (len) {
|
||||
var out = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
out += Math.random() < 0.5 ? '0' : '1';
|
||||
if (i % 4 === 3) out += ' ';
|
||||
}
|
||||
return out;
|
||||
})(80);
|
||||
document.getElementById('marquee').textContent = binary + ' ' + binary;
|
||||
|
||||
var eyeLeft = document.getElementById('eyeLeft');
|
||||
var eyeRight = document.getElementById('eyeRight');
|
||||
var pupilLeft = document.getElementById('pupilLeft');
|
||||
var pupilRight = document.getElementById('pupilRight');
|
||||
var MAX_OFFSET = 8;
|
||||
var rafPending = false;
|
||||
|
||||
function updatePupils(clientX, clientY) {
|
||||
[[eyeLeft, pupilLeft], [eyeRight, pupilRight]].forEach(function (pair) {
|
||||
var eye = pair[0], pupil = pair[1];
|
||||
var rect = eye.getBoundingClientRect();
|
||||
var cx = rect.left + rect.width / 2;
|
||||
var cy = rect.top + rect.height / 2;
|
||||
var angle = Math.atan2(clientY - cy, clientX - cx);
|
||||
pupil.style.transform = 'translate(' + (Math.cos(angle) * MAX_OFFSET) + 'px, ' + (Math.sin(angle) * MAX_OFFSET) + 'px)';
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('mousemove', function (e) {
|
||||
if (rafPending) return;
|
||||
rafPending = true;
|
||||
var clientX = e.clientX, clientY = e.clientY;
|
||||
requestAnimationFrame(function () {
|
||||
rafPending = false;
|
||||
updatePupils(clientX, clientY);
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
# Cloudflare Workers config for the portfolio site, served at ayushya.dev.
|
||||
# Deployed separately from the noo worker (see .gitea/workflows/deploy-portfolio.yml).
|
||||
name = "portfolio"
|
||||
compatibility_date = "2026-09-17"
|
||||
|
||||
# Serves this directory as static assets; non-site files (including
|
||||
# node_modules created by `npm install` during CI) are listed in
|
||||
# .assetsignore so they are not uploaded.
|
||||
[assets]
|
||||
directory = "."
|
||||
not_found_handling = "404-page"
|
||||
Reference in New Issue
Block a user