@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Furbooru Tagging Assistant",
|
||||
"description": "Experimental extension with a set of tools to make the tagging faster and easier. Made specifically for Furbooru.",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.3",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "furbooru-tagging-assistant@thecore.city"
|
||||
|
||||
18
package-lock.json
generated
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "furbooru-tagging-assistant",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "furbooru-tagging-assistant",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.3",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.1",
|
||||
"lz-string": "^1.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -405,6 +406,14 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-free": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.1.tgz",
|
||||
"integrity": "sha512-ALIk/MOh5gYe1TG/ieS5mVUsk7VUIJTJKPMK9rFFqOgfp0Q3d5QiBXbcOMwUvs37fyZVCz46YjOE6IFeOAXCHA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
@@ -2395,6 +2404,11 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@fortawesome/fontawesome-free": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.1.tgz",
|
||||
"integrity": "sha512-ALIk/MOh5gYe1TG/ieS5mVUsk7VUIJTJKPMK9rFFqOgfp0Q3d5QiBXbcOMwUvs37fyZVCz46YjOE6IFeOAXCHA=="
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "furbooru-tagging-assistant",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run build:popup && npm run build:extension",
|
||||
"build:popup": "vite build",
|
||||
"build:extension": "node build-extension.js",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
@@ -24,6 +24,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.1",
|
||||
"lz-string": "^1.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
41
src/app.d.ts
vendored
@@ -1,24 +1,31 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
type LinkTarget = "_blank" | "_self" | "_parent" | "_top";
|
||||
type IconName = (
|
||||
"tag"
|
||||
| "paint-brush"
|
||||
| "arrow-left"
|
||||
| "info-circle"
|
||||
| "wrench"
|
||||
| "globe"
|
||||
| "plus"
|
||||
| "file-export"
|
||||
);
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
type LinkTarget = "_blank" | "_self" | "_parent" | "_top";
|
||||
type IconName = (
|
||||
"tag"
|
||||
| "paint-brush"
|
||||
| "arrow-left"
|
||||
| "info-circle"
|
||||
| "wrench"
|
||||
| "globe"
|
||||
| "plus"
|
||||
| "file-export"
|
||||
| "trash"
|
||||
);
|
||||
|
||||
interface EntityNamesMap {
|
||||
profiles: MaintenanceProfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
/** @type {import('$lib/extension/entities/MaintenanceProfile.js').default} */
|
||||
/** @type {import('$entities/MaintenanceProfile.ts').default} */
|
||||
export let profile;
|
||||
|
||||
const sortedTagsList = profile.settings.tags.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
@@ -2,9 +2,11 @@ import {BaseComponent} from "$lib/components/base/BaseComponent.js";
|
||||
|
||||
export class FullscreenViewer extends BaseComponent {
|
||||
/** @type {HTMLVideoElement} */
|
||||
#videoElement;
|
||||
#videoElement = document.createElement('video');
|
||||
/** @type {HTMLImageElement} */
|
||||
#imageElement;
|
||||
#imageElement = document.createElement('img');
|
||||
|
||||
#spinnerElement = document.createElement('i');
|
||||
|
||||
/** @type {number|null} */
|
||||
#touchId = null;
|
||||
@@ -20,9 +22,9 @@ export class FullscreenViewer extends BaseComponent {
|
||||
*/
|
||||
build() {
|
||||
this.container.classList.add('fullscreen-viewer');
|
||||
this.container.append(this.#spinnerElement);
|
||||
|
||||
this.#videoElement = document.createElement('video');
|
||||
this.#imageElement = document.createElement('img');
|
||||
this.#spinnerElement.classList.add('spinner', 'fa', 'fa-circle-notch', 'fa-spin');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,6 +37,13 @@ export class FullscreenViewer extends BaseComponent {
|
||||
this.on('touchstart', this.#onTouchStart.bind(this));
|
||||
this.on('touchmove', this.#onTouchMove.bind(this));
|
||||
this.on('touchend', this.#onTouchEnd.bind(this));
|
||||
|
||||
this.#videoElement.addEventListener('loadeddata', this.#onLoaded.bind(this));
|
||||
this.#imageElement.addEventListener('load', this.#onLoaded.bind(this));
|
||||
}
|
||||
|
||||
#onLoaded() {
|
||||
this.container.classList.remove('loading');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,6 +178,8 @@ export class FullscreenViewer extends BaseComponent {
|
||||
* @param {string} url
|
||||
*/
|
||||
show(url) {
|
||||
this.container.classList.add('loading');
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
this.container.classList.add(FullscreenViewer.#shownState);
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import MaintenanceSettings from "$lib/extension/settings/MaintenanceSettings.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
import {BaseComponent} from "$lib/components/base/BaseComponent.js";
|
||||
import {getComponent} from "$lib/components/base/ComponentUtils.js";
|
||||
import ScrapedAPI from "$lib/booru/scraped/ScrapedAPI.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {BaseComponent} from "$lib/components/base/BaseComponent.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
import MaintenanceSettings from "$lib/extension/settings/MaintenanceSettings.js";
|
||||
import {getComponent} from "$lib/components/base/ComponentUtils.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import StorageHelper from "$lib/browser/StorageHelper.js";
|
||||
import type StorageEntity from "$lib/extension/base/StorageEntity.ts";
|
||||
|
||||
export default class EntitiesController {
|
||||
static #storageHelper = new StorageHelper(chrome.storage.local);
|
||||
@@ -6,15 +7,13 @@ export default class EntitiesController {
|
||||
/**
|
||||
* Read all entities of the given type from the storage. Build the entities from the raw data and return them.
|
||||
*
|
||||
* @template EntityClass
|
||||
* @param entityName Name of the entity to read.
|
||||
* @param entityClass Class of the entity to read. Must have a constructor that accepts the ID and the settings
|
||||
* object.
|
||||
*
|
||||
* @param {string} entityName Name of the entity to read.
|
||||
* @param {EntityClass} entityClass Class of the entity to read. Must have a constructor that accepts the ID and the
|
||||
* settings object.
|
||||
*
|
||||
* @return {Promise<InstanceType<EntityClass>[]>} List of entities of the given type.
|
||||
* @return List of entities of the given type.
|
||||
*/
|
||||
static async readAllEntities(entityName, entityClass) {
|
||||
static async readAllEntities<Type extends StorageEntity<any>>(entityName: string, entityClass: new (...any: any[]) => Type): Promise<Type[]> {
|
||||
const rawEntities = await this.#storageHelper.read(entityName, {});
|
||||
|
||||
if (!rawEntities || Object.keys(rawEntities).length === 0) {
|
||||
@@ -29,13 +28,11 @@ export default class EntitiesController {
|
||||
/**
|
||||
* Update the single entity in the storage. If the entity with the given ID already exists, it will be overwritten.
|
||||
*
|
||||
* @param {string} entityName Name of the entity to update.
|
||||
* @param {StorageEntity} entity Entity to update.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
* @param entityName Name of the entity to update.
|
||||
* @param entity Entity to update.
|
||||
*/
|
||||
static async updateEntity(entityName, entity) {
|
||||
await this.#storageHelper.write(
|
||||
static async updateEntity(entityName: string, entity: StorageEntity<Object>): Promise<void> {
|
||||
this.#storageHelper.write(
|
||||
entityName,
|
||||
Object.assign(
|
||||
await this.#storageHelper.read(
|
||||
@@ -51,15 +48,13 @@ export default class EntitiesController {
|
||||
/**
|
||||
* Delete the entity with the given ID.
|
||||
*
|
||||
* @param {string} entityName Name of the entity to delete.
|
||||
* @param {string} entityId ID of the entity to delete.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
* @param entityName Name of the entity to delete.
|
||||
* @param entityId ID of the entity to delete.
|
||||
*/
|
||||
static async deleteEntity(entityName, entityId) {
|
||||
static async deleteEntity(entityName: string, entityId: string): Promise<void> {
|
||||
const entities = await this.#storageHelper.read(entityName, {});
|
||||
delete entities[entityId];
|
||||
await this.#storageHelper.write(entityName, entities);
|
||||
this.#storageHelper.write(entityName, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,17 +62,16 @@ export default class EntitiesController {
|
||||
*
|
||||
* @template EntityClass
|
||||
*
|
||||
* @param {string} entityName Name of the entity to subscribe to.
|
||||
* @param {EntityClass} entityClass Class of the entity to subscribe to.
|
||||
* @param {function(InstanceType<EntityClass>[]): any} callback Callback to call when the storage changes.
|
||||
* @return {function(): void} Unsubscribe function.
|
||||
* @param entityName Name of the entity to subscribe to.
|
||||
* @param entityClass Class of the entity to subscribe to.
|
||||
* @param callback Callback to call when the storage changes.
|
||||
* @return Unsubscribe function.
|
||||
*/
|
||||
static subscribeToEntity(entityName, entityClass, callback) {
|
||||
static subscribeToEntity<Type extends StorageEntity<any>>(entityName: string, entityClass: new (...any: any[]) => Type, callback: (entities: Type[]) => void): () => void {
|
||||
/**
|
||||
* Watch the changes made to the storage and call the callback when the entity changes.
|
||||
* @param {Object<string, StorageChange>} changes Changes made to the storage.
|
||||
*/
|
||||
const storageChangesSubscriber = changes => {
|
||||
const storageChangesSubscriber = (changes: Record<string, chrome.storage.StorageChange>) => {
|
||||
if (!changes[entityName]) {
|
||||
return;
|
||||
}
|
||||
@@ -1,16 +1,28 @@
|
||||
import {validateImportedEntity} from "$lib/extension/transporting/validators.js";
|
||||
import {exportEntityToObject} from "$lib/extension/transporting/exporters.js";
|
||||
import StorageEntity from "./base/StorageEntity.js";
|
||||
import {exportEntityToObject} from "$lib/extension/transporting/exporters.ts";
|
||||
import StorageEntity from "$lib/extension/base/StorageEntity.ts";
|
||||
import {compressToEncodedURIComponent, decompressFromEncodedURIComponent} from "lz-string";
|
||||
|
||||
type EntityConstructor<T extends StorageEntity> =
|
||||
(new (id: string, settings: Record<string, any>) => T)
|
||||
& typeof StorageEntity;
|
||||
export default class EntitiesTransporter<EntityType> {
|
||||
readonly #targetEntityConstructor: new (...any: any[]) => EntityType;
|
||||
|
||||
export default class EntitiesTransporter<EntityType extends StorageEntity> {
|
||||
readonly #targetEntityConstructor: EntityConstructor<EntityType>;
|
||||
/**
|
||||
* Name of the entity, exported directly from the constructor.
|
||||
* @private
|
||||
*/
|
||||
get #entityName() {
|
||||
// How the hell should I even do this?
|
||||
return ((this.#targetEntityConstructor as any) as typeof StorageEntity)._entityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityConstructor Class which should be used for import or export.
|
||||
*/
|
||||
constructor(entityConstructor: new (...any: any[]) => EntityType) {
|
||||
if (!(entityConstructor.prototype instanceof StorageEntity)) {
|
||||
throw new TypeError('Invalid class provided as the target for importing!');
|
||||
}
|
||||
|
||||
constructor(entityConstructor: EntityConstructor<EntityType>) {
|
||||
this.#targetEntityConstructor = entityConstructor;
|
||||
}
|
||||
|
||||
@@ -23,7 +35,7 @@ export default class EntitiesTransporter<EntityType extends StorageEntity> {
|
||||
|
||||
validateImportedEntity(
|
||||
importedObject,
|
||||
this.#targetEntityConstructor._entityName
|
||||
this.#entityName
|
||||
);
|
||||
|
||||
return new this.#targetEntityConstructor(
|
||||
@@ -43,9 +55,13 @@ export default class EntitiesTransporter<EntityType extends StorageEntity> {
|
||||
throw new TypeError('Transporter should be connected to the same entity to export!');
|
||||
}
|
||||
|
||||
if (!(entityObject instanceof StorageEntity)) {
|
||||
throw new TypeError('Only storage entities could be exported!');
|
||||
}
|
||||
|
||||
const exportableObject = exportEntityToObject(
|
||||
entityObject,
|
||||
this.#targetEntityConstructor._entityName
|
||||
this.#entityName
|
||||
);
|
||||
|
||||
return JSON.stringify(exportableObject, null, 2);
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import EntitiesController from "$lib/extension/EntitiesController.js";
|
||||
|
||||
class StorageEntity {
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
#id;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
#settings;
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {Object} settings
|
||||
*/
|
||||
constructor(id, settings = {}) {
|
||||
this.#id = id;
|
||||
this.#settings = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
get id() {
|
||||
return this.#id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object}
|
||||
*/
|
||||
get settings() {
|
||||
return this.#settings;
|
||||
}
|
||||
|
||||
static _entityName = "entity";
|
||||
|
||||
async save() {
|
||||
await EntitiesController.updateEntity(this.constructor._entityName, this);
|
||||
}
|
||||
|
||||
async delete() {
|
||||
await EntitiesController.deleteEntity(this.constructor._entityName, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to read all entities of this type from the storage. Must be implemented in the child class.
|
||||
* @return {Promise<array>}
|
||||
*/
|
||||
static async readAll() {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
export default StorageEntity;
|
||||
59
src/lib/extension/base/StorageEntity.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import EntitiesController from "$lib/extension/EntitiesController.js";
|
||||
|
||||
export default abstract class StorageEntity<SettingsType extends Object = {}> {
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
readonly #id: string;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
readonly #settings: SettingsType;
|
||||
|
||||
protected constructor(id: string, settings: SettingsType) {
|
||||
this.#id = id;
|
||||
this.#settings = settings;
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
return this.#id;
|
||||
}
|
||||
|
||||
get settings(): SettingsType {
|
||||
return this.#settings;
|
||||
}
|
||||
|
||||
public static readonly _entityName: string = "entity";
|
||||
|
||||
async save() {
|
||||
await EntitiesController.updateEntity(
|
||||
(this.constructor as typeof StorageEntity)._entityName,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
async delete() {
|
||||
await EntitiesController.deleteEntity(
|
||||
(this.constructor as typeof StorageEntity)._entityName,
|
||||
this.id
|
||||
);
|
||||
}
|
||||
|
||||
public static async readAll<Type extends StorageEntity<any>>(this: new (...args: any[]) => Type): Promise<Type[]> {
|
||||
return await EntitiesController.readAllEntities(
|
||||
// Voodoo magic, once again.
|
||||
((this as any) as typeof StorageEntity)._entityName,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
public static subscribe<Type extends StorageEntity<any>>(this: new (...args: any[]) => Type, callback: (entities: Type[]) => void): () => void {
|
||||
return EntitiesController.subscribeToEntity(
|
||||
// And once more.
|
||||
((this as any) as typeof StorageEntity)._entityName,
|
||||
this,
|
||||
callback
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import StorageEntity from "$lib/extension/base/StorageEntity.js";
|
||||
import EntitiesController from "$lib/extension/EntitiesController.js";
|
||||
|
||||
/**
|
||||
* @typedef {Object} MaintenanceProfileSettings
|
||||
* @property {string} name
|
||||
* @property {string[]} tags
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class representing the maintenance profile entity.
|
||||
*/
|
||||
class MaintenanceProfile extends StorageEntity {
|
||||
/**
|
||||
* @param {string} id ID of the entity.
|
||||
* @param {Partial<MaintenanceProfileSettings>} settings Maintenance profile settings object.
|
||||
*/
|
||||
constructor(id, settings) {
|
||||
super(id, {
|
||||
name: settings.name || '',
|
||||
tags: settings.tags || []
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {MaintenanceProfileSettings}
|
||||
*/
|
||||
get settings() {
|
||||
return super.settings;
|
||||
}
|
||||
|
||||
static _entityName = "profiles";
|
||||
|
||||
/**
|
||||
* Read all maintenance profiles from the storage.
|
||||
*
|
||||
* @return {Promise<InstanceType<MaintenanceProfile>[]>}
|
||||
*/
|
||||
static async readAll() {
|
||||
return await EntitiesController.readAllEntities(
|
||||
this._entityName,
|
||||
MaintenanceProfile
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the changes and receive the new list of profiles when they change.
|
||||
*
|
||||
* @param {function(MaintenanceProfile[]): void} callback Callback to call when the profiles change. The new list of
|
||||
* profiles is passed as an argument.
|
||||
*
|
||||
* @return {function(): void} Unsubscribe function.
|
||||
*/
|
||||
static subscribe(callback) {
|
||||
return EntitiesController.subscribeToEntity(
|
||||
this._entityName,
|
||||
MaintenanceProfile,
|
||||
callback
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MaintenanceProfile;
|
||||
25
src/lib/extension/entities/MaintenanceProfile.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import StorageEntity from "$lib/extension/base/StorageEntity.ts";
|
||||
import EntitiesController from "$lib/extension/EntitiesController.ts";
|
||||
|
||||
export interface MaintenanceProfileSettings {
|
||||
name: string;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing the maintenance profile entity.
|
||||
*/
|
||||
export default class MaintenanceProfile extends StorageEntity<MaintenanceProfileSettings> {
|
||||
/**
|
||||
* @param id ID of the entity.
|
||||
* @param settings Maintenance profile settings object.
|
||||
*/
|
||||
constructor(id: string, settings: Partial<MaintenanceProfileSettings>) {
|
||||
super(id, {
|
||||
name: settings.name || '',
|
||||
tags: settings.tags || []
|
||||
});
|
||||
}
|
||||
|
||||
public static readonly _entityName = "profiles";
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import ConfigurationController from "$lib/extension/ConfigurationController.js";
|
||||
import MaintenanceProfile from "$lib/extension/entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
import CacheableSettings from "$lib/extension/base/CacheableSettings.js";
|
||||
|
||||
export default class MaintenanceSettings extends CacheableSettings {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* @type {Map<string, ((entity: import('../base/StorageEntity.js').default) => Record<string, any>)>}
|
||||
*/
|
||||
const entitiesExporters = new Map([
|
||||
['profiles', /** @param {import('../entities/MaintenanceProfile.js').default} entity */entity => {
|
||||
return {
|
||||
v: 1,
|
||||
id: entity.id,
|
||||
name: entity.settings.name,
|
||||
tags: entity.settings.tags,
|
||||
}
|
||||
}]
|
||||
])
|
||||
|
||||
/**
|
||||
* @param entityInstance
|
||||
* @param {string} entityName
|
||||
* @returns {Record<string, *>}
|
||||
*/
|
||||
export function exportEntityToObject(entityInstance, entityName) {
|
||||
if (!entitiesExporters.has(entityName)) {
|
||||
throw new Error(`Missing exporter for entity: ${entityName}`);
|
||||
}
|
||||
|
||||
return entitiesExporters.get(entityName).call(null, entityInstance);
|
||||
}
|
||||
24
src/lib/extension/transporting/exporters.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import StorageEntity from "$lib/extension/base/StorageEntity.ts";
|
||||
|
||||
type ExportersMap = {
|
||||
[EntityName in keyof App.EntityNamesMap]: (entity: App.EntityNamesMap[EntityName]) => Record<string, any>
|
||||
};
|
||||
|
||||
const entitiesExporters: ExportersMap = {
|
||||
profiles: entity => {
|
||||
return {
|
||||
v: 1,
|
||||
id: entity.id,
|
||||
name: entity.settings.name,
|
||||
tags: entity.settings.tags,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export function exportEntityToObject(entityInstance: StorageEntity<any>, entityName: string): Record<string, any> {
|
||||
if (!(entityName in entitiesExporters) || !entitiesExporters.hasOwnProperty(entityName)) {
|
||||
throw new Error(`Missing exporter for entity: ${entityName}`);
|
||||
}
|
||||
|
||||
return entitiesExporters[entityName as keyof App.EntityNamesMap].call(null, entityInstance);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Map of validators for each entity. Function should throw the error if validation failed.
|
||||
* @type {Map<string, ((importedObject: Object) => void)>}
|
||||
* @type {Map<keyof App.EntityNamesMap|string, ((importedObject: Object) => void)>}
|
||||
*/
|
||||
const entitiesValidators = new Map([
|
||||
['profiles', importedObject => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { activeProfileStore, maintenanceProfilesStore } from "$stores/maintenance-profiles-store.js";
|
||||
import MenuCheckboxItem from "$components/ui/menu/MenuCheckboxItem.svelte";
|
||||
|
||||
/** @type {import('$lib/extension/entities/MaintenanceProfile.js').default|undefined} */
|
||||
/** @type {import('$entities/MaintenanceProfile.ts').default|undefined} */
|
||||
let activeProfile;
|
||||
|
||||
$: activeProfile = $maintenanceProfilesStore.find(profile => profile.id === $activeProfileStore);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import MenuRadioItem from "$components/ui/menu/MenuRadioItem.svelte";
|
||||
import {activeProfileStore, maintenanceProfilesStore} from "$stores/maintenance-profiles-store.js";
|
||||
|
||||
/** @type {import('$lib/extension/entities/MaintenanceProfile.js').default[]} */
|
||||
/** @type {import('$entities/MaintenanceProfile.ts').default[]} */
|
||||
let profiles = [];
|
||||
|
||||
$: profiles = $maintenanceProfilesStore.sort((a, b) => a.settings.name.localeCompare(b.settings.name));
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import ProfileView from "$components/maintenance/ProfileView.svelte";
|
||||
|
||||
const profileId = $page.params.id;
|
||||
/** @type {import('$lib/extension/entities/MaintenanceProfile.js').default|null} */
|
||||
/** @type {import('$entities/MaintenanceProfile.ts').default|null} */
|
||||
let profile = null;
|
||||
let isActiveProfile = false;
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
<MenuItem icon="file-export" href="/features/maintenance/{profileId}/export">
|
||||
Export Profile
|
||||
</MenuItem>
|
||||
<MenuItem icon="trash" href="/features/maintenance/{profileId}/delete">
|
||||
Delete Profile
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
41
src/routes/features/maintenance/[id]/delete/+page.svelte
Normal file
@@ -0,0 +1,41 @@
|
||||
<script>
|
||||
import { goto } from "$app/navigation";
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import { page } from "$app/stores";
|
||||
import { maintenanceProfilesStore } from "$stores/maintenance-profiles-store.js";
|
||||
|
||||
const profileId = $page.params.id;
|
||||
const targetProfile = $maintenanceProfilesStore.find(profile => profile.id===profileId);
|
||||
|
||||
if (!targetProfile) {
|
||||
void goto('/features/maintenance');
|
||||
}
|
||||
|
||||
async function deleteProfile() {
|
||||
if (!targetProfile) {
|
||||
console.warn('Attempting to delete the profile, but the profile is not loaded yet.');
|
||||
return;
|
||||
}
|
||||
|
||||
await targetProfile.delete();
|
||||
await goto('/features/maintenance');
|
||||
}
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
<MenuItem icon="arrow-left" href="/features/maintenance/{profileId}">Back</MenuItem>
|
||||
<hr>
|
||||
</Menu>
|
||||
{#if targetProfile}
|
||||
<p>
|
||||
Do you want to remove profile "{targetProfile.settings.name}"? This action is irreversible.
|
||||
</p>
|
||||
<Menu>
|
||||
<hr>
|
||||
<MenuItem on:click={deleteProfile}>Yes</MenuItem>
|
||||
<MenuItem href="/features/maintenance/{profileId}">No</MenuItem>
|
||||
</Menu>
|
||||
{:else}
|
||||
<p>Loading...</p>
|
||||
{/if}
|
||||
@@ -8,7 +8,7 @@
|
||||
import {page} from "$app/stores";
|
||||
import {goto} from "$app/navigation";
|
||||
import {maintenanceProfilesStore} from "$stores/maintenance-profiles-store.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
|
||||
/** @type {string} */
|
||||
let profileId = $page.params.id;
|
||||
@@ -46,16 +46,6 @@
|
||||
await targetProfile.save();
|
||||
await goto('/features/maintenance/' + targetProfile.id);
|
||||
}
|
||||
|
||||
async function deleteProfile() {
|
||||
if (!targetProfile) {
|
||||
console.warn('Attempting to delete the profile, but the profile is not loaded yet.');
|
||||
return;
|
||||
}
|
||||
|
||||
await targetProfile.delete();
|
||||
await goto('/features/maintenance');
|
||||
}
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
@@ -75,7 +65,4 @@
|
||||
<Menu>
|
||||
<hr>
|
||||
<MenuItem href="#" on:click={saveProfile}>Save Profile</MenuItem>
|
||||
{#if profileId !== 'new'}
|
||||
<MenuItem href="#" on:click={deleteProfile}>Delete Profile</MenuItem>
|
||||
{/if}
|
||||
</Menu>
|
||||
|
||||
@@ -7,13 +7,9 @@
|
||||
import FormContainer from "$components/ui/forms/FormContainer.svelte";
|
||||
import FormControl from "$components/ui/forms/FormControl.svelte";
|
||||
import EntitiesTransporter from "$lib/extension/EntitiesTransporter.ts";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
|
||||
const profileId = $page.params.id;
|
||||
|
||||
/**
|
||||
* @type {import('$lib/extension/entities/MaintenanceProfile.js').default|undefined}
|
||||
*/
|
||||
const profile = $maintenanceProfilesStore.find(profile => profile.id === profileId);
|
||||
|
||||
const profilesTransporter = new EntitiesTransporter(MaintenanceProfile);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Menu from "$components/ui/menu/Menu.svelte";
|
||||
import MenuItem from "$components/ui/menu/MenuItem.svelte";
|
||||
import FormContainer from "$components/ui/forms/FormContainer.svelte";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
import FormControl from "$components/ui/forms/FormControl.svelte";
|
||||
import ProfileView from "$components/maintenance/ProfileView.svelte";
|
||||
import {maintenanceProfilesStore} from "$stores/maintenance-profiles-store.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {writable} from "svelte/store";
|
||||
import MaintenanceProfile from "$lib/extension/entities/MaintenanceProfile.js";
|
||||
import MaintenanceProfile from "$entities/MaintenanceProfile.ts";
|
||||
import MaintenanceSettings from "$lib/extension/settings/MaintenanceSettings.js";
|
||||
|
||||
/**
|
||||
|
||||
@@ -177,6 +177,21 @@
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
position: fixed;
|
||||
opacity: 0;
|
||||
left: 50vw;
|
||||
top: 50vh;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 64px;
|
||||
text-shadow: 0 0 15px black;
|
||||
}
|
||||
|
||||
img, video, .spinner {
|
||||
transition: opacity .25s ease;
|
||||
}
|
||||
|
||||
&.shown {
|
||||
@@ -188,4 +203,14 @@
|
||||
opacity: var(--opacity, 1);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
img, video {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@mixin insert-icon($icon_src) {
|
||||
mask-image: url($icon_src);
|
||||
-webkit-mask-image: url($icon_src);
|
||||
@mixin insert-icon($url) {
|
||||
mask-image: $url;
|
||||
-webkit-mask-image: $url;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@@ -11,33 +11,37 @@
|
||||
}
|
||||
|
||||
.icon.icon-tag {
|
||||
@include insert-icon('/img/tag.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/tag.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-paint-brush {
|
||||
@include insert-icon('/img/paint-brush.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/paintbrush.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-arrow-left {
|
||||
@include insert-icon('/img/arrow-left.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/arrow-left.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-info-circle {
|
||||
@include insert-icon('/img/info-circle.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/circle-info.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-wrench {
|
||||
@include insert-icon('/img/wrench.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/wrench.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-globe {
|
||||
@include insert-icon('/img/globe.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/globe.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-plus {
|
||||
@include insert-icon('/img/plus.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/plus.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-file-export {
|
||||
@include insert-icon('/img/file-export.svg');
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/file-export.svg'));
|
||||
}
|
||||
|
||||
.icon.icon-trash {
|
||||
@include insert-icon(url('@fortawesome/fontawesome-free/svgs/solid/trash.svg'));
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<svg width="32" height="32" version="1.1" viewBox="0 -256 1472 1558" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1,0,0,-1,-64,1099)">
|
||||
<path d="m1536 640v-128q0-53-32.5-90.5t-84.5-37.5h-704l293-294q38-36 38-90t-38-90l-75-76q-37-37-90-37-52 0-91 37l-651 652q-37 37-37 90 0 52 37 91l651 650q38 38 91 38 52 0 90-38l75-74q38-38 38-91t-38-91l-293-293h704q52 0 84.5-37.5t32.5-90.5z"
|
||||
fill="currentColor"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 453 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path d="M384 121.9c0-6.3-2.5-12.4-7-16.9L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1zM192 336v-32c0-8.84 7.16-16 16-16h176V160H248c-13.2 0-24-10.8-24-24V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V352H208c-8.84 0-16-7.16-16-16zm379.05-28.02l-95.7-96.43c-10.06-10.14-27.36-3.01-27.36 11.27V288H384v64h63.99v65.18c0 14.28 17.29 21.41 27.36 11.27l95.7-96.42c6.6-6.66 6.6-17.4 0-24.05z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 492 B |
@@ -1,6 +0,0 @@
|
||||
<svg width="32" height="32" version="1.1" viewBox="0 -256 1536 1536" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1,0,0,-1,0,1152)">
|
||||
<path d="m1193 993q11 7 25 22v-1q0-2-9.5-10t-11.5-12q-1 1-4 1zm-6-1q-1 1-2.5 3t-1.5 3q3-2 10-5-6-4-6-1zm-459 183q-16 2-26 5 1 0 6.5-1t10.5-2 9-2zm45 37q7 4 13.5 2.5t7.5-7.5q-5 3-21 5zm-8-6-3 2q-2 3-5.5 5t-4.5 2q2-1 21-3-6-4-8-6zm-102 84v2q1-2 3-5.5t3-5.5zm-105-40q0-2-1-2l-1 2zm375-1044v-1zm-165 1202q209 0 385.5-103t279.5-279.5 103-385.5-103-385.5-279.5-279.5-385.5-103-385.5 103-279.5 279.5-103 385.5 103 385.5 279.5 279.5 385.5 103zm472-1246 5 5q-7 10-29 12 1 12-14 26.5t-27 15.5q0 4-10.5 11t-17.5 8q-9 2-27-9-7-3-4-5-3 3-12 11t-16 11q-2 1-7.5 1t-8.5 2q-1 1-6 4.5t-7 4.5-6.5 3-7.5 1.5-7.5-2.5-8.5-6-4.5-15.5-2.5-14.5q-8 6-0.5 20t1.5 20q-7 7-21 0.5t-21-15.5q-1-1-9.5-5.5t-11.5-7.5q-4-6-9-17.5t-6-13.5q0 2-2.5 6.5t-2.5 6.5q-12-2-16 3 5-16 8-17l-4 2q-1-6 3-15t4-11q1-5-1.5-13t-2.5-11q0-2 5-11 4-19-2-32 0-1-3.5-7t-6.5-11l-2-5-2 1q-1 1-2 0-1-6-9-13t-10-11q-15-23-9-38 3-8 10-10 3-1 3 2 1-9-11-27 1-1 4-3-17 0-10-14 202 36 352 181h-3zm-560 185q16 3 30.5-16t22.5-23q41-20 59-11 0-9 14-28 3-4 6.5-11.5t5.5-10.5q5-7 19-16t19-16q6 3 9 9 13-35 24-34 5 0 8 8 0-1-0.5-3t-1.5-3q7 15 5 26l6 4q5 4 5 5-6 6-9-3-30-14-48 22-2 3-4.5 8t-5 12-1.5 11.5 6 4.5q11 0 12.5 1.5t-2.5 6-4 7.5q-1 4-1.5 12.5t-1.5 12.5l-5 6q-5 6-11.5 13.5t-7.5 9.5q-4-10-16.5-8.5t-18.5 9.5q1-2-0.5-6.5t-1.5-6.5q-14 0-17 1 1 6 3 21t4 22q1 5 5.5 13.5t8 15.5 4.5 14-4.5 10.5-18.5 2.5q-20-1-29-22-1-3-3-11.5t-5-12.5-9-7q-8-3-27-2t-26 5q-14 8-24 30.5t-11 41.5q0 10 3 27.5t3 27-6 26.5q3 2 10 10.5t11 11.5q2 2 5 2h5t4 2 3 6q-1 1-4 3-3 3-4 3 4-3 19-1t19 2q0 1 22 0 17-13 24 2 0 1-2.5 10.5t-0.5 14.5q5-29 32-10 3-4 16.5-6t18.5-5q3-2 7-5.5t6-5 6-0.5 9 7q11-17 13-25 11-43 20-48 8-2 12.5-2t5 10.5 0 15.5-1.5 13l-2 37q-16 3-20 12.5t1.5 20 16.5 19.5q1 1 16.5 8t21.5 12q24 19 17 39 9-2 11 9l-5 3q-4 3-8 5.5t-5 1.5q11 7 2 18 5 3 8 11.5t9 11.5q9-14 22-3 8 9 2 18 5 8 22 11.5t20 9.5q5-1 7 0t2 4.5v7.5t1 8.5 3 7.5q4 6 16 10.5t14 5.5l19 12q4 4 0 4 18-2 32 11 13 12-5 23 2 7-4 10.5t-16 5.5q3 1 12 0.5t12 1.5q15 11-7 17-20 5-47-13-3-2-13-12t-17-11q15 18 5 22 8-1 22.5 9t15.5 11q4 2 10.5 2.5t8.5 1.5q71 25 92-1 8 11 11 15t9.5 9 15.5 8q21 7 23 9l1 23q-12-1-18 8t-7 22l-6-8q0 6-3.5 7.5t-7.5 0.5-9.5-2-7.5 0q-9 2-19.5 15.5t-14.5 16.5q9 0 9 5-2 5-10 8 1 6-2 8t-9 0q-2 12-1 13-6 1-11 11t-8 10q-2 0-4.5-2t-5-5.5l-5-7t-3.5-5.5l-2-2q-12 6-24-10-9 1-17-2 15 6 2 13-11 5-21 2 12 5 10 14t-12 16q1 0 4-1t4-1q-1 5-9.5 9.5t-19.5 9-14 6.5q-7 5-36 10.5t-36 1.5q-5-3-6-6t1.5-8.5 3.5-8.5q6-23 5-27-1-3-8.5-8t-5.5-12q1-4 11.5-10t12.5-12q5-13-4-25-4-5-15-11t-14-10q-5-5-3.5-11.5t0.5-9.5q1 1 1 2.5t1 2.5q0-13 11-22 8-6-16-18-20-11-20-4 1 8-7.5 16t-10.5 12-3.5 19-9.5 21q-6 4-19 4t-18-5q0 10-49 30-17 8-58 4 7 1 0 17-8 16-21 12-8 25-4 35 2 5 9 14t9 15q1 3 15.5 6t16.5 8q1 4-2.5 6.5t-9.5 4.5q53-6 63 18 5 9 3 14 0-1 2-1t2-1q12 3 7 17 19 8 26 8 5-1 11-6t10-5q17-3 21.5 10t-9.5 23q7-4 7 6-1 13-7 19-3 2-6.5 2.5t-6.5 0-7 0.5q-1 0-8 2-1-1-2-1h-8q-4-2-4-5v-1q-1-3 4-6l5-1 3-2q-1 0-2.5-2.5t-2.5-2.5q0-3 3-5-2-1-14-7.5t-17-10.5q-1-1-4-2.5t-4-2.5q-2-1-4 2t-4 9-4 11.5-4.5 10-5.5 4.5q-12 0-18-17 3 10-13 17.5t-25 7.5q20 15-9 30l-1 1q-30-4-45-7-2-6 3-12-1-7 6-9 0-1 0.5-1t0.5-1q0 1-0.5 1t-0.5 1q3-1 10.5-1.5t9.5-1.5q3-1 4.5-2l7.5-5t5.5-6-2.5-5q-2-1-9-4t-12.5-5.5-6.5-3.5q-3-5 0-16t-2-15q-5 5-10 18.5t-8 17.5q8-9-30-6l-8 1q-4 0-15-2t-16-1q-7 0-29 6 7 17 5 25 5 0 7 2l-6 3q-3-1-25-9 2-3 8-9.5t9-11.5q-22 6-27-2 0-1-9 0-25 1-24-7 1-4 9-12 0-9-1-9-27 22-30 23-172-83-276-248 1-2 2.5-11t3.5-8.5 11 4.5q9-9 3-21 2 2 36-21 56-40 22-53v5.5t1 6.5q-9-1-19 5-3-6 0.5-20t11.5-14q-8 0-10.5-17t-2.5-38.5-1-25.5l2-1q-3-13 6-37.5t24-20.5q-4-18 5-21-1-4 0-8t4.5-8.5 6-7l13.5-13.5q28-11 41-29 4-6 10.5-24.5t15.5-25.5q-2-6 10-21.5t11-25.5q-1 0-2.5-0.5t-2.5-0.5q3-8 16.5-16t16.5-14q2-3 2.5-10.5t3-12 8.5-2.5q3 24-26 68-16 27-18 31-3 5-5.5 16.5t-4.5 15.5q27-9 26-13-5-10 26-52 2-3 10-10t11-12q3-4 9.5-14.5t10.5-15.5q-1 0-3-2l-3-3q4-2 9-5t8-4.5 7.5-5 7.5-7.5q16-18 20-33 1-4 0.5-15.5t1.5-16.5q2-6 6-11t11.5-10 11.5-7 14.5-6.5 11.5-5.5q2-1 18-11t25-14q10-4 16.5-4.5t16 2.5 15.5 4z"
|
||||
fill="currentColor"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="32" height="32" version="1.1" viewBox="0 0 496 496" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m248 0c-136.96 0-248 111.08-248 248 0 137 111.04 248 248 248s248-111 248-248c0-136.92-111.04-248-248-248zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 514 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="32" height="32" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M167.02 309.34c-40.12 2.58-76.53 17.86-97.19 72.3-2.35 6.21-8 9.98-14.59 9.98-11.11 0-45.46-27.67-55.25-34.35C0 439.62 37.93 512 128 512c75.86 0 128-43.77 128-120.19 0-3.11-.65-6.08-.97-9.13l-88.01-73.34zM457.89 0c-15.16 0-29.37 6.71-40.21 16.45C213.27 199.05 192 203.34 192 257.09c0 13.7 3.25 26.76 8.73 38.7l63.82 53.18c7.21 1.8 14.64 3.03 22.39 3.03 62.11 0 98.11-45.47 211.16-256.46 7.38-14.35 13.9-29.85 13.9-45.99C512 20.64 486 0 457.89 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 554 B |
@@ -1,6 +0,0 @@
|
||||
<svg width="1408" height="1408" version="1.1" viewBox="0 -256 1408 1408" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1,0,0,-1,0,1152)">
|
||||
<path d="m1408 800v-192q0-40-28-68t-68-28h-416v-416q0-40-28-68t-68-28h-192q-40 0-68 28t-28 68v416h-416q-40 0-68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68-28t28-68v-416h416q40 0 68-28t28-68z"
|
||||
fill="currentColor"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 430 B |
@@ -1,6 +0,0 @@
|
||||
<svg width="32" height="32" version="1.1" viewBox="0 -256 1515 1515" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1,0,0,-1,0,1152)">
|
||||
<path d="m448 1088q0 53-37.5 90.5t-90.5 37.5-90.5-37.5-37.5-90.5 37.5-90.5 90.5-37.5 90.5 37.5 37.5 90.5zm1067-576q0-53-37-90l-491-492q-39-37-91-37-53 0-90 37l-715 716q-38 37-64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117-26.5t102-64.5l715-714q37-39 37-91z"
|
||||
fill="currentColor"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 473 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="32" height="32" version="1.1" viewBox="0 -256 1641 1643" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1,0,0,-1,-21,1152)">
|
||||
<path d="m384 64q0 26-19 45t-45 19-45-19-19-45 19-45 45-19 45 19 19 45zm644 420-682-682q-37-37-90-37-52 0-91 37l-106 108q-38 36-38 90 0 53 38 91l681 681q39-98 114.5-173.5t173.5-114.5zm634 435q0-39-23-106-47-134-164.5-217.5t-258.5-83.5q-185 0-316.5 131.5t-131.5 316.5 131.5 316.5 316.5 131.5q58 0 121.5-16.5t107.5-46.5q16-11 16-28t-16-28l-293-169v-224l193-107q5 3 79 48.5t135.5 81 70.5 35.5q15 0 23.5-10t8.5-25z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 589 B |
@@ -2,7 +2,11 @@ import {sveltekit} from '@sveltejs/kit/vite';
|
||||
import {defineConfig} from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
// SVGs imported from the FA6 don't need to be inlined!
|
||||
assetsInlineLimit: 0
|
||||
},
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
]
|
||||
],
|
||||
});
|
||||