@geniusdynamics/ns8-ui-lib 1.0.2 → 1.0.4
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 +8 -18
- package/dist/ns8-ui-lib.css +1 -1
- package/dist/ns8-ui-lib.es.js +925 -921
- package/dist/ns8-ui-lib.es.js.map +1 -1
- package/dist/ns8-ui-lib.umd.js +8 -8
- package/dist/ns8-ui-lib.umd.js.map +1 -1
- package/dist/src/components/NS/cards/NSBackupCard.vue.d.ts +1 -1
- package/dist/src/components/NS/empty-state/NSEmptyState.vue.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/NS/cards/NSBackupCard.vue +95 -76
- package/src/components/NS/empty-state/NSEmptyState.vue +106 -97
|
@@ -5,8 +5,8 @@ interface Props {
|
|
|
5
5
|
lottiePath?: string;
|
|
6
6
|
lottieData?: any;
|
|
7
7
|
animationTitle?: string;
|
|
8
|
-
size?:
|
|
9
|
-
variant?:
|
|
8
|
+
size?: "default" | "sm" | "lg";
|
|
9
|
+
variant?: "default" | "muted";
|
|
10
10
|
loop?: boolean | number;
|
|
11
11
|
animateOnHover?: boolean;
|
|
12
12
|
autoPlay?: boolean;
|
package/package.json
CHANGED
|
@@ -1,111 +1,130 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
Save,
|
|
5
|
+
AlertCircle,
|
|
6
|
+
CheckCircle,
|
|
7
|
+
Loader2,
|
|
8
|
+
MoreHorizontal,
|
|
9
|
+
} from "lucide-vue-next";
|
|
10
|
+
import { Button } from "@/components/ui/button";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
Card,
|
|
14
|
+
CardContent,
|
|
15
|
+
CardDescription,
|
|
16
|
+
CardHeader,
|
|
17
|
+
CardTitle,
|
|
18
|
+
} from "@/components/ui/card";
|
|
19
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
20
|
+
import { cn } from "@/lib/utils";
|
|
8
21
|
|
|
9
22
|
interface Backup {
|
|
10
|
-
id: string
|
|
11
|
-
name: string
|
|
12
|
-
date: string
|
|
13
|
-
size: string
|
|
14
|
-
enabled: boolean
|
|
15
|
-
status?:
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
date: string;
|
|
26
|
+
size: string;
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
status?: "success" | "error" | "running" | "pending";
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
interface Status {
|
|
19
32
|
[key: string]: {
|
|
20
|
-
success?: boolean
|
|
21
|
-
message?: string
|
|
22
|
-
}
|
|
33
|
+
success?: boolean;
|
|
34
|
+
message?: string;
|
|
35
|
+
};
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
interface Props {
|
|
26
|
-
title?: string
|
|
27
|
-
loading?: boolean
|
|
28
|
-
backups?: Backup[]
|
|
29
|
-
status?: Status
|
|
30
|
-
noBackupMessage?: string
|
|
31
|
-
statusLabel?: string
|
|
32
|
-
statusSuccessLabel?: string
|
|
33
|
-
backupDisabledLabel?: string
|
|
34
|
-
light?: boolean
|
|
35
|
-
maxHeight?: string
|
|
36
|
-
class?: string
|
|
39
|
+
title?: string;
|
|
40
|
+
loading?: boolean;
|
|
41
|
+
backups?: Backup[];
|
|
42
|
+
status?: Status;
|
|
43
|
+
noBackupMessage?: string;
|
|
44
|
+
statusLabel?: string;
|
|
45
|
+
statusSuccessLabel?: string;
|
|
46
|
+
backupDisabledLabel?: string;
|
|
47
|
+
light?: boolean;
|
|
48
|
+
maxHeight?: string;
|
|
49
|
+
class?: string;
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
const props = withDefaults(defineProps<Props>(), {
|
|
40
|
-
title:
|
|
53
|
+
title: "Backup",
|
|
41
54
|
loading: false,
|
|
42
55
|
backups: () => [],
|
|
43
56
|
status: () => ({}),
|
|
44
|
-
noBackupMessage:
|
|
45
|
-
statusLabel:
|
|
46
|
-
statusSuccessLabel:
|
|
47
|
-
backupDisabledLabel:
|
|
57
|
+
noBackupMessage: "No backups available",
|
|
58
|
+
statusLabel: "Status",
|
|
59
|
+
statusSuccessLabel: "Enabled",
|
|
60
|
+
backupDisabledLabel: "Disabled",
|
|
48
61
|
light: false,
|
|
49
|
-
})
|
|
62
|
+
});
|
|
50
63
|
|
|
51
64
|
const emit = defineEmits<{
|
|
52
|
-
backup: [backupId: string]
|
|
53
|
-
restore: [backupId: string]
|
|
54
|
-
delete: [backupId: string]
|
|
55
|
-
enable: [backupId: string]
|
|
56
|
-
disable: [backupId: string]
|
|
57
|
-
}>()
|
|
65
|
+
backup: [backupId: string];
|
|
66
|
+
restore: [backupId: string];
|
|
67
|
+
delete: [backupId: string];
|
|
68
|
+
enable: [backupId: string];
|
|
69
|
+
disable: [backupId: string];
|
|
70
|
+
}>();
|
|
58
71
|
|
|
59
|
-
const hasBackups = computed(() => props.backups.length > 0)
|
|
60
|
-
const backupsContainingInstance = computed(() =>
|
|
61
|
-
|
|
72
|
+
const hasBackups = computed(() => props.backups.length > 0);
|
|
73
|
+
const backupsContainingInstance = computed(() =>
|
|
74
|
+
props.backups.filter((backup) => backup.enabled),
|
|
75
|
+
);
|
|
76
|
+
const singleBackup = computed(() =>
|
|
77
|
+
backupsContainingInstance.value.length === 1
|
|
78
|
+
? backupsContainingInstance.value[0]
|
|
79
|
+
: null,
|
|
80
|
+
);
|
|
62
81
|
|
|
63
82
|
const getStatusIcon = (backup: Backup) => {
|
|
64
83
|
switch (backup.status) {
|
|
65
|
-
case
|
|
66
|
-
return CheckCircle
|
|
67
|
-
case
|
|
68
|
-
return AlertCircle
|
|
69
|
-
case
|
|
70
|
-
return Loader2
|
|
84
|
+
case "success":
|
|
85
|
+
return CheckCircle;
|
|
86
|
+
case "error":
|
|
87
|
+
return AlertCircle;
|
|
88
|
+
case "running":
|
|
89
|
+
return Loader2;
|
|
71
90
|
default:
|
|
72
|
-
return null
|
|
91
|
+
return null;
|
|
73
92
|
}
|
|
74
|
-
}
|
|
93
|
+
};
|
|
75
94
|
|
|
76
95
|
const getStatusClass = (backup: Backup) => {
|
|
77
96
|
switch (backup.status) {
|
|
78
|
-
case
|
|
79
|
-
return
|
|
80
|
-
case
|
|
81
|
-
return
|
|
82
|
-
case
|
|
83
|
-
return
|
|
97
|
+
case "success":
|
|
98
|
+
return "text-green-600";
|
|
99
|
+
case "error":
|
|
100
|
+
return "text-destructive";
|
|
101
|
+
case "running":
|
|
102
|
+
return "text-blue-600";
|
|
84
103
|
default:
|
|
85
|
-
return
|
|
104
|
+
return "text-muted-foreground";
|
|
86
105
|
}
|
|
87
|
-
}
|
|
106
|
+
};
|
|
88
107
|
|
|
89
108
|
const containerClasses = computed(() => {
|
|
90
|
-
return cn(
|
|
91
|
-
})
|
|
109
|
+
return cn("w-full", props.class);
|
|
110
|
+
});
|
|
92
111
|
|
|
93
112
|
const cardClasses = computed(() => {
|
|
94
113
|
return cn(
|
|
95
|
-
|
|
96
|
-
props.light ?
|
|
97
|
-
)
|
|
98
|
-
})
|
|
114
|
+
"transition-all duration-200 hover:shadow-md",
|
|
115
|
+
props.light ? "bg-background/95" : "bg-background",
|
|
116
|
+
);
|
|
117
|
+
});
|
|
99
118
|
|
|
100
119
|
const tableWrapperClasses = computed(() => {
|
|
101
|
-
return cn(
|
|
102
|
-
|
|
103
|
-
})
|
|
104
|
-
})
|
|
120
|
+
return cn("w-full overflow-auto", {
|
|
121
|
+
"max-h-64": props.maxHeight,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
105
124
|
|
|
106
125
|
const tableClasses = computed(() => {
|
|
107
|
-
return
|
|
108
|
-
})
|
|
126
|
+
return "w-full min-w-[300px]";
|
|
127
|
+
});
|
|
109
128
|
</script>
|
|
110
129
|
|
|
111
130
|
<template>
|
|
@@ -125,7 +144,10 @@ const tableClasses = computed(() => {
|
|
|
125
144
|
</div>
|
|
126
145
|
|
|
127
146
|
<!-- No backups state -->
|
|
128
|
-
<div
|
|
147
|
+
<div
|
|
148
|
+
v-else-if="!hasBackups"
|
|
149
|
+
class="flex items-center gap-3 text-muted-foreground"
|
|
150
|
+
>
|
|
129
151
|
<AlertCircle class="h-5 w-5" />
|
|
130
152
|
<span>{{ noBackupMessage }}</span>
|
|
131
153
|
</div>
|
|
@@ -138,10 +160,7 @@ const tableClasses = computed(() => {
|
|
|
138
160
|
<div class="flex items-center justify-between py-2 border-b">
|
|
139
161
|
<span class="text-sm font-medium">{{ statusLabel }}</span>
|
|
140
162
|
<div class="flex items-center gap-2">
|
|
141
|
-
<span
|
|
142
|
-
v-if="!singleBackup.enabled"
|
|
143
|
-
class="text-destructive"
|
|
144
|
-
>
|
|
163
|
+
<span v-if="!singleBackup.enabled" class="text-destructive">
|
|
145
164
|
{{ backupDisabledLabel }}
|
|
146
165
|
</span>
|
|
147
166
|
<span
|
|
@@ -231,7 +250,7 @@ const tableClasses = computed(() => {
|
|
|
231
250
|
:class="cn('h-4 w-4', getStatusClass(backup))"
|
|
232
251
|
/>
|
|
233
252
|
<span :class="getStatusClass(backup)">
|
|
234
|
-
{{ backup.status ||
|
|
253
|
+
{{ backup.status || "Unknown" }}
|
|
235
254
|
</span>
|
|
236
255
|
</div>
|
|
237
256
|
</td>
|
|
@@ -269,4 +288,4 @@ const tableClasses = computed(() => {
|
|
|
269
288
|
</div>
|
|
270
289
|
</CardContent>
|
|
271
290
|
</Card>
|
|
272
|
-
</template>
|
|
291
|
+
</template>
|
|
@@ -1,133 +1,148 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
FileX,
|
|
5
|
+
Search,
|
|
6
|
+
AlertCircle,
|
|
7
|
+
Info,
|
|
8
|
+
BoxIcon,
|
|
9
|
+
Inbox,
|
|
10
|
+
} from "lucide-vue-next";
|
|
11
|
+
import { NSLottieAnimation } from "@/components/NS/lottie-animation";
|
|
12
|
+
import { cn } from "@/lib/utils";
|
|
6
13
|
|
|
7
14
|
interface Props {
|
|
8
|
-
title?: string
|
|
9
|
-
description?: string
|
|
10
|
-
icon?: string | object
|
|
11
|
-
lottiePath?: string // Path to Lottie JSON file
|
|
12
|
-
lottieData?: any // Direct Lottie animation data
|
|
13
|
-
animationTitle?: string
|
|
14
|
-
size?:
|
|
15
|
-
variant?:
|
|
16
|
-
loop?: boolean | number
|
|
17
|
-
animateOnHover?: boolean
|
|
18
|
-
autoPlay?: boolean
|
|
19
|
-
class?: string
|
|
20
|
-
iconClass?: string
|
|
21
|
-
titleClass?: string
|
|
22
|
-
descriptionClass?: string
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
icon?: string | object;
|
|
18
|
+
lottiePath?: string; // Path to Lottie JSON file
|
|
19
|
+
lottieData?: any; // Direct Lottie animation data
|
|
20
|
+
animationTitle?: string;
|
|
21
|
+
size?: "default" | "sm" | "lg";
|
|
22
|
+
variant?: "default" | "muted";
|
|
23
|
+
loop?: boolean | number;
|
|
24
|
+
animateOnHover?: boolean;
|
|
25
|
+
autoPlay?: boolean;
|
|
26
|
+
class?: string;
|
|
27
|
+
iconClass?: string;
|
|
28
|
+
titleClass?: string;
|
|
29
|
+
descriptionClass?: string;
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
-
title:
|
|
27
|
-
size:
|
|
28
|
-
variant:
|
|
33
|
+
title: "No data available",
|
|
34
|
+
size: "default",
|
|
35
|
+
variant: "default",
|
|
29
36
|
loop: true,
|
|
30
37
|
animateOnHover: false,
|
|
31
38
|
autoPlay: true,
|
|
32
|
-
})
|
|
39
|
+
});
|
|
33
40
|
|
|
34
41
|
const DefaultIcon = computed(() => {
|
|
35
42
|
if (props.icon) {
|
|
36
|
-
return null // Use custom icon
|
|
43
|
+
return null; // Use custom icon
|
|
37
44
|
}
|
|
38
|
-
|
|
45
|
+
|
|
39
46
|
// Choose appropriate default icon based on title content
|
|
40
|
-
const title = props.title?.toLowerCase() ||
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return
|
|
48
|
-
} else if (
|
|
49
|
-
|
|
47
|
+
const title = props.title?.toLowerCase() || "";
|
|
48
|
+
|
|
49
|
+
if (
|
|
50
|
+
title.includes("search") ||
|
|
51
|
+
title.includes("find") ||
|
|
52
|
+
title.includes("result")
|
|
53
|
+
) {
|
|
54
|
+
return Search;
|
|
55
|
+
} else if (
|
|
56
|
+
title.includes("empty") ||
|
|
57
|
+
title.includes("no") ||
|
|
58
|
+
title.includes("data")
|
|
59
|
+
) {
|
|
60
|
+
return FileX;
|
|
61
|
+
} else if (
|
|
62
|
+
title.includes("message") ||
|
|
63
|
+
title.includes("notification") ||
|
|
64
|
+
title.includes("alert")
|
|
65
|
+
) {
|
|
66
|
+
return Inbox;
|
|
67
|
+
} else if (title.includes("error") || title.includes("warning")) {
|
|
68
|
+
return AlertCircle;
|
|
50
69
|
} else {
|
|
51
|
-
return Info
|
|
70
|
+
return Info;
|
|
52
71
|
}
|
|
53
|
-
})
|
|
72
|
+
});
|
|
54
73
|
|
|
55
74
|
const iconComponent = computed(() => {
|
|
56
|
-
if (typeof props.icon ===
|
|
57
|
-
return props.icon // Vue component
|
|
75
|
+
if (typeof props.icon === "object") {
|
|
76
|
+
return props.icon; // Vue component
|
|
58
77
|
}
|
|
59
|
-
|
|
60
|
-
if (typeof props.icon ===
|
|
78
|
+
|
|
79
|
+
if (typeof props.icon === "string") {
|
|
61
80
|
// Map string to Lucide icons
|
|
62
81
|
const iconMap: Record<string, any> = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return iconMap[props.icon] || DefaultIcon.value
|
|
82
|
+
"file-x": FileX,
|
|
83
|
+
search: Search,
|
|
84
|
+
inbox: Inbox,
|
|
85
|
+
"alert-circle": AlertCircle,
|
|
86
|
+
info: Info,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return iconMap[props.icon] || DefaultIcon.value;
|
|
71
90
|
}
|
|
72
|
-
|
|
73
|
-
return DefaultIcon.value
|
|
74
|
-
})
|
|
91
|
+
|
|
92
|
+
return DefaultIcon.value;
|
|
93
|
+
});
|
|
75
94
|
|
|
76
95
|
const containerClasses = computed(() => {
|
|
77
96
|
const sizeClasses = {
|
|
78
|
-
default:
|
|
79
|
-
sm:
|
|
80
|
-
lg:
|
|
81
|
-
}
|
|
97
|
+
default: "p-8",
|
|
98
|
+
sm: "p-4",
|
|
99
|
+
lg: "p-12",
|
|
100
|
+
};
|
|
82
101
|
|
|
83
102
|
const variantClasses = {
|
|
84
|
-
default:
|
|
85
|
-
muted:
|
|
86
|
-
}
|
|
103
|
+
default: "text-foreground",
|
|
104
|
+
muted: "text-muted-foreground",
|
|
105
|
+
};
|
|
87
106
|
|
|
88
107
|
return cn(
|
|
89
|
-
|
|
108
|
+
"flex flex-col items-center justify-center text-center",
|
|
90
109
|
sizeClasses[props.size],
|
|
91
110
|
variantClasses[props.variant],
|
|
92
|
-
props.class
|
|
93
|
-
)
|
|
94
|
-
})
|
|
111
|
+
props.class,
|
|
112
|
+
);
|
|
113
|
+
});
|
|
95
114
|
|
|
96
115
|
const iconClasses = computed(() => {
|
|
97
116
|
const sizeClasses = {
|
|
98
|
-
default:
|
|
99
|
-
sm:
|
|
100
|
-
lg:
|
|
101
|
-
}
|
|
117
|
+
default: "h-16 w-16",
|
|
118
|
+
sm: "h-12 w-12",
|
|
119
|
+
lg: "h-20 w-20",
|
|
120
|
+
};
|
|
102
121
|
|
|
103
|
-
return cn(
|
|
104
|
-
})
|
|
122
|
+
return cn("text-muted-foreground", sizeClasses[props.size], props.iconClass);
|
|
123
|
+
});
|
|
105
124
|
|
|
106
125
|
const titleClasses = computed(() => {
|
|
107
126
|
return cn(
|
|
108
|
-
|
|
127
|
+
"text-lg font-semibold mb-2",
|
|
109
128
|
{
|
|
110
|
-
|
|
111
|
-
|
|
129
|
+
"text-foreground": props.variant === "default",
|
|
130
|
+
"text-muted-foreground": props.variant === "muted",
|
|
112
131
|
},
|
|
113
|
-
props.titleClass
|
|
114
|
-
)
|
|
115
|
-
})
|
|
132
|
+
props.titleClass,
|
|
133
|
+
);
|
|
134
|
+
});
|
|
116
135
|
|
|
117
136
|
const descriptionClasses = computed(() => {
|
|
118
137
|
return cn(
|
|
119
|
-
|
|
138
|
+
"text-sm max-w-md mb-6",
|
|
120
139
|
{
|
|
121
|
-
|
|
122
|
-
|
|
140
|
+
"text-muted-foreground": props.variant === "default",
|
|
141
|
+
"text-muted-foreground/70": props.variant === "muted",
|
|
123
142
|
},
|
|
124
|
-
props.descriptionClass
|
|
125
|
-
)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
const hasIconSlot = computed(() => !!$slots.icon)
|
|
129
|
-
const hasDescriptionSlot = computed(() => !!$slots.description)
|
|
130
|
-
const hasActionsSlot = computed(() => !!$slots.actions)
|
|
143
|
+
props.descriptionClass,
|
|
144
|
+
);
|
|
145
|
+
});
|
|
131
146
|
</script>
|
|
132
147
|
|
|
133
148
|
<template>
|
|
@@ -147,10 +162,10 @@ const hasActionsSlot = computed(() => !!$slots.actions)
|
|
|
147
162
|
:play-on-hover="true"
|
|
148
163
|
:stop-on-hover-out="true"
|
|
149
164
|
/>
|
|
150
|
-
|
|
165
|
+
|
|
151
166
|
<!-- Custom icon or default Lucide icon -->
|
|
152
167
|
<component
|
|
153
|
-
v-else-if="iconComponent &&
|
|
168
|
+
v-else-if="iconComponent && !$slots.icon"
|
|
154
169
|
:is="iconComponent"
|
|
155
170
|
:class="iconClasses"
|
|
156
171
|
/>
|
|
@@ -158,25 +173,19 @@ const hasActionsSlot = computed(() => !!$slots.actions)
|
|
|
158
173
|
</div>
|
|
159
174
|
|
|
160
175
|
<!-- Title section -->
|
|
161
|
-
<h3
|
|
162
|
-
v-if="title || $slots.title"
|
|
163
|
-
:class="titleClasses"
|
|
164
|
-
>
|
|
176
|
+
<h3 v-if="title || $slots.title" :class="titleClasses">
|
|
165
177
|
<slot name="title">{{ title }}</slot>
|
|
166
178
|
</h3>
|
|
167
179
|
|
|
168
180
|
<!-- Description section -->
|
|
169
|
-
<div
|
|
170
|
-
v-if="hasDescriptionSlot || description"
|
|
171
|
-
:class="descriptionClasses"
|
|
172
|
-
>
|
|
181
|
+
<div v-if="$slots.description || description" :class="descriptionClasses">
|
|
173
182
|
<slot name="description">
|
|
174
183
|
<p>{{ description }}</p>
|
|
175
184
|
</slot>
|
|
176
185
|
</div>
|
|
177
186
|
|
|
178
187
|
<!-- Actions section -->
|
|
179
|
-
<div v-if="
|
|
188
|
+
<div v-if="$slots.actions" class="mt-4">
|
|
180
189
|
<slot name="actions" />
|
|
181
190
|
</div>
|
|
182
191
|
|
|
@@ -185,4 +194,4 @@ const hasActionsSlot = computed(() => !!$slots.actions)
|
|
|
185
194
|
<slot name="extra" />
|
|
186
195
|
</div>
|
|
187
196
|
</div>
|
|
188
|
-
</template>
|
|
197
|
+
</template>
|