mirror of
https://github.com/koloml/furbooru-tagging-assistant.git
synced 2026-02-06 23:32:58 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef76560bfb | |||
| faa909a0db | |||
| 3955e3191e | |||
| 17dab5854c | |||
| a20632e58e | |||
| 5f4a1a6c00 | |||
| 48fc58f042 | |||
| 8356956b2e | |||
| 3833cada1e | |||
| f3d80b58b1 | |||
| d567ab4dec | |||
| e4322b3021 | |||
| 4907efdaab | |||
| c6b9250d71 | |||
| c330aa303a | |||
| 9ed3f6939d | |||
| 5584733b17 | |||
| 91947b8cc7 | |||
| df61c812fe | |||
| 65c420c36c | |||
| 79cd9bc44d | |||
| cf28d2d131 | |||
| 50238d8ef4 | |||
| 98b5311cfc | |||
| e60d20fd60 |
BIN
.github/assets/derpibooru-colors-in-editor.png
vendored
Normal file
BIN
.github/assets/derpibooru-colors-in-editor.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
BIN
.github/assets/derpibooru-groups-showcase-0.png
vendored
Normal file
BIN
.github/assets/derpibooru-groups-showcase-0.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
.github/assets/derpibooru-groups-showcase-1.png
vendored
Normal file
BIN
.github/assets/derpibooru-groups-showcase-1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -16,7 +16,8 @@ below.
|
||||
|
||||
### Derpibooru Tagging Assistant
|
||||
|
||||
I wasn't able to release the extension for Derpibooru yet. Links will be available shortly.
|
||||
[](https://addons.mozilla.org/en-US/firefox/addon/derpibooru-tagging-assistant/)
|
||||
[](https://chromewebstore.google.com/detail/pnmbomcdbfcghgmegklfofncfigdielb)
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Furbooru Tagging Assistant",
|
||||
"description": "Small experimental extension for slightly quicker tagging experience. Furbooru Edition.",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.2",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "furbooru-tagging-assistant@thecore.city"
|
||||
@@ -47,6 +47,9 @@
|
||||
],
|
||||
"js": [
|
||||
"src/content/tags-editor.ts"
|
||||
],
|
||||
"css": [
|
||||
"src/styles/content/tags-editor.scss"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
1039
package-lock.json
generated
1039
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "furbooru-tagging-assistant",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run build:popup && npm run build:extension",
|
||||
@@ -13,26 +13,26 @@
|
||||
"test:watch": "vitest watch --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@sveltejs/kit": "^2.21.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.0",
|
||||
"@types/chrome": "^0.0.326",
|
||||
"@types/node": "^22.15.29",
|
||||
"@vitest/coverage-v8": "^3.2.0",
|
||||
"cheerio": "^1.0.0",
|
||||
"@types/node": "^22.18.6",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"cheerio": "^1.1.2",
|
||||
"cross-env": "^10.0.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"sass": "^1.89.1",
|
||||
"svelte": "^5.33.14",
|
||||
"svelte-check": "^4.2.1",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.5",
|
||||
"vitest": "^3.2.0"
|
||||
"jsdom": "^27.0.0",
|
||||
"svelte-check": "^4.3.1",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^7.1.6",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@sveltejs/adapter-static": "^3.0.9",
|
||||
"@sveltejs/kit": "^2.42.2",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"amd-lite": "^1.0.1",
|
||||
"lz-string": "^1.5.0"
|
||||
"lz-string": "^1.5.0",
|
||||
"sass": "^1.93.0",
|
||||
"svelte": "^5.39.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,52 @@ import { amdLite } from "amd-lite";
|
||||
|
||||
const originalDefine = amdLite.define;
|
||||
|
||||
/**
|
||||
* Set of already defined modules. Used for deduplication.
|
||||
*/
|
||||
const definedModules = new Set<string>();
|
||||
|
||||
/**
|
||||
* Throttle timer to make sure only one attempt at loading modules will run for a batch of loaded scripts.
|
||||
*/
|
||||
let throttledAutoRunTimer: NodeJS.Timeout | number | undefined;
|
||||
|
||||
/**
|
||||
* Schedule the automatic resolving of all waiting modules on the next available frame.
|
||||
*/
|
||||
function scheduleModulesAutoRun() {
|
||||
clearTimeout(throttledAutoRunTimer);
|
||||
|
||||
throttledAutoRunTimer = setTimeout(() => {
|
||||
amdLite.resolveDependencies(Object.keys(amdLite.waitingModules));
|
||||
});
|
||||
}
|
||||
|
||||
amdLite.define = (name, dependencies, originalCallback) => {
|
||||
return originalDefine(name, dependencies, function () {
|
||||
// Chrome doesn't run the same content script multiple times, while Firefox does. Since each content script and their
|
||||
// chunks are intended to be run only once, we should just ignore any attempts of running the same module more than
|
||||
// once. Names of the modules are assumed to be unique.
|
||||
if (definedModules.has(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
definedModules.add(name);
|
||||
|
||||
originalDefine(name, dependencies, function () {
|
||||
const callbackResult = originalCallback(...arguments);
|
||||
|
||||
// Workaround for the entry script not returning anything causing AMD-Lite to send warning about modules not
|
||||
// being loaded/not existing.
|
||||
return typeof callbackResult !== 'undefined' ? callbackResult : {};
|
||||
})
|
||||
});
|
||||
|
||||
// Schedule the auto run on the next available frame. Firefox and Chromium have a lot of differences in how they
|
||||
// decide to execute content scripts. For example, Firefox might decide to skip a frame before attempting to load
|
||||
// different groups of them. Chromium on the other hand doesn't have that issue, but it doesn't allow us to, for
|
||||
// example, schedule a microtask to run the modules.
|
||||
scheduleModulesAutoRun();
|
||||
}
|
||||
|
||||
amdLite.init({
|
||||
publicScope: window
|
||||
});
|
||||
|
||||
// We don't have anything asynchronous, so it's safe to execute everything on the next frame.
|
||||
requestAnimationFrame(() => {
|
||||
amdLite.resolveDependencies(Object.keys(amdLite.waitingModules))
|
||||
});
|
||||
|
||||
@@ -148,7 +148,12 @@ export class TagDropdownWrapper extends BaseComponent {
|
||||
profileSpecificButtonText = `Remove from profile "${profileName}"`;
|
||||
}
|
||||
|
||||
this.#toggleOnExistingButton.innerText = profileSpecificButtonText;
|
||||
if (this.#toggleOnExistingButton.lastChild instanceof Text) {
|
||||
this.#toggleOnExistingButton.lastChild.textContent = ` ${profileSpecificButtonText}`;
|
||||
} else {
|
||||
// Just in case last child is missing, then update the text on the full element.
|
||||
this.#toggleOnExistingButton.textContent = profileSpecificButtonText;
|
||||
}
|
||||
|
||||
if (!this.#toggleOnExistingButton.isConnected) {
|
||||
this.#dropdownContainer?.append(this.#toggleOnExistingButton);
|
||||
@@ -243,9 +248,14 @@ export class TagDropdownWrapper extends BaseComponent {
|
||||
static #createDropdownLink(text: string, onClickHandler: (event: MouseEvent) => void): HTMLAnchorElement {
|
||||
const dropdownLink = document.createElement('a');
|
||||
dropdownLink.href = '#';
|
||||
dropdownLink.innerText = text;
|
||||
dropdownLink.className = 'tag__dropdown__link';
|
||||
|
||||
const dropdownLinkIcon = document.createElement('i');
|
||||
dropdownLinkIcon.classList.add('fa', 'fa-tags');
|
||||
|
||||
dropdownLink.textContent = ` ${text}`;
|
||||
dropdownLink.insertAdjacentElement('afterbegin', dropdownLinkIcon);
|
||||
|
||||
dropdownLink.addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
onClickHandler(event);
|
||||
|
||||
@@ -134,6 +134,7 @@ export class TagsListBlock extends BaseComponent {
|
||||
heading.style.display = 'none';
|
||||
heading.style.order = `var(${TagsListBlock.#orderCssVariableForGroup(group.id)}, 0)`;
|
||||
heading.style.flexBasis = '100%';
|
||||
heading.classList.add('tag-category-headline');
|
||||
|
||||
// We're inserting heading to the top just to make sure that heading is always in front of the tags related to
|
||||
// this category.
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
$background-color: var(--background-color);
|
||||
$media-border: var(--media-border);
|
||||
$media-box-color: var(--media-box-color);
|
||||
$padding-small: var(--padding-small);
|
||||
$padding-normal: var(--padding-normal);
|
||||
$padding-large: var(--padding-large);
|
||||
|
||||
// These variables are defined dynamically based on the category of the tag
|
||||
$resolved-tag-background: var(--tag-background);
|
||||
|
||||
@@ -68,15 +68,8 @@
|
||||
.tag {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
// Derpibooru has slight differences in how tags are displayed.
|
||||
@if environment.$current-site == 'derpibooru' {
|
||||
padding: 0 5px;
|
||||
gap: 0;
|
||||
}
|
||||
@else {
|
||||
padding: 5px;
|
||||
}
|
||||
padding: 0 5px;
|
||||
gap: 0;
|
||||
|
||||
&:hover {
|
||||
background: booru-vars.$resolved-tag-color;
|
||||
|
||||
13
src/styles/content/tags-editor.scss
Normal file
13
src/styles/content/tags-editor.scss
Normal file
@@ -0,0 +1,13 @@
|
||||
@use '$styles/booru-vars';
|
||||
@use '$styles/environment';
|
||||
|
||||
h2.tag-category-headline {
|
||||
// Basic margin top and bottom values gathered from Chrome.
|
||||
$base-margin-top: .83em;
|
||||
$base-margin-bottom: .62em;
|
||||
|
||||
margin: {
|
||||
top: calc(#{$base-margin-top} - #{booru-vars.$padding-small});
|
||||
bottom: calc(#{$base-margin-bottom} - #{booru-vars.$padding-small});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
.tag {
|
||||
background: colors.$tag-background;
|
||||
line-height: 28px;
|
||||
color: colors.$tag-text;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
@@ -12,6 +11,10 @@
|
||||
|
||||
@if environment.$current-site == 'derpibooru' {
|
||||
border: 1px solid colors.$tag-border;
|
||||
line-height: 24px;
|
||||
}
|
||||
@else {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.remove {
|
||||
|
||||
Reference in New Issue
Block a user