diff --git a/Source/SuperOffice.DocsNext/ClientApp/astro.config.mjs b/Source/SuperOffice.DocsNext/ClientApp/astro.config.mjs index a28417b5..c2266a64 100644 --- a/Source/SuperOffice.DocsNext/ClientApp/astro.config.mjs +++ b/Source/SuperOffice.DocsNext/ClientApp/astro.config.mjs @@ -10,6 +10,7 @@ import { rehypeHeadingIds } from "@astrojs/markdown-remark"; import rehypeAutolinkHeadings from "rehype-autolink-headings"; import remarkIncludeDirective from "./src/plugins/AddIncludesToMarkdown.js"; import remarkRestyleDirective from "./src/plugins/RestyleDirectives.js"; +import remarkFixRelativeLinks from "./src/plugins/FixMarkdownLinks.js" import react from "@astrojs/react"; import yaml from '@rollup/plugin-yaml'; import redirectFrom from "astro-redirect-from"; @@ -22,7 +23,8 @@ export default defineConfig({ ], markdown: { - remarkPlugins: [remarkDirective, codeImport, remarkIncludeDirective, remarkRestyleDirective], + remarkPlugins: [remarkDirective, codeImport, remarkIncludeDirective, remarkRestyleDirective, remarkFixRelativeLinks + ], rehypePlugins: [ rehypeHeadingIds, [ @@ -123,5 +125,5 @@ export default defineConfig({ logLevel: process.env.CI ? 'error' : 'info', site: "https://app-superoffice-docs-dev.azurewebsites.net/", // base: "/", - // trailingSlash: "never", + // trailingSlash: "ignore", }); diff --git a/Source/SuperOffice.DocsNext/ClientApp/src/components/CategoryLandingAdditionalContentCard.astro b/Source/SuperOffice.DocsNext/ClientApp/src/components/CategoryLandingAdditionalContentCard.astro index 211e0a4e..d6464e0a 100644 --- a/Source/SuperOffice.DocsNext/ClientApp/src/components/CategoryLandingAdditionalContentCard.astro +++ b/Source/SuperOffice.DocsNext/ClientApp/src/components/CategoryLandingAdditionalContentCard.astro @@ -17,14 +17,14 @@ interface Props { class={`bg-white px-3 py-5 lg:m-0 duration-300 ease-in-out transition-shadow hover:shadow-[0_0px_8px_rgba(0,0,0,0.70)] min-h-full`} >
- {item.title} + {item.title} { item.links?.map((subitem) => { return (
{subitem.text} diff --git a/Source/SuperOffice.DocsNext/ClientApp/src/components/TableOfContentList.tsx b/Source/SuperOffice.DocsNext/ClientApp/src/components/TableOfContentList.tsx index ca5bfa3c..887fff4b 100644 --- a/Source/SuperOffice.DocsNext/ClientApp/src/components/TableOfContentList.tsx +++ b/Source/SuperOffice.DocsNext/ClientApp/src/components/TableOfContentList.tsx @@ -104,7 +104,7 @@ export default function TableOfContentList({ // console.warn(`[generatePath] Missing href/topicHref for TOC item:`, item); return "#"; } - const formattedURL = `${slug}/${trimFileExtension(rawPath)}`.replace("/index", "") + const formattedURL = `${slug}/${trimFileExtension(rawPath)}`.replace("/index", "/") const resolvedPath = new URL(formattedURL, "http://docs.superoffice.com").pathname; return resolvedPath; }; diff --git a/Source/SuperOffice.DocsNext/ClientApp/src/plugins/FixMarkdownLinks.js b/Source/SuperOffice.DocsNext/ClientApp/src/plugins/FixMarkdownLinks.js new file mode 100644 index 00000000..326e069d --- /dev/null +++ b/Source/SuperOffice.DocsNext/ClientApp/src/plugins/FixMarkdownLinks.js @@ -0,0 +1,26 @@ +import { visit } from 'unist-util-visit'; + +/** + * Fix Markdown links and definitions that end with `.md` or `/index.md` + */ +export default function remarkFixMarkdownLinks() { + return (tree) => { + // Handle both inline links and reference definitions + visit(tree, ['link', 'definition'], (node) => { + if (!node.url || typeof node.url !== 'string') return; + + let url = node.url.trim(); + + // Skip external and anchor links + if (url.startsWith('http') || url.startsWith('#')) return; + + // Remove trailing /index.md + url = url.replace(/\/index\.md(?=$|[?#])/i, '/'); + + // Remove trailing .md + url = url.replace(/\.md$/i, ''); + + node.url = url; + }); + }; +} diff --git a/Source/SuperOffice.DocsNext/ClientApp/src/plugins/RestyleDirectives.js b/Source/SuperOffice.DocsNext/ClientApp/src/plugins/RestyleDirectives.js index a52007a4..2ed8d653 100644 --- a/Source/SuperOffice.DocsNext/ClientApp/src/plugins/RestyleDirectives.js +++ b/Source/SuperOffice.DocsNext/ClientApp/src/plugins/RestyleDirectives.js @@ -46,9 +46,10 @@ export default function remarkRestyleDirective() { if (remainingText) { textNode.value = remainingText; - contentChildren = para.children; + contentChildren = node.children; } else { - contentChildren = para.children.slice(1); + // Remove first paragraph if it only contained the directive + contentChildren = node.children.slice(1); } node.type = 'parent'; diff --git a/Source/SuperOffice.DocsNext/ClientApp/src/utils/slugUtils.ts b/Source/SuperOffice.DocsNext/ClientApp/src/utils/slugUtils.ts index a4b8ce5e..03247637 100644 --- a/Source/SuperOffice.DocsNext/ClientApp/src/utils/slugUtils.ts +++ b/Source/SuperOffice.DocsNext/ClientApp/src/utils/slugUtils.ts @@ -9,7 +9,7 @@ const contentRepo = "superoffice-docs"; // primary content repository */ export function stripFilePathAndExtension(filePath: string, collection: string): string { const base = `${contentDir}/` - return filePath.replace(base, "").replace(`${collection}/`, "").replace(/\/index/g, "").replace(/\.(md|yml|yaml)$/g, "");; + return filePath.replace(base, "").replace(`${collection}/`, "").replace(/\/index/g, "/").replace(/\.(md|yml|yaml)$/g, "");; } /** @@ -154,6 +154,6 @@ export function resolveRelativeFilePath(currentPath: string, filepath: string): return filepath } - return `${currentPath.split("/").pop()?.replace(/\.html$/, "")}/${trimFileExtension(filepath).replace(/\/index$/, "")}` + return `${currentPath.split("/").filter(Boolean).pop()?.replace(/\.html$/, "")}/${trimFileExtension(filepath).replace(/\/index$/, "/")}` } \ No newline at end of file diff --git a/Source/SuperOffice.DocsNext/Program.cs b/Source/SuperOffice.DocsNext/Program.cs index 5b7a74b2..7073ff34 100644 --- a/Source/SuperOffice.DocsNext/Program.cs +++ b/Source/SuperOffice.DocsNext/Program.cs @@ -108,6 +108,7 @@ // Redirect /something.html -> /something (permanent redirect) .AddRedirect(@"^(.*)\.html$", "$1", statusCode: 301) .AddRewrite(@"^$", "index.html", skipRemainingRules: true) + .AddRewrite(@"^(.*)/$", "$1.html", skipRemainingRules: true) // Rewrite /something -> /something.html (internal rewrite) // But avoids rewriting known static file types .AddRewrite(@"^(?!.*\.(?:js|css|png|jpg|jpeg|gif|svg|ico|json|txt|xml|map)$)(.*)$", "$1.html", skipRemainingRules: true);