@lilaquadrat/design-core 0.1.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/README.md +236 -0
- package/html/index.html +25 -0
- package/html/index.mail.html +15 -0
- package/html/index.server.html +29 -0
- package/package.json +148 -0
- package/src/client-entry.ts +28 -0
- package/src/components/partials/action.partial.vue +30 -0
- package/src/components/partials/client-only.partial.vue +11 -0
- package/src/components/partials/error.partial.vue +73 -0
- package/src/components/partials/main-components.partial.vue +167 -0
- package/src/components/partials/mediadetection.partial.vue +71 -0
- package/src/components/partials/qrcode.partial.vue +35 -0
- package/src/customs.ts +12 -0
- package/src/env.d.ts +1 -0
- package/src/functions/PaymenyProviderFactory.ts +27 -0
- package/src/functions/lila-dom.ts +100 -0
- package/src/functions/shopify.provider.ts +378 -0
- package/src/functions/stripe.provider.ts +181 -0
- package/src/globals.d.ts +19 -0
- package/src/index.ts +47 -0
- package/src/interfaces/AppState.interface.ts +4 -0
- package/src/interfaces/EditorConfiguration.interface.ts +15 -0
- package/src/interfaces/EventDeclaration.interface.ts +19 -0
- package/src/interfaces/FrontendConfig.interface.ts +42 -0
- package/src/interfaces/GenericEvents.interface.ts +6 -0
- package/src/interfaces/GenericState.interface.ts +5 -0
- package/src/interfaces/IconsPartial.ts +9 -0
- package/src/interfaces/IdTokenExtended.interface.ts +7 -0
- package/src/interfaces/ModuleBaseProps.interface.ts +8 -0
- package/src/interfaces/PaymentProvider.interface.ts +13 -0
- package/src/libs/ActionNotice.ts +235 -0
- package/src/libs/Models.class.ts +482 -0
- package/src/main.ts +84 -0
- package/src/mixins/createCookieString.ts +78 -0
- package/src/mixins/createModelDeclaration.ts +29 -0
- package/src/mixins/createRouter.ts +30 -0
- package/src/mixins/date.ts +23 -0
- package/src/mixins/formatSize.ts +12 -0
- package/src/mixins/getAnchor.ts +14 -0
- package/src/mixins/getRoutes.ts +50 -0
- package/src/mixins/hasSlotContent.ts +32 -0
- package/src/mixins/hooks.ts +104 -0
- package/src/mixins/loadComponents.ts +107 -0
- package/src/mixins/logger.ts +32 -0
- package/src/mixins/replaceVariables.ts +19 -0
- package/src/mixins/scroll.ts +83 -0
- package/src/models/Address.model.ts +24 -0
- package/src/models/Contact.model.ts +22 -0
- package/src/models.ts +2 -0
- package/src/plugins/auth.ts +121 -0
- package/src/plugins/currency.ts +26 -0
- package/src/plugins/events.ts +156 -0
- package/src/plugins/filters.ts +43 -0
- package/src/plugins/inview.ts +351 -0
- package/src/plugins/replacer.ts +18 -0
- package/src/plugins/resize.ts +128 -0
- package/src/plugins/signupFlow.ts +89 -0
- package/src/plugins/traceable.ts +53 -0
- package/src/plugins/translations.ts +29 -0
- package/src/plugins/youtube.ts +80 -0
- package/src/routes.ts +132 -0
- package/src/server-entry.ts +113 -0
- package/src/stores/calls.store.ts +33 -0
- package/src/stores/cart.store.ts +186 -0
- package/src/stores/content.store.ts +83 -0
- package/src/stores/editor.store.ts +27 -0
- package/src/stores/files.store.ts +166 -0
- package/src/stores/main.store.ts +184 -0
- package/src/stores/user.store.ts +124 -0
- package/src/translations/de.ts +138 -0
- package/src/views/content.view.vue +219 -0
- package/src/views/download.view.vue +143 -0
- package/src/views/editor.view.vue +243 -0
- package/src/views/login.view.vue +82 -0
- package/src/views/signup-account.view.vue +64 -0
- package/tooling/cypress/config.ts +80 -0
- package/tooling/cypress/generate-manifest.js +5 -0
- package/tooling/cypress/manifest-utils.mjs +40 -0
- package/tooling/cypress/run-parallel.mjs +77 -0
- package/tooling/cypress/support/commands.ts +436 -0
- package/tooling/cypress/support/e2e.ts +17 -0
- package/tooling/eslint.config.js +223 -0
- package/tooling/preview.plugin.ts +134 -0
- package/tooling/ssr-test/index.mjs +391 -0
- package/tooling/stylelint.config.mjs +24 -0
- package/tooling/vite.ts +246 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { HelpersPlugin } from '../../plugins/filters';
|
|
3
|
+
import useContentStore from '../../stores/content.store';
|
|
4
|
+
import useMainStore from '../../stores/main.store';
|
|
5
|
+
import useUserStore from '../../stores/user.store';
|
|
6
|
+
import type { BasicData, Content, ContentWithPositions, GenericData } from '@lilaquadrat/interfaces';
|
|
7
|
+
import type { SDKResponse } from '@lilaquadrat/sdk';
|
|
8
|
+
import { distributeGenericData, generateDataWithContent, hardCopy, prepareContent } from '@lilaquadrat/studio';
|
|
9
|
+
import { ref, computed, watch, onServerPrefetch, onBeforeMount } from 'vue';
|
|
10
|
+
import { useRoute } from 'vue-router';
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
type: 'footer' | 'navigation'
|
|
14
|
+
}>();
|
|
15
|
+
const store = useMainStore();
|
|
16
|
+
const userStore = useUserStore();
|
|
17
|
+
const contentStore = useContentStore();
|
|
18
|
+
const route = useRoute();
|
|
19
|
+
const data = ref<SDKResponse<BasicData<Content>>>();
|
|
20
|
+
const dataMerged = ref<ContentWithPositions>();
|
|
21
|
+
const loading = ref<number>(0);
|
|
22
|
+
const error = ref<boolean>(false);
|
|
23
|
+
const typeCache = ref<string>();
|
|
24
|
+
const contentType = computed(() => route.meta.contentType as 'public' | 'members');
|
|
25
|
+
const isLocked = computed(() => contentType.value == 'members' && userStore.locked?.length);
|
|
26
|
+
|
|
27
|
+
watch(route, () => getContent());
|
|
28
|
+
watch(() => userStore.locked, () => {
|
|
29
|
+
|
|
30
|
+
if(!userStore.locked) {
|
|
31
|
+
getContent();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
onBeforeMount(async () => await getContent());
|
|
37
|
+
onServerPrefetch(() => getStoreContent());
|
|
38
|
+
|
|
39
|
+
function getStoreContent () {
|
|
40
|
+
|
|
41
|
+
const contentId = HelpersPlugin.getFilename(route.meta.contentType as 'public' | 'members', props.type);
|
|
42
|
+
const storeContent = contentStore.findByFilename(contentId);
|
|
43
|
+
|
|
44
|
+
if(!storeContent) return;
|
|
45
|
+
|
|
46
|
+
data.value = {
|
|
47
|
+
data : storeContent,
|
|
48
|
+
status: 200,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
loading.value = 200;
|
|
52
|
+
|
|
53
|
+
dataMerged.value = mergeContent(data.value.data);
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function getContent () {
|
|
58
|
+
|
|
59
|
+
getStoreContent();
|
|
60
|
+
|
|
61
|
+
const contentId = HelpersPlugin.getFilename(route.meta.contentType as 'public' | 'members', props.type);
|
|
62
|
+
|
|
63
|
+
if(data.value?.data?.id === contentId) {
|
|
64
|
+
|
|
65
|
+
return;
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if(isLocked.value) {
|
|
70
|
+
|
|
71
|
+
loading.value = 0;
|
|
72
|
+
error.value = true;
|
|
73
|
+
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if(contentType.value !== typeCache.value) {
|
|
78
|
+
|
|
79
|
+
loading.value = 0;
|
|
80
|
+
error.value = false;
|
|
81
|
+
data.value = undefined;
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const storeData = contentStore.findByFilename(contentId);
|
|
86
|
+
|
|
87
|
+
if(storeData) {
|
|
88
|
+
|
|
89
|
+
data.value = {data: storeData, status: 200};
|
|
90
|
+
loading.value = 200;
|
|
91
|
+
return;
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// get content only if there is a difference between the current and the needed content
|
|
96
|
+
if (data.value?.data?.id !== contentId && loading.value === 0) {
|
|
97
|
+
|
|
98
|
+
loading.value = 100;
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
|
|
102
|
+
data.value = await store.getContent({filename: contentId}, contentType.value) as SDKResponse<BasicData<Content>>;
|
|
103
|
+
loading.value = data.value.status;
|
|
104
|
+
|
|
105
|
+
} catch (e: any) {
|
|
106
|
+
|
|
107
|
+
data.value = undefined;
|
|
108
|
+
error.value = true;
|
|
109
|
+
loading.value = e?.response?.status;
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if(data.value?.status === 403 || data.value?.status === 401) {
|
|
114
|
+
|
|
115
|
+
error.value = true;
|
|
116
|
+
loading.value = data.value?.status;
|
|
117
|
+
data.value = undefined;
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
typeCache.value = route.meta.contentType as string;
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if(data.value) {
|
|
126
|
+
|
|
127
|
+
dataMerged.value = mergeContent(data.value?.data);
|
|
128
|
+
|
|
129
|
+
} else {
|
|
130
|
+
|
|
131
|
+
dataMerged.value = undefined;
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function mergeContent (baseContent: BasicData<Content>) {
|
|
138
|
+
|
|
139
|
+
if(baseContent) {
|
|
140
|
+
|
|
141
|
+
const safeData = hardCopy(baseContent);
|
|
142
|
+
|
|
143
|
+
if(safeData.modules) {
|
|
144
|
+
/**
|
|
145
|
+
* content without generic data is the normal case for a static page, and
|
|
146
|
+
* generateDataWithContent reads Object.keys of what it is given - so it
|
|
147
|
+
* throws on undefined instead of returning nothing
|
|
148
|
+
*/
|
|
149
|
+
if(safeData.genericData) {
|
|
150
|
+
|
|
151
|
+
distributeGenericData(safeData.modules, generateDataWithContent(safeData.genericData as GenericData));
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return prepareContent(safeData);
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return undefined;
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
</script>
|
|
165
|
+
<template>
|
|
166
|
+
<lila-content-module v-if="dataMerged" :content="dataMerged" />
|
|
167
|
+
</template>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useResize } from '../../plugins/resize';
|
|
3
|
+
import { onMounted } from 'vue';
|
|
4
|
+
|
|
5
|
+
const {plugin} = useResize();
|
|
6
|
+
|
|
7
|
+
onMounted(() => plugin.getMediaQuery());
|
|
8
|
+
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<section id="mediadetection" class="mediadetection">
|
|
12
|
+
<div class="mobile" />
|
|
13
|
+
<div class="tablet" />
|
|
14
|
+
<div class="desktop" />
|
|
15
|
+
<div class="wide" />
|
|
16
|
+
</section>
|
|
17
|
+
</template>
|
|
18
|
+
<style lang="less" scoped>
|
|
19
|
+
.mediadetection {
|
|
20
|
+
|
|
21
|
+
.tablet,
|
|
22
|
+
.desktop,
|
|
23
|
+
.wide {
|
|
24
|
+
display: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.mobile {
|
|
28
|
+
display: block;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@media @tablet {
|
|
32
|
+
|
|
33
|
+
.mobile,
|
|
34
|
+
.desktop,
|
|
35
|
+
.wide {
|
|
36
|
+
display: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tablet {
|
|
40
|
+
display: block
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media @desktop {
|
|
45
|
+
|
|
46
|
+
.mobile,
|
|
47
|
+
.tablet,
|
|
48
|
+
.wide {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.desktop {
|
|
53
|
+
display: block;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@media @wide {
|
|
58
|
+
|
|
59
|
+
.mobile,
|
|
60
|
+
.tablet,
|
|
61
|
+
.desktop {
|
|
62
|
+
display: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.wide {
|
|
66
|
+
display: block
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import QRCode from 'qrcode';
|
|
3
|
+
import { ref, onMounted } from 'vue';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
content: string
|
|
7
|
+
}>();
|
|
8
|
+
const qrCanvas = ref<HTMLCanvasElement | null>(null);
|
|
9
|
+
|
|
10
|
+
onMounted(() => {
|
|
11
|
+
|
|
12
|
+
renderQRCode();
|
|
13
|
+
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const renderQRCode = () => {
|
|
17
|
+
|
|
18
|
+
if (qrCanvas.value) {
|
|
19
|
+
|
|
20
|
+
QRCode.toCanvas(qrCanvas.value, props.content, {
|
|
21
|
+
errorCorrectionLevel: 'M',
|
|
22
|
+
margin : 5,
|
|
23
|
+
width : 250,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
</script>
|
|
31
|
+
<template>
|
|
32
|
+
<div class="qrcode">
|
|
33
|
+
<canvas ref="qrCanvas" />
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
package/src/customs.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HelpersPlugin } from './plugins/filters'
|
|
2
|
+
import type {formatCurrency} from './plugins/currency'
|
|
3
|
+
|
|
4
|
+
export {}
|
|
5
|
+
|
|
6
|
+
declare module 'vue' {
|
|
7
|
+
interface ComponentCustomProperties {
|
|
8
|
+
$currency: typeof formatCurrency
|
|
9
|
+
$helpers: typeof HelpersPlugin
|
|
10
|
+
$replacer: (content: string) => string | undefined
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import ShopifyGraphQLAPI from './shopify.provider';
|
|
2
|
+
import type PaymentProvider from '../interfaces/PaymentProvider.interface';
|
|
3
|
+
import StripePaymentProvider from './stripe.provider';
|
|
4
|
+
|
|
5
|
+
export default function PaymentProviderFactory (type: 'internal' | 'shopify' | 'stripe', config?: Record<string, string>): PaymentProvider {
|
|
6
|
+
|
|
7
|
+
let newProvider: PaymentProvider;
|
|
8
|
+
|
|
9
|
+
if(type === 'shopify') {
|
|
10
|
+
|
|
11
|
+
if(!config?.store || !config.token) throw new Error('PAYMENT_CONFIG_MISSING');
|
|
12
|
+
|
|
13
|
+
newProvider = new ShopifyGraphQLAPI(config.store, config.token);
|
|
14
|
+
|
|
15
|
+
} else if(type === 'stripe') {
|
|
16
|
+
|
|
17
|
+
newProvider = new StripePaymentProvider();
|
|
18
|
+
|
|
19
|
+
} else {
|
|
20
|
+
|
|
21
|
+
throw new Error('NO_PAYMENT_PROVIDER');
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return newProvider;
|
|
26
|
+
|
|
27
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export class Dom {
|
|
2
|
+
|
|
3
|
+
bindings: {event: string, element: any, func: EventListenerOrEventListenerObject}[];
|
|
4
|
+
|
|
5
|
+
constructor () {
|
|
6
|
+
|
|
7
|
+
this.bindings = [];
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
on (events: string, selector: string, func: EventListener) {
|
|
12
|
+
|
|
13
|
+
const splitEvents = events.split(' ');
|
|
14
|
+
const selectedElement = this.getElement(selector);
|
|
15
|
+
|
|
16
|
+
splitEvents.forEach((event) => {
|
|
17
|
+
|
|
18
|
+
this.bindings.push({ event, element: selectedElement, func });
|
|
19
|
+
selectedElement.addEventListener(event, func);
|
|
20
|
+
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onElement (events: string, element: HTMLElement, func: EventListener) {
|
|
26
|
+
|
|
27
|
+
const splitEvents = events.split(' ');
|
|
28
|
+
|
|
29
|
+
splitEvents.forEach((event) => {
|
|
30
|
+
|
|
31
|
+
this.bindings.push({ event, element, func });
|
|
32
|
+
element.addEventListener(event, func);
|
|
33
|
+
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
off (events: string, selector: string) {
|
|
39
|
+
|
|
40
|
+
const splitEvents = events.split(' ');
|
|
41
|
+
const selectedElement = this.getElement(selector);
|
|
42
|
+
let item;
|
|
43
|
+
|
|
44
|
+
splitEvents.forEach((event) => {
|
|
45
|
+
|
|
46
|
+
item = this.bindings.find((e) => event === e.event && e.element === selectedElement);
|
|
47
|
+
|
|
48
|
+
if(!item) return;
|
|
49
|
+
|
|
50
|
+
this.bindings.splice(this.bindings.indexOf(item), 1);
|
|
51
|
+
|
|
52
|
+
selectedElement.removeEventListener(event, item.func);
|
|
53
|
+
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
destroyBindings () {
|
|
59
|
+
|
|
60
|
+
this.bindings.forEach((e) => {
|
|
61
|
+
|
|
62
|
+
e.element.removeEventListener(e.event, e.func);
|
|
63
|
+
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
this.bindings = [];
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getElement (selector: string) {
|
|
71
|
+
|
|
72
|
+
let selectedElement: Document | HTMLElement;
|
|
73
|
+
|
|
74
|
+
if (selector.length > 0) {
|
|
75
|
+
|
|
76
|
+
selectedElement = document.querySelector(selector) as HTMLElement;
|
|
77
|
+
|
|
78
|
+
} else {
|
|
79
|
+
|
|
80
|
+
selectedElement = document;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return selectedElement;
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// set title (title: string) {
|
|
89
|
+
|
|
90
|
+
// document.title = title
|
|
91
|
+
// ? `${title} ${this.store.settings?.title?.short}`
|
|
92
|
+
// : this.store.settings?.title?.full;
|
|
93
|
+
|
|
94
|
+
// }
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const dom = new Dom();
|
|
99
|
+
|
|
100
|
+
export default dom;
|