Skip to content

Commit b922893

Browse files
committed
last main commit
1 parent 136d1fe commit b922893

File tree

5 files changed

+153
-219
lines changed

5 files changed

+153
-219
lines changed

.github/workflows/ci-dev.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# .github/workflows/ci-dev.yml
2+
name: CI — dev 🛠️
3+
4+
on:
5+
push:
6+
branches: [dev]
7+
pull_request:
8+
branches: [dev]
9+
workflow_dispatch:
10+
11+
concurrency:
12+
group: ci-${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
permissions:
16+
contents: read
17+
18+
defaults:
19+
run:
20+
shell: bash
21+
22+
jobs:
23+
build-and-test:
24+
name: Build & Test (Node 20) 🧪
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 15
27+
strategy:
28+
fail-fast: true
29+
env:
30+
CI: true
31+
steps:
32+
- name: ⬇️ Checkout
33+
uses: actions/checkout@v4
34+
35+
- name: 🔧 Setup Node 20
36+
uses: actions/setup-node@v4
37+
with:
38+
node-version: 20.x
39+
cache: npm
40+
41+
- name: 📦 Install, 🔎 Typecheck, 🏗️ Build, ✅ Test
42+
run: |
43+
set -euo pipefail
44+
npm ci
45+
npm run typecheck
46+
npm run build
47+
npm test -- --run

.github/workflows/ci-main.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# .github/workflows/ci-main.yml
2+
name: CI — main 🚀
3+
4+
on:
5+
push:
6+
branches: [main]
7+
pull_request:
8+
branches: [main]
9+
workflow_dispatch:
10+
11+
concurrency:
12+
group: ci-${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
permissions:
16+
contents: read
17+
18+
defaults:
19+
run:
20+
shell: bash
21+
22+
jobs:
23+
build-and-test:
24+
name: Build & Test (Node 20) 🧪
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 15
27+
strategy:
28+
fail-fast: true
29+
env:
30+
CI: true
31+
steps:
32+
- name: ⬇️ Checkout
33+
uses: actions/checkout@v4
34+
35+
- name: 🔧 Setup Node 20
36+
uses: actions/setup-node@v4
37+
with:
38+
node-version: 20.x
39+
cache: npm
40+
41+
- name: 📦 Install, 🔎 Typecheck, 🏗️ Build, ✅ Test
42+
run: |
43+
set -euo pipefail
44+
npm ci
45+
npm run typecheck
46+
npm run build
47+
npm test -- --run

README.md

Lines changed: 15 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
# Next Crumb
1+
_# Next Crumb
22

33
> MUI 7 Breadcrumbs with **Next.js Link** support, optional **URL-based generation**, and **SEO microdata**. Router-agnostic, zero runtime deps.
44
5-
| Item | Value |
6-
|-----------------------|-------|
7-
| **GitHub repo** | [github.com/ameshkin/nextcrumbs](https://github.com/ameshkin/nextcrumbs) |
8-
| **npm package name** | `@ameshkin/nextcrumbs` |
9-
| **Install** | `npm i @ameshkin/nextcrumbs` |
10-
| **Peer deps** | `@mui/material@^7`, `@mui/icons-material@^7`, `react@>=18`, `react-dom@>=18` |
11-
| **CI badge** | [![CI](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/ci.yml?branch=main&label=CI)](https://github.com/ameshkin/nextcrumbs/actions) |
12-
| **npm badge** | [![npm](https://img.shields.io/npm/v/@ameshkin/nextcrumbs.svg)](https://www.npmjs.com/package/@ameshkin/nextcrumbs) |
13-
| **Types badge** | ![types](https://img.shields.io/badge/types-TypeScript-blue.svg) |
14-
| **License badge** | [![license](https://img.shields.io/badge/license-MIT-black.svg)](LICENSE) |
15-
| **Bundle size badge** | [![bundle size](https://img.shields.io/bundlephobia/minzip/%40ameshkin%2Fnextcrumbs?label=bundle%20size)](https://bundlephobia.com/package/@ameshkin/nextcrumbs) |
16-
| **Deps badge** | [![deps](https://img.shields.io/librariesio/release/npm/%40ameshkin%2Fnextcrumbs)](https://libraries.io/npm/%40ameshkin%2Fnextcrumbs) |
5+
| Item | Value | Badge |
6+
|-----------------|-------------------------------------------------------------------------------------------|-------|
7+
| **GitHub repo** | [github.com/ameshkin/nextcrumbs](https://github.com/ameshkin/nextcrumbs) | |
8+
| **CI (main)** | `.github/workflows/ci-main.yml` | [![CI — main](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/ci-main.yml?branch=main&label=ci%20(main))](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci-main.yml) |
9+
| **CI (dev)** | `.github/workflows/ci-dev.yml` | [![CI — dev](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/ci-dev.yml?branch=dev&label=ci%20(dev))](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci-dev.yml) |
10+
| **npm package** | [@ameshkin/nextcrumbs](https://www.npmjs.com/package/@ameshkin/nextcrumbs) | [![npm](https://img.shields.io/npm/v/@ameshkin/nextcrumbs.svg)](https://www.npmjs.com/package/@ameshkin/nextcrumbs) |
11+
| **Install** | `npm i @ameshkin/nextcrumbs` | [![Install test — main](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/install.yml?branch=main&label=install%20test)](https://github.com/ameshkin/nextcrumbs/actions/workflows/install.yml) |
12+
| **Peer deps** | `@mui/material@^7`, `@mui/icons-material@^7`, `react@>=18`, `react-dom@>=18` | ![peer deps](https://img.shields.io/badge/peer_deps-MUI%207%20%7C%20Icons%207%20%7C%20React%2018-blue) |
13+
| **Types** | TypeScript | ![types](https://img.shields.io/badge/types-TypeScript-blue.svg) |
14+
| **License** | MIT | [![license](https://img.shields.io/badge/license-MIT-black.svg)](LICENSE) |
15+
| **Bundle size** | bundlephobia | [![bundle size](https://img.shields.io/bundlephobia/minzip/%40ameshkin%2Fnextcrumbs?label=bundle%20size)](https://bundlephobia.com/package/@ameshkin/nextcrumbs) |
16+
| **Deps status** | libraries.io | [![deps](https://img.shields.io/librariesio/release/npm/%40ameshkin%2Fnextcrumbs)](https://libraries.io/npm/%40ameshkin%2Fnextcrumbs) |
1717

1818
---
1919

@@ -26,9 +26,9 @@
2626
- [Auto from URL (Next App Router)](#auto-from-url-next-app-router)
2727
- [Props](#props)
2828
- [Icon & Separator Examples](#icon--separator-examples)
29+
- [Automated Testing](#automated-testing)
2930
- [Accessibility & SEO](#accessibility--seo)
3031
- [Dependency Checks](#dependency-checks)
31-
- [FAQ](#faq)
3232
- [Contributing](#contributing)
3333
- [License](#license)
3434

@@ -48,7 +48,7 @@
4848

4949
- React **18+**
5050
- @mui/material **7+**
51-
- (Optional) @mui/icons-material **7+** for built-in icons
51+
- (Optional) @mui/icons-material **7+**
5252
- Next.js **13.4+** (if using Next + App Router)
5353

5454
---
@@ -59,200 +59,6 @@
5959
npm i @ameshkin/nextcrumbs
6060
# peer deps
6161
npm i @mui/material @mui/icons-material react react-dom
62-
````
63-
64-
> Using pnpm or yarn? Replace `npm i` with your package manager’s command.
65-
66-
---
67-
68-
## Quick Start (Next.js)
69-
70-
Manual items with `next/link`:
71-
72-
```tsx
73-
"use client";
74-
import Link from "next/link";
75-
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
76-
77-
export default function HeaderTrail() {
78-
return (
79-
<Breadcrumbs
80-
LinkComponent={Link}
81-
items={[
82-
{ label: "Dashboard", href: "/" },
83-
{ label: "Products", href: "/products" },
84-
{ label: "New" }
85-
]}
86-
/>
87-
);
88-
}
89-
```
90-
91-
---
92-
93-
## Auto from URL (Next App Router)
94-
95-
Generate items from the current pathname:
96-
97-
```tsx
98-
"use client";
99-
import Link from "next/link";
100-
import { usePathname } from "next/navigation";
101-
import { Breadcrumbs, usePathBreadcrumbs } from "@ameshkin/nextcrumbs";
102-
103-
export default function AutoTrail() {
104-
const pathname = usePathname();
105-
const items = usePathBreadcrumbs(pathname, {
106-
baseHref: "/",
107-
labelMap: { new: "Create" },
108-
exclude: ["_private"]
109-
});
110-
111-
return <Breadcrumbs LinkComponent={Link} items={items} />;
112-
}
113-
```
114-
115-
---
116-
117-
## Props
118-
119-
### `<Breadcrumbs />`
120-
121-
| Prop | Type | Default | Description |
122-
| --------------- | ------------------------------------------------------ | -------------------- | ---------------------------------------------------------------- |
123-
| `items` | `{ label: string; href?: string; icon?: ReactNode }[]` | **required** | The breadcrumb trail; last item usually has no `href`. |
124-
| `LinkComponent` | `ElementType` | `@mui/material/Link` | Custom link component (e.g., Next.js `Link`). |
125-
| `muiProps` | `Omit<MUIBreadcrumbsProps, "children">` || Pass-through props to MUI `<Breadcrumbs />`. |
126-
| `separatorIcon` | `ReactNode` | `ChevronRightIcon` | Icon/node placed between items. |
127-
| `homeLabel` | `string` | `"Dashboard"` | If an item’s label matches this, it gets a Home icon by default. |
128-
| `withSchema` | `boolean` | `true` | Adds `schema.org/BreadcrumbList` microdata. |
129-
130-
### `usePathBreadcrumbs(pathname, options?)`
131-
132-
| Option | Type | Default | Description |
133-
| ---------- | ----------------------- | ------- | ---------------------------------- |
134-
| `baseHref` | `string` | `"/"` | Root href for the first crumb. |
135-
| `labelMap` | `Record<string,string>` | `{}` | Override labels by segment. |
136-
| `exclude` | `string[]` | `[]` | Skip specific path segments. |
137-
| `decode` | `boolean` | `true` | `decodeURIComponent` each segment. |
138-
139-
---
140-
141-
## Icon & Separator Examples
142-
143-
Change the separator and home icon behavior:
144-
145-
```tsx
146-
import Link from "next/link";
147-
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
148-
import NavigateNextIcon from "@mui/icons-material/NavigateNext";
149-
import HomeOutlinedIcon from "@mui/icons-material/HomeOutlined";
150-
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
151-
152-
<Breadcrumbs
153-
LinkComponent={Link}
154-
separatorIcon={<NavigateNextIcon fontSize="small" />}
155-
items={[
156-
{ label: "Dashboard", href: "/", icon: <HomeOutlinedIcon /> },
157-
{ label: "Products", href: "/products" },
158-
{ label: "Gadgets" }
159-
]}
160-
/>;
161-
```
162-
163-
* Any MUI icon works for `separatorIcon` or per-item `icon`.
164-
* If you set `homeLabel="Home"`, the component shows a Home icon automatically when a crumb’s label is `"Home"`.
165-
166-
---
167-
168-
## Accessibility & SEO
169-
170-
* Uses MUI’s accessible `<Breadcrumbs aria-label="breadcrumbs">`.
171-
* Adds **schema.org** `BreadcrumbList` microdata by default (set `withSchema={false}` to disable).
172-
* Minimal DOM/no extra wrappers (uses `display: contents` for the list wrapper).
173-
174-
---
175-
176-
## Dependency Checks
177-
178-
Make sure peer deps resolve cleanly:
179-
180-
```bash
181-
# in your app
182-
npm ls @mui/material @mui/icons-material react react-dom
18362
```
18463

185-
Optional size/security checks:
186-
187-
* Size: [https://bundlephobia.com/package/@ameshkin/nextcrumbs](https://bundlephobia.com/package/@ameshkin/nextcrumbs)
188-
* Vulnerabilities (example): `npx snyk test` or GitHub Advanced Security (CodeQL)
189-
190-
---
191-
192-
## FAQ
193-
194-
**Does it work with React Router?**
195-
Yes—pass your router’s `<Link>` as `LinkComponent`. The UI is MUI; navigation is your router.
196-
197-
**How do I change the last crumb’s style?**
198-
The last item usually has no `href`. You can add conditional styles by checking `href` presence in your `items` or wrap this component with your own style logic.
199-
200-
**Can I disable icons entirely?**
201-
Yes—don’t pass `icon` and set `homeLabel` to a non-matching value.
202-
203-
---
204-
205-
## Accessibility & SEO
206-
207-
This component previously supported `schema.org` microdata via a `withSchema` and `withJsonLd` prop. These have been **removed** for the following reasons:
208-
209-
- ⚠️ **Google no longer consistently indexes client-side microdata** (e.g. via React or `dangerouslySetInnerHTML`) unless it's rendered server-side.
210-
- 🧼 Breadcrumb JSON-LD tags added via `<script>` often **conflict with route-based apps** (e.g. dynamic segments in Next.js).
211-
- 🔍 Most modern SEO guidance encourages **server-side or static rendering** of JSON-LD, not runtime injection.
212-
- 🔧 Removing these props results in **simpler DOM output**, cleaner markup, and improved developer control.
213-
214-
**If you need structured breadcrumbs for SEO**, we recommend injecting them at the page level with your own layout component, using `<script type="application/ld+json">` manually for static pages only.
215-
216-
This component still provides:
217-
218-
- Accessible markup (`aria-label`, correct role semantics)
219-
- Customizable separator, label, and icon logic
220-
- Dynamic routing support via the `items` prop or `usePathBreadcrumbs` helper
221-
222-
223-
## Contributing
224-
225-
* CI badge above expects a workflow at `.github/workflows/ci.yml`.
226-
* Please run `npm run build` before sending a PR.
227-
* Keep peer ranges broad enough for MUI 7 / React 18–19.
228-
229-
---
230-
231-
## License
232-
233-
[MIT](LICENSE)
234-
235-
```
236-
237-
238-
---
239-
240-
## Additional Example — Minimal AutoTrail
241-
242-
> Simple usage with default behavior (no `labelMap`, `exclude`, or `baseHref`)
243-
244-
```tsx
245-
"use client";
246-
import { usePathname } from "next/navigation";
247-
import { Breadcrumbs, usePathBreadcrumbs } from "@ameshkin/nextcrumbs";
248-
import Link from "next/link";
249-
250-
export default function AutoTrail() {
251-
const pathname = usePathname();
252-
const items = usePathBreadcrumbs(pathname);
253-
254-
return <Breadcrumbs LinkComponent={Link} items={items} />;
255-
}
256-
```
25764

258-
✅ Great for dashboards or quick scaffolded layouts. Automatically capitalizes, cleans up slugs, and converts URL segments into breadcrumb labels.

0 commit comments

Comments
 (0)