Free Laravel 9.x Jetstream Inertia Bulma Buefy Vue.js 2.x Dashboard
MIT License
This guide will help you integrate your Laravel Jetstream application with vikdiesel/admin-one-vue-bulma-dashboard Vue Bulma Buefy dashboard.
Please note: this document is work in progress, so some things are missing.
Simple, beautiful and free Vue.js 2.x Bulma Buefy admin dashboard for Laravel 9.x Jetstream Inertia + Vue stack
data
, computed
, methods
, etc.cd
to project dirresources/js
folder to resources-temp/js
. These js files will serve as a reference during development process (just in case, you'll ever need to extract some logic, that is missing here)npm remove @inertiajs/inertia-vue3 @vue/compiler-sfc @tailwindcss/forms @tailwindcss/typography postcss postcss-import tailwindcss
npm i vuex@^3 vue@^2 vue-loader@^15 @vue/composition-api @inertiajs/inertia-vue bulma buefy chart.js vue-chartjs numeral sass sass-loader -D
Replace postCss()
with sass()
and app.scss
with main.scss
in webpack.mix.js
:
mix.js('resources/js/app.js', 'public/js').vue()
.sass('resources/scss/main.scss', 'public/css')
.alias({
'@': 'resources/js',
})
Clone either vikdiesel/admin-one-vue-bulma-dashboard or vikdiesel/admin-two-vue-bulma-dashboard project locally into a separate folder
Next, copy these files from cloned dashboard project directory to laravel project directory:
src/components
src/store
src/menu.js
to resources/js/
src/App.vue
and src/FullPage.vue
to resources/Layouts/
src/css
and src/scss
to resources/
src/assets/justboil-logo.svg
to resources/js/images/
resources/css/app.css
resources
directory from this repository to to laravel project
Replace app.css
with main.css
:
<!-- Styles -->
<link rel="stylesheet" href="{{ mix('css/main.css') }}">
Add before </body>
:
<link href="https://cdn.materialdesignicons.com/4.9.95/css/materialdesignicons.min.css" rel="stylesheet" type="text/css">
Replace <router-view />
with <slot />
Add this.$store.dispatch('toggleFullPage', false)
to created()
lifecycle hook
Add this.$store.dispatch('toggleFullPage', true)
to created()
lifecycle hook
Remove beforeDestroy()
lifecycle hook
Add import filter from 'lodash/filter'
Add filter()
and replace this.$slots.default
with slots
in render()
method, so you'll get:
render (createElement) {
const renderAncestor = elements => createElement(
// ...
)
const slots = filter(this.$slots.default, slot => !!slot.tag)
if (slots.length <= this.maxPerRow) {
return renderAncestor(slots)
} else {
return createElement(
'div',
{ attrs: { class: 'is-tiles-wrapper' } },
chunk(slots, this.maxPerRow).map(group => {
return renderAncestor(group)
})
)
}
}
Let's just add first page. You can repeat these steps for other pages, if you wish to. If you've followed previous steps, there's already resources/js/Pages/HomeExample.vue
for your reference.
First, copy src/views/Home.vue
(original dashboard project) to resources/js/Pages/
(your Laravel project).
Add Head
. Then, wrap page contents into App
Layout component:
<template>
<app>
<Head title="Dashboard" />
<title-bar :title-stack="titleStack" />
<!-- ... -->
</app>
</template>
<script>
import { Head } from '@inertiajs/inertia-vue'
import App from '@/Layouts/App.vue'
// ...
export default defineComponent({
name: 'Home',
components: {
Head,
App,
// ...
}
// ...
})
</script>
Add route in routes/web.php
. There's a /dashboard
route already defined by default, so just replace Inertia::render('Dashboard')
with Inertia::render('Home')
:
Route::get('/dashboard', function () {
return Inertia::render('Home');
})->name('dashboard');
Here we replace router-link with Inertia Link.
Optionally, you can pass menu via Inertia shared props, so it's going to be controlled with PHP. Here we'd just use JS.
to
should be replaced with route
which specifies route name defined in routes/web.php
. For external links href
should be used instead. Here's an example for menu.js
:
export default [
'General',
[
{
route: 'dashboard',
icon: mdiDesktopMac,
label: 'Dashboard'
},
{
href: 'https://example.com/',
icon: mdiDesktopMac,
label: 'Example.com'
}
]
]
Route names reflect ones defined in routes/web.php
:
Route::get('/dashboard', function () {
return Inertia::render('Home');
})->name('dashboard');
Now, let's update vue files, to make them work with route names and Inertia links.
Add Link
import to <script>
:
<script>
import { Link } from '@inertiajs/inertia-vue'
// ...
</script>
Replace componentIs
in computed{}
with:
<script>
export default defineComponent({
// ...
computed: {
componentIs () {
return this.item.route ? Link : 'a'
}
// ...
}
// ...
})
</script>
Replace <component>
attrs with:
<template>
<component
:is="componentIs"
:href="item.route ? $route(item.route) : item.href"
:target="item.target"
:class="{ 'has-icon': !!item.icon, 'has-dropdown-icon': hasDropdown, 'is-active': item.route && $route().current(item.route) }"
@click="menuClick"
>
<!-- ... -->
</component>
</template>
Import and register Link
component:
<script>
import { Link } from '@inertiajs/inertia-vue'
// ...
export default defineComponent({
components: {
Link
// ...
}
// ...
})
</script>
Replace <router-link>
with <Link>
:
<template>
<Link
:href="$route('dashboard')"
class="navbar-item"
:class="{ 'is-active': $route().current('dashboard') }"
>
<!-- ... -->
</Link>
</template>
Replace this.$router
with Inertia
:
<script>
import { Inertia } from '@inertiajs/inertia'
// ...
export default defineComponent({
// ...
mounted () {
Inertia.on('navigate', (event) => {
this.isMenuActive = false
})
}
// ...
})
</script>
Fix newAvatar
computed property, so it fetches profile photo from backend:
<script>
export default defineComponent({
// ...
computed: {
newAvatar () {
return this.avatar ? this.avatar : this.$page.props.user.profile_photo_url
}
}
})
</script>
Update userName
and logout
:
<script>
export default defineComponent({
// ...
computed: {
// ...
userName () {
return this.$page.props.user.name
},
...mapState([
'isAsideMobileExpanded',
'isNavBarVisible',
// remove 'userName'
])
},
methods: {
// ...
logout () {
Inertia.post(route('logout'))
}
}
// ...
})
</script>
As mentioned, this guide is WIP - work in progress. Contributions open. Here's the list of what's missing right now:
If you're using an older version of Laravel, please follow Laravel 7.x & 8.x guide.