diff --git a/.env.example b/.env.example index 56b55dbade..c5a3a49171 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,6 @@ # Absolute path to the root of the docs source repository. # This directory must contain en/components/toc.yml and en/components/*.md # -# Windows example: DOCS_SOURCE_PATH=C:/Repos/docs/igniteui-docfx -# macOS/Linux: DOCS_SOURCE_PATH=/home/user/repos/igniteui-docfx +# Windows example: DOCS_SOURCE_PATH=C:/Repos/docs/my-docs-source +# macOS/Linux: DOCS_SOURCE_PATH=/home/user/repos/my-docs-source DOCS_SOURCE_PATH= diff --git a/astro.config.ts b/astro.config.ts index 636cc04321..c8530eefcf 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -1,132 +1,17 @@ -import { defineConfig } from 'astro/config'; -import mdx from '@astrojs/mdx'; -import { buildSidebarFromToc, siteMetaIntegration } from './src/integration'; -import { getPlatformHead } from './src/platform'; -import path from 'node:path'; -import { loadEnv } from 'vite'; - -// Load .env into process.env — Vite/Astro does this for the browser bundle -// but NOT for astro.config.ts itself, so we do it explicitly here. -const env = loadEnv('', process.cwd(), ''); -Object.assign(process.env, env); - // --------------------------------------------------------------------------- -// Source paths — set via DOCS_SOURCE_PATH env var. -// For local development copy .env.example to .env and set an absolute path: -// DOCS_SOURCE_PATH=C:/Repos/docs/igniteui-docfx (Windows) -// DOCS_SOURCE_PATH=/home/user/repos/igniteui-docfx (macOS/Linux) +// Root astro.config.ts — NOT used for production builds. +// +// The actual docs sites are built via: +// docs/angular/astro.config.ts → Angular docs +// docs/xplat/astro.config.ts → React / Blazor / Web Components docs +// +// Both call createDocsSite() from src/integration.ts which assembles the +// full Astro configuration (plugins, sidebar, head entries, etc.). +// +// This file exists only so Astro tooling (language server, CLI) has a +// valid config when opened from the repo root. // --------------------------------------------------------------------------- -if (!process.env.DOCS_SOURCE_PATH) { - throw new Error( - '[docs-template] DOCS_SOURCE_PATH env var is required. ' + - 'Copy .env.example to .env and set an absolute path to the docs source repo root.' - ); -} - -const SOURCE_ROOT = path.resolve(process.env.DOCS_SOURCE_PATH); -const COMPONENTS = path.join(SOURCE_ROOT, 'en/components'); -const TOC_PATH = path.join(SOURCE_ROOT, 'en/components/toc.yml'); - -process.env.DOCS_SOURCE_PATH = COMPONENTS; - -const sidebar = buildSidebarFromToc({ - tocPath: TOC_PATH, - docsDir: COMPONENTS, - exclude: [ - /^grids_templates\//i, - /^style-guide\.md$/i, - /^themes\/sass\/presets\//i, - /^themes\.md$/i, - ], -}); +import { defineConfig } from 'astro/config'; -// https://astro.build/config -export default defineConfig({ - site: 'localhost:4321', - trailingSlash: 'never', - compressHTML: true, - build: { - assets: '_assets', - }, - vite: { - css: { - preprocessorOptions: { - scss: { - loadPaths: [path.join(process.cwd(), 'node_modules')], - silenceDeprecations: ['if-function'], - }, - }, - }, - }, - integrations: [ - starlight({ - title: 'Ignite UI for Angular', - logo: { - src: './public/favicon.svg', - }, - social: [ - { icon: 'github', label: 'GitHub', href: 'https://github.com/IgniteUI/igniteui-angular' }, - ], - sidebar, - // Prepend the packaged theme entry so consuming projects get the theme. - customCss: [ - './src/styles/ig-theme.scss', - ], - head: [ - // Platform CDN assets — driven by platform below - ...getPlatformHead('angular', 'en'), - // Angular-specific Ignite UI component bundle (repo-specific, not in shared registry) - // { tag: 'link', attrs: { rel: 'stylesheet', href: 'https://www.infragistics.com/products/ignite-ui-angular/angular/bundles/igniteui.f5cfb48022e69dd66658.css' } }, - // highlight.js for code-tab syntax highlighting inside code-view widgets - { tag: 'link', attrs: { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css' } }, - { tag: 'script', attrs: { src: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js', defer: true } }, - ], - editLink: { - baseUrl: 'https://github.com/IgniteUI/igniteui-docfx/edit/master/en/components/', - }, - components: { - PageFrame: './src/components/overrides/CustomPageFrame.astro', - Head: './src/components/overrides/Head.astro', - Header: './src/components/overrides/Header.astro', - Footer: './src/components/overrides/Footer.astro', - MobileTableOfContents: './src/components/overrides/MobileTableOfContents.astro', - Sidebar: './src/components/overrides/Sidebar/Sidebar.astro', - PageSidebar: './src/components/overrides/PageSidebar.astro', - }, - expressiveCode: { - themes: ['dark-plus'], - } - }), - siteMetaIntegration({ - title: 'Ignite UI for Angular', - platform: 'angular', - description: - 'Complete reference documentation for Ignite UI for Angular — a Material-based ' + - 'UI component library including Data Grid, Charts, Gauges, Calendars, and more.', - docsDir: COMPONENTS, - sidebar, - head: [ - ...getPlatformHead('angular', 'en'), - { tag: 'link', attrs: { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css' } }, - { tag: 'script', attrs: { src: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js', defer: true } }, - ], - productLinks: [ - { label: 'Angular', href: '#', platform: 'angular' }, - { label: 'React', href: '#', platform: 'react' }, - { label: 'Blazor', href: '#', platform: 'blazor' }, - { label: 'Web Components', href: '#', platform: 'web-components' }, - ], - }), - mdx(), - staticImagesIntegration(IMAGES), - ], - markdown: { - remarkPlugins: [ - (await import('./src/plugins/remark-docfx')).remarkDocfx, - ], - rehypePlugins: [ - (await import('./src/plugins/remark-docfx')).rehypeCodeView, - ], - }, -}); +export default defineConfig({}); diff --git a/docs/angular/astro.config.ts b/docs/angular/astro.config.ts index c13b8885f5..7ad23c613f 100644 --- a/docs/angular/astro.config.ts +++ b/docs/angular/astro.config.ts @@ -74,9 +74,6 @@ export default createDocsSite({ docsDir: componentsDocsDir, }, sidebar: { exclude: [/^internal\//] }, - starlight: { - // logo: { src: './public/favicon.svg' }, - }, integrations: [mdx()], // Expose @/ alias so MDX files can import Sample.astro and peer components. // @xplat-images resolves xplat-sourced MDX image imports to the angular images dir. diff --git a/docs/angular/package.json b/docs/angular/package.json index 9f396a5e3b..6e0eeb929f 100644 --- a/docs/angular/package.json +++ b/docs/angular/package.json @@ -3,9 +3,6 @@ "type": "module", "version": "1.0.0", "scripts": { - "sync:en": "node scripts/sync-docfx.mjs --lang=en", - "sync:jp": "node scripts/sync-docfx.mjs --lang=jp", - "sync:kr": "node scripts/sync-docfx.mjs --lang=kr", "generate": "node scripts/generate.mjs", "generate:en": "node scripts/generate.mjs --lang=en", "generate:jp": "node scripts/generate.mjs --lang=jp", @@ -40,7 +37,7 @@ "dependencies": { "astro": "^6.1.6", "docs-template": "file:../../", - "igniteui-astro-components": "0.0.5", + "igniteui-astro-components": "0.0.8", "sharp": "^0.34.2" }, "devDependencies": { diff --git a/docs/angular/src/env.d.ts b/docs/angular/src/env.d.ts index d072f07e4c..247311d29f 100644 --- a/docs/angular/src/env.d.ts +++ b/docs/angular/src/env.d.ts @@ -1,22 +1 @@ -declare module 'virtual:docs-template/site-meta' { - export const title: string; - export const description: string; - export const sidebar: { label: string; slug?: string; items?: unknown[] }[]; - export const mode: 'dev' | 'staging' | 'prod'; - export const trailingSlash: 'always' | 'never' | 'ignore'; -} - -declare module 'virtual:docs-template/nav-html' { - export const platform: 'igniteui' | 'angular' | 'react' | 'blazor' | 'web-components' | 'slingshot' | 'appbuilder' | null; - export const navLang: string; - export const prefetched: boolean; - export const headerHtml: string; - export const uiFooterHtml: string; - export const footerHtml: string; - export const abPrefetched: boolean; - export const abHeaderHtml: string; - export const abFooterHtml: string; - export const abFooterUtilsHtml: string; - export const abFooterCopyrightHtml: string; - export const abContactSalesHtml: string; -} \ No newline at end of file +/// \ No newline at end of file diff --git a/docs/xplat/astro.config.ts b/docs/xplat/astro.config.ts index 87fe21a14b..75e6f9da98 100644 --- a/docs/xplat/astro.config.ts +++ b/docs/xplat/astro.config.ts @@ -354,9 +354,6 @@ export default createDocsSite({ href: mode === 'production' ? `${PROD_HOST}${b}` : `${STAGING_HOST}${b}`, platform: key, })), - starlight: { - logo: { src: './public/favicon.svg' }, - }, integrations: [mdx()], vite: { plugins: [vitePluginPlatformTokens()], diff --git a/docs/xplat/package.json b/docs/xplat/package.json index 23757d3c3f..c73deec660 100644 --- a/docs/xplat/package.json +++ b/docs/xplat/package.json @@ -67,7 +67,7 @@ "dependencies": { "astro": "^6.1.6", "docs-template": "file:../../", - "igniteui-astro-components": "0.0.5", + "igniteui-astro-components": "0.0.8", "sharp": "^0.34.2" }, "devDependencies": { diff --git a/docs/xplat/src/content/jp/components/grids/hierarchical-grid/overview.mdx b/docs/xplat/src/content/jp/components/grids/hierarchical-grid/overview.mdx index 800745f1fd..e70ff5ab60 100644 --- a/docs/xplat/src/content/jp/components/grids/hierarchical-grid/overview.mdx +++ b/docs/xplat/src/content/jp/components/grids/hierarchical-grid/overview.mdx @@ -922,11 +922,7 @@ $custom-theme: grid-theme( ### サンプル - - + サンプルは、**テーマの変更**で選択したグローバル テーマの影響を受けません。 diff --git a/package-lock.json b/package-lock.json index a1a3cfcf18..ff162d523c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@astrojs/check": "^0.9.8", "@astrojs/mdx": ">=5", "gray-matter": "^4.0.3", - "igniteui-astro-components": "0.0.5", + "igniteui-astro-components": "0.0.8", "js-yaml": "^4.1.1", "jsdom": "^29.0.1", "pagefind": "^1.5.2" @@ -44,7 +44,7 @@ "dependencies": { "astro": "^6.1.6", "docs-template": "file:../../", - "igniteui-astro-components": "0.0.5", + "igniteui-astro-components": "0.0.8", "sharp": "^0.34.2" }, "devDependencies": { @@ -79,7 +79,7 @@ "dependencies": { "astro": "^6.1.6", "docs-template": "file:../../", - "igniteui-astro-components": "0.0.5", + "igniteui-astro-components": "0.0.8", "sharp": "^0.34.2" }, "devDependencies": { @@ -172,13 +172,13 @@ } }, "node_modules/@astrojs/language-server": { - "version": "2.16.8", - "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.8.tgz", - "integrity": "sha512-yg1pZF6hs9FaKr2fgXMOGbW7pDLgFexFjuhWilPAc8VybTU+WSnbfbhYaUL1exm6dAK4sM3aKXGcfVwss+HXbg==", + "version": "2.16.9", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.9.tgz", + "integrity": "sha512-L9kddTg+ZSO3X0Pwfx0ZPO+Z+eSSq0/39jXRyIkHzcBICzusdn2T464R4P6K0WcDZ6pMkLlFpuGS73u1pOnMSw==", "license": "MIT", "dependencies": { "@astrojs/compiler": "^2.13.1", - "@astrojs/yaml2ts": "^0.2.3", + "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", @@ -297,14 +297,14 @@ } }, "node_modules/@astrojs/ts-plugin": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/@astrojs/ts-plugin/-/ts-plugin-1.10.8.tgz", - "integrity": "sha512-fispa3VB/bRozjeLb8SqsnEWOIX8AIbDM9+yX2WTIhkIgO7axcstQYmfc6Oq0ZYRWQfLqdsW4CKxeClNcJ35tA==", + "version": "1.10.9", + "resolved": "https://registry.npmjs.org/@astrojs/ts-plugin/-/ts-plugin-1.10.9.tgz", + "integrity": "sha512-2pNc9EMXJcvYsmjQahYyqOiUNN9hMzgnxgIE/fZBLJAeOxPeOCSMa6BdngwV+bMgZDJcUSfC3qFt3+9abuUxtQ==", "dev": true, "license": "MIT", "dependencies": { "@astrojs/compiler": "^2.13.1", - "@astrojs/yaml2ts": "^0.2.3", + "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/language-core": "~2.4.28", "@volar/typescript": "~2.4.28", @@ -313,12 +313,12 @@ } }, "node_modules/@astrojs/yaml2ts": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.3.tgz", - "integrity": "sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", + "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", "license": "MIT", "dependencies": { - "yaml": "^2.8.2" + "yaml": "^2.8.3" } }, "node_modules/@babel/helper-string-parser": { @@ -2563,13 +2563,13 @@ ] }, "node_modules/@shikijs/core": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz", - "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.1.0.tgz", + "integrity": "sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==", "license": "MIT", "dependencies": { - "@shikijs/primitive": "4.0.2", - "@shikijs/types": "4.0.2", + "@shikijs/primitive": "4.1.0", + "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" @@ -2579,26 +2579,26 @@ } }, "node_modules/@shikijs/engine-javascript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz", - "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.1.0.tgz", + "integrity": "sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.2", + "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.4" + "oniguruma-to-es": "^4.3.6" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz", - "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.1.0.tgz", + "integrity": "sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.2", + "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { @@ -2606,24 +2606,24 @@ } }, "node_modules/@shikijs/langs": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz", - "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.1.0.tgz", + "integrity": "sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.2" + "@shikijs/types": "4.1.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/primitive": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz", - "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.1.0.tgz", + "integrity": "sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.2", + "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, @@ -2632,21 +2632,21 @@ } }, "node_modules/@shikijs/themes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz", - "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.1.0.tgz", + "integrity": "sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.0.2" + "@shikijs/types": "4.1.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", - "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz", + "integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -2739,9 +2739,9 @@ } }, "node_modules/@types/node": { - "version": "25.8.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", - "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz", + "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3047,9 +3047,9 @@ } }, "node_modules/astro": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/astro/-/astro-6.3.3.tgz", - "integrity": "sha512-wvLIZQYbBZt6U8gyflBW4SLBypaqdwLZUH93rT3oT53cmQ0bTGubvMAGjqBRoheOYzYcTJZtW6czztzbu4kQ5g==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/astro/-/astro-6.3.5.tgz", + "integrity": "sha512-gU+4KedkbTuVgz7YoVAN+9Ftnq0GaYwejxK2NbqDzB0M9dWd0f3kXZBuaM9hzbchRFoRAJfJjFtdX9LK6Ir7ZA==", "license": "MIT", "dependencies": { "@astrojs/compiler": "^4.0.0", @@ -4265,9 +4265,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-wrap-ansi": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", - "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "license": "MIT", "dependencies": { "fast-string-width": "^3.0.2" @@ -4839,9 +4839,9 @@ } }, "node_modules/hono": { - "version": "4.12.18", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", - "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", + "version": "4.12.21", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.21.tgz", + "integrity": "sha512-uV63apnb0kyPtAUwoWgaGh9HyIFcv8lgmzPZSiTBQAFOFGIzka5EZ1dZocmGnn0XdX0+XTqJ6Tqv7selMuGLRQ==", "dev": true, "license": "MIT", "engines": { @@ -4921,9 +4921,9 @@ } }, "node_modules/igniteui-astro-components": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/igniteui-astro-components/-/igniteui-astro-components-0.0.5.tgz", - "integrity": "sha512-w3F4Pl0UkJBUIQFP/0PlEj6sfBUg2Yyt1sJpczc9w+l3ErteLl2IqPKTdKV7FHEqUmXfZoczn/AT+lVMmn2WiA==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/igniteui-astro-components/-/igniteui-astro-components-0.0.8.tgz", + "integrity": "sha512-mJtRQaBIU4wGPpsbcWjtbhGSDXUJD2hMKLC4XvSL/sRqcXbRK3y6vFXTZ1XwMULgyB31hi9tVEsO10TYGdtyJw==", "license": "MIT", "workspaces": [ "playground" @@ -4932,7 +4932,6 @@ "@fontsource-variable/instrument-sans": "^5.2.8", "@fontsource-variable/jetbrains-mono": "^5.2.8", "igniteui-webcomponents": "^7.1.3", - "js-yaml": "^4.1.0", "jsdom": "^29.0.1" }, "engines": { @@ -5860,9 +5859,9 @@ } }, "node_modules/lru-cache": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", - "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.4.0.tgz", + "integrity": "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -7212,9 +7211,9 @@ } }, "node_modules/p-queue": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.2.0.tgz", - "integrity": "sha512-dWgLE8AH0HjQ9fe74pUkKkvzzYT18Inp4zra3lKHnnwqGvcfcUBrvF2EAVX+envufDNBOzpPq/IBUONDbI7+3g==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.0.tgz", + "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==", "license": "MIT", "dependencies": { "eventemitter3": "^5.0.4", @@ -7391,9 +7390,9 @@ } }, "node_modules/postcss": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", - "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -7410,7 +7409,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7476,9 +7475,9 @@ } }, "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8503,17 +8502,17 @@ } }, "node_modules/shiki": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz", - "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.1.0.tgz", + "integrity": "sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==", "license": "MIT", "dependencies": { - "@shikijs/core": "4.0.2", - "@shikijs/engine-javascript": "4.0.2", - "@shikijs/engine-oniguruma": "4.0.2", - "@shikijs/langs": "4.0.2", - "@shikijs/themes": "4.0.2", - "@shikijs/types": "4.0.2", + "@shikijs/core": "4.1.0", + "@shikijs/engine-javascript": "4.1.0", + "@shikijs/engine-oniguruma": "4.1.0", + "@shikijs/langs": "4.1.0", + "@shikijs/themes": "4.1.0", + "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, diff --git a/package.json b/package.json index 6dfcad5256..0476e67f5d 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "@astrojs/check": "^0.9.8", "@astrojs/mdx": ">=5", "gray-matter": "^4.0.3", - "igniteui-astro-components": "0.0.5", + "igniteui-astro-components": "0.0.8", "js-yaml": "^4.1.1", "jsdom": "^29.0.1", "pagefind": "^1.5.2" diff --git a/src/components/ThemingWidget.astro b/src/components/ThemingWidget.astro index 8549120fa5..5bfca0dfbd 100644 --- a/src/components/ThemingWidget.astro +++ b/src/components/ThemingWidget.astro @@ -2,15 +2,11 @@ /** * ThemingWidget * - * Renders the `` web component. Mirrors the - * behaviour from igniteui-docfx-template: - * template/partials/themeselect*.tmpl.partial - * src/app/handlers/theming.ts + * Renders the `` web component. * * Behaviour: * - `themeApiUrl` and `widgetVersion` are resolved from environment.json at - * build time via the `virtual:docs-template/nav-html` virtual module - * (same step as the header/footer prefetch in siteMetaIntegration). + * build time via the `virtual:docs-template/nav-html` virtual module. * - Renders nothing when `themeApiUrl` is unavailable. * - The widget container starts hidden and is revealed client-side only * when at least one themeable `` + - `` + - `` + - `` - ); -} - -/** - * Transform ... raw HTML blocks into the - * pre-rendered widget shell consumed by sample-widget.ts at runtime. - */ -function transformCodeView(html: string): string { - return html.replace( - /\s*(?:<\/code-view>)?/g, - (_match, attrs: string) => { - const stackblitzMatch = attrs.match(/stackblitz="([^"]*)"/); - const codesandboxMatch = attrs.match(/codesandbox="([^"]*)"/); - const srcMatch = attrs.match(/iframe-src="([^"]*)"/); - const demosBaseMatch = attrs.match(/data-demos-base-url="([^"]*)"/); - const githubSrcMatch = attrs.match(/github-src="([^"]*)"/); - const heightMatch = attrs.match(/style="height:\s*(\d+px)"/); - const altMatch = attrs.match(/alt="([^"]*)"/); - const height = heightMatch ? heightMatch[1] : '400px'; - const alt = altMatch ? altMatch[1] : 'Demo'; - - // Explicit StackBlitz embed (stackblitz="") - if (stackblitzMatch) { - const project = replaceEnvVars(stackblitzMatch[1]); - const embedUrl = project.startsWith('http') - ? project - : `https://stackblitz.com/edit/${project}?embed=1&file=src/app/app.component.ts`; - return ``; - } - - // Explicit CodeSandbox embed (codesandbox="") - if (codesandboxMatch) { - const project = replaceEnvVars(codesandboxMatch[1]); - const embedUrl = project.startsWith('http') - ? project - : `https://codesandbox.io/embed/${project}?fontsize=14&hidenavigation=1&theme=light`; - return ``; - } - - // Standard docfx code-view with iframe-src + data-demos-base-url. - // Output the pre-rendered widget shell; sample-widget.ts activates it at runtime. - if (srcMatch) { - const src = replaceEnvVars(srcMatch[1]); - if (!src || src.includes('{environment:')) return ''; // env var not resolved - const demosBaseUrl = demosBaseMatch ? replaceEnvVars(demosBaseMatch[1]) : ''; - const githubSrc = githubSrcMatch ? githubSrcMatch[1] : ''; - const platform = process.env.DOCS_PLATFORM || 'angular'; - return buildWidgetHtml(src, demosBaseUrl, githubSrc, height, alt, platform); - } - - return ''; - } - ); -} - -/** - * Transform
into
- */ -function transformDividers(html: string): string { - return html.replace(/\s*<\/div>/g, '
'); -} - -function strVal(v: unknown): string { - return typeof v === 'string' ? v : Array.isArray(v) ? v.join(' ') : String(v ?? ''); -} - -/** - * Rehype plugin — transforms elements into the pre-rendered widget shell. - * - * Handles two HAST representations depending on what's in the pipeline: - * - * 1. `element` nodes (tagName === 'code-view') — produced when rehype-raw is - * present and re-parses raw HTML fragments into proper HAST elements. - * - * 2. `raw` string nodes — produced when rehype-raw is NOT in the pipeline - * (e.g. Astro content-collection .md files). In that case multiline - * blocks are opaque raw strings; we run the same regex - * transformer used in the remark stage. - */ -export function rehypeCodeView() { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return (tree: any) => { - // ── 1. element nodes (after rehype-raw) ────────────────────────────────── - // eslint-disable-next-line @typescript-eslint/no-explicit-any - visit(tree, 'element', (node: any) => { - if (node.tagName !== 'code-view') return; - - const p = node.properties || {}; - - // HAST converts hyphenated attributes to camelCase via property-information. - const iframeSrc = strVal(p.iframeSrc ?? p['iframe-src'] ?? ''); - const demosBase = strVal(p.dataDemosBaseUrl ?? p['data-demos-base-url'] ?? ''); - const githubSrc = strVal(p.githubSrc ?? p['github-src'] ?? ''); - const styleStr = strVal(p.style ?? ''); - const alt = strVal(p.alt ?? 'Demo'); - - const src = replaceEnvVars(iframeSrc); - const baseUrl = replaceEnvVars(demosBase); - - if (!src || src.includes('{environment:')) return; - - const heightMatch = styleStr.match(/height:\s*(\d+\s*px)/i); - const height = heightMatch ? heightMatch[1].replace(/\s+/, '') : '400px'; - const platform = process.env.DOCS_PLATFORM || 'angular'; - const widgetId = 'cw' + src.replace(/[^a-z0-9]/gi, '-'); - const tabId = `${widgetId}-example`; - - node.tagName = 'div'; - node.properties = { - className: ['code-view'], - id: widgetId, - 'data-iframe-src': src, - 'data-platform': platform, - ...(baseUrl ? { 'data-demos-base-url': baseUrl } : {}), - ...(githubSrc ? { 'data-github-src': githubSrc } : {}), - }; - node.children = [ - { - type: 'element', tagName: 'div', - properties: { className: ['code-view-navbar'] }, - children: [ - { - type: 'element', tagName: 'div', - properties: { className: ['code-view-tab', 'code-view-tab--active'], 'data-tab-id': tabId }, - children: [{ type: 'text', value: 'EXAMPLE' }], - }, - { - type: 'element', tagName: 'span', - properties: { className: ['fs-button-container'], title: 'Expand to fullscreen' }, - children: [], - }, - ], - }, - { - type: 'element', tagName: 'div', - properties: { className: ['code-views-container'] }, - children: [ - { - type: 'element', tagName: 'div', - properties: { - id: tabId, - className: ['sample-container', 'code-view-tab-content', 'loading'], - style: `height: ${height}`, - }, - children: [ - { - type: 'element', tagName: 'iframe', - properties: { - 'data-src': src, - title: alt, - style: 'width: 100%; height: 100%;', - frameBorder: '0', - seamless: '', - }, - children: [], - }, - ], - }, - ], - }, - ]; - }); - - // ── 2. raw string nodes (no rehype-raw in pipeline) ────────────────────── - // eslint-disable-next-line @typescript-eslint/no-explicit-any - visit(tree, 'raw', (node: any) => { - if (!node.value || !node.value.includes(' { - const filePath = (file.path as string) ?? ''; - const docsDir = process.env.DOCS_SOURCE_PATH - ? path.resolve(process.env.DOCS_SOURCE_PATH) - : (filePath ? path.dirname(filePath) : ''); - // 1. Walk the AST and replace environment variables in text/links/html - // eslint-disable-next-line @typescript-eslint/no-explicit-any - visit(tree, (node: any) => { - // Text nodes - if (node.type === 'text' && node.value) { - node.value = replaceEnvVars(node.value as string); - } - - // Links - if (node.type === 'link' && node.url) { - node.url = replaceEnvVars(node.url as string); - node.url = rewriteMdLink(node.url as string, filePath, docsDir); - // Prepend DOCS_BASE to root-relative internal links that were not already - // rewritten by rewriteMdLink (e.g. bare /grids/grid/… links that skip - // the .md-only rewriter above). - const docsBase = (process.env.DOCS_BASE ?? '').replace(/\/$/, ''); - if ( - docsBase && - (node.url as string).startsWith('/') && - !(node.url as string).startsWith('//') && - !(node.url as string).startsWith(docsBase + '/') - ) { - node.url = docsBase + (node.url as string); - } - } - - // Images - if (node.type === 'image' && node.url) { - node.url = replaceEnvVars(node.url as string); - node.url = (node.url as string).replace(/^(\.\.\/)+images\//, '/images/'); - } - - // Code blocks — normalize language identifiers to lowercase - if (node.type === 'code' && node.lang) { - node.lang = (node.lang as string).toLowerCase(); - } - - // Inline HTML - if (node.type === 'html' && node.value) { - node.value = replaceEnvVars(node.value as string); - node.value = transformCodeView(node.value as string); - node.value = transformDividers(node.value as string); - node.value = (node.value as string).replace(/src="(\.\.\/)+images\//g, 'src="/images/'); - } - }); - }; -} diff --git a/src/plugins/remark-env-vars.ts b/src/plugins/remark-env-vars.ts new file mode 100644 index 0000000000..1ea9838e6e --- /dev/null +++ b/src/plugins/remark-env-vars.ts @@ -0,0 +1,110 @@ +/** + * Remark plugin: environment variable substitution. + * + * Replaces `{environment:key}` tokens in markdown text, link URLs, image URLs, + * and inline HTML with values from the project's environment.json. + * + * Resolution order for environment.json: + * 1. {DOCS_SOURCE_PATH}/en/environment.json + * 2. {DOCS_SOURCE_PATH}/environment.json + * 3. {DOCS_SOURCE_PATH}/../environment.json + * 4. {DOCS_SOURCE_PATH}/../en/environment.json + * 5. Fallback: read demosBaseUrl from docConfig.json + * + * DOCS_ENV (or NODE_ENV) selects the env block: development | staging | production. + */ + +import { visit } from 'unist-util-visit'; +import fs from 'node:fs'; +import path from 'node:path'; + +const ENV_PATTERN = /\{environment:(\w+)\}/g; + +const DOCCONFIG_PLATFORM_MAP: Record = { + angular: 'Angular', + react: 'React', + 'web-components': 'WebComponents', + blazor: 'Blazor', +}; + +// Lazy-loaded, cached per DOCS_SOURCE_PATH value. +let _env: Record | null = null; +let _envSourcePath: string | null = null; + +function loadEnv(): Record { + const currentPath = process.env.DOCS_SOURCE_PATH ?? null; + if (_env !== null && currentPath === _envSourcePath) return _env; + _envSourcePath = currentPath; + _env = null; + + if (!currentPath) { _env = {}; return _env; } + const sourceRoot = path.resolve(currentPath); + const parent = path.dirname(sourceRoot); + + const candidates = [ + path.join(sourceRoot, 'en', 'environment.json'), + path.join(sourceRoot, 'environment.json'), + path.join(parent, 'environment.json'), + path.join(parent, 'en', 'environment.json'), + ]; + + const envPath = candidates.find(c => fs.existsSync(c)); + + if (!envPath) { + try { + const envKey = process.env.DOCS_ENV ?? process.env.NODE_ENV ?? 'production'; + const platform = DOCCONFIG_PLATFORM_MAP[process.env.DOCS_PLATFORM ?? ''] ?? ''; + if (platform) { + const configPath = path.resolve(process.cwd(), 'docConfig.json'); + const docConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + const demosUrl: string = + docConfig[platform]?.samplesBrowsers?.[envKey] ?? + docConfig[platform]?.samplesBrowsers?.['development'] ?? ''; + _env = { dvDemosBaseUrl: demosUrl, demosBaseUrl: demosUrl, infragisticsBaseUrl: 'https://www.infragistics.com' }; + } else { + _env = {}; + } + } catch { + _env = {}; + } + return _env; + } + + try { + const data = JSON.parse(fs.readFileSync(envPath, 'utf-8')); + const envKey = process.env.DOCS_ENV ?? process.env.NODE_ENV ?? 'production'; + _env = data[envKey] ?? data.production ?? {}; + } catch { + _env = {}; + } + return _env!; +} + +/** Replace all `{environment:key}` tokens in a string. Exported for use by other modules. */ +export function replaceEnvVars(str: string): string { + if (!str || typeof str !== 'string') return str; + const env = loadEnv(); + return str.replace(ENV_PATTERN, (_match, key) => env[key] ?? `{environment:${key}}`); +} + +/** Remark plugin that substitutes `{environment:key}` tokens in the markdown AST. */ +export function remarkEnvVars() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (tree: any) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + visit(tree, (node: any) => { + if (node.type === 'text' && node.value) { + node.value = replaceEnvVars(node.value); + } + if (node.type === 'link' && node.url) { + node.url = replaceEnvVars(node.url); + } + if (node.type === 'image' && node.url) { + node.url = replaceEnvVars(node.url); + } + if (node.type === 'html' && node.value) { + node.value = replaceEnvVars(node.value); + } + }); + }; +} diff --git a/src/plugins/remark-html-transforms.ts b/src/plugins/remark-html-transforms.ts new file mode 100644 index 0000000000..701010ae78 --- /dev/null +++ b/src/plugins/remark-html-transforms.ts @@ -0,0 +1,32 @@ +/** + * Remark plugin: inline HTML transforms. + * + * Handles legacy HTML patterns in markdown content: + * - `
` → `
` + * - Normalizes code block language identifiers to lowercase + */ + +import { visit } from 'unist-util-visit'; + +const DIVIDER_PATTERN = /\s*<\/div>/g; +const IMG_SRC_PATTERN = /src="(\.\.\/)+images\//g; + +/** Remark plugin that transforms legacy HTML patterns in the AST. */ +export function remarkHtmlTransforms() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (tree: any) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + visit(tree, (node: any) => { + // Inline HTML: divider → hr, relative img src → root-relative + if (node.type === 'html' && node.value) { + node.value = (node.value as string).replace(DIVIDER_PATTERN, '
'); + node.value = (node.value as string).replace(IMG_SRC_PATTERN, 'src="/images/'); + } + + // Code blocks: normalize language to lowercase + if (node.type === 'code' && node.lang) { + node.lang = (node.lang as string).toLowerCase(); + } + }); + }; +} diff --git a/src/plugins/remark-md-links.ts b/src/plugins/remark-md-links.ts new file mode 100644 index 0000000000..8fe567d3f9 --- /dev/null +++ b/src/plugins/remark-md-links.ts @@ -0,0 +1,75 @@ +/** + * Remark plugin: rewrite relative .md links to Astro-compatible URLs. + * + * Transforms `[label](./some-page.md)` or `[label](../folder/page.md#section)` + * into root-relative URLs like `/products/.../some-page/` (with DOCS_BASE prepended). + * + * Also prepends DOCS_BASE to bare root-relative internal links (e.g. `/grids/grid/...`) + * that are already absolute but missing the site base path. + */ + +import { visit } from 'unist-util-visit'; +import path from 'node:path'; + +/** + * Resolve a relative .md link to an absolute Astro URL. + * Non-relative, non-.md, and external links are returned unchanged. + */ +function rewriteMdLink(url: string, filePath: string, docsDir: string): string { + if (!url) return url; + if ( + url.startsWith('http://') || url.startsWith('https://') || + url.startsWith('/') || url.startsWith('#') || url.startsWith('mailto:') + ) return url; + + const hashIdx = url.indexOf('#'); + const qIdx = url.indexOf('?'); + const splitAt = hashIdx !== -1 ? hashIdx : qIdx !== -1 ? qIdx : -1; + let mdPath = splitAt !== -1 ? url.slice(0, splitAt) : url; + const suffix = splitAt !== -1 ? url.slice(splitAt) : ''; + + if (!mdPath.endsWith('.md')) return url; + + const fileDir = path.dirname(filePath); + const resolved = path.resolve(fileDir, mdPath); + const rel = path.relative(docsDir, resolved).replace(/\\/g, '/'); + const slug = rel.endsWith('.md') ? rel.slice(0, -3) : rel; + + const docsBase = (process.env.DOCS_BASE ?? '').replace(/\/$/, ''); + return docsBase + '/' + slug.toLowerCase() + '/' + suffix; +} + +/** Remark plugin that rewrites relative .md links, prepends DOCS_BASE, and fixes relative image paths. */ +export function remarkMdLinks() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (tree: any, file: any) => { + const filePath = (file.path as string) ?? ''; + const docsDir = process.env.DOCS_SOURCE_PATH + ? path.resolve(process.env.DOCS_SOURCE_PATH) + : (filePath ? path.dirname(filePath) : ''); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + visit(tree, (node: any) => { + if (node.type === 'link' && node.url) { + node.url = rewriteMdLink(node.url as string, filePath, docsDir); + + // Prepend DOCS_BASE to root-relative internal links not already prefixed. + const docsBase = (process.env.DOCS_BASE ?? '').replace(/\/$/, ''); + if ( + docsBase && + (node.url as string).startsWith('/') && + !(node.url as string).startsWith('//') && + !(node.url as string).startsWith(docsBase + '/') + ) { + node.url = docsBase + (node.url as string); + } + } + + // Rewrite relative `../images/` paths in markdown image nodes to root-relative `/images/`. + // Generated MDX files may contain relative image references that Vite cannot resolve. + if (node.type === 'image' && node.url) { + node.url = (node.url as string).replace(/^(\.\.\/)+images\//, '/images/'); + } + }); + }; +} diff --git a/src/sidebar.ts b/src/sidebar.ts index 279635e05e..4c79d86dea 100644 --- a/src/sidebar.ts +++ b/src/sidebar.ts @@ -1,7 +1,7 @@ /** * sidebar.ts * - * Builds an Astro Starlight sidebar from a YAML or JSON TOC file. + * Builds an Astro sidebar from a JSON TOC file. * Source-agnostic: consuming repos pass their own paths. * * Usage in a consuming repo's astro.config.ts: @@ -9,7 +9,7 @@ * import { buildSidebarFromToc } from 'docs-template/sidebar'; * * const sidebar = buildSidebarFromToc({ - * tocPath: './node_modules/my-docs-source/toc.yml', // YAML or JSON + * tocPath: './node_modules/my-docs-source/toc.json', * docsDir: './node_modules/my-docs-source/en/components', * // exclude: [/^internal\//], // optional extra exclude patterns * }); @@ -17,7 +17,6 @@ import fs from 'node:fs'; import path from 'node:path'; -import * as yaml from 'js-yaml'; import type { SidebarEntry, SidebarGroup, SidebarLink } from './lib/sidebar/types'; // Re-export so consumers (astro.config.ts in child sites) can import the @@ -102,16 +101,16 @@ function convertTocItem( if (item.href) { if (!docExists(docsDir, item.href, exclude)) return null; const entry: SidebarLink = { label: item.name, slug: hrefToSlug(item.href) }; - // Status badge — only one slot available in Starlight, priority order: - if (item.new) entry.badge = { text: 'New', variant: 'new' }; - else if (item.preview) entry.badge = { text: 'Preview', variant: 'preview' }; - else if (item.updated) entry.badge = { text: 'Updated', variant: 'updated' }; + // Status badge — only one slot available, priority order: + if (item.new) entry.badges = [{ text: 'New', variant: 'new' }]; + else if (item.preview) entry.badges = [{ text: 'Preview', variant: 'preview' }]; + else if (item.updated) entry.badges = [{ text: 'Updated', variant: 'updated' }]; // Premium is rendered via data-premium attr so it can coexist with a // status badge (CSS ::after pseudo-element adds the star icon). if (item.premium) { entry.attrs = { 'data-premium': 'true' }; // Only use the badge slot for premium when no status badge is shown. - if (!entry.badge) entry.badge = { text: 'Premium', variant: 'premium' }; + if (!entry.badges) entry.badges = [{ text: 'Premium', variant: 'premium' }]; } return entry; } @@ -124,7 +123,7 @@ function convertTocItem( // --------------------------------------------------------------------------- export interface BuildSidebarFromTocOptions { - /** Absolute path to the TOC file (.yml or .json). */ + /** Absolute path to the TOC file (.json). */ tocPath: string; /** Absolute path to the Markdown docs directory. */ docsDir: string; @@ -133,12 +132,12 @@ export interface BuildSidebarFromTocOptions { } /** - * Reads a YAML or JSON TOC file and converts it to a Starlight sidebar array. + * Reads a JSON TOC file and converts it to a sidebar array. */ export function buildSidebarFromToc({ tocPath, docsDir, exclude = [] }: BuildSidebarFromTocOptions): SidebarEntry[] { if (!tocPath || !fs.existsSync(tocPath)) return []; const tocRaw = fs.readFileSync(tocPath, 'utf-8'); - const tocItems = tocPath.endsWith('.json') ? JSON.parse(tocRaw) : yaml.load(tocRaw) as TocItem[]; + const tocItems: TocItem[] = JSON.parse(tocRaw); const sidebar: SidebarEntry[] = []; let currentGroup: SidebarGroup | null = null; diff --git a/src/styles/ig-theme.scss b/src/styles/ig-theme.scss index caaedaafbb..2a8a0d71aa 100644 --- a/src/styles/ig-theme.scss +++ b/src/styles/ig-theme.scss @@ -18,7 +18,7 @@ $ig-palette: palette( @include palette($ig-palette); -// Starlight accent bridge — maps IG palette shades to Starlight accent vars +// Accent bridge — maps IG palette shades to --sl-color-accent-* CSS vars [data-theme='light'] { --sl-color-accent-low: var(--ig-primary-200); --sl-color-accent: var(--ig-primary-500); @@ -26,7 +26,7 @@ $ig-palette: palette( } // Dark mode — re-emit palette with lighter primary/secondary for legibility -// on dark surfaces. Starlight writes [data-theme='dark'] on . +// on dark surfaces. The theme sets [data-theme='dark'] on . [data-theme='dark'] { $ig-palette-dark: palette( $primary: #4db8ff, diff --git a/src/virtual-modules.d.ts b/src/virtual-modules.d.ts index 04446d4002..4fb5dcf7cb 100644 --- a/src/virtual-modules.d.ts +++ b/src/virtual-modules.d.ts @@ -1,6 +1,7 @@ declare module 'virtual:docs-template/site-meta' { export const sidebar: { label: string; slug?: string; items?: unknown[] }[]; export const title: string; + export const navLang: import('./platform.ts').NavLang; /** Cross-product navigation links for the DocsSubHeader. */ export const productLinks: Array<{ label: string; @@ -15,23 +16,12 @@ declare module 'virtual:docs-template/site-meta' { }>; /** Astro trailingSlash config value: 'always' | 'never' | 'ignore'. */ export const trailingSlash: 'always' | 'never' | 'ignore'; + /** Locale for the nav prefetch URL. Mirrors the value on `virtual:docs-template/nav-html`. */ + export const navLang: NavLang; } -import type { NavLang, NavTheme } from './platform.ts'; - declare module 'virtual:docs-template/nav-html' { export const platform: 'igniteui' | 'angular' | 'react' | 'blazor' | 'web-components' | 'slingshot' | 'appbuilder' | null; - export const navLang: NavLang; export const themeApiUrl: string; export const widgetScriptSrc: string; - export const prefetched: boolean; - export const headerHtml: string; - export const uiFooterHtml: string; - export const footerHtml: string; - export const abPrefetched: boolean; - export const abHeaderHtml: string; - export const abFooterHtml: string; - export const abFooterUtilsHtml: string; - export const abFooterCopyrightHtml: string; - export const abContactSalesHtml: string; }