<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Bike Finder</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div id="app">
        <product></product>
    </div>
</body>

</html>
.question-section {
    margin-bottom: 2rem;
}

.container__question {
    margin-bottom: 2rem;
}

input[type="checkbox"].favourite-brand {
    display: none;
}

input[type="checkbox"].favourite-brand#apollo+label {
    background-image: url('images/brands/brand_apollo.png')
}

input[type="checkbox"].favourite-brand#assist+label {
    background-image: url('images/brands/brand_assist.png')
}

input[type="checkbox"].favourite-brand#boardman+label {
    background-image: url('images/brands/brand_boardman.png')
}

input[type="checkbox"].favourite-brand#carrera+label {
    background-image: url('images/brands/brand_carrera.png')
}

input[type="checkbox"].favourite-brand#voodoo+label {
    background-image: url('images/brands/brand_voodoo.png')
}

label.favourite-brand {
    display: inline-block;
    margin-right: 1rem;
    width: 200px;
    height: 200px;
    cursor: pointer;
    background-color: #66a1bf;
    background-position: center center;
    background-repeat: no-repeat;
    background-size: 100%;
    transition: background-size 0.1s linear;
}

input.favourite-brand:checked+label {
    background-size: 90%;
    background-color: #244f66;
}

.container__answer--colours{
    display: flex;
}

input[type="checkbox"].colour {
    display: none;
}

label.colour {
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    margin-right: 1rem;
    width: 50px;
    height: 50px;
    cursor: pointer;
    border: 1px solid black;
    border-radius: 50%;
    opacity: 1;
}

input#multicoloured+label{
    background: rgb(255,0,0);
    background: -moz-linear-gradient(180deg, rgba(255,0,0,1) 0%, rgba(255,158,0,1) 10%, rgba(255,248,0,1) 25%, rgba(91,255,0,1) 40%, rgba(0,224,255,1) 55%, rgba(0,22,255,1) 70%, rgba(192,0,255,1) 85%, rgba(255,0,219,1) 100%);
    background: -webkit-linear-gradient(180deg, rgba(255,0,0,1) 0%, rgba(255,158,0,1) 10%, rgba(255,248,0,1) 25%, rgba(91,255,0,1) 40%, rgba(0,224,255,1) 55%, rgba(0,22,255,1) 70%, rgba(192,0,255,1) 85%, rgba(255,0,219,1) 100%);
    background: linear-gradient(180deg, rgba(255,0,0,1) 0%, rgba(255,158,0,1) 10%, rgba(255,248,0,1) 25%, rgba(91,255,0,1) 40%, rgba(0,224,255,1) 55%, rgba(0,22,255,1) 70%, rgba(192,0,255,1) 85%, rgba(255,0,219,1) 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff0000",endColorstr="#ff00db",GradientType=1);
}

label.colour::before {
    content: " ";
    position: absolute;
    height: 25px;
    transition-duration: 0.4s;
}

input.colour:checked+label.colour::before {
    content: '✓';
    color: #66a1bf;
}

.product-feed{
    display: grid;
    flex-direction: row;
    grid-template-columns: repeat(4, 0.25fr);
    grid-gap: 1rem;
}

.product-feed__item{
    padding: 1rem;
    outline: 1px solid grey;
    border-radius: 10px;
}

.product-feed__item--womens{
    background-color: lightpink;
}

.product-feed__item--mens{
    background-color: lightblue;
}

.product-feed__item--neutral{
    background-color: lightgray;
}

.product-feed__item--kids{
    background-color: lightgreen;
}

.product-feed__item__brand{
    font-weight: 600;
    text-transform: capitalize;
}

.product-feed__item__image{
    width: 100%;
}

.product-feed__item__gender{
    text-transform: capitalize;
}
Vue.component('product', {
    props: {

    },
    template: `
    <div class="container">
        <h2>About You</h2>
        <div class="question-section question-section--aboutyou">
            <div class="container__question">
                <strong>Preferred bike category?</strong>
                <div>
                    <template v-for="category in filterCategories">
                    <label :for="category">
                        <input type="radio" :id="category" :name="category" :value="category" v-model="selectedCategory">{{category}}</label>
                    </template>
                </div>
            </div>
            <div class="container__question">
                <strong>What terrain do you normally ride on?</strong>
                <div>
                    <template v-for="terrain in filterTerrains">
                        <input type="checkbox" :id="terrain" :name="terrain" :key="terrain" v-model="selectedTerrains"><label :for="terrain">{{terrain}}</label>
                    </template>
                </div>
            </div>
        </div>
        <h2>Products:</h2>
        <div class="product-feed">
            <div v-for="bike in filterBikes" :key="bike.id" class="product-feed__item" :class="'product-feed__item--' + bike.category">
                <span class="product-feed__item__brand">{{ bike.brand }} {{ bike.name }}</span> - <span class="product-feed__item__category">{{ bike.category }}</span>
                <img :src="'images/' + bike.category + '/' + bike.image" class="product-feed__item__image" />
            </div>
        </div>
    </div>
    `,

    data() {
        return {
            selectedCategory: '',
            selectedTerrains: [],
            "bikes": [
                {
                    id: 1,
                    image: "womens_hybrid_apollo_cosmo_blue.jpg",
                    terrain: "gravel",
                    category: "womens",
                    type: "hybrid",
                    brand: "apollo",
                    name: "cosmo",
                    colour: "blue",
                    gears: 18,
                    suspension: "none",
                    brakeType: "v-brakes",
                    electricMilesMaxRange: null,
                    inStock: true,
                    stockLeadtimeWeeks: null,
                    pricePounds: 205,
                    priceEuros: null
                },
                {
                    id: 2,
                    image: "mens_hybrid_boardman_hyb89_blue.jpg",
                    terrain: "road",
                    category: "mens",
                    type: "hybrid",
                    brand: "boardman",
                    name: "hyb89",
                    colour: "blue",
                    gears: 20,
                    suspension: "hard tail",
                    brakeType: "hydraulic disc brakes",
                    electricMilesMaxRange: null,
                    inStock: true,
                    stockLeadtimeWeeks: 2,
                    pricePounds: 750,
                    priceEuros: null
                },
                {
                    id: 3,
                    image: "mens_hybrid_carrera_code_orange.jpg",
                    terrain: "gravel",
                    category: "mens",
                    type: "hybrid",
                    brand: "carrera",
                    name: "code",
                    colour: "orange",
                    gears: 16,
                    suspension: "hard tail",
                    brakeType: "mechanical disc brakes",
                    electricMilesMaxRange: null,
                    inStock: true,
                    stockLeadtimeWeeks: null,
                    pricePounds: 350,
                    priceEuros: null
                },
                {
                    id: 4,
                    image: "mens_mountain_apollo_valier_green.jpg",
                    terrain: "mountain",
                    category: "mens",
                    type: "mountain",
                    brand: "apollo",
                    name: "valier",
                    colour: "green",
                    gears: 21,
                    suspension: "hard tail",
                    brakeType: "mechanical disc brakes",
                    electricMilesMaxRange: null,
                    inStock: true,
                    stockLeadtimeWeeks: 4,
                    pricePounds: 228,
                    priceEuros: null
                },
                {
                    id: 5,
                    image: "neutral_adventure_voodoo_limba_green.jpg",
                    terrain: "mountain",
                    category: "neutral",
                    type: "adventure",
                    brand: "voodoo",
                    name: "limba",
                    colour: "green",
                    gears: 16,
                    suspension: "none",
                    brakeType: "mechanical disc brakes",
                    electricMilesMaxRange: null,
                    inStock: true,
                    stockLeadtimeWeeks: 2,
                    pricePounds: 428,
                    priceEuros: null
                },
            ]

        }
    },
    methods: {
        cleanData(dataType, dataToClean) {
            const cleanData = [];
            let multiColouredDuplicate = false;

            // Loop through data to clean based on amount of data
            for (let i = 0; i < dataToClean.length; i++) {

                // Grab data at index
                let filteredData = dataToClean[i];
                let spaceFound;

                // If data is a string, find spaces
                if (typeof filteredData === "string") {
                    spaceFound = filteredData.indexOf(' ') > 0;
                }

                // If dataType is colour, check for duplicate colour names
                if (dataType === "colour") {

                    // If space found but duplicate multicoloured result, skip
                    if (spaceFound && multiColouredDuplicate) {
                        multiColouredDuplicate = false;
                        continue;

                        // If space found and first multicoloured
                    } else if (spaceFound && !multiColouredDuplicate) {
                        filteredData = "multicoloured";
                        multiColouredDuplicate = true;
                    }
                }

                // Return filteredData value
                cleanData.push(filteredData);
            }

            return cleanData;
        },
    },
    computed: {
        filterCategories() {
            const typeCategory = "category";
            const filterCategories = Array.from(new Set(this.bikes.map(bike => bike.category)));

            let formatCategories = this.cleanData(typeCategory, filterCategories);

            return formatCategories;
        },
        filterTerrains() {
            const typeTerrain = "terrain";
            const filterTerrains = Array.from(new Set(this.bikes.map(bike => bike.terrain)));

            let formatTerrains = this.cleanData(typeTerrain, filterTerrains);

            return formatTerrains;
        },
        filterBikes() {
            if (this.selectedCategory) {
                return this.bikes.filter(bike => bike.category === this.selectedCategory);
            } else if(this.selectedTerrains.length > 0){
                console.log(this.selectedTerrains);

                for(terrain of this.selectedTerrains){
                    return this.bikes.filter(bike => bike.terrain === terrain);
                }
            } else {
                return this.bikes;
            }
        },
    }

})

// Creates new Vue instance with options
var app = new Vue({

    // Property to connect to div with 'app' ID
    el: '#app',
    data: {
        premium: true
    }
})
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js