Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions static/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,20 @@ if (isIndexPage) {
var visibleSuggestions = [];
var activeSuggestionIndex = -1;

function initSkillStripMarquee() {
var marquee = document.querySelector(".skill-strip-marquee");
var track = marquee && marquee.querySelector(".skill-strip-track");

if (!marquee || !track || track.querySelector(".skill-strip-items[data-marquee-clone='true']")) {
return;
}

var clone = track.querySelector(".skill-strip-items").cloneNode(true);
clone.setAttribute("aria-hidden", "true");
clone.setAttribute("data-marquee-clone", "true");
track.appendChild(clone);
}

availableSkills = availableSkills.filter(function (skill, index, list) {
return typeof skill === "string" && skill.trim() &&
list.findIndex(function (item) {
Expand All @@ -106,6 +120,8 @@ if (isIndexPage) {
suggestionsDiv.setAttribute("role", "listbox");
}

initSkillStripMarquee();

function normalizeSkill(skill) {
return skill.trim().toLowerCase();
}
Expand Down
168 changes: 152 additions & 16 deletions static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -586,46 +586,182 @@ ul, ol { list-style: none; }

/* ---- Skill Strip ------------------------------------------ */
.skill-strip {
background: var(--gray-50);
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
position: relative;
overflow: hidden;
background:
radial-gradient(circle at top left, rgba(79, 110, 247, 0.12), transparent 34%),
radial-gradient(circle at bottom right, rgba(91, 33, 182, 0.08), transparent 30%),
linear-gradient(180deg, var(--gray-50), var(--indigo-50));
border-top: 1px solid rgba(35, 53, 194, 0.08);
border-bottom: 1px solid rgba(35, 53, 194, 0.08);
padding: 18px 32px;
}
.skill-strip::before,
.skill-strip::after {
content: "";
position: absolute;
inset: auto;
width: 180px;
height: 180px;
border-radius: 50%;
pointer-events: none;
filter: blur(24px);
opacity: 0.18;
}
.skill-strip::before {
top: -90px;
left: -40px;
background: rgba(79, 110, 247, 0.4);
}
.skill-strip::after {
bottom: -110px;
right: -30px;
background: rgba(236, 72, 153, 0.28);
}
.skill-strip-inner {
max-width: 1140px;
margin: 0 auto;
display: flex;
align-items: center;
gap: 20px;
flex-wrap: wrap;
gap: 18px;
padding: 16px 22px;
background: rgba(255, 255, 255, 0.72);
border: 1px solid rgba(79, 110, 247, 0.12);
border-radius: var(--r-xl);
box-shadow: var(--shadow-sm);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.skill-strip-label {
font-size: 0.8rem;
font-weight: 600;
color: var(--gray-500);
letter-spacing: 0.04em;
flex-shrink: 0;
font-size: 0.74rem;
font-weight: 700;
color: var(--indigo-700);
letter-spacing: 0.12em;
text-transform: uppercase;
white-space: nowrap;
}
.skill-strip-marquee {
flex: 1;
min-width: 0;
overflow: hidden;
mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
-webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.skill-strip-marquee:hover .skill-strip-track {
animation-play-state: paused;
}
.skill-strip-track {
display: flex;
align-items: center;
width: max-content;
gap: 18px;
animation: skill-strip-marquee 30s linear infinite;
will-change: transform;
}
.skill-strip-items {
display: flex;
align-items: center;
flex-wrap: wrap;
flex-wrap: nowrap;
gap: 0;
white-space: nowrap;
}
.ss-item {
font-size: 0.88rem;
font-weight: 600;
display: inline-flex;
align-items: center;
min-height: 34px;
font-size: 0.84rem;
font-weight: 700;
color: var(--gray-700);
padding: 0 16px;
background: rgba(255, 255, 255, 0.92);
border: 1px solid rgba(79, 110, 247, 0.14);
border-radius: var(--r-full);
padding: 6px 14px;
box-shadow: 0 1px 2px rgba(15, 21, 96, 0.04);
transition:
transform 180ms ease,
background 180ms ease,
color 180ms ease,
border-color 180ms ease,
box-shadow 180ms ease;
}
.ss-item:hover {
transform: translateY(-1px);
color: var(--indigo-700);
background: var(--white);
border-color: rgba(79, 110, 247, 0.28);
box-shadow: 0 8px 20px rgba(15, 21, 96, 0.08);
}
.ss-sep {
width: 1px;
height: 16px;
background: var(--gray-300);
width: 6px;
height: 6px;
margin: 0 10px;
background: rgba(79, 110, 247, 0.3);
border-radius: 50%;
flex-shrink: 0;
}

@keyframes skill-strip-marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
.skill-strip-track {
animation: none;
width: 100%;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
}

.skill-strip-items + .skill-strip-items {
display: none;
}

.skill-strip-marquee {
overflow: visible;
mask-image: none;
-webkit-mask-image: none;
}
}

@media (max-width: 768px) {
.skill-strip {
padding: 14px 16px;
}

.skill-strip-inner {
padding: 14px 16px;
flex-direction: column;
align-items: flex-start;
}

.skill-strip-label {
white-space: normal;
}

.skill-strip-marquee {
width: 100%;
}
}

@media (max-width: 480px) {
.skill-strip-inner {
border-radius: var(--r-lg);
}

.skill-strip-track {
gap: 14px;
animation-duration: 36s;
}

.ss-item {
font-size: 0.8rem;
padding: 5px 12px;
}
}

/* ---- How It Works ----------------------------------------- */
.how-section {
padding: 96px 0;
Expand Down
64 changes: 34 additions & 30 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -178,50 +178,54 @@ <h1 class="hero-heading">
<div class="skill-strip">
<div class="skill-strip-inner">
<span class="skill-strip-label">Supports skills including:</span>
<div class="skill-strip-items">
<span class="ss-item">Python</span>
<span class="ss-sep"></span>
<div class="skill-strip-marquee" aria-label="Supported skills">
<div class="skill-strip-track">
<div class="skill-strip-items">
<span class="ss-item">Python</span>
<span class="ss-sep"></span>

<span class="ss-item">JavaScript</span>
<span class="ss-sep"></span>
<span class="ss-item">JavaScript</span>
<span class="ss-sep"></span>

<span class="ss-item">HTML / CSS</span>
<span class="ss-sep"></span>
<span class="ss-item">HTML / CSS</span>
<span class="ss-sep"></span>

<span class="ss-item">Flask</span>
<span class="ss-sep"></span>
<span class="ss-item">Flask</span>
<span class="ss-sep"></span>

<span class="ss-item">SQL</span>
<span class="ss-sep"></span>
<span class="ss-item">SQL</span>
<span class="ss-sep"></span>

<span class="ss-item">React</span>
<span class="ss-sep"></span>
<span class="ss-item">React</span>
<span class="ss-sep"></span>

<span class="ss-item">Node.js</span>
<span class="ss-sep"></span>
<span class="ss-item">Node.js</span>
<span class="ss-sep"></span>

<span class="ss-item">pandas</span>
<span class="ss-sep"></span>
<span class="ss-item">pandas</span>
<span class="ss-sep"></span>

<span class="ss-item">C++</span>
<span class="ss-sep"></span>
<span class="ss-item">C++</span>
<span class="ss-sep"></span>

<span class="ss-item">Java</span>
<span class="ss-sep"></span>
<span class="ss-item">Java</span>
<span class="ss-sep"></span>

<span class="ss-item">TypeScript</span>
<span class="ss-sep"></span>
<span class="ss-item">TypeScript</span>
<span class="ss-sep"></span>

<span class="ss-item">Go</span>
<span class="ss-sep"></span>
<span class="ss-item">Go</span>
<span class="ss-sep"></span>

<span class="ss-item">Rust</span>
<span class="ss-sep"></span>
<span class="ss-item">Rust</span>
<span class="ss-sep"></span>

<span class="ss-item">C#</span>
<span class="ss-sep"></span>
<span class="ss-item">C#</span>
<span class="ss-sep"></span>

<span class="ss-item">Kotlin</span>
<span class="ss-item">Kotlin</span>
</div>
</div>
</div>
</div>
</div>
Expand Down
Loading