Skip to content

Commit

Permalink
Merge pull request #494 from code-hike/next
Browse files Browse the repository at this point in the history
✨ Update website ✨
  • Loading branch information
pomber authored Dec 31, 2024
2 parents 4605fbd + 8540c25 commit 4edf769
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 75 deletions.
31 changes: 17 additions & 14 deletions apps/web/content/docs/code/focus.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,14 @@ We need two things:
- Get a `ref` of the `pre` element, and scroll it if needed

```tsx focus.tsx -c
"use client"

import {
AnnotationHandler,
InnerPre,
getPreRef,
InnerLine,
} from "codehike/code"
import React, { useLayoutEffect, useRef } from "react"
// !fold[/className="(.*?)"/gm]
import { AnnotationHandler, InnerLine } from "codehike/code"
import { PreWithFocus } from "./focus.client"

export const focus: AnnotationHandler = {
name: "focus",
onlyIfAnnotated: true,
PreWithRef: (props) => {
const ref = getPreRef(props)
useScrollToFocus(ref)
return <InnerPre merge={props} />
},
PreWithRef: PreWithFocus,
Line: (props) => (
<InnerLine
merge={props}
Expand All @@ -49,6 +38,20 @@ export const focus: AnnotationHandler = {
<InnerLine merge={props} data-focus={true} className="bg-zinc-700/30" />
),
}
```

```tsx focus.client.tsx -c
// !fold[/className="(.*?)"/gm]
"use client"

import React, { useLayoutEffect, useRef } from "react"
import { AnnotationHandler, InnerPre, getPreRef } from "codehike/code"

export const PreWithFocus: AnnotationHandler["PreWithRef"] = (props) => {
const ref = getPreRef(props)
useScrollToFocus(ref)
return <InnerPre merge={props} />
}

function useScrollToFocus(ref: React.RefObject<HTMLPreElement>) {
const firstRender = useRef(true)
Expand Down
2 changes: 1 addition & 1 deletion apps/web/content/docs/concepts/blocks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ The same applies to images, codeblocks, and paragraphs.
## Nesting
You can use headigns with different levels to create nested blocks.
You can use headings with different levels to create nested blocks.
<BlocksDemo>
Expand Down
65 changes: 5 additions & 60 deletions apps/web/demos/focus/code.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
"use client"

import {
HighlightedCode,
Pre,
AnnotationHandler,
InnerPre,
getPreRef,
InnerLine,
} from "codehike/code"
import React, { useLayoutEffect, useRef, useState } from "react"
import { HighlightedCode, Pre } from "codehike/code"
import React, { useState } from "react"
import { focus } from "./focus"

const ranges = {
lorem: { fromLineNumber: 1, toLineNumber: 5 },
Expand Down Expand Up @@ -42,67 +36,18 @@ export function CodeContainer({ code }: { code: HighlightedCode }) {
<button
onClick={() => setFocused("lorem")}
disabled={focused === "lorem"}
className="border border-current rounded px-2 disabled:opacity-60"
className="border border-current rounded px-2"
>
focus `lorem`
</button>{" "}
<button
onClick={() => setFocused("dolor")}
disabled={focused === "dolor"}
className="border border-current rounded px-2 disabled:opacity-60"
className="border border-current rounded px-2"
>
focus `dolor`
</button>
</div>
</>
)
}

const focus: AnnotationHandler = {
name: "focus",
PreWithRef: (props) => {
const ref = getPreRef(props)
useScrollToFocus(ref)
return <InnerPre merge={props} />
},
Line: (props) => (
<InnerLine
merge={props}
className="opacity-50 data-[focus]:opacity-100 px-2"
/>
),
AnnotatedLine: ({ annotation, ...props }) => (
<InnerLine merge={props} data-focus={true} className="bg-zinc-700/30" />
),
}

function useScrollToFocus(ref: React.RefObject<HTMLPreElement>) {
const firstRender = useRef(true)
useLayoutEffect(() => {
if (ref.current) {
// find all descendants whith data-focus="true"
const focusedElements = ref.current.querySelectorAll(
"[data-focus=true]",
) as NodeListOf<HTMLElement>

// find top and bottom of the focused elements
const containerRect = ref.current.getBoundingClientRect()
let top = Infinity
let bottom = -Infinity
focusedElements.forEach((el) => {
const rect = el.getBoundingClientRect()
top = Math.min(top, rect.top - containerRect.top)
bottom = Math.max(bottom, rect.bottom - containerRect.top)
})

// scroll to the focused elements if any part of them is not visible
if (bottom > containerRect.height || top < 0) {
ref.current.scrollTo({
top: ref.current.scrollTop + top - 10,
behavior: firstRender.current ? "instant" : "smooth",
})
}
firstRender.current = false
}
})
}
41 changes: 41 additions & 0 deletions apps/web/demos/focus/focus.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client"

import React, { useLayoutEffect, useRef } from "react"
import { AnnotationHandler, InnerPre, getPreRef } from "codehike/code"

export const PreWithFocus: AnnotationHandler["PreWithRef"] = (props) => {
const ref = getPreRef(props)
useScrollToFocus(ref)
return <InnerPre merge={props} />
}

function useScrollToFocus(ref: React.RefObject<HTMLPreElement>) {
const firstRender = useRef(true)
useLayoutEffect(() => {
if (ref.current) {
// find all descendants whith data-focus="true"
const focusedElements = ref.current.querySelectorAll(
"[data-focus=true]",
) as NodeListOf<HTMLElement>

// find top and bottom of the focused elements
const containerRect = ref.current.getBoundingClientRect()
let top = Infinity
let bottom = -Infinity
focusedElements.forEach((el) => {
const rect = el.getBoundingClientRect()
top = Math.min(top, rect.top - containerRect.top)
bottom = Math.max(bottom, rect.bottom - containerRect.top)
})

// scroll to the focused elements if any part of them is not visible
if (bottom > containerRect.height || top < 0) {
ref.current.scrollTo({
top: ref.current.scrollTop + top - 10,
behavior: firstRender.current ? "instant" : "smooth",
})
}
firstRender.current = false
}
})
}
17 changes: 17 additions & 0 deletions apps/web/demos/focus/focus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AnnotationHandler, InnerLine } from "codehike/code"
import { PreWithFocus } from "./focus.client"

export const focus: AnnotationHandler = {
name: "focus",
onlyIfAnnotated: true,
PreWithRef: PreWithFocus,
Line: (props) => (
<InnerLine
merge={props}
className="opacity-50 data-[focus]:opacity-100 px-2"
/>
),
AnnotatedLine: ({ annotation, ...props }) => (
<InnerLine merge={props} data-focus={true} className="bg-zinc-700/30" />
),
}

0 comments on commit 4edf769

Please sign in to comment.