From 7ac66cd53d241bf2a068af7e745b631e25c0df58 Mon Sep 17 00:00:00 2001 From: Cosku Cinkilic Date: Fri, 18 Oct 2024 14:16:03 +0200 Subject: [PATCH] Add banner --- src/docs/constants/docs.constants.ts | 6 + src/lib/components.ts | 1 + src/lib/components/Banner.svelte | 84 +++++++++++ src/routes/(split)/components/banner/+page.md | 132 ++++++++++++++++++ src/tests/lib/components/Banner.spec.ts | 49 +++++++ src/tests/lib/components/BannerTest.svelte | 10 ++ 6 files changed, 282 insertions(+) create mode 100644 src/lib/components/Banner.svelte create mode 100644 src/routes/(split)/components/banner/+page.md create mode 100644 src/tests/lib/components/Banner.spec.ts create mode 100644 src/tests/lib/components/BannerTest.svelte diff --git a/src/docs/constants/docs.constants.ts b/src/docs/constants/docs.constants.ts index f5336d56..9d886ddf 100644 --- a/src/docs/constants/docs.constants.ts +++ b/src/docs/constants/docs.constants.ts @@ -161,6 +161,12 @@ export const COMPONENT_ROUTES: ComponentRoute[] = [ description: "A main banner for landing pages.", }, + { + path: "/components/banner", + title: "Banner", + + description: "Inside page banner", + }, { path: "/components/popover", diff --git a/src/lib/components.ts b/src/lib/components.ts index 73da112a..6e642ce0 100644 --- a/src/lib/components.ts +++ b/src/lib/components.ts @@ -1,5 +1,6 @@ export { default as Back } from "./components/Back.svelte"; export { default as Backdrop } from "./components/Backdrop.svelte"; +export { default as Banner } from "./components/Banner.svelte"; export { default as BottomSheet } from "./components/BottomSheet.svelte"; export { default as BusyScreen } from "./components/BusyScreen.svelte"; export { default as Card } from "./components/Card.svelte"; diff --git a/src/lib/components/Banner.svelte b/src/lib/components/Banner.svelte new file mode 100644 index 00000000..2b84de53 --- /dev/null +++ b/src/lib/components/Banner.svelte @@ -0,0 +1,84 @@ + + +{#if visible} + +{/if} + + diff --git a/src/routes/(split)/components/banner/+page.md b/src/routes/(split)/components/banner/+page.md new file mode 100644 index 00000000..05d2e69b --- /dev/null +++ b/src/routes/(split)/components/banner/+page.md @@ -0,0 +1,132 @@ + + +# Banner + +A versatile component to render informative banners with customizable content, actions, and visibility control. + +| Property | Description | Type | Default | +| --------- | --------------------------------------------------------------- | ----------------------- | ----------- | +| `testId` | Add a `data-tid` attribute to the DOM, useful for test purpose. | `string` or `undefined` | `undefined` | +| `visible` | Controls the visibility of the banner. | `boolean` | `true` | + +## Slots + +| Slot name | Description | +| ------------- | --------------------------------------------------------------------------- | +| `icon` | Icon appearing at the start of the banner. | +| `title` | Title of the banner. | +| `description` | Description text below the title. It should explain the banner's purpose. | +| `action` | Located on the right side of the banner. Useful for call-to-action buttons. | + +## Events + +| Event | Description | +| ---------- | -------------------------------------------- | +| `nnsClose` | Dispatched when the close button is clicked. | + +## Showcase + +The component has its own background color and visibility control, which can be customized using props and CSS variables. + +### Example + + + + Your ICP Wallet + + Create and link accounts, transfer ICP, participate in governance, and earn + rewards. + + + + +
+ + + +#### Code + +```text + + +Your ICP Wallet + +Create and link accounts, transfer ICP, participate in governance, and earn +rewards. + + + + + + +``` + +## Visibility Control + +The Banner component includes built-in visibility control: + +- The `visible` prop controls the visibility of the banner. +- When the close button is clicked, the `visible` prop is set to `false` and an `nnsClose` event is dispatched. + +## Customization + +You can customize the appearance of the Banner component using CSS variables: + +| CSS Variable | Description | Default Value | +| ------------------------------ | ------------------------------------ | ------------------------------ | +| `--banner-background` | Background color of the banner | `var(--input-background)` | +| `--banner-radius` | Border radius of the banner | `var(--border-radius)` | +| `--banner-top-bottom-padding` | Vertical padding inside the banner | `var(--padding)` | +| `--banner-left-right-padding` | Horizontal padding inside the banner | `var(--padding-1_5x)` | +| `--banner-column-gap` | Gap between banner elements | `var(--padding-1_5x)` | +| `--icon-background-padding` | Padding around the icon | `6px` | +| `--icon-background-color` | Background color of the icon wrapper | `var(--dropdown-border-color)` | +| `--icon-border-radius` | Border radius of the icon wrapper | `50%` | +| `--icon-color` | Color of the icon | `var(--elements-icons)` | +| `--close-button-padding` | Padding of the close button | `10px` | +| `--close-button-border-radius` | Border radius of the close button | `var(--border-radius)` | +| `--close-button-background` | Background color of the close button | `var(--card-background)` | + +Example of customization: + +```svelte + + + + + +``` + +This customization will apply a light blue theme to the banner and adjust the padding, border radius, and colors. diff --git a/src/tests/lib/components/Banner.spec.ts b/src/tests/lib/components/Banner.spec.ts new file mode 100644 index 00000000..61badbf4 --- /dev/null +++ b/src/tests/lib/components/Banner.spec.ts @@ -0,0 +1,49 @@ +import Banner from "$lib/components/Banner.svelte"; +import { fireEvent, render } from "@testing-library/svelte"; +import BannerTest from "./BannerTest.svelte"; + +describe("Banner", () => { + it("should render the banner when visible is true", () => { + const { container } = render(Banner); + expect(container.querySelector(".banner")).not.toBeNull(); + }); + + it("should not render the banner when visible is false", () => { + const { container } = render(Banner, { props: { visible: false } }); + expect(container.querySelector(".banner")).toBeNull(); + }); + + it("should render slotted content", () => { + const { getByText } = render(BannerTest); + expect(getByText("Test Icon")).toBeInTheDocument(); + expect(getByText("Test Title")).toBeInTheDocument(); + expect(getByText("Test Description")).toBeInTheDocument(); + expect(getByText("Test Action")).toBeInTheDocument(); + }); + + it("should close the banner when close button is clicked", async () => { + const { container, component } = render(Banner); + + const closeButton = container.querySelector( + ".close-button", + ) as HTMLButtonElement; + expect(closeButton).not.toBeNull(); + + const onClose = vi.fn(); + component.$on("nnsClose", onClose); + + await fireEvent.click(closeButton); + + expect(onClose).toHaveBeenCalled(); + expect(container.querySelector(".banner")).toBeNull(); + }); + + it("should apply custom test ID", () => { + const testId = "custom-banner-id"; + const { container } = render(Banner, { props: { testId } }); + + const banner = container.querySelector(".banner"); + expect(banner).not.toBeNull(); + expect(banner?.getAttribute("data-tid")).toBe(testId); + }); +}); diff --git a/src/tests/lib/components/BannerTest.svelte b/src/tests/lib/components/BannerTest.svelte new file mode 100644 index 00000000..c6873b3e --- /dev/null +++ b/src/tests/lib/components/BannerTest.svelte @@ -0,0 +1,10 @@ + + + + Test Icon + Test Title + Test Description + +