Added animation to content tabs

This commit is contained in:
squidfunk 2021-12-18 00:36:45 +01:00
parent dffcba47fb
commit 4b2a97a51d
7 changed files with 74 additions and 26 deletions

View File

@ -34,7 +34,7 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block styles %} {% block styles %}
<link rel="stylesheet" href="{{ 'assets/stylesheets/main.8e8281cd.min.css' | url }}"> <link rel="stylesheet" href="{{ 'assets/stylesheets/main.ffa0dd14.min.css' | url }}">
{% if config.theme.palette %} {% if config.theme.palette %}
{% set palette = config.theme.palette %} {% set palette = config.theme.palette %}
<link rel="stylesheet" href="{{ 'assets/stylesheets/palette.e6a45f82.min.css' | url }}"> <link rel="stylesheet" href="{{ 'assets/stylesheets/palette.e6a45f82.min.css' | url }}">
@ -213,7 +213,7 @@
</script> </script>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="{{ 'assets/javascripts/bundle.649a939e.min.js' | url }}"></script> <script src="{{ 'assets/javascripts/bundle.1cbe63b4.min.js' | url }}"></script>
{% for path in config["extra_javascript"] %} {% for path in config["extra_javascript"] %}
<script src="{{ path | url }}"></script> <script src="{{ path | url }}"></script>
{% endfor %} {% endfor %}

View File

@ -29,12 +29,14 @@ import {
map, map,
mapTo, mapTo,
merge, merge,
startWith,
tap tap
} from "rxjs" } from "rxjs"
import { import {
getElement, getElement,
getElementOffset, getElementOffset,
getElementSize,
getElements getElements
} from "~/browser" } from "~/browser"
@ -65,14 +67,18 @@ export interface ContentTabs {
export function watchContentTabs( export function watchContentTabs(
el: HTMLElement el: HTMLElement
): Observable<ContentTabs> { ): Observable<ContentTabs> {
return merge(...getElements(":scope > input", el) const inputs = getElements(":scope > input", el)
.map(input => fromEvent(input, "change") return merge(...inputs.map(input => fromEvent(input, "change")
.pipe( .pipe(
mapTo<ContentTabs>({ mapTo<ContentTabs>({
active: getElement(`label[for=${input.id}]`) active: getElement(`label[for=${input.id}]`)
}) })
) )
) ))
.pipe(
startWith({
active: getElement(`label[for=${inputs[0].id}]`)
} as ContentTabs)
) )
} }
@ -94,12 +100,29 @@ export function mountContentTabs(
const container = getElement(".tabbed-labels", el) const container = getElement(".tabbed-labels", el)
return defer(() => { return defer(() => {
const push$ = new Subject<ContentTabs>() const push$ = new Subject<ContentTabs>()
push$.subscribe(({ active }) => { push$.subscribe({
const { x } = getElementOffset(active)
/* Handle emission */
next({ active }) {
const offset = getElementOffset(active)
const { width } = getElementSize(active)
/* Set tab indicator offset and width */
el.style.setProperty("--md-indicator-x", `${offset.x}px`)
el.style.setProperty("--md-indicator-width", `${width}px`)
/* Smoothly scroll container */
container.scrollTo({ container.scrollTo({
behavior: "smooth", behavior: "smooth",
left: x left: offset.x
}) })
},
/* Handle complete */
complete() {
el.style.removeProperty("--md-indicator-x")
el.style.removeProperty("--md-indicator-width")
}
}) })
/* Create and return component */ /* Create and return component */

View File

@ -87,6 +87,27 @@
display: contents; display: contents;
} }
// [js]: Show animated tab indicator
.js & {
position: relative;
// Tab indicator
&::after {
position: absolute;
bottom: 0;
display: block;
width: var(--md-indicator-width);
height: 2px;
background: var(--md-accent-fg-color);
transform: translateX(var(--md-indicator-x));
transition:
width 250ms,
transform 250ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
content: "";
}
}
// Webkit scrollbar // Webkit scrollbar
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; // Chrome, Safari display: none; // Chrome, Safari
@ -207,8 +228,12 @@
// [screen]: Show active state // [screen]: Show active state
@media screen { @media screen {
color: var(--md-accent-fg-color); color: var(--md-accent-fg-color);
// [no-js]: Show border (indicator is animated with JavaScript)
.no-js & {
border-color: var(--md-accent-fg-color); border-color: var(--md-accent-fg-color);
} }
}
} }
// Tab label on keyboard focus placeholder // Tab label on keyboard focus placeholder