├── .commitlintrc.json ├── .dockerignore ├── .eslintrc.cjs ├── .gitattributes ├── .github └── workflows │ └── publish.yml ├── .gitignore ├── .husky ├── _ │ ├── husky.sh │ ├── pre-commit │ └── pre-push ├── pre-commit └── pre-push ├── .prettierignore ├── .prettierrc ├── .storybook ├── main.ts └── preview.tsx ├── .stylelintrc.json ├── .vscode └── settings.json ├── .yarn └── releases │ └── yarn-1.22.21.cjs ├── .yarnrc ├── Dockerfile ├── README.md ├── app-server └── server.mjs ├── astro-i18next.config.mjs ├── astro.config.mjs ├── commitlint.config.js ├── deployment ├── development │ └── deploy.yml └── production │ └── deploy.yml ├── docs ├── PubSub.md ├── fetch-wrapper.md ├── i18next-integration.md ├── images │ ├── articles.png │ ├── error404.png │ ├── error500.png │ ├── pipeline.png │ └── site.png ├── integratrations.md ├── style-library.md ├── svg-icons-integration.md └── test.md ├── env.example ├── ls ├── package.json ├── public ├── favicon.svg ├── fonts │ ├── Lato-Bold.woff2 │ ├── Lato-Light.woff2 │ ├── Lato-Regular.woff2 │ ├── Montserrat-Light.woff2 │ ├── Poppins-Bold.ttf │ ├── Poppins-BoldItalic.ttf │ ├── Poppins-Italic.ttf │ ├── Poppins-Light.ttf │ ├── Poppins-LightItalic.ttf │ ├── Poppins-Medium.ttf │ ├── Poppins-MediumItalic.ttf │ ├── Poppins-Regular.ttf │ ├── Poppins-SemiBold.ttf │ ├── Poppins-SemiBoldItalic.ttf │ ├── Roboto-Bold.woff2 │ └── Roboto-Regular.ttf ├── images │ └── flags │ │ ├── ar.svg │ │ ├── bo.svg │ │ ├── cl.svg │ │ └── pe.svg └── locales │ ├── en │ └── translation.json │ └── es │ └── translation.json ├── scripts └── tokenizer.mjs ├── src ├── PubSub │ ├── Base.ts │ ├── Broker.ts │ ├── Publisher.ts │ ├── SimpleBroker.ts │ ├── SimplePublisher.ts │ ├── SimpleSubscriber.ts │ ├── Subscriber.ts │ ├── messages │ │ └── messages-model.ts │ └── types │ │ └── types.ts ├── Shadows │ ├── Shadows.scss │ └── ShadowsDemo.tsx ├── assets │ └── icons │ │ ├── Close-URL.svg │ │ ├── Info-Tooltip.svg │ │ ├── article.svg │ │ ├── articles.svg │ │ ├── burger-menu.svg │ │ ├── button-burguer.svg │ │ ├── button-burguer1.svg │ │ ├── caret_down.svg │ │ ├── check.svg │ │ ├── circle-quarters.svg │ │ ├── close.svg │ │ ├── close_circle.svg │ │ ├── close_simple.svg │ │ ├── downloads.svg │ │ ├── error.svg │ │ ├── eye.svg │ │ ├── facebook.svg │ │ ├── facebook1.svg │ │ ├── facelocation.svg │ │ ├── fi-rr-copy.svg │ │ ├── fi-sr-globe.svg │ │ ├── fi-sr-phone-call.svg │ │ ├── globe.svg │ │ ├── google.svg │ │ ├── home.svg │ │ ├── icon-upload-default.svg │ │ ├── icon-upload-primary.svg │ │ ├── info.svg │ │ ├── left-arrow.svg │ │ ├── location.svg │ │ ├── logo.svg │ │ ├── magnifyingglass.svg │ │ ├── media.svg │ │ ├── pdf.svg │ │ ├── reference.svg │ │ ├── reference1.svg │ │ ├── right-arrow.svg │ │ ├── search.svg │ │ ├── share.svg │ │ ├── start.svg │ │ ├── telegram.svg │ │ ├── vector.svg │ │ ├── volume.svg │ │ ├── volumes.svg │ │ └── whatsapp.svg ├── astro-env.d.ts ├── components │ └── tokens │ │ ├── ColorPreview.stories.tsx │ │ ├── ColorPreview.test.tsx │ │ └── ColorPreview.tsx ├── config │ └── seo-config.mock.js ├── env.d.ts ├── fetch │ ├── fetch.ts │ ├── types │ │ └── headers.ts │ └── utils.ts ├── globals │ ├── _breakpoints.scss │ ├── _fonts.scss │ ├── _mixins.scss │ ├── _sizes.scss │ ├── _typography.scss │ ├── _variables.scss │ ├── globals.scss │ ├── main.scss │ ├── styles │ │ ├── padding.scss │ │ └── tokens.scss │ ├── theme │ │ └── index.ts │ ├── tokens.scss │ └── tokens │ │ └── colors.ts ├── layouts │ ├── Layout.astro │ └── gridly │ │ ├── breakpoints-grid.scss │ │ └── gridzone.scss ├── library │ └── component │ │ ├── atoms │ │ ├── pills │ │ │ ├── pills.module.scss │ │ │ ├── pills.stories.tsx │ │ │ ├── pills.test.tsx │ │ │ ├── pills.tsx │ │ │ └── types │ │ │ │ └── IProps.tsx │ │ ├── text-content │ │ │ ├── TextContent.module.scss │ │ │ ├── TextContent.stories.tsx │ │ │ ├── TextContent.test.tsx │ │ │ ├── TextContent.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ └── text-title │ │ │ ├── TextTitle.module.scss │ │ │ ├── TextTitle.stories.tsx │ │ │ ├── TextTitle.test.tsx │ │ │ ├── TextTitle.tsx │ │ │ └── types │ │ │ └── IProps.ts │ │ └── molecules │ │ ├── icon-text-stat │ │ ├── icon-text-stat.module.scss │ │ ├── icon-text-stat.stories.tsx │ │ ├── icon-text-stat.test.tsx │ │ ├── icon-text-stat.tsx │ │ └── types │ │ │ ├── IProps.ts │ │ │ └── iconMap.ts │ │ ├── phone-dropdown │ │ ├── PhoneDropdown.module.scss │ │ ├── PhoneDropdown.stories.tsx │ │ ├── PhoneDropdown.test.tsx │ │ ├── PhoneDropdown.tsx │ │ └── types │ │ │ └── IProps.ts │ │ ├── text-arrangement │ │ ├── TextArrangement.module.scss │ │ ├── TextArrangement.stories.tsx │ │ ├── TextArrangement.test.tsx │ │ ├── TextArrangement.tsx │ │ └── types │ │ │ └── IProps.ts │ │ └── user-text-card │ │ ├── types │ │ └── IProps.ts │ │ ├── user-text-card.module.scss │ │ ├── user-text-card.stories.tsx │ │ ├── user-text-card.test.tsx │ │ └── user-text-card.tsx ├── middleware │ ├── auth.ts │ ├── errors.ts │ ├── index.ts │ ├── loadEmotionCache.ts │ └── loadEnvs.ts ├── pages │ ├── articles │ │ ├── [id].astro │ │ └── index.astro │ ├── en │ │ ├── errors │ │ │ ├── 400.astro │ │ │ └── 500.astro │ │ └── index.astro │ ├── errors │ │ ├── 400.astro │ │ └── 500.astro │ ├── experiment │ │ └── index.astro │ ├── index.astro │ ├── login │ │ └── index.astro │ ├── register │ │ └── index.astro │ ├── volumenes │ │ ├── index.astro │ │ └── utils │ │ │ └── fetchData.ts │ └── volumes │ │ └── index.astro ├── services │ ├── http-client │ │ ├── cache │ │ │ ├── cache-factory.ts │ │ │ ├── cache-manager.ts │ │ │ └── strategies │ │ │ │ ├── base-cache-actions.ts │ │ │ │ ├── memory-cache.ts │ │ │ │ └── redis-cache.ts │ │ ├── network │ │ │ └── fetch-wrapper.ts │ │ └── types │ │ │ ├── cache-types.ts │ │ │ └── index.ts │ └── utils │ │ ├── environments.ts │ │ └── request-utils.ts ├── setupTests.ts ├── stories │ ├── GridSystem.stories.tsx │ └── GridTest.stories.tsx ├── style-library │ ├── core │ │ ├── ThemeProvider.tsx │ │ └── ThemeSwitcher.tsx │ ├── createEmotionCache.ts │ ├── providers │ │ ├── ThemeProvider.tsx │ │ └── useThemeProvider.ts │ ├── stories │ │ ├── Alert.stories.tsx │ │ ├── Avatar.stories.tsx │ │ ├── Button.stories.tsx │ │ └── Typography.stories.tsx │ └── themes │ │ ├── dark.ts │ │ ├── default.ts │ │ └── tokens │ │ ├── tokens.json │ │ └── tokens.ts ├── styles │ ├── grid.scss │ └── tokens │ │ └── border-radius.scss ├── test │ └── simple.test.ts ├── types │ ├── config.ts │ └── locals.d.ts └── ui │ ├── components │ ├── atoms │ │ ├── Author-Label │ │ │ ├── AuthorLabel.module.scss │ │ │ ├── AuthorLabel.stories.tsx │ │ │ ├── AuthorLabel.test.jsx │ │ │ ├── AuthorLabel.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── CountryList │ │ │ ├── CountryList.module.scss │ │ │ ├── CountryList.stories.tsx │ │ │ ├── CountryList.test.tsx │ │ │ ├── CountryList.tsx │ │ │ └── __snapshots__ │ │ │ │ └── CountryList.test.tsx.snap │ │ ├── Default-Input │ │ │ ├── DefaultInput.scss │ │ │ ├── DefaultInput.stories.tsx │ │ │ ├── DefaultInput.test.tsx │ │ │ ├── DefaultInput.tsx │ │ │ └── types │ │ │ │ └── DefaultInputProps.ts │ │ ├── Ghost-Button │ │ │ ├── ghost-button.stories.tsx │ │ │ ├── ghost-button.test.tsx │ │ │ ├── ghost-button.tsx │ │ │ ├── styles.module.scss │ │ │ └── types │ │ │ │ └── types.ts │ │ ├── HeadingTitle │ │ │ ├── HeadingTitle.module.scss │ │ │ ├── HeadingTitle.stories.tsx │ │ │ ├── HeadingTitle.test.tsx │ │ │ ├── HeadingTitle.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── IconButtons │ │ │ ├── IconButtons.module.scss │ │ │ ├── IconButtons.stories.tsx │ │ │ ├── IconButtons.test.tsx │ │ │ ├── IconButtons.tsx │ │ │ └── types │ │ │ │ └── Iprops.ts │ │ ├── Tags │ │ │ ├── Tags.module.scss │ │ │ ├── Tags.stories.tsx │ │ │ ├── Tags.test.tsx │ │ │ ├── Tags.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── TextCardList │ │ │ ├── TextCardList.module.scss │ │ │ ├── TextCardList.stories.tsx │ │ │ ├── TextCardList.test.tsx │ │ │ ├── TextCardList.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── Toggle │ │ │ ├── toggle.module.scss │ │ │ ├── toggle.stories.tsx │ │ │ ├── toggle.test.tsx │ │ │ ├── toggle.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── article-description │ │ │ ├── ArticleDescription.module.scss │ │ │ ├── ArticleDescription.stories.tsx │ │ │ ├── ArticleDescription.test.tsx │ │ │ ├── ArticleDescription.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── article-title │ │ │ ├── ArticleTitle.module.scss │ │ │ ├── ArticleTitle.scss │ │ │ ├── ArticleTitle.stories.tsx │ │ │ ├── ArticleTitle.test.tsx │ │ │ ├── ArticleTitle.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── badges │ │ │ ├── Icon.tsx │ │ │ ├── badge.scss │ │ │ ├── badge.stories.tsx │ │ │ ├── badge.test.jsx │ │ │ ├── badge.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── burger-button │ │ │ ├── BurgerButton.module.scss │ │ │ ├── BurgerButton.stories.tsx │ │ │ ├── BurgerButton.test.jsx │ │ │ ├── BurgerButton.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── button-burger │ │ │ ├── ButtonBurger.module.scss │ │ │ ├── ButtonBurger.stories.tsx │ │ │ ├── ButtonBurger.test.tsx │ │ │ ├── ButtonBurger.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── button-label │ │ │ ├── Button.test.jsx │ │ │ ├── ButtonLabel.module.scss │ │ │ ├── ButtonLabel.stories.tsx │ │ │ ├── ButtonLabel.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── button-number │ │ │ ├── ButtonNumber.module.scss │ │ │ ├── ButtonNumber.stories.tsx │ │ │ ├── ButtonNumber.test.jsx │ │ │ ├── ButtonNumber.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── button-with-variants │ │ │ ├── ButtonWithVariants.module.scss │ │ │ ├── ButtonWithVariants.stories.tsx │ │ │ ├── ButtonWithVariants.test.jsx │ │ │ ├── ButtonWithVariants.tsx │ │ │ └── types │ │ │ │ └── IProps.tsx │ │ ├── button-year │ │ │ ├── ButtonYear.module.scss │ │ │ ├── ButtonYear.stories.tsx │ │ │ ├── ButtonYear.test.tsx │ │ │ ├── ButtonYear.tsx │ │ │ └── types │ │ │ │ └── IProps.tsx │ │ ├── button │ │ │ ├── Button.scss │ │ │ └── styles.scss │ │ ├── check │ │ │ ├── Icon.tsx │ │ │ ├── check.scss │ │ │ ├── check.stories.tsx │ │ │ ├── check.test.jsx │ │ │ ├── check.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── close-download-button │ │ │ ├── CloseDownloadButton.module.scss │ │ │ ├── CloseDownloadButton.stories.tsx │ │ │ ├── CloseDownloadButton.test.tsx │ │ │ ├── CloseDownloadButton.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── divider-variables │ │ │ ├── DividerVariables.stories.tsx │ │ │ ├── DividerVariables.test.jsx │ │ │ ├── DividerVariables.tsx │ │ │ └── styles.scss │ │ ├── divider │ │ │ ├── Divider.module.scss │ │ │ ├── Divider.scss │ │ │ ├── Divider.stories.tsx │ │ │ ├── Divider.test.jsx │ │ │ ├── Divider.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── error-message │ │ │ ├── ErrorMessage.module.scss │ │ │ ├── ErrorMessage.stories.tsx │ │ │ ├── ErrorMessage.test.jsx │ │ │ ├── ErrorMessage.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── gradient-colors │ │ │ ├── GradientColors.module.scss │ │ │ ├── GradientColors.stories.tsx │ │ │ ├── GradientColors.test.tsx │ │ │ └── GradientColors.tsx │ │ ├── hero-banner │ │ │ ├── HeroBanner.module.scss │ │ │ ├── HeroBanner.stories.tsx │ │ │ ├── HeroBanner.test.tsx │ │ │ ├── HeroBanner.tsx │ │ │ ├── __mock__ │ │ │ │ └── imgs │ │ │ │ │ ├── Rectangle10.png │ │ │ │ │ ├── Rectangle11.png │ │ │ │ │ ├── Rectangle12.png │ │ │ │ │ ├── Rectangle17.png │ │ │ │ │ └── Rectangle6.png │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── icon-button │ │ │ ├── IconButton.scss │ │ │ ├── IconButton.stories.tsx │ │ │ ├── IconButton.test.tsx │ │ │ ├── IconButton.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── icon-svgr │ │ │ └── SvgIcons.stories.tsx │ │ ├── icon-upload │ │ │ ├── IconUpload.module.scss │ │ │ ├── IconUpload.stories.tsx │ │ │ ├── IconUpload.test.tsx │ │ │ ├── IconUpload.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── input-country │ │ │ ├── InputCountry.module.scss │ │ │ ├── InputCountry.stories.tsx │ │ │ ├── InputCountry.test.tsx │ │ │ ├── InputCountry.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── InputCountry.test.tsx.snap │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── input-text │ │ │ ├── InputText.module.scss │ │ │ ├── InputText.stories.tsx │ │ │ ├── InputText.test.tsx │ │ │ ├── InputText.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-articles │ │ │ ├── LabelArticles.module.scss │ │ │ ├── LabelArticles.scss │ │ │ ├── LabelArticles.stories.tsx │ │ │ ├── LabelArticles.test.jsx │ │ │ ├── LabelArticles.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-date │ │ │ ├── LabelDate.module.scss │ │ │ ├── LabelDate.scss │ │ │ ├── LabelDate.stories.tsx │ │ │ ├── LabelDate.test.jsx │ │ │ ├── LabelDate.tsx │ │ │ ├── types │ │ │ │ └── IProps.ts │ │ │ └── utils │ │ │ │ └── dateFormatter.ts │ │ ├── label-featured-articles │ │ │ ├── LabelFeaturedArticles.module.scss │ │ │ ├── LabelFeaturedArticles.scss │ │ │ ├── LabelFeaturedArticles.stories.tsx │ │ │ ├── LabelFeaturedArticles.test.tsx │ │ │ ├── LabelFeaturedArticles.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-recent-articles │ │ │ ├── LabelRecentsArticles.module.scss │ │ │ ├── LabelRecentsArticles.stories.tsx │ │ │ ├── LabelRecentsArticles.test.tsx │ │ │ ├── LabelRecentsArticles.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-ref │ │ │ ├── LabelRef.module.scss │ │ │ ├── LabelRef.stories.tsx │ │ │ ├── LabelRef.test.tsx │ │ │ ├── LabelRef.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-references │ │ │ ├── LabelReferences.module.scss │ │ │ ├── LabelReferences.stories.tsx │ │ │ ├── LabelReferences.test.tsx │ │ │ ├── LabelReferences.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-resources-page │ │ │ ├── LabelResourcesPage.stories.tsx │ │ │ ├── LabelResourcesPage.test.jsx │ │ │ ├── LabelResourcesPage.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-share │ │ │ ├── Share.module.scss │ │ │ ├── Share.stories.tsx │ │ │ ├── Share.test.tsx │ │ │ ├── Share.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-variables │ │ │ ├── Variables.module.scss │ │ │ ├── Variables.stories.tsx │ │ │ ├── Variables.test.tsx │ │ │ ├── Variables.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-vol │ │ │ ├── LabelVol.module.scss │ │ │ ├── LabelVol.stories.tsx │ │ │ ├── LabelVol.test.jsx │ │ │ ├── LabelVol.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── label-volumes │ │ │ ├── LabelVolumes.module.scss │ │ │ ├── LabelVolumes.stories.tsx │ │ │ ├── LabelVolumes.test.jsx │ │ │ ├── LabelVolumes.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── logo-footer │ │ │ ├── LogoFooter.module.scss │ │ │ ├── LogoFooter.stories.tsx │ │ │ ├── LogoFooter.test.tsx │ │ │ ├── LogoFooter.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── logo │ │ │ ├── logo.module.scss │ │ │ ├── logo.stories.tsx │ │ │ ├── logo.test.jsx │ │ │ ├── logo.tsx │ │ │ ├── style.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── main-input │ │ │ ├── MainInput.module.scss │ │ │ ├── MainInput.stories.tsx │ │ │ ├── MainInput.test.tsx │ │ │ ├── MainInput.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── multi-function-button │ │ │ ├── MultiFunctionButton.module.scss │ │ │ ├── MultiFunctionButton.stories.tsx │ │ │ ├── MultiFunctionButton.test.tsx │ │ │ ├── MultiFunctionButton.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── navbar │ │ │ ├── Navbar.stories.tsx │ │ │ ├── Navbar.test.tsx │ │ │ ├── Navbar.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── ol-bullet │ │ │ ├── OLBullet.module.scss │ │ │ ├── OLBullet.stories.tsx │ │ │ ├── OLBullet.test.tsx │ │ │ ├── OLBullet.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── ol-item │ │ │ ├── OLItem.module.scss │ │ │ ├── OLItem.stories.tsx │ │ │ ├── OLItem.test.tsx │ │ │ ├── OLItem.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── phone-input │ │ │ ├── phoneinput.module.scss │ │ │ ├── phoneinput.stories.tsx │ │ │ ├── phoneinput.test.tsx │ │ │ ├── phoneinput.tsx │ │ │ └── types │ │ │ │ ├── IProps.ts │ │ │ │ └── countryCodes.ts │ │ ├── points-divider │ │ │ ├── PointsDivider.module.scss │ │ │ ├── PointsDivider.scss │ │ │ ├── PointsDivider.stories.tsx │ │ │ ├── PointsDivider.test.jsx │ │ │ ├── PointsDivider.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── primary-buttons │ │ │ ├── PrimaryButtons.module.scss │ │ │ ├── PrimaryButtons.stories.tsx │ │ │ ├── PrimaryButtons.test.jsx │ │ │ ├── PrimaryButtons.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── publish-button │ │ │ ├── PublishButton.module.scss │ │ │ ├── PublishButton.stories.tsx │ │ │ ├── PublishButton.test.jsx │ │ │ ├── PublishButton.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── reference-information │ │ │ ├── Reference.module.scss │ │ │ ├── Reference.stories.tsx │ │ │ ├── Reference.test.jsx │ │ │ ├── Reference.tsx │ │ │ ├── _mocked │ │ │ │ └── references.json │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── shadow-card │ │ │ └── ShadowCard.stories.tsx │ │ ├── social-media-button │ │ │ ├── Button.module.scss │ │ │ ├── Button.stories.tsx │ │ │ ├── Button.test.jsx │ │ │ ├── Button.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── start-button │ │ │ ├── StartButton.scss │ │ │ ├── StartButton.stories.tsx │ │ │ ├── StartButton.test.jsx │ │ │ ├── StartButton.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── text-field │ │ │ ├── Icon.tsx │ │ │ ├── text-field.scss │ │ │ ├── text-field.stories.tsx │ │ │ ├── text-field.test.jsx │ │ │ ├── text-field.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── thumbnail │ │ │ ├── Thumbnail.module.scss │ │ │ ├── Thumbnail.scss │ │ │ ├── Thumbnail.stories.tsx │ │ │ ├── Thumbnail.test.jsx │ │ │ ├── Thumbnail.tsx │ │ │ ├── __mock__ │ │ │ │ └── imgs │ │ │ │ │ ├── Rectangle27.png │ │ │ │ │ ├── Rectangle28.png │ │ │ │ │ ├── Rectangle29.png │ │ │ │ │ ├── Rectangle30.png │ │ │ │ │ ├── Rectangle31.png │ │ │ │ │ └── Rectangle32.png │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── tokens │ │ │ └── BorderRadiusTokens.stories.tsx │ │ ├── typography-paragraph │ │ │ ├── TypographyParagraph.module.scss │ │ │ ├── TypographyParagraph.stories.tsx │ │ │ ├── TypographyParagraph.test.jsx │ │ │ ├── TypographyParagraph.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── url-input │ │ │ ├── URLinput.module.scss │ │ │ ├── URLinput.stories.tsx │ │ │ ├── URLinput.test.tsx │ │ │ ├── URLinput.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── variable-button │ │ │ ├── VariableButton.tsx │ │ │ ├── types │ │ │ │ └── IProps.ts │ │ │ ├── variableButton.module.scss │ │ │ ├── variableButton.stories.tsx │ │ │ └── variableButton.test.tsx │ │ └── year │ │ │ ├── Year.module.scss │ │ │ ├── Year.stories.tsx │ │ │ ├── Year.test.tsx │ │ │ ├── Year.tsx │ │ │ └── types │ │ │ └── IProps.tsx │ ├── molecules │ │ ├── InfoTooltip │ │ │ ├── InfoTooltip.module.scss │ │ │ ├── InfoTooltip.stories.tsx │ │ │ ├── InfoTooltip.test.tsx │ │ │ ├── InfoTooltip.tsx │ │ │ ├── TooltipIcon.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── LoginPage │ │ │ ├── LoginPage.scss │ │ │ ├── LoginPage.stories.tsx │ │ │ ├── LoginPage.test.tsx │ │ │ ├── LoginPage.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── article-publish │ │ │ ├── ArticlePublish.module.scss │ │ │ ├── ArticlePublish.stories.tsx │ │ │ ├── ArticlePublish.test.tsx │ │ │ ├── ArticlePublish.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── article │ │ │ ├── Article.stories.tsx │ │ │ ├── Article.test.jsx │ │ │ ├── Article.tsx │ │ │ └── styles.scss │ │ ├── banner-articles │ │ │ ├── BannerArticles.scss │ │ │ ├── BannerArticles.stories.tsx │ │ │ ├── BannerArticles.test.tsx │ │ │ ├── BannerArticles.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── banner-volumes │ │ │ ├── BannerVolumes.scss │ │ │ ├── BannerVolumes.stories.tsx │ │ │ ├── BannerVolumes.test.tsx │ │ │ ├── BannerVolumes.tsx │ │ │ ├── __mock__ │ │ │ │ └── datamock.json │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── buttons-pdf-share │ │ │ ├── ButtonsPdfShare.scss │ │ │ ├── ButtonsPdfShare.stories.tsx │ │ │ ├── ButtonsPdfShare.test.tsx │ │ │ ├── ButtonsPdfShare.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── experiment-pubsub │ │ │ ├── receive-component.tsx │ │ │ └── sender-component.tsx │ │ ├── featured-article │ │ │ ├── FeaturedArticle.scss │ │ │ ├── FeaturedArticle.stories.tsx │ │ │ ├── FeaturedArticle.test.tsx │ │ │ ├── FeaturedArticle.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── footer-variables │ │ │ ├── FooterVariables.stories.tsx │ │ │ ├── FooterVariables.test.jsx │ │ │ ├── FooterVariables.tsx │ │ │ └── styles.scss │ │ ├── header-banner │ │ │ ├── HeaderBanner.scss │ │ │ ├── HeaderBanner.stories.tsx │ │ │ ├── HeaderBanner.test.tsx │ │ │ ├── HeaderBanner.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── location-variable │ │ │ ├── Location.stories.tsx │ │ │ ├── Location.test.jsx │ │ │ ├── Location.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── login-register-buttons │ │ │ ├── LoginRegisterButton.module.scss │ │ │ ├── LoginRegisterButton.stories.tsx │ │ │ ├── LoginRegisterButton.test.tsx │ │ │ ├── LoginRegisterButtons.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── magnifying-glass │ │ │ ├── MagnifyingGlass.stories.tsx │ │ │ ├── MagnifyingGlass.test.tsx │ │ │ ├── MagnifyingGlass.tsx │ │ │ ├── style.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── network-login │ │ │ ├── network-login.scss │ │ │ ├── network-login.stories.tsx │ │ │ ├── network-login.test.tsx │ │ │ ├── network-login.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── option-menu │ │ │ ├── OptionMenu.stories.tsx │ │ │ ├── OptionMenu.test.tsx │ │ │ ├── OptionMenu.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── pdf-share-buttons │ │ │ ├── PdfShareButton.scss │ │ │ ├── PdfShareButton.stories.tsx │ │ │ ├── PdfShareButton.test.tsx │ │ │ ├── PdfShareButton.tsx │ │ │ └── types │ │ │ │ └── IProps.tsx │ │ ├── recent-articles-image │ │ │ ├── RecentArticlesImage.stories.tsx │ │ │ ├── RecentArticlesImage.test.jsx │ │ │ ├── RecentArticlesImage.tsx │ │ │ ├── styles.scss │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── references │ │ │ ├── References.scss │ │ │ ├── References.stories.tsx │ │ │ ├── References.test.tsx │ │ │ ├── References.tsx │ │ │ └── types │ │ │ │ └── IProps.tsx │ │ ├── side-panel │ │ │ ├── mobile-side-pandel │ │ │ │ ├── MSPanel.scss │ │ │ │ ├── MSPanel.stories.tsx │ │ │ │ ├── MSPanel.test.tsx │ │ │ │ ├── MSPanel.tsx │ │ │ │ └── types │ │ │ │ │ └── IProps.ts │ │ │ └── panel │ │ │ │ ├── SPanel.scss │ │ │ │ ├── SPanel.stories.tsx │ │ │ │ ├── SPanel.test.tsx │ │ │ │ ├── SPanel.tsx │ │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── volume-box │ │ │ ├── VolumeBox.scss │ │ │ ├── VolumeBox.stories.tsx │ │ │ ├── VolumeBox.test.tsx │ │ │ ├── VolumeBox.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── volume-carousel │ │ │ ├── VolumeCarousel.module.scss │ │ │ ├── VolumeCarousel.stories.tsx │ │ │ ├── VolumeCarousel.test.tsx │ │ │ ├── VolumeCarousel.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── volume-list │ │ │ ├── VolumeList.scss │ │ │ ├── VolumeList.stories.tsx │ │ │ ├── VolumeList.test.jsx │ │ │ ├── VolumeList.tsx │ │ │ ├── __mock__ │ │ │ │ └── datamock.json │ │ │ └── types │ │ │ │ └── IProps.ts │ │ ├── volume │ │ │ ├── Volume.scss │ │ │ ├── Volume.stories.tsx │ │ │ ├── Volume.test.tsx │ │ │ ├── Volume.tsx │ │ │ └── types │ │ │ │ └── IProps.ts │ │ └── year-list │ │ │ ├── YearList.scss │ │ │ ├── YearList.stories.tsx │ │ │ ├── YearList.test.tsx │ │ │ ├── YearList.tsx │ │ │ ├── __mock__ │ │ │ └── datamock.json │ │ │ └── types │ │ │ └── IProps.ts │ └── organisms │ │ ├── articles-page │ │ ├── ArticlesPage.stories.tsx │ │ ├── ArticlesPage.test.jsx │ │ ├── ArticlesPage.tsx │ │ └── styles.scss │ │ ├── demo-branch-story │ │ ├── demo-branch-story.stories.tsx │ │ └── demo-branch-story.tsx │ │ ├── homepage │ │ ├── HomePage.scss │ │ ├── HomePage.stories.tsx │ │ ├── HomePage.test.jsx │ │ ├── HomePage.tsx │ │ ├── __mock__ │ │ │ └── datamock.json │ │ └── types │ │ │ └── IProps.ts │ │ └── sectiontwo-page │ │ ├── SectiontwoPage.scss │ │ ├── SectiontwoPage.stories.tsx │ │ ├── SectiontwoPage.test.tsx │ │ ├── SectiontwoPage.tsx │ │ ├── __mock__ │ │ ├── breakpoints.json │ │ ├── secctiontwo.svg │ │ ├── secctiontwoone.svg │ │ └── section.json │ │ └── types │ │ └── IProps.ts │ └── utils │ ├── hooks │ ├── useDynamicIcon.tsx │ └── useForm.ts │ ├── svg-icons │ ├── icons.tsx │ ├── optimizeSvg.ts │ └── types │ │ └── SvgIconProps.ts │ └── vite-svgr │ ├── Icon.tsx │ ├── Loader.tsx │ ├── loadSvgIcon.ts │ └── types │ ├── IProps.ts │ └── IconType.ts ├── style-guide ├── astro.js ├── configurations │ ├── _base.js │ ├── constants.js │ ├── ignorePattern.js │ ├── typescript.js │ └── vitest.js ├── prettier │ └── config.js ├── react.js ├── rules │ ├── astro.js │ ├── base.js │ ├── internal.js │ └── nomenclature.js ├── stylelint.json └── tsconfig │ └── base.json ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | .gitignore 5 | Dockerfile 6 | docker-compose.yml 7 | README.md -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [require.resolve('./style-guide/astro')], 4 | }; 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # fixed LF 2 | * text=auto 3 | *.js eol=lf 4 | *.jsx eol=lf 5 | *.ts eol=lf 6 | *.tsx eol=lf 7 | *.css eol=lf 8 | *.scss eol=lf 9 | *.json eol=lf 10 | *.md eol=lf 11 | *.astro eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | 4 | # generated types 5 | .astro/ 6 | 7 | # dependencies 8 | node_modules/ 9 | 10 | # logs 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | 23 | # jetbrains setting folder 24 | .idea/ 25 | coverage 26 | 27 | *storybook.log 28 | 29 | #ignore build of storyb-book 30 | storybook-static -------------------------------------------------------------------------------- /.husky/_/husky.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/.husky/_/husky.sh -------------------------------------------------------------------------------- /.husky/_/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "${0%/*}/h" -------------------------------------------------------------------------------- /.husky/_/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "${0%/*}/h" -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | yarn lint 4 | yarn lint:css -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | yarn test -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | dist/ 4 | .yarn 5 | app-server/ 6 | coverage/ 7 | docs/ 8 | public/ 9 | storybool-static/ 10 | .github/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | "./style-guide/prettier/config.js" 2 | -------------------------------------------------------------------------------- /.storybook/preview.tsx: -------------------------------------------------------------------------------- 1 | import type { Preview } from '@storybook/react'; 2 | import ThemeProvider from '../src/style-library/core/ThemeProvider'; 3 | 4 | const previewDecorator = (Story, context) => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export const decorators = [previewDecorator]; 13 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./style-guide/stylelint.json", 3 | "ignoreFiles": [ 4 | "./src/examples/stories/**", 5 | "./src/layouts/*/Layout.astro", 6 | "./coverage/**", 7 | "./storybook-static/**" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll": "explicit" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | yarn-path ".yarn/releases/yarn-1.22.21.cjs" 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | ARG WEB_APP 3 | ENV COMMIT_HASH=${WEB_APP} 4 | RUN echo "Commit hash: ${COMMIT_HASH}" 5 | WORKDIR /app 6 | RUN echo ${COMMIT_HASH} > /app/commit.txt 7 | RUN echo "node version " && node -v 8 | COPY package.json yarn.lock ./ 9 | COPY . . 10 | RUN yarn install --frozen-lockfile 11 | RUN yarn build 12 | EXPOSE 3000 13 | CMD ["node", "app-server/server.mjs"] -------------------------------------------------------------------------------- /app-server/server.mjs: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import { handler } from '../dist/server/entry.mjs'; 3 | import fs from 'fs'; 4 | import path from 'path'; 5 | 6 | if (process.env.ENV === 'local') { 7 | require('dotenv').config(); 8 | } 9 | const app = express(); 10 | const PORT = process.env.PORT || 3000; 11 | 12 | app.use(express.static('public')); 13 | 14 | app.get('/systeminfo', (req, res) => { 15 | const route = path.resolve('/app/commit.txt'); 16 | const hash = fs.readFileSync(route, 'utf8'); 17 | 18 | const commitHash = hash || 'unknown'; 19 | res.json({ hashcommit: commitHash }); 20 | }); 21 | 22 | app.use(handler); 23 | 24 | app.listen(PORT, () => { 25 | console.log(`Server is running on http://localhost:${PORT}`); 26 | }); 27 | -------------------------------------------------------------------------------- /astro-i18next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('astro-i18next').AstroI18nextConfig} */ 2 | export default { 3 | defaultLocale: 'es', 4 | locales: ['es', 'en'], 5 | }; 6 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/images/articles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/docs/images/articles.png -------------------------------------------------------------------------------- /docs/images/error404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/docs/images/error404.png -------------------------------------------------------------------------------- /docs/images/error500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/docs/images/error500.png -------------------------------------------------------------------------------- /docs/images/pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/docs/images/pipeline.png -------------------------------------------------------------------------------- /docs/images/site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/docs/images/site.png -------------------------------------------------------------------------------- /docs/test.md: -------------------------------------------------------------------------------- 1 | ## Test Documentation here 2 | -------------------------------------------------------------------------------- /env.example: -------------------------------------------------------------------------------- 1 | API_END_POINT=https://api.themoviedb.org 2 | API_KEY=bb207f6bb3ec02ab983a14ed248eebb3 3 | API_BASE_ROUTE=https://image.tmdb.org/t/p/w500 4 | DOMAIN=localhost 5 | CACHE_TTL=2000 -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /public/fonts/Lato-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Lato-Bold.woff2 -------------------------------------------------------------------------------- /public/fonts/Lato-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Lato-Light.woff2 -------------------------------------------------------------------------------- /public/fonts/Lato-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Lato-Regular.woff2 -------------------------------------------------------------------------------- /public/fonts/Montserrat-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Montserrat-Light.woff2 -------------------------------------------------------------------------------- /public/fonts/Poppins-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-BoldItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-Italic.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-Light.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-LightItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-Medium.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-MediumItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /public/fonts/Poppins-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Poppins-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /public/fonts/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /public/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/public/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /public/images/flags/pe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/locales/en/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "page": { 3 | "title": "Welcome to Astro!", 4 | "articletitle": "Home - Recent Articles", 5 | "description": "Welcome to Openscience home page. Here you will find the most recent and featured articles." 6 | }, 7 | "error500": { 8 | "title": "Error 500", 9 | "message500": "Internal Server Error", 10 | "mainmessage": "An internal server error has occurred." 11 | }, 12 | "error404": { 13 | "title": "Error 404", 14 | "message404": "Page not found", 15 | "mainmessage": "The page you are looking for doesn´t or an other error occurred.", 16 | "messageinit": " Go back, or head over ", 17 | "messagefinish": " to choose a new direction " 18 | } 19 | } -------------------------------------------------------------------------------- /public/locales/es/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "page": { 3 | "title": "Bienvenido a Astro!", 4 | "articletitle": "Home - Artículos Recientes", 5 | "description": "Bienvenido a la página principal de Openscience. Aquí encontrarás los artículos más recientes y destacados." 6 | }, 7 | "error500": { 8 | "title": "Error 500", 9 | "message500": "Error interno del servidor", 10 | "mainmessage": "Se ha producido un error interno del servidor." 11 | }, 12 | "error404": { 13 | "title": "Error 404", 14 | "message404": "Pagina no encontrada", 15 | "mainmessage": "La página que busca no existe o se ha producido otro error.", 16 | "messageinit": " Vuelve atrás, o dirígete a ", 17 | "messagefinish": " elegir una nueva dirección " 18 | } 19 | } -------------------------------------------------------------------------------- /src/PubSub/Base.ts: -------------------------------------------------------------------------------- 1 | import type { EventEmitter } from './types/types'; 2 | 3 | export interface Publisher { 4 | publish(topic: string, message: T): void; 5 | } 6 | 7 | export interface Subscriber { 8 | subscribe(topic: string, callback: EventEmitter): void; 9 | } 10 | 11 | export interface Broker { 12 | publish(topic: string, message: T): void; 13 | subscribe(topic: string, callback: EventEmitter): void; 14 | } 15 | -------------------------------------------------------------------------------- /src/PubSub/Publisher.ts: -------------------------------------------------------------------------------- 1 | import type { Broker } from './Base'; 2 | 3 | export class Publisher { 4 | constructor(private broker: Broker) {} 5 | 6 | publish(topic: string, message: T): void { 7 | this.broker.publish(topic, message); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/PubSub/SimpleBroker.ts: -------------------------------------------------------------------------------- 1 | import { Broker } from './Broker'; 2 | import type { BasicMessage } from './messages/messages-model'; 3 | 4 | export class SimpleBroker extends Broker { 5 | private static instance: SimpleBroker | null = null; 6 | 7 | private constructor() { 8 | super(); 9 | } 10 | 11 | static getInstance(): SimpleBroker { 12 | if (!SimpleBroker.instance) { 13 | SimpleBroker.instance = new SimpleBroker(); 14 | } 15 | return SimpleBroker.instance; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/PubSub/SimplePublisher.ts: -------------------------------------------------------------------------------- 1 | import { Publisher } from './Publisher'; 2 | import { SimpleBroker } from './SimpleBroker'; 3 | 4 | export class SimplePublisher extends Publisher { 5 | public constructor(broker: SimpleBroker) { 6 | super(broker); 7 | } 8 | 9 | publish(topic: string, message: T): void { 10 | super.publish(topic, message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/PubSub/SimpleSubscriber.ts: -------------------------------------------------------------------------------- 1 | import { Subscriber } from './Subscriber'; 2 | import { SimpleBroker } from './SimpleBroker'; 3 | 4 | export class SimpleSubscriber extends Subscriber { 5 | public constructor(broker: SimpleBroker) { 6 | super(broker); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/PubSub/Subscriber.ts: -------------------------------------------------------------------------------- 1 | import type { Broker, Subscriber as ISubscriber } from './Base'; 2 | import type { EventEmitter } from './types/types'; 3 | 4 | export class Subscriber implements ISubscriber { 5 | private broker: Broker; 6 | 7 | constructor(broker: Broker) { 8 | this.broker = broker; 9 | } 10 | 11 | subscribe(topic: string, callback: EventEmitter): void { 12 | this.broker.subscribe(topic, callback); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/PubSub/messages/messages-model.ts: -------------------------------------------------------------------------------- 1 | export interface BasicMessage { 2 | id: string; 3 | text: string; 4 | timestamp: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/PubSub/types/types.ts: -------------------------------------------------------------------------------- 1 | export interface EventEmitter { 2 | callBack: (message: T) => void; 3 | } 4 | -------------------------------------------------------------------------------- /src/Shadows/ShadowsDemo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import './Shadows.scss'; 3 | 4 | const shadowLevels = ['xs', 'sm', 'md', 'lg', 'xl', '3xl']; 5 | 6 | function ShadowsDemo() { 7 | return ( 8 |
18 | {shadowLevels.map((level) => ( 19 |
24 |

Sombra {level.toUpperCase()}

25 |
26 | ))} 27 |
28 | ); 29 | } 30 | 31 | export default ShadowsDemo; 32 | -------------------------------------------------------------------------------- /src/assets/icons/Close-URL.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/Info-Tooltip.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/icons/burger-menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/icons/caret_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/assets/icons/check.svg: -------------------------------------------------------------------------------- 1 | 8 | 15 | -------------------------------------------------------------------------------- /src/assets/icons/circle-quarters.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/close_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/assets/icons/close_simple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/icons/fi-rr-copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/fi-sr-phone-call.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/left-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/icons/right-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/astro-env.d.ts: -------------------------------------------------------------------------------- 1 | import type { Locals } from './types/locals'; 2 | 3 | declare module 'astro' { 4 | interface AstroGlobal { 5 | locals: Locals; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/tokens/ColorPreview.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react'; 2 | import { ColorPreview } from './ColorPreview'; 3 | 4 | const meta: Meta = { 5 | title: 'Tokens/ColorPreview', 6 | component: ColorPreview, 7 | }; 8 | 9 | export default meta; 10 | 11 | export const AllColors: StoryObj = { 12 | render: () => , 13 | }; 14 | -------------------------------------------------------------------------------- /src/config/seo-config.mock.js: -------------------------------------------------------------------------------- 1 | export const seoConfig = { 2 | title: 'Título Mockeado', 3 | description: 'Descripción mockeada para pruebas.', 4 | openGraph: { 5 | type: 'website', 6 | url: 'https://example.com', 7 | title: 'Título de OpenScience', 8 | description: 'Descripción de OpenScience', 9 | images: [ 10 | { 11 | url: 'https://science-i.storage.googleapis.com/wp-content/uploads/2024/02/11175815/cropped-Science-I-logo1-scaled-1.jpg', 12 | alt: 'Imagen de OpenScience', 13 | }, 14 | ], 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /src/fetch/types/headers.ts: -------------------------------------------------------------------------------- 1 | export interface HeadersConfig { 2 | 'Content-Type'?: string; 3 | Authorization?: string; 4 | 'Custom-Header'?: string; 5 | Accept?: string; 6 | 'User-Agent'?: string; 7 | [key: string]: string | undefined; 8 | } 9 | -------------------------------------------------------------------------------- /src/fetch/utils.ts: -------------------------------------------------------------------------------- 1 | import NodeCache from 'node-cache'; 2 | 3 | // eslint-disable-next-line turbo/no-undeclared-env-vars 4 | const cacheTTL = Number(process.env.CACHE_TTL) || 600; 5 | const cache = new NodeCache({ stdTTL: cacheTTL }); 6 | 7 | export const getCache = (key: string) => cache.get(key) as T; 8 | export const setCache = (key: string, value: T) => cache.set(key, value); 9 | export const delCache = (key: string) => cache.del(key); 10 | -------------------------------------------------------------------------------- /src/globals/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | $ads-breakpoints-scales: ( 2 | 'small': 480px, 3 | 'small-mobile': 320px, 4 | 'small-mobile-large': 568px, 5 | 'medium': 768px, 6 | 'large': 1024px, 7 | 'large-tablet': 1112px, 8 | 'extra-large': 1280px, 9 | ); 10 | -------------------------------------------------------------------------------- /src/globals/_mixins.scss: -------------------------------------------------------------------------------- 1 | @import 'breakpoints'; 2 | 3 | @mixin respond-to($breakpoint) { 4 | @if map-has-key($ads-breakpoints-scales, $breakpoint) { 5 | @media (min-width: map-get($ads-breakpoints-scales, $breakpoint)) { 6 | @content; 7 | } 8 | } 9 | 10 | @else { 11 | @warn "It has not been found: #{$breakpoint}."; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/globals/_sizes.scss: -------------------------------------------------------------------------------- 1 | $ads-size-xs: 1.5rem; 2 | $ads-size-sm: 2rem; 3 | $ads-size-md: 2.5rem; 4 | $ads-size-lg: 3rem; 5 | -------------------------------------------------------------------------------- /src/globals/_typography.scss: -------------------------------------------------------------------------------- 1 | $ads-font-size-headingone: 3rem; 2 | $ads-font-size-headingtwo: 2.25rem; 3 | $ads-font-size-headingthree: 1.5; 4 | 5 | $ads-line-height-headingone: 4.5rem; 6 | $ads-line-height-headingtwo: 3.375rem; 7 | $ads-line-height-headingthree: 2.25rem; 8 | 9 | $ads-font-weight-regular: 400; 10 | $ads-font-weight-medium: 500; 11 | $ads-font-weight-semibold: 600; 12 | 13 | $ads-font-family-sans: 'Helvetica Neue', arial, sans-serif; 14 | $ads-font-family-serif: 'Georgia', serif; 15 | $ads-font-family-italic: 'Times New Roman', times, serif; 16 | $ads-font-family-monospace: 'Courier New', courier, monospace; 17 | -------------------------------------------------------------------------------- /src/globals/main.scss: -------------------------------------------------------------------------------- 1 | @use '../styles/tokens/border-radius.scss'; 2 | @use './tokens.scss'; 3 | -------------------------------------------------------------------------------- /src/globals/styles/tokens.scss: -------------------------------------------------------------------------------- 1 | $ads-padding-scale: ( 2 | 'minus_one': -1px, 3 | '1px': 1px, 4 | '2px': 2px, 5 | '4px': 4px, 6 | '6px': 6px, 7 | '8px': 8px, 8 | '10px': 10px, 9 | 'minus_10px': -10px, 10 | '12px': 12px, 11 | ); 12 | -------------------------------------------------------------------------------- /src/globals/theme/index.ts: -------------------------------------------------------------------------------- 1 | import { colors } from '../tokens/colors'; 2 | 3 | export const theme = { 4 | colors, 5 | }; 6 | -------------------------------------------------------------------------------- /src/layouts/gridly/breakpoints-grid.scss: -------------------------------------------------------------------------------- 1 | $ads-breakpoints-scales: ( 2 | xs: 576px, 3 | md: 992px, 4 | lg: 1200px, 5 | ); 6 | $ads-alignments-map-list: ( 7 | start: flex-start, 8 | center: center, 9 | end: flex-end, 10 | ); 11 | -------------------------------------------------------------------------------- /src/library/component/atoms/pills/types/IProps.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export interface IProps { 4 | text: string; 5 | color?: 6 | | 'neutral-dark' 7 | | 'neutral-light' 8 | | 'brand-primary' 9 | | 'brand-secondary' 10 | | 'brand-tertiary' 11 | | 'feedback-positive' 12 | | 'feedback-negative' 13 | | 'feedback-warning' 14 | | 'read-only-disabled'; 15 | variant?: 'filled' | 'outline' | 'soft'; 16 | size?: 'sm' | 'md' | 'lg'; 17 | rounded?: 'r_none' | 'r_md' | 'r_full'; 18 | ariaLabel?: string; 19 | shadow?: boolean; 20 | stroke?: 'border-soft' | 'border-strong'; 21 | icon?: string | ReactNode; 22 | iconPosition?: 'left' | 'right'; 23 | } 24 | -------------------------------------------------------------------------------- /src/library/component/atoms/text-content/TextContent.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/typography'; 3 | @import '../../../../globals/fonts'; 4 | 5 | .text-content { 6 | color: $ads-color-gray-soft-500; 7 | font-family: Poppins-Regular, sans-serif; 8 | font-weight: $ads-font-weight-regular; 9 | line-height: 1.5; 10 | margin: 0; 11 | padding: 0; 12 | 13 | &.compact { 14 | line-height: 1.1; 15 | } 16 | 17 | &.default { 18 | line-height: 1.5; 19 | } 20 | 21 | &.spacious { 22 | line-height: 1.8; 23 | } 24 | 25 | &.xs { 26 | font-size: 0.850rem; 27 | } 28 | 29 | &.sm { 30 | font-size: 0.875rem; 31 | } 32 | 33 | &.md { 34 | font-size: 1rem; 35 | } 36 | 37 | &.lg { 38 | font-size: 1.25rem; 39 | } 40 | 41 | &.xl { 42 | font-size: 1.5rem; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/library/component/atoms/text-content/TextContent.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import styles from './TextContent.module.scss'; 3 | 4 | function TextContent({ text, size, spacing }: IProps) { 5 | const sizeClass = size ? styles[size] : styles.lg; 6 | const spacingClass = spacing ? styles[spacing] : styles.default; 7 | const className = `${styles['text-content']} ${sizeClass} ${spacingClass}`; 8 | return

{text}

; 9 | } 10 | 11 | export default TextContent; 12 | -------------------------------------------------------------------------------- /src/library/component/atoms/text-content/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | spacing?: 'compact' | 'default' | 'spacious'; 3 | weight?: 'regular' | 'medium' | 'semibold'; 4 | size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; 5 | text: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/library/component/atoms/text-title/TextTitle.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import styles from './TextTitle.module.scss'; 3 | 4 | function TextTitle({ text, size = 'lg', weight = 'regular', spacing = 'default' }: IProps) { 5 | const classNames = [styles.title, styles[size], styles[weight], styles[spacing]].join(' '); 6 | 7 | return

{text}

; 8 | } 9 | 10 | export default TextTitle; 11 | -------------------------------------------------------------------------------- /src/library/component/atoms/text-title/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | spacing?: 'compact' | 'default' | 'spacious'; 3 | weight?: 'regular' | 'medium' | 'semibold'; 4 | size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; 5 | text: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/library/component/molecules/icon-text-stat/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | import type { IconName } from './iconMap'; 3 | 4 | export interface IProps { 5 | title: string; 6 | mainValue: string | number; 7 | subValue?: string | number; 8 | variant?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'error'; 9 | size?: 'small' | 'medium' | 'large'; 10 | border?: 'sharp' | 'soft'; 11 | icon?: IconName; 12 | description?: string; 13 | onClick?: () => void; 14 | className?: string; 15 | children?: React.ReactNode; 16 | } 17 | -------------------------------------------------------------------------------- /src/library/component/molecules/icon-text-stat/types/iconMap.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ArrowUpward, 3 | ArrowDownward, 4 | Warning, 5 | CheckCircle, 6 | Error as ErrorIcon, 7 | } from '@mui/icons-material'; 8 | import HighlightOffIcon from '@mui/icons-material/HighlightOff'; 9 | 10 | export const iconMap = { 11 | close: HighlightOffIcon, 12 | up: ArrowUpward, 13 | down: ArrowDownward, 14 | warning: Warning, 15 | success: CheckCircle, 16 | error: ErrorIcon, 17 | }; 18 | 19 | export type IconName = keyof typeof iconMap; 20 | -------------------------------------------------------------------------------- /src/library/component/molecules/phone-dropdown/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface ICountry { 2 | code: string; 3 | name: string; 4 | flag: string; 5 | dialCode: string; 6 | } 7 | 8 | export interface IProps { 9 | label?: string; 10 | value?: string; 11 | onChange?: (countryCode: string, phoneNumber: string) => void; 12 | countries?: ICountry[]; 13 | placeholder?: string; 14 | error?: boolean; 15 | helperText?: string; 16 | disabled?: boolean; 17 | className?: string; 18 | defaultCountry?: string; 19 | size?: 'small' | 'medium' | 'large'; 20 | border?: 'rounded' | 'straight'; 21 | } 22 | -------------------------------------------------------------------------------- /src/library/component/molecules/text-arrangement/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type SizeType = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; 4 | export type LayoutType = 'featured' | 'columns' | 'cards' | 'standard'; 5 | export type AlignmentType = 'left' | 'center' | 'right' | 'justified'; 6 | export type SpacingType = 'default' | 'compact' | 'spacious'; 7 | 8 | export interface ContentType { 9 | title: string; 10 | text: string; 11 | } 12 | 13 | export interface IProps { 14 | titleSize?: SizeType; 15 | layout?: LayoutType; 16 | alignment?: AlignmentType; 17 | titleSpacing?: SpacingType; 18 | contentSpacing?: SpacingType; 19 | contentSize?: SizeType; 20 | showBadge?: boolean; 21 | content: ContentType; 22 | responsive?: boolean; 23 | className?: string; 24 | children?: React.ReactNode; 25 | } 26 | -------------------------------------------------------------------------------- /src/library/component/molecules/user-text-card/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export interface IProps { 4 | avatar: string | ReactNode; 5 | userName: string; 6 | userHandle?: string; 7 | content: string | ReactNode; 8 | timestamp?: string | Date; 9 | actions?: { label: string; onClick: () => void }[]; 10 | variant?: 'default' | 'compact' | 'expanded'; 11 | isVerified?: boolean; 12 | onClick: () => void; 13 | className?: string; 14 | isChecked: boolean; 15 | onCheckChange?: (checked: boolean) => void; 16 | } 17 | -------------------------------------------------------------------------------- /src/middleware/auth.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import { defineMiddleware } from 'astro:middleware'; 3 | 4 | export const auth = defineMiddleware((context, next) => { 5 | return next(); 6 | }); 7 | -------------------------------------------------------------------------------- /src/middleware/errors.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import { defineMiddleware } from 'astro:middleware'; 3 | import type { Config } from '../types/config'; 4 | 5 | export const errors = defineMiddleware(async (context, next) => { 6 | const defineErrorPages: Config = { 7 | path: '/errors', 8 | }; 9 | const { redirect } = context; 10 | const errorMapping: Record = { 11 | 404: `${defineErrorPages.path}/400`, 12 | 500: `${defineErrorPages.path}/500`, 13 | }; 14 | const response = await next(); 15 | if (response.status > 399) { 16 | return redirect(errorMapping[response.status]); 17 | } 18 | return next(); 19 | }); 20 | -------------------------------------------------------------------------------- /src/middleware/index.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import { sequence } from 'astro:middleware'; 3 | import { loadEnvs } from './loadEnvs'; 4 | import { errors } from './errors'; 5 | import { auth } from './auth'; 6 | 7 | export const onRequest = sequence(loadEnvs, errors, auth); 8 | -------------------------------------------------------------------------------- /src/pages/articles/[id].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from 'layouts/Layout.astro'; 3 | import ArticleTitle from '../../ui/components/atoms/article-title/ArticleTitle'; 4 | import ArticleDescription from '../../ui/components/atoms/article-description/ArticleDescription'; 5 | --- 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/articles/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../layouts/Layout.astro'; 3 | import ArticleTitle from '../../ui/components/atoms/article-title/ArticleTitle'; 4 | import ArticleDescription from '../../ui/components/atoms/article-description/ArticleDescription'; 5 | 6 | async function getData() { 7 | const API_ROUTE = Astro.locals.API_END_POINT; 8 | const data = Astro.locals.collections(`${API_ROUTE}/api/articles`); 9 | return data; 10 | } 11 | 12 | const collections = await getData(); 13 | const articles = collections?.data; 14 | console.log(articles); 15 | --- 16 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /src/pages/en/errors/400.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | import { t, changeLanguage } from 'i18next'; 4 | import Layout from '../../../layouts/Layout.astro'; 5 | import ErrorMessage from '../../../ui/components/atoms/error-message/ErrorMessage'; 6 | 7 | changeLanguage('en'); 8 | --- 9 | 10 | 404 {t('error404.message404')} 11 | 12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/pages/en/errors/500.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | import { t, changeLanguage } from 'i18next'; 4 | import Layout from '../../../layouts/Layout.astro'; 5 | import ErrorMessage from '../../../ui/components/atoms/error-message/ErrorMessage'; 6 | 7 | changeLanguage('en'); 8 | --- 9 | 10 | Error 500 {t('error500.message500')} 11 | 12 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/pages/en/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | import { t, changeLanguage } from 'i18next'; 4 | import Layout from '../../layouts/Layout.astro'; 5 | import ArticleTitle from '../../ui/components/atoms/article-title/ArticleTitle'; 6 | import ArticleDescription from '../../ui/components/atoms/article-description/ArticleDescription'; 7 | 8 | changeLanguage('en'); 9 | --- 10 | 11 | 12 |

OPENSCIENCE V 0.1.2

13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /src/pages/errors/400.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | import { t, changeLanguage } from 'i18next'; 4 | import Layout from '../../layouts/Layout.astro'; 5 | import ErrorMessage from '../../ui/components/atoms/error-message/ErrorMessage'; 6 | 7 | changeLanguage('es'); 8 | --- 9 | 10 | 404 {t('error404.message404')} 11 | 12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/pages/errors/500.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | import { t, changeLanguage } from 'i18next'; 4 | import Layout from '../../layouts/Layout.astro'; 5 | import ErrorMessage from '../../ui/components/atoms/error-message/ErrorMessage'; 6 | 7 | changeLanguage('es'); 8 | --- 9 | 10 | Error 500 {t('error500.message500')} 11 | 12 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/pages/experiment/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { SenderComponent } from 'ui/components/molecules/experiment-pubsub/sender-component'; 3 | import { ReceiveComponent } from 'ui/components/molecules/experiment-pubsub/receive-component'; 4 | import Layout from '../../layouts/Layout.astro'; 5 | --- 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/pages/login/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../layouts/Layout.astro'; 3 | import ArticleTitle from '../../ui/components/atoms/article-title/ArticleTitle'; 4 | import ArticleDescription from '../../ui/components/atoms/article-description/ArticleDescription'; 5 | --- 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/register/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../layouts/Layout.astro'; 3 | import ArticleTitle from '../../ui/components/atoms/article-title/ArticleTitle'; 4 | import ArticleDescription from '../../ui/components/atoms/article-description/ArticleDescription'; 5 | --- 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/volumenes/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../layouts/Layout.astro'; 3 | import Rectangle12 from '../../ui/components/atoms/hero-banner/__mock__/imgs/Rectangle12.png'; 4 | import BannerVolumes from '../../ui/components/molecules/banner-volumes/BannerVolumes'; 5 | import dataMock from '../../ui/components/molecules/year-list/__mock__/datamock.json'; 6 | import LogoSvg from '../../assets/icons/logo.svg'; 7 | import type { ApiResponse } from './utils/fetchData'; 8 | import { fetchData } from './utils/fetchData'; 9 | 10 | const localsData = Astro.locals; 11 | const data: ApiResponse = (await fetchData(localsData?.API_END_POINT)) || dataMock; 12 | --- 13 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /src/pages/volumenes/utils/fetchData.ts: -------------------------------------------------------------------------------- 1 | import FetchCache from '../../../fetch/fetch'; 2 | 3 | export interface ApiResponse { 4 | data: { 5 | id: number; 6 | attributes: { 7 | Year: string; 8 | Volumes: string; 9 | }; 10 | }[]; 11 | } 12 | 13 | export async function fetchData(API_ENDPOINT: string) { 14 | const fetcher = new FetchCache(`${API_ENDPOINT}/api/year-volumes`, {}); 15 | 16 | try { 17 | const response = await fetcher.get(); 18 | return response; 19 | } catch (error) { 20 | console.error('Error fetching data:', error); 21 | return null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/pages/volumes/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../layouts/Layout.astro'; 3 | import ArticleTitle from '../../ui/components/atoms/article-title/ArticleTitle'; 4 | import ArticleDescription from '../../ui/components/atoms/article-description/ArticleDescription'; 5 | --- 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src/services/http-client/cache/cache-factory.ts: -------------------------------------------------------------------------------- 1 | import { MemoryCache } from './strategies/memory-cache'; 2 | import { RedisCache } from './strategies/redis-cache'; 3 | import { CacheType } from '../types/cache-types'; 4 | import type { CacheActions } from './strategies/base-cache-actions'; 5 | 6 | export function cacheFactory(type: CacheType): CacheActions { 7 | switch (type) { 8 | case CacheType.MEMORY: 9 | return new MemoryCache(); 10 | case CacheType.REDIS: 11 | return new RedisCache(); 12 | default: 13 | throw new Error('Invalid cache type'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/services/http-client/cache/cache-manager.ts: -------------------------------------------------------------------------------- 1 | import type { CacheActions } from './strategies/base-cache-actions'; 2 | import { CacheType } from '../types/cache-types'; 3 | import { cacheFactory } from './cache-factory'; 4 | 5 | // eslint-disable-next-line @typescript-eslint/no-extraneous-class 6 | export class SingletonCache { 7 | // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents 8 | public static instance: unknown | null = null; 9 | 10 | static getInstance(type: CacheType): CacheActions { 11 | if (!SingletonCache.instance) { 12 | SingletonCache.instance = cacheFactory(type); 13 | } 14 | return SingletonCache.instance as CacheActions; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/services/http-client/cache/strategies/base-cache-actions.ts: -------------------------------------------------------------------------------- 1 | export interface CacheActions { 2 | get(key: string): Promise; 3 | set(key: string, data: T, ttl: number): Promise; 4 | clear(): Promise; 5 | has(key: string): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /src/services/http-client/types/cache-types.ts: -------------------------------------------------------------------------------- 1 | export enum CacheType { 2 | MEMORY = 'memory', 3 | REDIS = 'redis', 4 | } 5 | -------------------------------------------------------------------------------- /src/services/http-client/types/index.ts: -------------------------------------------------------------------------------- 1 | export interface RedisConnectionOptions { 2 | username: string; 3 | password: string; 4 | socket: { 5 | host: string; 6 | port: number; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /src/services/utils/environments.ts: -------------------------------------------------------------------------------- 1 | export const getEnvironment = (key: string): string => { 2 | return import.meta.env[key] as string; 3 | }; 4 | -------------------------------------------------------------------------------- /src/services/utils/request-utils.ts: -------------------------------------------------------------------------------- 1 | interface IRequestOptions { 2 | url: string; 3 | method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; 4 | } 5 | 6 | export function generateKey(options: IRequestOptions): string { 7 | const key = `${options.url}-${options.method}`; 8 | return key; 9 | } 10 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import '@testing-library/jest-dom'; 3 | -------------------------------------------------------------------------------- /src/style-library/core/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { CacheProvider, type EmotionCache } from '@emotion/react'; 3 | import { ThemeProvider } from '../providers/ThemeProvider'; 4 | import createEmotionCache from '../createEmotionCache'; 5 | 6 | const clientSideEmotionCache = createEmotionCache(); 7 | 8 | interface AppProps { 9 | children: React.ReactNode; 10 | emotionCache?: EmotionCache; 11 | } 12 | 13 | function ThemeWrapper({ children, emotionCache = clientSideEmotionCache }: AppProps) { 14 | return ( 15 | 16 | {children} 17 | 18 | ); 19 | } 20 | 21 | export default ThemeWrapper; 22 | -------------------------------------------------------------------------------- /src/style-library/core/ThemeSwitcher.tsx: -------------------------------------------------------------------------------- 1 | import { Select, MenuItem } from '@mui/material'; 2 | import { useThemeMode } from '../providers/useThemeProvider'; 3 | 4 | export function ModeSwitcher() { 5 | const { mode, setMode } = useThemeMode(); 6 | 7 | return ( 8 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/style-library/createEmotionCache.ts: -------------------------------------------------------------------------------- 1 | import createCache from '@emotion/cache'; 2 | 3 | export default function createEmotionCache() { 4 | return createCache({ key: 'openscience-mui', prepend: true }); 5 | } 6 | -------------------------------------------------------------------------------- /src/style-library/providers/useThemeProvider.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ThemeContext } from './ThemeProvider'; 3 | 4 | export function useThemeMode() { 5 | const context = useContext(ThemeContext); 6 | if (!context) { 7 | throw new Error('useThemeMode must be used within a ThemeProvider'); 8 | } 9 | return context; 10 | } 11 | -------------------------------------------------------------------------------- /src/styles/tokens/border-radius.scss: -------------------------------------------------------------------------------- 1 | $ads-radius-none: 0; 2 | $ads-radius-xsm: 1px; 3 | $ads-radius-sm: 2px; 4 | $ads-radius-sm-extra: 4px; 5 | $ads-radius-sm-plus: 6px; 6 | $ads-radius-sm-max: 8px; 7 | $ads-radius-md: 12px; 8 | $ads-radius-md-extra: 16px; 9 | $ads-radius-md-plus: 18px; 10 | $ads-radius-lg: 20px; 11 | $ads-radius-lg-extra: 24px; 12 | $ads-radius-lg-max: 32px; 13 | $ads-radius-full: 9999px; 14 | -------------------------------------------------------------------------------- /src/test/simple.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('Simple test', () => { 4 | it('should always pass', () => { 5 | expect(true).toBe(true); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /src/types/config.ts: -------------------------------------------------------------------------------- 1 | export interface Config { 2 | path: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/types/locals.d.ts: -------------------------------------------------------------------------------- 1 | export interface ArticlesApiResponse { 2 | data: { 3 | id: number; 4 | attributes: { 5 | title: string; 6 | date: string; 7 | complete_text: string; 8 | brief: string; 9 | createdAt: string; 10 | updatedAt: string; 11 | publishedAt: string; 12 | }; 13 | }[]; 14 | } 15 | export interface Locals { 16 | API_END_POINT: string; 17 | API_KEY: string; 18 | API_BASE_ROUTE: string; 19 | DOMAIN: string; 20 | collections: (API_ROUTE: string) => Promise; 21 | } 22 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Author-Label/AuthorLabel.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/fonts'; 2 | @import '../../../../globals/mixins'; 3 | @import '../../../../globals/variables'; 4 | 5 | .author { 6 | color: $ads-text-secondary; 7 | font-family: Lato, sans-serif; 8 | font-size: 0.625rem; 9 | font-weight: 275; 10 | line-height: 0.85rem; 11 | 12 | @include respond-to('small') { 13 | font-size: 0.625rem; 14 | } 15 | 16 | @include respond-to('medium') { 17 | font-size: 1rem; 18 | } 19 | 20 | @include respond-to('large') { 21 | font-size: 1.5rem; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Author-Label/AuthorLabel.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import AuthorLabel from './AuthorLabel'; 3 | 4 | const meta = { 5 | title: 'ui/components/atoms/author-label', 6 | component: AuthorLabel, 7 | argTypes: { 8 | onClick: { 9 | action: 'click', 10 | }, 11 | }, 12 | } as Meta; 13 | 14 | export default meta; 15 | 16 | type Story = StoryObj; 17 | 18 | export const Primary: Story = { 19 | args: { 20 | variant: 'Marco Antonio Lopez', 21 | }, 22 | }; 23 | export const Secondary: Story = { 24 | args: { 25 | variant: 'jk Rolling', 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Author-Label/AuthorLabel.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import AuthorLabel from './AuthorLabel.tsx'; 3 | 4 | describe('Testing Author React Component', () => { 5 | test('should be rendere Marco antonio lopez', () => { 6 | render(); 7 | const lavelElement = screen.getByText('Marco antonio lopez'); 8 | expect(lavelElement).toBeInTheDocument(); 9 | }); 10 | 11 | test('should be rendere jk Rolling', () => { 12 | render(); 13 | const lavelElement = screen.getByText('jk Rolling'); 14 | expect(lavelElement).toBeInTheDocument(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Author-Label/AuthorLabel.tsx: -------------------------------------------------------------------------------- 1 | import styles from './AuthorLabel.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function AuthorLabel({ variant }: IProps) { 5 | const variantClass = styles[variant as keyof typeof styles]; 6 | 7 | return

{variant}

; 8 | } 9 | 10 | export default AuthorLabel; 11 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Author-Label/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | variant?: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Default-Input/types/DefaultInputProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface DefaultInputProps extends React.InputHTMLAttributes { 4 | label?: string; 5 | placeholder?: string; 6 | value?: string; 7 | onChange?: (e: React.ChangeEvent) => void; 8 | leftIcon?: React.ReactNode; 9 | rightIcon?: React.ReactNode; 10 | hint?: string; 11 | error?: string; 12 | disabled?: boolean; 13 | className?: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Ghost-Button/types/types.ts: -------------------------------------------------------------------------------- 1 | export interface GhostButtonProps { 2 | ghostbutton: string; 3 | variant: 4 | | 'primary' 5 | | 'dark' 6 | | 'intenseviolet' 7 | | 'violet' 8 | | 'teritary' 9 | | 'green' 10 | | 'red' 11 | | 'yellow'; 12 | size?: 'small' | 'medium' | 'large'; 13 | disabled?: boolean; 14 | onClick?: () => void; 15 | withIcon?: boolean; 16 | } 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/HeadingTitle/HeadingTitle.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import styles from './HeadingTitle.module.scss'; 3 | 4 | function HeadingTitle({ text, Styles = 'monospace', Weight = 'semi-bold', Level = 'h1' }: IProps) { 5 | const headingClass = `${styles['heading-title']} ${styles['heading-title__text']} 6 | ${styles[`heading-title--level-${Level}`]} 7 | ${styles[`heading-title--style-${Styles}`]} 8 | ${styles[`heading-title--weight-${Weight}`]}`; 9 | 10 | const HeadingTag = Level as keyof JSX.IntrinsicElements; 11 | 12 | return {text}; 13 | } 14 | 15 | export default HeadingTitle; 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/HeadingTitle/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | Weight?: 'regular' | 'medium' | 'semi-bold'; 4 | Styles?: 'sans' | 'italic' | 'serif' | 'monospace'; 5 | Level?: 'h1' | 'h2' | 'h3'; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/IconButtons/types/Iprops.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type IconButtonSize = 'xs' | 'sm' | 'md' | 'lg'; 4 | export type IconButtonShape = 'square' | 'rounded' | 'circle'; 5 | export type IconButtonColor = 'neutral' | 'brand' | 'feedback'; 6 | 7 | export interface IIconButtonProps extends React.ButtonHTMLAttributes { 8 | icon: React.ReactNode; 9 | ariaLabel: string; 10 | size?: IconButtonSize; 11 | shape?: IconButtonShape; 12 | color?: IconButtonColor; 13 | disabled?: boolean; 14 | className?: string; 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Tags/Tags.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import { describe, it, expect } from 'vitest'; 3 | import Tags from './Tags'; 4 | 5 | describe('Tags Component', () => { 6 | it('should render the correct number of tags', () => { 7 | const labels = ['Workings', 'Optimism', 'Meaning', 'Promoting']; 8 | render(); 9 | labels.forEach((label) => { 10 | expect(screen.getByText(label)).toBeInTheDocument(); 11 | }); 12 | }); 13 | 14 | it('should handle an empty list of tags', () => { 15 | render(); 16 | expect(screen.queryByText(/./)).not.toBeInTheDocument(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Tags/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface ITagsProps { 2 | labels: string[]; 3 | variant?: 'default' | 'black' | 'large-text'; 4 | to?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/atoms/TextCardList/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export type Variant = 'default' | 'info' | 'warning' | 'success' | 'error'; 2 | 3 | export interface BadgeProps { 4 | avatarUrl: string; 5 | text: string; 6 | trailingText: string; 7 | } 8 | 9 | export interface TextCardPropsList { 10 | title: string; 11 | description?: string; 12 | categoryTag?: string; 13 | selected?: boolean; 14 | onSelect?: (selected: boolean) => void; 15 | variant?: Variant; 16 | className?: string; 17 | badge?: BadgeProps; 18 | } 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/Toggle/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | checked: boolean; 3 | onChange: (value: boolean) => void; 4 | disabled?: boolean; 5 | variant?: 'default' | 'success' | 'info' | 'warning' | 'danger'; 6 | size?: 'small' | 'medium' | 'large'; 7 | 'aria-label'?: string; 8 | 'aria-labelledby'?: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/atoms/article-description/ArticleDescription.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './ArticleDescription.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function ArticleDescription({ article, variant }: IProps) { 6 | const textStyleMap: Record = { 7 | bold: styles['bold-text'], 8 | italic: styles['italic-text'], 9 | underline: styles['underline-text'], 10 | highlight: styles['highlight-text'], 11 | default: styles['default-text'], 12 | }; 13 | 14 | const textStyle = variant && textStyleMap[variant] ? textStyleMap[variant] : textStyleMap.default; 15 | 16 | return ( 17 |
18 |

{article}

19 |
20 | ); 21 | } 22 | 23 | export default ArticleDescription; 24 | -------------------------------------------------------------------------------- /src/ui/components/atoms/article-description/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | article: string; 6 | variant?: 'default' | 'bold' | 'italic' | 'underline' | 'highlight'; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/article-title/ArticleTitle.tsx: -------------------------------------------------------------------------------- 1 | import styles from './ArticleTitle.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function ArticleTitle({ title, variant }: IProps) { 5 | const getTextStyle = () => { 6 | if (variant === 'primary') { 7 | return styles['article-title__text--primary']; 8 | } 9 | if (variant === 'secondary') { 10 | return styles['article-title__text--secondary']; 11 | } 12 | return ''; 13 | }; 14 | 15 | const textStyle = getTextStyle(); 16 | return ( 17 |
18 |

{title}

19 |
20 | ); 21 | } 22 | 23 | export default ArticleTitle; 24 | -------------------------------------------------------------------------------- /src/ui/components/atoms/article-title/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | title: string; 3 | variant?: 'default' | 'primary' | 'secondary'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/badges/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CircleQuarters from '../../../../assets/icons/circle-quarters.svg?react'; 3 | import Close from '../../../../assets/icons/Close-URL.svg?react'; 4 | 5 | interface IconProps { 6 | className?: string; 7 | style?: React.CSSProperties; 8 | } 9 | 10 | export function IconCircleQuarters({ className, style }: IconProps) { 11 | return ; 12 | } 13 | 14 | export function IconClose({ className, style }: IconProps) { 15 | return ; 16 | } 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/badges/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface BadgeProps { 4 | variant: 'filled' | 'outline' | 'soft'; 5 | color: 'neutral' | 'gray' | 'violet' | 'blue' | 'custom'; 6 | customColor?: string; 7 | icon?: React.ReactNode; 8 | image?: string; 9 | shape: 'default' | 'rounded'; 10 | size: 'sm' | 'md'; 11 | children?: React.ReactNode; 12 | leftCount?: number; 13 | rightCount?: number; 14 | onClose?: () => void; 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/burger-button/BurgerButton.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import BurgerButton from './BurgerButton.tsx'; 3 | import IconBurger from '../../../../assets/icons/button-burguer.svg?raw'; 4 | 5 | describe('Testing BurgerButton React Component', () => { 6 | test('should be rendere burger', () => { 7 | render(); 8 | const buttonElement = screen.getByTestId('button-icon'); 9 | expect(buttonElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/atoms/burger-button/BurgerButton.tsx: -------------------------------------------------------------------------------- 1 | import styles from './BurgerButton.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function BurgerButton({ icon, color, onClick }: IProps) { 6 | const colorClass = color ? styles[color as keyof typeof styles] : ''; 7 | 8 | return ( 9 | 16 | ); 17 | } 18 | 19 | export default BurgerButton; 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/burger-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | variant?: 'main' | 'secondary'; 3 | icon?: string; 4 | color?: 'primary' | 'secondary'; 5 | onClick?: () => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-burger/ButtonBurger.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj } from '@storybook/react'; 2 | import Burger from './ButtonBurger'; 3 | import burger from '../../../../assets/icons/burger-menu.svg?raw'; 4 | 5 | const meta = { 6 | title: 'ui/components/atoms/button-burger', 7 | component: Burger, 8 | argTypes: { 9 | onClick: { 10 | action: 'click', 11 | }, 12 | }, 13 | }; 14 | 15 | export default meta; 16 | 17 | type Story = StoryObj; 18 | 19 | export const Primary: Story = { 20 | args: { 21 | variant: 'main', 22 | color: 'primary', 23 | icon: burger, 24 | }, 25 | }; 26 | 27 | export const Secondary: Story = { 28 | args: { 29 | variant: 'secondary', 30 | color: 'secondary', 31 | icon: burger, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-burger/ButtonBurger.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import ButtonBurger from './ButtonBurger'; 3 | import burger from '../../../../assets/icons/burger-menu.svg?raw'; 4 | 5 | describe('Testing ButtonBurger React Component', () => { 6 | test('should be rendere burger', () => { 7 | render(); 8 | const buttonElement = screen.getByTestId('button-icon'); 9 | expect(buttonElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-burger/ButtonBurger.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import { Icon } from '../../../utils/svg-icons/icons'; 3 | import styles from './ButtonBurger.module.scss'; 4 | 5 | function ButtonBurger({ icon, color, onClick }: IProps) { 6 | const colorClass = styles[color as keyof typeof styles] || ''; 7 | return ( 8 | 11 | ); 12 | } 13 | 14 | export default ButtonBurger; 15 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-burger/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | variant?: 'main' | 'secondary'; 3 | icon?: string; 4 | color?: 'primary' | 'secondary'; 5 | onClick?: () => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-label/ButtonLabel.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './ButtonLabel.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | import { Icon } from '../../../utils/svg-icons/icons'; 5 | 6 | function ButtonLabel({ children, variant = 'primary', icon }: IProps) { 7 | const colorFont = styles[`label-icon__icon--${variant}`]; 8 | return ( 9 |
10 | {icon && ( 11 | 16 | )} 17 | {children} 18 |
19 | ); 20 | } 21 | 22 | export default ButtonLabel; 23 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-label/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant?: 'primary' | 'secondary' | 'tertiary'; 6 | icon?: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-number/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant?: 'filled' | 'outline' | 'ghost'; 6 | shape?: 'square' | 'rounded' | 'circle'; 7 | size?: 'small' | 'medium' | 'large'; 8 | inactive?: boolean; 9 | selected?: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-with-variants/ButtonWithVariants.tsx: -------------------------------------------------------------------------------- 1 | import styles from './ButtonWithVariants.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function ButtonWithVariants({ children, variant = 'primary', onClick }: IProps) { 5 | const variantClass = styles[`button-variant--${variant}`]; 6 | return ( 7 | 10 | ); 11 | } 12 | 13 | export default ButtonWithVariants; 14 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-with-variants/types/IProps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant?: 'primary' | 'secondary' | 'tertiary'; 6 | onClick?: () => void; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-year/ButtonYear.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import ButtonYear from './ButtonYear'; 3 | 4 | const meta = { 5 | title: 'ui/components/atoms/button-year', 6 | component: ButtonYear, 7 | argTypes: { 8 | onClick: { 9 | action: 'click', 10 | }, 11 | variant: { 12 | control: 'select', 13 | }, 14 | }, 15 | } as Meta; 16 | 17 | export default meta; 18 | 19 | type Story = StoryObj; 20 | 21 | export const Primary: Story = { 22 | args: { 23 | children: 'año', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-year/ButtonYear.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import ButtonYear from './ButtonYear'; 3 | 4 | describe('Testing ButtonWithVariants React Component', () => { 5 | test('should render test 1', () => { 6 | render(año); 7 | const buttonElement = screen.getByText('año'); 8 | expect(buttonElement).toBeInTheDocument(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-year/ButtonYear.tsx: -------------------------------------------------------------------------------- 1 | import styles from './ButtonYear.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function ButtonYear({ children, onClick }: IProps) { 5 | const variantClass = styles[`button-year`]; 6 | return ( 7 | 10 | ); 11 | } 12 | 13 | export default ButtonYear; 14 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button-year/types/IProps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | onClick?: () => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/button/styles.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .button { 5 | background: $ads-primary-main; 6 | border: 2px solid transparent; 7 | border-radius: 1.5rem; 8 | padding: 1.26rem; 9 | width: 100%; 10 | 11 | .button__icon--before { 12 | content: ''; 13 | display: inline-block; 14 | height: 16px; 15 | width: 16px; 16 | } 17 | 18 | @include respond-to('medium') { 19 | width: 80%; 20 | } 21 | 22 | @include respond-to('large') { 23 | width: 30%; 24 | } 25 | 26 | @include respond-to('extra-large') { 27 | width: 30%; 28 | } 29 | } 30 | 31 | .button:hover { 32 | background: $ads-secondary-main; 33 | } 34 | 35 | .button__label { 36 | color: $ads-color-main; 37 | font-size: $ads-size-main; 38 | margin-left: 1rem; 39 | margin-right: 1rem; 40 | } 41 | -------------------------------------------------------------------------------- /src/ui/components/atoms/check/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CheckIcon from '../../../../assets/icons/check.svg?react'; 3 | 4 | const icons: Record>> = { 5 | check: CheckIcon, 6 | }; 7 | 8 | interface IconProps { 9 | name: keyof typeof icons; 10 | className?: string; 11 | } 12 | 13 | function Icon({ name, className }: IconProps) { 14 | const SvgIcon = icons[name]; 15 | return ; 16 | } 17 | 18 | export default Icon; 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/check/types/IProps.ts: -------------------------------------------------------------------------------- 1 | type CheckboxVariant = 'default' | 'success' | 'info' | 'warning' | 'danger'; 2 | type CheckboxShape = 'circle' | 'square'; 3 | 4 | export interface CheckboxProps { 5 | checked: boolean; 6 | onChange: (value: boolean) => void; 7 | disabled?: boolean; 8 | variant?: CheckboxVariant; 9 | shape?: CheckboxShape; 10 | className?: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/components/atoms/close-download-button/CloseDownloadButton.tsx: -------------------------------------------------------------------------------- 1 | import styles from './CloseDownloadButton.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function CloseDownloadButton(props: IProps) { 6 | const { icon, onClick, color } = props; 7 | const colorFont = styles[color as keyof typeof styles]; 8 | 9 | return ( 10 | 17 | ); 18 | } 19 | export default CloseDownloadButton; 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/close-download-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | icon?: string; 6 | color?: 'primary' | 'secondary'; 7 | onClick?: () => void; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider-variables/DividerVariables.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import DividerVariables from './DividerVariables'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/atoms/divider-variables', 6 | component: DividerVariables, 7 | }; 8 | 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = {}; 14 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider-variables/DividerVariables.test.jsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import DividerVariables from './DividerVariables.tsx'; 3 | 4 | describe('DividerVariables', () => { 5 | test('renders the divider bar', () => { 6 | const { container } = render(); 7 | const divider = container.querySelector('.divider-bar'); 8 | expect(divider).toBeInTheDocument(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider-variables/DividerVariables.tsx: -------------------------------------------------------------------------------- 1 | import './styles.scss'; 2 | 3 | function DividerVariables() { 4 | return
; 5 | } 6 | 7 | export default DividerVariables; 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider-variables/styles.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .divider-bar { 5 | background-color: $ads-text-main; 6 | height: 7.813rem; 7 | width: 0.25rem; 8 | 9 | @include respond-to('small-mobile') { 10 | height: 6em; 11 | width: 0.25rem; 12 | } 13 | 14 | @include respond-to('small') { 15 | height: 6rem; 16 | width: 0.25rem; 17 | } 18 | 19 | @include respond-to('large-tablet') { 20 | height: 6rem; 21 | width: 0.25rem; 22 | } 23 | 24 | @include respond-to('large') { 25 | height: 6rem; 26 | width: 0.25rem; 27 | } 28 | 29 | @include respond-to('extra-large') { 30 | height: 7.813rem; 31 | width: 0.25rem; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider/Divider.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .divider--solid { 5 | border-style: solid; 6 | color: $ads-text-main; 7 | width: 85%; 8 | } 9 | 10 | .divider--solid:hover { 11 | color: $ads-text-main-alpha; 12 | } 13 | 14 | .divider--dotted { 15 | border-style: dotted; 16 | color: $ads-text-main; 17 | width: 85%; 18 | } 19 | 20 | .divider--dotted:hover { 21 | color: $ads-text-main-alpha; 22 | } 23 | 24 | .divider--dashed { 25 | border-style: dashed; 26 | color: $ads-text-main; 27 | width: 85%; 28 | } 29 | 30 | .divider--dashed:hover { 31 | color: $ads-text-main-alpha; 32 | } 33 | // 34 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider/Divider.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .divider--solid { 5 | border-style: solid; 6 | color: $ads-text-main; 7 | width: 85%; 8 | } 9 | 10 | .divider--solid:hover { 11 | color: $ads-text-main-alpha; 12 | } 13 | 14 | .divider--dotted { 15 | border-style: dotted; 16 | color: $ads-text-main; 17 | width: 85%; 18 | } 19 | 20 | .divider--dotted:hover { 21 | color: $ads-text-main-alpha; 22 | } 23 | 24 | .divider--dashed { 25 | border-style: dashed; 26 | color: $ads-text-main; 27 | width: 85%; 28 | } 29 | 30 | .divider--dashed:hover { 31 | color: $ads-text-main-alpha; 32 | } 33 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider/Divider.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Divider from './Divider'; 3 | 4 | const meta = { 5 | title: 'ui/components/atoms/divider', 6 | component: Divider, 7 | argTypes: { 8 | variant: { 9 | control: { type: 'select' }, 10 | options: ['solid', 'dotted', 'dashed'], 11 | }, 12 | }, 13 | } as Meta; 14 | 15 | export default meta; 16 | 17 | type Story = StoryObj; 18 | 19 | export const Solid: Story = { 20 | args: { 21 | variant: 'solid', 22 | }, 23 | }; 24 | 25 | export const Dotted: Story = { 26 | args: { 27 | variant: 'dotted', 28 | }, 29 | }; 30 | 31 | export const Dashed: Story = { 32 | args: { 33 | variant: 'dashed', 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider/Divider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Divider.module.scss'; // Importamos los estilos como CSS Modules 3 | import type { IProps } from './types/IProps'; 4 | 5 | function Divider(props: IProps) { 6 | const { variant } = props; 7 | const variantClass = `divider--${variant}`; // Convertimos el variant a BEM 8 | return
; 9 | } 10 | 11 | export default Divider; 12 | -------------------------------------------------------------------------------- /src/ui/components/atoms/divider/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | variant: 'solid' | 'dotted' | 'dashed'; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/components/atoms/error-message/ErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | import styles from './ErrorMessage.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function ErrorMessage(props: IProps) { 5 | const { code, title, message, redirectTo, linkText, messageinit, messagefinish } = props; 6 | const isServerError = code === 500; 7 | 8 | return ( 9 |
10 |

{code}

11 |

{title}

12 |

{message}

13 |

14 | {messageinit} 15 | 16 | {linkText} 17 | 18 | {messagefinish} 19 |

20 |
21 | ); 22 | } 23 | 24 | export default ErrorMessage; 25 | -------------------------------------------------------------------------------- /src/ui/components/atoms/error-message/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | code: number; 3 | title: string; 4 | message: string; 5 | redirectTo: string; 6 | linkText?: string; 7 | messageinit?: string; 8 | messagefinish?: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/HeroBanner.tsx: -------------------------------------------------------------------------------- 1 | import styles from './HeroBanner.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function HeroBanner({ backgroundImage, alt, children, className }: IProps) { 5 | return ( 6 |
7 | {alt} 8 |
9 |
{children}
10 |
11 |
12 | ); 13 | } 14 | 15 | export default HeroBanner; 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle10.png -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle11.png -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle12.png -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle17.png -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/hero-banner/__mock__/imgs/Rectangle6.png -------------------------------------------------------------------------------- /src/ui/components/atoms/hero-banner/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | backgroundImage: string; 5 | alt?: string; 6 | children: React.ReactNode; 7 | className: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/atoms/icon-button/IconButton.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .button__share { 5 | background: $ads-primary-main; 6 | border: none; 7 | height: 2.8rem; 8 | padding: 0.1rem; 9 | width: 3rem; 10 | 11 | @include respond-to('small') { 12 | height: 2rem; 13 | width: 2rem; 14 | } 15 | 16 | @include respond-to('medium') { 17 | height: 3rem; 18 | width: 2.5rem; 19 | } 20 | 21 | @include respond-to('large') { 22 | height: 4rem; 23 | width: 4rem; 24 | } 25 | 26 | @include respond-to('extra-large') { 27 | height: 6rem; 28 | width: 5.2rem; 29 | } 30 | } 31 | 32 | .button__icons svg { 33 | display: flexbox; 34 | height: 80%; 35 | width: 80%; 36 | } 37 | 38 | .button__share:hover { 39 | background: $ads-secondary-main; 40 | } 41 | -------------------------------------------------------------------------------- /src/ui/components/atoms/icon-button/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import './IconButton.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function IconButton(props: IProps) { 6 | const { icon, color } = props; 7 | const colorFont = `logo--${color as string}`; 8 | return ( 9 | 12 | ); 13 | } 14 | export default IconButton; 15 | -------------------------------------------------------------------------------- /src/ui/components/atoms/icon-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | variant?: string; 6 | icon?: string; 7 | color?: 'primary' | 'secondary'; 8 | onClick?: () => void; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/atoms/icon-upload/IconUpload.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj } from '@storybook/react'; 2 | import IconUpload from './IconUpload'; 3 | import icon_upload_default from '../../../../assets/icons/icon-upload-default.svg?raw'; 4 | import icon_upload_primary from '../../../../assets/icons/icon-upload-primary.svg?raw'; 5 | 6 | const meta = { 7 | title: 'ui/components/atoms/icon-upload', 8 | component: IconUpload, 9 | argTypes: { 10 | onClick: { 11 | action: 'click', 12 | }, 13 | }, 14 | }; 15 | 16 | export default meta; 17 | 18 | type Story = StoryObj; 19 | 20 | export const Default: Story = { 21 | args: { 22 | children: 'icon_upload_default', 23 | icon: icon_upload_default, 24 | }, 25 | }; 26 | 27 | export const Primary: Story = { 28 | args: { 29 | children: 'icon_upload_primary', 30 | icon: icon_upload_primary, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /src/ui/components/atoms/icon-upload/IconUpload.tsx: -------------------------------------------------------------------------------- 1 | import styles from './IconUpload.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function IconUpload(props: IProps) { 6 | const { icon, onClick } = props; 7 | 8 | return ( 9 | 14 | ); 15 | } 16 | 17 | export default IconUpload; 18 | -------------------------------------------------------------------------------- /src/ui/components/atoms/icon-upload/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | icon?: string; 6 | onClick?: () => void; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/input-country/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface Option { 2 | country: string; 3 | code: string; 4 | } 5 | 6 | export interface IProps { 7 | label?: string; 8 | options: Option[]; 9 | error?: boolean; 10 | helperText: string; 11 | disabled?: boolean; 12 | borderRadius?: 'normal' | 'semi' | 'circle'; 13 | size?: 'small' | 'medium' | 'large'; 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/components/atoms/input-text/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | id: string; 3 | label: string; 4 | type: 'email' | 'password' | 'text'; 5 | name: string; 6 | placeholder?: string; 7 | value: string; 8 | isValid: boolean; 9 | eyeIcon?: string; 10 | onChangeValue: (value: { value: string }) => void; 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-articles/LabelArticles.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import '../../../../globals/_variables.scss'; 3 | import LabelArticles from './LabelArticles'; 4 | 5 | const meta = { 6 | title: 'ui/components/atoms/label-articles', 7 | component: LabelArticles, 8 | argTypes: { 9 | children: { control: 'text' }, 10 | variant: { 11 | control: 'select', 12 | options: ['primary', 'secondary'], 13 | }, 14 | }, 15 | } as Meta; 16 | 17 | export default meta; 18 | 19 | type Story = StoryObj; 20 | 21 | export const Default: Story = { 22 | args: { 23 | children: 'ARTÍCULOS', 24 | variant: 'default', 25 | }, 26 | }; 27 | 28 | export const Primary: Story = { 29 | args: { 30 | children: 'ARTÍCULOS', 31 | variant: 'primary', 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-articles/LabelArticles.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import LabelArticles from './LabelArticles.tsx'; 3 | 4 | describe('Testing LabelArticles React Component', () => { 5 | test('should render with default props', () => { 6 | render(ARTÍCULOS); 7 | const labelElement = screen.getByText(/Artículos/i); 8 | expect(labelElement).toBeInTheDocument(); 9 | }); 10 | 11 | test('should render with a different child', () => { 12 | render(Different Child); 13 | const labelElement = screen.getByText(/Different Child/i); 14 | expect(labelElement).toBeInTheDocument(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-articles/LabelArticles.tsx: -------------------------------------------------------------------------------- 1 | import './LabelArticles.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function LabelArticles(props: IProps) { 5 | const { children, variant } = props; 6 | return ( 7 | 10 | ); 11 | } 12 | 13 | export default LabelArticles; 14 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-articles/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-date/LabelDate.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/breakpoints'; 2 | @import '../../../../globals/fonts'; 3 | @import '../../../../globals/mixins'; 4 | @import '../../../../globals/variables'; 5 | 6 | .labeldate { 7 | color: $ads-text-secondary; 8 | font-family: Lato, Arial, Helvetica, sans-serif; 9 | font-size: $ads-font-size-sixth; 10 | font-weight: $ads-font-size-first; 11 | line-height: $ads-line-height-default; 12 | width: fit-content; 13 | 14 | &:hover { 15 | color: $ads-text-main-hover; 16 | } 17 | 18 | @include respond-to('small') { 19 | font-size: 1rem; 20 | } 21 | 22 | @include respond-to('medium') { 23 | font-size: $ads-font-size-sixth; 24 | } 25 | 26 | @include respond-to('large') { 27 | font-size: 1rem; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-date/LabelDate.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/breakpoints'; 2 | @import '../../../../globals/fonts'; 3 | @import '../../../../globals/mixins'; 4 | @import '../../../../globals/variables'; 5 | 6 | .labeldate { 7 | color: $ads-text-secondary; 8 | font-family: Lato, Arial, Helvetica, sans-serif; 9 | font-size: $ads-font-size-sixth; 10 | font-weight: $ads-font-size-first; 11 | line-height: $ads-line-height-default; 12 | width: fit-content; 13 | 14 | &:hover { 15 | color: $ads-text-main-hover; 16 | } 17 | 18 | @include respond-to('small') { 19 | font-size: 1rem; 20 | } 21 | 22 | @include respond-to('medium') { 23 | font-size: $ads-font-size-sixth; 24 | } 25 | 26 | @include respond-to('large') { 27 | font-size: 1rem; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-date/LabelDate.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import LabelDate from './LabelDate'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/atoms/label-date', 6 | component: LabelDate, 7 | argTypes: { 8 | date: { control: 'date' }, 9 | overflow: { control: 'boolean' }, 10 | }, 11 | }; 12 | export default meta; 13 | 14 | type Story = StoryObj; 15 | 16 | const createStory = (date: Date, overflow?: boolean): Story => ({ 17 | render: (args) => , 18 | args: { 19 | date, 20 | overflow, 21 | }, 22 | }); 23 | 24 | export const LabelDate1 = createStory(new Date(2001, 0, 1)); 25 | export const LabelDate2 = createStory(new Date(2018, 3, 30)); 26 | export const LabelDate3 = createStory(new Date(2022, 11, 20)); 27 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-date/LabelDate.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { IProps } from './types/IProps'; 3 | import { formatDate } from './utils/dateFormatter'; 4 | import styles from './LabelDate.module.scss'; 5 | 6 | function LabelDate({ date, overflow = false }: IProps) { 7 | if (!(date instanceof Date)) { 8 | return null; 9 | } 10 | const formattedDate = formatDate(date); 11 | const isoDate = date.toISOString().split('T')[0]; 12 | const className = `${styles.labeldate}${overflow ? ` ${styles['labeldate--overflow']}` : ''}`; 13 | return ( 14 |

15 | {formattedDate} 16 |

17 | ); 18 | } 19 | 20 | export default LabelDate; 21 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-date/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | date: Date; 3 | overflow?: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-date/utils/dateFormatter.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: Date): string => { 2 | const month = date.toLocaleString('es-ES', { month: 'long' }); 3 | const capitalizedMonth = month.charAt(0).toUpperCase() + month.slice(1); 4 | const day = date.getDate().toString(); 5 | const year = date.getFullYear().toString(); 6 | return `${capitalizedMonth} ${day} | ${year}`; 7 | }; 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-featured-articles/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | ColorVariant?: 'main' | 'primary' | 'secondary'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-recent-articles/LabelRecentsArticles.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .label-recents-articles { 5 | background-color: $ads-background-main; 6 | display: inline-block; 7 | font-family: Montserrat, sans-serif; 8 | font-size: 1.875rem; 9 | font-weight: $ads-font-weight-second; 10 | padding: 0.625rem 1.25rem; 11 | 12 | &--primary { 13 | color: $ads-secondary-main; 14 | } 15 | 16 | &--secondary { 17 | color: $ads-primary-main; 18 | } 19 | 20 | @include respond-to('small') { 21 | font-size: 1.5rem; 22 | padding: 0.5rem 1rem; 23 | } 24 | 25 | @include respond-to('medium') { 26 | font-size: 1.75rem; 27 | padding: 0.625rem 1.25rem; 28 | } 29 | 30 | @include respond-to('large') { 31 | font-size: 1.875rem; 32 | padding: 0.625rem 1.25rem; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-recent-articles/LabelRecentsArticles.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import '../../../../globals/_variables.scss'; 3 | import LabelRecentsArticles from './LabelRecentsArticles'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/atoms/label-recent-articles', 7 | component: LabelRecentsArticles, 8 | }; 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Primary: Story = { 14 | args: { 15 | text: 'ARTICULOS MAS RECIENTES', 16 | color: 'primary', 17 | }, 18 | }; 19 | 20 | export const Secundary: Story = { 21 | args: { 22 | text: 'ARTICULOS MAS RECIENTES', 23 | color: 'secondary', 24 | }, 25 | }; 26 | 27 | export const Tertiary: Story = { 28 | args: { 29 | text: 'ARTICULOS MAS RECIENTES', 30 | color: 'tertiary', 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-recent-articles/LabelRecentsArticles.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import styles from './LabelRecentsArticles.module.scss'; 3 | 4 | function LabelRecentsArticles(props: IProps) { 5 | const { text, color = 'primary' } = props; 6 | const colorText = styles[`label-recents-articles--${color}`]; 7 | 8 | return ( 9 |
10 | {text} 11 |
12 | ); 13 | } 14 | 15 | export default LabelRecentsArticles; 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-recent-articles/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | color?: 'primary' | 'secondary' | 'tertiary'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-ref/LabelRef.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import LabelRef from './LabelRef'; 3 | 4 | describe('Testing LabelRef React Component', () => { 5 | test('should render with default text', () => { 6 | render(REFERENCIAS); 7 | const labelElement = screen.getByText(/REFERENCIAS/i); 8 | expect(labelElement).toBeInTheDocument(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-ref/LabelRef.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './LabelRef.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function LabelRef(props: IProps) { 6 | const { children, variant = 'default' } = props; 7 | return ( 8 |
9 |

R

10 |

{children}

11 |
12 | ); 13 | } 14 | 15 | export default LabelRef; 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-ref/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant: 'default' | 'secondary'; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-references/LabelReferences.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import LabelReferences from './LabelReferences'; 3 | import '../../../../globals/_variables.scss'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/atoms/label-references', 7 | component: LabelReferences, 8 | argTypes: { 9 | text: { control: 'text' }, 10 | colorVariant: { control: { type: 'select', options: ['primary', 'main'] } }, 11 | }, 12 | }; 13 | 14 | export default meta; 15 | 16 | type Story = StoryObj; 17 | 18 | export const Default: Story = { 19 | args: { 20 | text: 'Referencias', 21 | }, 22 | }; 23 | 24 | export const Primary: Story = { 25 | args: { 26 | colorVariant: 'main', 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-references/LabelReferences.tsx: -------------------------------------------------------------------------------- 1 | import styles from './LabelReferences.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function LabelReferences({ text = 'Referencias', colorVariant = 'primary' }: IProps) { 5 | const getColorClassName = () => { 6 | return colorVariant === 'main' 7 | ? styles['label-references--main'] 8 | : styles['label-references--primary']; 9 | }; 10 | 11 | return ( 12 |
13 | {text} 14 |
15 | ); 16 | } 17 | 18 | export default LabelReferences; 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-references/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | colorVariant?: 'primary' | 'main'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-resources-page/LabelResourcesPage.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import LabelResourcesPage from './LabelResourcesPage'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/atoms/lavel-resources-page', 6 | component: LabelResourcesPage, 7 | }; 8 | export default meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const RECURSOS: Story = { 13 | args: { 14 | text: 'RECURSOS ', 15 | }, 16 | }; 17 | export const PAGINA: Story = { 18 | args: { 19 | text: 'PAGINA', 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-resources-page/LabelResourcesPage.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import LabelResourcesPage from './LabelResourcesPage.tsx'; 3 | 4 | describe('LabelResourcesPage', () => { 5 | test('renders the text correctly', () => { 6 | render(); 7 | const labelText = screen.getByText('RECURSOS'); 8 | expect(labelText).toBeInTheDocument(); 9 | }); 10 | 11 | test('applies the correct styles', () => { 12 | render(); 13 | const labelText = screen.getByText('PAGINA'); 14 | expect(labelText).toHaveClass('text'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-resources-page/LabelResourcesPage.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import './styles.scss'; 3 | 4 | function LabelResourcesPage(props: IProps) { 5 | const { text } = props; 6 | 7 | return ( 8 |
9 | {text} 10 |
11 | ); 12 | } 13 | 14 | export default LabelResourcesPage; 15 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-resources-page/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-share/Share.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Share from './Share'; 3 | import '../../../../globals/_variables.scss'; 4 | import share from '../../../../assets/icons/share.svg?raw'; 5 | 6 | const meta: Meta = { 7 | title: 'ui/components/atoms/label-share', 8 | component: Share, 9 | argTypes: { 10 | text: { control: 'text' }, 11 | colorVariant: { control: { type: 'select', options: ['primary', 'main'] } }, 12 | }, 13 | }; 14 | 15 | export default meta; 16 | 17 | type Story = StoryObj; 18 | 19 | export const Default: Story = { 20 | args: { 21 | text: 'Compatir', 22 | icon: share, 23 | }, 24 | }; 25 | 26 | export const Primary: Story = { 27 | args: { 28 | colorVariant: 'main', 29 | icon: share, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-share/Share.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import Share from './Share'; 3 | import share from '../../../../assets/icons/share.svg?raw'; 4 | 5 | describe('Testing Share React Component', () => { 6 | test('should render Compartir', () => { 7 | render(); 8 | const labelElement = screen.getByText(/Compartir/i); 9 | expect(labelElement).toBeInTheDocument(); 10 | }); 11 | 12 | test('should render icon for Compartir', () => { 13 | render(); 14 | const iconElement = screen.getByTestId('share-icon'); 15 | expect(iconElement).toBeInTheDocument(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-share/Share.tsx: -------------------------------------------------------------------------------- 1 | import styles from './Share.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function Share({ text = 'Compartir', colorVariant = 'primary', icon }: IProps) { 6 | const colorFont = 7 | colorVariant === 'main' ? styles['label-share--main'] : styles['label-share--primary']; 8 | 9 | return ( 10 |
11 | {icon && } 12 | {text} 13 |
14 | ); 15 | } 16 | 17 | export default Share; 18 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-share/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | colorVariant?: 'primary' | 'main'; 4 | icon: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-variables/Variables.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Variables from './Variables'; 3 | import '../../../../globals/_variables.scss'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/atoms/label-variables', 7 | component: Variables, 8 | argTypes: { 9 | colorVariant: { control: { type: 'select', options: ['primary', 'main', 'secondary'] } }, 10 | }, 11 | }; 12 | 13 | export default meta; 14 | 15 | type Story = StoryObj; 16 | 17 | export const Default: Story = { 18 | args: {}, 19 | }; 20 | 21 | export const Volumenes: Story = { 22 | args: { 23 | colorVariant: 'main', 24 | text: 'VOLÚMENES', 25 | }, 26 | }; 27 | 28 | export const Enlace: Story = { 29 | args: { 30 | colorVariant: 'secondary', 31 | text: 'UNIPOL.EDU.BO', 32 | href: 'https://www.unipol.edu.bo', 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-variables/Variables.tsx: -------------------------------------------------------------------------------- 1 | import './styles.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | const colorClassNames: Record = { 5 | main: 'variables--main', 6 | secondary: 'variables--secondary', 7 | default: 'variables--primary', 8 | }; 9 | 10 | function Variables({ text = 'ARTICULOS', colorVariant = 'primary', href }: IProps) { 11 | const className = colorClassNames[colorVariant] || colorClassNames.default; 12 | 13 | return ( 14 |
15 | {href ? ( 16 | 17 | {text} 18 | 19 | ) : ( 20 | {text} 21 | )} 22 |
23 | ); 24 | } 25 | 26 | export default Variables; 27 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-variables/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | colorVariant?: 'primary' | 'main' | 'secondary'; 4 | href?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-vol/LabelVol.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/breakpoints'; 2 | @import '../../../../globals/mixins'; 3 | @import '../../../../globals/variables'; 4 | 5 | .volumen { 6 | color: $ads-text-main; 7 | font-family: Arial, Helvetica, sans-serif; 8 | font-size: $ads-size-main; 9 | font-weight: $ads-font-weight; 10 | width: fit-content; 11 | 12 | &:hover { 13 | color: $ads-text-main-hover; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-vol/LabelVol.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Volumen from './LabelVol'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/atoms/volumen-id', 6 | component: Volumen, 7 | argTypes: {}, 8 | }; 9 | 10 | export default meta; 11 | 12 | type Story = StoryObj; 13 | const createStory = (id: number, synonym: string): Story => ({ 14 | render: (args) => , 15 | args: { 16 | volumen: synonym, 17 | id, 18 | }, 19 | }); 20 | 21 | export const Vol1 = createStory(1, 'Vol.'); 22 | export const Vol2 = createStory(2, 'Tome.'); 23 | export const Vol3 = createStory(3, 'Part.'); 24 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-vol/LabelVol.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import Volumen from './LabelVol.tsx'; 3 | 4 | describe('Testing React Label Volument Component', () => { 5 | test('Must Render Volume 1', () => { 6 | render(); 7 | const volumenElement = screen.getByText('Vol. 1'); 8 | expect(volumenElement).toBeInTheDocument(); 9 | }); 10 | test('Must Render Tome 2', () => { 11 | render(); 12 | const volumenElement = screen.getByText('Tome. 2'); 13 | expect(volumenElement).toBeInTheDocument(); 14 | }); 15 | test('Must Render Part 3', () => { 16 | render(); 17 | const volumenElement = screen.getByText('Part. 3'); 18 | expect(volumenElement).toBeInTheDocument(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-vol/LabelVol.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import style from './LabelVol.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function Volumen({ volumen, id }: IProps) { 6 | return ( 7 |

8 | {volumen} {id} 9 |

10 | ); 11 | } 12 | export default Volumen; 13 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-vol/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | volumen: string; 3 | id: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-volumes/LabelVolumes.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import '../../../../globals/_variables.scss'; 3 | import LabelVolumes from './LabelVolumes'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/atoms/label-volumes', 7 | component: LabelVolumes, 8 | }; 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = { 14 | args: { 15 | text: 'VOLÚMENES', 16 | color: 'primary', 17 | }, 18 | }; 19 | 20 | export const OptionSecond: Story = { 21 | args: { 22 | text: 'VOLÚMENES', 23 | color: 'secondary', 24 | }, 25 | }; 26 | 27 | export const OptionTertiary: Story = { 28 | args: { 29 | text: 'VOLÚMENES', 30 | color: 'tertiary', 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-volumes/LabelVolumes.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import LabelVolumes from './LabelVolumes.tsx'; 3 | 4 | describe('LabelVolumes Component', () => { 5 | test('Should display the correct text', () => { 6 | render(); 7 | expect(screen.getByText('VOLÚMENES')).toBeInTheDocument(); 8 | }); 9 | 10 | test('Should render the provided text', () => { 11 | render(); 12 | expect(screen.getByText('CUSTOM TEXT')).toBeInTheDocument(); 13 | }); 14 | 15 | test('Should apply the correct CSS class', () => { 16 | render(); 17 | const labelElement = screen.getByTestId('label-volumes-text'); 18 | expect(labelElement).toBeInTheDocument(); 19 | expect(labelElement).toHaveTextContent('VOLÚMENES'); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-volumes/LabelVolumes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './LabelVolumes.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function LabelVolumes({ text, color = 'primary' }: IProps) { 6 | const colorText = styles[`label-volumes__text--${color}`]; 7 | 8 | return ( 9 |
13 | {text} 14 |
15 | ); 16 | } 17 | 18 | export default LabelVolumes; 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/label-volumes/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | color?: 'primary' | 'secondary' | 'tertiary'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo-footer/LogoFooter.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .logo-icon svg { 5 | height: 4.5rem; 6 | width: 11.875rem; 7 | } 8 | 9 | .logo { 10 | display: grid; 11 | height: 4.5rem; 12 | width: 11.875rem; 13 | 14 | &.primary { 15 | background-color: $ads-tertiary-main; 16 | } 17 | 18 | &.secondary { 19 | background-color: $ads-background-main; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo-footer/LogoFooter.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import '../../../../globals/_variables.scss'; 3 | import logo from '../../../../assets/icons/logo.svg?raw'; 4 | import LogoFooter from './LogoFooter'; 5 | 6 | const meta: Meta = { 7 | title: 'ui/components/atoms/logo-footer', 8 | component: LogoFooter, 9 | }; 10 | export default meta; 11 | 12 | type Story = StoryObj; 13 | 14 | export const Primary: Story = { 15 | args: { 16 | icon: logo, 17 | color: 'primary', 18 | }, 19 | }; 20 | 21 | export const Secundary: Story = { 22 | args: { 23 | icon: logo, 24 | color: 'secondary', 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo-footer/LogoFooter.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import logo from '../../../../assets/icons/logo.svg?raw'; 3 | import LogoFooter from './LogoFooter'; 4 | 5 | describe('Testing LogoFooter React Component', () => { 6 | test('should be rendere logo', () => { 7 | render(); 8 | const buttonElement = screen.getByTestId('logo_icon'); 9 | expect(buttonElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo-footer/LogoFooter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './LogoFooter.module.scss'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | import type { IProps } from './types/IProps'; 5 | 6 | function LogoFooter({ icon, color }: IProps) { 7 | const colorFont = color === 'secondary' ? styles['logo--secondary'] : ''; 8 | 9 | return ( 10 |
11 | {icon && } 12 |
13 | ); 14 | } 15 | 16 | export default LogoFooter; 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo-footer/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | icon?: string; 3 | color?: 'primary' | 'secondary'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo/logo.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Logo from './logo'; 3 | import '../../../../globals/_variables.scss'; 4 | import image from '../../../../assets/icons/logo.svg'; 5 | 6 | const logoImage = image as unknown as string; 7 | 8 | const meta: Meta = { 9 | title: 'ui/components/atoms/logo', 10 | component: Logo, 11 | }; 12 | 13 | export default meta; 14 | 15 | type Story = StoryObj; 16 | 17 | export const Default: Story = { 18 | args: { 19 | src: logoImage, 20 | variant: 'default', 21 | }, 22 | }; 23 | 24 | export const Primary: Story = { 25 | args: { 26 | src: logoImage, 27 | variant: 'primary', 28 | }, 29 | }; 30 | 31 | export const Secondary: Story = { 32 | args: { 33 | src: logoImage, 34 | variant: 'secondary', 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo/logo.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import Logo from './logo.tsx'; // Adjust the import to your actual file structure 3 | import logoImage from '../../../../assets/icons/logo.svg'; // Adjust the import to your actual file structure 4 | 5 | test('should render the logo image', () => { 6 | render(); 7 | const logoElement = screen.getByRole('img', { name: /Logotipo de la empresa/i }); 8 | expect(logoElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo/logo.tsx: -------------------------------------------------------------------------------- 1 | import styles from './logo.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function Logo(props: IProps) { 5 | const { src, alt, variant = 'primary' } = props; 6 | const colorClass = `logo-container--${variant}`; 7 | 8 | return ( 9 |
10 |
11 | {alt} 12 |
13 |
14 |
15 | ); 16 | } 17 | 18 | export default Logo; 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/logo/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | src?: string; 6 | text?: string; 7 | alt?: string; 8 | variant: 'default' | 'primary' | 'secondary'; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/atoms/main-input/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | label: string; 5 | placeholder: string; 6 | value: string; 7 | onChange: (e: React.ChangeEvent) => void; 8 | leftIcon?: React.ReactNode; 9 | rightIcon?: React.ReactNode; 10 | hint?: string; 11 | error?: string; 12 | disabled?: boolean; 13 | } 14 | -------------------------------------------------------------------------------- /src/ui/components/atoms/multi-function-button/MultiFunctionButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './MultiFunctionButton.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | import { Icon } from '../../../utils/svg-icons/icons'; 5 | 6 | function MultiFunctionButton(props: IProps) { 7 | const { icon, onClick, color = 'primary' } = props; 8 | const colorFont = `${styles['variable-button']}--${color as string}`; 9 | return ( 10 | 17 | ); 18 | } 19 | 20 | export default MultiFunctionButton; 21 | -------------------------------------------------------------------------------- /src/ui/components/atoms/multi-function-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | icon?: string; 6 | onClick?: () => void; 7 | color?: 'primary' | 'secondary'; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/atoms/navbar/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import './styles.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function Button(props: IProps) { 6 | const { children, icon } = props; 7 | return ( 8 |
9 | 13 |
14 | ); 15 | } 16 | export default Button; 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/navbar/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | icon?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/ol-bullet/OLBullet.tsx: -------------------------------------------------------------------------------- 1 | import styles from './OLBullet.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function OLBullet(props: IProps) { 5 | const { shape = 'square', size = 'md', active = false } = props; 6 | 7 | const bulletClass = ` 8 | ${styles['ol-bullet']} 9 | ${styles[`ol-bullet--${shape}`]} 10 | ${styles[`ol-bullet--${size}`]} 11 | ${active ? styles['ol-bullet--active'] : ''} 12 | `.trim(); 13 | 14 | return ; 15 | } 16 | 17 | export default OLBullet; 18 | -------------------------------------------------------------------------------- /src/ui/components/atoms/ol-bullet/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | shape?: 'square' | 'rounded' | 'circle'; 3 | size?: 'sm' | 'md' | 'lg'; 4 | active?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/atoms/ol-item/OLItem.tsx: -------------------------------------------------------------------------------- 1 | import styles from './OLItem.module.scss'; 2 | import type { OLItemProps } from './types/IProps'; 3 | 4 | function OLItem({ value, shape = 'square', size = 'md', active = false }: OLItemProps) { 5 | const olItemClass = ` 6 | ${styles['ol-item']} 7 | ${styles[`ol-item--${shape}`]} 8 | ${styles[`ol-item--${size}`]} 9 | ${active ? styles['ol-item--active'] : ''} 10 | `.trim(); 11 | 12 | return ( 13 |
14 | {value} 15 |
16 | ); 17 | } 18 | 19 | export default OLItem; 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/ol-item/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface OLItemProps { 2 | value: number | string; 3 | shape?: 'square' | 'rounded' | 'circle'; 4 | size?: 'sm' | 'md' | 'lg'; 5 | active?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/phone-input/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | value: string; 3 | onChange: (value: string) => void; 4 | placeholder?: string; 5 | label?: string; 6 | variant?: 'default' | 'focus' | 'error' | 'disabled'; 7 | size?: 'small' | 'medium' | 'large'; 8 | borderRadius?: 'none' | 'small' | 'full'; 9 | showCloseIcon?: boolean; 10 | onCloseClick?: () => void; 11 | onCopyClick?: () => void; 12 | showHintText?: boolean; 13 | hintText?: string; 14 | className?: string; 15 | 16 | // Nuevo: Código de país 17 | countryCode?: string; // Ej: "+591" 18 | onCountryChange?: (code: string) => void; 19 | } 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/phone-input/types/countryCodes.ts: -------------------------------------------------------------------------------- 1 | export const countryCodes = [ 2 | { code: '+1', name: 'Estados Unidos' }, 3 | { code: '+54', name: 'Argentina' }, 4 | { code: '+55', name: 'Brasil' }, 5 | { code: '+591', name: 'Bolivia' }, 6 | { code: '+34', name: 'España' }, 7 | ]; 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/points-divider/PointsDivider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './PointsDivider.module.scss'; 3 | import type { DividerProps } from './types/IProps'; 4 | 5 | function PointsDivider(props: DividerProps) { 6 | const { color = 'primary', size = 'small', variant = 'solid' } = props; 7 | 8 | return ( 9 |
14 | {variant === 'points' && ( 15 | <> 16 | 17 | 18 | 19 | 20 | )} 21 |
22 | ); 23 | } 24 | 25 | export default PointsDivider; 26 | -------------------------------------------------------------------------------- /src/ui/components/atoms/points-divider/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface DividerProps { 2 | color?: 'primary' | 'secondary' | 'tertiary'; 3 | size?: 'small' | 'medium' | 'large'; 4 | variant?: 'solid-line' | 'segmented-line' | 'points'; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/atoms/primary-buttons/PrimaryButtons.tsx: -------------------------------------------------------------------------------- 1 | import styles from './PrimaryButtons.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function PrimaryButtons(props: IProps) { 5 | const { children, variant, onClick } = props; 6 | const buttonClass = `${styles['buttons-primary__button']} ${ 7 | styles[`buttons-primary__button--${variant}`] 8 | }`; 9 | const labelClass = styles['buttons-primary__label']; 10 | return ( 11 |
12 | 15 |
16 | ); 17 | } 18 | export default PrimaryButtons; 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/primary-buttons/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant: 'primary' | 'secondary' | 'tertiary'; 6 | onClick?: () => void; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/publish-button/PublishButton.tsx: -------------------------------------------------------------------------------- 1 | import styles from './PublishButton.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function PublishButton(props: IProps) { 5 | const { children, variant, onClick } = props; 6 | return ( 7 |
8 | 16 |
17 | ); 18 | } 19 | export default PublishButton; 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/publish-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant: 'primary' | 'secondary' | 'tertiary' | 'warning' | 'danger'; 6 | onClick?: () => void; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/reference-information/Reference.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import ReferenceAPA from './Reference.tsx'; 3 | 4 | describe('Testing ReferenceAPA React Component', () => { 5 | test('should render with correct reference', () => { 6 | const referenceText = 7 | '1 A. Gessain, E. Nakoune, Y. Yazdanpanah, Monkeypox. N. Engl. J. Med. 387, 1783–1793 (2022)'; 8 | render(); 9 | const referenceElement = screen.getByText(referenceText); 10 | expect(referenceElement).toBeInTheDocument(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/ui/components/atoms/reference-information/_mocked/references.json: -------------------------------------------------------------------------------- 1 | { 2 | "pnasUrl": "https://www.pnas.org/doi/10.1073/pnas.2301662120#body-ref-r1", 3 | "nejmUrl": "https://www.nejm.org/doi/10.1056/NEJMra2208860", 4 | "pubmedUrl": "https://pubmed.ncbi.nlm.nih.gov/36286263/", 5 | "googleScholarUrl": "https://scholar.google.com/scholar_lookup?title=Monkeypox&author=A.+Gessain" 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/reference-information/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | color?: 'primary' | 'secondary' | 'tertiary'; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/shadow-card/ShadowCard.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react'; 2 | import React from 'react'; 3 | import ShadowsDemo from '../../../../Shadows/ShadowsDemo'; 4 | 5 | const meta: Meta = { 6 | title: 'Design System/Shadows', 7 | component: ShadowsDemo, 8 | }; 9 | 10 | export default meta; 11 | type Story = StoryObj; 12 | 13 | export const AllShadows: Story = { 14 | render: () => , 15 | }; 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/social-media-button/Button.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Button from './Button'; 3 | import Facebook from '../../../../assets/icons/facebook.svg?raw'; 4 | import Google from '../../../../assets/icons/google.svg?raw'; 5 | 6 | const meta = { 7 | title: 'ui/components/atoms/social-media-button', 8 | component: Button, 9 | argTypes: { 10 | onClick: { 11 | action: 'click', 12 | }, 13 | }, 14 | } as Meta; 15 | 16 | export default meta; 17 | 18 | type Story = StoryObj; 19 | 20 | export const Primary: Story = { 21 | args: { 22 | children: 'Google', 23 | icon: Google, 24 | }, 25 | }; 26 | 27 | export const Secondary: Story = { 28 | args: { 29 | children: 'Facebook', 30 | icon: Facebook, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /src/ui/components/atoms/social-media-button/Button.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import Facebook from '../../../../assets/icons/facebook.svg?raw'; 3 | import Google from '../../../../assets/icons/google.svg?raw'; 4 | import Button from './Button.tsx'; 5 | 6 | describe('Testing Button React Component', () => { 7 | test('should be rendere Google', () => { 8 | render(); 9 | const buttonElement = screen.getByText(/Google/i); 10 | expect(buttonElement).toBeInTheDocument(); 11 | }); 12 | 13 | test('should be rendere Facebook', () => { 14 | render(); 15 | const buttonElement = screen.getByText(/Facebook/i); 16 | expect(buttonElement).toBeInTheDocument(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/social-media-button/Button.tsx: -------------------------------------------------------------------------------- 1 | import styles from './Button.module.scss'; 2 | import { Icon } from '../../../utils/svg-icons/icons'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function SMButton(props: IProps) { 6 | const { children, icon, color } = props; 7 | const colorFont = styles[`button--${color as string}`]; 8 | return ( 9 | 15 | ); 16 | } 17 | export default SMButton; 18 | -------------------------------------------------------------------------------- /src/ui/components/atoms/social-media-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | variant?: string; 6 | icon?: string; 7 | color?: 'primary' | 'secondary'; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/atoms/start-button/StartButton.tsx: -------------------------------------------------------------------------------- 1 | import './StartButton.scss'; 2 | import { Icon } from '../../../utils/svg-icons/icons'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function StartButton(props: IProps) { 6 | const { children, icon, variant = 'primary' } = props; 7 | 8 | return ( 9 | 13 | ); 14 | } 15 | 16 | export default StartButton; 17 | -------------------------------------------------------------------------------- /src/ui/components/atoms/start-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | children?: string; 3 | variant?: 'primary' | 'secondary' | 'tertiary'; 4 | icon?: string | null; 5 | onClick?: () => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/atoms/text-field/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import SearchIcon from '../../../../assets/icons/search.svg?react'; 3 | import ErrorIcon from '../../../../assets/icons/error.svg?react'; 4 | 5 | const icons: Record>> = { 6 | search: SearchIcon, 7 | error: ErrorIcon, 8 | }; 9 | 10 | interface IconProps { 11 | name: keyof typeof icons; 12 | className?: string; 13 | } 14 | 15 | function Icon({ name, className }: IconProps): JSX.Element { 16 | const SvgIcon = icons[name]; 17 | return ; 18 | } 19 | 20 | export default Icon; 21 | -------------------------------------------------------------------------------- /src/ui/components/atoms/text-field/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export interface ITextFieldProps { 4 | label?: string; 5 | value: string; 6 | onChange: (val: string) => void; 7 | placeholder?: string; 8 | error?: boolean; 9 | helperText?: string; 10 | disabled?: boolean; 11 | leftIcon?: ReactNode; 12 | rightIcon?: ReactNode; 13 | size?: 'small' | 'medium' | 'large'; 14 | className?: string; 15 | type?: 'text' | 'email' | 'password' | 'number'; 16 | name?: string; 17 | required?: boolean; 18 | autoComplete?: string; 19 | } 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/Thumbnail.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Thumbnail.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | 5 | function Thumbnail(props: IProps) { 6 | const { pathImage, alt } = props; 7 | 8 | return ( 9 |
10 | {alt} 11 |
12 | {' '} 13 | {/* Contenido del overlay */} 14 |
15 |
16 | ); 17 | } 18 | 19 | export default Thumbnail; 20 | -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle27.png -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle28.png -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle29.png -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle30.png -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle31.png -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ditmar/OpenScience/f659c7b51d989fcf64d754bfa76615a642856447/src/ui/components/atoms/thumbnail/__mock__/imgs/Rectangle32.png -------------------------------------------------------------------------------- /src/ui/components/atoms/thumbnail/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | pathImage: string; 3 | alt?: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/atoms/typography-paragraph/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | text?: string; 3 | size?: 'extra-small' | 'small' | 'medium-size' | 'large' | 'extra-large'; 4 | weight?: 'light' | 'regular' | 'medium' | 'semi-bold' | 'bold'; 5 | color?: 'dark' | 'white'; 6 | textDecoration?: 'none-line' | 'underline' | 'line-through'; 7 | italic?: boolean; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/atoms/url-input/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | value: string; 3 | onChange: (value: string) => void; 4 | placeholder?: string; 5 | label?: string; 6 | variant?: 'default' | 'focus' | 'error' | 'disabled'; 7 | size?: 'small' | 'medium' | 'large'; 8 | borderRadius?: 'none' | 'small' | 'full'; 9 | showCloseIcon?: boolean; 10 | onCloseClick?: () => void; 11 | onCopyClick?: () => void; 12 | showHintText?: boolean; 13 | hintText?: string; 14 | className?: string; 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/variable-button/VariableButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './variableButton.module.scss'; 3 | import type { IProps } from './types/IProps'; 4 | import { Icon } from '../../../utils/svg-icons/icons'; 5 | 6 | function VariableButton(props: IProps) { 7 | const { icon, onClick } = props; 8 | return ( 9 | 12 | ); 13 | } 14 | 15 | export default VariableButton; 16 | -------------------------------------------------------------------------------- /src/ui/components/atoms/variable-button/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | icon?: string; 6 | onClick?: () => void; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/atoms/variable-button/variableButton.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import VariableButton from './VariableButton'; 3 | import PdfIcon from '../../../../assets/icons/pdf.svg?raw'; 4 | import LinkIcon from '../../../../assets/icons/share.svg?raw'; 5 | 6 | const meta = { 7 | title: 'ui/components/atoms/variable-button', 8 | component: VariableButton, 9 | argTypes: { 10 | onClick: { 11 | action: 'click', 12 | }, 13 | }, 14 | } as Meta; 15 | 16 | export default meta; 17 | 18 | type Story = StoryObj; 19 | 20 | export const PdfButton: Story = { 21 | args: { 22 | children: 'PDF', 23 | icon: PdfIcon, 24 | }, 25 | }; 26 | 27 | export const LinkButton: Story = { 28 | args: { 29 | children: 'SHARE', 30 | icon: LinkIcon, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /src/ui/components/atoms/variable-button/variableButton.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import PdfIcon from '../../../../assets/icons/pdf.svg?raw'; 3 | import LinkIcon from '../../../../assets/icons/share.svg?raw'; 4 | import VariableButton from './VariableButton'; 5 | 6 | describe('VariableButton Component', () => { 7 | test('renders PDF button', () => { 8 | render(); 9 | const buttonElement = screen.getByTestId('button-icon'); 10 | expect(buttonElement).toBeInTheDocument(); 11 | }); 12 | 13 | test('renders Link button', () => { 14 | render(); 15 | const buttonElement = screen.getByTestId('button-icon'); 16 | expect(buttonElement).toBeInTheDocument(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/ui/components/atoms/year/Year.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | @import '../../../../globals/fonts'; 4 | 5 | .year { 6 | background-color: transparent; 7 | border: none; 8 | border-radius: 0.2rem; 9 | color: $ads-color-main; 10 | height: 1.2rem; 11 | text-transform: uppercase; 12 | width: 2.5rem; 13 | 14 | .year-label { 15 | color: $ads-color-main; 16 | font-family: Lato, Arial, Helvetica, sans-serif; 17 | font-size: 0.75rem; 18 | font-weight: bold; 19 | } 20 | 21 | @include respond-to('small') { 22 | height: 2rem; 23 | text-transform: capitalize; 24 | width: 4rem; 25 | 26 | .year-label { 27 | font-size: 1.15rem; 28 | } 29 | } 30 | 31 | &:hover { 32 | background-color: $ads-background-color-black; 33 | cursor: pointer; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ui/components/atoms/year/Year.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import ButtonYear from './Year'; 3 | 4 | const meta = { 5 | title: 'ui/components/atoms/year', 6 | component: ButtonYear, 7 | argTypes: { 8 | onClick: { 9 | action: 'click', 10 | }, 11 | variant: { 12 | control: 'select', 13 | }, 14 | }, 15 | } as Meta; 16 | 17 | export default meta; 18 | 19 | type Story = StoryObj; 20 | 21 | export const Primary: Story = { 22 | args: { 23 | children: '2023', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/ui/components/atoms/year/Year.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import Year from './Year'; 3 | 4 | describe('Testing ButtonWithVariants React Component', () => { 5 | test('should render test 1', () => { 6 | render(2023); 7 | const buttonElement = screen.getByText('2023'); 8 | expect(buttonElement).toBeInTheDocument(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/ui/components/atoms/year/Year.tsx: -------------------------------------------------------------------------------- 1 | import styles from './Year.module.scss'; 2 | import type { IProps } from './types/IProps'; 3 | 4 | function Year({ children, onClick }: IProps) { 5 | const variantClass = styles.year; 6 | return ( 7 | 10 | ); 11 | } 12 | 13 | export default Year; 14 | -------------------------------------------------------------------------------- /src/ui/components/atoms/year/types/IProps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | onClick?: () => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/molecules/InfoTooltip/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface InfoTooltipProps { 4 | content: string; 5 | position?: 'top' | 'bottom' | 'left' | 'right'; 6 | size?: 'small' | 'medium' | 'large'; 7 | className?: string; 8 | icon?: React.ReactNode; 9 | delay?: number; 10 | children?: React.ReactNode; 11 | } 12 | -------------------------------------------------------------------------------- /src/ui/components/molecules/LoginPage/LoginPage.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import logo from '../../../../assets/icons/logo.svg?raw'; 3 | import NetworkLogin from './LoginPage'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/molecules/login-page', 7 | component: NetworkLogin, 8 | argTypes: {}, 9 | }; 10 | export default meta; 11 | 12 | type Story = StoryObj; 13 | 14 | export const Primary: Story = { 15 | args: { 16 | icon: logo, 17 | color: 'primary', 18 | }, 19 | }; 20 | 21 | export const Secodary: Story = { 22 | args: { 23 | icon: logo, 24 | color: 'secondary', 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/ui/components/molecules/LoginPage/LoginPage.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import NetworkLogin from './LoginPage'; 4 | 5 | describe('NetworkLogin Component', () => { 6 | it('should render NetworkLogin component', () => { 7 | const { getByTestId } = render(); 8 | const pageElement = getByTestId('login-page'); 9 | expect(pageElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/molecules/LoginPage/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import LogoFooter from '../../atoms/logo-footer/LogoFooter'; 3 | import './LoginPage.scss'; 4 | import logo from '../../../../assets/icons/logo.svg?raw'; 5 | import vector from '../../../../assets/icons/vector.svg?raw'; 6 | import StartButton from '../../atoms/start-button/StartButton'; 7 | 8 | function LoginPage({ color = 'primary' }: IProps) { 9 | const getColorClassName = () => { 10 | return color === 'primary' ? 'page--primary' : 'page--secondary'; 11 | }; 12 | 13 | return ( 14 |
15 | 16 |
17 | INICIAR 18 |
19 |
20 | ); 21 | } 22 | 23 | export default LoginPage; 24 | -------------------------------------------------------------------------------- /src/ui/components/molecules/LoginPage/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | icon?: string | null; 3 | color?: 'primary' | 'secondary'; 4 | onClick?: () => void; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/article-publish/ArticlePublish.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .article-publish { 5 | align-items: center; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | text-align: center; 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/components/molecules/article-publish/ArticlePublish.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import styles from './ArticlePublish.module.scss'; 3 | 4 | function ArticlePublish(props: IProps) { 5 | const { children } = props; 6 | 7 | return
{children}
; 8 | } 9 | 10 | export default ArticlePublish; 11 | -------------------------------------------------------------------------------- /src/ui/components/molecules/article-publish/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/article/Article.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react'; 2 | import Article from './Article'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/molecules/articles-page', 6 | component: Article, 7 | parameters: { 8 | layout: 'fullscreen', 9 | }, 10 | }; 11 | 12 | export default meta; 13 | 14 | type Story = StoryObj; 15 | 16 | export const Default: Story = {}; 17 | -------------------------------------------------------------------------------- /src/ui/components/molecules/banner-articles/BannerArticles.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import BannerVolumes from './BannerArticles'; 3 | import Rectangle12 from '../../atoms/hero-banner/__mock__/imgs/Rectangle12.png'; 4 | import LogoSvg from '../../../../assets/icons/logo.svg'; 5 | 6 | const meta: Meta = { 7 | title: 'ui/components/molecules/banner-articles', 8 | component: BannerVolumes, 9 | }; 10 | 11 | export default meta; 12 | 13 | type Story = StoryObj; 14 | 15 | export const Default: Story = { 16 | args: { 17 | textSearch: 'Buscar', 18 | backgroundImage: String(Rectangle12), 19 | logo: String(LogoSvg), 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/ui/components/molecules/banner-articles/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | textSearch: string; 3 | backgroundImage: string; 4 | logo: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/banner-volumes/BannerVolumes.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import BannerVolumes from './BannerVolumes'; 3 | import dataMock from './__mock__/datamock.json'; 4 | import Rectangle12 from '../../atoms/hero-banner/__mock__/imgs/Rectangle12.png'; 5 | import LogoSvg from '../../../../assets/icons/logo.svg'; 6 | 7 | const meta: Meta = { 8 | title: 'ui/components/molecules/banner-volumes', 9 | component: BannerVolumes, 10 | }; 11 | 12 | export default meta; 13 | 14 | type Story = StoryObj; 15 | 16 | export const Default: Story = { 17 | args: { 18 | data: dataMock.data, 19 | textSearch: 'Buscar', 20 | yearText: 'año', 21 | backgroundImage: String(Rectangle12), 22 | logo: String(LogoSvg), 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /src/ui/components/molecules/banner-volumes/BannerVolumes.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import { describe, it, expect } from 'vitest'; 3 | import BannerVolumes from './BannerVolumes'; 4 | import dataMock from './__mock__/datamock.json'; 5 | import Rectangle12 from '../../atoms/hero-banner/__mock__/imgs/Rectangle12.png'; 6 | import LogoSvg from '../../../../assets/icons/logo.svg'; 7 | 8 | describe('YearList', () => { 9 | it('should render the correct text button', () => { 10 | render( 11 | , 18 | ); 19 | 20 | expect(screen.getByText(/año/i)).toBeInTheDocument(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/ui/components/molecules/banner-volumes/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IAttributes { 2 | Year: string; 3 | Volumes: string; 4 | } 5 | 6 | export interface IData { 7 | id: number; 8 | attributes: IAttributes; 9 | } 10 | export interface IProps { 11 | data: IData[]; 12 | yearText: string; 13 | textSearch: string; 14 | backgroundImage: string; 15 | logo: string; 16 | } 17 | -------------------------------------------------------------------------------- /src/ui/components/molecules/buttons-pdf-share/ButtonsPdfShare.scss: -------------------------------------------------------------------------------- 1 | .button-pdf-share { 2 | align-items: center; 3 | display: flex; 4 | gap: 1.5rem; 5 | margin-top: 13rem; 6 | } 7 | 8 | .share-container { 9 | position: relative; 10 | } 11 | 12 | .share-button { 13 | bottom: 100%; 14 | display: flex; 15 | flex-direction: column; 16 | gap: 0; 17 | left: 0; 18 | position: absolute; 19 | } 20 | -------------------------------------------------------------------------------- /src/ui/components/molecules/buttons-pdf-share/ButtonsPdfShare.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import ButtonsPdfShare from './ButtonsPdfShare'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/molecules/PdfShareButton', 6 | component: ButtonsPdfShare, 7 | argTypes: { 8 | onClick: { action: 'clicked' }, 9 | }, 10 | }; 11 | export default meta; 12 | 13 | type Story = StoryObj; 14 | 15 | export const Primary: Story = { 16 | args: {}, 17 | }; 18 | -------------------------------------------------------------------------------- /src/ui/components/molecules/buttons-pdf-share/ButtonsPdfShare.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import PdfShareButton from './ButtonsPdfShare'; 3 | 4 | describe('PdfShareButton Component', () => { 5 | it('should render PdfShareButton component', () => { 6 | render(); 7 | const shareButton = screen.getByTestId('pdf-share-button'); 8 | expect(shareButton).toBeInTheDocument(); 9 | }); 10 | test('items should not be visible initially', () => { 11 | render(); 12 | expect(screen.queryByText('WhatsappIcon')).not.toBeInTheDocument(); 13 | expect(screen.queryByText('FacebookIcon')).not.toBeInTheDocument(); 14 | expect(screen.queryByText('TelegramIcon')).not.toBeInTheDocument(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/ui/components/molecules/buttons-pdf-share/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | icon?: string; 3 | onClick?: () => void; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/molecules/featured-article/FeaturedArticle.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .featured-article { 5 | position: relative; 6 | } 7 | 8 | .divider { 9 | align-items: center; 10 | display: flex; 11 | justify-content: space-between; 12 | margin: 0; 13 | width: 100%; 14 | 15 | .buttons { 16 | display: flex; 17 | gap: 10px; 18 | margin-left: auto; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ui/components/molecules/featured-article/FeaturedArticle.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps.js'; 2 | import './FeaturedArticle.scss'; 3 | 4 | function FeaturedArticle(props: IProps) { 5 | const { children } = props; 6 | return
{children}
; 7 | } 8 | 9 | export default FeaturedArticle; 10 | -------------------------------------------------------------------------------- /src/ui/components/molecules/featured-article/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | onClick?: () => void; 6 | text?: string; 7 | icon?: string; 8 | size?: 'small' | 'medium' | 'large'; 9 | variant: 'default' | 'primary' | 'secondary ' | 'solid-line' | 'points' | 'main'; 10 | color?: 'primary' | 'secondary' | 'tertiary'; 11 | ColorVariant?: 'main' | 'primary' | 'secondary'; 12 | article: string; 13 | date: Date; 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/components/molecules/footer-variables/FooterVariables.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import FooterVariables from './FooterVariables'; 3 | import '../../../../globals/_variables.scss'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/molecules/footer-variables', 7 | component: FooterVariables, 8 | }; 9 | 10 | export default meta; 11 | 12 | type Story = StoryObj; 13 | 14 | export const Default: Story = {}; 15 | -------------------------------------------------------------------------------- /src/ui/components/molecules/header-banner/HeaderBanner.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import BannerVolumes from './HeaderBanner'; 3 | import Rectangle12 from '../../atoms/hero-banner/__mock__/imgs/Rectangle12.png'; 4 | import LogoSvg from '../../../../assets/icons/logo.svg'; 5 | 6 | const meta: Meta = { 7 | title: 'ui/components/molecules/header-banner', 8 | component: BannerVolumes, 9 | }; 10 | 11 | export default meta; 12 | 13 | type Story = StoryObj; 14 | 15 | export const Default: Story = { 16 | args: { 17 | textSearch: 'Buscar', 18 | backgroundImage: String(Rectangle12), 19 | logo: String(LogoSvg), 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/ui/components/molecules/header-banner/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IAttributes { 2 | Year: string; 3 | Volumes: string; 4 | } 5 | 6 | export interface IData { 7 | id: number; 8 | attributes: IAttributes; 9 | } 10 | export interface IProps { 11 | textSearch: string; 12 | backgroundImage: string; 13 | logo: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/components/molecules/location-variable/Location.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import Facebook from '../../../../assets/icons/facelocation.svg?raw'; 3 | import location from '../../../../assets/icons/location.svg?raw'; 4 | import Location from './Location'; 5 | 6 | const meta = { 7 | title: 'ui/components/molecules/location-variable', 8 | component: Location, 9 | argTypes: { 10 | variant: { 11 | control: { type: 'select' }, 12 | options: ['solid', 'dotted', 'dashed'], 13 | }, 14 | }, 15 | } as Meta; 16 | 17 | export default meta; 18 | 19 | type Story = StoryObj; 20 | 21 | export const Primary: Story = { 22 | args: { 23 | icon: location, 24 | children: 'UBICACIÓN', 25 | variant: 'solid', 26 | icon1: Facebook, 27 | children1: 'SÍGUENOS EN', 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/ui/components/molecules/location-variable/Location.tsx: -------------------------------------------------------------------------------- 1 | import './styles.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function Location(props: IProps) { 6 | const { variant, children, icon, icon1, children1 } = props; 7 | return ( 8 |
9 | {children} 10 | 13 |
14 | {children1} 15 | 18 |
19 | ); 20 | } 21 | export default Location; 22 | -------------------------------------------------------------------------------- /src/ui/components/molecules/location-variable/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | icon?: string; 5 | icon1?: string; 6 | children: React.ReactNode; 7 | children1: React.ReactNode; 8 | variant: 'solid' | 'dotted' | 'dashed'; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/molecules/login-register-buttons/LoginRegisterButton.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .auth-buttons { 5 | display: flex; 6 | gap: 1rem; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/molecules/login-register-buttons/LoginRegisterButton.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import LoginRegisterButtons from './LoginRegisterButtons'; 3 | import PrimaryButtons from '../../atoms/primary-buttons/PrimaryButtons'; 4 | 5 | describe('LoginRegisterButtons Component', () => { 6 | test('should render both buttons', () => { 7 | render( 8 | 9 | Iniciar sesión 10 | Registrarse 11 | , 12 | ); 13 | const loginButton = screen.getByText(/Iniciar sesión/i); 14 | const registerButton = screen.getByText(/Registrarse/i); 15 | 16 | expect(loginButton).toBeInTheDocument(); 17 | expect(registerButton).toBeInTheDocument(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/ui/components/molecules/login-register-buttons/LoginRegisterButtons.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import styles from './LoginRegisterButton.module.scss'; 3 | 4 | function LoginRegisterButtons(props: IProps) { 5 | const { children } = props; 6 | return
{children}
; 7 | } 8 | 9 | export default LoginRegisterButtons; 10 | -------------------------------------------------------------------------------- /src/ui/components/molecules/login-register-buttons/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | onClick?: () => void; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/molecules/magnifying-glass/MagnifyingGlass.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import '../../../../globals/_variables.scss'; 3 | import magnifyingglass from '../../../../assets/icons/magnifyingglass.svg?raw'; 4 | import MagnifyingGlass from './MagnifyingGlass'; 5 | 6 | const meta = { 7 | title: 'ui/components/molecules/magnifying-glass', 8 | component: MagnifyingGlass, 9 | argTypes: { 10 | onClick: { 11 | action: 'click', 12 | }, 13 | variant: { 14 | control: { type: 'select' }, 15 | options: ['solid', 'dotted', 'dashed'], 16 | }, 17 | }, 18 | } as Meta; 19 | 20 | export default meta; 21 | 22 | type Story = StoryObj; 23 | 24 | export const MagnifyinGlass: Story = { 25 | args: { 26 | icon: magnifyingglass, 27 | variant: 'solid', 28 | children: 'BUSCAR', 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /src/ui/components/molecules/magnifying-glass/MagnifyingGlass.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import magnifyingglass from '../../../../assets/icons/magnifyingglass.svg?raw'; 3 | import MagnifyingGlass from './MagnifyingGlass'; 4 | 5 | describe('Testing MagnifyingGlass React Component', () => { 6 | test('should be rendere MagnifyingGlass icon', () => { 7 | render(); 8 | const buttonElement = screen.getByTestId('button__glass'); 9 | expect(buttonElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/molecules/magnifying-glass/MagnifyingGlass.tsx: -------------------------------------------------------------------------------- 1 | import './style.scss'; 2 | import type { IProps } from './types/IProps'; 3 | import { Icon } from '../../../utils/svg-icons/icons'; 4 | 5 | function MagnifyingGlass(props: IProps) { 6 | const { icon, onClick } = props; 7 | 8 | return ( 9 |
10 | 13 |
14 | ); 15 | } 16 | export default MagnifyingGlass; 17 | -------------------------------------------------------------------------------- /src/ui/components/molecules/magnifying-glass/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | @import '../../../../globals/fonts'; 4 | 5 | .glass { 6 | align-items: center; 7 | display: flex; 8 | flex-direction: column; 9 | justify-content: center; 10 | } 11 | 12 | .disguise { 13 | background-color: transparent; 14 | border: none; 15 | margin-left: 94%; 16 | margin-top: -0.4rem; 17 | } 18 | 19 | .button__icons--glass svg { 20 | height: 1.125rem; 21 | width: 1.125rem; 22 | 23 | @include respond-to('medium') { 24 | height: 2rem; 25 | width: 2rem; 26 | } 27 | 28 | @include respond-to('extra-large') { 29 | height: 2rem; 30 | width: 2rem; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ui/components/molecules/magnifying-glass/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | icon: string; 6 | variant: 'solid' | 'dotted' | 'dashed'; 7 | onClick?: () => void; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/components/molecules/network-login/network-login.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import logo from '../../../../assets/icons/logo.svg?raw'; 3 | import NetworkLogin from './network-login'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/molecules/network-login', 7 | component: NetworkLogin, 8 | argTypes: {}, 9 | }; 10 | export default meta; 11 | 12 | type Story = StoryObj; 13 | 14 | export const Primary: Story = { 15 | args: { 16 | icon: logo, 17 | color: 'primary', 18 | }, 19 | }; 20 | 21 | export const Secodary: Story = { 22 | args: { 23 | icon: logo, 24 | color: 'secondary', 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/ui/components/molecules/network-login/network-login.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import NetworkLogin from './network-login'; 4 | 5 | describe('NetworkLogin Component', () => { 6 | it('should render NetworkLogin component', () => { 7 | const { getByTestId } = render(); 8 | const panelElement = getByTestId('net-login'); 9 | expect(panelElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/molecules/network-login/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | icon?: string | null; 3 | color?: 'primary' | 'secondary'; 4 | onClick?: () => void; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/option-menu/OptionMenu.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react'; 2 | import OptionMenu from './OptionMenu'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/molecules/Option-Menu', 6 | component: OptionMenu, 7 | }; 8 | 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = {}; 14 | -------------------------------------------------------------------------------- /src/ui/components/molecules/option-menu/OptionMenu.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import OptionMenu from './OptionMenu'; 3 | 4 | describe('OptionMenu Component', () => { 5 | test('should render ButtonBurger', () => { 6 | render(); 7 | const burgerButton = screen.getByLabelText('Menu'); 8 | expect(burgerButton).toBeInTheDocument(); 9 | }); 10 | 11 | test('menu items should not be visible initially', () => { 12 | render(); 13 | expect(screen.queryByText('Pdf')).not.toBeInTheDocument(); 14 | expect(screen.queryByText('Share')).not.toBeInTheDocument(); 15 | expect(screen.queryByText('Media')).not.toBeInTheDocument(); 16 | expect(screen.queryByText('Reference')).not.toBeInTheDocument(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/ui/components/molecules/option-menu/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | icon?: string; 3 | onClick?: () => void; 4 | } 5 | -------------------------------------------------------------------------------- /src/ui/components/molecules/pdf-share-buttons/PdfShareButton.scss: -------------------------------------------------------------------------------- 1 | .pdf-share-buttons { 2 | align-items: center; 3 | display: flex; 4 | gap: 1.5rem; 5 | margin-top: 13rem; 6 | } 7 | 8 | .share { 9 | position: relative; 10 | } 11 | 12 | .share-buttons { 13 | bottom: 100%; 14 | display: flex; 15 | flex-direction: column; 16 | gap: 0; 17 | left: 0; 18 | position: absolute; 19 | } 20 | -------------------------------------------------------------------------------- /src/ui/components/molecules/pdf-share-buttons/PdfShareButton.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import PdfShareButton from './PdfShareButton'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/molecules/pdf-share-buttons', 6 | component: PdfShareButton, 7 | }; 8 | 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = {}; 14 | -------------------------------------------------------------------------------- /src/ui/components/molecules/pdf-share-buttons/types/IProps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/recent-articles-image/RecentArticlesImage.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps.js'; 2 | import './styles.scss'; 3 | import Rectangle29 from '../../atoms/thumbnail/__mock__/imgs/Rectangle29.png'; 4 | import Thumbnail from '../../atoms/thumbnail/Thumbnail'; 5 | 6 | console.log('Rectangle29:', Rectangle29); 7 | 8 | function RecentArticlesImage(props: IProps) { 9 | const { children } = props; 10 | return ( 11 |
12 |
{children}
13 |
14 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default RecentArticlesImage; 27 | -------------------------------------------------------------------------------- /src/ui/components/molecules/recent-articles-image/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | onClick?: () => void; 6 | text?: string; 7 | icon?: string; 8 | size?: 'small' | 'medium' | 'large'; 9 | variant: 'default' | 'primary' | 'secondary ' | 'solid-line' | 'points' | 'main'; 10 | color?: 'primary' | 'secondary' | 'tertiary'; 11 | ColorVariant?: 'main' | 'primary' | 'secondary'; 12 | article: string; 13 | date: Date; 14 | pathImage: string; 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/components/molecules/references/References.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .references { 5 | background-color: $ads-background-desktop; 6 | 7 | a { 8 | color: $ads-text-main-hover; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/components/molecules/references/References.tsx: -------------------------------------------------------------------------------- 1 | import type { IProps } from './types/IProps'; 2 | import './References.scss'; 3 | 4 | function References(props: IProps) { 5 | const { children } = props; 6 | 7 | return
{children}
; 8 | } 9 | 10 | export default References; 11 | -------------------------------------------------------------------------------- /src/ui/components/molecules/references/types/IProps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/mobile-side-pandel/MSPanel.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import MSPanel from './MSPanel'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/molecules/side-panel/Mobile-side-panel', 6 | component: MSPanel, 7 | argTypes: {}, 8 | }; 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Primary: Story = { 14 | args: { 15 | variant: 'default', 16 | }, 17 | }; 18 | 19 | export const Secondary: Story = { 20 | args: { 21 | variant: 'color', 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/mobile-side-pandel/MSPanel.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import MSPanel from './MSPanel'; 4 | 5 | describe('MSPanel Component', () => { 6 | it('should render SPanel component', () => { 7 | const { getByTestId } = render(); 8 | const panelElement = getByTestId('ms-panel'); 9 | expect(panelElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/mobile-side-pandel/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | variant?: 'default' | 'color'; 3 | } 4 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/panel/SPanel.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../../globals/variables'; 2 | @import '../../../../../globals/mixins'; 3 | 4 | .panel { 5 | background: $ads-background-main; 6 | display: flex; 7 | flex-direction: column; 8 | height: 280px; 9 | padding: 2.2rem; 10 | width: 200px; 11 | 12 | &--secondary { 13 | position: sticky; 14 | } 15 | } 16 | 17 | .tags .tag { 18 | font-size: $ads-font-size-second; 19 | margin: 0.5rem; 20 | 21 | &--secondary { 22 | background: $ads-secondary-main; 23 | } 24 | } 25 | 26 | .tag:hover { 27 | text-decoration: underline; 28 | } 29 | 30 | .logo { 31 | align-items: center; 32 | background: transparent; 33 | display: flexbox; 34 | height: 70px; 35 | width: 155px; 36 | } 37 | 38 | .logo .logo-icon { 39 | & svg { 40 | height: 100%; 41 | width: 100%; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/panel/SPanel.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import SidePanel from './SPanel'; 3 | import logo from '../../../../../assets/icons/logo.svg?raw'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/molecules/side-panel/panel', 7 | component: SidePanel, 8 | argTypes: { 9 | onClick: { 10 | action: 'click', 11 | }, 12 | }, 13 | }; 14 | export default meta; 15 | 16 | type Story = StoryObj; 17 | 18 | export const Primary: Story = { 19 | args: { 20 | icon: logo, 21 | color: 'primary', 22 | }, 23 | }; 24 | 25 | export const Secodary: Story = { 26 | args: { 27 | icon: logo, 28 | color: 'secondary', 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/panel/SPanel.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import SPanel from './SPanel'; 4 | 5 | describe('SPanel Component', () => { 6 | it('should render SPanel component', () => { 7 | const { getByTestId } = render(); 8 | const panelElement = getByTestId('s-panel'); 9 | expect(panelElement).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/panel/SPanel.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { IProps } from './types/IProps'; 3 | import LogoFooter from '../../../atoms/logo-footer/LogoFooter'; 4 | import Tags from '../../../atoms/Tags/Tags'; 5 | import './SPanel.scss'; 6 | import logo from '../../../../../assets/icons/logo.svg?raw'; 7 | 8 | function SPanel({ color = 'primary' }: IProps) { 9 | const tags = ['workings', 'optimism', 'meaning', 'promoting']; 10 | const getColorClassName = () => { 11 | return color === 'primary' ? 'panel--primary' : 'panel--secondary'; 12 | }; 13 | 14 | return ( 15 |
16 | 17 | 18 |
19 | ); 20 | } 21 | 22 | export default SPanel; 23 | -------------------------------------------------------------------------------- /src/ui/components/molecules/side-panel/panel/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | icon?: string | null; 3 | color?: 'primary' | 'secondary'; 4 | onClick?: () => void; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume-box/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | className?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume-carousel/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | rightIcon?: string; 6 | leftIcon?: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume-list/VolumeList.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import VolumeList from './VolumeList'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/molecules/volume-list', 6 | component: VolumeList, 7 | }; 8 | 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = {}; 14 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume-list/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IProps { 2 | id: number; 3 | attributes: { 4 | title: string; 5 | date: string; 6 | portrait: { 7 | data: { 8 | id: number; 9 | attributes: { 10 | url: string; 11 | }; 12 | }; 13 | }; 14 | year_volume: { 15 | data: { 16 | id: number; 17 | attributes: { 18 | Year: string; 19 | Volumes: string; 20 | }; 21 | }; 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume/Volume.scss: -------------------------------------------------------------------------------- 1 | .volume { 2 | align-items: center; 3 | display: flex; 4 | flex-direction: column; 5 | height: 100vh; 6 | justify-content: center; 7 | text-align: center; 8 | 9 | > * { 10 | margin: 10px 0; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume/Volume.tsx: -------------------------------------------------------------------------------- 1 | import './Volume.scss'; 2 | import LabelVol from '../../atoms/label-vol/LabelVol'; 3 | import LabelDate from '../../atoms/label-date/LabelDate'; 4 | import Thumbnail from '../../atoms/thumbnail/Thumbnail'; 5 | import type { IProps } from './types/IProps'; 6 | 7 | function Volume({ pathImage, alt, volumen, id, date, overflow }: IProps) { 8 | return ( 9 |
10 | 11 | 12 | 13 |
14 | ); 15 | } 16 | 17 | export default Volume; 18 | -------------------------------------------------------------------------------- /src/ui/components/molecules/volume/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import type { IProps as IThumbnailProps } from 'ui/components/atoms/thumbnail/types/IProps'; 2 | import type { IProps as ILabelVolProps } from 'ui/components/atoms/label-vol/types/IProps'; 3 | import type { IProps as ILabelDateProps } from 'ui/components/atoms/label-date/types/IProps'; 4 | 5 | export interface IProps extends IThumbnailProps, ILabelVolProps, ILabelDateProps {} 6 | -------------------------------------------------------------------------------- /src/ui/components/molecules/year-list/YearList.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../globals/variables'; 2 | @import '../../../../globals/mixins'; 3 | 4 | .year-list__wrapper { 5 | display: flex; 6 | flex-direction: column; 7 | justify-content: center; 8 | } 9 | 10 | @include respond-to('medium') { 11 | .year-list__wrapper { 12 | align-items: center; 13 | } 14 | } 15 | 16 | .year-list__container { 17 | display: grid; 18 | grid-template-columns: repeat(auto-fit, minmax(2.5rem, 1fr)); 19 | margin-top: 1rem; 20 | place-items: center center; 21 | width: 100%; 22 | } 23 | 24 | .year-list__hidden { 25 | display: none; 26 | } 27 | 28 | @include respond-to('medium') { 29 | .year-list__container { 30 | grid-template-columns: repeat(auto-fit, minmax(6.25rem, 1fr)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ui/components/molecules/year-list/YearList.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import YearList from './YearList'; 3 | import dataMock from './__mock__/datamock.json'; 4 | 5 | const meta: Meta = { 6 | title: 'ui/components/molecules/year-list', 7 | component: YearList, 8 | }; 9 | 10 | export default meta; 11 | 12 | type Story = StoryObj; 13 | 14 | export const Default: Story = { 15 | args: { 16 | data: dataMock.data, 17 | buttonText: 'año', 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/ui/components/molecules/year-list/YearList.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import { describe, it, expect } from 'vitest'; 3 | import YearList from './YearList'; 4 | import dataMock from './__mock__/datamock.json'; 5 | 6 | describe('YearList', () => { 7 | it('should render the correct text button', () => { 8 | render(); 9 | 10 | expect(screen.getByText(/año/i)).toBeInTheDocument(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/ui/components/molecules/year-list/types/IProps.ts: -------------------------------------------------------------------------------- 1 | export interface IAttributes { 2 | Year: string; 3 | Volumes: string; 4 | } 5 | 6 | export interface IData { 7 | id: number; 8 | attributes: IAttributes; 9 | } 10 | 11 | export interface IProps { 12 | data: IData[]; 13 | buttonText: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/components/organisms/articles-page/ArticlesPage.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react'; 2 | import ArticlesPage from './ArticlesPage'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/organisms/articles-page', 6 | component: ArticlesPage, 7 | parameters: { 8 | layout: 'fullscreen', 9 | }, 10 | }; 11 | 12 | export default meta; 13 | 14 | type Story = StoryObj; 15 | 16 | export const Default: Story = {}; 17 | -------------------------------------------------------------------------------- /src/ui/components/organisms/articles-page/ArticlesPage.test.jsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import ArticlesPage from './ArticlesPage.tsx'; 3 | 4 | describe('ArticlesPage', () => { 5 | beforeEach(() => { 6 | render(); 7 | }); 8 | 9 | test('renders the "ARTÍCULOS" label', () => { 10 | const articlesLabel = screen.getByText('ARTÍCULOS'); 11 | expect(articlesLabel).toBeInTheDocument(); 12 | }); 13 | 14 | test('renders the "VOLÚMENES" label', () => { 15 | const volumesLabel = screen.getByText('VOLÚMENES'); 16 | expect(volumesLabel).toBeInTheDocument(); 17 | }); 18 | 19 | test('renders volume labels in the carousel', () => { 20 | const volumes = screen.getAllByText(/Vol\./); 21 | expect(volumes.length).toBe(4); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/ui/components/organisms/demo-branch-story/demo-branch-story.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react'; 2 | import { DemoBranchStory } from './demo-branch-story'; 3 | 4 | const meta: Meta = { 5 | title: 'Organisms/DemoBranchStory', 6 | component: DemoBranchStory, 7 | parameters: { 8 | layout: 'fullscreen', 9 | }, 10 | }; 11 | 12 | export default meta; 13 | 14 | type Story = StoryObj; 15 | 16 | export const Default: Story = { 17 | args: {}, 18 | }; 19 | 20 | export const WithTheme: Story = { 21 | args: {}, 22 | decorators: [ 23 | (Story) => ( 24 |
25 | 26 |
27 | ), 28 | ], 29 | }; 30 | -------------------------------------------------------------------------------- /src/ui/components/organisms/homepage/HomePage.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { StoryObj, Meta } from '@storybook/react'; 2 | import HomePage from './HomePage'; 3 | 4 | const meta: Meta = { 5 | title: 'ui/components/organisms/homepage', 6 | component: HomePage, 7 | }; 8 | 9 | export default meta; 10 | 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = {}; 14 | -------------------------------------------------------------------------------- /src/ui/components/organisms/homepage/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children?: React.ReactNode; 5 | } 6 | -------------------------------------------------------------------------------- /src/ui/components/organisms/sectiontwo-page/__mock__/breakpoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "small": "480px", 3 | "small-mobile": "320px", 4 | "small-mobile-large": "568px", 5 | "medium": "768px", 6 | "large": "1024px", 7 | "large-tablet": "1112px", 8 | "extra-large": "1280px" 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/components/organisms/sectiontwo-page/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface IProps { 4 | children: React.ReactNode; 5 | backgroundImageDesktop: string; 6 | backgroundImageMobile: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/ui/utils/hooks/useForm.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import type { ChangeEvent } from 'react'; 3 | 4 | type FormFields = Record; 5 | 6 | interface UseFormReturn { 7 | form: T; 8 | handlerChangeForm: (event: ChangeEvent) => void; 9 | handlerResetForm: () => void; 10 | } 11 | 12 | const useForm = (initForm: T): UseFormReturn => { 13 | const [form, setForm] = useState(initForm); 14 | 15 | const handlerChangeForm = ({ target }: ChangeEvent) => { 16 | setForm({ ...form, [target.name]: target.value }); 17 | }; 18 | 19 | const handlerResetForm = () => { 20 | setForm(initForm); 21 | }; 22 | 23 | return { form, handlerChangeForm, handlerResetForm }; 24 | }; 25 | 26 | export default useForm; 27 | -------------------------------------------------------------------------------- /src/ui/utils/svg-icons/optimizeSvg.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import { optimize } from 'svgo'; 3 | 4 | function optimizeSvg(svg: string, size = '24px') { 5 | const result = optimize(svg, { 6 | plugins: [ 7 | { 8 | name: 'removeDimensions', 9 | }, 10 | { 11 | name: 'addAttributesToSVGElement', 12 | params: { 13 | attributes: [ 14 | { 15 | viewBox: `0 0 ${size.replace('px', '')} ${size.replace('px', '')}`, 16 | }, 17 | ], 18 | }, 19 | }, 20 | ], 21 | }); 22 | 23 | return result.data; 24 | } 25 | 26 | export default optimizeSvg; 27 | -------------------------------------------------------------------------------- /src/ui/utils/svg-icons/types/SvgIconProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface SvgIconProps { 4 | src: string; 5 | size?: string; 6 | className?: string; 7 | styles?: React.CSSProperties; 8 | ['data-testid']?: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/utils/vite-svgr/Icon.tsx: -------------------------------------------------------------------------------- 1 | import { useDynamicIcon } from '../hooks/useDynamicIcon'; 2 | import type { IconProps } from './types/IProps'; 3 | import { Loader } from './Loader'; 4 | 5 | export function Icon({ iconName, ...props }: IconProps) { 6 | const [DynamicComponent] = useDynamicIcon(iconName); 7 | 8 | return ( 9 |
10 | {DynamicComponent ? ( 11 | // eslint-disable-next-line react/jsx-props-no-spreading 12 | 13 | ) : ( 14 | 15 | )} 16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/ui/utils/vite-svgr/Loader.tsx: -------------------------------------------------------------------------------- 1 | import { Box, CircularProgress } from '@mui/material'; 2 | import ThemeWrapper from '../../../style-library/core/ThemeProvider'; 3 | 4 | export function Loader() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/ui/utils/vite-svgr/loadSvgIcon.ts: -------------------------------------------------------------------------------- 1 | import type { DynamicIcon } from './types/IconType'; 2 | 3 | export async function loadSvgIcon(iconName: string): Promise { 4 | const module = (await import(`../../../assets/icons/${iconName}.svg?react`)) as { 5 | default: DynamicIcon; 6 | }; 7 | return module.default; 8 | } 9 | -------------------------------------------------------------------------------- /src/ui/utils/vite-svgr/types/IProps.ts: -------------------------------------------------------------------------------- 1 | import type { SVGProps } from 'react'; 2 | 3 | export interface IconProps extends SVGProps { 4 | iconName: IconName; 5 | } 6 | 7 | export type IconName = 8 | | 'article' 9 | | 'articles' 10 | | 'burger-menu' 11 | | 'button-burguer' 12 | | 'button-burguer1' 13 | | 'close_simple' 14 | | 'close' 15 | | 'downloads' 16 | | 'eye' 17 | | 'facebook' 18 | | 'facebook1' 19 | | 'facelocation' 20 | | 'google' 21 | | 'home' 22 | | 'icon-upload-default' 23 | | 'icon-upload-primary' 24 | | 'left-arrow' 25 | | 'location' 26 | | 'logo' 27 | | 'magnifyingglass' 28 | | 'media' 29 | | 'pdf' 30 | | 'reference' 31 | | 'reference1' 32 | | 'right-arrow' 33 | | 'share' 34 | | 'start' 35 | | 'telegram' 36 | | 'vector' 37 | | 'volume' 38 | | 'volumes' 39 | | 'whatsapp'; 40 | -------------------------------------------------------------------------------- /src/ui/utils/vite-svgr/types/IconType.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { FunctionComponent } from 'react'; 3 | 4 | export type DynamicIcon = FunctionComponent> | null; 5 | -------------------------------------------------------------------------------- /style-guide/astro.js: -------------------------------------------------------------------------------- 1 | const { rules } = require('./rules/astro'); 2 | 3 | module.exports = { 4 | extends: [ 5 | require.resolve('./react'), 6 | require.resolve('./configurations/_base'), 7 | 'plugin:svelte/recommended', 8 | 'plugin:astro/recommended', 9 | ], 10 | ignorePatterns: ['app-server/**', '.yarn/**', 'Dockerfile'], 11 | overrides: [ 12 | { 13 | files: ['*.astro'], 14 | parser: 'astro-eslint-parser', 15 | parserOptions: { 16 | parser: '@typescript-eslint/parser', 17 | extraFileExtensions: ['.astro'], 18 | }, 19 | rules: rules, 20 | }, 21 | { 22 | files: ['*.svelte'], 23 | parser: 'svelte-eslint-parser', 24 | parserOptions: { 25 | parser: { 26 | ts: '@typescript-eslint/parser', 27 | typescript: '@typescript-eslint/parser', 28 | }, 29 | }, 30 | }, 31 | ], 32 | }; 33 | -------------------------------------------------------------------------------- /style-guide/configurations/constants.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ECMA_VERSION: 2021, 3 | JAVASCRIPT_FILES: ['*.js?(x)', '*.mjs'], 4 | TYPESCRIPT_FILES: ['*.ts?(x)'], 5 | ASTRO_FILES: ['*.astro'], 6 | SVELTE_FILES: ['*.svelte'], 7 | TEST_FILES: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'], 8 | }; 9 | -------------------------------------------------------------------------------- /style-guide/configurations/ignorePattern.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ignorePatterns: [ 3 | 'node_modules/', 4 | 'dist/', 5 | 'build/', 6 | 'public/', 7 | 'stories', 8 | 'style-guide', 9 | 'agnosticStyles/', 10 | 'storybook-static/', 11 | 'storybook-global/', 12 | '.eslintrc.js', 13 | '.eslintrc.cjs', 14 | 'astro-config.ts', 15 | 'vite.config.ts', 16 | 'vite.config.js', 17 | 'vitest.config.unit.ts', 18 | 'vitest.config.e2e.ts', 19 | '*.d.ts', 20 | 'vite.config.ts.timestamp-*.mjs', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /style-guide/configurations/typescript.js: -------------------------------------------------------------------------------- 1 | const { TYPESCRIPT_FILES } = require('./constants.js'); 2 | module.exports = { 3 | overrides: [ 4 | { 5 | files: TYPESCRIPT_FILES, 6 | extends: [ 7 | 'plugin:@typescript-eslint/recommended', 8 | 'plugin:@typescript-eslint/recommended-type-checked', 9 | 'plugin:@typescript-eslint/strict', 10 | 'plugin:@typescript-eslint/strict-type-checked', 11 | 'plugin:@typescript-eslint/stylistic', 12 | 'plugin:@typescript-eslint/stylistic-type-checked', 13 | 'plugin:import/typescript', 14 | 'airbnb-typescript', 15 | 'prettier', 16 | ], 17 | rules: { 18 | 'import/prefer-default-export': 0, 19 | }, 20 | }, 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /style-guide/configurations/vitest.js: -------------------------------------------------------------------------------- 1 | const { TEST_FILES } = require('./constants.js'); 2 | module.exports = { 3 | overrides: [ 4 | { 5 | files: TEST_FILES, 6 | plugins: ['vitest'], 7 | extends: ['plugin:vitest/recommended'], 8 | rules: { 9 | 'import/no-extraneous-dependencies': [ 10 | 'off', 11 | { devDependencies: ['**/*.test.[jt]s?(x)', '**/*.spec.[jt]s?(x)'] }, 12 | ], 13 | }, 14 | }, 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /style-guide/prettier/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require.resolve('prettier-plugin-astro'), require.resolve('prettier-plugin-svelte')], 3 | overrides: [ 4 | { 5 | files: '*.astro', 6 | options: { 7 | parser: 'astro', 8 | }, 9 | }, 10 | { files: '*.svelte', options: { parser: 'svelte' } }, 11 | ], 12 | arrowParens: 'always', 13 | bracketSpacing: true, 14 | printWidth: 100, 15 | proseWrap: 'preserve', 16 | requirePragma: false, 17 | semi: true, 18 | singleQuote: true, 19 | tabWidth: 2, 20 | trailingComma: 'all', 21 | useTabs: false, 22 | svelteSortOrder: 'options-styles-scripts-markup', 23 | svelteStrictMode: true, 24 | svelteAllowShorthand: false, 25 | svelteIndentScriptAndStyle: false, 26 | endOfLine: 'lf', 27 | }; 28 | -------------------------------------------------------------------------------- /style-guide/rules/base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | 'max-len': ['error', { code: 150 }], 4 | 'import/no-named-as-default': 0, 5 | 'import/no-named-as-default-member': 0, 6 | 'import/prefer-default-export': 0, 7 | 'react/jsx-filename-extension': 'off', 8 | 'react/require-default-props': 'off', 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /style-guide/rules/nomenclature.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | 'check-file/no-index': 'off', 4 | 'check-file/filename-blocklist': ['error', {}], 5 | 'check-file/folder-match-with-fex': [ 6 | 'off', 7 | { 8 | '*.test.{js,jsx,ts,tsx}': '**/__tests__/', 9 | }, 10 | ], 11 | 'check-file/filename-naming-convention': [ 12 | 'error', 13 | { 14 | '{**/!(index|main).{jsx,tsx,svelte},**/!(*pages*)/!/^[A-Z]([A-Za-z0-9]+)?([w+])?.astro$/': 15 | 'PASCAL_CASE', 16 | '{**/!(index|main).{js,ts}}': 'KEBAB_CASE', 17 | }, 18 | { ignoreMiddleExtensions: true }, 19 | ], 20 | 'check-file/folder-naming-convention': [ 21 | 'error', 22 | { 23 | '**/!(__tests__|.)': 'KEBAB_CASE', 24 | }, 25 | ], 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /style-guide/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationMap": true, 6 | "inlineSources": false, 7 | "noUnusedLocals": false, 8 | "noUnusedParameters": false, 9 | "preserveWatchOutput": true, 10 | "target": "ESNext", 11 | "module": "ESNext", 12 | "moduleResolution": "Bundler", 13 | "allowImportingTsExtensions": true, 14 | "resolveJsonModule": true, 15 | "verbatimModuleSyntax": true, 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "esModuleInterop": true, 20 | "skipLibCheck": true, 21 | "allowJs": true, 22 | "strict": true, 23 | "strictNullChecks": true, 24 | "plugins": [ 25 | { 26 | "name": "typescript-plugin-css-modules" 27 | } 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Astro Project", 4 | "extends": "./style-guide/tsconfig/base.json", 5 | "compilerOptions": { 6 | "baseUrl": "./src", 7 | "paths": { 8 | "@PubSub/*": ["./PubSub/*"], 9 | "@icons": ["./ui/utils/svg-icons/icons"], 10 | "@services/*": ["./services/*"] 11 | }, 12 | "jsx": "react-jsx", 13 | "jsxImportSource": "react", 14 | "plugins": [ 15 | { 16 | "name": "@astrojs/ts-plugin" 17 | } 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | test: { 7 | globals: true, 8 | environment: 'jsdom', 9 | setupFiles: './src/setupTests.ts', 10 | }, 11 | }); 12 | --------------------------------------------------------------------------------