Skip to content

Instantly share code, notes, and snippets.

@JordanMajd
Last active October 9, 2020 16:59
Show Gist options
  • Save JordanMajd/c30e5ee053d92530cb6bad8ee2fde33b to your computer and use it in GitHub Desktop.
Save JordanMajd/c30e5ee053d92530cb6bad8ee2fde33b to your computer and use it in GitHub Desktop.

Bootstrap & SASS in Intuition

The goal of this document is to provide a high level overview of scss and bootstrap in relation to Intuition and provide you with resources to dig deeper.

SASS/SCSS

SCSS turns CSS into a full blown language and an overwhelming number of features. We will primarily benefit from:

  • Imports
  • Variables
  • Mixins
  • Functions

SASS & SCSS are the same, SASS is just a different syntax (like coffeescript to javascript).

For an example of importing, variables and function see statement-charge-breakdown.vue:

<style scoped lang="scss">
@import "src/styles/wyyerd_intuition.scss";
.chip {
  background: $primary_1_;
  border-radius: 1.2rem;
  padding-left: 1.2rem;
  padding-right: 1.2rem;
  padding-top: 0.2rem;
  padding-bottom: 0.2rem;
}

th {
  color: color("gray");
}
</style>

For an example of nesting, selectors & combinators see statement-details.vue:

<style scoped lang="scss">
.statement-details {
  ::v-deep tr {
    border-bottom: 1px solid #dfe3e7;
    &.total-row {
      border-bottom: 0;
    }
    > td,
    > th {
      border-top: 0;
    }
  }
}
</style>

Here is a mixin defined in wyyerd_intuition.scss

@mixin noto_sans_h1($text-align: "") {
  @if $text-align != "" {
    text-align: $text-align;
  }
  font-weight: 300;
  line-height: 64px;
  font-size: 52px;
  letter-spacing: 0.20000000298023px;
}
<template>
    <div>
      <label class="title">I'm primary color, aligned center, with a big ol' typeface</label>
    </div>
<template>
<style scoped lang="scss">
@import "src/styles/wyyerd_intuition.scss";
.title {
  // mixin defined in wyyerd_intuition.scss
  @include noto_sans_h1("center"); 
  color: $primary;
}
</style>

What else do we get access to when we import wyyerd_intuition.scss? Navigate to the file and ctrl click to view.

@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
// Optional
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/images";
@import "~bootstrap/scss/code";
@import "~bootstrap/scss/grid";

Styling / Theming

"Where should I put my styles?"

There are two primary areas we will be putting styles:

  • The component. If you want a style to only affect a single component (and possibly it's children) it goes here.
  • wyyerd_intuition.scss. If the style is overriding a bootstrap style, variable or defining a new color it should go here. Every color we use should be defined here.

We also have 2 other places, but usage of these will be less common:

  • main.scss: This is where we put any styles that should apply to our app, multiple components, but aren’t bootstrap specific.

  • overrides.scss: This is where we lay down the hammer and resolve any CSS conflicts. In an ideal world this wouldn’t exist; however, since we have 3 CSS frameworks it does.

  • Theming Bootstrap-vue

  • Bootstrap Theming

  • Bootstrap Variables

Grid

Bootstrap provides a grid system that enables us to easily define a layout and position elements in a responsive manner.

Careful styling the grid elements, as some changes can break an entire layout.

  • For b-col you shouldn't mess with anything that changes the sizing, positioning, display etc.
  • For b-row changing the left - right padding
<b-row>
  <b-col cols="8">Takes up 8 out of 12</b-col>
  <b-col>Takes up 2 out of 12</b-col>
  <b-col>Takes up 2 out of 12</b-col>
</b-row>

Grid supports:

  • Custom width columns

  • Equal width column

  • Multiline columns

  • Variable width content

  • Sizing columns for different display sizes

  • Offsetting columns

  • Bootstrap Grid

  • Bootstrap Vue Grid

Utilities

Utilities are classes that bootstrap provides for common things you would normally write styles for.

Form Validation

We use vee-validate for form validation.

In order for a component to validate it needs to be wrapped in a validation-observer and needs to have a ref defined for us to access it. b-enhanced-form already handles this, so any forms wrapped in a b-enhanced-form don't need to worry about this.

b-enhanced-form

<template>
  <validation-observer ref="observer">
    <b-form ref="form">
      <b-alert v-model="showError" variant="danger" dismissible>{{
        displayError
      }}</b-alert>
      <slot />
    </b-form>
  </validation-observer>
</template>

Here is an example of how to validate all the validation-providers inside of the observer:

const validationObs: InstanceType<typeof ValidationObserver> = this.$refs
.observer as InstanceType<typeof ValidationObserver>;
let isValid = await validationObs.validate();

Each input will need to be wrapped in a validation-provider with a v-slot="v" and rules.

  • Slot provides us with validation messaging, classes and more
  • The rules is where we define rules for the input, see rules.ts.

To validate a b-form-group

  • Add a :class="v.classes" binding to the input element.
  • Add a <b-form-invalid-feedback>{{ v.errors[0] }}</b-form-invalid-feedback> (or </b-form-valid-feedback>) This will show or hide depending on what classes get set by the validator.

This is an excerpt from form-reset-password demonstrating the above:

<validation-provider v-slot="v" name="Login" rules="required">
      <b-form-group label="Login">
        <b-form-select
          v-model="form.loginId"
          placeholder
          :options="logins"
          value-field="id"
          :class="v.classes"
          text-field="username"
        >
          <template v-slot:first>
            <b-form-select-option :value="null" disabled
              >-- Select Login --</b-form-select-option
            >
          </template>
        </b-form-select>
        <b-form-invalid-feedback>{{ v.errors[0] }}</b-form-invalid-feedback>
      </b-form-group>
    </validation-provider>

Examples of validation in our app:

Masking

We use a library called v-maska for input masking. To add masking to an input add a v-maska directive to the input and provide a string.

Here we can see it used by b-input-phone.vue, which uses a computed string to set the mask:

<b-form-input
ref="input"
v-model="number"
v-maska="phoneMask"
type="tel"
:readonly="isReadonly"
:disabled="disabled"
:required="required"
:maxlength="dialCode === 1 ? 14 : 15"
:placeholder="placeholder"
@input="onInput"
></b-form-input>
...
computed: {
    phoneMask(): string {
      if (this.dialCode === 1) {
        // Phone mask for North American numbers
        return "(###) ###-####";
      } else {
        // Allow any digit for other numbers
        return "#*";
      }
    },
}

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment