Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 54 additions & 0 deletions landing/public/llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Shepherd.js

> Shepherd is an open-source JavaScript library for building guided product
> tours, user onboarding flows, trainings, and feature announcements on any
> website or web app. Steps render as accessible dialogs (keyboard navigation,
> focus trapping, aria attributes) that attach to DOM elements and are
> positioned by Floating UI. Works with React, Ember, Angular, Vue.js,
> ES Modules, or plain JavaScript. Free for open-source, personal, and
> non-commercial use (AGPL-3.0); commercial licenses are available.

## When to use Shepherd

Use Shepherd when a project needs to guide users through a web interface:

- Onboarding new users with a step-by-step walkthrough of an app
- Announcing or explaining new features in context
- Guiding users through complex forms, wizards, or multi-step workflows
- Building in-app training or self-serve product education
- Highlighting one or more DOM elements with a modal overlay while explaining them

How to use it: install with `npm install shepherd.js`, then in a module
`import Shepherd from 'shepherd.js'` and load the stylesheet
`shepherd.js/dist/css/shepherd.css` (import it, or link it from a stylesheet
tag). Create a `new Shepherd.Tour({ ... })`, add steps with
`tour.addStep({ title, text, attachTo, buttons })`, then call `tour.start()`.
`shepherd.mjs` is an ES module with a default export and does not define a
global `Shepherd`, so import it rather than loading it from a plain script tag.
It runs entirely in the browser; no backend service is required.

Shepherd is not a native mobile (iOS/Android) tour library and is not an
analytics product — it renders and orchestrates the tour UI itself.

## Docs

- [Documentation](https://docs.shepherdjs.dev/): installation, guides, API reference
- [Homepage in markdown](https://www.shepherdjs.dev/index.md): overview, install, quick example
- [Pricing and licensing](https://www.shepherdjs.dev/pricing): free plan, commercial licenses

## Code

- [GitHub repository](https://github.com/shipshapecode/shepherd): source, issues, releases
- [npm package](https://www.npmjs.com/package/shepherd.js): shepherd.js

## Company

- [About](https://www.shepherdjs.dev/about): who maintains Shepherd
- [Contact](https://www.shepherdjs.dev/contact): email, GitHub, Discord
- [Privacy](https://www.shepherdjs.dev/privacy): privacy policy
- [Ship Shape](https://shipshape.io/): the consultancy that maintains Shepherd

## Optional

- [Blog](https://www.shepherdjs.dev/blog): announcements and articles
- [Sitemap](https://www.shepherdjs.dev/sitemap-index.xml)
10 changes: 9 additions & 1 deletion landing/src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@ import ShepherdWink from '../images/shepherd-head-wink.svg';
</span>
</div>

<div class="flex items-center">
<nav
class="flex flex-wrap font-heading items-center justify-center mt-4 text-sm uppercase w-full md:mt-0 md:w-auto"
>
<a class="mr-4 hover:text-navy-light" href="/about">About</a>
<a class="mr-4 hover:text-navy-light" href="/contact">Contact</a>
<a class="mr-4 hover:text-navy-light" href="/privacy">Privacy</a>
</nav>

<div class="flex items-center mt-4 md:mt-0">
<a
class="footer-icon mr-4 w-6"
href="https://github.com/shipshapecode/shepherd"
Expand Down
3 changes: 2 additions & 1 deletion landing/src/components/Posthog.astro
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
(e.__SV = 1));
})(document, window.posthog || []);
posthog.init('phc_sl7TroBwU2fA7dJVU70ZV5u0575fQNWYv1GK5enODkX', {
api_host: 'https://us.i.posthog.com'
api_host: 'https://us.i.posthog.com',
respect_dnt: true
});
</script>
29 changes: 29 additions & 0 deletions landing/src/layouts/ContentPage.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
import Base from './Base.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import { SITE_TITLE } from '../consts';

interface Props {
title: string;
description: string;
heading: string;
}

const { title, description, heading } = Astro.props;
---

<Base overrideTitle={title} overrideDescription={description}>
<Header title={SITE_TITLE} />
<main class="flex justify-center w-full">
<div class="max-w-3xl my-12 px-4 w-full">
<h1 class="font-heading text-4xl uppercase">{heading}</h1>
<div
class="content-page font-body mt-6 space-y-4 text-xl [&_a]:underline [&_a:hover]:text-navy-light [&_h2]:font-heading [&_h2]:mt-8 [&_h2]:text-2xl [&_h2]:uppercase [&_ul]:list-disc [&_ul]:pl-6"
>
<slot />
</div>
</div>
</main>
<Footer />
</Base>
56 changes: 56 additions & 0 deletions landing/src/pages/404.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
import Base from '@layouts/Base.astro';
import Header from '@components/Header.astro';
import Footer from '@components/Footer.astro';
import { SITE_DESCRIPTION } from '../consts';
---

<Base
overrideTitle="Page not found — Shepherd.js"
overrideDescription={SITE_DESCRIPTION}
>
<Header title="Page not found" />
<main class="flex justify-center w-full">
<div class="max-w-3xl my-12 px-4 text-center w-full">
<h1 class="font-heading text-4xl uppercase">404 — Page not found</h1>

<p class="font-body mt-6 text-xl">
The page you requested does not exist. Here is where to look instead:
</p>

<ul class="font-body mt-6 space-y-2 text-xl">
<li>
<a class="underline hover:text-navy-light" href="/">Homepage</a>
</li>
<li>
<a
class="underline hover:text-navy-light"
href="https://docs.shepherdjs.dev"
>
Documentation
</a>
</li>
<li>
<a class="underline hover:text-navy-light" href="/pricing">Pricing</a>
</li>
<li>
<a class="underline hover:text-navy-light" href="/blog">Blog</a>
</li>
<li>
<a class="underline hover:text-navy-light" href="/llms.txt">
llms.txt (guidance for AI agents)
</a>
</li>
<li>
<a class="underline hover:text-navy-light" href="/sitemap-index.xml">
Sitemap
</a>
</li>
<li>
<a class="underline hover:text-navy-light" href="/contact">Contact</a>
</li>
</ul>
</div>
</main>
<Footer />
</Base>
49 changes: 49 additions & 0 deletions landing/src/pages/about.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
import ContentPage from '@layouts/ContentPage.astro';
---

<ContentPage
title="About Shepherd.js"
description="What Shepherd.js is, who maintains it, and how it is licensed."
heading="About Shepherd"
>
<p>
Shepherd is an open-source JavaScript library for guiding users through your
app. It lets you build product tours, user onboarding flows, trainings, and
feature announcements as a sequence of steps — dialogs that attach to
elements in your interface, highlight them with a modal overlay, and walk
users through what to do next. Steps are positioned by
<a href="https://floating-ui.com/">Floating UI</a>, so they never end up off
screen or cropped by an overflow.
</p>

<p>
Shepherd ships with full keyboard navigation support, focus trapping, and
a11y compliance via aria attributes, and its minimal default styles make it
easy to match your product's look and feel. It works with React, Ember,
Angular, Vue.js, ES Modules, or plain JavaScript, and is used in production
by companies such as Google, Ally, and CodePen.
</p>

<h2>Who maintains Shepherd</h2>

<p>
Shepherd is maintained by <a href="https://shipshape.io">Ship Shape</a>, a
software consultancy specializing in web app development. Development
happens in the open on
<a href="https://github.com/shipshapecode/shepherd">GitHub</a>, where you
can report issues, propose changes, and follow releases. The library is
published to npm as
<a href="https://www.npmjs.com/package/shepherd.js">shepherd.js</a>.
</p>

<h2>Licensing</h2>

<p>
Shepherd is free for open-source, personal, and non-commercial projects
under the AGPL-3.0 license. Commercial licenses fund the ongoing maintenance
of the library, documentation, and community — see
<a href="/pricing">pricing</a> for details, or read the
<a href="https://docs.shepherdjs.dev/">documentation</a> to get started.
</p>
</ContentPage>
47 changes: 47 additions & 0 deletions landing/src/pages/contact.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
import ContentPage from '@layouts/ContentPage.astro';
---

<ContentPage
title="Contact — Shepherd.js"
description="How to reach the Shepherd.js team: email, GitHub, and Discord."
heading="Contact"
>
<p>
Shepherd is maintained by <a href="https://shipshape.io">Ship Shape</a>.
Whether you have a question about using the library, want to report a bug,
are interested in a commercial license, or would like help building tours
for your product, here is the best way to reach us:
</p>

<ul>
<li>
<strong>Email:</strong>
<a href="mailto:ahoy@shipshape.io">ahoy@shipshape.io</a> — licensing, consulting,
and general inquiries. This is the fastest route for commercial questions.
</li>
<li>
<strong>GitHub:</strong>
<a href="https://github.com/shipshapecode/shepherd/issues">
github.com/shipshapecode/shepherd/issues
</a> — bug reports and feature requests for the library itself.
</li>
<li>
<strong>Discord:</strong>
<a href="https://discord.gg/EGcDW5NSud">join our Discord server</a> — community
chat and support from other Shepherd users and maintainers.
</li>
<li>
<strong>LinkedIn:</strong>
<a href="https://www.linkedin.com/company/ship-shape/">Ship Shape</a> — company
updates.
</li>
</ul>

<p>
For documentation, guides, and the full API reference, visit
<a href="https://docs.shepherdjs.dev/">docs.shepherdjs.dev</a>. For
licensing tiers and purchasing a commercial license, see
<a href="/pricing">pricing</a>.
</p>
</ContentPage>
57 changes: 57 additions & 0 deletions landing/src/pages/privacy.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
import ContentPage from '@layouts/ContentPage.astro';
---

<ContentPage
title="Privacy Policy — Shepherd.js"
description="How the shepherdjs.dev website handles analytics, payments, and personal data."
heading="Privacy Policy"
>
<p>
This policy describes how the shepherdjs.dev website, operated by
<a href="https://shipshape.io">Ship Shape</a>, handles data. It applies to
this website only — not to applications that embed the Shepherd library.
</p>

<h2>What we collect</h2>

<p>
shepherdjs.dev is a static marketing and documentation site. We do not
require accounts, and we do not collect personal information to browse the
site. We use <a href="https://posthog.com/">PostHog</a> for product analytics,
which records anonymous usage data such as pages viewed, referring site, and browser
and device type. This helps us understand which parts of the site and documentation
are useful. PostHog may use cookies or local storage to distinguish visitors;
data is processed on PostHog's US cloud.
</p>

<h2>Payments</h2>

<p>
Commercial license purchases are processed by
<a href="https://polar.sh/">Polar</a>, our checkout provider. Your payment
details are entered on and processed by Polar — they are never sent to or
stored on shepherdjs.dev. Polar shares with us only the information needed
to fulfill your license, such as your name, email address, and order
details.
</p>

<h2>The Shepherd library</h2>

<p>
The Shepherd JavaScript library itself, installed in your own applications,
does not collect, transmit, or store any data about your users. It runs
entirely in the browser of the application that embeds it.
</p>

<h2>Your choices and contact</h2>

<p>
You can block analytics with standard browser tooling (content blockers, Do
Not Track) without affecting your ability to use this site. If you have
questions about this policy, or want data we may hold about you (such as
order records) accessed or deleted, email
<a href="mailto:ahoy@shipshape.io">ahoy@shipshape.io</a>. We will update
this page if our practices change.
</p>
</ContentPage>
29 changes: 29 additions & 0 deletions landing/test/agent-recovery.e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, expect, it } from 'vitest';

import { TEST_BASE_URL } from './setup/dev-server';

describe('404 handling', () => {
it('returns HTTP 404 with recovery links for nonexistent paths', async () => {
const response = await fetch(
`${TEST_BASE_URL}/some-path-that-does-not-exist`
);
const html = await response.text();

expect(response.status).toBe(404);
expect(html).toContain('/llms.txt');
expect(html).toContain('/sitemap-index.xml');
expect(html).toContain('https://docs.shepherdjs.dev');
});
});

describe('llms.txt', () => {
it('serves /llms.txt with when-to-use guidance', async () => {
const response = await fetch(`${TEST_BASE_URL}/llms.txt`);
const body = await response.text();

expect(response.status).toBe(200);
expect(body).toMatch(/^# Shepherd\.js/);
expect(body).toContain('## When to use Shepherd');
expect(body).toContain('https://docs.shepherdjs.dev/');
});
});
19 changes: 19 additions & 0 deletions landing/test/dist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,23 @@ describe.skipIf(!staticDir)('build output', () => {
expect(functionRoutes).toContain('^/$');
expect(functionRoutes).toContain('^/index\\.md/?$');
});

it('includes the trust pages in the sitemap', () => {
const sitemap = readFileSync(join(staticDir!, 'sitemap-0.xml'), 'utf-8');

expect(sitemap).toContain('<loc>https://www.shepherdjs.dev/about/</loc>');
expect(sitemap).toContain('<loc>https://www.shepherdjs.dev/contact/</loc>');
expect(sitemap).toContain('<loc>https://www.shepherdjs.dev/privacy/</loc>');
});

it('emits a 404 page with recovery links', () => {
const notFound = readFileSync(join(staticDir!, '404.html'), 'utf-8');

expect(notFound).toContain('/llms.txt');
expect(notFound).toContain('/sitemap-index.xml');
});

it('emits llms.txt', () => {
expect(existsSync(join(staticDir!, 'llms.txt'))).toBe(true);
});
});
Loading
Loading