Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";
import { PlaceholderIcon } from "@lifesg/react-icons/placeholder";
import { NotificationBanner } from "@lifesg/react-design-system/notification-banner";

export default function Story() {
return (
<div className="story-column-container">
<NotificationBanner data-testid="banner-default">
This is a default notification banner
</NotificationBanner>

<NotificationBanner
data-testid="banner-with-icon"
icon={<PlaceholderIcon />}
>
This is a notification banner with an icon
</NotificationBanner>

<NotificationBanner
data-testid="banner-non-dismissible"
dismissible={false}
>
This is a non-dismissible notification banner
</NotificationBanner>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use client";
import { GearFillIcon } from "@lifesg/react-icons/gear-fill";
import { NotificationBanner } from "@lifesg/react-design-system/notification-banner";
import styles from "./notification-banner.module.css";

export default function Story() {
return (
<div className="story-column-container">
<NotificationBanner data-testid="banner-custom-content">
<div
data-testid="custom-content-wrapper"
className={styles.custom}
>
<GearFillIcon />
Custom content
</div>
</NotificationBanner>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";
import { NotificationBanner } from "@lifesg/react-design-system/notification-banner";
import { ArrowRightIcon } from "@lifesg/react-icons/arrow-right";

export default function Story() {
return (
<div className="story-column-container">
<NotificationBanner
data-testid="banner-long-content"
maxCollapsedHeight={100}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
</NotificationBanner>

<NotificationBanner
data-testid="banner-long-content-action-button"
maxCollapsedHeight={100}
actionButton={{
children: (
<>
View more
<ArrowRightIcon />
</>
),
}}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
</NotificationBanner>
</div>
);
}
Comment thread
qroll marked this conversation as resolved.
Comment thread
qroll marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";
import { NotificationBanner } from "@lifesg/react-design-system/notification-banner";
import styles from "./notification-banner.module.css";

export default function Story() {
return (
<div>
<NotificationBanner data-testid="banner-non-sticky" sticky={false}>
This is a non-sticky notification banner.
</NotificationBanner>
<div className={styles.sticky}>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</p>
</div>
</div>
);
}
Comment thread
qroll marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.custom {
display: flex;
gap: 1rem;
align-items: center;
width: 100%;
padding: 1rem;
color: black;
background: yellow;
}

.sticky {
height: 200vh;
background-color: teal;
border: solid 10px crimson;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";
import { NotificationBanner } from "@lifesg/react-design-system/notification-banner";
import styles from "./notification-banner.module.css";

export default function Story() {
return (
<div>
<NotificationBanner data-testid="banner-sticky">
This is a sticky notification banner.
</NotificationBanner>
<div className={styles.sticky}>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</p>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";
import { NotificationBanner } from "@lifesg/react-design-system/notification-banner";

export default function Story() {
return (
<div className="story-column-container">
<NotificationBanner data-testid="banner-text-styling">
This banner has <strong>bold text</strong>, <em>italic text</em>
, anchor tag for normal{" "}
<a href="https://sample-url.com">link</a>, and Link component
for{" "}
<NotificationBanner.Link href="https://sample-url.com" external>
external link
</NotificationBanner.Link>
.
</NotificationBanner>
</div>
);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { test as base, expect, Locator, Page } from "@playwright/test";
import { AbstractStoryPage, compareScreenshot } from "../../utils";

class StoryPage extends AbstractStoryPage {
protected readonly component = "notification-banner";

public readonly locators: {
bannerNonSticky: Locator;
bannerSticky: Locator;
};

constructor(page: Page) {
super(page);

this.locators = {
bannerNonSticky: page.getByTestId("banner-non-sticky"),
bannerSticky: page.getByTestId("banner-sticky"),
};
}
}

const test = base.extend<{ story: StoryPage }>({
story: async ({ page }, use) => {
const story = new StoryPage(page);
await use(story);
},
});

test.describe("NotificationBanner", () => {
test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("all-variants");
});

test("All variants", async ({ story }) => {
await compareScreenshot(story, "mount");
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("all-variants", { mode: "dark" });
});

test("All variants (dark mode)", async ({ story }) => {
await compareScreenshot(story, "mount");
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("all-variants", { size: "mobile" });
});

test("Mobile", async ({ story }) => {
await compareScreenshot(story, "mount");
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("long-content");
});

test("Long content", async ({ story }) => {
await compareScreenshot(story, "mount");
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("custom-content");
});

test("Custom content", async ({ story }) => {
await compareScreenshot(story, "mount");
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("text-styling");
});

test("Text styling", async ({ story }) => {
await compareScreenshot(story, "mount");
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("non-sticky");
});

test("Non-sticky banner scrolls out of view", async ({ story }) => {
await test.step("Verify non-sticky banner is visible initially", async () => {
await expect(story.locators.bannerNonSticky).toBeInViewport();
});

await test.step("Scroll down the page", async () => {
await story.page.mouse.wheel(0, 100);
await story.page.waitForTimeout(300);
});

await test.step("Verify non-sticky banner scrolled out of view", async () => {
await expect(
story.locators.bannerNonSticky
).not.toBeInViewport();
});
});
});

test.describe(() => {
test.beforeEach(async ({ story }) => {
await story.init("sticky");
});

test("Sticky banner behaviour", async ({ story }) => {
await test.step("Verify sticky banner is visible initially", async () => {
await expect(story.locators.bannerSticky).toBeInViewport();
await compareScreenshot(story, "mount", { fullscreen: true });
});

await test.step("Scroll down the page", async () => {
await story.scrollToEnd({ scrollTarget: story.layout });
});

await test.step("Verify sticky banner remains in view", async () => {
await expect(story.locators.bannerSticky).toBeInViewport();
await compareScreenshot(story, "after-scroll", {
fullscreen: true,
});
});
});
});
});
Loading