carousel, display logs
This commit is contained in:
		@ -174,16 +174,16 @@ a.navbar-item.is-active {
 | 
			
		||||
    --highlight-color-2-alpha: rgb(0, 0, 254, 0.7);
 | 
			
		||||
    --highlight-color-2-grey: rgba(50, 200, 200, 1);
 | 
			
		||||
 | 
			
		||||
    --header-height: 30em;
 | 
			
		||||
    --header-height: 30rem;
 | 
			
		||||
 | 
			
		||||
    --heading-height: 30em;
 | 
			
		||||
    --heading-height: 30rem;
 | 
			
		||||
    --heading-title-bg-color: rgba(255, 255, 0, 1);
 | 
			
		||||
    --heading-bg-color: var(--highlight-color);
 | 
			
		||||
    --heading-bg-highlight-color: var(--highlight-color-2);
 | 
			
		||||
    --heading-font-family: default;
 | 
			
		||||
 | 
			
		||||
    --preview-cover-size: 18em;
 | 
			
		||||
    --preview-cover-small-size: 10em;
 | 
			
		||||
    --preview-cover-size: 24rem;
 | 
			
		||||
    --preview-cover-small-size: 10rem;
 | 
			
		||||
 | 
			
		||||
    --player-panel-bg: var(--highlight-color);
 | 
			
		||||
    --player-bar-bg: var(--highlight-color);
 | 
			
		||||
@ -262,6 +262,9 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
 | 
			
		||||
.no-border { border: 0px !important; }
 | 
			
		||||
 | 
			
		||||
// -- colors
 | 
			
		||||
.highlight-color { color: var(--highlight-color); }
 | 
			
		||||
.highlight-color-2 { color: var(--highlight-color-2); }
 | 
			
		||||
 | 
			
		||||
.is-success {
 | 
			
		||||
    background-color: $green !important;
 | 
			
		||||
    border-color: $green-dark !important;
 | 
			
		||||
@ -328,25 +331,6 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
 | 
			
		||||
        border-color: var(--highlight-color-2-alpha);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .actions &, &.action {
 | 
			
		||||
        background-color: var(--highlight-color);
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        min-width: 2rem;
 | 
			
		||||
 | 
			
		||||
        .not-selected { opacity: 0.6; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        .icon { margin: 0em !important; }
 | 
			
		||||
 | 
			
		||||
        label {
 | 
			
		||||
            margin-left: $mp-2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:hover, .selected {
 | 
			
		||||
            color: var(--highlight-color-2) !important;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .dropdown-trigger {
 | 
			
		||||
        border-radius: 1.5em;
 | 
			
		||||
    }
 | 
			
		||||
@ -366,9 +350,34 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.actions {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    gap: $mp-3;
 | 
			
		||||
    justify-content: right;
 | 
			
		||||
 | 
			
		||||
    &.no-label label {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    button, .action {
 | 
			
		||||
        background-color: var(--highlight-color);
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        min-width: 2rem;
 | 
			
		||||
 | 
			
		||||
        .not-selected { opacity: 0.6; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        .icon { margin: 0em !important; }
 | 
			
		||||
 | 
			
		||||
        label {
 | 
			
		||||
            margin-left: $mp-2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:hover, .selected {
 | 
			
		||||
            color: var(--highlight-color-2) !important;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -379,6 +388,7 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
 | 
			
		||||
    &.is-3 {
 | 
			
		||||
        margin-top: $mp-3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.heading {
 | 
			
		||||
@ -406,6 +416,10 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    background-color: var(--highlight-color);
 | 
			
		||||
 | 
			
		||||
    &:empty {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .nav-item {
 | 
			
		||||
        padding: $mp-3;
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
@ -513,16 +527,11 @@ nav li {
 | 
			
		||||
    background-size: cover;
 | 
			
		||||
    margin-bottom: $mp-6 !important;
 | 
			
		||||
 | 
			
		||||
    &.preview-card {
 | 
			
		||||
        &:not(.wide) {
 | 
			
		||||
            max-width: 30em;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.preview-item {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // FIXME: remove
 | 
			
		||||
    &.columns, .headings.columns {
 | 
			
		||||
        margin-left: 0em;
 | 
			
		||||
        margin-right: 0em;
 | 
			
		||||
@ -553,123 +562,21 @@ nav li {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    .preview.comment {
 | 
			
		||||
        .title { font-size: $text-size-bigger; }
 | 
			
		||||
        .subtitle { font-size: $text-size; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.list-item {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
 | 
			
		||||
    &:not(:first-child) {
 | 
			
		||||
        margin-top: calc($mp-4 / 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .headings {
 | 
			
		||||
        padding-top: 0em;
 | 
			
		||||
        margin-bottom: $mp-4 !important;
 | 
			
		||||
        background-color: var(--heading-bg-color);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .subtitle {
 | 
			
		||||
        text-align: right;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .media-content {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        min-height: var(--preview-cover-small-size);
 | 
			
		||||
 | 
			
		||||
        .content {
 | 
			
		||||
            flex-grow: 1;
 | 
			
		||||
            margin-bottom: auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .actions {
 | 
			
		||||
            flex-grow: unset;
 | 
			
		||||
            text-align: right;
 | 
			
		||||
            margin-top: auto;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- cards
 | 
			
		||||
.preview-wide {
 | 
			
		||||
    height: var(--preview-cover-size);
 | 
			
		||||
 | 
			
		||||
    &:not(.header) .headings {
 | 
			
		||||
        box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & .headings {
 | 
			
		||||
        width: var(--preview-cover-size);
 | 
			
		||||
        flex-grow: 0;
 | 
			
		||||
        margin-right: $mp-4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & .content {
 | 
			
		||||
        font-size: $text-size-big;
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.preview-card {
 | 
			
		||||
    height: var(--preview-cover-size);
 | 
			
		||||
    min-width: var(--preview-cover-size);
 | 
			
		||||
 | 
			
		||||
    &:not(.header) {
 | 
			
		||||
        box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card-grid & {
 | 
			
		||||
        min-width: unset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .actions {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: $mp-3;
 | 
			
		||||
        right: $mp-3;
 | 
			
		||||
 | 
			
		||||
        label {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.preview-cover {
 | 
			
		||||
    background-size: cover;
 | 
			
		||||
    background-color: transparent !important;
 | 
			
		||||
    height: var(--preview-cover-size);
 | 
			
		||||
    width: var(--preview-cover-size);
 | 
			
		||||
    min-width: var(--preview-cover-size);
 | 
			
		||||
 | 
			
		||||
    &.small {
 | 
			
		||||
        min-width: unset;
 | 
			
		||||
        height: var(--preview-cover-small-size);
 | 
			
		||||
        width: var(--preview-cover-small-size) !important;
 | 
			
		||||
        min-width: var(--preview-cover-small-size);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.preview-card-headings {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    min-width: var(--preview-cover-size);
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
 | 
			
		||||
    padding-top: $mp-3;
 | 
			
		||||
 | 
			
		||||
    & > div:not(:last-child),
 | 
			
		||||
    & .column > div {
 | 
			
		||||
        margin-bottom: $mp-3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    preview-header:not(.no-cover) & .heading {
 | 
			
		||||
        margin-bottom: $mp-3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.preview-header {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
 | 
			
		||||
@ -695,6 +602,120 @@ nav li {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- specific
 | 
			
		||||
.preview.comment {
 | 
			
		||||
    .title { font-size: $text-size-bigger; }
 | 
			
		||||
    .subtitle { font-size: $text-size; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- list
 | 
			
		||||
.list-item {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
 | 
			
		||||
    &:not(:first-child) {
 | 
			
		||||
        margin-top: calc($mp-4 / 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .headings {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: row;
 | 
			
		||||
        padding-top: 0em;
 | 
			
		||||
        margin-bottom: $mp-4 !important;
 | 
			
		||||
        background-color: var(--heading-bg-color);
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
            flex-grow: 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .subtitle {
 | 
			
		||||
        text-align: right;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .media-content {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
 | 
			
		||||
        .list-item:not(.no-cover) & {
 | 
			
		||||
            min-height: var(--preview-cover-small-size);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .content {
 | 
			
		||||
            flex-grow: 1;
 | 
			
		||||
            margin-bottom: auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .actions {
 | 
			
		||||
            flex-grow: unset;
 | 
			
		||||
            text-align: right;
 | 
			
		||||
            margin-top: auto;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- wide
 | 
			
		||||
.preview-wide {
 | 
			
		||||
    height: var(--preview-cover-size);
 | 
			
		||||
 | 
			
		||||
    &:not(.header) .headings {
 | 
			
		||||
        box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & .headings {
 | 
			
		||||
        width: var(--preview-cover-size);
 | 
			
		||||
        flex-grow: 0;
 | 
			
		||||
        margin-right: $mp-4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & .content {
 | 
			
		||||
        font-size: $text-size-big;
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- card
 | 
			
		||||
.preview-card {
 | 
			
		||||
    height: var(--preview-cover-size);
 | 
			
		||||
    width: var(--preview-cover-size);
 | 
			
		||||
 | 
			
		||||
    &:not(.header) {
 | 
			
		||||
        box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card-grid & {
 | 
			
		||||
        min-width: unset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .actions {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: $mp-3;
 | 
			
		||||
        right: $mp-3;
 | 
			
		||||
 | 
			
		||||
        label {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.preview-card-headings {
 | 
			
		||||
    padding-top: $mp-3;
 | 
			
		||||
 | 
			
		||||
    & > div:not(:last-child),
 | 
			
		||||
    & .column > div {
 | 
			
		||||
        margin-bottom: $mp-3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    preview-header:not(.no-cover) & .heading {
 | 
			
		||||
        margin-bottom: $mp-3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.header {
 | 
			
		||||
    background-size: cover;
 | 
			
		||||
 | 
			
		||||
@ -723,34 +744,54 @@ nav li {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -- program grid
 | 
			
		||||
// ---- card grid
 | 
			
		||||
.card-grid {
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: 1fr 1fr 1fr;
 | 
			
		||||
    gap: $mp-4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.a-carousel-container {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    gap: $mp-4;
 | 
			
		||||
    transition: margin-left 1s;
 | 
			
		||||
 | 
			
		||||
@media screen and (max-width: $screen-wide) {
 | 
			
		||||
    .preview-card:not(.preview-header) {
 | 
			
		||||
        height: 20em !important;
 | 
			
		||||
    > * {
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    .card-grid .preview-card {
 | 
			
		||||
        height: 20em;
 | 
			
		||||
.a-carousel-button-container {
 | 
			
		||||
    button, .button {
 | 
			
		||||
        z-index:1000;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        top: calc(var(--preview-cover-size) - $text-size-medium);
 | 
			
		||||
 | 
			
		||||
        &.prev { left: -$mp-3e; }
 | 
			
		||||
        &.next { right: -$mp-3e; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- responsive
 | 
			
		||||
@media screen and (max-width: $screen-wide) {
 | 
			
		||||
    :root {
 | 
			
		||||
        --preview-cover-size: 18em;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-width: $screen-normal) {
 | 
			
		||||
    .card-grid {
 | 
			
		||||
        grid-template-columns: 1fr 1fr;
 | 
			
		||||
 | 
			
		||||
        .preview-card:nth-child(3) {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    .page .container {
 | 
			
		||||
        margin-left: $mp-4;
 | 
			
		||||
        margin-right: $mp-4;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-width: $screen-small) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ---- player
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										184
									
								
								assets/src/components/ACarousel.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								assets/src/components/ACarousel.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,184 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="a-carousel-button-container" v-if="showPrevButton">
 | 
			
		||||
        <button :class="[buttonClass, 'prev']" aria-label="Go left" @click="prev">
 | 
			
		||||
            <span class="icon">
 | 
			
		||||
                <i :class="leftButtonIcon"></i>
 | 
			
		||||
            </span>
 | 
			
		||||
        </button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="a-carousel-button-container" v-if="showNextButton">
 | 
			
		||||
        <button :class="[buttonClass, 'next']" aria-label="Go left" @click="next">
 | 
			
		||||
            <span class="icon">
 | 
			
		||||
                <i :class="rightButtonIcon"></i>
 | 
			
		||||
            </span>
 | 
			
		||||
        </button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div ref="viewport" class="a-carousel-viewport">
 | 
			
		||||
        <section ref="container" :class="['a-carousel-container', containerClass]">
 | 
			
		||||
            <slot name="default"></slot>
 | 
			
		||||
        </section>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
<style scoped>
 | 
			
		||||
.a-carousel-viewport {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.a-carousel-container {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    align-items: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.a-carousel-container > * {
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
import {ref} from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    setup() {
 | 
			
		||||
        return {
 | 
			
		||||
            viewport: ref(null),
 | 
			
		||||
            container: ref(null),
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            cards: [],
 | 
			
		||||
            index: 0,
 | 
			
		||||
            refresh_: 0,
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    props: {
 | 
			
		||||
        cardSelector: {type: String, default: ''},
 | 
			
		||||
        containerClass: {type: String, default: ''},
 | 
			
		||||
        buttonClass: {type: String, default: 'button'},
 | 
			
		||||
        leftButtonIcon: {type: String, default: "fas fa-chevron-left"},
 | 
			
		||||
        rightButtonIcon: {type: String, default: "fas fa-chevron-right"},
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computed: {
 | 
			
		||||
        card() { return this.cards()[this.index] },
 | 
			
		||||
        showPrevButton() {
 | 
			
		||||
            return this.index > 0
 | 
			
		||||
        },
 | 
			
		||||
        showNextButton() {
 | 
			
		||||
            if(!this.cards || this.cards.length <= 1)
 | 
			
		||||
                return false
 | 
			
		||||
 | 
			
		||||
            let { count } = this.visibility
 | 
			
		||||
            return (this.index + count) < this.cards.length
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        visibility() {
 | 
			
		||||
            // force refresh on index
 | 
			
		||||
            [this.index, this.refresh_]
 | 
			
		||||
 | 
			
		||||
            if(!this.cards)
 | 
			
		||||
                return {min: -1, max: -1, count: 0};
 | 
			
		||||
 | 
			
		||||
            const vOff = this.offset(this.$refs.viewport)
 | 
			
		||||
            var [min, max] = [-1, -1]
 | 
			
		||||
            for(let at=0; at < this.cards.length; at++) {
 | 
			
		||||
                const card = this.cards[at]
 | 
			
		||||
                const cOff = this.offset(card)
 | 
			
		||||
                const visible = vOff.min <= cOff.min && vOff.max >= cOff.max
 | 
			
		||||
                if(visible) {
 | 
			
		||||
                    if(min === -1)
 | 
			
		||||
                        min = parseInt(at)
 | 
			
		||||
                    max = parseInt(at)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if(max !== -1)
 | 
			
		||||
                max++
 | 
			
		||||
            return {
 | 
			
		||||
                min, max,
 | 
			
		||||
                count: (min !== -1) ? max-min : 0
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        offset(el, parent=null) {
 | 
			
		||||
            const rect = el.getBoundingClientRect()
 | 
			
		||||
            const off = {min: rect.left, max: rect.right  }
 | 
			
		||||
            if(parent === null)
 | 
			
		||||
                return off
 | 
			
		||||
 | 
			
		||||
            const pOff = this.offset(parent)
 | 
			
		||||
            return {
 | 
			
		||||
                min: off.min - pOff.min,
 | 
			
		||||
                max: off.max - pOff.max,
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        getCards() {
 | 
			
		||||
            if(!this.cardSelector)
 | 
			
		||||
                return this.$refs.container.children
 | 
			
		||||
            return this.$refs.container.querySelectorAll(this.cardSelector)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        selectIndex(index, relative=false) {
 | 
			
		||||
            if(relative)
 | 
			
		||||
                index = this.index + index
 | 
			
		||||
 | 
			
		||||
            index = Math.min(this.cards.length, index)
 | 
			
		||||
            const el = this.cards[index]
 | 
			
		||||
            const elOff = this.offset(el, this.$refs.container)
 | 
			
		||||
            this.$refs.container.style.marginLeft = `-${elOff.min}px`
 | 
			
		||||
            this.index = index;
 | 
			
		||||
            return el
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        next() {
 | 
			
		||||
            if(!this.visibility.count)
 | 
			
		||||
                return
 | 
			
		||||
            let {count} = this.visibility
 | 
			
		||||
            let at = Math.min(
 | 
			
		||||
                count === 1 ? this.index+count : this.index+count-1,
 | 
			
		||||
                this.cards.length-count
 | 
			
		||||
            )
 | 
			
		||||
            this.selectIndex(at)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        prev() {
 | 
			
		||||
            if(!this.visibility.count)
 | 
			
		||||
                return
 | 
			
		||||
            const {min, count} = this.visibility
 | 
			
		||||
            let at = Math.max(0, min-count)
 | 
			
		||||
            if(min < 0 || count <= 0)
 | 
			
		||||
                return
 | 
			
		||||
            this.selectIndex(at)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        refresh() {
 | 
			
		||||
            this.cards = this.getCards()
 | 
			
		||||
            this.selectIndex(this.index)
 | 
			
		||||
            this.refresh_++
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.observer = [
 | 
			
		||||
            new MutationObserver(() => this.refresh()),
 | 
			
		||||
            new ResizeObserver(() => this.refresh())
 | 
			
		||||
        ]
 | 
			
		||||
        this.observer[0].observe(this.$refs.container, {"childList": true})
 | 
			
		||||
        this.observer[1].observe(this.$refs.container)
 | 
			
		||||
        this.refresh()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    unmounted() {
 | 
			
		||||
        for(var observer of this.observers)
 | 
			
		||||
            observer.disconnect()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import AAutocomplete from './AAutocomplete.vue'
 | 
			
		||||
import ACarousel from './ACarousel.vue'
 | 
			
		||||
import ADropdown from "./ADropdown.vue"
 | 
			
		||||
import AEpisode from './AEpisode.vue'
 | 
			
		||||
import AList from './AList.vue'
 | 
			
		||||
@ -15,7 +16,7 @@ import AStreamer from './AStreamer.vue'
 | 
			
		||||
 * Core components
 | 
			
		||||
 */
 | 
			
		||||
export const base = {
 | 
			
		||||
    AAutocomplete, ADropdown, AEpisode, AList, APage, APlayer, APlaylist,
 | 
			
		||||
    AAutocomplete, ACarousel, ADropdown, AEpisode, AList, APage, APlayer, APlaylist,
 | 
			
		||||
    AProgress, ASoundItem,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user