diff options
-rw-r--r-- | src/App.vue | 23 | ||||
-rw-r--r-- | src/components/EditPage.vue | 183 |
2 files changed, 203 insertions, 3 deletions
diff --git a/src/App.vue b/src/App.vue index 80e462e..ddccf26 100644 --- a/src/App.vue +++ b/src/App.vue @@ -6,11 +6,13 @@ prepend-icon="mdi-home" title="Home" value="home" + @click="atHome = true" ></v-list-item> <v-list-item prepend-icon="mdi-pencil" title="Edit" value="edit" + @click="atHome = false" ></v-list-item> <v-list-item prepend-icon="mdi-theme-light-dark" @@ -19,9 +21,17 @@ @click="toggleTheme" ></v-list-item> </v-list ></v-navigation-drawer> + <v-snackbar color="grey" v-model="snackbar"> + {{ snackbarText }} + + <template v-slot:actions> + <v-btn variant="snackbarText" @click="snackbar = false"> Close </v-btn> + </template> + </v-snackbar> <v-main> - <v-container> - <HomePage class="float-end w-50" /> + <v-container class="float-end w-50"> + <HomePage v-if="atHome == true" /> + <EditPage v-else @snackbar-notification="setSnackbarText" /> </v-container> </v-main> </v-app> @@ -30,18 +40,21 @@ <script> import { useTheme } from "vuetify"; import HomePage from "./components/HomePage.vue"; +import EditPage from "./components/EditPage.vue"; export default { name: "App", components: { HomePage, + EditPage, }, data: () => ({ drawer: null, + atHome: true, snackbar: false, - snackbarColor: "black", + snackbarText: "Default snackbar text (End-user shouldn't see this)", bg: { backgroundColor: "grey", // backgroundImage: "url(https://wallpapercave.com/wp/wp9649930.jpg)", @@ -65,6 +78,10 @@ export default { toggleDrawer() { this.drawer = !this.drawer; }, + setSnackbarText(text) { + this.snackbarText = text; + this.snackbar = true; + }, }, }; </script> diff --git a/src/components/EditPage.vue b/src/components/EditPage.vue new file mode 100644 index 0000000..ea47926 --- /dev/null +++ b/src/components/EditPage.vue @@ -0,0 +1,183 @@ +<template> + <v-switch + v-model="switchModel" + label="I want to create a new SubCard" + ></v-switch> + + <v-form v-show="switchModel" lazy-validate ref="form1" v-model="valid1"> + <v-text-field + v-model="title" + :counter="titleMaxLength" + :rules="titleRules" + label="Title" + required + ></v-text-field> + + <v-textarea + auto-grow + clearable + clear-icon="mdi-close-circle" + outlined + name="textarea" + label="Content" + v-model="content" + :rules="contentRules" + required + ></v-textarea> + + <v-btn + :disabled="!valid1" + variant="outlined" + class="mr-4" + @click=" + validate(this.$refs.form1); + write(this.$refs.form1); + " + > + Save + </v-btn> + + <v-btn variant="outlined" class="mr-4" @click="reset(this.$refs.form1)"> + Reset Form + </v-btn> + </v-form> + + <v-form v-show="!switchModel" lazy-validate ref="form2" v-model="valid2"> + <v-select + v-model="select" + variant="outlined" + :items="items" + :rules="[(v) => !!v || 'Item is required']" + label="Item" + required + ></v-select> + + <v-textarea + auto-grow + clearable + clear-icon="mdi-close-circle" + outlined + name="textarea" + label="Content" + v-model="content" + :rules="contentRules" + required + ></v-textarea> + + <v-btn + :disabled="!valid2" + variant="outlined" + class="mr-4" + @click=" + validate(this.$refs.form2); + write(this.$refs.form2); + " + > + Save + </v-btn> + + <v-btn variant="outlined" class="mr-4" @click="reset(this.$refs.form2)"> + Reset Validation + </v-btn> + <v-btn variant="outlined" class="mr-4" @click="deleteItem"> + Delete Item + </v-btn> + </v-form> +</template> + +<script> +export default { + name: "EditPage", + + emits: ["snackbarNotification"], + + data: () => ({ + valid1: true, + valid2: true, + title: "", + titleMaxLength: 15, + titleRules: [ + (v) => !!v || "Title is required", + (v) => { + let titleMaxLength = 15; + return ( + (v && v.length <= titleMaxLength) || + `Title must be less than ${titleMaxLength} characters` + ); + }, + ], + content: "", + contentRules: [(v) => !!v || "Content is required"], + select: null, + items: [], + switchModel: false, + LSData: {}, + }), + + mounted() { + this.loadFromLS(); + this.readAllItems(); + }, + + methods: { + validate(form) { + form.validate(); + }, + reset(form) { + // Resets validation of all registered inputs without modifying their state. + // TODO: clearify this (do we need form.reset() ?) + form.resetValidation(); + }, + write(form) { + if (form == this.$refs.form1 && this.title in this.LSData) { + this.$emit("snackbarNotification", "Title already exists"); + return; + } + if (form == this.$refs.form2) { + // Sync LSData(title) with form data + this.title = this.select; + } + this.LSData[this.title] = this.content; + this.writeToLS(); + this.$emit("snackbarNotification", "Done!"); + // Let's do a reset. + this.reset(form); + // Re-read all items. + this.readAllItems(); + }, + readAllItems() { + this.items = []; // Reset items list + for (let key in this.LSData) { + this.items.push(key); + } + }, + deleteItem() { + delete this.LSData[this.select]; + this.writeToLS(); + // Re-read all items. + this.readAllItems(); + this.$emit("snackbarNotification", "Item deleted"); + this.reset(this.$refs.form2); + }, + + // LocalStorage + loadFromLS() { + this.LSData = JSON.parse(localStorage.getItem("LSData")) || this.LSData; + }, + writeToLS() { + localStorage.setItem("LSData", JSON.stringify(this.LSData)); + }, + clearLS() { + localStorage.clear(); + }, + }, + + watch: { + // eslint-disable-next-line no-unused-vars + select(newSelected, _) { + // Load content whenever select changes + this.content = this.LSData[newSelected]; + }, + }, +}; +</script> |