more changes for #48, the UI now works \o/

This commit is contained in:
mProjectsCode 2022-09-24 20:33:06 +02:00
parent e00c5ce2c2
commit 14719efa22
17 changed files with 381 additions and 165 deletions

36
src/settings/Icon.svelte Normal file
View file

@ -0,0 +1,36 @@
<!--adapted from @joethei's code: https://github.com/joethei/obsidian-rss/blob/master/src/view/IconComponent.svelte-->
<!--adapted from @javalent's code: https://discord.com/channels/686053708261228577/840286264964022302/902949764209987654-->
<script lang="ts">
import {setIcon} from 'obsidian';
import {onMount} from 'svelte';
export let iconName: string = '';
export let iconSize: number = 20;
let iconEl: HTMLElement;
onMount(() => {
setIcon(iconEl, iconName, iconSize);
});
</script>
<style>
.icon-wrapper {
display: inline-block;
position: relative;
width: 20px;
}
.icon {
position: absolute;
height: 20px;
width: 20px;
top: calc(50% - 10px);
}
</style>
{#if iconName.length > 0}
<div class="icon-wrapper">
<div bind:this={iconEl} class="icon"></div>
</div>
{/if}

View file

@ -1,74 +0,0 @@
<script lang="ts">
import {capitalizeFirstLetter} from '../utils/Utils';
import {PropertyMappingModel, PropertyMappingOption, propertyMappingOptions} from './PropertyMapping';
export let models: PropertyMappingModel[] = [];
export let save: (models: PropertyMappingModel[]) => void;
</script>
<style>
.media-db-plugin-property-mappings-container {
margin: 10px 0;
display: flex;
flex-direction: column;
gap: 10px;
}
.media-db-plugin-property-mapping-element {
display: flex;
flex-direction: row;
gap: 10px;
}
.media-db-plugin-property-mapping-element-property-name-wrapper {
min-width: 160px;
background: var(--background-modifier-form-field);
padding: 2px 5px;
border-radius: 5px;
}
.media-db-plugin-property-mapping-element-property-name {
margin: 0;
}
</style>
<div class="setting-item" style="display: block;">
{ #each models as model }
<div class="setting-item-name">{capitalizeFirstLetter(model.type)}</div>
<div class="media-db-plugin-property-mappings-container">
{ #each model.properties as property }
<div class="media-db-plugin-property-mapping-element">
<div class="media-db-plugin-property-mapping-element-property-name-wrapper">
<pre
class="media-db-plugin-property-mapping-element-property-name"><code>{property.property}</code></pre>
</div>
{#if property.locked}
<div class="media-db-plugin-property-binding-text">
property can not be remapped
</div>
{:else}
<select bind:value={property.mapping}>
{#each propertyMappingOptions as remappingOption}
<option value={remappingOption}>
{remappingOption}
</option>
{/each}
</select>
{#if property.mapping === PropertyMappingOption.Map}
<div class="media-db-plugin-property-mapping-text">
->
</div>
<div class="media-db-plugin-property-binding-to">
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
</div>
{/if}
{/if}
</div>
{ /each }
</div>
{ /each }
<pre>{JSON.stringify(models, null, 4)}</pre>
</div>

View file

@ -26,7 +26,7 @@ export class PropertyMapper {
}
// @ts-ignore
const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties;
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
const newObj: object = {};
@ -38,7 +38,7 @@ export class PropertyMapper {
newObj[propertyMapping.newProperty] = value;
} else if (propertyMapping.mapping === PropertyMappingOption.Remove) {
} else if (propertyMapping.mapping === PropertyMappingOption.None) {
} else if (propertyMapping.mapping === PropertyMappingOption.Default) {
// @ts-ignore
newObj[key] = value;
}
@ -67,7 +67,7 @@ export class PropertyMapper {
}
// @ts-ignore
const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties;
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
const originalObj: object = {};

View file

@ -2,12 +2,12 @@ import {containsOnlyLettersAndUnderscores} from '../utils/Utils';
import {MediaType} from '../utils/MediaType';
export enum PropertyMappingOption {
None = 'none',
Default = 'default',
Map = 'remap',
Remove = 'remove',
}
export const propertyMappingOptions = [PropertyMappingOption.None, PropertyMappingOption.Map, PropertyMappingOption.Remove];
export const propertyMappingOptions = [PropertyMappingOption.Default, PropertyMappingOption.Map, PropertyMappingOption.Remove];
export interface PropertyMappingModel {
type: MediaType,
@ -62,7 +62,7 @@ export class PropertyMapping {
}
toString(): string {
if (this.mapping === PropertyMappingOption.None) {
if (this.mapping === PropertyMappingOption.Default) {
return this.property;
} else if (this.mapping === PropertyMappingOption.Map) {
return `${this.property} -> ${this.newProperty}`;

View file

@ -0,0 +1,106 @@
<script lang="ts">
import {capitalizeFirstLetter} from '../utils/Utils';
import {PropertyMappingModel, PropertyMappingOption, propertyMappingOptions} from './PropertyMapping';
import Icon from './Icon.svelte';
export let models: PropertyMappingModel[] = [];
export let save: (model: PropertyMappingModel) => void;
// TODO: validate all the mappings before saving.
</script>
<style>
.media-db-plugin-property-mappings-model-container {
border: 1px solid var(--background-modifier-border);
border-radius: 5px;
padding: 10px;
width: 100%;
}
.media-db-plugin-property-mappings-container {
margin: 10px 0;
display: flex;
flex-direction: column;
gap: 5px;
}
.media-db-plugin-property-mapping-element {
display: flex;
flex-direction: row;
gap: 10px;
}
.media-db-plugin-property-mapping-element-property-name-wrapper {
min-width: 160px;
background: var(--background-modifier-form-field);
padding: 2px 5px;
border-radius: 5px;
display: flex;
align-items: center;
}
.media-db-plugin-property-mapping-element-property-name {
margin: 0;
}
.media-db-plugin-property-mappings-save-button {
margin: 0;
}
.media-db-plugin-property-binding-to {
display: flex;
align-items: center;
}
</style>
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
{ #each models as model }
<div class="media-db-plugin-property-mappings-model-container">
<div class="setting-item-name">{capitalizeFirstLetter(model.type)}</div>
<div class="media-db-plugin-property-mappings-container">
{ #each model.properties as property }
<div class="media-db-plugin-property-mapping-element">
<div class="media-db-plugin-property-mapping-element-property-name-wrapper">
<pre
class="media-db-plugin-property-mapping-element-property-name"><code>{property.property}</code></pre>
</div>
{#if property.locked}
<div class="media-db-plugin-property-binding-text">
property can not be remapped
</div>
{:else}
<select class="dropdown" bind:value={property.mapping}>
{#each propertyMappingOptions as remappingOption}
<option value={remappingOption}>
{remappingOption}
</option>
{/each}
</select>
{#if property.mapping === PropertyMappingOption.Map}
<Icon iconName="arrow-right"/>
<div class="media-db-plugin-property-binding-to">
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
</div>
{/if}
{/if}
</div>
{ /each }
</div>
<button class="mod-cta media-db-plugin-property-mappings-save-button" on:click={() => save(model)}>Save
</button>
</div>
{ /each }
<pre>{JSON.stringify(models, null, 4)}</pre>
<!--
{ #each ICON_LIST as icon }
<p>
{icon} <Icon iconName="{icon}"/>
</p>
{/each}
-->
</div>

View file

@ -1,11 +1,12 @@
import {App, PluginSettingTab, Setting} from 'obsidian';
import {App, Notice, PluginSettingTab, Setting} from 'obsidian';
import MediaDbPlugin from '../main';
import {FolderSuggest} from './suggesters/FolderSuggest';
import {FileSuggest} from './suggesters/FileSuggest';
import PropertyBindingsComponent from './PropertyBindingsComponent.svelte';
import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte';
import {PropertyMapping, PropertyMappingModel, PropertyMappingOption} from './PropertyMapping';
import {MediaType} from '../utils/MediaType';
import {MEDIA_TYPES} from '../utils/MediaTypeManager';
import {MediaTypeModel} from '../models/MediaTypeModel';
export interface MediaDbPluginSettings {
@ -37,7 +38,7 @@ export interface MediaDbPluginSettings {
musicReleasePropertyConversionRules: string,
boardgamePropertyConversionRules: string,
propertyMappings: PropertyMappingModel[],
propertyMappingModels: PropertyMappingModel[],
}
@ -69,62 +70,96 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = {
musicReleasePropertyConversionRules: '',
boardgamePropertyConversionRules: '',
propertyMappings: [
propertyMappingModels: [
/*
{
type: MediaType.Movie,
properties: [
new PropertyMapping('type', '', PropertyMappingOption.None, true),
new PropertyMapping('subType', '', PropertyMappingOption.None),
new PropertyMapping('title', '', PropertyMappingOption.None),
new PropertyMapping('englishTitle', '', PropertyMappingOption.None),
new PropertyMapping('year', '', PropertyMappingOption.None),
new PropertyMapping('dataSource', '', PropertyMappingOption.None, true),
new PropertyMapping('url', '', PropertyMappingOption.None),
new PropertyMapping('id', '', PropertyMappingOption.None, true),
new PropertyMapping('type', '', PropertyMappingOption.Default, true),
new PropertyMapping('subType', '', PropertyMappingOption.Default),
new PropertyMapping('title', '', PropertyMappingOption.Default),
new PropertyMapping('englishTitle', '', PropertyMappingOption.Default),
new PropertyMapping('year', '', PropertyMappingOption.Default),
new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true),
new PropertyMapping('url', '', PropertyMappingOption.Default),
new PropertyMapping('id', '', PropertyMappingOption.Default, true),
new PropertyMapping('genres', '', PropertyMappingOption.None),
new PropertyMapping('producer', '', PropertyMappingOption.None),
new PropertyMapping('duration', '', PropertyMappingOption.None),
new PropertyMapping('onlineRating', '', PropertyMappingOption.None),
new PropertyMapping('image', '', PropertyMappingOption.None),
new PropertyMapping('released', '', PropertyMappingOption.None),
new PropertyMapping('premiere', '', PropertyMappingOption.None),
new PropertyMapping('watched', '', PropertyMappingOption.None),
new PropertyMapping('lastWatched', '', PropertyMappingOption.None),
new PropertyMapping('personalRating', '', PropertyMappingOption.None),
new PropertyMapping('genres', '', PropertyMappingOption.Default),
new PropertyMapping('producer', '', PropertyMappingOption.Default),
new PropertyMapping('duration', '', PropertyMappingOption.Default),
new PropertyMapping('onlineRating', '', PropertyMappingOption.Default),
new PropertyMapping('image', '', PropertyMappingOption.Default),
new PropertyMapping('released', '', PropertyMappingOption.Default),
new PropertyMapping('premiere', '', PropertyMappingOption.Default),
new PropertyMapping('watched', '', PropertyMappingOption.Default),
new PropertyMapping('lastWatched', '', PropertyMappingOption.Default),
new PropertyMapping('personalRating', '', PropertyMappingOption.Default),
],
},
{
type: MediaType.Series,
properties: [
new PropertyMapping('type', '', PropertyMappingOption.None, true),
new PropertyMapping('subType', '', PropertyMappingOption.None),
new PropertyMapping('title', '', PropertyMappingOption.None),
new PropertyMapping('englishTitle', '', PropertyMappingOption.None),
new PropertyMapping('year', '', PropertyMappingOption.None),
new PropertyMapping('dataSource', '', PropertyMappingOption.None, true),
new PropertyMapping('url', '', PropertyMappingOption.None),
new PropertyMapping('id', '', PropertyMappingOption.None, true),
new PropertyMapping('type', '', PropertyMappingOption.Default, true),
new PropertyMapping('subType', '', PropertyMappingOption.Default),
new PropertyMapping('title', '', PropertyMappingOption.Default),
new PropertyMapping('englishTitle', '', PropertyMappingOption.Default),
new PropertyMapping('year', '', PropertyMappingOption.Default),
new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true),
new PropertyMapping('url', '', PropertyMappingOption.Default),
new PropertyMapping('id', '', PropertyMappingOption.Default, true),
new PropertyMapping('genres', '', PropertyMappingOption.None),
new PropertyMapping('studios', '', PropertyMappingOption.None),
new PropertyMapping('episodes', '', PropertyMappingOption.None),
new PropertyMapping('duration', '', PropertyMappingOption.None),
new PropertyMapping('onlineRating', '', PropertyMappingOption.None),
new PropertyMapping('image', '', PropertyMappingOption.None),
new PropertyMapping('released', '', PropertyMappingOption.None),
new PropertyMapping('airing', '', PropertyMappingOption.None),
new PropertyMapping('airedFrom', '', PropertyMappingOption.None),
new PropertyMapping('airedTo', '', PropertyMappingOption.None),
new PropertyMapping('watched', '', PropertyMappingOption.None),
new PropertyMapping('lastWatched', '', PropertyMappingOption.None),
new PropertyMapping('personalRating', '', PropertyMappingOption.None),
new PropertyMapping('genres', '', PropertyMappingOption.Default),
new PropertyMapping('studios', '', PropertyMappingOption.Default),
new PropertyMapping('episodes', '', PropertyMappingOption.Default),
new PropertyMapping('duration', '', PropertyMappingOption.Default),
new PropertyMapping('onlineRating', '', PropertyMappingOption.Default),
new PropertyMapping('image', '', PropertyMappingOption.Default),
new PropertyMapping('released', '', PropertyMappingOption.Default),
new PropertyMapping('airing', '', PropertyMappingOption.Default),
new PropertyMapping('airedFrom', '', PropertyMappingOption.Default),
new PropertyMapping('airedTo', '', PropertyMappingOption.Default),
new PropertyMapping('watched', '', PropertyMappingOption.Default),
new PropertyMapping('lastWatched', '', PropertyMappingOption.Default),
new PropertyMapping('personalRating', '', PropertyMappingOption.Default),
],
},
*/
],
};
export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource'];
export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings {
let defaultSettings = DEFAULT_SETTINGS;
// construct property mapping defaults
const propertyMappingModels: PropertyMappingModel[] = [];
for (const mediaType of MEDIA_TYPES) {
const model: MediaTypeModel = plugin.mediaTypeManager.createMediaTypeModelFromMediaType({}, mediaType);
const metadataObj = model.toMetaDataObject();
// console.log(metadataObj);
// console.log(model);
const propertyMappingModel: PropertyMappingModel = {
type: mediaType,
properties: [],
};
for (const key of Object.keys(metadataObj)) {
propertyMappingModel.properties.push(
new PropertyMapping(key, '', PropertyMappingOption.Default, lockedPropertyMappings.contains(key)),
);
}
propertyMappingModels.push(propertyMappingModel);
}
defaultSettings.propertyMappingModels = propertyMappingModels;
return defaultSettings;
}
export class MediaDbSettingTab extends PluginSettingTab {
plugin: MediaDbPlugin;
@ -433,14 +468,38 @@ export class MediaDbSettingTab extends PluginSettingTab {
*/
// endregion
console.log(this.plugin.settings.propertyMappings);
console.log(this.plugin.settings.propertyMappingModels);
// console.log(getDefaultSettings(this.plugin));
new PropertyBindingsComponent({
let propertyMappingExplanation = containerEl.createEl('div');
propertyMappingExplanation.innerHTML = `<p>Allow you to remap the metadata fields of newly created media db entries.</p>
<p>
The different options are:
<lu>
<li>"default": does no remapping and keeps the metadata field as it is</li>
<li>"remap": renames the metadata field to what ever you specify</li>
<li>"remove": removes the metadata field entirely</li>
</lu>
</p>`;
new PropertyMappingModelsComponent({
target: this.containerEl,
props: {
models: this.plugin.settings.propertyMappings,
save: (models: PropertyMappingModel[]) => {
this.plugin.settings.propertyMappings = models;
models: JSON.parse(JSON.stringify(this.plugin.settings.propertyMappingModels)),
save: (model: PropertyMappingModel) => {
let propertyMappingModels: PropertyMappingModel[] = [];
for (const model2 of this.plugin.settings.propertyMappingModels) {
if (model2.type === model.type) {
propertyMappingModels.push(model);
} else {
propertyMappingModels.push(model2);
}
}
this.plugin.settings.propertyMappingModels = propertyMappingModels;
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
this.plugin.saveSettings();
},
},

View file

@ -80,7 +80,7 @@ export class Suggest<T> {
}
setSelectedItem(selectedIndex: number, scrollIntoView: boolean) {
const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length);
const normalizedIndex = this.suggestions.length > 0 ? wrapAround(selectedIndex, this.suggestions.length) : 0;
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
const selectedSuggestion = this.suggestions[normalizedIndex];