feat: Added footer component (#190)

* feat: Added footer component (#126)

* add/prepare component files

* make footer component basic

* improve FooterCopyright component

* add FooterLink component

* add/add FooterBrand Component

* add vertival align to FooterListGroup

* add/add footer icon component

* add/add FooterSitemapExample

* add/FooterSitemapLinks remained part

* add/add example

---------

Co-authored-by: Ilya Artamonov <hire@ilya-artamonov.ru>

* feat: Reworked footer component

* docs: Updated components section in README.md

---------

Co-authored-by: hirakei1203 <56023847+hirakei1203@users.noreply.github.com>
This commit is contained in:
Ilya Artamonov
2023-09-13 13:31:11 +03:00
committed by GitHub
parent 9dd6b15371
commit 920157170b
18 changed files with 1076 additions and 378 deletions

View File

@@ -1,42 +1,32 @@
<script lang="ts" setup>
import { useAttrs } from 'vue'
import { twMerge } from 'tailwind-merge'
defineOptions({
inheritAttrs: false,
})
type FooterType = 'sitemap' | 'default' | 'logo' | 'socialmedia'
interface IFooterProps {
sticky?: boolean
footerType?: FooterType
}
const props = withDefaults(defineProps<IFooterProps>(), {
sticky: false,
footerType: 'default',
})
const attrs = useAttrs()
const wrapperClasses = twMerge(
props.footerType === 'sitemap' && 'bg-gray-800',
props.footerType === 'socialmedia' && 'p-4 bg-white sm:p-6 dark:bg-gray-800',
props.footerType === 'logo' && 'p-4 bg-white rounded-lg shadow md:px-6 md:py-8 dark:bg-gray-800',
props.footerType === 'default' && 'p-4 bg-white rounded-lg shadow md:flex md:items-center md:justify-between md:p-6 dark:bg-gray-800',
props.sticky && 'absolute bottom-0 left-0 z-20 w-full border-t border-gray-200 dark:border-gray-600',
attrs.class as string,
)
</script>
<template>
<footer class="p-4 bg-white rounded-lg shadow md:flex md:items-center md:justify-between md:p-6 dark:bg-gray-800">
<span class="text-sm text-gray-500 sm:text-center dark:text-gray-400">© 2022 <a href="https://flowbite.com/" class="hover:underline">Flowbite</a>. All Rights Reserved.
</span>
<ul class="flex flex-wrap items-center mt-3 text-sm text-gray-500 dark:text-gray-400 sm:mt-0">
<li>
<a href="#" class="mr-4 hover:underline md:mr-6 ">About</a>
</li>
<li>
<a href="#" class="mr-4 hover:underline md:mr-6">Privacy Policy</a>
</li>
<li>
<a href="#" class="mr-4 hover:underline md:mr-6">Licensing</a>
</li>
<li>
<a href="#" class="hover:underline">Contact</a>
</li>
</ul>
<footer v-bind="$attrs" :class="wrapperClasses">
<slot></slot>
</footer>
</template>
<script lang="ts" setup>
import { computed, toRefs } from 'vue'
import type { PropType } from 'vue'
const props = defineProps({
children: {
type: Array,
default() {
return []
},
},
bgDark: {
type: Boolean,
default: false,
},
container: {
type: Boolean,
default: false,
},
})
</script>

View File

@@ -0,0 +1,40 @@
<script setup lang="ts">
import { twMerge } from 'tailwind-merge'
import { useAttrs } from 'vue'
defineOptions({
inheritAttrs: false,
})
const attrs = useAttrs()
interface IFooterProps {
href: string
src: string
alt?: string
name: string
imageClass?: string
nameClass?: string
aClass?: string
}
const props = withDefaults(defineProps<IFooterProps>(), {
href: '',
src: '',
alt: '',
name: '',
imageClass: '',
nameClass: '',
aClass: '',
})
const wrapperClasses = twMerge('mb-6 md:mb-0', attrs.class as string)
const aClasses = twMerge('flex items-center', props.aClass)
const imageClasses = twMerge('h-8 mr-3', props.imageClass)
const mameClasses = twMerge('self-center text-2xl font-semibold whitespace-nowrap dark:text-white', props.nameClass)
</script>
<template>
<div v-bind="$attrs" :class="wrapperClasses">
<a :href="href" :class="aClasses">
<img :src="src" :class="imageClasses" :alt="alt" />
<span :class="mameClasses">{{ name }}</span>
</a>
</div>
</template>

View File

@@ -0,0 +1,34 @@
<script setup lang="ts">
import { twMerge } from 'tailwind-merge'
import { useAttrs } from 'vue'
defineOptions({
inheritAttrs: false,
})
interface IFooterCopyrigthProps {
year?: string | number
by?: string
href?: string
aClass?: string
copyrightMessage?: string
}
const props = withDefaults(defineProps<IFooterCopyrigthProps>(), {
year: new Date().getFullYear(),
by: '',
href: '',
aClass: '',
copyrightMessage: 'All Rights Reserved.',
})
const attrs = useAttrs()
const spanClasses = twMerge('block text-sm text-gray-500 sm:text-center dark:text-gray-400', attrs.class as string)
const aClasses = twMerge(props.href ? 'hover:underline' : 'ml-1', props.aClass)
const byComponent = props.href ? 'a' : 'span'
</script>
<template>
<span v-bind="$attrs" :class="spanClasses">
&copy; {{ year }}
<component :is="byComponent" :href="href" :class="aClasses">{{ by }}</component>
{{ copyrightMessage }}
</span>
</template>

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
import { twMerge } from 'tailwind-merge'
import { useAttrs } from 'vue'
defineOptions({
inheritAttrs: false,
})
const attrs = useAttrs()
interface IFooterIconProps {
href?: string
ariaLabel?: string
srText?: string
}
const props = withDefaults(defineProps<IFooterIconProps>(), {
href: '',
ariaLabel: '',
srText: '',
})
const iconComponent = props.href ? 'a' : 'span'
const aClasses = twMerge('text-gray-500 hover:text-gray-900 dark:hover:text-white', attrs.class as string)
</script>
<template>
<component v-bind="$attrs" :is="iconComponent" :href="href" :aria-label="ariaLabel" :class="aClasses">
<slot />
<span class="sr-only">{{ srText }}</span>
</component>
</template>

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
import { resolveComponent, useAttrs } from 'vue'
import { twMerge } from 'tailwind-merge'
defineOptions({
inheritAttrs: false,
})
const attrs = useAttrs()
interface IFooterLinkProps {
href: string
aClass?: string
component?: string
}
const props = withDefaults(defineProps<IFooterLinkProps>(), {
href: '',
aClass: '',
component: 'a',
})
const linkComponent = props.component === 'a' ? 'a' : resolveComponent(props.component)
const linkAttr = props.component === 'router-link' ? 'to' : 'href'
const aClasses = twMerge('hover:underline', props.aClass)
const liClasses = twMerge('mr-4 md:mr-6 last:mr-0', attrs.class as string)
</script>
<template>
<li v-bind="$attrs" :class="liClasses">
<component :is="linkComponent" :[linkAttr]="href" :class="aClasses">
<slot />
</component>
</li>
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts" setup>
import { useAttrs } from 'vue'
import { twMerge } from 'tailwind-merge'
defineOptions({
inheritAttrs: false,
})
const attrs = useAttrs()
const wrapperClasses = twMerge('flex flex-wrap items-center mt-3 text-sm font-medium text-gray-500 dark:text-gray-400 sm:mt-0', attrs.class as string)
</script>
<template>
<ul v-bind="$attrs" :class="wrapperClasses">
<slot></slot>
</ul>
</template>

View File

@@ -20,6 +20,11 @@ export { default as Badge } from './components/Badge/Badge.vue'
export { default as TheCard } from './components/Card/TheCard.vue'
export { default as Carousel } from './components/Carousel/Carousel.vue'
export { default as Footer } from './components/Footer/Footer.vue'
export { default as FooterBrand } from './components/Footer/FooterBrand.vue'
export { default as FooterCopyright } from './components/Footer/FooterCopyright.vue'
export { default as FooterLink } from './components/Footer/FooterLink.vue'
export { default as FooterLinkGroup } from './components/Footer/FooterLinkGroup.vue'
export { default as FooterIcon } from './components/Footer/FooterIcon.vue'
export { default as ListGroup } from './components/ListGroup/ListGroup.vue'
export { default as ListGroupItem } from './components/ListGroup/components/ListGroupItem/ListGroupItem.vue'
export { default as Modal } from './components/Modal/Modal.vue'