mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-13 07:40:06 +00:00
This reverts commit 3b53bfd2f7.
This commit is contained in:
@@ -1,148 +0,0 @@
|
||||
<!--
|
||||
Tabs Slide Indicator - transitions.dev-inspired primitive for HyperFrames.
|
||||
|
||||
Paste the markup, CSS and script into a composition. Use the timeline
|
||||
integration note at the bottom as the starting point for deterministic GSAP
|
||||
animation.
|
||||
|
||||
Variables. The script reads each one, falls back to the declared default on
|
||||
anything missing or unrecognised, and writes the result as a custom property
|
||||
the CSS below consumes. The timeline recipe at the bottom is untouched by
|
||||
them: it keeps sliding the pill one tab to the right, and these decide how
|
||||
wide that tab is, what the pill looks like and what the tabs say.
|
||||
|
||||
- accent (ink | green | blue | violet, default ink): fill of the sliding
|
||||
pill. ink is a literal near-black; the other three ride the composition's
|
||||
own brand, accent and accent-2 tokens and fall back to that same ink when
|
||||
the composition declares none. The labels sitting on it stay white, so all
|
||||
four keep the active tab readable.
|
||||
- width (compact | standard | wide, default standard): width of one tab,
|
||||
72px, 86px or 104px. The slide the timeline drives is scaled by the same
|
||||
ratio, so the pill still lands exactly on the next tab rather than
|
||||
stopping short or overshooting it.
|
||||
- shape (pill | rounded | square, default pill): corner radius of the track
|
||||
and the pill, 999px, 12px or 4px.
|
||||
- labels (text, default "Plan,Debug,Ask"): the tab names, separated by
|
||||
commas. Two or more names rebuild the row, one name or none leaves the
|
||||
authored markup alone, since a single tab has nowhere to slide to.
|
||||
|
||||
On every default the result is identical to the original: three 86px tabs in
|
||||
a light pill track, a near-black pill sliding from the first to the second.
|
||||
-->
|
||||
|
||||
<div
|
||||
class="hf-transition-tabs-slide-indicator"
|
||||
data-composition-variables='[
|
||||
{ "id": "accent", "type": "enum", "role": "style", "label": "Accent", "description": "Fill of the sliding pill. ink is literal; the rest ride the composition theme tokens.", "default": "ink", "options": [{ "value": "ink", "label": "Ink" }, { "value": "green", "label": "Green" }, { "value": "blue", "label": "Blue" }, { "value": "violet", "label": "Violet" }] },
|
||||
{ "id": "width", "type": "enum", "role": "layout", "label": "Tab width", "description": "Width of one tab. The slide the timeline drives is scaled to match, so the pill still lands on the next tab.", "default": "standard", "options": [{ "value": "compact", "label": "Compact" }, { "value": "standard", "label": "Standard" }, { "value": "wide", "label": "Wide" }] },
|
||||
{ "id": "shape", "type": "enum", "role": "style", "label": "Shape", "description": "Corner radius of the track and the pill.", "default": "pill", "options": [{ "value": "pill", "label": "Pill" }, { "value": "rounded", "label": "Rounded" }, { "value": "square", "label": "Square" }] },
|
||||
{ "id": "labels", "type": "string", "role": "content", "label": "Labels", "description": "The tab names, separated by commas. Two or more names rebuild the row.", "default": "Plan,Debug,Ask" }
|
||||
]'
|
||||
>
|
||||
<span class="indicator"></span><button>Plan</button><button>Debug</button><button>Ask</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hf-transition-tabs-slide-indicator {
|
||||
--hf-tab-x: 0px;
|
||||
position: relative;
|
||||
display: inline-grid;
|
||||
grid-template-columns: repeat(var(--hf-tab-count, 3), var(--hf-tab-width, 86px));
|
||||
padding: 4px;
|
||||
border: 1px solid #e4e4e7;
|
||||
border-radius: var(--hf-tab-radius, 999px);
|
||||
background: #f4f4f5;
|
||||
font-family: Inter, system-ui, sans-serif;
|
||||
}
|
||||
.hf-transition-tabs-slide-indicator .indicator {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
width: var(--hf-tab-width, 86px);
|
||||
height: 36px;
|
||||
border-radius: var(--hf-tab-radius, 999px);
|
||||
background: var(--hf-tab-fill, #18181b);
|
||||
transform: translateX(calc(var(--hf-tab-x) * var(--hf-tab-step, 1)));
|
||||
box-shadow: 0 12px 26px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
.hf-transition-tabs-slide-indicator button {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 36px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #71717a;
|
||||
font-weight: 850;
|
||||
}
|
||||
.hf-transition-tabs-slide-indicator button:nth-of-type(2) {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var vars =
|
||||
window.__hyperframes && window.__hyperframes.getVariables
|
||||
? window.__hyperframes.getVariables()
|
||||
: {};
|
||||
|
||||
// Unrecognised overrides return to their declared defaults.
|
||||
// The pill is the one accent-carrying element here, so the three chromatic
|
||||
// options ride the composition's own tokens and fall back to ink.
|
||||
var accents = {
|
||||
ink: "#18181b",
|
||||
green: "var(--brand, #18181b)",
|
||||
blue: "var(--accent, #18181b)",
|
||||
violet: "var(--accent-2, #18181b)",
|
||||
};
|
||||
var widths = { compact: 72, standard: 86, wide: 104 };
|
||||
var shapes = { pill: "999px", rounded: "12px", square: "4px" };
|
||||
|
||||
function pick(table, value, fallback) {
|
||||
return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
|
||||
}
|
||||
|
||||
var accent = accents[pick(accents, vars.accent, "ink")];
|
||||
var width = widths[pick(widths, vars.width, "standard")];
|
||||
var radius = shapes[pick(shapes, vars.shape, "pill")];
|
||||
var labels =
|
||||
typeof vars.labels === "string"
|
||||
? vars.labels.split(",").map(function (part) {
|
||||
return part.trim();
|
||||
})
|
||||
: [];
|
||||
labels = labels.filter(function (part) {
|
||||
return part.length > 0;
|
||||
});
|
||||
|
||||
var roots = document.querySelectorAll(".hf-transition-tabs-slide-indicator");
|
||||
for (var i = 0; i < roots.length; i += 1) {
|
||||
roots[i].style.setProperty("--hf-tab-fill", accent);
|
||||
roots[i].style.setProperty("--hf-tab-width", width + "px");
|
||||
// The timeline slides the pill by one standard tab, so scale that slide
|
||||
// to whatever a tab is actually worth here.
|
||||
roots[i].style.setProperty("--hf-tab-step", String(width / 86));
|
||||
roots[i].style.setProperty("--hf-tab-radius", radius);
|
||||
// A single tab has nowhere to slide to, so it is left as authored.
|
||||
if (labels.length > 1) {
|
||||
var old = roots[i].querySelectorAll("button");
|
||||
for (var j = 0; j < old.length; j += 1) {
|
||||
old[j].parentNode.removeChild(old[j]);
|
||||
}
|
||||
for (var k = 0; k < labels.length; k += 1) {
|
||||
var button = document.createElement("button");
|
||||
button.textContent = labels[k];
|
||||
roots[i].appendChild(button);
|
||||
}
|
||||
roots[i].style.setProperty("--hf-tab-count", String(labels.length));
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!--
|
||||
Timeline integration:
|
||||
tl.fromTo('.hf-transition-tabs-slide-indicator .indicator', { '--hf-tab-x': '0px' }, { '--hf-tab-x': '86px', duration: 0.42, ease: 'power3.inOut' }, startTime);
|
||||
-->
|
||||
Reference in New Issue
Block a user