Iniciar a sua viagem transfronteiriça
Contactar-nos agora

Desenvolvimento de sítios Web serviço ao cliente

Serviço ao cliente

Designer (realização de protótipos Figma)

Wrodpress Categoria de produto Comutação esquerda/direita

[category_carousel ids="19,21,23,25,27,29"]
产品分类左右滑动

add_shortcode('category_carousel', function($atts) {
    $cat_ids = !empty($atts['ids']) ? explode(',', $atts['ids']) : [];
    if (empty($cat_ids)) return '';
    $per_row = 3;
    $cats = get_terms([
        'taxonomy'   => 'product_cat',
        'include'    => $cat_ids,
        'hide_empty' => false,
        'orderby'    => 'include',
    ]);
    if (empty($cats) || is_wp_error($cats)) return '';

    $groups = array_chunk($cats, $per_row);
    $total_groups = count($groups);

    ob_start();
    ?>
    <div class="cat-carousel-wrap">
        <div class="cat-carousel-inner">
            <?php foreach ($groups as $g=>$group): ?>
            <div class="cat-carousel-group<?php if($g==0) echo ' active'; ?>" data-group="<?php echo $g; ?>">
                <?php foreach ($group as $cat):
                    $img_id = get_term_meta($cat->term_id, 'thumbnail_id', true);
                    $img_url = $img_id ? wp_get_attachment_image_url($img_id, 'large') : wc_placeholder_img_src();
                    ?>
                    <a href="<?php echo get_term_link($cat); ?>" class="cat-carousel-card">
                        <div class="cat-carousel-img-wrap">
                            <div class="cat-carousel-img" style="background-image:url('<?php echo esc_url($img_url); ?>')"></div>
                        </div>
                        <div class="cat-carousel-title"><?php echo esc_html($cat->name); ?></div>
                    </a>
                <?php endforeach; ?>
            </div>
            <?php endforeach; ?>

            <div class="cat-carousel-group-mobile">
                <?php foreach ($cats as $cat):
                    $img_id = get_term_meta($cat->term_id, 'thumbnail_id', true);
                    $img_url = $img_id ? wp_get_attachment_image_url($img_id, 'large') : wc_placeholder_img_src();
                ?>
                <a href="<?php echo get_term_link($cat); ?>" class="cat-carousel-card">
                    <div class="cat-carousel-img-wrap">
                        <div class="cat-carousel-img" style="background-image:url('<?php echo esc_url($img_url); ?>')"></div>
                    </div>
                    <div class="cat-carousel-title"><?php echo esc_html($cat->name); ?></div>
                </a>
                <?php endforeach; ?>
            </div>
        </div>
        <button class="cat-carousel-btn prev" aria-label="Previous">
            <svg fill="#000000" viewBox="0 0 24 24" id="left-circle-1" data-name="Flat Line" xmlns="http://www.w3.org/2000/svg" class="icon flat-line" width="44" height="44"><g><circle cx="12" cy="12" r="9" style="fill: #F05B2D; stroke-width: 2;"></circle><polyline points="13 9 10 12 13 15" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></polyline><circle cx="12" cy="12" r="9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></circle></g></svg>
        </button>
        <button class="cat-carousel-btn next" aria-label="Next">
            <svg fill="#000000" viewBox="0 0 24 24" id="right-circle" data-name="Flat Line" xmlns="http://www.w3.org/2000/svg" class="icon flat-line" width="44" height="44"><g><circle cx="12" cy="12" r="9" style="fill: #F05B2D; stroke-width: 2;"></circle><polyline points="11 15 14 12 11 9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></polyline><circle cx="12" cy="12" r="9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></circle></g></svg>
        </button>
        <div class="cat-carousel-progress">
            <div class="cat-carousel-progress-bg"></div>
            <div class="cat-carousel-progress-bar"></div>
        </div>
    </div>
    <style>
    @import url('https://fonts.googleapis.com/css2?family=Marcellus:wght@400&display=swap');
    .cat-carousel-wrap { width:100%; margin:0 auto 24px auto; position:relative; box-sizing:border-box; padding:0; max-width:100vw;}
    .cat-carousel-inner { position:relative; width:100%;}
    .cat-carousel-group, .cat-carousel-group-mobile { display:none; }
    .cat-carousel-group.active { display:flex; flex-wrap:nowrap; width:100%; animation:fadeIn .6s; justify-content:flex-start; align-items:stretch; gap:30px;}
    .cat-carousel-card { flex:1 1 0; max-width:calc((100% - 60px)/3); min-width:0; background:#fff; text-decoration:none; color:#222; display:flex; flex-direction:column; align-items:flex-start; border-radius:0; overflow:hidden; margin:0; box-shadow:none !important; border:none; position:relative; transition:none;}
    .cat-carousel-img-wrap { width:100%; aspect-ratio:3/2; position:relative; overflow:hidden; background:#f7f7f7;}
    .cat-carousel-img { width:100%; height:100%; background-size:cover; background-position:center; background-repeat:no-repeat; transition:transform .42s cubic-bezier(.28,.62,.37,1.18), box-shadow .38s; will-change:transform; box-shadow:none;}
    .cat-carousel-card:hover .cat-carousel-img { transform:scale(1.06) translateY(-4px); box-shadow:0 6px 38px #f05b2d44; z-index:2;}
    .cat-carousel-title { padding:12px 0 6px 0; font-family:'Marcellus',serif !important; font-size:24px; color:#222; text-align:left; font-weight:400; width:100%; border-radius:0; letter-spacing:0; line-height:1.2; margin:0;}
    .cat-carousel-btn, .cat-carousel-btn:active, .cat-carousel-btn:focus, .cat-carousel-btn:hover { background:transparent !important; box-shadow:none !important; border:none !important; outline:none !important;}
    .cat-carousel-btn { position:absolute; top:50%; transform:translateY(-50%); z-index:5; width:54px; height:54px; border-radius:50%; cursor:pointer; opacity:0; pointer-events:none; transition:opacity .22s; display:flex; align-items:center; justify-content:center; padding:0; visibility:visible;}
    .cat-carousel-btn.hidden { display:none !important;}
    .cat-carousel-btn svg { background:none !important;}
    .cat-carousel-btn.prev { left:-27px;}
    .cat-carousel-btn.next { right:-27px;}
    .cat-carousel-wrap:hover .cat-carousel-btn { opacity:1; pointer-events:auto;}
    .cat-carousel-progress { width:100%; height:2px; margin:40px 0 0 0; position:relative; background:none; z-index:1; user-select:none; pointer-events:none;}
    .cat-carousel-progress-bg { position:absolute; top:0; left:0; width:100%; height:100%; background:#D9DFD7; border-radius:3px; z-index:0;}
    .cat-carousel-progress-bar { position:absolute; top:0; left:0; height:100%; width:0; background:#2E4D37; border-radius:3px; z-index:1; transition:width .35s cubic-bezier(.44,.67,.6,1.12);}
    @keyframes fadeIn { from { opacity:0; transform:translateY(30px);} to { opacity:1; transform:none;}}
    @media (max-width:700px) {
        .cat-carousel-wrap { margin:0 auto 12px auto;}
        .cat-carousel-group { display:none !important;}
        .cat-carousel-group-mobile { display:flex !important; flex-direction:row; gap:10px; overflow-x:auto; overflow-y:hidden; scroll-snap-type:x mandatory; -webkit-overflow-scrolling:touch; justify-content:flex-start; width:100%;}
        .cat-carousel-card { flex:0 0 calc((100vw - 10px)/1.5); max-width:calc((100vw - 10px)/1.5); min-width:160px; scroll-snap-align:start;}
        .cat-carousel-img-wrap { aspect-ratio:3/2;}
        .cat-carousel-title { font-size:16px; padding:8px 0 4px 0;}
        .cat-carousel-btn { display:none !important;}
        .cat-carousel-group-mobile::-webkit-scrollbar { display:none; height:0;}
        .cat-carousel-group-mobile { -ms-overflow-style:none; scrollbar-width:none;}
        .cat-carousel-progress { margin:8px 0 0 0;}
    }
    </style>
    <script>
    (function(){
        var wrap = document.currentScript.parentElement,
            groups = wrap.querySelectorAll('.cat-carousel-group'),
            groupMobile = wrap.querySelector('.cat-carousel-group-mobile'),
            btnPrev = wrap.querySelector('.cat-carousel-btn.prev'),
            btnNext = wrap.querySelector('.cat-carousel-btn.next'),
            progressBar = wrap.querySelector('.cat-carousel-progress-bar');
        var total = groups.length, current = 0;

        function updateCarousel(idx){
            groups.forEach(function(g, i){ g.classList.toggle('active', i === idx); });
            if(progressBar) progressBar.style.width = ((idx+1)/total*100)+'%';
            if(btnPrev) btnPrev.classList.toggle('hidden', idx===0);
            if(btnNext) btnNext.classList.toggle('hidden', idx===total-1);
        }
        if(btnPrev) btnPrev.onclick = function(){ if(current>0) current--; updateCarousel(current);}
        if(btnNext) btnNext.onclick = function(){ if(current<total-1) current++; updateCarousel(current);}
        wrap.tabIndex = 0;
        wrap.addEventListener('keydown', function(e){
            if(e.key==="ArrowLeft") btnPrev && btnPrev.click();
            if(e.key==="ArrowRight") btnNext && btnNext.click();
        });

        function isMobile(){ return window.innerWidth <= 700; }
        function setMobileProgress(){
            if(!isMobile() || !groupMobile || !progressBar) return;
            var scrollL = groupMobile.scrollLeft, w = groupMobile.scrollWidth, vw = groupMobile.clientWidth;
            var maxScroll = w-vw;
            var percent = maxScroll>0 ? Math.min(scrollL/maxScroll,1) : 0;
            if(scrollL<=1) percent = (vw/w);
            progressBar.style.width = (percent*100)+'%';
        }
        if(groupMobile){
            groupMobile.addEventListener('scroll', setMobileProgress, {passive:true});
            window.addEventListener('resize', function(){
                if(isMobile()) setMobileProgress();
                else updateCarousel(current);
            });
        }
        if(isMobile()) setMobileProgress(); else updateCarousel(current);
        window.addEventListener('resize', function(){
            if(isMobile()) setMobileProgress();
            else updateCarousel(current);
        });
    })();
    </script>
    <?php
    return ob_get_clean();
});