@stephenov/feedbackwidget 0.2.2 → 0.3.5
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/dist/auto.d.mts +5 -0
- package/dist/auto.d.ts +5 -0
- package/dist/auto.js +1529 -0
- package/dist/auto.mjs +46 -0
- package/dist/chunk-QQLLK6MC.mjs +1457 -0
- package/dist/cli.js +86 -64
- package/dist/cli.mjs +86 -64
- package/dist/index.mjs +21 -1459
- package/package.json +8 -3
package/dist/cli.js
CHANGED
|
@@ -45,13 +45,6 @@ async function main() {
|
|
|
45
45
|
}
|
|
46
46
|
async function initProject() {
|
|
47
47
|
console.log("\n\u{1F3A4} feedbackwidget - Voice-first feedback for your app\n");
|
|
48
|
-
const existingKey = getStoredApiKey();
|
|
49
|
-
if (existingKey) {
|
|
50
|
-
console.log("\u2705 Already configured!");
|
|
51
|
-
console.log(` API Key: ${existingKey.slice(0, 20)}...`);
|
|
52
|
-
console.log("\n To reconfigure, delete .feedbackwidgetrc and run again.\n");
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
48
|
const state = (0, import_crypto.randomBytes)(16).toString("hex");
|
|
56
49
|
const apiKey = await new Promise((resolve, reject) => {
|
|
57
50
|
const server = import_http.default.createServer((req, res) => {
|
|
@@ -95,48 +88,44 @@ async function initProject() {
|
|
|
95
88
|
reject(new Error("Authentication timed out"));
|
|
96
89
|
}, 5 * 60 * 1e3);
|
|
97
90
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<FeedbackWidget apiKey="${apiKey}" />`;
|
|
91
|
+
const snippet = `<FeedbackWidget apiKey="${apiKey}" />`;
|
|
92
|
+
let copied = false;
|
|
102
93
|
try {
|
|
103
94
|
await copyToClipboard(snippet);
|
|
104
|
-
|
|
105
|
-
console.log(` API Key: ${apiKey.slice(0, 20)}...`);
|
|
106
|
-
console.log(" Saved to .feedbackwidgetrc\n");
|
|
107
|
-
console.log(" \u{1F4CB} Code snippet copied to clipboard! Just paste into your app.\n");
|
|
95
|
+
copied = true;
|
|
108
96
|
} catch {
|
|
109
|
-
console.log("\u2705 Authenticated successfully!\n");
|
|
110
|
-
console.log(` API Key: ${apiKey.slice(0, 20)}...`);
|
|
111
|
-
console.log(" Saved to .feedbackwidgetrc\n");
|
|
112
|
-
console.log(" Add to your app:\n");
|
|
113
|
-
console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"');
|
|
114
|
-
console.log(` <FeedbackWidget apiKey="${apiKey}" />
|
|
115
|
-
`);
|
|
116
97
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
98
|
+
console.log("\u2705 Authenticated!\n");
|
|
99
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
100
|
+
console.log(" Your API Key:\n");
|
|
101
|
+
console.log(` ${apiKey}
|
|
102
|
+
`);
|
|
103
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
104
|
+
if (copied) {
|
|
105
|
+
console.log(" \u{1F4CB} Copied to clipboard!\n");
|
|
123
106
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
107
|
+
const framework = detectFramework();
|
|
108
|
+
console.log(" Add to your app:\n");
|
|
109
|
+
console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"\n');
|
|
110
|
+
console.log(` ${snippet}
|
|
111
|
+
`);
|
|
112
|
+
if (framework.name) {
|
|
113
|
+
console.log(` Detected: ${framework.name}
|
|
114
|
+
`);
|
|
115
|
+
console.log(` Add to: ${framework.file}
|
|
116
|
+
`);
|
|
117
|
+
if (framework.note) {
|
|
118
|
+
console.log(` Note: ${framework.note}
|
|
133
119
|
`);
|
|
134
|
-
} else {
|
|
135
|
-
console.log("\nInvalid API key. Run: npx @stephenov/feedbackwidget init\n");
|
|
136
120
|
}
|
|
137
|
-
}
|
|
138
|
-
console.log("
|
|
121
|
+
} else {
|
|
122
|
+
console.log(" Add to your root component (renders on every page)\n");
|
|
139
123
|
}
|
|
124
|
+
console.log(" Dashboard: https://feedbackwidget-api.vercel.app/dashboard\n");
|
|
125
|
+
}
|
|
126
|
+
async function whoami() {
|
|
127
|
+
console.log("\nRun 'npx feedbackwidget init' to get your API key.\n");
|
|
128
|
+
console.log("Then check your dashboard at: https://feedbackwidget-api.vercel.app/dashboard\n");
|
|
140
129
|
}
|
|
141
130
|
function showHelp() {
|
|
142
131
|
console.log(`
|
|
@@ -151,29 +140,6 @@ Usage:
|
|
|
151
140
|
npx @stephenov/feedbackwidget whoami
|
|
152
141
|
`);
|
|
153
142
|
}
|
|
154
|
-
function getStoredApiKey() {
|
|
155
|
-
const rcPath = import_path.default.join(process.cwd(), ".feedbackwidgetrc");
|
|
156
|
-
try {
|
|
157
|
-
const content = import_fs.default.readFileSync(rcPath, "utf-8");
|
|
158
|
-
const match = content.match(/FEEDBACKWIDGET_API_KEY=(.+)/);
|
|
159
|
-
return match ? match[1].trim() : null;
|
|
160
|
-
} catch {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function saveApiKey(apiKey) {
|
|
165
|
-
const rcPath = import_path.default.join(process.cwd(), ".feedbackwidgetrc");
|
|
166
|
-
import_fs.default.writeFileSync(rcPath, `FEEDBACKWIDGET_API_KEY=${apiKey}
|
|
167
|
-
`);
|
|
168
|
-
const gitignorePath = import_path.default.join(process.cwd(), ".gitignore");
|
|
169
|
-
try {
|
|
170
|
-
const gitignore = import_fs.default.readFileSync(gitignorePath, "utf-8");
|
|
171
|
-
if (!gitignore.includes(".feedbackwidgetrc")) {
|
|
172
|
-
import_fs.default.appendFileSync(gitignorePath, "\n.feedbackwidgetrc\n");
|
|
173
|
-
}
|
|
174
|
-
} catch {
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
143
|
function successPage() {
|
|
178
144
|
return `
|
|
179
145
|
<!DOCTYPE html>
|
|
@@ -220,6 +186,62 @@ function errorPage(error) {
|
|
|
220
186
|
</body>
|
|
221
187
|
</html>`;
|
|
222
188
|
}
|
|
189
|
+
function detectFramework() {
|
|
190
|
+
const cwd = process.cwd();
|
|
191
|
+
try {
|
|
192
|
+
const pkgPath = import_path.default.join(cwd, "package.json");
|
|
193
|
+
const pkg = JSON.parse(import_fs.default.readFileSync(pkgPath, "utf-8"));
|
|
194
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
195
|
+
if (deps.next && import_fs.default.existsSync(import_path.default.join(cwd, "app"))) {
|
|
196
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "app", "layout.tsx"))) {
|
|
197
|
+
return { name: "Next.js (App Router)", file: "app/layout.tsx", note: "Add inside <body> before {children}" };
|
|
198
|
+
}
|
|
199
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "app", "layout.js"))) {
|
|
200
|
+
return { name: "Next.js (App Router)", file: "app/layout.js", note: "Add inside <body> before {children}" };
|
|
201
|
+
}
|
|
202
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "app", "layout.tsx"))) {
|
|
203
|
+
return { name: "Next.js (App Router)", file: "src/app/layout.tsx", note: "Add inside <body> before {children}" };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (deps.next && import_fs.default.existsSync(import_path.default.join(cwd, "pages"))) {
|
|
207
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "pages", "_app.tsx"))) {
|
|
208
|
+
return { name: "Next.js (Pages Router)", file: "pages/_app.tsx", note: "Add after <Component {...pageProps} />" };
|
|
209
|
+
}
|
|
210
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "pages", "_app.js"))) {
|
|
211
|
+
return { name: "Next.js (Pages Router)", file: "pages/_app.js", note: "Add after <Component {...pageProps} />" };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (deps.vite && (deps.react || deps["@vitejs/plugin-react"])) {
|
|
215
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.tsx"))) {
|
|
216
|
+
return { name: "Vite + React", file: "src/App.tsx", note: "Add at the end of your App component" };
|
|
217
|
+
}
|
|
218
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.jsx"))) {
|
|
219
|
+
return { name: "Vite + React", file: "src/App.jsx", note: "Add at the end of your App component" };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (deps["react-scripts"]) {
|
|
223
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.tsx"))) {
|
|
224
|
+
return { name: "Create React App", file: "src/App.tsx", note: "Add at the end of your App component" };
|
|
225
|
+
}
|
|
226
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "src", "App.js"))) {
|
|
227
|
+
return { name: "Create React App", file: "src/App.js", note: "Add at the end of your App component" };
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (deps.astro) {
|
|
231
|
+
return { name: "Astro", file: "Create a React component", note: "Use client:load directive" };
|
|
232
|
+
}
|
|
233
|
+
if (deps["@remix-run/react"]) {
|
|
234
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "app", "root.tsx"))) {
|
|
235
|
+
return { name: "Remix", file: "app/root.tsx", note: "Add inside <body>" };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (deps.react) {
|
|
239
|
+
return { name: "React", file: "Your main App component", note: "Add anywhere it renders on every page" };
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
return { name: null, file: "Your root component" };
|
|
244
|
+
}
|
|
223
245
|
async function copyToClipboard(text) {
|
|
224
246
|
return new Promise((resolve, reject) => {
|
|
225
247
|
const platform = process.platform;
|
package/dist/cli.mjs
CHANGED
|
@@ -22,13 +22,6 @@ async function main() {
|
|
|
22
22
|
}
|
|
23
23
|
async function initProject() {
|
|
24
24
|
console.log("\n\u{1F3A4} feedbackwidget - Voice-first feedback for your app\n");
|
|
25
|
-
const existingKey = getStoredApiKey();
|
|
26
|
-
if (existingKey) {
|
|
27
|
-
console.log("\u2705 Already configured!");
|
|
28
|
-
console.log(` API Key: ${existingKey.slice(0, 20)}...`);
|
|
29
|
-
console.log("\n To reconfigure, delete .feedbackwidgetrc and run again.\n");
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
25
|
const state = randomBytes(16).toString("hex");
|
|
33
26
|
const apiKey = await new Promise((resolve, reject) => {
|
|
34
27
|
const server = http.createServer((req, res) => {
|
|
@@ -72,48 +65,44 @@ async function initProject() {
|
|
|
72
65
|
reject(new Error("Authentication timed out"));
|
|
73
66
|
}, 5 * 60 * 1e3);
|
|
74
67
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
<FeedbackWidget apiKey="${apiKey}" />`;
|
|
68
|
+
const snippet = `<FeedbackWidget apiKey="${apiKey}" />`;
|
|
69
|
+
let copied = false;
|
|
79
70
|
try {
|
|
80
71
|
await copyToClipboard(snippet);
|
|
81
|
-
|
|
82
|
-
console.log(` API Key: ${apiKey.slice(0, 20)}...`);
|
|
83
|
-
console.log(" Saved to .feedbackwidgetrc\n");
|
|
84
|
-
console.log(" \u{1F4CB} Code snippet copied to clipboard! Just paste into your app.\n");
|
|
72
|
+
copied = true;
|
|
85
73
|
} catch {
|
|
86
|
-
console.log("\u2705 Authenticated successfully!\n");
|
|
87
|
-
console.log(` API Key: ${apiKey.slice(0, 20)}...`);
|
|
88
|
-
console.log(" Saved to .feedbackwidgetrc\n");
|
|
89
|
-
console.log(" Add to your app:\n");
|
|
90
|
-
console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"');
|
|
91
|
-
console.log(` <FeedbackWidget apiKey="${apiKey}" />
|
|
92
|
-
`);
|
|
93
74
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
75
|
+
console.log("\u2705 Authenticated!\n");
|
|
76
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
77
|
+
console.log(" Your API Key:\n");
|
|
78
|
+
console.log(` ${apiKey}
|
|
79
|
+
`);
|
|
80
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
81
|
+
if (copied) {
|
|
82
|
+
console.log(" \u{1F4CB} Copied to clipboard!\n");
|
|
100
83
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
84
|
+
const framework = detectFramework();
|
|
85
|
+
console.log(" Add to your app:\n");
|
|
86
|
+
console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"\n');
|
|
87
|
+
console.log(` ${snippet}
|
|
88
|
+
`);
|
|
89
|
+
if (framework.name) {
|
|
90
|
+
console.log(` Detected: ${framework.name}
|
|
91
|
+
`);
|
|
92
|
+
console.log(` Add to: ${framework.file}
|
|
93
|
+
`);
|
|
94
|
+
if (framework.note) {
|
|
95
|
+
console.log(` Note: ${framework.note}
|
|
110
96
|
`);
|
|
111
|
-
} else {
|
|
112
|
-
console.log("\nInvalid API key. Run: npx @stephenov/feedbackwidget init\n");
|
|
113
97
|
}
|
|
114
|
-
}
|
|
115
|
-
console.log("
|
|
98
|
+
} else {
|
|
99
|
+
console.log(" Add to your root component (renders on every page)\n");
|
|
116
100
|
}
|
|
101
|
+
console.log(" Dashboard: https://feedbackwidget-api.vercel.app/dashboard\n");
|
|
102
|
+
}
|
|
103
|
+
async function whoami() {
|
|
104
|
+
console.log("\nRun 'npx feedbackwidget init' to get your API key.\n");
|
|
105
|
+
console.log("Then check your dashboard at: https://feedbackwidget-api.vercel.app/dashboard\n");
|
|
117
106
|
}
|
|
118
107
|
function showHelp() {
|
|
119
108
|
console.log(`
|
|
@@ -128,29 +117,6 @@ Usage:
|
|
|
128
117
|
npx @stephenov/feedbackwidget whoami
|
|
129
118
|
`);
|
|
130
119
|
}
|
|
131
|
-
function getStoredApiKey() {
|
|
132
|
-
const rcPath = path.join(process.cwd(), ".feedbackwidgetrc");
|
|
133
|
-
try {
|
|
134
|
-
const content = fs.readFileSync(rcPath, "utf-8");
|
|
135
|
-
const match = content.match(/FEEDBACKWIDGET_API_KEY=(.+)/);
|
|
136
|
-
return match ? match[1].trim() : null;
|
|
137
|
-
} catch {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function saveApiKey(apiKey) {
|
|
142
|
-
const rcPath = path.join(process.cwd(), ".feedbackwidgetrc");
|
|
143
|
-
fs.writeFileSync(rcPath, `FEEDBACKWIDGET_API_KEY=${apiKey}
|
|
144
|
-
`);
|
|
145
|
-
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
146
|
-
try {
|
|
147
|
-
const gitignore = fs.readFileSync(gitignorePath, "utf-8");
|
|
148
|
-
if (!gitignore.includes(".feedbackwidgetrc")) {
|
|
149
|
-
fs.appendFileSync(gitignorePath, "\n.feedbackwidgetrc\n");
|
|
150
|
-
}
|
|
151
|
-
} catch {
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
120
|
function successPage() {
|
|
155
121
|
return `
|
|
156
122
|
<!DOCTYPE html>
|
|
@@ -197,6 +163,62 @@ function errorPage(error) {
|
|
|
197
163
|
</body>
|
|
198
164
|
</html>`;
|
|
199
165
|
}
|
|
166
|
+
function detectFramework() {
|
|
167
|
+
const cwd = process.cwd();
|
|
168
|
+
try {
|
|
169
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
170
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
171
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
172
|
+
if (deps.next && fs.existsSync(path.join(cwd, "app"))) {
|
|
173
|
+
if (fs.existsSync(path.join(cwd, "app", "layout.tsx"))) {
|
|
174
|
+
return { name: "Next.js (App Router)", file: "app/layout.tsx", note: "Add inside <body> before {children}" };
|
|
175
|
+
}
|
|
176
|
+
if (fs.existsSync(path.join(cwd, "app", "layout.js"))) {
|
|
177
|
+
return { name: "Next.js (App Router)", file: "app/layout.js", note: "Add inside <body> before {children}" };
|
|
178
|
+
}
|
|
179
|
+
if (fs.existsSync(path.join(cwd, "src", "app", "layout.tsx"))) {
|
|
180
|
+
return { name: "Next.js (App Router)", file: "src/app/layout.tsx", note: "Add inside <body> before {children}" };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (deps.next && fs.existsSync(path.join(cwd, "pages"))) {
|
|
184
|
+
if (fs.existsSync(path.join(cwd, "pages", "_app.tsx"))) {
|
|
185
|
+
return { name: "Next.js (Pages Router)", file: "pages/_app.tsx", note: "Add after <Component {...pageProps} />" };
|
|
186
|
+
}
|
|
187
|
+
if (fs.existsSync(path.join(cwd, "pages", "_app.js"))) {
|
|
188
|
+
return { name: "Next.js (Pages Router)", file: "pages/_app.js", note: "Add after <Component {...pageProps} />" };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (deps.vite && (deps.react || deps["@vitejs/plugin-react"])) {
|
|
192
|
+
if (fs.existsSync(path.join(cwd, "src", "App.tsx"))) {
|
|
193
|
+
return { name: "Vite + React", file: "src/App.tsx", note: "Add at the end of your App component" };
|
|
194
|
+
}
|
|
195
|
+
if (fs.existsSync(path.join(cwd, "src", "App.jsx"))) {
|
|
196
|
+
return { name: "Vite + React", file: "src/App.jsx", note: "Add at the end of your App component" };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (deps["react-scripts"]) {
|
|
200
|
+
if (fs.existsSync(path.join(cwd, "src", "App.tsx"))) {
|
|
201
|
+
return { name: "Create React App", file: "src/App.tsx", note: "Add at the end of your App component" };
|
|
202
|
+
}
|
|
203
|
+
if (fs.existsSync(path.join(cwd, "src", "App.js"))) {
|
|
204
|
+
return { name: "Create React App", file: "src/App.js", note: "Add at the end of your App component" };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (deps.astro) {
|
|
208
|
+
return { name: "Astro", file: "Create a React component", note: "Use client:load directive" };
|
|
209
|
+
}
|
|
210
|
+
if (deps["@remix-run/react"]) {
|
|
211
|
+
if (fs.existsSync(path.join(cwd, "app", "root.tsx"))) {
|
|
212
|
+
return { name: "Remix", file: "app/root.tsx", note: "Add inside <body>" };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (deps.react) {
|
|
216
|
+
return { name: "React", file: "Your main App component", note: "Add anywhere it renders on every page" };
|
|
217
|
+
}
|
|
218
|
+
} catch {
|
|
219
|
+
}
|
|
220
|
+
return { name: null, file: "Your root component" };
|
|
221
|
+
}
|
|
200
222
|
async function copyToClipboard(text) {
|
|
201
223
|
return new Promise((resolve, reject) => {
|
|
202
224
|
const platform = process.platform;
|