Skip to content

Commit

Permalink
frontpage: add vanilla js version of communities carousel
Browse files Browse the repository at this point in the history
  • Loading branch information
jennur authored and zzacharo committed Jul 11, 2023
1 parent 4215924 commit 5c592c3
Show file tree
Hide file tree
Showing 13 changed files with 421 additions and 3 deletions.
88 changes: 88 additions & 0 deletions assets/less/zenodo-rdm/modules/transition.overrides
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/***********************************************
Zenodo RDM Transition Overrides
***********************************************/

#carousel-container {
position: relative;
min-height: @carouselPageHeightComputer;
width: 100%;

@media screen and (max-width: @largestTabletScreen) {
min-height: @carouselPageHeightTablet;
}

@media screen and (max-width: @largestMobileScreen) {
min-height: @carouselPageHeightMobile;
}


#carousel-slides.ui.items {
position: relative;
width: max-content;
min-height: @carouselPageHeightComputer;

@media screen and (max-width: @largestTabletScreen) {
min-height: @carouselPageHeightTablet;
}

@media screen and (max-width: @largestMobileScreen) {
min-height: @carouselPageHeightMobile;
}

@media screen and (min-width: @computerBreakpoint) {
margin-top: 0 !important;
}

> .item.slide {
position: relative;
width: @carouselItemWidthComputer;
margin: 0 !important;
padding: 0 1rem;

@media screen and (max-width: @largestTabletScreen) {
width: @carouselItemWidthTablet;
}
@media screen and (max-width: @largestMobileScreen) {
text-align: center;
width: @carouselItemWidthMobile;
}

&.visible {
animation: fadein .3s;
animation-fill-mode: forwards;
}
&.hidden {
animation: fadeout .3s;
animation-fill-mode: forwards;
}

.ui.mini.button {
@media screen and (max-width: @largestMobileScreen) {
margin-bottom: .5rem;
}
}
}

}
}



@keyframes fadein {
from {
opacity: 0;
}

to {
opacity: 1;
}
}
@keyframes fadeout {
from {
opacity: 1;
}

to {
opacity: 0;
}
}
11 changes: 11 additions & 0 deletions assets/less/zenodo-rdm/modules/transition.variables
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/***********************************************
Invenio App RDM Transition Variables
***********************************************/

@carouselPageHeightComputer: 15rem;
@carouselPageHeightTablet: 18rem;
@carouselPageHeightMobile: 40rem;

@carouselItemWidthComputer: 68rem;
@carouselItemWidthTablet: 40rem;
@carouselItemWidthMobile: 15rem;
1 change: 1 addition & 0 deletions invenio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ APP_DEFAULT_SECURE_HEADERS = {
'strict_transport_security_preload': False,
}

APP_RDM_ROUTES["index"] = ("/", frontpage_view_function)

# Celery
# ======
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
document.addEventListener("DOMContentLoaded", () => initCommunityCarousel());

function initCommunityCarousel() {
const carousel = document.getElementById("communities-carousel");
const slidesContainer = document.getElementById("carousel-slides");
const carouselSlides = slidesContainer.querySelectorAll(".item.slide");
const prevSlideBtn = document.getElementById("prev-slide-btn");
const nextSlideBtn = document.getElementById("next-slide-btn");

const animationSpeed = parseInt(carousel.dataset.animationSpeed);
const intervalDelay = parseInt(carousel.dataset.intervalDelay);

const numSlides = carouselSlides.length;
const slideWidth = carouselSlides[0].offsetWidth;

const minIndex = 0;
const maxIndex = numSlides - 1;
var activeIndex = 0;

var transitionCompleted = true;

carouselSlides.forEach((slide, index) => {
// Remove all inactive slides from the DOM.
if (index !== activeIndex) slide.remove();
});

/**
* Switches carousel slide
* @param {string} direction Direction to slide - left or right
*/
const slide = (direction) => {
const currentSlide = slidesContainer.querySelector(".item.slide");
const slideLeft = direction === "left";

if (transitionCompleted) {
transitionCompleted = false;
const prevVisibleIndex = slideLeft ? 0 : 1;
const currentVisibleIndex = slideLeft ? 1 : 0;
const slideAmount = -slideWidth;

if (direction === "left") {
activeIndex++;
if (activeIndex > maxIndex) {
activeIndex = minIndex;
}

// Add active slide after currently visible slide
currentSlide.after(carouselSlides[activeIndex]);

// Translate the slides-container such that the active slide comes to center.
slidesContainer.style.transitionDuration = `${animationSpeed}ms`;
slidesContainer.style.transform = `translateX(${slideAmount}px)`;
} else {
activeIndex--;
if (activeIndex < minIndex) {
activeIndex = maxIndex;
}

// Add active slide before currently visible slide
currentSlide.before(carouselSlides[activeIndex]);

// Translate the slides-container such that the previously active slide stays in center.
slidesContainer.style.transition = "transform .001ms";
slidesContainer.style.transform = `translateX(${slideAmount}px)`;
}

const currentSlides = slidesContainer.querySelectorAll(".item.slide");

// Control slide visibility by adding/removing classes
currentSlides[prevVisibleIndex].classList.remove("visible");
currentSlides[prevVisibleIndex].classList.add("hidden");

currentSlides[currentVisibleIndex].classList.add("visible");
currentSlides[currentVisibleIndex].classList.remove("hidden");

// Transition-end event handler, runs once when slides-container transition is finished
const transitionEndHandler = (direction) => {
if (direction === "left") {
// Tranlate the slides-container such that the active item will be
// in center once the previously active item is removed, then remove that item
slidesContainer.style.transitionDuration = "0s";
slidesContainer.style.transform = "translateX(0px)";
currentSlides[prevVisibleIndex].remove();
} else {
const removePreviousSlide = () => {
currentSlides[prevVisibleIndex].remove();
slidesContainer.removeEventListener("transitionend", removePreviousSlide);
};

// Remove previous slide once the second transition is completed
slidesContainer.addEventListener("transitionend", removePreviousSlide, {
once: true,
});

// Translate slides-container to center
slidesContainer.style.transitionDuration = `${animationSpeed}ms`;
slidesContainer.style.transform = "translateX(0px)";
}

transitionCompleted = true;
slidesContainer.removeEventListener("transitionend", transitionEndHandler);
};

slidesContainer.addEventListener(
"transitionend",
() => transitionEndHandler(direction),
{ once: true }
);
}
};

// Run carousel automatically on page load
const setCarouselTimer = () => setInterval(() => slide("left"), intervalDelay);
var carouselTimer = setCarouselTimer();

// Pause carousel on focus
carousel.addEventListener("focusin", () => {
clearInterval(carouselTimer);
});
carousel.addEventListener("focusout", () => {
carouselTimer = setCarouselTimer();
});

// Navigation arrow event handlers
prevSlideBtn.addEventListener("click", () => slide("right"));
prevSlideBtn.addEventListener("keydown", (event) => {
event.key === "Enter" && slide("right");
});

nextSlideBtn.addEventListener("click", () => slide("left"));
nextSlideBtn.addEventListener("keydown", (event) => {
event.key === "Enter" && slide("left");
});
}
8 changes: 8 additions & 0 deletions site/zenodo_rdm/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""Additional views."""

from flask import Blueprint, current_app, g, render_template
from invenio_communities.proxies import current_communities
from invenio_rdm_records.proxies import current_rdm_records
from invenio_rdm_records.resources.serializers import UIJSONSerializer
from invenio_records_resources.resources.records.utils import search_preference
Expand All @@ -33,10 +34,17 @@ def frontpage_view_function():
record_ui = UIJSONSerializer().dump_obj(record)
records_ui.append(record_ui)

featured_communities = current_communities.service.featured_search(
identity=g.identity,
params=None,
search_preference=search_preference(),
)

return render_template(
current_app.config["THEME_FRONTPAGE_TEMPLATE"],
show_intro_section=current_app.config["THEME_SHOW_FRONTPAGE_INTRO_SECTION"],
recent_uploads=records_ui,
featured_communities=featured_communities,
)


Expand Down
1 change: 1 addition & 0 deletions site/zenodo_rdm/webpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
# Add your webpack entrypoints
"zenodo-rdm-support": "./js/zenodo_rdm/src/support/support.js",
"zenodo-rdm-citations": "./js/zenodo_rdm/src/citations/index.js",
"zenodo-rdm-communities-carousel": "./js/zenodo_rdm/src/communities-carousel.js",
},
dependencies={
"@babel/runtime": "^7.9.0",
Expand Down
7 changes: 7 additions & 0 deletions templates/semantic-ui/zenodo_rdm/frontpage.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@
-#}

{% from "zenodo_rdm/macros/recent_uploads_list.html" import recent_uploads_list %}
{% from "zenodo_rdm/macros/featured_communities_carousel.html" import featured_communities_carousel %}
{%- extends "invenio_app_rdm/frontpage.html" %}

{%- block page_header %}
{%- include "zenodo_rdm/header_frontpage.html" %}
{%- endblock page_header %}

{%- block top_banner %}
{% if featured_communities %}
{{ featured_communities_carousel(communities=featured_communities) }}
{% endif %}
{%- endblock top_banner %}

{% block main_column_content %}
{% if recent_uploads %}
{{ recent_uploads_list(records=recent_uploads) }}
Expand Down
58 changes: 58 additions & 0 deletions templates/semantic-ui/zenodo_rdm/macros/carousel_item.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{#
# This file is part of Zenodo.
# Copyright (C) 2023 CERN.
#
# Zenodo is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# Zenodo is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Zenodo; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.
-#}

{% macro carousel_item(community=None, index=0) %}
<div class="item slide flex align-items-center {{ 'visible' if index == 1 else 'hidden' }}">
<img class="ui small image has-placeholder" src="{{ community.links.logo }}" />
<div class="content">
<div class="ui middle aligned grid rel-pb-1">
<div class="ten wide computer sixteen wide tablet column">
<a class="ui medium header" href="{{ community.links.self_html }}">
{{ community.metadata.title }}
</a>
</div>

<div class="six wide computer sixteen wide tablet column buttons">
<a
class="ui mini button"
href={community.links.self_html}
>
{{ _("Browse") }}
</a>
<a
class="ui mini icon positive left labeled button"
href="/uploads/new?community={{community.slug}}"
>
<i class="upload icon" aria-hidden="true"></i>
{{ _("New upload") }}
</a>
</div>
</div>

<p class="description">
{{ community.metadata.description | truncate(length=300, end='...') }}
</p>
</div>
</div>
{% endmacro %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{#
# This file is part of Zenodo.
# Copyright (C) 2023 CERN.
#
# Zenodo is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# Zenodo is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Zenodo; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.
-#}

{% from "zenodo_rdm/macros/carousel_item.html" import carousel_item %}

{% macro communities_carousel_slides(communities) %}
<div id="carousel-container">
<div id="carousel-slides" class="ui items flex align-items-center">
{% for community in communities|list %}
{{ carousel_item(community=community, index=loop.index) }}
{% endfor %}
</div>
</div>
{% endmacro %}
Loading

0 comments on commit 5c592c3

Please sign in to comment.