Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ce20bb2
Add tutorial runner and Playwright harness
WiktorStarczewski Jan 27, 2026
166c532
Migrate tutorials to Miden SDK 0.13.0-next.4
WiktorStarczewski Jan 27, 2026
39f132e
fix(ci): use crates.io miden client
WiktorStarczewski Jan 29, 2026
ce607e0
docs: add Building a React Wallet tutorial
WiktorStarczewski Feb 6, 2026
7eb8197
docs: add React SDK examples to existing tutorials
WiktorStarczewski Feb 6, 2026
a86f9ef
docs: specify filenames in unauthenticated note tutorial
WiktorStarczewski Feb 6, 2026
b5abd6c
docs: specify filenames in tutorials instead of generic 'library file'
WiktorStarczewski Feb 6, 2026
f25ec4e
style: format markdown with prettier
WiktorStarczewski Feb 6, 2026
c459143
fix: restore prettier-ignore comments mangled by prettier
WiktorStarczewski Feb 6, 2026
82d38f8
fix: remove prettier-ignore comments that get mangled
WiktorStarczewski Feb 6, 2026
6dec03b
docs: update signer package names and Turnkey connect flow
WiktorStarczewski Feb 9, 2026
59975a3
style: format markdown with prettier
WiktorStarczewski Feb 9, 2026
068395a
docs: update TurnkeySignerProvider usage to use defaults
WiktorStarczewski Feb 9, 2026
97c8fcb
style: fix markdown formatting and add CLAUDE.md
WiktorStarczewski Feb 9, 2026
15359a0
switch tutorials from devnet to testnet
WiktorStarczewski Feb 16, 2026
6e85ae6
fix: address PR #159 review feedback
WiktorStarczewski Feb 18, 2026
8d198a0
rename contributing.md to CONTRIBUTING.md
WiktorStarczewski Feb 18, 2026
671c9b4
fix: address final PR #159 review feedback
WiktorStarczewski Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ web-client/.next/
web-client/playwright-report/
web-client/test-results/
**/.DS_Store
.DS_Store
.DS_Store
93 changes: 93 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Contributing to Miden Tutorials

#### First off, thanks for taking the time to contribute!

## Markdown Formatting with Prettier

We use [Prettier](https://prettier.io/) to ensure our Markdown files are consistently formatted.

### Installation

- **Global Installation:**

```bash
npm install -g prettier
```

- **Local (Dev Dependency) Installation:**

```bash
npm install --save-dev prettier
```

### Formatting Files

From the root of the project, run:

```bash
prettier --write "**/*.md"
```

Make sure to run this command before submitting pull requests.

## CodeSdkTabs: Dot-Indentation Convention

The `CodeSdkTabs` component (in `docs/src/components/CodeSdkTabs.tsx`) lets tutorials show React and TypeScript code side-by-side. Code is passed as template literals inside MDX props:

```mdx
<CodeSdkTabs
example={{
react: { code: `...` },
typescript: { code: `...` },
}}
reactFilename="lib/example.tsx"
tsFilename="lib/example.ts"
/>
```

**Problem:** MDX/webpack strips leading whitespace from template literals, so indented code renders flush-left.

**Solution:** Use leading dots (`.`) to represent indentation. Each dot equals one indent level (2 spaces). The `preserveIndent()` function in `CodeSdkTabs.tsx` converts dots to spaces at render time.

### Example

Source in `.md` file:

```
typescript: { code: `export function foo() {
.const x = 1;
.if (x) {
..console.log(x);
.}
}` }
```

Renders as:

```ts
export function foo() {
const x = 1;
if (x) {
console.log(x);
}
}
```

### Rules

| Context | Dots | Spaces |
| ------------------------------------------- | ---- | ------ |
| Top-level (`export`, `import`, closing `}`) | 0 | 0 |
| Inside function body | 1 | 2 |
| Inside nested block (`if`, `for`, etc.) | 2 | 4 |
| Function call arguments (continuation) | +1 | +2 |
| Deeper nesting | 3+ | 6+ |

### Tips

- Standalone code blocks (` ```ts...``` `) outside `CodeSdkTabs` use normal space indentation -- the dot convention only applies inside `CodeSdkTabs` template literals.
- The React and TypeScript code snippets both follow this convention. If you add or edit snippets, apply the same pattern.

---

Thank you for contributing!
35 changes: 0 additions & 35 deletions contributing.md

This file was deleted.

82 changes: 82 additions & 0 deletions docs/src/components/CodeSdkTabs.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* CodeSdkTabs Component Styles */

.codeContainer {
margin: 1rem 0;
border: 1px solid var(--ifm-color-emphasis-300);
border-radius: var(--ifm-global-radius);
overflow: hidden;
background: var(--ifm-background-color);
}

.tabContainer {
background: var(--ifm-color-emphasis-100);
border-bottom: 1px solid var(--ifm-color-emphasis-300);
}

.tabButtons {
display: flex;
gap: 0;
}

.tabButton {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
border: none;
background: transparent;
color: var(--ifm-color-content-secondary);
cursor: pointer;
font-size: 0.875rem;
font-weight: 500;
transition: all 0.2s ease;
border-bottom: 2px solid transparent;
}

.tabButton:hover {
color: var(--ifm-color-primary);
background: var(--ifm-color-emphasis-200);
}

.tabButton.active {
color: var(--ifm-color-primary);
background: var(--ifm-color-emphasis-200);
border-bottom: 2px solid var(--ifm-color-primary);
}

.codeSection {
position: relative;
margin: 0;
}

.codeSection pre {
margin: 0;
border-radius: 0;
border: none;
}

/* Remove any extra bottom spacing from the theme code block */
.codeSection :global(.theme-code-block) {
margin-bottom: 0 !important;
}

.outputSection {
border-top: 1px solid var(--ifm-color-emphasis-300);
background: var(--ifm-color-emphasis-50);
}

.outputHeader {
padding: 0.5rem 1rem;
font-size: 0.875rem;
font-weight: 600;
color: var(--ifm-color-content-secondary);
background: var(--ifm-color-emphasis-100);
border-bottom: 1px solid var(--ifm-color-emphasis-200);
}

.outputSection pre {
margin: 0;
border-radius: 0;
border: none;
background: var(--ifm-color-emphasis-50) !important;
}
138 changes: 138 additions & 0 deletions docs/src/components/CodeSdkTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import React, { useState } from "react";
import CodeBlock from "@theme/CodeBlock";
import styles from "./CodeSdkTabs.module.css";

interface CodeExample {
react?: {
code: string;
output?: string;
};
typescript?: {
code: string;
output?: string;
};
}

interface CodeSdkTabsProps {
example: CodeExample;
reactFilename?: string;
tsFilename?: string;
}

// Dot-indentation convention for CodeSdkTabs
// ─────────────────────────────────────────────
// MDX/webpack strips leading whitespace from template literals inside JSX props.
// To preserve indentation in code snippets, use leading dots in the markdown
// source. Each dot represents one indent level (2 spaces).
//
// Example in a .md file:
// typescript: { code: `export function foo() {
// .const x = 1;
// .if (x) {
// ..console.log(x);
// .}
// }` }
//
// Renders as:
// export function foo() {
// const x = 1;
// if (x) {
// console.log(x);
// }
// }
//
// Rules:
// 0 dots → top-level declarations (export, import, closing braces)
// 1 dot → first level inside a function/block body
// 2 dots → second level (nested blocks, function call arguments)
// 3+ dots → deeper nesting
function preserveIndent(code: string): string {
return code.replace(/^(\.+)/gm, (match) => ' '.repeat(match.length));
}

export default function CodeSdkTabs({
example,
reactFilename = "index.tsx",
tsFilename = "index.ts",
}: CodeSdkTabsProps): JSX.Element {
const [activeTab, setActiveTab] = useState<"react" | "typescript">(
example.react ? "react" : "typescript"
);

const hasReact = !!example.react;
const hasTypeScript = !!example.typescript;

// Infer syntax language from filename extension (.tsx → tsx, .ts → ts)
const langFor = (filename: string, fallback: string) =>
filename.endsWith(".tsx") ? "tsx" : filename.endsWith(".ts") ? "ts" : fallback;

// Don't show tabs if there's only one language
if (!hasReact || !hasTypeScript) {
const singleLang = hasReact ? "react" : "typescript";
const singleExample = example[singleLang];
const filename = singleLang === "react" ? reactFilename : tsFilename;

return (
<div className={styles.codeContainer}>
<div className={styles.codeSection}>
<CodeBlock
language={langFor(filename, singleLang === "react" ? "tsx" : "ts")}
title={filename}
>
{preserveIndent(singleExample!.code)}
</CodeBlock>
</div>
{singleExample!.output && (
<div className={styles.outputSection}>
<div className={styles.outputHeader}>Output</div>
<CodeBlock language="bash">{singleExample.output}</CodeBlock>
</div>
)}
</div>
);
}

const currentExample = example[activeTab];
const activeFilename = activeTab === "react" ? reactFilename : tsFilename;

return (
<div className={styles.codeContainer}>
<div className={styles.tabContainer}>
<div className={styles.tabButtons}>
<button
className={`${styles.tabButton} ${
activeTab === "react" ? styles.active : ""
}`}
onClick={() => setActiveTab("react")}
>
React
</button>
<button
className={`${styles.tabButton} ${
activeTab === "typescript" ? styles.active : ""
}`}
onClick={() => setActiveTab("typescript")}
>
TypeScript
</button>
</div>
</div>

<div className={styles.codeSection}>
<CodeBlock
language={langFor(activeFilename, activeTab === "react" ? "tsx" : "ts")}
title={activeFilename}
>
{preserveIndent(currentExample!.code)}
</CodeBlock>
</div>

{currentExample!.output && (
<div className={styles.outputSection}>
<div className={styles.outputHeader}>Output</div>
<CodeBlock language="bash">{currentExample.output}</CodeBlock>
</div>
)}
</div>
);
}
1 change: 1 addition & 0 deletions docs/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as CodeSdkTabs } from './CodeSdkTabs';
Loading