solution • Vuetify templates - martindubenet/wed-dev-design GitHub Wiki

Vue.js coding  ][  Vuetify templates  ][  Vue.js setup for Vuetify  ][  Vue headless CMS site  ]

Vuetify

https://vuetifyjs.com/

 

Tips and Tricks

Nested activator button

When having two interactions set on a single button declare them as an array within the v-on parameter.

In this example, a mouse-hover activates a V-Tooltip while the click activates the V-Dialog.

<v-dialog v-model="modalDialog">
  <template #activator="{ on: dialog, attrs }">
    <v-tooltip top>
      <template v-slot:activator="{ on: tooltip }">
        <v-btn
          v-bind="attrs"
          v-on="{ ...tooltip, ...dialog }"
          @click="redirecToPage2"
          …
        />
      </template>
      <p>Tooltip text lorem ipsum</p>
    </v-tooltip>
  </template>
  …
</v-dialog>

Share Variables

 

Style Sheets

Scoping the stylesheets adds specificity to your CSS based on the HTML data attributes (<div data-v-…>) dynamically generated by Vue.js on the « component.vue » rendered in the DOM.

<style lang="scss" scoped>
  .selector{}
</style>
.selector[data-v-…] {}

::v-deep

This is a deep selector that allows to target styles from within a parent or grand-parent to a child component. We could resume the logic of ::v-deep to some kind of CSS !important declaration where they both kind of bypass the cascading logic of CSS.

::v-deep .child-component-selector .example { … }
.parent-selector::v-deep .child-component-selector .example { … }

 

@import Vuetify Sass

This is how Vuetify propose in their doc about Sass Material Color Pack : Set the Sass variable $color-pack to false so we don't import all Vuetify Material Colors Sass files in order to customise some parameters for our solution BEFORE compiling it.

// src/sass/yourFile.scss 

// Parameter
$color-pack: false;

// Load Vuetify within your Sass
@import '~vuetify/src/styles/main.sass';

Over-rule Vuetify's Default CSS Values

If you want your UI controls (links, switchs, sliders and form elements as button, input, select, textarea, fieldset, legend) in their default, disabled and active states to match, you need to control the text color, border-color and background-color CSS values that are applied on ALL Vuetify components « as a all ». In Vuetify v.2.6 this is manage by src/styles/styles.scss that loads src/styles/tools/* and src/styles/settings/*.

Material Theme Driven Colors

Any color that is trigged by Dark or Light Modes refers to Google's Material Design theming.

Sass variable npm package file
$color-pack ~/node_mobules/vuetify/src/styles/settings/_variables.scss
$grey:()
$shades:()
~/node_mobules/vuetify/src/styles/settings/_colors.scss
$material-dark:() ~/node_mobules/vuetify/src/styles/settings/_dark.scss
$material-light:() ~/node_mobules/vuetify/src/styles/settings/_light.scss

 

Utility classes

Custom utility class for Vuetify projects

Flex column gap

Custom column gaps based on Vuetify's responsive $grid-gutter variable for any Flex positionned elements.

You will find below my «$rv-*» set of variable values.

// Hard values (duplicated from Vuetify)
$rv-grid-gutter-xs: 12px;
$rv-grid-gutter-sm: 20px;
$rv-grid-gutter-md: 24px;
$rv-grid-gutter-lg: 32px;
$rv-grid-gutter-xl: 40px;

// Create one reponsive Grid Gutter variable adapted for every breakpoints
--grid-gutter: #{$rv-grid-gutter-xs};
@media ($rv-sm-min) {
    --grid-gutter: #{$rv-grid-gutter-sm};
}
@media ($rv-md-min) {
    --grid-gutter: #{$rv-grid-gutter-md};
}
@media ($rv-lg-min) {
    --grid-gutter: #{$rv-grid-gutter-lg};
}
@media ($rv-xl-min) {
    --grid-gutter: #{$rv-grid-gutter-xl};
}

// Generate inline-margins between childs of `d-flex`
.flex-column-gap {
  column-gap: var(--grid-gutter);
}
.flex-small-column-gap {
  column-gap: calc(var(--grid-gutter) / 2);
}
.flex-button-column-gap {
  column-gap: 8px;

  > .v-btn.flex-grow-1 {
    margin-left: 0;
    margin-right: 0;
  }
}

Scroolbar Y container

Container show vertical scrollbar when child overflows

// Hard values
--scrollbar-y-width: 10px; // from inspecting Chromio/Webkit browsers
--color-control-theme: lime; // ............. replace by your color
--color-control-contrast-theme: red; // ..... replace by your color

// styling
.scrollbar-y-container {
  overflow-x: hidden; // prevent horizontal scroll
  overflow-y: scroll;
  max-height: 100%;

  // cross-browser style hack: No Gecko/Firefox compatibility
  &::-webkit-scrollbar {
    width: var(--scrollbar-y-width);
    background-color: transparent;
  }
  &::-webkit-scrollbar-thumb {
    background-color: var(--color-control-theme);
    border-radius: var(--scrollbar-y-width);
    &:hover {
      background-color: var(--color-control-contrast-theme);
    }
  }
}

 

Same logic as Bootsatrp (v4) Grid System with it's own methods of declaring Breakpoints where you have a <v-container fluid> within a <v-row> where the set of <v-col cols="12"> exists. We also have a <v-spacer> to offset some containers if required.

Default Breakpoints

XS 0 @media screen and (min-width:0) Breakpoints
SM 600 @media screen and (min-width:600px)
MD 960 @media screen and (min-width:960px)
LG 1264 @media screen and (min-width:1264px)
XL 1904 @media screen and (min-width:1904px)
XXL <* class="container-fluid">

Vuetify script for responsive design

isMobile()

Vuetify comes with a mobileBreakpoint variable to trigger the styles for its components to switch from « Mobile VS Desktop » layout.

This variable can then be computed in a template via the «isMobile» statement to differentiate any mobile device viewport dimensions, both Tablets and Phones, from larger Computers browser viewport dimensions.

isMobilePhone()

With the «isMobile» we are missing a granular statement to differentiate Smartphones from other « mobile devices » (tablets). Therefor the «isMobilePhone» statement below rely on the «xs» breakpoint to get his true statement.

<template>
  <fragment>
    <figure v-if="isMobile" :class="isMobilePhone ? 'is-mobile-phone' : 'is-mobile-tablet'"></figure>
    <artile v-if="isMobilePhone">
      <section>
        @media XS : Smartphones only!
      </section>
    </artile>
    <artile v-if="!isMobilePhone">
      <section v-if="isMobile">
        @media SM ≥ MD : Tablets and reduced browser windows on computers.
      </section>
      <section v-if="!isMobile">
        @media LG ≥ ∞ : Computer’s monitor screens.
      </section>
    </artile>
</template>
<script>
  …
  computed: {
    isMobile() {
      return this.$vuetify.breakpoint.mobile;
    },
    isMobilePhone() {
      const vbpName = this.$vuetify.breakpoint.name;
      let phoneBreakpoint = false;
      if (vbpName === "xs") {
        phoneBreakpoint = true;
      }
      return phoneBreakpoint;
    },
  },

Manage responsive column using boolean props

In this example, depending on the contexts where this component is imported, we may or not display multiple columns. Not that the :lg declaration below is a classic interpolation condition.

<template><v-col 
      cols="12"
      :md="{ 6: setDisplayOptionalColumn }"
      :lg="setDisplayOptionalColumn ? 7 : null"
      ></v-col><v-col v-if="setDisplayOptionalColumn()">
      <slot name="optional-column-container" />
    </v-col></template>
<script>
  …
  props: {
    isDisplayOptionalColumn: {
      type: Boolean,
      default: () => false,
    },
  },
  methods: {
    setDisplayOptionalColumn() {
      return this.isDisplayOptionalColumn;
    },
  },

Responsive cascading logic

  1. styles/_values.scss
  2. styles/_sass-responsive-variables.scss
  3. styles/responsive-variables.scss
  4. plugins/vuetify.js

_values.scss

The values from this file can be mapped within other Sass and/or exported to JavaScript so no values from this Sass document are duplicated in our project making it THE SOURCE OF TRUTH to import where needed, like in Vuetify config file (vuetify.js) where they then get exported within the breakpoint thresholds.

$breakpoints: (
  "smBreakpoint": 600px,
  "mdBreakpoint": 960px,
  "lgBreakpoint": 1264px,
  "xlBreakpoint": 1904px,
);

:export {
  /**
   * Remove quotes (required by Sass) so JavaScript won't read these as strings.
   * Divide value by 1px to get a unitless value, stripping the "px". ex: 600px / 1px = 600
   */
  @each $key, $value in $breakpoints {
    #{unquote($key)}: $value / 1px;
  }
}

_sass-responsive-variables.scss

@use "sass:map";
@import "_values";

$rv-breakpoint-sm: map.get($breakpoints, "smBreakpoint");
$rv-breakpoint-md: map.get($breakpoints, "mdBreakpoint");
$rv-breakpoint-lg: map.get($breakpoints, "lgBreakpoint");
$rv-breakpoint-xl: map.get($breakpoints, "xlBreakpoint");

/** ----------------------
 * Media queries to be used within `Component.vue` file
 * ex: `@media ($rv-min-md) {}`
 */

// Maximum viewport width (for smartphones)
$rv-max-xs: "max-width: " + ($rv-breakpoint-sm - 1px);

// Minimum viewport widths
$rv-min-sm: "min-width: " + $rv-breakpoint-sm;
$rv-min-md: "min-width: " + $rv-breakpoint-md;
$rv-min-lg: "min-width: " + $rv-breakpoint-lg;
$rv-min-xl: "min-width: " + $rv-breakpoint-xl;

/** ----------------------
 * Breakpoint related variables
 */
$rv-grid-gutter-xs: 12px;
$rv-grid-gutter-sm: 20px;
$rv-grid-gutter-md: 24px;
$rv-grid-gutter-lg: 32px;
$rv-grid-gutter-xl: 40px;

$rv-font-size-xs: 1rem;
$rv-font-size-sm: 1.25rem;
$rv-font-size-xl: 2rem;

responsive-variables.scss

The following responsive variables are safe to use within any component since they will be compiled as CSS.

@import "_values";
@import "_sass-variables";

:root {
  // Responsive Variables
  --rv-font-size-base: #{$rv-font-size-xs};
  --rv-grid-gutter: #{$rv-gutter-xs};
  @media ($mainrv-sm-min) {
    --rv-font-size-base: #{$rv-font-size-sm};
    --rv-grid-gutter: #{$rv-gutter-sm};
  }
  @media ($mainrv-md-min) {
    --rv-grid-gutter: #{$rv-gutter-md};
  }
  @media ($mainrv-lg-min) {
    --rv-grid-gutter: #{$rv-gutter-lg};
  }
  @media ($mainrv-xl-min) {
    --rv-font-size-base: #{$rv-font-size-xl};
    --rv-grid-gutter: #{$rv-gutter-xl};
  }
}

vuetify.js

import Values from "@/styles/_values.scss";

export default new Vuetify({
  breakpoint: {
    thresholds: {
      xs: Values.smBreakpoint,
      sm: Values.mdBreakpoint,
      md: Values.lgBreakpoint,
      lg: Values.xlBreakpoint,
    },
    scrollBarWidth: 0,
    mobileBreakpoint: "sm", // default: Larger then this = Desktop style
  },
});

 

 

⚠️ **GitHub.com Fallback** ⚠️