Skip to content

Commit

Permalink
docs(suspensive.org): code transition (#1369)
Browse files Browse the repository at this point in the history
close #1367 

# Code transition for main page

<!--
    A clear and concise description of what this pr is about.
 -->

![chrome-capture-2024-11-24
(1)](https://github.com/user-attachments/assets/469513be-7c0d-4de4-a431-bb5c0a886e2d)

## PR Checklist

- [x] I did below actions if need

1. I read the [Contributing
Guide](https://github.com/toss/suspensive/blob/main/CONTRIBUTING.md)
2. I added documents and tests.
  • Loading branch information
manudeli authored Nov 23, 2024
1 parent 1f07080 commit 63a126e
Show file tree
Hide file tree
Showing 7 changed files with 1,095 additions and 7 deletions.
11 changes: 10 additions & 1 deletion docs/suspensive.org/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { recmaCodeHike, remarkCodeHike } from 'codehike/mdx'
import nextra from 'nextra'
import { remarkSandpack } from 'remark-sandpack'

/** @type {import('codehike/mdx').CodeHikeConfig} */
const chConfig = {
syntaxHighlighting: {
theme: 'github-dark',
},
}

const withNextra = nextra({
autoImportThemeStyle: true,
theme: 'nextra-theme-docs',
themeConfig: './theme.config.tsx',
defaultShowCopyCode: true,
latex: true,
mdxOptions: {
remarkPlugins: [remarkSandpack],
remarkPlugins: [[remarkCodeHike, chConfig], remarkSandpack],
recmaPlugins: [[recmaCodeHike, chConfig]],
rehypePlugins: [],
rehypePrettyCodeOptions: {
theme: 'github-dark-default',
Expand Down
4 changes: 3 additions & 1 deletion docs/suspensive.org/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@suspensive/react-query-4": "workspace:*",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-query-devtools": "^4.36.1",
"codehike": "^1.0.4",
"d3": "^7.9.0",
"framer-motion": "^11.11.8",
"next": "catalog:",
Expand All @@ -35,7 +36,8 @@
"react": "catalog:react18",
"react-dom": "catalog:react18",
"remark-sandpack": "^0.0.5",
"sharp": "catalog:"
"sharp": "catalog:",
"zod": "^3.23.8"
},
"devDependencies": {
"@suspensive/eslint-config": "workspace:*",
Expand Down
204 changes: 204 additions & 0 deletions docs/suspensive.org/src/components/Scrollycoding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import { Block, HighlightedCodeBlock, parseProps } from 'codehike/blocks'
import {
type AnnotationHandler,
type CustomPreProps,
type HighlightedCode,
InnerLine,
InnerPre,
InnerToken,
Pre,
getPreRef,
} from 'codehike/code'
import {
Selectable,
Selection,
SelectionProvider,
} from 'codehike/utils/selection'
import {
type TokenTransitionsSnapshot,
calculateTransitions,
getStartingSnapshot,
} from 'codehike/utils/token-transitions'
import { Component, type RefObject } from 'react'
import { z } from 'zod'

const MAX_TRANSITION_DURATION = 900 // milliseconds

export class SmoothPre extends Component<CustomPreProps> {
ref: RefObject<HTMLPreElement>
constructor(props: CustomPreProps) {
super(props)
this.ref = getPreRef(this.props)
}

render() {
return <InnerPre merge={this.props} style={{ position: 'relative' }} />
}

getSnapshotBeforeUpdate() {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return getStartingSnapshot(this.ref.current!)
}

componentDidUpdate(
prevProps: never,
prevState: never,
snapshot: TokenTransitionsSnapshot
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const transitions = calculateTransitions(this.ref.current!, snapshot)
transitions.forEach(({ element, keyframes, options }) => {
const { translateX, translateY, ...kf } = keyframes as any
if (translateX && translateY) {
kf.translate = [
`${translateX[0]}px ${translateY[0]}px`,
`${translateX[1]}px ${translateY[1]}px`,
]
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
element.animate(kf, {
duration: options.duration * MAX_TRANSITION_DURATION,
delay: options.delay * MAX_TRANSITION_DURATION,
easing: options.easing,
fill: 'both',
})
})
}
}

const Schema = Block.extend({
steps: z.array(Block.extend({ code: HighlightedCodeBlock })),
})

export function Scrollycoding(props: unknown) {
const { steps } = parseProps(props, Schema)
return (
<>
{/* only in desktop */}
<SelectionProvider className="my-4 mb-24 hidden gap-4 md:flex">
<div className="mb-[40vh]" style={{ flex: 1 }}>
{steps.map((step, i) => (
<Selectable
key={i}
index={i}
selectOn={['click', 'scroll']}
className="mb-56 cursor-pointer px-5 py-2 opacity-30 blur-lg transition data-[selected=true]:opacity-100 data-[selected=true]:blur-none"
>
<h2 className="2xl mb-4 mt-4 text-lg font-bold">{step.title}</h2>
<div className="opacity-90">{step.children}</div>
</Selectable>
))}
</div>

<div
className="rounded-xl border-2 border-[#ffffff10] bg-[#191919]"
style={{ flex: 2 }}
>
<div className="sticky top-16 overflow-auto">
<Selection
from={steps.map((step) => (
<Code
// eslint-disable-next-line @eslint-react/no-duplicate-key
key="this key should be same desktop"
codeblock={step.code}
/>
))}
/>
</div>
</div>
</SelectionProvider>
{/* only in mobile */}
<SelectionProvider className="my-4 mb-24 flex gap-2 md:hidden">
<div className="mb-[40vh]" style={{ flex: 1 }}>
{steps.map((step, i) => (
<Selectable
key={i}
index={i}
selectOn={['click', 'scroll']}
className="mb-20 cursor-pointer py-2 opacity-30 blur-lg transition data-[selected=true]:opacity-100 data-[selected=true]:blur-none"
>
<h2 className="mb-2 text-lg font-bold">{step.title}</h2>
<div className="opacity-90">{step.children}</div>
</Selectable>
))}
</div>
<div className="-mr-6 rounded-xl" style={{ flex: 2 }}>
<div className="sticky top-28 overflow-auto">
<Selection
from={steps.map((step) => (
<CodeMobile
// eslint-disable-next-line @eslint-react/no-duplicate-key
key="this key should be same mobile"
codeblock={step.code}
/>
))}
/>
</div>
</div>
</SelectionProvider>
</>
)
}

const tokenTransitions: AnnotationHandler = {
name: 'token-transitions',
PreWithRef: SmoothPre,
Token: (props) => (
<InnerToken merge={props} style={{ display: 'inline-block' }} />
),
}
const wordWrap: AnnotationHandler = {
name: 'word-wrap',
Pre: (props) => <InnerPre merge={props} className="whitespace-pre-wrap" />,
Line: (props) => (
<InnerLine
merge={props}
style={{
textIndent: `${-props.indentation}ch`,
marginLeft: `${props.indentation}ch`,
}}
/>
),
Token: (props) => <InnerToken merge={props} style={{ textIndent: 0 }} />,
}
function Code({ codeblock }: { codeblock: HighlightedCode }) {
return (
<Pre
code={codeblock}
handlers={[tokenTransitions, wordWrap]}
className="min-h-[40rem] p-6"
/>
)
}

const tokenTransitionsMobile: AnnotationHandler = {
name: 'token-transitions',
PreWithRef: SmoothPre,
Token: (props) => (
<InnerToken merge={props} style={{ display: 'inline-block' }} />
),
}
const wordWrapMobile: AnnotationHandler = {
name: 'word-wrap',
Pre: (props) => <InnerPre merge={props} className="whitespace-pre-wrap" />,
Line: (props) => (
<InnerLine
merge={props}
style={{
fontSize: '0.5rem',
textIndent: `${-props.indentation}ch`,
marginLeft: `${props.indentation}ch`,
}}
/>
),
Token: (props) => <InnerToken merge={props} style={{ textIndent: 0 }} />,
}
function CodeMobile({ codeblock }: { codeblock: HighlightedCode }) {
return (
<Pre
code={codeblock}
handlers={[tokenTransitionsMobile, wordWrapMobile]}
className="min-h-[40rem] p-2"
/>
)
}
1 change: 1 addition & 0 deletions docs/suspensive.org/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { Callout } from './Callout'
export { HomePage } from './HomePage'
export { Sandpack } from './Sandpack'
export { BubbleChart } from './BubbleChart'
export { Scrollycoding } from './Scrollycoding'
Loading

0 comments on commit 63a126e

Please sign in to comment.