player final

Build a Music Player With Vuetify

Final product image
What You’ll Be Creating

Building apps with Vue.js is easy, fun, and enjoyable. You can build a working app with minimum effort. To prove that, today I’ll show you how easy it is to build your own full-featured music player. To make things even easier, we’ll use Vuetify.js, a Vue.js powered UI library, which will speed up the UI construction. I can almost feel your impatience, so let’s get started. 

You can find the full source code in the GitHub repo. And here is the working demo. To follow this tutorial, you should be familiar with Vue components, Vue single file components, and ES2015 syntax.

Planning the App

Every creation starts with an idea and at least some basic planning. So first we need to decide what we want to build and what functionality we want to implement. It’s said that a picture is worth a thousand words, so let’s start with a simple sketch of the music player.

Vue music player wireframe sketch

I made this wireframe so you can get a general notion of the UI we want to build. The next step is to describe the functionality we intend to implement.

As John Johnson says: 

First, solve the problem. Then, write the code.

We’ll use that as a source of wisdom, and we’ll plan the app out before we start coding it.

App Components

Vue.js is a component-based framework. So we need first to split the app into individual components (five in our case, as shown in the sketch above), and to outline the features and functionality for each of them. 

Title Bar

This component will contain the following parts:

  • a menu on the left side
  • the name of the app in the center
  • three static icons on the right side

Info Panel

This component will show basic information about the currently played track:

  • the track’s artist and title on the left side
  • the current track’s position and duration on the right side

Control Bars

This component will contain two bars, which will include all the controls necessary to manipulate the audio tracks in the player’s playlist.

  • a volume slider with an icon on the left (its appearance will change according to the volume level and when the sound is muted), and volume percentage on the right
  • buttons for playing, pausing, stopping, and skipping the tracks.
  • two buttons on the far right: one for repeating the current track, and one for shuffling the tracks’ order of playing
  • a seek bar showing the currently played track’s position, with the ability to change it with a mouse click on the bar

Playlist Panel

This component will contain the tracks’ playlist with the following functionality:

  • display a track with the proper number, artist, title, and duration properties
  • select a track on single click
  • play a track on double click

Search Bar

This component will offer search functionality in the cases when we want to find and play particular track(s).

Of course, the above outline cannot cover all the details and nuances, and this is perfectly fine. For now, it’s enough for us to get an overall picture of the final product. We’ll handle all the details and eventual challenges during the building process.

So let’s get into the fun part and write some code!

Getting Started

Vuetify’s quick start page offers plenty of options to get you started. We’ll use one of the pre-made Vue CLI templates called Webpack Simple. Run the following commands in the directory you want to use for this project:

First, install Vue CLI:

Then, create the app: 

Next, go to the app’s directory and install all dependencies: 

We’ll use Howler.js (a JavaScript audio library) to handle the audio parts of the music player. So we need to include it in the project too. Run the following command:

And finally, run the app:

The app will open on localhost:8080 in your default browser. You should see a simple Vuetify app skeleton. 

Tweaking the Template

To adjust it to our needs, we need to clean up the template and tweak it a bit. Rename the App.vue file to Player.vue, open it, delete everything inside, and add the following instead:

We wrap our music player app in the v-app component, which is required for the app to work properly. We also pass the dark prop, to apply the Vuetify dark theme.

Now, open the main.js file, delete the original content, and add the following:

Also, open the index.html file and change the content of the </code> tag to <em>Vue Music Player</em>.</p> <p>Now, in your browser, you should see an empty dark page. And voila. You are ready to start creating.</p> <p>Before you start coding, it’s good to know that Vuetify offers code snippets and autocompletion for the major code editors: VS Code, Atom, and Sublime. To get the snippets, search for the extension in your favorite editor (<code class="inline">vuetify-vscode</code>, or <code class="inline">vuetify-atom</code>, or <code class="inline">vuetify-sublime</code>).</p> <h2>Build the Title Bar Component</h2> <p>In the <strong>src</strong> directory, create a new <strong>components</strong> folder. Then, in that folder, create the <strong>PlayerTitleBar.vue</strong> file with the following content: </p> <pre class="brush: html noskimlinks noskimwords"><template> <v-system-bar window> <v-menu offset-y transition="slide-y-transition"> <v-btn flat small right slot="activator"> <v-icon>headset</v-icon> MENU </v-btn> <v-list> <v-list-tile @click="dialog = true"> <v-list-tile-title>About</v-list-tile-title> </v-list-tile> <v-dialog v-model="dialog" max-width="300"> <v-card> <v-card-title><h2>Vue Music Player</h2></v-card-title> <v-card-text>Version 1.0.0</v-card-text> <v-card-actions> <v-spacer></v-spacer> <v-btn flat @click="dialog = false">OK</v-btn> </v-card-actions> </v-card> </v-dialog> </v-list> </v-menu> <v-spacer></v-spacer> VUE MUSIC PLAYER <v-spacer></v-spacer> <v-icon>remove</v-icon> <v-icon>check_box_outline_blank</v-icon> <v-icon>close</v-icon> </v-system-bar> </template> </pre> <p>Here, we use the following Vuetify components: toolbar, menu, button, icon, list, dialog, and card. </p> <p>We separate the menu, the name, and the icons with the <code class="inline"><v-spacer></code> component. To show or hide the dialog, we create the <code class="inline">dialog: false</code> data property. Its value will toggle when we click on the <em>About</em> menu item.</p> <p>Now, in the <strong>Player.vue</strong> file, import the title bar component, register it in the components object, and add it in the template.</p> <pre class="brush: html noskimlinks noskimwords"><template> <v-app dark> <v-content> <v-container> <player-title-bar></player-title-bar> // ADD the component in the template </v-container> </v-content> </v-app> </template> </pre> <p>Now, check the result in your browser. You should see the following:</p> <figure class="post_image"><img alt="The player title bar" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_title_bar.png"></figure> <p>We’ll repeat these three steps for the other four components. So when in the next sections I tell you to import, register and add a component in the template, you should follow the same procedure described here.</p> <h2>Build the Playlist Component<br /></h2> <p>In the root directory, create a new <strong>playlist</strong> folder and add the audio files you want to play. The file names must be written with underscores between the words and a <strong>.mp3</strong> extension at the end—for example, <strong>Remember_the_Way.mp3</strong>. Now, create an audio tracks array inside <strong>Player.vue</strong>‘s data object: </p> <pre class="brush: javascript noskimlinks noskimwords">playlist: [ {title: "Streets of Sant'Ivo", artist: "Ask Again", howl: null, display: true}, {title: "Remember the Way", artist: "Ask Again", howl: null, display: true}, ... ]</pre> <p>Each track has <code class="inline">title</code> and <code class="inline">artist</code> properties, a <code class="inline">howl</code> object set to <code class="inline">null</code>, and a <code class="inline">display</code> property set to <code class="inline">true</code>. </p> <p>The <code class="inline">display</code> property will be used when we implement the search functionality. Now it is set to <code class="inline">true</code> for all tracks, so all of them are visible.</p> <p>Howler wraps an audio file in a <code class="inline">howl</code> object. We set <code class="inline">howl</code> to <code class="inline">null</code> because we’ll populate it dynamically at the creation of the Vue instance. To do that, we use the Vue’s <code class="inline">created</code> lifecycle hook. </p> <pre class="brush: javascript noskimlinks noskimwords">created: function () { this.playlist.forEach( (track) => { let file = track.title.replace(/s/g, "_") track.howl = new Howl({ src: [`./playlist/${file}.mp3`] }) }) }</pre> <p>This will set a new <code class="inline">Howl</code> object for each track in the playlist.</p> <p>Now, create the <strong>PlayerPlaylistPanel.vue</strong> component and add this inside: </p> <pre class="brush: html noskimlinks noskimwords"><template> <v-card height="330"> <v-list> <v-list-tile v-for="(track, index) in playlist" :key="track.title" v-show="track.display"> <v-list-tile-content> <v-list-tile-title>{{ index }} {{ track.artist }} - {{ track.title }}</v-list-tile-title> </v-list-tile-content> <v-spacer></v-spacer> {{ track.howl.duration() }} </v-list-tile> </v-list> </v-card> </template> </pre> <p>First, we pass the prop <code class="inline">playlist</code> from the <strong>Player.vue</strong> file. Next, in the template, we go through each track with the <code class="inline">v-for</code> directive and display the track’s index, followed by the track’s artist and title, and the duration of the track on the far right. We also use <code class="inline">v-show</code> bound to the <code class="inline">display</code> property. A track will be visible only if <code class="inline">display</code> is <code class="inline">true</code>.</p> <p>Now, in the <strong>Player.vue</strong> file, we import, register, and add the playlist component in the template. Then, we bind the <code class="inline">playlist</code> prop to the <code class="inline">playlist</code> data property like this: <code class="inline"><player-playlist-panel :playlist="playlist"></player-playlist-panel></code>.</p> <p>Let’s check the result in the browser:</p> <figure class="post_image"><img alt="The player playlist panel" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_playlist_panel.png"></figure> <p>There are two problems here. First, the numbers of the tracks are not correct, and second, the track’s duration is shown in milliseconds, but we want it to be in minutes. We’ll fix each of these issues by creating a formatting filter. </p> <p>In the <strong>main.js</strong> file, create a <code class="inline">numbers</code> filter and a <code class="inline">minutes</code> filter, which will be globally accessible. Next, in <strong>PlayerPlaylistPanel.vue</strong>, we use them like this: <code class="inline">{{ index | numbers }}</code> and <code class="inline">{{ track.howl.duration() | minutes }}</code>.</p> <p>Now, if you check the app, everything should display correctly. </p> <figure class="post_image"><img alt="The player playlist panel with fixed numbers and minutes" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_playlist_panel_fixed.png"></figure> <h3>Make Tracks Selectable<br /></h3> <p>In the <strong>Player.vue</strong> file, add the <code class="inline">selectedTrack: null</code> data property and bind it to the playlist component (<code class="inline">:selectedTrack="selectedTrack"</code>). Then, we pass the prop in the <strong>PlayerPlaylistPanel.vue</strong> file (<code class="inline">selectedTrack: Object</code>).  </p> <p>We also add a click event listener to <code class="inline"><v-list-tile-content @click="selectTrack(track)"></code> and then create the <code class="inline">selectTrack()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">methods: { selectTrack (track) { this.$emit('selecttrack', track) } } </pre> <p>Now, back in <code class="inline">Player.vue</code>, add the <code class="inline">selecttrack</code> event to the playlist component (<code class="inline">@selecttrack="selectTrack"</code>) and create the <code class="inline">selectTrack()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">selectTrack (track) { this.selectedTrack = track }</pre> <p>Now, if you go to the playlist and click on a track, it will be selected. We can’t see it, but we can prove it in the Vue DevTools. In the following screenshot, the second track is selected:</p> <figure class="post_image"><img alt="The player playlist with selected track shown in DevTools " data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_playlist_selected_track.png"></figure> <h4>Row and Selection Styling</h4> <p>The next step is to make the selection visible. To do it, we’ll bind a class which will color the selected track in orange and another class which will make even rows darker to make the tracks more distinguishable. Put the following after the <code class="inline">v-show</code> directive:</p> <pre class="brush: html noskimlinks noskimwords">:class="[{selected: track === selectedTrack}, {even: index % 2 == 0}]" </pre> <p>We’ll also add another class, which will show a scrollbar when the list gets too big.</p> <pre class="brush: html noskimlinks noskimwords"><v-card height="330" :class="{playlist}"></pre> <p>We add the necessary classes at the end of the file. </p> <pre class="brush: css noskimlinks noskimwords"><style scoped> .selected { background-color: orange !important; } .even { background-color: #505050 } .playlist { overflow: auto } </style></pre> <p>And that’s it. Now, the selected track is highlighted in orange.</p> <figure class="post_image"><img alt="The player playlist with selected track colored" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_playlist_selected_track_color.png"></figure> <p>We’ll add the double click play functionality at the end of the next section.</p> <h2>Build the Player Controls Component<br /></h2> <p>Let’s create the player controls now. We’ll start with the play, pause, and stop buttons. </p> <h3>Add the Play, Pause, and Stop Buttons<br /></h3> <p>Create the <strong>PlayerControlsBars.vue</strong> component and add this inside: </p> <pre class="brush: html noskimlinks noskimwords"><template> <div> <v-toolbar flat height=90> <v-spacer></v-spacer> <v-btn outline fab small color="light-blue" @click="stopTrack"> <v-icon>stop</v-icon> </v-btn> <v-btn outline fab color="light-blue" @click="playTrack()"> <v-icon large>play_arrow</v-icon> </v-btn> <v-btn outline fab small color="light-blue" @click="pauseTrack"> <v-icon>pause</v-icon> </v-btn> <v-spacer></v-spacer> </v-toolbar> </div> </template></pre> <p>Here, we use the Vuetify toolbar component.</p> <p>There are three buttons with registered click event listeners. Let’s create the methods for them: </p> <pre class="brush: javascript noskimlinks noskimwords">methods: { playTrack(index) { this.$emit('playtrack', index) }, pauseTrack() { this.$emit('pausetrack') }, stopTrack() { this.$emit('stoptrack') } }</pre> <p>Now, in the <strong>Player.vue</strong> file, import, register, and add the component in the template. Then, register the event listeners (<code class="inline">@playtrack="play"</code>, <code class="inline">@pausetrack="pause"</code>, <code class="inline">@stoptrack="stop"</code>).</p> <p>Next, create the <code class="inline">index: 0</code> data property, which will hold the index of the current track. Then, create a computed <code class="inline">currentTrack()</code>: </p> <pre class="brush: javascript noskimlinks noskimwords">computed: { currentTrack () { return this.playlist[this.index] } }</pre> <p>And now we can start to create the <code class="inline">play</code>, <code class="inline">pause</code>, and <code class="inline">stop</code> methods. We’ll start with the <code class="inline">play()</code> method, but before that we need to create the <code class="inline">playing: false</code> data property, which will indicate whether the track is playing or not. Add the following code for the <code class="inline">play()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">play (index) { let selectedTrackIndex = this.playlist.findIndex(track => track === this.selectedTrack) if (typeof index === 'number') { index = index } else if (this.selectedTrack) { if (this.selectedTrack != this.currentTrack) { this.stop() } index = selectedTrackIndex } else { index = this.index } let track = this.playlist[index].howl if (track.playing()) { return } else { track.play() } this.selectedTrack = this.playlist[index] this.playing = true this.index = index }</pre> <p>The method takes an index as the parameter, which specifies the track to be played. First, we get the index of the selected track. Then, we make some checks to determine the value of the <code class="inline">index</code>. If an index is provided as an argument and it’s a number, then we use it. If a track is selected, we use the index of the selected track. If the selected track is different from the current one, we use the <code class="inline">stop()</code> method to stop the current one. Finally, if neither an index argument is passed nor a track is selected, we use the value of the <code class="inline">index</code> data property.</p> <p>Next, we get the howl (based on the index value) for the track and check whether it is playing. If it is, we return nothing; if it’s not, we play it. </p> <p>Finally, we update the <code class="inline">selectedTrack</code>, <code class="inline">playing</code> and <code class="inline">index</code> data properties.</p> <p>Let’s now create the <code class="inline">pause()</code> and <code class="inline">stop()</code> methods. </p> <pre class="brush: javascript noskimlinks noskimwords">pause () { this.currentTrack.howl.pause() this.playing = false }, stop () { this.currentTrack.howl.stop() this.playing = false }</pre> <p>Here, we just pause or stop the current track and update the <code class="inline">playing</code> data property.</p> <p>Let’s also make a track start playing on double click.</p> <p>Add <code class="inline">@dblclick="playTrack()"</code> to <code class="inline"><v-list-tile-content></code> in the <strong>PlayerPlaylistPanel.vue</strong> and create the <code class="inline">playTrack()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">playTrack(index) { this.$emit('playtrack', index) }</pre> <p>Register the listener <code class="inline">@playtrack="play"</code> in the <strong>Player.vue</strong> file and voila.</p> <h3>Add the Previous and Next Buttons</h3> <p>Let’s now add the previous and next buttons.</p> <pre class="brush: html noskimlinks noskimwords"><v-btn outline fab small color="light-blue" @click="skipTrack('prev')"> <v-icon>skip_previous</v-icon> </v-btn> <!-- stop, play, and pause buttons are here --> <v-btn outline fab small color="light-blue" @click="skipTrack('next')"> <v-icon>skip_next</v-icon> </v-btn></pre> <p>Create the <code class="inline">skipTrack()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">skipTrack (direction) { this.$emit('skiptrack', direction) }</pre> <p>Register the event listener (<code class="inline">@skiptrack="skip"</code>) in <strong>Player.vue</strong>.</p> <p>And create the <code class="inline">skip()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">skip (direction) { let index = 0 if (direction === "next") { index = this.index + 1 if (index >= this.playlist.length) { index = 0 } } else { index = this.index - 1 if (index < 0) { index = this.playlist.length - 1 } } this.skipTo(index) }, skipTo (index) { if (this.currentTrack) { this.currentTrack.howl.stop() } this.play(index) }</pre> <p>We first check if the direction is <code class="inline">next</code>. If so, we increment the index by 1. And if the index gets bigger than the last index in the array, then we start again from zero. When the direction is <code class="inline">prev</code>, we decrement the index by 1. And if the index is less than zero, then we use the last index. At the end, we use the <code class="inline">index</code> as an argument for the <code class="inline">skipTo()</code> method. It stops the current track and plays the next or previous.</p> <p>Here is how the player looks with the buttons:</p> <figure class="post_image"><img alt="The player play buttons" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_controls_play_buttons.png"></figure> <h3>Add the Volume Slider<br /></h3> <p>Add the following before all the buttons:</p> <pre class="brush: html noskimlinks noskimwords"><v-slider v-model="volume" @input="updateVolume(volume)" max="1" step="0.1"></v-slider></pre> <p>Here, we use the Vuetify slider component.</p> <p>Add the <code class="inline">volume: 0.5</code> data property, and then create the <code class="inline">updateVolume()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">updateVolume (volume) { Howler.volume(volume) }</pre> <p>Here, we use the global Howler object to set the volume globally for all howls.</p> <p>Also, we need to sync the initial Howler volume, which by default is set to 1, to the <code class="inline">volume</code> property. If you don't do it, the volume will show 0.5 but will be 1 initially. To do that, we'll use the <code class="inline">created</code> hook again:</p> <pre class="brush: javascript noskimlinks noskimwords">created: function () { Howler.volume(this.volume) }</pre> <p>We want to see the volume level as a percentage on the right of the volume slider, so we add this in the template: <code class="inline">{{this.volume * 100 + '%'}}</code> </p> <h3>Add the Mute Button </h3> <p>Now, we add a volume icon before the slider. </p> <pre class="brush: html noskimlinks noskimwords"><v-btn flat icon @click="toggleMute"> <template v-if="!this.muted"> <v-icon v-if="this.volume >= 0.5">volume_up</v-icon> <v-icon v-else-if="this.volume > 0">volume_down</v-icon> <v-icon v-else>volume_mute</v-icon> </template> <v-icon v-show="this.muted">volume_off</v-icon> </v-btn></pre> <p>The icon will change according to the values of the <code class="inline">volume</code> and <code class="inline">muted</code> properties.</p> <p>Add the <code class="inline">muted: false</code> data property and create the <code class="inline">toggleMute()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">toggleMute () { Howler.mute(!this.muted) this.muted = !this.muted }</pre> <p>We use the global Howler object again to set the mute globally, and then we toggle the <code class="inline">muted</code> value. </p> <p>In the screenshot below, you can see how the volume slider should look:</p> <figure class="post_image"><img alt="The player volume slider" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_controls_volume_slider.png"></figure> <h3>Add the Repeat Button</h3> <p>Add the following after all the buttons:</p> <pre class="brush: html noskimlinks noskimwords"><v-btn flat icon @click="toggleLoop"> <v-icon color="light-blue" v-if="this.loop">repeat_one</v-icon> <v-icon color="blue-grey" v-else>repeat_one</v-icon> </v-btn></pre> <p>Add the <code class="inline">loop: false</code> property in <strong>Player.vue</strong>, bind it <code class="inline">:loop="loop"</code> and pass the prop (<code class="inline">loop: Boolean</code>) in <strong>PlayerControlsBars.vue</strong>. </p> <p>Now, let's create the <code class="inline">toggleLoop()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">toggleLoop () { this.$emit('toggleloop', !this.loop) }</pre> <p>Now, back in <strong>Player.vue</strong>, register the event listener (<code class="inline">@toggleloop="toggleLoop"</code>) and create the <code class="inline">toggleLoop()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">toggleLoop (value) { this.loop = value }</pre> <p>At this point, we face a small problem. When a track seeks the end, it just stops. The player doesn't move to the next track, nor does it repeat the current track. To fix that, we need to add the following to the <code class="inline">created</code> function after the <code class="inline">src</code> property:</p> <pre class="brush: javascript noskimlinks noskimwords">onend: () => { if (this.loop) { this.play(this.index) } else { this.skip('next') } }</pre> <p>Now, when the <code class="inline">loop</code> is on, the current track will be repeated. If it's off, the player will move on the next track.</p> <h3>Add the Shuffle Button</h3> <p>Add the following after the repeat button:</p> <pre class="brush: html noskimlinks noskimwords"><v-btn flat icon @click="toggleShuffle"> <v-icon color="light-blue" v-if="this.shuffle">shuffle</v-icon> <v-icon color="blue-grey" v-else>shuffle</v-icon> </v-btn></pre> <p>Add the <code class="inline">shuffle: false</code> property in <code class="inline">Player.vue</code>, bind it (<code class="inline">:shuffle="shuffle"</code>), and pass the prop (<code class="inline">shuffle: Boolean</code>) in <code class="inline">PlayerControlsBars.vue</code>. </p> <p>Now, let's create the <code class="inline">toggleShuffle()</code> method;</p> <pre class="brush: javascript noskimlinks noskimwords">toggleShuffle () { this.$emit('toggleshuffle', !this.shuffle) }</pre> <p>Now, back in <strong>Player.vue</strong>, register the event listener (<code class="inline">@toggleshuffle="toggleShuffle"</code>) and create the <code class="inline">toggleShuffle()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">toggleShuffle (value) { this.shuffle = value }</pre> <p>Now, add the following to the <code class="inline">skip()</code> method after <code class="inline">index = 0</code>:</p> <pre class="brush: javascript noskimlinks noskimwords">lastIndex = this.playlist.length - 1 if (this.shuffle) { index = Math.round(Math.random() * lastIndex) while (index === this.index) { index = Math.round(Math.random() * lastIndex) } } else if (direction === "next") { ...</pre> <p>Here's how your app should look now:</p> <figure class="post_image"><img alt="The player repeat and shuffle buttons" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_controls_repeat_shuffle_buttons.png"></figure> <h3>Add the Seek Bar</h3> <p>First, in <strong>Player.vue</strong>, create the <code class="inline">seek: 0</code> property. Then we'll need to watch the <code class="inline">playing</code> property in order to update the seek.</p> <pre class="brush: javascript noskimlinks noskimwords">watch: { playing(playing) { this.seek = this.currentTrack.howl.seek() let updateSeek if (playing) { updateSeek = setInterval(() => { this.seek = this.currentTrack.howl.seek() }, 250) } else { clearInterval(updateSeek) } }, }</pre> <p>This will update the seek value four times per second.</p> <p>Now, create a computed <code class="inline">progress()</code>:</p> <pre class="brush: javascript noskimlinks noskimwords">progress () { if (this.currentTrack.howl.duration() === 0) return 0 return this.seek / this.currentTrack.howl.duration() }</pre> <p>Bind it (<code class="inline">:progress="progress"</code>) in the template. </p> <p>Now, in <strong>PlayerControlsBars.vue</strong>, pass the <code class="inline">progress</code> prop (<code class="inline">progress: Number</code>) and add another toolbar below the one we've already created:</p> <pre class="brush: html noskimlinks noskimwords"><v-toolbar flat height="40"> <v-progress-linear height="40" v-model="trackProgress" @click="updateSeek($event)"></v-progress-linear> </v-toolbar></pre> <p>Here, we use the Vuetify progress component.</p> <p>Create a computed <code class="inline">trackProgress()</code>, which will get the track's progress as a percentage.</p> <pre class="brush: javascript noskimlinks noskimwords">computed: { trackProgress () { return this.progress * 100 }, }</pre> <p>And now, create the <code class="inline">updateSeek()</code> method: </p> <pre class="brush: javascript noskimlinks noskimwords">updateSeek (event) { let el = document.querySelector(".progress-linear__bar"), mousePos = event.offsetX, elWidth = el.clientWidth, percents = (mousePos / elWidth) * 100 this.$emit('updateseek', percents) } </pre> <p>Here, we get the progress bar element, which uses the <code class="inline">.progress-linear__bar</code> class. I found this with the Browser DevTools. Next, we get the mouse position and the width of the bar. Then, we get the mouse click position as a percentage.</p> <p>Back in <strong>Player.vue</strong>, add and register the event listener (<code class="inline">@updateseek="setSeek"</code>) and create the <code class="inline">setSeek()</code> method:</p> <pre class="brush: javascript noskimlinks noskimwords">setSeek (percents) { let track = this.currentTrack.howl if (track.playing()) { track.seek((track.duration() / 100) * percents) } }</pre> <p>And boom! You can use your mouse to change the position of the played track.</p> <h2>Build the Info Panel Component</h2> <p>Create the <strong>PlayerInfoPanel.vue</strong> file with the following content:</p> <pre class="brush: html noskimlinks noskimwords"><template> <v-card height="60"> <v-card-title> <h2>{{ trackInfo.artist }} - {{ trackInfo.title }}</h2> <v-spacer></v-spacer> <h3>{{trackInfo.seek | minutes}}/{{trackInfo.duration | minutes}}</h3> </v-card-title> </v-card> </template> </pre> <p>Here, we pass a prop <code class="inline">trackInfo</code>, which we use to populate the track information in our component.</p> <p>Now, back in <strong>Player.vue</strong>, import, register and add the component in the template. </p> <p>Then, create a computed <code class="inline">getTrackInfo()</code>: </p> <pre class="brush: javascript noskimlinks noskimwords">getTrackInfo () { let artist = this.currentTrack.artist, title = this.currentTrack.title, seek = this.seek, duration = this.currentTrack.howl.duration() return { artist, title, seek, duration, } }</pre> <p>Next, we bind it in the template (<code class="inline">:trackInfo="getTrackInfo"</code>) and voila. We get some basic info for the currently played track, as you can see in the screenshot below.</p> <figure class="post_image"><img alt="The player info panel" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_info_panel.png"></figure> <h2>Build the Search Bar Component</h2> <p>Create the <strong>PlayerSearchBar.vue</strong> file with the following content: </p> <pre class="brush: html noskimlinks noskimwords"><template> <v-toolbar flat> <v-text-field clearable prepend-icon="search" placeholder="Quick search" v-model="searchString" @input="searchPlaylist"> </v-text-field> <v-spacer></v-spacer> </v-toolbar> </template> </pre> <p>We create a text field and add the <code class="inline">clearable</code> prop to show a clearing icon when we type something.</p> <p>By using <code class="inline">v-model</code>, we bind it to the <code class="inline">searchString</code>, which is an empty string initially. And we add an input event listener.</p> <p>We also pass the <code class="inline">playlist</code> prop, which we use in the <code class="inline">searchPlaylist()</code> method. In this method, we use the <code class="inline">display</code> property and turn it <code class="inline">off</code> for each track where the title or artist doesn't match the search string, and we keep it or turn it <code class="inline">on</code> for all matches. Finally, if the search string is empty or equal to <code class="inline">null</code>, which happens when we clear the field with the clear button, we turn <code class="inline">on</code> the <code class="inline">display</code> for all tracks.</p> <p>Now, back in <strong>Player.vue</strong>, import, register and add the component in the template. </p> <p>Bind the playlist property (<code class="inline">:playlist="playlist"</code>) and check the functionality. Here is how it should look in action:</p> <figure class="post_image"><img alt="The player search bar test" data-src="https://cms-assets.tutsplus.com/uploads/users/2028/posts/31228/image/player_search_bar_test.png"></figure> <h2>Some Improvement Ideas</h2> <p>As you can see, with a clear goal and proper planning, building a Vue/Vuetify app can be really easy and enjoyable. You now have a working music player which you can use during your relaxation or coding time. Of course, there is always room for further improvements and additions, so here are some ideas you can try out to make the player even more feature-rich: </p> <ul> <li>multiple playlist support</li> <li>ability to add or remove tracks from the playlist</li> <li>drag-and-drop support</li> <li>ability to sort the tracks</li> <li>audio visualization </li> </ul> <h2>Conclusion</h2> <p>In this tutorial, we saw how easy and enjoyable it can be to build an app with Vue.js, and with Vuetify.js in particular. I hope you enjoyed building this player as much as I did. I'll be glad to see your own improved version of the player. So if you create one, just drop a demo link in the comments!</p> <div class="mediafed_ad"><img decoding="async" border="0" height="1" src="https://audio.tutsplus.com.feedsportal.com/c/35227/f/668806/s/31228/sc/4/mf.gif" width="1"><img decoding="async" border="0" src="https://da.feedsportal.com/r/186529796139/u/407/f/668806/c/35227/s/31228/a2.img"><img decoding="async" border="0" height="1" src="https://pi.feedsportal.com/r/186529796139/u/407/f/668806/c/35227/s/31228/a2t.img" width="1"></div> </div> <p class="wpematico_credit"><small>Powered by <a href="http://www.wpematico.com" target="_blank">WPeMatico</a></small></p> <div data-animation="no-animation" data-icons-animation="no-animation" data-overlay="on" data-change-size="" data-button-size="1" style="font-size:1em!important;display:none;" class="supsystic-social-sharing supsystic-social-sharing-package-flat supsystic-social-sharing-hide-on-homepage supsystic-social-sharing-hide-on-mobile supsystic-social-sharing-spacing supsystic-social-sharing-content supsystic-social-sharing-content-align-left" data-text=""><a data-networks="[]" class="social-sharing-button sharer-flat sharer-flat-3 counter-standard without-counter facebook" target="_blank" title="Facebook" href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F" data-main-href="http://www.facebook.com/sharer.php?u={url}" data-nid="1" data-name="" data-pid="1" data-post-id="3560" data-url="https://www.medianic.co.uk/wp-admin/admin-ajax.php" rel="nofollow" data-mailto=""><i class="fa-ssbs fa-ssbs-fw fa-ssbs-facebook"></i><div class="counter-wrap standard"><span class="counter">0</span></div></a><a data-networks="[]" class="social-sharing-button sharer-flat sharer-flat-3 counter-standard without-counter twitter" target="_blank" title="Twitter" href="https://twitter.com/share?url=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F&text=Build+a+Music+Player+With+Vuetify" data-main-href="https://twitter.com/share?url={url}&text={title}" data-nid="2" data-name="" data-pid="1" data-post-id="3560" data-url="https://www.medianic.co.uk/wp-admin/admin-ajax.php" rel="nofollow" data-mailto=""><i class="fa-ssbs fa-ssbs-fw fa-ssbs-twitter"></i><div class="counter-wrap standard"><span class="counter">0</span></div></a><a data-networks="[]" class="social-sharing-button sharer-flat sharer-flat-3 counter-standard without-counter googleplus" target="_blank" title="Google+" href="https://plus.google.com/share?url=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F" data-main-href="https://plus.google.com/share?url={url}" data-nid="3" data-name="" data-pid="1" data-post-id="3560" data-url="https://www.medianic.co.uk/wp-admin/admin-ajax.php" rel="nofollow" data-mailto=""><i class="fa-ssbs fa-ssbs-fw fa-ssbs-google-plus"></i><div class="counter-wrap standard"><span class="counter">0</span></div></a><a data-networks="[]" class="social-sharing-button sharer-flat sharer-flat-3 counter-standard without-counter digg" target="_blank" title="Digg" href="http://digg.com/submit?url=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F&title=Build+a+Music+Player+With+Vuetify" data-main-href="http://digg.com/submit?url={url}&title={title}" data-nid="8" data-name="" data-pid="1" data-post-id="3560" data-url="https://www.medianic.co.uk/wp-admin/admin-ajax.php" rel="nofollow" data-mailto=""><i class="fa-ssbs fa-ssbs-fw fa-ssbs-digg"></i><div class="counter-wrap standard"><span class="counter">0</span></div></a><a data-networks="[]" class="social-sharing-button sharer-flat sharer-flat-3 counter-standard without-counter linkedin" target="_blank" title="Linkedin" href="https://www.linkedin.com/shareArticle?mini=true&title=Build+a+Music+Player+With+Vuetify&url=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F" data-main-href="https://www.linkedin.com/shareArticle?mini=true&title={title}&url={url}" data-nid="13" data-name="" data-pid="1" data-post-id="3560" data-url="https://www.medianic.co.uk/wp-admin/admin-ajax.php" rel="nofollow" data-mailto=""><i class="fa-ssbs fa-ssbs-fw fa-ssbs-linkedin"></i><div class="counter-wrap standard"><span class="counter">0</span></div></a><a data-networks="[]" class="social-sharing-button sharer-flat sharer-flat-3 counter-standard without-counter delicious" target="_blank" title="Delicious" href="https://del.icio.us/save?v=5&jump=close&url=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F&title=Build+a+Music+Player+With+Vuetify" data-main-href="https://del.icio.us/save?v=5&jump=close&url={url}&title={title}" data-nid="10" data-name="" data-pid="1" data-post-id="3560" data-url="https://www.medianic.co.uk/wp-admin/admin-ajax.php" rel="nofollow" data-mailto=""><i class="fa-ssbs fa-ssbs-fw fa-ssbs-delicious"></i><div class="counter-wrap standard"><span class="counter">0</span></div></a></div><!-- CONTENT END 2 --> </div><!-- .entry-content .clear --> </div> </article><!-- #post-## --> <nav class="navigation post-navigation" aria-label="Post navigation"> <span class="screen-reader-text">Post navigation</span> <div class="nav-links"><div class="nav-previous"><a title="20 Best Bootstrap 4 Plugins" href="https://www.medianic.co.uk/20-best-bootstrap-4-plugins/" rel="prev"><span class="ast-left-arrow">←</span> Previous Post</a></div><div class="nav-next"><a title="Set Up Routing in PHP Applications Using the Symfony Routing Component" href="https://www.medianic.co.uk/set-up-routing-in-php-applications-using-the-symfony-routing-component/" rel="next">Next Post <span class="ast-right-arrow">→</span></a></div></div> </nav> <div id="comments" class="comments-area comment-form-position-below "> <div id="respond" class="comment-respond"> <h3 id="reply-title" class="comment-reply-title">Leave a Comment <small><a rel="nofollow" id="cancel-comment-reply-link" href="/build-a-music-player-with-vuetify/#respond" style="display:none;">Cancel Reply</a></small></h3><p class="must-log-in">You must be <a href="https://www.medianic.co.uk/wp-login.php?redirect_to=https%3A%2F%2Fwww.medianic.co.uk%2Fbuild-a-music-player-with-vuetify%2F">logged in</a> to post a comment.</p> </div><!-- #respond --> </div><!-- #comments --> <div class='code-block code-block-2' style='margin: 8px 0; clear: both;'> <script type="rocketlazyloadscript" async data-rocket-src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-0143475477975142" crossorigin="anonymous"></script> <!-- Medianic 2 --> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-0143475477975142" data-ad-slot="5286066963" data-ad-format="auto" data-full-width-responsive="true"></ins> <script type="rocketlazyloadscript"> (adsbygoogle = window.adsbygoogle || []).push({}); </script></div> </main><!-- #main --> </div><!-- #primary --> <div class="widget-area secondary" id="secondary" itemtype="https://schema.org/WPSideBar" itemscope="itemscope"> <div class="sidebar-main" > <aside id="search-2" class="widget widget_search"><form role="search" method="get" class="search-form" action="https://www.medianic.co.uk/"> <label for="search-field"> <span class="screen-reader-text">Search for:</span> <input type="search" id="search-field" class="search-field" placeholder="Search..." value="" name="s" tabindex="-1"> </label> <input type="submit" class="search-submit" value="Search"> </form> </aside><aside id="rpwe_widget-2" class="widget rpwe_widget recent-posts-extended"><h2 class="widget-title">Recent Posts</h2><div class="rpwe-block"><ul class="rpwe-ul"><li class="rpwe-li rpwe-clearfix"><a class="rpwe-img" href="https://www.medianic.co.uk/alt-text-not-always-needed/" rel="bookmark"><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/medianiclogo.png.webp" type="image/webp"><img class="rpwe-alignleft rpwe-thumb rpwe-default-thumb webpexpress-processed" src="https://www.medianic.co.uk/wp-content/uploads/2015/07/medianiclogo.png" alt="Alt Text: Not Always Needed" width="45" height="45"></picture></a><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/alt-text-not-always-needed/" target="_self">Alt Text: Not Always Needed</a></h3><time class="rpwe-time published" datetime="2024-11-26T15:01:46+00:00">26th November 2024</time></li><li class="rpwe-li rpwe-clearfix"><a class="rpwe-img" href="https://www.medianic.co.uk/15-best-free-sports-fonts-for-creatives/" rel="bookmark"><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/medianiclogo.png.webp" type="image/webp"><img class="rpwe-alignleft rpwe-thumb rpwe-default-thumb webpexpress-processed" src="https://www.medianic.co.uk/wp-content/uploads/2015/07/medianiclogo.png" alt="15+ Best Free Sports Fonts for Creatives" width="45" height="45"></picture></a><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/15-best-free-sports-fonts-for-creatives/" target="_self">15+ Best Free Sports Fonts for Creatives</a></h3><time class="rpwe-time published" datetime="2024-11-26T12:01:48+00:00">26th November 2024</time></li><li class="rpwe-li rpwe-clearfix"><a class="rpwe-img" href="https://www.medianic.co.uk/50-free-christmas-templates-resources-for-designers/" rel="bookmark"><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/medianiclogo.png.webp" type="image/webp"><img class="rpwe-alignleft rpwe-thumb rpwe-default-thumb webpexpress-processed" src="https://www.medianic.co.uk/wp-content/uploads/2015/07/medianiclogo.png" alt="50+ Free Christmas Templates & Resources for Designers" width="45" height="45"></picture></a><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/50-free-christmas-templates-resources-for-designers/" target="_self">50+ Free Christmas Templates & Resources for Designers</a></h3><time class="rpwe-time published" datetime="2024-11-24T12:01:48+00:00">24th November 2024</time></li><li class="rpwe-li rpwe-clearfix"><a class="rpwe-img" href="https://www.medianic.co.uk/invoker-commands-additional-ways-to-work-with-dialog-popover-and-more/" rel="bookmark"><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/medianiclogo.png.webp" type="image/webp"><img class="rpwe-alignleft rpwe-thumb rpwe-default-thumb webpexpress-processed" src="https://www.medianic.co.uk/wp-content/uploads/2015/07/medianiclogo.png" alt="Invoker Commands: Additional Ways to Work With Dialog, Popover… and More?" width="45" height="45"></picture></a><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/invoker-commands-additional-ways-to-work-with-dialog-popover-and-more/" target="_self">Invoker Commands: Additional Ways to Work With Dialog, Popover… and More?</a></h3><time class="rpwe-time published" datetime="2024-11-21T15:01:30+00:00">21st November 2024</time></li><li class="rpwe-li rpwe-clearfix"><a class="rpwe-img" href="https://www.medianic.co.uk/20-best-slideshow-photo-gallery-templates-for-davinci-resolve/" target="_self"><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2024/11/slideshow-photo-gallery-template-davinci-resolve-02-45x45.jpg.webp" type="image/webp"><img class="rpwe-alignleft rpwe-thumb webpexpress-processed" src="https://www.medianic.co.uk/wp-content/uploads/2024/11/slideshow-photo-gallery-template-davinci-resolve-02-45x45.jpg" alt="20+ Best Slideshow & Photo Gallery Templates for DaVinci Resolve" height="45" width="45" loading="lazy" decoding="async"></picture></a><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/20-best-slideshow-photo-gallery-templates-for-davinci-resolve/" target="_self">20+ Best Slideshow & Photo Gallery Templates for DaVinci Resolve</a></h3><time class="rpwe-time published" datetime="2024-11-21T12:01:37+00:00">21st November 2024</time></li></ul><a href="https://www.medianic.co.uk/technical-news/">All News</a></div><!-- Generated by http://wordpress.org/plugins/recent-posts-widget-extended/ --></aside><aside id="text-4" class="widget widget_text"><h2 class="widget-title">Subscribe to our Articles</h2> <div class="textwidget"><style type="text/css"> #mc_embed_signup{clear:left; font:14px Helvetica,Arial,sans-serif; } </style> <div id="mc_embed_signup"> <form id="mc-embedded-subscribe-form" class="validate" action="https://medianic.us19.list-manage.com/subscribe/post?u=ae2ef0f4629bbb4c0df68bef7&id=c260f14d5a" method="post" name="mc-embedded-subscribe-form" novalidate="" target="_blank"> <div id="mc_embed_signup_scroll"> <div class="mc-field-group"><label for="mce-EMAIL">Email Address <span class="asterisk">*</span><br /> </label><br /> <input id="mce-EMAIL" class="required email" name="EMAIL" type="email" value="" /></div> <div class="mc-field-group input-group" style="display: none;"><strong>Newsletter </strong></p> <ul> <li><input id="mce-group[12716]-12716-0" checked="checked" name="group[12716][1]" type="checkbox" value="1" /><label for="mce-group[12716]-12716-0">News</label></li> </ul> </div> <div id="mce-responses" class="clear"> <div id="mce-error-response" class="response" style="display: none;"></div> <div id="mce-success-response" class="response" style="display: none;"></div> </div> <p><!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups--></p> <div style="position: absolute; left: -5000px;" aria-hidden="true"><input tabindex="-1" name="b_ae2ef0f4629bbb4c0df68bef7_c260f14d5a" type="text" value="" /></div> <div class="clear"><input id="mc-embedded-subscribe" class="button" name="subscribe" type="submit" value="Subscribe" /></div> </div> </form> </div> <p><script type="rocketlazyloadscript" data-minify="1" data-rocket-type='text/javascript' data-rocket-src='https://www.medianic.co.uk/wp-content/cache/min/1/downloads.mailchimp.com/js/mc-validate.js?ver=1643632898' defer></script><script type="rocketlazyloadscript" data-rocket-type='text/javascript'>window.addEventListener('DOMContentLoaded', function() {(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[2]='LNAME';ftypes[2]='text';fnames[3]='ADDRESS';ftypes[3]='address';fnames[4]='PHONE';ftypes[4]='phone';fnames[5]='BIRTHDAY';ftypes[5]='birthday';}(jQuery));var $mcj = jQuery.noConflict(true);});</script><br /> <!--End mc_embed_signup--></p> </div> </aside><aside id="grw_widget-3" class="widget google-reviews-widget"> <div class="wp-gr wpac wp-dark" data-id="grw_widget-3" data-layout="" data-exec="false" data-options='{"text_size":"120","trans":{"read more":"read more"}}'><div class="wp-google-list"><div class="wp-google-place"><div class="wp-google-left"><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo.png.webp" alt="Medianic Web Design" width="50" height="50" title="Medianic Web Design" class="webpexpress-processed"></picture></div><div class="wp-google-right"><div class="wp-google-name"><a href="https://maps.google.com/?cid=11678638714541381611" target="_blank" rel="nofollow noopener"><span>Medianic Web Design</span></a></div><div><span class="wp-google-rating">5.0</span><span class="wp-google-stars"><span class="wp-stars"><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span></span></span></div><div class="wp-google-powered"><img src="https://www.medianic.co.uk/wp-content/plugins/widget-google-reviews/assets/img/powered_by_google_on_non_white.png" alt="powered by Google" width="144" height="18" title="powered by Google"></div><div class="wp-google-wr"><a href="https://search.google.com/local/writereview?placeid=ChIJuRB6mGsFmkcR6xdd6AjcEqI" target="_blank" rel="nofollow noopener" onclick="return rplg_leave_review_window.call(this)">review us on<svg viewBox="0 0 512 512" height="18" width="18"><g fill="none" fill-rule="evenodd"><path d="M482.56 261.36c0-16.73-1.5-32.83-4.29-48.27H256v91.29h127.01c-5.47 29.5-22.1 54.49-47.09 71.23v59.21h76.27c44.63-41.09 70.37-101.59 70.37-173.46z" fill="#4285f4"/><path d="M256 492c63.72 0 117.14-21.13 156.19-57.18l-76.27-59.21c-21.13 14.16-48.17 22.53-79.92 22.53-61.47 0-113.49-41.51-132.05-97.3H45.1v61.15c38.83 77.13 118.64 130.01 210.9 130.01z" fill="#34a853"/><path d="M123.95 300.84c-4.72-14.16-7.4-29.29-7.4-44.84s2.68-30.68 7.4-44.84V150.01H45.1C29.12 181.87 20 217.92 20 256c0 38.08 9.12 74.13 25.1 105.99l78.85-61.15z" fill="#fbbc05"/><path d="M256 113.86c34.65 0 65.76 11.91 90.22 35.29l67.69-67.69C373.03 43.39 319.61 20 256 20c-92.25 0-172.07 52.89-210.9 130.01l78.85 61.15c18.56-55.78 70.59-97.3 132.05-97.3z" fill="#ea4335"/><path d="M20 20h472v472H20V20z"/></g></svg></a></div></div></div><div class="wp-google-content-inner"><div class="wp-google-reviews"><div class="wp-google-review"><div class="wp-google-left"><img src="https://lh3.googleusercontent.com/a-/AOh14GjuZe0ESqEGbG0o_TOF9sKPYBmN05Z9Ic7uhJQAmQ=s56-c0x00000000-cc-rp-mo" loading="lazy" class="rplg-review-avatar" alt="John Fegan" width="50" height="50" title="John Fegan" onerror="if(this.src!='https://www.medianic.co.uk/wp-content/plugins/widget-google-reviews/assets/img/guest.png')this.src='https://www.medianic.co.uk/wp-content/plugins/widget-google-reviews/assets/img/guest.png';" ></div><div class="wp-google-right"><a href="https://www.google.com/maps/contrib/106918007433001339712/reviews" class="wp-google-name" target="_blank" rel="nofollow noopener">John Fegan</a><div class="wp-google-time" data-time="1626989111">21:25 22 Jul 21</div><div class="wp-google-feedback"><span class="wp-google-stars"><span class="wp-stars"><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span></span></span><span class="wp-google-text">Professional and rapid support for the development and ongoing maintenance of our business website. Nothing too much trouble. Highly recommended.</span></div></div></div><div class="wp-google-review"><div class="wp-google-left"><img src="https://lh3.googleusercontent.com/a-/AD5-WCkpT55_U31N0IerWCKchbh3gQNfhfkDq1kitqsgXA=s56-c0x00000000-cc-rp-mo" loading="lazy" class="rplg-review-avatar" alt="Paul Jackson" width="50" height="50" title="Paul Jackson" onerror="if(this.src!='https://www.medianic.co.uk/wp-content/plugins/widget-google-reviews/assets/img/guest.png')this.src='https://www.medianic.co.uk/wp-content/plugins/widget-google-reviews/assets/img/guest.png';" ></div><div class="wp-google-right"><a href="https://www.google.com/maps/contrib/101042578538339892805/reviews" class="wp-google-name" target="_blank" rel="nofollow noopener">Paul Jackson</a><div class="wp-google-time" data-time="1624879496">11:24 28 Jun 21</div><div class="wp-google-feedback"><span class="wp-google-stars"><span class="wp-stars"><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span><span class="wp-star"><svg width="17" height="17" viewBox="0 0 1792 1792"><path d="M1728 647q0 22-26 48l-363 354 86 500q1 7 1 20 0 21-10.5 35.5t-30.5 14.5q-19 0-40-12l-449-236-449 236q-22 12-40 12-21 0-31.5-14.5t-10.5-35.5q0-6 2-20l86-500-364-354q-25-27-25-48 0-37 56-46l502-73 225-455q19-41 49-41t49 41l225 455 502 73q56 9 56 46z" fill="#fb8e28"></path></svg></span></span></span><span class="wp-google-text">Superb service very professional and quickvery responsive i was kept informed and consulted throughout the entire process.</span></div></div></div></div><a href="https://search.google.com/local/reviews?placeid=ChIJuRB6mGsFmkcR6xdd6AjcEqI" class="wp-google-url" target="_blank" rel="nofollow noopener">See All Reviews</a></div></div><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="js_loader" onload="(function(el, data) {var f = function() { window.grw_init ? grw_init(el, data) : setTimeout(f, 400) }; f() })(this);" width="1" height="1" style="display:none"></div> </aside><aside id="fbrev_widget-2" class="widget fb-reviews-widget"></aside><aside id="text-6" class="widget widget_text"> <div class="textwidget"><div class="trustpilot-widget" data-locale="en-GB" data-template-id="5419b6a8b0d04a076446a9ad" data-businessunit-id="5c11278e393a0100015d0c2e" data-style-height="24px" data-style-width="100%" data-theme="dark"><a href="https://uk.trustpilot.com/review/www.medianic.co.uk" target="_blank" rel="noopener">Trustpilot</a></div> <p><!-- End TrustBox widget --><br /> <!-- TrustBox script --><br /> <script type="rocketlazyloadscript" data-minify="1" data-rocket-type="text/javascript" data-rocket-src="https://www.medianic.co.uk/wp-content/cache/min/1/bootstrap/v5/tp.widget.bootstrap.min.js?ver=1643632898" async></script><br /> <!-- End TrustBox script --></p> </div> </aside><aside id="block-5" class="widget widget_block"><p><script type="rocketlazyloadscript" async="" data-rocket-src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-0143475477975142" crossorigin="anonymous"></script><br> <!-- Medianic news 1 --><br> <ins class="adsbygoogle" style="display:inline-block;width:300px;height:250px" data-ad-client="ca-pub-0143475477975142" data-ad-slot="6221888689"></ins><br> <script type="rocketlazyloadscript"><br /> (adsbygoogle = window.adsbygoogle || []).push({});<br /> </script></p></aside> </div><!-- .sidebar-main --> </div><!-- #secondary --> </div> <!-- ast-container --> </div><!-- #content --> <div class="hfe-before-footer-wrap"> <div class='footer-width-fixer'> <div data-elementor-type="wp-post" data-elementor-id="223" class="elementor elementor-223" data-elementor-post-type="elementor-hf"> <section class="elementor-section elementor-top-section elementor-element elementor-element-5eb6ae3 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="5eb6ae3" data-element_type="section"> <div class="elementor-container elementor-column-gap-no"> <div class="elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-b90033e elementor-hidden-tablet elementor-hidden-phone" data-id="b90033e" data-element_type="column"> <div class="elementor-widget-wrap"> </div> </div> <div class="elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-6c2f831" data-id="6c2f831" data-element_type="column"> <div class="elementor-widget-wrap elementor-element-populated"> <section class="elementor-section elementor-inner-section elementor-element elementor-element-a0fb86e elementor-reverse-mobile elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a0fb86e" data-element_type="section"> <div class="elementor-container elementor-column-gap-no"> <div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-79b8cd6" data-id="79b8cd6" data-element_type="column"> <div class="elementor-widget-wrap elementor-element-populated"> <div class="elementor-element elementor-element-12e63be elementor-testimonial--layout-image_stacked elementor-testimonial--skin-default elementor-testimonial--align-center elementor-arrows-yes elementor-pagination-type-bullets elementor-widget elementor-widget-testimonial-carousel" data-id="12e63be" data-element_type="widget" data-settings="{"show_arrows":"yes","pagination":"bullets","speed":500,"autoplay":"yes","autoplay_speed":5000,"loop":"yes","pause_on_hover":"yes","pause_on_interaction":"yes","space_between":{"unit":"px","size":10,"sizes":[]},"space_between_tablet":{"unit":"px","size":10,"sizes":[]},"space_between_mobile":{"unit":"px","size":10,"sizes":[]}}" data-widget_type="testimonial-carousel.default"> <div class="elementor-widget-container"> <div class="elementor-swiper"> <div class="elementor-main-swiper swiper"> <div class="swiper-wrapper"> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Kate has been so helpful, patient with our constant changes and so professional in all respects. Many thanks and very done! </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/11/golf.jpg.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/11/golf.jpg" alt="Club de Golf Javea" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Club de Golf Javea</span><span class="elementor-testimonial__title">Website Redesign</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Kate is the person to go to in regards to these matters. Had a lot of problems with my website, errors, payment issues and more. Every problem was resolved quickly and professionally and cannot recommend Kate's company highly enough. Personal and responsive service. 5 Stars! </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/11/wowvac.jpg.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/11/wowvac.jpg" alt="WowVac Pro" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">WowVac Pro</span><span class="elementor-testimonial__title">E-Commerce Configuration</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Best Developer in Spain! Outstanding web services no matter where you are in the world. Great support and attention to detail. Kate is a real life developer. She can work across multiple platforms and understands the technology your company is using on a line to line basis. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/11/favicon.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/11/favicon.png" alt="Favicon" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Pure Organic CBD</span><span class="elementor-testimonial__title">Web development and support</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Professional and rapid support for the development and ongoing maintenance of our business website. Nothing too much trouble. Highly recommended. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/11/cafeciclistalogo.jpg.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/11/cafeciclistalogo.jpg" alt="Cafeciclistalogo" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Cafe Ciclista</span><span class="elementor-testimonial__title">Web maintenance</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Superb service very professional and quick very responsive I was kept informed and consulted throughout the entire process. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/11/partnerchipz_black.jpg.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/11/partnerchipz_black.jpg" alt="Partnerchipz Black" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Paul Jackson</span><span class="elementor-testimonial__title">Web design & Development</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Kate Langshaw of Medianic is awesomely recommended by us for all your website needs. Kate translated our story and brand into an elegant, transparent and to the point representation of CaffèMilano -The Italian Coffee House. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/01/caffemilanologo.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/01/caffemilanologo.png" alt="CaffèMilano" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">CaffèMilano</span><span class="elementor-testimonial__title">Web design and Development</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Absolute Class service from Start to finish, nothing is too much hassle for them and will recommend to everybody looking to update or have their website designed by the Amazing Kate Langshaw </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2019/10/draoninsure.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2019/10/draoninsure.png" alt="Dragon Insure" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Dragon Insure</span><span class="elementor-testimonial__title">Web design and Development</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> I have to say that my experience with Medianic has been different to any previous. I have been constantly kept up to date, communication has been fluid, and we had no down time at all. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2019/07/banuls.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2019/07/banuls.png" alt="Dr Banuls" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Dr Banuls</span><span class="elementor-testimonial__title">Web Hosting</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> I’m very happy about Kate’s work! Recommend her services to everybody. Looking for a good website builder/designer? Look no further and contact Medianic. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2018/12/voiceprod.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2018/12/voiceprod.png" alt="Voice Productions" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Voice Productions</span><span class="elementor-testimonial__title">Web development</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> On Behalf of all at the Marina Alta Classic Car Club I would like to thank Kate for the wonderful work she did in Kick starting our Club website this year. I can highly recommend her. Thanks Kate </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2018/12/maccc.png.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2018/12/maccc.png" alt="Marina Alta Car Club" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Marina Alta Car Club</span><span class="elementor-testimonial__title">Web Design</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Excellent knowledge and service, competitive pricing too. Definitely a solid go to company. Thanks for the great results we’ve had </div> </div> <div class="elementor-testimonial__footer"> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Jim Jimney</span><span class="elementor-testimonial__title">Design and Branding</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Totally reliable, totally capable and totally delivers. I’m loving working with Kate to help grow my business. I’m full of motivation because of you Kate </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2020/11/FB_profile.jpg.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2020/11/FB_profile.jpg" alt="Javea Blinds" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Javea Blinds</span><span class="elementor-testimonial__title">Web Design</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> I cannot praise Medianic enough. They have built the Javea Connect website quickly and efficiently, taught and old dog new tricks and have been there for me, sometimes within minutes, when I needed help. Excellent service and very very competitively priced. Highly recommended for both website and design work. Kate is to be congratulated on such a high standard of work and customer loyalty. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <img width="200" height="171" src="https://www.medianic.co.uk/wp-content/uploads/2021/02/javeaconnect-1.png.webp" alt="Javea Connect"> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Javea Connect</span><span class="elementor-testimonial__title">Web Design & Development</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> Medianic has done a outstanding job in creating our company website in such a short time at unbeatable prices, rovtec marine services recommended Medianic for their superior skill in Web design, thank you outstanding job! </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2017/01/rovtecmain.jpg.webp" type="image/webp"><img src="https://www.medianic.co.uk/wp-content/uploads/2017/01/rovtecmain.jpg" alt="Rovtech" class="webpexpress-processed"></picture> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Rovtech</span><span class="elementor-testimonial__title">Web Design</span></cite> </div> </div> </div> <div class="swiper-slide"> <div class="elementor-testimonial"> <div class="elementor-testimonial__content"> <div class="elementor-testimonial__text"> The only thing that beat the quality of the work Medianic did for us was how quick and responsive they were whenever we had feedback or needed something extra. Would highly recommend. </div> </div> <div class="elementor-testimonial__footer"> <div class="elementor-testimonial__image"> <img width="120" height="100" src="https://www.medianic.co.uk/wp-content/uploads/2015/07/pokerencore_thumb1.gif" alt="Poker Encore"> </div> <cite class="elementor-testimonial__cite"><span class="elementor-testimonial__name">Poker Encore</span><span class="elementor-testimonial__title">Custom Programming</span></cite> </div> </div> </div> </div> <div class="swiper-pagination"></div> <div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0"> <i aria-hidden="true" class="eicon-chevron-left"></i> <span class="elementor-screen-only">Previous</span> </div> <div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0"> <i aria-hidden="true" class="eicon-chevron-right"></i> <span class="elementor-screen-only">Next</span> </div> </div> </div> </div> </div> </div> </div> <div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-3f972ed" data-id="3f972ed" data-element_type="column"> <div class="elementor-widget-wrap elementor-element-populated"> <div class="elementor-element elementor-element-4d1de9e elementor-widget-mobile__width-inherit elementor-widget elementor-widget-heading" data-id="4d1de9e" data-element_type="widget" data-widget_type="heading.default"> <div class="elementor-widget-container"> <h3 class="elementor-heading-title elementor-size-default">Thank you!</h3> </div> </div> <div class="elementor-element elementor-element-cb007db elementor-widget-mobile__width-inherit elementor-widget elementor-widget-heading" data-id="cb007db" data-element_type="widget" data-widget_type="heading.default"> <div class="elementor-widget-container"> <h5 class="elementor-heading-title elementor-size-default">For your kind words...</h5> </div> </div> <div class="elementor-element elementor-element-6dcc44f elementor-view-framed elementor-shape-circle elementor-widget elementor-widget-icon" data-id="6dcc44f" data-element_type="widget" data-widget_type="icon.default"> <div class="elementor-widget-container"> <div class="elementor-icon-wrapper"> <div class="elementor-icon"> <i aria-hidden="true" class="fas fa-heart"></i> </div> </div> </div> </div> </div> </div> </div> </section> </div> </div> </div> </section> <section class="elementor-section elementor-top-section elementor-element elementor-element-467c6a2 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="467c6a2" data-element_type="section"> <div class="elementor-container elementor-column-gap-default"> <div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-12fead1" data-id="12fead1" data-element_type="column"> <div class="elementor-widget-wrap elementor-element-populated"> <div class="elementor-element elementor-element-bf080fd elementor-widget elementor-widget-html" data-id="bf080fd" data-element_type="widget" data-widget_type="html.default"> <div class="elementor-widget-container"> <!-- Global site tag (gtag.js) - Google Analytics --> <script type="rocketlazyloadscript" async data-rocket-src="https://www.googletagmanager.com/gtag/js?id=UA-17356469-1"></script> <script type="rocketlazyloadscript"> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-17356469-1'); </script> </div> </div> </div> </div> </div> </section> </div> </div> </div> <footer class="site-footer" id="colophon" itemtype="https://schema.org/WPFooter" itemscope="itemscope" itemid="#colophon" > <div class="footer-adv footer-adv-layout-3"> <div class="footer-adv-overlay"> <div class="ast-container"> <div class="ast-row"> <div class="ast-col-lg-4 ast-col-md-4 ast-col-sm-12 ast-col-xs-12 footer-adv-widget footer-adv-widget-1"> <div id="text-5" class="widget widget_text"> <div class="textwidget"><p><picture><source srcset="https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo.png.webp 512w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-300x300.png.webp 300w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-150x150.png.webp 150w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-45x45.png.webp 45w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-100x100.png.webp 100w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-270x270.png.webp 270w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-192x192.png.webp 192w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-180x180.png.webp 180w, https://www.medianic.co.uk/wp-content/webp-express/webp-images/uploads/2015/07/cropped-medianiclogo-32x32.png.webp 32w" sizes="(max-width: 300px) 100vw, 300px" type="image/webp"><img fetchpriority="high" decoding="async" class="size-full wp-image-5842 alignnone webpexpress-processed" src="https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo.png.webp" alt="" width="300" height="300" srcset="https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo.png.webp 512w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-300x300.png.webp 300w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-150x150.png.webp 150w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-45x45.png.webp 45w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-100x100.png.webp 100w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-270x270.png 270w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-192x192.png 192w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-180x180.png 180w,https://www.medianic.co.uk/wp-content/uploads/2015/07/cropped-medianiclogo-32x32.png 32w" sizes="(max-width: 300px) 100vw, 300px"></picture></p> </div> </div> </div> <div class="ast-col-lg-4 ast-col-md-4 ast-col-sm-12 ast-col-xs-12 footer-adv-widget footer-adv-widget-2"> <div id="rpwe_widget-3" class="widget rpwe_widget recent-posts-extended"><h2 class="widget-title">Latest News</h2><div class="rpwe-block"><ul class="rpwe-ul"><li class="rpwe-li rpwe-clearfix"><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/alt-text-not-always-needed/" target="_self">Alt Text: Not Always Needed</a></h3><time class="rpwe-time published" datetime="2024-11-26T15:01:46+00:00">26th November 2024</time></li><li class="rpwe-li rpwe-clearfix"><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/15-best-free-sports-fonts-for-creatives/" target="_self">15+ Best Free Sports Fonts for Creatives</a></h3><time class="rpwe-time published" datetime="2024-11-26T12:01:48+00:00">26th November 2024</time></li><li class="rpwe-li rpwe-clearfix"><h3 class="rpwe-title"><a href="https://www.medianic.co.uk/50-free-christmas-templates-resources-for-designers/" target="_self">50+ Free Christmas Templates & Resources for Designers</a></h3><time class="rpwe-time published" datetime="2024-11-24T12:01:48+00:00">24th November 2024</time></li></ul></div><!-- Generated by http://wordpress.org/plugins/recent-posts-widget-extended/ --></div> </div> <div class="ast-col-lg-4 ast-col-md-4 ast-col-sm-12 ast-col-xs-12 footer-adv-widget footer-adv-widget-3"> <div id="astra-widget-address-2" class="widget astra-widget-address"><h2 class="widget-title">Find Medianic Web Design</h2> <div class="address clearfix"> <address class="widget-address widget-address-stack widget-address-icons-1"> <div class="widget-address-field"> <svg xmlns="http://www.w3.org/2000/svg" class="address-icons" width="15px" height="15px" viewBox="0 0 496 512"><path d="M336.5 160C322 70.7 287.8 8 248 8s-74 62.7-88.5 152h177zM152 256c0 22.2 1.2 43.5 3.3 64h185.3c2.1-20.5 3.3-41.8 3.3-64s-1.2-43.5-3.3-64H155.3c-2.1 20.5-3.3 41.8-3.3 64zm324.7-96c-28.6-67.9-86.5-120.4-158-141.6 24.4 33.8 41.2 84.7 50 141.6h108zM177.2 18.4C105.8 39.6 47.8 92.1 19.3 160h108c8.7-56.9 25.5-107.8 49.9-141.6zM487.4 192H372.7c2.1 21 3.3 42.5 3.3 64s-1.2 43-3.3 64h114.6c5.5-20.5 8.6-41.8 8.6-64s-3.1-43.5-8.5-64zM120 256c0-21.5 1.2-43 3.3-64H8.6C3.2 212.5 0 233.8 0 256s3.2 43.5 8.6 64h114.6c-2-21-3.2-42.5-3.2-64zm39.5 96c14.5 89.3 48.7 152 88.5 152s74-62.7 88.5-152h-177zm159.3 141.6c71.4-21.2 129.4-73.7 158-141.6h-108c-8.8 56.9-25.6 107.8-50 141.6zM19.3 352c28.6 67.9 86.5 120.4 158 141.6-24.4-33.8-41.2-84.7-50-141.6h-108z"></path> </svg> <span class="address-meta">Javea, Costa Blanca Alicante Spain, 03730</span> </div> <div class="widget-address-field"> <svg xmlns="http://www.w3.org/2000/svg" class="address-icons" width="15px" height="15px" viewBox="0 0 512 512"><path d="M493.4 24.6l-104-24c-11.3-2.6-22.9 3.3-27.5 13.9l-48 112c-4.2 9.8-1.4 21.3 6.9 28l60.6 49.6c-36 76.7-98.9 140.5-177.2 177.2l-49.6-60.6c-6.8-8.3-18.2-11.1-28-6.9l-112 48C3.9 366.5-2 378.1.6 389.4l24 104C27.1 504.2 36.7 512 48 512c256.1 0 464-207.5 464-464 0-11.2-7.7-20.9-18.6-23.4z"></path> </svg> <span class="address-meta"> <a href="tel:34610151306" >+34 610 151 306</a> </span> </div> <div class="widget-address-field"> <svg xmlns="http://www.w3.org/2000/svg" class="address-icons" width="15px" height="15px" viewBox="0 0 512 512"><path d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path> </svg> <span class="address-meta"> <a href="mailto:info@medianic.co.uk" >info@medianic.co.uk</a> </span> </div> </address> </div> </div><div id="astra-widget-social-profiles-2" class="widget astra-widget-social-profiles"><h2 class="widget-title">Follow Us</h2> <div class="astra-widget-social-profiles-inner clearfix inline square-outline icon-custom-color"> <ul> <li> <a href="https://www.facebook.com/medianicdesign/" target="_blank" rel="noopener nofollow" aria-label="facebook"> <span class="ast-widget-icon facebook"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="20" height="20"><path d="M448 56.7v398.5c0 13.7-11.1 24.7-24.7 24.7H309.1V306.5h58.2l8.7-67.6h-67v-43.2c0-19.6 5.4-32.9 33.5-32.9h35.8v-60.5c-6.2-.8-27.4-2.7-52.2-2.7-51.6 0-87 31.5-87 89.4v49.9h-58.4v67.6h58.4V480H24.7C11.1 480 0 468.9 0 455.3V56.7C0 43.1 11.1 32 24.7 32h398.5c13.7 0 24.8 11.1 24.8 24.7z"></path></svg> </span> </a> </li> <li> <a href="https://twitter.com/medianicdesign" target="_blank" rel="noopener nofollow" aria-label="twitter-square"> <span class="ast-widget-icon twitter-square"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="20" height="20"><path d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-48.9 158.8c.2 2.8.2 5.7.2 8.5 0 86.7-66 186.6-186.6 186.6-37.2 0-71.7-10.8-100.7-29.4 5.3.6 10.4.8 15.8.8 30.7 0 58.9-10.4 81.4-28-28.8-.6-53-19.5-61.3-45.5 10.1 1.5 19.2 1.5 29.6-1.2-30-6.1-52.5-32.5-52.5-64.4v-.8c8.7 4.9 18.9 7.9 29.6 8.3a65.447 65.447 0 0 1-29.2-54.6c0-12.2 3.2-23.4 8.9-33.1 32.3 39.8 80.8 65.8 135.2 68.6-9.3-44.5 24-80.6 64-80.6 18.9 0 35.9 7.9 47.9 20.7 14.8-2.8 29-8.3 41.6-15.8-4.9 15.2-15.2 28-28.8 36.1 13.2-1.4 26-5.1 37.8-10.2-8.9 13.1-20.1 24.7-32.9 34z"></path></svg> </span> </a> </li> <li> <a href="https://goo.gl/maps/sGcEcP3v9BFHG3EM8" target="_blank" rel="noopener nofollow" aria-label="google"> <span class="ast-widget-icon google"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 488 512" width="20" height="20"><path d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"></path></svg> </span> </a> </li> <li> <a href="http://www.linkedin.com/in/medianic" target="_blank" rel="noopener nofollow" aria-label="linkedin"> <span class="ast-widget-icon linkedin"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="20" height="20"><path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"></path></svg> </span> </a> </li> <li> <a href="https://www.youtube.com/channel/UCSGH4AtRbaLAdI1c1del7eQ" target="_blank" rel="noopener nofollow" aria-label="youtube"> <span class="ast-widget-icon youtube"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" width="20" height="20"><path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"></path></svg> </span> </a> </li> <li> <a href="https://www.trustpilot.com/review/www.medianic.co.uk" target="_blank" rel="noopener nofollow" aria-label="star"> <span class="ast-widget-icon star"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" width="20" height="20"><path d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"></path></svg> </span> </a> </li> </ul> </div> </div> </div> </div><!-- .ast-row --> </div><!-- .ast-container --> </div><!-- .footer-adv-overlay--> </div><!-- .ast-theme-footer .footer-adv-layout-3 --> <div class="ast-small-footer footer-sml-layout-2"> <div class="ast-footer-overlay"> <div class="ast-container"> <div class="ast-small-footer-wrap" > <div class="ast-row ast-flex"> <div class="ast-small-footer-section ast-small-footer-section-1 ast-small-footer-section-equally ast-col-md-6" > Copyright © 2024 <span class="ast-footer-site-title">Medianic</span> Web Design </div> <div class="ast-small-footer-section ast-small-footer-section-2 ast-small-footer-section-equally ast-col-md-6" > <div class="footer-primary-navigation"><ul id="menu-footer" class="nav-menu"><li id="menu-item-6104" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-privacy-policy menu-item-6104"><a rel="privacy-policy" href="https://www.medianic.co.uk/privacy-policy/" class="menu-link">Privacy Policy</a></li> <li id="menu-item-6216" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-6216"><a href="https://www.medianic.co.uk/wp-content/uploads/2023/04/Medianic-TC.pdf" class="menu-link">Terms & Conditions</a></li> <li id="menu-item-6105" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-6105"><a href="https://www.medianic.co.uk/contact/" class="menu-link">Contact</a></li> </ul></div> </div> </div> <!-- .ast-row.ast-flex --> </div><!-- .ast-small-footer-wrap --> </div><!-- .ast-container --> </div><!-- .ast-footer-overlay --> </div><!-- .ast-small-footer--> </footer><!-- #colophon --> </div><!-- #page --> <div itemscope itemType="http://schema.org/BlogPosting"> <meta itemprop="inLanguage" content="en-GB"/> <meta itemprop="headline" content="Build a Music Player With Vuetify"> <meta itemprop="mainEntityOfPage" content="https://www.medianic.co.uk/build-a-music-player-with-vuetify/"/> <meta itemprop="datePublished" content="2018-07-12"> <meta itemprop="dateModified" content="2018-07-12"> <meta itemprop="articleBody" content="What You’ll Be Creating Building apps with Vue.js is easy, fun, and enjoyable. You can build a working app with minimum effort. To prove that, today […]"> <div itemprop="image" itemscope="" itemtype="https://schema.org/ImageObject"/> <meta itemprop="url" content="https://www.medianic.co.uk/wp-content/uploads/2018/07/player_final-300x219.png"> <meta itemprop="width" content="300"> <meta itemprop="height" content="300"> </div> <div itemprop="author" itemscope="" itemtype="http://schema.org/Person"> <meta itemprop="name" content="Medianic"> </div> <div itemprop="publisher" itemscope itemtype="https://schema.org/Organization"> <meta itemprop="name" content="Medianic"> <meta itemprop="url" href="https://www.medianic.co.uk"> <meta itemprop="description" content="Web Design in Javea – Established since 2006"> <span itemprop="logo" itemscope itemtype="https://schema.org/ImageObject"> <meta itemprop="image" content="https://www.medianic.co.uk/wp-content/uploads/2015/07/logo.jpg"> <meta itemprop="url" content="https://www.medianic.co.uk/wp-content/uploads/2015/07/logo.jpg"> <meta itemprop="width" content="300"> <meta itemprop="height" content="300"> </span> </div> <!--googleoff: all--><div id="cookie-law-info-bar" data-nosnippet="true"><span>This website uses cookies to improve your experience. <a role='button' data-cli_action="accept" id="cookie_action_close_header" class="medium cli-plugin-button cli-plugin-main-button cookie_action_close_header cli_action_button wt-cli-accept-btn">Accept</a> <a href="https://www.medianic.co.uk/privacy-policy/" id="CONSTANT_OPEN_URL" target="_blank" class="cli-plugin-main-link">Read More</a></span></div><div id="cookie-law-info-again" data-nosnippet="true"><span id="cookie_hdr_showagain">Privacy & Cookies Policy</span></div><div class="cli-modal" data-nosnippet="true" id="cliSettingsPopup" tabindex="-1" role="dialog" aria-labelledby="cliSettingsPopup" aria-hidden="true"> <div class="cli-modal-dialog" role="document"> <div class="cli-modal-content cli-bar-popup"> <button type="button" class="cli-modal-close" id="cliModalClose"> <svg class="" viewBox="0 0 24 24"><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"></path><path d="M0 0h24v24h-24z" fill="none"></path></svg> <span class="wt-cli-sr-only">Close</span> </button> <div class="cli-modal-body"> <div class="cli-container-fluid cli-tab-container"> <div class="cli-row"> <div class="cli-col-12 cli-align-items-stretch cli-px-0"> <div class="cli-privacy-overview"> <h4>Privacy Overview</h4> <div class="cli-privacy-content"> <div class="cli-privacy-content-text">This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.</div> </div> <a class="cli-privacy-readmore" aria-label="Show more" role="button" data-readmore-text="Show more" data-readless-text="Show less"></a> </div> </div> <div class="cli-col-12 cli-align-items-stretch cli-px-0 cli-tab-section-container"> <div class="cli-tab-section"> <div class="cli-tab-header"> <a role="button" tabindex="0" class="cli-nav-link cli-settings-mobile" data-target="necessary" data-toggle="cli-toggle-tab"> Necessary </a> <div class="wt-cli-necessary-checkbox"> <input type="checkbox" class="cli-user-preference-checkbox" id="wt-cli-checkbox-necessary" data-id="checkbox-necessary" checked="checked" /> <label class="form-check-label" for="wt-cli-checkbox-necessary">Necessary</label> </div> <span class="cli-necessary-caption">Always Enabled</span> </div> <div class="cli-tab-content"> <div class="cli-tab-pane cli-fade" data-id="necessary"> <div class="wt-cli-cookie-description"> Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information. </div> </div> </div> </div> <div class="cli-tab-section"> <div class="cli-tab-header"> <a role="button" tabindex="0" class="cli-nav-link cli-settings-mobile" data-target="non-necessary" data-toggle="cli-toggle-tab"> Non-necessary </a> <div class="cli-switch"> <input type="checkbox" id="wt-cli-checkbox-non-necessary" class="cli-user-preference-checkbox" data-id="checkbox-non-necessary" checked='checked' /> <label for="wt-cli-checkbox-non-necessary" class="cli-slider" data-cli-enable="Enabled" data-cli-disable="Disabled"><span class="wt-cli-sr-only">Non-necessary</span></label> </div> </div> <div class="cli-tab-content"> <div class="cli-tab-pane cli-fade" data-id="non-necessary"> <div class="wt-cli-cookie-description"> Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website. </div> </div> </div> </div> </div> </div> </div> </div> <div class="cli-modal-footer"> <div class="wt-cli-element cli-container-fluid cli-tab-container"> <div class="cli-row"> <div class="cli-col-12 cli-align-items-stretch cli-px-0"> <div class="cli-tab-footer wt-cli-privacy-overview-actions"> <a id="wt-cli-privacy-save-btn" role="button" tabindex="0" data-cli-action="accept" class="wt-cli-privacy-btn cli_setting_save_button wt-cli-privacy-accept-btn cli-btn">SAVE & ACCEPT</a> </div> </div> </div> </div> </div> </div> </div> </div> <div class="cli-modal-backdrop cli-fade cli-settings-overlay"></div> <div class="cli-modal-backdrop cli-fade cli-popupbar-overlay"></div> <!--googleon: all--> <div id="ast-scroll-top" tabindex="0" class="ast-scroll-top-icon ast-scroll-to-top-right" data-on-devices="both"> <span class="screen-reader-text">Scroll to Top</span> </div> <script type="rocketlazyloadscript" data-rocket-type='text/javascript'> const lazyloadRunObserver = () => { const lazyloadBackgrounds = document.querySelectorAll( `.e-con.e-parent:not(.e-lazyloaded)` ); const lazyloadBackgroundObserver = new IntersectionObserver( ( entries ) => { entries.forEach( ( entry ) => { if ( entry.isIntersecting ) { let lazyloadBackground = entry.target; if( lazyloadBackground ) { lazyloadBackground.classList.add( 'e-lazyloaded' ); } lazyloadBackgroundObserver.unobserve( entry.target ); } }); }, { rootMargin: '200px 0px 200px 0px' } ); lazyloadBackgrounds.forEach( ( lazyloadBackground ) => { lazyloadBackgroundObserver.observe( lazyloadBackground ); } ); }; const events = [ 'DOMContentLoaded', 'elementor/lazyload/observe', ]; events.forEach( ( event ) => { document.addEventListener( event, lazyloadRunObserver ); } ); </script> <script type="rocketlazyloadscript"> (function () { var c = document.body.className; c = c.replace(/woocommerce-no-js/, 'woocommerce-js'); document.body.className = c; })(); </script> <link data-minify="1" rel='stylesheet' id='wc-blocks-style-css' href='https://www.medianic.co.uk/wp-content/cache/min/1/wp-content/plugins/woocommerce/assets/client/blocks/wc-blocks.css?ver=1727877110' media='all' /> <link data-minify="1" rel='stylesheet' id='rpwe-style-css' href='https://www.medianic.co.uk/wp-content/cache/min/1/wp-content/plugins/recent-posts-widget-extended/assets/css/rpwe-frontend.css?ver=1727877110' media='all' /> <link rel='stylesheet' id='widget-carousel-css' href='https://www.medianic.co.uk/wp-content/plugins/elementor-pro/assets/css/widget-carousel.min.css?ver=3.24.3' media='all' /> <link rel='stylesheet' id='widget-heading-css' href='https://www.medianic.co.uk/wp-content/plugins/elementor/assets/css/widget-heading.min.css?ver=3.25.10' media='all' /> <link rel='stylesheet' id='astra-widgets-astra-widget-address-css' href='https://www.medianic.co.uk/wp-content/plugins/astra-widgets/assets/css/minified/astra-widget-address.min.css?ver=1.2.15' media='all' /> <style id='astra-widgets-astra-widget-address-inline-css'> #astra-widget-address-2 .widget-address-field svg{fill:#006789;}#astra-widget-address-2 .widget-address .widget-address-field .address-meta{margin-left:10px;}#astra-widget-address-2 .widget-address.widget-address-stack .widget-address-field{padding-top:0;padding-bottom:12px;}#astra-widget-address-2 .widget-address.widget-address-inline .widget-address-field{padding-right:12px;}#astra-widget-address-2 .address .widget-address.widget-address-stack .widget-address-field:last-child{padding-bottom:0;}#astra-widget-address-2 .address .widget-address.widget-address-inline .widget-address-field:last-child{padding-right:0;} </style> <link rel='stylesheet' id='astra-widgets-astra-widget-social-profiles-css' href='https://www.medianic.co.uk/wp-content/plugins/astra-widgets/assets/css/minified/astra-widget-social-profiles.min.css?ver=1.2.15' media='all' /> <style id='astra-widgets-astra-widget-social-profiles-inline-css'> #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner li .ast-widget-icon svg{fill:#ffffff;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner li .ast-widget-icon:hover svg{fill:#006789;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square-outline li .ast-widget-icon, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle-outline li .ast-widget-icon{background:transparent;border-color:#006789;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square-outline li .ast-widget-icon svg, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle-outline li .ast-widget-icon svg{background:transparent;fill:#ffffff;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square .ast-widget-icon, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle .ast-widget-icon{background:#006789;border-color:#006789;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square .ast-widget-icon svg, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle .ast-widget-icon svg{fill:#ffffff;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square .ast-widget-icon:hover svg, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle .ast-widget-icon:hover svg{fill:#006789;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square .ast-widget-icon:hover, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle .ast-widget-icon:hover{background:#ffffff;border-color:#ffffff;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square-outline li .ast-widget-icon:hover, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle-outline li .ast-widget-icon:hover{background:transparent;border-color:#ffffff;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.square-outline li .ast-widget-icon:hover svg, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle-outline li .ast-widget-icon:hover svg{fill:#006789;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner .ast-widget-icon{font-size:20px;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle li .ast-widget-icon, #astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.circle-outline li .ast-widget-icon{font-size:20px;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner li > a .ast-widget-icon{margin-right:px;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.stack li > a {padding-bottom:5px;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.inline li > a {padding-right:5px;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner.inline li:last-child a {padding-right:0;}#astra-widget-social-profiles-2 .astra-widget-social-profiles-inner li:last-child a{margin-right:0;padding-bottom:0;} </style> <link rel='stylesheet' id='astra-addon-megamenu-dynamic-css' href='https://www.medianic.co.uk/wp-content/plugins/astra-addon/addons/nav-menu/assets/css/minified/magamenu-frontend.min.css?ver=4.6.4' media='all' /> <style id='astra-addon-megamenu-dynamic-inline-css'> .ast-desktop .menu-item-22 .astra-mm-icon-label.icon-item-22, .ast-header-break-point .menu-item-22 .astra-mm-icon-label.icon-item-22{display:inline-block;vertical-align:middle;line-height:0;margin:5px;}.ast-desktop .menu-item-22 .astra-mm-icon-label.icon-item-22 svg, .ast-header-break-point .menu-item-22 .astra-mm-icon-label.icon-item-22 svg{color:var(--ast-global-color-0);fill:var(--ast-global-color-0);width:20px;height:20px;}.ast-desktop .menu-item-23 .astra-mm-icon-label.icon-item-23, .ast-header-break-point .menu-item-23 .astra-mm-icon-label.icon-item-23{display:inline-block;vertical-align:middle;line-height:0;margin:5px;}.ast-desktop .menu-item-23 .astra-mm-icon-label.icon-item-23 svg, .ast-header-break-point .menu-item-23 .astra-mm-icon-label.icon-item-23 svg{color:var(--ast-global-color-0);fill:var(--ast-global-color-0);width:20px;height:20px;}.ast-desktop .menu-item-20 .astra-mm-icon-label.icon-item-20, .ast-header-break-point .menu-item-20 .astra-mm-icon-label.icon-item-20{display:inline-block;vertical-align:middle;line-height:0;margin:5px;}.ast-desktop .menu-item-20 .astra-mm-icon-label.icon-item-20 svg, .ast-header-break-point .menu-item-20 .astra-mm-icon-label.icon-item-20 svg{color:var(--ast-global-color-0);fill:var(--ast-global-color-0);width:20px;height:20px;}.ast-desktop .menu-item-19 .astra-mm-icon-label.icon-item-19, .ast-header-break-point .menu-item-19 .astra-mm-icon-label.icon-item-19{display:inline-block;vertical-align:middle;line-height:0;margin:5px;}.ast-desktop .menu-item-19 .astra-mm-icon-label.icon-item-19 svg, .ast-header-break-point .menu-item-19 .astra-mm-icon-label.icon-item-19 svg{color:var(--ast-global-color-0);fill:var(--ast-global-color-0);width:20px;height:20px;}.ast-desktop .menu-item-6248 .astra-mm-icon-label.icon-item-6248, .ast-header-break-point .menu-item-6248 .astra-mm-icon-label.icon-item-6248{display:inline-block;vertical-align:middle;line-height:0;margin:5px;}.ast-desktop .menu-item-6248 .astra-mm-icon-label.icon-item-6248 svg, .ast-header-break-point .menu-item-6248 .astra-mm-icon-label.icon-item-6248 svg{color:var(--ast-global-color-0);fill:var(--ast-global-color-0);width:20px;height:20px;}.ast-desktop .menu-item-21 .astra-mm-icon-label.icon-item-21, .ast-header-break-point .menu-item-21 .astra-mm-icon-label.icon-item-21{display:inline-block;vertical-align:middle;line-height:0;margin:5px;}.ast-desktop .menu-item-21 .astra-mm-icon-label.icon-item-21 svg, .ast-header-break-point .menu-item-21 .astra-mm-icon-label.icon-item-21 svg{color:var(--ast-global-color-0);fill:var(--ast-global-color-0);width:20px;height:20px;} </style> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-includes/js/comment-reply.min.js?ver=6.7.1" id="comment-reply-js" async data-wp-strategy="async"></script> <script id="astra-theme-js-js-extra"> var astra = {"break_point":"921","isRtl":"","is_scroll_to_id":"","is_scroll_to_top":"1","is_header_footer_builder_active":"","responsive_cart_click":"flyout","revealEffectEnable":"","edit_post_url":"https:\/\/www.medianic.co.uk\/wp-admin\/post.php?post={{id}}&action=edit","ajax_url":"https:\/\/www.medianic.co.uk\/wp-admin\/admin-ajax.php","infinite_count":"2","infinite_total":"0","pagination":"infinite","infinite_scroll_event":"scroll","no_more_post_message":"No more posts to show.","grid_layout":"1","site_url":"https:\/\/www.medianic.co.uk","blogArchiveTitleLayout":"","show_comments":"Show Comments","masonryEnabled":"","blogMasonryBreakPoint":"921","shop_infinite_count":"2","shop_infinite_total":"0","shop_pagination":"number","shop_infinite_scroll_event":"scroll","shop_no_more_post_message":"No more products to show.","checkout_prev_text":"Back to my details","checkout_next_text":"Proceed to payment","shop_quick_view_enable":"disabled","shop_quick_view_stick_cart":"","shop_quick_view_auto_height":"1","woo_cart_empty_featured_product":"","single_product_qty_ajax_nonce":"80d6edfb0b","single_product_ajax_add_to_cart":"","is_cart":"","is_single_product":"","view_cart":"View cart","cart_url":"https:\/\/www.medianic.co.uk\/cart\/","checkout_url":"https:\/\/www.medianic.co.uk\/card\/","add_to_cart_options_single":"default","is_astra_pro":"1","shopRevealEffectEnable":""}; </script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/themes/astra/assets/js/minified/style.min.js?ver=4.8.7" id="astra-theme-js-js" defer></script> <script type="rocketlazyloadscript" id="rocket-browser-checker-js-after"> "use strict";var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||!1,descriptor.configurable=!0,"value"in descriptor&&(descriptor.writable=!0),Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){return protoProps&&defineProperties(Constructor.prototype,protoProps),staticProps&&defineProperties(Constructor,staticProps),Constructor}}();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}var RocketBrowserCompatibilityChecker=function(){function RocketBrowserCompatibilityChecker(options){_classCallCheck(this,RocketBrowserCompatibilityChecker),this.passiveSupported=!1,this._checkPassiveOption(this),this.options=!!this.passiveSupported&&options}return _createClass(RocketBrowserCompatibilityChecker,[{key:"_checkPassiveOption",value:function(self){try{var options={get passive(){return!(self.passiveSupported=!0)}};window.addEventListener("test",null,options),window.removeEventListener("test",null,options)}catch(err){self.passiveSupported=!1}}},{key:"initRequestIdleCallback",value:function(){!1 in window&&(window.requestIdleCallback=function(cb){var start=Date.now();return setTimeout(function(){cb({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-start))}})},1)}),!1 in window&&(window.cancelIdleCallback=function(id){return clearTimeout(id)})}},{key:"isDataSaverModeOn",value:function(){return"connection"in navigator&&!0===navigator.connection.saveData}},{key:"supportsLinkPrefetch",value:function(){var elem=document.createElement("link");return elem.relList&&elem.relList.supports&&elem.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype}},{key:"isSlowConnection",value:function(){return"connection"in navigator&&"effectiveType"in navigator.connection&&("2g"===navigator.connection.effectiveType||"slow-2g"===navigator.connection.effectiveType)}}]),RocketBrowserCompatibilityChecker}(); </script> <script id="rocket-preload-links-js-extra"> var RocketPreloadLinksConfig = {"excludeUris":"\/card\/|\/cart\/|\/|\/seo-package-terms-conditions\/|\/(?:.+\/)?feed(?:\/(?:.+\/?)?)?$|\/(?:.+\/)?embed\/|\/card\/??(.*)|\/cart\/?|\/my-account\/??(.*)|\/(index.php\/)?(.*)wp-json(\/.*|$)|\/refer\/|\/go\/|\/recommend\/|\/recommends\/","usesTrailingSlash":"1","imageExt":"jpg|jpeg|gif|png|tiff|bmp|webp|avif|pdf|doc|docx|xls|xlsx|php","fileExt":"jpg|jpeg|gif|png|tiff|bmp|webp|avif|pdf|doc|docx|xls|xlsx|php|html|htm","siteUrl":"https:\/\/www.medianic.co.uk","onHoverDelay":"100","rateThrottle":"3"}; </script> <script type="rocketlazyloadscript" id="rocket-preload-links-js-after"> (function() { "use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e=function(){function i(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),e}}();function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var t=function(){function n(e,t){i(this,n),this.browser=e,this.config=t,this.options=this.browser.options,this.prefetched=new Set,this.eventTime=null,this.threshold=1111,this.numOnHover=0}return e(n,[{key:"init",value:function(){!this.browser.supportsLinkPrefetch()||this.browser.isDataSaverModeOn()||this.browser.isSlowConnection()||(this.regex={excludeUris:RegExp(this.config.excludeUris,"i"),images:RegExp(".("+this.config.imageExt+")$","i"),fileExt:RegExp(".("+this.config.fileExt+")$","i")},this._initListeners(this))}},{key:"_initListeners",value:function(e){-1<this.config.onHoverDelay&&document.addEventListener("mouseover",e.listener.bind(e),e.listenerOptions),document.addEventListener("mousedown",e.listener.bind(e),e.listenerOptions),document.addEventListener("touchstart",e.listener.bind(e),e.listenerOptions)}},{key:"listener",value:function(e){var t=e.target.closest("a"),n=this._prepareUrl(t);if(null!==n)switch(e.type){case"mousedown":case"touchstart":this._addPrefetchLink(n);break;case"mouseover":this._earlyPrefetch(t,n,"mouseout")}}},{key:"_earlyPrefetch",value:function(t,e,n){var i=this,r=setTimeout(function(){if(r=null,0===i.numOnHover)setTimeout(function(){return i.numOnHover=0},1e3);else if(i.numOnHover>i.config.rateThrottle)return;i.numOnHover++,i._addPrefetchLink(e)},this.config.onHoverDelay);t.addEventListener(n,function e(){t.removeEventListener(n,e,{passive:!0}),null!==r&&(clearTimeout(r),r=null)},{passive:!0})}},{key:"_addPrefetchLink",value:function(i){return this.prefetched.add(i.href),new Promise(function(e,t){var n=document.createElement("link");n.rel="prefetch",n.href=i.href,n.onload=e,n.onerror=t,document.head.appendChild(n)}).catch(function(){})}},{key:"_prepareUrl",value:function(e){if(null===e||"object"!==(void 0===e?"undefined":r(e))||!1 in e||-1===["http:","https:"].indexOf(e.protocol))return null;var t=e.href.substring(0,this.config.siteUrl.length),n=this._getPathname(e.href,t),i={original:e.href,protocol:e.protocol,origin:t,pathname:n,href:t+n};return this._isLinkOk(i)?i:null}},{key:"_getPathname",value:function(e,t){var n=t?e.substring(this.config.siteUrl.length):e;return n.startsWith("/")||(n="/"+n),this._shouldAddTrailingSlash(n)?n+"/":n}},{key:"_shouldAddTrailingSlash",value:function(e){return this.config.usesTrailingSlash&&!e.endsWith("/")&&!this.regex.fileExt.test(e)}},{key:"_isLinkOk",value:function(e){return null!==e&&"object"===(void 0===e?"undefined":r(e))&&(!this.prefetched.has(e.href)&&e.origin===this.config.siteUrl&&-1===e.href.indexOf("?")&&-1===e.href.indexOf("#")&&!this.regex.excludeUris.test(e.href)&&!this.regex.images.test(e.href))}}],[{key:"run",value:function(){"undefined"!=typeof RocketPreloadLinksConfig&&new n(new RocketBrowserCompatibilityChecker({capture:!0,passive:!0}),RocketPreloadLinksConfig).init()}}]),n}();t.run(); }()); </script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/woocommerce/assets/js/flexslider/jquery.flexslider.min.js?ver=2.7.2-wc.9.4.2" id="flexslider-js" data-wp-strategy="defer" defer></script> <script id="astra-addon-js-js-extra"> var astraAddon = {"sticky_active":"","svgIconClose":"<span class=\"ast-icon icon-close\"><\/span>","header_main_stick":"0","header_above_stick":"0","header_below_stick":"0","stick_header_meta":"","header_main_stick_meta":"","header_above_stick_meta":"","header_below_stick_meta":"","sticky_header_on_devices":"desktop","sticky_header_style":"none","sticky_hide_on_scroll":"0","break_point":"921","tablet_break_point":"921","mobile_break_point":"544","header_main_shrink":"1","header_logo_width":"","responsive_header_logo_width":{"desktop":"","tablet":"","mobile":""},"stick_origin_position":"","site_layout":"ast-full-width-layout","site_content_width":"1180","site_layout_padded_width":"1200","site_layout_box_width":"1200","header_builder_active":"","component_limit":"10","cart_sticky_cart_totals":"","order_review_toggle_texts":{"toggle_show_text":"Show Order Summary","toggle_hide_text":"Hide Order Summary"},"check_user_exist_nonce":"6dc91af824","woocommerce_login_nonce":"b9e05c6b84","is_logged_in":"","user_validation_msgs":{"error_msg":"Entered user detail is not a valid.","success_msg":"This user is already registered. Please enter the password to continue."},"checkout_order_review_sticky":"","cartflows_version":"","is_registration_required":"","is_complete_package":"1","is_header_builder_active":""}; </script> <script type="rocketlazyloadscript" data-minify="1" data-rocket-src="https://www.medianic.co.uk/wp-content/cache/min/1/wp-content/uploads/astra-addon/astra-addon-65d5de71e95671-83074165.js?ver=1708515192" id="astra-addon-js-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/astra-addon/addons/woocommerce/assets/js/minified/single-product-ajax-cart.min.js?ver=4.6.4" id="astra-single-product-ajax-cart-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/woocommerce/assets/js/sourcebuster/sourcebuster.min.js?ver=9.4.2" id="sourcebuster-js-js" defer></script> <script id="wc-order-attribution-js-extra"> var wc_order_attribution = {"params":{"lifetime":1.0000000000000000818030539140313095458623138256371021270751953125e-5,"session":30,"base64":false,"ajaxurl":"https:\/\/www.medianic.co.uk\/wp-admin\/admin-ajax.php","prefix":"wc_order_attribution_","allowTracking":true},"fields":{"source_type":"current.typ","referrer":"current_add.rf","utm_campaign":"current.cmp","utm_source":"current.src","utm_medium":"current.mdm","utm_content":"current.cnt","utm_id":"current.id","utm_term":"current.trm","utm_source_platform":"current.plt","utm_creative_format":"current.fmt","utm_marketing_tactic":"current.tct","session_entry":"current_add.ep","session_start_time":"current_add.fd","session_pages":"session.pgs","session_count":"udata.vst","user_agent":"udata.uag"}}; </script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/woocommerce/assets/js/frontend/order-attribution.min.js?ver=9.4.2" id="wc-order-attribution-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-includes/js/imagesloaded.min.js?ver=5.0.0" id="imagesloaded-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/elementor-pro/assets/js/webpack-pro.runtime.min.js?ver=3.24.3" id="elementor-pro-webpack-runtime-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/elementor/assets/js/webpack.runtime.min.js?ver=3.25.10" id="elementor-webpack-runtime-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/elementor/assets/js/frontend-modules.min.js?ver=3.25.10" id="elementor-frontend-modules-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-includes/js/dist/hooks.min.js?ver=4d63a3d491d11ffd8ac6" id="wp-hooks-js"></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-includes/js/dist/i18n.min.js?ver=5e580eb46a90c2b997e6" id="wp-i18n-js"></script> <script type="rocketlazyloadscript" id="wp-i18n-js-after"> wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ 'ltr' ] } ); </script> <script type="rocketlazyloadscript" id="elementor-pro-frontend-js-before"> var ElementorProFrontendConfig = {"ajaxurl":"https:\/\/www.medianic.co.uk\/wp-admin\/admin-ajax.php","nonce":"910bc245fa","urls":{"assets":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/elementor-pro\/assets\/","rest":"https:\/\/www.medianic.co.uk\/wp-json\/"},"settings":{"lazy_load_background_images":true},"shareButtonsNetworks":{"facebook":{"title":"Facebook","has_counter":true},"twitter":{"title":"Twitter"},"linkedin":{"title":"LinkedIn","has_counter":true},"pinterest":{"title":"Pinterest","has_counter":true},"reddit":{"title":"Reddit","has_counter":true},"vk":{"title":"VK","has_counter":true},"odnoklassniki":{"title":"OK","has_counter":true},"tumblr":{"title":"Tumblr"},"digg":{"title":"Digg"},"skype":{"title":"Skype"},"stumbleupon":{"title":"StumbleUpon","has_counter":true},"mix":{"title":"Mix"},"telegram":{"title":"Telegram"},"pocket":{"title":"Pocket","has_counter":true},"xing":{"title":"XING","has_counter":true},"whatsapp":{"title":"WhatsApp"},"email":{"title":"Email"},"print":{"title":"Print"},"x-twitter":{"title":"X"},"threads":{"title":"Threads"}},"woocommerce":{"menu_cart":{"cart_page_url":"https:\/\/www.medianic.co.uk\/cart\/","checkout_page_url":"https:\/\/www.medianic.co.uk\/card\/","fragments_nonce":"84a15dd4ce"}},"facebook_sdk":{"lang":"en_GB","app_id":""},"lottie":{"defaultAnimationUrl":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/elementor-pro\/modules\/lottie\/assets\/animations\/default.json"}}; </script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/elementor-pro/assets/js/frontend.min.js?ver=3.24.3" id="elementor-pro-frontend-js" defer></script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-includes/js/jquery/ui/core.min.js?ver=1.13.3" id="jquery-ui-core-js" defer></script> <script id="elementor-frontend-js-extra"> var uael_particles_script = {"uael_particles_url":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/min-js\/uael-particles.min.js","particles_url":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/lib\/particles\/particles.min.js","snowflakes_image":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/snowflake.svg","gift":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/gift.png","tree":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/tree.png","skull":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/skull.png","ghost":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/ghost.png","moon":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/moon.png","bat":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/bat.png","pumpkin":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/ultimate-elementor\/assets\/img\/pumpkin.png"}; </script> <script type="rocketlazyloadscript" id="elementor-frontend-js-before"> var elementorFrontendConfig = {"environmentMode":{"edit":false,"wpPreview":false,"isScriptDebug":false},"i18n":{"shareOnFacebook":"Share on Facebook","shareOnTwitter":"Share on Twitter","pinIt":"Pin it","download":"Download","downloadImage":"Download image","fullscreen":"Fullscreen","zoom":"Zoom","share":"Share","playVideo":"Play Video","previous":"Previous","next":"Next","close":"Close","a11yCarouselWrapperAriaLabel":"Carousel | Horizontal scrolling: Arrow Left & Right","a11yCarouselPrevSlideMessage":"Previous slide","a11yCarouselNextSlideMessage":"Next slide","a11yCarouselFirstSlideMessage":"This is the first slide","a11yCarouselLastSlideMessage":"This is the last slide","a11yCarouselPaginationBulletMessage":"Go to slide"},"is_rtl":false,"breakpoints":{"xs":0,"sm":480,"md":768,"lg":1025,"xl":1440,"xxl":1600},"responsive":{"breakpoints":{"mobile":{"label":"Mobile Portrait","value":767,"default_value":767,"direction":"max","is_enabled":true},"mobile_extra":{"label":"Mobile Landscape","value":880,"default_value":880,"direction":"max","is_enabled":false},"tablet":{"label":"Tablet Portrait","value":1024,"default_value":1024,"direction":"max","is_enabled":true},"tablet_extra":{"label":"Tablet Landscape","value":1200,"default_value":1200,"direction":"max","is_enabled":false},"laptop":{"label":"Laptop","value":1366,"default_value":1366,"direction":"max","is_enabled":false},"widescreen":{"label":"Widescreen","value":2400,"default_value":2400,"direction":"min","is_enabled":false}},"hasCustomBreakpoints":false},"version":"3.25.10","is_static":false,"experimentalFeatures":{"additional_custom_breakpoints":true,"e_swiper_latest":true,"e_nested_atomic_repeaters":true,"e_optimized_control_loading":true,"e_onboarding":true,"e_css_smooth_scroll":true,"theme_builder_v2":true,"home_screen":true,"landing-pages":true,"nested-elements":true,"editor_v2":true,"link-in-bio":true,"floating-buttons":true,"display-conditions":true,"form-submissions":true},"urls":{"assets":"https:\/\/www.medianic.co.uk\/wp-content\/plugins\/elementor\/assets\/","ajaxurl":"https:\/\/www.medianic.co.uk\/wp-admin\/admin-ajax.php","uploadUrl":"https:\/\/www.medianic.co.uk\/wp-content\/uploads"},"nonces":{"floatingButtonsClickTracking":"0f12b8b21b"},"swiperClass":"swiper","settings":{"page":[],"editorPreferences":[]},"kit":{"active_breakpoints":["viewport_mobile","viewport_tablet"],"global_image_lightbox":"yes","lightbox_enable_counter":"yes","lightbox_enable_fullscreen":"yes","lightbox_enable_zoom":"yes","lightbox_enable_share":"yes","lightbox_title_src":"title","lightbox_description_src":"description","woocommerce_notices_elements":[]},"post":{"id":3560,"title":"Build%20a%20Music%20Player%20With%20Vuetify%20-%20Medianic","excerpt":"","featuredImage":"https:\/\/www.medianic.co.uk\/wp-content\/uploads\/2018\/07\/player_final.png"}}; </script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/elementor/assets/js/frontend.min.js?ver=3.25.10" id="elementor-frontend-js" defer></script> <script type="rocketlazyloadscript" id="elementor-frontend-js-after">window.addEventListener('DOMContentLoaded', function() { window.scope_array = []; window.backend = 0; jQuery.cachedScript = function( url, options ) { // Allow user to set any option except for dataType, cache, and url. options = jQuery.extend( options || {}, { dataType: "script", cache: true, url: url }); // Return the jqXHR object so we can chain callbacks. return jQuery.ajax( options ); }; jQuery( window ).on( "elementor/frontend/init", function() { elementorFrontend.hooks.addAction( "frontend/element_ready/global", function( $scope, $ ){ if ( "undefined" == typeof $scope ) { return; } if ( $scope.hasClass( "uael-particle-yes" ) ) { window.scope_array.push( $scope ); $scope.find(".uael-particle-wrapper").addClass("js-is-enabled"); }else{ return; } if(elementorFrontend.isEditMode() && $scope.find(".uael-particle-wrapper").hasClass("js-is-enabled") && window.backend == 0 ){ var uael_url = uael_particles_script.uael_particles_url; jQuery.cachedScript( uael_url ); window.backend = 1; }else if(elementorFrontend.isEditMode()){ var uael_url = uael_particles_script.uael_particles_url; jQuery.cachedScript( uael_url ).done(function(){ var flag = true; }); } }); }); jQuery( document ).on( "ready elementor/popup/show", () => { if ( jQuery.find( ".uael-particle-yes" ).length < 1 ) { return; } var uael_url = uael_particles_script.uael_particles_url; jQuery.cachedScript = function( url, options ) { // Allow user to set any option except for dataType, cache, and url. options = jQuery.extend( options || {}, { dataType: "script", cache: true, url: url }); // Return the jqXHR object so we can chain callbacks. return jQuery.ajax( options ); }; jQuery.cachedScript( uael_url ); }); });</script> <script type="rocketlazyloadscript" data-rocket-src="https://www.medianic.co.uk/wp-content/plugins/elementor-pro/assets/js/elements-handlers.min.js?ver=3.24.3" id="pro-elements-handlers-js" defer></script> <script type="rocketlazyloadscript"> /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1); </script> <script>class RocketElementorAnimation{constructor(){this.deviceMode=document.createElement("span"),this.deviceMode.id="elementor-device-mode-wpr",this.deviceMode.setAttribute("class","elementor-screen-only"),document.body.appendChild(this.deviceMode)}_detectAnimations(){let t=getComputedStyle(this.deviceMode,":after").content.replace(/"/g,"");this.animationSettingKeys=this._listAnimationSettingsKeys(t),document.querySelectorAll(".elementor-invisible[data-settings]").forEach(t=>{const e=t.getBoundingClientRect();if(e.bottom>=0&&e.top<=window.innerHeight)try{this._animateElement(t)}catch(t){}})}_animateElement(t){const e=JSON.parse(t.dataset.settings),i=e._animation_delay||e.animation_delay||0,n=e[this.animationSettingKeys.find(t=>e[t])];if("none"===n)return void t.classList.remove("elementor-invisible");t.classList.remove(n),this.currentAnimation&&t.classList.remove(this.currentAnimation),this.currentAnimation=n;let s=setTimeout(()=>{t.classList.remove("elementor-invisible"),t.classList.add("animated",n),this._removeAnimationSettings(t,e)},i);window.addEventListener("rocket-startLoading",function(){clearTimeout(s)})}_listAnimationSettingsKeys(t="mobile"){const e=[""];switch(t){case"mobile":e.unshift("_mobile");case"tablet":e.unshift("_tablet");case"desktop":e.unshift("_desktop")}const i=[];return["animation","_animation"].forEach(t=>{e.forEach(e=>{i.push(t+e)})}),i}_removeAnimationSettings(t,e){this._listAnimationSettingsKeys().forEach(t=>delete e[t]),t.dataset.settings=JSON.stringify(e)}static run(){const t=new RocketElementorAnimation;requestAnimationFrame(t._detectAnimations.bind(t))}}document.addEventListener("DOMContentLoaded",RocketElementorAnimation.run);</script></body> </html> <!-- This website is like a Rocket, isn't it? Performance optimized by WP Rocket. Learn more: https://wp-rocket.me - Debug: cached@1732710827 --><script src="/cdn-cgi/scripts/7d0fa10a/cloudflare-static/rocket-loader.min.js" data-cf-settings="ce7a65fd500996f1d50346de-|49" defer></script>