feat: 添加 husky 和 lint-staged 支持,配置 prettier 进行代码格式化
This commit is contained in:
@@ -0,0 +1 @@
|
||||
npx lint-staged
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": false,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
+32
-46
@@ -1,5 +1,4 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { copyToClipboard } from '@/utils/chromeUtils';
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
|
||||
const CopyButton = ({
|
||||
text = '要复制的文本',
|
||||
@@ -7,14 +6,13 @@ const CopyButton = ({
|
||||
className = 'action-btn',
|
||||
successMessage = '复制成功!',
|
||||
errorMessage = '复制失败,请手动复制。',
|
||||
onCopyOverride = null,
|
||||
}) => {
|
||||
const [status, setStatus] = useState('idle'); // 'idle' | 'copying' | 'success' | 'error'
|
||||
|
||||
useEffect(() => {
|
||||
let timer;
|
||||
let timer: number;
|
||||
if (status === 'success' || status === 'error') {
|
||||
timer = setTimeout(() => {
|
||||
timer = window.setTimeout(() => {
|
||||
setStatus('idle');
|
||||
}, 2000);
|
||||
}
|
||||
@@ -30,29 +28,15 @@ const CopyButton = ({
|
||||
|
||||
const safeText = String(text);
|
||||
|
||||
// 优先使用传入的复制函数
|
||||
if (onCopyOverride) {
|
||||
return await onCopyOverride(safeText);
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(safeText);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error('使用 Clipboard API 复制失败:', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = safeText;
|
||||
|
||||
// 确保元素存在但不可见,且不影响布局
|
||||
textArea.style.position = "fixed";
|
||||
textArea.style.left = "-9999px";
|
||||
textArea.style.top = "0";
|
||||
textArea.style.opacity = "0";
|
||||
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
const successful = document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
|
||||
// 使用通用的复制函数
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
@@ -65,35 +49,37 @@ const CopyButton = ({
|
||||
console.error('复制时出错:', error);
|
||||
setStatus('error');
|
||||
}
|
||||
}, [text, onCopyOverride]);
|
||||
}, [text]);
|
||||
|
||||
// 根据状态计算当前显示的文本
|
||||
const currentText = status === 'success' ? successMessage
|
||||
: status === 'error' ? errorMessage
|
||||
: buttonText;
|
||||
const currentText =
|
||||
status === 'success' ? successMessage : status === 'error' ? errorMessage : buttonText;
|
||||
|
||||
// 根据状态计算样式 (建议使用 CSS Module 或 Tailwind,这里为了演示保留内联)
|
||||
const getBackgroundColor = () => {
|
||||
switch (status) {
|
||||
case 'success': return '#4CAF50';
|
||||
case 'error': return '#f44336';
|
||||
default: return '#4CAF50'; // 让 CSS 类控制默认颜色
|
||||
// 动态样式:只在非默认状态下覆盖颜色,平时让 className 控制
|
||||
const getStyle = () => {
|
||||
const baseStyle = {
|
||||
transition: 'all 0.3s ease',
|
||||
cursor: 'pointer', // 确保有手型光标
|
||||
// 这里去掉了 padding/border/radius 的硬编码,建议在 CSS 类中定义
|
||||
// 除非你想强制覆盖
|
||||
};
|
||||
|
||||
if (status === 'success') {
|
||||
return { ...baseStyle, backgroundColor: '#4CAF50', color: 'white' };
|
||||
}
|
||||
if (status === 'error') {
|
||||
return { ...baseStyle, backgroundColor: '#f44336', color: 'white' };
|
||||
}
|
||||
|
||||
return baseStyle;
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={handleClick}
|
||||
className={`${className} ${status} copy-button`}
|
||||
style={{
|
||||
backgroundColor: getBackgroundColor(),
|
||||
color: status !== 'idle' ? 'white' : undefined,
|
||||
transition: 'all 0.3s ease',
|
||||
padding: '8px 16px',
|
||||
border: 'none',
|
||||
borderRadius: '8px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
style={getStyle()}
|
||||
disabled={status === 'copying'}
|
||||
>
|
||||
{currentText}
|
||||
</button>
|
||||
|
||||
@@ -1,30 +1,3 @@
|
||||
export default defineBackground(() => {
|
||||
console.log('Hello background!', { id: browser.runtime.id });
|
||||
|
||||
console.log('Background script loaded');
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
console.log('收到消息:', request);
|
||||
|
||||
if (request.action === 'copy') {
|
||||
console.log('开始复制文本:', request.text);
|
||||
|
||||
navigator.clipboard
|
||||
.writeText(request.text)
|
||||
.then(() => {
|
||||
console.log('复制成功');
|
||||
sendResponse({ success: true });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('复制失败:', err);
|
||||
sendResponse({ success: false, error: err.message });
|
||||
});
|
||||
|
||||
return true; // 保持消息端口开放以支持异步响应
|
||||
}
|
||||
|
||||
// 对于未知的操作,也返回响应
|
||||
sendResponse({ success: false, error: '未知操作' });
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
</head>
|
||||
<body>
|
||||
Hello Options Page
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Generated
+207
@@ -33,6 +33,9 @@
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@wxt-dev/module-react": "^1.1.5",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.7",
|
||||
"prettier": "^3.8.1",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "^0.20.6"
|
||||
}
|
||||
@@ -3634,6 +3637,22 @@
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/husky": {
|
||||
"version": "9.1.7",
|
||||
"resolved": "https://registry.npmmirror.com/husky/-/husky-9.1.7.tgz",
|
||||
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"husky": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz",
|
||||
@@ -4198,6 +4217,139 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged": {
|
||||
"version": "16.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-16.2.7.tgz",
|
||||
"integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^14.0.2",
|
||||
"listr2": "^9.0.5",
|
||||
"micromatch": "^4.0.8",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"pidtree": "^0.6.0",
|
||||
"string-argv": "^0.3.2",
|
||||
"yaml": "^2.8.1"
|
||||
},
|
||||
"bin": {
|
||||
"lint-staged": "bin/lint-staged.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/lint-staged"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/cli-truncate": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-5.1.1.tgz",
|
||||
"integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"slice-ansi": "^7.1.0",
|
||||
"string-width": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/commander": {
|
||||
"version": "14.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/commander/-/commander-14.0.2.tgz",
|
||||
"integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/is-fullwidth-code-point": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
|
||||
"integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/listr2": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/listr2/-/listr2-9.0.5.tgz",
|
||||
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cli-truncate": "^5.0.0",
|
||||
"colorette": "^2.0.20",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"log-update": "^6.1.0",
|
||||
"rfdc": "^1.4.1",
|
||||
"wrap-ansi": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/nano-spawn": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/nano-spawn/-/nano-spawn-2.0.0.tgz",
|
||||
"integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/slice-ansi": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-7.1.2.tgz",
|
||||
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"is-fullwidth-code-point": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged/node_modules/string-width": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-8.1.0.tgz",
|
||||
"integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.3.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2": {
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/listr2/-/listr2-8.3.3.tgz",
|
||||
@@ -5278,6 +5430,19 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pidtree": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/pidtree/-/pidtree-0.6.0.tgz",
|
||||
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"pidtree": "bin/pidtree.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pino": {
|
||||
"version": "9.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/pino/-/pino-9.7.0.tgz",
|
||||
@@ -5358,6 +5523,22 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.8.1.tgz",
|
||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
@@ -6251,6 +6432,16 @@
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-argv": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.2.tgz",
|
||||
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.19"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz",
|
||||
@@ -7160,6 +7351,22 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.8.2.tgz",
|
||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz",
|
||||
|
||||
+12
-3
@@ -4,6 +4,11 @@
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx,json,css,scss,md}": [
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
"dev:firefox": "wxt -b firefox",
|
||||
@@ -12,11 +17,10 @@
|
||||
"zip": "wxt zip",
|
||||
"zip:firefox": "wxt zip -b firefox",
|
||||
"compile": "tsc --noEmit",
|
||||
"postinstall": "wxt prepare"
|
||||
"postinstall": "wxt prepare",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"@rrweb/all": "^2.0.0-alpha.18",
|
||||
"@rrweb/rrweb-plugin-console-record": "^2.0.0-alpha.18",
|
||||
"@rrweb/rrweb-plugin-console-replay": "^2.0.0-alpha.18",
|
||||
@@ -27,6 +31,8 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"dexie": "^4.2.1",
|
||||
"dexie-react-hooks": "^4.2.0",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-markdown": "^6.0.3",
|
||||
"react-router-dom": "^6.30.2",
|
||||
"remark-gfm": "^1.0.0",
|
||||
@@ -39,6 +45,9 @@
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@wxt-dev/module-react": "^1.1.5",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.7",
|
||||
"prettier": "^3.8.1",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "^0.20.6"
|
||||
}
|
||||
|
||||
+18
-17
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
// import {sendRecordCommand} from '../services/bridge'
|
||||
// import {storage} from "../services/storage";
|
||||
import {useRecorder} from "../hooks/useRecorder";
|
||||
import {downloadHtml} from '../utils/recordUtils';
|
||||
import { useRecorder } from '../hooks/useRecorder';
|
||||
import { downloadHtml } from '../utils/recordUtils';
|
||||
|
||||
const RecordeReplayPage = () => {
|
||||
// const [isRecording, setIsRecording] = useState(false);
|
||||
|
||||
const {startRecord, stopRecord, getEvents, isRecording} = useRecorder();
|
||||
|
||||
|
||||
const { startRecord, stopRecord, getEvents, isRecording } = useRecorder();
|
||||
|
||||
const handleStart = async () => {
|
||||
try {
|
||||
// await sendRecordCommand("START_RECORD");
|
||||
@@ -20,10 +20,10 @@ const RecordeReplayPage = () => {
|
||||
// await storage.set({isRecording: true, recordingStartTime: Date.now()});
|
||||
// console.log('events', events);
|
||||
} catch (e) {
|
||||
console.error("Error starting recording:", e);
|
||||
console.error('Error starting recording:', e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const handleStop = async () => {
|
||||
try {
|
||||
// await sendRecordCommand("STOP_RECORD");
|
||||
@@ -35,24 +35,25 @@ const RecordeReplayPage = () => {
|
||||
downloadHtml(getEvents());
|
||||
// console.log('events', getEvents());
|
||||
} catch (e) {
|
||||
console.error("Error stopping recording:", e)
|
||||
console.error('Error stopping recording:', e);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div style={{width: "300px", padding: "16px"}}>
|
||||
<div style={{ width: '300px', padding: '16px' }}>
|
||||
<h3>RRWeb Recorder</h3>
|
||||
|
||||
|
||||
{/* 3. 选择标签页逻辑:默认为当前页,如果需要跨页,需先列出 chrome.tabs.query */}
|
||||
|
||||
<div style={{display: "flex", gap: "10px", marginBottom: "20px"}}>
|
||||
|
||||
<div style={{ display: 'flex', gap: '10px', marginBottom: '20px' }}>
|
||||
{!isRecording ? (
|
||||
<button onClick={handleStart} className={"action-btn"}>
|
||||
<button onClick={handleStart} className={'action-btn'}>
|
||||
开始录制
|
||||
</button>
|
||||
) : (
|
||||
<button className={"action-btn stop-btn"}
|
||||
onClick={handleStop}>停止录制</button>
|
||||
<button className={'action-btn stop-btn'} onClick={handleStop}>
|
||||
停止录制
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+10
-10
@@ -1,15 +1,15 @@
|
||||
import {TimestampToDatetime} from "../components/TimestampToDatetime";
|
||||
import {DatetimeToTimestamp} from "../components/DatetimeToTimestamp";
|
||||
import {TimestampExecution} from "../components/TimestampExecution";
|
||||
|
||||
import { TimestampToDatetime } from '../components/TimestampToDatetime';
|
||||
import { DatetimeToTimestamp } from '../components/DatetimeToTimestamp';
|
||||
import { TimestampExecution } from '../components/TimestampExecution';
|
||||
|
||||
const TimestampPage = () => {
|
||||
|
||||
return (<div className="timestamp-utils">
|
||||
<TimestampExecution/>
|
||||
<TimestampToDatetime/>
|
||||
<DatetimeToTimestamp/>
|
||||
</div>);
|
||||
return (
|
||||
<div className="timestamp-utils">
|
||||
<TimestampExecution />
|
||||
<TimestampToDatetime />
|
||||
<DatetimeToTimestamp />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TimestampPage;
|
||||
|
||||
+39
-2
@@ -1,7 +1,44 @@
|
||||
{
|
||||
"extends": "./.wxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
/* --- 原有配置保持 --- */
|
||||
"allowImportingTsExtensions": true,
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* --- 1. 严格类型检查 (关键) --- */
|
||||
// 开启所有严格检查,包括 noImplicitAny。
|
||||
// 这能帮你捕获 "timer" 隐式 any 等错误,强制你写出更高质量的代码。
|
||||
"strict": true,
|
||||
|
||||
/* --- 2. 代码质量检查 --- */
|
||||
// 声明了但没使用的变量报错(防止代码冗余)
|
||||
"noUnusedLocals": true,
|
||||
// 函数参数没使用报错
|
||||
"noUnusedParameters": true,
|
||||
// switch 语句没有 break 时报错
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
/* --- 3. 路径与环境 --- */
|
||||
// 设置基础目录,方便解析相对路径
|
||||
"baseUrl": ".",
|
||||
// 确保包含 DOM 类型(解决 setTimeout、document 等报错)
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
// 编译目标设置为最新,WXT 底层 Vite 会处理降级兼容
|
||||
"target": "ESNext",
|
||||
|
||||
/* --- 4. 路径别名 (可选) --- */
|
||||
// 如果你的 @/utils/... 爆红,可以手动添加这个映射。
|
||||
// WXT 通常会自动处理,但在这里显式声明有助于 VS Code 智能提示。
|
||||
"paths": {
|
||||
"@/*": ["./entrypoints/*", "./components/*", "./utils/*", "./assets/*"]
|
||||
}
|
||||
},
|
||||
// 确保包含你的源代码目录
|
||||
"include": [
|
||||
"entrypoints/**/*",
|
||||
"components/**/*",
|
||||
"utils/**/*",
|
||||
"assets/**/*",
|
||||
".wxt/types/**/*.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user