const path = require('path'); const stylusNodes = require('stylus/lib/nodes'); const highlight = require('./highlight'); const examples = require('./containers/examples'); const exampleWithoutTabs = require('./containers/example-without-tabs'); const sourceCodeLink = require('./containers/sourceCodeLink'); const nginxRedirectsPlugin = require('./plugins/generate-nginx-redirects'); const nginxVariablesPlugin = require('./plugins/generate-nginx-variables'); const extendPageDataPlugin = require('./plugins/extend-page-data'); const dumpDocsDataPlugin = require('./plugins/dump-docs-data'); const dumpRedirectPageIdsPlugin = require('./plugins/dump-redirect-page-ids'); const firstHeaderInjection = require('./plugins/markdown-it-header-injection'); const headerAnchor = require('./plugins/markdown-it-header-anchor'); const conditionalContainer = require('./plugins/markdown-it-conditional-container'); const includeCodeSnippet = require('./plugins/markdown-it-include-code-snippet'); const tableWrapper = require('./plugins/markdown-it-table-wrapper'); const { createSymlinks, getDocsBase, getDocsBaseFullUrl, getDocsHostname, getIgnorePagesPatternList, getThisDocsVersion, MULTI_FRAMEWORKED_CONTENT_DIR, } = require('./helpers'); require('dotenv').config(); const buildMode = process.env.BUILD_MODE; const isProduction = buildMode === 'production'; const environmentHead = isProduction ? [ // Google Tag Manager, an extra element within the `ssr.html` file. [ 'script', {}, ` (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-55L5D3'); `, ], // HotJar, an extra element within the `ssr.html` file. [ 'script', {}, ` (function(h,o,t,j,a,r){ window.addEventListener('DOMContentLoaded', function(){ if(h.innerWidth > 600){ h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; h._hjSettings={hjid:329042,hjsv:6}; a=o.getElementsByTagName('head')[0]; r=o.createElement('script');r.async=1; r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; a.appendChild(r); } }); })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); `, ], ] : []; // The `vuepress dev` command needs placing directories in proper place. It's done by creating temporary directories // which are watched by the script. It's done before a compilation is starting. createSymlinks(); module.exports = { // by default this always returns true, this is a issue as it preloads every documentation pages content shouldPrefetch: (_, type) => { if (type === 'script') { return false; } return true; }, define: { GA_ID: 'UA-33932793-7', }, patterns: [ `${MULTI_FRAMEWORKED_CONTENT_DIR}/**/*.md`, ...getIgnorePagesPatternList(), ], description: 'Handsontable', base: `${getDocsBase()}/`, head: [ [ 'link', { rel: 'icon', media: '(prefers-color-scheme: light)', href: `${getDocsBaseFullUrl()}/img/favicon.png`, }, ], [ 'link', { rel: 'icon', media: '(prefers-color-scheme: dark)', href: `${getDocsBaseFullUrl()}/img/favicon-dark.png`, }, ], [ 'link', { rel: 'preload', href: `${getDocsBaseFullUrl()}/data/common.json`, as: 'fetch', crossorigin: '', }, ], [ 'meta', { name: 'viewport', content: 'width=device-width, initial-scale=1' }, ], // Sentry monitoring [ 'script', {}, ` window.sentryOnLoad = function () { Sentry.init({ environment: '${buildMode || 'testing'}', tracesSampleRate: 0, profilesSampleRate: 0, replaysSessionSampleRate: 0, replaysOnErrorSampleRate: 0.2, integrations: [ // If you use a bundle with performance monitoring enabled, add the BrowserTracing integration new Sentry.BrowserTracing(), // If you use a bundle with session replay enabled, add the SessionReplay integration new Sentry.Replay({ maskAllText: false, blockAllMedia: false, }), ], }); }; `, ], [ 'script', { id: 'Sentry.io', src: 'https://js.sentry-cdn.com/611b4dbe630c4a434fe1367b98ba3644.min.js', crossorigin: 'anonymous', defer: true, }, ], // Cookiebot - cookie consent popup [ 'script', { id: 'Cookiebot', src: 'https://consent.cookiebot.com/uc.js', 'data-cbid': 'ef171f1d-a288-433f-b680-3cdbdebd5646', defer: true, }, ], // Headwayapp [ 'script', { id: 'Headwayapp', src: 'https://cdn.headwayapp.co/widget.js', defer: true, }, ], ['script', {}, `const DOCS_VERSION = '${getThisDocsVersion()}';`], [ 'script', {}, ` (function(w, d) { const colorScheme = localStorage.getItem('handsontable/docs::color-scheme'); const systemPrefersDark = w.matchMedia && w.matchMedia('(prefers-color-scheme: dark)').matches; const preferredScheme = colorScheme ? colorScheme : (systemPrefersDark ? 'dark' : 'light'); if (preferredScheme === 'dark') { d.documentElement.classList.add('theme-dark'); d.documentElement.setAttribute('data-theme', 'dark'); } w.SELECTED_COLOR_SCHEME = preferredScheme; }(window, document)); `, ], ...environmentHead, ], markdown: { toc: { includeLevel: [2, 3], containerHeaderHtml: '
On this page
', }, anchor: { permalink: false, }, externalLinks: { target: '_blank', rel: 'nofollow noopener noreferrer', }, extendMarkdown(md) { md.use(includeCodeSnippet) .use(conditionalContainer) .use(firstHeaderInjection) .use(headerAnchor) .use(tableWrapper); }, }, configureWebpack: { resolve: { symlinks: false, }, }, stylus: { preferPathResolver: 'webpack', define: { url: (expression) => { return new stylusNodes.Literal( `url("${expression.string.replace( '{{$basePath}}', getDocsBaseFullUrl() )}")` ); }, }, }, plugins: [ extendPageDataPlugin, 'tabs', [ 'sitemap', { hostname: getDocsHostname(), exclude: ['/404.html'], }, ], ['container', examples(getThisDocsVersion(), getDocsBaseFullUrl())], [ 'container', exampleWithoutTabs(getThisDocsVersion(), getDocsBaseFullUrl()), ], ['container', sourceCodeLink], { extendMarkdown(md) { const imageOrig = md.renderer.rules.image; // Add support for markdown images and links to have ability to substitute the // docs latest version variable to the "src" or "href" attributes. md.renderer.rules.image = function(tokens, ...rest) { tokens.forEach((token) => { token.attrs.forEach(([name, value], index) => { if (name === 'src') { token.attrs[index][1] = decodeURIComponent(value).replace( '{{$basePath}}', getDocsBaseFullUrl() ); } }); }); return imageOrig(tokens, ...rest); }; const linkOrig = md.renderer.rules.link_open; md.renderer.rules.link_open = function(tokens, ...rest) { tokens.forEach((token) => { if (token.type !== 'link_open') { return; } token.attrs.forEach(([name, value], index) => { if (name === 'href') { token.attrs[index][1] = decodeURIComponent(value).replace( '{{$basePath}}', getDocsBaseFullUrl() ); } }); }); return linkOrig(tokens, ...rest); }; const render = function(tokens, options, env) { let i; let type; let result = ''; const rules = this.rules; for (i = 0; i < tokens.length; i++) { // overwritten here type = tokens[i].type; if (type === 'inline') { result += this.renderInline(tokens[i].children, options, env); } else if (typeof rules[type] !== 'undefined') { result += rules[tokens[i].type]( tokens, i, options, env, this, getThisDocsVersion() ); } else { result += this.renderToken(tokens, i, options, env); } } return result; }; // overwrite markdown `render` function to allow extending tokens array (remove caching before loop). md.renderer.render = (tokens, options, env) => render.call(md.renderer, tokens, options, env); }, chainMarkdown(config) { // inject custom markdown highlight with our snippet runner config.options.highlight(highlight).end(); }, chainWebpack: (config) => { config.module .rule('md') .test(/\.md$/) .use(path.resolve(__dirname, 'docs-links')) .loader(path.resolve(__dirname, 'docs-links')) .end(); }, }, [ dumpDocsDataPlugin, { outputDir: path.resolve(__dirname, './public/data/'), }, ], [ dumpRedirectPageIdsPlugin, { outputFile: path.resolve(__dirname, '../docker/redirect-page-ids.json'), }, ], [ nginxRedirectsPlugin, { outputFile: path.resolve( __dirname, '../docker/redirects-autogenerated.conf' ), }, ], [ nginxVariablesPlugin, { outputFile: path.resolve(__dirname, '../docker/variables.conf'), }, ], ], themeConfig: { nextLinks: false, prevLinks: false, repo: 'handsontable/handsontable', docsRepo: 'handsontable/handsontable', docsDir: 'docs/content', docsBranch: 'develop', editLinks: true, editLinkText: 'Edit on GitHub', lastUpdated: false, smoothScroll: false, nav: [ // Guide & API Reference has been defined in theme/components/NavLinks.vue // { text: 'GitHub', link: 'https://github.com/handsontable/handsontable' }, { text: 'Support', items: [ { text: 'Developers Forum', link: 'https://forum.handsontable.com', }, { text: 'GitHub Discussions', link: 'https://github.com/handsontable/handsontable/discussions', }, { text: 'StackOverflow', link: 'https://stackoverflow.com/tags/handsontable', }, { text: 'Contact support', link: 'https://handsontable.com/contact?category=technical_support', }, ], }, ], displayAllHeaders: true, // collapse other pages activeHeaderLinks: true, sidebarDepth: 0, organization: { name: 'Handsontable', author: 'Handsontable Team', url: 'https://handsontable.com', socialMedia: [ 'https://twitter.com/handsontable', 'https://www.linkedin.com/company/handsontable', ], image: `${getDocsBaseFullUrl()}/img/handsontable-docs-cover.png` }, searchPlaceholder: 'Search...', algolia: { indexName: 'handsontable', apiKey: 'c2430302c91e0162df988d4b383c9d8b', appId: 'MMN6OTJMGX' } }, };