Skip to content
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

Login page #31

Merged
merged 6 commits into from
May 2, 2022
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,11 @@
### Strapi init

[pull request](https://github.com/nickovchinnikov/coursesbox/pull/30)

### User, roles and auth flow

### Login page part 1

### Login page part 2

[pull request](https://github.com/nickovchinnikov/coursesbox/pull/31)
4 changes: 2 additions & 2 deletions frontend/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");

module.exports = {
stories: [
"../pages/**/*.stories.mdx",
"../pages/**/*.stories.@(js|jsx|ts|tsx)",
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)",
"../components/**/*.stories.mdx",
"../components/**/*.stories.@(js|jsx|ts|tsx)",
],
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type Props = {
/** Button color */
color?: Color;
/** Click handler */
onClick: (event: MouseEvent<HTMLButtonElement>) => void;
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
};

export const getColors = (theme: AppTheme, color?: Color): SerializedStyles => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`Course test cases Course render check 1`] = `
class="css-1d06jht"
>
<a
class="css-19pssqw"
class="css-1qm6sqv"
href="/hands-on-reactjs"
>
<h2>
Expand Down
21 changes: 12 additions & 9 deletions frontend/components/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import { Feedback } from "./Feedback";
export default {
title: "Controls/Input",
component: Input,
args: {
placeholder: "Your name",
label: "Name:",
},
args: {},
} as ComponentMeta<typeof Input>;

export const PrimaryInput: ComponentStoryObj<typeof Input> = {
Expand All @@ -21,19 +18,23 @@ export const PrimaryInput: ComponentStoryObj<typeof Input> = {
// await expect(args.onChange).toHaveBeenCalledTimes(6);
},
args: {
feedback: "Looks cool!",
placeholder: "Your name",
label: "Name:",
},
};

export const WithIcon: ComponentStoryObj<typeof Input> = {
args: {
icon: "Search",
placeholder: "Search",
height: 4,
},
};

export const WithValidFeedback: ComponentStoryObj<typeof Input> = {
export const WithInvalidFeedback: ComponentStoryObj<typeof Input> = {
args: {
feedback: <Feedback isValid={true}>Looks good!</Feedback>,
placeholder: "Some text",
feedback: <Feedback isValid={false}>Required!</Feedback>,
},
argTypes: {
feedback: {
Expand All @@ -42,9 +43,11 @@ export const WithValidFeedback: ComponentStoryObj<typeof Input> = {
},
};

export const WithInvalidFeedback: ComponentStoryObj<typeof Input> = {
export const WithValidFeedback: ComponentStoryObj<typeof Input> = {
args: {
feedback: <Feedback isValid={false}>Required!</Feedback>,
placeholder: "Some text",
label: "Text:",
feedback: <Feedback isValid={true}>Looks good!</Feedback>,
},
argTypes: {
feedback: {
Expand Down
96 changes: 63 additions & 33 deletions frontend/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,50 @@ import styled from "@emotion/styled";
import { Icon, AvailableIcons } from "@/components/Icon";
import { boxShadow } from "@/components/styles";

type WrapperProps = {
/** Input height */
height?: number;
/** Input width */
width?: number;
/** Label visibilty */
isLabelVisible?: boolean;
/** Feedback visibilty */
isFeedbackVisible?: boolean;
};

const Wrapper = styled.label<WrapperProps>`
display: grid;
gap: 0.1rem;
grid-template-areas:
"label"
"input"
"feedback";
grid-template-rows: ${({ isLabelVisible, isFeedbackVisible }) => {
if (isLabelVisible && isFeedbackVisible) {
return "1fr 3fr 1fr";
} else if (isLabelVisible) {
return "1fr 4fr 0fr";
} else if (isFeedbackVisible) {
return "0fr 4fr 1fr";
} else {
return "0fr 1fr 0fr";
}
}};
width: ${({ width }) => width}rem;
height: ${({ height }) => height}rem;
color: ${({ theme }) => theme.font.regular};
font-size: 1rem;
`;

const InputWrapper = styled.div`
grid-area: input;
display: flex;
position: relative;
align-items: center;
width: 100%;
height: 100%;
`;

const StyledInput = styled.input`
all: unset;
width: 100%;
Expand All @@ -27,54 +71,34 @@ const StyledInput = styled.input`
}
`;

type LabelProps = {
/** Input height */
height?: number;
/** Input width */
width?: number;
};

const Label = styled.label<LabelProps>`
display: flex;
justify-content: flex-start;
flex-direction: column;
width: ${({ width }) => width}rem;
height: ${({ height }) => height}rem;
color: ${({ theme }) => theme.font.regular};
font-size: 1rem;
`;

const StyledIcon = styled(Icon)`
position: absolute;
right: 0.3rem;
color: ${({ theme }) => theme.font.placeholder};
opacity: 0.7;
`;

const InputWrapper = styled.div`
display: flex;
position: relative;
align-items: center;
width: 100%;
height: 100%;
const Label = styled.span`
grid-area: label;
padding-left: 1.4rem;
`;

const Text = styled.span`
padding-left: 1.4rem;
const Feedback = styled(Label)`
grid-area: feedback;
`;

export type Props = {
/** Placeholder */
placeholder: string;
/** onChange handler */
onChange: ChangeEventHandler<HTMLInputElement>;
onChange?: ChangeEventHandler<HTMLInputElement>;
/** Input label */
label?: string;
/** Icon */
icon?: AvailableIcons;
/** Feedback for input */
feedback?: ReactChild;
} & LabelProps;
} & WrapperProps;

export const Input: FC<Props & InputHTMLAttributes<HTMLInputElement>> = ({
label,
Expand All @@ -83,14 +107,20 @@ export const Input: FC<Props & InputHTMLAttributes<HTMLInputElement>> = ({
icon,
feedback,
className,
...props
...rest
}) => (
<Label height={height} width={width} className={className}>
{label && <Text>{label}</Text>}
<Wrapper
isLabelVisible={Boolean(label)}
isFeedbackVisible={Boolean(feedback)}
height={height}
width={width}
className={className}
>
<Label>{label}</Label>
<InputWrapper>
<StyledInput {...props} />
<StyledInput {...rest} />
{icon && <StyledIcon name={icon} />}
</InputWrapper>
{feedback && <Text>{feedback}</Text>}
</Label>
<Feedback>{feedback}</Feedback>
</Wrapper>
);
18 changes: 12 additions & 6 deletions frontend/components/Input/__snapshots__/Input.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,44 @@
exports[`Input test cases Render check 1`] = `
<DocumentFragment>
<label
class="css-1oh93gp"
class="css-7e1mv2"
height="7"
width="20"
>
<span
class="css-1g58nbn"
class="css-1grri41"
>
Label
</span>
<div
class="css-1v67xy3"
class="css-52ovgc"
>
<input
class="css-1bj11r8"
placeholder="Plaiceholder"
/>
</div>
<span
class="css-1reg724"
/>
</label>
</DocumentFragment>
`;

exports[`Input test cases Render check with icon 1`] = `
<DocumentFragment>
<label
class="css-1oh93gp"
class="css-7e1mv2"
height="7"
width="20"
>
<span
class="css-1g58nbn"
class="css-1grri41"
>
Label
</span>
<div
class="css-1v67xy3"
class="css-52ovgc"
>
<input
class="css-1bj11r8"
Expand All @@ -60,6 +63,9 @@ exports[`Input test cases Render check with icon 1`] = `
/>
</svg>
</div>
<span
class="css-1reg724"
/>
</label>
</DocumentFragment>
`;
16 changes: 11 additions & 5 deletions frontend/components/Layout/__snapshots__/Layout.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`Layout test cases Render check 1`] = `
class="css-u0jlnf"
>
<a
class="css-vbvevl"
class="css-4w3zwj"
href="/"
>
<header
Expand All @@ -29,13 +29,13 @@ exports[`Layout test cases Render check 1`] = `
class="css-1sstk05"
>
<a
class="css-19yrd4a"
class="css-1sdexyg"
href="/all"
>
All
</a>
<a
class="css-19yrd4a"
class="css-1sdexyg"
href="/news"
>
News
Expand Down Expand Up @@ -64,12 +64,15 @@ exports[`Layout test cases Render check 1`] = `
</button>
</nav>
<label
class="css-1w3lqlr"
class="css-fabfz"
height="7"
width="20"
>
<span
class="css-1grri41"
/>
<div
class="css-1v67xy3"
class="css-52ovgc"
>
<input
class="css-1bj11r8"
Expand All @@ -92,6 +95,9 @@ exports[`Layout test cases Render check 1`] = `
/>
</svg>
</div>
<span
class="css-1reg724"
/>
</label>
<main
class="css-1qc1fvq"
Expand Down
7 changes: 6 additions & 1 deletion frontend/components/StyledLink/StyledLink.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import styled from "@emotion/styled";

export const StyledLink = styled.a`
export type Props = {
underline?: boolean;
};

export const StyledLink = styled.a<Props>`
all: unset;
cursor: pointer;
color: ${({ theme }) => theme.font.regular};
text-decoration: ${({ underline }) => (underline ? "underline" : "none")};
&:hover {
opacity: 0.7;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`StyledLink test cases StyledLink render check 1`] = `
<DocumentFragment>
<a
class="css-19yrd4a"
class="css-1sdexyg"
href="/hands-on-react-js"
>
Hands-On React. Build advanced React JS Frontend with expert
Expand Down
20 changes: 20 additions & 0 deletions frontend/components/Tile/CenteredTile.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { expect } from "@storybook/jest";
import { screen } from "@storybook/testing-library";
import { ComponentStoryObj, ComponentMeta } from "@storybook/react";

import { CenteredTile } from "./CenteredTile";

export default {
title: "Content/Tile",
component: CenteredTile,
} as ComponentMeta<typeof CenteredTile>;

export const CenteredTileExample: ComponentStoryObj<typeof CenteredTile> = {
play: async () => {
await expect(screen.getByRole("heading")).toBeInTheDocument();
},
args: {
header: "Lorem ipsum dolor sit amet",
children: "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
},
};
Loading