diff --git a/public/navigation.json b/public/navigation.json index de7a30e9..6afabaf9 100644 --- a/public/navigation.json +++ b/public/navigation.json @@ -3650,7 +3650,7 @@ "name": { "en": "Beta", "es": "Beta", "pt": "Beta" }, "slug": "beta-products", "origin": "", - "type": "category", + "type": "tutorial-category", "children": [ { "name": { @@ -3660,7 +3660,7 @@ }, "slug": "subscriptions-beta", "origin": "", - "type": "category", + "type": "tutorial-category", "children": [ { "name": { diff --git a/src/components/article-pagination/index.tsx b/src/components/article-pagination/index.tsx index 08629e13..3eb1c354 100644 --- a/src/components/article-pagination/index.tsx +++ b/src/components/article-pagination/index.tsx @@ -55,7 +55,11 @@ const ArticlePagination = ({ handleClick(e, pagination.nextDoc.slug as string) }} > - + {pagination.nextDoc.name} Next » diff --git a/src/components/article-pagination/styles.ts b/src/components/article-pagination/styles.ts index 61731976..d0001a1d 100644 --- a/src/components/article-pagination/styles.ts +++ b/src/components/article-pagination/styles.ts @@ -27,6 +27,20 @@ const paginationBox: SxStyleProp = { color: '#4A596B', } +const justNext: SxStyleProp = { + ':hover': { + border: '1px solid #CCCED8', + boxShadow: '0px 0px 16px rgba(0, 0, 0, 0.1)', + color: '#000711', + }, + justifySelf: 'right', + border: '1px solid #E7E9EE', + padding: '16px', + borderRadius: '4px', + textAlign: 'right', + color: '#4A596B', +} + const paginationText: SxStyleProp = { whiteSpace: 'nowrap', overflow: 'hidden', @@ -48,6 +62,7 @@ const paginationLinkNext: SxStyleProp = { ...paginationLink, justifySelf: 'flex-end', textAlign: 'right', + justifyContent: 'right', } const paginationLinkPrevious: SxStyleProp = { @@ -56,6 +71,7 @@ const paginationLinkPrevious: SxStyleProp = { } export default { + justNext, mainContainer, flexContainer, paginationLinkNext, diff --git a/src/components/tutorial-index/index.tsx b/src/components/tutorial-index/index.tsx new file mode 100644 index 00000000..16a1dc95 --- /dev/null +++ b/src/components/tutorial-index/index.tsx @@ -0,0 +1,71 @@ +import { Box, Flex, Link, Text } from '@vtex/brand-ui' +import Breadcrumb from 'components/breadcrumb' + +import FeedbackSection from 'components/feedback-section' +import startHereImage from '../../../public/images/start-here.png' +import PageHeader from 'components/page-header' + +import styles from 'styles/documentation-page' +import ArticlePagination from 'components/article-pagination' +import { useIntl } from 'react-intl' + +const TutorialIndexing = ({ ...props }) => { + const intl = useIntl() + + return ( + <> + + + + +
+
+ {props.breadcrumbList.length > 1 ? ( + + ) : undefined} +
+ + + {props.name} + + + + In this section + + + {props.children.map( + (el: { slug: string; name: string }) => ( + {el.name} + ) + )} + + + +
+
+ + {props.isListed && ( + + )} +
+
+ + ) +} + +export default TutorialIndexing diff --git a/src/components/tutorial-markdown-render/index.tsx b/src/components/tutorial-markdown-render/index.tsx new file mode 100644 index 00000000..1cf13526 --- /dev/null +++ b/src/components/tutorial-markdown-render/index.tsx @@ -0,0 +1,145 @@ +import Head from 'next/head' +import { Box, Flex, Text } from '@vtex/brand-ui' +import Breadcrumb from 'components/breadcrumb' + +import FeedbackSection from 'components/feedback-section' +import OnThisPage from 'components/on-this-page' +import SeeAlsoSection from 'components/see-also-section' +import startHereImage from '../../../public/images/start-here.png' +import PageHeader from 'components/page-header' +import { useIntl } from 'react-intl' +import DocumentContextProvider from 'utils/contexts/documentContext' +import { Item, MarkdownRenderer, TableOfContents } from '@vtexdocs/components' + +import styles from 'styles/documentation-page' +import ArticlePagination from 'components/article-pagination' +import Contributors from 'components/contributors' +import { MDXRemoteSerializeResult } from 'next-mdx-remote' +import { ContributorsType } from 'utils/getFileContributors' + +interface Props { + content: string + serialized: MDXRemoteSerializeResult + contributors: ContributorsType[] + path: string + headingList: Item[] + seeAlsoData: { + url: string + title: string + category: string + }[] + // sectionSelected: string + // sidebarfallback: any //eslint-disable-line + slug: string + // parentsArray: string[] + // path: string + isListed: boolean + branch: string + pagination: { + previousDoc: { + slug: string | null + name: string | null + } + nextDoc: { + slug: string | null + name: string | null + } + } + breadcrumbList: { slug: string; name: string; type: string }[] + headings: Item[] +} +const TutorialMarkdownRender = (props: Props) => { + const intl = useIntl() + + return ( + <> + + {props.serialized.frontmatter?.title as string} + + {props.serialized.frontmatter?.hidden && ( + + )} + {props.serialized.frontmatter?.excerpt && ( + + )} + + + + + + +
+
+ + + {props.serialized.frontmatter?.title} + + + {props.serialized.frontmatter?.excerpt} + +
+ + {intl.formatMessage( + { + id: 'documentation_reading_time.text', + defaultMessage: '', + }, + { + minutes: props.serialized.frontmatter?.readingTime, + } + )} + + +
+
+ + + + + + + + {props.isListed && ( + + )} + {props.serialized.frontmatter?.seeAlso && ( + + )} + + + + + + +
+
+ + ) +} + +export default TutorialMarkdownRender diff --git a/src/messages/en.json b/src/messages/en.json index 23bf8572..d1ad571d 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -244,6 +244,11 @@ "sort.label": "Sort by:", "sort.recently_updated": "Recently updated", "sort.newest": "Newest", + "known_issues_result.empty": "No matching results. Try other filters.", + "known_issues_date.created": "Created at", + "known_issues_date.updated": "Updated at", + "tutorial_and_solutions_page.title": "Tutorials & Solutions", + "tutorial_and_solutions_page.description": "Access the documentation of all platform modules and clarify your doubts.", "date_text.created": "Published on", "date_text.updated": "Last update on", "announcements_page_result.empty": "No matching results.", diff --git a/src/messages/es.json b/src/messages/es.json index 39215cf7..7a76b725 100644 --- a/src/messages/es.json +++ b/src/messages/es.json @@ -250,6 +250,11 @@ "sort.label": "Ordenar por:", "sort.recently_updated": "Recientemente actualizados", "sort.newest": "Más nuevos", + "known_issues_result.empty": "Ningún resultado coincidente. Pruebe con otros filtros.", + "known_issues_date.created": "Creado en", + "known_issues_date.updated": "Actualizado en", + "tutorial_and_solutions_page.title": "Tutoriales y Soluciones", + "tutorial_and_solutions_page.description": "Accede a la documentación de todos los módulos de la plataforma y resuelve tus dudas.", "date_text.created": "Publicado en", "date_text.updated": "Última actualización", "announcements_page_result.empty": "Ningún resultado coincidente.", diff --git a/src/messages/pt.json b/src/messages/pt.json index ddc0382d..7d034786 100644 --- a/src/messages/pt.json +++ b/src/messages/pt.json @@ -265,6 +265,11 @@ "sort.label": "Ordenar por:", "sort.recently_updated": "Recentemente atualizado", "sort.newest": "Mais novos", + "known_issues_result.empty": "Nenhum resultado correspondente. Tente outros filtros.", + "known_issues_date.created": "Criado em", + "known_issues_date.updated": "Atualizado em", + "tutorial_and_solutions_page.title": "Tutoriais & Soluções", + "tutorial_and_solutions_page.description": "Acesse a documentação de todas os módulos da plataforma e tire suas dúvidas.", "date_text.created": "Publicado em", "date_text.updated": "Última atualização em", "announcements_page_result.empty": "Nenhum resultado correspondente.", diff --git a/src/pages/docs/tutorial/[slug].tsx b/src/pages/docs/tutorial/[slug].tsx index 1af7a8bb..c8b60ff2 100644 --- a/src/pages/docs/tutorial/[slug].tsx +++ b/src/pages/docs/tutorial/[slug].tsx @@ -1,9 +1,8 @@ -import Head from 'next/head' import { useEffect, useState, useContext } from 'react' import { GetStaticPaths, GetStaticProps, NextPage } from 'next' import { PHASE_PRODUCTION_BUILD } from 'next/constants' import jp from 'jsonpath' -import ArticlePagination from 'components/article-pagination' + import { serialize } from 'next-mdx-remote/serialize' import { MDXRemoteSerializeResult } from 'next-mdx-remote' import remarkGFM from 'remark-gfm' @@ -13,17 +12,7 @@ import remarkBlockquote from 'utils/remark_plugins/rehypeBlockquote' import remarkImages from 'utils/remark_plugins/plaiceholder' -import { Box, Flex, Text } from '@vtex/brand-ui' - -import DocumentContextProvider from 'utils/contexts/documentContext' - -import Contributors from 'components/contributors' -import { Item, LibraryContext, MarkdownRenderer } from '@vtexdocs/components' -import FeedbackSection from 'components/feedback-section' -import OnThisPage from 'components/on-this-page' -import SeeAlsoSection from 'components/see-also-section' -import { TableOfContents } from '@vtexdocs/components' -import Breadcrumb from 'components/breadcrumb' +import { Item, LibraryContext } from '@vtexdocs/components' import getHeadings from 'utils/getHeadings' import getNavigation from 'utils/getNavigation' @@ -34,27 +23,41 @@ import escapeCurlyBraces from 'utils/escapeCurlyBraces' import replaceHTMLBlocks from 'utils/replaceHTMLBlocks' import { PreviewContext } from 'utils/contexts/preview' -import styles from 'styles/documentation-page' import { ContributorsType } from 'utils/getFileContributors' import { getLogger } from 'utils/logging/log-util' import { flattenJSON, + getChildren, getKeyByValue, getParents, localeType, } from 'utils/navigation-utils' + +import { remarkReadingTime } from 'utils/remark_plugins/remarkReadingTime' + +import TutorialIndexing from 'components/tutorial-index' +import TutorialMarkdownRender from 'components/tutorial-markdown-render' + // import { ParsedUrlQuery } from 'querystring' const docsPathsGLOBAL = await getTutorialsPaths('tutorials') -interface Props { - sectionSelected: string - parentsArray: string[] - breadcrumbList: { slug: string; name: string; type: string }[] +interface TutorialIndexingDataI { + name: string + children: { name: string; slug: string }[] + hidePaginationPrevious: boolean + hidePaginationNext: boolean +} + +interface TutorialIndexingProps { + tutorialData: TutorialIndexingDataI +} + +interface MarkDownProps { + // sectionSelected: string content: string serialized: MDXRemoteSerializeResult - sidebarfallback: any //eslint-disable-line contributors: ContributorsType[] path: string headingList: Item[] @@ -63,105 +66,102 @@ interface Props { title: string category: string }[] - pagination: { - previousDoc: { - slug: string | null - name: string | null +} + +type Props = + | { + sectionSelected: string + sidebarfallback: any //eslint-disable-line + slug: string + parentsArray: string[] + // path: string + isListed: boolean + branch: string + pagination: { + previousDoc: { + slug: string | null + name: string | null + } + nextDoc: { + slug: string | null + name: string | null + } + } + breadcrumbList: { slug: string; name: string; type: string }[] + type: 'markdown' + componentProps: MarkDownProps } - nextDoc: { - slug: string | null - name: string | null + | { + sectionSelected: string + sidebarfallback: any //eslint-disable-line + slug: string + parentsArray: string[] + isListed: boolean + branch: string + pagination: { + previousDoc: { + slug: string | null + name: string | null + } + nextDoc: { + slug: string | null + name: string | null + } + } + breadcrumbList: { slug: string; name: string; type: string }[] + type: 'tutorial-category' + componentProps: TutorialIndexingProps } - } - isListed: boolean - branch: string -} const TutorialPage: NextPage = ({ - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore + type, slug, - serialized, - path, - headingList, - contributors, - seeAlsoData, - pagination, isListed, - breadcrumbList, branch, + pagination, + breadcrumbList, + componentProps, }) => { const [headings, setHeadings] = useState([]) const { setBranchPreview } = useContext(PreviewContext) setBranchPreview(branch) const { setActiveSidebarElement } = useContext(LibraryContext) + useEffect(() => { - setActiveSidebarElement(slug) - setHeadings(headingList) - }, [serialized.frontmatter]) - return ( - <> - - {serialized.frontmatter?.title as string} - - {serialized.frontmatter?.hidden && ( - - )} - {serialized.frontmatter?.excerpt && ( - - )} - - - - - -
-
- - - {serialized.frontmatter?.title} - - - {serialized.frontmatter?.excerpt} - -
- -
-
- - - - - - - - {isListed && ( - - )} - {serialized.frontmatter?.seeAlso && ( - - )} - - - - - - -
-
- + if (type === 'markdown') { + setActiveSidebarElement(slug) + setHeadings(componentProps.headingList) + } + }, []) + + return type === 'markdown' ? ( + + ) : ( + ) } @@ -202,13 +202,137 @@ export const getStaticProps: GetStaticProps = async ({ const currentLocale: localeType = locale ? (locale as localeType) : ('en' as localeType) + const logger = getLogger('Tutorials & Solutions') + + const sidebarfallback = await getNavigation() + const flattenedSidebar = flattenJSON(sidebarfallback) + const keyPath = getKeyByValue(flattenedSidebar, slug) + + if (!keyPath) { + return { + notFound: true, + } + } + + const keyPathType = keyPath.split('slug')[0].concat('type') + const type = flattenedSidebar[keyPathType] + + const parentsArray: string[] = [] + const parentsArrayName: string[] = [] + const parentsArrayType: string[] = [] + + const isListed = !(keyPath === undefined) + + getParents(keyPath, 'slug', flattenedSidebar, currentLocale, parentsArray) + parentsArray.push(slug) + + getParents(keyPath, 'name', flattenedSidebar, currentLocale, parentsArrayName) + const mainKeyPath = keyPath.split('slug')[0] + const nameKeyPath = mainKeyPath.concat(`name.${locale}`) + const categoryTitle = flattenedSidebar[nameKeyPath] + parentsArrayName.push(categoryTitle) + + getParents(keyPath, 'type', flattenedSidebar, currentLocale, parentsArrayType) + const typeKeyPath = mainKeyPath.concat('type') + parentsArrayType.push(flattenedSidebar[typeKeyPath]) + + const sectionSelected = flattenedSidebar[`${keyPath[0]}.documentation`] + console.log('TUTORIAL', sectionSelected) + + const breadcrumbList: { slug: string; name: string; type: string }[] = [] + parentsArrayName.forEach((_el: string, idx: number) => { + breadcrumbList.push({ + slug: `/docs/tutorial/${parentsArray[idx]}`, + name: parentsArrayName[idx], + type: parentsArrayType[idx], + }) + }) + + if (type === 'tutorial-category') { + const childrenArrayName: string[] = [] + const childrenArraySlug: string[] = [] + + getChildren( + keyPath, + 'name', + flattenedSidebar, + currentLocale, + childrenArrayName + ) + getChildren( + keyPath, + 'slug', + flattenedSidebar, + currentLocale, + childrenArraySlug + ) + + const childrenList: { slug: string; name: string }[] = [] + childrenArrayName.forEach((_el: string, idx: number) => { + childrenList.push({ + slug: `/docs/tutorial/${childrenArraySlug[idx]}`, + name: childrenArrayName[idx], + }) + }) + + const previousDoc: { slug: string; name: string } = + breadcrumbList.length > 1 + ? { + slug: breadcrumbList[breadcrumbList.length - 2].slug, + name: breadcrumbList[breadcrumbList.length - 2].name, + } + : { + slug: '', + name: '', + } + const nextDoc: { slug: string; name: string } = { + slug: childrenList[0].slug, + name: childrenList[0].name, + } + + let hidePaginationPrevious = false + if (breadcrumbList.length < 2) { + hidePaginationPrevious = true + } + + let hidePaginationNext = false + if (!childrenList) { + hidePaginationNext = true + } + + const pagination = { previousDoc: previousDoc, nextDoc: nextDoc } + const componentProps = { + tutorialData: { + name: categoryTitle, + children: childrenList, + hidePaginationPrevious: hidePaginationPrevious, + hidePaginationNext: hidePaginationNext, + }, + } + + return { + props: { + type, + sectionSelected, + sidebarfallback, + parentsArray, + slug, + pagination, + isListed, + breadcrumbList, + branch, + componentProps, + }, + revalidate: 600, + } + } + const docsPaths = process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD ? docsPathsGLOBAL : await getTutorialsPaths('tutorials', branch) - const logger = getLogger('Tutorials & Solutions') - const path = docsPaths[slug].find((e) => e.locale === locale)?.path + const path = docsPaths[slug]?.find((e) => e.locale === locale)?.path if (!path) { return { @@ -216,13 +340,6 @@ export const getStaticProps: GetStaticProps = async ({ } } - // let documentationContent = await getGithubFile( - // 'vtexdocs', - // 'help-center-content', - // branch, - // pathcontribut - // ) - let documentationContent = (await fetch( `https://raw.githubusercontent.com/vtexdocs/help-center-content/${branch}/${path}` @@ -230,16 +347,6 @@ export const getStaticProps: GetStaticProps = async ({ .then((res) => res.text()) .catch((err) => console.log(err))) || '' - // const contributors = - // (await getFileContributors( - // 'vtexdocs', - // 'help-center-content', - // branch, - // path - // ).catch((err) => { - // console.log(err) - // })) || [] - const contributors = (await fetch( `https://github.com/vtexdocs/help-center-content/file-contributors/${branch}/${path}`, @@ -292,6 +399,7 @@ export const getStaticProps: GetStaticProps = async ({ remarkImages, [getHeadings, { headingList }], remarkBlockquote, + remarkReadingTime, ], rehypePlugins: [ [rehypeHighlight, { languages: { hljsCurl }, ignoreMissing: true }], @@ -300,7 +408,6 @@ export const getStaticProps: GetStaticProps = async ({ }, }) - const sidebarfallback = await getNavigation() serialized = JSON.parse(JSON.stringify(serialized)) logger.info(`Processing ${slug}`) @@ -382,60 +489,26 @@ export const getStaticProps: GetStaticProps = async ({ }, } - const flattenedSidebar = flattenJSON(sidebarfallback) - const isListed: boolean = getKeyByValue(flattenedSidebar, slug) - ? true - : false - const keyPath = getKeyByValue(flattenedSidebar, slug) - const parentsArray: string[] = [] - const parentsArrayName: string[] = [] - const parentsArrayType: string[] = [] - let sectionSelected = '' - if (keyPath) { - sectionSelected = flattenedSidebar[`${keyPath[0]}.documentation`] - getParents(keyPath, 'slug', flattenedSidebar, currentLocale, parentsArray) - parentsArray.push(slug) - getParents( - keyPath, - 'name', - flattenedSidebar, - currentLocale, - parentsArrayName - ) - getParents( - keyPath, - 'type', - flattenedSidebar, - currentLocale, - parentsArrayType - ) + const componentProps = { + serialized: serialized, + headingList: headingList, + contributors: contributors, + path: path, + seeAlsoData: seeAlsoData, } - const breadcrumbList: { slug: string; name: string; type: string }[] = [] - parentsArrayName.forEach((_el: string, idx: number) => { - breadcrumbList.push({ - slug: `/docs/tutorial/${parentsArray[idx]}`, - name: parentsArrayName[idx], - type: parentsArrayType[idx], - }) - }) - return { props: { + type, sectionSelected, + sidebarfallback, parentsArray, slug, - serialized, - sidebarfallback, - headingList, - contributors, - path, - seeAlsoData, pagination, isListed, breadcrumbList, branch, - locale, + componentProps, }, revalidate: 600, } diff --git a/src/styles/documentation-page.ts b/src/styles/documentation-page.ts index c5f615fb..4ea3b2b0 100644 --- a/src/styles/documentation-page.ts +++ b/src/styles/documentation-page.ts @@ -20,6 +20,7 @@ const innerContainer: SxStyleProp = { const articleBox: SxStyleProp = { fontSize: '1em', lineHeight: '1.375em', + width: ['100%', 'auto'], a: { color: '#E31C58', }, @@ -139,7 +140,37 @@ const id: SxStyleProp = { wordBreak: 'break-all', } +const indexContainer: SxStyleProp = { + borderTop: '1px solid #E7E9EE', + gap: '32px', +} + +const textContainer: SxStyleProp = { + width: ['100%', '544px'], + gap: '8px', + pb: '43px', + mb: '64px', +} + +const titleContainer: SxStyleProp = { + fontSize: '24px', + color: '#4A4A4A', + marginBottom: '8px', +} + +const linksContainer: SxStyleProp = { + flexDirection: 'column', + pl: '16px', + gap: '16px', + mt: '32px', + borderLeft: '3px solid #E7E9EE', +} + export default { + linksContainer, + titleContainer, + textContainer, + indexContainer, container, mainContainer, articleBox, diff --git a/src/utils/getNavigation.ts b/src/utils/getNavigation.ts index 6c25a75c..05408c74 100644 --- a/src/utils/getNavigation.ts +++ b/src/utils/getNavigation.ts @@ -1,9 +1,12 @@ -import { enumerateNavigation } from './enumerate-navigation' +// import { enumerateNavigation } from './enumerate-navigation' + +import navigationjson from '../../public/navigation.json' export default async function getNavigation() { - const navigationJsonUrl = process.env.navigationJsonUrl - const result = await fetch(navigationJsonUrl as string) - .then((res) => res.json()) - .then((res) => enumerateNavigation(res.navbar)) - return result + // const navigationJsonUrl = process.env.navigationJsonUrl + // const result = await fetch(navigationJsonUrl as string) + // .then((res) => res.json()) + // .then((res) => enumerateNavigation(res.navbar)) + // return result + return navigationjson.navbar } diff --git a/src/utils/navigation-utils.ts b/src/utils/navigation-utils.ts index f092f45b..35d08aac 100644 --- a/src/utils/navigation-utils.ts +++ b/src/utils/navigation-utils.ts @@ -54,3 +54,27 @@ export const getParents = ( return parentsArray } + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const getChildren = ( + path: string, + data: string, + flattenedSidebar: { [x: string]: string }, + locale: localeType = 'en', + childrenArray: string[] +) => { + const childrenBasePath = path?.split('slug')[0].concat('children.') + const desiredData = data === 'name' ? `${data}.${locale}` : data + + for (let i = 0; i < 100; i++) { + const completePath = childrenBasePath + .concat(String(i)) + .concat(`.${desiredData}`) + if (!flattenedSidebar[completePath]) { + break + } + childrenArray.push(flattenedSidebar[completePath]) + } + + return childrenArray +}