0% found this document useful (0 votes)
9 views11 pages

20 Searchbars with Slider Effects

This document is an HTML5 template for a web page featuring a smooth slider with 20 searchbars, customizable themes, and keyboard navigation. It includes detailed CSS styles for layout, responsiveness, and visual effects, such as animations and hover effects. The design is tailored for a modern user interface with a focus on aesthetics and usability.

Uploaded by

adeyemimalik207
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views11 pages

20 Searchbars with Slider Effects

This document is an HTML5 template for a web page featuring a smooth slider with 20 searchbars, customizable themes, and keyboard navigation. It includes detailed CSS styles for layout, responsiveness, and visual effects, such as animations and hover effects. The design is tailored for a modern user interface with a focus on aesthetics and usability.

Uploaded by

adeyemimalik207
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

<!DOCTYPE html> <!

-- HTML5 document type declaration -->


<html lang="tr"> <!-- Set document language to Turkish -->
<head> <!-- Document head starts -->
<meta charset="utf-8" /> <!-- Use UTF-8 character encoding -->
<meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- Make
layout responsive on mobile -->
<title>20× Searchbars — Smooth Slider, Per-Card Themes, Keyboard Nav</title> <!--
Browser tab title -->
<style> /* Begin embedded CSS */

:root{ /* Global design tokens on the root element */


--bg:#0b0f1a; /* Body background base color */
--bg-2:#0e1424; /* Secondary background gradient color */
--edge:#ffffff22; /* Generic border color with alpha */
--text:#eaf1ff; /* Base text color */
--muted:#9db1ce; /* Muted text color */
--r:18px; /* Generic border radius */
--shadow:0 14px 40px #0009; /* Soft drop shadow */
} /* End root tokens */

*{box-sizing:border-box} /* Include padding/border inside element width/height


*/
body{ /* Body layout and background */
margin:0; /* Remove default margin */
min-height:100svh; /* Ensure body fills the small viewport height */
overflow-x:hidden; /* Hide horizontal overflow */
font-family:Inter, system-ui, Segoe UI, Roboto, Arial, sans-serif; /* Font
stack */
color:var(--text); /* Set default text color */
background: /* Layered background for depth */
radial-gradient(1200px 600px at 10% -10%, #13203a66, transparent),
linear-gradient(180deg, var(--bg), #050811);
} /* End body */

.topbar{ /* Sticky header bar */


position:sticky; top:0; z-index:10; /* Pin to top and bring above content */
display:flex; align-items:center; justify-content:space-between; gap:12px; /*
Flex layout */
padding:16px clamp(14px,4vw,32px); /* Responsive padding */
background:#0b0f1a80; /* Translucent background */
border-bottom:1px solid var(--edge); /* Bottom divider */
backdrop-filter:blur(8px); /* Frosted glass effect */
} /* End topbar */
.brand{display:flex; align-items:center; gap:10px; font-weight:800} /* Logo +
title style */
.dot{ /* Animated color dot in brand */
width:12px; height:12px; border-radius:50%; /* Circle shape */
background:conic-gradient(from 120deg, #60e5ff, #a78bfa); /* Conic color
sweep */
box-shadow:0 0 0 4px #60e5ff1a, 0 0 22px #60e5ff80; /* Glow rings */
animation:pulse 2.2s ease-in-out infinite; /* Breathing animation */
} /* End dot */
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.25)}} /*
Breathing keyframes */

.controls{display:flex; gap:8px; align-items:center} /* Container for nav


buttons */
.ctrl{ /* Navigation button style */
width:44px; height:44px; border-radius:12px; /* Rounded square */
border:1px solid var(--edge); background:#0f1733; /* Button colors */
display:grid; place-items:center; cursor:pointer; /* Center icon and pointer
cursor */
transition:transform .2s, border-color .2s; /* Hover transitions */
} /* End ctrl */
.ctrl:hover{transform:translateY(-2px); border-color:#7dd3fc66} /* Lift and
highlight on hover */
.ctrl svg{width:18px; height:18px; fill:#bfe8ff} /* Icon size and color */

.shell{position:relative; z-index:1; padding:24px clamp(12px,4vw,32px) 40px} /*


Content wrapper with spacing */

.slider{ /* Horizontal slider rail */


position:relative; /* Needed for decorative line */
display:grid; grid-auto-flow:column; /* Flow cards in columns horizontally */
grid-auto-columns:clamp(280px, 42vw, 420px); /* Card width responsive clamp
*/
gap:16px; padding:16px; /* Space around cards */
border:1px solid var(--edge); border-radius:var(--r); /* Outer border and
radius */
background:linear-gradient(180deg, var(--bg-2), #0a1122); /* Slider
background */
box-shadow:var(--shadow); /* Depth shadow */
overflow-x:auto; scroll-snap-type:x mandatory; /* Snap scrolling per card */
scrollbar-width:none; /* Hide Firefox scrollbar */
mask-image:linear-gradient(to right, transparent 0, #000 40px, #000 calc(100%
- 40px), transparent 100%); /* Fade edges */
} /* End slider */
.slider::-webkit-scrollbar{display:none} /* Hide WebKit scrollbar */
.slider::before{ /* Decorative animated glow baseline */
content:""; position:absolute; left:10%; right:10%; bottom:0; height:1px; /*
Position and size */
background:linear-gradient(90deg, transparent, #7dd3fc, transparent); /*
Gradient line */
opacity:.25; transform-origin:left; animation:glowline 4s ease-in-out
infinite; /* Scale animation */
} /* End decorative line */
@keyframes glowline{0%{transform:scaleX(0)}50%{transform:scaleX(1)}100%
{transform:scaleX(0)}} /* Line animation keyframes */

.[Link]-hover .card{transition:transform .35s, filter .35s,


opacity .35s} /* Smooth sibling reaction when hovering a card */
.[Link]-hover .card:not(.is-hover){transform:scale(.9); filter:blur(1px);
opacity:.7} /* Shrink and blur non-hovered cards */

.card{ /* Individual card container */


/* Per-card theme CSS variables with sensible defaults */
--c-bg:#101a33cc; --c-edge:#ffffff24; --c-text:#eaf1ff; --c-muted:#9db1ce; --
c-accent:#60e5ff; --c-accent2:#a78bfa; /* Defaults */
scroll-snap-align:center; /* Snap this card to center when scrolling */
background:var(--c-bg); border:1px solid var(--c-edge); border-radius:var(--
r); /* Themed background/border/radius */
padding:14px; display:flex; flex-direction:column; gap:12px; /* Internal
layout spacing */
position:relative; isolation:isolate; /* Ensure pseudo elements stay inside
*/
color:var(--c-text); /* Inherit themed text color */
transition:transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s,
background .35s, border-color .35s; /* Hover transitions */
animation:pop .6s both; /* Entrance animation */
} /* End card */
.card:nth-child(odd){animation-delay:.06s} /* Stagger odd cards slightly */
.card:nth-child(3n){animation-delay:.1s} /* Stagger each third card */
@keyframes pop{from{transform:translateY(10px) scale(.98); opacity:0}
to{transform:none; opacity:1}} /* Pop-in animation */
.card::after{ /* Gradient border sheen on hover */
content:""; position:absolute; inset:-1px; padding:1px; border-
radius:inherit; /* Overlay border area */
background:linear-gradient(130deg, #ffffff12, transparent 30%, var(--c-
accent) 70%, var(--c-accent2)); /* Sheen gradient */
-webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0
0); /* Mask to edges only */
-webkit-mask-composite:xor; mask-composite:exclude; /* Exclude content area
*/
opacity:0; transition:opacity .35s; /* Fade in on hover */
} /* End sheen */
.card:hover{transform:translateY(-8px) scale(1.06); box-shadow:0 24px 60px
#000c; border-color:#ffffff2a; background:#0f1b35cc} /* Lift card on hover */
.card:hover::after{opacity:.6} /* Reveal sheen on hover */

.head{display:flex; align-items:center; gap:10px} /* Card header row */


.badge{ /* Small gradient badge icon */
width:28px; height:28px; border-radius:10px; display:grid; place-
items:center; /* Rounded square badge */
background:linear-gradient(180deg, color-mix(in oklab, var(--c-accent), #fff
18%), var(--c-accent)); /* Vertical gradient */
box-shadow:0 6px 18px color-mix(in oklab, var(--c-accent), #000 50%); /* Glow
shadow */
} /* End badge */
.badge svg{width:16px; height:16px; fill:#061018} /* Badge icon color and size
*/
.meta{opacity:.75; font-size:12px} /* Small metadata under title */

.themes{ /* Per-card theme switch (icon-only) */


position:absolute; right:8px; top:8px; z-index:2; /* Place at top-right of
the card */
display:flex; gap:6px; padding:6px; /* Compact spacing */
background:#0c1222a6; border:1px solid #ffffff25; border-radius:12px;
backdrop-filter:blur(6px); /* Frosted mini bar */
} /* End themes bar */
.tbtn{ /* Theme icon button */
width:26px; height:26px; border-radius:8px; border:1px solid #ffffff20; /*
Shape and border */
background:#0b1222; display:grid; place-items:center; cursor:pointer; /*
Center emoji and pointer */
color:#d8e8ff; font-size:14px; line-height:1; /* Emoji size */
transition:transform .2s, border-color .2s, background .2s; /* Hover and
active transitions */
} /* End theme button */
.tbtn:hover{transform:translateY(-1px); border-color:var(--c-accent)} /* Lift
and highlight on hover */
.tbtn[data-active="true"]{background:linear-gradient(180deg, color-mix(in
oklab, var(--c-accent), #fff 20%), var(--c-accent)); color:#0a0f18} /* Active state
*/

.sb{display:flex; align-items:center; gap:10px} /* Shared searchbar row */


.sb input{flex:1; min-width:0; outline:none} /* Make search input flexible */
.sb button{cursor:pointer} /* Pointer for buttons in searchbars */
/* Searchbar visual variants (kept concise; reused across 20 cards) */
.s1{padding:10px; background:#0d1a33cc; border:1px solid #ffffff22; border-
radius:999px; backdrop-filter:blur(10px)} /* Glass pill field */
.s1 .i{width:18px; height:18px; color:var(--c-muted)} /* Icon color in s1 */
.s1 .i svg{width:100%; height:100%; fill:currentColor} /* SVG inherits color */
.s1 input{background:transparent; border:0; color:var(--c-text)} /* Transparent
input text */
.s1 input::placeholder{color:var(--c-muted)} /* Placeholder muted color */
.s1 button{border:1px solid #2b445c; background:linear-gradient(180deg, color-
mix(in oklab, var(--c-accent), #fff 20%), var(--c-accent)); color:#0a1620; border-
radius:999px; padding:8px 14px; font-weight:700} /* Gradient button */

.s2{padding-top:4px} /* Minimal underline variant */


.s2 .i{width:20px; height:20px; color:var(--c-accent)} /* Accent icon color */
.s2 input{background:transparent; border:0; border-bottom:2px solid #ffffff26;
color:var(--c-text); padding:8px 2px 10px} /* Underline input */
.s2 input:focus{border-bottom-color:var(--c-accent)} /* Accent underline on
focus */

.s3{background:#0e1a2c; border:1px solid #ffffff22; border-radius:14px;


padding:8px 10px} /* Chip+Mic container */
.s3 .chip{width:34px; height:34px; border-radius:10px; display:grid; place-
items:center; background:linear-gradient(#0000,#0000) padding-box, conic-
gradient(from 120deg, var(--c-accent), var(--c-accent2)) border-box; border:2px
solid transparent} /* Gradient ring chip */
.s3 .chip svg{width:18px; height:18px; fill:#dff} /* Chip icon color */
.s3 input{background:transparent; border:0; color:var(--c-text)} /* Transparent
text input */
.s3 .mic{width:36px; height:36px; border-radius:10px; border:1px solid
#ffffff28; background:#0d1a28; display:grid; place-items:center} /* Mic button */
.s3 .mic svg{width:16px; height:16px; fill:var(--c-accent)} /* Mic icon color
*/

.s4{gap:10px} /* Card with GO button */


.s4 input{background:#0e111a; border:1px solid #ffffff22; border-radius:10px;
color:var(--c-text); padding:10px 12px} /* Boxed input */
.s4 .go{width:40px; height:40px; border-radius:10px; border:1px solid
#ffffff28; background:#0d0f18; display:grid; place-items:center} /* Square go
button */
.s4 .go svg{width:18px; height:18px; fill:var(--c-accent2)} /* Go arrow color
*/

.s5{background:#0e1228; border:1px solid #ffffff1f; border-radius:14px;


padding:8px} /* Compact navbar style */
.s5 .cat{display:flex; align-items:center; gap:8px; padding:8px 10px; border-
radius:10px; border:1px solid #ffffff1a; background:#0c1022} /* Category button */
.s5 .cat svg{width:16px; height:16px; fill:var(--c-accent2)} /* Category icon
*/
.s5 .sep{width:1px; height:20px; background:#ffffff1f} /* Vertical separator */
.s5 input{background:transparent; border:0; color:var(--c-text)} /* Transparent
input */
.s5 .submit{width:40px; height:40px; border-radius:10px; border:1px solid
#ffffff22; background:linear-gradient(180deg,#121633,#0d1028); display:grid; place-
items:center} /* Submit square */
.s5 .submit svg{width:18px; height:18px; fill:var(--c-accent)} /* Submit icon
color */

/* Per-card theme palettes (apply by data-theme) */


.card[data-theme="light"] {--c-bg:#172033cc; --c-edge:#ffffff28; --c-
text:#f8fbff; --c-muted:#cbd7e8; --c-accent:#ffd84d; --c-accent2:#ffb347} /* Light
palette */
.card[data-theme="dark"] {--c-bg:#0c0f1acc; --c-edge:#ffffff22; --c-
text:#eaf1ff; --c-muted:#9db1ce; --c-accent:#60e5ff; --c-accent2:#a78bfa} /* Dark
palette */
.card[data-theme="love"] {--c-bg:#1a0e16cc; --c-edge:#ffffff22; --c-
text:#fff1f8; --c-muted:#f3c4de; --c-accent:#ff6aa9; --c-accent2:#ff9ed1} /* Love
(pink) */
.card[data-theme="forest"]{--c-bg:#0c1512cc; --c-edge:#ffffff20; --c-
text:#eafff7; --c-muted:#a4dbc7; --c-accent:#41f5a5; --c-accent2:#27c79a} /* Forest
(green) */
.card[data-theme="mist"] {--c-bg:#0d1316cc; --c-edge:#ffffff22; --c-
text:#eef7fb; --c-muted:#b8c9d3; --c-accent:#7ad1e6; --c-accent2:#c1d7e6} /* Mist
(grey/teal) */
.card[data-theme="space"] {--c-bg:#0b0a18cc; --c-edge:#ffffff22; --c-text:#eef;
--c-muted:#b9b9e0; --c-accent:#8a7bff; --c-accent2:#3de0ff} /* Space (violet/blue)
*/
.card[data-theme="ocean"] {--c-bg:#0a1622cc; --c-edge:#ffffff22; --c-
text:#eaf6ff; --c-muted:#b5d4ea; --c-accent:#28d0ff; --c-accent2:#52f0ff} /* Ocean
(blue) */

</style> <!-- End CSS -->


</head> <!-- End head -->
<body> <!-- Document body starts -->

<header class="topbar"> <!-- Sticky header container -->


<div class="brand"> <!-- Brand container -->
<span class="dot"></span> <!-- Animated conic dot -->
20× Searchbars <!-- Title text -->
</div> <!-- End brand -->
<div class="controls"> <!-- Control buttons wrapper -->
<button class="ctrl" id="prev" title="Previous"> <!-- Previous slide button
-->
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15.41 7.41 14 6 8.59
11 14 16 15.41 14.59 11.83 11z"/></svg> <!-- Left arrow icon -->
</button> <!-- End previous button -->
<button class="ctrl" id="next" title="Next"> <!-- Next slide button -->
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8.59 16.59 10
18l5.41-5L10 8.59 8.59 10l4.58 4z"/></svg> <!-- Right arrow icon -->
</button> <!-- End next button -->
<button class="ctrl" id="play" title="Autoplay / Pause"> <!-- Autoplay toggle
button -->
<svg id="playIcon" viewBox="0 0 24 24" aria-hidden="true"><path d="M8
5v14l11-7z"/></svg> <!-- Play icon (triangle) -->
</button> <!-- End autoplay button -->
</div> <!-- End controls -->
</header> <!-- End header -->

<main class="shell"> <!-- Main content wrapper -->


<section class="slider" id="slider" aria-label="Searchbar Slider"> <!--
Horizontal slider rail -->
<!-- Cards will be injected by JavaScript for compactness and reusability -->
<!-- JS will populate 20 cards -->
</section> <!-- End slider -->
<br>
</main> <!-- End main -->

<script> // Begin JavaScript


// ---------- Utility: create an element with classes and optional HTML
----------
const el = (tag, cls = "", html = "") => { /* Helper function to create
elements quickly */
const node = [Link](tag); /* Create the DOM element */
if(cls) [Link] = cls; /* Assign class list if provided */
if(html) [Link] = html; /* Set inner HTML if provided */
return node; /* Return the element */
}; /* End helper */

// ---------- Data: 20 cards configuration (title, meta, variant, placeholder,


initial theme) ----------
const CARDS = [ /* Array describing each card */
{t:"Glass Pill", m:"Ocean glow", v:"s1", p:"Search anything…", theme:"dark"},
/* Card #1 config */
{t:"Underline Minimal", m:"Focus spark", v:"s2", p:"Quick search…",
theme:"light"}, /* Card #2 config */
{t:"Chip + Mic", m:"Gradient ring", v:"s3", p:"Search docs, issues…",
theme:"love"}, /* Card #3 config */
{t:"Card Header", m:"Go arrow", v:"s4", p:"Discover datasets…",
theme:"forest"}, /* Card #4 config */
{t:"Compact Navbar", m:"Categories + search", v:"s5", p:"Search products…",
theme:"mist"}, /* Card #5 config */
{t:"Outline Dashed", m:"CTA split", v:"s4", p:"Find tutorials…",
theme:"space"}, /* Card #6 config (reuse s4) */
{t:"Soft Rounded", m:"Pill focus", v:"s1", p:"Search settings…",
theme:"ocean"}, /* Card #7 config (reuse s1) */
{t:"Focus Ring", m:"Elevated", v:"s4", p:"Search tasks…", theme:"dark"}, /*
Card #8 config */
{t:"Split Button", m:"Dashboard UX", v:"s5", p:"Search analytics…",
theme:"forest"}, /* Card #9 config */
{t:"Tags + Hint", m:"Assistive", v:"s1", p:"Type to filter…",
theme:"mist"}, /* Card #10 config */
{t:"Keyword Finder", m:"chips", v:"s1", p:"Filter keywords…", theme:"light"},
/* Card #11 config */
{t:"Run Query", m:"play", v:"s5", p:"Search jobs…", theme:"space"}, /* Card
#12 config */
{t:"Tickets", m:"search tasks", v:"s4", p:"Find tickets by id…",
theme:"ocean"}, /* Card #13 config */
{t:"Commands", m:"palette", v:"s3", p:"Run command…", theme:"love"}, /* Card
#14 config */
{t:"Datasets", m:"find", v:"s1", p:"Search datasets…", theme:"forest"}, /*
Card #15 config */
{t:"Quick Jump", m:"smart", v:"s2", p:"Go to page…", theme:"space"}, /* Card
#16 config */
{t:"Dash Search", m:"split-btn", v:"s5", p:"Search dashboards…",
theme:"ocean"}, /* Card #17 config */
{t:"Settings", m:"rounded", v:"s1", p:"Search settings…", theme:"love"}, /*
Card #18 config */
{t:"Catalog", m:"input+btn", v:"s4", p:"Search catalog…", theme:"mist"}, /*
Card #19 config */
{t:"Snippets", m:"chips", v:"s1", p:"Filter snippets…", theme:"light"}, /*
Card #20 config */
]; /* End card data */

// ---------- Icons (inline SVG paths) ----------


const ICONS = { /* Small reusable SVG snippets */
search:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15.5
14h-.79l-.28-.27a6.5 6.5 0 1 0-1.41 1.41l.27.28v.79L20 21l1-1-5.5-5z"/></svg>', /*
Magnifier icon */
star:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2l2 6 6 2-6 2-
2 6-2-6-6-2 6-2 2-6z"/></svg>', /* Starburst icon */
doc:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 4h16v4H4zm0
6h10v10H4z"/></svg>', /* Page icon */
go:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4l1.41 1.41L8.83
10H20v2H8.83l4.58 4.59L12 18l-8-8z"/></svg>', /* Arrow right icon */
play:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8
5v14l11-7z"/></svg>', /* Play triangle icon */
pause:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 5h4v14H6zm8
0h4v14h-4z"/></svg>', /* Pause bars icon */
}; /* End icon map */

// ---------- Build one searchbar DOM for a given variant ----------


function buildSearchbar(variant, placeholder){ /* Create the specific searchbar
UI */
if(variant === 's1'){ /* Glass pill variant path */
const label = el('label', 'sb s1'); /* Create label wrapper with classes */
[Link](el('span', 'i', [Link])); /* Add leading search icon */
const input = el('input'); [Link] = 'search'; [Link] =
placeholder; /* Make input type=search and set placeholder */
[Link](input); /* Append input into label */
const btn = el('button', '', 'Search'); /* Create Search button */
[Link](btn); /* Append button */
return label; /* Return the assembled searchbar */
} /* End s1 */

if(variant === 's2'){ /* Minimal underline variant path */


const label = el('label', 'sb s2'); /* Create label wrapper */
[Link](el('span', 'i', [Link])); /* Add spark icon */
const input = el('input'); [Link]='search';
[Link]=placeholder; /* Configure input */
[Link](input); /* Place input */
return label; /* Return the label */
} /* End s2 */

if(variant === 's3'){ /* Chip + Mic variant path */


const wrap = el('div', 'sb s3'); /* Create container div */
[Link](el('span', 'chip', [Link])); /* Add gradient ring chip with
doc icon */
const input = el('input'); [Link]='search';
[Link]=placeholder; /* Configure input */
[Link](input); /* Append input */
const mic = el('button', 'mic', [Link]); /* Use play triangle as mic
placeholder icon */
[Link](mic); /* Append mic button */
return wrap; /* Return composite */
} /* End s3 */

if(variant === 's4'){ /* Boxed input + Go button variant */


const form = el('form', 'sb s4'); [Link] =
(e)=>[Link](); /* Prevent default submit */
const input = el('input'); [Link]='search';
[Link]=placeholder; /* Configure input */
[Link](input); /* Add input into form */
const go = el('button', 'go', [Link]); /* Create Go button with arrow
icon */
[Link](go); /* Append button */
return form; /* Return form */
} /* End s4 */

if(variant === 's5'){ /* Compact navbar + split button variant */


const bar = el('div', 'sb s5'); /* Create bar container */
const cat = el('button', 'cat', '<svg viewBox="0 0 24 24" aria-
hidden="true"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h10v2H4z"/></svg>'); /* Category
button with menu icon */
[Link](cat); /* Append category button */
[Link](el('span','sep')); /* Vertical separator between category and
input */
const input = el('input'); [Link]='search';
[Link]=placeholder; /* Configure input */
[Link](input); /* Append input */
const sub = el('button','submit', [Link]); /* Create submit button
with magnifier icon */
[Link](sub); /* Append submit button */
return bar; /* Return bar */
} /* End s5 */

return el('div','sb', ''); /* Fallback empty bar if unknown variant */


} /* End buildSearchbar */

// ---------- Build one card DOM ----------


function buildCard(cfg){ /* Compose a card using cfg object */
const card = el('article', 'card'); /* Create card element */
[Link]('data-theme', [Link]); /* Apply initial per-card theme
*/
const themes = el('div','themes'); /* Create theme switcher strip */
// Add icon-only theme buttons (emoji as simple iconography)
const THEME_KEYS =
['light','dark','love','forest','mist','space','ocean']; /* Supported theme keys */
const THEME_EMOJI = {light:'☀️', dark:'', love:'💖', forest:'🌲', mist:'🌫️
',
space:'🪐', ocean:'🌊'}; /* Emoji map */
THEME_KEYS.forEach(k=>{ /* Loop through themes to add buttons */
const b = el('button','tbtn', THEME_EMOJI[k]); /* Create theme button with
emoji */
[Link]='button'; [Link] = k[0].toUpperCase()+[Link](1); /* Set button
type and tooltip */
[Link] = k; /* Store theme key on data attribute */
if(k===[Link]) [Link] = 'true'; /* Mark current theme as
active */
[Link](b); /* Append theme button into strip */
}); /* End theme buttons loop */
[Link](themes); /* Attach theme strip to card */

const head = el('div','head'); /* Create card header row */


[Link](el('span','badge', [Link])); /* Add small gradient badge
with icon */
[Link](el('div','', `<strong>${cfg.t}</strong><div class="meta">$
{cfg.m}</div>`)); /* Add title and meta */
[Link](head); /* Attach header to card */

const sb = buildSearchbar(cfg.v, cfg.p); /* Build the chosen searchbar


variant */
[Link](sb); /* Append searchbar to card */
return card; /* Return complete card element */
} /* End buildCard */
// ---------- Populate slider with 20 cards ----------
const slider = [Link]('slider'); /* Reference to the slider
rail */
[Link](cfg => [Link](buildCard(cfg))); /* Create and insert each
configured card */

// ---------- Per-card theme switching (only affect that card) ----------


[Link]('click', (e)=>{ /* Delegate click events within the
slider */
const btn = [Link]('.tbtn'); /* Find the nearest theme button */
if(!btn) return; /* Exit if click is not on a theme button */
const card = [Link]('.card'); /* Find the owning card */
const theme = [Link]; /* Read requested theme key */
[Link]('data-theme', theme); /* Apply theme to this card only */
[Link]('.tbtn').forEach(b=>[Link]('data-
active')); /* Clear previous active state */
[Link] = 'true'; /* Mark clicked theme as active */
}); /* End theme switch handler */

// ---------- Hover focus: enlarge hovered card, shrink siblings + trigger


burst ----------
[Link]('mouseover', (e)=>{ /* When pointer enters inside
slider */
const card = [Link]('.card'); /* Find hovered card if any */
if(!card) return; /* Ignore if not over a card */
[Link]('has-hover'); /* Enable sibling reaction mode */
[Link]('.card').forEach(c=>[Link]('is-hover',
c===card)); /* Mark only hovered card */
burst(card); /* Trigger particle burst on this card */
}); /* End mouseover */
[Link]('mouseout', (e)=>{ /* When pointer leaves slider area
*/
if(![Link] || ![Link]([Link])){ /* Check pointer
truly left the slider */
[Link]('has-hover'); /* Disable sibling reaction mode */
[Link]('.card').forEach(c=>[Link]('is-
hover')); /* Clear hover flag */
} /* End contains check */
}); /* End mouseout */

// ---------- Autoplay: smooth infinite scroll using requestAnimationFrame


----------
const playBtn = [Link]('play'); /* Get autoplay toggle button
*/
const playIcon = [Link]('playIcon'); /* Get SVG icon inside
button */
let playing = true; /* Track autoplay state (default on) */
let rafId = null; /* Store RAF id to cancel later */
let last = 0; /* Keep last frame timestamp for delta time */
function loop(ts){ /* Animation loop callback (ts = high-res timestamp) */
if(!playing){rafId=null; return;} /* Stop loop if not playing */
if(!last) last = ts; /* Initialize last timestamp */
const dt = ts - last; last = ts; /* Compute delta time */
const cycle = ([Link]()/1000) % 6; /* 6s breathing cycle */
const ease = 0.6 + 0.4*[Link](cycle*[Link]*2); /* Eased speed factor */
const dx = dt * (0.22) * (1+ease); /* Pixels to scroll this frame */
const max = [Link] - [Link]; /* Max scroll offset */
const nextX = [Link] + dx; /* Compute next scroll position */
[Link] = nextX >= max ? 0 : nextX; /* Wrap back to start at end */
rafId = requestAnimationFrame(loop); /* Request next frame */
} /* End loop */
function setPlaying(v){ /* Toggle autoplay on/off */
playing = v; /* Update flag */
if(playing){ /* If playing is enabled */
[Link] = [Link]('<svg','<svg'); /* Show pause icon
*/
if(!rafId) rafId = requestAnimationFrame(loop); /* Start RAF loop if not
already */
}else{ /* If playing is disabled */
[Link] = [Link]('<svg','<svg'); /* Show play icon
*/
if(rafId){cancelAnimationFrame(rafId); rafId=null;} /* Stop RAF loop */
} /* End condition */
} /* End setPlaying */
[Link]('click', ()=> setPlaying(!playing)); /* Click to
toggle autoplay */
['mousedown','touchstart','wheel','keydown'].forEach(ev =>
[Link](ev, ()=> setPlaying(false), {passive:true})); /* Pause on
user interaction */
setPlaying(true); /* Start autoplay initially */

// ---------- Keyboard navigation: ArrowLeft/ArrowRight and A/D ----------


const step = ()=> [Link] * 0.85; /* Compute one navigation step
based on viewport */
const goLeft = ()=> [Link]({left:-step(), behavior:'smooth'}); /*
Smoothly scroll left by one step */
const goRight = ()=> [Link]({left: step(), behavior:'smooth'}); /*
Smoothly scroll right by one step */
[Link]('prev').addEventListener('click', goLeft); /* Bind
previous button to goLeft */
[Link]('next').addEventListener('click', goRight); /* Bind
next button to goRight */
[Link]('keydown', (e)=>{ /* Listen for global key presses */
const tag = [Link]?.tagName || ""; /* Get currently focused
tag name */
if(/INPUT|TEXTAREA/.test(tag)) return; /* Do not intercept when typing in
inputs/areas */
if([Link] === 'ArrowLeft' || [Link]() === 'a'){ /* Check for left
arrow or 'a' */
[Link](); setPlaying(false); goLeft(); /* Stop autoplay and move
left */
} /* End left keys */
if([Link] === 'ArrowRight' || [Link]() === 'd'){ /* Check for right
arrow or 'd' */
[Link](); setPlaying(false); goRight(); /* Stop autoplay and move
right */
} /* End right keys */
}); /* End keyboard handler */

// ---------- “/” shortcut: focus first visible search input ----------


[Link]('keydown', (e)=>{ /* Listen for slash key */
if([Link] === '/' && !/INPUT|TEXTAREA/.test([Link]))
{ /* When not currently typing */
[Link](); /* Prevent browser quick find */
const cards = [Link]([Link]('.card')); /* Collect all
cards */
const vw = innerWidth; /* Get viewport width */
const target = [Link](c=>{const r=[Link](); return
[Link]<vw && [Link]>0;}); /* Find first visible card */
target?.querySelector('input[type="search"]')?.focus(); /* Focus its search
input if available */
} /* End slash check */
}); /* End slash shortcut */

// ---------- Burst particles: create quick sparkles on hovered card ----------


function burst(card){ /* Create radial sparkles relative to a card */
const r = [Link](); /* Measure card screen rectangle */
const cx = [Link] + [Link]/2; /* Compute center X */
const cy = [Link] + [Link]/3; /* Compute slightly upper center Y */
const styles = getComputedStyle(card); /* Read computed styles for theme
colors */
const c1 = [Link]('--c-accent').trim() || '#60e5ff'; /*
Primary accent color */
const c2 = [Link]('--c-accent2').trim() || '#a78bfa'; /*
Secondary accent color */
const count = 12; /* Number of particles to emit */
for(let i=0;i<count;i++){ /* Loop to create each particle */
const p = [Link]('span'); /* Create particle element */
[Link]='fixed'; [Link] = cx+'px'; [Link] = cy+'px'; /*
Position particle at origin */
[Link] = [Link] = (3+[Link]()*5)+'px'; /* Random
particle size */
[Link]='50%'; /* Make particle circular */
const col = i%2 ? c1 : c2; /* Alternate between two theme colors */
[Link] = col; /* Fill with color */
[Link] = `0 0 10px ${col}88`; /* Soft glow shadow */
[Link]='none'; [Link]=30; /* Prevent interaction and
bring above UI */
[Link]='translate(-50%,-50%)'; /* Center transform origin */
[Link](p); /* Add particle to the document */
const ang = ([Link]*2)*(i/count) + ([Link]()*0.6-0.3); /* Spread
angle with jitter */
const dist = 18 + [Link]()*36; /* Random travel distance */
const tx = [Link](ang)*dist; const ty = [Link](ang)*dist; /* Compute
travel offset */
[Link]([ /* Animate particle movement and fade */
{transform:'translate(-50%,-50%) translate(0,0) scale(1)', opacity:1}, /*
Start at origin fully visible */
{transform:`translate(-50%,-50%) translate(${tx}px,${ty}px) scale(0.6)`,
opacity:0} /* Move out and fade */
], {duration:600+[Link]()*400, easing:'cubic-
bezier(.2,.8,.2,1)'}).onfinish = ()=> [Link](); /* Remove at end */
} /* End loop */
} /* End burst */

</script> <!-- End JavaScript -->


</body> <!-- End body -->
</html> <!-- End HTML document -->

You might also like