diff --git a/package.json b/package.json
index 3ba8665..0273842 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/components/Article/Article.tsx b/src/components/Article/Article.tsx
new file mode 100644
index 0000000..9e10af2
--- /dev/null
+++ b/src/components/Article/Article.tsx
@@ -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
{children}
;
+}
+
+Article.Title = ArticleTitle;
+Article.Breadcumbs = ArticleBreadcumbs;
+Article.Authors = ArticleAuthors;
+Article.Keywords = ArticleKeywords;
+Article.InteractionButtons = ArticleInteractionButtons;
+Article.Description = ArticleDescription;
+Article.SubscriptionsButtons = ArticleSubscriptionsButtons;
diff --git a/src/components/Article/ArticleParts/ArticleAuthors.tsx b/src/components/Article/ArticleParts/ArticleAuthors.tsx
new file mode 100644
index 0000000..5e2e16d
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleAuthors.tsx
@@ -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 (
+
+
+ {author}
+ {i != React.Children.count(children) - 1 ? "," : null}
+
+
+ );
+ });
+
+ return (
+
+ );
+}
+
+ArticleAuthors.displayName = "ArticleAuthors";
diff --git a/src/components/Article/ArticleParts/ArticleBreadcumbs.tsx b/src/components/Article/ArticleParts/ArticleBreadcumbs.tsx
new file mode 100644
index 0000000..e52881e
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleBreadcumbs.tsx
@@ -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 (
+
+ {emphasis === "high" ? : null}
+ {children}
+
+ );
+}
+
+ArticleBreadcumbs.displayName = "ArticleBreadcumbs";
diff --git a/src/components/Article/ArticleParts/ArticleDescription.tsx b/src/components/Article/ArticleParts/ArticleDescription.tsx
new file mode 100644
index 0000000..119241d
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleDescription.tsx
@@ -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" ? (
+
+
+ {children}
+
+
+ ) : (
+
+ {children}
+
+ );
+}
+
+ArticleDescription.displayName = "ArticleDescription";
diff --git a/src/components/Article/ArticleParts/ArticleInteractionButtons.tsx b/src/components/Article/ArticleParts/ArticleInteractionButtons.tsx
new file mode 100644
index 0000000..ef69869
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleInteractionButtons.tsx
@@ -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: ,
+ title: "Read file",
+ buttonEmphasis: "high",
+ iconClassName: "h-6 fill-white stroke-white",
+ },
+ {
+ icon: ,
+ title: "Download",
+ buttonEmphasis: "low",
+ iconClassName: "w-6 fill-gray-900 stroke-gray-900",
+ },
+ {
+ icon: ,
+ title: "Cite",
+ buttonEmphasis: "low",
+ iconClassName: "w-6 fill-gray-900 stroke-gray-900",
+ },
+ {
+ icon: ,
+ title: "Share",
+ buttonEmphasis: "low",
+ iconClassName: "w-6 fill-gray-900 stroke-gray-900",
+ },
+];
+
+type ArticleButtonProps = {
+ children?: React.ReactNode;
+ className?: string;
+ emphasis?: "high" | "low";
+} & Omit, "">;
+
+export function ArticleInteractionButtons({
+ children,
+ className,
+ emphasis, //to change displaying of component
+ ...props
+}: ArticleButtonProps) {
+ const abstractButton = (
+
+ );
+
+ const fileInteractionButtons = interactionButtonsStore.map((button) => {
+ return (
+
+ );
+ });
+
+ return (
+
+ {emphasis === "low" && !children ? abstractButton : null}
+ {children ? children : fileInteractionButtons}
+
+ );
+}
+
+ArticleInteractionButtons.displayName = "ArticleInteractionButtons";
diff --git a/src/components/Article/ArticleParts/ArticleKeywords.tsx b/src/components/Article/ArticleParts/ArticleKeywords.tsx
new file mode 100644
index 0000000..01b5546
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleKeywords.tsx
@@ -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 (
+
+
+
+ {keyword}
+ {i != React.Children.count(children) - 1 && emphasis === "low"
+ ? ","
+ : null}
+
+
+
+ );
+ });
+ return (
+
+ {emphasis === "low" ? (
+
+ ) : null}
+
{keywords}
+
+ );
+}
+
+ArticleKeywords.displayName = "ArticleKeywords";
diff --git a/src/components/Article/ArticleParts/ArticleSubscriptionsButton.tsx b/src/components/Article/ArticleParts/ArticleSubscriptionsButton.tsx
new file mode 100644
index 0000000..ad6dd09
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleSubscriptionsButton.tsx
@@ -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, "">;
+
+export function ArticleSubscriptionsButtons({
+ className,
+ favorite = false,
+}: ArticleSubscriptionsButtonsProps) {
+ return (
+
+
+
+
+ );
+}
diff --git a/src/components/Article/ArticleParts/ArticleTitle.tsx b/src/components/Article/ArticleParts/ArticleTitle.tsx
new file mode 100644
index 0000000..7a5ae89
--- /dev/null
+++ b/src/components/Article/ArticleParts/ArticleTitle.tsx
@@ -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 (
+
+
+ {children}
+
+
+ );
+}
+
+ArticleTitle.displayName = "ArticleTitle";
diff --git a/src/components/Article/ArticleSearch.tsx b/src/components/Article/ArticleSearch.tsx
new file mode 100644
index 0000000..8b0e397
--- /dev/null
+++ b/src/components/Article/ArticleSearch.tsx
@@ -0,0 +1,45 @@
+import React from "react";
+import { Article } from "./Article";
+
+export function ArticleSearch() {
+ return (
+
+
+
+ {["Yoda", "Lallalla", "Maxim"]}
+
+
+
+
+
+
+ {["Reavap", "aldjfoa", "dkfjaoif"]}
+
+
+ {["porn", "development", "frontend"]}
+
+
+
+ low
+
+
+ {" "}
+ 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.
+
+
+ );
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index f8b96c6..8f4d294 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -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)",
+ },
},
},
};