314 lines
8.9 KiB
Markdown
314 lines
8.9 KiB
Markdown
|
---
|
|||
|
title: Rebuilding Bartik (Drupal’s Default Theme) with Vue.js and Tailwind CSS - part 2
|
|||
|
date: 2018-12-27
|
|||
|
excerpt: A follow-up to my original post on rebuilding Bartik with Tailwind and Vue.js.
|
|||
|
tags:
|
|||
|
- drupal
|
|||
|
- tailwind-css
|
|||
|
- tweet
|
|||
|
- vuejs
|
|||
|
has_tweets: true
|
|||
|
---
|
|||
|
|
|||
|
In [the original post](/blog/rebuilding-bartik-with-vuejs-tailwind-css) I
|
|||
|
detailed how I built [a clone of Drupal’s Bartik theme][netlify] with
|
|||
|
[Vue.js][vuejs] and [Tailwind CSS][tailwind]. This follow-up post details some
|
|||
|
updates that I’ve made to it since then.
|
|||
|
|
|||
|
## Customising Tailwind’s colours
|
|||
|
|
|||
|
During the first version of the page, my thoughts were to not edit the Tailwind
|
|||
|
configuration, however I changed my mind on this whilst working on the
|
|||
|
subsequent updates and did make some changes and customisations to the
|
|||
|
`tailwind.js` file.
|
|||
|
|
|||
|
By default, Tailwind includes a full colour palette including colours such as
|
|||
|
yellows, oranges, reds that weren’t being used in this page so they were
|
|||
|
removed. This makes the file more readable as well as reduces the number of
|
|||
|
classes that Tailwind generates.
|
|||
|
|
|||
|
Whist I was changing the colours, I also took the opportunity to tweak the
|
|||
|
values of the remaining colours to more closely match Bartik’s original colours.
|
|||
|
|
|||
|
I also added a `black-60` class which uses
|
|||
|
[RGBA](https://css-tricks.com/the-power-of-rgba) to provide a semi-transparent
|
|||
|
background. I used this when adding the
|
|||
|
[skip to main content link](#adding-the-skip-to-main-content-link).
|
|||
|
|
|||
|
```js
|
|||
|
let colors = {
|
|||
|
transparent: 'transparent',
|
|||
|
|
|||
|
black: '#22292f',
|
|||
|
'grey-darkest': '#3d4852',
|
|||
|
'grey-dark': '#8795a1',
|
|||
|
grey: '#b8c2cc',
|
|||
|
'grey-light': '#dae1e7',
|
|||
|
'grey-lighter': '#f0f0f0',
|
|||
|
'grey-lightest': '#F6F6F2',
|
|||
|
white: '#ffffff',
|
|||
|
|
|||
|
'black-60': 'rgba(0, 0, 0, .6)',
|
|||
|
|
|||
|
'blue-dark': '#2779bd',
|
|||
|
blue: '#3490dc',
|
|||
|
'blue-light': '#bcdefa',
|
|||
|
|
|||
|
'green-dark': '#325E1C',
|
|||
|
green: '#77B159',
|
|||
|
'green-light': '#CDE2C2',
|
|||
|
'green-lighter': '#F3FAEE',
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
## Adding default styling for links
|
|||
|
|
|||
|
In the first version, every link was individually styled which resulted in a lot
|
|||
|
of duplicate classes and a potential maintenance issue.
|
|||
|
|
|||
|
I added a `style` section within `Welcome.vue`, and added some default styling
|
|||
|
for links based on their location on the page -
|
|||
|
[extracting some Tailwind components](https://tailwindcss.com/docs/extracting-components).
|
|||
|
|
|||
|
<div v-pre markdown="1">
|
|||
|
```html
|
|||
|
<template>
|
|||
|
...
|
|||
|
|
|||
|
<div id="footer" class="text-xs text-white">
|
|||
|
<div class="container px-4 pt-16 pb-4 mx-auto">
|
|||
|
<div class="pt-6 -mb-6 border-t border-gray-900 border-solid">
|
|||
|
<div class="mb-6">
|
|||
|
<p><a href="#0">Contact</a></p>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="mb-6">
|
|||
|
<p>
|
|||
|
A clone of <a href="https://www.drupal.org">Drupal</a>’s default theme (Bartik).
|
|||
|
Built by <a href="https://www.oliverdavies.uk">Oliver Davies</a>
|
|||
|
using <a href="https://vuejs.org">Vue.js</a>
|
|||
|
and <a href="https://tailwindcss.com">Tailwind CSS</a>.
|
|||
|
</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
```
|
|||
|
|
|||
|
Within the `style` section, I’m able to use Tailwind’s custom `@apply` directive
|
|||
|
to inject it’s rules into more traditional CSS, rather than needing to add them
|
|||
|
onto every link.
|
|||
|
|
|||
|
```vue-html
|
|||
|
<style lang="sass">
|
|||
|
#header a
|
|||
|
@apply text-white no-underline
|
|||
|
|
|||
|
&:hover,
|
|||
|
&:focus
|
|||
|
@apply underline
|
|||
|
|
|||
|
#main a
|
|||
|
@apply text-blue-dark no-underline border-b border-blue-600 border-dotted
|
|||
|
|
|||
|
&:hover,
|
|||
|
&:focus
|
|||
|
@apply text-blue-600 border-solid
|
|||
|
|
|||
|
#footer a
|
|||
|
@apply text-white no-underline border-b border-dotted border-white
|
|||
|
|
|||
|
&:hover,
|
|||
|
&:focus
|
|||
|
@apply border-none
|
|||
|
</style>
|
|||
|
```
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
## Extracting a Vue component for Drupal blocks
|
|||
|
|
|||
|
As well as being able to extract re-usable components within Tailwind, the same
|
|||
|
can be done within Vue. As the page could potentially have multiple sidebar
|
|||
|
blocks, I extracted a `SidebarBlock` component which would act as a wrapper
|
|||
|
around the block’s contents.
|
|||
|
|
|||
|
```vue-html
|
|||
|
// src/components/Sidebar.vue
|
|||
|
|
|||
|
<template>
|
|||
|
<div class="p-4 mb-4 bg-gray-200">
|
|||
|
<slot></slot>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
```
|
|||
|
|
|||
|
The component provides the wrapping div and the appropriate classes in a single
|
|||
|
easy-to-maintain location, and
|
|||
|
[uses a slot](https://vuejs.org/v2/guide/components-slots.html) as a placeholder
|
|||
|
for the main content.
|
|||
|
|
|||
|
That means that within `Welcome.vue`, the markup within the `sidebar-block` tags
|
|||
|
will be used as the block contents.
|
|||
|
|
|||
|
```html
|
|||
|
<sidebar-block>
|
|||
|
<p>My block contents.</p>
|
|||
|
</sidebar-block>
|
|||
|
```
|
|||
|
|
|||
|
## Adding the Skip to Main Content Link
|
|||
|
|
|||
|
One thing
|
|||
|
[that was missing](https://github.com/opdavies/rebuilding-bartik/issues/1) was
|
|||
|
the 'Skip to main content link'. This an accessibility feature that allows for
|
|||
|
users who are navigating the page using only a keyboard to bypass the navigation
|
|||
|
links and skip straight to the main content if they wish by clicking a link that
|
|||
|
is hidden and only visible whilst it’s focussed on.
|
|||
|
|
|||
|
Here is the markup that I used, which is placed directly after the opening
|
|||
|
`<body>` tag.
|
|||
|
|
|||
|
```html
|
|||
|
<a
|
|||
|
href="#0"
|
|||
|
class="py-1 px-2 text-white rounded-b-lg focus:no-underline focus:outline-none skip-link bg-black-60"
|
|||
|
>
|
|||
|
Skip to main content
|
|||
|
</a>
|
|||
|
```
|
|||
|
|
|||
|
I initially tried to implement the same feature on this website using
|
|||
|
[Tailwind’s visually hidden plugin](https://www.npmjs.com/package/tailwindcss-visuallyhidden)
|
|||
|
which also contains a `focussable` class, though I wasn’t able to style it the
|
|||
|
way that I needed. I created my own
|
|||
|
[Tailwind skip link plugin](https://www.npmjs.com/package/tailwindcss-skip-link)
|
|||
|
and moved the re-usable styling there.
|
|||
|
|
|||
|
To enable the plugin, I needed to add it within the `plugins` section of my
|
|||
|
`tailwind.js` file:
|
|||
|
|
|||
|
```js
|
|||
|
plugins: [
|
|||
|
require('tailwindcss/plugins/container')(),
|
|||
|
require('tailwindcss-skip-link')(),
|
|||
|
],
|
|||
|
```
|
|||
|
|
|||
|
I added only the page-specific styling classes to the link (as well as the
|
|||
|
`skip-link` class that the plugin requires) as well as my own focus state to the
|
|||
|
skip link that I did within the `style` section of `App.vue`.
|
|||
|
|
|||
|
```vue-html
|
|||
|
<style lang="sass">
|
|||
|
@tailwind preflight
|
|||
|
@tailwind components
|
|||
|
|
|||
|
.skip-link:focus
|
|||
|
left: 50%
|
|||
|
transform: translateX(-50%)
|
|||
|
|
|||
|
@tailwind utilities
|
|||
|
</style>
|
|||
|
```
|
|||
|
|
|||
|
![The Bartik clone with the skip to main content link visible](/images/blog/rebuilding-bartik-vue-tailwind-part-2/skip-link.png){.border}
|
|||
|
|
|||
|
## Adding the DrupalMessage component
|
|||
|
|
|||
|
I also added a version of Drupal’s status message as another Vue component. This
|
|||
|
also uses a slot to include the message contents and accepts a
|
|||
|
[prop](https://vuejs.org/v2/guide/components-props.html) for the message type.
|
|||
|
|
|||
|
```html
|
|||
|
<template>
|
|||
|
<div :class="[ wrapperClasses, wrapperClasses ? 'pl-2 rounded-sm' : '' ]">
|
|||
|
<div
|
|||
|
class="flex items-center py-4 pr-4 pl-3 mb-4 rounded-sm border"
|
|||
|
:class="classes"
|
|||
|
>
|
|||
|
<svg
|
|||
|
v-if="type == 'status'"
|
|||
|
class="mr-3 w-4 h-4 fill-current text-green"
|
|||
|
xmlns="http://www.w3.org/2000/svg"
|
|||
|
>
|
|||
|
<path
|
|||
|
d="M6.464 13.676a.502.502 0 0 1-.707 0L.797 8.721a.502.502 0 0 1 0-.707l1.405-1.407a.5.5 0 0 1 .707 0l2.849 2.848a.504.504 0 0 0 .707 0l6.629-6.626a.502.502 0 0 1 .707 0l1.404 1.404a.504.504 0 0 1 0 .707l-8.741 8.736z"
|
|||
|
/>
|
|||
|
</svg>
|
|||
|
<slot></slot>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
```
|
|||
|
|
|||
|
The value of the `type` prop is then used within some computed properties to
|
|||
|
determine the type specific classes to add (e.g. green for success, and red for
|
|||
|
warning), as well as whether or not to include the checkmark SVG image.
|
|||
|
|
|||
|
```js
|
|||
|
<script>
|
|||
|
export default {
|
|||
|
props: {
|
|||
|
type: String,
|
|||
|
},
|
|||
|
|
|||
|
computed: {
|
|||
|
classes: function () {
|
|||
|
return {
|
|||
|
status: 'border-green-light text-green-dark bg-green-lighter',
|
|||
|
}[this.type]
|
|||
|
},
|
|||
|
|
|||
|
wrapperClasses: function () {
|
|||
|
return {
|
|||
|
status: 'bg-green',
|
|||
|
}[this.type]
|
|||
|
},
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
```
|
|||
|
|
|||
|
I did need to make one change to the `tailwind.js` file in order to change the
|
|||
|
border on links when they are hovered over - within `modules` I needed to enable
|
|||
|
the `borderStyle` module for hover and focus states in order for Tailwind to
|
|||
|
generate the additional classes.
|
|||
|
|
|||
|
```js
|
|||
|
modules: {
|
|||
|
// ...
|
|||
|
borderStyle: ['responsive', 'hover', 'focus'],
|
|||
|
// ...
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
The message is included within the Welcome component by including the
|
|||
|
`<drupal-message />` element, though rather than importing it there, it’s
|
|||
|
registed as a global component so it would be available to any other components
|
|||
|
that could be added in the future.
|
|||
|
|
|||
|
This is done within `main.js`:
|
|||
|
|
|||
|
```js
|
|||
|
// ...
|
|||
|
|
|||
|
Vue.component('drupal-message', require('@/components/DrupalMessage').default);
|
|||
|
|
|||
|
new Vue({
|
|||
|
render: h => h(App),
|
|||
|
}).$mount('#app');
|
|||
|
```
|
|||
|
|
|||
|
![The Bartik clone with the Drupal Message component visible](/images/blog/rebuilding-bartik-vue-tailwind-part-2/drupal-message.png){.border}
|
|||
|
|
|||
|
**The updated version is [live on Netlify][netlify], and the [latest source code
|
|||
|
is available on GitHub][github].**
|
|||
|
|
|||
|
[github]: https://github.com/opdavies/rebuilding-bartik
|
|||
|
[netlify]: https://rebuilding-bartik.oliverdavies.uk
|
|||
|
[tailwind]: https://tailwindcss.com
|
|||
|
[vuejs]: https://vuejs.org
|