mirror of
https://github.com/koloml/furbooru-tagging-assistant.git
synced 2026-02-07 07:42:59 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab625d0181 | |||
| c59d8f55f0 | |||
| 8dfc5f49f9 | |||
| 2ecd37512f | |||
| c8ff80d445 | |||
| 38cbd725d9 | |||
| 26f09c7c46 | |||
| 64be6a6e15 | |||
| cb22b2deab | |||
| 5c5e0812dc | |||
| 70129d7a0e | |||
| 5fd6dee999 | |||
| ec41ba5030 | |||
| 55624285e1 | |||
| b97255ccd6 | |||
| 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/colors-in-editor.png
vendored
Normal file
BIN
.github/assets/colors-in-editor.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
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 |
BIN
.github/assets/groups-showcase-0.png
vendored
Normal file
BIN
.github/assets/groups-showcase-0.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
BIN
.github/assets/groups-showcase-1.png
vendored
Normal file
BIN
.github/assets/groups-showcase-1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
63
.github/workflows/build-extensions.yml
vendored
Normal file
63
.github/workflows/build-extensions.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Build Extensions
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build-extensions:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
site: [furbooru, derpibooru]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build extension for ${{ matrix.site }}
|
||||
run: |
|
||||
if [ "${{ matrix.site }}" = "derpibooru" ]; then
|
||||
npm run build:derpibooru
|
||||
else
|
||||
npm run build
|
||||
fi
|
||||
|
||||
- name: Create extension zip
|
||||
run: |
|
||||
cd build
|
||||
zip -r "../${{ matrix.site }}-tagging-assistant-extension.zip" .
|
||||
|
||||
- name: Upload extension artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.site }}-tagging-assistant-extension
|
||||
path: ${{ matrix.site }}-tagging-assistant-extension.zip
|
||||
retention-days: 30
|
||||
|
||||
create-release-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-extensions
|
||||
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Create combined artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: all-extensions
|
||||
path: artifacts/
|
||||
retention-days: 90
|
||||
@@ -51,6 +51,7 @@ function wrapScriptIntoIIFE() {
|
||||
function makeAliases(rootDir) {
|
||||
return {
|
||||
"$config": path.resolve(rootDir, 'src/config'),
|
||||
"$content": path.resolve(rootDir, 'src/content'),
|
||||
"$lib": path.resolve(rootDir, 'src/lib'),
|
||||
"$entities": path.resolve(rootDir, 'src/lib/extension/entities'),
|
||||
"$styles": path.resolve(rootDir, 'src/styles'),
|
||||
|
||||
@@ -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.3",
|
||||
"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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
2168
package-lock.json
generated
2168
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "furbooru-tagging-assistant",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.3",
|
||||
"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",
|
||||
"@types/chrome": "^0.0.326",
|
||||
"@types/node": "^22.15.29",
|
||||
"@vitest/coverage-v8": "^3.2.0",
|
||||
"cheerio": "^1.0.0",
|
||||
"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"
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.3",
|
||||
"@types/chrome": "^0.1.32",
|
||||
"@types/node": "^25.0.3",
|
||||
"@vitest/coverage-v8": "^4.0.16",
|
||||
"cheerio": "^1.1.2",
|
||||
"cross-env": "^10.1.0",
|
||||
"jsdom": "^27.4.0",
|
||||
"svelte-check": "^4.3.5",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vitest": "^4.0.16"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.49.4",
|
||||
"@fortawesome/fontawesome-free": "^7.1.0",
|
||||
"amd-lite": "^1.0.1",
|
||||
"lz-string": "^1.5.0"
|
||||
"lz-string": "^1.5.0",
|
||||
"sass": "^1.97.2",
|
||||
"svelte": "^5.46.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
let { profile }: ProfileViewProps = $props();
|
||||
|
||||
const sortedTagsList = profile.settings.tags.sort((a, b) => a.localeCompare(b));
|
||||
const sortedTagsList = $derived(profile.settings.tags.sort((a, b) => a.localeCompare(b)));
|
||||
</script>
|
||||
|
||||
<div class="block">
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { PLUGIN_NAME } from "$lib/constants";
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<a href="/">{__CURRENT_SITE_NAME__} Tagging Assistant</a>
|
||||
<a href="/">{PLUGIN_NAME}</a>
|
||||
</header>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import SelectField from "$components/ui/forms/SelectField.svelte";
|
||||
import { categories } from "$lib/booru/tag-categories";
|
||||
import { categories } from "$config/tags";
|
||||
|
||||
interface TagCategorySelectFieldProps {
|
||||
value?: string;
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/**
|
||||
* List of categories defined by the sites.
|
||||
*/
|
||||
export const categories: string[] = [
|
||||
'rating',
|
||||
'spoiler',
|
||||
'origin',
|
||||
'oc',
|
||||
'error',
|
||||
'character',
|
||||
'content-official',
|
||||
'content-fanmade',
|
||||
'species',
|
||||
'body-type',
|
||||
];
|
||||
|
||||
/**
|
||||
* List of tags which marked by the site as blacklisted. These tags are blocked from being added by the tag editor and
|
||||
* should usually just be removed automatically.
|
||||
*/
|
||||
export const tagsBlacklist: string[] = (__CURRENT_SITE__ === 'furbooru' ? [
|
||||
"anthro art",
|
||||
"anthro artist",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import MiscSettings, { type FullscreenViewerSize } from "$lib/extension/settings/MiscSettings";
|
||||
import { emit, on } from "$lib/components/events/comms";
|
||||
import { EVENT_SIZE_LOADED } from "$lib/components/events/fullscreen-viewer-events";
|
||||
import { emit, on } from "$content/components/events/comms";
|
||||
import { EVENT_SIZE_LOADED } from "$content/components/events/fullscreen-viewer-events";
|
||||
|
||||
export class FullscreenViewer extends BaseComponent {
|
||||
#videoElement: HTMLVideoElement = document.createElement('video');
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import MiscSettings from "$lib/extension/settings/MiscSettings";
|
||||
import { FullscreenViewer } from "$lib/components/FullscreenViewer";
|
||||
import type { MediaBoxTools } from "$lib/components/MediaBoxTools";
|
||||
import { FullscreenViewer } from "$content/components/FullscreenViewer";
|
||||
import type { MediaBoxTools } from "$content/components/MediaBoxTools";
|
||||
|
||||
export class ImageShowFullscreenButton extends BaseComponent {
|
||||
#mediaBoxTools: MediaBoxTools | null = null;
|
||||
@@ -1,16 +1,16 @@
|
||||
import MaintenanceSettings from "$lib/extension/settings/MaintenanceSettings";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import ScrapedAPI from "$lib/booru/scraped/ScrapedAPI";
|
||||
import { tagsBlacklist } from "$config/tags";
|
||||
import { emitterAt } from "$lib/components/events/comms";
|
||||
import { emitterAt } from "$content/components/events/comms";
|
||||
import {
|
||||
EVENT_ACTIVE_PROFILE_CHANGED,
|
||||
EVENT_MAINTENANCE_STATE_CHANGED,
|
||||
EVENT_TAGS_UPDATED
|
||||
} from "$lib/components/events/maintenance-popup-events";
|
||||
import type { MediaBoxTools } from "$lib/components/MediaBoxTools";
|
||||
} from "$content/components/events/maintenance-popup-events";
|
||||
import type { MediaBoxTools } from "$content/components/MediaBoxTools";
|
||||
|
||||
class BlackListedTagsEncounteredError extends Error {
|
||||
constructor(tagName: string) {
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { on } from "$lib/components/events/comms";
|
||||
import { EVENT_MAINTENANCE_STATE_CHANGED } from "$lib/components/events/maintenance-popup-events";
|
||||
import type { MediaBoxTools } from "$lib/components/MediaBoxTools";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import { on } from "$content/components/events/comms";
|
||||
import { EVENT_MAINTENANCE_STATE_CHANGED } from "$content/components/events/maintenance-popup-events";
|
||||
import type { MediaBoxTools } from "$content/components/MediaBoxTools";
|
||||
|
||||
export class MaintenanceStatusIcon extends BaseComponent {
|
||||
#mediaBoxTools: MediaBoxTools | null = null;
|
||||
@@ -1,9 +1,9 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { MaintenancePopup } from "$lib/components/MaintenancePopup";
|
||||
import { on } from "$lib/components/events/comms";
|
||||
import { EVENT_ACTIVE_PROFILE_CHANGED } from "$lib/components/events/maintenance-popup-events";
|
||||
import type { MediaBoxWrapper } from "$lib/components/MediaBoxWrapper";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import { MaintenancePopup } from "$content/components/MaintenancePopup";
|
||||
import { on } from "$content/components/events/comms";
|
||||
import { EVENT_ACTIVE_PROFILE_CHANGED } from "$content/components/events/maintenance-popup-events";
|
||||
import type { MediaBoxWrapper } from "$content/components/MediaBoxWrapper";
|
||||
import type MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
|
||||
export class MediaBoxTools extends BaseComponent {
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import { buildTagsAndAliasesMap } from "$lib/booru/tag-utils";
|
||||
import { on } from "$lib/components/events/comms";
|
||||
import { EVENT_TAGS_UPDATED } from "$lib/components/events/maintenance-popup-events";
|
||||
import { on } from "$content/components/events/comms";
|
||||
import { EVENT_TAGS_UPDATED } from "$content/components/events/maintenance-popup-events";
|
||||
|
||||
export class MediaBoxWrapper extends BaseComponent {
|
||||
#thumbnailContainer: HTMLElement | null = null;
|
||||
@@ -1,11 +1,11 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import MaintenanceSettings from "$lib/extension/settings/MaintenanceSettings";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import CustomCategoriesResolver from "$lib/extension/CustomCategoriesResolver";
|
||||
import { on } from "$lib/components/events/comms";
|
||||
import { EVENT_FORM_EDITOR_UPDATED } from "$lib/components/events/tags-form-events";
|
||||
import { EVENT_TAG_GROUP_RESOLVED } from "$lib/components/events/tag-dropdown-events";
|
||||
import { on } from "$content/components/events/comms";
|
||||
import { EVENT_FORM_EDITOR_UPDATED } from "$content/components/events/tags-form-events";
|
||||
import { EVENT_TAG_GROUP_RESOLVED } from "$content/components/events/tag-dropdown-events";
|
||||
import type TagGroup from "$entities/TagGroup";
|
||||
|
||||
const categoriesResolver = new CustomCategoriesResolver();
|
||||
@@ -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);
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { emit, on, type UnsubscribeFunction } from "$lib/components/events/comms";
|
||||
import { EVENT_FETCH_COMPLETE } from "$lib/components/events/booru-events";
|
||||
import { EVENT_FORM_EDITOR_UPDATED } from "$lib/components/events/tags-form-events";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import { emit, on, type UnsubscribeFunction } from "$content/components/events/comms";
|
||||
import { EVENT_FETCH_COMPLETE } from "$content/components/events/booru-events";
|
||||
import { EVENT_FORM_EDITOR_UPDATED } from "$content/components/events/tags-form-events";
|
||||
|
||||
export class TagsForm extends BaseComponent {
|
||||
protected init() {
|
||||
@@ -1,10 +1,10 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import type TagGroup from "$entities/TagGroup";
|
||||
import type { TagDropdownWrapper } from "$lib/components/TagDropdownWrapper";
|
||||
import { on } from "$lib/components/events/comms";
|
||||
import { EVENT_FORM_EDITOR_UPDATED } from "$lib/components/events/tags-form-events";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { EVENT_TAG_GROUP_RESOLVED } from "$lib/components/events/tag-dropdown-events";
|
||||
import type { TagDropdownWrapper } from "$content/components/TagDropdownWrapper";
|
||||
import { on } from "$content/components/events/comms";
|
||||
import { EVENT_FORM_EDITOR_UPDATED } from "$content/components/events/tags-form-events";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import { EVENT_TAG_GROUP_RESOLVED } from "$content/components/events/tag-dropdown-events";
|
||||
import TagSettings from "$lib/extension/settings/TagSettings";
|
||||
|
||||
export class TagsListBlock extends BaseComponent {
|
||||
@@ -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,4 +1,4 @@
|
||||
import { bindComponent } from "$lib/components/base/component-utils";
|
||||
import { bindComponent } from "$content/components/base/component-utils";
|
||||
|
||||
type ComponentEventListener<EventName extends keyof HTMLElementEventMap> =
|
||||
(this: HTMLElement, event: HTMLElementEventMap[EventName]) => void;
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import type { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
|
||||
const instanceSymbol = Symbol.for('instance');
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { MaintenancePopupEventsMap } from "$lib/components/events/maintenance-popup-events";
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import type { FullscreenViewerEventsMap } from "$lib/components/events/fullscreen-viewer-events";
|
||||
import type { BooruEventsMap } from "$lib/components/events/booru-events";
|
||||
import type { TagsFormEventsMap } from "$lib/components/events/tags-form-events";
|
||||
import type { TagDropdownEvents } from "$lib/components/events/tag-dropdown-events";
|
||||
import type { MaintenancePopupEventsMap } from "$content/components/events/maintenance-popup-events";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import type { FullscreenViewerEventsMap } from "$content/components/events/fullscreen-viewer-events";
|
||||
import type { BooruEventsMap } from "$content/components/events/booru-events";
|
||||
import type { TagsFormEventsMap } from "$content/components/events/tags-form-events";
|
||||
import type { TagDropdownEvents } from "$content/components/events/tag-dropdown-events";
|
||||
|
||||
type EventsMapping =
|
||||
MaintenancePopupEventsMap
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { ImageListInfo } from "$lib/components/listing/ImageListInfo";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { ImageListInfo } from "$content/components/listing/ImageListInfo";
|
||||
|
||||
export class ImageListContainer extends BaseComponent {
|
||||
#info: ImageListInfo | null = null;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
|
||||
export class ImageListInfo extends BaseComponent {
|
||||
#tagElement: HTMLElement | null = null;
|
||||
@@ -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))
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { createMaintenancePopup } from "$lib/components/MaintenancePopup";
|
||||
import { createMediaBoxTools } from "$lib/components/MediaBoxTools";
|
||||
import { calculateMediaBoxesPositions, initializeMediaBox } from "$lib/components/MediaBoxWrapper";
|
||||
import { createMaintenanceStatusIcon } from "$lib/components/MaintenanceStatusIcon";
|
||||
import { createImageShowFullscreenButton } from "$lib/components/ImageShowFullscreenButton";
|
||||
import { initializeImageListContainer } from "$lib/components/listing/ImageListContainer";
|
||||
import { createMaintenancePopup } from "$content/components/MaintenancePopup";
|
||||
import { createMediaBoxTools } from "$content/components/MediaBoxTools";
|
||||
import { calculateMediaBoxesPositions, initializeMediaBox } from "$content/components/MediaBoxWrapper";
|
||||
import { createMaintenanceStatusIcon } from "$content/components/MaintenanceStatusIcon";
|
||||
import { createImageShowFullscreenButton } from "$content/components/ImageShowFullscreenButton";
|
||||
import { initializeImageListContainer } from "$content/components/listing/ImageListContainer";
|
||||
|
||||
const mediaBoxes = document.querySelectorAll<HTMLElement>('.media-box');
|
||||
const imageListContainer = document.querySelector<HTMLElement>('#imagelist-container');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TagsForm } from "$lib/components/TagsForm";
|
||||
import { initializeAllTagsLists, watchForUpdatedTagLists } from "$lib/components/TagsListBlock";
|
||||
import { TagsForm } from "$content/components/TagsForm";
|
||||
import { initializeAllTagsLists, watchForUpdatedTagLists } from "$content/components/TagsListBlock";
|
||||
|
||||
initializeAllTagsLists();
|
||||
watchForUpdatedTagLists();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { watchTagDropdownsInTagsEditor, wrapTagDropdown } from "$lib/components/TagDropdownWrapper";
|
||||
import { watchTagDropdownsInTagsEditor, wrapTagDropdown } from "$content/components/TagDropdownWrapper";
|
||||
|
||||
for (let tagDropdownElement of document.querySelectorAll<HTMLElement>('.tag.dropdown')) {
|
||||
wrapTagDropdown(tagDropdownElement);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
export const categories = [
|
||||
'rating',
|
||||
'spoiler',
|
||||
'origin',
|
||||
'oc',
|
||||
'error',
|
||||
'character',
|
||||
'content-official',
|
||||
'content-fanmade',
|
||||
'species',
|
||||
'body-type',
|
||||
];
|
||||
4
src/lib/constants.ts
Normal file
4
src/lib/constants.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Automatically generated name of the plugin.
|
||||
*/
|
||||
export const PLUGIN_NAME = __CURRENT_SITE_NAME__ + ' Tagging Assistant';
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { TagDropdownWrapper } from "$lib/components/TagDropdownWrapper";
|
||||
import type { TagDropdownWrapper } from "$content/components/TagDropdownWrapper";
|
||||
import TagGroup from "$entities/TagGroup";
|
||||
import { escapeRegExp } from "$lib/utils";
|
||||
import { emit } from "$lib/components/events/comms";
|
||||
import { EVENT_TAG_GROUP_RESOLVED } from "$lib/components/events/tag-dropdown-events";
|
||||
import { emit } from "$content/components/events/comms";
|
||||
import { EVENT_TAG_GROUP_RESOLVED } from "$content/components/events/tag-dropdown-events";
|
||||
|
||||
export default class CustomCategoriesResolver {
|
||||
#exactGroupMatches = new Map<string, TagGroup>();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import Footer from "$components/layout/Footer.svelte";
|
||||
import { initializeLinksReplacement } from "$lib/popup-links";
|
||||
import { onDestroy } from "svelte";
|
||||
import { headTitle } from "$stores/popup";
|
||||
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet;
|
||||
@@ -22,6 +23,10 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{$headTitle}</title>
|
||||
</svelte:head>
|
||||
|
||||
<Header/>
|
||||
<main>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
import { activeProfileStore, maintenanceProfiles } from "$stores/entities/maintenance-profiles";
|
||||
import MenuCheckboxItem from "$components/ui/menu/MenuCheckboxItem.svelte";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = null;
|
||||
|
||||
let activeProfile = $derived<MaintenanceProfile | null>(
|
||||
$maintenanceProfiles.find(profile => profile.id === $activeProfileStore) || null
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<script>
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { PLUGIN_NAME } from "$lib/constants";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'About';
|
||||
|
||||
let currentSiteUrl = 'https://furbooru.org';
|
||||
|
||||
@@ -14,7 +18,7 @@
|
||||
<hr>
|
||||
</Menu>
|
||||
<h1>
|
||||
{__CURRENT_SITE_NAME__} Tagging Assistant
|
||||
{PLUGIN_NAME}
|
||||
</h1>
|
||||
<p>
|
||||
This is a small tool to make tagging on {__CURRENT_SITE_NAME__} just a little bit more convenient. Group tags with
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { tagGroups } from "$stores/entities/tag-groups";
|
||||
import TagGroup from "$entities/TagGroup";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Tag Groups';
|
||||
|
||||
let groups = $derived<TagGroup[]>($tagGroups.sort((a, b) => a.settings.name.localeCompare(b.settings.name)));
|
||||
</script>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { tagGroups } from "$stores/entities/tag-groups";
|
||||
import TagGroup from "$entities/TagGroup";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let groupId = $derived<string>(page.params.id);
|
||||
let group = $derived<TagGroup | null>($tagGroups.find(group => group.id === groupId) || null);
|
||||
@@ -19,6 +20,8 @@
|
||||
if (!group) {
|
||||
console.warn(`Group ${groupId} not found.`);
|
||||
goto('/features/groups');
|
||||
} else {
|
||||
$popupTitle = `Tag Group: ${group.settings.name}`;
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { tagGroups } from "$stores/entities/tag-groups";
|
||||
import type TagGroup from "$entities/TagGroup";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
const groupId = $derived<string>(page.params.id);
|
||||
const targetGroup = $derived<TagGroup | undefined>($tagGroups.find(group => group.id === groupId));
|
||||
@@ -12,6 +13,8 @@
|
||||
$effect(() => {
|
||||
if (!targetGroup) {
|
||||
goto('/features/groups');
|
||||
} else {
|
||||
$popupTitle = `Deleting Tag Group: ${targetGroup.settings.name}`;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import TagGroup from "$entities/TagGroup";
|
||||
import { tagGroups } from "$stores/entities/tag-groups";
|
||||
import CheckboxField from "$components/ui/forms/CheckboxField.svelte";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let groupId = $derived(page.params.id);
|
||||
|
||||
@@ -32,6 +33,7 @@
|
||||
|
||||
$effect(() => {
|
||||
if (groupId === 'new') {
|
||||
$popupTitle = 'Create Tag Group';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -40,6 +42,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
$popupTitle = `Edit Tag Group: ${targetGroup.settings.name}`;
|
||||
|
||||
groupName = targetGroup.settings.name;
|
||||
tagsList = [...targetGroup.settings.tags].sort((a, b) => a.localeCompare(b));
|
||||
prefixesList = [...targetGroup.settings.prefixes].sort((a, b) => a.localeCompare(b));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import TagGroup from "$entities/TagGroup";
|
||||
import EntitiesTransporter from "$lib/extension/EntitiesTransporter";
|
||||
import { tagGroups } from "$stores/entities/tag-groups";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let isEncodedGroupShown = $state(true);
|
||||
|
||||
@@ -17,6 +18,8 @@
|
||||
$effect(() => {
|
||||
if (!group) {
|
||||
goto('/features/groups');
|
||||
} else {
|
||||
$popupTitle = `Export Tag Group: ${group.settings.name}`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import TagGroup from "$entities/TagGroup";
|
||||
import EntitiesTransporter from "$lib/extension/EntitiesTransporter";
|
||||
import { tagGroups } from "$stores/entities/tag-groups";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
const groupTransporter = new EntitiesTransporter(TagGroup);
|
||||
|
||||
@@ -17,6 +18,12 @@
|
||||
let candidateGroup = $state<TagGroup | null>(null);
|
||||
let existingGroup = $state<TagGroup | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
$popupTitle = candidateGroup
|
||||
? 'Confirm Imported Tag Group'
|
||||
: 'Import Tag Group';
|
||||
});
|
||||
|
||||
function tryImportingGroup() {
|
||||
candidateGroup = null;
|
||||
existingGroup = null;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
import MenuRadioItem from "$components/ui/menu/MenuRadioItem.svelte";
|
||||
import { activeProfileStore, maintenanceProfiles } from "$stores/entities/maintenance-profiles";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Tagging Profiles';
|
||||
|
||||
let profiles = $derived<MaintenanceProfile[]>(
|
||||
$maintenanceProfiles.sort((a, b) => a.settings.name.localeCompare(b.settings.name))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { page } from "$app/state";
|
||||
@@ -8,7 +7,7 @@
|
||||
import ProfileView from "$components/features/ProfileView.svelte";
|
||||
import MenuCheckboxItem from "$components/ui/menu/MenuCheckboxItem.svelte";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { onMount } from "svelte";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let profileId = $derived(page.params.id);
|
||||
let profile = $derived<MaintenanceProfile|null>(
|
||||
@@ -24,6 +23,8 @@
|
||||
if (!profile) {
|
||||
console.warn(`Profile ${profileId} not found.`);
|
||||
goto('/features/maintenance');
|
||||
} else {
|
||||
$popupTitle = `Tagging Profile: ${profile.settings.name}`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { page } from "$app/state";
|
||||
import { maintenanceProfiles } from "$stores/entities/maintenance-profiles";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
const profileId = $derived(page.params.id);
|
||||
const targetProfile = $derived<MaintenanceProfile | null>(
|
||||
@@ -14,6 +15,8 @@
|
||||
$effect(() => {
|
||||
if (!targetProfile) {
|
||||
goto('/features/maintenance');
|
||||
} else {
|
||||
$popupTitle = `Deleting Tagging Profile: ${targetProfile.settings.name}`
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { goto } from "$app/navigation";
|
||||
import { maintenanceProfiles } from "$stores/entities/maintenance-profiles";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
|
||||
let profileId = $derived(page.params.id);
|
||||
@@ -26,6 +27,7 @@
|
||||
|
||||
$effect(() => {
|
||||
if (profileId === 'new') {
|
||||
$popupTitle = 'Create Tagging Profile';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,6 +36,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
$popupTitle = `Edit Tagging Profile: ${targetProfile.settings.name}`;
|
||||
|
||||
profileName = targetProfile.settings.name;
|
||||
tagsList = [...targetProfile.settings.tags].sort((a, b) => a.localeCompare(b));
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import FormControl from "$components/ui/forms/FormControl.svelte";
|
||||
import EntitiesTransporter from "$lib/extension/EntitiesTransporter";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let isCompressedProfileShown = $state(true);
|
||||
|
||||
@@ -19,6 +20,8 @@
|
||||
$effect(() => {
|
||||
if (!profile) {
|
||||
goto('/features/maintenance/');
|
||||
} else {
|
||||
$popupTitle = `Export Tagging Profile: ${profile.settings.name}`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { maintenanceProfiles } from "$stores/entities/maintenance-profiles";
|
||||
import { goto } from "$app/navigation";
|
||||
import EntitiesTransporter from "$lib/extension/EntitiesTransporter";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
const profilesTransporter = new EntitiesTransporter(MaintenanceProfile);
|
||||
|
||||
@@ -17,6 +18,11 @@
|
||||
let candidateProfile = $state<MaintenanceProfile | null>(null);
|
||||
let existingProfile = $state<MaintenanceProfile | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
$popupTitle = candidateProfile
|
||||
? 'Confirm Imported Tagging Profile'
|
||||
: 'Import Tagging Profile';
|
||||
})
|
||||
function tryImportingProfile() {
|
||||
candidateProfile = null;
|
||||
existingProfile = null;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script>
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Preferences';
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script>
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Debugging Tools';
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import { storagesCollection } from "$stores/debug";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Storage Inspector';
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import StorageViewer from "$components/debugging/StorageViewer.svelte";
|
||||
import { page } from "$app/state";
|
||||
import { goto } from "$app/navigation";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let pathArray = $derived.by<string[]>(() => {
|
||||
const pathString = page.params.path;
|
||||
@@ -30,6 +31,10 @@
|
||||
if (!storageName) {
|
||||
goto("/preferences/debug/storage");
|
||||
}
|
||||
|
||||
$popupTitle = storageName
|
||||
? 'Inspecting: ' + storageName
|
||||
: 'Storage Inspector';
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
import FormControl from "$components/ui/forms/FormControl.svelte";
|
||||
import CheckboxField from "$components/ui/forms/CheckboxField.svelte";
|
||||
import { fullScreenViewerEnabled } from "$stores/preferences/misc";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Misc Preferences';
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { stripBlacklistedTagsEnabled } from "$stores/preferences/maintenance";
|
||||
import { shouldSeparateTagGroups } from "$stores/preferences/tag";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Tagging Preferences';
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
$popupTitle = 'Import/Export';
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import type StorageEntity from "$lib/extension/base/StorageEntity";
|
||||
import FormControl from "$components/ui/forms/FormControl.svelte";
|
||||
import FormContainer from "$components/ui/forms/FormContainer.svelte";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
const bulkTransporter = new BulkEntitiesTransporter();
|
||||
|
||||
@@ -46,6 +47,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
$popupTitle = displayExportedString
|
||||
? 'Exported String'
|
||||
: 'Select Entities to Export';
|
||||
});
|
||||
|
||||
function refreshAreAllEntitiesChecked() {
|
||||
requestAnimationFrame(() => {
|
||||
exportAllProfiles = $maintenanceProfiles.every(profile => exportedEntities.profiles[profile.id]);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import GroupView from "$components/features/GroupView.svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import type { SameSiteStatus } from "$lib/extension/EntitiesTransporter";
|
||||
import { popupTitle } from "$stores/popup";
|
||||
|
||||
let importedString = $state('');
|
||||
let errorMessage = $state('');
|
||||
@@ -49,6 +50,16 @@
|
||||
Boolean(importedProfiles.length || importedGroups.length)
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
$popupTitle = hasImportedEntities
|
||||
? (
|
||||
previewedEntity
|
||||
? 'Preview of Imported Entity'
|
||||
: 'Select & Preview Imported Entities'
|
||||
)
|
||||
: 'Import';
|
||||
});
|
||||
|
||||
const transporter = new BulkEntitiesTransporter();
|
||||
|
||||
let lastImportStatus = $state<SameSiteStatus>(null);
|
||||
|
||||
15
src/stores/popup.ts
Normal file
15
src/stores/popup.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { derived, writable } from "svelte/store";
|
||||
import { PLUGIN_NAME } from "$lib/constants";
|
||||
|
||||
/**
|
||||
* Store containing the name of the subpage. This name will be added to the title alongside the name of the plugin.
|
||||
*/
|
||||
export const popupTitle = writable<string | null>(null);
|
||||
|
||||
/**
|
||||
* Name of the current route with the name of the plugin appended to it.
|
||||
*/
|
||||
export const headTitle = derived(
|
||||
popupTitle,
|
||||
$popupTitle => ($popupTitle ? `${$popupTitle} | ` : '') + PLUGIN_NAME
|
||||
);
|
||||
@@ -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 {
|
||||
|
||||
@@ -15,6 +15,7 @@ const config = {
|
||||
},
|
||||
alias: {
|
||||
"$config": "./src/config",
|
||||
"$content": "./src/content",
|
||||
"$components": "./src/components",
|
||||
"$styles": "./src/styles",
|
||||
"$stores": "./src/stores",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseComponent } from "$lib/components/base/BaseComponent";
|
||||
import { getComponent } from "$lib/components/base/component-utils";
|
||||
import { BaseComponent } from "$content/components/base/BaseComponent";
|
||||
import { getComponent } from "$content/components/base/component-utils";
|
||||
import { randomString } from "$tests/utils";
|
||||
|
||||
describe('BaseComponent', () => {
|
||||
Reference in New Issue
Block a user