An open API service indexing awesome lists of open source software.

https://github.com/markbang/memos-embed

Memos Embed — Type‑safe memo card embeds for usememos.com with a ready‑to‑deploy site plus React and Web Component packages.
https://github.com/markbang/memos-embed

memos usememos

Last synced: 2 months ago
JSON representation

Memos Embed — Type‑safe memo card embeds for usememos.com with a ready‑to‑deploy site plus React and Web Component packages.

Awesome Lists containing this project

README

          

![Memos Embed Logo](./apps/site/public/android-chrome-512x512.png)

# Memos Embed

[![CI](https://github.com/markbang/memos-embed/actions/workflows/ci.yml/badge.svg)](https://github.com/markbang/memos-embed/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/memos-embed.svg)](https://www.npmjs.com/package/memos-embed)

Embeddable memo cards for Memos, delivered as a website and npm packages.

## Features
- Rich memo cards with themes, density presets, and extendable design tokens
- Core HTML renderer for SSR and static-site workflows
- Batch multi-memo fetching and shared-style list rendering for note digests and weekly roundups
- Shared memo client for cross-embed request deduping on React and MDX pages
- React components for single embeds and multi-memo roundups, with optional pre-fetched memo rendering
- Web Component wrapper with exposed `::part(...)` hooks
- Iframe embed route for no-build integrations
- Lightweight markdown support for headings, lists, task lists, quotes, links, and fenced code blocks
- Attachment previews for images and grouped reaction badges
- Optional auto-resizing iframe snippets via `postMessage`

## Workspace Layout
- `apps/site`: TanStack Start website (docs, playground, iframe embeds)
- `packages/memos-embed`: core API + SSR HTML helpers
- `packages/memos-embed-react`: React component wrapper
- `packages/memos-embed-wc`: Web Component wrapper

## Quick Start
```bash
pnpm install
pnpm dev
```

Open:
- site: `http://localhost:3000`
- playground: `http://localhost:3000/playground`

## Build
```bash
pnpm -r build
```

## Tests
```bash
pnpm test
pnpm test:artifacts
```

## Validation
```bash
pnpm validate
```

## Git Hooks
This repo uses [`prek`](https://github.com/j178/prek) for local Git hooks.

- `pnpm install` auto-installs the configured `pre-commit` and `pre-push` hooks when possible
- `pre-commit` runs `pnpm check`
- `pre-push` runs `pnpm validate`
- to reinstall hooks manually: `pnpm prek:install`
- to run all configured hooks on demand: `pnpm prek:run`

## Releasing
- Add a changeset for package changes with `pnpm changeset`
- The `Publish Packages` workflow versions changed packages directly on `main`, publishes them to npm, then creates a Git tag and a GitHub Release generated by `changelogithub`
- If your `main` branch blocks workflow pushes or release creation, add a `CHANGESETS_GITHUB_TOKEN` secret with repo write access
- Set `NPM_TOKEN` so package publishing can authenticate with npm

## Base URL handling
`baseUrl` accepts any of these forms and normalizes them internally:
- `https://demo.usememos.com`
- `https://demo.usememos.com/api`
- `https://demo.usememos.com/api/v1`

Use whichever shape you already have. The client resolves memo and user requests against `/api/v1` automatically.

## Usage
### Core package
```ts
import { extendTheme, fetchMemo, renderMemoHtmlSnippet } from 'memos-embed'

const memo = await fetchMemo({
baseUrl: 'https://demo.usememos.com/api/v1',
memoId: '1',
})

const blogTheme = extendTheme('paper', {
radius: 'var(--radius)',
fontFamily: 'inherit',
tokens: {
background: 'var(--card)',
foreground: 'var(--card-foreground)',
border: 'var(--border)',
accent: 'var(--primary)',
accentForeground: 'var(--primary-foreground)',
mutedForeground: 'var(--muted-foreground)',
codeBackground: 'var(--muted)',
},
})

const html = renderMemoHtmlSnippet(memo, {
includeStyles: true,
theme: blogTheme,
density: 'comfortable',
showAttachments: true,
showReactions: true,
linkTarget: '_blank',
})
```

### Multiple memos on one page
```ts
import { fetchMemos, renderMemoListHtmlSnippet } from 'memos-embed'

const memos = await fetchMemos({
baseUrl: 'https://demo.usememos.com/api/v1',
memoIds: ['1', '2', '3'],
})

const html = renderMemoListHtmlSnippet(memos, {
layout: 'stack',
gap: '20px',
theme: 'paper',
})
```

### Shared memo client
```ts
import { createMemoClient } from 'memos-embed'

const memoClient = createMemoClient()
```

### React
```tsx
import { MemoEmbed } from '@memos-embed/react'

```

### React with pre-fetched data
```tsx
import { fetchMemo } from 'memos-embed'
import { MemoEmbed } from '@memos-embed/react'

const memo = await fetchMemo({
baseUrl: 'https://demo.usememos.com/api/v1',
memoId: '1',
})

```

When you pass a pre-fetched `memo`, the React component now renders the full embed HTML during SSR/SSG instead of waiting for hydration.

### React roundup component
```tsx
import { MemoEmbedList } from '@memos-embed/react'

```

### React shared client
```tsx
import { createMemoClient } from 'memos-embed'
import { MemoClientProvider, MemoEmbed, MemoEmbedList } from '@memos-embed/react'

const client = createMemoClient()


```

Use a shared client when multiple embeds on one page should reuse memo and creator fetches instead of issuing duplicate requests.

### React shared client with pre-fetched data
```tsx
import { createMemoClient, fetchMemo, fetchMemos } from 'memos-embed'
import { MemoClientProvider, MemoEmbed, MemoEmbedList } from '@memos-embed/react'

const client = createMemoClient()

const [heroMemo, roundupMemos] = await Promise.all([
fetchMemo({
baseUrl: 'https://demo.usememos.com/api/v1',
memoId: '1',
}),
fetchMemos({
baseUrl: 'https://demo.usememos.com/api/v1',
memoIds: ['2', '3'],
}),
])


```

Passing `memo` or `memos` while a `MemoClientProvider` is active primes the shared client cache, so later embeds for the same ids can reuse already-fetched data. Those pre-fetched props also render immediately in the initial HTML response for SSR/SSG pages.

### Web Component
```html

```

```css
memos-embed::part(container) {
border-radius: 24px;
}
```

### Iframe
```ts
import { renderIframeHtml } from 'memos-embed'

const iframe = renderIframeHtml({
embedBaseUrl: 'https://your-site.com',
baseUrl: 'https://demo.usememos.com/api/v1',
memoId: '1',
height: 240,
autoResize: true,
})
```

`autoResize` works through a `postMessage` handshake keyed by `frameId`. `renderIframeHtml()` keeps that wiring aligned for you. If you hand-roll the iframe markup, make sure the iframe element `id` matches the `frameId` query param you send to `/embed/:memoId`.

For pages with multiple embeds, give each iframe a distinct `frameId` to keep resize events scoped correctly.

## Blog integration examples
- `examples/next-mdx`: Next.js App Router + server-fetched memo data
- `examples/mdx-components`: reusable MDX component pattern for React-based blogs
- `examples/astro-blog`: Astro + MDX blog usage
- `examples/static-html`: iframe and Web Component copy-paste examples for static sites and CMS pages

## Development Notes
- The site uses source aliases so local changes in `packages/*` show up immediately in `apps/site`
- The playground keeps its configuration in the URL for easy sharing
- Package builds are powered by `tsup`; site builds use Vite + TanStack Start
- CI runs `pnpm validate`, including lint, Biome checks, tests, package-consumer smoke tests, and the site build
- Releases are managed with Changesets on `main`: the workflow versions packages, commits the release changes, publishes to npm, and creates a Git tag plus a `changelogithub`-powered GitHub Release automatically