├── .changeset ├── README.md └── config.json ├── .github ├── scripts │ ├── git-utils.mjs │ ├── md-utils.mjs │ ├── params.mjs │ ├── pr-merged.mjs │ ├── pr-updated.mjs │ ├── prepare-release.mjs │ ├── readme.md │ ├── release.mjs │ └── website-pr.mjs └── workflows │ ├── pr-merged.yml │ ├── pr-updated.yml │ ├── push-to-next.yml │ └── release-pr-merged.yml ├── .gitignore ├── .prettierrc ├── .vscode └── settings.json ├── CHANGELOG.md ├── apps └── web │ ├── .gitignore │ ├── app │ ├── api │ │ ├── revalidate │ │ │ ├── sponsors │ │ │ │ └── route.ts │ │ │ └── test │ │ │ │ └── route.ts │ │ └── search │ │ │ └── route.ts │ ├── blog │ │ ├── [slug] │ │ │ ├── page.tsx │ │ │ └── pomber.jpg │ │ ├── feed.xml │ │ │ └── route.ts │ │ ├── layout.tsx │ │ ├── og │ │ │ └── page.tsx │ │ └── page.tsx │ ├── demo │ │ ├── client.tsx │ │ ├── content.mdx │ │ └── page.tsx │ ├── docs │ │ ├── [[...slug]] │ │ │ ├── code-example.tsx │ │ │ ├── layout-example.tsx │ │ │ ├── page.tsx │ │ │ └── preview-implementation.tsx │ │ └── layout.tsx │ ├── favicon.ico │ ├── global.css │ ├── landing │ │ ├── boxes.tsx │ │ ├── demo.md │ │ ├── demo.tsx │ │ ├── download.tsx │ │ ├── logo.drivly.png │ │ ├── logo.github.png │ │ ├── logo.meta.png │ │ ├── logo.speakeasy.svg │ │ ├── logo.uidev.svg │ │ ├── placeholdifier-monospace.woff2 │ │ ├── placeholdifier.woff2 │ │ ├── profile.md │ │ ├── sponsors.json │ │ ├── sponsors.tsx │ │ ├── sponsors │ │ │ ├── codehike-transactions.csv │ │ │ ├── csv.js │ │ │ ├── gh-sponsors.js │ │ │ ├── oc-sponsors.js │ │ │ └── update.js │ │ └── text.github.png │ ├── layout.tsx │ ├── not-found.tsx │ ├── page.tsx │ ├── play │ │ └── page.tsx │ ├── source.ts │ ├── test │ │ ├── client.tsx │ │ ├── content.md │ │ └── page.tsx │ └── top-sponsors.png │ │ └── route.tsx │ ├── components.json │ ├── components │ ├── all-code-demos.tsx │ ├── annotations │ │ ├── callout.tsx │ │ ├── collapse.tsx │ │ ├── diff.tsx │ │ ├── focus.client.tsx │ │ ├── focus.tsx │ │ ├── fold.client.tsx │ │ ├── fold.tsx │ │ ├── icons.tsx │ │ ├── line-numbers.tsx │ │ ├── link.tsx │ │ ├── mark.tsx │ │ ├── pill.tsx │ │ ├── ruler.tsx │ │ ├── token-transitions.client.tsx │ │ ├── token-transitions.tsx │ │ ├── tooltip.tsx │ │ └── word-wrap.tsx │ ├── blocks-to-context.tsx │ ├── code.tsx │ ├── code │ │ ├── blocks-demo.tsx │ │ ├── code-with-notes.tsx │ │ └── side-by-side.tsx │ ├── component-pack-link.tsx │ ├── copy-button.tsx │ ├── demo.tsx │ ├── layout-demo.tsx │ ├── smooth-pre.tsx │ ├── time-ago.tsx │ └── ui │ │ ├── collapsible.tsx │ │ ├── dropdown-menu.tsx │ │ ├── hover-card.tsx │ │ ├── resizable.tsx │ │ ├── select.tsx │ │ ├── tabs.tsx │ │ └── tooltip.tsx │ ├── content │ ├── blog │ │ ├── .prettierrc │ │ ├── bestiary.mdx │ │ ├── build-time-components.mdx │ │ ├── build-time-components.tsx │ │ ├── codeblocks.mdx │ │ ├── content-presentation-gap.mdx │ │ ├── content-presentation-gap.tsx │ │ ├── fine-grained-markdown.mdx │ │ ├── fine-grained │ │ │ ├── code.tsx │ │ │ └── scrolly.tsx │ │ ├── headless-codeblocks.md │ │ ├── hello-server.mdx │ │ ├── known-keys.mdx │ │ ├── markdown.mdx │ │ ├── migrate-to-ch.mdx │ │ ├── participation.mdx │ │ ├── power-of-the-web.mdx │ │ ├── remotion.mdx │ │ ├── remotion │ │ │ ├── .prettierrc │ │ │ ├── 00.jsx │ │ │ ├── 01.jsx │ │ │ ├── 02.jsx │ │ │ ├── 03.jsx │ │ │ ├── 04.jsx │ │ │ ├── 05.jsx │ │ │ ├── 06.jsx │ │ │ └── code.tsx │ │ ├── rich-content-websites.mdx │ │ ├── rsc-and-css.mdx │ │ ├── test.mdx │ │ ├── the-curse-of-markdown.mdx │ │ ├── the-curse-of-markdown.steps.tsx │ │ ├── the-curse-of-markdown.tsx │ │ ├── three-component-problem.mdx │ │ ├── type-safe-markdown.mdx │ │ ├── v1-migration.mdx │ │ ├── v1.mdx │ │ └── v1.tsx │ ├── components │ │ ├── .prettierrc │ │ ├── api-reference │ │ │ ├── api-reference.tsx │ │ │ ├── collapsible.tsx │ │ │ └── source.mdx │ │ └── slideshow │ │ │ ├── slides.tsx │ │ │ ├── slideshow.tsx │ │ │ └── source.mdx │ └── docs │ │ ├── api.mdx │ │ ├── api.tsx │ │ ├── code │ │ ├── callout.mdx │ │ ├── classname.mdx │ │ ├── code-mentions.mdx │ │ ├── collapse.mdx │ │ ├── copy-button.mdx │ │ ├── diff.mdx │ │ ├── filename.mdx │ │ ├── focus.mdx │ │ ├── fold.mdx │ │ ├── footnotes.mdx │ │ ├── index.mdx │ │ ├── language-switcher.mdx │ │ ├── line-numbers.mdx │ │ ├── link.mdx │ │ ├── mark.mdx │ │ ├── tabs.mdx │ │ ├── token-transitions.mdx │ │ ├── tooltip.mdx │ │ ├── transpile.mdx │ │ ├── twoslash.mdx │ │ └── word-wrap.mdx │ │ ├── concepts │ │ ├── annotations.mdx │ │ ├── assets │ │ │ └── index.js │ │ ├── blocks.mdx │ │ ├── code.mdx │ │ ├── theme-picker.tsx │ │ └── utils.mdx │ │ ├── examples.mdx │ │ ├── examples.tsx │ │ ├── index.mdx │ │ ├── layouts │ │ ├── scrollycoding.mdx │ │ ├── slideshow.mdx │ │ └── spotlight.mdx │ │ ├── meta.json │ │ └── test.mdx │ ├── demos │ ├── annotations │ │ ├── basic │ │ │ ├── content.md │ │ │ └── page.tsx │ │ ├── groups │ │ │ ├── content.md │ │ │ └── page.tsx │ │ ├── mark │ │ │ ├── content.md │ │ │ └── page.tsx │ │ ├── query │ │ │ ├── content.md │ │ │ └── page.tsx │ │ └── regex │ │ │ ├── content.md │ │ │ └── page.tsx │ ├── api-reference │ │ ├── .prettierrc │ │ ├── content.md │ │ └── page.tsx │ ├── autolink │ │ ├── content.md │ │ └── page.tsx │ ├── callout │ │ ├── content.md │ │ └── page.tsx │ ├── classname │ │ ├── content.md │ │ └── page.tsx │ ├── collapse │ │ ├── content.md │ │ └── page.tsx │ ├── copy-button │ │ ├── button.tsx │ │ ├── content.md │ │ └── page.tsx │ ├── diff │ │ ├── content.md │ │ └── page.tsx │ ├── filename │ │ ├── content.md │ │ └── page.tsx │ ├── focus │ │ ├── code.tsx │ │ ├── content.md │ │ ├── focus.client.tsx │ │ ├── focus.tsx │ │ └── page.tsx │ ├── fold │ │ ├── annotations.tsx │ │ ├── content.md │ │ └── page.tsx │ ├── footnotes │ │ ├── content.md │ │ └── page.tsx │ ├── hover │ │ ├── content.mdx │ │ ├── page.tsx │ │ └── styles.css │ ├── language-switcher │ │ ├── content.mdx │ │ ├── multi-code.tsx │ │ └── page.tsx │ ├── line-numbers │ │ ├── content.md │ │ └── page.tsx │ ├── link │ │ ├── content.md │ │ └── page.tsx │ ├── mark │ │ ├── content.md │ │ └── page.tsx │ ├── occurrences │ │ ├── code.tsx │ │ ├── content.md │ │ └── page.tsx │ ├── scrollycoding │ │ ├── .prettierrc │ │ ├── content.md │ │ └── page.tsx │ ├── slideshow │ │ ├── .prettierrc │ │ ├── content.md │ │ ├── controls.tsx │ │ └── page.tsx │ ├── spotlight │ │ ├── .prettierrc │ │ ├── content.md │ │ └── page.tsx │ ├── tabs │ │ ├── content.mdx │ │ └── page.tsx │ ├── token-transitions │ │ ├── code.tsx │ │ ├── content.md │ │ ├── content.mdx │ │ └── page.tsx │ ├── tooltip │ │ ├── content.mdx │ │ └── page.tsx │ ├── transpile │ │ ├── content.md │ │ └── page.tsx │ ├── twoslash │ │ ├── content.md │ │ └── page.tsx │ └── word-wrap │ │ ├── content.md │ │ └── page.tsx │ ├── lib │ └── utils.ts │ ├── mdx-components.tsx │ ├── next.config.mjs │ ├── package.json │ ├── postcss.config.js │ ├── public │ ├── blog │ │ ├── build-time-components.png │ │ ├── curse │ │ │ ├── nat.org.png │ │ │ └── tailwindcss.com.png │ │ ├── fine-grained-markdown.png │ │ ├── remotion.png │ │ ├── remotion │ │ │ ├── 00.mp4 │ │ │ ├── 02.mp4 │ │ │ ├── 04.mp4 │ │ │ ├── 06.mp4 │ │ │ └── examples.mp4 │ │ ├── rich-content-websites.png │ │ ├── the-curse-of-markdown.png │ │ ├── v1-migration.png │ │ └── v1.png │ ├── codehike.png │ ├── dark-grid.svg │ ├── examples │ │ ├── docusaurus.png │ │ ├── fumadocs.png │ │ ├── nextra-3.png │ │ ├── remotion.png │ │ ├── shopify.png │ │ └── swiftui.png │ ├── grid.svg │ └── logo.png │ ├── tailwind.config.ts │ ├── theme.mjs │ ├── tsconfig.json │ └── ui │ ├── dependency-terminal.tsx │ ├── example-tabs.tsx │ ├── nav.tsx │ ├── tabs-toggle.tsx │ ├── tabs.tsx │ ├── toggle-group.tsx │ └── toggle.tsx ├── license ├── package.json ├── packages ├── codehike │ ├── CHANGELOG.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── blocks.ts │ │ ├── code.tsx │ │ ├── code │ │ │ ├── block.tsx │ │ │ ├── extract-annotations.test.ts │ │ │ ├── extract-annotations.tsx │ │ │ ├── highlight.ts │ │ │ ├── inline.tsx │ │ │ ├── inner.tsx │ │ │ ├── lines.tsx │ │ │ ├── merge-props.ts │ │ │ ├── pre-ref.tsx │ │ │ ├── pre.tsx │ │ │ ├── tokens.tsx │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── mdx.ts │ │ ├── mdx │ │ │ ├── 0.import-code-from-path.ts │ │ │ ├── 1.0.transform-hikes.ts │ │ │ ├── 1.1.remark-list-to-section.ts │ │ │ ├── 1.2.remark-section-to-attribute.ts │ │ │ ├── 2.transform-code.ts │ │ │ ├── 3.transform-hike-props.ts │ │ │ ├── config.ts │ │ │ └── estree.ts │ │ ├── utils.tsx │ │ └── utils │ │ │ ├── scroller.tsx │ │ │ ├── selection.tsx │ │ │ ├── static-fallback.tsx │ │ │ └── token-transitions.tsx │ ├── tests │ │ ├── md-suite │ │ │ ├── _readme.md │ │ │ ├── annotation.0.mdx │ │ │ ├── annotation.0.render.tsx │ │ │ ├── annotation.9.rendered.html │ │ │ ├── assets │ │ │ │ └── test.py │ │ │ ├── basic.0.mdx │ │ │ ├── basic.2.before-remark.json │ │ │ ├── basic.3.after-remark.json │ │ │ ├── basic.4.after-rehype.json │ │ │ ├── basic.5.before-recma-compiled-function.jsx │ │ │ ├── basic.5.before-recma-compiled-js.js │ │ │ ├── basic.5.before-recma-compiled-jsx.jsx │ │ │ ├── basic.5.before-recma-js-dev.json │ │ │ ├── basic.5.before-recma-js.json │ │ │ ├── basic.5.before-recma-jsx.json │ │ │ ├── basic.6.after-recma-js-dev.json │ │ │ ├── basic.6.after-recma-js.json │ │ │ ├── basic.6.after-recma-jsx.json │ │ │ ├── basic.7.compiled-function.jsx │ │ │ ├── basic.7.compiled-js-dev.js │ │ │ ├── basic.7.compiled-js.js │ │ │ ├── basic.7.compiled-jsx.jsx │ │ │ ├── basic.8.parsed-jsx.jsx │ │ │ ├── basic.9.rendered-dev.html │ │ │ ├── basic.9.rendered.html │ │ │ ├── code-empty.0.mdx │ │ │ ├── code-empty.7.compiled-jsx.jsx │ │ │ ├── code-empty.9.rendered.html │ │ │ ├── code.0.mdx │ │ │ ├── code.7.compiled-jsx.jsx │ │ │ ├── code.9.rendered.html │ │ │ ├── empty-block.0.mdx │ │ │ ├── empty-block.8.parsed-jsx.jsx │ │ │ ├── empty-children-and-import.0.mdx │ │ │ ├── empty-children-and-import.7.compiled-jsx.jsx │ │ │ ├── empty-line.0.mdx │ │ │ ├── empty-line.7.compiled-jsx.jsx │ │ │ ├── empty-line.9.rendered.html │ │ │ ├── ignore-codeblock.0.mdx │ │ │ ├── ignore-codeblock.7.compiled-jsx.jsx │ │ │ ├── import-code.0.mdx │ │ │ ├── import-code.0.render.tsx │ │ │ ├── import-code.7.compiled-jsx.jsx │ │ │ ├── import-code.9.rendered.html │ │ │ ├── indentation.0.mdx │ │ │ ├── indentation.0.render.tsx │ │ │ ├── indentation.9.rendered.html │ │ │ ├── inline-code-highlighted.0.mdx │ │ │ ├── inline-code-highlighted.2.before-remark.json │ │ │ ├── inline-code-highlighted.7.compiled-jsx.jsx │ │ │ ├── inline-code-highlighted.9.rendered.html │ │ │ ├── inline-code.0.mdx │ │ │ ├── inline-code.2.before-remark.json │ │ │ ├── inline-code.7.compiled-jsx.jsx │ │ │ ├── inline-code.9.rendered.html │ │ │ ├── nested-blocks.0.mdx │ │ │ ├── nested-blocks.8.parsed-jsx.jsx │ │ │ ├── no-hike.0.mdx │ │ │ ├── no-hike.7.compiled-jsx.jsx │ │ │ ├── only-if-annotated.0.mdx │ │ │ ├── only-if-annotated.0.render.tsx │ │ │ ├── only-if-annotated.9.rendered.html │ │ │ ├── regex-range.0.mdx │ │ │ ├── regex-range.0.render.tsx │ │ │ ├── regex-range.9.rendered.html │ │ │ ├── stacked-line.0.mdx │ │ │ ├── stacked-line.0.render.tsx │ │ │ ├── stacked-line.9.rendered.html │ │ │ ├── stacked-token.0.mdx │ │ │ ├── stacked-token.0.render.tsx │ │ │ ├── stacked-token.9.rendered.html │ │ │ ├── static-children.0.mdx │ │ │ ├── static-children.5.before-recma-compiled-js.js │ │ │ ├── static-children.5.before-recma-js-dev.json │ │ │ ├── static-children.5.before-recma-js.json │ │ │ ├── static-children.6.after-recma-js-dev.json │ │ │ ├── static-children.6.after-recma-js.json │ │ │ ├── static-children.7.compiled-js-dev.js │ │ │ ├── static-children.7.compiled-js.js │ │ │ ├── static-children.9.rendered-dev.html │ │ │ ├── syntax-highlight.0.mdx │ │ │ ├── syntax-highlight.7.compiled-jsx.jsx │ │ │ ├── two-ps.0.mdx │ │ │ ├── two-ps.2.before-remark.json │ │ │ ├── two-ps.8.parsed-jsx.jsx │ │ │ ├── unknown-lang.0.mdx │ │ │ └── unknown-lang.9.rendered.html │ │ ├── md.test.tsx │ │ ├── utils.ast.tsx │ │ └── utils.suite.tsx │ └── tsconfig.json ├── recma │ ├── index.js │ └── package.json └── remark │ ├── index.js │ └── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── readme.md └── turbo.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { "repo": "code-hike/codehike" } 6 | ], 7 | "commit": false, 8 | "fixed": [], 9 | "linked": [], 10 | "access": "restricted", 11 | "baseBranch": "main", 12 | "updateInternalDependencies": "patch", 13 | "ignore": ["web"] 14 | } 15 | -------------------------------------------------------------------------------- /.github/scripts/git-utils.mjs: -------------------------------------------------------------------------------- 1 | import { exec, getExecOutput } from "@actions/exec" 2 | import github from "@actions/github" 3 | import fs from "fs" 4 | 5 | export async function checkout(branch) { 6 | let { stderr } = await getExecOutput("git", ["checkout", branch], { 7 | ignoreReturnCode: true, 8 | }) 9 | let isCreatingBranch = !stderr 10 | .toString() 11 | .includes(`Switched to a new branch '${branch}'`) 12 | if (isCreatingBranch) { 13 | await exec("git", ["checkout", "-b", branch]) 14 | } 15 | } 16 | 17 | export async function resetBranch() { 18 | // reset current branch to the commit that triggered the workflow 19 | await exec("git", ["reset", `--hard`, github.context.sha]) 20 | } 21 | 22 | export async function commitAll(message) { 23 | await exec("git", ["add", "."]) 24 | await exec("git", ["commit", "-m", message]) 25 | } 26 | 27 | export async function forcePush(branch) { 28 | await exec("git", ["push", "origin", `HEAD:${branch}`, "--force"]) 29 | } 30 | 31 | export async function setupUser() { 32 | await exec("git", ["config", "user.name", `"github-actions[bot]"`]) 33 | await exec("git", [ 34 | "config", 35 | "user.email", 36 | `"github-actions[bot]@users.noreply.github.com"`, 37 | ]) 38 | await fs.promises.writeFile( 39 | `${process.env.HOME}/.netrc`, 40 | `machine github.com\nlogin github-actions[bot]\npassword ${process.env.GITHUB_TOKEN}`, 41 | ) 42 | } 43 | 44 | export async function pushTags() { 45 | await exec("git", ["push", "origin", "--tags"]) 46 | } 47 | -------------------------------------------------------------------------------- /.github/scripts/md-utils.mjs: -------------------------------------------------------------------------------- 1 | import { unified } from "unified" 2 | import remarkParse from "remark-parse" 3 | import remarkStringify from "remark-stringify" 4 | import * as mdastToString from "mdast-util-to-string" 5 | 6 | const BumpLevels = { 7 | dep: 0, 8 | patch: 1, 9 | minor: 2, 10 | major: 3, 11 | } 12 | 13 | export function getChangelogEntry(changelog, version) { 14 | let ast = unified().use(remarkParse).parse(changelog) 15 | 16 | let highestLevel = BumpLevels.dep 17 | 18 | let nodes = ast.children 19 | let headingStartInfo 20 | let endIndex 21 | 22 | for (let i = 0; i < nodes.length; i++) { 23 | let node = nodes[i] 24 | if (node.type === "heading") { 25 | let stringified = mdastToString.toString(node) 26 | let match = stringified.toLowerCase().match(/(major|minor|patch)/) 27 | if (match !== null) { 28 | let level = BumpLevels[match[0]] 29 | highestLevel = Math.max(level, highestLevel) 30 | } 31 | if (headingStartInfo === undefined && stringified === version) { 32 | headingStartInfo = { 33 | index: i, 34 | depth: node.depth, 35 | } 36 | continue 37 | } 38 | if ( 39 | endIndex === undefined && 40 | headingStartInfo !== undefined && 41 | headingStartInfo.depth === node.depth 42 | ) { 43 | endIndex = i 44 | break 45 | } 46 | } 47 | } 48 | if (headingStartInfo) { 49 | ast.children = ast.children.slice(headingStartInfo.index + 1, endIndex) 50 | } 51 | return { 52 | content: unified().use(remarkStringify).stringify(ast), 53 | highestLevel: highestLevel, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.github/scripts/params.mjs: -------------------------------------------------------------------------------- 1 | export const PACKAGE_NAME = "codehike" 2 | export const VERSION_COMMAND = "pnpm version-packages" 3 | export const PUBLISH_COMMAND = "pnpm release" 4 | export const RELEASE_BRANCH = "release" 5 | export const BASE_BRANCH = "next" 6 | export const PACKAGE_DIR = `packages/${PACKAGE_NAME}` 7 | 8 | export const IDENTIFIER = "" 9 | -------------------------------------------------------------------------------- /.github/scripts/pr-merged.mjs: -------------------------------------------------------------------------------- 1 | import { Octokit } from "@octokit/action" 2 | import { IDENTIFIER, PACKAGE_NAME } from "./params.mjs" 3 | import github from "@actions/github" 4 | 5 | const octokit = new Octokit({}) 6 | const prNumber = github.context.payload.pull_request.number 7 | 8 | console.log("Querying closing issues") 9 | const query = `query ($owner: String!, $repo: String!, $prNumber: Int!) { 10 | repository(owner: $owner, name: $repo) { 11 | pullRequest(number: $prNumber) { 12 | title 13 | state 14 | closingIssuesReferences(first: 10) { 15 | nodes { 16 | number 17 | } 18 | } 19 | } 20 | } 21 | }` 22 | const result = await octokit.graphql(query, { 23 | ...github.context.repo, 24 | prNumber: Number(prNumber), 25 | }) 26 | 27 | const body = `${IDENTIFIER} 28 | This issue has been fixed but not yet released. 29 | 30 | Try it in your project before the release with: 31 | 32 | ${"```"} 33 | npm i https://pkg.pr.new/${PACKAGE_NAME}@${prNumber} 34 | ${"```"} 35 | 36 | Or wait for the next [release](https://github.com/${github.context.repo.owner}/${github.context.repo.repo}/pulls?q=is%3Aopen+is%3Apr+label%3Arelease). 37 | ` 38 | 39 | console.log("Commenting issues") 40 | await Promise.all( 41 | result.repository.pullRequest.closingIssuesReferences.nodes.map( 42 | async ({ number }) => { 43 | console.log("Commenting issue", number) 44 | await octokit.issues.createComment({ 45 | ...github.context.repo, 46 | issue_number: number, 47 | body, 48 | }) 49 | }, 50 | ), 51 | ) 52 | -------------------------------------------------------------------------------- /.github/scripts/website-pr.mjs: -------------------------------------------------------------------------------- 1 | import { Octokit } from "@octokit/action" 2 | import github from "@actions/github" 3 | import { BASE_BRANCH } from "./params.mjs" 4 | 5 | const octokit = new Octokit({}) 6 | 7 | console.log("Find existing PR") 8 | const { data: prs } = await octokit.pulls.list({ 9 | ...github.context.repo, 10 | state: "open", 11 | base: "main", 12 | head: `${github.context.repo.owner}:${BASE_BRANCH}`, 13 | }) 14 | console.log("Existing PRs", prs) 15 | 16 | const title = `✨ Update website ✨` 17 | const body = "" 18 | 19 | if (prs.length === 0) { 20 | console.log("Creating new PR") 21 | await octokit.rest.pulls.create({ 22 | ...github.context.repo, 23 | base: "main", 24 | head: BASE_BRANCH, 25 | title, 26 | body, 27 | }) 28 | } else { 29 | // console.log("Updating existing PR") 30 | // const { number } = prs[0] 31 | // await octokit.rest.pulls.update({ 32 | // ...github.context.repo, 33 | // pull_number: number, 34 | // title, 35 | // body, 36 | // }) 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/pr-merged.yml: -------------------------------------------------------------------------------- 1 | name: PR Merged 2 | 3 | on: 4 | pull_request_target: 5 | types: [closed] 6 | branches: 7 | - next 8 | 9 | jobs: 10 | comment-issues: 11 | name: Comment Issues 12 | if: > 13 | github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'changeset') 14 | 15 | runs-on: ubuntu-latest 16 | 17 | permissions: 18 | issues: write 19 | pull-requests: write 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | with: 25 | ref: "${{ github.event.pull_request.merge_commit_sha }}" 26 | 27 | - name: Install pnpm 28 | uses: pnpm/action-setup@v4 29 | with: 30 | run_install: false 31 | 32 | - name: Set up Node.js 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: 20 36 | cache: "pnpm" 37 | 38 | - run: pnpm install 39 | 40 | - name: Add comment to issues 41 | run: node .github/scripts/pr-merged.mjs 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | -------------------------------------------------------------------------------- /.github/workflows/pr-updated.yml: -------------------------------------------------------------------------------- 1 | name: PR Updated 2 | 3 | on: 4 | pull_request_target: 5 | branches: 6 | - next 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | comment-pr: 14 | name: Comment PR 15 | runs-on: ubuntu-latest 16 | 17 | permissions: 18 | issues: write 19 | pull-requests: write 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | with: 25 | ref: "${{ github.event.pull_request.head.sha }}" 26 | 27 | - name: Install pnpm 28 | uses: pnpm/action-setup@v4 29 | with: 30 | run_install: false 31 | 32 | - name: Set up Node.js 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: 20 36 | cache: "pnpm" 37 | 38 | - run: pnpm install 39 | 40 | - run: pnpm build 41 | 42 | - run: pnpm canary 43 | 44 | - name: Add or update PR comment 45 | run: node .github/scripts/pr-updated.mjs ${{ github.event.pull_request.number }} 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | -------------------------------------------------------------------------------- /.github/workflows/release-pr-merged.yml: -------------------------------------------------------------------------------- 1 | name: Release PR Merged 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | branches: 7 | - next 8 | 9 | jobs: 10 | release: 11 | name: Release 12 | if: > 13 | github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release') 14 | 15 | runs-on: ubuntu-latest 16 | 17 | permissions: 18 | issues: write 19 | pull-requests: write 20 | contents: write 21 | 22 | steps: 23 | - name: Checkout code 24 | uses: actions/checkout@v4 25 | 26 | - name: Install pnpm 27 | uses: pnpm/action-setup@v4 28 | with: 29 | run_install: false 30 | 31 | - name: Set up Node.js 32 | uses: actions/setup-node@v4 33 | with: 34 | node-version: 20 35 | cache: "pnpm" 36 | 37 | - run: pnpm install 38 | 39 | - run: pnpm build 40 | 41 | - name: Release and update issues comments 42 | run: node .github/scripts/release.mjs 43 | env: 44 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "explorer.fileNesting.enabled": true, 3 | "explorer.fileNesting.patterns": { 4 | "*.0.mdx": "${capture}.*", 5 | "*.mdx": "${capture}.*" 6 | }, 7 | "explorer.fileNesting.expand": false 8 | } 9 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # deps 2 | /node_modules 3 | 4 | # generated content 5 | .map.ts 6 | .contentlayer 7 | 8 | # test & build 9 | /coverage 10 | /.next/ 11 | /out/ 12 | /build 13 | *.tsbuildinfo 14 | 15 | # misc 16 | .DS_Store 17 | *.pem 18 | /.pnp 19 | .pnp.js 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | # others 25 | .env*.local 26 | .vercel 27 | next-env.d.ts 28 | -------------------------------------------------------------------------------- /apps/web/app/api/revalidate/sponsors/route.ts: -------------------------------------------------------------------------------- 1 | import { revalidatePath } from "next/cache" 2 | 3 | export async function POST(request: Request) { 4 | try { 5 | const text = await request.text() 6 | console.log("[GitHub] Webhook received", text) 7 | 8 | revalidatePath("/") 9 | } catch (error: any) { 10 | return new Response(`Webhook error: ${error.message}`, { 11 | status: 400, 12 | }) 13 | } 14 | 15 | return new Response("Success!", { 16 | status: 200, 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/app/api/revalidate/test/route.ts: -------------------------------------------------------------------------------- 1 | import { revalidatePath } from "next/cache" 2 | 3 | export async function POST(request: Request) { 4 | try { 5 | const text = await request.text() 6 | console.log("[GitHub] Webhook received", text) 7 | 8 | revalidatePath("/test") 9 | } catch (error: any) { 10 | return new Response(`Webhook error: ${error.message}`, { 11 | status: 400, 12 | }) 13 | } 14 | 15 | return new Response("Success!", { 16 | status: 200, 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/app/api/search/route.ts: -------------------------------------------------------------------------------- 1 | import { docs } from "@/app/source" 2 | import { createSearchAPI } from "next-docs-zeta/search/server" 3 | 4 | export const { GET } = createSearchAPI("advanced", { 5 | indexes: docs.getPages().map((page) => ({ 6 | title: page.data.title, 7 | structuredData: page.data.exports.structuredData, 8 | id: page.url, 9 | url: page.url, 10 | })), 11 | }) 12 | -------------------------------------------------------------------------------- /apps/web/app/blog/[slug]/pomber.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/blog/[slug]/pomber.jpg -------------------------------------------------------------------------------- /apps/web/app/blog/feed.xml/route.ts: -------------------------------------------------------------------------------- 1 | import RSS from "rss" 2 | import { blog } from "../../source" 3 | 4 | const posts = blog.getPages().filter((page) => page.data.draft !== true) 5 | 6 | export const dynamic = "force-static" 7 | 8 | export async function GET() { 9 | const feed = new RSS({ 10 | title: "Code Hike", 11 | description: "Markdown, React and everything in between.", 12 | generator: "RSS for Node and Next.js", 13 | feed_url: "https://codehike.org/blog/feed.xml", 14 | site_url: "https://codehike.org/blog", 15 | language: "en-US", 16 | pubDate: new Date().toUTCString(), 17 | ttl: 120, 18 | image_url: "https://codehike.org/logo.png", 19 | }) 20 | 21 | posts.map(({ data, url }) => { 22 | feed.item({ 23 | title: data.title, 24 | description: data.description || "", 25 | url: `https://codehike.org${url}`, 26 | author: data.authors[0], 27 | date: data.date, 28 | }) 29 | }) 30 | 31 | return new Response(feed.xml({ indent: true }), { 32 | headers: { 33 | "Content-Type": "application/atom+xml; charset=utf-8", 34 | }, 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /apps/web/app/blog/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from "react" 2 | 3 | export default function RootBlogLayout({ children }: { children: ReactNode }) { 4 | return <>{children} 5 | } 6 | -------------------------------------------------------------------------------- /apps/web/app/blog/og/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image" 2 | import { CodeHikeLogo } from "../../../ui/nav" 3 | 4 | const title = "The Curse of Markdown" 5 | const description = "And the content website wasteland" 6 | const date = "November 21, 2024" 7 | 8 | import pomber from "../[slug]/pomber.jpg" 9 | 10 | export default function Page() { 11 | return ( 12 |
13 |
17 |
18 | 19 | Code Hike's blog 20 | 21 | 22 | {date} 23 | 24 |
25 |

{title}

26 |

27 |
{description}
28 |

29 |
30 | pomber 38 |
39 |
Rodrigo Pombo
40 |
@pomber
41 |
42 |
43 |
44 |
45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /apps/web/app/demo/client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { 4 | AnnotationHandler, 5 | CustomPreProps, 6 | InnerPre, 7 | getPreRef, 8 | } from "codehike/code" 9 | import { forwardRef } from "react" 10 | import React from "react" 11 | import { 12 | TokenTransitionsSnapshot, 13 | calculateTransitions, 14 | getStartingSnapshot, 15 | } from "codehike/utils/token-transitions" 16 | 17 | const MAX_TRANSITION_DURATION = 900 // milliseconds 18 | export class SmoothPre extends React.Component { 19 | ref: React.RefObject 20 | constructor(props: CustomPreProps) { 21 | super(props) 22 | this.ref = getPreRef(this.props) 23 | } 24 | 25 | render() { 26 | return 27 | } 28 | 29 | getSnapshotBeforeUpdate() { 30 | return getStartingSnapshot(this.ref.current!) 31 | } 32 | 33 | componentDidUpdate( 34 | prevProps: never, 35 | prevState: never, 36 | snapshot: TokenTransitionsSnapshot, 37 | ) { 38 | const transitions = calculateTransitions(this.ref.current!, snapshot) 39 | transitions.forEach(({ element, keyframes, options }) => { 40 | const { translateX, translateY, ...kf } = keyframes as any 41 | if (translateX && translateY) { 42 | kf.translate = [ 43 | `${translateX[0]}px ${translateY[0]}px`, 44 | `${translateX[1]}px ${translateY[1]}px`, 45 | ] 46 | } 47 | element.animate(kf, { 48 | duration: options.duration * MAX_TRANSITION_DURATION, 49 | delay: options.delay * MAX_TRANSITION_DURATION, 50 | easing: options.easing, 51 | fill: "both", 52 | }) 53 | }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /apps/web/app/demo/content.mdx: -------------------------------------------------------------------------------- 1 | normal, extra spacer right 2 | 3 | ```js 4 | function lorem(ipsum, dolor = 1) { 5 | // !mark 6 | dolor = sit - amet(dolor) 7 | dolor = sit - amet(dolor) 8 | dolor = sit - amet(dolor) 9 | dolor = sit - amet(dolor) 10 | // !mark 11 | dolor = sit - amet(dolor) 12 | dolor = sit - amet(dolor) 13 | // !diff + 14 | dolor = sit - amet(dolor) 15 | dolor = sit - amet(dolor) 16 | dolor = sit - amet(dolor) 17 | dolor = sit - amet(dolor) 18 | // !collapse(1:3) 19 | dolor = sit - amet(dolor) 20 | // !callout[/sit/] hey 21 | dolor = sit - amet(dolor) 22 | dolor = sit - amet(dolor) 23 | } 24 | ``` 25 | 26 |
27 | 28 | overflow 29 | 30 | ```js 31 | function lorem(ipsum, dolor = 1) { 32 | // !mark 33 | dolor = sit 34 | } 35 | ``` 36 | 37 |
38 | 39 |
40 | 41 | wrap 42 | 43 | ```js w 44 | // !callout[/lorem/] hey 45 | function lorem(ipsum) { 46 | // !mark 47 | dolor = sit - amet(dolor) - consectetur(ipsum) 48 | // !callout[/dolor/] hey 49 | if (dolor === 1) { 50 | // !callout[/sit/] hey 51 | dolor = sit 52 | } 53 | } 54 | ``` 55 | 56 |
57 | -------------------------------------------------------------------------------- /apps/web/app/docs/[[...slug]]/code-example.tsx: -------------------------------------------------------------------------------- 1 | import { Block, parseRoot } from "codehike/blocks" 2 | import React from "react" 3 | 4 | const ContentSchema = Block.extend({}) 5 | 6 | export function CodeExample({ MDX }: { MDX: any }) { 7 | const { children } = parseRoot(MDX, ContentSchema, { 8 | components: { PreviewContainer }, 9 | }) 10 | 11 | return children 12 | } 13 | 14 | function PreviewContainer({ children }: { children: React.ReactNode }) { 15 | return ( 16 |
17 | {children} 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/app/docs/[[...slug]]/preview-implementation.tsx: -------------------------------------------------------------------------------- 1 | import { Block, parseRoot } from "codehike/blocks" 2 | import React from "react" 3 | import { z } from "zod" 4 | import { Demo } from "@/components/demo" 5 | import { Pre, RawCode, highlight } from "codehike/code" 6 | import { CopyButton } from "@/components/copy-button" 7 | import { ComponentPackLink } from "@/components/component-pack-link" 8 | 9 | const ContentSchema = Block.extend({ 10 | demo: Block, 11 | implementation: Block, 12 | }) 13 | 14 | export function PreviewImplementation({ MDX }: { MDX: any }) { 15 | const { demo, implementation } = parseRoot(MDX, ContentSchema, { 16 | components: { Demo }, 17 | }) 18 | 19 | return ( 20 | <> 21 | {demo.children} 22 |

Implementation

23 | {implementation.children} 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /apps/web/app/docs/layout.tsx: -------------------------------------------------------------------------------- 1 | import { docs } from "../source" 2 | import { DocsLayout } from "next-docs-ui/layout" 3 | import type { ReactNode } from "react" 4 | export default function RootDocsLayout({ children }: { children: ReactNode }) { 5 | return ( 6 | <> 7 | 14 | {children} 15 | 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/favicon.ico -------------------------------------------------------------------------------- /apps/web/app/landing/demo.md: -------------------------------------------------------------------------------- 1 | ```jsx !page page.jsx 2 | import Content from "./content.md" 3 | import { parse } from "codehike" 4 | 5 | // !rainbow(1:2) 6 | // extract structured content: 7 | // !tt[/content/] foo 8 | const content = parse(Content) 9 | 10 | export function Page() { 11 | // !rainbow(3:5) 1 12 | return ( 13 |
14 | {/* render it as you want: */} 15 |
16 |
17 |
18 | ) 19 | } 20 | ``` 21 | 22 | ```jsx !content 23 | content = { 24 | // !block(1:4) 1 25 | intro: { 26 | title: "Roman Emperors", 27 | children:

The ...

, 28 | }, 29 | emperors: [ 30 | // !block(1:9) 2 31 | { 32 | title: "Augustus", 33 | children:

The ...

, 34 | img: { src: "/one.png" }, 35 | code: { 36 | lang: "js", 37 | value: "console.log(1)", 38 | }, 39 | }, 40 | // !block 3 41 | { title: "Nero", ... }, 42 | // !block 4 43 | { title: "Trajan", ... }, 44 | ], 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /apps/web/app/landing/download.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import * as htmlToImage from "html-to-image" 3 | 4 | export function Download({ selector }: { selector: string }) { 5 | const onClick = async () => { 6 | const nodes = document.querySelectorAll(selector) as any 7 | for (const node of nodes) { 8 | const dataUrl = await htmlToImage.toPng(node as HTMLElement) 9 | var img = new Image() 10 | img.src = dataUrl 11 | document.getElementById("out")!.appendChild(img) 12 | } 13 | } 14 | return ( 15 |
16 | 17 |
18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/app/landing/logo.drivly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/landing/logo.drivly.png -------------------------------------------------------------------------------- /apps/web/app/landing/logo.github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/landing/logo.github.png -------------------------------------------------------------------------------- /apps/web/app/landing/logo.meta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/landing/logo.meta.png -------------------------------------------------------------------------------- /apps/web/app/landing/logo.uidev.svg: -------------------------------------------------------------------------------- 1 | ui.dev -------------------------------------------------------------------------------- /apps/web/app/landing/placeholdifier-monospace.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/landing/placeholdifier-monospace.woff2 -------------------------------------------------------------------------------- /apps/web/app/landing/placeholdifier.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/landing/placeholdifier.woff2 -------------------------------------------------------------------------------- /apps/web/app/landing/profile.md: -------------------------------------------------------------------------------- 1 | I ([@pomber](https://github.com/pomber)) am working full-time on this project. The official reason is that _I want to raise the bar on the formatting of technical content_, but the main reason is that I'm having a lot of fun building it. 2 | 3 | The goal of [Code Hike](https://codehike.org) is to provide the best experience for both authors and consumers of technical content on the web. 4 | 5 | Your sponsorship not only helps keep the project running but also supports the innovation that inspired some of your favorite websites. 6 | 7 | Sponsorship perks: 8 | 9 | - **$299/month or more**: I'll join your company's Slack channel for direct feedbacks and feature requests. 10 | - **$499/month or more**: You get a spot on our Top Sponsors (limited to 6 spots). 11 | - **$999/month or more**: You get up to 1 hour a month of personalized support (two 30-minute calls). 12 | -------------------------------------------------------------------------------- /apps/web/app/landing/sponsors/oc-sponsors.js: -------------------------------------------------------------------------------- 1 | const parseCSV = require("./csv") 2 | const path = require("path") 3 | 4 | function getSponsors() { 5 | // https://opencollective.com/codehike/transactions?type=CREDIT 6 | const data = parseCSV(path.join(__dirname, "./codehike-transactions.csv")) 7 | 8 | const transactions = data.map((d) => ({ 9 | date: d["date"], 10 | name: d["oppositeAccountSlug"], 11 | amount: parseInt(d["amount"]), 12 | })) 13 | 14 | const totals = {} 15 | transactions.forEach((t) => { 16 | totals[t.name] = (totals[t.name] || 0) + t.amount 17 | }) 18 | 19 | const list = [] 20 | for (let name in totals) { 21 | list.push({ name, amount: Math.round(totals[name]) }) 22 | } 23 | 24 | return list 25 | } 26 | 27 | module.exports = getSponsors 28 | -------------------------------------------------------------------------------- /apps/web/app/landing/sponsors/update.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const path = require("path") 3 | 4 | const getOpenCollectiveSponsors = require("./oc-sponsors.js") 5 | const fetchGitHubSponsors = require("./gh-sponsors.js") 6 | 7 | const ignore = ["outerbounds", "github-sponsors", "guest-fbd7c737"] 8 | const replace = { 9 | speakeasybot: "speakeasy-api", 10 | ndimares: "speakeasy-api", 11 | hamelsmu: "outerbounds", 12 | "severin-ibarluzea": "seveibar", 13 | fbopensource: "facebook", 14 | } 15 | const others = [ 16 | // from paypal 17 | { name: "matthiaszepper", amount: Math.round(94.3 + 108.71 + 47) }, 18 | // missing from gh api 19 | { name: "github", amount: 20550 }, 20 | ] 21 | 22 | Promise.all([getOpenCollectiveSponsors(), fetchGitHubSponsors()]).then( 23 | ([ocSponsors, ghSponsors]) => { 24 | const all = [...ocSponsors, ...ghSponsors, ...others] 25 | .filter((s) => !ignore.includes(s.name)) 26 | .map((s) => ({ name: replace[s.name] || s.name, amount: s.amount })) 27 | 28 | const sponsors = [] 29 | all.forEach((s) => { 30 | const index = sponsors.findIndex((sp) => sp.name === s.name) 31 | if (index === -1) { 32 | sponsors.push(s) 33 | } else { 34 | sponsors[index].amount += s.amount 35 | } 36 | }) 37 | 38 | sponsors.sort((a, b) => b.amount - a.amount) 39 | 40 | console.table(sponsors) 41 | fs.writeFileSync( 42 | path.join(__dirname, "../sponsors.json"), 43 | JSON.stringify(sponsors, null, 2), 44 | ) 45 | }, 46 | ) 47 | -------------------------------------------------------------------------------- /apps/web/app/landing/text.github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/app/landing/text.github.png -------------------------------------------------------------------------------- /apps/web/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./global.css" 2 | import { RootProvider } from "next-docs-ui/provider" 3 | import { Inter } from "next/font/google" 4 | import type { ReactNode } from "react" 5 | import { NavBar } from "../ui/nav" 6 | import { Analytics } from "@vercel/analytics/react" 7 | 8 | const inter = Inter({ 9 | subsets: ["latin"], 10 | }) 11 | 12 | import ch from "codehike/package.json" 13 | import { Metadata } from "next" 14 | 15 | export default function Layout({ children }: { children: ReactNode }) { 16 | return ( 17 | 22 | {/* */} 23 | 24 | 25 | 26 | {children} 27 | 28 | 29 | 30 | 31 | ) 32 | } 33 | export const metadata: Metadata = { 34 | title: "Code Hike", 35 | description: 36 | "Use Markdown and React to build rich content websites. Documentation, tutorials, blogs, videos, interactive walkthroughs, and more.", 37 | // metadataBase: new URL("https://codehike.org"), 38 | openGraph: { 39 | title: "Code Hike", 40 | images: `https://codehike.org/codehike.png`, 41 | siteName: "Code Hike", 42 | }, 43 | twitter: { 44 | card: "summary_large_image", 45 | site: "@codehike_", 46 | creator: "@pomber", 47 | images: `https://codehike.org/codehike.png`, 48 | }, 49 | alternates: { 50 | types: { 51 | "application/rss+xml": "https://codehike.org/blog/feed.xml", 52 | }, 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /apps/web/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { usePathname } from "next/navigation" 3 | 4 | export default function NotFound() { 5 | const pathname = usePathname() 6 | const v0url = "v0.codehike.org" + pathname 7 | return ( 8 |
9 |

Page not found.

10 |

11 | For older versions try:{" "} 12 | 13 | {v0url} 14 | 15 |

16 |
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/app/play/page.tsx: -------------------------------------------------------------------------------- 1 | export default function Playground() { 2 | return ( 3 |
4 | // TO DO 5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/app/source.ts: -------------------------------------------------------------------------------- 1 | import { map } from "@/.map" 2 | import { createMDXSource, defaultSchemas } from "next-docs-mdx" 3 | import { loader } from "next-docs-zeta/source" 4 | import { z } from "zod" 5 | 6 | export const docs = loader({ 7 | baseUrl: "/docs", 8 | rootDir: "docs", 9 | source: createMDXSource(map, { 10 | schema: { 11 | frontmatter: defaultSchemas.frontmatter.extend({ 12 | layout: z.string().default("Docs"), 13 | }), 14 | }, 15 | }), 16 | }) 17 | 18 | export const blog = loader({ 19 | baseUrl: "/blog", 20 | rootDir: "blog", 21 | source: createMDXSource(map, { 22 | schema: { 23 | frontmatter: defaultSchemas.frontmatter.extend({ 24 | authors: z.array(z.string()).default([]), 25 | date: z.date().default(new Date()), 26 | draft: z.boolean().default(false), 27 | className: z.string().default(""), 28 | }), 29 | }, 30 | }), 31 | }) 32 | -------------------------------------------------------------------------------- /apps/web/app/test/client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { 4 | AnnotationHandler, 5 | CustomPreProps, 6 | InnerPre, 7 | getPreRef, 8 | } from "codehike/code" 9 | import { forwardRef } from "react" 10 | import React from "react" 11 | import { 12 | TokenTransitionsSnapshot, 13 | calculateTransitions, 14 | getStartingSnapshot, 15 | } from "codehike/utils/token-transitions" 16 | 17 | const MAX_TRANSITION_DURATION = 900 // milliseconds 18 | export class SmoothPre extends React.Component { 19 | ref: React.RefObject 20 | constructor(props: CustomPreProps) { 21 | super(props) 22 | this.ref = getPreRef(this.props) 23 | } 24 | 25 | render() { 26 | return 27 | } 28 | 29 | getSnapshotBeforeUpdate() { 30 | return getStartingSnapshot(this.ref.current!) 31 | } 32 | 33 | componentDidUpdate( 34 | prevProps: never, 35 | prevState: never, 36 | snapshot: TokenTransitionsSnapshot, 37 | ) { 38 | const transitions = calculateTransitions(this.ref.current!, snapshot) 39 | transitions.forEach(({ element, keyframes, options }) => { 40 | const { translateX, translateY, ...kf } = keyframes as any 41 | if (translateX && translateY) { 42 | kf.translate = [ 43 | `${translateX[0]}px ${translateY[0]}px`, 44 | `${translateX[1]}px ${translateY[1]}px`, 45 | ] 46 | } 47 | element.animate(kf, { 48 | duration: options.duration * MAX_TRANSITION_DURATION, 49 | delay: options.delay * MAX_TRANSITION_DURATION, 50 | easing: options.easing, 51 | fill: "both", 52 | }) 53 | }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /apps/web/app/test/content.md: -------------------------------------------------------------------------------- 1 | ## The mother of all codeblocks 2 | 3 | ```js foo.js -awnc 4 | // !collapse(1:4) 5 | function lorem(ipsum, dolor = 1) { 6 | const sit = ipsum == null ? 0 : ipsum.sit 7 | // !mark(1:2) 8 | dolor = sit - amet(dolor) 9 | // !callout[/sit/] lorem ipsum dolor sit 10 | return sit ? consectetur(ipsum) : [] 11 | } 12 | 13 | // !collapse(1:4) collapsed 14 | function ipsum(ipsum, dolor = 1) { 15 | const sit = ipsum == null ? 0 : ipsum.sit 16 | // !mark(1:2) 17 | dolor = sit - amet(dolor) 18 | return sit ? consectetur(ipsum) : [] 19 | } 20 | ``` 21 | 22 | ```js foo.js -anc 23 | // !collapse(1:4) 24 | function lorem(ipsum, dolor = 1) { 25 | const sit = ipsum == null ? 0 : ipsum.sit 26 | // !mark(1:2) 27 | dolor = sit - amet(dolor) 28 | // !callout[/sit/] lorem ipsum dolor sit 29 | return sit ? consectetur(ipsum) : [] 30 | } 31 | 32 | // !collapse(1:4) collapsed 33 | function ipsum(ipsum, dolor = 1) { 34 | const sit = ipsum == null ? 0 : ipsum.sit 35 | // !mark(1:2) 36 | dolor = sit - amet(dolor) 37 | return sit ? consectetur(ipsum) : [] 38 | } 39 | ``` 40 | 41 | ```js -c 42 | function lorem(ipsum, dolor = 1) { 43 | const sit = ipsum == null ? 0 : ipsum.sit 44 | // !mark(1:2) 45 | dolor = sit - amet(dolor) 46 | // !callout[/sit/] lorem ipsum dolor sit 47 | return sit ? consectetur(ipsum) : [] 48 | } 49 | 50 | function ipsum(ipsum, dolor = 1) { 51 | const sit = ipsum == null ? 0 : ipsum.sit 52 | // !mark(1:2) 53 | dolor = sit - amet(dolor) 54 | return sit ? consectetur(ipsum) : [] 55 | } 56 | ``` 57 | 58 | ```bash -c 59 | npx create-next-app -e https://github.com/code-hike/v1-starter 60 | ``` 61 | -------------------------------------------------------------------------------- /apps/web/app/test/page.tsx: -------------------------------------------------------------------------------- 1 | import { LatestSponsor } from "../landing/sponsors" 2 | import Content from "./content.md" 3 | import { Code } from "@/components/code" 4 | 5 | export default function Page() { 6 | return ( 7 |
8 |
{new Date().toString()}
9 | 10 | 11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/web/app/top-sponsors.png/route.tsx: -------------------------------------------------------------------------------- 1 | import { ImageResponse } from "next/og" 2 | 3 | export const dynamic = "force-static" 4 | 5 | export async function GET(request: Request) { 6 | return new ImageResponse( 7 | ( 8 |
9 | hello, world 10 | 11 |
12 | ), 13 | { 14 | width: 600, 15 | height: 400, 16 | }, 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/global.css", 9 | "baseColor": "zinc", 10 | "cssVariables": false, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/components/all-code-demos.tsx: -------------------------------------------------------------------------------- 1 | import { docs } from "@/app/source" 2 | import { Block, parseRoot } from "codehike/blocks" 3 | import { Demo } from "@/components/demo" 4 | import { CodeWithNotes } from "@/components/code/code-with-notes" 5 | import Link from "next/link" 6 | 7 | export function AllCodeDemos() { 8 | const p = docs.getPages() 9 | const codePages = p.filter((page) => page.slugs[0] === "code") 10 | const demoPages = codePages.filter( 11 | (page) => page.data.layout === "PreviewAndImplementation", 12 | ) 13 | 14 | return demoPages.map((page) => { 15 | const { title, exports } = page.data 16 | const { default: MDX } = exports 17 | const { demo } = parseRoot(MDX, Block.extend({ demo: Block }), { 18 | components: { Demo, CodeWithNotes }, 19 | }) 20 | const href = `/docs/${page.slugs.join("/")}` 21 | 22 | return ( 23 |
24 |

{title}

25 | {demo.children} 26 |

27 | See {title} implementation. 28 |

29 |
30 | ) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /apps/web/components/annotations/callout.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InlineAnnotation, InnerLine } from "codehike/code" 2 | 3 | export const callout: AnnotationHandler = { 4 | name: "callout", 5 | transform: (annotation: InlineAnnotation) => { 6 | // transform inline annotation to block annotation 7 | const { name, query, lineNumber, fromColumn, toColumn } = annotation 8 | return { 9 | name, 10 | query, 11 | fromLineNumber: lineNumber, 12 | toLineNumber: lineNumber, 13 | data: { 14 | ...annotation.data, 15 | column: (fromColumn + toColumn) / 2, 16 | }, 17 | } 18 | }, 19 | AnnotatedLine: ({ annotation, ...props }) => { 20 | const { column } = annotation.data 21 | const { indentation, children } = props 22 | return ( 23 | 24 | {children} 25 |
32 |
36 | {annotation.data.children || ( 37 |
{annotation.query}
38 | )} 39 |
40 | 41 | ) 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /apps/web/components/annotations/diff.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InnerLine, BlockAnnotation } from "codehike/code" 2 | 3 | export const diff: AnnotationHandler = { 4 | name: "diff", 5 | onlyIfAnnotated: true, 6 | transform: (annotation: BlockAnnotation) => { 7 | const color = annotation.query == "-" ? "#f85149" : "#3fb950" 8 | return [annotation, { ...annotation, name: "mark", query: color }] 9 | }, 10 | Line: ({ annotation, ...props }) => ( 11 | <> 12 |
13 | {annotation?.query} 14 |
15 | 16 | 17 | ), 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/components/annotations/focus.client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { CustomPreProps, InnerPre, getPreRef } from "codehike/code" 4 | import { useLayoutEffect, useRef } from "react" 5 | 6 | export function PreWithRef(props: CustomPreProps) { 7 | const ref = getPreRef(props) 8 | useScrollToFocus(ref) 9 | return 10 | } 11 | 12 | function useScrollToFocus(ref: React.RefObject) { 13 | const firstRender = useRef(true) 14 | useLayoutEffect(() => { 15 | if (ref.current) { 16 | // find all descendants whith data-focus="true" 17 | const focusedElements = ref.current.querySelectorAll( 18 | "[data-focus=true]", 19 | ) as NodeListOf 20 | 21 | // container rect 22 | const containerRect = ref.current.getBoundingClientRect() 23 | 24 | // find top and bottom of the focused elements 25 | let top = Infinity 26 | let bottom = -Infinity 27 | focusedElements.forEach((el) => { 28 | const rect = el.getBoundingClientRect() 29 | top = Math.min(top, rect.top - containerRect.top) 30 | bottom = Math.max(bottom, rect.bottom - containerRect.top) 31 | }) 32 | 33 | // scroll to the focused elements if any part of them is not visible 34 | if (bottom > containerRect.height || top < 0) { 35 | ref.current.scrollTo({ 36 | top: ref.current.scrollTop + top - 10, 37 | behavior: firstRender.current ? "instant" : "smooth", 38 | }) 39 | } 40 | firstRender.current = false 41 | } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /apps/web/components/annotations/focus.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InnerLine } from "codehike/code" 2 | import { PreWithRef } from "./focus.client" 3 | 4 | export const focus: AnnotationHandler = { 5 | name: "focus", 6 | PreWithRef, 7 | onlyIfAnnotated: true, 8 | Line: (props) => ( 9 | 10 | ), 11 | AnnotatedLine: ({ annotation, ...props }) => ( 12 | 13 | ), 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/components/annotations/fold.client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { AnnotationHandler } from "codehike/code" 4 | import { useState } from "react" 5 | 6 | export const InlineFold: AnnotationHandler["Inline"] = ({ 7 | annotation, 8 | children, 9 | }) => { 10 | const [folded, setFolded] = useState(true) 11 | if (!folded) { 12 | return children 13 | } 14 | return ( 15 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /apps/web/components/annotations/fold.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler } from "codehike/code" 2 | import { InlineFold } from "./fold.client" 3 | 4 | export const fold: AnnotationHandler = { 5 | name: "fold", 6 | Inline: InlineFold, 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/components/annotations/icons.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode } from "codehike/code" 2 | import { themeIcons } from "seti-icons" 3 | 4 | export function CodeIcon({ title }: { title: string }) { 5 | let filename = title || "" 6 | if (filename.endsWith(".mdx")) { 7 | filename = filename.slice(0, -4) 8 | filename += ".md" 9 | } else if (filename.endsWith(".mjs")) { 10 | filename = filename.slice(0, -4) 11 | filename += ".js" 12 | } 13 | 14 | const { svg, color } = getLightIcon(filename) 15 | const __html = svg.replace( 16 | /svg/, 17 | `svg fill='${color}' height='28' style='margin: -8px'`, 18 | ) 19 | return ( 20 | 24 | ) 25 | } 26 | 27 | const getDarkIcon = themeIcons({ 28 | blue: "#519aba", 29 | grey: "#4d5a5e", 30 | "grey-light": "#6d8086", 31 | green: "#8dc149", 32 | orange: "#e37933", 33 | pink: "#f55385", 34 | purple: "#a074c4", 35 | red: "#cc3e44", 36 | white: "#d4d7d6", 37 | yellow: "#cbcb41", 38 | ignore: "#41535b", 39 | }) 40 | 41 | const getLightIcon = themeIcons({ 42 | blue: "#498ba7", 43 | grey: "#455155", 44 | "grey-light": "#627379", 45 | green: "#7fae42", 46 | orange: "#f05138", 47 | pink: "#dd4b78", 48 | purple: "#9068b0", 49 | red: "#b8383d", 50 | white: "#bfc2c1", 51 | yellow: "#b7b73b", 52 | ignore: "#3b4b52", 53 | }) 54 | -------------------------------------------------------------------------------- /apps/web/components/annotations/line-numbers.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InnerLine } from "codehike/code" 2 | 3 | export const lineNumbers: AnnotationHandler = { 4 | name: "line-numbers", 5 | Line: (props) => { 6 | const width = props.totalLines.toString().length + 1 7 | return ( 8 | <> 9 | 13 | {props.lineNumber} 14 | 15 | 16 | 17 | ) 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /apps/web/components/annotations/link.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler } from "codehike/code" 2 | import Link from "next/link" 3 | 4 | export const link: AnnotationHandler = { 5 | name: "link", 6 | Inline: ({ annotation, children }) => { 7 | const { query } = annotation 8 | 9 | return ( 10 | 11 | {children} 12 | 13 | ) 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /apps/web/components/annotations/mark.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, BlockAnnotation, InnerLine } from "codehike/code" 2 | 3 | export const mark: AnnotationHandler = { 4 | name: "mark", 5 | Line: ({ annotation, ...props }) => { 6 | const color = getColor(annotation) 7 | return ( 8 |
16 | 17 |
18 | ) 19 | }, 20 | Inline: ({ annotation, children }) => { 21 | const color = getColor(annotation) 22 | return ( 23 | 30 | {children} 31 | 32 | ) 33 | }, 34 | } 35 | 36 | function getColor(annotation?: { query?: string }) { 37 | const n = Number(annotation?.query || "2") % colors.length 38 | return colors[n] || annotation?.query 39 | } 40 | 41 | const colors = [ 42 | "#22c55e", 43 | "#14b8a6", 44 | "#0ea5e9", 45 | "#8b5cf6", 46 | "#d946ef", 47 | "#ec4899", 48 | ] 49 | -------------------------------------------------------------------------------- /apps/web/components/annotations/pill.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler } from "codehike/code" 2 | 3 | const colors = [ 4 | "bg-green-500/20", 5 | "bg-teal-500/20", 6 | "bg-sky-500/20", 7 | "bg-violet-500/20", 8 | "bg-fuchsia-500/20", 9 | "bg-pink-500/20", 10 | // if adding more colors, dont forget to update global.css 11 | ] 12 | 13 | export const pill: AnnotationHandler = { 14 | name: "pill", 15 | Inline: ({ annotation, children }) => { 16 | const n = Number(annotation.query || "1") 17 | const bg = colors[n % colors.length] 18 | return {children} 19 | }, 20 | } 21 | 22 | export function Pill({ 23 | children, 24 | n = 1, 25 | }: { 26 | children: React.ReactNode 27 | n: number 28 | }) { 29 | const bg = colors[n % colors.length] 30 | return ( 31 | 35 | {children} 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /apps/web/components/annotations/ruler.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler } from "codehike/code" 2 | 3 | const colors = [ 4 | "bg-green-500/20", 5 | "bg-teal-500/20", 6 | "bg-sky-500/20", 7 | "bg-violet-500/20", 8 | "bg-fuchsia-500/20", 9 | "bg-pink-500/20", 10 | // if adding more colors, dont forget to update global.css 11 | ] 12 | 13 | // needs ruler-group class in container 14 | 15 | export const ruler: AnnotationHandler = { 16 | name: "ruler", 17 | Block: ({ annotation, children }) => { 18 | const [k, c] = annotation.query?.split(" ") 19 | const n = Number(k || "1") % colors.length 20 | const bg = colors[n] 21 | return ( 22 |
23 |
27 |
30 |
{children}
31 |
32 | ) 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /apps/web/components/annotations/token-transitions.client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { CustomPreProps, InnerPre, getPreRef } from "codehike/code" 4 | import { 5 | TokenTransitionsSnapshot, 6 | calculateTransitions, 7 | getStartingSnapshot, 8 | } from "codehike/utils/token-transitions" 9 | import React from "react" 10 | 11 | const MAX_TRANSITION_DURATION = 900 // milliseconds 12 | export class PreWithRef extends React.Component { 13 | ref: React.RefObject 14 | constructor(props: CustomPreProps) { 15 | super(props) 16 | this.ref = getPreRef(this.props) 17 | } 18 | 19 | render() { 20 | return 21 | } 22 | 23 | getSnapshotBeforeUpdate() { 24 | return getStartingSnapshot(this.ref.current!) 25 | } 26 | 27 | componentDidUpdate( 28 | prevProps: never, 29 | prevState: never, 30 | snapshot: TokenTransitionsSnapshot, 31 | ) { 32 | const transitions = calculateTransitions(this.ref.current!, snapshot) 33 | transitions.forEach(({ element, keyframes, options }) => { 34 | const { translateX, translateY, ...kf } = keyframes as any 35 | if (translateX && translateY) { 36 | kf.translate = [ 37 | `${translateX[0]}px ${translateY[0]}px`, 38 | `${translateX[1]}px ${translateY[1]}px`, 39 | ] 40 | } 41 | element.animate(kf, { 42 | duration: options.duration * MAX_TRANSITION_DURATION, 43 | delay: options.delay * MAX_TRANSITION_DURATION, 44 | easing: options.easing, 45 | fill: "both", 46 | }) 47 | }) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /apps/web/components/annotations/token-transitions.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InnerToken } from "codehike/code" 2 | import { PreWithRef } from "./token-transitions.client" 3 | 4 | export const tokenTransitions: AnnotationHandler = { 5 | name: "token-transitions", 6 | PreWithRef, 7 | Token: (props) => ( 8 | 9 | ), 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/components/annotations/tooltip.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InlineAnnotationComponent } from "codehike/code" 2 | import { 3 | TooltipProvider, 4 | Tooltip, 5 | TooltipTrigger, 6 | TooltipContent, 7 | TooltipArrow, 8 | } from "@/components/ui/tooltip" 9 | 10 | export const tooltip: AnnotationHandler = { 11 | name: "tooltip", 12 | Inline: ({ children, annotation }) => { 13 | const { query, data } = annotation 14 | return ( 15 | 16 | 17 | 18 | {children} 19 | 20 | 26 | {data?.children || query} 27 | 28 | 29 | 30 | ) 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /apps/web/components/annotations/word-wrap.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | AnnotationHandler, 3 | InnerLine, 4 | InnerPre, 5 | InnerToken, 6 | } from "codehike/code" 7 | 8 | export const wordWrap: AnnotationHandler = { 9 | name: "word-wrap", 10 | Pre: (props) => , 11 | Line: (props) => ( 12 | 13 |
19 | {props.children} 20 |
21 |
22 | ), 23 | Token: (props) => , 24 | } 25 | -------------------------------------------------------------------------------- /apps/web/components/blocks-to-context.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { 3 | Tooltip, 4 | TooltipContent, 5 | TooltipProvider, 6 | TooltipTrigger, 7 | } from "@/components/ui/tooltip" 8 | 9 | import React from "react" 10 | 11 | const BlocksContext = React.createContext(null) 12 | 13 | export function BlocksToContext({ 14 | children, 15 | ...rest 16 | }: { 17 | children: React.ReactNode 18 | rest: any 19 | }) { 20 | return ( 21 | {children} 22 | ) 23 | } 24 | 25 | export function useBlocksContext(name: string) { 26 | return React.useContext(BlocksContext)[name] 27 | } 28 | 29 | export function WithTooltip({ 30 | children, 31 | name, 32 | }: { 33 | children: React.ReactNode 34 | name: string 35 | }) { 36 | const block = useBlocksContext(name) 37 | const className = block.isCode 38 | ? "p-0 [&>*]:my-0 border-none overflow-auto rounded-none" 39 | : "" 40 | return ( 41 | 42 | 43 | 44 | 45 | {children} 46 | 47 | 48 | {block?.children} 49 | 50 | 51 | ) 52 | } 53 | -------------------------------------------------------------------------------- /apps/web/components/code/code-with-notes.tsx: -------------------------------------------------------------------------------- 1 | import { highlight } from "codehike/code" 2 | import { Block, CodeBlock, ImageBlock, parseProps } from "codehike/blocks" 3 | import { z } from "zod" 4 | import theme from "@/theme.mjs" 5 | import { HighCode } from "../code" 6 | 7 | const ContentSchema = z.object({ 8 | code: CodeBlock, 9 | notes: z 10 | .array( 11 | Block.extend({ 12 | code: CodeBlock.optional(), 13 | }), 14 | ) 15 | .optional(), 16 | }) 17 | 18 | export async function CodeWithNotes(props: unknown) { 19 | const { code, notes = [] } = parseProps(props, ContentSchema) 20 | const highlighted = await highlight(code, theme) 21 | 22 | // find matches between annotations and notes 23 | // and add the note as data to the annotation 24 | highlighted.annotations = await Promise.all( 25 | highlighted.annotations.map(async (a) => { 26 | const note = notes.find((n) => a.query && n.title === a.query) 27 | if (!note) return a 28 | 29 | let children = note.children 30 | if (note.code) { 31 | const highlighted = await highlight(note.code, theme) 32 | children = ( 33 | 34 | ) 35 | } 36 | 37 | return { 38 | ...a, 39 | data: { 40 | ...a.data, 41 | children, 42 | }, 43 | } 44 | }), 45 | ) 46 | 47 | return 48 | } 49 | -------------------------------------------------------------------------------- /apps/web/components/code/side-by-side.tsx: -------------------------------------------------------------------------------- 1 | export function SideBySide(props: React.HTMLProps) { 2 | return ( 3 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /apps/web/components/component-pack-link.tsx: -------------------------------------------------------------------------------- 1 | import { ArrowRight } from "lucide-react" 2 | 3 | export function ComponentPackLink() { 4 | return ( 5 |
6 | Don't have time to build it yourself? Get a documentation component 7 | library customized for your tech stack and design system. 8 | 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/components/copy-button.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { Copy, Check } from "lucide-react" 4 | import * as React from "react" 5 | import { cn } from "../lib/utils" 6 | 7 | export function CopyButton({ 8 | text, 9 | className, 10 | }: { 11 | text: string 12 | className?: string 13 | }) { 14 | const [copied, setCopied] = React.useState(false) 15 | 16 | return ( 17 | 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /apps/web/components/demo.tsx: -------------------------------------------------------------------------------- 1 | import fs from "fs" 2 | import path from "path" 3 | import { Code } from "./code" 4 | import { cn } from "../lib/utils" 5 | 6 | export async function Demo({ 7 | name, 8 | children, 9 | className, 10 | content = "content.md", 11 | }: { 12 | name: string 13 | content?: string 14 | children: React.ReactNode 15 | className?: string 16 | }) { 17 | const value = await fs.promises.readFile( 18 | path.join(process.cwd(), "demos", name, content), 19 | "utf-8", 20 | ) 21 | 22 | const usage = ( 23 | 31 | ) 32 | 33 | const { default: Page } = await import(`@/demos/${name}/page`) 34 | 35 | const preview = ( 36 |
37 | 38 | {children && ( 39 |
40 | {children} 41 |
42 | )} 43 |
44 | ) 45 | 46 | return ( 47 |
*]:flex-1 [&>*]:min-w-72", 50 | className, 51 | )} 52 | > 53 |
{usage}
54 | {preview} 55 |
56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /apps/web/components/layout-demo.tsx: -------------------------------------------------------------------------------- 1 | import fs from "fs" 2 | import path from "path" 3 | import { Tab, Tabs } from "next-docs-ui/components/tabs" 4 | import { Code } from "./code" 5 | 6 | export async function LayoutDemo({ 7 | name, 8 | children, 9 | content = "content.md", 10 | }: { 11 | name: string 12 | content?: string 13 | children: React.ReactNode 14 | }) { 15 | const value = await fs.promises.readFile( 16 | path.join(process.cwd(), "demos", name, content), 17 | "utf-8", 18 | ) 19 | 20 | const { default: Page } = await import(`@/demos/${name}/page`) 21 | 22 | return ( 23 | 24 | 28 |
29 | 30 |
31 |
32 | 33 | 40 | 41 | {children} 42 |
43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /apps/web/components/time-ago.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | export function TimeAgo({ date }: { date: string }) { 4 | const time = new Date(date) 5 | return ( 6 | 9 | ) 10 | } 11 | 12 | const MINUTE = 60 13 | const HOUR = MINUTE * 60 14 | const DAY = HOUR * 24 15 | const WEEK = DAY * 7 16 | const MONTH = DAY * 30 17 | const YEAR = DAY * 365 18 | 19 | function getTimeAgo(date: Date) { 20 | const secondsAgo = Math.round((Date.now() - Number(date)) / 1000) 21 | 22 | if (secondsAgo < MINUTE) { 23 | return secondsAgo + ` second${secondsAgo !== 1 ? "s" : ""} ago` 24 | } 25 | 26 | let divisor 27 | let unit = "" 28 | 29 | if (secondsAgo < HOUR) { 30 | ;[divisor, unit] = [MINUTE, "minute"] 31 | } else if (secondsAgo < DAY) { 32 | ;[divisor, unit] = [HOUR, "hour"] 33 | } else if (secondsAgo < WEEK) { 34 | ;[divisor, unit] = [DAY, "day"] 35 | } else if (secondsAgo < MONTH) { 36 | ;[divisor, unit] = [WEEK, "week"] 37 | } else if (secondsAgo < YEAR) { 38 | ;[divisor, unit] = [MONTH, "month"] 39 | } else { 40 | ;[divisor, unit] = [YEAR, "year"] 41 | } 42 | 43 | const count = Math.floor(secondsAgo / divisor) 44 | return `${count} ${unit}${count > 1 ? "s" : ""} ago` 45 | } 46 | -------------------------------------------------------------------------------- /apps/web/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 4 | 5 | const Collapsible = CollapsiblePrimitive.Root 6 | 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger 8 | 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent 10 | 11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 12 | -------------------------------------------------------------------------------- /apps/web/components/ui/hover-card.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as HoverCardPrimitive from "@radix-ui/react-hover-card" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const HoverCard = HoverCardPrimitive.Root 9 | 10 | const HoverCardTrigger = HoverCardPrimitive.Trigger 11 | 12 | const HoverCardContent = React.forwardRef< 13 | React.ElementRef, 14 | React.ComponentPropsWithoutRef 15 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 16 | 26 | )) 27 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName 28 | 29 | export { HoverCard, HoverCardTrigger, HoverCardContent } 30 | -------------------------------------------------------------------------------- /apps/web/components/ui/tooltip.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as TooltipPrimitive from "@radix-ui/react-tooltip" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const TooltipProvider = TooltipPrimitive.Provider 9 | 10 | const Tooltip = TooltipPrimitive.Root 11 | 12 | const TooltipTrigger = TooltipPrimitive.Trigger 13 | 14 | const TooltipArrow = TooltipPrimitive.Arrow 15 | 16 | const TooltipContent = React.forwardRef< 17 | React.ElementRef, 18 | React.ComponentPropsWithoutRef 19 | >(({ className, sideOffset = 4, ...props }, ref) => ( 20 | 29 | )) 30 | TooltipContent.displayName = TooltipPrimitive.Content.displayName 31 | 32 | export { 33 | Tooltip, 34 | TooltipTrigger, 35 | TooltipContent, 36 | TooltipProvider, 37 | TooltipArrow, 38 | } 39 | -------------------------------------------------------------------------------- /apps/web/content/blog/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false, 4 | "overrides": [ 5 | { 6 | "files": ["remotion.mdx", "fine-grained-markdown.mdx"], 7 | "options": { 8 | "printWidth": 42, 9 | "semi": false 10 | } 11 | }, 12 | 13 | { 14 | "files": ["v1.mdx"], 15 | "options": { 16 | "printWidth": 52, 17 | "semi": false 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /apps/web/content/blog/bestiary.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Technical content bestiary 3 | description: Catalog of all the UI patterns commonly used in technical content. 4 | date: 2024-02-05 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | ## Hello World 10 | 11 | loremp ipsum 12 | -------------------------------------------------------------------------------- /apps/web/content/blog/codeblocks.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Perfect codeblocks 3 | description: All the small details that make flawless codeblocks. 4 | date: 2024-01-02 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | Lorem ipsum 10 | 11 | ```js 12 | const a = 1 13 | 14 | // !Collapse(1:3) collapsed 15 | function foo() { 16 | let b = 2 17 | return a + b 18 | } 19 | 20 | // !Collapse(1:3) 21 | function bar() { 22 | let b = 2 23 | return a + b 24 | } 25 | 26 | console.log(foo()) 27 | ``` 28 | 29 | Lorem ipsum 30 | 31 | Lorem ipsum 32 | 33 | Lorem ipsum 34 | 35 | Lorem ipsum 36 | 37 | Lorem ipsum 38 | 39 | Lorem ipsum 40 | 41 | Lorem ipsum 42 | 43 | Lorem ipsum 44 | 45 | Lorem ipsum 46 | 47 | Lorem ipsum 48 | 49 | Lorem ipsum 50 | 51 | Lorem ipsum 52 | 53 | Lorem ipsum 54 | 55 | Lorem ipsum 56 | 57 | Lorem ipsum 58 | 59 | Lorem ipsum 60 | 61 | Lorem ipsum 62 | 63 | Lorem ipsum 64 | 65 | Lorem ipsum 66 | 67 | Lorem ipsum 68 | 69 | Lorem ipsum 70 | 71 | Lorem ipsum 72 | 73 | Lorem ipsum 74 | 75 | Lorem ipsum 76 | 77 | Lorem ipsum 78 | 79 | Lorem ipsum 80 | -------------------------------------------------------------------------------- /apps/web/content/blog/fine-grained/code.tsx: -------------------------------------------------------------------------------- 1 | import { InnerToken, RawCode } from "codehike/code" 2 | import { Code as TheCode } from "@/components/code" 3 | import { AnnotationHandler, InnerLine } from "codehike/code" 4 | import { cn } from "@/lib/utils" 5 | 6 | export async function Code(props: { codeblock: RawCode; className?: string }) { 7 | return 8 | } 9 | 10 | export const fblock: AnnotationHandler = { 11 | name: "fblock", 12 | Line: ({ annotation, ...props }) => { 13 | const bg = "bg-sky-500/10" 14 | const border = "border-sky-500" 15 | 16 | return ( 17 |
25 | 26 |
27 | ) 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /apps/web/content/blog/headless-codeblocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Headless Codeblocks 3 | description: Headless codeblocks 4 | date: 2024-08-15 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | TO DO 10 | -------------------------------------------------------------------------------- /apps/web/content/blog/hello-server.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: React Soup Components 3 | description: A fan-fiction about React and Food 4 | date: 2024-01-25 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | Hello Server 10 | -------------------------------------------------------------------------------- /apps/web/content/blog/known-keys.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Known keys 3 | description: When you need an object where all the keys are mapped to one type except some known keys that are mapped to different types. 4 | date: 2024-02-20 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | Sources: 10 | 11 | - https://github.com/microsoft/TypeScript/issues/31153 12 | - https://github.dev/sindresorhus/type-fest/blob/main/source/merge.d.ts 13 | 14 | ```ts 15 | type MyType = { 16 | [s: string]: string 17 | foo: number 18 | } 19 | ``` 20 | 21 | When you need an object where all the keys are mapped to one type except some known keys that are mapped to different types. 22 | 23 | Why Omit doesn't work: 24 | 25 | ```ts 26 | type Omit = Pick> 27 | ``` 28 | 29 | ```ts 30 | interface FancyIndices { 31 | [x: symbol]: number 32 | [x: `${string}Token`]: string 33 | } 34 | ``` 35 | 36 | does this work? 37 | -------------------------------------------------------------------------------- /apps/web/content/blog/markdown.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Skeuomorphic Markdown 3 | description: Breaking the shackles of static content. 4 | date: 2023-12-24 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | This is how markdown is usually used: 10 | 11 | ```js 12 | import { frontmatter, Content } from "./some.md" 13 | ``` 14 | 15 | Examples: 16 | 17 | - https://docs.astro.build/en/guides/content-collections/ 18 | - https://contentlayer.dev/docs/concepts/content-modeling-dc68721f 19 | - https://nuejs.org/blog/introducing-nuemark/ 20 | 21 | One of the reasons why markdown has so good authoring experience is because of its focus on content, as oppose to presentation. 22 | 23 | This suits linear layouts, but it's not enough for more complex layouts. For more complex layouts we need to group pieces of content in sections, and put those sections in a hierarchy. 24 | -------------------------------------------------------------------------------- /apps/web/content/blog/migrate-to-ch.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Migrate to Code Hike 3 | description: You have an existing website and want to migrate to Code Hike. 4 | date: 2024-01-18 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | -------------------------------------------------------------------------------- /apps/web/content/blog/participation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: The participation continuum 3 | description: Active vs passive learning 4 | date: 2024-01-19 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | ## Hello World 10 | 11 | loremp ipsum 12 | -------------------------------------------------------------------------------- /apps/web/content/blog/power-of-the-web.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: The power of the Web 3 | description: Embracing the uniqueness of the medium. 4 | date: 2023-12-29 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | Interactivity, personalization, accessiblity, collaboration. 10 | -------------------------------------------------------------------------------- /apps/web/content/blog/remotion/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false, 4 | "overrides": [ 5 | { 6 | "files": ["*.jsx"], 7 | "options": { 8 | "printWidth": 42, 9 | "semi": false 10 | } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /apps/web/content/blog/remotion/00.jsx: -------------------------------------------------------------------------------- 1 | // !mark 2 2 | import Content from "./content.md" 3 | 4 | // !f 5 | 6 | import { 7 | parseRoot, 8 | Block, 9 | } from "code-hike/blocks" 10 | import { z } from "zod" 11 | 12 | const Schema = Block.extend({ 13 | steps: z.array(Block), 14 | }) 15 | 16 | // !mark(1:4) 4 17 | const { steps } = parseRoot( 18 | Content, 19 | Schema, 20 | ) 21 | 22 | import { 23 | AbsoluteFill, 24 | Sequence, 25 | Composition, 26 | } from "remotion" 27 | 28 | const STEP_FRAMES = 60 29 | function Video({ steps }) { 30 | return ( 31 | 34 | {/* !mark(1:10) 0 */} 35 | {steps.map((step, i) => ( 36 | 42 | {step.children} 43 | 44 | ))} 45 | 46 | ) 47 | } 48 | 49 | export function RemotionRoot() { 50 | return ( 51 | 62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /apps/web/content/blog/remotion/01.jsx: -------------------------------------------------------------------------------- 1 | import Content from "./content.md" 2 | 3 | // !mark(1:11) 4 | // !focus(1:11) 5 | const Schema = Block.extend({ 6 | steps: z.array( 7 | Block.extend({ 8 | code: HighlightedCodeBlock, 9 | }), 10 | ), 11 | }) 12 | const { steps } = parseRoot( 13 | Content, 14 | Schema, 15 | ) 16 | 17 | const STEP_FRAMES = 60 18 | function Video({ steps }) { 19 | return ( 20 | 26 | {steps.map((step, i) => ( 27 | 33 | 34 | 35 | ))} 36 | 37 | ) 38 | } 39 | 40 | export function RemotionRoot() { 41 | return ( 42 | 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /apps/web/content/blog/remotion/02.jsx: -------------------------------------------------------------------------------- 1 | import Content from "./content.md" 2 | 3 | const Schema = Block.extend({ 4 | steps: z.array( 5 | Block.extend({ 6 | code: HighlightedCodeBlock, 7 | }), 8 | ), 9 | }) 10 | const { steps } = parseRoot( 11 | Content, 12 | Schema, 13 | ) 14 | 15 | const STEP_FRAMES = 60 16 | function Video({ steps }) { 17 | return ( 18 | 24 | {steps.map((step, i) => ( 25 | 31 | {/* !focus */} 32 | {/* !mark */} 33 | 34 | 35 | ))} 36 | 37 | ) 38 | } 39 | 40 | // !focus(1:3) 41 | // !mark(1:3) 42 | function Code({ code }) { 43 | return
44 | }
45 | 
46 | export function RemotionRoot() {
47 |   return (
48 |     
59 |   )
60 | }
61 | 


--------------------------------------------------------------------------------
/apps/web/content/blog/remotion/03.jsx:
--------------------------------------------------------------------------------
 1 | import Content from "./content.md"
 2 | 
 3 | const Schema = Block.extend({
 4 |   steps: z.array(
 5 |     Block.extend({
 6 |       code: HighlightedCodeBlock,
 7 |     }),
 8 |   ),
 9 | })
10 | const { steps } = parseRoot(
11 |   Content,
12 |   Schema,
13 | )
14 | 
15 | const STEP_FRAMES = 60
16 | function Video({ steps }) {
17 |   return (
18 |     
24 |       {steps.map((step, i) => (
25 |         
31 |           
32 |         
33 |       ))}
34 |     
35 |   )
36 | }
37 | 
38 | // !focus(1:17)
39 | // !mark(1:17)
40 | function Code({ code }) {
41 |   return (
42 |     
43 |   )
44 | }
45 | 
46 | const mark = {
47 |   name: "mark",
48 |   Block: ({ children }) => {
49 |     const background = "#F2CC6044"
50 |     return (
51 |       
52 | {children} 53 |
54 | ) 55 | }, 56 | } 57 | 58 | export function RemotionRoot() { 59 | return ( 60 | 71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /apps/web/content/blog/rsc-and-css.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: The server and the cascade 3 | description: How React Server Components make you better at CSS. 4 | authors: [pomber] 5 | date: 2024-02-10 6 | draft: true 7 | --- 8 | -------------------------------------------------------------------------------- /apps/web/content/blog/test.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Test post 3 | description: test description 4 | date: 2024-06-20 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | test 10 | -------------------------------------------------------------------------------- /apps/web/content/blog/type-safe-markdown.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Type-safe Markdown 3 | description: test description 4 | date: 2024-06-20 5 | authors: [pomber] 6 | draft: true 7 | --- 8 | 9 | test 10 | -------------------------------------------------------------------------------- /apps/web/content/components/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false, 4 | "overrides": [ 5 | { 6 | "files": ["*.mdx"], 7 | "options": { 8 | "printWidth": 42, 9 | "semi": false 10 | } 11 | }, 12 | { 13 | "files": ["*.tsx"], 14 | "options": { 15 | "printWidth": 60, 16 | "semi": false 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/content/components/api-reference/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 3 | 4 | const Collapsible = CollapsiblePrimitive.Root 5 | const CollapsibleTrigger = 6 | CollapsiblePrimitive.CollapsibleTrigger 7 | const CollapsibleContent = 8 | CollapsiblePrimitive.CollapsibleContent 9 | 10 | export { 11 | Collapsible, 12 | CollapsibleTrigger, 13 | CollapsibleContent, 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/content/components/slideshow/slides.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import * as React from "react" 3 | 4 | const StepIndexContext = React.createContext< 5 | [number, React.Dispatch>] 6 | >([0, () => {}]) 7 | 8 | export function Slides({ 9 | slides, 10 | }: { 11 | slides: React.ReactNode[] 12 | }) { 13 | const [selectedIndex, setSelectedIndex] = 14 | React.useState(0) 15 | 16 | return ( 17 | 20 | {slides[selectedIndex]} 21 | 22 | ) 23 | } 24 | 25 | export function Controls({ length }: { length: number }) { 26 | const [selectedIndex, setSelectedIndex] = 27 | React.useContext(StepIndexContext) 28 | 29 | return ( 30 |
31 | 39 | {[...Array(length)].map((_, i) => ( 40 | 58 |
59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /apps/web/content/components/slideshow/slideshow.tsx: -------------------------------------------------------------------------------- 1 | import { Slides, Controls } from "./slides" 2 | import { Pre, RawCode, highlight } from "codehike/code" 3 | 4 | export function Slideshow({ hike }: { hike: any }) { 5 | return ( 6 | ( 8 |
9 | 10 | 11 | 12 |
{step.children}
13 |
14 | ))} 15 | /> 16 | ) 17 | } 18 | 19 | async function Code({ codeblock }: { codeblock: RawCode }) { 20 | const info = await highlight(codeblock, "github-dark") 21 | return ( 22 |
26 |   )
27 | }
28 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/api.tsx:
--------------------------------------------------------------------------------
 1 | import { Block, parseProps } from "codehike/blocks"
 2 | import { z } from "zod"
 3 | 
 4 | export function Usage(props: unknown) {
 5 |   const { left, right, caption } = parseProps(
 6 |     props,
 7 |     Block.extend({ left: Block, right: Block, caption: Block.optional() }),
 8 |   )
 9 |   return (
10 |     
11 |
12 |
13 | {left.children} 14 |
15 |
16 | {right.children} 17 |
18 |
19 |
{caption?.children}
20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /apps/web/content/docs/code/classname.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: ClassName 3 | description: Add a class name to a piece of code 4 | layout: PreviewAndImplementation 5 | --- 6 | 7 | ## !demo 8 | 9 | Add a class name to a piece of code. 10 | 11 | 12 | 13 | ## !implementation 14 | 15 | ```tsx classname.tsx -c 16 | import { AnnotationHandler } from "codehike/code" 17 | 18 | export const className: AnnotationHandler = { 19 | name: "className", 20 | Block: ({ annotation, children }) => ( 21 |
{children}
22 | ), 23 | Inline: ({ annotation, children }) => ( 24 | {children} 25 | ), 26 | } 27 | ``` 28 | 29 | And then add the handler to your `Code` component: 30 | 31 | ```tsx code.tsx -c 32 | import { RawCode, Pre, highlight } from "codehike/code" 33 | import { className } from "./classname" 34 | 35 | async function Code({ codeblock }: { codeblock: RawCode }) { 36 | const highlighted = await highlight(codeblock, "github-dark") 37 | return
38 | }
39 | ```
40 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/copy-button.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Copy Button
 3 | description: Copy Button
 4 | layout: PreviewAndImplementation
 5 | ---
 6 | 
 7 | ## !demo
 8 | 
 9 | Add a copy button to a code block.
10 | 
11 | 
12 | 
13 | ## !implementation
14 | 
15 | First we make the button component:
16 | 
17 | ```tsx button.tsx -c
18 | "use client"
19 | 
20 | import { Copy, Check } from "lucide-react"
21 | import { useState } from "react"
22 | 
23 | // !fold[/className="(.*?)"/gm]
24 | export function CopyButton({ text }: { text: string }) {
25 |   const [copied, setCopied] = useState(false)
26 | 
27 |   return (
28 |     
39 |   )
40 | }
41 | ```
42 | 
43 | And then we use it when rendering the code block:
44 | 
45 | ```tsx code.tsx -c
46 | import { Pre, RawCode, highlight } from "codehike/code"
47 | import { CopyButton } from "./button"
48 | 
49 | // !fold[/className="(.*?)"/gm]
50 | async function Code({ codeblock }: { codeblock: RawCode }) {
51 |   const highlighted = await highlight(codeblock, "github-dark")
52 | 
53 |   return (
54 |     
55 | 56 |
57 |     
58 | ) 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /apps/web/content/docs/code/diff.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Diff 3 | description: Diff 4 | layout: PreviewAndImplementation 5 | --- 6 | 7 | ## !demo 8 | 9 | Show inserted and deleted lines. 10 | 11 | 12 | 13 | ## !implementation 14 | 15 | There are two parts: 16 | 17 | - for the `+` and `-` icons, we customize the `Line` and prepend the `annotation.query` 18 | - for the border and color we use the `transform` function to add `mark` annotations and use the `AnnotationHandler` from the [mark example](/docs/code/mark) 19 | 20 | ```tsx diff.tsx -c 21 | import { AnnotationHandler, InnerLine, BlockAnnotation } from "codehike/code" 22 | // !fold[/className="(.*?)"/gm] 23 | 24 | export const diff: AnnotationHandler = { 25 | name: "diff", 26 | onlyIfAnnotated: true, 27 | transform: (annotation: BlockAnnotation) => { 28 | const color = annotation.query == "-" ? "#f85149" : "#3fb950" 29 | return [annotation, { ...annotation, name: "mark", query: color }] 30 | }, 31 | Line: ({ annotation, ...props }) => ( 32 | <> 33 |
34 | {annotation?.query} 35 |
36 | 37 | 38 | ), 39 | } 40 | ``` 41 | 42 | Then pass the `mark` and `diff` handlers to the `Pre` component: 43 | 44 | ```tsx code.tsx -c 45 | import { diff } from "./diff" 46 | import { mark } from "./mark" 47 | 48 | async function Code({ codeblock }: { codeblock: RawCode }) { 49 | const highlighted = await highlight(codeblock, "github-dark") 50 | return
51 | }
52 | ```
53 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/filename.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: File name
 3 | description: Show the file name in the code block
 4 | layout: PreviewAndImplementation
 5 | ---
 6 | 
 7 | ## !demo
 8 | 
 9 | Show a title or file name with the code block.
10 | 
11 | 
12 | 
13 | ## !implementation
14 | 
15 | ```tsx code.tsx -cw
16 | import { RawCode, Pre, highlight } from "codehike/code"
17 | 
18 | // !fold[/className="(.*?)"/gm]
19 | async function Code({ codeblock }: { codeblock: RawCode }) {
20 |   const highlighted = await highlight(codeblock, "github-dark")
21 |   return (
22 |     
23 |
24 | {highlighted.meta} 25 |
26 |
27 |     
28 | ) 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /apps/web/content/docs/code/fold.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fold 3 | description: Fold annotation 4 | layout: PreviewAndImplementation 5 | --- 6 | 7 | ## !demo 8 | 9 | Fold inline content. 10 | 11 | Click on the ... to unfold the className 12 | 13 | ## !implementation 14 | 15 | ```tsx fold.tsx -c 16 | "use client" 17 | import { AnnotationHandler } from "codehike/code" 18 | import { useState } from "react" 19 | 20 | export const InlineFold: AnnotationHandler["Inline"] = ({ children }) => { 21 | const [folded, setFolded] = useState(true) 22 | if (!folded) { 23 | return children 24 | } 25 | return ( 26 | 29 | ) 30 | } 31 | ``` 32 | 33 | And then add the handler to your `Code` component: 34 | 35 | ```tsx code.tsx -c 36 | import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code" 37 | import { InlineFold } from "./fold" 38 | 39 | async function Code({ codeblock }: { codeblock: RawCode }) { 40 | const highlighted = await highlight(codeblock, "github-dark") 41 | return
42 | }
43 | 
44 | const fold: AnnotationHandler = {
45 |   name: "fold",
46 |   Inline: InlineFold,
47 | }
48 | ```
49 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/index.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Code Examples
 3 | description: Code examples
 4 | layout: CodeIndex
 5 | ---
 6 | 
 7 | These are examples of codeblock components you can build using Code Hike.
 8 | 
 9 | You can find the explanation and implementation in each example's page. Feel free to copy, paste, modify and combine them to create the perfect codeblocks for your project.
10 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/line-numbers.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Line Numbers
 3 | description: Line numbers
 4 | layout: PreviewAndImplementation
 5 | ---
 6 | 
 7 | ## !demo
 8 | 
 9 | Display line numbers.
10 | 
11 | 
12 | 
13 | ## !implementation
14 | 
15 | Using a [custom line component](/docs/concepts/annotations#customizing-line-and-token-components):
16 | 
17 | ```tsx line-numbers.tsx -c
18 | import { AnnotationHandler, InnerLine } from "codehike/code"
19 | 
20 | // !fold[/className="(.*?)"/gm]
21 | export const lineNumbers: AnnotationHandler = {
22 |   name: "line-numbers",
23 |   Line: (props) => {
24 |     const width = props.totalLines.toString().length + 1
25 |     return (
26 |       
27 | 31 | {props.lineNumber} 32 | 33 | 34 |
35 | ) 36 | }, 37 | } 38 | ``` 39 | 40 | Pass it to the `handlers` prop of the `Pre` component: 41 | 42 | ```tsx code.tsx -c 43 | import { lineNumbers } from "./line-numbers" 44 | 45 | async function Code({ codeblock }: { codeblock: RawCode }) { 46 | const highlighted = await highlight(codeblock, "github-dark") 47 | return
48 | }
49 | ```
50 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/link.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Link
 3 | description: Add links to code snippets
 4 | layout: PreviewAndImplementation
 5 | ---
 6 | 
 7 | ## !demo
 8 | 
 9 | Add links to code snippets.
10 | 
11 | **ipsum** is a link to example.com
12 | 
13 | ## !implementation
14 | 
15 | ```tsx code.tsx
16 | import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code"
17 | 
18 | const link: AnnotationHandler = {
19 |   name: "link",
20 |   Inline: ({ annotation, children }) => {
21 |     const { query } = annotation
22 |     return {children}
23 |   },
24 | }
25 | 
26 | async function Code({ codeblock }: { codeblock: RawCode }) {
27 |   const highlighted = await highlight(codeblock, "github-dark")
28 |   return 
29 | }
30 | ```
31 | 
32 | ### Autolinking
33 | 
34 | Instead of manually adding links to code snippets, you can use a regex to automatically link URLs.
35 | 
36 | 
37 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/transpile.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Transpile
 3 | description: Show code together with its transpiled version
 4 | layout: PreviewAndImplementation
 5 | ---
 6 | 
 7 | ## !demo
 8 | 
 9 | Sometimes you have a code block that you want to show together with its versions in different languages. It may be typescript and javascript, or sass and css, or maybe you want to transform a cURL command into calls to SDKs in different languages.
10 | 
11 | If you are using React Server Components and you have a function to transpile the code, you can call that function inside the component.
12 | 
13 | Here's an example showing how to transpile a typescript code block to javascript, and then showing both versions in tabs:
14 | 
15 | 
16 | 
17 | ## !implementation
18 | 
19 | ```tsx code.tsx -c
20 | import { RawCode } from "codehike/code"
21 | // !link[/tabs example/] tabs
22 | // CodeTabs is the component from the tabs example
23 | // !link[/CodeTabs/] tabs
24 | import { CodeTabs } from "@/components/tabs"
25 | import ts from "typescript"
26 | 
27 | async function Code({ codeblock }: { codeblock: RawCode }) {
28 |   // Since this is a RSC we can transpile stuff here
29 |   // (there are probably more efficient ways to do this)
30 |   const result = ts.transpileModule(codeblock.value, {
31 |     compilerOptions: {
32 |       module: ts.ModuleKind.CommonJS,
33 |       target: ts.ScriptTarget.ESNext,
34 |     },
35 |   })
36 | 
37 |   const tsCode = {
38 |     ...codeblock,
39 |     meta: "typescript",
40 |   }
41 |   const jsCode = {
42 |     ...codeblock,
43 |     value: result.outputText,
44 |     lang: "js",
45 |     meta: "javascript",
46 |   }
47 | 
48 |   return 
49 | }
50 | ```
51 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/code/word-wrap.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Word Wrap
 3 | description: Word wrap
 4 | layout: PreviewAndImplementation
 5 | ---
 6 | 
 7 | ## !demo
 8 | 
 9 | Wrap lines to avoid horizontal overflow.
10 | 
11 | Drag the right handle to resize the width
12 | 
13 | ## !implementation
14 | 
15 | The easy way to make the code wrap is to style the `
` component with `white-space: pre-wrap;`. But, when wrapping code, it's better to wrap the lines at the same indentation level. To do this, we can adjust the `text-indent` of each line:
16 | 
17 | ```tsx word-wrap.tsx -c
18 | import {
19 |   AnnotationHandler,
20 |   InnerLine,
21 |   InnerPre,
22 |   InnerToken,
23 | } from "codehike/code"
24 | 
25 | export const wordWrap: AnnotationHandler = {
26 |   name: "word-wrap",
27 |   Pre: (props) => ,
28 |   Line: (props) => (
29 |     
30 |       
36 | {props.children} 37 |
38 |
39 | ), 40 | Token: (props) => , 41 | } 42 | ``` 43 | 44 | Pass it to the `handlers` prop of the `Pre` component: 45 | 46 | ```tsx code.tsx -c 47 | import { wordWrap } from "./word-wrap" 48 | 49 | async function Code({ codeblock }: { codeblock: RawCode }) { 50 | const highlighted = await highlight(codeblock, "github-dark") 51 | return
52 | }
53 | ```
54 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/concepts/assets/index.js:
--------------------------------------------------------------------------------
1 | !from ./assets/index.js


--------------------------------------------------------------------------------
/apps/web/content/docs/examples.mdx:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Full Examples and Templates
 3 | description: Code Hike examples and templates
 4 | ---
 5 | 
 6 | import { Examples } from "./examples.tsx"
 7 | 
 8 | 
 9 | 
10 | Examples with minimal content showing how to use Code Hike with different frameworks and libraries.
11 | 
12 | ## !! Next.js + Fumadocs
13 | 
14 | ![!repo](https://github.com/code-hike/examples/tree/main/with-fumadocs)
15 | ![!img](/examples/fumadocs.png)
16 | 
17 | ## !! Docusaurus
18 | 
19 | ![!repo](https://github.com/code-hike/examples/tree/main/with-docusaurus)
20 | ![!img](/examples/docusaurus.png)
21 | 
22 | ## !! Remotion
23 | 
24 | ![!repo](https://github.com/code-hike/examples/tree/main/with-remotion)
25 | ![!img](/examples/remotion.png)
26 | 
27 | ## !! Nextra
28 | 
29 | ![!repo](https://github.com/code-hike/examples/tree/main/with-nextra-3)
30 | ![!img](/examples/nextra-3.png)
31 | 
32 | 
33 | 
34 | 
35 | 
36 | Using Code Hike to rebuild some inspiring websites.
37 | 
38 | ## !! Shopify API Reference
39 | 
40 | ![!repo](https://clone-shopify-api-reference.vercel.app/)
41 | ![!img](/examples/shopify.png)
42 | 
43 | ## !! Swift UI Tutorials
44 | 
45 | ![!repo](https://clone-swiftui-tutorial.vercel.app/)
46 | ![!img](/examples/swiftui.png)
47 | 
48 | 
49 | 


--------------------------------------------------------------------------------
/apps/web/content/docs/examples.tsx:
--------------------------------------------------------------------------------
 1 | import { Block, ImageBlock, parseProps } from "codehike/blocks"
 2 | import { z } from "zod"
 3 | 
 4 | export function Examples(props: unknown) {
 5 |   const { blocks, title, children } = parseProps(
 6 |     props,
 7 |     Block.extend({
 8 |       blocks: z.array(
 9 |         Block.extend({
10 |           repo: ImageBlock,
11 |           img: ImageBlock,
12 |         }),
13 |       ),
14 |     }),
15 |   )
16 |   return (
17 |     
18 |

{title}

19 |
{children}
20 |
21 | {blocks.map((example) => ( 22 | 29 | {example.title} 30 |

{example.title}

31 |
32 | ))} 33 |
34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /apps/web/content/docs/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Docs", 3 | "pages": [ 4 | "index", 5 | "concepts/blocks", 6 | "concepts/code", 7 | "concepts/annotations", 8 | "concepts/utils", 9 | "---Examples---", 10 | "code", 11 | "layouts", 12 | "examples" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/content/docs/test.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Components 3 | description: Components 4 | --- 5 | 6 | ## Code Block 7 | 8 | ```mdx 9 | import { Hike } from "codehike" 10 | import { MyLayout } from "./my-layout.tsx" 11 | 12 | 13 | 14 | # !main Hello World 15 | 16 | Something 17 | 18 | 19 | ``` 20 | 21 | ## Cards 22 | 23 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /apps/web/demos/annotations/basic/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | // !border(1:2) 3 | const lorem = ipsum == null ? 0 : 1 4 | dolor = lorem - sit(dolor) 5 | // !bg[5:16] 6 | let amet = lorem ? consectetur(ipsum) : 3 7 | ``` 8 | -------------------------------------------------------------------------------- /apps/web/demos/annotations/basic/page.tsx: -------------------------------------------------------------------------------- 1 | import Content from "./content.md" 2 | import { RawCode, Pre, highlight } from "codehike/code" 3 | import { AnnotationHandler } from "codehike/code" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | export async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const highlighted = await highlight(codeblock, "github-dark") 11 | return ( 12 |
17 |   )
18 | }
19 | const borderHandler: AnnotationHandler = {
20 |   name: "border",
21 |   Block: ({ annotation, children }) => (
22 |     
{children}
23 | ), 24 | } 25 | 26 | const bgHandler: AnnotationHandler = { 27 | name: "bg", 28 | Inline: ({ annotation, children }) => ( 29 | {children} 30 | ), 31 | } 32 | -------------------------------------------------------------------------------- /apps/web/demos/annotations/groups/content.md: -------------------------------------------------------------------------------- 1 | ```jsx 2 | // !border[/className="(.*?)"/gm] pink 3 | function Foo() { 4 | return ( 5 |
6 | hey 7 |
8 | ) 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /apps/web/demos/annotations/groups/page.tsx: -------------------------------------------------------------------------------- 1 | import Content from "./content.md" 2 | import { RawCode, Pre, highlight } from "codehike/code" 3 | import { AnnotationHandler } from "codehike/code" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | export async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const highlighted = await highlight(codeblock, "github-dark") 11 | return ( 12 |
17 |   )
18 | }
19 | const borderHandler: AnnotationHandler = {
20 |   name: "border",
21 |   Inline: ({ annotation, children }) => {
22 |     const borderColor = annotation.query || "yellow"
23 |     return {children}
24 |   },
25 | }
26 | 


--------------------------------------------------------------------------------
/apps/web/demos/annotations/mark/content.md:
--------------------------------------------------------------------------------
1 | ```js
2 | const lorem = ipsum == null ? 0 : 1
3 | // !mark(1:2)
4 | dolor = lorem - sit(dolor)
5 | let amet = lorem ? consectetur(ipsum) : 3
6 | ```
7 | 


--------------------------------------------------------------------------------
/apps/web/demos/annotations/mark/page.tsx:
--------------------------------------------------------------------------------
 1 | import Content from "./content.md"
 2 | import { RawCode, Pre, highlight, InnerLine } from "codehike/code"
 3 | import { AnnotationHandler } from "codehike/code"
 4 | 
 5 | export default function Page() {
 6 |   return 
 7 | }
 8 | 
 9 | export async function Code({ codeblock }: { codeblock: RawCode }) {
10 |   const highlighted = await highlight(codeblock, "github-dark")
11 |   return (
12 |     
17 |   )
18 | }
19 | const mark: AnnotationHandler = {
20 |   name: "mark",
21 |   AnnotatedLine: ({ annotation, ...props }) => (
22 |     
23 |   ),
24 |   Line: (props) => (
25 |     
29 |   ),
30 | }
31 | 


--------------------------------------------------------------------------------
/apps/web/demos/annotations/query/content.md:
--------------------------------------------------------------------------------
1 | ```js
2 | // !border(1:2) purple
3 | const lorem = ipsum == null ? 0 : 1
4 | dolor = lorem - sit(dolor)
5 | // !bg[5:16] darkblue
6 | let amet = lorem ? consectetur(ipsum) : 3
7 | ```
8 | 


--------------------------------------------------------------------------------
/apps/web/demos/annotations/query/page.tsx:
--------------------------------------------------------------------------------
 1 | import Content from "./content.md"
 2 | import { RawCode, Pre, highlight } from "codehike/code"
 3 | import { AnnotationHandler } from "codehike/code"
 4 | 
 5 | export default function Page() {
 6 |   return 
 7 | }
 8 | 
 9 | export async function Code({ codeblock }: { codeblock: RawCode }) {
10 |   const highlighted = await highlight(codeblock, "github-dark")
11 |   return (
12 |     
17 |   )
18 | }
19 | const borderHandler: AnnotationHandler = {
20 |   name: "border",
21 |   Block: ({ annotation, children }) => {
22 |     const borderColor = annotation.query || "red"
23 |     return 
{children}
24 | }, 25 | } 26 | 27 | const bgHandler: AnnotationHandler = { 28 | name: "bg", 29 | Inline: ({ annotation, children }) => { 30 | const background = annotation.query || "#2d26" 31 | return {children} 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /apps/web/demos/annotations/regex/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | // !border[/ipsum/] yellow 3 | const lorem = ipsum == null ? ipsum : 1 4 | // !border[/dolor/g] lime 5 | dolor = lorem - sit(dolor) 6 | let amet = dolor ? consectetur(ipsum) : 3 7 | ``` 8 | 9 | ```js 10 | // !border[/ipsum/gm] orange 11 | const lorem = ipsum == null ? ipsum : 1 12 | dolor = lorem - sit(dolor) 13 | let amet = dolor ? consectetur(ipsum) : 3 14 | ``` 15 | -------------------------------------------------------------------------------- /apps/web/demos/annotations/regex/page.tsx: -------------------------------------------------------------------------------- 1 | import Content from "./content.md" 2 | import { RawCode, Pre, highlight } from "codehike/code" 3 | import { AnnotationHandler } from "codehike/code" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | export async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const highlighted = await highlight(codeblock, "github-dark") 11 | return ( 12 |
17 |   )
18 | }
19 | const borderHandler: AnnotationHandler = {
20 |   name: "border",
21 |   Inline: ({ annotation, children }) => {
22 |     const borderColor = annotation.query || "yellow"
23 |     return {children}
24 |   },
25 | }
26 | 


--------------------------------------------------------------------------------
/apps/web/demos/api-reference/.prettierrc:
--------------------------------------------------------------------------------
 1 | {
 2 |   "trailingComma": "all",
 3 |   "semi": false,
 4 |   "overrides": [
 5 |     {
 6 |       "files": ["*.md"],
 7 |       "options": {
 8 |         "printWidth": 42,
 9 |         "semi": false
10 |       }
11 |     },
12 |     {
13 |       "files": ["*.tsx"],
14 |       "options": {
15 |         "printWidth": 60,
16 |         "semi": false
17 |       }
18 |     }
19 |   ]
20 | }
21 | 


--------------------------------------------------------------------------------
/apps/web/demos/autolink/content.md:
--------------------------------------------------------------------------------
 1 | ```js
 2 | // !link[/"(http.*?)"/gm]
 3 | function lorem(ipsum, dolor = 1) {
 4 |   const links = [
 5 |     "https://codehike.org",
 6 |     "https://twitter.com/codehike_",
 7 |     "https://github.com/code-hike",
 8 |   ]
 9 |   return links
10 | }
11 | ```
12 | 


--------------------------------------------------------------------------------
/apps/web/demos/autolink/page.tsx:
--------------------------------------------------------------------------------
 1 | import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code"
 2 | import Content from "./content.md"
 3 | 
 4 | export default function Page() {
 5 |   return 
 6 | }
 7 | 
 8 | async function Code({ codeblock }: { codeblock: RawCode }) {
 9 |   const highlighted = await highlight(codeblock, "github-dark")
10 |   return (
11 |     
12 |   )
13 | }
14 | 
15 | const link: AnnotationHandler = {
16 |   name: "link",
17 |   Inline: ({ annotation, children }) => {
18 |     const { query } = annotation
19 |     return {children}
20 |   },
21 | }
22 | 


--------------------------------------------------------------------------------
/apps/web/demos/callout/content.md:
--------------------------------------------------------------------------------
 1 | ```js
 2 | const lorem = ipsum(dolor, sit)
 3 | // !callout[/amet/] This is a callout
 4 | const [amet, consectetur] = [0, 0]
 5 | lorem.adipiscing((sed, elit) => {
 6 |   if (sed) {
 7 |     amet += elit
 8 |   }
 9 | })
10 | ```
11 | 


--------------------------------------------------------------------------------
/apps/web/demos/callout/page.tsx:
--------------------------------------------------------------------------------
 1 | import Content from "./content.md"
 2 | import { RawCode, Pre, highlight } from "codehike/code"
 3 | import { InlineAnnotation, AnnotationHandler } from "codehike/code"
 4 | 
 5 | export default function Page() {
 6 |   return 
 7 | }
 8 | 
 9 | export async function Code({ codeblock }: { codeblock: RawCode }) {
10 |   const highlighted = await highlight(codeblock, "github-dark")
11 | 
12 |   return (
13 |     
18 |   )
19 | }
20 | 
21 | const callout: AnnotationHandler = {
22 |   name: "callout",
23 |   transform: (annotation: InlineAnnotation) => {
24 |     const { name, query, lineNumber, fromColumn, toColumn, data } = annotation
25 |     return {
26 |       name,
27 |       query,
28 |       fromLineNumber: lineNumber,
29 |       toLineNumber: lineNumber,
30 |       data: { ...data, column: (fromColumn + toColumn) / 2 },
31 |     }
32 |   },
33 |   Block: ({ annotation, children }) => {
34 |     const { column } = annotation.data
35 |     return (
36 |       <>
37 |         {children}
38 |         
42 |
46 | {annotation.query} 47 |
48 | 49 | ) 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /apps/web/demos/classname/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function lorem(ipsum, dolor = 1) { 3 | // !className line-through 4 | const sit = ipsum == null ? 0 : ipsum.sit 5 | dolor = sit - amet(dolor) 6 | // !className[/sit/] bg-red-700 rounded-lg px-1 7 | return sit ? consectetur(ipsum) : [] 8 | } 9 | ``` 10 | -------------------------------------------------------------------------------- /apps/web/demos/classname/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code" 2 | import Content from "./content.md" 3 | 4 | export default function Page() { 5 | return 6 | } 7 | 8 | async function Code({ codeblock }: { codeblock: RawCode }) { 9 | const highlighted = await highlight(codeblock, "github-dark") 10 | return ( 11 |
16 |   )
17 | }
18 | 
19 | const className: AnnotationHandler = {
20 |   name: "className",
21 |   Block: ({ annotation, children }) => (
22 |     
{children}
23 | ), 24 | Inline: ({ annotation, children }) => ( 25 | {children} 26 | ), 27 | } 28 | -------------------------------------------------------------------------------- /apps/web/demos/collapse/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | // !collapse(1:4) 3 | function lorem(ipsum, dolor = 1) { 4 | const sit = ipsum == null ? 0 : 1 5 | dolor = sit - amet(dolor) 6 | return sit ? consectetur(ipsum) : [] 7 | } 8 | 9 | // !collapse(1:4) collapsed 10 | function ipsum(ipsum, dolor = 1) { 11 | const sit = ipsum == null ? 0 : 1 12 | dolor = sit - amet(dolor) 13 | return sit ? consectetur(ipsum) : [] 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /apps/web/demos/copy-button/button.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { Copy, Check } from "lucide-react" 4 | import { useState } from "react" 5 | 6 | export function CopyButton({ text }: { text: string }) { 7 | const [copied, setCopied] = useState(false) 8 | 9 | return ( 10 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /apps/web/demos/copy-button/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function lorem(ipsum, dolor = 1) { 3 | const sit = ipsum == null ? 0 : ipsum.sit 4 | dolor = sit - amet(dolor) 5 | return sit ? consectetur(ipsum) : [] 6 | } 7 | ``` 8 | -------------------------------------------------------------------------------- /apps/web/demos/copy-button/page.tsx: -------------------------------------------------------------------------------- 1 | import { Pre, RawCode, highlight } from "codehike/code" 2 | import Content from "./content.md" 3 | import { CopyButton } from "./button" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const highlighted = await highlight(codeblock, "github-dark") 11 | 12 | return ( 13 |
14 | 15 |
16 |     
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/demos/diff/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function lorem(ipsum, dolor = 1) { 3 | const sit = ipsum == null ? 0 : ipsum.sit 4 | // !diff - 5 | dolor = ipsum - sit 6 | // !diff + 7 | dolor = sit - amet(dolor) 8 | return sit ? consectetur(ipsum) : [] 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /apps/web/demos/filename/content.md: -------------------------------------------------------------------------------- 1 | ```js index.js 2 | function lorem(ipsum, dolor = 1) { 3 | const sit = ipsum == null ? 0 : 1 4 | dolor = sit - amet(dolor) 5 | return sit ? consectetur(ipsum) : [] 6 | } 7 | ``` 8 | -------------------------------------------------------------------------------- /apps/web/demos/filename/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, Pre, highlight } from "codehike/code" 2 | import Content from "./content.md" 3 | 4 | export default function Page() { 5 | return 6 | } 7 | 8 | async function Code({ codeblock }: { codeblock: RawCode }) { 9 | const highlighted = await highlight(codeblock, "github-dark") 10 | return ( 11 |
12 |
13 | {highlighted.meta} 14 |
15 |
16 |     
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/demos/focus/code.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { HighlightedCode, Pre } from "codehike/code" 4 | import React, { useState } from "react" 5 | import { focus } from "./focus" 6 | 7 | const ranges = { 8 | lorem: { fromLineNumber: 1, toLineNumber: 5 }, 9 | ipsum: { fromLineNumber: 7, toLineNumber: 11 }, 10 | dolor: { fromLineNumber: 11, toLineNumber: 15 }, 11 | } 12 | 13 | export function CodeContainer({ code }: { code: HighlightedCode }) { 14 | const [focused, setFocused] = useState<"lorem" | "ipsum" | "dolor">("dolor") 15 | 16 | return ( 17 | <> 18 |
32 |       
33 | You can also change the focus annotations on a rendered codeblock: 34 |
35 |
36 | {" "} 43 | 50 |
51 | 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /apps/web/demos/focus/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function lorem(ipsum, dolor = 1) { 3 | const sit = ipsum == null ? 0 : ipsum.sit 4 | dolor = sit - amet(dolor) 5 | return sit ? consectetur(ipsum) : [] 6 | } 7 | 8 | function ipsum(ipsum, dolor = 1) { 9 | return dolor 10 | } 11 | 12 | // !focus(1:5) 13 | function dolor(ipsum, dolor = 1) { 14 | const sit = ipsum == null ? 0 : ipsum.sit 15 | dolor = sit - amet(dolor) 16 | return sit ? consectetur(ipsum) : [] 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/web/demos/focus/focus.client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import React, { useLayoutEffect, useRef } from "react" 4 | import { AnnotationHandler, InnerPre, getPreRef } from "codehike/code" 5 | 6 | export const PreWithFocus: AnnotationHandler["PreWithRef"] = (props) => { 7 | const ref = getPreRef(props) 8 | useScrollToFocus(ref) 9 | return 10 | } 11 | 12 | function useScrollToFocus(ref: React.RefObject) { 13 | const firstRender = useRef(true) 14 | useLayoutEffect(() => { 15 | if (ref.current) { 16 | // find all descendants whith data-focus="true" 17 | const focusedElements = ref.current.querySelectorAll( 18 | "[data-focus=true]", 19 | ) as NodeListOf 20 | 21 | // find top and bottom of the focused elements 22 | const containerRect = ref.current.getBoundingClientRect() 23 | let top = Infinity 24 | let bottom = -Infinity 25 | focusedElements.forEach((el) => { 26 | const rect = el.getBoundingClientRect() 27 | top = Math.min(top, rect.top - containerRect.top) 28 | bottom = Math.max(bottom, rect.bottom - containerRect.top) 29 | }) 30 | 31 | // scroll to the focused elements if any part of them is not visible 32 | if (bottom > containerRect.height || top < 0) { 33 | ref.current.scrollTo({ 34 | top: ref.current.scrollTop + top - 10, 35 | behavior: firstRender.current ? "instant" : "smooth", 36 | }) 37 | } 38 | firstRender.current = false 39 | } 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /apps/web/demos/focus/focus.tsx: -------------------------------------------------------------------------------- 1 | import { AnnotationHandler, InnerLine } from "codehike/code" 2 | import { PreWithFocus } from "./focus.client" 3 | 4 | export const focus: AnnotationHandler = { 5 | name: "focus", 6 | onlyIfAnnotated: true, 7 | PreWithRef: PreWithFocus, 8 | Line: (props) => ( 9 | 13 | ), 14 | AnnotatedLine: ({ annotation, ...props }) => ( 15 | 16 | ), 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/demos/focus/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, highlight } from "codehike/code" 2 | import Content from "./content.md" 3 | import { CodeContainer } from "./code" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const info = await highlight(codeblock, "github-dark") 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /apps/web/demos/fold/annotations.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { AnnotationHandler } from "codehike/code" 4 | import { useState } from "react" 5 | 6 | export const InlineFold: AnnotationHandler["Inline"] = ({ children }) => { 7 | const [folded, setFolded] = useState(true) 8 | if (!folded) { 9 | return children 10 | } 11 | return ( 12 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/demos/fold/content.md: -------------------------------------------------------------------------------- 1 | ```jsx 2 | // !fold[/className="(.*?)"/gm] 3 | function Foo() { 4 | return ( 5 |
6 | hey 7 |
8 | ) 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /apps/web/demos/fold/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code" 2 | import Content from "./content.md" 3 | import { InlineFold } from "./annotations" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const info = await highlight(codeblock, "github-dark") 11 | 12 | return
13 | }
14 | 
15 | export const fold: AnnotationHandler = {
16 |   name: "fold",
17 |   Inline: InlineFold,
18 | }
19 | 


--------------------------------------------------------------------------------
/apps/web/demos/footnotes/content.md:
--------------------------------------------------------------------------------
 1 | ```rb
 2 | # !ref Library import
 3 | require 'sinatra'
 4 | 
 5 | # !ref URL mapping
 6 | get '/hi' do
 7 |   "Hello World!"
 8 | end
 9 | ```
10 | 


--------------------------------------------------------------------------------
/apps/web/demos/hover/content.mdx:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | The [base case](hover:one) returns 1.
 4 | 
 5 | ```cpp
 6 | int factorial(int n) {
 7 |   if (n == 0) {
 8 |     // !hover one
 9 |     return 1;
10 |   } else {
11 |     // !hover two
12 |     return n * factorial(n - 1);
13 |   }
14 | }
15 | ```
16 | 
17 | The [recursive case](hover:two) multiplies something.
18 | 
19 | 
20 | 


--------------------------------------------------------------------------------
/apps/web/demos/hover/page.tsx:
--------------------------------------------------------------------------------
 1 | import {
 2 |   AnnotationHandler,
 3 |   InnerLine,
 4 |   Pre,
 5 |   RawCode,
 6 |   highlight,
 7 | } from "codehike/code"
 8 | import Content from "./content.mdx"
 9 | import "./styles.css"
10 | 
11 | import React from "react"
12 | 
13 | export default function Page() {
14 |   return 
15 | }
16 | 
17 | function HoverContainer(props: { children: React.ReactNode }) {
18 |   return (
19 |     
20 | {props.children} 21 |
22 | ) 23 | } 24 | 25 | function Link(props: { href?: string; children?: React.ReactNode }) { 26 | if (props.href?.startsWith("hover:")) { 27 | const hover = props.href.slice("hover:".length) 28 | return ( 29 | 33 | {props.children} 34 | 35 | ) 36 | } else { 37 | return 38 | } 39 | } 40 | 41 | async function Code({ codeblock }: { codeblock: RawCode }) { 42 | const highlighted = await highlight(codeblock, "github-dark") 43 | return
44 | }
45 | 
46 | const hover: AnnotationHandler = {
47 |   name: "hover",
48 |   onlyIfAnnotated: true,
49 |   Line: ({ annotation, ...props }) => (
50 |     
55 |   ),
56 | }
57 | 


--------------------------------------------------------------------------------
/apps/web/demos/hover/styles.css:
--------------------------------------------------------------------------------
1 | .hover-container:has([data-hover="one"]:hover)
2 |   [data-line]:not([data-line="one"]),
3 | .hover-container:has([data-hover="two"]:hover)
4 |   [data-line]:not([data-line="two"]) {
5 |   opacity: 0.4;
6 | }
7 | 


--------------------------------------------------------------------------------
/apps/web/demos/language-switcher/multi-code.tsx:
--------------------------------------------------------------------------------
 1 | "use client"
 2 | 
 3 | import { HighlightedCode, Pre, RawCode, highlight } from "codehike/code"
 4 | 
 5 | import { useState } from "react"
 6 | import {
 7 |   Select,
 8 |   SelectContent,
 9 |   SelectItem,
10 |   SelectTrigger,
11 |   SelectValue,
12 | } from "@/components/ui/select"
13 | import { tokenTransitions } from "@/components/annotations/token-transitions"
14 | 
15 | export function Code({ highlighted }: { highlighted: HighlightedCode[] }) {
16 |   const [selectedLang, setSelectedLang] = useState(highlighted[0].lang)
17 |   const selectedCode = highlighted.find((code) => code.lang === selectedLang)!
18 | 
19 |   return (
20 |     
21 |
26 |       
27 | 43 |
44 |
45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /apps/web/demos/language-switcher/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, highlight } from "codehike/code" 2 | import Content from "./content.mdx" 3 | 4 | import { Code } from "./multi-code" 5 | 6 | export default function Page() { 7 | return 8 | } 9 | 10 | async function CodeSwitcher(props: { code: RawCode[] }) { 11 | const highlighted = await Promise.all( 12 | props.code.map((codeblock) => highlight(codeblock, "github-dark")), 13 | ) 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /apps/web/demos/line-numbers/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function lorem(ipsum, dolor = 1) { 3 | const sit = ipsum == null ? 0 : 1 4 | dolor = sit - amet(dolor) 5 | return sit ? consectetur(ipsum) : [] 6 | } 7 | ``` 8 | -------------------------------------------------------------------------------- /apps/web/demos/line-numbers/page.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | RawCode, 3 | Pre, 4 | highlight, 5 | AnnotationHandler, 6 | InnerLine, 7 | } from "codehike/code" 8 | import Content from "./content.md" 9 | 10 | export default function Page() { 11 | return 12 | } 13 | 14 | async function Code({ codeblock }: { codeblock: RawCode }) { 15 | const info = await highlight(codeblock, "github-dark") 16 | 17 | return ( 18 |
23 |   )
24 | }
25 | 
26 | export const lineNumbers: AnnotationHandler = {
27 |   name: "line-numbers",
28 |   Line: (props) => {
29 |     const width = props.totalLines.toString().length + 1
30 |     return (
31 |       
32 | 36 | {props.lineNumber} 37 | 38 | 39 |
40 | ) 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /apps/web/demos/link/content.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function lorem(ipsum, dolor = 1) { 3 | const sit = ipsum == null ? 0 : ipsum.sit 4 | dolor = sit - amet(dolor) 5 | // !link[/ipsum/] https://example.com 6 | return sit ? consectetur(ipsum) : [] 7 | } 8 | ``` 9 | -------------------------------------------------------------------------------- /apps/web/demos/link/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, Pre, highlight, AnnotationHandler } from "codehike/code" 2 | import Content from "./content.md" 3 | 4 | export default function Page() { 5 | return 6 | } 7 | 8 | async function Code({ codeblock }: { codeblock: RawCode }) { 9 | const highlighted = await highlight(codeblock, "github-dark") 10 | return ( 11 |
12 |   )
13 | }
14 | 
15 | const link: AnnotationHandler = {
16 |   name: "link",
17 |   Inline: ({ annotation, children }) => {
18 |     const { query } = annotation
19 |     return {children}
20 |   },
21 | }
22 | 


--------------------------------------------------------------------------------
/apps/web/demos/mark/content.md:
--------------------------------------------------------------------------------
 1 | ```js
 2 | function lorem(ipsum, dolor = 1) {
 3 |   // !mark
 4 |   return dolor
 5 | }
 6 | 
 7 | function ipsum(lorem, dolor = 1) {
 8 |   // !mark(1:2) gold
 9 |   const sit = lorem == null ? 0 : lorem.sit
10 |   dolor = sit - amet(dolor)
11 |   // !mark[/sit/] pink
12 |   return sit ? consectetur(lorem) : []
13 | }
14 | ```
15 | 


--------------------------------------------------------------------------------
/apps/web/demos/mark/page.tsx:
--------------------------------------------------------------------------------
 1 | import {
 2 |   RawCode,
 3 |   Pre,
 4 |   highlight,
 5 |   AnnotationHandler,
 6 |   InnerLine,
 7 | } from "codehike/code"
 8 | import Content from "./content.md"
 9 | 
10 | export default function Page() {
11 |   return 
12 | }
13 | 
14 | const mark: AnnotationHandler = {
15 |   name: "mark",
16 |   Line: ({ annotation, ...props }) => {
17 |     const color = annotation?.query || "rgb(14 165 233)"
18 |     return (
19 |       
27 | 28 |
29 | ) 30 | }, 31 | Inline: ({ annotation, children }) => { 32 | const color = annotation?.query || "rgb(14 165 233)" 33 | return ( 34 | 41 | {children} 42 | 43 | ) 44 | }, 45 | } 46 | 47 | async function Code({ codeblock }: { codeblock: RawCode }) { 48 | const highlighted = await highlight(codeblock, "github-dark") 49 | return ( 50 |
55 |   )
56 | }
57 | 


--------------------------------------------------------------------------------
/apps/web/demos/occurrences/code.tsx:
--------------------------------------------------------------------------------
 1 | "use client"
 2 | 
 3 | import { HighlightedCode, Pre } from "codehike/code"
 4 | import React from "react"
 5 | 
 6 | export function CodeWithOccurrences({ code }: { code: HighlightedCode }) {
 7 |   const ref = React.useRef(null)
 8 |   React.useEffect(() => {
 9 |     const handler: EventListener = (e) => {
10 |       const selected = document.getSelection()!.toString().trim()
11 |       ref.current!.querySelectorAll("span:not(:has(*))").forEach((element) => {
12 |         if (element.textContent === selected) {
13 |           element.setAttribute("data-selected", "true")
14 |         } else {
15 |           element.removeAttribute("data-selected")
16 |         }
17 |       })
18 |     }
19 |     document.addEventListener("selectionchange", handler)
20 |     return () => {
21 |       document.removeEventListener("selectionchange", handler)
22 |     }
23 |   }, [])
24 | 
25 |   return (
26 |     
31 |   )
32 | }
33 | 
34 | // const Token: TokenComponent = ({ value, lineNumber, ...props }) => {
35 | //   return (
36 | //     
40 | //       {value}
41 | //     
42 | //   )
43 | // }
44 | 


--------------------------------------------------------------------------------
/apps/web/demos/occurrences/content.md:
--------------------------------------------------------------------------------
 1 | ## Lorem Ipsum
 2 | 
 3 | One thing I miss while reading code on websites is the ability to highlight all occurrences of a particular piece of code.
 4 | 
 5 | This works similar to a code editor, you can select a token and all occurrences of that token will be highlighted.
 6 | 
 7 | ```js
 8 | function foo(ipsum, dolor = 1) {
 9 |   const sit = ipsum == null ? 0 : ipsum.sit
10 | "use client"
11 | 
12 | import { useState } from "react"
13 | import { Carousel } from "acme-carousel"
14 | 
15 | export default function Gallery() {
16 |   let [isOpen, setIsOpen] = useState(false)
17 | 
18 |   return (
19 |     
20 | 21 | {isOpen && } 22 |
23 | ) 24 | } 25 | ``` 26 | 27 | It also works if you selecte a word from a paragraph, try: button or `Carousel`. 28 | -------------------------------------------------------------------------------- /apps/web/demos/occurrences/page.tsx: -------------------------------------------------------------------------------- 1 | import { RawCode, Pre, highlight } from "codehike/code" 2 | import Content from "./content.md" 3 | import { CodeWithOccurrences } from "./code" 4 | 5 | export default function Page() { 6 | return 7 | } 8 | 9 | async function Code({ codeblock }: { codeblock: RawCode }) { 10 | const info = await highlight(codeblock, "github-dark") 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /apps/web/demos/scrollycoding/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false, 4 | "overrides": [ 5 | { 6 | "files": ["*.md"], 7 | "options": { 8 | "printWidth": 42, 9 | "semi": false 10 | } 11 | }, 12 | { 13 | "files": ["*.tsx"], 14 | "options": { 15 | "printWidth": 60, 16 | "semi": false 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/demos/slideshow/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": false, 4 | "overrides": [ 5 | { 6 | "files": ["*.md"], 7 | "options": { 8 | "printWidth": 42, 9 | "semi": false 10 | } 11 | }, 12 | { 13 | "files": ["*.tsx"], 14 | "options": { 15 | "printWidth": 60, 16 | "semi": false 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/demos/slideshow/content.md: -------------------------------------------------------------------------------- 1 | ## !!steps 2 | 3 | This is the first step. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 4 | 5 | ```js ! 6 | function lorem(ipsum) { 7 | const sit = ipsum == null ? 0 : 1 8 | dolor = sit - amet(dolor) 9 | return consectetur(ipsum) 10 | } 11 | ``` 12 | 13 | ## !!steps 14 | 15 | The second step, lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 16 | 17 | ```js ! 18 | function lorem(ipsum, dolor = 1) { 19 | const sit = ipsum == null ? 0 : 1 20 | dolor = sit - amet(dolor) 21 | return sit ? consectetur(ipsum) : [] 22 | } 23 | ``` 24 | 25 | ## !!steps 26 | 27 | And the third step, lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 28 | 29 | ```js ! 30 | function lorem(ipsum, dolor = 1) { 31 | const sit = ipsum == null ? 0 : 1 32 | dolor = sit - amet(dolor) 33 | if (dolor) { 34 | dolor += 100 35 | } 36 | return sit ? consectetur(ipsum) : [] 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /apps/web/demos/slideshow/controls.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { useSelectedIndex } from "codehike/utils/selection" 3 | 4 | export function Controls({ length }: { length: number }) { 5 | const [selectedIndex, setSelectedIndex] = 6 | useSelectedIndex() 7 | 8 | return ( 9 |
10 | 18 | {[...Array(length)].map((_, i) => ( 19 | 37 |
38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /apps/web/demos/slideshow/page.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Block, 3 | CodeBlock, 4 | parseRoot, 5 | } from "codehike/blocks" 6 | import Content from "./content.md" 7 | import { z } from "zod" 8 | import { 9 | Selection, 10 | SelectionProvider, 11 | } from "codehike/utils/selection" 12 | import { Pre, RawCode, highlight } from "codehike/code" 13 | import { Controls } from "./controls" 14 | import { tokenTransitions } from "@/components/annotations/token-transitions" 15 | 16 | const Schema = Block.extend({ 17 | steps: z.array(Block.extend({ code: CodeBlock })), 18 | }) 19 | 20 | export default function Page() { 21 | const { steps } = parseRoot(Content, Schema) 22 | return ( 23 | 24 | ( 26 | 27 | ))} 28 | /> 29 | 30 |
31 | step.children)} 33 | /> 34 |
35 |
36 | ) 37 | } 38 | 39 | async function Code({ codeblock }: { codeblock: RawCode }) { 40 | const highlighted = await highlight( 41 | codeblock, 42 | "github-dark", 43 | ) 44 | return ( 45 |
50 |   )
51 | }
52 | 


--------------------------------------------------------------------------------
/apps/web/demos/spotlight/.prettierrc:
--------------------------------------------------------------------------------
 1 | {
 2 |   "trailingComma": "all",
 3 |   "semi": false,
 4 |   "overrides": [
 5 |     {
 6 |       "files": ["*.md"],
 7 |       "options": {
 8 |         "printWidth": 42,
 9 |         "semi": false
10 |       }
11 |     },
12 |     {
13 |       "files": ["*.tsx"],
14 |       "options": {
15 |         "printWidth": 60,
16 |         "semi": false
17 |       }
18 |     }
19 |   ]
20 | }
21 | 


--------------------------------------------------------------------------------
/apps/web/demos/tabs/content.mdx:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | ```js !!tabs main.js
 4 | function lorem(ipsum, dolor = 1) {
 5 |   const sit = ipsum == null ? 0 : ipsum.sit
 6 |   dolor = sit - amet(dolor)
 7 |   return sit ? consectetur(ipsum) : []
 8 | }
 9 | ```
10 | 
11 | ```css !!tabs styles.css
12 | body {
13 |   margin: 0;
14 |   padding: 0;
15 | }
16 | ```
17 | 
18 | 
19 | 


--------------------------------------------------------------------------------
/apps/web/demos/tabs/page.tsx:
--------------------------------------------------------------------------------
 1 | import { Pre, RawCode, highlight } from "codehike/code"
 2 | import Content from "./content.mdx"
 3 | import { Block, CodeBlock, parseProps } from "codehike/blocks"
 4 | import { z } from "zod"
 5 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
 6 | 
 7 | export default async function Page() {
 8 |   return 
 9 | }
10 | 
11 | const Schema = Block.extend({ tabs: z.array(CodeBlock) })
12 | 
13 | async function CodeWithTabs(props: unknown) {
14 |   const { tabs } = parseProps(props, Schema)
15 |   return 
16 | }
17 | 
18 | export async function CodeTabs(props: { tabs: RawCode[] }) {
19 |   const { tabs } = props
20 |   const highlighted = await Promise.all(
21 |     tabs.map((tab) => highlight(tab, "github-dark")),
22 |   )
23 |   return (
24 |     
25 |       
26 |         {tabs.map((tab) => (
27 |           
28 |             {tab.meta}
29 |           
30 |         ))}
31 |       
32 |       {tabs.map((tab, i) => (
33 |         
34 |           
35 |         
36 |       ))}
37 |     
38 |   )
39 | }
40 | 


--------------------------------------------------------------------------------
/apps/web/demos/token-transitions/code.tsx:
--------------------------------------------------------------------------------
 1 | "use client"
 2 | 
 3 | import React from "react"
 4 | import { HighlightedCode } from "codehike/code"
 5 | import { Pre } from "codehike/code"
 6 | import { tokenTransitions } from "@/components/annotations/token-transitions"
 7 | 
 8 | export function CodeSwitcher({ infos }: { infos: HighlightedCode[] }) {
 9 |   const [index, setIndex] = React.useState(0)
10 |   const next = () => setIndex((index + 1) % infos.length)
11 | 
12 |   return (
13 |     <>
14 |       
15 |       
16 | 19 |
20 | 21 | ) 22 | } 23 | 24 | export function CodeClient(props: { highlighted: HighlightedCode }) { 25 | const { highlighted } = props 26 | return ( 27 |
32 |   )
33 | }
34 | 


--------------------------------------------------------------------------------
/apps/web/demos/token-transitions/content.md:
--------------------------------------------------------------------------------
 1 | ```scala
 2 | object Main {
 3 |   def factorial(n: Int): Int = {
 4 |     if (n == 0) {
 5 |       return 1
 6 |     } else {
 7 |       return n * factorial(n - 1)
 8 |     }
 9 |   }
10 | }
11 | ```
12 | 
13 | ```python
14 | def factorial(n):
15 |     if n == 0:
16 |         return 1
17 |     else:
18 |         return n * factorial(n - 1)
19 | ```
20 | 


--------------------------------------------------------------------------------
/apps/web/demos/token-transitions/content.mdx:
--------------------------------------------------------------------------------
 1 | ```scala !!
 2 | object Main {
 3 |   def factorial(n: Int): Int = {
 4 |     if (n == 0) {
 5 |       return 1
 6 |     } else {
 7 |       return n * factorial(n - 1)
 8 |     }
 9 |   }
10 | }
11 | ```
12 | 
13 | ```python !!
14 | def factorial(n):
15 |     if n == 0:
16 |         return 1
17 |     else:
18 |         return n * factorial(n - 1)
19 | ```
20 | 


--------------------------------------------------------------------------------
/apps/web/demos/token-transitions/page.tsx:
--------------------------------------------------------------------------------
 1 | import { highlight } from "codehike/code"
 2 | import Content from "./content.mdx"
 3 | import { CodeSwitcher } from "./code"
 4 | import { Block, CodeBlock, parseRoot } from "codehike/blocks"
 5 | import { z } from "zod"
 6 | 
 7 | export default async function Page() {
 8 |   const { code } = parseRoot(
 9 |     Content,
10 |     Block.extend({ code: z.array(CodeBlock) }),
11 |   )
12 | 
13 |   const infos = await Promise.all(
14 |     code.map((codeblock: any) => highlight(codeblock, "github-dark")),
15 |   )
16 |   return 
17 | }
18 | 


--------------------------------------------------------------------------------
/apps/web/demos/tooltip/content.mdx:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | ```js !code
 4 | // !tooltip[/lorem/] description
 5 | function lorem(ipsum, dolor = 1) {
 6 |   const sit = ipsum == null ? 0 : ipsum.sit
 7 |   dolor = sit - amet(dolor)
 8 |   // !tooltip[/consectetur/] inspect
 9 |   return sit ? consectetur(ipsum) : []
10 | }
11 | ```
12 | 
13 | ## !!tooltips description
14 | 
15 | ### Hello world
16 | 
17 | Lorem ipsum **dolor** sit amet `consectetur`.
18 | 
19 | Adipiscing elit _sed_ do eiusmod.
20 | 
21 | ## !!tooltips inspect
22 | 
23 | ```js
24 | function consectetur(ipsum) {
25 |   const { a, b } = ipsum
26 |   return a + b
27 | }
28 | ```
29 | 
30 | 
31 | 


--------------------------------------------------------------------------------
/apps/web/demos/transpile/content.md:
--------------------------------------------------------------------------------
 1 | ```ts
 2 | interface Greeter {
 3 |   greet(): string
 4 | }
 5 | 
 6 | function sayHello(greeter: Greeter) {
 7 |   console.log(greeter.greet())
 8 | }
 9 | ```
10 | 


--------------------------------------------------------------------------------
/apps/web/demos/transpile/page.tsx:
--------------------------------------------------------------------------------
 1 | import { RawCode } from "codehike/code"
 2 | 
 3 | import Content from "./content.md"
 4 | import ts from "typescript"
 5 | import { CodeTabs } from "../tabs/page"
 6 | 
 7 | export default function Page() {
 8 |   return 
 9 | }
10 | 
11 | async function Code({ codeblock }: { codeblock: RawCode }) {
12 |   // Since this is a RSC we can transpile stuff here
13 |   // (there are probably more efficient ways to do this)
14 |   const result = ts.transpileModule(codeblock.value, {
15 |     compilerOptions: {
16 |       module: ts.ModuleKind.CommonJS,
17 |       target: ts.ScriptTarget.ESNext,
18 |     },
19 |   })
20 | 
21 |   const tsCode = { ...codeblock, meta: "typescript" }
22 |   const jsCode = {
23 |     ...codeblock,
24 |     value: result.outputText,
25 |     lang: "js",
26 |     meta: "javascript",
27 |   }
28 | 
29 |   return 
30 | }
31 | 


--------------------------------------------------------------------------------
/apps/web/demos/twoslash/content.md:
--------------------------------------------------------------------------------
1 | ```ts
2 | const hi = "Hello"
3 | const msg = `${hi}, world`
4 | //    ^?
5 | 
6 | // @errors: 2588
7 | msg = 123
8 | ```
9 | 


--------------------------------------------------------------------------------
/apps/web/demos/word-wrap/content.md:
--------------------------------------------------------------------------------
 1 | ```js
 2 | function lorem(ipsum, dolor, sit) {
 3 |   ipsum.amet(
 4 |     { consectetur: [0, 1] },
 5 |     {
 6 |       adipiscing: elit.sed,
 7 |       eiusmod: "lorem ipsum dolor sit amet",
 8 |       sit,
 9 |     },
10 |   )
11 | }
12 | ```
13 | 


--------------------------------------------------------------------------------
/apps/web/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 | 
4 | export function cn(...inputs: ClassValue[]) {
5 |   return twMerge(clsx(inputs))
6 | }
7 | 


--------------------------------------------------------------------------------
/apps/web/mdx-components.tsx:
--------------------------------------------------------------------------------
 1 | import type { MDXComponents } from "mdx/types"
 2 | import defaultComponents from "next-docs-ui/mdx/default"
 3 | import { Code, InlineCode } from "./components/code"
 4 | 
 5 | export function useMDXComponents(components: MDXComponents): MDXComponents {
 6 |   return {
 7 |     ...defaultComponents,
 8 |     ...components,
 9 |     Code,
10 |     InlineCode,
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/apps/web/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |   plugins: {
3 |     tailwindcss: {},
4 |     autoprefixer: {},
5 |   },
6 | };
7 | 


--------------------------------------------------------------------------------
/apps/web/public/blog/build-time-components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/build-time-components.png


--------------------------------------------------------------------------------
/apps/web/public/blog/curse/nat.org.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/curse/nat.org.png


--------------------------------------------------------------------------------
/apps/web/public/blog/curse/tailwindcss.com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/curse/tailwindcss.com.png


--------------------------------------------------------------------------------
/apps/web/public/blog/fine-grained-markdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/fine-grained-markdown.png


--------------------------------------------------------------------------------
/apps/web/public/blog/remotion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/remotion.png


--------------------------------------------------------------------------------
/apps/web/public/blog/remotion/00.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/remotion/00.mp4


--------------------------------------------------------------------------------
/apps/web/public/blog/remotion/02.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/remotion/02.mp4


--------------------------------------------------------------------------------
/apps/web/public/blog/remotion/04.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/remotion/04.mp4


--------------------------------------------------------------------------------
/apps/web/public/blog/remotion/06.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/remotion/06.mp4


--------------------------------------------------------------------------------
/apps/web/public/blog/remotion/examples.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/remotion/examples.mp4


--------------------------------------------------------------------------------
/apps/web/public/blog/rich-content-websites.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/rich-content-websites.png


--------------------------------------------------------------------------------
/apps/web/public/blog/the-curse-of-markdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/the-curse-of-markdown.png


--------------------------------------------------------------------------------
/apps/web/public/blog/v1-migration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/v1-migration.png


--------------------------------------------------------------------------------
/apps/web/public/blog/v1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/blog/v1.png


--------------------------------------------------------------------------------
/apps/web/public/codehike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/codehike.png


--------------------------------------------------------------------------------
/apps/web/public/dark-grid.svg:
--------------------------------------------------------------------------------
1 | 
3 |   
4 | 
5 | 


--------------------------------------------------------------------------------
/apps/web/public/examples/docusaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/examples/docusaurus.png


--------------------------------------------------------------------------------
/apps/web/public/examples/fumadocs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/examples/fumadocs.png


--------------------------------------------------------------------------------
/apps/web/public/examples/nextra-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/examples/nextra-3.png


--------------------------------------------------------------------------------
/apps/web/public/examples/remotion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/examples/remotion.png


--------------------------------------------------------------------------------
/apps/web/public/examples/shopify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/examples/shopify.png


--------------------------------------------------------------------------------
/apps/web/public/examples/swiftui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/examples/swiftui.png


--------------------------------------------------------------------------------
/apps/web/public/grid.svg:
--------------------------------------------------------------------------------
1 | 
3 |   
4 | 
5 | 


--------------------------------------------------------------------------------
/apps/web/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-hike/codehike/43e599f7bafe2cc32a08dae0bc0c452ea714154f/apps/web/public/logo.png


--------------------------------------------------------------------------------
/apps/web/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "es5",
 4 |     "lib": ["dom", "dom.iterable", "esnext"],
 5 |     "allowJs": true,
 6 |     "skipLibCheck": true,
 7 |     "strict": true,
 8 |     "noEmit": true,
 9 |     "esModuleInterop": true,
10 |     "module": "esnext",
11 |     "moduleResolution": "bundler",
12 |     "resolveJsonModule": true,
13 |     "isolatedModules": true,
14 |     "jsx": "preserve",
15 |     "incremental": true,
16 |     "plugins": [
17 |       {
18 |         "name": "next"
19 |       }
20 |     ],
21 |     "paths": {
22 |       "@/*": ["./*"]
23 |     }
24 |   },
25 |   "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 |   "exclude": ["node_modules"]
27 | }
28 | 


--------------------------------------------------------------------------------
/apps/web/ui/dependency-terminal.tsx:
--------------------------------------------------------------------------------
 1 | import { CopyButton } from "@/components/copy-button"
 2 | import { TerminalSquare } from "lucide-react"
 3 | import { TabsContent, TabsList, TabsToggle } from "./tabs-toggle"
 4 | import { RawCode, Pre, highlight } from "codehike/code"
 5 | 
 6 | async function Code({ codeblock }: { codeblock: RawCode }) {
 7 |   const info = await highlight(codeblock, "github-dark")
 8 |   return 
 9 | }
10 | 
11 | export function DependencyTerminal({ codeblock }: { codeblock: RawCode }) {
12 |   const options = ["npm install", "yarn add", "pnpm install"].map(
13 |     (command) => ({
14 |       name: command.split(" ")[0],
15 |       content: (
16 |         
23 |       ),
24 |     }),
25 |   )
26 | 
27 |   return (
28 |     
32 |       
33 | 34 | Terminal 35 | 36 | 37 | 38 |
39 | 40 | 41 |
42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /apps/web/ui/tabs-toggle.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { ToggleGroup, ToggleGroupItem } from "./toggle-group" 3 | 4 | import React from "react" 5 | 6 | const TabsContext = React.createContext({ 7 | selectedIndex: 0, 8 | setSelectedIndex: () => {}, 9 | options: [], 10 | }) 11 | 12 | export function TabsToggle({ children, className, options }: any) { 13 | const [selectedIndex, setSelectedIndex] = React.useState(0) 14 | return ( 15 | 16 |
{children}
17 |
18 | ) 19 | } 20 | 21 | export function TabsList({ className }: any) { 22 | const { selectedIndex, setSelectedIndex, options } = 23 | React.useContext(TabsContext) 24 | return ( 25 | { 30 | console.log(value) 31 | setSelectedIndex(Number(value)) 32 | }} 33 | value={String(selectedIndex)} 34 | > 35 | {options.map((option: any, i: number) => ( 36 | 42 | {option.name} 43 | 44 | ))} 45 | 46 | ) 47 | } 48 | 49 | export function TabsContent({ className }: any) { 50 | const { selectedIndex, options } = React.useContext(TabsContext) 51 | const option = options[selectedIndex] 52 | return
{option.content}
53 | } 54 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Code Hike 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "turbo build --filter=codehike...", 5 | "web": "turbo dev --filter=web --filter=codehike... ", 6 | "test": "turbo test", 7 | "clean": "turbo clean && rm -rf node_modules", 8 | "format": "prettier --write \"**/*.{ts,tsx,md,mdx}\"", 9 | "changeset": "changeset", 10 | "version-packages": "changeset version", 11 | "release": "changeset publish", 12 | "canary": "pkg-pr-new publish --json=canary.json --comment=off --compact './packages/codehike'" 13 | }, 14 | "devDependencies": { 15 | "@changesets/read": "0.6.1", 16 | "@changesets/cli": "2.27.1", 17 | "@changesets/changelog-github": "0.5.0", 18 | "@octokit/action": "7.0.0", 19 | "@octokit/rest": "21.0.2", 20 | "@actions/exec": "1.1.1", 21 | "@actions/github": "6.0.0", 22 | "prettier": "^3.1.1", 23 | "turbo": "^1.11.2", 24 | "pkg-pr-new": "0.0.24", 25 | "human-id": "4.1.1", 26 | "unified": "11.0.5", 27 | "remark-parse": "11.0.0", 28 | "remark-stringify": "11.0.0", 29 | "mdast-util-to-string": "4.0.0" 30 | }, 31 | "packageManager": "pnpm@9.7.1", 32 | "repository": "code-hike/codehike", 33 | "homepage": "https://codehike.org", 34 | "funding": { 35 | "type": "github", 36 | "url": "https://github.com/sponsors/code-hike" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/codehike/readme.md: -------------------------------------------------------------------------------- 1 | # Code Hike 2 | 3 | Build rich content websites with Markdown and React 4 | 5 | ## Quick Start 6 | 7 | Try it online on [StackBlitz](https://stackblitz.com/github/code-hike/v1-starter?file=app%2Fpage.mdx). Or clone the Code Hike starter: 8 | 9 | ```bash 10 | npx create-next-app -e https://github.com/code-hike/v1-starter 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [https://codehike.org/docs](https://codehike.org/docs) 16 | -------------------------------------------------------------------------------- /packages/codehike/src/code.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | Token, 3 | RawCode, 4 | HighlightedCode, 5 | CodeAnnotation, 6 | Theme, 7 | InlineAnnotation, 8 | BlockAnnotation, 9 | InlineAnnotationComponent, 10 | BlockAnnotationComponent, 11 | AnnotationHandler, 12 | CustomPreProps, 13 | CustomPre, 14 | CustomLine, 15 | CustomLineWithAnnotation, 16 | CustomToken, 17 | CustomTokenWithAnnotation, 18 | InlineProps, 19 | } from "./code/types.js" 20 | 21 | import { highlight } from "./code/highlight.js" 22 | import { Pre, Inline } from "./code/pre.js" 23 | import { InnerPre, getPreRef, InnerLine, InnerToken } from "./code/inner.js" 24 | 25 | export type { 26 | RawCode, 27 | HighlightedCode, 28 | Token, 29 | InlineAnnotation, 30 | BlockAnnotation, 31 | CodeAnnotation, 32 | // AnnotationHandler: 33 | AnnotationHandler, 34 | InlineProps, 35 | CustomPre, 36 | CustomPreProps, 37 | BlockAnnotationComponent, 38 | CustomLine, 39 | CustomLineWithAnnotation, 40 | InlineAnnotationComponent, 41 | CustomToken, 42 | CustomTokenWithAnnotation, 43 | Theme, 44 | } 45 | 46 | export { highlight, Pre, InnerPre, InnerLine, InnerToken, getPreRef, Inline } 47 | -------------------------------------------------------------------------------- /packages/codehike/src/code/pre-ref.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useRef } from "react" 4 | import { InnerPre } from "./inner.js" 5 | import { CustomPre } from "./types.js" 6 | 7 | export const AddRefIfNedded: CustomPre = (props: any) => { 8 | const innerRef = useRef(null) 9 | const ref = props._ref || innerRef 10 | // @ts-ignore 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /packages/codehike/src/index.ts: -------------------------------------------------------------------------------- 1 | import { MDXProps } from "mdx/types.js" 2 | 3 | type MDXContent = (props: MDXProps) => JSX.Element 4 | 5 | export function parse(Content: MDXContent, props: MDXProps = {}) { 6 | return Content({ _returnBlocks: true, ...props }) as any 7 | } 8 | -------------------------------------------------------------------------------- /packages/codehike/src/mdx.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from "unified" 2 | // this adds the jsx node types to Root 3 | import "mdast-util-mdx-jsx" 4 | import { Root } from "mdast" 5 | 6 | import { transformImportedCode } from "./mdx/0.import-code-from-path.js" 7 | import { transformAllHikes } from "./mdx/1.0.transform-hikes.js" 8 | import { transformAllCode } from "./mdx/2.transform-code.js" 9 | import { transformHikeProps } from "./mdx/3.transform-hike-props.js" 10 | import { CodeHikeConfig } from "./mdx/config.js" 11 | 12 | export type { CodeHikeConfig } 13 | 14 | export const remarkCodeHike: Plugin<[CodeHikeConfig?], Root, Root> = ( 15 | config, 16 | ) => { 17 | const safeConfig = config || {} 18 | return async (root, file) => { 19 | let tree = await transformImportedCode(root, file) 20 | tree = await transformAllHikes(tree, safeConfig) 21 | tree = await transformAllCode(tree, safeConfig) 22 | return tree 23 | } 24 | } 25 | 26 | export const recmaCodeHike: Plugin<[CodeHikeConfig?], Root, Root> = ( 27 | config, 28 | ) => { 29 | return async (root) => { 30 | let tree = transformHikeProps(root) as any 31 | return tree as any 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/codehike/src/mdx/1.0.transform-hikes.ts: -------------------------------------------------------------------------------- 1 | import { Root } from "mdast" 2 | import { MdxJsxFlowElement } from "mdast-util-mdx-jsx" 3 | import { visit } from "unist-util-visit" 4 | import { isHikeElement, listToSection } from "./1.1.remark-list-to-section.js" 5 | import { sectionToAttribute } from "./1.2.remark-section-to-attribute.js" 6 | import { CodeHikeConfig } from "./config.js" 7 | 8 | export async function transformAllHikes(root: Root, config: CodeHikeConfig) { 9 | let tree = wrapInHike(root) 10 | 11 | const hikes: MdxJsxFlowElement[] = [] 12 | 13 | visit(tree, "mdxJsxFlowElement", (node) => { 14 | if (node.children?.some(isHikeElement)) { 15 | hikes.push(node) 16 | } 17 | }) 18 | 19 | await Promise.all(hikes.map((h) => transformRemarkHike(h, config))) 20 | 21 | return tree 22 | } 23 | 24 | function wrapInHike(root: Root) { 25 | // if we find any hikeable element outside of s, 26 | // let's wrap everything in a 27 | if (root.children?.some(isHikeElement)) { 28 | root.children = [ 29 | { 30 | type: "mdxJsxFlowElement", 31 | name: "slot", 32 | attributes: [], 33 | // todo what is different between RootContent and (BlockContent | DefinitionContent) 34 | children: root.children as any, 35 | }, 36 | ] 37 | } 38 | return root 39 | } 40 | 41 | async function transformRemarkHike( 42 | node: MdxJsxFlowElement, 43 | config: CodeHikeConfig, 44 | ) { 45 | const section = await listToSection(node, config) 46 | const { children, attributes } = sectionToAttribute(section) 47 | 48 | node.children = children 49 | node.attributes.push(...attributes) 50 | 51 | return node 52 | } 53 | -------------------------------------------------------------------------------- /packages/codehike/src/mdx/config.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from "@code-hike/lighter" 2 | import { RawCode } from "../code/types.js" 3 | 4 | /** 5 | * Code Hike configuration object 6 | * @see [configuration documentation](https://codehike.org/docs) 7 | */ 8 | export type CodeHikeConfig = { 9 | components?: { 10 | code?: string 11 | inlineCode?: string 12 | } 13 | ignoreCode?: (codeblock: RawCode) => boolean 14 | syntaxHighlighting?: { 15 | theme?: Theme 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/_readme.md: -------------------------------------------------------------------------------- 1 | # MD Test Suite 2 | 3 | All the `*.0.mdx` files in this directory are tests 4 | 5 | Add the snapshots you are interested in testing to the `snapshots` array in the frontmatter of the mdx file: 6 | 7 | ```md 8 | --- 9 | syntaxHighlight: github-light 10 | snapshots: 11 | - before-remark 12 | - after-remark 13 | - after-rehype 14 | - before-recma-compiled-js 15 | - before-recma-compiled-jsx 16 | - before-recma-compiled-function 17 | - before-recma-js 18 | - before-recma-js-dev 19 | - before-recma-jsx 20 | - after-recma-js 21 | - after-recma-js-dev 22 | - after-recma-jsx 23 | - compiled-js 24 | - compiled-js-dev 25 | - compiled-jsx 26 | - compiled-function 27 | - parsed-jsx 28 | - rendered 29 | - rendered-dev 30 | --- 31 | ``` 32 | 33 | ## Errors 34 | 35 | If there are errors in the test, it will be snapshoted in the `testname.1.error.md` file 36 | 37 | ## Running only one test: 38 | 39 | filter by test name: `pnpm watch -t foo` and then `r` to rerun the current test 40 | 41 | ## TODO 42 | 43 | - rerun tests when md file changes 44 | - remove carriage returns from snapshots 45 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/annotation.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | ```js 7 | // !mark 8 | const a = 1 9 | const b = 2 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/annotation.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { 3 | AnnotationHandler, 4 | highlight, 5 | InnerPre, 6 | Pre, 7 | RawCode, 8 | } from "../../src/code" 9 | import React from "react" 10 | 11 | export function render(Content: MDXContent) { 12 | // @ts-ignore 13 | return 14 | } 15 | 16 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 17 | const highlighted = await highlight(codeblock, "github-dark") 18 | return
19 | }
20 | 
21 | const mark: AnnotationHandler = {
22 |   name: "mark",
23 |   Pre: (props) => ,
24 |   Block: ({ children }) => {children},
25 | }
26 | 


--------------------------------------------------------------------------------
/packages/codehike/tests/md-suite/annotation.9.rendered.html:
--------------------------------------------------------------------------------
1 | 
const a = 1 8 |
const b = 2
9 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/assets/test.py: -------------------------------------------------------------------------------- 1 | # !mark inside 2 | import random 3 | my_list = [] -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - before-remark 4 | - after-remark 5 | - after-rehype 6 | - before-recma-compiled-js 7 | - before-recma-compiled-jsx 8 | - before-recma-compiled-function 9 | - before-recma-js 10 | - before-recma-js-dev 11 | - before-recma-jsx 12 | - after-recma-js 13 | - after-recma-js-dev 14 | - after-recma-jsx 15 | - compiled-js 16 | - compiled-js-dev 17 | - compiled-jsx 18 | - compiled-function 19 | - parsed-jsx 20 | - rendered 21 | - rendered-dev 22 | --- 23 | 24 | # Lorem 25 | 26 | !hello world 27 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.2.before-remark.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "root", 3 | "children": [ 4 | { 5 | "type": "heading", 6 | "depth": 1, 7 | "children": [{ "type": "text", "value": "Lorem" }] 8 | }, 9 | { 10 | "type": "paragraph", 11 | "children": [{ "type": "text", "value": "!hello world" }] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.5.before-recma-compiled-function.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | "use strict" 3 | function _createMdxContent(props) { 4 | const _components = { 5 | h1: "h1", 6 | slot: "slot", 7 | ...props.components, 8 | } 9 | return ( 10 | <_components.slot 11 | __hike={{ 12 | children: "", 13 | title: "", 14 | _data: { 15 | header: "", 16 | }, 17 | hello: "world", 18 | }} 19 | > 20 | <_components.slot path=""> 21 | <_components.h1>{"Lorem"} 22 | 23 | 24 | ) 25 | } 26 | function MDXContent(props = {}) { 27 | const { wrapper: MDXLayout } = props.components || {} 28 | return MDXLayout ? ( 29 | 30 | <_createMdxContent {...props} /> 31 | 32 | ) : ( 33 | _createMdxContent(props) 34 | ) 35 | } 36 | return { 37 | default: MDXContent, 38 | } 39 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.5.before-recma-compiled-js.js: -------------------------------------------------------------------------------- 1 | import { jsx as _jsx } from "react/jsx-runtime" 2 | function _createMdxContent(props) { 3 | const _components = { 4 | h1: "h1", 5 | slot: "slot", 6 | ...props.components, 7 | } 8 | return _jsx(_components.slot, { 9 | __hike: { 10 | children: "", 11 | title: "", 12 | _data: { 13 | header: "", 14 | }, 15 | hello: "world", 16 | }, 17 | children: _jsx(_components.slot, { 18 | path: "", 19 | children: _jsx(_components.h1, { 20 | children: "Lorem", 21 | }), 22 | }), 23 | }) 24 | } 25 | export default function MDXContent(props = {}) { 26 | const { wrapper: MDXLayout } = props.components || {} 27 | return MDXLayout 28 | ? _jsx(MDXLayout, { 29 | ...props, 30 | children: _jsx(_createMdxContent, { 31 | ...props, 32 | }), 33 | }) 34 | : _createMdxContent(props) 35 | } 36 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.5.before-recma-compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | function _createMdxContent(props) { 3 | const _components = { 4 | h1: "h1", 5 | slot: "slot", 6 | ...props.components, 7 | } 8 | return ( 9 | <_components.slot 10 | __hike={{ 11 | children: "", 12 | title: "", 13 | _data: { 14 | header: "", 15 | }, 16 | hello: "world", 17 | }} 18 | > 19 | <_components.slot path=""> 20 | <_components.h1>{"Lorem"} 21 | 22 | 23 | ) 24 | } 25 | export default function MDXContent(props = {}) { 26 | const { wrapper: MDXLayout } = props.components || {} 27 | return MDXLayout ? ( 28 | 29 | <_createMdxContent {...props} /> 30 | 31 | ) : ( 32 | _createMdxContent(props) 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.7.compiled-function.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | "use strict" 3 | function _createMdxContent(props) { 4 | const _components = { 5 | h1: "h1", 6 | slot: "slot", 7 | ...props.components, 8 | } 9 | const _blocks = { 10 | children: <_components.h1>{"Lorem"}, 11 | title: "", 12 | _data: { 13 | header: "", 14 | }, 15 | hello: "world", 16 | } 17 | if (props._returnBlocks) { 18 | return _blocks 19 | } 20 | return _blocks.children 21 | } 22 | function MDXContent(props = {}) { 23 | const { wrapper: MDXLayout } = props.components || {} 24 | return MDXLayout ? ( 25 | 26 | <_createMdxContent {...props} /> 27 | 28 | ) : ( 29 | _createMdxContent(props) 30 | ) 31 | } 32 | return { 33 | default: MDXContent, 34 | } 35 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.7.compiled-js.js: -------------------------------------------------------------------------------- 1 | import { jsx as _jsx } from "react/jsx-runtime" 2 | function _createMdxContent(props) { 3 | const _components = { 4 | h1: "h1", 5 | slot: "slot", 6 | ...props.components, 7 | } 8 | const _blocks = { 9 | children: _jsx(_components.h1, { 10 | children: "Lorem", 11 | }), 12 | title: "", 13 | _data: { 14 | header: "", 15 | }, 16 | hello: "world", 17 | } 18 | if (props._returnBlocks) { 19 | return _blocks 20 | } 21 | return _blocks.children 22 | } 23 | export default function MDXContent(props = {}) { 24 | const { wrapper: MDXLayout } = props.components || {} 25 | return MDXLayout 26 | ? _jsx(MDXLayout, { 27 | ...props, 28 | children: _jsx(_createMdxContent, { 29 | ...props, 30 | }), 31 | }) 32 | : _createMdxContent(props) 33 | } 34 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | function _createMdxContent(props) { 3 | const _components = { 4 | h1: "h1", 5 | slot: "slot", 6 | ...props.components, 7 | } 8 | const _blocks = { 9 | children: <_components.h1>{"Lorem"}, 10 | title: "", 11 | _data: { 12 | header: "", 13 | }, 14 | hello: "world", 15 | } 16 | if (props._returnBlocks) { 17 | return _blocks 18 | } 19 | return _blocks.children 20 | } 21 | export default function MDXContent(props = {}) { 22 | const { wrapper: MDXLayout } = props.components || {} 23 | return MDXLayout ? ( 24 | 25 | <_createMdxContent {...props} /> 26 | 27 | ) : ( 28 | _createMdxContent(props) 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.8.parsed-jsx.jsx: -------------------------------------------------------------------------------- 1 | var block = { 2 | "_data": { 3 | "header": "", 4 | }, 5 | "children":

6 | Lorem 7 |

, 8 | "hello": "world", 9 | "title": "", 10 | } -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.9.rendered-dev.html: -------------------------------------------------------------------------------- 1 |

Lorem

2 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/basic.9.rendered.html: -------------------------------------------------------------------------------- 1 |

Lorem

2 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/code-empty.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | - rendered 5 | --- 6 | 7 | {/* prettier-ignore */} 8 | ``` 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/code-empty.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | /*prettier-ignore*/ 3 | function _createMdxContent(props) { 4 | const {MyCode} = props.components || ({}); 5 | if (!MyCode) _missingMdxReference("MyCode", true); 6 | return <>{}{"\n"}; 11 | } 12 | export default function MDXContent(props = {}) { 13 | const { wrapper: MDXLayout } = props.components || {} 14 | return MDXLayout ? ( 15 | 16 | <_createMdxContent {...props} /> 17 | 18 | ) : ( 19 | _createMdxContent(props) 20 | ) 21 | } 22 | function _missingMdxReference(id, component) { 23 | throw new Error( 24 | "Expected " + 25 | (component ? "component" : "object") + 26 | " `" + 27 | id + 28 | "` to be defined: you likely forgot to import, pass, or provide it.", 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/code-empty.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/code.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | - rendered 5 | --- 6 | 7 | ```js 8 | console.log(1) 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/code.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | function _createMdxContent(props) { 3 | const { MyCode } = props.components || {} 4 | if (!MyCode) _missingMdxReference("MyCode", true) 5 | return ( 6 | 13 | ) 14 | } 15 | export default function MDXContent(props = {}) { 16 | const { wrapper: MDXLayout } = props.components || {} 17 | return MDXLayout ? ( 18 | 19 | <_createMdxContent {...props} /> 20 | 21 | ) : ( 22 | _createMdxContent(props) 23 | ) 24 | } 25 | function _missingMdxReference(id, component) { 26 | throw new Error( 27 | "Expected " + 28 | (component ? "component" : "object") + 29 | " `" + 30 | id + 31 | "` to be defined: you likely forgot to import, pass, or provide it.", 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/code.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | console. 4 | log 5 | ( 6 | 1 7 | ) 8 |
9 |
10 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-block.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - parsed-jsx 4 | --- 5 | 6 | hello 7 | 8 | # !foo hey 9 | 10 | # / 11 | 12 | hey 13 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-block.8.parsed-jsx.jsx: -------------------------------------------------------------------------------- 1 | var block = { 2 | "_data": { 3 | "header": "", 4 | }, 5 | "children": 6 |

7 | hello 8 |

9 |

10 | hey 11 |

12 |
, 13 | "foo": { 14 | "_data": { 15 | "header": "# !foo hey", 16 | }, 17 | "children": , 18 | "title": "hey", 19 | }, 20 | "title": "", 21 | } -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-children-and-import.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | --- 5 | 6 | import { x } from "@/components/code/code-with-notes" 7 | 8 | ## !demo 9 | 10 | Add callouts inside your code blocks. 11 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-children-and-import.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | import { x } from "@/components/code/code-with-notes" 3 | function _createMdxContent(props) { 4 | const _components = { 5 | p: "p", 6 | slot: "slot", 7 | ...props.components, 8 | } 9 | const _blocks = { 10 | children: undefined, 11 | title: "", 12 | _data: { 13 | header: "", 14 | }, 15 | demo: { 16 | children: ( 17 | <_components.p>{"Add callouts inside your code blocks."} 18 | ), 19 | title: "", 20 | _data: { 21 | header: "## !demo", 22 | }, 23 | }, 24 | } 25 | if (props._returnBlocks) { 26 | return _blocks 27 | } 28 | return _blocks.children 29 | } 30 | export default function MDXContent(props = {}) { 31 | const { wrapper: MDXLayout } = props.components || {} 32 | return MDXLayout ? ( 33 | 34 | <_createMdxContent {...props} /> 35 | 36 | ) : ( 37 | _createMdxContent(props) 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-line.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | - rendered 5 | --- 6 | 7 | {/* prettier-ignore */} 8 | ```js 9 | 10 | // !m 343 11 | const a = 1 12 | const b = 2 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-line.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | /*prettier-ignore*/ 3 | function _createMdxContent(props) { 4 | const {MyCode} = props.components || ({}); 5 | if (!MyCode) _missingMdxReference("MyCode", true); 6 | return <>{}{"\n"}; 11 | } 12 | export default function MDXContent(props = {}) { 13 | const { wrapper: MDXLayout } = props.components || {} 14 | return MDXLayout ? ( 15 | 16 | <_createMdxContent {...props} /> 17 | 18 | ) : ( 19 | _createMdxContent(props) 20 | ) 21 | } 22 | function _missingMdxReference(id, component) { 23 | throw new Error( 24 | "Expected " + 25 | (component ? "component" : "object") + 26 | " `" + 27 | id + 28 | "` to be defined: you likely forgot to import, pass, or provide it.", 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/empty-line.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | const 5 | a 6 | = 7 | 1 8 |
9 |
10 | const 11 | b 12 | = 13 | 2 14 |
15 |
16 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/ignore-codeblock.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | --- 5 | 6 | hey 7 | 8 | ```mermaid foo 9 | graph TD; 10 | A-->B; 11 | A-->C; 12 | B-->D; 13 | C-->D; 14 | ``` 15 | 16 | ```js index.js 17 | console.log(2) 18 | ``` 19 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/ignore-codeblock.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | function _createMdxContent(props) { 3 | const _components = { 4 | code: "code", 5 | p: "p", 6 | pre: "pre", 7 | ...props.components, 8 | }, 9 | { MyCode } = _components 10 | if (!MyCode) _missingMdxReference("MyCode", true) 11 | return ( 12 | <> 13 | <_components.p>{"hey"} 14 | {"\n"} 15 | <_components.pre> 16 | <_components.code className="language-mermaid"> 17 | { 18 | "graph TD;\r\n A-->B;\r\n A-->C;\r\n B-->D;\r\n C-->D;\n" 19 | } 20 | 21 | 22 | {"\n"} 23 | 30 | 31 | ) 32 | } 33 | export default function MDXContent(props = {}) { 34 | const { wrapper: MDXLayout } = props.components || {} 35 | return MDXLayout ? ( 36 | 37 | <_createMdxContent {...props} /> 38 | 39 | ) : ( 40 | _createMdxContent(props) 41 | ) 42 | } 43 | function _missingMdxReference(id, component) { 44 | throw new Error( 45 | "Expected " + 46 | (component ? "component" : "object") + 47 | " `" + 48 | id + 49 | "` to be defined: you likely forgot to import, pass, or provide it.", 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/import-code.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | - rendered 5 | --- 6 | 7 | hello 8 | 9 | ```py 10 | !from ./assets/test.py 11 | ``` 12 | 13 | ```py ! 14 | !from ./assets/test.py 15 | ``` 16 | 17 | ```py 18 | # !mark(2) bar 19 | !from ./assets/test.py 20 | 21 | def hello(): 22 | print("hello") 23 | 24 | !from ./assets/test.py 25 | ``` 26 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/import-code.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { AnnotationHandler, highlight, Pre, RawCode } from "../../src/code" 3 | import React from "react" 4 | 5 | export function render(Content: MDXContent) { 6 | // @ts-ignore 7 | return 8 | } 9 | 10 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 11 | const highlighted = await highlight(codeblock, "github-dark") 12 | return
13 | }
14 | 
15 | const mark: AnnotationHandler = {
16 |   name: "mark",
17 |   Pre: ({ _stack, ...props }) => 
, 18 | Block: ({ children, annotation }) => ( 19 | {children} 20 | ), 21 | } 22 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/indentation.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | {/* prettier-ignore */} 7 | ```js 8 | if (true) 9 | return 3 10 | ``` 11 | 12 | {/* prettier-ignore */} 13 | ```py 14 | if True: 15 | return 1 16 | return 2 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/indentation.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { 3 | AnnotationHandler, 4 | highlight, 5 | InnerLine, 6 | Pre, 7 | RawCode, 8 | } from "../../src/code" 9 | import React from "react" 10 | 11 | export function render(Content: MDXContent) { 12 | // @ts-ignore 13 | return 14 | } 15 | 16 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 17 | const highlighted = await highlight(codeblock, "github-dark") 18 | return
19 | }
20 | 
21 | const line: AnnotationHandler = {
22 |   name: "line",
23 |   Pre: ({ _stack, ...props }) => 
, 24 | Line: (props) => , 25 | } 26 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/indentation.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | if 4 | ( 5 | true 6 | ) 7 |
8 |
9 | return 10 | 3 11 |
12 |
13 | 14 |
15 |
16 | if 17 | True 18 | : 19 |
20 |
21 | return 22 | 1 23 |
24 |
25 | return 26 | 2 27 |
28 |
29 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/inline-code-highlighted.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | syntaxHighlight: github-dark 3 | snapshots: 4 | - before-remark 5 | - compiled-jsx 6 | - rendered 7 | --- 8 | 9 | _`var x = 1`_ 10 | 11 | hello _html`
hey
`_ world 12 | 13 | two lines _`var x = 1 14 | var y = 2`_ 15 | 16 | extra meta _jsx foo`var x = 1`bar bar_ 17 | 18 | lorem _just emphasize_ ipsum 19 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/inline-code.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - before-remark 4 | - compiled-jsx 5 | - rendered 6 | --- 7 | 8 | _`var x = 1`_ 9 | 10 | hello _html`
hey
`_ world 11 | 12 | two lines _`var x = 1 13 | var y = 2`_ 14 | 15 | extra meta _jsx foo`var x = 1`bar bar_ 16 | 17 | lorem _just emphasize_ ipsum 18 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/nested-blocks.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - parsed-jsx 4 | --- 5 | 6 | hello 7 | 8 | # !one uno 9 | 10 | 1 11 | 12 | ## !!foo 111 13 | 14 | 1.1 15 | 16 | ### !bar b 17 | 18 | 1.1.1 19 | 20 | ### / 21 | 22 | more 23 | 24 | ## !!foo 222 25 | 26 | hey 27 | 28 | ## / 29 | 30 | ho 31 | 32 | ## !extra 33 | 34 | extra 35 | 36 | # / 37 | 38 | hey 39 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/nested-blocks.8.parsed-jsx.jsx: -------------------------------------------------------------------------------- 1 | var block = { 2 | "_data": { 3 | "header": "", 4 | }, 5 | "children": 6 |

7 | hello 8 |

9 |

10 | hey 11 |

12 |
, 13 | "one": { 14 | "_data": { 15 | "header": "# !one uno", 16 | }, 17 | "children": 18 |

19 | 1 20 |

21 |

22 | ho 23 |

24 |
, 25 | "extra": { 26 | "_data": { 27 | "header": "## !extra", 28 | }, 29 | "children":

30 | extra 31 |

, 32 | "title": "", 33 | }, 34 | "foo": [ 35 | { 36 | "_data": { 37 | "header": "## !!foo 111", 38 | }, 39 | "bar": { 40 | "_data": { 41 | "header": "### !bar b", 42 | }, 43 | "children":

44 | 1.1.1 45 |

, 46 | "title": "b", 47 | }, 48 | "children": 49 |

50 | 1.1 51 |

52 |

53 | more 54 |

55 |
, 56 | "title": "111", 57 | }, 58 | { 59 | "_data": { 60 | "header": "## !!foo 222", 61 | }, 62 | "children":

63 | hey 64 |

, 65 | "title": "222", 66 | }, 67 | ], 68 | "title": "uno", 69 | }, 70 | "title": "", 71 | } -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/no-hike.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - compiled-jsx 4 | --- 5 | 6 | ## Hello world 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/no-hike.7.compiled-jsx.jsx: -------------------------------------------------------------------------------- 1 | /*@jsxRuntime automatic @jsxImportSource react*/ 2 | function _createMdxContent(props) { 3 | const _components = { 4 | h2: "h2", 5 | ...props.components, 6 | } 7 | return ( 8 | <> 9 | <_components.h2>{"Hello world"} 10 | {"\n"} 11 | 16 | 17 | ) 18 | } 19 | export default function MDXContent(props = {}) { 20 | const { wrapper: MDXLayout } = props.components || {} 21 | return MDXLayout ? ( 22 | 23 | <_createMdxContent {...props} /> 24 | 25 | ) : ( 26 | _createMdxContent(props) 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/only-if-annotated.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | ```js 7 | a 8 | // !mark 9 | b 10 | ``` 11 | 12 | ```js 13 | a 14 | b 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/only-if-annotated.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { 3 | AnnotationHandler, 4 | highlight, 5 | InnerLine, 6 | Pre, 7 | RawCode, 8 | } from "../../src/code" 9 | import React from "react" 10 | 11 | export function render(Content: MDXContent) { 12 | // @ts-ignore 13 | return 14 | } 15 | 16 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 17 | const highlighted = await highlight(codeblock, "github-dark") 18 | return
19 | }
20 | 
21 | const mark: AnnotationHandler = {
22 |   name: "mark",
23 |   onlyIfAnnotated: true,
24 |   Line: (props) => ,
25 | }
26 | 


--------------------------------------------------------------------------------
/packages/codehike/tests/md-suite/only-if-annotated.9.rendered.html:
--------------------------------------------------------------------------------
 1 | 
a 6 |
b
7 |
a 12 |
b
13 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/regex-range.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | ```jsx 7 | // !fold[/className="(.*?)"/gm] folded 8 | const Foo = () => ( 9 |
10 | hey 11 |
12 | ) 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/regex-range.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { 3 | AnnotationHandler, 4 | highlight, 5 | InnerToken, 6 | Pre, 7 | RawCode, 8 | } from "../../src/code" 9 | import React from "react" 10 | 11 | export function render(Content: MDXContent) { 12 | // @ts-ignore 13 | return 14 | } 15 | 16 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 17 | const highlighted = await highlight(codeblock, "github-dark") 18 | return
19 | }
20 | 
21 | const fold: AnnotationHandler = {
22 |   name: "fold",
23 |   Pre: ({ children }) => 
{children}
, 24 | Token: ({ annotation, ...props }) => ( 25 | 26 | 27 | 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/stacked-line.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | ```js 7 | const a = 1 8 | // !mark(1:3) 1 9 | const b = 2 10 | // !mark 2 11 | const c = 3 12 | ``` 13 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/stacked-line.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { 3 | AnnotationHandler, 4 | highlight, 5 | InnerLine, 6 | Pre, 7 | RawCode, 8 | } from "../../src/code" 9 | import React from "react" 10 | 11 | export function render(Content: MDXContent) { 12 | // @ts-ignore 13 | return 14 | } 15 | 16 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 17 | const highlighted = await highlight(codeblock, "github-dark") 18 | return
19 | }
20 | 
21 | const mark: AnnotationHandler = {
22 |   name: "mark",
23 |   Pre: ({ children }) => 
{children}
, 24 | Line: ({ annotation, ...props }) => ( 25 |
26 | 27 |
28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/stacked-line.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | const 5 | a 6 | = 7 | 1 8 |
9 |
10 |
11 |
12 | const 13 | b 14 | = 15 | 2 16 |
17 |
18 |
19 |
20 |
21 | const 22 | c 23 | = 24 | 3 25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/stacked-token.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | ```js 7 | const a = 1 8 | // !mark(1:3) 1 9 | const b = 2 10 | // !mark 2 11 | const c = 3 12 | ``` 13 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/stacked-token.0.render.tsx: -------------------------------------------------------------------------------- 1 | import { MDXContent } from "mdx/types" 2 | import { 3 | AnnotationHandler, 4 | highlight, 5 | InnerPre, 6 | InnerToken, 7 | Pre, 8 | RawCode, 9 | } from "../../src/code" 10 | import React from "react" 11 | 12 | export function render(Content: MDXContent) { 13 | // @ts-ignore 14 | return 15 | } 16 | 17 | async function MyCode({ codeblock }: { codeblock: RawCode }) { 18 | const highlighted = await highlight(codeblock, "github-dark") 19 | return
20 | }
21 | 
22 | const mark: AnnotationHandler = {
23 |   name: "mark",
24 |   Pre: ({ children }) => 
{children}
, 25 | Token: ({ annotation, ...props }) => ( 26 | 27 | 28 | 29 | ), 30 | } 31 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/stacked-token.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | const 4 | a 5 | = 6 | 1 7 |
8 |
9 | const 10 | b 11 | = 12 | 2 13 |
14 |
15 | 16 | const 17 | 18 | 19 | c 20 | 21 | 22 | = 23 | 24 | 25 | 3 26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/static-children.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - before-recma-compiled-js 4 | - before-recma-js-dev 5 | - before-recma-js 6 | - after-recma-js 7 | - after-recma-js-dev 8 | - compiled-js 9 | - compiled-js-dev 10 | - rendered-dev 11 | issue: https://github.com/code-hike/codehike/issues/433 12 | --- 13 | 14 |
15 | 16 | hey 17 | 18 | ho 19 | 20 | ## !foo 21 | 22 | bar 23 | 24 |
25 | 26 |
27 | 28 | asdf 29 | 30 | aa 31 | 32 |
33 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/static-children.7.compiled-js.js: -------------------------------------------------------------------------------- 1 | import { 2 | Fragment as _Fragment, 3 | jsx as _jsx, 4 | jsxs as _jsxs, 5 | } from "react/jsx-runtime" 6 | function _createMdxContent(props) { 7 | const _components = { 8 | p: "p", 9 | slot: "slot", 10 | ...props.components, 11 | } 12 | return _jsxs(_Fragment, { 13 | children: [ 14 | _jsx("div", { 15 | children: _jsxs(_Fragment, { 16 | children: [ 17 | _jsx(_components.p, { 18 | children: "hey", 19 | }), 20 | _jsx(_components.p, { 21 | children: "ho", 22 | }), 23 | ], 24 | }), 25 | title: "", 26 | _data: { 27 | header: "", 28 | }, 29 | foo: { 30 | children: _jsx(_components.p, { 31 | children: "bar", 32 | }), 33 | title: "", 34 | _data: { 35 | header: "## !foo", 36 | }, 37 | }, 38 | }), 39 | "\n", 40 | _jsxs("section", { 41 | children: [ 42 | _jsx(_components.p, { 43 | children: "asdf", 44 | }), 45 | _jsx(_components.p, { 46 | children: "aa", 47 | }), 48 | ], 49 | }), 50 | ], 51 | }) 52 | } 53 | export default function MDXContent(props = {}) { 54 | const { wrapper: MDXLayout } = props.components || {} 55 | return MDXLayout 56 | ? _jsx(MDXLayout, { 57 | ...props, 58 | children: _jsx(_createMdxContent, { 59 | ...props, 60 | }), 61 | }) 62 | : _createMdxContent(props) 63 | } 64 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/static-children.9.rendered-dev.html: -------------------------------------------------------------------------------- 1 |
2 |

hey

3 |

ho

4 |
5 |
6 |

asdf

7 |

aa

8 |
9 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/syntax-highlight.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | syntaxHighlight: github-dark 3 | snapshots: 4 | - compiled-jsx 5 | --- 6 | 7 | ```js lorem.js 8 | // !mark[6:10] hey 9 | const a = 1 10 | ``` 11 | 12 | ```js !foo bar.js 13 | // !mark 1 14 | const b = 2 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/two-ps.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - before-remark 4 | - parsed-jsx 5 | --- 6 | 7 | ## !valid 8 | 9 | !a1 1 10 | !!a2 2 11 | 2 12 | !a3 3 13 | 14 | ![!b1 x](https://b1.com) 15 | ![!!b2 x](https://b2.com) 16 | 17 | !c1 1 18 | cc 19 | ![!c2 x](https://c2.com) 20 | 21 | ![!d1 x](https://d1.com) 22 | !!d2 2 23 | 24 | !e1 1 25 | ee ee 26 | ee 27 | 28 | !k two-spaces-after-value 29 | !l because-some-use-prettier-proseWrap 30 | 31 | ## !invalid 32 | 33 | ff ff 34 | !f1 dd 35 | 36 | gg gg 37 | ![!g1 x](https://g1.com) 38 | 39 | ![!h1 x](https://h1.com) 40 | hh hh 41 | 42 | ii ![!i1 x](https://i1.com) ii 43 | 44 | ![!j1 x](https://j2.com) 45 | jjj 46 | !j2 2 47 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/unknown-lang.0.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | snapshots: 3 | - rendered 4 | --- 5 | 6 | ```firulete 7 | console.log(1) 8 | ``` 9 | -------------------------------------------------------------------------------- /packages/codehike/tests/md-suite/unknown-lang.9.rendered.html: -------------------------------------------------------------------------------- 1 |
2 |
console.log(1)
3 |
4 | -------------------------------------------------------------------------------- /packages/codehike/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "NodeNext", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "jsx": "react-jsx", 19 | "lib": ["dom", "es2019"], 20 | "module": "NodeNext", 21 | "target": "es2019", 22 | "outDir": "dist" 23 | }, 24 | "include": ["src"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/recma/index.js: -------------------------------------------------------------------------------- 1 | import { recmaCodeHike } from "codehike/mdx" 2 | export default recmaCodeHike 3 | -------------------------------------------------------------------------------- /packages/recma/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recma-codehike", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "type": "module", 6 | "sideEffects": false, 7 | "license": "MIT", 8 | "repository": "code-hike/codehike", 9 | "dependencies": { 10 | "codehike": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/remark/index.js: -------------------------------------------------------------------------------- 1 | import { remarkCodeHike } from "codehike/mdx" 2 | export default remarkCodeHike 3 | -------------------------------------------------------------------------------- /packages/remark/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remark-codehike", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "type": "module", 6 | "sideEffects": false, 7 | "license": "MIT", 8 | "repository": "code-hike/codehike", 9 | "dependencies": { 10 | "codehike": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "pipeline": { 5 | "build": { 6 | "outputs": ["dist/**", ".next/**", "!.next/cache/**"], 7 | "dependsOn": ["^build"] 8 | }, 9 | "test": { 10 | "outputs": ["coverage/**"], 11 | "dependsOn": [] 12 | }, 13 | "dev": { 14 | "cache": false, 15 | "persistent": true 16 | }, 17 | "clean": { 18 | "cache": false 19 | } 20 | } 21 | } 22 | --------------------------------------------------------------------------------