mango-cms 0.1.22 → 0.1.24
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/cli.js +9 -1
- package/default/src/components/pages/home.vue +48 -4
- package/default/src/helpers/Mango.vue +0 -100
- package/default/src/helpers/email.js +36 -0
- package/default/src/helpers/mango.js +2 -2
- package/default/src/main.js +1 -8
- package/default/vite.config.js +2 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -168,9 +168,17 @@ program
|
|
|
168
168
|
console.log('Error reading settings file:', error.message);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
// Convert project name to lowercase and remove spaces for domain/DB names
|
|
172
|
+
const projectSlug = answers.projectName.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
173
|
+
|
|
171
174
|
settings = {
|
|
172
175
|
...settings,
|
|
173
|
-
license: answers.license
|
|
176
|
+
license: answers.license,
|
|
177
|
+
siteName: answers.projectName,
|
|
178
|
+
siteDomain: `${projectSlug}.com`,
|
|
179
|
+
domain: `api.${projectSlug}.com`,
|
|
180
|
+
database: `${projectSlug}`,
|
|
181
|
+
s3Bucket: `${projectSlug}`
|
|
174
182
|
};
|
|
175
183
|
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
176
184
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
@@ -7,12 +7,29 @@
|
|
|
7
7
|
<div>{{ online ? 'Online' : 'Offline' }}</div>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
+
<!-- Dark Mode Toggle -->
|
|
11
|
+
<div class="absolute top-4 right-4 z-20">
|
|
12
|
+
<button @click="darkMode.enabled = !darkMode.enabled"
|
|
13
|
+
class="p-2 rounded-full bg-white dark:bg-indigo-950/80 shadow-md hover:shadow-lg transition-all">
|
|
14
|
+
<svg v-if="darkMode.enabled" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-yellow-400"
|
|
15
|
+
fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
16
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
17
|
+
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
18
|
+
</svg>
|
|
19
|
+
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-slate-700" fill="none"
|
|
20
|
+
viewBox="0 0 24 24" stroke="currentColor">
|
|
21
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
22
|
+
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
23
|
+
</svg>
|
|
24
|
+
</button>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
10
27
|
<div class="pt-16 lg:pt-32 flex items-center justify-center w-full">
|
|
11
28
|
|
|
12
29
|
<div class="w-full max-2xl py-16 md:py-32 text-center flex flex-col items-center px-8 md:px-16">
|
|
13
30
|
<div class="text-9xl pb-8">🥭</div>
|
|
14
31
|
<h1 class="font-bold text-5xl pb-4 bg-clip-text bg-gradient-to-r from-orange-500 to-green-500 text-transparent">Welcome to Mango</h1>
|
|
15
|
-
<h1 class="font-bold text-lg bg-clip-text bg-gradient-to-r from-orange-500 to-green-500 text-transparent italic opacity-50">Here to make your life
|
|
32
|
+
<h1 class="font-bold text-lg bg-clip-text bg-gradient-to-r from-orange-500 to-green-500 text-transparent italic opacity-50">Here to make your life easier.</h1>
|
|
16
33
|
</div>
|
|
17
34
|
|
|
18
35
|
</div>
|
|
@@ -22,7 +39,20 @@
|
|
|
22
39
|
<div v-else class="space-y-8">
|
|
23
40
|
<div class="text-lg">Looks like the local Mango server isn't up and running yet. Please start it by running:</div>
|
|
24
41
|
<div class="w-full">
|
|
25
|
-
<
|
|
42
|
+
<div class="flex items-center space-x-2 relative">
|
|
43
|
+
<code class="bg-gray-200 dark:bg-black p-3 border border-gray-700 rounded-lg flex-grow dark:selection:bg-sky-700">cd mango; yarn; yarn watch;</code>
|
|
44
|
+
<button @click="copyToClipboard('cd mango; yarn; yarn watch;')" class="p-2 rounded-lg bg-gray-200 dark:bg-black border border-gray-700 hover:bg-gray-300 dark:hover:bg-gray-800 transition-colors relative group">
|
|
45
|
+
<svg v-if="!copied" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
46
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
|
|
47
|
+
</svg>
|
|
48
|
+
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
49
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
50
|
+
</svg>
|
|
51
|
+
<div class="absolute -top-8 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white px-2 py-1 rounded text-sm whitespace-nowrap opacity-0 transition-opacity duration-300" :class="{ 'opacity-100': copied }">
|
|
52
|
+
Copied!
|
|
53
|
+
</div>
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
26
56
|
</div>
|
|
27
57
|
</div>
|
|
28
58
|
</div>
|
|
@@ -33,7 +63,7 @@
|
|
|
33
63
|
<div class="text mb-4">Great! Now you're logged in as:</div>
|
|
34
64
|
<div class="text-2xl mb-8">{{ store.user.title }}</div>
|
|
35
65
|
<div class="rounded-lg bg-gray-100 dark:bg-gray-800 p-4 ">
|
|
36
|
-
<
|
|
66
|
+
<pre class="tracking-widest opacity-75 font-mono mt-2 truncate text-xs" v-html="JSON.stringify(store.user, undefined, 4).replaceAll('\n', '<br>').replaceAll(' ', ' ')" />
|
|
37
67
|
</div>
|
|
38
68
|
</div>
|
|
39
69
|
|
|
@@ -54,11 +84,25 @@ import Login from '../layout/login.vue'
|
|
|
54
84
|
|
|
55
85
|
export default {
|
|
56
86
|
components: { Login },
|
|
57
|
-
inject: ['store'],
|
|
87
|
+
inject: ['store','darkMode'],
|
|
88
|
+
methods: {
|
|
89
|
+
async copyToClipboard(text) {
|
|
90
|
+
try {
|
|
91
|
+
await navigator.clipboard.writeText(text);
|
|
92
|
+
this.copied = true;
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
this.copied = false;
|
|
95
|
+
}, 2000);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error('Failed to copy text:', err);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
},
|
|
58
101
|
data() {
|
|
59
102
|
return {
|
|
60
103
|
online: false,
|
|
61
104
|
checker: null,
|
|
105
|
+
copied: false,
|
|
62
106
|
}
|
|
63
107
|
},
|
|
64
108
|
async created() {
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
<script setup>
|
|
8
8
|
import Mango from './mango'
|
|
9
9
|
import { siteName } from '@config/config/settings.json'
|
|
10
|
-
import rws from './reconnecting-websocket'
|
|
11
10
|
import { ref, watch, computed, nextTick, onUnmounted } from 'vue'
|
|
12
11
|
import { useRoute } from 'vue-router'
|
|
13
12
|
|
|
@@ -245,105 +244,6 @@ async function init() {
|
|
|
245
244
|
|
|
246
245
|
}
|
|
247
246
|
|
|
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
247
|
// init()
|
|
348
248
|
// await init()
|
|
349
249
|
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
async 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
|
+
try {
|
|
27
|
+
await axios.post(`https://churchandfamilylife.us2.list-manage.com/subscribe/post?u=12eae89c5f8969e490844c75a&id=${listId}`, { EMAIL: email, MMERGE3: source })
|
|
28
|
+
.then(response => { if (alert) new Swal('Subscribed!', 'Thank you for subscribing.', 'success') })
|
|
29
|
+
// MC apparently doesn't give a proper error message we can read at the time of writing this...
|
|
30
|
+
.catch(response => { if (alert) new Swal('Subscribed!', 'Thank you for subscribing.', 'success') })
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.log(e)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { subscribeToMailChimp, validateEmail }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// import collections from '../../../mango/config/.collections.json'
|
|
2
2
|
// import { algoliaAppId, algoliaSearchKey, algoliaIndex, port, domain } from '../../../mango/config/settings'
|
|
3
|
-
import collections from '@
|
|
4
|
-
import { algoliaAppId, algoliaSearchKey, algoliaIndex, port, domain } from '@
|
|
3
|
+
import collections from '@collections'
|
|
4
|
+
import { algoliaAppId, algoliaSearchKey, algoliaIndex, port, domain } from '@settings'
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import { ref } from 'vue'
|
|
7
7
|
import algoliasearch from 'algoliasearch/lite'
|
package/default/src/main.js
CHANGED
|
@@ -2,8 +2,7 @@ import axios from 'axios'
|
|
|
2
2
|
import { computed, createApp, defineAsyncComponent, reactive, ref } from 'vue'
|
|
3
3
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
4
4
|
import { MotionPlugin } from '@vueuse/motion'
|
|
5
|
-
|
|
6
|
-
import { port, domain } from '../../config/config/settings'
|
|
5
|
+
import { port, domain } from '@settings'
|
|
7
6
|
import VueClipboard from 'vue3-clipboard'
|
|
8
7
|
import Vue3TouchEvents from "vue3-touch-events";
|
|
9
8
|
import App from './App.vue'
|
|
@@ -62,12 +61,9 @@ Global Properties
|
|
|
62
61
|
|
|
63
62
|
*/
|
|
64
63
|
|
|
65
|
-
import breakpoints from './helpers/breakpoints'
|
|
66
64
|
import darkMode from './helpers/darkMode'
|
|
67
|
-
import formatPhone from './helpers/formatPhone'
|
|
68
65
|
import { initUser } from './helpers/user';
|
|
69
66
|
|
|
70
|
-
app.provide('breakpoints', breakpoints().breakpoints)
|
|
71
67
|
app.provide('darkMode', darkMode().darkMode)
|
|
72
68
|
|
|
73
69
|
const user = initUser()
|
|
@@ -90,7 +86,6 @@ app.provide('store', store)
|
|
|
90
86
|
app.provide('axios', axios)
|
|
91
87
|
|
|
92
88
|
app.provide('mode', import.meta.env.MODE)
|
|
93
|
-
app.provide('formatPhone', formatPhone)
|
|
94
89
|
|
|
95
90
|
|
|
96
91
|
/*
|
|
@@ -102,12 +97,10 @@ Global Components
|
|
|
102
97
|
import Mango from './helpers/Mango.vue'
|
|
103
98
|
import Spinner from './components/layout/spinner.vue'
|
|
104
99
|
import Modal from './components/layout/modal.vue'
|
|
105
|
-
import Button from './components/partials/button.vue'
|
|
106
100
|
|
|
107
101
|
app.component('Mango', Mango)
|
|
108
102
|
app.component('Spinner', Spinner)
|
|
109
103
|
app.component('Modal', Modal)
|
|
110
|
-
app.component('btn', Button)
|
|
111
104
|
// app.component('resource', defineAsyncComponent(Layouter.vue')))
|
|
112
105
|
|
|
113
106
|
/*
|
package/default/vite.config.js
CHANGED
|
@@ -27,6 +27,8 @@ export default defineConfig({
|
|
|
27
27
|
resolve: {
|
|
28
28
|
alias: {
|
|
29
29
|
'@config': configPath,
|
|
30
|
+
'@settings': path.resolve(configPath, 'config/settings.json'),
|
|
31
|
+
'@collections': path.resolve(configPath, 'config/.collections.json'),
|
|
30
32
|
'@plugins': path.resolve(configPath, 'plugins'),
|
|
31
33
|
'vue': path.resolve(__dirname, 'node_modules/vue'),
|
|
32
34
|
}
|