1
0
mirror of https://github.com/koloml/furbooru-tagging-assistant.git synced 2026-02-06 23:32:58 +00:00

15 Commits

Author SHA1 Message Date
ab625d0181 Merge pull request #141 from koloml/release/0.5.3
Release: 0.5.3
2026-01-09 08:51:45 +04:00
c59d8f55f0 Bumped version to 0.5.3 2026-01-09 08:50:05 +04:00
8dfc5f49f9 Merge pull request #143 from koloml/feature/code-reorganization
Slight change in code organization for content script components
2026-01-09 08:48:59 +04:00
2ecd37512f Moving all content_scripts-related components under $content directory
Having $lib/component with just $component was a bit confusing,
especially since $lib is also used in Svelte components all over the
place. This move will hopefully make it less confusing for me.
2026-01-09 07:06:58 +04:00
c8ff80d445 Move list of tag categories into the tags config script 2026-01-09 06:55:51 +04:00
38cbd725d9 Merge pull request #142 from koloml/bugfix/profile-view-tags-list
Profile View: Fixed tags list not being properly reactive in the extension popup
2026-01-09 06:44:23 +04:00
26f09c7c46 Fixed tags list for tagging profiles not updating reactively in popup 2026-01-09 06:41:28 +04:00
64be6a6e15 Bumping dependencies (#140)
* Updated `vite` from 7.1.6 to 7.3.1

* Updated `@sveltejs/vite-plugin-svelte` from 6.2.0 to 6.2.3

* Updated `@sveltejs/kit` from 2.42.2 to 2.49.4

* Updated `@sveltejs/adapter-static` from 3.0.9 to 3.0.10

* Updated `svelte` from 5.39.4 to 5.46.1

* Updated `svelte-check` from 4.3.1 to 4.3.5

* Updated `typescript` from 5.9.2 to 5.9.3

* Updated `sass` from 1.93.0 to 1.97.2

* Updated `jsdom` from 27.0.0 to 27.4.0

* Updated `cross-env` from 10.0.0 to 10.1.0

* Updated `@types/node` from 22.18.6 to 25.0.3

* Updated `@types/chrome` from 0.0.326 to 0.1.32

* Updated `vitest` and `@vitest/coverage-v8` from 3.2.4 to 4.0.16

* Updated `@fortawesome/fontawesome-free` from 6.7.2 to 7.1.0
2026-01-09 06:35:52 +04:00
cb22b2deab Merge pull request #139 from koloml/feature/display-dedicated-popup-titles
Popup: Display different tab titles for different routes
2026-01-09 06:35:25 +04:00
5c5e0812dc Provide names for all popup routes using new store 2026-01-09 05:56:33 +04:00
70129d7a0e Added the store for dynamically changing the popup titles 2026-01-09 05:27:48 +04:00
5fd6dee999 Added constant with the full name of the plugin 2026-01-09 05:27:11 +04:00
ec41ba5030 Furbooru: Added screenshots for tag groups feature 2025-11-04 19:26:47 -05:00
55624285e1 Merge pull request #138 from koloml/feature/release-build-pipeline
Added GitHub action for building the project in CI
2025-10-02 13:41:29 +04:00
b97255ccd6 Release CI action
Builds the extension for both sites and uploads them as artifacts. This
will make it possible to just release the project and then grab the
ready-to-be-deployed archive for publishing.

This change was made using Cursor. Just a small test run to check how
useful it is for my workflows.
2025-10-02 13:40:02 +04:00
64 changed files with 792 additions and 1063 deletions

BIN
.github/assets/colors-in-editor.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

63
.github/workflows/build-extensions.yml vendored Normal file
View 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

View File

@@ -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'),

View File

@@ -1,7 +1,7 @@
{
"name": "Furbooru Tagging Assistant",
"description": "Small experimental extension for slightly quicker tagging experience. Furbooru Edition.",
"version": "0.5.2",
"version": "0.5.3",
"browser_specific_settings": {
"gecko": {
"id": "furbooru-tagging-assistant@thecore.city"

1457
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "furbooru-tagging-assistant",
"version": "0.5.2",
"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/vite-plugin-svelte": "^6.2.0",
"@types/chrome": "^0.0.326",
"@types/node": "^22.18.6",
"@vitest/coverage-v8": "^3.2.4",
"@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.0.0",
"jsdom": "^27.0.0",
"svelte-check": "^4.3.1",
"typescript": "^5.9.2",
"vite": "^7.1.6",
"vitest": "^3.2.4"
"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": {
"@sveltejs/adapter-static": "^3.0.9",
"@sveltejs/kit": "^2.42.2",
"@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",
"sass": "^1.93.0",
"svelte": "^5.39.4"
"sass": "^1.97.2",
"svelte": "^5.46.1"
}
}

View File

@@ -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">

View File

@@ -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">

View File

@@ -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;

View File

@@ -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",

View File

@@ -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');

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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();

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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');

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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');

View File

@@ -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();

View File

@@ -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);

View File

@@ -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
View File

@@ -0,0 +1,4 @@
/**
* Automatically generated name of the plugin.
*/
export const PLUGIN_NAME = __CURRENT_SITE_NAME__ + ' Tagging Assistant';

View File

@@ -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>();

View File

@@ -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?.()}

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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}`;
}
})

View File

@@ -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));

View File

@@ -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}`;
}
});

View File

@@ -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;

View File

@@ -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))

View File

@@ -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}`;
}
});

View File

@@ -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}`
}
});

View File

@@ -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));
});

View File

@@ -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}`;
}
});

View File

@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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]);

View File

@@ -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
View 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
);

View File

@@ -15,6 +15,7 @@ const config = {
},
alias: {
"$config": "./src/config",
"$content": "./src/content",
"$components": "./src/components",
"$styles": "./src/styles",
"$stores": "./src/stores",

View File

@@ -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', () => {