manolis-ui 0.0.1
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 +5 -0
- package/dist/App.vue.d.ts +2 -0
- package/dist/components/actions/ButtonComponent.vue.d.ts +29 -0
- package/dist/components/actions/dropdown.vue.d.ts +47 -0
- package/dist/components/actions/modal.vue.d.ts +36 -0
- package/dist/components/actions/swap.vue.d.ts +21 -0
- package/dist/components/actions/theme-controller.vue.d.ts +9 -0
- package/dist/components/data-display/accordion.vue.d.ts +14 -0
- package/dist/components/data-display/avatar.vue.d.ts +9 -0
- package/dist/components/data-display/badge.vue.d.ts +26 -0
- package/dist/components/data-display/card.vue.d.ts +35 -0
- package/dist/components/data-input/advancedSearch.vue.d.ts +46 -0
- package/dist/components/data-input/rating.vue.d.ts +15 -0
- package/dist/components/feedback/loader.vue.d.ts +7 -0
- package/dist/components/layout/footer.vue.d.ts +29 -0
- package/dist/components/layout/hero.vue.d.ts +23 -0
- package/dist/components/navigation/categoryNavigation.vue.d.ts +22 -0
- package/dist/components/navigation/navigationBar.vue.d.ts +25 -0
- package/dist/components/navigation/tab.vue.d.ts +24 -0
- package/dist/index.d.ts +18 -0
- package/dist/main.d.ts +0 -0
- package/dist/manolis-ui.css +1 -0
- package/dist/manolis-ui.js +1278 -0
- package/dist/manolis-ui.umd.cjs +36 -0
- package/dist/style.css +3170 -0
- package/dist/vite.svg +1 -0
- package/package.json +72 -0
- package/src/components/actions/ButtonComponent.vue +80 -0
- package/src/components/actions/dropdown.vue +46 -0
- package/src/components/actions/modal.vue +52 -0
- package/src/components/actions/swap.vue +15 -0
- package/src/components/actions/theme-controller.vue +52 -0
- package/src/components/data-display/accordion.vue +29 -0
- package/src/components/data-display/avatar.vue +36 -0
- package/src/components/data-display/badge.vue +35 -0
- package/src/components/data-display/card.vue +60 -0
- package/src/components/data-display/carousel.vue +34 -0
- package/src/components/data-input/advancedSearch.vue +227 -0
- package/src/components/data-input/datetimePicker.vue +409 -0
- package/src/components/data-input/input.vue +98 -0
- package/src/components/data-input/rating.vue +60 -0
- package/src/components/feedback/loader.vue +25 -0
- package/src/components/layout/footer.vue +42 -0
- package/src/components/layout/hero.vue +15 -0
- package/src/components/navigation/categoryNavigation.vue +40 -0
- package/src/components/navigation/navigationBar.vue +107 -0
- package/src/components/navigation/tab.vue +62 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<!-- <script setup lang="ts">
|
|
2
|
+
import { ref, watch, withDefaults } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
9
|
+
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const rating = ref<number>(props.initialRating);
|
|
13
|
+
|
|
14
|
+
const updateRating = (newRating: number) => {
|
|
15
|
+
rating.value = newRating;
|
|
16
|
+
};
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<input type="text" placeholder="Type here" class="w-full max-w-xs input" v-model="" />
|
|
21
|
+
</template> -->
|
|
22
|
+
|
|
23
|
+
<script setup lang="ts">
|
|
24
|
+
import { defineProps, defineEmits } from "vue";
|
|
25
|
+
|
|
26
|
+
// Define props with TypeScript types
|
|
27
|
+
const props = defineProps<{
|
|
28
|
+
modelValue: string;
|
|
29
|
+
label?: string;
|
|
30
|
+
labelSecondary?: string;
|
|
31
|
+
placeholder?: string;
|
|
32
|
+
type?: "text" | "password" | "email" | "number" | "tel" | "url" | "search";
|
|
33
|
+
size: "xs" | "sm" | "md" | "lg";
|
|
34
|
+
bordered: boolean;
|
|
35
|
+
inputClass?: string;
|
|
36
|
+
wrapperClass?: string;
|
|
37
|
+
helperText?: string;
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
readonly?: boolean;
|
|
40
|
+
name?: string;
|
|
41
|
+
}>();
|
|
42
|
+
|
|
43
|
+
// Default prop values
|
|
44
|
+
const {
|
|
45
|
+
label = "",
|
|
46
|
+
labelSecondary = "",
|
|
47
|
+
placeholder = "",
|
|
48
|
+
bordered = true,
|
|
49
|
+
type = "text",
|
|
50
|
+
size = "md",
|
|
51
|
+
wrapperClass = "",
|
|
52
|
+
helperText = "",
|
|
53
|
+
disabled = false,
|
|
54
|
+
readonly = false,
|
|
55
|
+
name = "",
|
|
56
|
+
} = props;
|
|
57
|
+
|
|
58
|
+
// Define emits with TypeScript types
|
|
59
|
+
const emit = defineEmits<{
|
|
60
|
+
(e: "updated", value: string): void;
|
|
61
|
+
}>();
|
|
62
|
+
|
|
63
|
+
// Update the input value on user input
|
|
64
|
+
const updateValue = (event: Event) => {
|
|
65
|
+
const target = event.target as HTMLInputElement;
|
|
66
|
+
emit("updated", target.value);
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div class="form-control w-full" :class="wrapperClass">
|
|
72
|
+
<!-- Input Label -->
|
|
73
|
+
<label v-if="label" class="label">
|
|
74
|
+
<span class="label-text">{{ label }}</span>
|
|
75
|
+
<span v-if="labelSecondary" class="label-text-alt">{{ labelSecondary }}</span>
|
|
76
|
+
</label>
|
|
77
|
+
|
|
78
|
+
<!-- Input Field -->
|
|
79
|
+
<input
|
|
80
|
+
:type="type"
|
|
81
|
+
:value="modelValue"
|
|
82
|
+
:placeholder="placeholder"
|
|
83
|
+
class="w-full input"
|
|
84
|
+
:class="[`input-${size}` ,{
|
|
85
|
+
'bordered': bordered,
|
|
86
|
+
}]"
|
|
87
|
+
:disabled="disabled"
|
|
88
|
+
:readonly="readonly"
|
|
89
|
+
:name="name"
|
|
90
|
+
@input="updateValue"
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<!-- Helper Text -->
|
|
94
|
+
<label v-if="helperText" class="label">
|
|
95
|
+
<span class="label-text-alt">{{ helperText }}</span>
|
|
96
|
+
</label>
|
|
97
|
+
</div>
|
|
98
|
+
</template>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, withDefaults } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
initialRating: number;
|
|
6
|
+
numberOfStars?: number;
|
|
7
|
+
halfStars?: boolean;
|
|
8
|
+
isInteractive?: boolean;
|
|
9
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
13
|
+
initialRating: 0,
|
|
14
|
+
numberOfStars: 5,
|
|
15
|
+
halfStars: true,
|
|
16
|
+
isInteractive: false,
|
|
17
|
+
size: "sm",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const rating = ref<number>(props.initialRating);
|
|
21
|
+
|
|
22
|
+
watch(
|
|
23
|
+
() => props.initialRating,
|
|
24
|
+
(newValue) => {
|
|
25
|
+
rating.value = newValue;
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const updateRating = (newRating: number) => {
|
|
30
|
+
rating.value = newRating;
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div class="rating" :class="[
|
|
36
|
+
`rating-${props.size}`,
|
|
37
|
+
{ 'rating-half': halfStars }
|
|
38
|
+
]">
|
|
39
|
+
<input
|
|
40
|
+
v-for="i in numberOfStars * (halfStars ? 2 : 1)"
|
|
41
|
+
:key="i"
|
|
42
|
+
type="radio"
|
|
43
|
+
:value="halfStars ? i * 0.5 : i"
|
|
44
|
+
:checked="rating === (halfStars ? i * 0.5 : i)"
|
|
45
|
+
@change="isInteractive ? updateRating(halfStars ? i * 0.5 : i) : null"
|
|
46
|
+
class="mask mask-star"
|
|
47
|
+
:class="{
|
|
48
|
+
'bg-yellow-400': rating >= (halfStars ? i * 0.5 : i),
|
|
49
|
+
'mask-half-1': halfStars && i % 2 !== 0,
|
|
50
|
+
'mask-half-2': halfStars && i % 2 === 0,
|
|
51
|
+
'cursor-pointer': isInteractive,
|
|
52
|
+
'cursor-default': !isInteractive
|
|
53
|
+
}"
|
|
54
|
+
:disabled="!isInteractive"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
9
|
+
loading: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const loading = ref<boolean>(props.loading);
|
|
13
|
+
|
|
14
|
+
watch(
|
|
15
|
+
() => props.loading,
|
|
16
|
+
(newValue) => {
|
|
17
|
+
loading.value = newValue;
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<span class="loading loading-spinner loading-md mx-auto " v-if="loading"></span>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
items: Array<FooterNavigation>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const props = defineProps<Props>();
|
|
7
|
+
|
|
8
|
+
export interface FooterNavigation {
|
|
9
|
+
title: string;
|
|
10
|
+
items: Array<FooterNavigationItem>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface FooterNavigationItem {
|
|
14
|
+
text: string;
|
|
15
|
+
link: string;
|
|
16
|
+
enabled: Boolean;
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<footer class="bg-base-200 p-10 text-base-content">
|
|
22
|
+
<div class="flex lg:flex-row flex-col flex-wrap container space-between">
|
|
23
|
+
<div class="mb-16 w-full lg:w-2/3 footer">
|
|
24
|
+
<nav v-for="footerCols in props.items">
|
|
25
|
+
<h6 class="after:absolute after:flex opacity-100 border-b-4 border-base-300 after:border-b-2 after:border-base-300 after:w-full after:h-1 font-bold text-xl footer-title">{{ footerCols.title }}</h6>
|
|
26
|
+
<a v-for="footerItem in footerCols.items" class="link link-hover" :href="footerItem.link">{{ footerItem.text
|
|
27
|
+
}}</a>
|
|
28
|
+
</nav>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<slot></slot>
|
|
32
|
+
</div>
|
|
33
|
+
</footer>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
.footer>* {
|
|
39
|
+
width: max-content;
|
|
40
|
+
position: relative
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="min-h-40 container hero">
|
|
3
|
+
<div class="px-0! text-center hero-content">
|
|
4
|
+
<div>
|
|
5
|
+
<h1 class="mt-9 text-4xl">
|
|
6
|
+
<slot name="title">hero title</slot>
|
|
7
|
+
</h1>
|
|
8
|
+
<p>
|
|
9
|
+
<slot name="description" class="py-9" />
|
|
10
|
+
</p>
|
|
11
|
+
<slot name="call-to-action-block" class="max-w-full"><button class="btn btn-primary">Call to action</button></slot>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineProps, defineEmits } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface Tab {
|
|
5
|
+
name: string | any;
|
|
6
|
+
description: string;
|
|
7
|
+
type: "date" | "time" | "datetime" | any;
|
|
8
|
+
range: boolean;
|
|
9
|
+
props?: Object;
|
|
10
|
+
value?: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
interface Category {
|
|
15
|
+
category: string;
|
|
16
|
+
tabs: Tab[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
searchOptions: Array<Category>;
|
|
21
|
+
currentCategory: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const props = defineProps<Props>();
|
|
25
|
+
const emit = defineEmits<{ (e: 'update:currentCategory', category: string): void }>();
|
|
26
|
+
|
|
27
|
+
function changeCategory(category: string) {
|
|
28
|
+
emit('update:currentCategory', category);
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<div class="categories flex flex-row gap-4 place-content-center">
|
|
34
|
+
<div v-for="category in props.searchOptions" :key="category.category">
|
|
35
|
+
<button @click="changeCategory(category.category)" class="truncate" :class="{ 'font-semibold': props.currentCategory === category.category }">
|
|
36
|
+
{{ category.category }}
|
|
37
|
+
</button>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
// import { ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
isCollapsed: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
9
|
+
isCollapsed: true
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<nav class="place-items-start border-primary bg-base-100 px-5 py-5 border-b-4 transition-all navbar navigationbar"
|
|
16
|
+
:class="props.isCollapsed ? 'collapsed' : ''">
|
|
17
|
+
<div class="md:flex hidden navbar-start">
|
|
18
|
+
<slot name="start"></slot>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="md:flex justify-center items-center hidden navbar-center">
|
|
22
|
+
<slot name="center"></slot>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="md:flex hidden navbar-end">
|
|
26
|
+
<slot name="end"></slot>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="navbar-bottom md:flex hidden">
|
|
29
|
+
<slot name="bottom"></slot>
|
|
30
|
+
</div>
|
|
31
|
+
</nav>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<style scoped>
|
|
35
|
+
.navigationbar {
|
|
36
|
+
display: grid;
|
|
37
|
+
grid-template-columns: auto auto auto;
|
|
38
|
+
grid-template-rows: auto auto;
|
|
39
|
+
grid-template-areas:
|
|
40
|
+
"center center center"
|
|
41
|
+
"bottom bottom bottom";
|
|
42
|
+
position: fixed;
|
|
43
|
+
width: 100% !important;
|
|
44
|
+
gap: 0 1rem;
|
|
45
|
+
align-items: center;
|
|
46
|
+
padding: var(--navbar-padding, 0.5rem);
|
|
47
|
+
min-height: 4rem;
|
|
48
|
+
z-index: 5;
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@media (min-width: 768px) {
|
|
52
|
+
grid-template-columns: 0.7fr 1.6fr 0.7fr;
|
|
53
|
+
grid-template-areas:
|
|
54
|
+
"start center end"
|
|
55
|
+
"bottom bottom bottom";
|
|
56
|
+
|
|
57
|
+
grid-row-gap: 2rem;
|
|
58
|
+
padding: 2rem;
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.navbar-start {
|
|
64
|
+
grid-area: start;
|
|
65
|
+
height: 100%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.navbar-center {
|
|
69
|
+
grid-area: center;
|
|
70
|
+
width: 100%;
|
|
71
|
+
|
|
72
|
+
height: 100%;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.navbar-end {
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 100%;
|
|
78
|
+
grid-area: end;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.navbar-bottom {
|
|
82
|
+
grid-area: center;
|
|
83
|
+
width: 100%;
|
|
84
|
+
display: flex;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
align-items: center;
|
|
87
|
+
|
|
88
|
+
@media (min-width: 768px) {
|
|
89
|
+
grid-area: bottom;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
nav.navigationbar.collapsed {
|
|
94
|
+
top: 0;
|
|
95
|
+
z-index: 10;
|
|
96
|
+
grid-template-columns: auto 1fr auto !important;
|
|
97
|
+
|
|
98
|
+
@media (min-width: 768px) {
|
|
99
|
+
row-gap: 0;
|
|
100
|
+
padding: 1rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
& .navbar-bottom {
|
|
104
|
+
grid-area: center !important;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
</style>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, onUnmounted } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
items: Array<string>;
|
|
6
|
+
withControlls?: boolean;
|
|
7
|
+
rotateTabsAfter?: number;//in seconds
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = defineProps<Props>();
|
|
11
|
+
|
|
12
|
+
const currentTab = ref(props.items[0]);
|
|
13
|
+
|
|
14
|
+
// for setting a propperty in the template when needed (dynamic data for example)
|
|
15
|
+
const emit = defineEmits(['tab-changed']);
|
|
16
|
+
|
|
17
|
+
function setCurrentTab(tab: string) {
|
|
18
|
+
currentTab.value = tab;
|
|
19
|
+
emit('tab-changed', tab);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function nextTab() {
|
|
23
|
+
const currentIndex = props.items.indexOf(currentTab.value);
|
|
24
|
+
const nextIndex = (currentIndex + 1) % props.items.length;
|
|
25
|
+
setCurrentTab(props.items[nextIndex]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function previousTab() {
|
|
29
|
+
const currentIndex = props.items.indexOf(currentTab.value);
|
|
30
|
+
const previousIndex = (currentIndex - 1 + props.items.length) % props.items.length;
|
|
31
|
+
setCurrentTab(props.items[previousIndex]);
|
|
32
|
+
}
|
|
33
|
+
onUnmounted(() => {
|
|
34
|
+
if (props.rotateTabsAfter) {
|
|
35
|
+
setInterval(() => {
|
|
36
|
+
nextTab();
|
|
37
|
+
}, props.rotateTabsAfter * 1000);
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<div role="tablist" class="tabs tabs-bordered tabs-lg mt-28 relative w-full">
|
|
45
|
+
<!-- controls -->
|
|
46
|
+
<div v-if="withControlls" class="hidden md:flex gap-4 right-0 top-4 absolute">
|
|
47
|
+
<button @click="previousTab()" class="cursor-pointer">Previous</button>
|
|
48
|
+
<button @click="nextTab()" class="cursor-pointer text-primary">Next</button>
|
|
49
|
+
</div>
|
|
50
|
+
<!-- tab buttons -->
|
|
51
|
+
<template v-for="item in items">
|
|
52
|
+
<a type="button" role="tab" class="tab min-w-max"
|
|
53
|
+
:class="item === currentTab ? 'bg-primary text-base-100' : ''" @click="setCurrentTab(item)"
|
|
54
|
+
:aria-selected="currentTab == item"> {{ item }}</a>
|
|
55
|
+
<!-- tab content -->
|
|
56
|
+
<div role="tabpanel"
|
|
57
|
+
class="tab-content border-base-300 border-t-2 border-x-0 border-b-0 p-6 overflow-x-auto max-w-full">
|
|
58
|
+
<slot :name="`${item}-tab`"></slot>
|
|
59
|
+
</div>
|
|
60
|
+
</template>
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|