Quellcode durchsuchen

Added modular and reusable Modal system

theflametrooper vor 8 Jahren
Ursprung
Commit
6388837929

+ 42 - 47
frontend/components/Modals/AddSongToQueue.vue

@@ -1,56 +1,50 @@
 <template>
-	<div class="modal is-active">
-		<div class="modal-background"></div>
-		<div class="modal-card">
-			<header class="modal-card-head">
-				<p class="modal-card-title">Add Songs to Station</p>
-				<button class="delete" @click="$parent.modals.addSongToQueue = !$parent.modals.addSongToQueue" ></button>
-			</header>
-			<section class="modal-card-body">
-				<aside class='menu' v-if='$parent.$parent.loggedIn && $parent.type === "community"'>
-					<ul class='menu-list'>
-						<li v-for='playlist in playlists' track-by='$index'>
-							<a href='#' target='_blank' @click='$parent.editPlaylist(playlist._id)'>{{ playlist.displayName }}</a>
-							<div class='controls'>
-								<a href='#' @click='selectPlaylist(playlist._id)' v-if="!isPlaylistSelected(playlist._id)"><i class='material-icons'>panorama_fish_eye</i></a>
-								<a href='#' @click='unSelectPlaylist()' v-if="isPlaylistSelected(playlist._id)"><i class='material-icons'>lens</i></a>
-							</div>
-						</li>
-					</ul>
-					<br />
-				</aside>
-				<div class="control is-grouped">
-					<p class="control is-expanded">
-						<input class="input" type="text" placeholder="YouTube Query" v-model='querySearch' autofocus @keyup.enter='submitQuery()'>
-					</p>
-					<p class="control">
-						<a class="button is-info" @click="submitQuery()" href='#'>
-							Search
+	<modal title='Add Song To Queue'>
+		<div slot='body'>
+			<aside class='menu' v-if='$parent.$parent.loggedIn && $parent.type === "community"'>
+				<ul class='menu-list'>
+					<li v-for='playlist in playlists' track-by='$index'>
+						<a href='#' target='_blank' @click='$parent.editPlaylist(playlist._id)'>{{ playlist.displayName }}</a>
+						<div class='controls'>
+							<a href='#' @click='selectPlaylist(playlist._id)' v-if="!isPlaylistSelected(playlist._id)"><i class='material-icons'>panorama_fish_eye</i></a>
+							<a href='#' @click='unSelectPlaylist()' v-if="isPlaylistSelected(playlist._id)"><i class='material-icons'>lens</i></a>
+						</div>
+					</li>
+				</ul>
+				<br />
+			</aside>
+			<div class="control is-grouped">
+				<p class="control is-expanded">
+					<input class="input" type="text" placeholder="YouTube Query" v-model='querySearch' autofocus @keyup.enter='submitQuery()'>
+				</p>
+				<p class="control">
+					<a class="button is-info" @click="submitQuery()" href='#'>
+						Search
+					</a>
+				</p>
+			</div>
+			<table class="table">
+				<tbody>
+				<tr v-for="result in queryResults">
+					<td>
+						<img :src="result.thumbnail" />
+					</td>
+					<td>{{ result.title }}</td>
+					<td>
+						<a class="button is-success" @click="addSongToQueue(result.id)" href='#'>
+							Add
 						</a>
-					</p>
-				</div>
-				<table class="table">
-					<tbody>
-						<tr v-for="result in queryResults">
-							<td>
-								<img :src="result.thumbnail" />
-							</td>
-							<td>{{ result.title }}</td>
-							<td>
-								<a class="button is-success" @click="addSongToQueue(result.id)" href='#'>
-									Add
-								</a>
-							</td>
-						</tr>
-					</tbody>
-				</table>
-			</section>
+					</td>
+				</tr>
+				</tbody>
+			</table>
 		</div>
-	</div>
+	</modal>
 </template>
 
 <script>
 	import { Toast } from 'vue-roaster';
+	import Modal from './Modal.vue';
 	import io from '../../io';
 	import auth from '../../auth';
 
@@ -137,7 +131,8 @@
 			closeModal: function () {
 				this.$parent.modals.addSongToQueue = !this.$parent.modals.addSongToQueue;
 			}
-		}
+		},
+		components: { Modal }
 	}
 </script>
 

+ 43 - 49
frontend/components/Modals/EditStation.vue

@@ -1,33 +1,27 @@
 <template>
-	<div class='modal is-active'>
-		<div class='modal-background'></div>
-		<div class='modal-card'>
-			<header class='modal-card-head'>
-				<p class='modal-card-title'>Edit station</p>
-				<button class='delete' @click='$parent.modals.editStation = !$parent.modals.editStation'></button>
-			</header>
-			<section class='modal-card-body'>
-				<label class='label'>Display name</label>
-				<div class='control is-grouped'>
-					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Station Display Name' v-model='data.displayName' autofocus>
-					</p>
-					<p class='control'>
-						<a class='button is-info' @click='updateDisplayName()' href='#'>Update</a>
-					</p>
-				</div>
-				<label class='label'>Description</label>
-				<div class='control is-grouped'>
-					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Station Display Name' v-model='data.description'>
-					</p>
-					<p class='control'>
-						<a class='button is-info' @click='updateDescription()' href='#'>Update</a>
-					</p>
-				</div>
-				<label class='label'>Privacy</label>
-				<div class='control is-grouped'>
-					<p class='control is-expanded'>
+	<modal title='Edit Station'>
+		<div slot='body'>
+			<label class='label'>Display name</label>
+			<div class='control is-grouped'>
+				<p class='control is-expanded'>
+					<input class='input' type='text' placeholder='Station Display Name' v-model='data.displayName' autofocus>
+				</p>
+				<p class='control'>
+					<a class='button is-info' @click='updateDisplayName()' href='#'>Update</a>
+				</p>
+			</div>
+			<label class='label'>Description</label>
+			<div class='control is-grouped'>
+				<p class='control is-expanded'>
+					<input class='input' type='text' placeholder='Station Display Name' v-model='data.description'>
+				</p>
+				<p class='control'>
+					<a class='button is-info' @click='updateDescription()' href='#'>Update</a>
+				</p>
+			</div>
+			<label class='label'>Privacy</label>
+			<div class='control is-grouped'>
+				<p class='control is-expanded'>
 						<span class='select'>
 							<select v-model='data.privacy'>
 								<option :value='"public"'>Public</option>
@@ -35,29 +29,29 @@
 								<option :value='"private"'>Private</option>
 							</select>
 						</span>
-					</p>
-					<p class='control'>
-						<a class='button is-info' @click='updatePrivacy()' href='#'>Update</a>
-					</p>
-				</div>
-				<div class='control is-grouped' v-if="$parent.type === 'community'">
-					<p class="control is-expanded party-mode-outer">
-						<label class="checkbox party-mode-inner">
-							<input type="checkbox" v-model="data.partyMode">
-							&nbsp;Party mode
-						</label>
-					</p>
-					<p class='control'>
-						<a class='button is-info' @click='updatePartyMode()' href='#'>Update</a>
-					</p>
-				</div>
-			</section>
+				</p>
+				<p class='control'>
+					<a class='button is-info' @click='updatePrivacy()' href='#'>Update</a>
+				</p>
+			</div>
+			<div class='control is-grouped' v-if="$parent.type === 'community'">
+				<p class="control is-expanded party-mode-outer">
+					<label class="checkbox party-mode-inner">
+						<input type="checkbox" v-model="data.partyMode">
+						&nbsp;Party mode
+					</label>
+				</p>
+				<p class='control'>
+					<a class='button is-info' @click='updatePartyMode()' href='#'>Update</a>
+				</p>
+			</div>
 		</div>
-	</div>
+	</modal>
 </template>
 
 <script>
 	import { Toast } from 'vue-roaster';
+	import Modal from './Modal.vue';
 	import io from '../../io';
 
 	export default {
@@ -76,7 +70,6 @@
 				this.socket.emit('stations.updateDisplayName', this.data.stationId, this.data.displayName, res => {
 					if (res.status === 'success') {
 						this.$parent.station.displayName = this.data.displayName;
-						return Toast.methods.addToast(res.message, 4000);
 					}
 					Toast.methods.addToast(res.message, 8000);
 				});
@@ -124,7 +117,8 @@
 			closeModal: function() {
 				this.$parent.modals.editStation = !this.$parent.modals.editStation;
 			}
-		}
+		},
+		components: { Modal }
 	}
 </script>
 

+ 37 - 0
frontend/components/Modals/Modal.vue

@@ -0,0 +1,37 @@
+<template>
+	<div class='modal is-active'>
+		<div class='modal-background'></div>
+		<div class='modal-card'>
+			<header class='modal-card-head'>
+				<p class='modal-card-title'>{{ title }}</p>
+				<button class='delete' @click='$parent.$parent.modals[this.type] = !$parent.$parent.modals[this.type]'></button>
+			</header>
+			<section class='modal-card-body'>
+				<slot name='body'></slot>
+			</section>
+			<footer class='modal-card-foot' v-if='_slotContents["footer"] != null'>
+				<slot name='footer'></slot>
+			</footer>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		props: {
+			title: { type: String }
+		},
+		methods: {
+			toCamelCase: str => {
+				return str.toLowerCase()
+					.replace(/[-_]+/g, ' ')
+					.replace(/[^\w\s]/g, '')
+					.replace(/ (.)/g, function($1) { return $1.toUpperCase(); })
+					.replace(/ /g, '');
+			}
+		},
+		ready: function () {
+			this.type = this.toCamelCase(this.title);
+		}
+	}
+</script>

+ 79 - 84
frontend/components/Modals/Report.vue

@@ -1,107 +1,102 @@
 <template>
-	<div class='modal is-active'>
-		<div class='modal-background'></div>
-		<div class='modal-card'>
-			<header class='modal-card-head'>
-				<p class='modal-card-title'>Report</p>
-				<button class='delete' @click='$parent.modals.report = !$parent.modals.report'></button>
-			</header>
-			<section class='modal-card-body'>
-				<div class='columns song-types'>
-					<div class='column song-type' v-if='$parent.previousSong !== null'>
-						<div class='card is-fullwidth' :class="{ 'is-highlight-active': isPreviousSongActive }" @click="highlight('previousSong')">
-							<header class='card-header'>
-								<p class='card-header-title'>
-									Previous Song
-								</p>
-							</header>
-							<div class='card-content'>
-								<article class='media'>
-									<figure class='media-left'>
-										<p class='image is-64x64'>
-											<img :src='$parent.previousSong.thumbnail' onerror='this.src="/assets/notes-transparent.png"'>
+	<modal title='Report'>
+		<div slot='body'>
+			<div class='columns song-types'>
+				<div class='column song-type' v-if='$parent.previousSong !== null'>
+					<div class='card is-fullwidth' :class="{ 'is-highlight-active': isPreviousSongActive }" @click="highlight('previousSong')">
+						<header class='card-header'>
+							<p class='card-header-title'>
+								Previous Song
+							</p>
+						</header>
+						<div class='card-content'>
+							<article class='media'>
+								<figure class='media-left'>
+									<p class='image is-64x64'>
+										<img :src='$parent.previousSong.thumbnail' onerror='this.src="/assets/notes-transparent.png"'>
+									</p>
+								</figure>
+								<div class='media-content'>
+									<div class='content'>
+										<p>
+											<strong>{{ $parent.previousSong.title }}</strong>
+											<br>
+											<small>{{ $parent.previousSong.artists.split(' ,') }}</small>
 										</p>
-									</figure>
-									<div class='media-content'>
-										<div class='content'>
-											<p>
-												<strong>{{ $parent.previousSong.title }}</strong>
-												<br>
-												<small>{{ $parent.previousSong.artists.split(' ,') }}</small>
-											</p>
-										</div>
 									</div>
-								</article>
-							</div>
-							<a @click=highlight('previousSong') href='#' class='absolute-a'></a>
+								</div>
+							</article>
 						</div>
+						<a @click=highlight('previousSong') href='#' class='absolute-a'></a>
 					</div>
-					<div class='column song-type' v-if='$parent.currentSong !== {}'>
-						<div class='card is-fullwidth'  :class="{ 'is-highlight-active': isCurrentSongActive }" @click="highlight('currentSong')">
-							<header class='card-header'>
-								<p class='card-header-title'>
-									Current Song
-								</p>
-							</header>
-							<div class='card-content'>
-								<article class='media'>
-									<figure class='media-left'>
-										<p class='image is-64x64'>
-											<img :src='$parent.currentSong.thumbnail' onerror='this.src="/assets/notes-transparent.png"'>
+				</div>
+				<div class='column song-type' v-if='$parent.currentSong !== {}'>
+					<div class='card is-fullwidth'  :class="{ 'is-highlight-active': isCurrentSongActive }" @click="highlight('currentSong')">
+						<header class='card-header'>
+							<p class='card-header-title'>
+								Current Song
+							</p>
+						</header>
+						<div class='card-content'>
+							<article class='media'>
+								<figure class='media-left'>
+									<p class='image is-64x64'>
+										<img :src='$parent.currentSong.thumbnail' onerror='this.src="/assets/notes-transparent.png"'>
+									</p>
+								</figure>
+								<div class='media-content'>
+									<div class='content'>
+										<p>
+											<strong>{{ $parent.currentSong.title }}</strong>
+											<br>
+											<small>{{ $parent.currentSong.artists.split(' ,') }}</small>
 										</p>
-									</figure>
-									<div class='media-content'>
-										<div class='content'>
-											<p>
-												<strong>{{ $parent.currentSong.title }}</strong>
-												<br>
-												<small>{{ $parent.currentSong.artists.split(' ,') }}</small>
-											</p>
-										</div>
 									</div>
-								</article>
-							</div>
-							<a @click=highlight('currentSong') href='#' class='absolute-a'></a>
+								</div>
+							</article>
 						</div>
+						<a @click=highlight('currentSong') href='#' class='absolute-a'></a>
 					</div>
 				</div>
-				<div class='edit-report-wrapper'>
-					<div class='columns is-multiline'>
-						<div class='column is-half' v-for='issue in issues'>
-							<label class='label'>{{ issue.name }}</label>
-							<p class='control' v-for='reason in issue.reasons' track-by='$index'>
-								<label class='checkbox'>
-									<input type='checkbox' @click='toggleIssue(issue.name, reason)'>
-									{{ reason }}
-								</label>
-							</p>
-						</div>
-						<div class='column'>
-							<label class='label'>Other</label>
-							<textarea class='textarea' maxlength='400' placeholder='Any other details...' @keyup='updateCharactersRemaining()' v-model='report.description'></textarea>
-							<div class='textarea-counter'>{{ charactersRemaining }}</div>
-						</div>
+			</div>
+			<div class='edit-report-wrapper'>
+				<div class='columns is-multiline'>
+					<div class='column is-half' v-for='issue in issues'>
+						<label class='label'>{{ issue.name }}</label>
+						<p class='control' v-for='reason in issue.reasons' track-by='$index'>
+							<label class='checkbox'>
+								<input type='checkbox' @click='toggleIssue(issue.name, reason)'>
+								{{ reason }}
+							</label>
+						</p>
+					</div>
+					<div class='column'>
+						<label class='label'>Other</label>
+						<textarea class='textarea' maxlength='400' placeholder='Any other details...' @keyup='updateCharactersRemaining()' v-model='report.description'></textarea>
+						<div class='textarea-counter'>{{ charactersRemaining }}</div>
 					</div>
 				</div>
-			</section>
-			<footer class='modal-card-foot'>
-				<a class='button is-success' @click='create()' href='#'>
-					<i class='material-icons save-changes'>done</i>
-					<span>&nbsp;Create</span>
-				</a>
-				<a class='button is-danger' @click='$parent.modals.report = !$parent.modals.report' href='#'>
-					<span>&nbsp;Cancel</span>
-				</a>
-			</footer>
+			</div>
+		</div>
+		<div slot='footer'>
+			<a class='button is-success' @click='create()' href='#'>
+				<i class='material-icons save-changes'>done</i>
+				<span>&nbsp;Create</span>
+			</a>
+			<a class='button is-danger' @click='$parent.modals.report = !$parent.modals.report' href='#'>
+				<span>&nbsp;Cancel</span>
+			</a>
 		</div>
-	</div>
+	</modal>
 </template>
 
 <script>
 	import { Toast } from 'vue-roaster';
+	import Modal from './Modal.vue';
 	import io from '../../io';
 
 	export default {
+		components: { Modal },
 		data() {
 			return {
 				charactersRemaining: 400,