@katlux/block-ecommerce 0.1.0-beta.0 → 0.1.0-beta.10
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/module.d.mts +6 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +23 -0
- package/dist/runtime/components/KProductList/KProductList.d.vue.ts +32 -0
- package/dist/runtime/components/KProductList/KProductList.logic.d.ts +52 -0
- package/dist/runtime/components/KProductList/KProductList.logic.js +48 -0
- package/{src → dist}/runtime/components/KProductList/KProductList.vue +24 -34
- package/dist/runtime/components/KProductList/KProductList.vue.d.ts +32 -0
- package/dist/runtime/components/KProductListItem/KProductListItem.d.vue.ts +8 -0
- package/dist/runtime/components/KProductListItem/KProductListItem.logic.d.ts +20 -0
- package/dist/runtime/components/KProductListItem/KProductListItem.logic.js +25 -0
- package/dist/runtime/components/KProductListItem/KProductListItem.vue +113 -0
- package/dist/runtime/components/KProductListItem/KProductListItem.vue.d.ts +8 -0
- package/dist/types.d.mts +3 -0
- package/package.json +7 -3
- package/build.config.ts +0 -4
- package/src/module.ts +0 -25
- package/src/runtime/components/KProductList/KProductList.logic.ts +0 -64
- package/src/runtime/components/KProductListItem/KProductListItem.logic.ts +0 -36
- package/src/runtime/components/KProductListItem/KProductListItem.vue +0 -129
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addComponentsDir } from '@nuxt/kit';
|
|
2
|
+
|
|
3
|
+
const module$1 = defineNuxtModule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "@katlux/block-ecommerce",
|
|
6
|
+
configKey: "katluxEcommerceBlocks",
|
|
7
|
+
compatibility: {
|
|
8
|
+
nuxt: "^3.0.0"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
defaults: {},
|
|
12
|
+
async setup(options, nuxt) {
|
|
13
|
+
const resolver = createResolver(import.meta.url);
|
|
14
|
+
addComponentsDir({
|
|
15
|
+
path: resolver.resolve("./runtime/components"),
|
|
16
|
+
pathPrefix: false,
|
|
17
|
+
prefix: "",
|
|
18
|
+
global: true
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { KProductRowAction } from '@katlux/providers';
|
|
2
|
+
import { ADataProvider } from '@katlux/providers';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
dataProvider: ADataProvider;
|
|
5
|
+
layout?: 'grid' | 'list';
|
|
6
|
+
rowActions?: KProductRowAction[];
|
|
7
|
+
gridColumns?: number | string;
|
|
8
|
+
gap?: string;
|
|
9
|
+
};
|
|
10
|
+
declare var __VLS_1: {
|
|
11
|
+
item: import("@katlux/providers").TDataRow;
|
|
12
|
+
index: number;
|
|
13
|
+
}, __VLS_11: string, __VLS_12: any;
|
|
14
|
+
type __VLS_Slots = {} & {
|
|
15
|
+
[K in NonNullable<typeof __VLS_11>]?: (props: typeof __VLS_12) => any;
|
|
16
|
+
} & {
|
|
17
|
+
default?: (props: typeof __VLS_1) => any;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
20
|
+
rowActions: KProductRowAction[];
|
|
21
|
+
layout: "grid" | "list";
|
|
22
|
+
gridColumns: number | string;
|
|
23
|
+
gap: string;
|
|
24
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
25
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
26
|
+
declare const _default: typeof __VLS_export;
|
|
27
|
+
export default _default;
|
|
28
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
29
|
+
new (): {
|
|
30
|
+
$slots: S;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ADataProvider, KProductRowAction } from '@katlux/providers';
|
|
2
|
+
import { type PropType } from 'vue';
|
|
3
|
+
export interface KProductListProps {
|
|
4
|
+
dataProvider: ADataProvider;
|
|
5
|
+
layout?: 'grid' | 'list';
|
|
6
|
+
rowActions?: KProductRowAction[];
|
|
7
|
+
gridColumns?: number | string;
|
|
8
|
+
gap?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const KProductListDefaultProps: {
|
|
11
|
+
dataProvider: {
|
|
12
|
+
type: PropType<ADataProvider>;
|
|
13
|
+
required: boolean;
|
|
14
|
+
};
|
|
15
|
+
layout: {
|
|
16
|
+
type: PropType<"grid" | "list">;
|
|
17
|
+
default: string;
|
|
18
|
+
};
|
|
19
|
+
rowActions: {
|
|
20
|
+
type: PropType<KProductRowAction[]>;
|
|
21
|
+
default: () => never[];
|
|
22
|
+
};
|
|
23
|
+
gridColumns: {
|
|
24
|
+
type: (StringConstructor | NumberConstructor)[];
|
|
25
|
+
default: number;
|
|
26
|
+
};
|
|
27
|
+
gap: {
|
|
28
|
+
type: StringConstructor;
|
|
29
|
+
default: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export declare function useKProductListLogic(props: KProductListProps): {
|
|
33
|
+
isGrid: import("vue").ComputedRef<boolean>;
|
|
34
|
+
gridStyles: import("vue").ComputedRef<{
|
|
35
|
+
display?: undefined;
|
|
36
|
+
gridTemplateColumns?: undefined;
|
|
37
|
+
gap?: undefined;
|
|
38
|
+
} | {
|
|
39
|
+
display: string;
|
|
40
|
+
gridTemplateColumns: string;
|
|
41
|
+
gap: string | undefined;
|
|
42
|
+
}>;
|
|
43
|
+
listStyles: import("vue").ComputedRef<{
|
|
44
|
+
display?: undefined;
|
|
45
|
+
flexDirection?: undefined;
|
|
46
|
+
gap?: undefined;
|
|
47
|
+
} | {
|
|
48
|
+
display: string;
|
|
49
|
+
flexDirection: "column";
|
|
50
|
+
gap: string | undefined;
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
export const KProductListDefaultProps = {
|
|
3
|
+
dataProvider: {
|
|
4
|
+
type: Object,
|
|
5
|
+
required: true
|
|
6
|
+
},
|
|
7
|
+
layout: {
|
|
8
|
+
type: String,
|
|
9
|
+
default: "grid"
|
|
10
|
+
},
|
|
11
|
+
rowActions: {
|
|
12
|
+
type: Array,
|
|
13
|
+
default: () => []
|
|
14
|
+
},
|
|
15
|
+
gridColumns: {
|
|
16
|
+
type: [Number, String],
|
|
17
|
+
default: 4
|
|
18
|
+
},
|
|
19
|
+
gap: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: "1rem"
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export function useKProductListLogic(props) {
|
|
25
|
+
const isGrid = computed(() => props.layout !== "list");
|
|
26
|
+
const gridStyles = computed(() => {
|
|
27
|
+
if (!isGrid.value) return {};
|
|
28
|
+
const cols = props.gridColumns;
|
|
29
|
+
return {
|
|
30
|
+
display: "grid",
|
|
31
|
+
gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
|
|
32
|
+
gap: props.gap
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const listStyles = computed(() => {
|
|
36
|
+
if (isGrid.value) return {};
|
|
37
|
+
return {
|
|
38
|
+
display: "flex",
|
|
39
|
+
flexDirection: "column",
|
|
40
|
+
gap: props.gap
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
isGrid,
|
|
45
|
+
gridStyles,
|
|
46
|
+
listStyles
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -29,42 +29,32 @@
|
|
|
29
29
|
</div>
|
|
30
30
|
</template>
|
|
31
31
|
|
|
32
|
-
<script
|
|
33
|
-
import
|
|
34
|
-
import {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}>(), {
|
|
44
|
-
layout: 'grid',
|
|
45
|
-
rowActions: () => [],
|
|
46
|
-
gridColumns: 4,
|
|
47
|
-
gap: '1rem'
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
const { isGrid, gridStyles, listStyles } = useKProductListLogic(props as any)
|
|
32
|
+
<script setup>
|
|
33
|
+
import { ADataProvider } from "@katlux/providers";
|
|
34
|
+
import { useKProductListLogic } from "./KProductList.logic";
|
|
35
|
+
const props = defineProps({
|
|
36
|
+
dataProvider: { type: Object, required: true },
|
|
37
|
+
layout: { type: String, required: false, default: "grid" },
|
|
38
|
+
rowActions: { type: Array, required: false, default: () => [] },
|
|
39
|
+
gridColumns: { type: [Number, String], required: false, default: 4 },
|
|
40
|
+
gap: { type: String, required: false, default: "1rem" }
|
|
41
|
+
});
|
|
42
|
+
const { isGrid, gridStyles, listStyles } = useKProductListLogic(props);
|
|
51
43
|
</script>
|
|
52
44
|
|
|
53
|
-
<style
|
|
45
|
+
<style scoped>
|
|
54
46
|
.k-product-list {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
}
|
|
47
|
+
width: 100%;
|
|
48
|
+
}
|
|
49
|
+
.k-product-list .list-container {
|
|
50
|
+
width: 100%;
|
|
51
|
+
}
|
|
52
|
+
.k-product-list .footer {
|
|
53
|
+
display: flex;
|
|
54
|
+
justify-content: flex-end;
|
|
55
|
+
margin-top: var(--gap-lg, 24px);
|
|
56
|
+
}
|
|
57
|
+
.k-product-list .footer .pagination {
|
|
58
|
+
flex: 1;
|
|
69
59
|
}
|
|
70
60
|
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { KProductRowAction } from '@katlux/providers';
|
|
2
|
+
import { ADataProvider } from '@katlux/providers';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
dataProvider: ADataProvider;
|
|
5
|
+
layout?: 'grid' | 'list';
|
|
6
|
+
rowActions?: KProductRowAction[];
|
|
7
|
+
gridColumns?: number | string;
|
|
8
|
+
gap?: string;
|
|
9
|
+
};
|
|
10
|
+
declare var __VLS_1: {
|
|
11
|
+
item: import("@katlux/providers").TDataRow;
|
|
12
|
+
index: number;
|
|
13
|
+
}, __VLS_11: string, __VLS_12: any;
|
|
14
|
+
type __VLS_Slots = {} & {
|
|
15
|
+
[K in NonNullable<typeof __VLS_11>]?: (props: typeof __VLS_12) => any;
|
|
16
|
+
} & {
|
|
17
|
+
default?: (props: typeof __VLS_1) => any;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
20
|
+
rowActions: KProductRowAction[];
|
|
21
|
+
layout: "grid" | "list";
|
|
22
|
+
gridColumns: number | string;
|
|
23
|
+
gap: string;
|
|
24
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
25
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
26
|
+
declare const _default: typeof __VLS_export;
|
|
27
|
+
export default _default;
|
|
28
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
29
|
+
new (): {
|
|
30
|
+
$slots: S;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { KProductItemData, KProductRowAction } from '@katlux/providers';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
item: KProductItemData;
|
|
4
|
+
rowActions?: KProductRowAction[];
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type PropType } from 'vue';
|
|
2
|
+
import type { KProductItemData, KProductRowAction } from '@katlux/providers';
|
|
3
|
+
export interface KProductListItemProps {
|
|
4
|
+
item: KProductItemData;
|
|
5
|
+
rowActions?: KProductRowAction[];
|
|
6
|
+
}
|
|
7
|
+
export declare const KProductListItemDefaultProps: {
|
|
8
|
+
item: {
|
|
9
|
+
type: PropType<KProductItemData>;
|
|
10
|
+
required: true;
|
|
11
|
+
};
|
|
12
|
+
rowActions: {
|
|
13
|
+
type: PropType<KProductRowAction[]>;
|
|
14
|
+
default: () => never[];
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare function useKProductListItemLogic(props: KProductListItemProps): {
|
|
18
|
+
hasActions: import("vue").ComputedRef<boolean | undefined>;
|
|
19
|
+
formattedPrice: import("vue").ComputedRef<string>;
|
|
20
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
export const KProductListItemDefaultProps = {
|
|
3
|
+
item: {
|
|
4
|
+
type: Object,
|
|
5
|
+
required: true
|
|
6
|
+
},
|
|
7
|
+
rowActions: {
|
|
8
|
+
type: Array,
|
|
9
|
+
default: () => []
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export function useKProductListItemLogic(props) {
|
|
13
|
+
const hasActions = computed(() => props.rowActions && props.rowActions.length > 0);
|
|
14
|
+
const formattedPrice = computed(() => {
|
|
15
|
+
if (props.item.price === void 0) return "";
|
|
16
|
+
return new Intl.NumberFormat("en-US", {
|
|
17
|
+
style: "currency",
|
|
18
|
+
currency: props.item.currency || "USD"
|
|
19
|
+
}).format(props.item.price);
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
hasActions,
|
|
23
|
+
formattedPrice
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.k-product-list-item
|
|
3
|
+
.item-image(v-if="item.image")
|
|
4
|
+
img(:src="item.image" :alt="item.title")
|
|
5
|
+
.item-image-placeholder(v-else)
|
|
6
|
+
KIcon(name="tabler:photo" class="placeholder-icon")
|
|
7
|
+
.item-details
|
|
8
|
+
h3.item-title {{ item.title }}
|
|
9
|
+
p.item-description(v-if="item.description") {{ item.description }}
|
|
10
|
+
.item-price(v-if="formattedPrice") {{ formattedPrice }}
|
|
11
|
+
.item-actions(v-if="hasActions")
|
|
12
|
+
KButton(
|
|
13
|
+
v-for="(action, index) in rowActions"
|
|
14
|
+
:key="index"
|
|
15
|
+
:class="action.color || 'primary'"
|
|
16
|
+
@click="action.action(item)"
|
|
17
|
+
)
|
|
18
|
+
template(v-if="action.icon" #icon)
|
|
19
|
+
KIcon(:name="action.icon")
|
|
20
|
+
| {{ action.label }}
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
const props = defineProps({
|
|
25
|
+
item: { type: Object, required: true },
|
|
26
|
+
rowActions: { type: Array, required: false }
|
|
27
|
+
});
|
|
28
|
+
import { useKProductListItemLogic } from "./KProductListItem.logic";
|
|
29
|
+
const { hasActions, formattedPrice } = useKProductListItemLogic(props);
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<style scoped>
|
|
33
|
+
.k-product-list-item {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
border: 1px solid var(--border-color-light, #e9ecef);
|
|
37
|
+
border-radius: var(--border-radius-md, 8px);
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
background: var(--bg-color-surface, #ffffff);
|
|
40
|
+
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
|
41
|
+
height: 100%;
|
|
42
|
+
}
|
|
43
|
+
.k-product-list-item:hover {
|
|
44
|
+
box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.08));
|
|
45
|
+
transform: translateY(-2px);
|
|
46
|
+
}
|
|
47
|
+
.k-product-list-item .item-image, .k-product-list-item .item-image-placeholder {
|
|
48
|
+
width: 100%;
|
|
49
|
+
aspect-ratio: 1;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
justify-content: center;
|
|
54
|
+
background: var(--bg-color-muted, #f8f9fa);
|
|
55
|
+
border-bottom: 1px solid var(--border-color-light, #e9ecef);
|
|
56
|
+
}
|
|
57
|
+
.k-product-list-item .item-image img {
|
|
58
|
+
width: 100%;
|
|
59
|
+
height: 100%;
|
|
60
|
+
object-fit: cover;
|
|
61
|
+
transition: transform 0.3s ease;
|
|
62
|
+
}
|
|
63
|
+
.k-product-list-item:hover .item-image img {
|
|
64
|
+
transform: scale(1.05);
|
|
65
|
+
}
|
|
66
|
+
.k-product-list-item .item-image-placeholder .placeholder-icon {
|
|
67
|
+
font-size: 3rem;
|
|
68
|
+
color: var(--text-color-muted, #adb5bd);
|
|
69
|
+
opacity: 0.5;
|
|
70
|
+
}
|
|
71
|
+
.k-product-list-item .item-details {
|
|
72
|
+
padding: var(--gap-md, 16px);
|
|
73
|
+
flex-grow: 1;
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
}
|
|
77
|
+
.k-product-list-item .item-title {
|
|
78
|
+
margin: 0 0 var(--gap-xs, 4px) 0;
|
|
79
|
+
font-size: var(--font-size-lg, 1.1rem);
|
|
80
|
+
font-weight: 600;
|
|
81
|
+
color: var(--text-color-primary, #212529);
|
|
82
|
+
line-height: 1.3;
|
|
83
|
+
}
|
|
84
|
+
.k-product-list-item .item-description {
|
|
85
|
+
margin: 0 0 var(--gap-sm, 8px) 0;
|
|
86
|
+
font-size: var(--font-size-sm, 0.9rem);
|
|
87
|
+
color: var(--text-color-secondary, #6c757d);
|
|
88
|
+
line-height: 1.4;
|
|
89
|
+
flex-grow: 1;
|
|
90
|
+
display: -webkit-box;
|
|
91
|
+
-webkit-line-clamp: 2;
|
|
92
|
+
-webkit-box-orient: vertical;
|
|
93
|
+
overflow: hidden;
|
|
94
|
+
}
|
|
95
|
+
.k-product-list-item .item-price {
|
|
96
|
+
font-size: var(--font-size-xl, 1.25rem);
|
|
97
|
+
font-weight: 700;
|
|
98
|
+
color: var(--color-primary, #0d6efd);
|
|
99
|
+
margin-top: auto;
|
|
100
|
+
padding-top: var(--gap-sm, 8px);
|
|
101
|
+
}
|
|
102
|
+
.k-product-list-item .item-actions {
|
|
103
|
+
padding: var(--gap-md, 16px);
|
|
104
|
+
padding-top: 0;
|
|
105
|
+
display: flex;
|
|
106
|
+
gap: var(--gap-sm, 8px);
|
|
107
|
+
flex-wrap: wrap;
|
|
108
|
+
}
|
|
109
|
+
.k-product-list-item .item-actions :deep(.KButton) {
|
|
110
|
+
flex: 1;
|
|
111
|
+
min-width: 100px;
|
|
112
|
+
}
|
|
113
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { KProductItemData, KProductRowAction } from '@katlux/providers';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
item: KProductItemData;
|
|
4
|
+
rowActions?: KProductRowAction[];
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|
package/dist/types.d.mts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@katlux/block-ecommerce",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.10",
|
|
4
4
|
"description": "Pre-built eCommerce block components for Katlux toolkit",
|
|
5
5
|
"author": "Katlux",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"main": "./dist/module.mjs",
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "nuxt-module-build build",
|
|
13
|
-
"dev": "nuxt-module-build build --stub"
|
|
13
|
+
"dev": "nuxt-module-build build --stub",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
14
15
|
},
|
|
15
16
|
"exports": {
|
|
16
17
|
".": {
|
|
@@ -27,5 +28,8 @@
|
|
|
27
28
|
"@nuxt/kit": "^3.20.1",
|
|
28
29
|
"pug": "^3.0.0",
|
|
29
30
|
"sass": "^1.80.0"
|
|
30
|
-
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
]
|
|
31
35
|
}
|
package/build.config.ts
DELETED
package/src/module.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, addComponentsDir } from '@nuxt/kit'
|
|
2
|
-
|
|
3
|
-
export interface ModuleOptions { }
|
|
4
|
-
|
|
5
|
-
export default defineNuxtModule<ModuleOptions>({
|
|
6
|
-
meta: {
|
|
7
|
-
name: '@katlux/block-ecommerce',
|
|
8
|
-
configKey: 'katluxEcommerceBlocks',
|
|
9
|
-
compatibility: {
|
|
10
|
-
nuxt: '^3.0.0'
|
|
11
|
-
}
|
|
12
|
-
},
|
|
13
|
-
defaults: {},
|
|
14
|
-
async setup(options, nuxt) {
|
|
15
|
-
const resolver = createResolver(import.meta.url)
|
|
16
|
-
|
|
17
|
-
// Add components directory
|
|
18
|
-
addComponentsDir({
|
|
19
|
-
path: resolver.resolve('./runtime/components'),
|
|
20
|
-
pathPrefix: false,
|
|
21
|
-
prefix: '',
|
|
22
|
-
global: true
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
})
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ADataProvider, KProductItemData, KProductRowAction } from '@katlux/providers'
|
|
2
|
-
import { computed, type PropType } from 'vue'
|
|
3
|
-
|
|
4
|
-
export interface KProductListProps {
|
|
5
|
-
dataProvider: ADataProvider
|
|
6
|
-
layout?: 'grid' | 'list'
|
|
7
|
-
rowActions?: KProductRowAction[]
|
|
8
|
-
gridColumns?: number | string
|
|
9
|
-
gap?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const KProductListDefaultProps = {
|
|
13
|
-
dataProvider: {
|
|
14
|
-
type: Object as PropType<ADataProvider>,
|
|
15
|
-
required: true,
|
|
16
|
-
},
|
|
17
|
-
layout: {
|
|
18
|
-
type: String as PropType<'grid' | 'list'>,
|
|
19
|
-
default: 'grid',
|
|
20
|
-
},
|
|
21
|
-
rowActions: {
|
|
22
|
-
type: Array as PropType<KProductRowAction[]>,
|
|
23
|
-
default: () => [],
|
|
24
|
-
},
|
|
25
|
-
gridColumns: {
|
|
26
|
-
type: [Number, String],
|
|
27
|
-
default: 4,
|
|
28
|
-
},
|
|
29
|
-
gap: {
|
|
30
|
-
type: String,
|
|
31
|
-
default: '1rem',
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function useKProductListLogic(props: KProductListProps) {
|
|
36
|
-
const isGrid = computed(() => props.layout !== 'list')
|
|
37
|
-
|
|
38
|
-
const gridStyles = computed(() => {
|
|
39
|
-
if (!isGrid.value) return {}
|
|
40
|
-
|
|
41
|
-
const cols = props.gridColumns
|
|
42
|
-
return {
|
|
43
|
-
display: 'grid',
|
|
44
|
-
gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
|
|
45
|
-
gap: props.gap
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
const listStyles = computed(() => {
|
|
50
|
-
if (isGrid.value) return {}
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
display: 'flex',
|
|
54
|
-
flexDirection: 'column' as const,
|
|
55
|
-
gap: props.gap
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
isGrid,
|
|
61
|
-
gridStyles,
|
|
62
|
-
listStyles
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { computed, type PropType } from 'vue'
|
|
2
|
-
import type { KProductItemData, KProductRowAction } from '@katlux/providers'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface KProductListItemProps {
|
|
6
|
-
item: KProductItemData
|
|
7
|
-
rowActions?: KProductRowAction[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const KProductListItemDefaultProps = {
|
|
11
|
-
item: {
|
|
12
|
-
type: Object as PropType<KProductItemData>,
|
|
13
|
-
required: true as const,
|
|
14
|
-
},
|
|
15
|
-
rowActions: {
|
|
16
|
-
type: Array as PropType<KProductRowAction[]>,
|
|
17
|
-
default: () => [],
|
|
18
|
-
},
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function useKProductListItemLogic(props: KProductListItemProps) {
|
|
22
|
-
const hasActions = computed(() => props.rowActions && props.rowActions.length > 0)
|
|
23
|
-
|
|
24
|
-
const formattedPrice = computed(() => {
|
|
25
|
-
if (props.item.price === undefined) return ''
|
|
26
|
-
return new Intl.NumberFormat('en-US', {
|
|
27
|
-
style: 'currency',
|
|
28
|
-
currency: props.item.currency || 'USD'
|
|
29
|
-
}).format(props.item.price)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
hasActions,
|
|
34
|
-
formattedPrice
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
<template lang="pug">
|
|
2
|
-
.k-product-list-item
|
|
3
|
-
.item-image(v-if="item.image")
|
|
4
|
-
img(:src="item.image" :alt="item.title")
|
|
5
|
-
.item-image-placeholder(v-else)
|
|
6
|
-
KIcon(name="tabler:photo" class="placeholder-icon")
|
|
7
|
-
.item-details
|
|
8
|
-
h3.item-title {{ item.title }}
|
|
9
|
-
p.item-description(v-if="item.description") {{ item.description }}
|
|
10
|
-
.item-price(v-if="formattedPrice") {{ formattedPrice }}
|
|
11
|
-
.item-actions(v-if="hasActions")
|
|
12
|
-
KButton(
|
|
13
|
-
v-for="(action, index) in rowActions"
|
|
14
|
-
:key="index"
|
|
15
|
-
:class="action.color || 'primary'"
|
|
16
|
-
@click="action.action(item)"
|
|
17
|
-
)
|
|
18
|
-
template(v-if="action.icon" #icon)
|
|
19
|
-
KIcon(:name="action.icon")
|
|
20
|
-
| {{ action.label }}
|
|
21
|
-
</template>
|
|
22
|
-
|
|
23
|
-
<script lang="ts" setup>
|
|
24
|
-
import type { KProductItemData, KProductRowAction } from '@katlux/providers'
|
|
25
|
-
|
|
26
|
-
const props = defineProps<{
|
|
27
|
-
item: KProductItemData
|
|
28
|
-
rowActions?: KProductRowAction[]
|
|
29
|
-
}>()
|
|
30
|
-
|
|
31
|
-
import { useKProductListItemLogic } from './KProductListItem.logic'
|
|
32
|
-
const { hasActions, formattedPrice } = useKProductListItemLogic(props)
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<style lang="scss" scoped>
|
|
36
|
-
.k-product-list-item {
|
|
37
|
-
display: flex;
|
|
38
|
-
flex-direction: column;
|
|
39
|
-
border: 1px solid var(--border-color-light, #e9ecef);
|
|
40
|
-
border-radius: var(--border-radius-md, 8px);
|
|
41
|
-
overflow: hidden;
|
|
42
|
-
background: var(--bg-color-surface, #ffffff);
|
|
43
|
-
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
|
44
|
-
height: 100%;
|
|
45
|
-
|
|
46
|
-
&:hover {
|
|
47
|
-
box-shadow: var(--shadow-md, 0 4px 12px rgba(0,0,0,0.08));
|
|
48
|
-
transform: translateY(-2px);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.item-image, .item-image-placeholder {
|
|
52
|
-
width: 100%;
|
|
53
|
-
aspect-ratio: 1;
|
|
54
|
-
overflow: hidden;
|
|
55
|
-
display: flex;
|
|
56
|
-
align-items: center;
|
|
57
|
-
justify-content: center;
|
|
58
|
-
background: var(--bg-color-muted, #f8f9fa);
|
|
59
|
-
border-bottom: 1px solid var(--border-color-light, #e9ecef);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.item-image img {
|
|
63
|
-
width: 100%;
|
|
64
|
-
height: 100%;
|
|
65
|
-
object-fit: cover;
|
|
66
|
-
transition: transform 0.3s ease;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
&:hover .item-image img {
|
|
70
|
-
transform: scale(1.05);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.item-image-placeholder {
|
|
74
|
-
.placeholder-icon {
|
|
75
|
-
font-size: 3rem;
|
|
76
|
-
color: var(--text-color-muted, #adb5bd);
|
|
77
|
-
opacity: 0.5;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.item-details {
|
|
82
|
-
padding: var(--gap-md, 16px);
|
|
83
|
-
flex-grow: 1;
|
|
84
|
-
display: flex;
|
|
85
|
-
flex-direction: column;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.item-title {
|
|
89
|
-
margin: 0 0 var(--gap-xs, 4px) 0;
|
|
90
|
-
font-size: var(--font-size-lg, 1.1rem);
|
|
91
|
-
font-weight: 600;
|
|
92
|
-
color: var(--text-color-primary, #212529);
|
|
93
|
-
line-height: 1.3;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.item-description {
|
|
97
|
-
margin: 0 0 var(--gap-sm, 8px) 0;
|
|
98
|
-
font-size: var(--font-size-sm, 0.9rem);
|
|
99
|
-
color: var(--text-color-secondary, #6c757d);
|
|
100
|
-
line-height: 1.4;
|
|
101
|
-
flex-grow: 1;
|
|
102
|
-
display: -webkit-box;
|
|
103
|
-
-webkit-line-clamp: 2;
|
|
104
|
-
-webkit-box-orient: vertical;
|
|
105
|
-
overflow: hidden;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.item-price {
|
|
109
|
-
font-size: var(--font-size-xl, 1.25rem);
|
|
110
|
-
font-weight: 700;
|
|
111
|
-
color: var(--color-primary, #0d6efd);
|
|
112
|
-
margin-top: auto;
|
|
113
|
-
padding-top: var(--gap-sm, 8px);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.item-actions {
|
|
117
|
-
padding: var(--gap-md, 16px);
|
|
118
|
-
padding-top: 0;
|
|
119
|
-
display: flex;
|
|
120
|
-
gap: var(--gap-sm, 8px);
|
|
121
|
-
flex-wrap: wrap;
|
|
122
|
-
|
|
123
|
-
:deep(.KButton) {
|
|
124
|
-
flex: 1;
|
|
125
|
-
min-width: 100px;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
</style>
|