Skip to content

Commit

Permalink
add a Modal component
Browse files Browse the repository at this point in the history
  • Loading branch information
stasguma committed Mar 11, 2024
1 parent 3026400 commit 9af9adb
Show file tree
Hide file tree
Showing 26 changed files with 343 additions and 16 deletions.
1 change: 1 addition & 0 deletions config/storybook/decorators/withLangDecorator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const withLangDecorator: Decorator = (Story, context) => {
// const { i18n } = useTranslation();
// const [globals, updateGlobals] = useGlobals();

/* eslint-disable-next-line */
useEffect(() => {
/* eslint-disable-next-line */
i18n.changeLanguage(locale);
Expand Down
1 change: 1 addition & 0 deletions config/storybook/decorators/withThemeDecorator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { changeThemeInDOM } from '../../../src/app/providers/ThemeProvider/lib/c
export const withThemeDecorator: Decorator = (Story, context) => {
const { theme } = context.globals;

/* eslint-disable-next-line */
useEffect(() => {
changeThemeInDOM(theme as ETheme);
}, [theme]);
Expand Down
8 changes: 6 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import i18nextPlugin from 'eslint-plugin-i18next';
import stylistic from '@stylistic/eslint-plugin';
import jestDom from 'eslint-plugin-jest-dom';
import storybookPlugin from 'eslint-plugin-storybook';
import reactHooksPlugin from 'eslint-plugin-react-hooks';

// console.log(storybookPlugin.configs.recommended.overrides);
// console.log(reactHooksPlugin.configs.recommended);

const jsFiles = '**/*.?(*)js?(x)';
const tsFiles = '**/*.?(*)ts?(x)';
Expand All @@ -26,7 +27,8 @@ export default [
'**/.*',
'**/.*.{js,ts}',
'**/*.config.{js,ts}',
'**/jest-setup.ts'
'**/jest-setup.ts',
'storybook-static'
],
},
{
Expand Down Expand Up @@ -116,11 +118,13 @@ export default [
},
plugins: {
react: reactPlugin,
'react-hooks': reactHooksPlugin,
i18next: i18nextPlugin,
},
rules: {
...reactPlugin.configs.recommended.rules,
...reactPlugin.configs['jsx-runtime'].rules,
...reactHooksPlugin.configs.recommended.rules,
...i18nextPlugin.configs.recommended.rules,

'@stylistic/jsx-max-props-per-line': [1, {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@svgr/webpack": "^8.1.0",
"@testing-library/jest-dom": "^6.4.1",
"@testing-library/react": "^14.2.0",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.11",
"@types/node": "^20.10.8",
"@types/react": "^18.2.47",
Expand All @@ -69,6 +70,7 @@
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.6.15",
"globals": "^13.24.0",
"html-webpack-plugin": "^5.6.0",
Expand Down
24 changes: 24 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"reload": "Reload",
"errorBoundaryText": "Something went wrong. Please, reload the page!",
"home": "Home",
"about": "About"
"about": "About",
"Log In": "Log In"
}
3 changes: 2 additions & 1 deletion public/locales/ua/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"reload": "Перезавантажити",
"errorBoundaryText": "Щось пішло не за планом. Будь ласка, перезавантажте сторінку!",
"home": "Головна",
"about": "О нас"
"about": "О нас",
"Log In": "Увійти"
}
3 changes: 1 addition & 2 deletions src/app/layouts/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ const Layout: FC = () => {
</Suspense>
</main>
</div>
<footer>2024</footer>
<div style={{ 'display': 'flex', 'flex-flow': 'row' }}>
<div style={{ display: 'flex', flexFlow: 'row' }}>
<div style={{ width: '100%', height: '100%' }}>
<div className="p-orange-100">100</div>
<div className="p-orange-200">200</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ export const useThemeRelyOnColorScheme = (): void => {
return () => {
OSColorSchemeDark.removeEventListener('change', onThemeChange);
};
}, []);
}, [OSColorSchemeDark]);
};
2 changes: 1 addition & 1 deletion src/app/providers/router/ui/AppRouterProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type FC } from 'react';
import { RouterProvider, createBrowserRouter } from 'react-router-dom';

import routerConfig from '@/shared/config/routerConfig/routerConfig';
import routerConfig from '@/shared/config/router/routerConfig';

const router = createBrowserRouter(routerConfig);

Expand Down
1 change: 1 addition & 0 deletions src/app/styles/themes/_dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:root[data-theme="dark"] {
--color-bg: #{fn.pick-color($theme-colors, 'background', 'dark')};
--color-bg-accent: #{fn.pick-color($theme-colors, 'background2', 'dark')};
--color-backdrop: #{fn.pick-color($theme-colors, 'backdrop', 'dark')};
--color-text: #{fn.pick-color($theme-colors, 'text', 'dark')};
--color-heading: #{fn.pick-color($theme-colors, 'heading', 'dark')};
--color-primary: #{fn.pick-color($theme-colors, 'primary', 'dark')};
Expand Down
1 change: 1 addition & 0 deletions src/app/styles/themes/_light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:root[data-theme="light"] {
--color-bg: #{fn.pick-color($theme-colors, 'background')};
--color-bg-accent: #{fn.pick-color($theme-colors, 'background2')};
--color-backdrop: #{fn.pick-color($theme-colors, 'backdrop')};
--color-text: #{fn.pick-color($theme-colors, 'text')};
--color-heading: #{fn.pick-color($theme-colors, 'heading')};
--color-primary: #{fn.pick-color($theme-colors, 'primary')};
Expand Down
15 changes: 15 additions & 0 deletions src/app/styles/variables/_animations.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
@keyframes fade-in {
0% { opacity: 0 }
100% { opacity: 1 }
}

@keyframes fade-out {
0% { opacity: 1 }
100% { opacity: 0 }
}

@keyframes scale-up {
from { transform: scale(.75) }
to { transform: scale(1) }
}

@keyframes scale-down {
from { transform: scale(1) }
to { transform: scale(.75) }
}
4 changes: 4 additions & 0 deletions src/app/styles/variables/_theme-colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ $theme-colors: (
"light": $white-2,
"dark": $dark-blue,
),
"backdrop": (
"light": color.change(fn.pick-tint(p.$palette-gray, 900), $alpha: 0.8),
"dark": color.change(fn.pick-tint(p.$palette-gray, 900), $alpha: 0.8),
),
"navbar-background": (
"light": $pale-pink,
"dark": $dark-blue
Expand Down
2 changes: 1 addition & 1 deletion src/pages/HomePage/ui/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { type FC } from 'react';

import { useTranslation } from 'react-i18next';

const HomePage: FC = () => {
const { t } = useTranslation();

return (
<>
<h1>{t('home')}</h1>
Expand Down
3 changes: 3 additions & 0 deletions src/shared/assets/icons/x-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
75 changes: 75 additions & 0 deletions src/shared/ui/Modal/Modal.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
@use "@/app/styles/variables" as vars;

.modal {
position: fixed;
inset: 0;
display: none;

&__backdrop {
position: absolute;
inset: 0;
opacity: 0;
background-color: var(--color-backdrop);
transition: opacity .2s vars.$ease-3;
}

&__wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}

&__content {
position: relative;

max-width: clamp(550px, 60vw, 700px);
padding: 24px 20px;

opacity: 0;
background-color: var(--color-bg);
border-radius: 4px;
}

&__close-btn {
position: absolute;
top: 0;
right: 0;

width: 28px;
height: 28px;

color: #000;

background-color: #fff;
border-radius: 4px;
}

&:global(.is-open) {
z-index: 10;
display: block;

.modal__backdrop {
opacity: 1;
animation: fade-in .2s vars.$ease-3;
}

.modal__content {
opacity: 1;
animation: scale-up .4s vars.$ease-elastic-in-out-5, fade-in .4s vars.$ease-elastic-in-out-5;
}
}

&:global(.is-closing) {
.modal__backdrop {
opacity: 0;
animation: fade-out .3s vars.$ease-3;
}

.modal__content {
opacity: 0;
animation: scale-down .15s vars.$ease-3, fade-out .15s vars.$ease-3;
}
}
}
19 changes: 19 additions & 0 deletions src/shared/ui/Modal/Modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react';

import { Modal } from './Modal';

// 👇 This default export determines where your story goes in the story list
const meta: Meta<typeof Modal> = {
title: 'Shared/Modal',
component: Modal,
};

export default meta;
type Story = StoryObj<typeof Modal>;

export const Default: Story = {
args: {
children: 'Loasdoa sdas das daosdaosk doas dasdo kasdaskodkaso daso dkasodasod kasodkasodkaoskdoa sdo akosdk asod kasodk asodk asod kasod kaso dkaso kasodk asodj ashdu ashjhdasljdhasljdhlas jdhalsjhdlasjhdqwu hdsajhdlasjhdlajshld jasdh asjdhlasjhdasljdh saljdhlasjhdlasj hlsjakhdlajskhdlasjhda jsajldhlajshdaljsdals ljasd',
isOpen: true,
},
};
31 changes: 31 additions & 0 deletions src/shared/ui/Modal/Modal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { render, screen } from '@testing-library/react';
// import userEvent from '@testing-library/user-event';

import { Modal } from './Modal';

describe('<Modal />', () => {
test('modal is open', () => {
render(<Modal isOpen={true}>Modal</Modal>);
expect(screen.getByTestId('modal')).toBeInTheDocument();
expect(screen.getByTestId('modal')).toHaveClass('is-open');
});

// test('close modal by a close button', async () => {
// const closeHandler = jest.fn();
// render(<Modal isOpen={true} onClose={closeHandler}>Modal</Modal>);
// const modal = screen.getByTestId('modal');
// const modalBackdrop = screen.getByTestId('modal-backdrop');
// const closeBtn = screen.getByTestId('modal-close-btn');

// await userEvent.click(closeBtn);
// expect(modal).toHaveClass('is-closing');
// fireEvent.animationEnd(modalBackdrop);
// expect(modal).not.toHaveClass('is-closing');
// closeHandler();
// expect(closeHandler).toHaveBeenCalled();
// // await waitForElementToBeRemoved(() => expect(screen.queryByTestId('modal')).not.toBeInTheDocument());
// await waitForElementToBeRemoved(() => screen.queryByTestId('modal'));

// expect(modal).not.toBeInTheDocument();
// });
});
Loading

0 comments on commit 9af9adb

Please sign in to comment.