nextjs-ide-helper 1.0.0 → 1.1.1
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 +38 -24
- package/lib/index.d.ts +5 -5
- package/lib/index.js +6 -6
- package/lib/loader.js +5 -5
- package/lib/plugin.js +2 -2
- package/lib/withIdeButton.d.ts +7 -0
- package/lib/{withCursorButton.js → withIdeButton.js} +26 -11
- package/package.json +8 -5
- package/src/index.ts +5 -5
- package/src/loader.js +6 -6
- package/src/plugin.js +2 -2
- package/src/{withCursorButton.tsx → withIdeButton.tsx} +32 -13
- package/lib/withCursorButton.d.ts +0 -6
package/README.md
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
# NextJS
|
|
1
|
+
# NextJS IDE Helper
|
|
2
2
|
|
|
3
|
-
A Next.js plugin that automatically adds
|
|
3
|
+
A Next.js plugin that automatically adds IDE buttons to React components in development mode, enabling seamless IDE integration and faster development workflow. Supports Cursor, VS Code, WebStorm, and Atom.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- 🚀 **Automatic Integration**: Automatically wraps React components with
|
|
7
|
+
- 🚀 **Automatic Integration**: Automatically wraps React components with IDE buttons
|
|
8
8
|
- 🎯 **Smart Detection**: Only processes components in specified directories
|
|
9
|
-
- 🔧 **Zero Configuration**: Works out of the box with sensible defaults
|
|
9
|
+
- 🔧 **Zero Configuration**: Works out of the box with sensible defaults (Cursor as default IDE)
|
|
10
10
|
- 🏎️ **Development Only**: Only active in development mode, no production overhead
|
|
11
11
|
- 🎨 **Non-intrusive**: Uses absolute positioning to avoid layout disruption
|
|
12
12
|
- ⚡ **Hydration Safe**: No SSR/client hydration mismatches
|
|
13
13
|
- 📱 **TypeScript Support**: Full TypeScript definitions included
|
|
14
|
+
- 🔌 **Multi-IDE Support**: Supports Cursor, VS Code, WebStorm, and Atom
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
17
18
|
```bash
|
|
18
|
-
npm install nextjs-cursor-helper --save-dev
|
|
19
19
|
# or
|
|
20
|
-
yarn add nextjs-cursor-helper --dev
|
|
21
20
|
# or
|
|
22
|
-
pnpm add nextjs-cursor-helper --save-dev
|
|
23
21
|
```
|
|
24
22
|
|
|
25
23
|
## Quick Start
|
|
@@ -29,36 +27,37 @@ pnpm add nextjs-cursor-helper --save-dev
|
|
|
29
27
|
Add the plugin to your `next.config.js`:
|
|
30
28
|
|
|
31
29
|
```javascript
|
|
32
|
-
const
|
|
30
|
+
const withIdeHelper = require('nextjs-ide-plugin');
|
|
33
31
|
|
|
34
32
|
/** @type {import('next').NextConfig} */
|
|
35
33
|
const nextConfig = {
|
|
36
34
|
// your existing config
|
|
37
35
|
};
|
|
38
36
|
|
|
39
|
-
module.exports =
|
|
37
|
+
module.exports = withIdeHelper()(nextConfig);
|
|
40
38
|
```
|
|
41
39
|
|
|
42
40
|
### 2. That's it!
|
|
43
41
|
|
|
44
|
-
All React components in your `src/components` directory will automatically get
|
|
42
|
+
All React components in your `src/components` directory will automatically get IDE buttons in development mode (defaults to Cursor IDE).
|
|
45
43
|
|
|
46
44
|
## Configuration
|
|
47
45
|
|
|
48
46
|
You can customize the plugin behavior:
|
|
49
47
|
|
|
50
48
|
```javascript
|
|
51
|
-
const
|
|
49
|
+
const withIdeHelper = require('nextjs-ide-plugin');
|
|
52
50
|
|
|
53
51
|
const nextConfig = {
|
|
54
52
|
// your existing config
|
|
55
53
|
};
|
|
56
54
|
|
|
57
|
-
module.exports =
|
|
55
|
+
module.exports = withIdeHelper({
|
|
58
56
|
componentPaths: ['src/components', 'components', 'src/ui'], // directories to scan
|
|
59
57
|
projectRoot: process.cwd(), // project root directory
|
|
60
|
-
importPath: 'nextjs-
|
|
61
|
-
enabled: process.env.NODE_ENV === 'development' // enable/disable
|
|
58
|
+
importPath: 'nextjs-ide-plugin/withIdeButton', // import path for the HOC
|
|
59
|
+
enabled: process.env.NODE_ENV === 'development', // enable/disable
|
|
60
|
+
ideType: 'cursor' // IDE to use: 'cursor', 'vscode', 'webstorm', 'atom'
|
|
62
61
|
})(nextConfig);
|
|
63
62
|
```
|
|
64
63
|
|
|
@@ -68,21 +67,28 @@ module.exports = withCursorHelper({
|
|
|
68
67
|
|--------|------|---------|-------------|
|
|
69
68
|
| `componentPaths` | `string[]` | `['src/components']` | Directories to scan for React components |
|
|
70
69
|
| `projectRoot` | `string` | `process.cwd()` | Root directory of your project |
|
|
71
|
-
| `importPath` | `string` | `'nextjs-
|
|
70
|
+
| `importPath` | `string` | `'nextjs-ide-plugin/withIdeButton'` | Import path for the withIdeButton HOC |
|
|
72
71
|
| `enabled` | `boolean` | `process.env.NODE_ENV === 'development'` | Enable/disable the plugin |
|
|
72
|
+
| `ideType` | `'cursor' \| 'vscode' \| 'webstorm' \| 'atom'` | `'cursor'` | IDE to open files in |
|
|
73
73
|
|
|
74
74
|
## Manual Usage
|
|
75
75
|
|
|
76
76
|
You can also manually wrap components:
|
|
77
77
|
|
|
78
78
|
```tsx
|
|
79
|
-
import {
|
|
79
|
+
import { withIdeButton } from 'nextjs-ide-plugin';
|
|
80
80
|
|
|
81
81
|
const MyComponent = () => {
|
|
82
82
|
return <div>Hello World</div>;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
// Default (Cursor)
|
|
86
|
+
export default withIdeButton(MyComponent, 'src/components/MyComponent.tsx');
|
|
87
|
+
|
|
88
|
+
// With specific IDE
|
|
89
|
+
export default withIdeButton(MyComponent, 'src/components/MyComponent.tsx', {
|
|
90
|
+
ideType: 'vscode'
|
|
91
|
+
});
|
|
86
92
|
```
|
|
87
93
|
|
|
88
94
|
## How It Works
|
|
@@ -90,7 +96,7 @@ export default withCursorButton(MyComponent, 'src/components/MyComponent.tsx');
|
|
|
90
96
|
1. **Webpack Loader**: The plugin uses a custom webpack loader to transform your React components at build time
|
|
91
97
|
2. **Automatic Detection**: It scans specified directories for `.tsx` and `.jsx` files
|
|
92
98
|
3. **Smart Wrapping**: Only wraps components that export a default React component
|
|
93
|
-
4. **Development Only**: The
|
|
99
|
+
4. **Development Only**: The IDE buttons only appear in development mode
|
|
94
100
|
5. **Hydration Safe**: Uses client-side state to prevent SSR/hydration mismatches
|
|
95
101
|
|
|
96
102
|
## Example
|
|
@@ -115,7 +121,7 @@ After (automatically transformed):
|
|
|
115
121
|
```tsx
|
|
116
122
|
// src/components/Button.tsx (transformed by the plugin)
|
|
117
123
|
import React from 'react';
|
|
118
|
-
import {
|
|
124
|
+
import { withIdeButton } from 'nextjs-ide-plugin/withIdeButton';
|
|
119
125
|
|
|
120
126
|
const Button = ({ children, onClick }) => {
|
|
121
127
|
return (
|
|
@@ -125,7 +131,10 @@ const Button = ({ children, onClick }) => {
|
|
|
125
131
|
);
|
|
126
132
|
};
|
|
127
133
|
|
|
128
|
-
export default
|
|
134
|
+
export default withIdeButton(Button, 'src/components/Button.tsx', {
|
|
135
|
+
projectRoot: '/path/to/project',
|
|
136
|
+
ideType: 'cursor' // defaults to cursor, can be 'vscode', 'webstorm', 'atom'
|
|
137
|
+
});
|
|
129
138
|
```
|
|
130
139
|
|
|
131
140
|
## Troubleshooting
|
|
@@ -141,14 +150,19 @@ export default withCursorButton(Button, 'src/components/Button.tsx', { projectRo
|
|
|
141
150
|
The plugin is designed to prevent hydration errors, but if you encounter any:
|
|
142
151
|
|
|
143
152
|
1. Make sure you're using the latest version
|
|
144
|
-
2. Check that the 'use client' directive is present in the
|
|
153
|
+
2. Check that the 'use client' directive is present in the withIdeButton module
|
|
145
154
|
3. File an issue with details about your setup
|
|
146
155
|
|
|
147
|
-
###
|
|
156
|
+
### IDE not opening files
|
|
148
157
|
|
|
149
|
-
1. Ensure you have
|
|
158
|
+
1. Ensure you have your IDE installed and properly configured
|
|
159
|
+
- **Cursor**: Make sure Cursor IDE is installed
|
|
160
|
+
- **VS Code**: Make sure VS Code is installed and set up to handle `vscode://` links
|
|
161
|
+
- **WebStorm**: Ensure WebStorm is installed and configured
|
|
162
|
+
- **Atom**: Make sure Atom is installed (note: Atom is deprecated)
|
|
150
163
|
2. Check that the file paths are correct
|
|
151
|
-
3. Verify your browser allows
|
|
164
|
+
3. Verify your browser allows protocol links for your IDE
|
|
165
|
+
4. Try setting the `ideType` option explicitly in your configuration
|
|
152
166
|
|
|
153
167
|
## Contributing
|
|
154
168
|
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
3
|
-
declare const
|
|
4
|
-
export default
|
|
5
|
-
export {
|
|
1
|
+
export { withIdeButton } from './withIdeButton';
|
|
2
|
+
export type { WithIdeButtonOptions } from './withIdeButton';
|
|
3
|
+
declare const withIdeHelper: any;
|
|
4
|
+
export default withIdeHelper;
|
|
5
|
+
export { withIdeHelper };
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.withIdeHelper = exports.withIdeButton = void 0;
|
|
4
4
|
// Main exports
|
|
5
|
-
var
|
|
6
|
-
Object.defineProperty(exports, "
|
|
5
|
+
var withIdeButton_1 = require("./withIdeButton");
|
|
6
|
+
Object.defineProperty(exports, "withIdeButton", { enumerable: true, get: function () { return withIdeButton_1.withIdeButton; } });
|
|
7
7
|
// Next.js plugin
|
|
8
|
-
const
|
|
9
|
-
exports.
|
|
10
|
-
exports.default =
|
|
8
|
+
const withIdeHelper = require('./plugin');
|
|
9
|
+
exports.withIdeHelper = withIdeHelper;
|
|
10
|
+
exports.default = withIdeHelper;
|
package/lib/loader.js
CHANGED
|
@@ -31,7 +31,7 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Check if it's already wrapped
|
|
34
|
-
if (source.includes('
|
|
34
|
+
if (source.includes('withIdeButton')) {
|
|
35
35
|
return source;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -58,17 +58,17 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
58
58
|
|
|
59
59
|
if (imports.length === 0) {
|
|
60
60
|
// No imports found, add at top
|
|
61
|
-
const importStatement = `import {
|
|
62
|
-
const wrappedExport = `export default
|
|
61
|
+
const importStatement = `import { withIdeButton } from '${importPath}';\n`;
|
|
62
|
+
const wrappedExport = `export default withIdeButton(${componentName}, '${relativePath}', { projectRoot: '${projectRoot}' });`;
|
|
63
63
|
modifiedSource = importStatement + source.replace(/export\s+default\s+\w+;?/, wrappedExport);
|
|
64
64
|
} else {
|
|
65
65
|
const lastImportIndex = source.lastIndexOf(imports[imports.length - 1]) + imports[imports.length - 1].length;
|
|
66
66
|
|
|
67
67
|
// Add import statement
|
|
68
|
-
const importStatement = `\nimport {
|
|
68
|
+
const importStatement = `\nimport { withIdeButton } from '${importPath}';`;
|
|
69
69
|
|
|
70
70
|
// Replace the export
|
|
71
|
-
const wrappedExport = `export default
|
|
71
|
+
const wrappedExport = `export default withIdeButton(${componentName}, '${relativePath}', { projectRoot: '${projectRoot}' });`;
|
|
72
72
|
|
|
73
73
|
modifiedSource = source.slice(0, lastImportIndex) +
|
|
74
74
|
importStatement +
|
package/lib/plugin.js
CHANGED
|
@@ -5,7 +5,7 @@ const path = require('path');
|
|
|
5
5
|
* @typedef {Object} CursorHelperOptions
|
|
6
6
|
* @property {string[]} [componentPaths=['src/components']] - Paths to scan for React components
|
|
7
7
|
* @property {string} [projectRoot=process.cwd()] - Root directory of the project
|
|
8
|
-
* @property {string} [importPath='nextjs-
|
|
8
|
+
* @property {string} [importPath='nextjs-ide-helper/withIdeButton'] - Import path for withIdeButton
|
|
9
9
|
* @property {boolean} [enabled=process.env.NODE_ENV === 'development'] - Enable/disable the plugin
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ function withCursorHelper(options = {}) {
|
|
|
18
18
|
const defaultOptions = {
|
|
19
19
|
componentPaths: ['src/components'],
|
|
20
20
|
projectRoot: process.cwd(),
|
|
21
|
-
importPath: 'nextjs-
|
|
21
|
+
importPath: 'nextjs-ide-helper',
|
|
22
22
|
enabled: process.env.NODE_ENV === 'development'
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface WithIdeButtonOptions {
|
|
3
|
+
projectRoot?: string;
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
ideType?: 'cursor' | 'vscode' | 'webstorm' | 'atom';
|
|
6
|
+
}
|
|
7
|
+
export declare function withIdeButton<T extends object>(WrappedComponent: React.ComponentType<T>, filePath: string, options?: WithIdeButtonOptions): React.FC<T>;
|
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
'use client';
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.withIdeButton = withIdeButton;
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const react_1 = require("react");
|
|
7
|
-
const
|
|
7
|
+
const IdeButton = ({ filePath, projectRoot, ideType = 'cursor' }) => {
|
|
8
|
+
const getIdeUrl = (ide, path) => {
|
|
9
|
+
const fullPath = projectRoot ? `${projectRoot}/${path}` : path;
|
|
10
|
+
switch (ide) {
|
|
11
|
+
case 'cursor':
|
|
12
|
+
return `cursor://file${fullPath}`;
|
|
13
|
+
case 'vscode':
|
|
14
|
+
return `vscode://file${fullPath}`;
|
|
15
|
+
case 'webstorm':
|
|
16
|
+
return `webstorm://open?file=${fullPath}`;
|
|
17
|
+
case 'atom':
|
|
18
|
+
return `atom://open?path=${fullPath}`;
|
|
19
|
+
default:
|
|
20
|
+
return `cursor://file${fullPath}`;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
8
23
|
const handleClick = () => {
|
|
9
|
-
const
|
|
10
|
-
window.open(
|
|
24
|
+
const url = getIdeUrl(ideType, filePath);
|
|
25
|
+
window.open(url, '_blank');
|
|
11
26
|
};
|
|
12
27
|
return ((0, jsx_runtime_1.jsx)("button", { onClick: handleClick, style: {
|
|
13
28
|
position: 'absolute',
|
|
@@ -24,11 +39,11 @@ const CursorButton = ({ filePath, projectRoot }) => {
|
|
|
24
39
|
opacity: 0.7,
|
|
25
40
|
transition: 'opacity 0.2s',
|
|
26
41
|
fontFamily: 'monospace'
|
|
27
|
-
}, onMouseEnter: (e) => (e.currentTarget.style.opacity = '1'), onMouseLeave: (e) => (e.currentTarget.style.opacity = '0.7'), title: `Open ${filePath} in
|
|
42
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.opacity = '1'), onMouseLeave: (e) => (e.currentTarget.style.opacity = '0.7'), title: `Open ${filePath} in ${ideType.toUpperCase()}`, children: "\uD83D\uDCDD" }));
|
|
28
43
|
};
|
|
29
|
-
function
|
|
30
|
-
const { projectRoot, enabled = process.env.NODE_ENV === 'development' } = options;
|
|
31
|
-
const
|
|
44
|
+
function withIdeButton(WrappedComponent, filePath, options = {}) {
|
|
45
|
+
const { projectRoot, enabled = process.env.NODE_ENV === 'development', ideType = 'cursor' } = options;
|
|
46
|
+
const WithIdeButtonComponent = (props) => {
|
|
32
47
|
const [isClient, setIsClient] = (0, react_1.useState)(false);
|
|
33
48
|
(0, react_1.useEffect)(() => {
|
|
34
49
|
setIsClient(true);
|
|
@@ -37,8 +52,8 @@ function withCursorButton(WrappedComponent, filePath, options = {}) {
|
|
|
37
52
|
if (!enabled || !isClient) {
|
|
38
53
|
return (0, jsx_runtime_1.jsx)(WrappedComponent, { ...props });
|
|
39
54
|
}
|
|
40
|
-
return ((0, jsx_runtime_1.jsxs)("div", { style: { position: 'relative' }, children: [(0, jsx_runtime_1.jsx)(
|
|
55
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: { position: 'relative' }, children: [(0, jsx_runtime_1.jsx)(IdeButton, { filePath: filePath, projectRoot: projectRoot, ideType: ideType }), (0, jsx_runtime_1.jsx)(WrappedComponent, { ...props })] }));
|
|
41
56
|
};
|
|
42
|
-
|
|
43
|
-
return
|
|
57
|
+
WithIdeButtonComponent.displayName = `withIdeButton(${WrappedComponent.displayName || WrappedComponent.name})`;
|
|
58
|
+
return WithIdeButtonComponent;
|
|
44
59
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nextjs-ide-helper",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A Next.js plugin that automatically adds
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "A Next.js plugin that automatically adds IDE buttons to React components for seamless IDE integration. Supports Cursor, VS Code, WebStorm, and Atom.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"nextjs",
|
|
18
18
|
"react",
|
|
19
19
|
"cursor",
|
|
20
|
+
"vscode",
|
|
21
|
+
"webstorm",
|
|
22
|
+
"atom",
|
|
20
23
|
"ide",
|
|
21
24
|
"development",
|
|
22
25
|
"webpack",
|
|
@@ -36,10 +39,10 @@
|
|
|
36
39
|
},
|
|
37
40
|
"repository": {
|
|
38
41
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/yourusername/nextjs-
|
|
42
|
+
"url": "https://github.com/yourusername/nextjs-ide-plugin.git"
|
|
40
43
|
},
|
|
41
44
|
"bugs": {
|
|
42
|
-
"url": "https://github.com/yourusername/nextjs-
|
|
45
|
+
"url": "https://github.com/yourusername/nextjs-ide-plugin/issues"
|
|
43
46
|
},
|
|
44
|
-
"homepage": "https://github.com/yourusername/nextjs-
|
|
47
|
+
"homepage": "https://github.com/yourusername/nextjs-ide-plugin#readme"
|
|
45
48
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Main exports
|
|
2
|
-
export {
|
|
3
|
-
export type {
|
|
2
|
+
export { withIdeButton } from './withIdeButton';
|
|
3
|
+
export type { WithIdeButtonOptions } from './withIdeButton';
|
|
4
4
|
|
|
5
5
|
// Next.js plugin
|
|
6
|
-
const
|
|
7
|
-
export default
|
|
8
|
-
export {
|
|
6
|
+
const withIdeHelper = require('./plugin');
|
|
7
|
+
export default withIdeHelper;
|
|
8
|
+
export { withIdeHelper };
|
package/src/loader.js
CHANGED
|
@@ -12,7 +12,7 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
12
12
|
const {
|
|
13
13
|
componentPaths = ['src/components'],
|
|
14
14
|
projectRoot = process.cwd(),
|
|
15
|
-
importPath = 'nextjs-
|
|
15
|
+
importPath = 'nextjs-ide-helper',
|
|
16
16
|
enabled = process.env.NODE_ENV === 'development'
|
|
17
17
|
} = options;
|
|
18
18
|
|
|
@@ -31,7 +31,7 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Check if it's already wrapped
|
|
34
|
-
if (source.includes('
|
|
34
|
+
if (source.includes('withIdeButton')) {
|
|
35
35
|
return source;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -58,17 +58,17 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
58
58
|
|
|
59
59
|
if (imports.length === 0) {
|
|
60
60
|
// No imports found, add at top
|
|
61
|
-
const importStatement = `import {
|
|
62
|
-
const wrappedExport = `export default
|
|
61
|
+
const importStatement = `import { withIdeButton } from '${importPath}';\n`;
|
|
62
|
+
const wrappedExport = `export default withIdeButton(${componentName}, '${relativePath}', { projectRoot: '${projectRoot}' });`;
|
|
63
63
|
modifiedSource = importStatement + source.replace(/export\s+default\s+\w+;?/, wrappedExport);
|
|
64
64
|
} else {
|
|
65
65
|
const lastImportIndex = source.lastIndexOf(imports[imports.length - 1]) + imports[imports.length - 1].length;
|
|
66
66
|
|
|
67
67
|
// Add import statement
|
|
68
|
-
const importStatement = `\nimport {
|
|
68
|
+
const importStatement = `\nimport { withIdeButton } from '${importPath}';`;
|
|
69
69
|
|
|
70
70
|
// Replace the export
|
|
71
|
-
const wrappedExport = `export default
|
|
71
|
+
const wrappedExport = `export default withIdeButton(${componentName}, '${relativePath}', { projectRoot: '${projectRoot}' });`;
|
|
72
72
|
|
|
73
73
|
modifiedSource = source.slice(0, lastImportIndex) +
|
|
74
74
|
importStatement +
|
package/src/plugin.js
CHANGED
|
@@ -5,7 +5,7 @@ const path = require('path');
|
|
|
5
5
|
* @typedef {Object} CursorHelperOptions
|
|
6
6
|
* @property {string[]} [componentPaths=['src/components']] - Paths to scan for React components
|
|
7
7
|
* @property {string} [projectRoot=process.cwd()] - Root directory of the project
|
|
8
|
-
* @property {string} [importPath='nextjs-
|
|
8
|
+
* @property {string} [importPath='nextjs-ide-helper'] - Import path for withIdeButton
|
|
9
9
|
* @property {boolean} [enabled=process.env.NODE_ENV === 'development'] - Enable/disable the plugin
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ function withCursorHelper(options = {}) {
|
|
|
18
18
|
const defaultOptions = {
|
|
19
19
|
componentPaths: ['src/components'],
|
|
20
20
|
projectRoot: process.cwd(),
|
|
21
|
-
importPath: 'nextjs-
|
|
21
|
+
importPath: 'nextjs-ide-helper',
|
|
22
22
|
enabled: process.env.NODE_ENV === 'development'
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import React, { useState, useEffect } from 'react';
|
|
3
3
|
|
|
4
|
-
interface
|
|
4
|
+
interface IdeButtonProps {
|
|
5
5
|
filePath: string;
|
|
6
6
|
projectRoot?: string;
|
|
7
|
+
ideType?: 'cursor' | 'vscode' | 'webstorm' | 'atom';
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const IdeButton: React.FC<IdeButtonProps> = ({ filePath, projectRoot, ideType = 'cursor' }) => {
|
|
11
|
+
const getIdeUrl = (ide: string, path: string) => {
|
|
12
|
+
const fullPath = projectRoot ? `${projectRoot}/${path}` : path;
|
|
13
|
+
|
|
14
|
+
switch (ide) {
|
|
15
|
+
case 'cursor':
|
|
16
|
+
return `cursor://file${fullPath}`;
|
|
17
|
+
case 'vscode':
|
|
18
|
+
return `vscode://file${fullPath}`;
|
|
19
|
+
case 'webstorm':
|
|
20
|
+
return `webstorm://open?file=${fullPath}`;
|
|
21
|
+
case 'atom':
|
|
22
|
+
return `atom://open?path=${fullPath}`;
|
|
23
|
+
default:
|
|
24
|
+
return `cursor://file${fullPath}`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
10
28
|
const handleClick = () => {
|
|
11
|
-
const
|
|
12
|
-
window.open(
|
|
29
|
+
const url = getIdeUrl(ideType, filePath);
|
|
30
|
+
window.open(url, '_blank');
|
|
13
31
|
};
|
|
14
32
|
|
|
15
33
|
return (
|
|
@@ -33,26 +51,27 @@ const CursorButton: React.FC<CursorButtonProps> = ({ filePath, projectRoot }) =>
|
|
|
33
51
|
}}
|
|
34
52
|
onMouseEnter={(e) => (e.currentTarget.style.opacity = '1')}
|
|
35
53
|
onMouseLeave={(e) => (e.currentTarget.style.opacity = '0.7')}
|
|
36
|
-
title={`Open ${filePath} in
|
|
54
|
+
title={`Open ${filePath} in ${ideType.toUpperCase()}`}
|
|
37
55
|
>
|
|
38
56
|
📝
|
|
39
57
|
</button>
|
|
40
58
|
);
|
|
41
59
|
};
|
|
42
60
|
|
|
43
|
-
export interface
|
|
61
|
+
export interface WithIdeButtonOptions {
|
|
44
62
|
projectRoot?: string;
|
|
45
63
|
enabled?: boolean;
|
|
64
|
+
ideType?: 'cursor' | 'vscode' | 'webstorm' | 'atom';
|
|
46
65
|
}
|
|
47
66
|
|
|
48
|
-
export function
|
|
67
|
+
export function withIdeButton<T extends object>(
|
|
49
68
|
WrappedComponent: React.ComponentType<T>,
|
|
50
69
|
filePath: string,
|
|
51
|
-
options:
|
|
70
|
+
options: WithIdeButtonOptions = {}
|
|
52
71
|
) {
|
|
53
|
-
const { projectRoot, enabled = process.env.NODE_ENV === 'development' } = options;
|
|
72
|
+
const { projectRoot, enabled = process.env.NODE_ENV === 'development', ideType = 'cursor' } = options;
|
|
54
73
|
|
|
55
|
-
const
|
|
74
|
+
const WithIdeButtonComponent: React.FC<T> = (props) => {
|
|
56
75
|
const [isClient, setIsClient] = useState(false);
|
|
57
76
|
|
|
58
77
|
useEffect(() => {
|
|
@@ -66,13 +85,13 @@ export function withCursorButton<T extends object>(
|
|
|
66
85
|
|
|
67
86
|
return (
|
|
68
87
|
<div style={{ position: 'relative' }}>
|
|
69
|
-
<
|
|
88
|
+
<IdeButton filePath={filePath} projectRoot={projectRoot} ideType={ideType} />
|
|
70
89
|
<WrappedComponent {...props} />
|
|
71
90
|
</div>
|
|
72
91
|
);
|
|
73
92
|
};
|
|
74
93
|
|
|
75
|
-
|
|
94
|
+
WithIdeButtonComponent.displayName = `withIdeButton(${WrappedComponent.displayName || WrappedComponent.name})`;
|
|
76
95
|
|
|
77
|
-
return
|
|
96
|
+
return WithIdeButtonComponent;
|
|
78
97
|
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export interface WithCursorButtonOptions {
|
|
3
|
-
projectRoot?: string;
|
|
4
|
-
enabled?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare function withCursorButton<T extends object>(WrappedComponent: React.ComponentType<T>, filePath: string, options?: WithCursorButtonOptions): React.FC<T>;
|