add third party deck support

Co-authored-by: Niko Lockenvitz <nl@nikolockenvitz.de>
This commit is contained in:
Rene Fischer 2020-07-14 16:48:09 +02:00
parent 0fee66d4e2
commit e90f795f5e
No known key found for this signature in database
GPG key ID: 5D8E12AC54D3C1B5
16 changed files with 228 additions and 5 deletions

View file

@ -40,7 +40,7 @@
## Screenshots
<img src="docs/img/deck-selection.png" alt="Deck Selection" width="30%" /> <img src="docs/img/deck-selection-selected.png" alt="Deck Selection - one deck selected" width="30%" /> <img src="docs/img/q-and-a.png" alt="Card" width="30%" /> <img src="docs/img/finish.png" alt="Evaluation after finishing learning" width="30%" /> <img src="docs/img/menu.png" alt="Menu" width="30%" /> <img src="docs/img/import.png" alt="Import" width="30%" />
<img src="docs/img/deck-selection.png" alt="Deck Selection" width="24%" /> <img src="docs/img/deck-selection-selected.png" alt="Deck Selection - one deck selected" width="24%" /> <img src="docs/img/q-and-a.png" alt="Card" width="24%" /> <img src="docs/img/finish.png" alt="Evaluation after finishing learning" width="24%" /> <img src="docs/img/menu.png" alt="Menu" width="24%" /> <img src="docs/img/import.png" alt="Import" width="24%" /> <img src="docs/img/third-party-decks.png" alt="Third Party Decks" width="24%" /> <img src="docs/img/add-decks.png" alt="Successfully add a Deck" width="24%" />
## Deployment
The app is build and deployed to https://fancy-flashcard.github.io/ffc on every push to master branch (via GitHub Actions and GitHub Pages).

BIN
docs/img/add-decks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -2,6 +2,7 @@
<div class="settings">
<v-container fluid>
<v-row>
<ThirdPartyDeckCard />
<ImportDeckFromURL />
<ImportDeckFromFile />
<DeckCreator />
@ -16,12 +17,14 @@ import Component from "vue-class-component";
import ImportDeckFromURL from "./ImportDeckFromURL.vue";
import ImportDeckFromFile from "./ImportDeckFromFile.vue";
import ThirdPartyDeckCard from "./ThirdPartyDeckCard.vue"
import DeckCreator from "./DeckCreator.vue";
@Component({
components: {
ImportDeckFromURL,
ImportDeckFromFile,
ThirdPartyDeckCard,
DeckCreator
}
})

View file

@ -28,8 +28,7 @@ import Component from "vue-class-component";
@Component
export default class ImportDeckFromURL extends Vue {
chosenURL =
"https://raw.githubusercontent.com/fancy-flashcard/ffc/master/cli/test.json";
chosenURL = "";
fileContent = "";
urlRules = [
(value: string) =>
@ -46,7 +45,7 @@ export default class ImportDeckFromURL extends Vue {
// TODO: cors?!
this.$eventHub.$emit(
"snackbarEvent",
"An Error Occurred While Loading The File"
"An error occurred while loading the file"
);
}
}

View file

@ -0,0 +1,40 @@
<template>
<v-col cols="12" sm="12" md="6" lg="4" xl="4">
<v-card height="100%" raised>
<v-card-title>Third Party Decks</v-card-title>
<v-card-text>
Import decks created by others here.
You can add decks here as well, just checkout our GitHub repository.
</v-card-text>
<div class="horizontal-spacer"></div>
<v-card-actions class="button-padding">
<v-spacer></v-spacer>
<v-btn color="indigo" right @click="$router.push('thirdparty')">View Third Party Decks</v-btn>
</v-card-actions>
</v-card>
</v-col>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
@Component
export default class ThirdPartyDecks extends Vue {}
</script>
<style scoped>
#file-input-wrapper {
padding-bottom: 0;
}
.button-padding {
padding: 16px;
}
.v-card {
display: flex;
flex-direction: column;
}
.horizontal-spacer {
flex-grow: 1;
}
</style>

View file

@ -1,9 +1,27 @@
<template>
<v-dialog v-model="showDialog" max-width="400" persistent>
<v-card color="#2e2e2e">
<v-card-title class="headline">{{ options.title }}</v-card-title>
<v-card-title class="headline">
{{ options.title }}
<v-icon v-if="options.type" size="0.9em" color="indigo" class="mx-2">
{{options.type === 'sponsored' ?
'mdi-cash-usd-outline' : options.type === 'curated' ?
'mdi-check-decagram' : options.type === 'official' ?
'mdi-flash-circle' : null}}
</v-icon>
</v-card-title>
<v-card-text v-if="options.message" class="text-left">{{ options.message }}</v-card-text>
<v-card-text v-else-if="options.multipleMessages" class="text-left">
<p
class="multiple-messages"
v-for="message in options.multipleMessages"
:key="message.name"
>
<b>{{message.name}}:</b>
{{message.value}}
</p>
</v-card-text>
<v-list v-if="options.table">
<v-list-item v-if="options.tableHead">
@ -121,4 +139,7 @@ export default class Dialog extends Vue {
text-align: center;
margin: 0 24px;
}
.multiple-messages {
margin-bottom: 0;
}
</style>

View file

@ -9,6 +9,11 @@
"icon": "mdi-plus",
"title": "Add Deck"
},
{
"to": "/thirdparty",
"icon": "mdi-package-variant",
"title": "Third Party Decks"
},
{
"to": "/settings",
"icon": "mdi-cog",

View file

@ -0,0 +1,106 @@
<template>
<div class="ThirdPartyDeckSelection">
<v-subheader>Third Party Decks</v-subheader>
<v-list>
<v-list-item-group @change="onChange" v-model="deckModel">
<v-list-item
v-for="(deck, index) in thirdPartyList"
:key="index"
:value="deck.url"
:id="deck.url"
>
<v-list-item-content>
<v-list-item-title>
{{ deck.name }}
<v-icon size="1em" color="indigo">
{{deck.type === 'sponsored' ?
'mdi-cash-usd-outline' : deck.type === 'curated' ?
'mdi-check-decagram' : deck.type === 'official' ?
'mdi-flash-circle' : null}}
</v-icon>
</v-list-item-title>
</v-list-item-content>
<v-list-item-icon>
<v-btn icon dark @click.stop="onDownload(deck.url)">
<v-icon>mdi-download</v-icon>
</v-btn>
</v-list-item-icon>
</v-list-item>
</v-list-item-group>
</v-list>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import thirdPartyList from "../../../third-party-decks.json";
import { ThirdPartyDeck } from "../../types";
@Component
export default class ThirdPartyDeckSelection extends Vue {
thirdPartyList: ThirdPartyDeck[] = thirdPartyList;
deckModel = null;
onChange() {
const currentURL = this.deckModel;
const currentDeck = thirdPartyList.find(deck => deck.url === currentURL);
const options = {
title: currentDeck?.name,
type: currentDeck?.type,
multipleMessages: [
{
name: "Author",
value: currentDeck?.author
},
{
name: "Description",
value: currentDeck?.desc
},
{
name: "Type",
value: currentDeck?.type
}
],
buttons: [
{
name: "Close",
color: "indigo",
callback: () => {
this.deckModel = null;
}
}
]
};
this.$eventHub.$emit("showCustomDialog", options);
}
async onDownload(url: string) {
try {
const response = await fetch(url);
const fileContent = await response.json();
this.$eventHub.$emit("addDecksFromJSON", fileContent);
} catch (error) {
this.$eventHub.$emit(
"snackbarEvent",
"An error occurred while loading the third party deck"
);
}
this.deckModel = null;
}
}
</script>
<style scoped>
.v-list-item__icon {
margin: 8px;
}
.theme--dark.v-list-item--active:hover::before,
.theme--dark.v-list-item--active::before {
opacity: 0;
}
</style>

View file

@ -69,6 +69,7 @@ function showAddedDecksConfirmation(context: Context, addedDeckAndCards: addedDe
}
const options = {
persistent: false,
title: "Successfully Imported Decks",
message: "Following decks have been added:",
tableHead: { name: "Deck", value: "Number of Cards" },
@ -81,6 +82,10 @@ function showAddedDecksConfirmation(context: Context, addedDeckAndCards: addedDe
buttons: [
{
name: "Close",
color: "grey",
},
{
name: "Go Home",
color: "indigo",
callback: function() {
context.$router.push("/");

View file

@ -22,6 +22,11 @@ const routes: Array<RouteConfig> = [
component: () => import('../views/AddNewDeck.vue'),
props: true,
},
{
path: '/thirdparty',
name: 'Third Party Decks',
component: () => import('../views/ThirdPartyDecks.vue'),
},
{
path: '/settings',
name: 'Settings',

View file

@ -119,3 +119,11 @@ export interface NavBarConfigItem {
icon: string;
title: string;
}
export interface ThirdPartyDeck {
type: string;
name: string;
author: string;
desc: string;
url: string;
}

View file

@ -0,0 +1,22 @@
<template>
<div class="thirdpartydecks">
<ThirdPartyDeckSelection />
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import ThirdPartyDeckSelection from "../components/thirdparty/ThirdPartyDeckSelection.vue";
@Component({
components: {
ThirdPartyDeckSelection
}
})
export default class ThirdPartyDecks extends Vue {}
</script>
<style scoped>
</style>

9
third-party-decks.json Normal file
View file

@ -0,0 +1,9 @@
[
{
"type": "official",
"name": "Official Test Deck",
"author": "Niko Lockenvitz",
"desc": "Example Deck created with FFC CLI",
"url": "https://raw.githubusercontent.com/fancy-flashcard/ffc/master/cli/test.json"
}
]