diff --git a/content/_index.md b/content/_index.md index 9885e25f..edda6e41 100644 --- a/content/_index.md +++ b/content/_index.md @@ -10,7 +10,7 @@ headline= "Valkey: an open source, in-memory data store" long_description= "" [extra.hero] -headings = ["FAST.", "RELIABLE.", "OPEN SOURCE, FOREVER."] +headings = ["FAST. RELIABLE.", "OPEN SOURCE, FOREVER."] subtitle = "Valkey is an open source (BSD) high-performance key/value datastore that supports a variety of workloads such as caching, message queues, and can act as a primary database. The project is backed by the Linux Foundation, ensuring it will remain open source forever." button_text = "GET STARTED" button_url = "/topics/quickstart" @@ -48,11 +48,7 @@ url= "/download/" url= "/docs/" title= "Read the docs" -[[extra.sidebar]] -title= "Founding documents" -[[extra.sidebar.links]] -title= 'Linux Foundation Launches Open Source Valkey Community' -url= "https://www.linuxfoundation.org/press/linux-foundation-launches-open-source-valkey-community" + +++ diff --git a/sass/_valkey.scss b/sass/_valkey.scss index df1222ce..e133de13 100644 --- a/sass/_valkey.scss +++ b/sass/_valkey.scss @@ -173,7 +173,7 @@ p { >a { &:hover, &.active { - border-color: inherit; + border-color: inherit; text-decoration: underline; @include respond-min(768px) { @@ -920,8 +920,6 @@ aside { h4 { margin: 0 0 1.25rem; - display: -webkit-box; - -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; @@ -1604,9 +1602,8 @@ html.banner-hidden .banner { // Hero Section Styles .hero-section { position: relative; - min-height: none; background-size: cover; - background-position: center bottom; + background-position: right center; background-color: #30186e; background-image: linear-gradient(to bottom, rgba(48, 24, 110, 0.15), rgba(48, 24, 110, 0.75)), url('/img/hero-bg.webp'); display: flex; @@ -1616,8 +1613,7 @@ html.banner-hidden .banner { padding: 8rem 2rem; @include respond-min(768px) { - padding: 8rem 2rem; - min-height: 75vh; + padding: 10rem 2rem; } } @@ -1638,7 +1634,7 @@ html.banner-hidden .banner { color: white; @include respond-min(768px) { - font-size: 8rem; + font-size: 7rem; } } @@ -1657,9 +1653,9 @@ html.banner-hidden .banner { border-radius: 30px; font-weight: 600; height: auto; - font-size: 2.4rem; + font-size: 2.2rem; color: #6983FF; - padding: 10px 20px; + padding: 8px 15px; background-image: linear-gradient(to right, #ffffff, #B7C2F7); box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25); transition: all 0.3s ease-in-out; @@ -1672,8 +1668,8 @@ html.banner-hidden .banner { // Documentation Section Styles .documentation-section { - padding-bottom: 4rem; - background-image: linear-gradient(rgb(48, 23, 110), rgb(105, 131, 255)); + padding: 4rem 2rem; + background: #6983FF; position: relative; text-align: center; color: white; @@ -1772,11 +1768,11 @@ html.banner-hidden .banner { // What's New Section Styles .whats-new-section { - padding: 4rem 2rem; - background-image: linear-gradient(rgb(105, 131, 255), rgb(48, 23, 110)); + padding-bottom: 4rem; + background-image: linear-gradient(rgb(48, 23, 110), rgb(105, 131, 255)); @include respond-min(768px) { - padding: 8rem 0; + padding: 0 0 8rem; } h2 { @@ -1837,10 +1833,9 @@ html.banner-hidden .banner { } .community-header { - h1 { text-align: center; - background-image: linear-gradient(rgb(59, 42, 102), rgb(78, 81, 191)); + background-image: linear-gradient(#382270, #4e51bf); padding: 80px; margin: 0 0 5rem; font-size: 4rem; @@ -1996,4 +1991,380 @@ html.banner-hidden .banner { } } } +} + +// Homepage Blog Cards with Featured Images +.homepage-blog-section { + display: flex; + flex-direction: column; + gap: 2rem; +} + +.homepage-blog-card { + background: #fff; + border-radius: 10px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; + transition: box-shadow 0.2s ease; + display: flex; + flex-direction: column; +} + +.homepage-blog-card-image { + width: 100%; + height: 100px; + object-fit: cover; + border-top-left-radius: 10px; + border-top-right-radius: 10px; +} + +.homepage-blog-card-image-placeholder { + width: 100%; + height: 100px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-top-left-radius: 10px; + border-top-right-radius: 10px; +} + +.homepage-blog-card-content { + padding: 1.5rem; + flex: 1; + display: flex; + flex-direction: column; +} + +.homepage-blog-card-title { + margin: 0 0 1rem 0; + font-size: 1.6rem; + line-height: 1.3; + font-weight: 700; + + a { + color: #002a3a; + text-decoration: none; + transition: color 0.2s ease; + } + + a:hover { + color: #667eea; + } +} + +.homepage-blog-card-description { + margin: 0 0 1.5rem 0; + font-size: 1.4rem; + line-height: 1.4; + color: #4a5568; + display: -webkit-box; + -webkit-line-clamp: 5; + -webkit-box-orient: vertical; + overflow: hidden; + flex: 1; +} + +.homepage-blog-card-readmore { + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1.2; + font-weight: 600; + font-size: 1.4rem; + padding: 0.8rem 1.6rem; + border: 1px solid #e2e8f0; + border-radius: 50px; + color: #2d3748; + text-decoration: none; + align-self: flex-start; + transition: all 0.2s ease; + background: #fff; +} + +.homepage-blog-card-readmore:hover { + background: #667eea; + color: #fff; + border-color: #667eea; +} + +// Responsive adjustments for homepage blog cards +@media (max-width: 768px) { + .homepage-blog-card-image, + .homepage-blog-card-image-placeholder { + height: 140px; + } + + .homepage-blog-card-content { + padding: 1.2rem; + } + + .homepage-blog-card-title { + font-size: 1.5rem; + } + + .homepage-blog-card-description { + font-size: 1.3rem; + } +} + +// Homepage Participant Carousel Styles +.homepage-participants-section { + background: linear-gradient(180deg, #6983FF 0%, #BCB5E7 100%); + padding: 8rem 0; + + .homepage-participants-container { + max-width: var(--max-width); + margin: 0 auto; + padding: 0 2rem; + } + + .homepage-participants-header { + text-align: center; + margin-bottom: 6rem; + } + + .homepage-participants-title { + color: $white; + font-size: 4.8rem; + font-weight: 700; + margin: 0 0 2rem 0; + letter-spacing: -1px; + } + + .homepage-participants-description { + color: $white; + font-size: 1.8rem; + line-height: 1.6; + max-width: 80rem; + margin: 0 auto; + opacity: 0.95; + } + + .homepage-participants-error { + background: $white; + border-radius: 2rem; + padding: 4rem; + text-align: center; + + p { + color: $text-light; + font-size: 1.6rem; + margin: 0; + } + } + + .homepage-participants-carousel-container { + background: $white; + border-radius: 2rem; + position: relative; + overflow: hidden; + } + + .homepage-participants-carousel { + overflow: hidden; + position: relative; + + .homepage-participants-track { + display: flex; + transition: transform 0.5s ease-in-out; + width: 100%; + } + + .homepage-participant-card { + flex: 0 0 33.33%; + min-width: 0; + min-height: 100%; + border-radius: 1.2rem; + padding: 4rem; + transition: all 0.3s ease; + cursor: pointer; + + .homepage-participant-image-container { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 2rem; + } + + .homepage-participant-image { + object-fit: contain; + max-height: 40px; + margin-inline: auto; + } + + .homepage-participant-image-placeholder { + width: 6rem; + height: 6rem; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: $white; + font-size: 2.4rem; + font-weight: 700; + text-transform: uppercase; + } + + .homepage-participant-name { + font-size: 2rem; + font-weight: 700; + color: $text; + text-align: center; + margin: 0 0 1.2rem 0; + line-height: 1.3; + } + + .homepage-participant-offering { + font-size: 1.4rem; + line-height: 1.5; + color: $text-light; + margin: 0; + text-align: center; + word-wrap: break-word; + overflow-wrap: break-word; + display: -webkit-box; + -webkit-line-clamp: 7; + -webkit-box-orient: vertical; + overflow: hidden; + + a { + color: $text-link-alternate; + text-decoration: none; + transition: color 0.2s ease; + + &:hover { + color: $text-link-alternate-lighter; + text-decoration: underline; + } + } + } + } + } + + .homepage-participants-navigation { + display: flex; + justify-content: center; + margin-top: 1.25rem; + + .homepage-participants-dots { + display: flex; + gap: 0.5rem; + align-items: center; + + .homepage-participant-dot { + width: 0.5rem; + height: 0.5rem; + border-radius: 50%; + border: none; + background: rgba($color: #000000, $alpha: 0.25); + cursor: pointer; + transition: all 0.2s ease; + padding: 0; + + &:hover, + &:focus { + background: #000; + transform: scale(1.1); + outline-offset: 2px; + } + + &[aria-current="true"], + &.active { + background: #000; + transform: scale(1.2); + } + } + } + } +} + +// Responsive design for homepage participant carousel +@media (max-width: 1200px) { + .homepage-participants-section { + .homepage-participants-carousel { + .homepage-participant-card { + flex: 0 0 50%; + } + } + } +} + +@media (max-width: 768px) { + .homepage-participants-section { + padding: 6rem 2rem; + + .homepage-participants-container { + padding: 0 1.5rem; + } + + .homepage-participants-title { + font-size: 3.6rem; + } + + .homepage-participants-description { + font-size: 1.6rem; + max-width: 100%; + } + + .homepage-participants-carousel { + .homepage-participant-card { + flex: 0 0 100%; + padding: 1.8rem; + + .homepage-participant-image-container { + margin-bottom: 1.5rem; + } + + .homepage-participant-name { + font-size: 1.8rem; + margin-bottom: 1rem; + } + + .homepage-participant-offering { + font-size: 1.3rem; + } + } + } + + .homepage-participants-navigation { + margin-top: 2rem; + + .homepage-participants-dots { + gap: 0.75rem; + + .homepage-participant-dot { + width: 0.75rem; + height: 0.75rem; + } + } + } + } +} + +@media (max-width: 480px) { + .homepage-participants-section { + .homepage-participants-carousel { + .homepage-participant-card { + padding: 1.5rem; + } + } + + .homepage-participants-title { + font-size: 3rem; + } + + .homepage-participants-description { + font-size: 1.5rem; + } + + .homepage-participants-navigation { + .homepage-participants-dots { + gap: 1rem; + + .homepage-participant-dot { + width: 1rem; + height: 1rem; + } + } + } + } } \ No newline at end of file diff --git a/static/assets/js/carousel.js b/static/assets/js/carousel.js new file mode 100644 index 00000000..467cd9af --- /dev/null +++ b/static/assets/js/carousel.js @@ -0,0 +1,212 @@ +/** + * Homepage Participant Carousel Module + * + * Features: + * - Auto-scrolling carousel with pause on hover + * - Responsive design (1/2/3 cards per slide based on screen size) + * - Keyboard navigation support + * - Intersection Observer for performance optimization + * - Accessibility features with ARIA labels + * + */ + +(function() { + 'use strict'; + + // Cache DOM elements to avoid repeated queries + let carousel, track, dots, cards; + let currentSlide = 0; + let autoScrollInterval = null; + let dotButtons = []; + let isVisible = true; + let resizeTimeout; + + /** + * Get number of cards per slide based on screen size + * @returns {number} Number of cards to show per slide + */ + function getCardsPerSlide() { + const width = window.innerWidth; + if (width <= 768) { + return 1; // Mobile: 1 card per slide + } else if (width <= 1200) { + return 2; // Tablet: 2 cards per slide + } else { + return 3; // Desktop: 3 cards per slide + } + } + + /** + * Update dots based on current screen size + */ + function updateDotsForScreenSize() { + const cardsPerSlide = getCardsPerSlide(); + const totalSlides = Math.ceil(cards.length / cardsPerSlide); + + // Clear existing dots + dots.innerHTML = ''; + + // Create new dots + for (let i = 0; i < totalSlides; i++) { + const dot = document.createElement('button'); + dot.className = 'homepage-participant-dot'; + dot.setAttribute('data-slide', i); + dot.setAttribute('aria-label', `Go to slide ${i + 1}`); + dot.setAttribute('aria-current', 'false'); + + dot.addEventListener('click', () => { + goToSlide(i); + }); + + dots.appendChild(dot); + } + + // Update reference to dot buttons + dotButtons = dots.querySelectorAll('.homepage-participant-dot'); + + // Ensure current slide is valid + if (currentSlide >= totalSlides) { + currentSlide = totalSlides - 1; + } + + updateDots(); + } + + /** + * Start auto-scroll functionality + */ + function startAutoScroll() { + if (dotButtons.length <= 1 || !isVisible) return; // Don't auto-scroll if only one slide or not visible + + autoScrollInterval = setInterval(() => { + currentSlide = (currentSlide + 1) % dotButtons.length; + updateCarousel(); + }, 5000); // 5 seconds + } + + /** + * Update carousel position + */ + function updateCarousel() { + const slideWidth = carousel.offsetWidth; + const translateX = -currentSlide * slideWidth; + track.style.transform = `translateX(${translateX}px)`; + updateDots(); + } + + /** + * Update dot states + */ + function updateDots() { + dotButtons.forEach((dot, index) => { + if (index === currentSlide) { + dot.setAttribute('aria-current', 'true'); + dot.classList.add('active'); + } else { + dot.setAttribute('aria-current', 'false'); + dot.classList.remove('active'); + } + }); + } + + /** + * Go to specific slide + * @param {number} slideIndex - Index of slide to navigate to + */ + function goToSlide(slideIndex) { + currentSlide = Math.max(0, Math.min(slideIndex, dotButtons.length - 1)); + updateCarousel(); + } + + /** + * Add keyboard support for participant cards + */ + function setupKeyboardSupport() { + cards.forEach(card => { + card.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + card.click(); + } + }); + }); + } + + /** + * Setup event listeners + */ + function setupEventListeners() { + // Pause auto-scroll on hover + carousel.addEventListener('mouseenter', () => { + if (autoScrollInterval) { + clearInterval(autoScrollInterval); + autoScrollInterval = null; + } + }); + + carousel.addEventListener('mouseleave', () => { + startAutoScroll(); + }); + + // Handle window resize with debouncing + window.addEventListener('resize', () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => { + updateDotsForScreenSize(); + updateCarousel(); + }, 250); + }); + + // Add Intersection Observer to pause carousel when not visible + if ('IntersectionObserver' in window) { + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + isVisible = entry.isIntersecting; + if (isVisible) { + startAutoScroll(); + } else if (autoScrollInterval) { + clearInterval(autoScrollInterval); + autoScrollInterval = null; + } + }); + }, { threshold: 0.1 }); + + observer.observe(carousel); + } + } + + /** + * Initialize the carousel + */ + function init() { + carousel = document.getElementById('homepageParticipantsCarousel'); + track = document.getElementById('homepageParticipantsTrack'); + dots = document.getElementById('homepageParticipantsDots'); + + if (!carousel || !track || !dots) { + console.warn('Participant carousel elements not found'); + return; + } + + cards = track.querySelectorAll('.homepage-participant-card'); + + if (cards.length === 0) { + console.warn('No participant cards found'); + return; + } + + // Setup carousel functionality + updateDotsForScreenSize(); + setupKeyboardSupport(); + setupEventListeners(); + startAutoScroll(); + } + + // Initialize when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + +})(); diff --git a/templates/includes/head.html b/templates/includes/head.html index f88b7882..7fb5dd95 100644 --- a/templates/includes/head.html +++ b/templates/includes/head.html @@ -52,6 +52,13 @@ + + + + + + + diff --git a/templates/includes/participant-carousel.html b/templates/includes/participant-carousel.html new file mode 100644 index 00000000..87a30a2c --- /dev/null +++ b/templates/includes/participant-carousel.html @@ -0,0 +1,61 @@ +{% set participants = load_data(path="_data/participants.yml") %} + +
+
+
+

Participants

+

+ The Valkey project participants are a diverse group of organizations that have come together to maintain and contribute to the project. Valkey participants are more than vendors, they are dedicated to continuously strengthening the long-term health and viability of this project so that everyone can benefit from it. Since its inception Valkey has enjoyed steady adoption demonstrating the industry's desire for an open, community-driven database solution. We look forward to seeing our list of participants grow as more companies work on our project. +

+
+ + {% if participants and participants | length > 0 %} + + +
+
+ {% set total_participants = participants | length %} + {% set total_slides = (total_participants / 3) | round(method="ceil") | int %} + {% if total_slides > 1 %} + {% for i in range(start=1, end=total_slides + 1) %} + + {% endfor %} + {% endif %} +
+
+ {% else %} +
+

Unable to load participant information at this time. Please try again later.

+
+ {% endif %} +
+ +
diff --git a/templates/index.html b/templates/index.html index 26df713e..9a7b6e29 100644 --- a/templates/index.html +++ b/templates/index.html @@ -15,62 +15,25 @@

{{ heading }}

{% endif %} -
-
-
- {{ section.content | safe }} -
-
-
- {% if section.extra and section.extra.documentation_cards %} - {% for card in section.extra.documentation_cards %} -
-
-

{{ card.title }}

-

{{ card.description }}

- {% if card.features %} -
    - {% for feature in card.features %} -
  • {{ feature }}
  • - {% endfor %} -
- {% endif %} - {{ card.button_text }} -
-
- {% endfor %} - {% endif %} -
-
-
-

What's New?

- -
+
-

Release Notes

-
- {% set release_section = get_section(path="download/releases/_index.md") %} - {% set releases = release_section.pages | reverse %} - - {% set_global active_releases = [] %} - {% for release in releases %} - {% if release.extra.tag is not matching(".*-.*") %} - {% set_global active_releases = active_releases | concat(with=release) %} - {% endif %} - {% endfor %} - - {% set most_recent_release_page = active_releases | slice(end= 1) %} - {% set release_date = most_recent_release_page[0].date %} - {% set release = most_recent_release_page[0].extra %} - - {% set split_ver = release.tag | split(pat=".")%} - {% set_global major = split_ver | nth(n= 0) %} - -

You can get the latest releases of Valkey from this page.

-

For installation instructions, supported package managers, and how to configure Valkey, see the installation page.

-

The releases page contains links to download all current and previous releases (including any security fixes for previous released versions).

-
+ {% set release_section = get_section(path="download/releases/_index.md") %} + {% set releases = release_section.pages | reverse %} + + {% set_global active_releases = [] %} + {% for release in releases %} + {% if release.extra.tag is not matching(".*-.*") %} + {% set_global active_releases = active_releases | concat(with=release) %} + {% endif %} + {% endfor %} + + {% set most_recent_release_page = active_releases | slice(end= 1) %} + {% set release_date = most_recent_release_page[0].date %} + {% set release = most_recent_release_page[0].extra %} + + {% set split_ver = release.tag | split(pat=".")%} + {% set_global major = split_ver | nth(n= 0) %}

Version {{major}}.x.x

@@ -95,33 +58,21 @@

Version {{major}}.x.x

Latest From Our Blog

-
+
{% set blog_post_section = get_section(path="blog/_index.md") %} {% set blog_posts = blog_post_section.pages | slice(end=2) %} {% for post in blog_posts %} -

{{ post.title }}

-

{{ post.description }}

+
+
+

{{ post.title }}

+

{{ post.description }}

+ Read More +
+
{% endfor %}
- - {% if section.extra and section.extra.repos_heading %} -

{{section.extra.repos_heading}}

- {% endif %} - -
- {% set repos = load_data(path="/_data/repos.yml") %} - {% for repo in repos %} - {% if repo.featured %} -

{{ repo.title }}

-

{{ repo.description }}

- {% endif %} - {% endfor %} - {% if section.extra and section.extra.github_org and section.extra.github_org_text %} - {{ section.extra.github_org_text }} - {% endif %} -
{% if section.extra and section.extra.sidebar %} {% for sidebar_category in section.extra.sidebar %} @@ -142,4 +93,34 @@

{{sidebar_category.title}}

+
+
+
+ {{ section.content | safe }} +
+
+
+ {% if section.extra and section.extra.documentation_cards %} + {% for card in section.extra.documentation_cards %} +
+
+

{{ card.title }}

+

{{ card.description }}

+ {% if card.features %} +
    + {% for feature in card.features %} +
  • {{ feature }}
  • + {% endfor %} +
+ {% endif %} + {{ card.button_text }} +
+
+ {% endfor %} + {% endif %} +
+
+ +{% include "includes/participant-carousel.html" %} + {%- endblock content -%} \ No newline at end of file