Skip to content

Commit 87bfe7d

Browse files
authored
Merge pull request #139 from code-hike/better-sections
Better sections
2 parents 8c67c2f + 45d5e45 commit 87bfe7d

19 files changed

+604
-193
lines changed

.gitpod.yml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# This configuration file was automatically generated by Gitpod.
2+
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
3+
# and commit this file to your remote git repository to share the goodness with others.
4+
5+
tasks:
6+
- init: yarn install && yarn run build
7+
command: yarn run playground
8+
9+

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
},
2020
"devDependencies": {
2121
"auto": "^10.18.7",
22-
"lerna": "^4.0.0"
22+
"lerna": "^4.0.0",
23+
"prettier": "^2.5.1"
2324
},
2425
"repository": "code-hike/codehike",
2526
"author": "pomber <pombopombopombo@gmail.com>",

packages/highlighter/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
},
1818
"dependencies": {
1919
"@code-hike/utils": "^0.3.0-next.0",
20-
"shiki": "^0.9.14"
20+
"shiki": "^0.10.1"
2121
},
2222
"homepage": "https://codehike.org",
2323
"repository": "code-hike/codehike",

packages/mdx/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"node-fetch": "^2.0.0",
3535
"remark-rehype": "^8.1.0",
3636
"unified": "^9.2.2",
37-
"unist-util-visit": "^2.0.0"
37+
"unist-util-visit": "^2.0.0",
38+
"unist-util-visit-parents": "^3.0.0"
3839
},
3940
"peerDependencies": {
4041
"react": "^16.8.3 || ^17 || ^18"

packages/mdx/src/client/inline-code.tsx

+16-2
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,28 @@ import {
44
getColor,
55
transparent,
66
ColorName,
7+
Code,
78
} from "@code-hike/utils"
89

910
export function InlineCode({
1011
className,
1112
codeConfig,
1213
children,
14+
code,
1315
...rest
1416
}: {
1517
className: string
18+
code: Code
1619
children?: React.ReactNode
1720
codeConfig: { theme: EditorTheme }
1821
}) {
1922
const { theme } = codeConfig
23+
const { lines } = code
24+
const allTokens = lines.flatMap(line => line.tokens)
25+
const foreground = getColor(
26+
theme,
27+
ColorName.CodeForeground
28+
)
2029
return (
2130
<span
2231
className={
@@ -27,14 +36,19 @@ export function InlineCode({
2736
>
2837
<code
2938
style={{
39+
["--ch-code-foreground" as any]: foreground,
3040
background: transparent(
3141
getColor(theme, ColorName.CodeBackground),
3242
0.9
3343
),
34-
color: getColor(theme, ColorName.CodeForeground),
44+
color: foreground,
3545
}}
3646
>
37-
{children}
47+
{allTokens.map((token, j) => (
48+
<span key={j} {...token.props}>
49+
{token.content}
50+
</span>
51+
))}
3852
</code>
3953
</span>
4054
)

packages/mdx/src/client/scrollycoding.tsx

+24-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Step as ScrollerStep,
1010
} from "@code-hike/scroller"
1111
import { Preview, PresetConfig } from "./preview"
12+
import { LinkableSection } from "./section"
1213

1314
export function Scrollycoding({
1415
children,
@@ -45,6 +46,19 @@ export function Scrollycoding({
4546
setState({ ...state, step: newStep })
4647
}
4748

49+
function onLinkActivation(
50+
stepIndex: number,
51+
filename: string | undefined,
52+
focus: string | null
53+
) {
54+
const newStep = updateEditorStep(
55+
editorSteps[stepIndex],
56+
filename,
57+
focus
58+
)
59+
setState({ ...state, stepIndex, step: newStep })
60+
}
61+
4862
return (
4963
<section
5064
className={`ch-scrollycoding ${
@@ -64,7 +78,16 @@ export function Scrollycoding({
6478
i === state.stepIndex ? "true" : undefined
6579
}
6680
>
67-
{children}
81+
<LinkableSection
82+
onActivation={({ fileName, focus }) => {
83+
onLinkActivation(i, fileName, focus)
84+
}}
85+
onReset={() => {
86+
onStepChange(i)
87+
}}
88+
>
89+
{children}
90+
</LinkableSection>
6891
</ScrollerStep>
6992
))}
7093
</Scroller>

packages/mdx/src/client/section.tsx

+87-32
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@ import { InnerCode, updateEditorStep } from "./code"
44

55
const SectionContext = React.createContext<{
66
props: EditorProps
7-
selectedId?: string
87
setFocus: (x: {
98
fileName?: string
109
focus: string | null
1110
id: string
1211
}) => void
13-
resetFocus: () => void
1412
}>({
1513
props: null!,
1614
setFocus: () => {},
17-
resetFocus: () => {},
1815
})
1916

2017
export function Section({
@@ -48,23 +45,27 @@ export function Section({
4845
const { selectedId, ...rest } = state
4946

5047
return (
51-
<SectionContext.Provider
52-
value={{
53-
props: rest,
54-
setFocus,
55-
resetFocus,
56-
selectedId,
57-
}}
58-
>
59-
<section>{children}</section>
60-
</SectionContext.Provider>
48+
<section>
49+
<SectionContext.Provider
50+
value={{
51+
props: rest,
52+
setFocus,
53+
}}
54+
>
55+
<LinkableSection
56+
onActivation={setFocus}
57+
onReset={resetFocus}
58+
>
59+
{children}
60+
</LinkableSection>
61+
</SectionContext.Provider>
62+
</section>
6163
)
6264
}
6365

6466
export function SectionCode() {
65-
const { props, setFocus } = React.useContext(
66-
SectionContext
67-
)
67+
const { props, setFocus } =
68+
React.useContext(SectionContext)
6869

6970
const onTabClick = (filename: string) => {
7071
setFocus({ fileName: filename, focus: null, id: "" })
@@ -73,6 +74,8 @@ export function SectionCode() {
7374
return <InnerCode {...props} onTabClick={onTabClick} />
7475
}
7576

77+
// ---
78+
7679
export function SectionLink({
7780
focus,
7881
file,
@@ -84,27 +87,79 @@ export function SectionLink({
8487
file?: string
8588
children: React.ReactNode
8689
}) {
87-
const {
88-
setFocus,
89-
resetFocus,
90-
selectedId,
91-
} = React.useContext(SectionContext)
90+
const { activate, reset, activatedId } =
91+
React.useContext(LinkableContext)
9292

93-
const isSelected = selectedId === id
94-
const handleClick = isSelected
95-
? resetFocus
96-
: () => setFocus({ fileName: file, focus, id })
93+
const isSelected = activatedId === id
94+
// const handleClick = isSelected
95+
// ? resetFocus
96+
// : () => setFocus({ fileName: file, focus, id })
9797

9898
return (
9999
<span
100-
style={{
101-
textDecoration: "underline",
102-
textDecorationStyle: "dotted",
103-
cursor: "pointer",
104-
backgroundColor: isSelected ? "yellow" : undefined,
105-
}}
106-
onClick={handleClick}
100+
className="ch-section-link"
101+
data-active={isSelected}
102+
// onClick={handleClick}
107103
children={children}
104+
onMouseOver={() =>
105+
activate({ fileName: file, focus, id })
106+
}
107+
onMouseOut={reset}
108108
/>
109109
)
110110
}
111+
112+
const LinkableContext = React.createContext<{
113+
activate: (x: {
114+
fileName?: string
115+
focus: string | null
116+
id: string
117+
}) => void
118+
reset: () => void
119+
activatedId: string | undefined
120+
}>({
121+
activatedId: undefined,
122+
activate: () => {},
123+
reset: () => {},
124+
})
125+
126+
export function LinkableSection({
127+
onActivation,
128+
onReset,
129+
children,
130+
}: {
131+
onActivation: (x: {
132+
fileName?: string
133+
focus: string | null
134+
id: string
135+
}) => void
136+
onReset: () => void
137+
children: React.ReactNode
138+
}) {
139+
const [activatedId, setActivatedId] =
140+
React.useState<any>(undefined)
141+
142+
const activate = React.useCallback(
143+
x => {
144+
setActivatedId(x.id)
145+
onActivation(x)
146+
},
147+
[onActivation]
148+
)
149+
const reset = React.useCallback(() => {
150+
setActivatedId(undefined)
151+
onReset()
152+
}, [onReset])
153+
154+
return (
155+
<LinkableContext.Provider
156+
value={{
157+
activate,
158+
reset,
159+
activatedId,
160+
}}
161+
>
162+
{children}
163+
</LinkableContext.Provider>
164+
)
165+
}

packages/mdx/src/index.scss

+21-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,27 @@
2727
}
2828

2929
.ch-inline-code > code {
30-
padding: 0.2em 0.4em;
31-
margin: 0.1em -0.1em;
30+
padding: 0.2em 0.15em;
31+
margin: 0.1em -0.05em;
3232
border-radius: 0.25em;
3333
font-size: 0.9em;
3434
}
35+
36+
.ch-section-link,
37+
.ch-section-link * {
38+
text-decoration: underline;
39+
text-decoration-style: dotted;
40+
text-decoration-thickness: 1px;
41+
text-decoration-color: var(
42+
--ch-code-foreground,
43+
currentColor
44+
);
45+
}
46+
.ch-section-link[data-active="true"] {
47+
background-color: #bae6fd66;
48+
}
49+
50+
.ch-section-link[data-active="true"],
51+
.ch-section-link[data-active="true"] * {
52+
text-decoration-thickness: 1.5px;
53+
}

packages/mdx/src/plugin.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,19 @@ export function remarkCodeHike(
3434
}
3535
})
3636

37-
3837
addConfig(tree as Parent, config)
3938

4039
if (config.autoImport && !hasCodeHikeImport) {
4140
addImportNode(tree as Parent)
4241
}
4342

4443
try {
45-
await transformInlineCodes(tree)
4644
await transformPreviews(tree)
4745
await transformScrollycodings(tree, config)
4846
await transformSpotlights(tree, config)
4947
await transformSlideshows(tree, config)
5048
await transformSections(tree, config)
49+
await transformInlineCodes(tree, config)
5150
await transformEditorNodes(tree, config)
5251
await transformCodeNodes(tree, config)
5352
} catch (e) {
@@ -60,7 +59,11 @@ export function remarkCodeHike(
6059
function addConfigDefaults(
6160
config: Partial<CodeHikeConfig> | undefined
6261
): CodeHikeConfig {
63-
return { ...config, theme: config?.theme || {}, autoImport: config?.autoImport === false ? false : true }
62+
return {
63+
...config,
64+
theme: config?.theme || {},
65+
autoImport: config?.autoImport === false ? false : true,
66+
}
6467
}
6568

6669
function addConfig(tree: Parent, config: CodeHikeConfig) {
@@ -124,8 +127,7 @@ function addImportNode(tree: Parent) {
124127
type: "Literal",
125128
value:
126129
"@code-hike/mdx/dist/components.cjs.js",
127-
raw:
128-
'"@code-hike/mdx/dist/components.cjs.js"',
130+
raw: '"@code-hike/mdx/dist/components.cjs.js"',
129131
},
130132
},
131133
],

0 commit comments

Comments
 (0)