Migrate popup UI to Preact and Tailwind CSS
This commit is contained in:
+9
-152
@@ -4,6 +4,14 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>SparkAssist</title>
|
<title>SparkAssist</title>
|
||||||
|
<!-- Modern Typography -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
<script src="./popup.js" defer></script>
|
<script src="./popup.js" defer></script>
|
||||||
<link rel="icon" type="image/png" href="../icon.png" />
|
<link rel="icon" type="image/png" href="../icon.png" />
|
||||||
@@ -12,158 +20,7 @@
|
|||||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
||||||
/>
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<div id="root"></div>
|
||||||
<div class="header">
|
|
||||||
<img src="../icon.png" alt="SparkAssist Logo" />
|
|
||||||
<div class="header-text">
|
|
||||||
<h1>SparkAssist</h1>
|
|
||||||
<p id="version"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- MAIN SETTINGS -->
|
|
||||||
<div class="panel settings" id="settings">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="apiKey">Api Key<span class="required">*</span></label>
|
|
||||||
<input id="apiKey" type="text" placeholder="sk-..." />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="model">GPT Model<span class="required">*</span></label>
|
|
||||||
<div class="input-with-icon">
|
|
||||||
<input type="text" id="model" list="models" placeholder="gpt-4o" />
|
|
||||||
<datalist id="models"></datalist>
|
|
||||||
<i id="check-model" title="Test" class="fa-solid fa-play"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ADVANCED SETTINGS -->
|
|
||||||
<div class="panel settings" id="advanced-settings" style="display: none">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="code">Activation Code</label>
|
|
||||||
<input id="code" type="text" placeholder="Secret key..." />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="baseURL">Base URL</label>
|
|
||||||
<input id="baseURL" type="text" placeholder="https://api.openai.com/v1" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="projectId">Project ID</label>
|
|
||||||
<input id="projectId" type="text" placeholder="proj_..." />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="maxTokens">Max Tokens</label>
|
|
||||||
<input id="maxTokens" type="number" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="timeoutValue">Timeout (s)</label>
|
|
||||||
<input id="timeoutValue" type="number" placeholder="20" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a id="switch-settings" href="#">Show Advanced Settings</a>
|
|
||||||
|
|
||||||
<div class="section-title">
|
|
||||||
<i class="fa-solid fa-bolt"></i>
|
|
||||||
<span>Operating Mode</span>
|
|
||||||
</div>
|
|
||||||
<ul id="mode">
|
|
||||||
<li><button value="autocomplete">autocomplete</button></li>
|
|
||||||
<li><button value="clipboard" class="not-selected">clipboard</button></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="section-title">
|
|
||||||
<i class="fa-solid fa-sliders"></i>
|
|
||||||
<span>Options</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel options-grid">
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="logs">Console logs</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="logs" type="checkbox" />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="title">Title hint</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="title" type="checkbox" checked />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="cursor">Cursor hint</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="cursor" type="checkbox" checked />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="timeout">Timeout</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="timeout" type="checkbox" checked />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="typing">Typing effect</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="typing" type="checkbox" />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="mouseover">Hover effect</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="mouseover" type="checkbox" />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="infinite">Infinite try</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="infinite" type="checkbox" />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row">
|
|
||||||
<label for="history">History</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="history" type="checkbox" />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="toggle-row" id="includeImages-line" style="display: none">
|
|
||||||
<label for="includeImages">Images (GPT-4)</label>
|
|
||||||
<label class="toggle-switch">
|
|
||||||
<input id="includeImages" type="checkbox" />
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p id="message">{Message}</p>
|
|
||||||
|
|
||||||
<button class="save">Save Preferences</button>
|
|
||||||
|
|
||||||
<div class="footer">
|
|
||||||
<a
|
|
||||||
class="donate"
|
|
||||||
href="https://www.buymeacoffee.com/yoannchbpro"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>Support</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="https://github.com/yoannchb-pro/MoodleGPT"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>Docs</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1029
-250
File diff suppressed because it is too large
Load Diff
Generated
+743
-28
@@ -8,26 +8,46 @@
|
|||||||
"name": "sparkassist",
|
"name": "sparkassist",
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"preact": "^10.29.1"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.32.0",
|
"@eslint/js": "^9.32.0",
|
||||||
"@rollup/plugin-commonjs": "^28.0.6",
|
"@rollup/plugin-commonjs": "^28.0.6",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||||
|
"@rollup/plugin-replace": "^6.0.3",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^12.1.4",
|
"@rollup/plugin-typescript": "^12.1.4",
|
||||||
"@types/chrome": "^0.1.1",
|
"@types/chrome": "^0.1.1",
|
||||||
"@types/node": "^24.1.0",
|
"@types/node": "^24.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.38.0",
|
"@typescript-eslint/parser": "^8.38.0",
|
||||||
|
"autoprefixer": "^10.5.0",
|
||||||
"eslint": "^9.32.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"openai": "^5.23.2",
|
"openai": "^5.23.2",
|
||||||
|
"postcss": "^8.5.14",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"rollup": "^4.46.2",
|
"rollup": "^4.46.2",
|
||||||
"rollup-plugin-ts": "^3.2.0",
|
"rollup-plugin-ts": "^3.2.0",
|
||||||
|
"tailwindcss": "^3.4.19",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.38.0"
|
"typescript-eslint": "^8.38.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@alloc/quick-lru": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
|
||||||
@@ -414,6 +434,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/plugin-replace": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
|
"magic-string": "^0.30.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/plugin-terser": {
|
"node_modules/@rollup/plugin-terser": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
@@ -1163,6 +1205,47 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/any-promise": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/anymatch": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"picomatch": "^2.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/anymatch/node_modules/picomatch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/arg": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/argparse": {
|
"node_modules/argparse": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
@@ -1170,12 +1253,75 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/autoprefixer": {
|
||||||
|
"version": "10.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
|
||||||
|
"integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"browserslist": "^4.28.2",
|
||||||
|
"caniuse-lite": "^1.0.30001787",
|
||||||
|
"fraction.js": "^5.3.4",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"postcss-value-parser": "^4.2.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"autoprefixer": "bin/autoprefixer"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/baseline-browser-mapping": {
|
||||||
|
"version": "2.10.27",
|
||||||
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.27.tgz",
|
||||||
|
"integrity": "sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"baseline-browser-mapping": "dist/cli.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/binary-extensions": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
@@ -1199,9 +1345,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.24.4",
|
"version": "4.28.2",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
||||||
"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
|
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1217,11 +1363,13 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001688",
|
"baseline-browser-mapping": "^2.10.12",
|
||||||
"electron-to-chromium": "^1.5.73",
|
"caniuse-lite": "^1.0.30001782",
|
||||||
"node-releases": "^2.0.19",
|
"electron-to-chromium": "^1.5.328",
|
||||||
"update-browserslist-db": "^1.1.1"
|
"node-releases": "^2.0.36",
|
||||||
|
"update-browserslist-db": "^1.2.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
@@ -1274,10 +1422,20 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camelcase-css": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001706",
|
"version": "1.0.30001791",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz",
|
||||||
"integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==",
|
"integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1292,7 +1450,8 @@
|
|||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "CC-BY-4.0"
|
||||||
},
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
@@ -1310,6 +1469,44 @@
|
|||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chokidar": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"anymatch": "~3.1.2",
|
||||||
|
"braces": "~3.0.2",
|
||||||
|
"glob-parent": "~5.1.2",
|
||||||
|
"is-binary-path": "~2.1.0",
|
||||||
|
"is-glob": "~4.0.1",
|
||||||
|
"normalize-path": "~3.0.0",
|
||||||
|
"readdirp": "~3.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.10.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chokidar/node_modules/glob-parent": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@@ -1393,6 +1590,19 @@
|
|||||||
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
|
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/cssesc": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"cssesc": "bin/cssesc"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
@@ -1425,17 +1635,33 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/didyoumean": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/dlv": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.120",
|
"version": "1.5.349",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.120.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.349.tgz",
|
||||||
"integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==",
|
"integrity": "sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@@ -1732,10 +1958,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fdir": {
|
"node_modules/fdir": {
|
||||||
"version": "6.4.3",
|
"version": "6.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||||
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
|
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"picomatch": "^3 || ^4"
|
"picomatch": "^3 || ^4"
|
||||||
},
|
},
|
||||||
@@ -1804,6 +2034,20 @@
|
|||||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fraction.js": {
|
||||||
|
"version": "5.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
|
||||||
|
"integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/rawify"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
@@ -1924,6 +2168,19 @@
|
|||||||
"node": ">=0.8.19"
|
"node": ">=0.8.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-binary-path": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"binary-extensions": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
@@ -1999,6 +2256,16 @@
|
|||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/jiti": {
|
||||||
|
"version": "1.21.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||||
|
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"jiti": "bin/jiti.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||||
@@ -2053,6 +2320,26 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lilconfig": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antonk52"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lines-and-columns": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
@@ -2138,6 +2425,37 @@
|
|||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/mz": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"any-promise": "^1.0.0",
|
||||||
|
"object-assign": "^4.0.1",
|
||||||
|
"thenify-all": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||||
|
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/natural-compare": {
|
"node_modules/natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
@@ -2145,10 +2463,41 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.19",
|
"version": "2.0.38",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz",
|
||||||
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
"integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/normalize-path": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object-hash": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-path": {
|
"node_modules/object-path": {
|
||||||
"version": "0.11.8",
|
"version": "0.11.8",
|
||||||
@@ -2272,10 +2621,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -2283,6 +2633,199 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pify": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pirates": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.5.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
|
||||||
|
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.11",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-import": {
|
||||||
|
"version": "15.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||||
|
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"postcss-value-parser": "^4.0.0",
|
||||||
|
"read-cache": "^1.0.0",
|
||||||
|
"resolve": "^1.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-js": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"camelcase-css": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12 || ^14 || >= 16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.4.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-load-config": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lilconfig": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"jiti": ">=1.21.0",
|
||||||
|
"postcss": ">=8.0.9",
|
||||||
|
"tsx": "^4.8.1",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tsx": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"yaml": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-nested": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"postcss-selector-parser": "^6.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.2.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-selector-parser": {
|
||||||
|
"version": "6.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||||
|
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": "^3.0.0",
|
||||||
|
"util-deprecate": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-value-parser": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/preact": {
|
||||||
|
"version": "10.29.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz",
|
||||||
|
"integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@@ -2347,6 +2890,42 @@
|
|||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/read-cache": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pify": "^2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readdirp": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readdirp/node_modules/picomatch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.10",
|
"version": "1.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||||
@@ -2590,6 +3169,16 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-support": {
|
"node_modules/source-map-support": {
|
||||||
"version": "0.5.21",
|
"version": "0.5.21",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
@@ -2613,6 +3202,39 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sucrase": {
|
||||||
|
"version": "3.35.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
|
||||||
|
"integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
|
"commander": "^4.0.0",
|
||||||
|
"lines-and-columns": "^1.1.6",
|
||||||
|
"mz": "^2.7.0",
|
||||||
|
"pirates": "^4.0.1",
|
||||||
|
"tinyglobby": "^0.2.11",
|
||||||
|
"ts-interface-checker": "^0.1.9"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sucrase": "bin/sucrase",
|
||||||
|
"sucrase-node": "bin/sucrase-node"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sucrase/node_modules/commander": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/supports-color": {
|
"node_modules/supports-color": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
@@ -2637,6 +3259,44 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tailwindcss": {
|
||||||
|
"version": "3.4.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
||||||
|
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
|
"arg": "^5.0.2",
|
||||||
|
"chokidar": "^3.6.0",
|
||||||
|
"didyoumean": "^1.2.2",
|
||||||
|
"dlv": "^1.1.3",
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"glob-parent": "^6.0.2",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"jiti": "^1.21.7",
|
||||||
|
"lilconfig": "^3.1.3",
|
||||||
|
"micromatch": "^4.0.8",
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"object-hash": "^3.0.0",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"postcss": "^8.4.47",
|
||||||
|
"postcss-import": "^15.1.0",
|
||||||
|
"postcss-js": "^4.0.1",
|
||||||
|
"postcss-load-config": "^4.0.2 || ^5.0 || ^6.0",
|
||||||
|
"postcss-nested": "^6.2.0",
|
||||||
|
"postcss-selector-parser": "^6.1.2",
|
||||||
|
"resolve": "^1.22.8",
|
||||||
|
"sucrase": "^3.35.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"tailwind": "lib/cli.js",
|
||||||
|
"tailwindcss": "lib/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.39.0",
|
"version": "5.39.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
|
||||||
@@ -2655,6 +3315,46 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/thenify": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"any-promise": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/thenify-all": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"thenify": ">= 3.1.0 < 4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tinyglobby": {
|
||||||
|
"version": "0.2.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
||||||
|
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fdir": "^6.5.0",
|
||||||
|
"picomatch": "^4.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
@@ -2699,6 +3399,13 @@
|
|||||||
"typescript": "^3.x || ^4.x || ^5.x"
|
"typescript": "^3.x || ^4.x || ^5.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-interface-checker": {
|
||||||
|
"version": "0.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||||
|
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
@@ -2789,9 +3496,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.1.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
||||||
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
|
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2807,6 +3514,7 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"escalade": "^3.2.0",
|
"escalade": "^3.2.0",
|
||||||
"picocolors": "^1.1.1"
|
"picocolors": "^1.1.1"
|
||||||
@@ -2828,6 +3536,13 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
+10
-2
@@ -3,9 +3,10 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"description": "An AI study assistant for your quizzes.",
|
"description": "An AI study assistant for your quizzes.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run prettier && npm run lint && npm run fastBuild",
|
"build": "npm run prettier && npm run lint && npm run build:css && npm run fastBuild",
|
||||||
|
"build:css": "tailwindcss -i ./src/popup/style.css -o ./extension/popup/style.css",
|
||||||
"fastBuild": "rollup -c",
|
"fastBuild": "rollup -c",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint . --ext .ts,.tsx",
|
||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -29,19 +30,26 @@
|
|||||||
"@eslint/js": "^9.32.0",
|
"@eslint/js": "^9.32.0",
|
||||||
"@rollup/plugin-commonjs": "^28.0.6",
|
"@rollup/plugin-commonjs": "^28.0.6",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||||
|
"@rollup/plugin-replace": "^6.0.3",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^12.1.4",
|
"@rollup/plugin-typescript": "^12.1.4",
|
||||||
"@types/chrome": "^0.1.1",
|
"@types/chrome": "^0.1.1",
|
||||||
"@types/node": "^24.1.0",
|
"@types/node": "^24.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
"@typescript-eslint/parser": "^8.38.0",
|
"@typescript-eslint/parser": "^8.38.0",
|
||||||
|
"autoprefixer": "^10.5.0",
|
||||||
"eslint": "^9.32.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"openai": "^5.23.2",
|
"openai": "^5.23.2",
|
||||||
|
"postcss": "^8.5.14",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"rollup": "^4.46.2",
|
"rollup": "^4.46.2",
|
||||||
"rollup-plugin-ts": "^3.2.0",
|
"rollup-plugin-ts": "^3.2.0",
|
||||||
|
"tailwindcss": "^3.4.19",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.38.0"
|
"typescript-eslint": "^8.38.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"preact": "^10.29.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
+11
-3
@@ -1,7 +1,7 @@
|
|||||||
const ts = require('@rollup/plugin-typescript');
|
const ts = require('@rollup/plugin-typescript');
|
||||||
const terser = require('@rollup/plugin-terser');
|
const terser = require('@rollup/plugin-terser');
|
||||||
const { nodeResolve } = require('@rollup/plugin-node-resolve');
|
const { nodeResolve } = require('@rollup/plugin-node-resolve');
|
||||||
|
const replace = require('@rollup/plugin-replace');
|
||||||
const config = require('./tsconfig.json');
|
const config = require('./tsconfig.json');
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
@@ -17,13 +17,21 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
input: './src/popup/index.ts',
|
input: './src/popup/index.tsx',
|
||||||
output: {
|
output: {
|
||||||
file: './extension/popup/popup.js',
|
file: './extension/popup/popup.js',
|
||||||
format: 'umd',
|
format: 'umd',
|
||||||
sourcemap: true
|
sourcemap: true
|
||||||
},
|
},
|
||||||
onwarn() {},
|
onwarn() {},
|
||||||
plugins: [nodeResolve(), ts(config), terser()]
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||||
|
preventAssignment: true
|
||||||
|
}),
|
||||||
|
nodeResolve(),
|
||||||
|
ts(config),
|
||||||
|
terser()
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { MoodleGPTConfig } from '../hooks/useConfig';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
config: MoodleGPTConfig;
|
||||||
|
onChange: (key: keyof MoodleGPTConfig, value: MoodleGPTConfig[keyof MoodleGPTConfig]) => void;
|
||||||
|
visible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AdvancedSettingsPanel({ config, onChange, visible }: Props) {
|
||||||
|
if (!visible) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class="bg-panel-bg backdrop-blur-md border border-panel-border rounded-2xl p-4 shadow-[0_8px_32px_0_rgba(0,0,0,0.3)] flex flex-col gap-4"
|
||||||
|
id="advanced-settings"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label htmlFor="code" class="text-sm font-medium text-text-secondary">
|
||||||
|
Activation Code
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="code"
|
||||||
|
type="text"
|
||||||
|
placeholder="Secret key..."
|
||||||
|
class="w-full px-3 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.code || ''}
|
||||||
|
onInput={e => onChange('code', (e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label htmlFor="baseURL" class="text-sm font-medium text-text-secondary">
|
||||||
|
Base URL
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="baseURL"
|
||||||
|
type="text"
|
||||||
|
placeholder="https://api.openai.com/v1"
|
||||||
|
class="w-full px-3 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.baseURL || ''}
|
||||||
|
onInput={e => onChange('baseURL', (e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label htmlFor="projectId" class="text-sm font-medium text-text-secondary">
|
||||||
|
Project ID
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="projectId"
|
||||||
|
type="text"
|
||||||
|
placeholder="proj_..."
|
||||||
|
class="w-full px-3 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.projectId || ''}
|
||||||
|
onInput={e => onChange('projectId', (e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label htmlFor="maxTokens" class="text-sm font-medium text-text-secondary">
|
||||||
|
Max Tokens
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="maxTokens"
|
||||||
|
type="number"
|
||||||
|
class="w-full px-3 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.maxTokens || ''}
|
||||||
|
onInput={e => {
|
||||||
|
const val = (e.target as HTMLInputElement).value;
|
||||||
|
onChange('maxTokens', val ? parseInt(val) : undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label htmlFor="timeoutValue" class="text-sm font-medium text-text-secondary">
|
||||||
|
Timeout (s)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="timeoutValue"
|
||||||
|
type="number"
|
||||||
|
placeholder="20"
|
||||||
|
class="w-full px-3 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.timeoutValue || ''}
|
||||||
|
onInput={e => {
|
||||||
|
const val = (e.target as HTMLInputElement).value;
|
||||||
|
onChange('timeoutValue', val ? parseInt(val) : undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import { useState } from 'preact/hooks';
|
||||||
|
import { Header } from './Header';
|
||||||
|
import { SettingsPanel } from './SettingsPanel';
|
||||||
|
import { AdvancedSettingsPanel } from './AdvancedSettingsPanel';
|
||||||
|
import { OptionsGrid } from './OptionsGrid';
|
||||||
|
import { OperatingMode } from './OperatingMode';
|
||||||
|
import { useConfig, MoodleGPTConfig } from '../hooks/useConfig';
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
const { config, loading, saveConfig, setConfig } = useConfig();
|
||||||
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||||
|
const [message, setMessage] = useState<{ text: string; isError: boolean } | null>(null);
|
||||||
|
|
||||||
|
if (loading) return null;
|
||||||
|
|
||||||
|
const handleConfigChange = (
|
||||||
|
key: keyof MoodleGPTConfig,
|
||||||
|
value: MoodleGPTConfig[keyof MoodleGPTConfig]
|
||||||
|
) => {
|
||||||
|
setConfig(prev => ({ ...prev, [key]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const showMessage = (msg: string, isError = false) => {
|
||||||
|
setMessage({ text: msg, isError });
|
||||||
|
setTimeout(() => setMessage(null), 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
if (!config.apiKey || !config.model) {
|
||||||
|
showMessage('Please complete all the form', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (config.code && config.code.length > 0 && config.code.length < 2) {
|
||||||
|
showMessage('The code should at least contain 2 characters', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await saveConfig(config);
|
||||||
|
showMessage('Configuration saved');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main class="p-6 flex flex-col gap-5 bg-gradient-to-br from-gradient-start to-gradient-end text-text-primary min-h-screen font-sans antialiased overflow-x-hidden">
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<SettingsPanel
|
||||||
|
config={config}
|
||||||
|
onChange={handleConfigChange}
|
||||||
|
showMessage={showMessage}
|
||||||
|
visible={!showAdvanced}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AdvancedSettingsPanel config={config} onChange={handleConfigChange} visible={showAdvanced} />
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="block text-center text-sm text-text-secondary no-underline transition-colors hover:text-text-primary"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
setShowAdvanced(!showAdvanced);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showAdvanced ? 'Go back to settings' : 'Show Advanced Settings'}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<OperatingMode
|
||||||
|
mode={config.mode || 'autocomplete'}
|
||||||
|
onChange={m => handleConfigChange('mode', m)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 text-sm font-semibold text-text-primary my-2">
|
||||||
|
<i class="fa-solid fa-sliders text-primary"></i>
|
||||||
|
<span>Options</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<OptionsGrid config={config} onChange={handleConfigChange} />
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<p
|
||||||
|
class={`text-center text-sm font-medium m-0 min-h-[18px] ${message.isError ? 'text-error' : 'text-success'}`}
|
||||||
|
>
|
||||||
|
{message.text}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="w-full p-3 bg-gradient-to-br from-primary to-primary-hover text-white border-none rounded-xl text-base font-semibold cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-[0_4px_12px_rgba(99,102,241,0.4)] active:translate-y-0 mt-2"
|
||||||
|
onClick={handleSave}
|
||||||
|
>
|
||||||
|
Save Preferences
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="flex justify-center gap-6 mt-2">
|
||||||
|
<a
|
||||||
|
class="text-sm font-medium no-underline transition-colors text-amber-400 hover:text-amber-300"
|
||||||
|
href="https://www.buymeacoffee.com/yoannchbpro"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Support
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="text-sm font-medium no-underline transition-colors text-text-secondary hover:text-text-primary"
|
||||||
|
href="https://github.com/yoannchb-pro/MoodleGPT"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Docs
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { useEffect, useState } from 'preact/hooks';
|
||||||
|
|
||||||
|
export function Header() {
|
||||||
|
const [version, setVersion] = useState('2.0.0');
|
||||||
|
const [hasUpdate, setHasUpdate] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkVersion = async () => {
|
||||||
|
try {
|
||||||
|
const req = await fetch(
|
||||||
|
'https://raw.githubusercontent.com/yoannchb-pro/MoodleGPT/main/package.json'
|
||||||
|
);
|
||||||
|
const rep = await req.json();
|
||||||
|
const lastVersion = rep.version;
|
||||||
|
|
||||||
|
const lastVertionSplitted = lastVersion.split('.');
|
||||||
|
const currentVersionSplitted = version.split('.');
|
||||||
|
const minVersionLength = Math.min(
|
||||||
|
lastVertionSplitted.length,
|
||||||
|
currentVersionSplitted.length
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < minVersionLength; ++i) {
|
||||||
|
if (parseInt(lastVertionSplitted[i]) > parseInt(currentVersionSplitted[i])) {
|
||||||
|
setVersion(lastVersion);
|
||||||
|
setHasUpdate(true);
|
||||||
|
return;
|
||||||
|
} else if (parseInt(currentVersionSplitted[i]) > parseInt(lastVertionSplitted[i])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkVersion();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="flex items-center gap-4 mb-2">
|
||||||
|
<img
|
||||||
|
src="../icon.png"
|
||||||
|
alt="SparkAssist Logo"
|
||||||
|
class="w-12 h-12 drop-shadow-md animate-float"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<h1 class="m-0 text-2xl font-bold bg-gradient-to-r from-indigo-300 to-indigo-400 bg-clip-text text-transparent">
|
||||||
|
SparkAssist
|
||||||
|
</h1>
|
||||||
|
<p class="m-0 mt-1 text-xs text-text-secondary">
|
||||||
|
{hasUpdate ? (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
href="https://github.com/yoannchb-pro/MoodleGPT"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="text-sky-400 no-underline font-medium hover:text-sky-300 transition-colors"
|
||||||
|
>
|
||||||
|
v{version}
|
||||||
|
</a>{' '}
|
||||||
|
is now available !
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
`v${version}`
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
interface Props {
|
||||||
|
mode: 'autocomplete' | 'clipboard';
|
||||||
|
onChange: (mode: 'autocomplete' | 'clipboard') => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OperatingMode({ mode, onChange }: Props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="flex items-center gap-2 text-sm font-semibold text-text-primary my-2">
|
||||||
|
<i class="fa-solid fa-bolt text-primary"></i>
|
||||||
|
<span>Operating Mode</span>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
id="mode"
|
||||||
|
class="list-none p-0 m-0 flex bg-input-bg rounded-xl border border-input-border overflow-hidden"
|
||||||
|
>
|
||||||
|
<li class="flex-1">
|
||||||
|
<button
|
||||||
|
value="autocomplete"
|
||||||
|
class={`w-full p-2.5 border-none font-sans text-sm font-semibold cursor-pointer transition-colors duration-300 ${
|
||||||
|
mode === 'autocomplete'
|
||||||
|
? 'bg-primary text-text-primary shadow-[0_2px_8px_rgba(99,102,241,0.4)]'
|
||||||
|
: 'bg-transparent text-text-secondary hover:bg-white/5 hover:text-text-primary'
|
||||||
|
}`}
|
||||||
|
onClick={() => onChange('autocomplete')}
|
||||||
|
>
|
||||||
|
autocomplete
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li class="flex-1">
|
||||||
|
<button
|
||||||
|
value="clipboard"
|
||||||
|
class={`w-full p-2.5 border-none font-sans text-sm font-semibold cursor-pointer transition-colors duration-300 ${
|
||||||
|
mode === 'clipboard'
|
||||||
|
? 'bg-primary text-text-primary shadow-[0_2px_8px_rgba(99,102,241,0.4)]'
|
||||||
|
: 'bg-transparent text-text-secondary hover:bg-white/5 hover:text-text-primary'
|
||||||
|
}`}
|
||||||
|
onClick={() => onChange('clipboard')}
|
||||||
|
>
|
||||||
|
clipboard
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { MoodleGPTConfig } from '../hooks/useConfig';
|
||||||
|
import { useModel } from '../hooks/useModel';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
config: MoodleGPTConfig;
|
||||||
|
onChange: (key: keyof MoodleGPTConfig, value: MoodleGPTConfig[keyof MoodleGPTConfig]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OptionsGrid({ config, onChange }: Props) {
|
||||||
|
const { isCurrentVersionSupportingImages } = useModel();
|
||||||
|
|
||||||
|
const toggleRow = (id: keyof MoodleGPTConfig, label: string, visible = true) => {
|
||||||
|
if (!visible) return null;
|
||||||
|
return (
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<label htmlFor={id} class="text-sm text-text-primary">
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input
|
||||||
|
id={id}
|
||||||
|
type="checkbox"
|
||||||
|
checked={!!config[id]}
|
||||||
|
onChange={e => onChange(id, (e.target as HTMLInputElement).checked)}
|
||||||
|
/>
|
||||||
|
<span class="slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isClipboard = config.mode === 'clipboard';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="bg-panel-bg backdrop-blur-md border border-panel-border rounded-2xl p-4 shadow-[0_8px_32px_0_rgba(0,0,0,0.3)] grid grid-cols-2 gap-4">
|
||||||
|
{toggleRow('logs', 'Console logs')}
|
||||||
|
{toggleRow('title', 'Title hint')}
|
||||||
|
{toggleRow('cursor', 'Cursor hint')}
|
||||||
|
{toggleRow('timeout', 'Timeout')}
|
||||||
|
{toggleRow('typing', 'Typing effect', !isClipboard)}
|
||||||
|
{toggleRow('mouseover', 'Hover effect', !isClipboard)}
|
||||||
|
{toggleRow('infinite', 'Infinite try')}
|
||||||
|
{toggleRow('history', 'History')}
|
||||||
|
{toggleRow('includeImages', 'Images (GPT-4)', isCurrentVersionSupportingImages(config.model))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { useModel } from '../hooks/useModel';
|
||||||
|
import { MoodleGPTConfig } from '../hooks/useConfig';
|
||||||
|
import { useState } from 'preact/hooks';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
config: MoodleGPTConfig;
|
||||||
|
onChange: (key: keyof MoodleGPTConfig, value: MoodleGPTConfig[keyof MoodleGPTConfig]) => void;
|
||||||
|
showMessage: (msg: string, isError?: boolean) => void;
|
||||||
|
visible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsPanel({ config, onChange, showMessage, visible }: Props) {
|
||||||
|
if (!visible) return null;
|
||||||
|
const { models, fetchModels, validateModel } = useModel(
|
||||||
|
config.apiKey,
|
||||||
|
config.baseURL,
|
||||||
|
config.projectId
|
||||||
|
);
|
||||||
|
const [testing, setTesting] = useState(false);
|
||||||
|
|
||||||
|
const handleTest = async () => {
|
||||||
|
if (!config.model) {
|
||||||
|
showMessage('Please select a model first', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTesting(true);
|
||||||
|
showMessage('Checking GPT version...', false);
|
||||||
|
const result = await validateModel(config.model, config.maxTokens);
|
||||||
|
setTesting(false);
|
||||||
|
if (result.success) {
|
||||||
|
showMessage(result.message || 'Valid model');
|
||||||
|
} else {
|
||||||
|
showMessage(result.error || 'Invalid model', true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class="bg-panel-bg backdrop-blur-md border border-panel-border rounded-2xl p-4 shadow-[0_8px_32px_0_rgba(0,0,0,0.3)]"
|
||||||
|
id="settings"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-2 mb-4">
|
||||||
|
<label htmlFor="apiKey" class="text-sm font-medium text-text-secondary">
|
||||||
|
Api Key<span class="text-error ml-1">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="apiKey"
|
||||||
|
type="text"
|
||||||
|
placeholder="sk-..."
|
||||||
|
class="w-full px-3 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.apiKey || ''}
|
||||||
|
onInput={e => onChange('apiKey', (e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<label htmlFor="model" class="text-sm font-medium text-text-secondary">
|
||||||
|
GPT Model<span class="text-error ml-1">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="relative flex items-center">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="model"
|
||||||
|
list="models"
|
||||||
|
placeholder="gpt-4o"
|
||||||
|
class="w-full pl-3 pr-9 py-2.5 bg-input-bg border border-input-border rounded-lg text-text-primary text-sm transition-all focus:outline-none focus:border-input-focus focus:ring-2 focus:ring-primary/20 box-border"
|
||||||
|
value={config.model || ''}
|
||||||
|
onInput={e => onChange('model', (e.target as HTMLInputElement).value)}
|
||||||
|
onFocus={fetchModels}
|
||||||
|
/>
|
||||||
|
<datalist id="models">
|
||||||
|
{models.map(m => (
|
||||||
|
<option key={m} value={m}>
|
||||||
|
{m}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</datalist>
|
||||||
|
<i
|
||||||
|
class={`fa-solid ${testing ? 'fa-spinner fa-spin' : 'fa-play'} absolute right-3 text-primary text-sm transition-all hover:scale-110 hover:text-primary-hover cursor-pointer`}
|
||||||
|
onClick={handleTest}
|
||||||
|
title="Test"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
export const globalData = { actualMode: 'autocomplete' };
|
|
||||||
|
|
||||||
export const inputsCheckbox = [
|
|
||||||
'logs',
|
|
||||||
'title',
|
|
||||||
'cursor',
|
|
||||||
'typing',
|
|
||||||
'mouseover',
|
|
||||||
'infinite',
|
|
||||||
'timeout',
|
|
||||||
'history',
|
|
||||||
'includeImages'
|
|
||||||
];
|
|
||||||
export const mode = document.querySelector('#mode')!;
|
|
||||||
export const modes = mode.querySelectorAll('button')!;
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
import OpenAI from 'openai';
|
|
||||||
import { isCurrentVersionSupportingImages, showMessage } from './utils';
|
|
||||||
|
|
||||||
const apiKeySelector: HTMLInputElement = document.querySelector('#apiKey')!;
|
|
||||||
const inputModel: HTMLInputElement = document.querySelector('#model')!;
|
|
||||||
const modelsList: HTMLElement = document.querySelector('#models')!;
|
|
||||||
const imagesIntegrationLine: HTMLInputElement = document.querySelector('#includeImages-line')!;
|
|
||||||
const baseURLSelector: HTMLInputElement = document.querySelector('#baseURL')!;
|
|
||||||
const projectIdSelector: HTMLInputElement = document.querySelector('#projectId')!;
|
|
||||||
const maxTokensSelector: HTMLInputElement = document.querySelector('#maxTokens')!;
|
|
||||||
/**
|
|
||||||
* Check if the gpt version is at least 4 to show the option 'Include images'
|
|
||||||
*/
|
|
||||||
export function checkCanIncludeImages() {
|
|
||||||
const version = inputModel.value;
|
|
||||||
if (isCurrentVersionSupportingImages(version)) {
|
|
||||||
imagesIntegrationLine.style.display = 'flex';
|
|
||||||
} else {
|
|
||||||
imagesIntegrationLine.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inputModel.addEventListener('input', checkCanIncludeImages);
|
|
||||||
|
|
||||||
// We populate the datalist of the chatgpt model
|
|
||||||
export async function populateDatalistWithGptVersions() {
|
|
||||||
const apiKey = apiKeySelector.value?.trim();
|
|
||||||
const baseURL = baseURLSelector.value?.trim();
|
|
||||||
const projectId = projectIdSelector.value?.trim();
|
|
||||||
|
|
||||||
if (!apiKey) return;
|
|
||||||
|
|
||||||
inputModel.innerHTML = '';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const client = new OpenAI({
|
|
||||||
apiKey,
|
|
||||||
baseURL,
|
|
||||||
project: projectId,
|
|
||||||
dangerouslyAllowBrowser: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const rep = await client.models.list();
|
|
||||||
|
|
||||||
const models = rep.data.filter(
|
|
||||||
model =>
|
|
||||||
model.id.startsWith('gpt') ||
|
|
||||||
model.id.search(/^o\d+/gi) !== -1 ||
|
|
||||||
model.id.startsWith('chatgpt')
|
|
||||||
);
|
|
||||||
models.sort((a, b) => b.id.localeCompare(a.id)); // we sort the model to get the best chatgpt version first
|
|
||||||
|
|
||||||
for (const model of models) {
|
|
||||||
const opt = document.createElement('option');
|
|
||||||
opt.value = model.id;
|
|
||||||
opt.textContent = model.id;
|
|
||||||
modelsList.appendChild(opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCanIncludeImages();
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error(err);
|
|
||||||
showMessage({ msg: err, isError: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inputModel.addEventListener('focus', populateDatalistWithGptVersions);
|
|
||||||
|
|
||||||
export async function checkModel() {
|
|
||||||
const model = inputModel.value?.trim();
|
|
||||||
const apiKey = apiKeySelector.value?.trim();
|
|
||||||
const baseURL = baseURLSelector.value?.trim();
|
|
||||||
const projectId = projectIdSelector.value?.trim();
|
|
||||||
const maxTokens = maxTokensSelector.value ? parseInt(maxTokensSelector.value) : undefined;
|
|
||||||
|
|
||||||
try {
|
|
||||||
showMessage({ msg: 'Checking GPT version...', isInfinite: true, isError: false });
|
|
||||||
const client = new OpenAI({
|
|
||||||
apiKey,
|
|
||||||
baseURL,
|
|
||||||
project: projectId,
|
|
||||||
dangerouslyAllowBrowser: true
|
|
||||||
});
|
|
||||||
const completion = await client.chat.completions.create({
|
|
||||||
model,
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content:
|
|
||||||
'reply just pong, set success to true, and provide a random number between 1 and 100.'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
max_completion_tokens: maxTokens || 2000,
|
|
||||||
response_format: {
|
|
||||||
type: 'json_schema',
|
|
||||||
json_schema: {
|
|
||||||
name: 'model_test',
|
|
||||||
strict: true,
|
|
||||||
schema: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
reply: { type: 'string', description: 'The text reply' },
|
|
||||||
success: { type: 'boolean', description: 'Always true' },
|
|
||||||
data: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
number: { type: 'integer' }
|
|
||||||
},
|
|
||||||
required: ['number'],
|
|
||||||
additionalProperties: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
required: ['reply', 'success', 'data'],
|
|
||||||
additionalProperties: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const content = completion.choices[0]?.message?.content;
|
|
||||||
if (!content) {
|
|
||||||
throw new Error('No content returned from the model.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsed = JSON.parse(content);
|
|
||||||
if (
|
|
||||||
typeof parsed.reply !== 'string' ||
|
|
||||||
typeof parsed.success !== 'boolean' ||
|
|
||||||
typeof parsed.data !== 'object' ||
|
|
||||||
typeof parsed.data.number !== 'number'
|
|
||||||
) {
|
|
||||||
throw new Error('Model did not follow the JSON schema correctly.');
|
|
||||||
}
|
|
||||||
|
|
||||||
showMessage({ msg: 'The model is valid and supports structured outputs!' });
|
|
||||||
} catch (err: any) {
|
|
||||||
showMessage({ msg: err, isError: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkModelBtn: HTMLElement = document.querySelector('#check-model')!;
|
|
||||||
checkModelBtn.addEventListener('click', checkModel);
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { useState, useEffect } from 'preact/hooks';
|
||||||
|
|
||||||
|
export interface MoodleGPTConfig {
|
||||||
|
apiKey?: string;
|
||||||
|
code?: string;
|
||||||
|
model?: string;
|
||||||
|
baseURL?: string;
|
||||||
|
maxTokens?: number;
|
||||||
|
projectId?: string;
|
||||||
|
timeoutValue?: number;
|
||||||
|
logs?: boolean;
|
||||||
|
title?: boolean;
|
||||||
|
cursor?: boolean;
|
||||||
|
typing?: boolean;
|
||||||
|
mouseover?: boolean;
|
||||||
|
infinite?: boolean;
|
||||||
|
timeout?: boolean;
|
||||||
|
history?: boolean;
|
||||||
|
includeImages?: boolean;
|
||||||
|
mode?: 'autocomplete' | 'clipboard';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useConfig() {
|
||||||
|
const [config, setConfig] = useState<MoodleGPTConfig>({
|
||||||
|
mode: 'autocomplete',
|
||||||
|
title: true,
|
||||||
|
cursor: true,
|
||||||
|
timeout: true
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
chrome.storage.sync.get(['moodleGPT']).then(storage => {
|
||||||
|
if (storage.moodleGPT) {
|
||||||
|
setConfig(prev => ({ ...prev, ...storage.moodleGPT }));
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const saveConfig = async (newConfig: MoodleGPTConfig) => {
|
||||||
|
const updated = { ...config, ...newConfig };
|
||||||
|
setConfig(updated);
|
||||||
|
await chrome.storage.sync.set({ moodleGPT: updated });
|
||||||
|
};
|
||||||
|
|
||||||
|
return { config, loading, saveConfig, setConfig };
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { useState } from 'preact/hooks';
|
||||||
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
|
export function useModel(apiKey?: string, baseURL?: string, projectId?: string) {
|
||||||
|
const [models, setModels] = useState<string[]>([]);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const isCurrentVersionSupportingImages = (version?: string) => {
|
||||||
|
if (!version) return false;
|
||||||
|
const versionNumber = version.match(/gpt-(\d+)/);
|
||||||
|
if (!versionNumber?.[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Number(versionNumber[1]) >= 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchModels = async () => {
|
||||||
|
if (!apiKey) return;
|
||||||
|
try {
|
||||||
|
const client = new OpenAI({
|
||||||
|
apiKey,
|
||||||
|
baseURL: baseURL || undefined,
|
||||||
|
project: projectId || undefined,
|
||||||
|
dangerouslyAllowBrowser: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const rep = await client.models.list();
|
||||||
|
|
||||||
|
const filteredModels = rep.data.filter(
|
||||||
|
model =>
|
||||||
|
model.id.startsWith('gpt') ||
|
||||||
|
model.id.search(/^o\d+/gi) !== -1 ||
|
||||||
|
model.id.startsWith('chatgpt')
|
||||||
|
);
|
||||||
|
filteredModels.sort((a, b) => b.id.localeCompare(a.id));
|
||||||
|
|
||||||
|
setModels(filteredModels.map(m => m.id));
|
||||||
|
setError(null);
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error(err);
|
||||||
|
setError(err.message || String(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateModel = async (model: string, maxTokens?: number) => {
|
||||||
|
if (!apiKey || !model) return { success: false, error: 'API Key and Model are required' };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const client = new OpenAI({
|
||||||
|
apiKey,
|
||||||
|
baseURL: baseURL || undefined,
|
||||||
|
project: projectId || undefined,
|
||||||
|
dangerouslyAllowBrowser: true
|
||||||
|
});
|
||||||
|
const completion = await client.chat.completions.create({
|
||||||
|
model,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content:
|
||||||
|
'reply just pong, set success to true, and provide a random number between 1 and 100.'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_completion_tokens: maxTokens || 2000,
|
||||||
|
response_format: {
|
||||||
|
type: 'json_schema',
|
||||||
|
json_schema: {
|
||||||
|
name: 'model_test',
|
||||||
|
strict: true,
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
reply: { type: 'string', description: 'The text reply' },
|
||||||
|
success: { type: 'boolean', description: 'Always true' },
|
||||||
|
data: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
number: { type: 'integer' }
|
||||||
|
},
|
||||||
|
required: ['number'],
|
||||||
|
additionalProperties: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ['reply', 'success', 'data'],
|
||||||
|
additionalProperties: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const content = completion.choices[0]?.message?.content;
|
||||||
|
if (!content) {
|
||||||
|
throw new Error('No content returned from the model.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = JSON.parse(content);
|
||||||
|
if (
|
||||||
|
typeof parsed.reply !== 'string' ||
|
||||||
|
typeof parsed.success !== 'boolean' ||
|
||||||
|
typeof parsed.data !== 'object' ||
|
||||||
|
typeof parsed.data.number !== 'number'
|
||||||
|
) {
|
||||||
|
throw new Error('Model did not follow the JSON schema correctly.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true, message: 'The model is valid and supports structured outputs!' };
|
||||||
|
} catch (err: any) {
|
||||||
|
return { success: false, error: err.message || String(err) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { models, fetchModels, validateModel, error, isCurrentVersionSupportingImages };
|
||||||
|
}
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
import { globalData, inputsCheckbox, modes } from './data';
|
|
||||||
import { checkCanIncludeImages } from './gpt-version';
|
|
||||||
import { handleModeChange } from './mode-handler';
|
|
||||||
import './version';
|
|
||||||
import './settings';
|
|
||||||
|
|
||||||
import { showMessage } from './utils';
|
|
||||||
|
|
||||||
const saveBtn = document.querySelector('.save')!;
|
|
||||||
|
|
||||||
// inputs id
|
|
||||||
const inputsText = ['apiKey', 'code', 'model', 'baseURL', 'maxTokens', 'projectId', 'timeoutValue'];
|
|
||||||
|
|
||||||
// Save the configuration
|
|
||||||
saveBtn.addEventListener('click', function () {
|
|
||||||
const [apiKey, code, model, baseURL, maxTokens, projectId, timeoutValue] = inputsText.map(
|
|
||||||
selector => (document.querySelector('#' + selector) as HTMLInputElement).value.trim()
|
|
||||||
);
|
|
||||||
const [logs, title, cursor, typing, mouseover, infinite, timeout, history, includeImages] =
|
|
||||||
inputsCheckbox.map(selector => {
|
|
||||||
const element: HTMLInputElement = document.querySelector('#' + selector)!;
|
|
||||||
return element.checked && element.parentElement!.style.display !== 'none';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!apiKey || !model) {
|
|
||||||
showMessage({ msg: 'Please complete all the form', isError: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code.length > 0 && code.length < 2) {
|
|
||||||
showMessage({
|
|
||||||
msg: 'The code should at least contain 2 characters',
|
|
||||||
isError: true
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
moodleGPT: {
|
|
||||||
apiKey,
|
|
||||||
code,
|
|
||||||
model,
|
|
||||||
baseURL,
|
|
||||||
maxTokens: maxTokens ? parseInt(maxTokens) : undefined,
|
|
||||||
projectId,
|
|
||||||
timeoutValue: timeoutValue ? parseInt(timeoutValue) : undefined,
|
|
||||||
logs,
|
|
||||||
title,
|
|
||||||
cursor,
|
|
||||||
typing,
|
|
||||||
mouseover,
|
|
||||||
infinite,
|
|
||||||
timeout,
|
|
||||||
history,
|
|
||||||
includeImages,
|
|
||||||
mode: globalData.actualMode
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
showMessage({ msg: 'Configuration saved' });
|
|
||||||
});
|
|
||||||
|
|
||||||
// we load back the configuration
|
|
||||||
chrome.storage.sync.get(['moodleGPT']).then(function (storage) {
|
|
||||||
const config = storage.moodleGPT;
|
|
||||||
|
|
||||||
if (config) {
|
|
||||||
if (config.mode) {
|
|
||||||
globalData.actualMode = config.mode;
|
|
||||||
for (const mode of modes) {
|
|
||||||
if (mode.value === config.mode) {
|
|
||||||
mode.classList.remove('not-selected');
|
|
||||||
} else {
|
|
||||||
mode.classList.add('not-selected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inputsText.forEach(key =>
|
|
||||||
config[key]
|
|
||||||
? ((document.querySelector('#' + key) as HTMLInputElement).value = config[key])
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
inputsCheckbox.forEach(
|
|
||||||
key => ((document.querySelector('#' + key) as HTMLInputElement).checked = config[key] || '')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleModeChange();
|
|
||||||
checkCanIncludeImages();
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { render } from 'preact';
|
||||||
|
import { App } from './components/App';
|
||||||
|
|
||||||
|
const root = document.getElementById('root');
|
||||||
|
if (root) {
|
||||||
|
render(<App />, root);
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import { globalData, inputsCheckbox, modes } from './data';
|
|
||||||
|
|
||||||
// input to don't take in consideration
|
|
||||||
const toExcludes = ['includeImages'];
|
|
||||||
|
|
||||||
// inputs id that need to be disabled for a specific mode
|
|
||||||
const disabledForThisMode: Record<string, string[]> = {
|
|
||||||
autocomplete: [],
|
|
||||||
clipboard: ['typing', 'mouseover']
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle when a mode change to show specific input or to hide them
|
|
||||||
*/
|
|
||||||
export function handleModeChange() {
|
|
||||||
const needDisable = disabledForThisMode[globalData.actualMode];
|
|
||||||
const dontNeedDisable = inputsCheckbox.filter(
|
|
||||||
input => !needDisable.includes(input) && !toExcludes.includes(input)
|
|
||||||
);
|
|
||||||
for (const id of needDisable) {
|
|
||||||
document.querySelector('#' + id)!.parentElement!.style.display = 'none';
|
|
||||||
}
|
|
||||||
for (const id of dontNeedDisable) {
|
|
||||||
document.querySelector('#' + id)!.parentElement!.style.display = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mode hanlder
|
|
||||||
for (const button of modes) {
|
|
||||||
button.addEventListener('click', function () {
|
|
||||||
const value = button.value;
|
|
||||||
globalData.actualMode = value;
|
|
||||||
for (const mode of modes) {
|
|
||||||
if (mode.value !== value) {
|
|
||||||
mode.classList.add('not-selected');
|
|
||||||
} else {
|
|
||||||
mode.classList.remove('not-selected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handleModeChange();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
const settings: HTMLElement = document.querySelector('#settings')!;
|
|
||||||
const advencedSettings: HTMLElement = document.querySelector('#advanced-settings')!;
|
|
||||||
const switchSettings: HTMLLinkElement = document.querySelector('#switch-settings')!;
|
|
||||||
|
|
||||||
export function switchSettingsMode() {
|
|
||||||
const isAdvancedSettings = advencedSettings.style.display === 'flex';
|
|
||||||
|
|
||||||
if (isAdvancedSettings) {
|
|
||||||
settings.style.display = 'flex';
|
|
||||||
advencedSettings.style.display = 'none';
|
|
||||||
switchSettings.textContent = 'Advanced settings';
|
|
||||||
} else {
|
|
||||||
settings.style.display = 'none';
|
|
||||||
advencedSettings.style.display = 'flex';
|
|
||||||
switchSettings.textContent = 'Go back to settings';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switchSettings.addEventListener('click', function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
switchSettingsMode();
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
width: 380px;
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.toggle-switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 36px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: theme('colors.input.bg');
|
||||||
|
border: 1px solid theme('colors.input.border');
|
||||||
|
transition: 0.4s;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
left: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
background-color: theme('colors.text.secondary');
|
||||||
|
transition: 0.4s;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: theme('colors.primary.DEFAULT');
|
||||||
|
border-color: theme('colors.primary.DEFAULT');
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
transform: translateX(16px);
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* Show message into the popup
|
|
||||||
*/
|
|
||||||
export function showMessage({
|
|
||||||
msg,
|
|
||||||
isError,
|
|
||||||
isInfinite
|
|
||||||
}: {
|
|
||||||
msg: string;
|
|
||||||
isError?: boolean;
|
|
||||||
isInfinite?: boolean;
|
|
||||||
}) {
|
|
||||||
const message: HTMLElement = document.querySelector('#message')!;
|
|
||||||
message.style.color = isError ? 'red' : 'limegreen';
|
|
||||||
message.textContent = msg;
|
|
||||||
message.style.display = 'block';
|
|
||||||
if (!isInfinite) setTimeout(() => (message.style.display = 'none'), 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the current model support images integrations
|
|
||||||
* @param {string} version
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function isCurrentVersionSupportingImages(version: string) {
|
|
||||||
const versionNumber = version.match(/gpt-(\d+)/);
|
|
||||||
if (!versionNumber?.[1]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Number(versionNumber[1]) >= 4;
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
const CURRENT_VERSION = '2.0.0';
|
|
||||||
const versionDisplay = document.querySelector('#version')!;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last version from the github
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export async function getLastVersion(): Promise<string> {
|
|
||||||
const req = await fetch(
|
|
||||||
'https://raw.githubusercontent.com/yoannchb-pro/MoodleGPT/main/package.json'
|
|
||||||
);
|
|
||||||
const rep = await req.json();
|
|
||||||
return rep.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the version or an update message
|
|
||||||
* @param {string} version
|
|
||||||
* @param {boolean} isCurrent
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function setVersion(version: string, isCurrent = true) {
|
|
||||||
if (isCurrent) {
|
|
||||||
versionDisplay.textContent = 'v' + version;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = 'https://github.com/yoannchb-pro/MoodleGPT';
|
|
||||||
link.rel = 'noopener noreferrer';
|
|
||||||
link.target = '_blank';
|
|
||||||
link.textContent = 'v' + version;
|
|
||||||
versionDisplay.appendChild(link);
|
|
||||||
versionDisplay.appendChild(document.createTextNode(' is now available !'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the extension neeed an update or not
|
|
||||||
*/
|
|
||||||
export async function notifyUpdate() {
|
|
||||||
const lastVersion = await getLastVersion().catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
return CURRENT_VERSION;
|
|
||||||
});
|
|
||||||
|
|
||||||
const lastVertionSplitted = lastVersion.split('.');
|
|
||||||
const currentVersionSplitted = CURRENT_VERSION.split('.');
|
|
||||||
const minVersionLength = Math.min(lastVertionSplitted.length, currentVersionSplitted.length);
|
|
||||||
|
|
||||||
for (let i = 0; i < minVersionLength; ++i) {
|
|
||||||
if (parseInt(lastVertionSplitted[i]) > parseInt(currentVersionSplitted[i])) {
|
|
||||||
return setVersion(lastVersion, false);
|
|
||||||
} else if (parseInt(currentVersionSplitted[i]) > parseInt(lastVertionSplitted[i])) {
|
|
||||||
return setVersion(CURRENT_VERSION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setVersion(CURRENT_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyUpdate();
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ['./src/popup/**/*.{js,jsx,ts,tsx}', './extension/popup/index.html'],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
DEFAULT: '#6366f1',
|
||||||
|
hover: '#4f46e5'
|
||||||
|
},
|
||||||
|
gradient: {
|
||||||
|
start: '#0f172a',
|
||||||
|
end: '#1e1b4b'
|
||||||
|
},
|
||||||
|
panel: {
|
||||||
|
bg: 'rgba(255, 255, 255, 0.05)',
|
||||||
|
border: 'rgba(255, 255, 255, 0.1)'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: '#f8fafc',
|
||||||
|
secondary: '#94a3b8'
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
bg: 'rgba(0, 0, 0, 0.2)',
|
||||||
|
border: 'rgba(255, 255, 255, 0.15)',
|
||||||
|
focus: '#818cf8'
|
||||||
|
},
|
||||||
|
success: '#10b981',
|
||||||
|
error: '#ef4444'
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: [
|
||||||
|
'Inter',
|
||||||
|
'-apple-system',
|
||||||
|
'BlinkMacSystemFont',
|
||||||
|
'Segoe UI',
|
||||||
|
'Roboto',
|
||||||
|
'Helvetica',
|
||||||
|
'Arial',
|
||||||
|
'sans-serif'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
float: 'float 3s ease-in-out infinite'
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
float: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0)' },
|
||||||
|
'50%': { transform: 'translateY(-4px)' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: []
|
||||||
|
};
|
||||||
+3
-1
@@ -12,7 +12,9 @@
|
|||||||
"outDir": "extension",
|
"outDir": "extension",
|
||||||
"types": ["node", "chrome"],
|
"types": ["node", "chrome"],
|
||||||
"typeRoots": ["node_modules/@types"],
|
"typeRoots": ["node_modules/@types"],
|
||||||
"strictBindCallApply": true
|
"strictBindCallApply": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "preact"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user