commit 44fad476d2dfb38a53eaeafe733f5d1c8615d66f Author: Annika Merris Date: Tue Jan 16 17:06:01 2024 -0500 Initial commit... diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..6f40582 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,15 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + 'extends': [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/eslint-config-typescript', + '@vue/eslint-config-prettier/skip-formatting' + ], + parserOptions: { + ecmaVersion: 'latest' + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..66e2335 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none" +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..009a534 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "Vue.volar", + "Vue.vscode-typescript-vue-plugin", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8759d6 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# isl-calc + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types. + +If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps: + +1. Disable the built-in TypeScript Extension + 1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette + 2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)` +2. Reload the VSCode window by running `Developer: Reload Window` from the command palette. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run Unit Tests with [Vitest](https://vitest.dev/) + +```sh +npm run test:unit +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..4053ca7 Binary files /dev/null and b/bun.lockb differ 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 new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..b08cacf --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "isl-calc", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:unit": "vitest", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "axios": "^1.6.5", + "pinia": "^2.1.7", + "sass": "^1.69.7", + "vue": "^3.3.11", + "vue-router": "^4.2.5", + "vuetify": "^3.4.10" + }, + "devDependencies": { + "@mdi/font": "^7.4.47", + "@rushstack/eslint-patch": "^1.3.3", + "@tsconfig/node18": "^18.2.2", + "@types/jsdom": "^21.1.6", + "@types/node": "^18.19.3", + "@vitejs/plugin-vue": "^4.5.2", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/test-utils": "^2.4.3", + "@vue/tsconfig": "^0.5.0", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "jsdom": "^23.0.1", + "npm-run-all2": "^6.1.1", + "prettier": "^3.0.3", + "sass-loader": "^14.0.0", + "typescript": "~5.3.0", + "vite": "^5.0.10", + "vitest": "^1.0.4", + "vue-tsc": "^1.8.25" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/items/blessingPowerItems.json b/public/items/blessingPowerItems.json new file mode 100644 index 0000000..5d9a224 --- /dev/null +++ b/public/items/blessingPowerItems.json @@ -0,0 +1,68 @@ +{ + "d9def40f-6deb-45af-b8d1-d8af8a997b58": { + "iconURL": "", + "itemName": "Flower Necklace", + "minItemPower": 1, + "maxItemPower": 1 + }, + "facb5102-34d8-4813-ab06-ac2b8e9f3ed9": { + "iconURL": "", + "itemName": "Jewel Necklace", + "minItemPower": 2, + "maxItemPower": 2 + }, + "ddd29671-ca7f-4132-8784-80346e154059": { + "iconURL": "", + "itemName": "Blessing Power Cachapon", + "minItemPower": 10, + "maxItemPower": 30 + }, + "c1e029ff-b82c-48bd-a1f1-ea6291fad948": { + "iconURL": "", + "itemName": "Mandrake", + "minItemPower": 1, + "maxItemPower": 3 + }, + "52cd4a48-ff8a-4493-8030-b4e7754cd227": { + "iconURL": "", + "itemName": "Muddled Mushroom", + "minItemPower": 2, + "maxItemPower": 5 + }, + "636b7384-1389-4012-933c-9063baa7a38d": { + "iconURL": "", + "itemName": "Grassy Bunny", + "minItemPower": 3, + "maxItemPower": 6 + }, + "2563b5f8-8fd5-4795-af86-33200605cf3e": { + "iconURL": "", + "itemName": "Chirping Chick", + "minItemPower": 4, + "maxItemPower": 10 + }, + "54e9bcf5-f1a5-4350-a75d-88af02b4fc13": { + "iconURL": "", + "itemName": "Gorgeous Horse", + "minItemPower": 5, + "maxItemPower": 16 + }, + "e736d2b9-a8ec-4a4e-a721-24880c8a6038": { + "iconURL": "", + "itemName": "Blooming Fox", + "minItemPower": 7, + "maxItemPower": 24 + }, + "9fb7f9ba-e7ed-4e99-b161-386f48299443": { + "iconURL": "", + "itemName": "Frozen Dragon", + "minItemPower": 10, + "maxItemPower": 32 + }, + "e2472929-1218-4cd6-a73b-b783c17bbc31": { + "iconURL": "", + "itemName": "Flaming Lion", + "minItemPower": -1, + "maxItemPower": 0 + } +} \ No newline at end of file diff --git a/public/items/fellowPowerItems.json b/public/items/fellowPowerItems.json new file mode 100644 index 0000000..4c41ca8 --- /dev/null +++ b/public/items/fellowPowerItems.json @@ -0,0 +1,92 @@ +{ + "1f7aff96-030d-4007-9a70-82db7a8be3e3": { + "iconURL": "", + "itemName": "Contestant Portrait", + "minItemPower": 15000, + "maxItemPower": 40000 + }, + "2006c92e-8e32-4c9f-a913-3b2d1ed8dea0": { + "iconURL": "", + "itemName": "Potion of Bravery", + "minItemPower": 800, + "maxItemPower": 800 + }, + "30d05d98-a615-4e3a-94da-8aa6e4ad03a9": { + "iconURL": "", + "itemName": "Basic Elixir", + "minItemPower": 3000, + "maxItemPower": 3000 + }, + "3eccaaac-5afe-415a-ac8f-55df213cf015": { + "iconURL": "", + "itemName": "Potion of Freedom", + "minItemPower": 800, + "maxItemPower": 800 + }, + "68a7a68a-2123-4a8e-b64d-9dbdf0637521": { + "iconURL": "", + "itemName": "Potion of Erudition", + "minItemPower": 800, + "maxItemPower": 800 + }, + "7075da2f-a617-42a1-b142-fe2401ad87ec": { + "iconURL": "", + "itemName": "Potion of Inspiration", + "minItemPower": 800, + "maxItemPower": 800 + }, + "762a2775-ca50-4c13-8797-2f03b045ed10": { + "iconURL": "", + "itemName": "Red Contestant Portrait", + "minItemPower": 10000, + "maxItemPower": 25000 + }, + "9c95396d-e5d8-4f7d-9d37-1469e7dc0ee1": { + "iconURL": "", + "itemName": "Yellow Signed Towel", + "minItemPower": 4500, + "maxItemPower": 10000 + }, + "a351a27b-765b-46b5-95fc-99c47e63176d": { + "iconURL": "", + "itemName": "Potion of Diligence", + "minItemPower": 800, + "maxItemPower": 800 + }, + "a44b763b-833b-49d0-91d6-e5fcb8c6ce7c": { + "iconURL": "", + "itemName": "Yellow Signed Handkerchief", + "minItemPower": 2000, + "maxItemPower": 5000 + }, + "bc5fc5c6-65e1-41c8-822d-d6e06ec0894e": { + "iconURL": "", + "itemName": "Advanced Elixir", + "minItemPower": 30000, + "maxItemPower": 30000 + }, + "cd50f711-36a4-4b3b-b4ef-84b52c8a18e2": { + "iconURL": "", + "itemName": "Champion's Statue", + "minItemPower": 30000, + "maxItemPower": 80000 + }, + "ce522371-80bd-4266-b473-8f5ace7099c7": { + "iconURL": "", + "itemName": "Red Signed Handkerchief", + "minItemPower": 3000, + "maxItemPower": 8000 + }, + "d7d705d3-9562-4f03-98d8-3b0da81fcf47": { + "iconURL": "", + "itemName": "Champion's Belt", + "minItemPower": 20000, + "maxItemPower": 50000 + }, + "ed1663c2-aff0-41b4-b5ed-7f86463c1d69": { + "iconURL": "", + "itemName": "Red Signed Towel", + "minItemPower": 6000, + "maxItemPower": 15000 + } +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..f7d5fa9 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/assets/base.css b/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/src/assets/main.css b/src/assets/main.css new file mode 100644 index 0000000..1e37676 --- /dev/null +++ b/src/assets/main.css @@ -0,0 +1,31 @@ +@import './base.css'; + +#app { + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + place-items: center; + } + + #app { + padding: 0 2rem; + } +} diff --git a/src/components/BlessingPower/SpecialItemsCard.vue b/src/components/BlessingPower/SpecialItemsCard.vue new file mode 100644 index 0000000..03a4ccd --- /dev/null +++ b/src/components/BlessingPower/SpecialItemsCard.vue @@ -0,0 +1,55 @@ + + + diff --git a/src/components/BlessingPower/StandardItemsCard.vue b/src/components/BlessingPower/StandardItemsCard.vue new file mode 100644 index 0000000..32f068d --- /dev/null +++ b/src/components/BlessingPower/StandardItemsCard.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/components/BlessingPower/SummaryCard.vue b/src/components/BlessingPower/SummaryCard.vue new file mode 100644 index 0000000..0d04677 --- /dev/null +++ b/src/components/BlessingPower/SummaryCard.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/FellowPower/SpecialItemsCard.vue b/src/components/FellowPower/SpecialItemsCard.vue new file mode 100644 index 0000000..2cacf6d --- /dev/null +++ b/src/components/FellowPower/SpecialItemsCard.vue @@ -0,0 +1,55 @@ + + + diff --git a/src/components/FellowPower/StandardItemsCard.vue b/src/components/FellowPower/StandardItemsCard.vue new file mode 100644 index 0000000..dd8a4f6 --- /dev/null +++ b/src/components/FellowPower/StandardItemsCard.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/components/FellowPower/SummaryCard.vue b/src/components/FellowPower/SummaryCard.vue new file mode 100644 index 0000000..8fcd1ea --- /dev/null +++ b/src/components/FellowPower/SummaryCard.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/GlobalHeader.vue b/src/components/GlobalHeader.vue new file mode 100644 index 0000000..35d9861 --- /dev/null +++ b/src/components/GlobalHeader.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/components/SpecialItem.vue b/src/components/SpecialItem.vue new file mode 100644 index 0000000..6396933 --- /dev/null +++ b/src/components/SpecialItem.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/components/StandardItem.vue b/src/components/StandardItem.vue new file mode 100644 index 0000000..a6a002d --- /dev/null +++ b/src/components/StandardItem.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..b645d87 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,30 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router' + +// Vuetify +import 'vuetify/styles' +import '@mdi/font/css/materialdesignicons.css' +import { createVuetify } from 'vuetify' +import * as components from 'vuetify/components' +import * as directives from 'vuetify/directives' + +const vuetify = createVuetify({ + components, + directives, + icons: { + defaultSet: 'mdi', + } +}) + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(vuetify) + +app.mount('#app') diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..65c6ea2 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,25 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: "/blessing-power", + name: "blessing-power", + component: () => import('@/views/BlessingPowerView.vue') + }, + { + path: "/fellow-power", + name: "fellow-power", + component: () => import('@/views/FellowPowerView.vue') + } + ] +}) + +export default router diff --git a/src/stores/counter.ts b/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/src/stores/powerItems.ts b/src/stores/powerItems.ts new file mode 100644 index 0000000..ab902b5 --- /dev/null +++ b/src/stores/powerItems.ts @@ -0,0 +1,241 @@ +import type { PowerItem } from '@/types/PowerItem' +import axios from 'axios' +import { defineStore } from 'pinia' +import { computed, ref, toRaw } from 'vue' + +export const usePowerItems = defineStore('powerItems', () => { + const BLESSING_POWER_ITEM_STORAGE = 'BLESSING_POWER_ITEM_STORAGE' + const FELLOW_POWER_ITEM_STORAGE = 'FELLOW_POWER_ITEM_STORAGE' + const blessingPowerItems = ref(new Map()) + const fellowPowerItems = ref(new Map()) + + async function fetchPowerItems() { + axios + .get('/items/blessingPowerItems.json') + .then((resp) => { + const plainMap = new Map( + Object.entries(JSON.parse(localStorage.getItem(BLESSING_POWER_ITEM_STORAGE) || '{}')) + ) + Object.keys(resp.data).map((key) => { + const cur = resp.data[key] + if (cur['owned'] === undefined) cur['owned'] = 0 + cur['owned'] = plainMap.get(key) !== undefined ? plainMap.get(key)?.owned : 0 + blessingPowerItems.value.set(key, resp.data[key]) + }) + }) + .catch((err) => { + console.log(err) + }) + axios + .get('/items/fellowPowerItems.json') + .then((resp) => { + const plainMap = new Map( + Object.entries(JSON.parse(localStorage.getItem(FELLOW_POWER_ITEM_STORAGE) || '{}')) + ) + Object.keys(resp.data).map((key) => { + const cur = resp.data[key] + if (cur['owned'] === undefined) cur['owned'] = 0 + cur['owned'] = plainMap.get(key) !== undefined ? plainMap.get(key)?.owned : 0 + fellowPowerItems.value.set(key, resp.data[key]) + }) + }) + .catch((err) => { + console.log(err) + }) + } + + function updateOwned(key: string, newOwned: number) { + let cur = blessingPowerItems.value.get(key) + if (cur !== undefined) { + cur.owned = newOwned + blessingPowerItems.value.set(key, cur) + localStorage.setItem( + BLESSING_POWER_ITEM_STORAGE, + JSON.stringify(mapToObj(toRaw(blessingPowerItems.value))) + ) + return + } + cur = fellowPowerItems.value.get(key) + if (cur !== undefined) { + cur.owned = newOwned + fellowPowerItems.value.set(key, cur) + localStorage.setItem( + FELLOW_POWER_ITEM_STORAGE, + JSON.stringify(mapToObj(toRaw(fellowPowerItems.value))) + ) + } + } + + function mapToObj(map: Map) { + return Array.from(map).reduce((obj, [key, value]) => { + // Doing weird magic to work with maps is infuriating, and I haven't found a better solution for this. + // So ignore that error TypeScript, I (don't) know what I'm doing! + // @ts-ignore: noImplicitAny + obj[key] = value + return obj + }, {}) + } + + const totalBlessingPower = computed(() => + [...blessingPowerItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => { + return currentValue !== undefined + ? accumulator + + ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned + : 0 + }, + 0 + ) + ) + + const standardBlessingItems = computed( + () => + new Map( + [...blessingPowerItems.value.entries()].filter( + (cur) => cur[1].maxItemPower === cur[1].minItemPower + ) + ) + ) + + const standardBlessingItemTotal = computed(() => + [...standardBlessingItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + + ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned + : 0, + 0 + ) + ) + + const specialBlessingItems = computed( + () => + new Map( + [...blessingPowerItems.value.entries()].filter( + (cur) => cur[1].maxItemPower !== cur[1].minItemPower + ) + ) + ) + + const specialBlessingItemsMinTotal = computed(() => + [...specialBlessingItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + currentValue.minItemPower * currentValue.owned + : 0, + 0 + ) + ) + + const specialBlessingItemsMaxTotal = computed(() => + [...specialBlessingItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + currentValue.maxItemPower * currentValue.owned + : 0, + 0 + ) + ) + + const specialBlessingItemsAveTotal = computed(() => + [...specialBlessingItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + + ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned + : 0, + 0 + ) + ) + + const totalFellowPower = computed(() => + [...fellowPowerItems.value.values()].reduce((accumulator: number, currentValue: PowerItem) => { + return currentValue !== undefined + ? accumulator + + ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned + : 0 + }, 0) + ) + + const standardFellowItems = computed( + () => + new Map( + [...fellowPowerItems.value.entries()].filter( + (cur) => cur[1].maxItemPower === cur[1].minItemPower + ) + ) + ) + + const standardFellowItemTotal = computed(() => + [...standardFellowItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + + ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned + : 0, + 0 + ) + ) + + const specialFellowItems = computed( + () => + new Map( + [...fellowPowerItems.value.entries()].filter( + (cur) => cur[1].maxItemPower !== cur[1].minItemPower + ) + ) + ) + + const specialFellowItemsMinTotal = computed(() => + [...specialFellowItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + currentValue.minItemPower * currentValue.owned + : 0, + 0 + ) + ) + + const specialFellowItemsMaxTotal = computed(() => + [...specialFellowItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + currentValue.maxItemPower * currentValue.owned + : 0, + 0 + ) + ) + + const specialFellowItemsAveTotal = computed(() => + [...specialFellowItems.value.values()].reduce( + (accumulator: number, currentValue: PowerItem) => + currentValue !== undefined + ? accumulator + + ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned + : 0, + 0 + ) + ) + + fetchPowerItems() + + return { + blessingPowerItems, + fetchPowerItems, + updateOwned, + totalBlessingPower, + standardBlessingItems, + standardBlessingItemTotal, + specialBlessingItems, + specialBlessingItemsMinTotal, + specialBlessingItemsMaxTotal, + specialBlessingItemsAveTotal, + totalFellowPower, + standardFellowItems, + standardFellowItemTotal, + specialFellowItems, + specialFellowItemsMinTotal, + specialFellowItemsMaxTotal, + specialFellowItemsAveTotal + } +}) diff --git a/src/styles/settings.scss b/src/styles/settings.scss new file mode 100644 index 0000000..2021dde --- /dev/null +++ b/src/styles/settings.scss @@ -0,0 +1 @@ +@forward 'vuetify/settings'; diff --git a/src/types/PowerItem.ts b/src/types/PowerItem.ts new file mode 100644 index 0000000..89f2b4e --- /dev/null +++ b/src/types/PowerItem.ts @@ -0,0 +1,7 @@ +export type PowerItem = { + iconURL: string + itemName: string + minItemPower: number + maxItemPower: number + owned: number +} diff --git a/src/views/BlessingPowerView.vue b/src/views/BlessingPowerView.vue new file mode 100644 index 0000000..8ec1eaa --- /dev/null +++ b/src/views/BlessingPowerView.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/views/FellowPowerView.vue b/src/views/FellowPowerView.vue new file mode 100644 index 0000000..a0d58a6 --- /dev/null +++ b/src/views/FellowPowerView.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue new file mode 100644 index 0000000..2d55feb --- /dev/null +++ b/src/views/HomeView.vue @@ -0,0 +1,11 @@ + + + diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..491e093 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,13 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "noEmit": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..100cf6a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..46cf2e1 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,17 @@ +{ + "extends": "@tsconfig/node18/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/tsconfig.vitest.json b/tsconfig.vitest.json new file mode 100644 index 0000000..d080d61 --- /dev/null +++ b/tsconfig.vitest.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.app.json", + "exclude": [], + "compilerOptions": { + "composite": true, + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..10067d5 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url' +import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' +import viteConfig from './vite.config' + +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + environment: 'jsdom', + exclude: [...configDefaults.exclude, 'e2e/*'], + root: fileURLToPath(new URL('./', import.meta.url)) + } + }) +)