Skip to content

Instantly share code, notes, and snippets.

@hipertracker
Last active December 31, 2022 13:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hipertracker/3676ae8a5661f7d7423982188cc265fe to your computer and use it in GitHub Desktop.
Save hipertracker/3676ae8a5661f7d7423982188cc265fe to your computer and use it in GitHub Desktop.
Villus with Pinia integration (Vue 3, Quasar 2, TypeScript)
// src/boot.ts
import {createClient, defaultPlugins, handleSubscriptions} from "villus";
import {SubscriptionClient} from "subscriptions-transport-ws";
import {boot} from "quasar/wrappers";
import {OperationOptions} from "subscriptions-transport-ws/dist/client";
const subscriptionClient = new SubscriptionClient(import.meta.env.VITE_HASURA_WEBSOCKET, {});
const subscriptionForwarder = (operation: OperationOptions) => subscriptionClient.request(operation);
const client = createClient({
url: import.meta.env.VITE_HASURA_URL,
use: [handleSubscriptions(subscriptionForwarder), ...defaultPlugins()],
cachePolicy: "network-only"
});
export default boot(async ({app}) => {
app.use(client);
});
// stores/index.ts
import useLanguageChooserStore from "./languageChooserStore";
import {acceptHMRUpdate, defineStore} from "pinia";
export const useSearchStore = defineStore("search", () => {
const languageChooser = useLanguageChooserStore()
return {languageChooser}
})
export default useSearchStore;
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useSearchStore, import.meta.hot));
}
<script lang="ts" setup>
import {onMounted, reactive, toRefs} from "vue";
import {type CombinedError} from "villus";
import useSearchStore from "stores/search/";
interface State {
error: CombinedError | null;
isFetching: boolean;
}
const state: State = reactive({
error: null,
isFetching: false,
});
const store = useSearchStore().languageChooser;
const {displayValue, language, languages} = toRefs(store);
onMounted(async () => {
const {error, isFetching} = await store.loadLanguages();
state.isFetching = isFetching.value;
state.error = error.value;
});
</script>
<template>
<q-select
:dense="false"
:display-value="displayValue"
:error="!!state.error"
:label="$t('Language')"
:loading="state.isFetching"
:model-value="language"
:options="languages"
:virtual-scroll-slice-size="23"
emit-value
option-value="name"
outlined
style="width: 110px"
@update:model-value="store.setLanguage"
>
<template #label>
{{ $t('Language') }}
</template>
<template #error>
{{ state.error }}
</template>
<template #option="scope">
<q-item class="t-p-2" v-bind="scope.itemProps">
<q-item-section>
<q-item-label>{{ scope.opt.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label>{{ scope.opt.value }}</q-item-label>
</q-item-section>
</q-item>
<hr class="t-border-1 t-border-gray-500 t-border-solid"/>
</template>
</q-select>
</template>
// stores/search/languageChooserStore.ts
import {acceptHMRUpdate, defineStore} from "pinia";
import {computed, ref} from "vue";
import fp from "lodash/fp";
import {gql} froimport useLanguageChooserStore from "./languageChooserStore";
import {useBibleChooserStore} from "./bibleChooserStore";
import {acceptHMRUpdate, defineStore} from "pinia";
export const useSearchStore = defineStore("search", () => {
const languageChooser = useLanguageChooserStore()
const bibleChooser = useBibleChooserStore()
return {languageChooser, bibleChooser}
})
export default useSearchStore;
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useSearchStore, import.meta.hot));
}
m "graphql-tag";
import {useQuery} from "villus";
interface Language {
id: number;
name: string;
label: string;
}
const defaultLanguage = {
name: "pl",
label: "Polish"
};
export const useLanguageChooserStore = defineStore("languageChooser", () => {
const language = ref(defaultLanguage.name);
const languages = ref<Language[]>([]);
const displayValue = computed(() => {
const selected = fp.pipe(
fp.filter((item: Language) => item.name === language.value),
fp.first
)(languages.value);
return selected?.label || defaultLanguage.label;
});
function setLanguage(value: string) {
language.value = value;
}
async function loadLanguages() {
const {isFetching, error, data} = await useQuery({
query: gql(/* GraphQL */`
query Languages {
items: api_language(
order_by: { order: asc }
where: { available: { _eq: true } }
) {
id
name
label
}
}
`),
});
languages.value = data.value?.items;
return {error, isFetching};
}
return {
displayValue,
language,
languages,
loadLanguages,
setLanguage,
};
},
);
export default useLanguageChooserStore;
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useLanguageChooserStore, import.meta.hot));
}
// ...
module.exports = configure(function (/* ctx */) {
return {
eslint: {
// fix: true,
// include = [],
// exclude = [],
// rawOptions = {},
warnings: true,
errors: true,
},
// https://v2.quasar.dev/quasar-cli-vite/prefetch-feature
// preFetch: true,
// app boot file (/src/boot)
// --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli-vite/boot-files
boot: ["i18n", "axios", "villus"],
// ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment