added article with parts uses dot notation

This commit is contained in:
Maximus 2022-08-29 13:37:46 +03:00
parent 28854c35b1
commit bd3015dcf0
11 changed files with 491 additions and 38 deletions

View File

@ -27,11 +27,11 @@
"react-scripts": "5.0.1",
"react-scrollbars-custom": "^4.1.0",
"storybook-addon-pseudo-states": "^1.15.1",
"tailwindcss": "^3.1.7",
"tsconfig-paths-webpack-plugin": "^4.0.0",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4",
"yup": "^0.32.11",
"tailwindcss": "^3.1.7"
"yup": "^0.32.11"
},
"scripts": {
"dev-tools": "redux-devtools --hostname=localhost --port=8000",
@ -91,6 +91,7 @@
"@storybook/react": "^6.5.9",
"@storybook/testing-library": "^0.0.13",
"@svgr/webpack": "^6.3.1",
"@tailwindcss/line-clamp": "^0.4.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",

View File

@ -0,0 +1,75 @@
import React, { useState } from "react";
/* -------------------------------------------------------------------------- */
/* imports Article parts */
/* -------------------------------------------------------------------------- */
import { ArticleTitle } from "./ArticleParts/ArticleTitle";
import { ArticleBreadcumbs } from "./ArticleParts/ArticleBreadcumbs";
import { ArticleAuthors } from "./ArticleParts/ArticleAuthors";
import { ArticleKeywords } from "./ArticleParts/ArticleKeywords";
import { ArticleInteractionButtons } from "./ArticleParts/ArticleInteractionButtons";
import { ArticleDescription } from "./ArticleParts/ArticleDescription";
import { ArticleSubscriptionsButtons } from "./ArticleParts/ArticleSubscriptionsButton";
/**
* Reduces a sequence of names to initials.
* @param {String} name Space Delimited sequence of names.
* @param {String} sep A period separating the initials.
* @param {String} trail A period ending the initials.
* @param {String} hyph A hypen separating double names.
* @return {String} Properly formatted initials.
*/
type ArticleTileExtentions = {
Title?: {
children?: string;
className?: string;
};
Breadcumbs?: {
children?: string[];
highlightLAstChild?: boolean;
};
Authors?: {
children: React.ReactNode;
className?: string;
emphasis?: "low" | "high";
};
Keywords?: {
children?: React.ReactNode;
className?: string;
emphasis?: "low" | "high";
};
Description?: {
children?: React.ReactNode;
emphasis?: "low" | "high";
isShowing?: boolean;
};
InteractionButtons?: {
children?: React.ReactNode;
className?: string;
emphasis?: "high" | "low";
};
SubscriptionButtons?: {
className?: string;
};
};
type ArticleTileProps = {
/** Description of prop "foo". */
children?: React.ReactNode;
};
export function Article({
/** Description of prop "foo". */
children,
}: ArticleTileProps & ArticleTileExtentions) {
const [isShowing, setIsShowing] = useState(false);
return <div className="flex flex-col w-full">{children}</div>;
}
Article.Title = ArticleTitle;
Article.Breadcumbs = ArticleBreadcumbs;
Article.Authors = ArticleAuthors;
Article.Keywords = ArticleKeywords;
Article.InteractionButtons = ArticleInteractionButtons;
Article.Description = ArticleDescription;
Article.SubscriptionsButtons = ArticleSubscriptionsButtons;

View File

@ -0,0 +1,53 @@
import React, { useMemo } from "react";
import { RouterLink } from "components/typography/RouterLink";
import Typography from "components/typography/Typography";
import classNames from "classnames";
import { SVGUser } from "components/icons";
type AuthorsProps = {
children: React.ReactNode;
className?: string;
emphasis?: "low" | "high";
linkTo?: string;
};
export function ArticleAuthors({
children,
className,
emphasis = "high",
linkTo = "#",
}: AuthorsProps) {
const authors = React.Children.map(children, (author, i) => {
return (
<RouterLink to={linkTo}>
<Typography
fontWeightVariant={emphasis === "high" ? "medium" : "normal"}
className={classNames(
"hover:text-blue-600",
{
"text-xs leading-5 text-gray-500": emphasis === "low",
"text-lg leading-6 text-gray-900": emphasis === "high",
},
{
"mr-1": i != React.Children.count(children) - 1,
},
className
)}
>
{author}
{i != React.Children.count(children) - 1 ? "," : null}
</Typography>
</RouterLink>
);
});
return (
<div className="flex flex-row items-center">
<SVGUser className="w-6 fill-gray-500 stroke-gray-500"></SVGUser>
<div className="ml-2 flex flex-row">{authors}</div>
</div>
);
}
ArticleAuthors.displayName = "ArticleAuthors";

View File

@ -0,0 +1,31 @@
import React from "react";
import Breadcrumbs from "components/breadcrumbs";
import Logo from "components/Logo";
import classNames from "classnames";
type ArticleBreadcumbsProps = {
emphasis?: "high" | "low";
children?: string[];
};
export function ArticleBreadcumbs({
children,
emphasis = "high", //Emphasis high uses when we display article page
}: ArticleBreadcumbsProps) {
return (
<Breadcrumbs
divider="slash"
className={classNames(
"text-xs leading-4 text-gray-700 flex flex-row items-center",
{
"last:text-gray-900": emphasis === "high",
}
)}
>
{emphasis === "high" ? <Logo className="w-4" fillColors="gray" /> : null}
{children}
</Breadcrumbs>
);
}
ArticleBreadcumbs.displayName = "ArticleBreadcumbs";

View File

@ -0,0 +1,38 @@
import React from "react";
import Typography from "components/typography/Typography";
import { Transition } from "@headlessui/react";
type ArticleDescriptionProps = {
children?: React.ReactNode;
emphasis?: "low" | "high";
isShowing?: boolean;
};
export function ArticleDescription({
children,
emphasis = "high",
isShowing = false,
}: ArticleDescriptionProps) {
return emphasis === "low" ? (
<div className="overflow-hidden">
<Transition
appear
show={isShowing}
enter="ease-in-out duration-200"
enterFrom="-translate-y-full"
enterTo="translate-y-0"
leave="ease-in-out duration-200"
leaveFrom="translate-y-0"
leaveTo="-translate-y-full"
>
<Typography className="text-base text-gray-900">{children}</Typography>
</Transition>
</div>
) : (
<div>
<Typography className="text-base text-gray-900">{children}</Typography>
</div>
);
}
ArticleDescription.displayName = "ArticleDescription";

View File

@ -0,0 +1,87 @@
import React from "react";
import { Button } from "components/Button/Button";
import Typography from "components/typography/Typography";
import {
SVGArrowDown,
SVGArrowUp,
SVGCite,
SVGFiletext,
SVGDownload,
SVGShare,
SVGFolder,
} from "components/icons";
import classNames from "classnames";
const interactionButtonsStore = [
{
icon: <SVGFiletext />,
title: "Read file",
buttonEmphasis: "high",
iconClassName: "h-6 fill-white stroke-white",
},
{
icon: <SVGDownload />,
title: "Download",
buttonEmphasis: "low",
iconClassName: "w-6 fill-gray-900 stroke-gray-900",
},
{
icon: <SVGCite />,
title: "Cite",
buttonEmphasis: "low",
iconClassName: "w-6 fill-gray-900 stroke-gray-900",
},
{
icon: <SVGShare />,
title: "Share",
buttonEmphasis: "low",
iconClassName: "w-6 fill-gray-900 stroke-gray-900",
},
];
type ArticleButtonProps = {
children?: React.ReactNode;
className?: string;
emphasis?: "high" | "low";
} & Omit<React.ComponentPropsWithoutRef<"button">, "">;
export function ArticleInteractionButtons({
children,
className,
emphasis, //to change displaying of component
...props
}: ArticleButtonProps) {
const abstractButton = (
<Button emphasis="medium" className="text-sm leading-4 items-center px-3">
<Typography fontWeightVariant="bold" className="pr-2">
Abstract
</Typography>
<Button.Icon>
<SVGArrowDown className="w-4 fill-blue-700 stroke-blue-700" />
</Button.Icon>
</Button>
);
const fileInteractionButtons = interactionButtonsStore.map((button) => {
return (
<Button
emphasis={button.buttonEmphasis === "high" ? "high" : "low"}
className="h-max px-2"
>
<Button.Icon>
{React.cloneElement(button.icon, { className: button.iconClassName })}
</Button.Icon>
{emphasis === "high" ? <Typography>{button.title}</Typography> : null}
</Button>
);
});
return (
<div className="flex flex-row">
{emphasis === "low" && !children ? abstractButton : null}
{children ? children : fileInteractionButtons}
</div>
);
}
ArticleInteractionButtons.displayName = "ArticleInteractionButtons";

View File

@ -0,0 +1,55 @@
import React from "react";
import Typography from "components/typography/Typography";
import { SVGKey } from "components/icons";
import { RouterLink } from "components/typography/RouterLink";
import classNames from "classnames";
type KeywordsProps = {
children?: React.ReactNode;
className?: string;
emphasis?: "low" | "high";
linkTo?: string;
};
export function ArticleKeywords({
children,
className,
emphasis = "high",
linkTo = "#",
}: KeywordsProps) {
const keywords = React.Children.map(children, (keyword, i) => {
return (
<RouterLink to={linkTo}>
<div
className={classNames(
"mr-1",
"hover:text-blue-600",
{
"text-xs text-gray-500 leading-5": emphasis === "low",
"text-base text-gray-900 px-2 border rounded hover:border-blue-600 border-gray-900":
emphasis === "high",
},
className
)}
>
<Typography>
{keyword}
{i != React.Children.count(children) - 1 && emphasis === "low"
? ","
: null}
</Typography>
</div>
</RouterLink>
);
});
return (
<div className="flex flex-row items-center">
{emphasis === "low" ? (
<SVGKey className="w-6 fill-gray-500 stroke-gray-500" />
) : null}
<div className="flex flex-row ml-2">{keywords}</div>
</div>
);
}
ArticleKeywords.displayName = "ArticleKeywords";

View File

@ -0,0 +1,39 @@
import React, { useState } from "react";
import { Button } from "components/Button/Button";
import {
SVGFavoriteFilled,
SVGFavoriteOutlined,
SVGFolder,
} from "components/icons";
const subscriptionStyles = "fill-gray-500 stroke-gray-500 w-6";
type ArticleSubscriptionsButtonsProps = {
className?: string;
favorite?: boolean;
//Todo create tracking subscriptions and onClick props
} & Omit<React.ComponentPropsWithoutRef<"button">, "">;
export function ArticleSubscriptionsButtons({
className,
favorite = false,
}: ArticleSubscriptionsButtonsProps) {
return (
<div className="flex flex-row">
<Button emphasis="low">
<Button.Icon>
<SVGFolder className={subscriptionStyles} />
</Button.Icon>
</Button>
<Button emphasis="low" onClick={() => {}}>
<Button.Icon>
{!favorite ? (
<SVGFavoriteOutlined className={subscriptionStyles} />
) : (
<SVGFavoriteFilled className="fill-blue-600 stroke-blue-600 w-6" />
)}
</Button.Icon>
</Button>
</div>
);
}

View File

@ -0,0 +1,24 @@
import React from "react";
import Typography from "components/typography/Typography";
import { RouterLink } from "components/typography/RouterLink";
type ArticleTitleProps = {
className?: string;
children?: string;
linkTo?: string;
};
export function ArticleTitle({
className,
children,
linkTo = "#",
}: ArticleTitleProps) {
return (
<RouterLink to={linkTo}>
<Typography fontWeightVariant="semibold" className={className}>
{children}
</Typography>
</RouterLink>
);
}
ArticleTitle.displayName = "ArticleTitle";

View File

@ -0,0 +1,45 @@
import React from "react";
import { Article } from "./Article";
export function ArticleSearch() {
return (
<Article>
<div className="flex flex-row justify-between">
<Article.Breadcumbs emphasis="high">
{["Yoda", "Lallalla", "Maxim"]}
</Article.Breadcumbs>
<Article.SubscriptionsButtons />
</div>
<div className="flex flex-row">
<Article.Title className="text-3xl">Yeanda lacreav</Article.Title>
</div>
<Article.Authors emphasis="low">
{["Reavap", "aldjfoa", "dkfjaoif"]}
</Article.Authors>
<Article.Keywords emphasis="low">
{["porn", "development", "frontend"]}
</Article.Keywords>
<Article.InteractionButtons emphasis="low">
low
</Article.InteractionButtons>
<Article.Description>
{" "}
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere quidem
provident temporibus! Fuga dolores placeat at voluptatem quia, vero
molestiae animi et itaque a, officia ullam expedita temporibus cum
deserunt.Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere
quidem provident temporibus! Fuga dolores placeat at voluptatem quia,
vero molestiae animi et itaque a, officia ullam expedita temporibus cum
deserunt.Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere
quidem provident temporibus! Fuga dolores placeat at voluptatem quia,
vero molestiae animi et itaque a, officia ullam expedita temporibus cum
deserunt.Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere
quidem provident temporibus! Fuga dolores placeat at voluptatem quia,
vero molestiae animi et itaque a, officia ullam expedita temporibus cum
deserunt.
</Article.Description>
</Article>
);
}

View File

@ -12,7 +12,9 @@ function Helper() {
let obj = {};
obj[key] = this.withOpacityValue(`--color-${key}-text-base`);
obj[`${key}-muted`] = this.withOpacityValue(`--color-${key}-text-muted`);
obj[`${key}-inverted`] = this.withOpacityValue(`--color-${key}-text-inverted`);
obj[`${key}-inverted`] = this.withOpacityValue(
`--color-${key}-text-inverted`
);
return obj;
};
@ -22,7 +24,9 @@ function Helper() {
obj[key] = this.withOpacityValue(`--color-${key}`);
obj[`${key}-disabled`] = this.withOpacityValue(`--color-${key}-disabled`);
obj[`${key}-hover`] = this.withOpacityValue(`--color-${key}-hover`);
obj[`${key}-disabled-hover`] = this.withOpacityValue(`--color-${key}-disabled-hover`);
obj[`${key}-disabled-hover`] = this.withOpacityValue(
`--color-${key}-disabled-hover`
);
return obj;
};
@ -44,7 +48,7 @@ function Helper() {
this.luminanced = function (key, additionalStops = []) {
let obj = {};
obj['50'] = this.withOpacityValue(`--color-${key}-50`);
obj["50"] = this.withOpacityValue(`--color-${key}-50`);
for (let index = 0; index < additionalStops.length; index++) {
const element = additionalStops[index];
obj[element] = this.withOpacityValue(`--color-${key}-${element}`);
@ -62,64 +66,65 @@ const ColorHelper = new Helper();
* @type { import('@types/tailwindcss/tailwind-config').TailwindConfig }
*/
module.exports = {
content: ['./src/**/*.{jsx,tsx}'],
content: ["./src/**/*.{jsx,tsx}"],
plugins: [
function ({ addComponents }) {
addComponents({
'.container': {
maxWidth: '840px',
paddingLeft: '0.5rem',
paddingRight: '0.5rem',
'@screen sm': {
maxWidth: 'calc(100% - 30px)',
".container": {
maxWidth: "840px",
paddingLeft: "0.5rem",
paddingRight: "0.5rem",
"@screen sm": {
maxWidth: "calc(100% - 30px)",
},
'@screen md': {
maxWidth: 'calc(100% - 30px)',
"@screen md": {
maxWidth: "calc(100% - 30px)",
},
'@screen lg': {
maxWidth: '840px',
"@screen lg": {
maxWidth: "840px",
},
'@screen xl': {
maxWidth: '840px',
"@screen xl": {
maxWidth: "840px",
},
'@screen 2xl': {
maxWidth: '840px',
"@screen 2xl": {
maxWidth: "840px",
},
},
});
},
require("@tailwindcss/line-clamp"),
],
theme: {
extend: {
screens: {
tall: { raw: '(min-height: 1200px) and (orientation: portrait)' },
skewed: { raw: '(max-height: 600px)' },
"1.5xl": '1300px',
tall: { raw: "(min-height: 1200px) and (orientation: portrait)" },
skewed: { raw: "(max-height: 600px)" },
"1.5xl": "1300px",
},
height: {
'half-screen': '50vh',
"half-screen": "50vh",
},
minHeight: {
'half-screen': '50vh',
"half-screen": "50vh",
},
colors: {
aside: 'var(--color-aside)',
main: 'var(--color-body)',
header: '#191D2B',
transparent: 'transparent',
current: 'currentColor',
white: '#ffffff',
black: '#000000',
serv: ColorHelper.luminanced('serv'),
blue: ColorHelper.luminanced('blue'),
gray: ColorHelper.luminanced('gray', [75]),
aside: "var(--color-aside)",
main: "var(--color-body)",
header: "#191D2B",
transparent: "transparent",
current: "currentColor",
white: "#ffffff",
black: "#000000",
serv: ColorHelper.luminanced("serv"),
blue: ColorHelper.luminanced("blue"),
gray: ColorHelper.luminanced("gray", [75]),
},
gridTemplateColumns: {
'layout': 'min-content 7fr',
layout: "min-content 7fr",
},
gridTemplateRows: {
'page': '3.5rem calc(100vh - 3.5rem)'
}
page: "3.5rem calc(100vh - 3.5rem)",
},
},
},
};