-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Banner components #317
base: main
Are you sure you want to change the base?
Changes from all commits
1ba4c3f
4e220cd
cba7e22
6a83ec8
52623d2
316d0be
4ceb769
7330c52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<script setup> | ||
import FwbBannerDefaultExample from './banner/examples/FwbBannerDefaultExample.vue' | ||
import FwbBannerBottomExample from './banner/examples/FwbBannerBottomExample.vue' | ||
</script> | ||
|
||
# Vue Banner - Flowbite | ||
|
||
## Use the banner component to show marketing messages and CTA buttons at the top or bottom side of your website based on the utility classes from Tailwind CSS | ||
|
||
--- | ||
|
||
:::tip | ||
Original reference: [https://flowbite.com/docs/components/banner/](https://flowbite.com/docs/components/banner/) | ||
::: | ||
|
||
Get started with the sticky banner component coded with Tailwind CSS and Flowbite to show marketing, informational and CTA messages to your website visitors fixed to the top or bottom part of the page as the user scrolls down the main content area. | ||
|
||
## Default sticky banner | ||
|
||
Use this free example to show a text message for an announcement with a CTA link, an icon element and a close button to dismiss the banner. | ||
|
||
<fwb-banner-default-example /> | ||
|
||
|
||
```vue | ||
<template> | ||
<fwb-banner closable> | ||
<div class="bg-gray-50 p-4 dark:bg-gray-700"> | ||
<p class="flex items-center gap-2 text-sm font-normal text-gray-500 dark:text-gray-400"> | ||
<svg class="w-6 h-6 text-gray-800 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" | ||
width="24" height="24" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" | ||
d="M3.559 4.544c.355-.35.834-.544 1.33-.544H19.11c.496 0 .975.194 1.33.544.356.35.559.829.559 1.331v9.25c0 .502-.203.981-.559 1.331-.355.35-.834.544-1.33.544H15.5l-2.7 3.6a1 1 0 0 1-1.6 0L8.5 17H4.889c-.496 0-.975-.194-1.33-.544A1.868 1.868 0 0 1 3 15.125v-9.25c0-.502.203-.981.559-1.331ZM7.556 7.5a1 1 0 1 0 0 2h8a1 1 0 0 0 0-2h-8Zm0 3.5a1 1 0 1 0 0 2H12a1 1 0 1 0 0-2H7.556Z" | ||
clip-rule="evenodd" /> | ||
</svg> | ||
<span class="[&_p]:inline"> | ||
New brand identity has been launched for the | ||
<a href="https://flowbite.com" | ||
class="inline font-medium text-cyan-600 underline decoration-solid underline-offset-2 hover:no-underline dark:text-cyan-500"> | ||
Flowbite Library | ||
</a> | ||
</span> | ||
</p> | ||
</div> | ||
</fwb-banner> | ||
</template> | ||
``` | ||
|
||
## Bottom banner position | ||
|
||
This example can be used to position the sticky banner on the bottom side of the page instead of the top side. | ||
|
||
<fwb-banner-bottom-example /> | ||
|
||
```vue | ||
<template> | ||
<fwb-banner position="bottom" closable> | ||
<div class="bg-gray-50 p-4 dark:bg-gray-700"> | ||
<p class="flex items-center gap-2 text-sm font-normal text-gray-500 dark:text-gray-400"> | ||
<svg class="w-6 h-6 text-gray-800 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" | ||
width="24" height="24" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" | ||
d="M3.559 4.544c.355-.35.834-.544 1.33-.544H19.11c.496 0 .975.194 1.33.544.356.35.559.829.559 1.331v9.25c0 .502-.203.981-.559 1.331-.355.35-.834.544-1.33.544H15.5l-2.7 3.6a1 1 0 0 1-1.6 0L8.5 17H4.889c-.496 0-.975-.194-1.33-.544A1.868 1.868 0 0 1 3 15.125v-9.25c0-.502.203-.981.559-1.331ZM7.556 7.5a1 1 0 1 0 0 2h8a1 1 0 0 0 0-2h-8Zm0 3.5a1 1 0 1 0 0 2H12a1 1 0 1 0 0-2H7.556Z" | ||
clip-rule="evenodd" /> | ||
</svg> | ||
<span class="[&_p]:inline"> | ||
New brand identity has been launched for the | ||
<a href="https://flowbite.com" | ||
class="inline font-medium text-cyan-600 underline decoration-solid underline-offset-2 hover:no-underline dark:text-cyan-500"> | ||
Flowbite Library | ||
</a> | ||
</span> | ||
</p> | ||
</div> | ||
</fwb-banner> | ||
</template> | ||
``` | ||
|
||
## More Examples | ||
|
||
For more sticky banner examples you can check [banner sections](https://flowbite.com/blocks/marketing/banner/) from Flowbite Blocks. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<template> | ||
<div | ||
class="vp-raw h-[25rem] overflow-y-scroll relative border border-gray-200 rounded-md dark:bg-gray-900 dark:border-gray-800"> | ||
<div class="px-8 py-4"> | ||
<div class="pb-4 mb-8 border-b border-gray-200 dark:border-gray-800"> | ||
<h1 id="content" class="inline-block mb-2 text-3xl font-extrabold tracking-tight text-gray-900 dark:text-white"> | ||
Flowbite - Tailwind CSS component library | ||
</h1> | ||
<p class="mb-4 text-lg text-gray-600 dark:text-gray-400"> | ||
Get started with the most popular | ||
open-source library of interactive UI components built with the utility classes from Tailwind | ||
CSS | ||
</p> | ||
</div> | ||
|
||
<h2 class="relative group text-xl font-semibold leading-8 mb-4 mt-8"> | ||
Introduction | ||
<span id="introduction" class="absolute -top-[140px]" /> <a | ||
class="ml-2 text-blue-700 opacity-0 transition-opacity dark:text-blue-500 group-hover:opacity-100" | ||
href="#introduction" aria-label="Link to this section: Introduction">#</a> | ||
Check warning on line 20 in docs/components/banner/examples/FwbBannerBottomExample.vue GitHub Actions / lint (18.x)
|
||
</h2> | ||
<p class="text-gray-700 text-opacity-100 text-base font-normal leading-6 mb-4 dark:text-gray-400"> | ||
Flowbite is an open-source | ||
library of UI components based on the utility-first Tailwind CSS framework | ||
featuring dark mode support, a Figma design system, templates, and more. | ||
</p> | ||
<p class="text-gray-700 text-opacity-100 text-base font-normal leading-6 mb-4 dark:text-gray-400"> | ||
It includes all of the | ||
commonly used components that a website requires, such as buttons, dropdowns, | ||
navigation bars, modals, but also some more advanced interactive elements such as datepickers. | ||
</p> | ||
<p class="text-gray-700 text-opacity-100 text-base font-normal leading-6 mb-4 dark:text-gray-400"> | ||
All of the elements are built | ||
using the utility classes from Tailwind CSS and vanilla JavaScript with | ||
support for TypeScript. | ||
</p> | ||
<iframe sandbox="allow-same-origin allow-scripts" width="100%" height="500px" | ||
Check warning on line 37 in docs/components/banner/examples/FwbBannerBottomExample.vue GitHub Actions / lint (18.x)
Check warning on line 37 in docs/components/banner/examples/FwbBannerBottomExample.vue GitHub Actions / lint (18.x)
|
||
class="my-8 rounded-lg shadow-lg yt-video" src="https://www.youtube.com/embed/KaLxCiilHns" | ||
Check warning on line 38 in docs/components/banner/examples/FwbBannerBottomExample.vue GitHub Actions / lint (18.x)
|
||
title="YouTube video player" frameborder="0" | ||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" | ||
allowfullscreen="" /> | ||
</div> | ||
<fwb-banner class="sticky bottom-0 left-0" position="bottom" closable> | ||
<div class="bg-gray-50 p-4 dark:bg-gray-700"> | ||
<p class="flex items-center gap-2 text-sm font-normal text-gray-500 dark:text-gray-400"> | ||
<svg class="w-6 h-6 text-gray-800 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" | ||
width="24" height="24" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" | ||
d="M3.559 4.544c.355-.35.834-.544 1.33-.544H19.11c.496 0 .975.194 1.33.544.356.35.559.829.559 1.331v9.25c0 .502-.203.981-.559 1.331-.355.35-.834.544-1.33.544H15.5l-2.7 3.6a1 1 0 0 1-1.6 0L8.5 17H4.889c-.496 0-.975-.194-1.33-.544A1.868 1.868 0 0 1 3 15.125v-9.25c0-.502.203-.981.559-1.331ZM7.556 7.5a1 1 0 1 0 0 2h8a1 1 0 0 0 0-2h-8Zm0 3.5a1 1 0 1 0 0 2H12a1 1 0 1 0 0-2H7.556Z" | ||
clip-rule="evenodd" /> | ||
</svg> | ||
<span class="[&_p]:inline"> | ||
New brand identity has been launched for the | ||
<a href="https://flowbite.com" | ||
class="inline font-medium text-cyan-600 underline decoration-solid underline-offset-2 hover:no-underline dark:text-cyan-500"> | ||
Flowbite Library | ||
</a> | ||
</span> | ||
</p> | ||
</div> | ||
</fwb-banner> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { FwbBanner } from '../../../../src/index' | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<template> | ||
<div | ||
class="vp-raw h-[25rem] overflow-y-scroll relative border border-gray-200 rounded-md dark:bg-gray-900 dark:border-gray-800"> | ||
<fwb-banner class="sticky top-0 left-0" closable> | ||
<div class="bg-gray-50 p-4 dark:bg-gray-700"> | ||
<p class="flex items-center gap-2 text-sm font-normal text-gray-500 dark:text-gray-400"> | ||
<svg class="w-6 h-6 text-gray-800 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" | ||
width="24" height="24" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" | ||
d="M3.559 4.544c.355-.35.834-.544 1.33-.544H19.11c.496 0 .975.194 1.33.544.356.35.559.829.559 1.331v9.25c0 .502-.203.981-.559 1.331-.355.35-.834.544-1.33.544H15.5l-2.7 3.6a1 1 0 0 1-1.6 0L8.5 17H4.889c-.496 0-.975-.194-1.33-.544A1.868 1.868 0 0 1 3 15.125v-9.25c0-.502.203-.981.559-1.331ZM7.556 7.5a1 1 0 1 0 0 2h8a1 1 0 0 0 0-2h-8Zm0 3.5a1 1 0 1 0 0 2H12a1 1 0 1 0 0-2H7.556Z" | ||
clip-rule="evenodd" /> | ||
</svg> | ||
|
||
<span class="[&_p]:inline"> | ||
New brand identity has been launched for the | ||
<a href="https://flowbite.com" | ||
class="inline font-medium text-cyan-600 underline decoration-solid underline-offset-2 hover:no-underline dark:text-cyan-500"> | ||
Flowbite Library | ||
</a> | ||
</span> | ||
</p> | ||
</div> | ||
</fwb-banner> | ||
<div class="px-8 py-4"> | ||
<div class="pb-4 mb-8 border-b border-gray-200 dark:border-gray-800"> | ||
<h1 id="content" class="inline-block mb-2 text-3xl font-extrabold tracking-tight text-gray-900 dark:text-white"> | ||
Flowbite - Tailwind CSS component library | ||
</h1> | ||
<p class="mb-4 text-lg text-gray-600 dark:text-gray-400"> | ||
Get started with the most popular | ||
open-source library of interactive UI components built with the utility classes from Tailwind | ||
CSS | ||
</p> | ||
</div> | ||
|
||
<h2 class="relative group text-xl font-semibold leading-8 mb-4 mt-8"> | ||
Introduction | ||
<span id="introduction" class="absolute -top-[140px]" /> <a | ||
class="ml-2 text-blue-700 opacity-0 transition-opacity dark:text-blue-500 group-hover:opacity-100" | ||
href="#introduction" aria-label="Link to this section: Introduction">#</a> | ||
</h2> | ||
<p class="text-gray-700 text-opacity-100 text-base font-normal leading-6 mb-4 dark:text-gray-400"> | ||
Flowbite is an open-source | ||
library of UI components based on the utility-first Tailwind CSS framework | ||
featuring dark mode support, a Figma design system, templates, and more. | ||
</p> | ||
<p class="text-gray-700 text-opacity-100 text-base font-normal leading-6 mb-4 dark:text-gray-400"> | ||
It includes all of the | ||
commonly used components that a website requires, such as buttons, dropdowns, | ||
navigation bars, modals, but also some more advanced interactive elements such as datepickers. | ||
</p> | ||
<p class="text-gray-700 text-opacity-100 text-base font-normal leading-6 mb-4 dark:text-gray-400"> | ||
All of the elements are built | ||
using the utility classes from Tailwind CSS and vanilla JavaScript with | ||
support for TypeScript. | ||
</p> | ||
<iframe sandbox="allow-same-origin allow-scripts" width="100%" height="500px" | ||
class="my-8 rounded-lg shadow-lg yt-video" src="https://www.youtube.com/embed/KaLxCiilHns" | ||
title="YouTube video player" frameborder="0" | ||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" | ||
allowfullscreen="" /> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { FwbBanner } from '../../../../src/index' | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<template> | ||
<div :class="bannerClasses" tabindex="-1" role="banner" aria-label="Banner"> | ||
<slot /> | ||
<button v-if="closable" :class="defaultCollapseButtonClass" aria-label="Collapse" type="button" @click="handleCollapse"> | ||
<svg class="w-6 h-6" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" | ||
viewBox="0 0 24 24"> | ||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" | ||
d="M6 18 17.94 6M18 18 6.06 6" /> | ||
</svg> | ||
</button> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { computed } from 'vue' | ||
import { useMergeClasses } from '@/composables/useMergeClasses' | ||
|
||
type BannerPosition = 'top' | 'bottom' | ||
|
||
type BannerProps = { | ||
class?: string | ||
position?: BannerPosition | ||
closable?: boolean | ||
} | ||
|
||
const props: BannerProps = withDefaults(defineProps<BannerProps>(), { | ||
class: '', | ||
position: 'top', | ||
closable: false, | ||
}) | ||
|
||
const defaultBannerClass = 'fixed start-0 z-50 flex justify-between items-center w-full p-4 bg-gray-50 dark:bg-gray-700' | ||
const positionDefaultClass = 'top-0 border-b border-gray-200 dark:border-gray-600' | ||
const positionBottomClass = 'bottom-0 border-t border-gray-200 dark:border-gray-600' | ||
|
||
const defaultCollapseButtonClass = 'flex-shrink-0 inline-flex justify-center w-7 h-7 items-center text-gray-400 border-none hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 dark:hover:bg-gray-600 dark:hover:text-white' | ||
|
||
const bannerClasses = computed(() => useMergeClasses([ | ||
defaultBannerClass, | ||
props.position === 'top' ? positionDefaultClass : positionBottomClass, | ||
props.class ?? '', | ||
])) | ||
|
||
const handleCollapse = (e: MouseEvent) => { | ||
const collapseButton = e.target as HTMLElement | ||
const banner = collapseButton.closest('[role="banner"]') as HTMLElement | null | ||
|
||
if (banner) { | ||
banner.remove() | ||
} | ||
} | ||
Comment on lines
+44
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve the collapse function for better performance. The - const handleCollapse = (e: MouseEvent) => {
- const collapseButton = e.target as HTMLElement
- const banner = collapseButton.closest('[role="banner"]') as HTMLElement | null
- if (banner) {
- banner.remove()
- }
+ const handleCollapse = () => {
+ emit('collapse')
} In the parent component: <fwb-banner @collapse="handleBannerCollapse" /> |
||
|
||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider making the close button more accessible.
The close button uses an SVG for the icon. Ensure the button is accessible by providing a clear
aria-label
and considering keyboard accessibility.Committable suggestion