diff --git a/apps/front-end/src/components/panel/Panel.stories.tsx b/apps/front-end/src/components/panel/Panel.stories.tsx index 1b17c487..6bddd71c 100644 --- a/apps/front-end/src/components/panel/Panel.stories.tsx +++ b/apps/front-end/src/components/panel/Panel.stories.tsx @@ -8,12 +8,51 @@ import Panel from "./Panel"; import { store } from "../../app/store"; import { Provider } from "react-redux"; +// Helper function to prevent link navigation and handle clicks +const attachLinkClickListeners = async ( + canvasElement: HTMLElement, + onLinkClick: (link: string) => void, +) => { + const canvas = within(canvasElement); + const links = await canvas.getAllByRole("link"); + + // Prevent default behavior for all links + links.forEach((link) => { + link.addEventListener("click", (e) => { + e.preventDefault(); + onLinkClick(link.getAttribute("href") || "unknown"); // Trigger the onLinkClick action + }); + }); + + // Simulate clicking the first link for testing + if (links.length > 0) { + await userEvent.click(links[0]); + } +}; + +// Helper function to switch tabs and attach listeners +const clickInteraction = async (canvasElement: HTMLElement, args: any) => { + const canvas = within(canvasElement); + + // Click the "Directory" tab to show DirectoryPanel + const directoryTab = await canvas.getByRole("tab", { name: /Directory/i }); + await userEvent.click(directoryTab); + + // Attach event listeners to prevent navigation + await attachLinkClickListeners(canvasElement, args.onLinkClick); +}; + const meta: Meta = { title: "Components/Panel", component: Panel, parameters: { layout: "fullscreen", }, + argTypes: { + onTabChange: { action: "tabChanged" }, // Action for tab switching + onLinkClick: { action: "linkClicked" }, // Action for link clicks + onTogglePanel: { action: "panelToggled" }, // Action for toggling the panel + }, decorators: [ (Story) => ( @@ -32,14 +71,41 @@ export default meta; type Story = StoryObj; export const Default: Story = { - play: async ({ canvasElement }) => { + play: async ({ + canvasElement, + args, + }: { + canvasElement: HTMLElement; + args: any; + }) => { const canvas = within(canvasElement); - // Click to open the panel - const openButton = await canvas.getByRole("button"); - await userEvent.click(openButton); + // Initially click on "Directory" tab to show DirectoryPanel + await clickInteraction(canvasElement, args); + + // Now simulate switching to another tab and back to Directory + const searchTab = await canvas.getByRole("tab", { name: /Search/i }); + await userEvent.click(searchTab); + args.onTabChange(1); - // Wait and then close the panel - await userEvent.click(openButton); + // Switch back to Directory tab + const directoryTab = await canvas.getByRole("tab", { name: /Directory/i }); + await userEvent.click(directoryTab); + args.onTabChange(0); + + // Re-apply the link click listeners when the Directory tab is re-selected + await attachLinkClickListeners(canvasElement, args.onLinkClick); + }, + args: { + onTabChange: (tabIndex: number) => { + console.log(`Tab changed to ${tabIndex}`); + }, + onLinkClick: (link: string) => { + console.log(`Link clicked: ${link}`); + }, + onTogglePanel: (isOpen: boolean) => { + console.log(`Panel toggled: ${isOpen}`); + }, }, }; + diff --git a/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.stories.tsx b/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.stories.tsx new file mode 100644 index 00000000..7b3bf94b --- /dev/null +++ b/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.stories.tsx @@ -0,0 +1,46 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { userEvent, within } from "@storybook/test"; +import DirectoryPanel from "./DirectoryPanel"; +import { ThemeProvider } from "@mui/material/styles"; +import theme from "../../../theme/theme"; +import GlobalCSSVariables from "../../../theme/GlobalCSSVariables"; + +// Simulate a click event on a link within the DirectoryPanel +const clickInteraction = async (canvasElement: HTMLElement) => { + const canvas = within(canvasElement); + const links = await canvas.getAllByRole("link"); // Get all links in the panel + + links.forEach((link) => { + link.addEventListener("click", (e) => e.preventDefault()); // Prevent navigation for all links + }); + + // Simulate clicking on the first link, for example + await userEvent.click(links[0]); +}; + +const meta = { + title: "DirectoryPanel", + component: DirectoryPanel, + decorators: [ + (Story) => ( + + + + + ), + ], + tags: ["autodocs"], + parameters: { + layout: "centered", + actions: { + handles: ["click a"], + }, + }, +} as Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: ({ canvasElement }) => clickInteraction(canvasElement), +}; diff --git a/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.tsx b/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.tsx index ffe13037..68cd6ac8 100644 --- a/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.tsx +++ b/apps/front-end/src/components/panel/directoryPanel/DirectoryPanel.tsx @@ -1,42 +1,71 @@ import Heading from "../heading/Heading"; -import ContentPanel from "../contentPanel/ContentPanel"; import DirectoryItem from "./directoryItem/DirectoryItem"; import List from "@mui/material/List"; +import ListItem from "@mui/material/ListItem"; +import Link from "@mui/material/Link"; +import Box from "@mui/material/Box"; +import { styled } from "@mui/material/styles"; // Mock data const countries = [ - { id: "1", name: "Argentina", link: "#" }, - { id: "2", name: "Australia", link: "#" }, - { id: "3", name: "Austria", link: "#" }, - { id: "4", name: "Bangladesh", link: "#" }, - { id: "5", name: "Barbados", link: "#" }, - { id: "6", name: "Belarus", link: "#" }, - { id: "7", name: "Belgium", link: "#" }, - { id: "8", name: "Bolivia", link: "#" }, - { id: "9", name: "Brazil", link: "#" }, - { id: "10", name: "Bulgaria", link: "#" }, - { id: "11", name: "Canada", link: "#" }, - { id: "12", name: "Chile", link: "#" }, - { id: "13", name: "China", link: "#" }, - { id: "14", name: "Colombia", link: "#" }, - { id: "15", name: "Costa Rica", link: "#" }, - { id: "16", name: "Côte d'Ivoire", link: "#" }, - { id: "17", name: "Curaçao", link: "#" }, - { id: "18", name: "Cyprus", link: "#" }, - { id: "19", name: "Czechia", link: "#" }, + { id: "1", name: "Argentina", link: "" }, + { id: "2", name: "Australia", link: "" }, + { id: "3", name: "Austria", link: "" }, + { id: "4", name: "Bangladesh", link: "" }, + { id: "5", name: "Barbados", link: "" }, + { id: "6", name: "Belarus", link: "" }, + { id: "7", name: "Belgium", link: "" }, + { id: "8", name: "Bolivia", link: "" }, + { id: "9", name: "Brazil", link: "" }, + { id: "10", name: "Bulgaria", link: "" }, + { id: "11", name: "Canada", link: "" }, + { id: "12", name: "Chile", link: "" }, + { id: "13", name: "China", link: "" }, + { id: "14", name: "Colombia", link: "" }, + { id: "15", name: "Costa Rica", link: "" }, + { id: "16", name: "Côte d'Ivoire", link: "" }, + { id: "17", name: "Curaçao", link: "" }, + { id: "18", name: "Cyprus", link: "" }, + { id: "19", name: "Czechia", link: "" }, ]; -const DirectoryPanel = () => { +interface DirectoryPanelProps { + onClick?: (e: React.MouseEvent) => void; // for storybook testing +} + +const StyledDirectoryPanel = styled(Box)(() => ({ + padding: "var(--spacing-medium) 0", + maxWidth: "var(--panel-width-desktop)", + margin: "0 auto", + "@media (min-width: 768px)": { + padding: "var(--spacing-large) 0", + }, +})); + +const StyledLink = styled(Link)(() => ({ + color: "var(--color-primary)", + display: "block", + "&:hover": { + backgroundColor: "var(--color-neutral-light)", + }, +})); + +const DirectoryPanel = ({onClick}: DirectoryPanelProps) => { return ( <> - + + + + All Entries + + {countries.map((country) => ( ))} - + ); }; diff --git a/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.stories.tsx b/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.stories.tsx new file mode 100644 index 00000000..ef64a8ae --- /dev/null +++ b/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.stories.tsx @@ -0,0 +1,53 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { userEvent, within } from "@storybook/test"; +import DirectoryItem from "./DirectoryItem"; +import { ThemeProvider } from "@mui/material/styles"; +import theme from "../../../../theme/theme"; +import GlobalCSSVariables from "../../../../theme/GlobalCSSVariables"; + +// Simulate a click event on a link +const clickInteraction = async (canvasElement: HTMLElement) => { + const canvas = within(canvasElement); + const link = await canvas.getByRole("link"); + await userEvent.click(link); +}; + +const meta = { + title: "DirectoryItem", + component: DirectoryItem, + decorators: [ + (Story) => ( + + + + + ), + ], + tags: ["autodocs"], + argTypes: { + onClick: { action: "clicked" }, // This action will log the event + }, + args: { + link: "javascript:void(0)", // Prevent navigation by using this link + }, + parameters: { + layout: "centered", + actions: { + handles: ["click a"], + }, + }, +} as Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + name: "Directory Item", + onClick: (e: React.MouseEvent) => { + e.preventDefault(); + console.log("Link clicked"); // Log the event to show it's working + }, + }, + play: ({ canvasElement }) => clickInteraction(canvasElement), +}; diff --git a/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.tsx b/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.tsx index ec99cc22..ee6b9ee1 100644 --- a/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.tsx +++ b/apps/front-end/src/components/panel/directoryPanel/directoryItem/DirectoryItem.tsx @@ -1,13 +1,27 @@ -import React from "react"; import ListItem from "@mui/material/ListItem"; +import { styled } from "@mui/material/styles"; +import Link from "@mui/material/Link"; + interface DirectoryItemProps { id: string; name: string; link: string; + onClick?: (e: React.MouseEvent) => void; // for storybook testing } -const DirectoryItem = ({id, name, link}: DirectoryItemProps) => { - return {name}; +const StyledLink = styled(Link)(() => ({ + color: "var(--color-text)", + "&:hover": { + backgroundColor: "var(--color-neutral-light)", + }, +})); + +const DirectoryItem = ({ id, name, link, onClick }: DirectoryItemProps) => { + return ( + + {name} + + ); }; export default DirectoryItem; diff --git a/apps/front-end/src/theme/GlobalCSSVariables.tsx b/apps/front-end/src/theme/GlobalCSSVariables.tsx index d968e7a3..b3cae22f 100644 --- a/apps/front-end/src/theme/GlobalCSSVariables.tsx +++ b/apps/front-end/src/theme/GlobalCSSVariables.tsx @@ -25,6 +25,9 @@ const rootVariables = { "--font-size-xlarge": "20px", "--font-size-xxlarge": "24px", "--font-size-xxxlarge": "32px", + "--font-weight-normal": 400, + "--font-weight-medium": 500, + "--font-weight-bold": 600, }; const GlobalCSSVariables: FC = () => { diff --git a/apps/front-end/src/theme/theme.ts b/apps/front-end/src/theme/theme.ts index 343cde15..9a5ff643 100644 --- a/apps/front-end/src/theme/theme.ts +++ b/apps/front-end/src/theme/theme.ts @@ -1,7 +1,6 @@ import { createTheme, responsiveFontSizes } from "@mui/material/styles"; import type { ThemeOptions } from "@mui/material/styles"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; -import { m } from "vitest/dist/reporters-yx5ZTtEV.js"; const themeOptions: ThemeOptions = { breakpoints: { @@ -29,21 +28,21 @@ const themeOptions: ThemeOptions = { typography: { button: { textTransform: "none", - fontWeight: 400, + fontWeight: "var(--font-weight-normal)", color: "#fff", fontSize: "var(--font-size-small)", }, h1: { fontSize: "var(--font-size-xxlarge)", textAlign: "left", - fontWeight: 500, + fontWeight: "var(--font-weight-medium)", "@media (min-width: 600px)": { fontSize: "var(--font-size-xxxlarge)", }, }, h4: { fontSize: "var(--font-size-medium)", - fontWeight: 500, + fontWeight: "var(--font-weight-medium)", marginBottom: "var(--spacing-small)", color: "var(--color-primary)", "@media (min-width: 600px)": { @@ -82,7 +81,7 @@ const themeOptions: ThemeOptions = { minWidth: "unset", maxWidth: "110px", textTransform: "none", - fontWeight: 400, + fontWeight: "var(--font-weight-normal)", fontSize: "0", color: "#ffffffcc", backgroundColor: "var(--color-primary)", @@ -149,6 +148,20 @@ const themeOptions: ThemeOptions = { }, }, }, + MuiLink: { + styleOverrides: { + root: { + width: "100%", + padding: "var(--spacing-small) var(--spacing-medium)", + display: "block", + textDecoration: "none", + fontWeight: "var(--font-weight-medium)", + "@media (min-width: 768px)": { + padding: "var(--spacing-small) var(--spacing-large)", + }, + }, + }, + }, MuiOutlinedInput: { styleOverrides: { notchedOutline: { @@ -231,7 +244,7 @@ const themeOptions: ThemeOptions = { root: { width: "100%", color: "var(--color-text)", - fontWeight: 600, + fontWeight: "var(--font-weight-bold)", marginBottom: "var(--spacing-small)", }, }, @@ -256,6 +269,23 @@ const themeOptions: ThemeOptions = { }, }, }, + MuiList: { + styleOverrides: { + root: { + padding: "0", + margin: "0", + listStyleType: "none", + }, + }, + }, + MuiListItem: { + styleOverrides: { + root: { + padding: 0, + margin: 0, + }, + }, + }, }, };