Navigation sidebar vuex + typescript

Viewed 15

everyone!

How to make a sidebar navigator using veux + typescript?

I'm stuck and I don't know how to move on.. help me, dear, patient developers

using vue3 (Composition API setup) + Typescript + Tailwind CSS

Can u help me?

enter image description here

package.json

{
  "name": "kalys.io",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "@heroicons/vue": "^1.0.6",
    "@tailwindcss/postcss7-compat": "^2.2.17",
    "autoprefixer": "^9",
    "chart.js": "^3.7.1",
    "core-js": "^3.6.5",
    "heroicons": "^1.0.6",
    "postcss": "^7",
    "query-string": "^7.1.1",
    "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
    "vue": "^3.0.0",
    "vue-chartjs": "^4.1.0",
    "vue-google-maps-typescript": "^0.1.4",
    "vue-router": "^4.0.0-0",
    "vueperslides": "^3.3.2",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "typescript": "~4.1.5",
    "vue-cli-plugin-tailwind": "^2.2.18"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

inside store/index.ts

import {
  createStore,
  Store as VuexStore,
  CommitOptions,
  createLogger,
  DispatchOptions
} from 'vuex'

import { State, state } from './modules/state'
import { Mutations, mutations } from './modules/mutations'
import { Actions, actions } from './modules/actions'
import { Getters, getters } from './modules/getters'

export const store = createStore<State>({
  plugins: process.env.NODE_ENV === 'development' ? [createLogger()] : [],
  state,
  mutations,
  actions,
  getters,

  modules: {
  }
})

export function useStore() {
  return store as Store
}
export type Store = Omit<
VuexStore<State>,
'getters' | 'commit' | 'dispatch'
> & {
  commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
    key: K,
    payload: P,
    options?: CommitOptions
  ): ReturnType<Mutations[K]>
} & {
  dispatch<K extends keyof Actions>(
    key: K,
    payload?: Parameters<Actions[K]>[1],
    options?: DispatchOptions
  ): ReturnType<Actions[K]>
} & {
  getters: {
    [K in keyof Getters]: ReturnType<Getters[K]>
  }
}

inside store/modules/state.ts

export type State = {
  theme: string;
  showSidebar: boolean;
};

export const state: State = reactive({
  theme: 'light',
  showSidebar: true
});

inside store/modules/mutation-types.ts

export enum MutationTypes {
  SET_THEME = 'SET_THEME',
  SET_SHOWSIDEBAR = 'SET_SHOWSIDEBAR'
}

inside store/modules/mutation.ts

import { MutationTree } from "vuex";
import { MutationTypes } from "./mutation-types";
import { State } from './state';

export type Mutations<S = State> = {
  [MutationTypes.SET_THEME](state: S, payload: string | boolean): void;
  [MutationTypes.SET_SHOWSIDEBAR](state: S, payload: boolean): void;
}

export const mutations: MutationTree<State> & Mutations = {
  [MutationTypes.SET_THEME](state: State, payload: string) {
    state.theme = payload,
    localStorage.theme = payload
  },
  [MutationTypes.SET_SHOWSIDEBAR](state: State, payload: boolean) {
    state.showSidebar = payload
  },
}

inside store/modules/action-types.ts

export enum ActionTypes {
  INIT_THEME = 'INIT_THEME',
  toggle_theme = 'TOGGLE_THEME',
  toggle_sidebar = 'TOGGLE_SIDEBAR'
}

inside store/modules/action.ts

import { MutationTypes } from './mutation-types';
import { ActionContext, ActionTree } from "vuex";
import { ActionTypes } from "./action-types";
import { Mutations } from "./mutations";
import { State } from "./state";

type ActionAugments = Omit<ActionContext<State, State>, 'commit'> & {
  commit<K extends keyof Mutations>(
    key: K,
    payload: Parameters<Mutations[K]>[1]
  ): ReturnType<Mutations[K]>
}

export type Actions = {
  [ActionTypes.INIT_THEME](context: ActionAugments): void;
}

export const actions: ActionTree<State, State> & Actions = {
  [ActionTypes.INIT_THEME]({ commit }) {
    const cachedTheme: boolean = localStorage.theme ? localStorage.theme : false;

    const userPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

    if(cachedTheme) {
      commit(MutationTypes.SET_THEME, cachedTheme)
    } else if(userPrefersDark) {
      commit(MutationTypes.SET_THEME, 'dark')
    } else {
      commit(MutationTypes.SET_THEME, 'light')
    }
  },

  
  [ActionTypes.toggle_theme]({ commit }) {


    switch (localStorage.theme) {
      case 'light':
        commit('SET_THEME', 'dark')
        break;
    
      default:
        commit('SET_THEME', 'light')
        break;
    }
  },

  [ActionTypes.toggle_sidebar]({ commit }, state) {

    let sidebar = MutationTypes.SET_SHOWSIDEBAR ? false : true;
    commit(MutationTypes.SET_SHOWSIDEBAR, sidebar)
  }
}

inside store/modules/getters.ts

import { GetterTree } from "vuex";
import { State } from './state';

export type Getters = {
  GET_THEME(state: State): string 
  GET_SHOWSIDEBAR(state: State): boolean
}
export const getters: GetterTree<State, State> & Getters = {
  GET_THEME(state) {
    return state.theme;
  },
  
  GET_SHOWSIDEBAR(state) {
    return state.showSidebar;
  },
}

Components/TheHeaderUpNav.vue At the bottom I connect the sidebar and sidebar switch button (, )

<template>
  <div
    class="top-0 fixed lg:relative z-50 flex lg:justify-center justify-end items-center w-full py-1 lg:px-1 bg-gray-900 text-gray-300"
  >
    <div
      class="flex justify-between w-full text-xs md:text-sm lg:justify-around lg:gap-4 xl:gap-16"
    >
      <ul class="hidden lg:flex justify-around font-semibold py-2 text-xs xl:text-sm">
        <li class="xl:mx-3" v-for="(navup, index) in navups" :key="index">
          <router-link
            :to="navup.to"
            class="text-gray-300 px-3 py-2 rounded-sm hover:border-b-2 hover:border-white"
          >
            {{ navup.title }}
          </router-link>
        </li>
      </ul>
      <div class="flex items-center mx-5 sm:mr-20 lg:hidden">
        <TheMobileButtonHumburger />
        <div class="mx-3 flex xs:hidden">LOGO</div>
      </div>

      <div class="hidden items-center 2xl:flex">Пн-Пт. 9:00 - 17:30</div>
      <div class="flex mx-5 lg:mx-0">
        <div class="lg:hidden flex items-center">
          <MultiLanguage />
        </div>
        <div class="flex items-center right-0 py-1">
          <TheToggleTheme />
        </div>
      </div>
    </div>
  </div>
  <TheMobileSidebar />
</template>
<script lang="ts" setup>
  import TheMobileButtonHumburger from "./TheMobileButtonHumburger.vue";
  import TheMobileSidebar from "./TheMobileSidebar.vue";
<script/>

The component itself looks like this. Components/TheMobileSidebar.vue

<template>
  <div
    class="flex flex-col lg:hidden w-[300px] h-[100%] px-5 py-20 xs:py-10 text-gray-300 bg-black z-30 fixed bg-opacity-50 backdrop-filter backdrop-blur-lg"
    :class="{ '-left-full': !isShowSidebar }"
  >
    <ul class="w-full h-full" v-for="(navup, id) in navups" :key="id">
      <li>{{ navup.title }}</li>
    </ul>
  </div>
</template>

<script lang="ts" setup>
import { useStore } from "@/store";
import { ref } from "vue";

const store = useStore();
const navups = store.getters.GET_NAVUPS;
let isShowSidebar = ref(store.getters.GET_SHOWSIDEBAR);

//const theme = computed(() => store.getters.GET_THEME);

// watch(isShowSidebar, (newSidebar, oldSidebar) => {
//   const toggleSidebar = store.getters.GET_SHOWSIDEBAR;

//   newSidebar === false
//     ? commit(MutationTypes.SET_SHOWSIDEBAR, true)
//     : commit(MutationTypes.SET_SHOWSIDEBAR, false);
// });

// console.log(isShowSidebar);
</script>

The button itself looks like this Components/TheMobileButtonHumburger.vue

<template>
  <button class="cursor-pointer border-2 border-white rounded-md" @click="toggleSidebar">
    <svg
      xmlns="http://www.w3.org/2000/svg"
      class="h-5 w-5"
      fill="none"
      viewBox="0 0 24 24"
      stroke="currentColor"
    >
      <path
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="2"
        d="M4 6h16M4 12h16M4 18h7"
      />
    </svg>
  </button>
</template>

<script lang="ts">
import { ActionTypes } from "@/store/modules/action-types";
import { defineComponent } from "vue";
import { useStore } from "vuex";

export default defineComponent({
  name: "toggleSidebar",
  setup() {
    const store = useStore();

    const toggleSidebar = () => {
      store.dispatch(ActionTypes.toggle_sidebar);
      console.log(store.getters.GET_SHOWSIDEBAR);
    };

    return { toggleSidebar };
  },
});
</script>
0 Answers
Related