Skip to content

Commit 1f33495

Browse files
committed
Add slideshow component
1 parent b790fab commit 1f33495

File tree

7 files changed

+414
-0
lines changed

7 files changed

+414
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.ch-slideshow {
2+
margin: 1rem 0;
3+
}
4+
5+
.ch-slideshow-slide {
6+
display: flex;
7+
flex-flow: row;
8+
gap: 0.5rem;
9+
align-items: stretch;
10+
aspect-ratio: 16 / 9;
11+
}
12+
13+
.ch-slideshow-slide .ch-editor-frame,
14+
.ch-slideshow-slide .ch-code {
15+
flex: 2;
16+
}
17+
18+
.ch-slideshow-preview {
19+
flex: 1;
20+
height: auto;
21+
}
22+
23+
.ch-slideshow-range {
24+
margin-top: 1rem;
25+
display: flex;
26+
flex-flow: row;
27+
gap: 0.5rem;
28+
}
29+
30+
.ch-slideshow-range input {
31+
flex: 1;
32+
}
33+
34+
.ch-slideshow-note {
35+
height: 140px;
36+
overflow: auto;
37+
border-radius: 0.25rem;
38+
margin-top: 1rem;
39+
padding: 1rem;
40+
border: 1px solid #e3e3e3;
41+
}

packages/mdx/src/client/slideshow.tsx

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import React from "react"
2+
import {
3+
EditorProps,
4+
EditorStep,
5+
} from "@code-hike/mini-editor"
6+
import { InnerCode, updateEditorStep } from "./code"
7+
import { Preview, PresetConfig } from "./preview"
8+
9+
export function Slideshow({
10+
children,
11+
editorSteps,
12+
codeConfig,
13+
presetConfig,
14+
}: {
15+
children: React.ReactNode
16+
editorSteps: EditorStep[]
17+
codeConfig: EditorProps["codeConfig"]
18+
presetConfig?: PresetConfig
19+
}) {
20+
const stepsChildren = React.Children.toArray(children)
21+
22+
const hasNotes = stepsChildren.some(
23+
(child: any) => child.props?.children
24+
)
25+
26+
const [state, setState] = React.useState({
27+
stepIndex: 0,
28+
step: editorSteps[0],
29+
})
30+
const tab = state.step
31+
32+
function onTabClick(filename: string) {
33+
const newStep = updateEditorStep(
34+
state.step,
35+
filename,
36+
null
37+
)
38+
setState({ ...state, step: newStep })
39+
}
40+
41+
return (
42+
<div
43+
className={`ch-slideshow ${
44+
presetConfig ? "ch-slideshow-with-preview" : ""
45+
}`}
46+
>
47+
<div className="ch-slideshow-slide">
48+
<InnerCode
49+
{...(tab as any)}
50+
codeConfig={codeConfig}
51+
onTabClick={onTabClick}
52+
/>
53+
{presetConfig && (
54+
<Preview
55+
className="ch-slideshow-preview"
56+
files={tab.files}
57+
presetConfig={presetConfig}
58+
/>
59+
)}
60+
</div>
61+
62+
<div className="ch-slideshow-notes">
63+
<div className="ch-slideshow-range">
64+
<button
65+
onClick={() =>
66+
setState(s => {
67+
const stepIndex = Math.max(
68+
0,
69+
s.stepIndex - 1
70+
)
71+
return {
72+
stepIndex,
73+
step: editorSteps[stepIndex],
74+
}
75+
})
76+
}
77+
>
78+
Prev
79+
</button>
80+
<input
81+
type="range"
82+
min={0}
83+
max={editorSteps.length - 1}
84+
value={state.stepIndex}
85+
step={1}
86+
onChange={e =>
87+
setState({
88+
stepIndex: +e.target.value,
89+
step: editorSteps[+e.target.value],
90+
})
91+
}
92+
/>
93+
<button
94+
onClick={() =>
95+
setState(s => {
96+
const stepIndex = Math.min(
97+
editorSteps.length - 1,
98+
s.stepIndex + 1
99+
)
100+
return {
101+
stepIndex,
102+
step: editorSteps[stepIndex],
103+
}
104+
})
105+
}
106+
>
107+
Next
108+
</button>
109+
</div>
110+
111+
{hasNotes && (
112+
<div className="ch-slideshow-note">
113+
{stepsChildren[state.stepIndex]}
114+
</div>
115+
)}
116+
</div>
117+
</div>
118+
)
119+
}

packages/mdx/src/components.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { Code } from "./client/code"
77
import { Spotlight } from "./client/spotlight"
88
import { Scrollycoding } from "./client/scrollycoding"
9+
import { Slideshow } from "./client/slideshow"
910
import {
1011
annotationsMap,
1112
Annotation,
@@ -20,4 +21,5 @@ export const CH = {
2021
Scrollycoding,
2122
annotations: annotationsMap,
2223
Annotation,
24+
Slideshow,
2325
}

packages/mdx/src/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
@import "~@code-hike/mini-browser/dist/index.scss";
33
@import "./client/spotlight.scss";
44
@import "./client/scrollycoding.scss";
5+
@import "./client/slideshow.scss";
56

67
.ch-code {
78
border-radius: 6px;

packages/mdx/src/plugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { transformSections } from "./plugin/section"
55
import { transformSpotlights } from "./plugin/spotlight"
66
import { transformScrollycodings } from "./plugin/scrollycoding"
77
import visit from "unist-util-visit"
8+
import { transformSlideshows } from "./plugin/slideshow"
89

910
export function remarkCodeHike({ theme }: { theme: any }) {
1011
return async (tree: Node) => {
@@ -27,6 +28,7 @@ export function remarkCodeHike({ theme }: { theme: any }) {
2728
try {
2829
await transformScrollycodings(tree, { theme })
2930
await transformSpotlights(tree, { theme })
31+
await transformSlideshows(tree, { theme })
3032
await transformSections(tree, { theme })
3133
await transformEditorNodes(tree, { theme })
3234
await transformCodeNodes(tree, { theme })

packages/mdx/src/plugin/slideshow.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { visitAsync, toJSX } from "./unist-utils"
2+
import { Node, Parent } from "unist"
3+
import { extractStepsInfo } from "./steps"
4+
import { getPresetConfig } from "./preview"
5+
6+
export async function transformSlideshows(
7+
tree: Node,
8+
config: { theme: any }
9+
) {
10+
await visitAsync(
11+
tree,
12+
"mdxJsxFlowElement",
13+
async node => {
14+
if (node.name === "CH.Slideshow") {
15+
await transformSlideshow(node, config)
16+
}
17+
}
18+
)
19+
}
20+
async function transformSlideshow(
21+
node: Node,
22+
{ theme }: { theme: any }
23+
) {
24+
const editorSteps = await extractStepsInfo(
25+
node as Parent,
26+
{ theme },
27+
"merge step with previous"
28+
)
29+
30+
const presetConfig = await getPresetConfig(
31+
(node as any).attributes
32+
)
33+
34+
toJSX(node, {
35+
props: {
36+
codeConfig: { theme },
37+
editorSteps: editorSteps,
38+
presetConfig,
39+
},
40+
appendProps: true,
41+
})
42+
}

0 commit comments

Comments
 (0)