Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native demos in the docs #1447

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
692a4e4
WIP: Get rid of the vueoress build errors
sequba Sep 11, 2024
87964f2
Add markdown-it plugins
sequba Sep 11, 2024
8a1d567
Make HTML+CSS preview work
sequba Sep 11, 2024
8365cc5
Make some of the buttons work
sequba Sep 11, 2024
cd57741
Add edit-in-stackblitz button
sequba Sep 12, 2024
58d203f
Make the entire runtime of the demo work (including js)
sequba Sep 12, 2024
402c2a4
Add real HF demo. Currently failing to load HF
sequba Sep 12, 2024
f5045bc
Make HyperFormula import work in runtime of the docs examples
sequba Sep 18, 2024
e0a45ae
Add script code-examples-generator
sequba Sep 23, 2024
52a0954
Style stackblitz button
sequba Sep 25, 2024
f9ea2aa
Style demo internal buttons
sequba Sep 26, 2024
8d0216e
Remove unused glue-code
sequba Sep 26, 2024
dc6c826
Remove not needed vuepress plugins
sequba Sep 27, 2024
01b7d7a
Fix linter error
sequba Sep 27, 2024
2de2bcb
Reformat demo/example1.ts file
sequba Oct 1, 2024
5ba4b3d
Add advanced-usage demo
sequba Oct 1, 2024
ca0b39d
Change the framework demos in the docs to use Codesandbox iframe inst…
sequba Oct 2, 2024
7b439cc
Add basic-operations demo
sequba Oct 3, 2024
d810cd1
Add basic-usage demo
sequba Oct 3, 2024
a1a9988
Add batch-operations demo
sequba Oct 3, 2024
4d21152
Add demo clipboard-operations
sequba Oct 3, 2024
c6f4ccc
Changed the custom-functions demo to use Codesandbox instead of Stack…
sequba Oct 3, 2024
a327c4f
Add date-time demo
sequba Oct 3, 2024
56da535
Add demo i18n
sequba Oct 3, 2024
188f074
Add localizing-functions guide
sequba Oct 8, 2024
dfad1b0
Add named-expressions demo
sequba Oct 8, 2024
41d1ae7
Add sorting-data demo
sequba Oct 8, 2024
83b7b85
Add undo-redo demo
sequba Oct 8, 2024
95a1550
Fix lint errors
sequba Oct 9, 2024
6368ae1
Disable linter for the docs examples
sequba Oct 9, 2024
213f342
Tweak the styling of demo example
sequba Oct 10, 2024
7eb2b03
Fix row and column counting in the docs examples
sequba Oct 10, 2024
46f9de2
Adjust css of basic-usage demo
sequba Oct 10, 2024
af0d548
Adjust style of advanced-usage demo
sequba Oct 10, 2024
ba6fefb
Fix styles for basic-operations demo
sequba Oct 14, 2024
439af76
Fix styles for batch-operations demo
sequba Oct 14, 2024
f9e1b37
Fix styles for sorting demo
sequba Oct 14, 2024
30adad3
Fix height of the table cell in the demos
sequba Oct 15, 2024
fbbb10b
Adjust text decoration of the summary row in the i18n demo
sequba Oct 15, 2024
19a0f4a
Fix styles for basic-operations demo
sequba Oct 15, 2024
95ff6d7
Adjust styles for the inputs
sequba Oct 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Common files
node_modules

# example files
docs/examples/

# 3rd party
src/interpreter/plugin/3rdparty

Expand Down
39 changes: 39 additions & 0 deletions docs/.vuepress/components/ScriptLoader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
</template>

<script>
const decode = (base64data) => {
return decodeURI(base64data);
};

const useCodePreview = (code) => {
const scriptElement = document.createElement('script');

scriptElement.type = 'text/javascript';
scriptElement.innerHTML = code;

return [
(container) => {
container.appendChild(scriptElement);

return () => { scriptElement.parentElement.removeChild(scriptElement); };
},
];
};

export default {
name: 'ScriptLoader',
props: ['code'],
mounted() {
const [append] = useCodePreview(decode(this.$props.code));

this.removeScript = append(this.$el);
},
beforeDestroy() {
this.removeScript();
},
methods: {
decode
}
};
</script>
30 changes: 15 additions & 15 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ const highlight = require('./highlight');
const regexPlugin = require('markdown-it-regex').default;
const footnotePlugin = require('markdown-it-footnote');
const searchBoxPlugin = require('./plugins/search-box');
const examples = require('./plugins/examples/examples');
const HyperFormula = require('../../dist/hyperformula.full');
const fs = require('fs');
const path = require('path');
const includeCodeSnippet = require('./plugins/markdown-it-include-code-snippet');

const searchPattern = new RegExp('^/api', 'i');

module.exports = {
title: 'HyperFormula (v' + HyperFormula.version + ')',
description: 'HyperFormula is an open-source, high-performance calculation engine for spreadsheets and web applications.',
head: [
// Import HF (required for the examples)
[ 'script', { src: 'https://cdn.jsdelivr.net/npm/hyperformula/dist/hyperformula.full.min.js' } ],
[ 'script', { src: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/languages/enUS.js' } ],
[ 'script', { src: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/languages/frFR.js' } ],
// Import moment (required for the examples)
[ 'script', { src: 'https://cdn.jsdelivr.net/npm/moment/moment.min.js' } ],
// 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':
Expand Down Expand Up @@ -41,11 +47,11 @@ module.exports = {
`],
[
'script',
{
id: 'Sentry.io',
src: 'https://js.sentry-cdn.com/50617701901516ce348cb7b252564a60.min.js',
crossorigin: 'anonymous',
},
{
id: 'Sentry.io',
src: 'https://js.sentry-cdn.com/50617701901516ce348cb7b252564a60.min.js',
crossorigin: 'anonymous',
},
],
// Favicon
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/favicon/apple-touch-icon.png' }],
Expand All @@ -57,14 +63,7 @@ module.exports = {
base: '/',
plugins: [
searchBoxPlugin,
// [
// 'vuepress-plugin-clean-urls',
// {
// normalSuffix: '',
// indexSuffix: '/',
// notFoundPath: '/404.html',
// },
// ],
['container', examples()],
{
extendPageData ($page) {
// inject current HF version as {{ $page.version }} variable
Expand Down Expand Up @@ -109,6 +108,7 @@ module.exports = {
replace: () => `'${HyperFormula.releaseDate}'`
})
md.use(footnotePlugin)
md.use(includeCodeSnippet)
}
},
// TODO: It doesn't work. It's seems that this option is bugged. Documentation says that this option is configurable,
Expand Down
32 changes: 32 additions & 0 deletions docs/.vuepress/plugins/examples/code-builder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { transformSync } = require('@babel/core');

const babelConfig = {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript',
],
plugins: [
'@babel/plugin-transform-modules-commonjs',
'@babel/plugin-syntax-class-properties',
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
['@babel/plugin-proposal-private-methods', { loose: true }],
['@babel/plugin-proposal-private-property-in-object', { loose: true }]
],
targets: {
ie: 9
}
};

const buildCode = (filename, contentJs, relativePath = '') => {
try {
return transformSync(contentJs, { ...babelConfig, filename }).code;
} catch (error) {
// eslint-disable-next-line
console.error(`Babel error when building ${relativePath}`);
throw error;
}
};

module.exports = { buildCode };
119 changes: 119 additions & 0 deletions docs/.vuepress/plugins/examples/examples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
const Token = require('markdown-it/lib/token');
const { buildCode } = require('./code-builder');
const { stackblitz } = require('./stackblitz');

/**
* Matches into: `example #ID .class :preset --css 2 --html 0 --js 1 --ts 3 --no-edit`.
*
* @type {RegExp}
*/
const EXAMPLE_REGEX = /^(example)\s*(#\S*|)\s*(\.\S*|)\s*(:\S*|)\s*([\S|\s]*)$/;

const parseCode = (content) => {
if (!content) return '';

return content
// Remove the all "/* start:skip-in-preview */" and "/* end:skip-in-preview */" comments
.replace(/\/\*(\s+)?(start|end):skip-in-preview(\s+)?\*\/\n/gm, '')
// Remove the all "/* start:skip-in-sandbox */" and "/* end:skip-in-sandbox */" comments
.replace(/\/\*(\s+)?(start|end):skip-in-sandbox(\s+)?\*\/\n/gm, '')
// Remove the code between "/* start:skip-in-compilation */" and "/* end:skip-in-compilation */" expressions
.replace(/\/\*(\s+)?start:skip-in-compilation(\s+)?\*\/\n.*?\/\*(\s+)?end:skip-in-compilation(\s+)?\*\/\n/msg, '')
// Remove /* end-file */
.replace(/\/\* end-file \*\//gm, '');
};

const parseCodeSandbox = (content) => {
if (!content) return '';

return content
// Remove the code between "/* start:skip-in-sandbox */" and "/* end:skip-in-sandbox */" expressions
.replace(/\/\*(\s+)?start:skip-in-sandbox(\s+)?\*\/\n.*?\/\*(\s+)?end:skip-in-sandbox(\s+)?\*\/\n/msg, '')
// Remove the all "/* start:skip-in-preview */" and "/* end:skip-in-preview */" comments
.replace(/\/\*(\s+)?(start|end):skip-in-preview(\s+)?\*\/\n/gm, '')
// Remove the all "/* start:skip-in-compilation */" and "/* end:skip-in-compilation */" comments
.replace(/\/\*(\s+)?(start|end):skip-in-compilation(\s+)?\*\/\n/gm, '');
};

module.exports = function() {
return {
type: 'example',
render(tokens, index, _opts, env) {
const token = tokens[index];
const m = token.info.trim().match(EXAMPLE_REGEX);

if (token.nesting !== 1 || !m) {
return '';
}

let [, , id, klass, preset, args] = m;

id = id ? id.substring(1) : 'example1';
klass = klass ? klass.substring(1) : '';
preset = preset ? preset.substring(1) : 'hot';
args = args || '';

const htmlPos = args.match(/--html (\d*)/)?.[1];
const htmlIndex = htmlPos ? index + Number.parseInt(htmlPos, 10) : 0;
const htmlToken = htmlPos ? tokens[htmlIndex] : undefined;
const htmlContent = htmlToken
? htmlToken.content
: `<div id="${id}" class="hot ${klass}"></div>`;
const htmlContentRoot = `<div data-preset-type="${preset}" data-example-id="${id}" >${htmlContent}</div>`;

const cssPos = args.match(/--css (\d*)/)?.[1];
const cssIndex = cssPos ? index + Number.parseInt(cssPos, 10) : 0;
const cssToken = cssPos ? tokens[cssIndex] : undefined;
const cssContent = cssToken ? cssToken.content : '';

const jsPos = args.match(/--js (\d*)/)?.[1] || 1;
const jsIndex = jsPos ? index + Number.parseInt(jsPos, 10) : 0;
const jsToken = jsPos ? tokens[jsIndex] : undefined;

const tsPos = args.match(/--ts (\d*)/)?.[1];
const tsIndex = tsPos ? index + Number.parseInt(tsPos, 10) : 0;
const tsToken = tsPos ? tokens[tsIndex] : undefined;

// Parse code
const codeToCompile = parseCode(jsToken?.content);
const tsCodeToCompileSandbox = parseCodeSandbox(tsToken?.content);

[htmlIndex, jsIndex, tsIndex, cssIndex].filter(x => !!x).sort().reverse().forEach((x) => {
tokens.splice(x, 1);
});

const newTokens = [
new Token('container_div_open', 'div', 1),
new Token('container_div_close', 'div', -1),
new Token('container_div_open', 'div', 1),
new Token('container_div_close', 'div', -1),
];

tokens.splice(index + 1, 0, ...newTokens);

const builtCode = buildCode(
id + '.js',
codeToCompile,
env.relativePath
);
const encodedCode = encodeURI(builtCode);

return `
<div class="example-container">
<style v-pre>${cssContent}</style>
<div v-pre>${htmlContentRoot}</div>
<ScriptLoader code="${encodedCode}"></ScriptLoader>
</div>
<div class="example-controls">
${stackblitz(
id,
htmlContent,
tsCodeToCompileSandbox,
cssContent,
'ts'
)}
</div>
`;
},
};
};
77 changes: 77 additions & 0 deletions docs/.vuepress/plugins/examples/stackblitz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const buildJavascriptBody = ({ id, html, js, css, hyperformulaVersion, lang }) => {
return {
files: {
'package.json': {
content: `{
"name": "hyperformula-demo",
"version": "1.0.0",
"main": "index.html",
"dependencies": {
"hyperformula": "${hyperformulaVersion}",
"moment": "latest"
}
}`
},
'index.html': {
content: `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HyperFormula demo</title>
</head>

<body>
${html || `<div id="${id}"></div>`}
</body>
</html>`
},
'styles.css': {
content: css
},
[`index.${lang}`]: {
content: `import './styles.css'
${js}`
},
}
};
};

const stackblitz = (id, html, js, css, lang) => {
const hyperformulaVersion = 'latest';
const body = buildJavascriptBody({ id, html, js, css, hyperformulaVersion, lang });
const template = lang === 'ts' ? 'typescript' : 'node';

const projects = body?.files
? Object.entries(body?.files).map(([key, value]) => (
`<textarea class="hidden" name="project[files][${key}]" readOnly v-pre>${value.content}</textarea>`
)) : [];

return `
<form
class="form-stackblitz-external"
action="https://stackblitz.com/run"
method="post"
target="_blank"
>
${projects.join('\n')}
<input type="hidden" name="project[title]" value="hyperformula-demo"/>
<input type="hidden" name="project[dependencies]"
value='{"hyperformula":"${hyperformulaVersion}", "moment": "latest"}'
/>
<input type="hidden" name="project[template]" value="${template}"/>

<div class="js-stackblitz-link">
<button type="submit">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"
width="10.43" height="15" preserveAspectRatio="xMidYMid" viewBox="0 0 256 368" class="icon outbound">
<path fill="currentColor" d="M109.586 217.013H0L200.34 0l-53.926 150.233H256L55.645 367.246l53.927-150.233z"/>
</svg>
Open in Stackblitz
</button>
</div>
</form>
`;
};

module.exports = { stackblitz };
Loading
Loading