diff --git a/package.json b/package.json index 4dfd19d..fee1c7c 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,14 @@ "dependencies": { "buefy": "^0.8.2", "core-js": "^2.6.5", + "idb": "^4.0.4", "register-service-worker": "^1.6.2", "vue": "^2.6.10", "vue-class-component": "^7.0.2", "vue-property-decorator": "^8.1.0", "vue-router": "^3.0.3", - "vuex": "^3.0.1" + "vuex": "^3.0.1", + "vuex-class": "^0.3.2" }, "devDependencies": { "@vue/cli-plugin-babel": "^3.11.0", diff --git a/src/App.vue b/src/App.vue index e086ec2..60f68c6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,16 +1,33 @@ - diff --git a/src/assets/scss/app.scss b/src/assets/scss/app.scss index a378a0f..04c592c 100644 --- a/src/assets/scss/app.scss +++ b/src/assets/scss/app.scss @@ -3,4 +3,13 @@ @import "variables"; @import "~bulma/sass/utilities/derived-variables"; @import "~bulma"; -@import "~buefy/src/scss/buefy"; \ No newline at end of file +@import "~buefy/src/scss/buefy"; + +html { + scrollbar-color: #404245 #2f3132; + background-color: #2a2c2e; +} + +body { + color: white; +} \ No newline at end of file diff --git a/src/mlpccg/card.ts b/src/mlpccg/card.ts new file mode 100644 index 0000000..00966da --- /dev/null +++ b/src/mlpccg/card.ts @@ -0,0 +1,5 @@ +const imgBaseURL = "https://mcg.zyg.ovh/images/cards/"; + +export function cardImageURL(cardid: string): string { + return `${imgBaseURL}${cardid}.webp`; +} diff --git a/src/mlpccg/database.ts b/src/mlpccg/database.ts new file mode 100644 index 0000000..7ca0a86 --- /dev/null +++ b/src/mlpccg/database.ts @@ -0,0 +1,35 @@ +import { DBSchema, openDB } from "idb"; +import { Card } from "./types"; + +interface CardDB extends DBSchema { + card: { + key: string; + value: Card; + indexes: { + "by-set": string; + "by-element": string[]; + "by-type": string; + "by-cost": number; + "by-power": number; + "by-rarity": string; + }; + }; +} + +const cardDBName = "card-db"; + +export async function openCardDB() { + return await openDB(cardDBName, 1, { + upgrade(db) { + const cardStore = db.createObjectStore("card", { + keyPath: "ID" + }); + cardStore.createIndex("by-set", "Set"); + cardStore.createIndex("by-element", "Element"); + cardStore.createIndex("by-type", "Type"); + cardStore.createIndex("by-cost", "Cost"); + cardStore.createIndex("by-power", "Power"); + cardStore.createIndex("by-rarity", "Rarity"); + } + }); +} diff --git a/src/mlpccg/set.ts b/src/mlpccg/set.ts new file mode 100644 index 0000000..1609c17 --- /dev/null +++ b/src/mlpccg/set.ts @@ -0,0 +1,47 @@ +import { SetFile } from "./types"; +import { openCardDB } from "./database"; + +const baseURL = "https://mcg.zyg.ovh/setdata/"; +const allSets = [ + "PR", + "CN", + "RR", + "CS", + "CG", + "AD", + "EO", + "HM", + "MT", + "DE", + "SB", + "FF", + "Promo" +]; + +export async function loadSets() { + const db = await openCardDB(); + const itemcount = await db.count("card"); + if (itemcount > 100) { + // DB already filled, exit early + return; + } + const sets = await Promise.all(allSets.map(set => downloadSet(set))); + await Promise.all( + sets.map( + async set => + await Promise.all( + set.Cards.map(async card => await db.put("card", card)) + ) + ) + ); +} + +async function downloadSet(setid: string): Promise { + const setfile = await fetch(`${baseURL}${setid.toLowerCase()}.json`); + const setdata: SetFile = await setfile.json(); + setdata.Cards = setdata.Cards.map(c => { + c.Set = setid; + return c; + }); + return setdata; +} diff --git a/src/mlpccg/types.ts b/src/mlpccg/types.ts new file mode 100644 index 0000000..e879ba6 --- /dev/null +++ b/src/mlpccg/types.ts @@ -0,0 +1,28 @@ +export type Rarity = "C" | "U" | "R" | "SR" | "UR" | "RR"; + +export type PowerRequirement = { [key: string]: number }; + +export interface SetFile { + Name: string; + Cards: Card[]; +} + +export interface Card { + ID: string; + Set: string; + Name: string; + Subname: string; + Element: string[]; + Keywords: string[]; + Traits: string[]; + Requirement?: PowerRequirement; + Cost?: number; + Power?: number; + Type: string; + Text: string; + Rarity: Rarity; + ProblemBonus?: number; + ProblemOpponentPower?: number; + ProblemRequirement?: PowerRequirement; + Boosted?: Card; +} diff --git a/src/store/actions.ts b/src/store/actions.ts new file mode 100644 index 0000000..bc6cf05 --- /dev/null +++ b/src/store/actions.ts @@ -0,0 +1,18 @@ +import { ActionTree } from "vuex"; +import { AppState } from "./types"; + +const actions: ActionTree = { + showLoading({ commit }, message: string) { + commit("setLoading", message); + }, + + hideLoading({ commit }) { + commit("setLoading", ""); + }, + + setLoaded({ commit }, loaded: boolean) { + commit("setLoaded", loaded); + } +}; + +export default actions; diff --git a/src/store/getters.ts b/src/store/getters.ts new file mode 100644 index 0000000..b171a4e --- /dev/null +++ b/src/store/getters.ts @@ -0,0 +1,17 @@ +import { GetterTree } from "vuex"; +import { AppState } from "./types"; + +const getters: GetterTree = { + loaded(state): boolean { + return state.loaded; + }, + + loading(state): string | null { + if (state.loading) { + return state.loadingMessage; + } + return null; + } +}; + +export default getters; diff --git a/src/store/index.ts b/src/store/index.ts index 7273841..4909137 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -4,8 +4,19 @@ import { AppState } from "./types"; Vue.use(Vuex); +import actions from "./actions"; +import mutations from "./mutations"; +import getters from "./getters"; + const store: StoreOptions = { - state: {}, + state: { + loaded: false, + loading: false, + loadingMessage: "" + }, + actions, + mutations, + getters, modules: {} }; diff --git a/src/store/mutations.ts b/src/store/mutations.ts new file mode 100644 index 0000000..c0473e7 --- /dev/null +++ b/src/store/mutations.ts @@ -0,0 +1,15 @@ +import { MutationTree } from "vuex"; +import { AppState } from "./types"; + +const mutations: MutationTree = { + setLoaded(state, loaded: boolean) { + state.loaded = loaded; + }, + + setLoading(state, message: string) { + state.loading = message != ""; + state.loadingMessage = message; + } +}; + +export default mutations; diff --git a/src/store/types.ts b/src/store/types.ts index 06e2c2e..04230b8 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -1 +1,5 @@ -export interface AppState {} +export interface AppState { + loaded: boolean; + loading: boolean; + loadingMessage: string; +} diff --git a/yarn.lock b/yarn.lock index 26cd863..7b5d3c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4453,6 +4453,11 @@ icss-utils@^2.1.0: dependencies: postcss "^6.0.1" +idb@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/idb/-/idb-4.0.4.tgz#f0c06f58bd78fe557e4de944fd6ba6a3240faa8e" + integrity sha512-ZYsaBSNub2yAnjvmRKudQlMIPqZQIefAOwNIPeXC+RLIeXYFc0UNQqONKNuQeBNf8oBOV5L75yJ9zFISjHVj4g== + ieee754@^1.1.4: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" @@ -8814,6 +8819,11 @@ vue@^2.6.10: resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== +vuex-class@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/vuex-class/-/vuex-class-0.3.2.tgz#c7e96a076c1682137d4d23a8dcfdc63f220e17a8" + integrity sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ== + vuex@^3.0.1: version "3.1.1" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e"