webdrive 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/bin/webdrive.js +112 -0
- package/package.json +6 -1
- package/skills/webdrive/SKILL.md +212 -0
package/README.md
CHANGED
|
@@ -43,6 +43,26 @@ bun add webdrive
|
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
46
|
+
## 🤖 AI Agent Skill Installation
|
|
47
|
+
|
|
48
|
+
`webdrive` includes an official **Agent Skill** so AI coding assistants (Google Antigravity, Claude Code, Cursor, GitHub Copilot) can automatically help you scaffold, configure, and troubleshoot tours.
|
|
49
|
+
|
|
50
|
+
### Option A: Using WebDrive CLI (Instant)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx webdrive install-skill
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This installs `SKILL.md` into your project's `.agents/skills/webdrive/` folder.
|
|
57
|
+
|
|
58
|
+
### Option B: Using the Agent Skills Ecosystem
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx skills add Abhi-6284/webdrive
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
46
66
|
## 🚀 Quick Start
|
|
47
67
|
|
|
48
68
|
### 1. Import CSS & JavaScript
|
package/bin/webdrive.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const pkg = JSON.parse(
|
|
11
|
+
fs.readFileSync(path.resolve(__dirname, "../package.json"), "utf8")
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
const command = args[0];
|
|
16
|
+
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(`
|
|
19
|
+
\x1b[1m\x1b[34mWebDrive CLI\x1b[0m v${pkg.version}
|
|
20
|
+
Framework-Agnostic UI Tour & Onboarding Library
|
|
21
|
+
|
|
22
|
+
\x1b[1mUsage:\x1b[0m
|
|
23
|
+
webdrive <command> [options]
|
|
24
|
+
npx webdrive <command> [options]
|
|
25
|
+
|
|
26
|
+
\x1b[1mCommands:\x1b[0m
|
|
27
|
+
install-skill Install the WebDrive AI Agent Skill into your project
|
|
28
|
+
help, --help Display this help message
|
|
29
|
+
--version, -v Display the current version
|
|
30
|
+
|
|
31
|
+
\x1b[1mOptions for install-skill:\x1b[0m
|
|
32
|
+
--target <dir> Custom destination directory (default: .agents/skills/webdrive)
|
|
33
|
+
--all Also install to .claude/skills and skills/
|
|
34
|
+
|
|
35
|
+
\x1b[1mExamples:\x1b[0m
|
|
36
|
+
npx webdrive install-skill
|
|
37
|
+
npx skills add Abhi-6284/webdrive
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function installSkill() {
|
|
42
|
+
const cwd = process.cwd();
|
|
43
|
+
const sourceSkillPath = path.resolve(__dirname, "../skills/webdrive/SKILL.md");
|
|
44
|
+
|
|
45
|
+
if (!fs.existsSync(sourceSkillPath)) {
|
|
46
|
+
console.error(`\x1b[31mError: Source SKILL.md not found at ${sourceSkillPath}\x1b[0m`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const skillContent = fs.readFileSync(sourceSkillPath, "utf8");
|
|
51
|
+
|
|
52
|
+
// Determine target directories
|
|
53
|
+
let targets = [path.join(cwd, ".agents", "skills", "webdrive")];
|
|
54
|
+
|
|
55
|
+
const targetFlagIdx = args.indexOf("--target");
|
|
56
|
+
if (targetFlagIdx !== -1 && args[targetFlagIdx + 1]) {
|
|
57
|
+
targets = [path.resolve(cwd, args[targetFlagIdx + 1])];
|
|
58
|
+
} else if (args.includes("--all")) {
|
|
59
|
+
targets = [
|
|
60
|
+
path.join(cwd, ".agents", "skills", "webdrive"),
|
|
61
|
+
path.join(cwd, ".claude", "skills", "webdrive"),
|
|
62
|
+
path.join(cwd, "skills", "webdrive"),
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log(`\x1b[36mInstalling WebDrive AI Agent Skill...\x1b[0m`);
|
|
67
|
+
|
|
68
|
+
for (const targetDir of targets) {
|
|
69
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
70
|
+
const destPath = path.join(targetDir, "SKILL.md");
|
|
71
|
+
fs.writeFileSync(destPath, skillContent, "utf8");
|
|
72
|
+
const relativePath = path.relative(cwd, destPath);
|
|
73
|
+
console.log(`\x1b[32m✔ Installed skill to:\x1b[0m ${relativePath}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`
|
|
77
|
+
\x1b[32m✔ Success!\x1b[0m WebDrive Agent Skill is now ready.
|
|
78
|
+
AI agents (Antigravity, Claude Code, Cursor, Copilot) can now assist you in building,
|
|
79
|
+
customizing, and debugging WebDrive tours automatically.
|
|
80
|
+
`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
switch (command) {
|
|
84
|
+
case "install-skill":
|
|
85
|
+
case "skill":
|
|
86
|
+
case "skill:install":
|
|
87
|
+
case "add-skill":
|
|
88
|
+
installSkill();
|
|
89
|
+
break;
|
|
90
|
+
|
|
91
|
+
case "-v":
|
|
92
|
+
case "--version":
|
|
93
|
+
case "version":
|
|
94
|
+
console.log(`webdrive v${pkg.version}`);
|
|
95
|
+
break;
|
|
96
|
+
|
|
97
|
+
case "help":
|
|
98
|
+
case "--help":
|
|
99
|
+
case "-h":
|
|
100
|
+
printHelp();
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
default:
|
|
104
|
+
if (!command) {
|
|
105
|
+
printHelp();
|
|
106
|
+
} else {
|
|
107
|
+
console.log(`Unknown command: ${command}`);
|
|
108
|
+
printHelp();
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webdrive",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Production-ready, accessible, framework-agnostic TypeScript UI tour and onboarding walkthrough library",
|
|
6
6
|
"author": "webdrive",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"bin": {
|
|
9
|
+
"webdrive": "./bin/webdrive.js"
|
|
10
|
+
},
|
|
8
11
|
"keywords": [
|
|
9
12
|
"tour",
|
|
10
13
|
"onboarding",
|
|
@@ -30,6 +33,8 @@
|
|
|
30
33
|
},
|
|
31
34
|
"files": [
|
|
32
35
|
"dist",
|
|
36
|
+
"bin",
|
|
37
|
+
"skills",
|
|
33
38
|
"README.md",
|
|
34
39
|
"LICENSE"
|
|
35
40
|
],
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webdrive
|
|
3
|
+
description: >-
|
|
4
|
+
Guide for implementing, configuring, and troubleshooting UI product tours, feature walkthroughs,
|
|
5
|
+
and onboarding flows using webdrive (framework-agnostic TypeScript library).
|
|
6
|
+
Use this skill whenever adding an onboarding tour, step-by-step guide, feature highlight, or popover
|
|
7
|
+
walkthrough in Vanilla JS, React, Next.js, Vue, Nuxt, Angular, Svelte, or any web app.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# WebDrive — UI Tour & Onboarding Skill
|
|
11
|
+
|
|
12
|
+
`webdrive` is a production-ready, framework-agnostic TypeScript UI tour and onboarding library with zero runtime dependencies. It uses a non-destructive SVG cutout mask to highlight target elements without altering stacking contexts, z-index, or CSS transforms.
|
|
13
|
+
|
|
14
|
+
## Quick Installation & Setup
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install webdrive
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Essential Imports
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { WebDrive } from "webdrive";
|
|
24
|
+
import "webdrive/styles.css";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> **IMPORTANT:** In Next.js App Router, always import and initialize `WebDrive` inside Client Components (`"use client"`). It is 100% SSR-safe and will never crash on server evaluation.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Standard Tour Pattern
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const tour = new WebDrive({
|
|
35
|
+
id: "onboarding-tour", // Used for persistence
|
|
36
|
+
steps: [
|
|
37
|
+
{
|
|
38
|
+
element: "#navigation",
|
|
39
|
+
title: "Navigation",
|
|
40
|
+
description: "Quickly jump to any section of the app.",
|
|
41
|
+
position: "right", // "top" | "right" | "bottom" | "left"
|
|
42
|
+
align: "start", // "start" | "center" | "end"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
element: "#metrics-card",
|
|
46
|
+
title: "Key Metrics",
|
|
47
|
+
description: "Track real-time analytics and revenue performance.",
|
|
48
|
+
position: "bottom",
|
|
49
|
+
align: "center",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
element: "#profile-button",
|
|
53
|
+
title: "Account Settings",
|
|
54
|
+
description: "Manage your profile, team members, and preferences.",
|
|
55
|
+
position: "left",
|
|
56
|
+
align: "end",
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
showProgress: true,
|
|
60
|
+
animate: true,
|
|
61
|
+
smoothScroll: true,
|
|
62
|
+
keyboardNavigation: true,
|
|
63
|
+
allowClose: true,
|
|
64
|
+
remember: true, // Persists completion in localStorage
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Start the tour
|
|
68
|
+
tour.start();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Step Options Reference
|
|
74
|
+
|
|
75
|
+
| Property | Type | Description |
|
|
76
|
+
| :--- | :--- | :--- |
|
|
77
|
+
| `element` | `string \| HTMLElement` | Target CSS selector or DOM element (Required) |
|
|
78
|
+
| `title` | `string` | Header title |
|
|
79
|
+
| `description` | `string` | Safe text content for the popover card |
|
|
80
|
+
| `content` | `string` | Custom HTML content when rich markup is needed |
|
|
81
|
+
| `position` | `"top" \| "right" \| "bottom" \| "left"` | Preferred popover placement (default: `"bottom"`) |
|
|
82
|
+
| `align` | `"start" \| "center" \| "end"` | Alignment along target axis (default: `"center"`) |
|
|
83
|
+
| `padding` | `number` | Padding around cutout in pixels (default: `8`) |
|
|
84
|
+
| `offset` | `number` | Distance between target and popover in px (default: `12`) |
|
|
85
|
+
| `showNextButton` | `boolean` | Whether to display the Next button |
|
|
86
|
+
| `showPreviousButton`| `boolean` | Whether to display the Previous button |
|
|
87
|
+
| `showCloseButton` | `boolean` | Whether to display the Close button |
|
|
88
|
+
| `nextButtonText` | `string` | Custom label for Next button |
|
|
89
|
+
| `previousButtonText`| `string` | Custom label for Previous button |
|
|
90
|
+
| `doneButtonText` | `string` | Custom label for Done button on final step |
|
|
91
|
+
| `closeButtonText` | `string` | Custom label / aria-label for Close button |
|
|
92
|
+
| `onEnter` | `() => void \| Promise<void>` | Callback when entering step |
|
|
93
|
+
| `onLeave` | `() => void \| Promise<void>` | Callback when leaving step |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Dynamic Elements & Async Content
|
|
98
|
+
|
|
99
|
+
If a target element is created dynamically or loads after an API call:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const tour = new WebDrive({
|
|
103
|
+
missingElementBehavior: "wait", // "wait" | "skip" | "stop"
|
|
104
|
+
missingElementWaitTimeout: 4000, // Timeout in ms before falling back
|
|
105
|
+
steps: [
|
|
106
|
+
{ element: "#async-chart", title: "Charts", description: "Loaded dynamically." }
|
|
107
|
+
]
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Framework Recipes
|
|
114
|
+
|
|
115
|
+
### React & Next.js (`"use client"`)
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
"use client";
|
|
119
|
+
|
|
120
|
+
import { useEffect, useRef } from "react";
|
|
121
|
+
import { WebDrive } from "webdrive";
|
|
122
|
+
import "webdrive/styles.css";
|
|
123
|
+
|
|
124
|
+
export function ProductTour() {
|
|
125
|
+
const tourRef = useRef<WebDrive | null>(null);
|
|
126
|
+
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
tourRef.current = new WebDrive({
|
|
129
|
+
id: "app-intro",
|
|
130
|
+
remember: true,
|
|
131
|
+
steps: [
|
|
132
|
+
{ element: "#sidebar", title: "Menu", description: "Navigate here." },
|
|
133
|
+
{ element: "#main-cta", title: "Action", description: "Get started here." }
|
|
134
|
+
]
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
tourRef.current.start();
|
|
138
|
+
|
|
139
|
+
return () => {
|
|
140
|
+
tourRef.current?.destroy();
|
|
141
|
+
};
|
|
142
|
+
}, []);
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Vue 3 / Nuxt
|
|
149
|
+
|
|
150
|
+
```vue
|
|
151
|
+
<script setup>
|
|
152
|
+
import { onMounted, onUnmounted } from "vue";
|
|
153
|
+
import { WebDrive } from "webdrive";
|
|
154
|
+
import "webdrive/styles.css";
|
|
155
|
+
|
|
156
|
+
let tour = null;
|
|
157
|
+
|
|
158
|
+
onMounted(() => {
|
|
159
|
+
tour = new WebDrive({
|
|
160
|
+
steps: [
|
|
161
|
+
{ element: "#header", title: "Header", description: "Overview." }
|
|
162
|
+
]
|
|
163
|
+
});
|
|
164
|
+
tour.start();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
onUnmounted(() => {
|
|
168
|
+
tour?.destroy();
|
|
169
|
+
});
|
|
170
|
+
</script>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Theming & Styling
|
|
176
|
+
|
|
177
|
+
Customize colors using CSS custom properties:
|
|
178
|
+
|
|
179
|
+
```css
|
|
180
|
+
:root {
|
|
181
|
+
--webdrive-background: #ffffff;
|
|
182
|
+
--webdrive-foreground: #0f172a;
|
|
183
|
+
--webdrive-border: #e2e8f0;
|
|
184
|
+
--webdrive-primary: #2563eb;
|
|
185
|
+
--webdrive-primary-foreground: #ffffff;
|
|
186
|
+
--webdrive-muted: #64748b;
|
|
187
|
+
--webdrive-overlay: rgba(0, 0, 0, 0.6);
|
|
188
|
+
--webdrive-radius: 0.75rem;
|
|
189
|
+
--webdrive-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
|
190
|
+
--webdrive-z-index: 100000;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* Dark Mode automatically applied when .dark or [data-theme="dark"] is present */
|
|
194
|
+
.dark {
|
|
195
|
+
--webdrive-background: #0f172a;
|
|
196
|
+
--webdrive-foreground: #f8fafc;
|
|
197
|
+
--webdrive-border: #1e293b;
|
|
198
|
+
--webdrive-primary: #3b82f6;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Best Practices & Troubleshooting
|
|
205
|
+
|
|
206
|
+
1. **Always cleanup on unmount:** Call `tour.destroy()` in React's cleanup function, Vue's `onUnmounted`, or Svelte's `onDestroy` to remove DOM elements and listeners.
|
|
207
|
+
2. **Never hardcode generic IDs:** Prefer unique IDs or data attributes (e.g. `[data-tour="search-input"]`).
|
|
208
|
+
3. **Reset tour completion during testing:**
|
|
209
|
+
```typescript
|
|
210
|
+
await tour.reset(); // Clears completion status for this tour
|
|
211
|
+
```
|
|
212
|
+
4. **Do not modify application DOM styles:** WebDrive handles overlays and highlights externally without mutating the target element's styling.
|