From 554fa4facf85e5fd8cbbc09c483d59cf80a27ddb Mon Sep 17 00:00:00 2001 From: mayoforkovic Date: Sun, 29 Oct 2023 16:04:14 +0100 Subject: [PATCH 1/7] typescript rewrite --- .eslintrc.cjs | 68 + .gitignore | 4 +- .prettierrc.json | 11 + .vscode/extensions.json | 3 +- env.d.ts | 1 + index.html | 4 +- manual.d.ts | 7 - package-lock.json | 4446 +++++++++++++++-- package.json | 29 +- src/App.vue | 16 +- src/{app.js => app.ts} | 28 +- src/components/about/About.vue | 301 +- src/components/about/AboutCollapsible.vue | 48 +- src/components/author/AuthorDetails.vue | 8 +- src/components/author/AuthorSummary.vue | 23 +- src/components/author/AuthorityDetails.vue | 116 +- src/components/author/AuthoritySummary.vue | 32 +- src/components/bucketlist/Bucketlist.vue | 173 +- .../bucketlist/LockedItemThumbnail.vue | 36 +- src/components/forms/CircleButton.vue | 22 +- src/components/forms/ConfirmButton.vue | 14 +- src/components/forms/RectangleButton.vue | 11 +- src/components/forms/StoryButton.vue | 88 +- src/components/forms/WebumeniaButton.vue | 43 +- src/components/general/Collapsible.vue | 30 +- src/components/general/ImageLightbox.vue | 75 +- src/components/general/ImageMovable.vue | 78 +- src/components/general/ItemImage.vue | 42 +- src/components/general/ItemLoader.vue | 14 +- src/components/general/ItemPreview.vue | 85 +- src/components/general/ItemThumbnail.vue | 30 +- src/components/general/ResponsiveImage.vue | 8 +- .../general/ResponsiveImageWithSizes.vue | 41 +- .../general/ResponsiveVideoEmbed.vue | 26 +- src/components/general/Thumbnail.vue | 46 +- src/components/general/VideoSummary.vue | 34 +- .../interactions/InteractionItem.vue | 29 +- .../InteractionItemFavourited.vue | 17 +- .../interactions/InteractionItemViewed.vue | 11 +- .../interactions/InteractionPlaceViewed.vue | 28 +- .../interactions/InteractionSectionViewed.vue | 29 +- .../interactions/InteractionStory.vue | 122 +- .../interactions/StoryVideoLightbox.vue | 67 +- src/components/layout/CardModal.vue | 23 +- src/components/layout/CodePanel.vue | 222 +- src/components/layout/Header.vue | 92 +- src/components/layout/HelpModal.vue | 91 +- src/components/layout/LanguageSwitcher.vue | 63 +- src/components/misc/HelpStep.vue | 35 +- src/components/misc/HistoryBack.vue | 14 +- src/components/misc/ProgressDots.vue | 24 +- src/components/misc/ViewedItemsCount.vue | 43 +- src/components/misc/ZoomViewer.vue | 31 +- src/components/svg/SvgArrowSquareOut.vue | 49 +- src/components/svg/SvgArrowUp.vue | 13 +- src/components/svg/SvgArrowsOut.vue | 23 +- src/components/svg/SvgBack.vue | 9 +- src/components/svg/SvgCaretRight.vue | 13 +- src/components/svg/SvgChatCircle.vue | 15 +- src/components/svg/SvgChatCircleSmall.vue | 17 +- src/components/svg/SvgClose.vue | 9 +- src/components/svg/SvgCode.vue | 23 +- src/components/svg/SvgDownArrow.vue | 9 +- src/components/svg/SvgEye.vue | 15 +- src/components/svg/SvgHeart.vue | 13 +- src/components/svg/SvgHeartSmall.vue | 13 +- src/components/svg/SvgInfo.vue | 15 +- src/components/svg/SvgLinkSimple.vue | 19 +- src/components/svg/SvgLock.vue | 11 +- src/components/svg/SvgLogo.vue | 11 +- src/components/svg/SvgPlay.vue | 12 +- src/components/svg/SvgQuestion.vue | 27 +- src/components/svg/SvgSearch.vue | 15 +- src/components/timeline/ShareCollection.vue | 68 +- src/components/timeline/Timeline.vue | 67 +- src/composables/Survey.js | 27 - src/composables/Survey.ts | 30 + src/pages/[id].vue | 28 +- src/pages/collection.vue | 28 +- src/pages/index.vue | 194 +- src/pages/item/[id].vue | 265 +- src/pages/locked/[id].vue | 72 +- src/pages/place/[id].vue | 132 +- src/pages/reward/[id].vue | 38 +- src/pages/section/[id].vue | 110 +- src/pages/section/[sectionId]/[id].vue | 262 +- src/pages/story/[id].vue | 194 +- src/stores/BucketlistStore.js | 23 - src/stores/BucketlistStore.ts | 23 + src/stores/HistoryStore.js | 15 - src/stores/HistoryStore.ts | 15 + src/stores/InteractionStore.js | 111 - src/stores/InteractionStore.ts | 110 + src/stores/ItemStore.js | 52 - src/stores/ItemStore.ts | 51 + src/stores/LocaleStore.js | 19 - src/stores/LocaleStore.ts | 19 + src/stores/PlaceStore.js | 23 - src/stores/PlaceStore.ts | 23 + src/stores/SectionStore.js | 23 - src/stores/SectionStore.ts | 23 + src/stores/StoryStore.js | 23 - src/stores/StoryStore.ts | 23 + tsconfig.app.json | 12 + tsconfig.json | 11 + tsconfig.node.json | 16 + vite.config.js | 52 +- 107 files changed, 6771 insertions(+), 2724 deletions(-) create mode 100644 .eslintrc.cjs create mode 100644 .prettierrc.json create mode 100644 env.d.ts rename src/{app.js => app.ts} (63%) delete mode 100644 src/composables/Survey.js create mode 100644 src/composables/Survey.ts delete mode 100644 src/stores/BucketlistStore.js create mode 100644 src/stores/BucketlistStore.ts delete mode 100644 src/stores/HistoryStore.js create mode 100644 src/stores/HistoryStore.ts delete mode 100644 src/stores/InteractionStore.js create mode 100644 src/stores/InteractionStore.ts delete mode 100644 src/stores/ItemStore.js create mode 100644 src/stores/ItemStore.ts delete mode 100644 src/stores/LocaleStore.js create mode 100644 src/stores/LocaleStore.ts delete mode 100644 src/stores/PlaceStore.js create mode 100644 src/stores/PlaceStore.ts delete mode 100644 src/stores/SectionStore.js create mode 100644 src/stores/SectionStore.ts delete mode 100644 src/stores/StoryStore.js create mode 100644 src/stores/StoryStore.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..acc20d0 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,68 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + 'extends': [ + 'eslint:recommended', + '@vue/typescript/recommended', + 'plugin:vue/vue3-recommended', + 'plugin:prettier-vue/recommended', + 'prettier', + ], + parserOptions: { + ecmaVersion: 'latest' + }, + plugins: ['prettier', 'import'], + rules: { + 'vue/no-deprecated-slot-attribute': 'off', + 'vue/multi-word-component-names': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'vue/component-name-in-template-casing': ['error', 'PascalCase'], + 'vue/no-v-html': 'off', + 'no-mixed-operators': 'off', + 'vue/html-button-has-type': 'error', + 'unicorn/prefer-includes': 'off', + 'space-before-function-paren': 'off', + 'curly': 'error', + '@typescript-eslint/no-var-requires': 'off', + 'vue/valid-v-slot': 'off', + 'vue/no-unused-vars': 'warn', + '@typescript-eslint/quotes': ['error', 'single'], + '@typescript-eslint/consistent-type-imports': ['off'], + "no-restricted-imports": ["error", { + "patterns": [".*"] + }], + 'vue/component-tags-order': [ + 'error', + { + order: ['template', 'script', 'style'], + }, + ], + 'vue/define-macros-order': [ + 'error', + { + order: ['defineProps', 'defineEmits'], + }, + ], + 'import/order': [ + 'error', + { + 'newlines-between': 'always', + 'groups': [ + 'index', + ['sibling', 'parent'], + 'internal', + 'external', + 'builtin', + 'object', + 'type', + ], + }, + ], + 'vue/v-on-event-hyphenation': 'off', + 'vue/require-default-prop': 'off', + 'prettier-vue/prettier': ['error'], + '@typescript-eslint/ban-ts-comment': 'off', + } +} diff --git a/.gitignore b/.gitignore index fc1c33c..57ed8ec 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ dist-ssr *.sln *.sw? +src/app.js auto-imports.d.ts components.d.ts -/public/fonts/ +typed-router.d.ts +/public/fonts/* diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..eb4d3f0 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "trailingComma": "es5", + "semi": false, + "singleQuote": true, + "useTabs": false, + "quoteProps": "consistent", + "bracketSpacing": true, + "arrowParens": "always", + "printWidth": 100 +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c0a6e5a..e0691a7 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,4 @@ { - "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] + "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"], + "typescript.preferences.autoImportFileExcludePatterns": ["vue-router"] } diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/index.html b/index.html index 0c5de88..3805ec7 100644 --- a/index.html +++ b/index.html @@ -13,9 +13,9 @@ Atlas SNG - + - - - - + + + - + - diff --git a/src/components/layout/HelpModal.vue b/src/components/layout/HelpModal.vue index 39b04e4..2cf504b 100644 --- a/src/components/layout/HelpModal.vue +++ b/src/components/layout/HelpModal.vue @@ -1,56 +1,59 @@ - diff --git a/src/components/layout/LanguageSwitcher.vue b/src/components/layout/LanguageSwitcher.vue index 7dd7369..9a44ab2 100644 --- a/src/components/layout/LanguageSwitcher.vue +++ b/src/components/layout/LanguageSwitcher.vue @@ -1,29 +1,28 @@ - diff --git a/src/components/misc/HelpStep.vue b/src/components/misc/HelpStep.vue index b04532c..4a16319 100644 --- a/src/components/misc/HelpStep.vue +++ b/src/components/misc/HelpStep.vue @@ -1,20 +1,27 @@ - diff --git a/src/components/misc/HistoryBack.vue b/src/components/misc/HistoryBack.vue index 492513f..09ba5f9 100644 --- a/src/components/misc/HistoryBack.vue +++ b/src/components/misc/HistoryBack.vue @@ -1,16 +1,16 @@ - diff --git a/src/components/misc/ProgressDots.vue b/src/components/misc/ProgressDots.vue index aebffc4..e94a660 100644 --- a/src/components/misc/ProgressDots.vue +++ b/src/components/misc/ProgressDots.vue @@ -1,14 +1,18 @@ - diff --git a/src/components/misc/ViewedItemsCount.vue b/src/components/misc/ViewedItemsCount.vue index 6768d24..f26519e 100644 --- a/src/components/misc/ViewedItemsCount.vue +++ b/src/components/misc/ViewedItemsCount.vue @@ -1,27 +1,28 @@ - diff --git a/src/components/misc/ZoomViewer.vue b/src/components/misc/ZoomViewer.vue index bf4b694..6ee005c 100644 --- a/src/components/misc/ZoomViewer.vue +++ b/src/components/misc/ZoomViewer.vue @@ -1,26 +1,29 @@ - diff --git a/src/components/svg/SvgArrowSquareOut.vue b/src/components/svg/SvgArrowSquareOut.vue index d4ad042..c45e231 100644 --- a/src/components/svg/SvgArrowSquareOut.vue +++ b/src/components/svg/SvgArrowSquareOut.vue @@ -1,25 +1,28 @@ + diff --git a/src/components/svg/SvgArrowUp.vue b/src/components/svg/SvgArrowUp.vue index 36bd53a..af27465 100644 --- a/src/components/svg/SvgArrowUp.vue +++ b/src/components/svg/SvgArrowUp.vue @@ -1,8 +1,9 @@ + diff --git a/src/components/svg/SvgArrowsOut.vue b/src/components/svg/SvgArrowsOut.vue index 0327551..8c67fb9 100644 --- a/src/components/svg/SvgArrowsOut.vue +++ b/src/components/svg/SvgArrowsOut.vue @@ -1,12 +1,15 @@ + diff --git a/src/components/svg/SvgBack.vue b/src/components/svg/SvgBack.vue index 1574e22..f4cd23b 100644 --- a/src/components/svg/SvgBack.vue +++ b/src/components/svg/SvgBack.vue @@ -1,5 +1,8 @@ + diff --git a/src/components/svg/SvgCaretRight.vue b/src/components/svg/SvgCaretRight.vue index 7df6982..5c76738 100644 --- a/src/components/svg/SvgCaretRight.vue +++ b/src/components/svg/SvgCaretRight.vue @@ -1,8 +1,9 @@ + diff --git a/src/components/svg/SvgChatCircle.vue b/src/components/svg/SvgChatCircle.vue index b43ed1d..b504b12 100644 --- a/src/components/svg/SvgChatCircle.vue +++ b/src/components/svg/SvgChatCircle.vue @@ -1,8 +1,11 @@ + diff --git a/src/components/svg/SvgChatCircleSmall.vue b/src/components/svg/SvgChatCircleSmall.vue index 4fb2cd1..3f3c1f7 100644 --- a/src/components/svg/SvgChatCircleSmall.vue +++ b/src/components/svg/SvgChatCircleSmall.vue @@ -1,10 +1,11 @@ + diff --git a/src/components/svg/SvgClose.vue b/src/components/svg/SvgClose.vue index 274fafe..f196732 100644 --- a/src/components/svg/SvgClose.vue +++ b/src/components/svg/SvgClose.vue @@ -1,6 +1,7 @@ + diff --git a/src/components/svg/SvgCode.vue b/src/components/svg/SvgCode.vue index 1bf5556..fff6e38 100644 --- a/src/components/svg/SvgCode.vue +++ b/src/components/svg/SvgCode.vue @@ -1,13 +1,14 @@ + diff --git a/src/components/svg/SvgDownArrow.vue b/src/components/svg/SvgDownArrow.vue index 3f15041..059cb97 100644 --- a/src/components/svg/SvgDownArrow.vue +++ b/src/components/svg/SvgDownArrow.vue @@ -1,5 +1,8 @@ + diff --git a/src/components/svg/SvgEye.vue b/src/components/svg/SvgEye.vue index 8179a20..22237e2 100644 --- a/src/components/svg/SvgEye.vue +++ b/src/components/svg/SvgEye.vue @@ -1,8 +1,11 @@ + diff --git a/src/components/svg/SvgHeart.vue b/src/components/svg/SvgHeart.vue index 37ac870..3c9e9e4 100644 --- a/src/components/svg/SvgHeart.vue +++ b/src/components/svg/SvgHeart.vue @@ -1,7 +1,10 @@ + diff --git a/src/components/svg/SvgHeartSmall.vue b/src/components/svg/SvgHeartSmall.vue index a3d05d6..bec9dd7 100644 --- a/src/components/svg/SvgHeartSmall.vue +++ b/src/components/svg/SvgHeartSmall.vue @@ -1,7 +1,10 @@ + diff --git a/src/components/svg/SvgInfo.vue b/src/components/svg/SvgInfo.vue index 5572801..154a978 100644 --- a/src/components/svg/SvgInfo.vue +++ b/src/components/svg/SvgInfo.vue @@ -1,9 +1,10 @@ + diff --git a/src/components/svg/SvgLinkSimple.vue b/src/components/svg/SvgLinkSimple.vue index c2d345a..f97e8dc 100644 --- a/src/components/svg/SvgLinkSimple.vue +++ b/src/components/svg/SvgLinkSimple.vue @@ -1,11 +1,12 @@ + diff --git a/src/components/svg/SvgLock.vue b/src/components/svg/SvgLock.vue index cd36503..4fbc92b 100644 --- a/src/components/svg/SvgLock.vue +++ b/src/components/svg/SvgLock.vue @@ -1,7 +1,8 @@ + diff --git a/src/components/svg/SvgLogo.vue b/src/components/svg/SvgLogo.vue index dc12403..c0deb6b 100644 --- a/src/components/svg/SvgLogo.vue +++ b/src/components/svg/SvgLogo.vue @@ -1,7 +1,8 @@ + diff --git a/src/components/svg/SvgPlay.vue b/src/components/svg/SvgPlay.vue index 7b93471..2bd373d 100644 --- a/src/components/svg/SvgPlay.vue +++ b/src/components/svg/SvgPlay.vue @@ -1,6 +1,10 @@ + diff --git a/src/components/svg/SvgQuestion.vue b/src/components/svg/SvgQuestion.vue index ea3d996..b610cf1 100644 --- a/src/components/svg/SvgQuestion.vue +++ b/src/components/svg/SvgQuestion.vue @@ -1,14 +1,17 @@ + diff --git a/src/components/svg/SvgSearch.vue b/src/components/svg/SvgSearch.vue index 60f1bc3..63cc77c 100644 --- a/src/components/svg/SvgSearch.vue +++ b/src/components/svg/SvgSearch.vue @@ -1,9 +1,10 @@ + diff --git a/src/components/timeline/ShareCollection.vue b/src/components/timeline/ShareCollection.vue index 2ffdda3..59337de 100644 --- a/src/components/timeline/ShareCollection.vue +++ b/src/components/timeline/ShareCollection.vue @@ -1,45 +1,51 @@ - diff --git a/src/components/timeline/Timeline.vue b/src/components/timeline/Timeline.vue index 2c5db84..99e2c05 100644 --- a/src/components/timeline/Timeline.vue +++ b/src/components/timeline/Timeline.vue @@ -1,45 +1,44 @@ - diff --git a/src/composables/Survey.js b/src/composables/Survey.js deleted file mode 100644 index 2651d3e..0000000 --- a/src/composables/Survey.js +++ /dev/null @@ -1,27 +0,0 @@ -import { onUnmounted, ref, computed } from 'vue' -import { storeToRefs } from 'pinia' -import { useStorage } from '@vueuse/core' -import { createPopup } from '@typeform/embed' -import '@typeform/embed/build/css/popup.css' -import { getActiveLanguage } from 'laravel-vue-i18n' - -export function useSurvey() { - const interactionStore = useInteractionStore() - const { viewedItemsCount, stories } = storeToRefs(interactionStore) - const isDone = ref(useStorage('isSurveyDone', false)) - const wasExited = ref(useStorage('wasSurveyExited', false)) - const SURVEY_ID = getActiveLanguage() === 'sk' ? import.meta.env.VITE_SURVEY_SK : import.meta.env.VITE_SURVEY_EN - - const shouldLaunch = computed(() => (viewedItemsCount.value > 1 || stories.value.length > 4) && !wasExited.value) - function done() { - isDone.value = true - } - function exit() { - wasExited.value = true - } - - const { toggle, unmount } = createPopup(SURVEY_ID, { onClose: exit, onSubmit: done }) - - onUnmounted(unmount) - return { toggle, done, exit, shouldLaunch, isDone } -} diff --git a/src/composables/Survey.ts b/src/composables/Survey.ts new file mode 100644 index 0000000..365b4f5 --- /dev/null +++ b/src/composables/Survey.ts @@ -0,0 +1,30 @@ +import { storeToRefs } from 'pinia' +import { useStorage } from '@vueuse/core' +import { createPopup } from '@typeform/embed' +import '@typeform/embed/build/css/popup.css' +import { getActiveLanguage } from 'laravel-vue-i18n' + +export function useSurvey() { + const interactionStore = useInteractionStore() + + const { viewedItemsCount, stories } = storeToRefs(interactionStore) + const isDone = ref(useStorage('isSurveyDone', false)) + const wasExited = ref(useStorage('wasSurveyExited', false)) + const SURVEY_ID = + getActiveLanguage() === 'sk' ? import.meta.env.VITE_SURVEY_SK : import.meta.env.VITE_SURVEY_EN + + const shouldLaunch = computed( + () => (viewedItemsCount.value > 1 || stories.value.length > 4) && !wasExited.value + ) + function done() { + isDone.value = true + } + function exit() { + wasExited.value = true + } + + const { toggle, unmount } = createPopup(SURVEY_ID, { onClose: exit, onSubmit: done }) + + onUnmounted(unmount) + return { toggle, done, exit, shouldLaunch, isDone } +} diff --git a/src/pages/[id].vue b/src/pages/[id].vue index 5b7ba01..e61683d 100644 --- a/src/pages/[id].vue +++ b/src/pages/[id].vue @@ -1,30 +1,24 @@ - diff --git a/src/pages/collection.vue b/src/pages/collection.vue index c83afd1..5d4369e 100644 --- a/src/pages/collection.vue +++ b/src/pages/collection.vue @@ -1,28 +1,22 @@ - diff --git a/src/pages/index.vue b/src/pages/index.vue index 9054f8a..7af759f 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -1,64 +1,53 @@ - - - + + diff --git a/src/pages/item/[id].vue b/src/pages/item/[id].vue index e56c953..2e65d02 100644 --- a/src/pages/item/[id].vue +++ b/src/pages/item/[id].vue @@ -1,140 +1,159 @@ - diff --git a/src/pages/locked/[id].vue b/src/pages/locked/[id].vue index a7d5ebc..89ee248 100644 --- a/src/pages/locked/[id].vue +++ b/src/pages/locked/[id].vue @@ -1,47 +1,49 @@ - diff --git a/src/pages/place/[id].vue b/src/pages/place/[id].vue index 8e6ba36..e55718a 100644 --- a/src/pages/place/[id].vue +++ b/src/pages/place/[id].vue @@ -1,79 +1,81 @@ - diff --git a/src/pages/reward/[id].vue b/src/pages/reward/[id].vue index ce28c4a..a7b8a85 100644 --- a/src/pages/reward/[id].vue +++ b/src/pages/reward/[id].vue @@ -1,30 +1,30 @@ - diff --git a/src/pages/section/[id].vue b/src/pages/section/[id].vue index 312ac8c..eed949b 100644 --- a/src/pages/section/[id].vue +++ b/src/pages/section/[id].vue @@ -1,66 +1,74 @@ - diff --git a/src/pages/section/[sectionId]/[id].vue b/src/pages/section/[sectionId]/[id].vue index e56c953..ea0b02b 100644 --- a/src/pages/section/[sectionId]/[id].vue +++ b/src/pages/section/[sectionId]/[id].vue @@ -1,140 +1,158 @@ - diff --git a/src/pages/story/[id].vue b/src/pages/story/[id].vue index f98e7e4..79ba481 100644 --- a/src/pages/story/[id].vue +++ b/src/pages/story/[id].vue @@ -1,65 +1,53 @@ - - - + + diff --git a/src/stores/BucketlistStore.js b/src/stores/BucketlistStore.js deleted file mode 100644 index f241916..0000000 --- a/src/stores/BucketlistStore.js +++ /dev/null @@ -1,23 +0,0 @@ -import { defineStore } from 'pinia' -import { useStorage } from '@vueuse/core' -import axios from 'axios' - -export const useBucketlistStore = defineStore('BucketlistStore', { - state: () => ({ - bucketlists: useStorage('bucketlists', {}), - }), - actions: { - get(id) { - if (id in this.bucketlists) { - return this.bucketlists[id] - } - }, - async load(id) { - const response = await axios.get(`/api/bucketlists/${id}`) - return (this.bucketlists[id] = response.data.data) - }, - clearCache() { - this.bucketlists = [] - }, - }, -}) diff --git a/src/stores/BucketlistStore.ts b/src/stores/BucketlistStore.ts new file mode 100644 index 0000000..20b6c9f --- /dev/null +++ b/src/stores/BucketlistStore.ts @@ -0,0 +1,23 @@ +import { defineStore } from 'pinia' +import { useStorage } from '@vueuse/core' +import axios from 'axios' + +export const useBucketlistStore = defineStore('BucketlistStore', { + state: () => ({ + bucketlists: useStorage('bucketlists', {}) as any, // TODO: add model + }), + actions: { + get(id: string) { + if (id in this.bucketlists) { + return this.bucketlists[id] + } + }, + async load(id: string) { + const response = await axios.get(`/api/bucketlists/${id}`) + return (this.bucketlists[id] = response.data.data) + }, + clearCache() { + this.bucketlists = [] + }, + }, +}) diff --git a/src/stores/HistoryStore.js b/src/stores/HistoryStore.js deleted file mode 100644 index 0ca9791..0000000 --- a/src/stores/HistoryStore.js +++ /dev/null @@ -1,15 +0,0 @@ -import { defineStore } from 'pinia' - -export const useHistoryStore = defineStore('HistoryStore', { - state: () => ({ - history: null, - }), - actions: { - set(history) { - this.history = history - }, - getState() { - return this.history?.state - }, - }, -}) diff --git a/src/stores/HistoryStore.ts b/src/stores/HistoryStore.ts new file mode 100644 index 0000000..a6bf7d2 --- /dev/null +++ b/src/stores/HistoryStore.ts @@ -0,0 +1,15 @@ +import { defineStore } from 'pinia' + +export const useHistoryStore = defineStore('HistoryStore', { + state: () => ({ + history: null as any, + }), + actions: { + set(history: any) { + this.history = history + }, + getState() { + return this.history?.state + }, + }, +}) diff --git a/src/stores/InteractionStore.js b/src/stores/InteractionStore.js deleted file mode 100644 index c68a01d..0000000 --- a/src/stores/InteractionStore.js +++ /dev/null @@ -1,111 +0,0 @@ -import { useStorage } from '@vueuse/core' -import { defineStore } from 'pinia' -import { useStoryStore } from './StoryStore' - -export const useInteractionStore = defineStore('InteractionStore', { - state: () => ({ - interactions: useStorage('interactions', []), - peekCodePanel: useStorage('peekCodePanel', true), - cursor: useStorage('cursor', -1), - }), - getters: { - active() { - if (this.cursor > -1) { - return this.interactions[this.cursor] - } - }, - activeStory() { - if (this.active && this.active.type === 'story') { - const storiesStore = useStoryStore() - return storiesStore.get(this.active.id) - } - }, - lastStory() { - return this.stories[this.stories.length - 1] - }, - stories() { - const storiesStore = useStoryStore() - return this.interactions - .filter((interaction) => interaction.type === 'story') - .map((interaction) => storiesStore.get(interaction.id)) - }, - viewedItemIds() { - return new Set( - this.interactions - .filter((interaction) => interaction.type === 'itemViewed') - .map((interaction) => interaction.id) - .slice() - .reverse() - ) - }, - viewedItemsCount() { - return this.viewedItemIds.size - }, - }, - actions: { - isItemViewed(id) { - return this.viewedItemIds.has(id) - }, - addStory(id) { - const length = this.interactions.push({ - type: 'story', - id, - }) - this.cursor = length - 1 - }, - addItemViewed(id) { - this.interactions.push({ - type: 'itemViewed', - id, - }) - }, - addSectionViewed(id) { - this.interactions.push({ - type: 'sectionViewed', - id, - }) - }, - addPlaceViewed(id) { - this.interactions.push({ - type: 'placeViewed', - id, - }) - }, - selectLink(interaction, link) { - const index = this.interactions.indexOf(interaction) - this.interactions[index].linkId = link.id - this.cursor = -1 - }, - lastStoryIndex(from) { - let index = typeof from !== 'undefined' ? from : this.cursor - while (this.interactions[index].type !== 'story' && index > 0) { - index-- - } - return index - }, - setPreviousActive(interaction) { - const index = this.interactions.indexOf(interaction) - this.cursor = this.lastStoryIndex(index - 1) - this.active.linkId = undefined - return this.active - }, - remove(interaction) { - const toDelete = this.interactions.indexOf(interaction) - this.interactions.splice(toDelete, 1) - if (toDelete <= this.cursor) { - this.cursor = this.lastStoryIndex(this.cursor - 1) - } - }, - isVisited(id) { - return this.stories.some((interaction) => interaction.id === id) - }, - hasVisitedAllLinks(id) { - const storyStore = useStoryStore() - const story = storyStore.get(id) - return story?.links.every((link) => this.isVisited(link.story_id)) - }, - clear() { - this.interactions = [] - }, - }, -}) diff --git a/src/stores/InteractionStore.ts b/src/stores/InteractionStore.ts new file mode 100644 index 0000000..7396289 --- /dev/null +++ b/src/stores/InteractionStore.ts @@ -0,0 +1,110 @@ +import { useStorage } from '@vueuse/core' +import { defineStore } from 'pinia' + +export const useInteractionStore = defineStore('InteractionStore', { + state: () => ({ + interactions: useStorage('interactions', []), + peekCodePanel: useStorage('peekCodePanel', true), + cursor: useStorage('cursor', -1), + }), + getters: { + active() { + if (this.cursor > -1) { + return this.interactions[this.cursor] + } + }, + activeStory() { + if (this.active && this.active.type === 'story') { + const storiesStore = useStoryStore() + return storiesStore.get(this.active.id) + } + }, + lastStory() { + return this.stories[this.stories.length - 1] + }, + stories() { + const storiesStore = useStoryStore() + return this.interactions + .filter((interaction) => interaction.type === 'story') + .map((interaction) => storiesStore.get(interaction.id)) + }, + viewedItemIds() { + return new Set( + this.interactions + .filter((interaction) => interaction.type === 'itemViewed') + .map((interaction) => interaction.id) + .slice() + .reverse() + ) + }, + viewedItemsCount() { + return this.viewedItemIds.size + }, + }, + actions: { + isItemViewed(id) { + return this.viewedItemIds.has(id) + }, + addStory(id) { + const length = this.interactions.push({ + type: 'story', + id, + }) + this.cursor = length - 1 + }, + addItemViewed(id) { + this.interactions.push({ + type: 'itemViewed', + id, + }) + }, + addSectionViewed(id) { + this.interactions.push({ + type: 'sectionViewed', + id, + }) + }, + addPlaceViewed(id) { + this.interactions.push({ + type: 'placeViewed', + id, + }) + }, + selectLink(interaction, link) { + const index = this.interactions.indexOf(interaction) + this.interactions[index].linkId = link.id + this.cursor = -1 + }, + lastStoryIndex(from) { + let index = typeof from !== 'undefined' ? from : this.cursor + while (this.interactions[index].type !== 'story' && index > 0) { + index-- + } + return index + }, + setPreviousActive(interaction) { + const index = this.interactions.indexOf(interaction) + this.cursor = this.lastStoryIndex(index - 1) + this.active.linkId = undefined + return this.active + }, + remove(interaction) { + const toDelete = this.interactions.indexOf(interaction) + this.interactions.splice(toDelete, 1) + if (toDelete <= this.cursor) { + this.cursor = this.lastStoryIndex(this.cursor - 1) + } + }, + isVisited(id) { + return this.stories.some((interaction) => interaction.id === id) + }, + hasVisitedAllLinks(id) { + const storyStore = useStoryStore() + const story = storyStore.get(id) + return story?.links.every((link) => this.isVisited(link.story_id)) + }, + clear() { + this.interactions = [] + }, + }, +}) diff --git a/src/stores/ItemStore.js b/src/stores/ItemStore.js deleted file mode 100644 index 29553ff..0000000 --- a/src/stores/ItemStore.js +++ /dev/null @@ -1,52 +0,0 @@ -import { defineStore } from 'pinia' -import { useStorage } from '@vueuse/core' -import axios from 'axios' -import { useInteractionStore } from './InteractionStore' - -export const useItemStore = defineStore('ItemStore', { - state: () => ({ - items: useStorage('items', {}), - collectionLink: useStorage('collectionLink', null), - }), - actions: { - get(id) { - if (id in this.items) { - return this.items[id] - } - }, - async load(id) { - const response = await axios.get(`/api/items/${id}`) - return (this.items[id] = response.data.data) - }, - clearCollectionLink() { - this.collectionLink = null - }, - clearCache() { - this.items = {} - }, - async getCollectionLink() { - const interactionStore = useInteractionStore() - - if (this.collectionLink) { - return this.collectionLink - } else { - const response = await axios - .post('/api/collections', { - items: [...interactionStore.viewedItemIds], - }) - .catch((err) => { - console.log(err) - }) - const collectionLink = response.data.url - this.collectionLink = collectionLink - return collectionLink - } - }, - async fetch(collectionId) { - this.clearCollectionLink() - this.items = {} - // todo - // this.viewedIds = (await axios.get(`/api/collections/${collectionId}`)).data - }, - }, -}) diff --git a/src/stores/ItemStore.ts b/src/stores/ItemStore.ts new file mode 100644 index 0000000..f911067 --- /dev/null +++ b/src/stores/ItemStore.ts @@ -0,0 +1,51 @@ +import { defineStore } from 'pinia' +import { useStorage } from '@vueuse/core' +import axios from 'axios' + +export const useItemStore = defineStore('ItemStore', { + state: () => ({ + items: useStorage('items', {}), + collectionLink: useStorage('collectionLink', null), + }), + actions: { + get(id: string) { + if (id in this.items) { + return this.items[id] + } + }, + async load(id: string) { + const response = await axios.get(`/api/items/${id}`) + return (this.items[id] = response.data.data) + }, + clearCollectionLink() { + this.collectionLink = null + }, + clearCache() { + this.items = {} + }, + async getCollectionLink() { + const interactionStore = useInteractionStore() + + if (this.collectionLink) { + return this.collectionLink + } else { + const response = await axios + .post('/api/collections', { + items: [...interactionStore.viewedItemIds], + }) + .catch((err) => { + console.log(err) + }) + const collectionLink = response.data.url + this.collectionLink = collectionLink + return collectionLink + } + }, + async fetch(collectionId: string) { + this.clearCollectionLink() + this.items = {} + // todo + // this.viewedIds = (await axios.get(`/api/collections/${collectionId}`)).data + }, + }, +}) diff --git a/src/stores/LocaleStore.js b/src/stores/LocaleStore.js deleted file mode 100644 index ab57e70..0000000 --- a/src/stores/LocaleStore.js +++ /dev/null @@ -1,19 +0,0 @@ -import { useStorage } from '@vueuse/core' -import { defineStore } from 'pinia' - -const getBrowserLocale = () => { - const navigatorLocale = navigator.languages !== undefined ? navigator.languages[0] : navigator.language - - if (!navigatorLocale) { - return undefined - } - - const trimmedLocale = navigatorLocale.trim().split(/-|_/)[0] - return trimmedLocale -} - -export const useLocaleStore = defineStore('LocaleStore', { - state: () => ({ - locale: useStorage('locale', getBrowserLocale()), - }), -}) diff --git a/src/stores/LocaleStore.ts b/src/stores/LocaleStore.ts new file mode 100644 index 0000000..8d7c7ac --- /dev/null +++ b/src/stores/LocaleStore.ts @@ -0,0 +1,19 @@ +import { useStorage } from '@vueuse/core' +import { defineStore } from 'pinia' + +const getBrowserLocale = () => { + const navigatorLocale = + navigator.languages !== undefined ? navigator.languages[0] : navigator.language + + if (!navigatorLocale) { + return undefined + } + + return navigatorLocale.trim().split(/-|_/)[0] +} + +export const useLocaleStore = defineStore('LocaleStore', { + state: () => ({ + locale: useStorage('locale', getBrowserLocale()), + }), +}) diff --git a/src/stores/PlaceStore.js b/src/stores/PlaceStore.js deleted file mode 100644 index 8cdcfa7..0000000 --- a/src/stores/PlaceStore.js +++ /dev/null @@ -1,23 +0,0 @@ -import { defineStore } from 'pinia' -import axios from 'axios' -import { useStorage } from '@vueuse/core' - -export const usePlaceStore = defineStore('PlaceStore', { - state: () => ({ - places: useStorage('places', {}), - }), - actions: { - get(id) { - if (id in this.places) { - return this.places[id] - } - }, - async load(id) { - const response = await axios.get(`/api/places/${id}`) - return (this.places[id] = response.data.data) - }, - clearCache() { - this.places = {} - }, - }, -}) diff --git a/src/stores/PlaceStore.ts b/src/stores/PlaceStore.ts new file mode 100644 index 0000000..de5facf --- /dev/null +++ b/src/stores/PlaceStore.ts @@ -0,0 +1,23 @@ +import { defineStore } from 'pinia' +import axios from 'axios' +import { useStorage } from '@vueuse/core' + +export const usePlaceStore = defineStore('PlaceStore', { + state: () => ({ + places: useStorage('places', {}), + }), + actions: { + get(id: string) { + if (id in this.places) { + return this.places[id] + } + }, + async load(id: string) { + const response = await axios.get(`/api/places/${id}`) + return (this.places[id] = response.data.data) + }, + clearCache() { + this.places = {} + }, + }, +}) diff --git a/src/stores/SectionStore.js b/src/stores/SectionStore.js deleted file mode 100644 index d0aed6f..0000000 --- a/src/stores/SectionStore.js +++ /dev/null @@ -1,23 +0,0 @@ -import { defineStore } from 'pinia' -import axios from 'axios' -import { useStorage } from '@vueuse/core' - -export const useSectionStore = defineStore('SectionStore', { - state: () => ({ - sections: useStorage('sections', {}), - }), - actions: { - get(id) { - if (id in this.sections) { - return this.sections[id] - } - }, - async load(id) { - const response = await axios.get(`/api/sections/${id}`) - return (this.sections[id] = response.data.data) - }, - clearCache() { - this.sections = {} - }, - }, -}) diff --git a/src/stores/SectionStore.ts b/src/stores/SectionStore.ts new file mode 100644 index 0000000..0900bc8 --- /dev/null +++ b/src/stores/SectionStore.ts @@ -0,0 +1,23 @@ +import { defineStore } from 'pinia' +import axios from 'axios' +import { useStorage } from '@vueuse/core' + +export const useSectionStore = defineStore('SectionStore', { + state: () => ({ + sections: useStorage('sections', {}), + }), + actions: { + get(id: string) { + if (id in this.sections) { + return this.sections[id] + } + }, + async load(id: string) { + const response = await axios.get(`/api/sections/${id}`) + return (this.sections[id] = response.data.data) + }, + clearCache() { + this.sections = {} + }, + }, +}) diff --git a/src/stores/StoryStore.js b/src/stores/StoryStore.js deleted file mode 100644 index d91b45b..0000000 --- a/src/stores/StoryStore.js +++ /dev/null @@ -1,23 +0,0 @@ -import { defineStore } from 'pinia' -import axios from 'axios' -import { useStorage } from '@vueuse/core' - -export const useStoryStore = defineStore('StoryStore', { - state: () => ({ - stories: useStorage('stories', {}), - }), - actions: { - get(id) { - if (id in this.stories) { - return this.stories[id] - } - }, - async load(id) { - const response = await axios.get(`/api/stories/${id}`) - return (this.stories[id] = response.data.data) - }, - clearCache() { - this.stories = {} - }, - }, -}) diff --git a/src/stores/StoryStore.ts b/src/stores/StoryStore.ts new file mode 100644 index 0000000..d32bcb9 --- /dev/null +++ b/src/stores/StoryStore.ts @@ -0,0 +1,23 @@ +import { defineStore } from 'pinia' +import axios from 'axios' +import { useStorage } from '@vueuse/core' + +export const useStoryStore = defineStore('StoryStore', { + state: () => ({ + stories: useStorage('stories', {}), + }), + actions: { + get(id: string) { + if (id in this.stories) { + return this.stories[id] + } + }, + async load(id: string) { + const response = await axios.get(`/api/stories/${id}`) + return (this.stories[id] = response.data.data) + }, + clearCache() { + this.stories = {} + }, + }, +}) diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..bc9b0bd --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "typed-router.d.ts","auto-imports.d.ts", "components.d.ts", "manual.d.ts"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..dee96be --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,16 @@ +{ + "extends": "@tsconfig/node18/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/vite.config.js b/vite.config.js index 03fbaf0..cb66b41 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,42 +1,38 @@ -import path from 'node:path' - import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' - import VueRouter from 'unplugin-vue-router/vite' import { VueRouterAutoImports } from 'unplugin-vue-router' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' +import pluginRewriteAll from 'vite-plugin-rewrite-all' - - +import { fileURLToPath, URL } from 'node:url' // https://vitejs.dev/config/ export default defineConfig({ - resolve: { - alias: { - '~/': `${path.resolve(__dirname, 'src')}/`, - }, + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), }, + }, plugins: [ - VueRouter(), - AutoImport({ - dts: true, - dirs: [ - 'src/composables', - 'src/stores', - ], - imports: [ - 'vue', - VueRouterAutoImports, - ] - }), - Components({ - dts: true, - dirs: [ - 'src/components/svg', - ] - }), - vue(), + VueRouter(), + AutoImport({ + dts: true, + dirs: ['src/composables', 'src/stores'], + imports: ['vue', VueRouterAutoImports], + }), + Components({ + dts: true, + dirs: ['src/components/svg'], + }), + vue({ + script: { + defineModel: true, + propsDestructure: true, + }, + }), + // this is a workaround for dot in url + pluginRewriteAll(), ], }) From c66d58e922f06aa60f566c227b5a0f9a724550b4 Mon Sep 17 00:00:00 2001 From: Mayo Horkovic Date: Sun, 29 Oct 2023 19:52:52 +0100 Subject: [PATCH 2/7] husky pre-commit check --- .husky/pre-commit | 4 ++++ package.json | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..a43a286 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run type-check diff --git a/package.json b/package.json index e7cde53..def38b6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "build-only": "vite build", "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", - "format": "prettier --write src/" + "format": "prettier --write src/", + "prepare": "husky install" }, "dependencies": { "@sentry/vue": "^7.73.0", @@ -39,6 +40,7 @@ "eslint-plugin-import": "^2.27.5", "eslint-plugin-prettier-vue": "^4.2.0", "eslint-plugin-vue": "^9.17.0", + "husky": "^8.0.3", "lodash": "^4.17.21", "npm-run-all2": "^6.1.1", "prettier": "^3.0.3", From 0e6c858bf28d6bbcd6d3acedc6da9119088ce382 Mon Sep 17 00:00:00 2001 From: Mayo Horkovic Date: Sun, 29 Oct 2023 19:54:56 +0100 Subject: [PATCH 3/7] =?UTF-8?q?models,=20types=20&=C2=A0persistent=20stora?= =?UTF-8?q?ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 33 ++++++++-- package.json | 1 + src/app.ts | 13 ++-- src/components/author/AuthorDetails.vue | 4 +- src/components/author/AuthorSummary.vue | 4 +- src/components/author/AuthorityDetails.vue | 10 +-- src/components/author/AuthoritySummary.vue | 4 +- src/components/bucketlist/Bucketlist.vue | 13 ++-- .../bucketlist/LockedItemThumbnail.vue | 3 +- src/components/general/ImageLightbox.vue | 10 +-- src/components/general/ItemImage.vue | 2 +- src/components/general/ItemLoader.vue | 4 +- src/components/general/ItemPreview.vue | 3 +- src/components/general/ItemThumbnail.vue | 3 +- src/components/general/ResponsiveImage.vue | 4 +- .../general/ResponsiveImageWithSizes.vue | 4 +- .../general/ResponsiveVideoEmbed.vue | 4 +- src/components/general/VideoSummary.vue | 4 +- .../interactions/InteractionItem.vue | 8 ++- .../InteractionItemFavourited.vue | 4 +- .../interactions/InteractionItemViewed.vue | 5 +- .../interactions/InteractionPlaceViewed.vue | 4 +- .../interactions/InteractionSectionViewed.vue | 4 +- .../interactions/InteractionStory.vue | 9 ++- .../interactions/StoryVideoLightbox.vue | 8 ++- src/components/misc/ZoomViewer.vue | 6 +- src/composables/Params.ts | 7 +++ src/css/style.css | 11 ++++ src/models/Authority.ts | 22 +++++++ src/models/Bucketlist.ts | 23 +++++++ src/models/Interaction.ts | 17 +++++ src/models/Item.ts | 62 +++++++++++++++++++ src/models/Place.ts | 32 ++++++++++ src/models/Section.ts | 25 ++++++++ src/models/Story.ts | 27 ++++++++ src/models/_BaseModel.ts | 34 ++++++++++ src/models/_Interfaces.ts | 13 ++++ src/pages/[id].vue | 9 +-- src/pages/collection.vue | 7 --- src/pages/index.vue | 49 ++++++--------- src/pages/item/[id].vue | 43 ++++++++----- src/pages/locked/[id].vue | 10 +-- src/pages/place/[id].vue | 20 +++--- src/pages/reward/[id].vue | 6 +- src/pages/section/[id].vue | 30 ++++----- src/pages/section/[sectionId]/[id].vue | 37 ++++++----- src/pages/story/[id].vue | 52 +++++++--------- src/stores/BucketlistStore.ts | 12 ++-- src/stores/ItemStore.ts | 17 ++--- src/stores/LocaleStore.ts | 4 +- src/stores/PlaceStore.ts | 10 +-- src/stores/SectionStore.ts | 9 +-- src/stores/StoryStore.ts | 11 ++-- 53 files changed, 554 insertions(+), 216 deletions(-) create mode 100644 src/composables/Params.ts create mode 100644 src/models/Authority.ts create mode 100644 src/models/Bucketlist.ts create mode 100644 src/models/Interaction.ts create mode 100644 src/models/Item.ts create mode 100644 src/models/Place.ts create mode 100644 src/models/Section.ts create mode 100644 src/models/Story.ts create mode 100644 src/models/_BaseModel.ts create mode 100644 src/models/_Interfaces.ts diff --git a/package-lock.json b/package-lock.json index 7bcd6f7..f4efe74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "laravel-vue-i18n": "^2.7.1", "openseadragon": "^4.1.0", "pinia": "^2.1.6", - "vue": "^3.3.4", + "pinia-plugin-persistedstate": "^3.2.0", + "vue": "^3.3.7", "vue-router": "^4.2.5", "vue3-carousel": "^0.3.1" }, @@ -24,7 +25,7 @@ "@tsconfig/node18": "^18.2.2", "@types/node": "^18.18.5", "@types/openseadragon": "^3.0.8", - "@vitejs/plugin-vue": "^4.2.3", + "@vitejs/plugin-vue": "^4.4.0", "@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-typescript": "^12.0.0", "@vue/tsconfig": "^0.4.0", @@ -34,6 +35,7 @@ "eslint-plugin-import": "^2.27.5", "eslint-plugin-prettier-vue": "^4.2.0", "eslint-plugin-vue": "^9.17.0", + "husky": "^8.0.3", "lodash": "^4.17.21", "npm-run-all2": "^6.1.1", "prettier": "^3.0.3", @@ -43,9 +45,9 @@ "unplugin-auto-import": "^0.16.7", "unplugin-vue-components": "^0.25.2", "unplugin-vue-router": "^0.7.0", - "vite": "^4.4.5", + "vite": "^4.5.0", "vite-plugin-rewrite-all": "^1.0.1", - "vue-tsc": "^1.8.19" + "vue-tsc": "^1.8.22" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3368,6 +3370,21 @@ "node": ">=14.18.0" } }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -4612,6 +4629,14 @@ } } }, + "node_modules/pinia-plugin-persistedstate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.0.tgz", + "integrity": "sha512-tZbNGf2vjAQcIm7alK40sE51Qu/m9oWr+rEgNm/2AWr1huFxj72CjvpQcIQzMknDBJEkQznCLAGtJTIcLKrKdw==", + "peerDependencies": { + "pinia": "^2.0.0" + } + }, "node_modules/pinia/node_modules/vue-demi": { "version": "0.14.6", "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", diff --git a/package.json b/package.json index def38b6..ad59faa 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "laravel-vue-i18n": "^2.7.1", "openseadragon": "^4.1.0", "pinia": "^2.1.6", + "pinia-plugin-persistedstate": "^3.2.0", "vue": "^3.3.7", "vue-router": "^4.2.5", "vue3-carousel": "^0.3.1" diff --git a/src/app.ts b/src/app.ts index 6e7d201..5d2d569 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,14 +1,14 @@ -import './bootstrap' -import './css/style.css' - -import App from './App.vue' +import '@/bootstrap' +import '@/css/style.css' import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router/auto' import { i18nVue } from 'laravel-vue-i18n' import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import * as Sentry from '@sentry/vue' +import App from '@/App.vue' import { useLocaleStore } from '@/stores/LocaleStore' import { useHistoryStore } from '@/stores/HistoryStore' @@ -29,7 +29,10 @@ const app = createApp(App) Sentry.init({ app, dsn: import.meta.env.VITE_SENTRY_DSN }) app.use(router) -app.use(createPinia()) + +const pinia = createPinia() +pinia.use(piniaPluginPersistedstate) +app.use(pinia) const localeStore = useLocaleStore() app.use(i18nVue, { diff --git a/src/components/author/AuthorDetails.vue b/src/components/author/AuthorDetails.vue index 62141a9..f639709 100644 --- a/src/components/author/AuthorDetails.vue +++ b/src/components/author/AuthorDetails.vue @@ -3,7 +3,9 @@ diff --git a/src/components/author/AuthorSummary.vue b/src/components/author/AuthorSummary.vue index c9fa6d1..32e308b 100644 --- a/src/components/author/AuthorSummary.vue +++ b/src/components/author/AuthorSummary.vue @@ -13,7 +13,9 @@ diff --git a/src/components/author/AuthorityDetails.vue b/src/components/author/AuthorityDetails.vue index 49572bf..d7a10b4 100644 --- a/src/components/author/AuthorityDetails.vue +++ b/src/components/author/AuthorityDetails.vue @@ -42,12 +42,14 @@ import axios from 'axios' import ItemPreview from '@/components/general/ItemPreview.vue' import ItemImage from '@/components/general/ItemImage.vue' +import Authority from '@/models/Authority' +import Item from '@/models/Item' const props = defineProps<{ - authority: any // TODO: add model + authority: Authority }>() -const relatedItems = ref([]) // TODO: add model -const previewItem = ref(null) // TODO: add model +const relatedItems = ref([]) +const previewItem = ref(null) const isLoading = ref(true) onMounted(async () => { @@ -56,7 +58,7 @@ onMounted(async () => { const response = await axios.get( `/api/related_items/${props.authority.related_items.join(',')}` ) - relatedItems.value = response.data.data + relatedItems.value = response.data.data.map((item: any) => new Item(item)) } catch (error) { console.error(error) } finally { diff --git a/src/components/author/AuthoritySummary.vue b/src/components/author/AuthoritySummary.vue index 5a15c63..bb23b0c 100644 --- a/src/components/author/AuthoritySummary.vue +++ b/src/components/author/AuthoritySummary.vue @@ -16,7 +16,9 @@ diff --git a/src/components/bucketlist/Bucketlist.vue b/src/components/bucketlist/Bucketlist.vue index 86ed56e..08fcda5 100644 --- a/src/components/bucketlist/Bucketlist.vue +++ b/src/components/bucketlist/Bucketlist.vue @@ -9,8 +9,8 @@ unlocked ? $t('All artworks found') : $t(':found of :all artworks found', { - found: found.length, - all: bucketlist.items.length, + found: String(found?.length ?? 0), + all: String(bucketlist.items.length ?? 0), }) }}

@@ -58,7 +58,7 @@ -
+

{{ $t('Found') }}

@@ -82,13 +82,14 @@ import ItemThumbnail from '@/components/general/ItemThumbnail.vue' import LockedItemThumbnail from '@/components/bucketlist/LockedItemThumbnail.vue' import ResponsiveImageWithSizes from '@/components/general/ResponsiveImageWithSizes.vue' import Thumbnail from '@/components/general/Thumbnail.vue' +import Bucketlist from '@/models/Bucketlist' const props = defineProps<{ id: string }>() const bucketlistStore = useBucketlistStore() const interactionStore = useInteractionStore() -const bucketlist = ref(null) // TODO: add model +const bucketlist = ref(null) const found = computed(() => { return bucketlist.value?.items.filter((item) => interactionStore.isItemViewed(item.id)) @@ -98,10 +99,10 @@ const notFound = computed(() => { return bucketlist.value?.items.filter((item) => !interactionStore.isItemViewed(item.id)) }) -const unlocked = computed(() => !notFound.value.length) +const unlocked = computed(() => !notFound.value?.length) onMounted(async () => { - bucketlist.value = bucketlistStore.get(props.id) + bucketlist.value = bucketlistStore.get(props.id)! bucketlist.value = await bucketlistStore.load(props.id) }) diff --git a/src/components/bucketlist/LockedItemThumbnail.vue b/src/components/bucketlist/LockedItemThumbnail.vue index 40a491d..519fe67 100644 --- a/src/components/bucketlist/LockedItemThumbnail.vue +++ b/src/components/bucketlist/LockedItemThumbnail.vue @@ -17,8 +17,9 @@ diff --git a/src/components/general/ImageLightbox.vue b/src/components/general/ImageLightbox.vue index f0e5325..e39ba07 100644 --- a/src/components/general/ImageLightbox.vue +++ b/src/components/general/ImageLightbox.vue @@ -16,7 +16,7 @@
@@ -42,16 +42,18 @@ diff --git a/src/components/general/ResponsiveImage.vue b/src/components/general/ResponsiveImage.vue index a59104d..9b6aaa7 100644 --- a/src/components/general/ResponsiveImage.vue +++ b/src/components/general/ResponsiveImage.vue @@ -3,7 +3,9 @@ diff --git a/src/components/general/ResponsiveImageWithSizes.vue b/src/components/general/ResponsiveImageWithSizes.vue index d08d705..a961df6 100644 --- a/src/components/general/ResponsiveImageWithSizes.vue +++ b/src/components/general/ResponsiveImageWithSizes.vue @@ -11,8 +11,10 @@ diff --git a/src/components/general/VideoSummary.vue b/src/components/general/VideoSummary.vue index 1fc23ef..4ebf2ff 100644 --- a/src/components/general/VideoSummary.vue +++ b/src/components/general/VideoSummary.vue @@ -13,10 +13,12 @@ diff --git a/src/components/interactions/InteractionItemFavourited.vue b/src/components/interactions/InteractionItemFavourited.vue index 9cf81e6..d7e135b 100644 --- a/src/components/interactions/InteractionItemFavourited.vue +++ b/src/components/interactions/InteractionItemFavourited.vue @@ -4,15 +4,15 @@ icon-class="fill-current" :label="$t('Saved')" v-bind="props" - item="" /> diff --git a/src/components/interactions/InteractionItemViewed.vue b/src/components/interactions/InteractionItemViewed.vue index e9279e4..9b8a921 100644 --- a/src/components/interactions/InteractionItemViewed.vue +++ b/src/components/interactions/InteractionItemViewed.vue @@ -1,12 +1,13 @@ diff --git a/src/components/interactions/InteractionPlaceViewed.vue b/src/components/interactions/InteractionPlaceViewed.vue index 0dae8d5..aec684f 100644 --- a/src/components/interactions/InteractionPlaceViewed.vue +++ b/src/components/interactions/InteractionPlaceViewed.vue @@ -13,7 +13,9 @@ diff --git a/src/components/interactions/InteractionSectionViewed.vue b/src/components/interactions/InteractionSectionViewed.vue index 405be44..f4075e3 100644 --- a/src/components/interactions/InteractionSectionViewed.vue +++ b/src/components/interactions/InteractionSectionViewed.vue @@ -13,7 +13,9 @@ diff --git a/src/components/interactions/InteractionStory.vue b/src/components/interactions/InteractionStory.vue index 4d0fbd4..b92f8b5 100644 --- a/src/components/interactions/InteractionStory.vue +++ b/src/components/interactions/InteractionStory.vue @@ -59,18 +59,21 @@ diff --git a/src/components/misc/ZoomViewer.vue b/src/components/misc/ZoomViewer.vue index 6ee005c..770ed6a 100644 --- a/src/components/misc/ZoomViewer.vue +++ b/src/components/misc/ZoomViewer.vue @@ -5,11 +5,13 @@ diff --git a/src/pages/collection.vue b/src/pages/collection.vue index 5d4369e..cbbc3d3 100644 --- a/src/pages/collection.vue +++ b/src/pages/collection.vue @@ -10,13 +10,6 @@ import Bucketlist from '@/components/bucketlist/Bucketlist.vue' import Timeline from '@/components/timeline/Timeline.vue' -const route = useRoute() const itemStore = useItemStore() const bucketlistId = import.meta.env.VITE_DEFAULT_BUCKETLIST - -onMounted(async () => { - if (route.params.id) { - itemStore.fetch(route.params.id) - } -}) diff --git a/src/pages/index.vue b/src/pages/index.vue index 7af759f..8be9010 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -4,9 +4,9 @@ @@ -42,28 +42,31 @@ - - diff --git a/src/pages/item/[id].vue b/src/pages/item/[id].vue index 2e65d02..84b9747 100644 --- a/src/pages/item/[id].vue +++ b/src/pages/item/[id].vue @@ -8,18 +8,20 @@

{{ $t(':found of :all artworks found', { - found: found.length, - all: bucketlist.items.length, + found: String(found?.length ?? 0), + all: String(bucketlist?.items.length ?? 0), }) }}

- {{ $t(unlocked ? 'reward' : 'list') }} +
@@ -52,9 +54,9 @@
- + @@ -111,6 +113,8 @@ diff --git a/src/pages/locked/[id].vue b/src/pages/locked/[id].vue index 89ee248..77ef68e 100644 --- a/src/pages/locked/[id].vue +++ b/src/pages/locked/[id].vue @@ -26,16 +26,18 @@ diff --git a/src/pages/reward/[id].vue b/src/pages/reward/[id].vue index a7b8a85..2ff6fa6 100644 --- a/src/pages/reward/[id].vue +++ b/src/pages/reward/[id].vue @@ -18,13 +18,13 @@ diff --git a/src/pages/section/[id].vue b/src/pages/section/[id].vue index eed949b..f6ec6ec 100644 --- a/src/pages/section/[id].vue +++ b/src/pages/section/[id].vue @@ -12,10 +12,10 @@
- +

- {{ $t('Group of :count artworks', { count: section.items.length }) }} + {{ $t('Group of :count artworks', { count: String(section.items.length) }) }}

{{ section.title }}

@@ -24,11 +24,7 @@

{{ $t('More about artworks in the group') }}

- +
@@ -52,23 +48,23 @@ import HistoryBack from '@/components/misc/HistoryBack.vue' import ConfirmButton from '@/components/forms/ConfirmButton.vue' import ItemThumbnail from '@/components/general/ItemThumbnail.vue' import ItemImage from '@/components/general/ItemImage.vue' +import Section from '@/models/Section' -// TODO: why is this duplicated with ref? -// defineProps<{ -// section: any // TODO: add model -// }>() - -const route = useRoute() -const interactionStore = useInteractionStore() +// const interactionStore = useInteractionStore() const sectionStore = useSectionStore() -const section = ref(null) +const section = ref
(null) + +const { id } = useParams() onMounted(async () => { - const id = route.params.id section.value = await sectionStore.load(id) // TODO: where did item come from? - interactionStore.addSectionViewed(item.value.id) + // interactionStore.addSectionViewed(item.value.id) +}) + +const codeImage = computed(() => { + return `${import.meta.env.VITE_API_URL}/img/${section.value?.code}.svg` }) diff --git a/src/pages/section/[sectionId]/[id].vue b/src/pages/section/[sectionId]/[id].vue index ea0b02b..25de5f4 100644 --- a/src/pages/section/[sectionId]/[id].vue +++ b/src/pages/section/[sectionId]/[id].vue @@ -8,18 +8,20 @@

{{ $t(':found of :all artworks found', { - found: found.length, - all: bucketlist.items.length, + found: String(found?.length ?? 0), + all: String(bucketlist.items.length ?? 0), }) }}

- {{ $t(unlocked ? 'reward' : 'list') }} +
@@ -76,7 +78,7 @@ - + @@ -124,22 +126,25 @@ import AuthorSummary from '@/components/author/AuthorSummary.vue' import AuthorDetails from '@/components/author/AuthorDetails.vue' import HistoryBack from '@/components/misc/HistoryBack.vue' import ConfirmButton from '@/components/forms/ConfirmButton.vue' +import Bucketlist from '@/models/Bucketlist' +import Item from '@/models/Item' const route = useRoute() const bucketlistStore = useBucketlistStore() const interactionStore = useInteractionStore() const itemStore = useItemStore() -const item = ref(null) // TODO: add model -const bucketlist = ref(null) // TODO: add model +const item = ref(null) +const bucketlist = ref(null) const found = computed(() => - bucketlist.value.items.filter((item) => interactionStore.isItemViewed(item.id)) + bucketlist.value?.items.filter((item) => interactionStore.isItemViewed(item.id)) ) -const unlocked = computed(() => found.value.length === bucketlist.value.items.length) +const unlocked = computed(() => found.value?.length === bucketlist.value?.items.length) onMounted(async () => { - const id = route.params.id + const { id } = useParams() + item.value = await itemStore.load(id) interactionStore.addItemViewed(item.value.id) const defaultBucketlist = item.value.bucketlists.find( @@ -153,6 +158,6 @@ onMounted(async () => { }) const codeImage = computed(() => { - return `${import.meta.env.VITE_API_URL}/img/${item.value.code}.svg` + return `${import.meta.env.VITE_API_URL}/img/${item.value?.code}.svg` }) diff --git a/src/pages/story/[id].vue b/src/pages/story/[id].vue index 79ba481..f47b66b 100644 --- a/src/pages/story/[id].vue +++ b/src/pages/story/[id].vue @@ -4,9 +4,9 @@ @@ -42,28 +42,31 @@ - - diff --git a/src/stores/BucketlistStore.ts b/src/stores/BucketlistStore.ts index 20b6c9f..b7a3b4f 100644 --- a/src/stores/BucketlistStore.ts +++ b/src/stores/BucketlistStore.ts @@ -1,10 +1,10 @@ import { defineStore } from 'pinia' -import { useStorage } from '@vueuse/core' -import axios from 'axios' + +import Bucketlist from '@/models/Bucketlist' export const useBucketlistStore = defineStore('BucketlistStore', { state: () => ({ - bucketlists: useStorage('bucketlists', {}) as any, // TODO: add model + bucketlists: {} as Record, }), actions: { get(id: string) { @@ -13,11 +13,11 @@ export const useBucketlistStore = defineStore('BucketlistStore', { } }, async load(id: string) { - const response = await axios.get(`/api/bucketlists/${id}`) - return (this.bucketlists[id] = response.data.data) + return (this.bucketlists[id] = await Bucketlist.load(id)) }, clearCache() { - this.bucketlists = [] + this.bucketlists = {} }, }, + persist: true, }) diff --git a/src/stores/ItemStore.ts b/src/stores/ItemStore.ts index f911067..3605f03 100644 --- a/src/stores/ItemStore.ts +++ b/src/stores/ItemStore.ts @@ -1,11 +1,12 @@ import { defineStore } from 'pinia' -import { useStorage } from '@vueuse/core' import axios from 'axios' +import Item from '@/models/Item' + export const useItemStore = defineStore('ItemStore', { state: () => ({ - items: useStorage('items', {}), - collectionLink: useStorage('collectionLink', null), + items: {} as Record, + collectionLink: null, }), actions: { get(id: string) { @@ -14,8 +15,7 @@ export const useItemStore = defineStore('ItemStore', { } }, async load(id: string) { - const response = await axios.get(`/api/items/${id}`) - return (this.items[id] = response.data.data) + return (this.items[id] = await Item.load(id)) }, clearCollectionLink() { this.collectionLink = null @@ -29,23 +29,24 @@ export const useItemStore = defineStore('ItemStore', { if (this.collectionLink) { return this.collectionLink } else { - const response = await axios + const response = (await axios .post('/api/collections', { items: [...interactionStore.viewedItemIds], }) .catch((err) => { console.log(err) - }) + })) as any const collectionLink = response.data.url this.collectionLink = collectionLink return collectionLink } }, - async fetch(collectionId: string) { + async fetch() { this.clearCollectionLink() this.items = {} // todo // this.viewedIds = (await axios.get(`/api/collections/${collectionId}`)).data }, }, + persist: true, }) diff --git a/src/stores/LocaleStore.ts b/src/stores/LocaleStore.ts index 8d7c7ac..324747d 100644 --- a/src/stores/LocaleStore.ts +++ b/src/stores/LocaleStore.ts @@ -1,4 +1,3 @@ -import { useStorage } from '@vueuse/core' import { defineStore } from 'pinia' const getBrowserLocale = () => { @@ -14,6 +13,7 @@ const getBrowserLocale = () => { export const useLocaleStore = defineStore('LocaleStore', { state: () => ({ - locale: useStorage('locale', getBrowserLocale()), + locale: getBrowserLocale(), }), + persist: true, }) diff --git a/src/stores/PlaceStore.ts b/src/stores/PlaceStore.ts index de5facf..98859b8 100644 --- a/src/stores/PlaceStore.ts +++ b/src/stores/PlaceStore.ts @@ -1,10 +1,10 @@ import { defineStore } from 'pinia' -import axios from 'axios' -import { useStorage } from '@vueuse/core' + +import Place from '@/models/Place' export const usePlaceStore = defineStore('PlaceStore', { state: () => ({ - places: useStorage('places', {}), + places: {} as Record, }), actions: { get(id: string) { @@ -13,11 +13,11 @@ export const usePlaceStore = defineStore('PlaceStore', { } }, async load(id: string) { - const response = await axios.get(`/api/places/${id}`) - return (this.places[id] = response.data.data) + return (this.places[id] = await Place.load(id)) }, clearCache() { this.places = {} }, }, + persist: true, }) diff --git a/src/stores/SectionStore.ts b/src/stores/SectionStore.ts index 0900bc8..9a29280 100644 --- a/src/stores/SectionStore.ts +++ b/src/stores/SectionStore.ts @@ -1,10 +1,11 @@ import { defineStore } from 'pinia' import axios from 'axios' -import { useStorage } from '@vueuse/core' + +import Section from '@/models/Section' export const useSectionStore = defineStore('SectionStore', { state: () => ({ - sections: useStorage('sections', {}), + sections: {} as Record, }), actions: { get(id: string) { @@ -13,11 +14,11 @@ export const useSectionStore = defineStore('SectionStore', { } }, async load(id: string) { - const response = await axios.get(`/api/sections/${id}`) - return (this.sections[id] = response.data.data) + return (this.sections[id] = await Section.load(id)) }, clearCache() { this.sections = {} }, }, + persist: true, }) diff --git a/src/stores/StoryStore.ts b/src/stores/StoryStore.ts index d32bcb9..9c8764a 100644 --- a/src/stores/StoryStore.ts +++ b/src/stores/StoryStore.ts @@ -1,11 +1,12 @@ import { defineStore } from 'pinia' -import axios from 'axios' -import { useStorage } from '@vueuse/core' + +import Story from '@/models/Story' export const useStoryStore = defineStore('StoryStore', { state: () => ({ - stories: useStorage('stories', {}), + stories: {} as Record, }), + actions: { get(id: string) { if (id in this.stories) { @@ -13,11 +14,11 @@ export const useStoryStore = defineStore('StoryStore', { } }, async load(id: string) { - const response = await axios.get(`/api/stories/${id}`) - return (this.stories[id] = response.data.data) + return (this.stories[id] = await Story.load(id)) }, clearCache() { this.stories = {} }, }, + persist: true, }) From 0690daba9f29951d47c742f16bd21534dc3ec898 Mon Sep 17 00:00:00 2001 From: Mayo Horkovic Date: Sun, 29 Oct 2023 19:56:02 +0100 Subject: [PATCH 4/7] InteractionStore --- src/stores/InteractionStore.ts | 239 +++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 89 deletions(-) diff --git a/src/stores/InteractionStore.ts b/src/stores/InteractionStore.ts index 7396289..f13185a 100644 --- a/src/stores/InteractionStore.ts +++ b/src/stores/InteractionStore.ts @@ -1,110 +1,171 @@ -import { useStorage } from '@vueuse/core' import { defineStore } from 'pinia' -export const useInteractionStore = defineStore('InteractionStore', { - state: () => ({ - interactions: useStorage('interactions', []), - peekCodePanel: useStorage('peekCodePanel', true), - cursor: useStorage('cursor', -1), - }), - getters: { - active() { - if (this.cursor > -1) { - return this.interactions[this.cursor] +import type { ILink } from '@/models/_Interfaces' + +import Interaction from '@/models/Interaction' + +export const useInteractionStore = defineStore( + 'InteractionStore', + () => { + const interactions = ref([]) + const peekCodePanel = ref(true) + const cursor = ref(-1) + + const active = computed(() => { + if (cursor.value > -1) { + return interactions.value[cursor.value] } - }, - activeStory() { - if (this.active && this.active.type === 'story') { + }) + + const activeStory = computed(() => { + if (active.value !== undefined && active.value.type === 'story') { const storiesStore = useStoryStore() - return storiesStore.get(this.active.id) + return storiesStore.get(active.value!.id) } - }, - lastStory() { - return this.stories[this.stories.length - 1] - }, - stories() { + }) + + const lastStory = computed(() => { + return stories.value[stories.value.length - 1] + }) + + const stories = computed(() => { const storiesStore = useStoryStore() - return this.interactions + + return interactions.value .filter((interaction) => interaction.type === 'story') .map((interaction) => storiesStore.get(interaction.id)) - }, - viewedItemIds() { + }) + + const viewedItemIds = computed(() => { return new Set( - this.interactions + interactions.value .filter((interaction) => interaction.type === 'itemViewed') .map((interaction) => interaction.id) .slice() .reverse() ) - }, - viewedItemsCount() { - return this.viewedItemIds.size - }, - }, - actions: { - isItemViewed(id) { - return this.viewedItemIds.has(id) - }, - addStory(id) { - const length = this.interactions.push({ - type: 'story', - id, - }) - this.cursor = length - 1 - }, - addItemViewed(id) { - this.interactions.push({ - type: 'itemViewed', - id, - }) - }, - addSectionViewed(id) { - this.interactions.push({ - type: 'sectionViewed', - id, - }) - }, - addPlaceViewed(id) { - this.interactions.push({ - type: 'placeViewed', - id, - }) - }, - selectLink(interaction, link) { - const index = this.interactions.indexOf(interaction) - this.interactions[index].linkId = link.id - this.cursor = -1 - }, - lastStoryIndex(from) { - let index = typeof from !== 'undefined' ? from : this.cursor - while (this.interactions[index].type !== 'story' && index > 0) { + }) + + const viewedItemsCount = computed(() => { + return viewedItemIds.value.size + }) + + function isItemViewed(id: string) { + return viewedItemIds.value.has(id) + } + + function addStory(id: string) { + const length = interactions.value.push( + new Interaction({ + type: 'story', + id, + }) + ) + + cursor.value = length - 1 + } + + function addItemViewed(id: string) { + interactions.value.push( + new Interaction({ + type: 'itemViewed', + id, + }) + ) + } + + function addSectionViewed(id: string) { + interactions.value.push( + new Interaction({ + type: 'sectionViewed', + id, + }) + ) + } + + function addPlaceViewed(id: string) { + interactions.value.push( + new Interaction({ + type: 'placeViewed', + id, + }) + ) + } + + function selectLink(interaction: Interaction, link: ILink) { + const index = interactions.value.indexOf(interaction) + interactions.value[index].linkId = link.id + cursor.value = -1 + } + + function lastStoryIndex(from: number) { + let index = typeof from !== 'undefined' ? from : cursor.value + while (interactions.value[index].type !== 'story' && index > 0) { index-- } return index - }, - setPreviousActive(interaction) { - const index = this.interactions.indexOf(interaction) - this.cursor = this.lastStoryIndex(index - 1) - this.active.linkId = undefined - return this.active - }, - remove(interaction) { - const toDelete = this.interactions.indexOf(interaction) - this.interactions.splice(toDelete, 1) - if (toDelete <= this.cursor) { - this.cursor = this.lastStoryIndex(this.cursor - 1) + } + + function setPreviousActive(interaction: Interaction) { + const index = interactions.value.indexOf(interaction) + cursor.value = lastStoryIndex(index - 1) + + if (active.value) { + active.value.linkId = null + } + + return active.value + } + + function remove(interaction: Interaction) { + const toDelete = interactions.value.indexOf(interaction) + interactions.value.splice(toDelete, 1) + if (toDelete <= cursor.value) { + cursor.value = lastStoryIndex(cursor.value - 1) } - }, - isVisited(id) { - return this.stories.some((interaction) => interaction.id === id) - }, - hasVisitedAllLinks(id) { + } + + function isVisited(id: string) { + return stories.value.some((interaction) => interaction?.id === id) + } + + function hasVisitedAllLinks(id: string) { const storyStore = useStoryStore() const story = storyStore.get(id) - return story?.links.every((link) => this.isVisited(link.story_id)) - }, - clear() { - this.interactions = [] - }, + return story?.links.every((link) => isVisited(link.story_id)) + } + + function clear() { + interactions.value = [] + } + + return { + interactions, + peekCodePanel, + cursor, + + active, + activeStory, + lastStory, + stories, + viewedItemIds, + viewedItemsCount, + + isItemViewed, + addStory, + addItemViewed, + addSectionViewed, + addPlaceViewed, + selectLink, + lastStoryIndex, + setPreviousActive, + remove, + isVisited, + hasVisitedAllLinks, + clear, + } }, -}) + { + persist: true, + } +) From 167b84599cb619fb7bf651e33ff2cf63f72ed592 Mon Sep 17 00:00:00 2001 From: Mayo Horkovic Date: Sun, 29 Oct 2023 20:29:35 +0100 Subject: [PATCH 5/7] rest of stores --- src/stores/BucketlistStore.ts | 45 ++++++++++++-------- src/stores/HistoryStore.ts | 28 +++++++------ src/stores/ItemStore.ts | 79 +++++++++++++++++++++-------------- src/stores/LocaleStore.ts | 19 ++++++--- src/stores/PlaceStore.ts | 45 ++++++++++++-------- src/stores/SectionStore.ts | 46 ++++++++++++-------- src/stores/StoryStore.ts | 44 +++++++++++-------- 7 files changed, 188 insertions(+), 118 deletions(-) diff --git a/src/stores/BucketlistStore.ts b/src/stores/BucketlistStore.ts index b7a3b4f..6c50ef3 100644 --- a/src/stores/BucketlistStore.ts +++ b/src/stores/BucketlistStore.ts @@ -2,22 +2,33 @@ import { defineStore } from 'pinia' import Bucketlist from '@/models/Bucketlist' -export const useBucketlistStore = defineStore('BucketlistStore', { - state: () => ({ - bucketlists: {} as Record, - }), - actions: { - get(id: string) { - if (id in this.bucketlists) { - return this.bucketlists[id] +export const useBucketlistStore = defineStore( + 'BucketlistStore', + () => { + const bucketlists = ref>({}) + + function get(id: string) { + if (id in bucketlists.value) { + return bucketlists.value[id] } - }, - async load(id: string) { - return (this.bucketlists[id] = await Bucketlist.load(id)) - }, - clearCache() { - this.bucketlists = {} - }, + } + + async function load(id: string) { + return (bucketlists.value[id] = await Bucketlist.load(id)) + } + + function clearCache() { + bucketlists.value = {} + } + + return { + bucketlists, + get, + load, + clearCache, + } }, - persist: true, -}) + { + persist: true, + } +) diff --git a/src/stores/HistoryStore.ts b/src/stores/HistoryStore.ts index a6bf7d2..929a6b7 100644 --- a/src/stores/HistoryStore.ts +++ b/src/stores/HistoryStore.ts @@ -1,15 +1,19 @@ import { defineStore } from 'pinia' -export const useHistoryStore = defineStore('HistoryStore', { - state: () => ({ - history: null as any, - }), - actions: { - set(history: any) { - this.history = history - }, - getState() { - return this.history?.state - }, - }, +export const useHistoryStore = defineStore('HistoryStore', () => { + const history = ref(null) + + function set(history: any) { + history.value = history + } + + function getState() { + return history.value?.state + } + + return { + history, + set, + getState, + } }) diff --git a/src/stores/ItemStore.ts b/src/stores/ItemStore.ts index 3605f03..a5452ca 100644 --- a/src/stores/ItemStore.ts +++ b/src/stores/ItemStore.ts @@ -3,31 +3,34 @@ import axios from 'axios' import Item from '@/models/Item' -export const useItemStore = defineStore('ItemStore', { - state: () => ({ - items: {} as Record, - collectionLink: null, - }), - actions: { - get(id: string) { - if (id in this.items) { - return this.items[id] +export const useItemStore = defineStore( + 'ItemStore', + () => { + const items = ref>({}) + const collectionLink = ref(null) + + function get(id: string) { + if (id in items.value) { + return items.value[id] } - }, - async load(id: string) { - return (this.items[id] = await Item.load(id)) - }, - clearCollectionLink() { - this.collectionLink = null - }, - clearCache() { - this.items = {} - }, - async getCollectionLink() { - const interactionStore = useInteractionStore() + } + + async function load(id: string) { + return (items.value[id] = await Item.load(id)) + } + + function clearCollectionLink() { + collectionLink.value = null + } - if (this.collectionLink) { - return this.collectionLink + function clearCache() { + items.value = {} + } + + async function getCollectionLink() { + const interactionStore = useInteractionStore() + if (collectionLink.value) { + return collectionLink.value } else { const response = (await axios .post('/api/collections', { @@ -37,16 +40,30 @@ export const useItemStore = defineStore('ItemStore', { console.log(err) })) as any const collectionLink = response.data.url - this.collectionLink = collectionLink + collectionLink.value = collectionLink return collectionLink } - }, - async fetch() { - this.clearCollectionLink() - this.items = {} + } + + async function fetch() { + clearCollectionLink() + items.value = {} // todo // this.viewedIds = (await axios.get(`/api/collections/${collectionId}`)).data - }, + } + + return { + items, + collectionLink, + get, + load, + clearCollectionLink, + clearCache, + getCollectionLink, + fetch, + } }, - persist: true, -}) + { + persist: true, + } +) diff --git a/src/stores/LocaleStore.ts b/src/stores/LocaleStore.ts index 324747d..c25a5fd 100644 --- a/src/stores/LocaleStore.ts +++ b/src/stores/LocaleStore.ts @@ -11,9 +11,16 @@ const getBrowserLocale = () => { return navigatorLocale.trim().split(/-|_/)[0] } -export const useLocaleStore = defineStore('LocaleStore', { - state: () => ({ - locale: getBrowserLocale(), - }), - persist: true, -}) +export const useLocaleStore = defineStore( + 'LocaleStore', + () => { + const locale = ref(getBrowserLocale()) + + return { + locale, + } + }, + { + persist: true, + } +) diff --git a/src/stores/PlaceStore.ts b/src/stores/PlaceStore.ts index 98859b8..fb1aaf0 100644 --- a/src/stores/PlaceStore.ts +++ b/src/stores/PlaceStore.ts @@ -2,22 +2,33 @@ import { defineStore } from 'pinia' import Place from '@/models/Place' -export const usePlaceStore = defineStore('PlaceStore', { - state: () => ({ - places: {} as Record, - }), - actions: { - get(id: string) { - if (id in this.places) { - return this.places[id] +export const usePlaceStore = defineStore( + 'PlaceStore', + () => { + const places = ref>({}) + + function get(id: string) { + if (id in places.value) { + return places.value[id] } - }, - async load(id: string) { - return (this.places[id] = await Place.load(id)) - }, - clearCache() { - this.places = {} - }, + } + + async function load(id: string) { + return (places.value[id] = await Place.load(id)) + } + + function clearCache() { + places.value = {} + } + + return { + places, + get, + load, + clearCache, + } }, - persist: true, -}) + { + persist: true, + } +) diff --git a/src/stores/SectionStore.ts b/src/stores/SectionStore.ts index 9a29280..f98a55a 100644 --- a/src/stores/SectionStore.ts +++ b/src/stores/SectionStore.ts @@ -1,24 +1,34 @@ import { defineStore } from 'pinia' -import axios from 'axios' import Section from '@/models/Section' -export const useSectionStore = defineStore('SectionStore', { - state: () => ({ - sections: {} as Record, - }), - actions: { - get(id: string) { - if (id in this.sections) { - return this.sections[id] +export const useSectionStore = defineStore( + 'SectionStore', + () => { + const sections = ref>({}) + + function get(id: string) { + if (id in sections.value) { + return sections.value[id] } - }, - async load(id: string) { - return (this.sections[id] = await Section.load(id)) - }, - clearCache() { - this.sections = {} - }, + } + + async function load(id: string) { + return (sections.value[id] = await Section.load(id)) + } + + function clearCache() { + sections.value = {} + } + + return { + sections, + get, + load, + clearCache, + } }, - persist: true, -}) + { + persist: true, + } +) diff --git a/src/stores/StoryStore.ts b/src/stores/StoryStore.ts index 9c8764a..20eda61 100644 --- a/src/stores/StoryStore.ts +++ b/src/stores/StoryStore.ts @@ -2,23 +2,33 @@ import { defineStore } from 'pinia' import Story from '@/models/Story' -export const useStoryStore = defineStore('StoryStore', { - state: () => ({ - stories: {} as Record, - }), +export const useStoryStore = defineStore( + 'StoryStore', + () => { + const stories = ref>({}) - actions: { - get(id: string) { - if (id in this.stories) { - return this.stories[id] + function get(id: string) { + if (id in stories.value) { + return stories.value[id] } - }, - async load(id: string) { - return (this.stories[id] = await Story.load(id)) - }, - clearCache() { - this.stories = {} - }, + } + + async function load(id: string) { + return (stories.value[id] = await Story.load(id)) + } + + function clearCache() { + stories.value = {} + } + + return { + stories, + get, + load, + clearCache, + } }, - persist: true, -}) + { + persist: true, + } +) From 19e7083bad2aca5b67cc74b5f56da65248a975e0 Mon Sep 17 00:00:00 2001 From: mayoforkovic Date: Tue, 31 Oct 2023 18:22:23 +0100 Subject: [PATCH 6/7] feedback & some more cleanup --- src/App.vue | 2 +- src/components/about/About.vue | 10 +++++----- src/components/forms/StoryButton.vue | 6 +----- src/components/interactions/InteractionStory.vue | 4 ++-- src/components/misc/HistoryBack.vue | 2 +- src/stores/HistoryStore.ts | 4 ++-- src/stores/InteractionStore.ts | 4 ++-- 7 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/App.vue b/src/App.vue index 4416ca1..65bd299 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,7 +4,7 @@