Add code for loading sets and saving them locally

This commit is contained in:
Hamcha 2019-09-03 15:19:48 +02:00
parent 19f2e16c41
commit 2677a51872
Signed by: hamcha
GPG key ID: 44AD3571EB09A39E
13 changed files with 243 additions and 7 deletions

View file

@ -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",

View file

@ -1,16 +1,33 @@
<template>
<main>
<main v-if="loaded">
<TopBar v-if="!isFullscreen" />
<router-view />
</main>
<main class="loading-box" v-else>
<h1 class="loading-message" v-if="loading">{{ loading }}</h1>
</main>
</template>
<style lang="scss">
<style lang="scss" scoped>
main.loading-box {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
h1.loading-message {
flex: 1;
text-align: center;
}
</style>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import TopBar from "./components/Navigation/TopBar.vue";
import { Action, Getter } from "vuex-class";
import TopBar from "@/components/Navigation/TopBar.vue";
import { loadSets } from "@/mlpccg/set";
import { AppState } from "./store/types";
@Component({
components: {
@ -18,8 +35,26 @@ import TopBar from "./components/Navigation/TopBar.vue";
}
})
export default class App extends Vue {
@Action showLoading!: (msg: string) => void;
@Action hideLoading!: () => void;
@Action setLoaded!: (loaded: boolean) => void;
@Getter loaded!: boolean;
@Getter loading!: string | null;
private get isFullscreen(): boolean {
return this.$route.meta && this.$route.meta.fullscreen;
}
private mounted() {
// Load all sets
this.loadCards();
}
private async loadCards() {
this.showLoading("Downloading data for all sets");
await loadSets();
this.hideLoading();
this.setLoaded(true);
}
}
</script>

View file

@ -4,3 +4,12 @@
@import "~bulma/sass/utilities/derived-variables";
@import "~bulma";
@import "~buefy/src/scss/buefy";
html {
scrollbar-color: #404245 #2f3132;
background-color: #2a2c2e;
}
body {
color: white;
}

5
src/mlpccg/card.ts Normal file
View file

@ -0,0 +1,5 @@
const imgBaseURL = "https://mcg.zyg.ovh/images/cards/";
export function cardImageURL(cardid: string): string {
return `${imgBaseURL}${cardid}.webp`;
}

35
src/mlpccg/database.ts Normal file
View file

@ -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<CardDB>(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");
}
});
}

47
src/mlpccg/set.ts Normal file
View file

@ -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<SetFile> {
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;
}

28
src/mlpccg/types.ts Normal file
View file

@ -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;
}

18
src/store/actions.ts Normal file
View file

@ -0,0 +1,18 @@
import { ActionTree } from "vuex";
import { AppState } from "./types";
const actions: ActionTree<AppState, AppState> = {
showLoading({ commit }, message: string) {
commit("setLoading", message);
},
hideLoading({ commit }) {
commit("setLoading", "");
},
setLoaded({ commit }, loaded: boolean) {
commit("setLoaded", loaded);
}
};
export default actions;

17
src/store/getters.ts Normal file
View file

@ -0,0 +1,17 @@
import { GetterTree } from "vuex";
import { AppState } from "./types";
const getters: GetterTree<AppState, AppState> = {
loaded(state): boolean {
return state.loaded;
},
loading(state): string | null {
if (state.loading) {
return state.loadingMessage;
}
return null;
}
};
export default getters;

View file

@ -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<AppState> = {
state: {},
state: {
loaded: false,
loading: false,
loadingMessage: ""
},
actions,
mutations,
getters,
modules: {}
};

15
src/store/mutations.ts Normal file
View file

@ -0,0 +1,15 @@
import { MutationTree } from "vuex";
import { AppState } from "./types";
const mutations: MutationTree<AppState> = {
setLoaded(state, loaded: boolean) {
state.loaded = loaded;
},
setLoading(state, message: string) {
state.loading = message != "";
state.loadingMessage = message;
}
};
export default mutations;

View file

@ -1 +1,5 @@
export interface AppState {}
export interface AppState {
loaded: boolean;
loading: boolean;
loadingMessage: string;
}

View file

@ -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"