@wishbone-media/spark 0.5.2 → 0.6.0
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/dist/index.js +476 -485
- package/package.json +3 -2
- package/src/components/SparkBrandSelector.vue +7 -1
- package/src/stores/brand-filter.js +43 -18
- package/src/views/SparkForgotPasswordView.vue +75 -0
- package/src/views/SparkLoginView.vue +6 -19
- package/src/views/SparkLogoutView.vue +15 -0
- /package/src/assets/images/{mr-antenna.png → brands/mr-antenna.png} +0 -0
- /package/src/assets/images/{mr-gutter-cleaning.png → brands/mr-gutter-cleaning.png} +0 -0
- /package/src/assets/images/{mr-pest-controller.png → brands/mr-pest-controller.png} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wishbone-media/spark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"./formkit.config.js": "./formkit.config.js",
|
|
43
43
|
"./formkit.theme.mjs": "./formkit.theme.mjs",
|
|
44
44
|
"./assets/css/*": "./src/assets/css/*",
|
|
45
|
-
"./assets/fonts/*": "./src/assets/fonts/*"
|
|
45
|
+
"./assets/fonts/*": "./src/assets/fonts/*",
|
|
46
|
+
"./assets/images/brands/*": "./src/assets/images/brands/*"
|
|
46
47
|
},
|
|
47
48
|
"publishConfig": {
|
|
48
49
|
"access": "public"
|
|
@@ -12,9 +12,15 @@
|
|
|
12
12
|
/>
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
|
+
<div
|
|
16
|
+
v-if="sparkBrandFilterStore.allBrands.length === 0"
|
|
17
|
+
class="flex px-[22px] py-[15px] text-gray-500 text-sm"
|
|
18
|
+
>
|
|
19
|
+
No brands configured
|
|
20
|
+
</div>
|
|
15
21
|
<div
|
|
16
22
|
v-for="brand in sparkBrandFilterStore.allBrands"
|
|
17
|
-
:key="brand.
|
|
23
|
+
:key="brand.id"
|
|
18
24
|
:class="brand.current ? 'bg-gray-50' : 'hover:bg-gray-50'"
|
|
19
25
|
class="flex px-[22px] py-[15px] cursor-pointer"
|
|
20
26
|
@click="selectBrand(brand)"
|
|
@@ -1,31 +1,55 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { computed, reactive } from 'vue'
|
|
3
3
|
|
|
4
|
-
import mrPestControllerLogo from '@/assets/images/mr-pest-controller.png'
|
|
5
|
-
import mrGutterCleaningLogo from '@/assets/images/mr-gutter-cleaning.png'
|
|
6
|
-
import mrAntennaLogo from '@/assets/images/mr-antenna.png'
|
|
7
|
-
|
|
8
4
|
export const useSparkBrandFilterStore = defineStore('brandFilter', () => {
|
|
9
5
|
const state = reactive({
|
|
10
|
-
brands: [
|
|
11
|
-
{
|
|
12
|
-
name: 'Mr Pest Controller',
|
|
13
|
-
logo: mrPestControllerLogo,
|
|
14
|
-
current: false,
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
name: 'Mr Gutter Cleaning',
|
|
18
|
-
logo: mrGutterCleaningLogo,
|
|
19
|
-
current: false,
|
|
20
|
-
},
|
|
21
|
-
{ name: 'Mr Antenna', logo: mrAntennaLogo, current: true },
|
|
22
|
-
],
|
|
6
|
+
brands: [],
|
|
23
7
|
})
|
|
24
8
|
|
|
25
|
-
const
|
|
9
|
+
const initialize = (config = {}) => {
|
|
10
|
+
if (!config.brands || !Array.isArray(config.brands)) {
|
|
11
|
+
console.warn('useSparkBrandFilterStore: No brands provided to initialize()')
|
|
12
|
+
state.brands = []
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Validate brand structure
|
|
17
|
+
const validBrands = config.brands.filter((brand) => {
|
|
18
|
+
const isValid = brand.id && brand.name && brand.logo
|
|
19
|
+
if (!isValid) {
|
|
20
|
+
console.warn('useSparkBrandFilterStore: Invalid brand object', brand)
|
|
21
|
+
}
|
|
22
|
+
return isValid
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Ensure exactly one brand is marked as current
|
|
26
|
+
const currentBrands = validBrands.filter((b) => b.current)
|
|
27
|
+
if (currentBrands.length === 0 && validBrands.length > 0) {
|
|
28
|
+
validBrands[0].current = true
|
|
29
|
+
} else if (currentBrands.length > 1) {
|
|
30
|
+
// Only the first current brand stays current
|
|
31
|
+
validBrands.forEach((brand) => {
|
|
32
|
+
brand.current = brand === currentBrands[0]
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
state.brands = validBrands.map((brand) => ({
|
|
37
|
+
id: brand.id,
|
|
38
|
+
name: brand.name,
|
|
39
|
+
logo: brand.logo,
|
|
40
|
+
current: brand.current || false,
|
|
41
|
+
}))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const currentBrand = computed(() => state.brands.find((item) => item.current) || null)
|
|
26
45
|
const allBrands = computed(() => state.brands)
|
|
27
46
|
|
|
28
47
|
const toggleBrand = (brand) => {
|
|
48
|
+
if (!brand || !state.brands.includes(brand)) {
|
|
49
|
+
console.warn('useSparkBrandFilterStore: Invalid brand provided to toggleBrand()')
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
29
53
|
state.brands.forEach((item) => {
|
|
30
54
|
item.current = item === brand
|
|
31
55
|
})
|
|
@@ -33,6 +57,7 @@ export const useSparkBrandFilterStore = defineStore('brandFilter', () => {
|
|
|
33
57
|
|
|
34
58
|
return {
|
|
35
59
|
state,
|
|
60
|
+
initialize,
|
|
36
61
|
currentBrand,
|
|
37
62
|
allBrands,
|
|
38
63
|
toggleBrand,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="h-full grid place-content-center relative">
|
|
3
|
+
<div class="absolute top-8 left-8">
|
|
4
|
+
<svg
|
|
5
|
+
width="59"
|
|
6
|
+
height="23"
|
|
7
|
+
viewBox="0 0 59 23"
|
|
8
|
+
fill="none"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
>
|
|
11
|
+
<path
|
|
12
|
+
d="M49.2029 17.1264V8.03835H44.0829V5.22235H58.0989V8.03835H52.9629V17.1264H49.2029Z"
|
|
13
|
+
fill="#1C64F2"
|
|
14
|
+
/>
|
|
15
|
+
<path d="M34.5 5.22235H38.228V14.1664H46.5V17.1264H34.5V5.22235Z" fill="#1C64F2" />
|
|
16
|
+
<path
|
|
17
|
+
d="M28.3161 0C29.1499 0 29.7522 0.798785 29.5209 1.59757L27.1856 9.77748H30.9046C31.747 9.77748 32.4279 10.4584 32.4279 11.3008C32.4279 11.7504 32.2315 12.1738 31.891 12.4619L20.5989 22.0517C20.3719 22.2438 20.0839 22.3485 19.787 22.3485C18.9533 22.3485 18.351 21.5497 18.5823 20.751L20.9176 12.571H17.1463C16.33 12.571 15.6709 11.9119 15.6709 11.1001C15.6709 10.6679 15.8586 10.262 16.186 9.98263L27.5043 0.301181C27.7312 0.104759 28.0193 0 28.3161 0ZM26.7404 3.71021L18.8311 10.4759H22.3056C22.633 10.4759 22.9429 10.6286 23.1437 10.8905C23.3445 11.1524 23.4056 11.4929 23.3139 11.8072L21.3584 18.6601L29.355 11.8727H25.7976C25.4702 11.8727 25.1603 11.7199 24.9595 11.458C24.7587 11.1961 24.6976 10.8556 24.7893 10.5413L26.7404 3.71021Z"
|
|
18
|
+
fill="#1C64F2"
|
|
19
|
+
/>
|
|
20
|
+
<path
|
|
21
|
+
d="M0 17.1264V5.22235H10.192C13.6 5.22235 14.544 6.53435 14.544 7.94235V8.16635C14.544 9.70235 13.232 10.3264 12.656 10.4864C13.472 10.6944 15.216 11.3984 15.216 13.4784V13.7024C15.216 15.5904 14.144 17.1264 10.288 17.1264H0ZM9.552 7.73435H3.728V9.67035H9.552C10.592 9.67035 10.848 9.19035 10.848 8.71035V8.67835C10.848 8.18235 10.592 7.73435 9.552 7.73435ZM9.872 12.1984H3.728V14.5344H9.872C11.12 14.5344 11.344 13.8464 11.344 13.3664V13.3024C11.344 12.7904 11.104 12.1984 9.872 12.1984Z"
|
|
22
|
+
fill="#1C64F2"
|
|
23
|
+
/>
|
|
24
|
+
</svg>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="max-w-sm grid gap-y-1 -mt-8">
|
|
28
|
+
<div class="mb-7">
|
|
29
|
+
<h1 class="text-4xl text-gray-900 semibold tracking-tight mb-3">Log in</h1>
|
|
30
|
+
|
|
31
|
+
<p class="text-gray-600">
|
|
32
|
+
Welcome back{{ appStore.state.app ? ` to ${appStore.state.app}` : '' }}! Please enter
|
|
33
|
+
your details.
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<FormKit type="form" @submit="handleLogin" :actions="false">
|
|
38
|
+
<FormKit
|
|
39
|
+
label="Email"
|
|
40
|
+
name="email"
|
|
41
|
+
placeholder="Enter your email"
|
|
42
|
+
type="email"
|
|
43
|
+
validation="required|email"
|
|
44
|
+
outer-class="max-w-full"
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
<FormKit
|
|
48
|
+
label="Password"
|
|
49
|
+
name="password"
|
|
50
|
+
placeholder="••••••••"
|
|
51
|
+
type="password"
|
|
52
|
+
validation="required"
|
|
53
|
+
outer-class="max-w-full"
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
<div class="grid grid-flow-col justify-between my-1">
|
|
57
|
+
<FormKit label="Remember me" name="remember" type="checkbox" />
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div v-if="errorMessage" class="text-red-600 text-sm mb-2">
|
|
61
|
+
{{ errorMessage }}
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<spark-button type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
|
|
65
|
+
<span v-if="!isLoading">Sign in</span>
|
|
66
|
+
<span v-else>Signing in...</span>
|
|
67
|
+
</spark-button>
|
|
68
|
+
</FormKit>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<script setup>
|
|
74
|
+
import { SparkButton } from '@/index.js'
|
|
75
|
+
</script>
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
<h1 class="text-4xl text-gray-900 semibold tracking-tight mb-3">Log in</h1>
|
|
32
32
|
|
|
33
33
|
<p class="text-gray-600">
|
|
34
|
-
Welcome back{{
|
|
35
|
-
details.
|
|
34
|
+
Welcome back{{ appStore.state.app ? ` to ${appStore.state.app}` : '' }}! Please enter
|
|
35
|
+
your details.
|
|
36
36
|
</p>
|
|
37
37
|
</div>
|
|
38
38
|
|
|
@@ -70,35 +70,26 @@
|
|
|
70
70
|
{{ errorMessage }}
|
|
71
71
|
</div>
|
|
72
72
|
|
|
73
|
-
<spark-button type="submit" size="xl" :disabled="isLoading" button-class="w-full">
|
|
73
|
+
<spark-button type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
|
|
74
74
|
<span v-if="!isLoading">Sign in</span>
|
|
75
75
|
<span v-else>Signing in...</span>
|
|
76
76
|
</spark-button>
|
|
77
77
|
</FormKit>
|
|
78
|
-
|
|
79
|
-
<div v-if="props.signupRoute" class="mt-4 text-center text-sm text-gray-600">
|
|
80
|
-
Don't have an account?
|
|
81
|
-
<router-link :to="props.signupRoute" class="text-primary-600 font-semibold">
|
|
82
|
-
Sign up
|
|
83
|
-
</router-link>
|
|
84
|
-
</div>
|
|
85
78
|
</div>
|
|
86
79
|
</div>
|
|
87
80
|
</template>
|
|
88
81
|
|
|
89
82
|
<script setup>
|
|
90
83
|
import { ref } from 'vue'
|
|
91
|
-
import { SparkButton } from '@/index.js'
|
|
84
|
+
import { SparkButton, useSparkAppStore } from '@/index.js'
|
|
85
|
+
|
|
86
|
+
const appStore = useSparkAppStore()
|
|
92
87
|
|
|
93
88
|
const props = defineProps({
|
|
94
89
|
logo: {
|
|
95
90
|
type: String,
|
|
96
91
|
default: '',
|
|
97
92
|
},
|
|
98
|
-
appName: {
|
|
99
|
-
type: String,
|
|
100
|
-
default: '',
|
|
101
|
-
},
|
|
102
93
|
onLogin: {
|
|
103
94
|
type: Function,
|
|
104
95
|
required: true,
|
|
@@ -107,10 +98,6 @@ const props = defineProps({
|
|
|
107
98
|
type: String,
|
|
108
99
|
default: '/forgot-password',
|
|
109
100
|
},
|
|
110
|
-
signupRoute: {
|
|
111
|
-
type: String,
|
|
112
|
-
default: '',
|
|
113
|
-
},
|
|
114
101
|
})
|
|
115
102
|
|
|
116
103
|
const emit = defineEmits(['login-success', 'login-error'])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|