Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
a4ab6edca1 | |||
5308055a7b | |||
ca17da363d | |||
3a83348ed4 | |||
27579ade59 | |||
b61c96f9e5 | |||
6c19db0c07 | |||
b136154a26 | |||
4b7b8ef786 | |||
9a1eda1809 | |||
8488c70b44 | |||
78e8e524dc | |||
57bd46b201 | |||
7aa0c69354 | |||
c50cdb0ad8 | |||
164ee498e9 | |||
9ae9f077ce | |||
05540db8d3 | |||
2e568395a5 | |||
e2727a7b83 | |||
faf626fbca | |||
e6cae1aec9 | |||
39e135d038 | |||
64c32bd452 | |||
5ab9b3db4b | |||
00a8fc630e | |||
232329a05c | |||
d1ee2539a9 | |||
abb43e054e | |||
d824da5a39 | |||
e6fdbf7a94 | |||
b56cc416d0 | |||
a367b12150 |
@ -1,6 +0,0 @@
|
||||
<template>
|
||||
<h1>Hello Nuxt3</h1>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
275
app.vue
Normal file
275
app.vue
Normal file
@ -0,0 +1,275 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-10 bg-whitep-10">
|
||||
<div
|
||||
class="flex items-center justify-center gap-20 relative w-[1200px] mx-auto"
|
||||
>
|
||||
<!-- MlButton: This button can be used for various actions like form submissions or dialog openings. Customize its appearance using the :pt prop. -->
|
||||
<MlButton
|
||||
:pt="{
|
||||
root: {
|
||||
class: 'flex justify-center items-center disabled:opacity-60',
|
||||
},
|
||||
outer: {
|
||||
class:
|
||||
'bg-gradient-to-r from-green-300 to-red-400 p-[2px] w-full focus:outline-none rounded-3xl',
|
||||
},
|
||||
inner: {
|
||||
class:
|
||||
'justify-center flex items-center bg-white px-5 py-2 w-full h-full font-semibold leading-[1.5] back bg-white rounded-3xl',
|
||||
},
|
||||
}"
|
||||
>
|
||||
Let's talk
|
||||
</MlButton>
|
||||
|
||||
<!-- MlPaginator: Handles item pagination. Customize the appearance and behavior via props. Listens to changes with @update:paginatedItems to manage displayed items. -->
|
||||
<MlPaginator
|
||||
:items="items"
|
||||
:items-per-page="2"
|
||||
:max-pages-shown="2"
|
||||
@update:paginatedItems="handlePaginatedItems"
|
||||
v-model="currentPage"
|
||||
:pt="{
|
||||
root: {
|
||||
class:
|
||||
'w-auto flex space-x-1 bg-white/85 shadow-2xl items-center px-3 py-2 rounded-full text-black',
|
||||
},
|
||||
paginator: { class: '' },
|
||||
activePaginator: { class: 'bg-green-500' },
|
||||
}"
|
||||
/>
|
||||
<!-- MlDropDown: A customizable dropdown menu component for selecting options.
|
||||
Use the :pt prop to define styles for the root, dropdown, title, and arrow sections.
|
||||
The dropdown supports multiple items which can be styled individually using the :pt prop for each MlDropDownItem. -->
|
||||
|
||||
<MlDropDown
|
||||
title="Dropdown"
|
||||
:title="''"
|
||||
:pt="{
|
||||
root: {
|
||||
class: 'relative cursor-pointer w-[100px] h-10 text-left relative',
|
||||
},
|
||||
dropdown: {
|
||||
class: 'w-[150px] right-[-50px] absolute mt-4 block',
|
||||
},
|
||||
title: { class: 'w-[100px] h-10 bg-white shadow-2xl' },
|
||||
arrow: { class: 'hidden' },
|
||||
}"
|
||||
>
|
||||
<!-- Each MlDropDownItem represents an option in the dropdown menu. Style each item and define click behavior for interactivity. -->
|
||||
<MlDropDownItem :pt="{ root: { class: 'block px-1 py-3' } }">
|
||||
<span
|
||||
class="w-full cursor-pointer font-medium flex items-center justify-center"
|
||||
>English</span
|
||||
>
|
||||
</MlDropDownItem>
|
||||
<MlDropDownItem :pt="{ root: { class: 'block px-1 py-3' } }">
|
||||
<span
|
||||
class="w-full cursor-pointer font-medium flex items-center justify-center"
|
||||
>Polis</span
|
||||
>
|
||||
</MlDropDownItem>
|
||||
</MlDropDown>
|
||||
|
||||
<!-- MlThemeSwitch: A button for toggling between light and dark themes. Does not require additional props for basic functionality. -->
|
||||
<MlThemeSwitch />
|
||||
</div>
|
||||
|
||||
<!-- MlSlider: Displays a series of items as a slider. Use the :pt prop to style it and the default slot to customize the content of each slide. -->
|
||||
<MlSlider
|
||||
:items="items"
|
||||
:direction="'horizontal'"
|
||||
:pt="{
|
||||
root: { class: '' },
|
||||
slider: { class: 'text-white' },
|
||||
counter: { class: 'max-w-[1200px] mx-auto px-6 container text-black' },
|
||||
progress: { class: 'bg-black mt-4 h-1 transition-all duration-500' },
|
||||
}"
|
||||
class="my-[50px] relative z-30"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<div
|
||||
class="bg-white/85 backdrop-blur-md mx-auto my-4 rounded-3xl w-80 md:w-[800px] shadow-custom-lrb text-black"
|
||||
>
|
||||
<div class="flex justify-between items-center px-8 py-2 border-b-2">
|
||||
<p class="font-semibold text-[12px] uppercase tracking-widest">
|
||||
{{ item.title }}
|
||||
</p>
|
||||
<div class="bg-black rounded-lg w-5 h-0.5 cursor-pointer"></div>
|
||||
</div>
|
||||
<div
|
||||
class="flex md:flex-row-reverse flex-col gap-8 py-12 md:py-8 md:w-[800px]"
|
||||
>
|
||||
<div class="flex justify-center w-full">
|
||||
<!-- Placeholder for image content -->
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 mx-8">
|
||||
<h1 class="font-bold text-2xl md:text-[32px]">
|
||||
{{ item.title }}
|
||||
</h1>
|
||||
<p class="font-ibm text-lg">
|
||||
{{ item.info }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MlSlider>
|
||||
|
||||
<!-- MlSliderPoint: Similar to MlSlider but intended for full-page content viewing. Customize its layout and appearance using the :pt prop and slots. -->
|
||||
<div class="flex w-full justify-center text-black">
|
||||
<MlSliderPoint
|
||||
:direction="direction"
|
||||
:pt="{
|
||||
root: {
|
||||
class:
|
||||
'px-5 w-full flex items-center justify-center flex-col md:max-w-[1200px] lg:flex-row md:justify-between md:gap-20 lg:gap-0',
|
||||
},
|
||||
slider: { class: 'w-full h-full md:max-h-[470px]' },
|
||||
counter: { class: 'lg:rotate-90 z-10 w-[220px] md:w-[280px]' },
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="opacity-90 mx-auto rounded-3xl w-80 md:max-w-[800px] md:w-full h-full"
|
||||
>
|
||||
<div
|
||||
class="flex md:flex-row flex-col items-center gap-8 py-12 md:py-0 w-full h-full"
|
||||
>
|
||||
<div class="w-full">
|
||||
<!-- Placeholder for image content -->
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 mb-4">
|
||||
<h1 class="font-bold text-2xl md:text-[32px]">YourGold.cz</h1>
|
||||
<div class="flex items-center gap-2 font-ibm">
|
||||
<p class="bg-green-300 px-3 py-1 rounded-md">Tag one</p>
|
||||
<p class="bg-green-300 px-3 py-1 rounded-md">Tag two</p>
|
||||
<p class="bg-green-300 px-3 py-1 rounded-md">Tag three</p>
|
||||
</div>
|
||||
<p class="font-ibm text-[16px]">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Suspendisse varius enim in eros elementum tristique. Duis
|
||||
cursus, mi quis viverra ornare, eros dolor interdum nulla, ut
|
||||
commodo diam libero vitae erat.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MlSliderPoint>
|
||||
</div>
|
||||
|
||||
<!-- Tabber Component: Use this for tabbed data display. Bind the tabs data structure to manage different tab content dynamically. -->
|
||||
<div
|
||||
class="max-w-[1200px] mx-auto border-[1.5px] border-gray-400 rounded-2xl text-black dark:text-white"
|
||||
>
|
||||
<MlTabberBase :tabs="tabs" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// Setup script for handling paginator and tab data.
|
||||
const currentItems = ref([]);
|
||||
const currentPage = ref(1);
|
||||
const handlePaginatedItems = (items) => {
|
||||
currentItems.value = items;
|
||||
};
|
||||
// Array of items to be displayed and managed by MlPaginator.
|
||||
const items = [
|
||||
{
|
||||
id: 1,
|
||||
title:
|
||||
"How to enforce conventional commits using git-cliff with a CI pipeline?",
|
||||
date: "01.07.2024",
|
||||
persone1: "Natalia Goc",
|
||||
persone2: "Marek Goc",
|
||||
info: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Understanding JavaScript Promises",
|
||||
date: "02.07.2024",
|
||||
persone1: "John Doe",
|
||||
persone2: "Jane Smith",
|
||||
info: "JavaScript promises are used to handle asynchronous operations. They provide an alternative approach to callbacks by returning a value in the future.",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "An Introduction to WebAssembly",
|
||||
date: "03.07.2024",
|
||||
persone1: "Alice Johnson",
|
||||
persone2: "Bob Brown",
|
||||
info: "WebAssembly is a binary instruction format for a stack-based virtual machine, designed as a portable target for compilation of high-level languages like C, C++, and Rust.",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Building Responsive Web Applications",
|
||||
date: "04.07.2024",
|
||||
persone1: "Emily White",
|
||||
persone2: "Chris Green",
|
||||
info: "Responsive web design ensures that web applications work well on a variety of devices, providing an optimal user experience across different screen sizes.",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Exploring the Basics of Machine Learning",
|
||||
date: "05.07.2024",
|
||||
persone1: "Michael Lee",
|
||||
persone2: "Sara Kim",
|
||||
info: "Machine learning is a field of artificial intelligence that uses statistical techniques to give computer systems the ability to learn from data.",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "Getting Started with Docker",
|
||||
date: "06.07.2024",
|
||||
persone1: "David Brown",
|
||||
persone2: "Laura Black",
|
||||
info: "Docker is a tool designed to make it easier to create, deploy, and run applications by using containers, which allow a developer to package up an application with all of its parts.",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: "Introduction to Kubernetes",
|
||||
date: "07.07.2024",
|
||||
persone1: "James Wilson",
|
||||
persone2: "Olivia Martin",
|
||||
info: "Kubernetes is an open-source platform designed to automate deploying, scaling, and operating application containers, providing a framework to run distributed systems resiliently.",
|
||||
},
|
||||
];
|
||||
|
||||
// Array of tabber to be displayed and managed by MlTabberBase.
|
||||
const tabs = [
|
||||
{
|
||||
header: "Web App Development",
|
||||
content: {
|
||||
title: "Web App Development",
|
||||
info: "From simple business portfolios to complex interactive web applications, we can realize almost any service available through the Web. We will take care of the aesthetics, accessibility, stability and performance of your web application.",
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "E-commerce",
|
||||
content: {
|
||||
title: "Mobile App Development",
|
||||
info: "E-commerce services have became a fundamental element of many well prospering businesses. Having our own experience with it we will be able to help you with the high expectations of your online customers.",
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "Business Management and ERP Systems",
|
||||
content: {
|
||||
title: "Digital Marketing",
|
||||
info: "Well designed IT infrastructure can be a key element in your company’s success. With us you will discover how modern software can help you manage your business.",
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "Hosting and IT Infrastructure",
|
||||
content: {
|
||||
title: "Web App Development",
|
||||
info: "We are ready to fill any gaps in your infrastructure. Working with us you won’t have to worry about managing complex costs or hardware resources.",
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "IT Consulting",
|
||||
content: {
|
||||
title: "IT Consulting",
|
||||
info: "We are happy to share our experiences with other companies. Besides free consulting during project cost evaluation we offer our knowledge as an independent and affordable service.",
|
||||
},
|
||||
},
|
||||
];
|
||||
</script>
|
45
components/Ml/Button/MlButton.vue
Normal file
45
components/Ml/Button/MlButton.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<button :class="rootClasses" @click="useRipple($event, true)">
|
||||
<div :class="outerClasses">
|
||||
<div :class="innerClasses">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// import { useRipple } from "#imports";
|
||||
import { computed, ref } from "vue";
|
||||
import type { ButtonProps, PTAttribs } from "./types";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
rounded: true,
|
||||
spinerSize: "6",
|
||||
spinerColor: "accent1",
|
||||
spinerPlace: "prefix",
|
||||
});
|
||||
|
||||
const classes = ref({
|
||||
root: {
|
||||
class: ``,
|
||||
},
|
||||
outer: {
|
||||
class: ``,
|
||||
},
|
||||
inner: {
|
||||
class: ``,
|
||||
},
|
||||
} as PTAttribs);
|
||||
|
||||
const rootClasses = computed(() =>
|
||||
twMerge(classes.value.root?.class, props.pt?.root?.class)
|
||||
);
|
||||
const innerClasses = computed(() =>
|
||||
twMerge(classes.value.inner?.class, props.pt?.inner?.class)
|
||||
);
|
||||
const outerClasses = computed(() =>
|
||||
twMerge(classes.value.outer?.class, props.pt?.outer?.class)
|
||||
);
|
||||
</script>
|
@ -1,12 +1,7 @@
|
||||
import type { SpinnerSize, SpinnerColor } from '../Spinner/types';
|
||||
|
||||
export type ButtonProps = {
|
||||
rounded?: boolean;
|
||||
pt?: PTAttribs;
|
||||
spinerSize?: SpinnerSize;
|
||||
spinerColor?: SpinnerColor;
|
||||
spinerPlace?: spinerPlace;
|
||||
showSpiner?: boolean;
|
||||
};
|
||||
|
||||
export type PTAttribs = {
|
67
components/Ml/DropDown/MlDropDown.vue
Normal file
67
components/Ml/DropDown/MlDropDown.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div :class="rootPT">
|
||||
<button
|
||||
id="dropdownDefaultButton"
|
||||
data-dropdown-toggle="dropdown"
|
||||
:class="titlePT"
|
||||
type="button"
|
||||
@click="
|
||||
useRipple($event, props.ripple);
|
||||
openMenu();
|
||||
"
|
||||
>
|
||||
{{ props.title }}
|
||||
<span :class="arrowPT">
|
||||
<ml-arrow></ml-arrow>
|
||||
</span>
|
||||
</button>
|
||||
<div v-show="isMenuOpen" :class="dropdownPT" @click="isOpen = false">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { useRipple } from "#imports";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import type { DropDownProps, DropDownPT } from "./types";
|
||||
|
||||
const props = withDefaults(defineProps<DropDownProps>(), {
|
||||
isOpen: false,
|
||||
});
|
||||
|
||||
const PT = {
|
||||
root: {
|
||||
class: "",
|
||||
},
|
||||
dropdown: {
|
||||
class: "z-10 absolute bg-white rounded-3xl pointer text-black text-center",
|
||||
},
|
||||
title: {
|
||||
class:
|
||||
"text-black inline-flex items-center rounded-lg font-medium text-center text-base pointer ",
|
||||
},
|
||||
arrow: {
|
||||
class: "px-2",
|
||||
},
|
||||
} as DropDownPT;
|
||||
|
||||
const rootPT = computed(() => twMerge(PT.root?.class, props.pt?.root?.class));
|
||||
const titlePT = computed(() =>
|
||||
twMerge(PT.title?.class, props.pt?.title?.class)
|
||||
);
|
||||
const dropdownPT = computed(() =>
|
||||
twMerge(PT.dropdown?.class, props.pt?.dropdown?.class)
|
||||
);
|
||||
const arrowPT = computed(() =>
|
||||
twMerge(PT.arrow?.class, props.pt?.arrow?.class)
|
||||
);
|
||||
|
||||
const isOpen = ref(props.isOpen);
|
||||
|
||||
function openMenu() {
|
||||
isOpen.value = !isOpen.value;
|
||||
}
|
||||
|
||||
const isMenuOpen = computed(() => isOpen.value);
|
||||
</script>
|
@ -5,6 +5,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import type { DropDownItemPT, DropDownItemProps } from './types';
|
||||
|
@ -29,10 +29,7 @@
|
||||
</swiper>
|
||||
<div>
|
||||
<div :class="counterClasses">
|
||||
<div
|
||||
class="bg-BgDark dark:bg-BgLight mt-4 h-1 transition-all duration-500"
|
||||
:style="`width: ${progerssBar}%`"
|
||||
></div>
|
||||
<div :class="progressClass" :style="`width: ${progerssBar}%`"></div>
|
||||
<div class="flex justify-between my-4">
|
||||
<button
|
||||
:disabled="isPrevDisabled"
|
||||
@ -61,6 +58,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// import { useRipple } from "#imports";
|
||||
import { ref, computed, defineProps, withDefaults } from "vue";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import type { Swiper as swiper } from "swiper/types";
|
||||
@ -121,9 +119,12 @@ const classes = ref({
|
||||
class: ``,
|
||||
},
|
||||
counter: {
|
||||
class: `max-w-[1200px] mx-auto px-6 container`,
|
||||
class: ``,
|
||||
},
|
||||
} as PTAttribs);
|
||||
progress: {
|
||||
class: "",
|
||||
},
|
||||
} as unknown as PTAttribs);
|
||||
|
||||
const rootClasses = computed(() =>
|
||||
twMerge(classes.value.root?.class, props.pt?.root?.class)
|
||||
@ -134,6 +135,9 @@ const sliderClasses = computed(() =>
|
||||
const counterClasses = computed(() =>
|
||||
twMerge(classes.value.counter?.class, props.pt?.counter?.class)
|
||||
);
|
||||
const progressClass = computed(() =>
|
||||
twMerge(classes.value.progress?.class, props.pt?.progress?.class)
|
||||
);
|
||||
|
||||
const items = props.items;
|
||||
</script>
|
25
components/Ml/Slider/types.ts
Normal file
25
components/Ml/Slider/types.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export type SliderProps = {
|
||||
direction: "horizontal" | "vertical";
|
||||
pt?: PTAttribs;
|
||||
items: Array<[{ title: string; info: string }]>;
|
||||
};
|
||||
|
||||
export type PTAttribs = {
|
||||
root?: {
|
||||
class: string;
|
||||
};
|
||||
slider?: {
|
||||
class: string;
|
||||
};
|
||||
counter?: {
|
||||
class: string;
|
||||
};
|
||||
direction?: {
|
||||
direction: string;
|
||||
};
|
||||
progress?: {
|
||||
class: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type spinerPlace = "suffix" | "prefix";
|
@ -19,18 +19,16 @@
|
||||
<slot />
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
<div
|
||||
class="flex justify-between items-center h-10 cursor-pointer"
|
||||
:class="counterClasses"
|
||||
>
|
||||
<div :class="counterClasses">
|
||||
<div
|
||||
v-for="(slide, index) in 4"
|
||||
:key="index"
|
||||
:class="[
|
||||
'bg-BgDark dark:bg-BgLight h-[3px] transition-all duration-500',
|
||||
class="bg-black"
|
||||
:style="[
|
||||
'height: 3px; transition: all 0.5s;',
|
||||
index === currentSlideNumber
|
||||
? 'py-2 w-[16px] rounded-3xl'
|
||||
: 'w-[25px] rounded-sm md:w-[24px]',
|
||||
? 'padding-top : 8px; padding-bottom: 8px; width: 16px; border-radius : 50%;'
|
||||
: 'height: 3px; width: 25px;',
|
||||
]"
|
||||
@click="goToSlide(index), stopAutoSlide()"
|
||||
></div>
|
||||
@ -49,7 +47,7 @@ import type { PTAttribs } from "./types";
|
||||
const showSwiper = ref(false);
|
||||
const currentSlideNumber = ref(0);
|
||||
let swiperInstance: swiper | null = null;
|
||||
let intervalId: number | null = null;
|
||||
let intervalId: NodeJS.Timeout | null = null;
|
||||
|
||||
const onSwiper = (swiper: swiper) => {
|
||||
swiperInstance = swiper;
|
||||
@ -96,7 +94,9 @@ const props = withDefaults(
|
||||
const classes = ref({
|
||||
root: { class: `` },
|
||||
slider: { class: `` },
|
||||
counter: { class: `mx-auto px-6 container` },
|
||||
counter: {
|
||||
class: `mx-auto px-6 container flex justify-between items-center h-10 cursor-pointer`,
|
||||
},
|
||||
} as PTAttribs);
|
||||
|
||||
const rootClasses = computed(() =>
|
42
components/Ml/Tabber/MlTabberBase.vue
Normal file
42
components/Ml/Tabber/MlTabberBase.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="flex md:flex-row flex-col text-black">
|
||||
<div class="flex flex-col justify-between cursor-pointer w-[40%]" style="min-width: 40%;">
|
||||
<div
|
||||
v-for="(el, index) in props.tabs"
|
||||
:key="index"
|
||||
class="w-full text-left border-b border-gray-400 md:text-[18px] md:last:border-b-0 md:h-full flex items-center"
|
||||
style="padding: 32px 24px;"
|
||||
@click="
|
||||
showContent(index);
|
||||
useRipple($event, true);
|
||||
"
|
||||
>
|
||||
{{ el.header }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="tabs[indexItem]" class="md:flex-1 h-auto" style="padding: 20px">
|
||||
<div class="flex flex-col items-start h-full justify-center p-6">
|
||||
<!-- Your image -->
|
||||
<h1 class="font-bold text-2xl md:text-[32px]">
|
||||
{{ tabs[indexItem].content.title }}
|
||||
</h1>
|
||||
<p class="text-[16px] md:text-[18px]">
|
||||
{{ tabs[indexItem].content.info }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const indexItem = ref(0);
|
||||
|
||||
function showContent(index) {
|
||||
indexItem.value = index;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
tabs: Object,
|
||||
});
|
||||
</script>
|
3
index.js
Normal file
3
index.js
Normal file
@ -0,0 +1,3 @@
|
||||
import MyModule from './modules/module';
|
||||
|
||||
export default MyModule;
|
89
modules/module.ts
Normal file
89
modules/module.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import {
|
||||
defineNuxtModule,
|
||||
createResolver,
|
||||
addComponent,
|
||||
addImports,
|
||||
} from "@nuxt/kit";
|
||||
|
||||
export interface ModuleOptions {}
|
||||
|
||||
const components = [
|
||||
{
|
||||
name: "MlButton",
|
||||
path: "../components/Ml/Button/MlButton.vue",
|
||||
},
|
||||
{
|
||||
name: "MlPaginator",
|
||||
path: "../components/Ml/Paginator/MlPaginator.vue",
|
||||
},
|
||||
{
|
||||
name: "MlDropDown",
|
||||
path: "../components/Ml/DropDown/MlDropDown.vue",
|
||||
},
|
||||
{
|
||||
name: "MlDropDownItem",
|
||||
path: "../components/Ml/DropDown/MlDropDownItem.vue",
|
||||
},
|
||||
{
|
||||
name: "MlSlider",
|
||||
path: "../components/Ml/Slider/MlSlider.vue",
|
||||
},
|
||||
{
|
||||
name: "MlSliderPoint",
|
||||
path: "../components/Ml/SliderPoint/MlSliderPoint.vue",
|
||||
},
|
||||
{
|
||||
name: "MlTabberBase",
|
||||
path: "../components/Ml/Tabber/MlTabberBase.vue",
|
||||
},
|
||||
{
|
||||
name: "MyComponent",
|
||||
path: "../components/MyComponent",
|
||||
},
|
||||
];
|
||||
|
||||
const composables = [
|
||||
{
|
||||
name: "useRipple",
|
||||
path: "../composables/useRipple.ts",
|
||||
},
|
||||
{
|
||||
name: "useMergeClasses",
|
||||
path: "../composables/useMergeClasses.ts",
|
||||
},
|
||||
{
|
||||
name: "useBounce",
|
||||
path: "../composables/useBounce.ts",
|
||||
},
|
||||
{
|
||||
name: "useTailwindConf",
|
||||
path: "../composables/useTailwindConf.ts",
|
||||
},
|
||||
];
|
||||
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
meta: {
|
||||
name: "module",
|
||||
configKey: "myModule",
|
||||
},
|
||||
defaults: {},
|
||||
setup(_options, _nuxt) {
|
||||
const resolver = createResolver(import.meta.url);
|
||||
|
||||
for (let item of components) {
|
||||
addComponent({
|
||||
name: item.name,
|
||||
filePath: resolver.resolve(item.path),
|
||||
});
|
||||
}
|
||||
|
||||
for (let item of composables) {
|
||||
addImports([
|
||||
{
|
||||
name: item.name,
|
||||
from: resolver.resolve(item.path),
|
||||
},
|
||||
]);
|
||||
}
|
||||
},
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
modules: ["@nuxtjs/tailwindcss", "@nuxtjs/color-mode"],
|
||||
modules: ["@nuxtjs/tailwindcss", "@nuxtjs/color-mode", "./modules/module.ts"],
|
||||
compatibilityDate: "2024-04-03",
|
||||
devtools: { enabled: true },
|
||||
colorMode: {},
|
||||
|
14
package.json
14
package.json
@ -1,24 +1,25 @@
|
||||
{
|
||||
"name": "nuxt3-reusable-components",
|
||||
"version": "1.1.4",
|
||||
"version": "1.2.6",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
"main": "module.ts",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"prepack": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
"start": "nuxt start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/vue": "^2.1.4",
|
||||
"@nuxt/kit": "^3.12.3",
|
||||
"@nuxtjs/color-mode": "^3.4.2",
|
||||
"@nuxtjs/tailwindcss": "^6.12.0",
|
||||
"@vueuse/core": "^10.11.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"classnames": "^2.5.1",
|
||||
"nuxt": "^3.12.3",
|
||||
"pathe": "^1.1.2",
|
||||
"postcss": "^8.4.39",
|
||||
"swiper": "^11.1.4",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"typescript": "^5.5.3",
|
||||
@ -26,6 +27,7 @@
|
||||
},
|
||||
"packageManager": "pnpm@9.1.1+sha512.14e915759c11f77eac07faba4d019c193ec8637229e62ec99eefb7cf3c3b75c64447882b7c485142451ee3a6b408059cdfb7b7fa0341b975f12d0f7629c71195",
|
||||
"devDependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.12.0",
|
||||
"tailwindcss": "^3.4.4"
|
||||
}
|
||||
}
|
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@ -17,18 +17,24 @@ importers:
|
||||
'@nuxtjs/color-mode':
|
||||
specifier: ^3.4.2
|
||||
version: 3.4.2(magicast@0.3.4)(rollup@4.18.0)
|
||||
'@nuxtjs/tailwindcss':
|
||||
specifier: ^6.12.0
|
||||
version: 6.12.0(magicast@0.3.4)(rollup@4.18.0)
|
||||
'@vueuse/core':
|
||||
specifier: ^10.11.0
|
||||
version: 10.11.0(vue@3.4.31(typescript@5.5.3))
|
||||
autoprefixer:
|
||||
specifier: ^10.4.19
|
||||
version: 10.4.19(postcss@8.4.39)
|
||||
classnames:
|
||||
specifier: ^2.5.1
|
||||
version: 2.5.1
|
||||
nuxt:
|
||||
specifier: ^3.12.3
|
||||
version: 3.12.3(@opentelemetry/api@1.9.0)(@parcel/watcher@2.4.1)(@types/node@20.14.9)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.18.0)(terser@5.31.1)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(terser@5.31.1))
|
||||
pathe:
|
||||
specifier: ^1.1.2
|
||||
version: 1.1.2
|
||||
postcss:
|
||||
specifier: ^8.4.39
|
||||
version: 8.4.39
|
||||
swiper:
|
||||
specifier: ^11.1.4
|
||||
version: 11.1.4
|
||||
@ -42,6 +48,9 @@ importers:
|
||||
specifier: latest
|
||||
version: 3.4.31(typescript@5.5.3)
|
||||
devDependencies:
|
||||
'@nuxtjs/tailwindcss':
|
||||
specifier: ^6.12.0
|
||||
version: 6.12.0(magicast@0.3.4)(rollup@4.18.0)
|
||||
tailwindcss:
|
||||
specifier: ^3.4.4
|
||||
version: 3.4.4
|
||||
|
@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<button :class="rootClasses" @click="useRipple($event, true)">
|
||||
<div :class="outerClasses">
|
||||
<div :class="innerClasses">
|
||||
<ml-spinner v-if="spinerPlace == 'prefix' && props.showSpiner" :color="props.spinerColor" :size="props.spinerSize" class="mx-2 fill-accent1" />
|
||||
<slot></slot>
|
||||
<ml-spinner v-if="spinerPlace == 'suffix' && props.showSpiner" :color="props.spinerColor" :size="props.spinerSize" class="mx-2 fill-accent1" />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ButtonProps, PTAttribs } from './types';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
rounded: true,
|
||||
spinerSize: '6',
|
||||
spinerColor: 'accent1',
|
||||
spinerPlace: 'prefix'
|
||||
});
|
||||
|
||||
const classes = ref({
|
||||
root: {
|
||||
class: `flex justify-center items-center disabled:opacity-60`
|
||||
},
|
||||
outer: {
|
||||
class: `bg-gradient-to-r from-accent1 to-accent2 p-[2px] w-full focus:outline-none ${props.rounded ? 'rounded-3xl' : ''}`
|
||||
},
|
||||
inner: {
|
||||
class: `justify-center flex items-center bg-white dark:bg-gradient-to-r px-5 py-2 w-full h-full font-semibold leading-[1.5] back ${props.rounded ? 'rounded-3xl' : ''}`
|
||||
}
|
||||
} as PTAttribs);
|
||||
|
||||
const rootClasses = computed(() => twMerge(classes.value.root?.class, props.pt?.root?.class));
|
||||
const innerClasses = computed(() => twMerge(classes.value.inner?.class, props.pt?.inner?.class));
|
||||
const outerClasses = computed(() => twMerge(classes.value.outer?.class, props.pt?.outer?.class));
|
||||
</script>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div v-click-outside="closeDropDown" :class="rootPT">
|
||||
<button
|
||||
id="dropdownDefaultButton"
|
||||
data-dropdown-toggle="dropdown"
|
||||
:class="titlePT"
|
||||
type="button"
|
||||
@click="
|
||||
useRipple($event, props.ripple);
|
||||
openMenu();
|
||||
"
|
||||
>
|
||||
{{ props.title }}
|
||||
<span :class="arrowPT">
|
||||
<ml-arrow></ml-arrow>
|
||||
</span>
|
||||
</button>
|
||||
<div v-show="isMenuOpen" :class="dropdownPT" @click="isOpen = false">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import type { DropDownProps, DropDownPT } from './types';
|
||||
|
||||
const props = withDefaults(defineProps<DropDownProps>(), {
|
||||
isOpen: false
|
||||
});
|
||||
|
||||
const PT = {
|
||||
root: {
|
||||
class: 'relative pointer'
|
||||
},
|
||||
dropdown: {
|
||||
class: 'z-10 absolute bg-white dark:bg-BgDark/85 rounded-3xl pointer text-black dark:text-white text-center'
|
||||
},
|
||||
title: {
|
||||
class: 'text-black dark:text-BgLight inline-flex items-center rounded-lg font-medium text-center text-base pointer '
|
||||
},
|
||||
arrow: {
|
||||
class: 'px-2'
|
||||
}
|
||||
} as DropDownPT;
|
||||
|
||||
const rootPT = computed(() => twMerge(PT.root?.class, props.pt?.root?.class));
|
||||
const titlePT = computed(() => twMerge(PT.title?.class, props.pt?.title?.class));
|
||||
const dropdownPT = computed(() => twMerge(PT.dropdown?.class, props.pt?.dropdown?.class));
|
||||
const arrowPT = computed(() => twMerge(PT.arrow?.class, props.pt?.arrow?.class));
|
||||
|
||||
const isOpen = ref(props.isOpen);
|
||||
|
||||
function openMenu() {
|
||||
isOpen.value = !isOpen.value;
|
||||
}
|
||||
|
||||
function closeDropDown() {
|
||||
isOpen.value = false;
|
||||
}
|
||||
|
||||
const isMenuOpen = computed(() => isOpen.value);
|
||||
</script>
|
@ -1,22 +0,0 @@
|
||||
export type SliderProps = {
|
||||
direction: 'horizontal' | 'vertical';
|
||||
pt?: PTAttribs;
|
||||
items: Array<[{ title: string; info: string }]>;
|
||||
};
|
||||
|
||||
export type PTAttribs = {
|
||||
root?: {
|
||||
class: string;
|
||||
};
|
||||
slider?: {
|
||||
class: string;
|
||||
};
|
||||
counter?: {
|
||||
class: string;
|
||||
};
|
||||
direction?: {
|
||||
direction: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type spinerPlace = 'suffix' | 'prefix';
|
@ -1,46 +0,0 @@
|
||||
<template>
|
||||
<div class="flex md:flex-row flex-col">
|
||||
<div class="flex flex-col justify-between md:w-[40%] cursor-pointer">
|
||||
<div
|
||||
v-for="(el, index) in props.tabs"
|
||||
:key="index"
|
||||
:class="[
|
||||
'w-full px-6 py-4 md:py-8 rtl:text-right text-left border-b border-gray-400 md:text-[18px] md:last:border-b-0 md:h-full flex items-center',
|
||||
index === indexItem
|
||||
? 'md:border-r-0 font-[700]'
|
||||
: 'md:border-r font-medium',
|
||||
]"
|
||||
@click="
|
||||
showContent(index);
|
||||
useRipple($event, true);
|
||||
"
|
||||
>
|
||||
{{ el.header }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="tabs[indexItem]" class="md:flex-1 h-auto">
|
||||
<div class="flex flex-col items-start p-6 md:p-16">
|
||||
<!-- Your image -->
|
||||
<h1 class="my-5 font-bold text-2xl md:text-[32px]">
|
||||
{{ tabs[indexItem].content.title }}
|
||||
</h1>
|
||||
<p class="font-ibm text-[16px] md:text-[18px]">
|
||||
{{ tabs[indexItem].content.info }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const indexItem = ref(0);
|
||||
|
||||
function showContent(index) {
|
||||
indexItem.value = index;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
tabs: Object,
|
||||
});
|
||||
</script>
|
@ -1,9 +0,0 @@
|
||||
import { defineNuxtModule, addComponentsDir } from '@nuxt/kit'
|
||||
|
||||
export default defineNuxtModule({
|
||||
setup(options, nuxt) {
|
||||
addComponentsDir({
|
||||
path: '~/components/Ml',
|
||||
})
|
||||
}
|
||||
})
|
@ -1,57 +1,7 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./components/**/*.{vue,js}",
|
||||
"./layouts/**/*.vue",
|
||||
"./pages/**/*.vue",
|
||||
"./plugins/**/*.{js,ts}",
|
||||
"./nuxt.config.{js,ts}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
gradient:
|
||||
"linear-gradient(50deg, rgba(75,250,145,1) 0%, rgba(71,122,255,1) 100%);",
|
||||
MainLightGradient:
|
||||
"linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(114,151,246,0.6502976190476191) 36%, rgba(114,151,246,0.6502976190476191) 72%, rgba(0,0,0,0) 100%)",
|
||||
MainDarkGradient:
|
||||
"linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(13,54,161,0.6502976190476191) 49%, #161616 100%);",
|
||||
FooterLightGradient:
|
||||
"linear-gradient(180deg, #F8F8F8 0%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%), linear-gradient(65deg, rgba(75,250,145,0.5) 0%, rgba(20,76,220,0.5) 100%)",
|
||||
FooterDarkGradient:
|
||||
"linear-gradient(180deg, #161616 0%, rgba(0,0,0,0.5) 50%, rgba(0,0,0,0) 100%), linear-gradient(65deg, rgba(20,76,220,0.5) 0%, rgba(75,250,145,0.5) 100%)",
|
||||
FormLightGradient:
|
||||
"linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(114,151,246,1) 72%)",
|
||||
FormDarkGradient:
|
||||
"linear-gradient(180deg, #161616 20%, rgba(13,54,161,1) 90%)",
|
||||
StudyLightGradient:
|
||||
"linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(72,72,72,0.10127801120448177) 14%, rgba(249,249,249,0.3253676470588235) 50%, rgba(248,248,248,1) 100%), linear-gradient(65deg, rgba(75,250,145,0.5) 0%, rgba(20,76,220,0.5) 100%)",
|
||||
StudyDarkGradient:
|
||||
"linear-gradient(180deg, rgba(22,22,22,0) 0%, rgba(22,22,22,0.3309698879551821) 50%, #161616 100%), linear-gradient(72deg, rgba(20,76,220,0.5018382352941176) 0%, rgba(75,250,145,0.4990371148459384) 100%)",
|
||||
ContactDarkGradient:
|
||||
"linear-gradient(180deg, rgba(0,0,0,0) 20%, rgba(13,54,161,1) 90%)",
|
||||
ContactLightGradient:
|
||||
"linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(114,151,246,0.7231267507002801) 72%)",
|
||||
},
|
||||
colors: {
|
||||
gradient:
|
||||
"linear-gradient(50deg, rgba(75,250,145,1) 0%, rgba(71,122,255,1) 100%);",
|
||||
accent1: "#144CDC",
|
||||
accent2: "#4BFA91",
|
||||
|
||||
BgDark: "#090909",
|
||||
BgLight: "#F8F8F8",
|
||||
|
||||
BgDarkSecond: "#161616",
|
||||
},
|
||||
screens: {
|
||||
"3xl": "2560px",
|
||||
},
|
||||
boxShadow: {
|
||||
"custom-lrb":
|
||||
"0 10px 15px -3px rgba(0, 0, 0, 0.1), -10px 0 15px -3px rgba(0, 0, 0, 0.1), 10px 0 15px -3px rgba(0, 0, 0, 0.1)",
|
||||
"custom-drb": "-3px 28px 42px 3px rgba(23, 23, 24, 1)",
|
||||
},
|
||||
},
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
@ -1,38 +0,0 @@
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = {
|
||||
entry: "./src/index.js",
|
||||
output: {
|
||||
path: "./dist/",
|
||||
filename: "index.js",
|
||||
library: "VuejsPaginate",
|
||||
libraryTarget: "umd",
|
||||
},
|
||||
resolve: {
|
||||
extensions: ["", ".js", ".vue"],
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: "vue",
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: "babel",
|
||||
include: __dirname,
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
minimize: true,
|
||||
sourceMap: false,
|
||||
mangle: true,
|
||||
compress: {
|
||||
warnings: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user