mango-cms 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/bin/mango +4 -0
- package/frontend-starter/README.md +8 -0
- package/frontend-starter/dist/_redirects +1 -0
- package/frontend-starter/dist/assets/index.00922bd5.js +99 -0
- package/frontend-starter/dist/assets/index.1781f175.css +1 -0
- package/frontend-starter/dist/favicon.png +0 -0
- package/frontend-starter/dist/index.html +53 -0
- package/frontend-starter/dist/index.js +66 -0
- package/frontend-starter/index.html +25 -0
- package/frontend-starter/index.js +197 -0
- package/frontend-starter/package-lock.json +5454 -0
- package/frontend-starter/package.json +40 -0
- package/frontend-starter/postcss.config.js +6 -0
- package/frontend-starter/public/_redirects +1 -0
- package/frontend-starter/public/favicon.png +0 -0
- package/frontend-starter/public/index.js +66 -0
- package/frontend-starter/src/App.vue +27 -0
- package/frontend-starter/src/components/layout/login.vue +212 -0
- package/frontend-starter/src/components/layout/modal.vue +113 -0
- package/frontend-starter/src/components/layout/spinner.vue +17 -0
- package/frontend-starter/src/components/pages/404.vue +28 -0
- package/frontend-starter/src/components/pages/home.vue +74 -0
- package/frontend-starter/src/components/partials/button.vue +31 -0
- package/frontend-starter/src/helpers/Mango.vue +455 -0
- package/frontend-starter/src/helpers/breakpoints.js +34 -0
- package/frontend-starter/src/helpers/darkMode.js +38 -0
- package/frontend-starter/src/helpers/email.js +32 -0
- package/frontend-starter/src/helpers/formatPhone.js +18 -0
- package/frontend-starter/src/helpers/localDB.js +315 -0
- package/frontend-starter/src/helpers/mango.js +338 -0
- package/frontend-starter/src/helpers/model.js +9 -0
- package/frontend-starter/src/helpers/multiSelect.vue +252 -0
- package/frontend-starter/src/helpers/pills.vue +75 -0
- package/frontend-starter/src/helpers/reconnecting-websocket.js +357 -0
- package/frontend-starter/src/helpers/uploadFile.vue +157 -0
- package/frontend-starter/src/helpers/uploadFiles.vue +100 -0
- package/frontend-starter/src/helpers/uploadImages.vue +89 -0
- package/frontend-starter/src/helpers/user.js +40 -0
- package/frontend-starter/src/index.css +281 -0
- package/frontend-starter/src/main.js +145 -0
- package/frontend-starter/tailwind.config.js +46 -0
- package/frontend-starter/vite.config.js +10 -0
- package/frontend-starter/yarn.lock +3380 -0
- package/mango-cms-0.0.13.tgz +0 -0
- package/package.json +24 -0
- package/src/cli.js +93 -0
- package/src/default-config/automation/index.js +37 -0
- package/src/default-config/collections/examples.js +60 -0
- package/src/default-config/config/.collections.json +1 -0
- package/src/default-config/config/globalFields.js +15 -0
- package/src/default-config/config/settings.json +23 -0
- package/src/default-config/config/statuses.js +0 -0
- package/src/default-config/config/users.js +35 -0
- package/src/default-config/endpoints/index.js +19 -0
- package/src/default-config/fields/vimeo.js +36 -0
- package/src/default-config/hooks/test.js +5 -0
- package/src/default-config/plugins/mango-stand/index.js +206 -0
- package/src/main.js +278 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-infinite-scroll="loadMore">
|
|
3
|
+
<slot :data="data" :loading="loading" :loadingPage="loadingPage" :totalResults="totalResults" :save="save" :saving="saving" />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
import Mango from './mango'
|
|
9
|
+
import Swal from 'sweetalert2'
|
|
10
|
+
import 'sweetalert2/dist/sweetalert2.min.css';
|
|
11
|
+
// import { siteName } from '../../../mango/config/settings.json'
|
|
12
|
+
import { siteName } from '../../../config/config/settings.json'
|
|
13
|
+
import rws from './reconnecting-websocket'
|
|
14
|
+
|
|
15
|
+
import { ref, watch, computed, nextTick, onUnmounted } from 'vue'
|
|
16
|
+
// import { useRouter, useRoute, onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
|
|
17
|
+
import { useRoute, onBeforeRouteLeave } from 'vue-router'
|
|
18
|
+
|
|
19
|
+
const props = defineProps({
|
|
20
|
+
collection: {type: String},
|
|
21
|
+
algoliaSearch: {type: String},
|
|
22
|
+
algoliaFilters: {type: String},
|
|
23
|
+
id: {type: String},
|
|
24
|
+
query: {type: Object},
|
|
25
|
+
graphql: {type: String},
|
|
26
|
+
debounce: {type: Number, default: 500},
|
|
27
|
+
infinite: {type: Boolean, default: false},
|
|
28
|
+
suspend: {type: Boolean, default: false},
|
|
29
|
+
disabled: {type: Boolean, default: false},
|
|
30
|
+
main: {type: Boolean, default: false},
|
|
31
|
+
globalSearch: {type: Boolean, default: false},
|
|
32
|
+
subscribe: {type: Boolean, default: false},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
If I comment this out, some things are fixed and others are broken...
|
|
37
|
+
*/
|
|
38
|
+
onBeforeRouteLeave((to, from) => {
|
|
39
|
+
// console.log('onBeforeRouteLeave')
|
|
40
|
+
active.value = false
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const emit = defineEmits(['update:data'])
|
|
44
|
+
|
|
45
|
+
let webSocket
|
|
46
|
+
|
|
47
|
+
// const router = useRouter()
|
|
48
|
+
const route = useRoute()
|
|
49
|
+
|
|
50
|
+
let active = ref(true)
|
|
51
|
+
let autoPage = ref(null)
|
|
52
|
+
let loadingPage = ref(false)
|
|
53
|
+
let noneRemain = ref(false)
|
|
54
|
+
let saving = ref(false)
|
|
55
|
+
let inferedCollection = ref(props.collection || props.query?.collection || route.path.split('/')?.[1] || null)
|
|
56
|
+
|
|
57
|
+
let loading = ref(false)
|
|
58
|
+
let data = ref(null)
|
|
59
|
+
let error = ref(null)
|
|
60
|
+
let totalResults = ref(null)
|
|
61
|
+
let oldQuery = JSON.stringify(props.query || {})
|
|
62
|
+
|
|
63
|
+
let inferedId = computed(() => props.id !== undefined ? props.id : props.query?.id || route.params?.id || null )
|
|
64
|
+
let searchingAlgolia = computed(() => !!props.algoliaSearch || !!props.algoliaFilters )
|
|
65
|
+
|
|
66
|
+
let debounceInit = computed(() => {
|
|
67
|
+
let timer;
|
|
68
|
+
return (...args) => {
|
|
69
|
+
if (active.value === false || props.disabled) return
|
|
70
|
+
loading.value = true
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
timer = setTimeout(() => { init.apply(this, args); }, props.debounce);
|
|
73
|
+
};
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
watch(() => props.query, (n, o) => {
|
|
77
|
+
let newQuery = JSON.stringify(n)
|
|
78
|
+
if (oldQuery != newQuery) defer(newQuery, oldQuery, 'query')
|
|
79
|
+
}, { deep: true })
|
|
80
|
+
|
|
81
|
+
watch(inferedId, (n, o) => defer(null, null, 'id'))
|
|
82
|
+
watch(() => props.collection, (n, o) => defer(null, null, 'collection'))
|
|
83
|
+
watch(() => props.algoliaSearch, (n, o) => searchingAlgolia.value ? debounceInit.value() : init())
|
|
84
|
+
watch(() => props.algoliaFilters, (n, o) => searchingAlgolia.value ? debounceInit.value() : init())
|
|
85
|
+
watch(loading, (n, o) => emit('update:loading', loading.value))
|
|
86
|
+
watch(data, () => {
|
|
87
|
+
if (data?.value?.length && props.query?.limit && data?.value?.length < props.query?.limit) noneRemain.value = true
|
|
88
|
+
if (data?.value) emit('update:data', data.value)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
function defer(n,o,origin) {
|
|
93
|
+
console.log('n,o,origin', n,o,origin)
|
|
94
|
+
if (n == o && origin == 'query') return console.log(`they're the same...`)
|
|
95
|
+
if (origin == 'query') oldQuery = n
|
|
96
|
+
nextTick(() => init())
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function loadMore() {
|
|
100
|
+
|
|
101
|
+
// console.log('loadMore')
|
|
102
|
+
|
|
103
|
+
if (!props.infinite || !data?.value?.length || loadingPage.value || noneRemain.value || props.disabled) return
|
|
104
|
+
loadingPage.value = true
|
|
105
|
+
let query = props.query ? JSON.parse(JSON.stringify(props.query)) : {}
|
|
106
|
+
if (query.search && !query.search?.wordSearch) delete query.search.wordSearch
|
|
107
|
+
autoPage.value ++
|
|
108
|
+
query.page = autoPage.value
|
|
109
|
+
if (searchingAlgolia.value) {
|
|
110
|
+
var nextPage = (await Mango[inferedCollection.value].search(props.algoliaSearch, query, props.algoliaFilters))?.hits
|
|
111
|
+
} else if (inferedCollection.value?.includes('/')) {
|
|
112
|
+
var nextPage = await Mango.relationRequest({...query, path: inferedCollection.value})
|
|
113
|
+
} else {
|
|
114
|
+
var nextPage = await Mango[inferedCollection.value](query)
|
|
115
|
+
}
|
|
116
|
+
if (nextPage.length) data.value = data.value.concat(nextPage)
|
|
117
|
+
if (!nextPage.length || (query.limit && nextPage.length < query.limit)) noneRemain.value = true
|
|
118
|
+
loadingPage.value = false
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function init() {
|
|
123
|
+
|
|
124
|
+
console.log('init')
|
|
125
|
+
|
|
126
|
+
// If the main entry is provided in ssr
|
|
127
|
+
if (props.main && window.mainEntry?.id == inferedId.value) {
|
|
128
|
+
data.value = window.mainEntry
|
|
129
|
+
window.mainEntry = null
|
|
130
|
+
emit('update:data', data.value)
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (active.value === false || props.disabled) return
|
|
135
|
+
|
|
136
|
+
console.log('active', active.value)
|
|
137
|
+
|
|
138
|
+
loading.value = true
|
|
139
|
+
data.value = null
|
|
140
|
+
noneRemain.value = false
|
|
141
|
+
autoPage.value = props.query?.page || 0
|
|
142
|
+
|
|
143
|
+
// Using the computed here won't work because it hasn't been computed yet
|
|
144
|
+
let searchingAlgolia = !!props.algoliaSearch || !!props.algoliaFilters
|
|
145
|
+
|
|
146
|
+
if (props.graphql){
|
|
147
|
+
data.value = await Mango.graphql(props.graphql)
|
|
148
|
+
emit('update:data', data.value)
|
|
149
|
+
loading.value = false
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let collection = inferedCollection.value
|
|
154
|
+
let validatedCollection = Mango.collections.find(c => c.name == collection)
|
|
155
|
+
let id = props.id || props.query?.id || route.params?.id || null
|
|
156
|
+
if (props.id !== undefined) id = props.id // So you can pass null to id and get a list
|
|
157
|
+
|
|
158
|
+
let query = props.query ? JSON.parse(JSON.stringify(props.query)) : {}
|
|
159
|
+
if (query.search && !query.search?.wordSearch) delete query.search.wordSearch // So empty search still returns something
|
|
160
|
+
|
|
161
|
+
if (inferedCollection.value?.includes('/')) {
|
|
162
|
+
data.value = await Mango.relationRequest({...query, path: inferedCollection.value})
|
|
163
|
+
emit('update:data', data.value)
|
|
164
|
+
loading.value = false
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Global Algolia Search
|
|
169
|
+
if (props.globalSearch) {
|
|
170
|
+
data.value = await Mango.search(props.algoliaSearch, query, props.algoliaFilters)
|
|
171
|
+
emit('update:data', data.value)
|
|
172
|
+
loading.value = false
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!validatedCollection) return console.error(`🥠${collection} is not a valid collection.`)
|
|
177
|
+
if (id && !searchingAlgolia) collection = validatedCollection.singular
|
|
178
|
+
// if (id) query = id
|
|
179
|
+
|
|
180
|
+
console.log('collection, id:', collection, id)
|
|
181
|
+
// console.log('collection', collection)
|
|
182
|
+
|
|
183
|
+
if (searchingAlgolia) {
|
|
184
|
+
console.log('collection', collection)
|
|
185
|
+
let algoliaResponse = await Mango[collection].search(props.algoliaSearch, query, props.algoliaFilters)
|
|
186
|
+
data.value = algoliaResponse.hits
|
|
187
|
+
totalResults.value = algoliaResponse.nbHits
|
|
188
|
+
emit('update:data', data.value)
|
|
189
|
+
loading.value = false
|
|
190
|
+
} else {
|
|
191
|
+
if (id) data.value = await Mango[collection](id, query)
|
|
192
|
+
else data.value = await Mango[collection](query)
|
|
193
|
+
|
|
194
|
+
emit('update:data', data.value)
|
|
195
|
+
loading.value = false
|
|
196
|
+
|
|
197
|
+
if (id && props.main) document.title = data.value?.title || siteName
|
|
198
|
+
else document.title = siteName
|
|
199
|
+
|
|
200
|
+
if (props.subscribe) {
|
|
201
|
+
|
|
202
|
+
let sub = function() {
|
|
203
|
+
let subscribeCollection = `${validatedCollection.singular}Change`
|
|
204
|
+
console.log('subscribeCollection', subscribeCollection)
|
|
205
|
+
subscribe(subscribeCollection, id)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
sub()
|
|
209
|
+
|
|
210
|
+
let hidden;
|
|
211
|
+
let visibilityChange;
|
|
212
|
+
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
|
|
213
|
+
hidden = "hidden";
|
|
214
|
+
visibilityChange = "visibilitychange";
|
|
215
|
+
} else if (typeof document.msHidden !== "undefined") {
|
|
216
|
+
hidden = "msHidden";
|
|
217
|
+
visibilityChange = "msvisibilitychange";
|
|
218
|
+
} else if (typeof document.webkitHidden !== "undefined") {
|
|
219
|
+
hidden = "webkitHidden";
|
|
220
|
+
visibilityChange = "webkitvisibilitychange";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
document.addEventListener(visibilityChange, () => {
|
|
224
|
+
if (!document[hidden]) {
|
|
225
|
+
// Ensure connectivity
|
|
226
|
+
console.log('ensure connectivity')
|
|
227
|
+
init()
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// else {
|
|
231
|
+
// if (webSocket?.send) {
|
|
232
|
+
// webSocket.send(JSON.stringify({
|
|
233
|
+
// type: GQL.CONNECTION_TERMINATE
|
|
234
|
+
// }))
|
|
235
|
+
// }
|
|
236
|
+
// webSocket = null
|
|
237
|
+
// }
|
|
238
|
+
}, false)
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const GQL = {
|
|
249
|
+
CONNECTION_INIT: 'connection_init',
|
|
250
|
+
CONNECTION_ACK: 'connection_ack',
|
|
251
|
+
CONNECTION_ERROR: 'connection_error',
|
|
252
|
+
CONNECTION_KEEP_ALIVE: 'ka',
|
|
253
|
+
START: 'start',
|
|
254
|
+
STOP: 'stop',
|
|
255
|
+
CONNECTION_TERMINATE: 'connection_terminate',
|
|
256
|
+
DATA: 'data',
|
|
257
|
+
ERROR: 'error',
|
|
258
|
+
COMPLETE: 'complete'
|
|
259
|
+
}
|
|
260
|
+
function subscribe(collection, id) {
|
|
261
|
+
|
|
262
|
+
webSocket = new rws(Mango.ws, 'graphql-ws')
|
|
263
|
+
|
|
264
|
+
webSocket.onopen = event => {
|
|
265
|
+
|
|
266
|
+
webSocket.send(JSON.stringify({
|
|
267
|
+
type: GQL.CONNECTION_INIT,
|
|
268
|
+
payload: {}
|
|
269
|
+
}))
|
|
270
|
+
|
|
271
|
+
webSocket.send(JSON.stringify({
|
|
272
|
+
type: GQL.START,
|
|
273
|
+
id: Date.now(),
|
|
274
|
+
payload: {
|
|
275
|
+
query: `
|
|
276
|
+
subscription {
|
|
277
|
+
${collection}(id: "${id}") {
|
|
278
|
+
id
|
|
279
|
+
settings {
|
|
280
|
+
clueTimeLimit
|
|
281
|
+
guessTimeLimit
|
|
282
|
+
}
|
|
283
|
+
guesses {
|
|
284
|
+
word
|
|
285
|
+
playerId
|
|
286
|
+
time
|
|
287
|
+
}
|
|
288
|
+
clue {
|
|
289
|
+
text
|
|
290
|
+
number
|
|
291
|
+
time
|
|
292
|
+
team
|
|
293
|
+
words
|
|
294
|
+
guesses
|
|
295
|
+
}
|
|
296
|
+
words {
|
|
297
|
+
value
|
|
298
|
+
color
|
|
299
|
+
guessed
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}`,
|
|
303
|
+
variables: {},
|
|
304
|
+
operationName: null
|
|
305
|
+
}
|
|
306
|
+
}))
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
webSocket.onmessage = event => {
|
|
310
|
+
const response = JSON.parse(event.data)
|
|
311
|
+
switch (response.type) {
|
|
312
|
+
case GQL.CONNECTION_ACK: {
|
|
313
|
+
console.log('success')
|
|
314
|
+
break
|
|
315
|
+
}
|
|
316
|
+
case GQL.CONNECTION_ERROR: {
|
|
317
|
+
console.error(response.payload)
|
|
318
|
+
break
|
|
319
|
+
}
|
|
320
|
+
case GQL.CONNECTION_KEEP_ALIVE: {
|
|
321
|
+
break
|
|
322
|
+
}
|
|
323
|
+
case GQL.DATA: {
|
|
324
|
+
console.log(response.id, response.payload.errors, response.payload.data)
|
|
325
|
+
if (response.payload.data) {
|
|
326
|
+
data.value = response.payload.data[collection]
|
|
327
|
+
emit('update:data', data.value)
|
|
328
|
+
}
|
|
329
|
+
break
|
|
330
|
+
}
|
|
331
|
+
case GQL.COMPLETE: {
|
|
332
|
+
console.log('completed', response.id)
|
|
333
|
+
break
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
onUnmounted(() => {
|
|
340
|
+
if (webSocket?.send) {
|
|
341
|
+
webSocket.send(JSON.stringify({
|
|
342
|
+
type: GQL.CONNECTION_TERMINATE
|
|
343
|
+
}))
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
// init()
|
|
348
|
+
// await init()
|
|
349
|
+
|
|
350
|
+
if (props.suspend) {
|
|
351
|
+
await init()
|
|
352
|
+
} else {
|
|
353
|
+
init()
|
|
354
|
+
}
|
|
355
|
+
</script>
|
|
356
|
+
|
|
357
|
+
<script>
|
|
358
|
+
export default {
|
|
359
|
+
directives: {
|
|
360
|
+
infiniteScroll: {
|
|
361
|
+
mounted(element, binding) {
|
|
362
|
+
document.addEventListener("scroll", () => binding.dir.methods.handleScroll(element, binding.value))
|
|
363
|
+
},
|
|
364
|
+
unmounted(element, binding) {
|
|
365
|
+
document.removeEventListener("scroll", () => binding.dir.methods.handleScroll(element, binding.value))
|
|
366
|
+
},
|
|
367
|
+
methods: {
|
|
368
|
+
handleScroll(element, method) {
|
|
369
|
+
// console.log('triggered')
|
|
370
|
+
if (element.getBoundingClientRect().bottom - 100 < window.innerHeight) method()
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
watch: {
|
|
376
|
+
// id: 'defer',
|
|
377
|
+
// inferedId: 'oldDefer',
|
|
378
|
+
// collection: 'oldDefer',
|
|
379
|
+
// query: {
|
|
380
|
+
// handler(n, o) {
|
|
381
|
+
// let oldQuery = JSON.stringify(o)
|
|
382
|
+
// let newQuery = JSON.stringify(n)
|
|
383
|
+
// if (oldQuery != newQuery) console.log(`but they're not the same!`)
|
|
384
|
+
// this.defer(newQuery, oldQuery, 'query')
|
|
385
|
+
// },
|
|
386
|
+
// deep: true,
|
|
387
|
+
// },
|
|
388
|
+
// algoliaSearch() {
|
|
389
|
+
// if (this.searchingAlgolia) this.debounceInit()
|
|
390
|
+
// else this.init()
|
|
391
|
+
// },
|
|
392
|
+
// data() {
|
|
393
|
+
// if (this.data?.length && this.query?.limit && this.data?.length < this.query?.limit) {
|
|
394
|
+
// this.noneRemain = true
|
|
395
|
+
// }
|
|
396
|
+
// if (this.data) this.$emit('update:data', this.data)
|
|
397
|
+
// }
|
|
398
|
+
},
|
|
399
|
+
computed: {
|
|
400
|
+
// searchingAlgolia() {return !!this.algoliaSearch},
|
|
401
|
+
// inferedId() { return this.id !== undefined ? this.id : this.query?.id || this.$route.params?.id || null },
|
|
402
|
+
// debounceInit() {
|
|
403
|
+
// let timer;
|
|
404
|
+
// return (...args) => {
|
|
405
|
+
// this.loading = true
|
|
406
|
+
// clearTimeout(timer);
|
|
407
|
+
// timer = setTimeout(() => { this.init.apply(this, args); }, this.debounce);
|
|
408
|
+
// };
|
|
409
|
+
// }
|
|
410
|
+
},
|
|
411
|
+
methods: {
|
|
412
|
+
// async loadMore() {
|
|
413
|
+
|
|
414
|
+
// console.log('loadMore')
|
|
415
|
+
|
|
416
|
+
// if (!this.infinite || !this.data?.length || this.loadingPage || this.noneRemain) return
|
|
417
|
+
// this.loadingPage = true
|
|
418
|
+
// let query = this.query ? JSON.parse(JSON.stringify(this.query)) : {}
|
|
419
|
+
// if (query.search && !query.search?.wordSearch) delete query.search.wordSearch
|
|
420
|
+
// this.autoPage ++
|
|
421
|
+
// query.page = this.autoPage
|
|
422
|
+
// if (this.searchingAlgolia) {
|
|
423
|
+
// var nextPage = await Mango[this.inferedCollection].search(this.algoliaSearch, query)
|
|
424
|
+
// } else {
|
|
425
|
+
// var nextPage = await Mango[this.inferedCollection](query)
|
|
426
|
+
// }
|
|
427
|
+
// if (nextPage.length) this.data = this.data.concat(nextPage)
|
|
428
|
+
// if (!nextPage.length || (query.limit && nextPage.length < query.limit)) this.noneRemain = true
|
|
429
|
+
// this.loadingPage = false
|
|
430
|
+
|
|
431
|
+
// },
|
|
432
|
+
// oldDefer(n,o,origin) {
|
|
433
|
+
// console.log('n,o,origin', n,o,origin)
|
|
434
|
+
// if (n == o) { console.log(`they're the same...`); return }
|
|
435
|
+
// this.$nextTick(() => this.init())
|
|
436
|
+
// },
|
|
437
|
+
async save(data) {
|
|
438
|
+
data = data || this.data
|
|
439
|
+
if (Array.isArray(data)) {
|
|
440
|
+
console.log('You can only call save after querying for an individual document.')
|
|
441
|
+
return
|
|
442
|
+
} else {
|
|
443
|
+
if (this.saving) return
|
|
444
|
+
this.saving = true
|
|
445
|
+
let response = await Mango[this.inferedCollection].save(data)
|
|
446
|
+
this.saving = false
|
|
447
|
+
// if (response?.id) return Swal.fire({ title: 'Success!', icon: 'success', confirmButtonText: 'Awesome!' })
|
|
448
|
+
// return Swal.fire({ title: 'Error 😬', icon: 'error' })
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
activated() { this.active = true },
|
|
453
|
+
deactivated() { this.active = false },
|
|
454
|
+
}
|
|
455
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { reactive } from 'vue'
|
|
2
|
+
|
|
3
|
+
const screens = {
|
|
4
|
+
'2xs': 425,
|
|
5
|
+
xs: 475,
|
|
6
|
+
sm: 640,
|
|
7
|
+
md: 768,
|
|
8
|
+
lg: 1024,
|
|
9
|
+
xl: 1280
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const breakpoints = reactive({ xs: false, sm: false, md: false, lg: false, xl: false })
|
|
13
|
+
|
|
14
|
+
const setBreakpoint = () => {
|
|
15
|
+
breakpoints['2xs'] = window.innerWidth >= screens['2xs']
|
|
16
|
+
breakpoints.xs = window.innerWidth >= screens.xs
|
|
17
|
+
breakpoints.sm = window.innerWidth >= screens.sm
|
|
18
|
+
breakpoints.md = window.innerWidth >= screens.md
|
|
19
|
+
breakpoints.lg = window.innerWidth >= screens.lg
|
|
20
|
+
breakpoints.xl = window.innerWidth >= screens.xl
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const useBreakpoint = () => {
|
|
24
|
+
|
|
25
|
+
setBreakpoint()
|
|
26
|
+
window.addEventListener('resize', setBreakpoint)
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
breakpoints
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default useBreakpoint
|
|
34
|
+
export { screens }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { reactive } from 'vue'
|
|
2
|
+
|
|
3
|
+
const toggle = () => {
|
|
4
|
+
console.log('toggle')
|
|
5
|
+
if (darkMode.enabled) {
|
|
6
|
+
window.localStorage.setItem('darkMode', 'false')
|
|
7
|
+
} else {
|
|
8
|
+
window.localStorage.setItem('darkMode', 'true')
|
|
9
|
+
}
|
|
10
|
+
checkDarkMode()
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const darkMode = reactive({ enabled: false, toggle })
|
|
15
|
+
|
|
16
|
+
const systemChange = () => {
|
|
17
|
+
window.localStorage.removeItem('darkMode')
|
|
18
|
+
darkMode.enabled = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const checkDarkMode = () => {
|
|
22
|
+
let storedValue = window.localStorage.getItem('darkMode')
|
|
23
|
+
let enabledLocally = storedValue != null
|
|
24
|
+
let localBoolean = storedValue == 'true' ? true : false
|
|
25
|
+
let systemPreference = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
26
|
+
darkMode.enabled = enabledLocally ? localBoolean : systemPreference
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const useDarkMode = () => {
|
|
30
|
+
|
|
31
|
+
checkDarkMode()
|
|
32
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', systemChange)
|
|
33
|
+
|
|
34
|
+
return { darkMode }
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default useDarkMode
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Swal from "sweetalert2"
|
|
2
|
+
import axios from "axios"
|
|
3
|
+
|
|
4
|
+
function validateEmail(email) {
|
|
5
|
+
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
6
|
+
return re.test(String(email.trim()).toLowerCase());
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function subscribeToMailChimp({ email, list, source, alert }) {
|
|
10
|
+
|
|
11
|
+
let lists = {
|
|
12
|
+
master: '816047355d',
|
|
13
|
+
devotional: '5fbac827f8'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let listId = lists[list]
|
|
17
|
+
|
|
18
|
+
if (!listId) return console.error(`"${list}" is not a valid email list`)
|
|
19
|
+
if (!source) return console.error(`You must provide a subscription source`)
|
|
20
|
+
|
|
21
|
+
if (!validateEmail(email)) {
|
|
22
|
+
new Swal('Invalid Email', `"${email}" is not a valid email address`, 'warning')
|
|
23
|
+
return console.error(`"${email}" is not a valid email address`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
axios.get(`https://ncfic.us2.list-manage.com/subscribe/post-json?u=12eae89c5f8969e490844c75a&id=${listId}&c=jQuery190019886783748288184_1530501492048&MMERGE3=${source}&EMAIL=${email}&b_12eae89c5f8969e490844c75a_816047355d=&subscribe=Subscribe&_=1530501492049`)
|
|
27
|
+
.then(response => { if (alert) new Swal('Subscribed!', 'Thank you for subscribing.', 'success') })
|
|
28
|
+
// MC apparently doesn't give a proper error message we can read at the time of writing this...
|
|
29
|
+
.catch(response => { if (alert) new Swal('Subscribed!', 'Thank you for subscribing.', 'success') })
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { subscribeToMailChimp, validateEmail }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default (phone) => {
|
|
2
|
+
if (!phone) return ''
|
|
3
|
+
let formattedPhoneNumber = ''
|
|
4
|
+
let number = phone.replace(/\D/g, '').split('')
|
|
5
|
+
if (number.length == 11) {
|
|
6
|
+
formattedPhoneNumber += '+' + number[0] + ' '
|
|
7
|
+
number.splice(0, 1)
|
|
8
|
+
}
|
|
9
|
+
for (let [index, digit] in number) {
|
|
10
|
+
if (number.length >= 3) {
|
|
11
|
+
if (index == 0) formattedPhoneNumber += '('
|
|
12
|
+
if (index == 6) formattedPhoneNumber += '-'
|
|
13
|
+
if (number[index]) formattedPhoneNumber += number[index]
|
|
14
|
+
if (index == 2) formattedPhoneNumber += ') '
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return formattedPhoneNumber
|
|
18
|
+
}
|