diff --git a/src/_components/Layouts/ContentViewer.tsx b/src/_components/Layouts/ContentViewer.tsx index def2a43..7c80af5 100644 --- a/src/_components/Layouts/ContentViewer.tsx +++ b/src/_components/Layouts/ContentViewer.tsx @@ -25,7 +25,7 @@ import type { ContentItem, RelatedContent } from '@/lib/Types'; import { loadMDX } from './lib/loadMDX'; // import { mdComponents } from '../../constants/mdxProvider.js'; const logger = getLogger().child({ namespace: 'ContentViewer' }); -logger.level = 'error'; +logger.level = 'debug'; type Contributor = { authorName: string; @@ -92,6 +92,19 @@ export function ContentViewer({ router.push(`${currentPath}/print`); } + function handleContentChange(callback: any) { + // add '/related_content/' and the callback file to the path + router.push(`${currentPath}/related_content/${callback}`); + } + + function handlePageReset() { + // reset the path to the current path before /related_content + const rootPath = currentPath.split('/related_content')[0]; + if (rootPath) { + router.push(rootPath); + } + } + if (loading) { return ; } @@ -143,12 +156,9 @@ export function ContentViewer({ {}} - handlePageReset={() => {}} + handleContentChange={(callback) => handleContentChange(callback)} + handlePageReset={() => handlePageReset()} loading={false} - // handleContentChange={handleContentChange} - // handlePageReset={handlePageReset} - // file={context.file} /> {/* {sideComponent && } */} {frontmatter?.tableOfContents && ( diff --git a/src/_components/Layouts/lib/getTiles.ts b/src/_components/Layouts/lib/getTiles.ts index 7f7eb76..b1d430c 100644 --- a/src/_components/Layouts/lib/getTiles.ts +++ b/src/_components/Layouts/lib/getTiles.ts @@ -10,6 +10,7 @@ import type { FileContent, FrontMatter, GitHubFile, + MatterData, } from '@/lib/Types'; const logger = getLogger().child({ module: 'getTiles' }); @@ -25,11 +26,6 @@ interface Tile { [key: string]: any; } -interface MatterData { - title: string; - [key: string]: Date | string; -} - export async function getTiles(config: ContentItem): Promise<{ loading: boolean; error: Error | null | unknown; diff --git a/src/_components/Layouts/lib/mdxComponents.tsx b/src/_components/Layouts/lib/mdxComponents.tsx index 179c88b..ff9c712 100644 --- a/src/_components/Layouts/lib/mdxComponents.tsx +++ b/src/_components/Layouts/lib/mdxComponents.tsx @@ -67,7 +67,10 @@ const components = { showLineNumbers={!!language} // customStyle={{ overflow: 'clip', fontSize: '0.75rem', whiteSpace: 'pre-wrap' }} customStyle={{ - display: language ? 'block' : 'inline', + // display: language ? 'block' : 'inline', + display: 'block', + overflow: 'clip', + whiteSpace: 'pre-wrap', ...(language ? { fontSize: '0.75rem' } : { background: 'unset', padding: 'unset', fontSize: '0.85rem' }), diff --git a/src/app/api/content/github/route.ts b/src/app/api/content/github/route.ts index d641d44..f72249e 100644 --- a/src/app/api/content/github/route.ts +++ b/src/app/api/content/github/route.ts @@ -42,7 +42,7 @@ export async function GET(req: NextRequest) { // return NextResponse.json({ files }); // } - const data = await getFileContent(owner, repo, branch, filepath); + const data = await getFileContent({ owner, repo, branch, path: filepath }); const extension = path.extname(filepath); const contentType = mime.lookup(extension) || 'application/octet-stream'; // logger.info(`[GET /api/content/github][data]: ${util.inspect(data)}`); diff --git a/src/app/docs/[[...path]]/page.tsx b/src/app/docs/[[...path]]/page.tsx index d62618a..19fcc9e 100644 --- a/src/app/docs/[[...path]]/page.tsx +++ b/src/app/docs/[[...path]]/page.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next' +import matter from 'gray-matter'; import React from "react"; import { IndexTiles, LandingPage, MenuWrapper, ContentViewer, ContentLoader, ContentPrint } from "@/components/Layouts"; @@ -7,7 +8,7 @@ import { siteConfig } from "../../../../site.config"; import { notFound } from "next/navigation"; import { getFileContent } from "@/lib/Github"; import { getLogger } from '@/lib/Logger'; -import type { ContentItem } from '@/lib/Types'; +import type { ContentItem, MatterData } from '@/lib/Types'; import { loadMenu, nestMenu } from '@/lib/Content/loadMenu'; const logger = getLogger().child({ namespace: 'docs/page' }); logger.level = 'error'; @@ -16,6 +17,47 @@ export const metadata: Metadata = { description: "Airview AI", }; + +async function checkFrontmatter(content: string, context: ContentItem) { + const matterData = matter(content, { + excerpt: false, + }).data as MatterData; + if (matterData) { + Object.keys(matterData).forEach((key) => { + if ( + matterData && + matterData[key] && + matterData[key] instanceof Date + ) { + matterData[key] = (matterData[key] as Date).toISOString(); + } + }); + } + if (matterData && matterData.external_repo && matterData.external_owner && matterData.external_path && matterData.git_provider) { + const { external_repo, external_owner, external_path } = matterData; + const owner = external_owner as string; + const repo = external_repo as string; + const branch = context.branch + const file = external_path as string; + let pageContent; + try { + pageContent = await getFileContent({owner, repo, path: file}); + } catch (error) { + logger.error({ msg: 'checkFrontmatter: ', error}); + } + let linkedContent = ""; + if (pageContent && pageContent.content ) { + linkedContent = pageContent?.content + ? Buffer.from(pageContent.content).toString() + : ""; + } + return { content: linkedContent, context: { ...context, owner, repo, branch, file } }; + + } else { + return { content, context} + } +} + export default async function Page({ params, }: { @@ -33,7 +75,18 @@ export default async function Page({ path = path.slice(0, -1); isPrint = true; } - const file = path.join("/") as string; + + let file = ''; + + // if 'related_config' is somewhere in the path, then the file is the last element in the path + if (path.includes('related_content')) { + // join all the parts after related_config + file = path.slice(path.indexOf('related_content') + 1).join("/") as string; + } else { + file = path.join("/") as string; + } + + // const file = path.join("/") as string; let pageContent; let pageContentText; let loading = false; @@ -81,13 +134,17 @@ export default async function Page({ if (contentConfig?.owner && contentConfig?.repo && contentConfig?.branch && file) { const { owner, repo, branch } = contentConfig; - pageContent = await getFileContent(owner, repo, branch, file); + pageContent = await getFileContent({owner, repo, path: file, branch}); if (pageContent && pageContent.content ) { pageContentText = pageContent?.content ? Buffer.from(pageContent.content).toString() : ""; } + const { content: linkedPageContentText, context } = await checkFrontmatter(pageContentText || '', contentConfig); // check for frontmatter context + pageContentText = linkedPageContentText; + + logger.debug({ msg: 'context: ', context}); const content = await loadMenu(siteConfig, menuConfig(contentConfig)); @@ -113,7 +170,7 @@ export default async function Page({ menuStructure={menuStructure} loading={loading} context={contentConfig}> - + ); diff --git a/src/lib/Github.ts b/src/lib/Github.ts index b0ea9d9..1d8d569 100644 --- a/src/lib/Github.ts +++ b/src/lib/Github.ts @@ -255,13 +255,21 @@ async function getCachedFileContent( return null; } -async function getGitHubFileContent( - owner: string, - repo: string, - branch: string, - path: string, - branchShaParam: string | undefined = undefined, -): Promise<{ +interface GitHubFileContentOptions { + owner: string; + repo: string; + path: string; + branchShaParam?: string; + branch?: string; +} + +async function getGitHubFileContent({ + owner, + repo, + path, + branchShaParam, + branch, +}: GitHubFileContentOptions): Promise<{ content: Buffer | undefined; encoding: string; contributors: { authorName: string; authorDate: string }[]; @@ -279,26 +287,41 @@ async function getGitHubFileContent( branchShaParam, }); let branchSha = null; - if (!branchShaParam) { + if (!branchShaParam && branch) { branchSha = await getBranchSha(owner, repo, branch); - } else { + } else if (branchShaParam) { branchSha = branchShaParam; } let response; try { - response = (await gitHubInstance.repos.getContent({ - owner, - repo, - path, - ref: branchSha, - })) as { - data: { - encoding: string; - sha: string; - content?: string; - download_url?: string; + if (branchSha) { + response = (await gitHubInstance.repos.getContent({ + owner, + repo, + path, + ref: branchSha, + })) as { + data: { + encoding: string; + sha: string; + content?: string; + download_url?: string; + }; + }; + } else { + response = (await gitHubInstance.repos.getContent({ + owner, + repo, + path, + })) as { + data: { + encoding: string; + sha: string; + content?: string; + download_url?: string; + }; }; - }; + } } catch (error: any) { logger.error({ function: 'getGitHubFileContent', @@ -438,15 +461,24 @@ async function getGitHubFileContent( return null; } } + +interface FileContentOptions { + owner: string; + repo: string; + path: string; + fileSha?: string; + branchSha?: string; + branch?: string; +} // Function to get a file content -export async function getFileContent( - owner: string, - repo: string, - branch: string, - path: string, - fileSha: string | undefined = undefined, - branchSha: string | undefined = undefined, -): Promise<{ +export async function getFileContent({ + owner, + repo, + path, + fileSha, + branchSha, + branch, +}: FileContentOptions): Promise<{ content: Buffer | undefined; encoding: string; contributors: { @@ -457,25 +489,29 @@ export async function getFileContent( // if the SHA is passed, this is a specific revision of a file. // if not, pull back the generic revision of the file, stored with the branch sha instead. - const cachedContent = await getCachedFileContent( - owner, - repo, - branch, - path, - fileSha, - ); - // logger.info(`github:getFileContent:getCachedFileContent ${cachedContent}`); - if (cachedContent) { - logger.info(`[GitHub][getGitHubFileContent][Cache/Hit]: ${path}`); - return cachedContent; + if (branch) { + const cachedContent = await getCachedFileContent( + owner, + repo, + branch, + path, + fileSha, + ); + // logger.info(`github:getFileContent:getCachedFileContent ${cachedContent}`); + if (cachedContent) { + logger.info(`[GitHub][getGitHubFileContent][Cache/Hit]: ${path}`); + return cachedContent; + } + const file = await getGitHubFileContent({ + owner, + repo, + path, + branchShaParam: branchSha, + branch, + }); + return file; } - const file = await getGitHubFileContent(owner, repo, branch, path, branchSha); - - // const unencodedContent = Buffer.from( - // file?.content?.toString() || '', - // 'binary', - // ); - + const file = await getGitHubFileContent({ owner, repo, path }); return file; }