Skip to content

New landing page design #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open

New landing page design #119

wants to merge 51 commits into from

Conversation

shravanngoswamii
Copy link
Member

@shravanngoswamii shravanngoswamii commented Apr 14, 2025

Continuing #105
Preview the changes: https://turinglang.org/pr-previews/119

Copy link
Contributor

Preview the changes: https://turinglang.org/pr-previews/119
Please avoid using the search feature and navigation bar in PR previews!

@shravanngoswamii
Copy link
Member Author

If anyone is interested, then please feel free to take on this PR!

@shravanngoswamii shravanngoswamii linked an issue Apr 19, 2025 that may be closed by this pull request
simonsteiger and others added 22 commits April 21, 2025 22:54
* very basic redesign

* make buttons interactive
* add dangling code example

* add code example section
* quickfix alignment

* add news and clean up scss
* improve colors

* better link hover color
* paste in svg

* responsive svg header
using the same background colour for the team "cards" as for the non-hoverable cards on the landing page
- added links to discourse and slack to the buttons at the top of the page
- moved link to libraries page to "Learn more" section
@simonsteiger
Copy link
Contributor

I will definitely have time to finish this in July. Which points would you like to see addressed before this PR can be merged?

@penelopeysm
Copy link
Member

Revisiting this. Is there a reason why the old PR was closed?

Also, I'd personally be happy to merge if some of the placeholder content is removed. Honestly, it's not like the existing front page has any resources, so even a fairly clean slate would be a huge improvement over the current one.

@shravanngoswamii
Copy link
Member Author

@penelopeysm Just let me know your comments on current state of this PR whenever you have some time!

@penelopeysm
Copy link
Member

Very nice @shravanngoswamii! Could you also add this paper https://dl.acm.org/doi/10.1145/3711897?

I'll work on the placeholder text now.

@penelopeysm
Copy link
Member

There are some annoyances with the light/dark mode toggle (e.g. how it resets the animation), but I don't think they can be fixed while we are still using Quarto. (#110, but who has the time for that...)

@yebai
Copy link
Member

yebai commented Jun 18, 2025

I suggest that we keep only these sections below. The other sections are good, but too detailed. The styling can be tweaked so all the sections are consistent (e.g. title centred or left aligned).

image image

@penelopeysm
Copy link
Member

🤷‍♀️

@yebai
Copy link
Member

yebai commented Jun 18, 2025

Also, let's look at the Alan Turing Institute website and try to add the ATI logo or branding material on our landing page.

https://www.turing.ac.uk/

Cc @mhauru, who is coordinating this, I believe.

Copy link
Member

@penelopeysm penelopeysm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I'm done here.

Final comments:

  1. Is there a way to scroll the news carousel with the mouse? Right now there's some dragging behaviour but I think just plain x-scrolling would be more intuitive.

  2. The animation at the top replays when anything happens -- light/dark mode toggle is one but it also restarts when the window is resized. Is there a way to fix this?

@shravanngoswamii
Copy link
Member Author

shravanngoswamii commented Jun 18, 2025

  1. Is there a way to scroll the news carousel with the mouse? Right now there's some dragging behaviour but I think just plain x-scrolling would be more intuitive.

Yep, I will do this, I was thinking of some better ways for this but let's try a mouse scroll

There are some annoyances with the light/dark mode toggle (e.g. how it resets the animation), but I don't think they can be fixed while we are still using Quarto. (#110, but who has the time for that...)

  1. The animation at the top replays when anything happens -- light/dark mode toggle is one but it also restarts when the window is resized. Is there a way to fix this?

Actually, this isn't a Quarto issue, something on our side is triggering this, let me take a look at it!

@shravanngoswamii
Copy link
Member Author

shravanngoswamii commented Jun 18, 2025

Also, let's look at the Alan Turing Institute website and try to add the ATI logo or branding material on our landing page.

https://www.turing.ac.uk/

Cc @mhauru, who is coordinating this, I believe.

image

https://www.turing.ac.uk/contact-us/our-brand

Could someone please request the logo of The Alan Turing Institute and share it here?

As for how to display the branding material, here are a few suggestions:

  • Our Partners
  • Our Supporters
  • Thanks to Our Supporters
  • Proudly Supported By

Please suggest a better one...

@mhauru
Copy link
Member

mhauru commented Jun 18, 2025

I've requested the Turing Institute logo file from our comms team, I'll send it to you @shravanngoswamii once I get it.

@shravanngoswamii
Copy link
Member Author

shravanngoswamii commented Jun 22, 2025

Here is the News Carousel code for landing page, putting it here for just in case we want to use it again in future:

News Carousel Code

Directory structure:
└── news/
    ├── _news-carousel.ejs
    └── news.qmd

File: _news-carousel.ejs

/```{=html}
<div id="news-carousel-container">
    <div id="news-carousel-track">
        <% for (const item of items) { %>
            <div class="news-carousel-slide">
                <a href="<%- item.path %>" class="news-carousel-card">
                    <div class="news-carousel-card-body">
                        <h5 class="news-carousel-title"><%- item.title %></h5>
                        <p class="news-carousel-reading-time"><%- item['reading-time'] %> read</p>
                        <% if (item.description) { %>
                        <p class="news-carousel-description"><%- item.description %></p>
                        <% } %>
                        <div class="news-carousel-attribution">
                            <span class="news-carousel-author"><%- item.author %></span>
                            <span class="news-carousel-date"><%- item.date %></span>
                        </div>
                    </div>
                </a>
            </div>
        <% } %>
    </div>
</div>
/```

File: news.qmd

---
listing:
  - id: news-carousel
    contents: 
      - "news/posts/*/index.qmd"
    template: _includes/news/_news-carousel.ejs
    sort: "date desc"
---

### News

::: {#news-carousel}
:::

\```{=html}
<div class="d-flex flex-column align-items-center gap-0">
  <a href="news/" class="button btn">
    See all news &rarr;
  </a>
</div>

<style>
/* Scoped styles for the news carousel to avoid conflicts with global themes */
#news-carousel-container {
  overflow: hidden;
  position: relative;
  width: 100%;
  cursor: grab;
}

#news-carousel-container.grabbing {
  cursor: grabbing;
}

#news-carousel-container #news-carousel-track {
  display: flex;
  align-items: stretch;
}

#news-carousel-container .news-carousel-slide {
  flex-shrink: 0;
  width: 33.3333%;
  padding: 0.5rem;
  box-sizing: border-box;
}

@media (max-width: 1024px) {
  #news-carousel-container .news-carousel-slide {
    width: 50%;
  }
}

@media (max-width: 768px) {
  #news-carousel-container .news-carousel-slide {
    width: 100%;
  }
}

#news-carousel-container .news-carousel-card {
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  border-radius: 0.5rem;
  transition: background-color 0.3s ease, border-color 0.3s ease;
  background-color: #ffffff;
  border: 1px solid #e9ecef;
  color: #212529;
}

#news-carousel-container .news-carousel-card:hover {
  background-color: #e9ecef;
  border-color: #dee2e6;
}

#news-carousel-container .news-carousel-card-body {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  padding: 1rem;
}

#news-carousel-container .news-carousel-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.25rem;
  color: #212529;
  font-weight: 700;
}

#news-carousel-container .news-carousel-reading-time,
#news-carousel-container .news-carousel-description,
#news-carousel-container .news-carousel-attribution {
  color: #6c757d;
}

#news-carousel-container .news-carousel-reading-time {
  font-size: 0.9em;
  margin-bottom: 0.75rem;
}

#news-carousel-container .news-carousel-description {
  flex-grow: 1;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 1rem;
}

#news-carousel-container .news-carousel-attribution {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1em;
  font-size: 0.85em;
  margin-top: auto;
}

#news-carousel-container .news-carousel-author {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

#news-carousel-container .news-carousel-date {
  white-space: nowrap;
  flex-shrink: 0;
}
</style>

<script>
document.addEventListener('DOMContentLoaded', function () {
    const carouselContainer = document.getElementById('news-carousel-container');
    const carouselTrack = document.getElementById('news-carousel-track');
    
    if (!carouselContainer || !carouselTrack || !carouselTrack.children.length) {
        return;
    }
    
    const slides = Array.from(carouselTrack.children);
    const displayDuration = 2000;
    let currentTranslate = 0;
    let prevTranslate = 0;
    let currentIndex = 0;
    let intervalId;
    
    // Interaction state variables
    let isDragging = false;
    let startPos = 0;
    let hasDragged = false;
    let wheelTimeout;
    let isWheeling = false;

    const getItemsPerView = () => {
        const width = window.innerWidth;
        if (width <= 768) return 1;
        if (width > 768 && width <= 1024) return 2;
        return 3;
    }

    const getPositionX = (event) => {
        return event.type.includes('mouse') ? event.pageX : event.touches[0].clientX;
    }
    
    const startAutoplay = () => {
        stopAutoplay();
        intervalId = setInterval(autoplayNext, displayDuration);
    }

    const stopAutoplay = () => {
        clearInterval(intervalId);
    }

    const setSliderPosition = () => {
        carouselTrack.style.transform = `translateX(${currentTranslate}px)`;
    }

    const setPositionByIndex = () => {
        if (slides.length === 0) return;

        const itemsPerView = getItemsPerView();
        const maxIndex = slides.length > itemsPerView ? slides.length - itemsPerView : 0;
        
        if (currentIndex > maxIndex) currentIndex = maxIndex;
        if (currentIndex < 0) currentIndex = 0;
        
        const slideWidth = slides[0].getBoundingClientRect().width;
        currentTranslate = currentIndex * -slideWidth;
        
        carouselTrack.style.transition = 'transform 0.4s ease-out';
        setSliderPosition();
    }

    const autoplayNext = () => {
        if (document.hidden || isDragging) return;
        const itemsPerView = getItemsPerView();
        const maxIndex = slides.length > itemsPerView ? slides.length - itemsPerView : 0;
        
        currentIndex++;
        if (currentIndex > maxIndex) {
            currentIndex = 0;
        }
        setPositionByIndex();
    }

    function handleDragStart(event) {
        isDragging = true;
        hasDragged = false;
        startPos = getPositionX(event);
        const style = window.getComputedStyle(carouselTrack);
        const matrix = new DOMMatrix(style.transform);
        prevTranslate = matrix.m41;
        carouselContainer.classList.add('grabbing');
        carouselTrack.style.transition = 'none';
        stopAutoplay();
    }

    function handleDragMove(event) {
        if (!isDragging) return;
        const currentPosition = getPositionX(event);
        currentTranslate = prevTranslate + currentPosition - startPos;
        setSliderPosition();
        if (Math.abs(currentPosition - startPos) > 10) {
            hasDragged = true;
        }
    }

    function handleDragEnd() {
        if (!isDragging) return;
        isDragging = false;
        carouselContainer.classList.remove('grabbing');
        const movedBy = currentTranslate - prevTranslate;
        const itemsPerView = getItemsPerView();
        const maxIndex = slides.length > itemsPerView ? slides.length - itemsPerView : 0;

        if (movedBy < -50 && currentIndex < maxIndex) {
            currentIndex++;
        }
        if (movedBy > 50 && currentIndex > 0) {
            currentIndex--;
        }

        setPositionByIndex();
        startAutoplay();
    }
    
    function handleWheel(event) {
        event.preventDefault();
        if (isWheeling) return;
        isWheeling = true;
        stopAutoplay();

        const itemsPerView = getItemsPerView();
        const maxIndex = slides.length > itemsPerView ? slides.length - itemsPerView : 0;
        const delta = event.deltaY;

        if (delta > 0) {
            if (currentIndex < maxIndex) currentIndex++;
        } else if (delta < 0) {
            if (currentIndex > 0) currentIndex--;
        }
        setPositionByIndex();

        clearTimeout(wheelTimeout);
        wheelTimeout = setTimeout(startAutoplay, 500);
        setTimeout(() => { isWheeling = false; }, 100);
    }
        
    carouselContainer.addEventListener('mousedown', handleDragStart);
    window.addEventListener('mouseup', handleDragEnd);
    window.addEventListener('mousemove', handleDragMove);
    
    carouselContainer.addEventListener('touchstart', handleDragStart, { passive: true });
    window.addEventListener('touchend', handleDragEnd);
    window.addEventListener('touchmove', handleDragMove, { passive: true });

    carouselContainer.addEventListener('click', (e) => {
        if (hasDragged) {
            e.preventDefault();
        }
    }, true);

    carouselContainer.addEventListener('wheel', handleWheel, { passive: false });
    
    carouselContainer.addEventListener('mouseenter', stopAutoplay);
    carouselContainer.addEventListener('mouseleave', startAutoplay);
    document.addEventListener('visibilitychange', () => document.hidden ? stopAutoplay() : startAutoplay());
    
    window.addEventListener('resize', setPositionByIndex);

    setPositionByIndex();
    startAutoplay();
});
</script>
\```

File: theming/theme-dark.scss:

// Dark mode styles for the news carousel
#news-carousel-container {

  .news-carousel-card {
    border: 1px solid transparent !important;
    color: $body-color !important;

    &:hover {
      border-color: $lp-cyan !important;
    }
  }

  .news-carousel-title {
    color: $body-color !important;
  }

  .news-carousel-reading-time,
  .news-carousel-description,
  .news-carousel-attribution {
    color: $text-muted !important;
  }
}

@shravanngoswamii
Copy link
Member Author

@mhauru, here is the size and position of the logo: Preview Link. We have a fixed height of 80px, and the width will automatically adjust to maintain the aspect ratio. Please provide the logo in both light mode and dark mode versions. If the dark mode version is unavailable, we can invert the colors for the ATI logo.

Does this work for you? I think it would be helpful for @yebai and @penelopeysm to review the design before we request the logo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Redesign the landing page!
5 participants