@gpichot/spectacle-deck 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-dev.log +4 -0
- package/{index.cjs → dist/index.cjs} +5 -4
- package/{index.mjs → dist/index.mjs} +5 -4
- package/package.json +21 -16
- package/publish.sh +7 -0
- package/scripts/bundle.ts +84 -0
- package/src/SlideWrapper.tsx +25 -0
- package/src/colors.ts +42 -0
- package/src/components/CodeStepper/CodeStepper.tsx +228 -0
- package/src/components/CodeStepper/code-directives.test.ts +58 -0
- package/src/components/CodeStepper/code-directives.ts +129 -0
- package/src/components/DocumentationItem.tsx +85 -0
- package/src/components/FilePane.tsx +18 -0
- package/src/components/HorizontalList.tsx +141 -0
- package/src/components/IconBox.tsx +31 -0
- package/src/components/Image.tsx +39 -0
- package/src/components/ItemsColumn.tsx +60 -0
- package/src/components/QRCode.tsx +55 -0
- package/src/components/Timeline.styled.tsx +24 -0
- package/src/components/Timeline.tsx +159 -0
- package/src/components/map.tsx +128 -0
- package/src/components/styled.tsx +73 -0
- package/src/context.tsx +33 -0
- package/src/front.png +0 -0
- package/src/index.tsx +127 -0
- package/src/layouts/BaseLayout.tsx +52 -0
- package/src/layouts/CenteredLayout.tsx +40 -0
- package/src/layouts/Default3Layout.tsx +159 -0
- package/src/layouts/MainSectionLayout.tsx +31 -0
- package/src/layouts/QuoteLayout.tsx +107 -0
- package/src/layouts/SectionLayout.tsx +14 -0
- package/src/layouts/SideCodeLayout.tsx +44 -0
- package/src/layouts/SideImageLayout.tsx +82 -0
- package/src/layouts/SideLayout.tsx +31 -0
- package/src/layouts/columns.tsx +56 -0
- package/src/layouts/index.tsx +19 -0
- package/src/layouts/styled.ts +7 -0
- package/src/layouts/utils.ts +66 -0
- package/src/node.d.ts +5 -0
- package/src/style.d.ts +10 -0
- package/src/template.tsx +25 -0
- package/src/theme.ts +28 -0
- package/tsconfig.json +29 -0
- /package/{SlideWrapper.d.ts → dist/SlideWrapper.d.ts} +0 -0
- /package/{colors.d.ts → dist/colors.d.ts} +0 -0
- /package/{components → dist/components}/CodeStepper/CodeStepper.d.ts +0 -0
- /package/{components → dist/components}/CodeStepper/code-directives.d.ts +0 -0
- /package/{components → dist/components}/DocumentationItem.d.ts +0 -0
- /package/{components → dist/components}/FilePane.d.ts +0 -0
- /package/{components → dist/components}/HorizontalList.d.ts +0 -0
- /package/{components → dist/components}/IconBox.d.ts +0 -0
- /package/{components → dist/components}/Image.d.ts +0 -0
- /package/{components → dist/components}/ItemsColumn.d.ts +0 -0
- /package/{components → dist/components}/QRCode.d.ts +0 -0
- /package/{components → dist/components}/Timeline.d.ts +0 -0
- /package/{components → dist/components}/Timeline.styled.d.ts +0 -0
- /package/{components → dist/components}/map.d.ts +0 -0
- /package/{components → dist/components}/styled.d.ts +0 -0
- /package/{context.d.ts → dist/context.d.ts} +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{layouts → dist/layouts}/BaseLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/CenteredLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/Default3Layout.d.ts +0 -0
- /package/{layouts → dist/layouts}/MainSectionLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/QuoteLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/SectionLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/SideCodeLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/SideImageLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/SideLayout.d.ts +0 -0
- /package/{layouts → dist/layouts}/columns.d.ts +0 -0
- /package/{layouts → dist/layouts}/index.d.ts +0 -0
- /package/{layouts → dist/layouts}/styled.d.ts +0 -0
- /package/{layouts → dist/layouts}/utils.d.ts +0 -0
- /package/{template.d.ts → dist/template.d.ts} +0 -0
- /package/{theme.d.ts → dist/theme.d.ts} +0 -0
|
@@ -515,7 +515,7 @@ var DivWithHeading = import_styled_components5.default.div`
|
|
|
515
515
|
margin-top: 0;
|
|
516
516
|
}
|
|
517
517
|
h2 strong {
|
|
518
|
-
color:
|
|
518
|
+
color: var(--color-secondary);
|
|
519
519
|
font-weight: 400;
|
|
520
520
|
}
|
|
521
521
|
`;
|
|
@@ -657,7 +657,7 @@ var DivWithHeading2 = import_styled_components8.default.div`
|
|
|
657
657
|
margin-top: 0;
|
|
658
658
|
}
|
|
659
659
|
h2 strong {
|
|
660
|
-
color:
|
|
660
|
+
color: var(--color-secondary);
|
|
661
661
|
font-weight: 400;
|
|
662
662
|
}
|
|
663
663
|
`;
|
|
@@ -1431,8 +1431,8 @@ var DocContainer = import_styled_components12.default.div`
|
|
|
1431
1431
|
var DocLink = import_styled_components12.default.a`
|
|
1432
1432
|
text-decoration: none;
|
|
1433
1433
|
font-weight: normal;
|
|
1434
|
-
font-family:
|
|
1435
|
-
color:
|
|
1434
|
+
font-family: var(--font-family);
|
|
1435
|
+
color: var(--color-secondary);
|
|
1436
1436
|
`;
|
|
1437
1437
|
var DocLinkItem = (0, import_styled_components12.default)(DocLink)`
|
|
1438
1438
|
width: fit-content;
|
|
@@ -1791,6 +1791,7 @@ function Deck({
|
|
|
1791
1791
|
return import_styled_components17.createGlobalStyle`
|
|
1792
1792
|
:root {
|
|
1793
1793
|
${cssVariables}
|
|
1794
|
+
--font-family: ${theme_default.fonts.text}
|
|
1794
1795
|
}
|
|
1795
1796
|
`;
|
|
1796
1797
|
}, [theme]);
|
|
@@ -464,7 +464,7 @@ var DivWithHeading = styled5.div`
|
|
|
464
464
|
margin-top: 0;
|
|
465
465
|
}
|
|
466
466
|
h2 strong {
|
|
467
|
-
color:
|
|
467
|
+
color: var(--color-secondary);
|
|
468
468
|
font-weight: 400;
|
|
469
469
|
}
|
|
470
470
|
`;
|
|
@@ -606,7 +606,7 @@ var DivWithHeading2 = styled8.div`
|
|
|
606
606
|
margin-top: 0;
|
|
607
607
|
}
|
|
608
608
|
h2 strong {
|
|
609
|
-
color:
|
|
609
|
+
color: var(--color-secondary);
|
|
610
610
|
font-weight: 400;
|
|
611
611
|
}
|
|
612
612
|
`;
|
|
@@ -1384,8 +1384,8 @@ var DocContainer = styled12.div`
|
|
|
1384
1384
|
var DocLink = styled12.a`
|
|
1385
1385
|
text-decoration: none;
|
|
1386
1386
|
font-weight: normal;
|
|
1387
|
-
font-family:
|
|
1388
|
-
color:
|
|
1387
|
+
font-family: var(--font-family);
|
|
1388
|
+
color: var(--color-secondary);
|
|
1389
1389
|
`;
|
|
1390
1390
|
var DocLinkItem = styled12(DocLink)`
|
|
1391
1391
|
width: fit-content;
|
|
@@ -1744,6 +1744,7 @@ function Deck({
|
|
|
1744
1744
|
return createGlobalStyle`
|
|
1745
1745
|
:root {
|
|
1746
1746
|
${cssVariables}
|
|
1747
|
+
--font-family: ${theme_default.fonts.text}
|
|
1747
1748
|
}
|
|
1748
1749
|
`;
|
|
1749
1750
|
}, [theme]);
|
package/package.json
CHANGED
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpichot/spectacle-deck",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./index.d.ts",
|
|
12
|
-
"require": "./index.cjs",
|
|
13
|
-
"import": "./index.mjs"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"spectacle"
|
|
18
|
-
],
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"module": "src/index.tsx",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"keywords": [],
|
|
8
|
+
"author": "",
|
|
9
|
+
"license": "ISC",
|
|
19
10
|
"dependencies": {
|
|
20
11
|
"@fontsource/bitter": "^5.0.18",
|
|
21
12
|
"@mdx-js/react": "^3.0.1",
|
|
@@ -27,5 +18,19 @@
|
|
|
27
18
|
"react-syntax-highlighter": "^15.5.0",
|
|
28
19
|
"spectacle": "^10.1.8",
|
|
29
20
|
"styled-components": "^6.1.11"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@arnaud-barre/tnode": "^0.19.2",
|
|
24
|
+
"@types/react": "^18.3.2",
|
|
25
|
+
"@types/react-dom": "^18.3.0",
|
|
26
|
+
"@types/react-is": "^18.3.0",
|
|
27
|
+
"@types/react-syntax-highlighter": "^15.5.13",
|
|
28
|
+
"esbuild": "^0.21.3",
|
|
29
|
+
"typescript": "^5.4.5"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
33
|
+
"dev": "tnode scripts/bundle.ts",
|
|
34
|
+
"build": "tnode scripts/bundle.ts"
|
|
30
35
|
}
|
|
31
36
|
}
|
package/publish.sh
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { rmSync, writeFileSync, copyFileSync } from "node:fs";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { build, BuildOptions, context } from "esbuild";
|
|
4
|
+
|
|
5
|
+
import packageJSON from "../package.json";
|
|
6
|
+
|
|
7
|
+
const dev = process.argv.includes("--dev");
|
|
8
|
+
|
|
9
|
+
rmSync("dist", { force: true, recursive: true });
|
|
10
|
+
|
|
11
|
+
const serverOptions: BuildOptions = {
|
|
12
|
+
bundle: true,
|
|
13
|
+
platform: "node",
|
|
14
|
+
target: "node14",
|
|
15
|
+
legalComments: "inline",
|
|
16
|
+
loader: {
|
|
17
|
+
".png": "dataurl",
|
|
18
|
+
},
|
|
19
|
+
external: Object.keys(packageJSON.peerDependencies || {}).concat(
|
|
20
|
+
Object.keys(packageJSON.dependencies || {}),
|
|
21
|
+
),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const buildOrWatch = async (options: BuildOptions) => {
|
|
25
|
+
if (!dev) return build(options);
|
|
26
|
+
const ctx = await context(options);
|
|
27
|
+
await ctx.watch();
|
|
28
|
+
await ctx.rebuild();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Promise.all([
|
|
32
|
+
buildOrWatch({
|
|
33
|
+
...serverOptions,
|
|
34
|
+
stdin: {
|
|
35
|
+
contents: `import * as mod from "./src";
|
|
36
|
+
module.exports = mod;
|
|
37
|
+
`,
|
|
38
|
+
resolveDir: ".",
|
|
39
|
+
},
|
|
40
|
+
outfile: "dist/index.cjs",
|
|
41
|
+
logOverride: { "empty-import-meta": "silent" },
|
|
42
|
+
}),
|
|
43
|
+
buildOrWatch({
|
|
44
|
+
...serverOptions,
|
|
45
|
+
entryPoints: ["src/index.tsx"],
|
|
46
|
+
format: "esm",
|
|
47
|
+
outfile: "dist/index.mjs",
|
|
48
|
+
}),
|
|
49
|
+
]).then(() => {
|
|
50
|
+
// copyFileSync("LICENSE", "dist/LICENSE");
|
|
51
|
+
// copyFileSync("README.md", "dist/README.md");
|
|
52
|
+
|
|
53
|
+
execSync(
|
|
54
|
+
"tsc src/index.tsx --declaration --jsx react --emitDeclarationOnly --outDir dist --module preserve --target es2020 --allowSyntheticDefaultImports --skipLibCheck --moduleResolution bundler --types ./src/node.d.ts,./src/style.d.ts",
|
|
55
|
+
{ stdio: "inherit" },
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
writeFileSync(
|
|
59
|
+
"dist/package.json",
|
|
60
|
+
JSON.stringify(
|
|
61
|
+
{
|
|
62
|
+
name: "@gpichot/spectacle-deck",
|
|
63
|
+
version: packageJSON.version,
|
|
64
|
+
license: "MIT",
|
|
65
|
+
type: "module",
|
|
66
|
+
main: "index.cjs",
|
|
67
|
+
types: "index.d.ts",
|
|
68
|
+
module: "index.mjs",
|
|
69
|
+
exports: {
|
|
70
|
+
".": {
|
|
71
|
+
types: "./index.d.ts",
|
|
72
|
+
require: "./index.cjs",
|
|
73
|
+
import: "./index.mjs",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
keywords: ["spectacle"],
|
|
77
|
+
peerDependencies: packageJSON.peerDependencies,
|
|
78
|
+
dependencies: packageJSON.dependencies,
|
|
79
|
+
},
|
|
80
|
+
null,
|
|
81
|
+
2,
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { usePestacle } from "./context";
|
|
3
|
+
|
|
4
|
+
export function SlideWrapper({
|
|
5
|
+
children,
|
|
6
|
+
frontmatter,
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
frontmatter: { layout?: string };
|
|
10
|
+
}) {
|
|
11
|
+
const { layouts } = usePestacle();
|
|
12
|
+
const layout = frontmatter?.layout || "default";
|
|
13
|
+
console.log(layouts, layout);
|
|
14
|
+
const Layout = layout in layouts ? layouts[layout] : null;
|
|
15
|
+
|
|
16
|
+
if (layout && !Layout) {
|
|
17
|
+
console.warn(`Layout ${layout} not found`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (Layout) {
|
|
21
|
+
return <Layout {...frontmatter}>{children}</Layout>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <>{children}</>;
|
|
25
|
+
}
|
package/src/colors.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract colors from `rgb(...) or rgba(...)` string or #hex string
|
|
3
|
+
*/
|
|
4
|
+
export function extractColors(color: string): {
|
|
5
|
+
r: number;
|
|
6
|
+
g: number;
|
|
7
|
+
b: number;
|
|
8
|
+
} {
|
|
9
|
+
if (color.startsWith("rgb")) {
|
|
10
|
+
const [r, g, b] = color
|
|
11
|
+
.replace("rgb(", "")
|
|
12
|
+
.replace("rgba(", "")
|
|
13
|
+
.replace(")", "")
|
|
14
|
+
.split(",")
|
|
15
|
+
.map((c) => parseInt(c.trim(), 10));
|
|
16
|
+
return { r, g, b };
|
|
17
|
+
} else if (color.startsWith("#")) {
|
|
18
|
+
const hex = color.replace("#", "");
|
|
19
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
|
20
|
+
const g = parseInt(hex.substring(2, 4), 16);
|
|
21
|
+
const b = parseInt(hex.substring(4, 6), 16);
|
|
22
|
+
return { r, g, b };
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`Invalid color format: ${color}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create vars for css colors
|
|
29
|
+
*/
|
|
30
|
+
export function createCssVariables(colors: { [key: string]: string }) {
|
|
31
|
+
const base = Object.entries(colors)
|
|
32
|
+
.map(([key, value]) => `--color-${key}: ${value};`)
|
|
33
|
+
.join("\n");
|
|
34
|
+
const rgbs = Object.entries(colors)
|
|
35
|
+
.map(([key, value]) => {
|
|
36
|
+
const { r, g, b } = extractColors(value);
|
|
37
|
+
return `--color-${key}-rgb: ${r}, ${g}, ${b};`;
|
|
38
|
+
})
|
|
39
|
+
.join("\n");
|
|
40
|
+
|
|
41
|
+
return `${base}\n${rgbs}`;
|
|
42
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ReactIs from "react-is";
|
|
3
|
+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
4
|
+
import { gruvboxDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
|
5
|
+
import { Stepper } from "spectacle";
|
|
6
|
+
import styled from "styled-components";
|
|
7
|
+
|
|
8
|
+
import { parseStepDirectives, Step } from "./code-directives";
|
|
9
|
+
|
|
10
|
+
const Highlighter = SyntaxHighlighter as unknown as React.ElementType;
|
|
11
|
+
|
|
12
|
+
const CodeContainer = styled.div`
|
|
13
|
+
pre {
|
|
14
|
+
padding: 1rem 0rem !important;
|
|
15
|
+
background-color: transparent !important;
|
|
16
|
+
}
|
|
17
|
+
.linenumber {
|
|
18
|
+
min-width: 2rem !important;
|
|
19
|
+
}
|
|
20
|
+
[data-highlight-line="true"] {
|
|
21
|
+
&:before {
|
|
22
|
+
content: " ";
|
|
23
|
+
position: absolute;
|
|
24
|
+
background-color: rgba(var(--color-primary-rgb), 0.5);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&[data-step-active="true"]:before {
|
|
28
|
+
background-color: var(--color-secondary);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
function useCodeSteps(code: string) {
|
|
34
|
+
return React.useMemo(() => {
|
|
35
|
+
const prefixes = code.match(/(?:\/\/|<!--) @.*\n/g) || ([] as string[]);
|
|
36
|
+
const prefixesLength = prefixes.reduce(
|
|
37
|
+
(acc, prefix) => acc + prefix.length,
|
|
38
|
+
0,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const codeWithoutPrefixes = code.slice(prefixesLength);
|
|
42
|
+
|
|
43
|
+
const hasDirectives = prefixes.length > 0;
|
|
44
|
+
const allDirectives = hasDirectives ? [...prefixes] : [];
|
|
45
|
+
const steps = parseStepDirectives(allDirectives);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
steps,
|
|
49
|
+
code: codeWithoutPrefixes,
|
|
50
|
+
prefixes,
|
|
51
|
+
hasSteps: Boolean(steps.length),
|
|
52
|
+
hasName: steps.some((step) => step.name),
|
|
53
|
+
};
|
|
54
|
+
}, [code]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getCodeDetails(children: React.ReactNode) {
|
|
58
|
+
const child = React.Children.toArray(children)[0];
|
|
59
|
+
|
|
60
|
+
if (!React.isValidElement(child)) {
|
|
61
|
+
return {
|
|
62
|
+
language: "",
|
|
63
|
+
code: ReactIs.isFragment(child) ? "" : String(child || ""),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const result = {
|
|
68
|
+
language: (String(child.props.className) || "").replace("language-", ""),
|
|
69
|
+
code: (child.props.children as string).trim(),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function CodeWrapper({
|
|
76
|
+
name,
|
|
77
|
+
stepName,
|
|
78
|
+
hasName,
|
|
79
|
+
children,
|
|
80
|
+
}: {
|
|
81
|
+
name?: string;
|
|
82
|
+
stepName?: string;
|
|
83
|
+
hasName?: boolean;
|
|
84
|
+
children: React.ReactNode;
|
|
85
|
+
}) {
|
|
86
|
+
return (
|
|
87
|
+
<div
|
|
88
|
+
style={{
|
|
89
|
+
boxSizing: "border-box",
|
|
90
|
+
margin: "0.5rem 1rem",
|
|
91
|
+
backgroundColor: "rgb(38,39,40)",
|
|
92
|
+
borderRadius: "4px",
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{name && (
|
|
96
|
+
<span
|
|
97
|
+
style={{
|
|
98
|
+
fontFamily: 'Consolas, Monaco, "Andale Mono", monospace',
|
|
99
|
+
fontSize: "1rem",
|
|
100
|
+
color: "#ffffffbb",
|
|
101
|
+
backgroundColor: "#33333388",
|
|
102
|
+
display: "inline-block",
|
|
103
|
+
padding: "8px 8px",
|
|
104
|
+
width: "100%",
|
|
105
|
+
boxSizing: "border-box",
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
{name}
|
|
109
|
+
</span>
|
|
110
|
+
)}
|
|
111
|
+
{children}
|
|
112
|
+
{hasName && (
|
|
113
|
+
<span
|
|
114
|
+
style={{
|
|
115
|
+
fontFamily: 'Consolas, Monaco, "Andale Mono", monospace',
|
|
116
|
+
fontSize: "0.8rem",
|
|
117
|
+
color: "#ffffffaa",
|
|
118
|
+
backgroundColor: "#33333388",
|
|
119
|
+
display: "inline-block",
|
|
120
|
+
padding: "4px 8px",
|
|
121
|
+
width: "100%",
|
|
122
|
+
boxSizing: "border-box",
|
|
123
|
+
fontStyle: "italic",
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
{stepName || <span style={{ visibility: "hidden" }}>Step</span>}
|
|
127
|
+
</span>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default function CodeStepper({
|
|
134
|
+
priority,
|
|
135
|
+
name,
|
|
136
|
+
...props
|
|
137
|
+
}: React.ComponentProps<"pre"> & {
|
|
138
|
+
priority?: number;
|
|
139
|
+
name?: string;
|
|
140
|
+
}) {
|
|
141
|
+
const { language, code } = React.useMemo(() => {
|
|
142
|
+
return getCodeDetails(props.children);
|
|
143
|
+
}, [props.children]);
|
|
144
|
+
|
|
145
|
+
const {
|
|
146
|
+
steps,
|
|
147
|
+
code: codeNormalized,
|
|
148
|
+
prefixes,
|
|
149
|
+
hasSteps,
|
|
150
|
+
hasName,
|
|
151
|
+
} = useCodeSteps(code);
|
|
152
|
+
return (
|
|
153
|
+
<CodeContainer>
|
|
154
|
+
{import.meta.env.DEV && false && Boolean(prefixes?.length) && (
|
|
155
|
+
<div style={{ position: "absolute", top: 0, opacity: 0.5, left: 0 }}>
|
|
156
|
+
<Highlighter language={language} style={gruvboxDark}>
|
|
157
|
+
{prefixes.join("")}
|
|
158
|
+
</Highlighter>
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
<Stepper
|
|
162
|
+
values={steps}
|
|
163
|
+
alwaysVisible={!hasSteps}
|
|
164
|
+
priority={priority ? priority + 1 : undefined}
|
|
165
|
+
>
|
|
166
|
+
{(step, _, isActive) => {
|
|
167
|
+
console.log({ step, isActive });
|
|
168
|
+
return (
|
|
169
|
+
<CodeWrapper
|
|
170
|
+
name={name}
|
|
171
|
+
stepName={(step as Step | null)?.name}
|
|
172
|
+
hasName={hasName}
|
|
173
|
+
>
|
|
174
|
+
<Highlighter
|
|
175
|
+
language={language}
|
|
176
|
+
wrapLines
|
|
177
|
+
showLineNumbers
|
|
178
|
+
style={gruvboxDark}
|
|
179
|
+
lineNumberStyle={(lineNumber: number) => {
|
|
180
|
+
const { highlight = [] } = (step as Step) || {};
|
|
181
|
+
const isHighlighted = highlight.includes(lineNumber);
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
fontWeight: isHighlighted ? "bold" : "normal",
|
|
185
|
+
};
|
|
186
|
+
}}
|
|
187
|
+
lineProps={(lineNumber: number) => {
|
|
188
|
+
const { hiddenLines = [], highlight = [] } =
|
|
189
|
+
(step as Step) || {};
|
|
190
|
+
const isVisible =
|
|
191
|
+
hasSteps && isActive
|
|
192
|
+
? !hiddenLines.includes(lineNumber)
|
|
193
|
+
: isActive || !hasSteps;
|
|
194
|
+
const isHighlighted = highlight.includes(lineNumber);
|
|
195
|
+
const getOpacity = () => {
|
|
196
|
+
if (!isVisible) return 0;
|
|
197
|
+
if (isHighlighted || !highlight.length) return 1;
|
|
198
|
+
return 0.8;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
...(isHighlighted && {
|
|
203
|
+
"data-highlight-line": isHighlighted,
|
|
204
|
+
"data-step-active": isActive,
|
|
205
|
+
}),
|
|
206
|
+
style: {
|
|
207
|
+
opacity: getOpacity(),
|
|
208
|
+
transition: "all 0.3s ease",
|
|
209
|
+
display: "block",
|
|
210
|
+
width: "100%",
|
|
211
|
+
backgroundColor: isHighlighted
|
|
212
|
+
? "rgba(var(--color-secondary-rgb), 0.13)"
|
|
213
|
+
: "",
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}}
|
|
217
|
+
>
|
|
218
|
+
{codeNormalized}
|
|
219
|
+
</Highlighter>
|
|
220
|
+
</CodeWrapper>
|
|
221
|
+
);
|
|
222
|
+
}}
|
|
223
|
+
</Stepper>
|
|
224
|
+
</CodeContainer>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
CodeStepper.mdxType = "CodeStepper";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { parseStepDirectives } from './code-directives';
|
|
2
|
+
|
|
3
|
+
function splitDirectives(str: string): string[] {
|
|
4
|
+
return str.trim().split('\n');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
describe('parseStepDirectives', () => {
|
|
8
|
+
it('should reduce properly with showLines', () => {
|
|
9
|
+
const directives = splitDirectives(`
|
|
10
|
+
// @step showLines(1-3) highlight(1-3)
|
|
11
|
+
// @step showLines(4-6) highlight(4-6)
|
|
12
|
+
`);
|
|
13
|
+
|
|
14
|
+
const result = parseStepDirectives(directives);
|
|
15
|
+
expect(result[0]).toEqual({ hiddenLines: [4, 5, 6], highlight: [1, 2, 3] });
|
|
16
|
+
expect(result[1]).toEqual({ hiddenLines: [], highlight: [4, 5, 6] });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should reduce properly with highlight', () => {
|
|
20
|
+
const directives = splitDirectives(`
|
|
21
|
+
// @step highlight(3)
|
|
22
|
+
// @step showLines(4) highlight(4)
|
|
23
|
+
`);
|
|
24
|
+
|
|
25
|
+
const result = parseStepDirectives(directives);
|
|
26
|
+
expect(result).toHaveLength(2);
|
|
27
|
+
expect(result[0]).toEqual({ hiddenLines: [4], highlight: [3] });
|
|
28
|
+
expect(result[1]).toEqual({ hiddenLines: [], highlight: [4] });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('parse only highlights', () => {
|
|
32
|
+
const directives = splitDirectives(`
|
|
33
|
+
// @step highlight(6)
|
|
34
|
+
// @step highlight(7-9)
|
|
35
|
+
// @step highlight(10)
|
|
36
|
+
`);
|
|
37
|
+
|
|
38
|
+
const result = parseStepDirectives(directives);
|
|
39
|
+
expect(result).toHaveLength(3);
|
|
40
|
+
expect(result[0]).toEqual({ hiddenLines: [], highlight: [6] });
|
|
41
|
+
expect(result[1]).toEqual({ hiddenLines: [], highlight: [7, 8, 9] });
|
|
42
|
+
expect(result[2]).toEqual({ hiddenLines: [], highlight: [10] });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('parses typescript lines', () => {
|
|
46
|
+
const directives = splitDirectives(`
|
|
47
|
+
// @step highlight(3) name("(string|number)[]")
|
|
48
|
+
`);
|
|
49
|
+
|
|
50
|
+
const result = parseStepDirectives(directives);
|
|
51
|
+
expect(result).toHaveLength(1);
|
|
52
|
+
expect(result[0]).toEqual({
|
|
53
|
+
hiddenLines: [],
|
|
54
|
+
highlight: [3],
|
|
55
|
+
name: '(string|number)[]',
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|