backing up

This commit is contained in:
Lio 2024-08-08 14:12:51 +02:00
commit af881ecaec
24 changed files with 9449 additions and 0 deletions

30
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,30 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
npm-debug.log
node_modules/
dist/
tmp/

14
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,14 @@
{
"copyrighter.author": "R3BL LLC",
"copyrighter.license": "MIT",
"typescript.tsdk": "./node_modules/typescript/lib",
"files.eol": "\n",
"json.schemas": [
{
"fileMatch": [
"/manifest.json"
],
"url": "http://json.schemastore.org/chrome-manifest"
}
]
}

33
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,33 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"command": "npm",
"tasks": [
{
"label": "install",
"type": "shell",
"command": "npm",
"args": ["install"]
},
{
"label": "update",
"type": "shell",
"command": "npm",
"args": ["update"]
},
{
"label": "test",
"type": "shell",
"command": "npm",
"args": ["run", "test"]
},
{
"label": "build",
"type": "shell",
"group": "build",
"command": "npm",
"args": ["run", "watch"]
}
]
}

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Tomofumi Chiba
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

84
README.md Normal file
View file

@ -0,0 +1,84 @@
# Chrome extension template repo written in Typescript and React.
Table of contents:
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Prerequisites](#prerequisites)
- [Option](#option)
- [Includes the following](#includes-the-following)
- [Project Structure](#project-structure)
- [Setup](#setup)
- [Open in Visual Studio Code](#open-in-visual-studio-code)
- [Build](#build)
- [Build in watch mode](#build-in-watch-mode)
- [terminal](#terminal)
- [Visual Studio Code](#visual-studio-code)
- [Load extension to chrome](#load-extension-to-chrome)
- [Test](#test)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Prerequisites
- [node + npm](https://nodejs.org/) (Current Version)
## Option
- [Visual Studio Code](https://code.visualstudio.com/)
## Includes the following
- TypeScript
- Webpack
- React
- Jest
- Code
- Chrome Storage
- Badge number
- Background script
## Project Structure
| Folder | Description |
| ------------ | -------------------------- |
| `src/` | TypeScript source files |
| `public/` | static files |
| `dist` | Chrome Extension directory |
| `dist/js` | Generated JavaScript files |
## Setup
```
npm install
```
## Build
```
npm run build
```
## Build in watch mode
### terminal
```
npm run watch
```
### Visual Studio Code
Run watch mode.
type `Ctrl + Shift + B`
## Load extension to chrome
Load `dist` directory.
## Test
Run `npx jest` or `npm run test`.

8001
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

47
package.json Normal file
View file

@ -0,0 +1,47 @@
{
"name": "faex",
"version": "1.0.0",
"description": "FurAFfinity Gallery Exporter",
"main": "index.js",
"scripts": {
"build:watch": "webpack --config webpack/webpack.dev.js --watch",
"tailwind:watch": "npx tailwindcss -i ./src/styles/tailwind.css -o ./public/styles.css --watch",
"build": "webpack --config webpack/webpack.prod.js",
"tailwind": "npx tailwindcss -i ./src/styles/tailwind.css -o ./public/styles.css",
"clean": "rimraf dist",
"test": "npx jest",
"style": "prettier --write \"src/**/*.{ts,tsx}\"",
"update-all-deps": "npm update --save"
},
"author": "R3BL LLC",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/chibat/chrome-extension-typescript-starter.git"
},
"dependencies": {
"@types/chrome": "^0.0.240",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/jest": "^29.5.2",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"copy-webpack-plugin": "^9.1.0",
"css-loader": "^7.1.2",
"glob": "^7.2.3",
"jest": "^29.6.1",
"prettier": "^2.8.8",
"rimraf": "^3.0.2",
"style-loader": "^4.0.0",
"tailwindcss": "^3.4.8",
"ts-jest": "^29.1.1",
"ts-loader": "^8.4.0",
"typescript": "^5.1.6",
"webpack": "^5.93.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^5.0.4",
"webpack-merge": "^5.9.0"
}
}

BIN
public/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

36
public/manifest.json Normal file
View file

@ -0,0 +1,36 @@
{
"manifest_version": 3,
"name": "FAEX",
"description": "FurAFfinity Gallery Exporter",
"version": "1.0",
"options_ui": {
"page": "options.html",
"open_in_tab": true
},
"action": {
"default_icon": {
"16": "icon.png"
},
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": [
"*://*.furaffinity.net/*"
],
"js": [
"js/vendor.js",
"js/content_script.js"
]
}
],
"background": {
"service_worker": "js/background.js"
},
"permissions": [
"storage", "cookies"
],
"host_permissions": [
"*://*.furaffinity.net/*"
]
}

14
public/options.html Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>FAEX Options</title>
<script src="js/vendor.js"></script>
<link id="js-style" type="text/css" href="styles.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script src="js/options.js"></script>
</body>
</html>

14
public/popup.html Normal file
View file

@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Getting Started Extension's Popup</title>
<script src="js/vendor.js"></script>
<link href="./styles.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script src="js/popup.js"></script>
</body>
</html>

803
public/styles.css Normal file
View file

@ -0,0 +1,803 @@
/*
! tailwindcss v3.4.8 | MIT License | https://tailwindcss.com
*/
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box;
/* 1 */
border-width: 0;
/* 2 */
border-style: solid;
/* 2 */
border-color: #e5e7eb;
/* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS
*/
html,
:host {
line-height: 1.5;
/* 1 */
-webkit-text-size-adjust: 100%;
/* 2 */
-moz-tab-size: 4;
/* 3 */
-o-tab-size: 4;
tab-size: 4;
/* 3 */
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
/* 4 */
font-feature-settings: normal;
/* 5 */
font-variation-settings: normal;
/* 6 */
-webkit-tap-highlight-color: transparent;
/* 7 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0;
/* 1 */
line-height: inherit;
/* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0;
/* 1 */
color: inherit;
/* 2 */
border-top-width: 1px;
/* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* 1 */
font-feature-settings: normal;
/* 2 */
font-variation-settings: normal;
/* 3 */
font-size: 1em;
/* 4 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0;
/* 1 */
border-color: inherit;
/* 2 */
border-collapse: collapse;
/* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
/* 1 */
font-feature-settings: inherit;
/* 1 */
font-variation-settings: inherit;
/* 1 */
font-size: 100%;
/* 1 */
font-weight: inherit;
/* 1 */
line-height: inherit;
/* 1 */
letter-spacing: inherit;
/* 1 */
color: inherit;
/* 1 */
margin: 0;
/* 2 */
padding: 0;
/* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
input:where([type='button']),
input:where([type='reset']),
input:where([type='submit']) {
-webkit-appearance: button;
/* 1 */
background-color: transparent;
/* 2 */
background-image: none;
/* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield;
/* 1 */
outline-offset: -2px;
/* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button;
/* 1 */
font: inherit;
/* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
/*
Reset default styling for dialogs.
*/
dialog {
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::-moz-placeholder, textarea::-moz-placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
input::placeholder,
textarea::placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
/* 1 */
vertical-align: middle;
/* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/* Make elements with the HTML hidden attribute stay hidden by default */
[hidden] {
display: none;
}
*, ::before, ::after {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-gradient-from-position: ;
--tw-gradient-via-position: ;
--tw-gradient-to-position: ;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
::backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-gradient-from-position: ;
--tw-gradient-via-position: ;
--tw-gradient-to-position: ;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
.m-auto {
margin: auto;
}
.m-0 {
margin: 0px;
}
.m-1 {
margin: 0.25rem;
}
.m-3 {
margin: 0.75rem;
}
.m-2 {
margin: 0.5rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
.mt-1 {
margin-top: 0.25rem;
}
.mb-3 {
margin-bottom: 0.75rem;
}
.mt-4 {
margin-top: 1rem;
}
.mr-1 {
margin-right: 0.25rem;
}
.box-border {
box-sizing: border-box;
}
.flex {
display: flex;
}
.h-\[2px\] {
height: 2px;
}
.h-\[5px\] {
height: 5px;
}
.h-\[3px\] {
height: 3px;
}
.w-\[95\%\] {
width: 95%;
}
.w-\[100\%\] {
width: 100%;
}
.max-w-3xl {
max-width: 48rem;
}
.flex-col {
flex-direction: column;
}
.gap-4 {
gap: 1rem;
}
.rounded {
border-radius: 0.25rem;
}
.border-2 {
border-width: 2px;
}
.border-hidden {
border-style: hidden;
}
.border-red-400 {
--tw-border-opacity: 1;
border-color: rgb(248 113 113 / var(--tw-border-opacity));
}
.border-red-300 {
--tw-border-opacity: 1;
border-color: rgb(252 165 165 / var(--tw-border-opacity));
}
.border-yellow-300 {
--tw-border-opacity: 1;
border-color: rgb(253 224 71 / var(--tw-border-opacity));
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
.bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.bg-yellow-50 {
--tw-bg-opacity: 1;
background-color: rgb(254 252 232 / var(--tw-bg-opacity));
}
.bg-red-200 {
--tw-bg-opacity: 1;
background-color: rgb(254 202 202 / var(--tw-bg-opacity));
}
.bg-red-300 {
--tw-bg-opacity: 1;
background-color: rgb(252 165 165 / var(--tw-bg-opacity));
}
.bg-red-400 {
--tw-bg-opacity: 1;
background-color: rgb(248 113 113 / var(--tw-bg-opacity));
}
.bg-red-100 {
--tw-bg-opacity: 1;
background-color: rgb(254 226 226 / var(--tw-bg-opacity));
}
.bg-yellow-300 {
--tw-bg-opacity: 1;
background-color: rgb(253 224 71 / var(--tw-bg-opacity));
}
.bg-gray-300 {
--tw-bg-opacity: 1;
background-color: rgb(209 213 219 / var(--tw-bg-opacity));
}
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.p-2 {
padding: 0.5rem;
}
.p-20 {
padding: 5rem;
}
.p-3 {
padding: 0.75rem;
}
.p-5 {
padding: 1.25rem;
}
.p-1 {
padding: 0.25rem;
}
.text-center {
text-align: center;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.font-bold {
font-weight: 700;
}
.font-semibold {
font-weight: 600;
}
.text-red-400 {
--tw-text-opacity: 1;
color: rgb(248 113 113 / var(--tw-text-opacity));
}
.text-blue-700 {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
.text-black {
--tw-text-opacity: 1;
color: rgb(0 0 0 / var(--tw-text-opacity));
}
.text-gray-950 {
--tw-text-opacity: 1;
color: rgb(3 7 18 / var(--tw-text-opacity));
}
.text-gray-50 {
--tw-text-opacity: 1;
color: rgb(249 250 251 / var(--tw-text-opacity));
}
.placeholder-gray-600::-moz-placeholder {
--tw-placeholder-opacity: 1;
color: rgb(75 85 99 / var(--tw-placeholder-opacity));
}
.placeholder-gray-600::placeholder {
--tw-placeholder-opacity: 1;
color: rgb(75 85 99 / var(--tw-placeholder-opacity));
}

29
src/background.ts Normal file
View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2023 R3BL LLC
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
function polling() {
// console.log("polling");
setTimeout(polling, 1000 * 30)
}
polling()

3
src/content_script.tsx Normal file
View file

@ -0,0 +1,3 @@
// import { changeBackgroundListener } from "./message_passing"
// chrome.runtime.onMessage.addListener(changeBackgroundListener)

130
src/options.tsx Normal file
View file

@ -0,0 +1,130 @@
import React, { useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
const Options = () => {
const [cookieA, setCookieA] = useState<string>("");
const [cookieB, setCookieB] = useState<string>("");
const [status, setStatus] = useState<string>("");
const [grabbedCookies, setGrabbedCookies] = useState<{
a?: string;
b?: string;
}>({ a: undefined, b: undefined });
const fetchCookies = () => {
console.log('fetching cookies')
chrome.cookies.getAllCookieStores().then((stores) => {
stores.forEach((store) => {
chrome.cookies.getAll({ storeId: store.id }, (cookies) => {
cookies.forEach((cookie) => {
if (cookie.name === "a") {
setCookieA(cookie.value);
setGrabbedCookies({ ...grabbedCookies, a: cookie.value });
}
if (cookie.name === "b") {
setCookieB(cookie.value);
setGrabbedCookies({ ...grabbedCookies, b: cookie.value });
}
});
});
});
});
};
const saveCookies = () => {
// Saves options to chrome.storage.sync.
chrome.storage.sync.set(
{
FAEX_a: cookieA,
FAEX_b: cookieB,
},
() => {
// Update status to let user know options were saved.
setStatus("Options saved.");
const id = setTimeout(() => {
setStatus("");
}, 1000);
return () => clearTimeout(id);
}
);
};
return (
<>
<div className="p-20 w-[95%] max-w-3xl m-auto">
<div className="logo text-center">
<ruby className="text-xl">
FurAffinity Exporter <rt className="text-2xl">FAEX</rt>
</ruby>
</div>
<div id="settings" className="mt-3 bg-gray-100 p-5 rounded">
<h1 className="text-xl">Extension Settings</h1>
<p>
To use the Extension, you need to provide it with your FurAffinity
Cookies.
</p>
<p>
<a className="text-blue-700" href="http://">
Click here
</a>{" "}
to find out how they're used
</p>
<br />
<p>
Follow{" "}
<a className="text-blue-700" href="http://">
this guide
</a>
, if you want to get them manually.
</p>
<p>
You can also click on the <kbd className="p-1 bg-gray-300">Fetch Cookies</kbd> Button below to
fill them automatically.
</p>
<br />
<p>Once they're in the Fields, press the <kbd className="p-1 bg-gray-300">Save Cookies</kbd> Button to save them for the future.</p>
<hr className="mt-3 mb-3 h-[3px] m-0 w-[100%] border-hidden bg-gray-200" />
<div id="inputs" className="flex flex-col gap-4">
<div className="field">
<label className="text-md font-semibold" htmlFor="cookie_A">Cookie A</label>
<input
className="p-3 bg-gray-300 text-gray-950 placeholder-gray-600 rounded border-2 border-gray-300 w-[100%] box-border"
type="text"
name="cookieA"
id="cookie_A"
placeholder="Put your 'a' Cookie here."
/>
</div>
<div className="field">
<label className="text-md font-semibold" htmlFor="cookie_B">Cookie B</label>
<input
className="p-3 bg-gray-300 text-gray-950 placeholder-gray-600 rounded border-2 border-gray-300 w-[100%] box-border"
type="text"
name="cookieB"
id="cookie_B"
placeholder="Put your 'b' Cookie here."
/>
</div>
</div>
<div id="actions" className="mt-4">
<button className="text-gray-50 bg-gray-800 p-2 rounded box-border mr-1" onSubmit={saveCookies}>
Save Cookies
</button>
<button className="text-gray-50 bg-gray-800 p-2 rounded box-border mr-1" onSubmit={fetchCookies}>
Fetch Cookies
</button>
</div>
</div>
</div>
</>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<React.StrictMode>
<Options />
</React.StrictMode>
);

61
src/popup.tsx Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2023 R3BL LLC
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import React, { useEffect, useState } from "react"
import { createRoot } from "react-dom/client"
const Popup = () => {
const [count, setCount] = useState(0)
const [currentURL, setCurrentURL] = useState<string>()
useEffect(() => {
chrome.action.setBadgeText({ text: count.toString() })
}, [count])
useEffect(() => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
setCurrentURL(tabs[0].url)
})
}, [])
return (
<>
<ul style={{ minWidth: "700px" }}>
<li>Current URL: {currentURL}</li>
<li>Current Time: {new Date().toLocaleTimeString()}</li>
</ul>
<button onClick={() => setCount(count + 1)} style={{ marginRight: "5px" }}>
count up
</button>
</>
)
}
const root = createRoot(document.getElementById("root")!)
root.render(
<React.StrictMode>
<Popup />
</React.StrictMode>
)

3
src/styles/tailwind.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

8
tailwind.config.js Normal file
View file

@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,tsx,js}"],
theme: {
extend: {},
},
plugins: [],
}

24
tsconfig.json Normal file
View file

@ -0,0 +1,24 @@
{
"compilerOptions": {
"strict": true,
"target": "es6",
"moduleResolution": "bundler",
"module": "ES6",
"esModuleInterop": true,
"sourceMap": false,
"rootDir": "src",
"outDir": "dist/js",
"noEmitOnError": true,
"jsx": "react",
"typeRoots": [ "node_modules/@types" ],
"types": [
// Support for: https://www.npmjs.com/package/@types/chrome
// Run: `npm install --save @types/chrome`
// More info: https://stackoverflow.com/a/40826789/2085356
"chrome",
// Support for Jest
// Run: `npm i --save-dev @types/jest`
"jest",
]
}
}

7
tsconfig.test.json Normal file
View file

@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"sourceMap": true,
}
}

50
webpack/webpack.common.js Normal file
View file

@ -0,0 +1,50 @@
const webpack = require("webpack");
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const srcDir = path.join(__dirname, "..", "src");
const pubDir = path.join(__dirname, "..", "public");
module.exports = {
entry: {
popup: path.join(srcDir, 'popup.tsx'),
options: path.join(srcDir, 'options.tsx'),
background: path.join(srcDir, 'background.ts'),
content_script: path.join(srcDir, 'content_script.tsx'),
// styles: path.join(pubDir, 'styles.css'),
},
output: {
path: path.join(__dirname, "../dist/js"),
filename: "[name].js",
},
optimization: {
splitChunks: {
name: "vendor",
chunks(chunk) {
return chunk.name !== 'background';
}
},
},
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.css?$/,
use: ["css-loader"],
},
],
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
plugins: [
new CopyPlugin({
patterns: [{ from: ".", to: "../", context: "public" }],
options: {},
}),
],
};

27
webpack/webpack.dev.js Normal file
View file

@ -0,0 +1,27 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const CopyPlugin = require("copy-webpack-plugin");
const { HotModuleReplacementPlugin } = require('webpack');
module.exports = merge(common, {
devtool: 'inline-source-map',
mode: 'development',
devServer: {
static: './dist',
hot: true
},
plugins: [
new CopyPlugin({
patterns: [{ from: ".", to: "../", context: "public" }],
options: {},
}),
new HotModuleReplacementPlugin()
]
});
if (module.hot) {
module.hot.accept('styles.css', () => {
const baseStyle = window.document.getElementById('js-style')
baseStyle.setAttribute('href', 'styles.css?v=' + new Date().valueOf)
})
}

6
webpack/webpack.prod.js Normal file
View file

@ -0,0 +1,6 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production'
});