Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="app">
    <section class="player">
        <img class="player__cover" :src="currentTrack.cover.large" alt="" />
        <div class="player__timer">
            <div class="player__timer__elapsed" v-text="player.elapsed | time"></div>
            <div class="player__timer__total" v-text="currentTrack.duration | time"></div>
        </div>
        <div class="slider player__progress-bar">
            <input type="range" :value="player.elapsed" :max="currentTrack.duration" />
        </div>
        <ul class="player__controls">
            <li
                class="control control--small"
                v-bind:class="{
                    'control--active' : player.repeat,
                    'control--dimmed' : !player.repeat
                }"
                @click="toggleRepeat"
            >
                <svg class="icon" viewbox="0 0 100 100">
                    <use xlink:href="#repeat"></use>
                </svg>
            </li>
            <li class="control" @click="skipBack">
                <svg class="icon" viewbox="0 0 100 100" >
                    <use xlink:href="#skip-back"></use>
                </svg>
            </li>
            <li class="control control--outlined">
                <svg
                     class="icon"
                     viewbox="0 0 100 100"
                     @click="play"
                     v-if="!player.playing"
                >
                    <use xlink:href="#play"></use>
                </svg>
                <svg
                     class="icon"
                     viewbox="0 0 100 100"
                     @click="pause"
                     v-if="player.playing"
                >
                    <use xlink:href="#pause"></use>
                </svg>
            </li>
            <li class="control" @click="skipForward">
                <svg class="icon" viewbox="0 0 100 100">
                    <use xlink:href="#skip-forward"></use>
                </svg>
            </li>
            <li
                class="control control--small"
                v-bind:class="{
                    'control--active' : player.shuffle,
                    'control--dimmed' : !player.shuffle
                }"
                @click="toggleShuffle"
            >
                <svg class="icon" viewbox="0 0 100 100">
                    <use xlink:href="#shuffle"></use>
                </svg>
            </li>
        </ul>
        <h1 class="player__title" v-text="currentTrack.title"></h1>
        <h2 class="player__sub-title">{{currentTrack.album}} - {{currentTrack.artist}}</h2>
        <div class="player__volume">
            <div class="player__volume__icon">
                <svg class="icon" viewbox="0 0 100 100">
                    <use xlink:href="#volume"></use>
                </svg>
            </div>
            <div class="slider slider--volume player__volume__slider">
                <input type="range" :value="player.volume" max="100" />
            </div>
        </div>
    </section>
    <aside class="playlist">
        <header class="playlist__header">
            <h1 class="playlist__title" v-text="playlist.title"></h1>
            <div class="playlist__info">
                <a href="#" v-text="playlist.author"></a> - {{playlist.tracks.length}} songs, {{playlistDuration | minutes}} min
                <a href="#">
                    <svg class="icon icon--inline" viewbox="0 0 100 100">
                        <use xlink:href="#share"></use>
                    </svg>
                </a>
            </div>
        </header>
        <ol class="playlist__list">
            <li
                class="playlist__track"
                @click="selectTrack($index)"
                v-bind:class="{'playlist__track--active': player.currentTrack === $index}"
                v-for="track in playlist.tracks"
            >
                <img :src="track.cover.small" class="playlist__track__cover" />
                <div class="playlist__track__info">
                    <h3 class="playlist__track__title" v-text="track.title"></h3>
                    <span class="playlist__track__sub-title">{{track.album}} - {{track.artist}}</span>
                </div>
                <span class="playlist__track__time" v-text="track.duration | time"></span>
            </li>
        </ol>
    </aside>
</div>

<svg xmlns="http://www.w3.org/2000/svg" class="hide">
    <symbol id="play" viewBox="0 0 23.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M23 11.6L6.7 2.4c-1.4-.8-2.6 0-2.6 1.8V22c0 1.8 1.2 2.7 2.6 1.8L23 14.6c1.5-.8 1.5-2.2 0-3z" />
    </symbol>
    <symbol id="repeat" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M17.1 2.1v4h-10c-3.3 0-6 2.7-6 6 0 1 .3 1.9.7 2.8l2.5-1.8c-.1-.3-.2-.7-.2-1 0-1.7 1.3-3 3-3h10v4l8-5v-1l-8-5zm4.8 11c.1.3.2.7.2 1 0 1.7-1.3 3-3 3h-10v-4l-8 5v1l8 5v-4h10c3.3 0 6-2.7 6-6 0-1-.3-1.9-.7-2.8l-2.5 1.8z"
        />
    </symbol>
    <symbol id="share" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M23.1 23.1h-20v-20h10l2-2h-12c-1.1 0-2 .9-2 2v20c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2v-7l-2 2v5zm-18-2c3-8 7-8 13-8v4l7-7-7-7v4c-13 0-13 10-13 14z" />
    </symbol>
    <symbol id="shuffle" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M17.1 1.1v4h-3c-3.3 0-6 2.7-6 6v4c0 1.7-1.3 3-3 3h-4v3h4c3.3 0 6-2.7 6-6v-4c0-1.7 1.3-3 3-3h3v4l8-5v-1l-8-5zM6.4 8.4L8.2 6c-.9-.6-2-.9-3.1-.9h-4v3h4c.5 0 .9.1 1.3.3zm10.7 9.7h-3c-.5 0-.9-.1-1.3-.3L11 20.2c.9.6 2 .9 3.1.9h3v4l8-5v-1l-8-5v4z"
        />
    </symbol>
    <symbol id="skip-back" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M23.3 5.3l-8.2 4.8V6.7c0-1.3-.8-1.9-1.8-1.3L6.1 9.5V7.1c0-1.1-.9-2-2-2h-1c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h1c1.1 0 2-.9 2-2v-2.4l7.2 4.2c1 .6 1.8 0 1.8-1.3v-3.5l8.2 4.8c1 .6 1.8 0 1.8-1.3V6.7c0-1.4-.8-2-1.8-1.4z"
        />
    </symbol>
    <symbol id="skip-forward" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M23.1 5.1h-1c-1.1 0-2 .9-2 2v2.4l-7.2-4.2c-1-.6-1.8 0-1.8 1.3v3.5L2.9 5.3c-1-.6-1.8 0-1.8 1.3v12.9c0 1.3.8 1.9 1.8 1.3l8.2-4.8v3.5c0 1.3.8 1.9 1.8 1.3l7.2-4.2V19c0 1.1.9 2 2 2h1c1.1 0 2-.9 2-2V7c0-1-.9-1.9-2-1.9z"
        />
    </symbol>
    <symbol id="volume" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M21.1 13.1c0-3.3-2-6.2-4.9-7.4l-.8 1.8c2.2.9 3.7 3 3.7 5.5s-1.5 4.6-3.7 5.5l.8 1.8c2.9-1 4.9-3.9 4.9-7.2zm-4 0c0-1.7-1-3.1-2.5-3.7l-.8 1.8c.7.3 1.2 1 1.2 1.8s-.5 1.5-1.2 1.8l.8 1.8c1.5-.4 2.5-1.8 2.5-3.5zM17.7 2l-.8 1.8c3.6 1.5 6.2 5.1 6.2 9.2 0 4.2-2.5 7.7-6.2 9.2l.8 1.8c4.3-1.8 7.4-6.1 7.4-11.1s-3-9.1-7.4-10.9zM1.1 8.1v10h4l7 7v-24l-7 7h-4z"
        />
    </symbol>
    <symbol id="pause" viewBox="0 0 26.2 26.2">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M8.1 2.1h-4c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h4c1.1 0 2-.9 2-2v-18c0-1.1-.9-2-2-2zm14 0h-4c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h4c1.1 0 2-.9 2-2v-18c0-1.1-.9-2-2-2z" />
    </symbol>
</svg>
              
            
!

CSS

              
                // Variables
// =========

// Colors
// ------
$color__white: #fff;
$color__black: #3f3d34;
$color__gray: #7f7c6b;
$color__gray--dark: #4a473c;
$color__gray--light: #f2f2f2;
$color__yellow: #f9b94e;
$color__orange: #f9774e;
$color__beige: #ddd8c8;

// Font sizes
// -------
$font-size: 14;
$font-size--alpha: 1.95;
$font-size--beta: 1.5;

@mixin font-size($size){
    font-size: #{$size * $font-size}px;
    font-size: #{$size}rem;
    line-height: 1em;
    margin: 0 0 #{$size * $font-size / 2}px;
    margin: 0 0 #{$size / 2}rem;
}

// Widths
// ------
$width--main: 75em;
$width--player: 33em;
$width--playlist: $width--main - $width--player;

// Spacing
// -------
$spacing: 2rem;
$spacing--large: 3rem;
$spacing--small: 1rem;


// Base
// ====
*,
*:before,
*:after {
    box-sizing: border-box;
}

html {
    background-color: $color__orange;
    background-image: linear-gradient(
        135deg,
        $color__yellow 0%,
        $color__orange 100%
    );
    font-size: #{$font-size}px;
    font-family: Nunito, arial, sans-serif;
    font-weight: 400;
    min-height: 100%;
}

.app {
    color: $color__black;
    box-shadow: 0 0 $spacing--small rgba($color__black, .6);
    display: flex;
    flex-wrap: wrap;
    margin: 0 auto;
    max-width: $width--main;
    padding: 0;
    width: 100%;
    
    @media (min-width: $width--playlist) {
        margin: $spacing--small auto;
    }
    
    @media (min-width: $width--main) {
        margin: $spacing auto;
    }
}

// Generic
// -------
a {
    color: $color__orange;
    text-decoration: none;
    transition: color .4s;
    
    &:hover,
    &:focus {
        color: lighten($color__orange, 10%);
    }
}

img {
    height: auto;
    max-width: 100%;
}

// Components
// ==========

// Slider
// ------

$slider-height: 8px;
$slider__thumb-height: 20px;
$slider__thumb-width: 6px;

.slider {
    line-height: 1em;
    overflow: hidden;
    padding: ($slider__thumb-height - $slider-height) / 2 0;
    
    [type=range] {
        appearance: none;
        background: $color__gray--light;
        height: $slider-height;
        position: relative;
        width: 100%;
        
        &:focus {
            outline: none;
        }

        &::-webkit-slider-thumb {
            appearance: none;
            background-color: $color__black;
            border-radius: 99px;
            cursor: pointer;
            height: $slider__thumb-height;
            position: relative;
            transition: transform .2s;
            width: $slider__thumb-width;
            
            &:focus,
            &:active {
                transform: scale(1.3);
            }

            &:after {
                background: $color__orange;
                bottom: 0;
                content: '';
                display: block;
                height: $slider-height;
                margin-top: 0 - ($slider-height / 2);
                pointer-events: none;
                position: absolute;
                right: $slider__thumb-width;
                top: 50%;
                width: 999px;
            }
        }
    }
          
    &--volume {        
        [type=range] {
            &::-webkit-slider-thumb {
                background-color: $color__white;
                border: 3px solid $color__orange;
                width: $slider__thumb-height;
                
                &:after {
                    right: $slider__thumb-height - 6;
                }
            }
        }
    }
}

// Icon
// ----
.icon {
    fill: currentcolor;
    height: 100%;
    width: 100%;
    
    &--inline {
        display: inline-block;
        height: 1em;
        width: 1em;
    }
}

// Control
// -------
.control {
    cursor: pointer;
    margin: 0;
    padding: $spacing--small;
    transition: opacity .4s, color .4s;
    
    &:hover,
    &:focus {
        opacity: .8;
    }
    
    &:active {
        color: $color__orange;
        transition: none;
    }
    
    &--small {
        transform: scale(.4);
    }
    
    &--dimmed {
        opacity: .6;
    }
    
    &--outlined {
        border: 2px solid $color__gray--light;
        border-radius: 100%;
    }
    
    &--active {
        color: $color__orange;
    }
}


// UI
// ====

// Player
// ------
.player {
    background: $color__white;
    text-align: center;
    width: 100%;
    
    @media (min-width: $width--player) {
        width: percentage($width--player / $width--main);
    }
    
    &__title {
        @include font-size($font-size--alpha);
    }
    
    &__sub-title {
        @include font-size($font-size--beta);
        
        color: $color__gray;
        font-weight: 400;
    }
    
    &__cover {
        display: block;
        width: 100%;
    }
    
    &__timer {
        background: $color__beige;
        display: flex;
        justify-content: space-between;
        padding: $spacing--small;
    }
    
    &__progress-bar {
        margin-top: 0 - $spacing--small;
    }
    
    &__controls {
        display: flex;
        list-style: none;
        padding: $spacing--small $spacing;
    }
    
    &__volume {
        display: flex;
        padding: $spacing;
        
        &__icon {
            width: $spacing;
            height: $spacing;
            margin-right: $spacing--small;
        }
        
        &__slider {
            width: 100%;
        }
    }
}


// Playlist
// --------
.playlist {
    background: $color__gray--dark;
    color: $color__gray--light;
    width: 100%; 
    
    @media (min-width: $width--player) {
        width: percentage($width--playlist / $width--main);
    }
    
    &__header {
        background: $color__black;
        padding: $spacing--large;
    }
    
    &__title {
        @include font-size($font-size--alpha);
        
        margin-top: 0;
    }
    
    &__info {
        
    }
    
    &__list {
        list-style: none;
        margin: 0;
        padding: 0 $spacing--large;
    }
    
    &__track {
        border-bottom: 1px solid $color__black;
        cursor: pointer;
        display: flex;
        justify-content: space-between;
        margin: 0;
        padding: $spacing 0;
        
        &--active {
            color: $color__orange;
        }
        
        &__cover {
            height: $spacing--large;
            width: $spacing--large;
        }
        
        &__info {
            margin: 0 $spacing;
            width: 100%;
        }
        
        &__title {
            @include font-size($font-size--beta);
        }
    }
}


// Overrides
// =========
.hide.hide {
    display: none;
}
              
            
!

JS

              
                console.clear();

// Filters
// =======
Vue.filter('time', function(seconds) {
    var minutes = Math.floor(seconds / 60),
        seconds = Math.floor(seconds % 60);

    if (seconds < 10) {
        seconds = '0' + seconds;
    }

    return minutes + ':' + seconds;
});

Vue.filter('minutes', function(seconds) {
    var minutes = Math.floor(seconds / 60);
    
    return minutes;
})

// App
// =====
new Vue({
    el: '.app',
    data: function() {
        return {
            player: {
                currentTrack: 0,
                elapsed: 0,
                playing: false,
                repeat: false,
                shuffle: true,
                volume: 68
            },
            playlist: {
                title: 'Designers MX - Open Space',
                author: 'Kyle Barret',
                tracks: [{
                    title: 'Window',
                    artist: 'The Album Leaf',
                    album: 'In a Safe Place',
                    duration: 274,
                    cover: {
                        small: 'http://is5.mzstatic.com/image/pf/us/r30/Music/y2004/m06/d11/h18/s05.tjsjltyd.100x100-75.jpg',
                        large: 'https://yuq.me/albums/79/690/3374011100.jpg'
                    }
                }, {
                    title: 'Dayvan Cowboy',
                    artist: 'Boards of Canada',
                    album: 'The Campfire Headphase',
                    duration: 300,
                    cover: {
                        small: 'http://static.metacritic.com/images/products/music/8/a0c6c84a9d3ef6a577aee9a32d0b5b6f-98.jpg',
                        large: 'http://boardsofcanada.com/vinyl-reissues/_/img/WARPLP123R-Packshot-800.jpg'
                    }
                }, {
                    title: 'Adrift',
                    artist: 'Tycho',
                    album: 'Awake',
                    duration: 283,
                    cover: {
                        small: 'http://cdn.ghostly.com/images/artists/34/albums/454/GI-208_1500x300_188_188.jpg',
                        large: 'http://cdn.ghostly.com/images/artists/34/albums/454/GI-208_1500x300_540_540.jpg'
                    }
                }, {
                    title: 'Arrival at Sydney Harbour',
                    artist: 'Port Blue',
                    album: 'The Airship',
                    duration: 306,
                    cover: {
                        small: 'https://upload.wikimedia.org/wikipedia/ru/thumb/3/31/Port_Blue_-_The_Airship.jpg/200px-Port_Blue_-_The_Airship.jpg',
                        large: 'https://upload.wikimedia.org/wikipedia/en/8/8f/Theairship.jpg'
                    }
                }, {
                    title: 'The Backwards Step',
                    artist: 'Hammock',
                    album: 'Chasing After Shadows',
                    duration: 289,
                    cover: {
                        small: 'https://upload.wikimedia.org/wikipedia/en/thumb/3/36/Chasing_after_shadows.jpg/100px-Chasing_after_shadows.jpg',
                        large: 'http://f1.bcbits.com/img/a3547927520_10.jpg'
                    }
                }]
            }
        }
    },
    computed: {
        currentTrack: function() {
            return this.playlist.tracks[this.player.currentTrack];
        },
        playlistDuration: function() {
            var duration = 0,
                tracks = this.playlist.tracks,
                i;
            
            for (i = 0; i < tracks.length; i += 1) {
                duration += tracks[i].duration;
            }
            
            return duration;
        }
    },
    methods: {
        pause: function() {
            if (!this.player.playing) {
                return;
            }
            this.$set('player.playing', false);
            clearInterval(this.timer);
            this.$set('timer', false);
        },
        play: function() {
            if (this.player.playing) {
                return;
            }
            var _this = this,
                timer = setInterval(function() {
                    if (_this.player.elapsed >= _this.currentTrack.duration) {
                        _this.$set('player.elapsed', 0);
                        _this.skipForward();
                    }
                    _this.player.elapsed += .1;
                }, 100);
            
            this.$set('player.playing', true);
            this.$set('timer', timer);
        },
        selectTrack: function(id) {
            this.$set('player.currentTrack', id);
            this.$set('player.elapsed', 0);
            this.play();
        },
        skipForward: function() {
            var track = this.player.currentTrack + 1;
            
            track = track % this.playlist.tracks.length;
            this.selectTrack(track);
        },
        skipBack: function() {
            var track = this.player.currentTrack;
            
            if (this.player.elapsed < 2) {
                track = track - 1;
            }
            
            if (track < 0) {
                track = 0;
            }
            
            this.selectTrack(track);
        },
        toggleRepeat: function() {
            this.player.repeat = !this.player.repeat;
        },
        toggleShuffle: function() {
            this.player.shuffle = !this.player.shuffle;
        }
    }
});
              
            
!
999px

Console