diff --git a/changelog.md b/changelog.md index 6fed237..5005b95 100644 --- a/changelog.md +++ b/changelog.md @@ -10,16 +10,21 @@ - A new logo added to the app (better visibility of the logo in small scales and icons) - Massive overhaul of the search engine used by the Quick opening existing document and single/multi relationship fields (now supports tags, categories, document types, inteligent filtering and inteligent sorting via importance of the found values) +- Added color support to single/multi relationship fields +- Added a hierarchical path to Quick opening existing document and single/multi relationship fields +- Added filtering to include or exclude documents that are considered categories in the Quick opening existing document dialog +- Added automatic opening of hierarchical tree branches upon adding/moving documents under/among them +- Added tags support ### QoL adjustments -- Added a hierarchical path to Quick opening existing document and single/multi relationship fields -- Added color support to single/multi relationship fields -- Added filtering to include or exclude documents that are considered categories in the Quick opening existing document dialog +- Slightly modified the scrollbar visuals to be less intrusive +- Added a light golden tint to the background of the app to go easy on user's eyes before farkmode is added - Improved performance by reducing the amount of time the side-tree re-renders -- Added automatic opening of hierarchical tree branches upon adding/moving documents under/among them -- Alligned custom order sorting for both nodes with and without children +- Visually alligned custom order badge for both nodes with and without children +- Added dark visuals to the single-select and multi-select fields to align with thge rest of the app - All popup dialogs have been unified to dark-color mode +- Prettified a dialog popup for confirmation of closing a document with active edits - Added a small filter over the big white areas to ease-up on the user's eyes before darkmode is added ## 0.1.2 diff --git a/package.json b/package.json index 28b6cd7..86cbc01 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fantasiaarchive", - "version": "0.1.2", + "version": "0.1.3", "description": "A database manager for world building", "productName": "Fantasia archive", "author": "Elvanos ", diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue index c1bd9c1..f040219 100644 --- a/src/components/AppHeader.vue +++ b/src/components/AppHeader.vue @@ -44,6 +44,7 @@ export default class AppHeader extends BaseClass { } .appHeaderInner { + z-index: 999999; display: flex; min-height: 40px; -webkit-app-region: drag; diff --git a/src/components/ObjectTree.vue b/src/components/ObjectTree.vue index e8c3382..30646cd 100644 --- a/src/components/ObjectTree.vue +++ b/src/components/ObjectTree.vue @@ -28,7 +28,7 @@ @click.stop.prevent.middle="processNodeLabelMiddleClick(prop.node)" > @@ -56,7 +56,7 @@
{ + const tagDocs = allTreeDocuments + .filter(doc => { + const docTags = doc.extraFields.find(e => e.id === "tags")?.value as unknown as string[] + return (docTags && docTags.includes(tag)) + }) + .map((doc:I_ShortenedDocument) => { + // @ts-ignore + doc.key = `${tag}${doc._id}` + // @ts-ignore + doc.isTag = true + return doc + }) + .sort((a, b) => a.label.localeCompare(b.label)) + + const tagObject = { + label: `${tag}`, + icon: "mdi-tag", + _id: `tag-${tag}`, + key: `tag-${tag}`, + documentCount: tagDocs.length, + isRoot: true, + isTag: true, + children: tagDocs + } + treeObject.push(tagObject) + }) + // Assign the finished object to the render model this.hierarchicalTree = treeObject } @@ -539,10 +575,15 @@ export default class ObjectTree extends BaseClass { children: [] type: string isRoot: boolean + isTag: boolean specialLabel: string|boolean }) { this.selectedTreeNode = null + if (node.isRoot && node.isTag) { + return + } + if (!node.specialLabel && !node.isRoot) { // @ts-ignore this.openExistingDocumentRoute(node) @@ -582,6 +623,11 @@ export default class ObjectTree extends BaseClass { const isExpanded = treeDOM.isExpanded(node.key) treeDOM.setExpanded(node.key, !isExpanded) } + + determineNodeColor (node: {color: string, isTag: boolean, isRoot: boolean}) { + // @ts-ignore + return (node?.isTag && node?.isRoot) ? colors.getBrand("primary") : node.color + } } diff --git a/src/components/dialogs/ExistingDocument.vue b/src/components/dialogs/ExistingDocument.vue index 7089a4c..1864522 100644 --- a/src/components/dialogs/ExistingDocument.vue +++ b/src/components/dialogs/ExistingDocument.vue @@ -47,6 +47,17 @@ + + + + e.id === "tags")?.value, color: doc.extraFields.find(e => e.id === "documentColor")?.value, isCategory: doc.extraFields.find(e => e.id === "categorySwitch")?.value } as unknown as I_ShortenedDocument diff --git a/src/components/dialogs/NewDocument.vue b/src/components/dialogs/NewDocument.vue index c3221a9..5837e02 100644 --- a/src/components/dialogs/NewDocument.vue +++ b/src/components/dialogs/NewDocument.vue @@ -18,6 +18,8 @@ ref="ref_newDocument" style="flex-grow: 1;" dense + menu-anchor="bottom middle" + menu-self="top middle" class="newDocumentSelect" :options="filteredNewInput" use-input @@ -101,7 +103,7 @@ export default class NewDocumentDialog extends DialogBase { setTimeout( () =>{ // @ts-ignore this.$refs.ref_newDocument.focus() - }, 100) + }, 300) /* eslint-enable */ }) } diff --git a/src/components/fields/Field_MultiSelect.vue b/src/components/fields/Field_MultiSelect.vue index aa400fb..bc458ce 100644 --- a/src/components/fields/Field_MultiSelect.vue +++ b/src/components/fields/Field_MultiSelect.vue @@ -27,6 +27,10 @@ v-if="editMode" style="width: 100%;" dense + dark + menu-anchor="bottom middle" + menu-self="top middle" + class="multiSelect" :options="extraInput" use-input outlined diff --git a/src/components/fields/Field_SingleSelect.vue b/src/components/fields/Field_SingleSelect.vue index dabc072..0622bdf 100644 --- a/src/components/fields/Field_SingleSelect.vue +++ b/src/components/fields/Field_SingleSelect.vue @@ -24,6 +24,10 @@ v-if="editMode" style="width: 100%;" dense + dark + menu-anchor="bottom middle" + menu-self="top middle" + class="singleSelect" :options="extraInput" use-input outlined diff --git a/src/components/fields/Field_Tags.vue b/src/components/fields/Field_Tags.vue new file mode 100644 index 0000000..7c116c8 --- /dev/null +++ b/src/components/fields/Field_Tags.vue @@ -0,0 +1,127 @@ + + + diff --git a/src/css/app.scss b/src/css/app.scss index fd91651..c3a916d 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -66,6 +66,9 @@ body { left: calc(100% - 30px); } +.tagSelect, +.singleSelect, +.multiSelect, .singleRelashionshipSelect, .multiRelashionshipSelect, .existingDocumentSelect, @@ -89,7 +92,7 @@ body { } .q-position-engine { - overflow-y: scroll !important; + overflow-y: auto !important; } .text-underline { diff --git a/src/interfaces/I_Blueprint.ts b/src/interfaces/I_Blueprint.ts index 4de2101..8ee05c9 100644 --- a/src/interfaces/I_Blueprint.ts +++ b/src/interfaces/I_Blueprint.ts @@ -19,7 +19,8 @@ export interface I_ExtraFields { "singleToManyRelationship" | "manyToSingleRelationship" | "manyToManyRelationship" | - "break" + "break" | + "tags" predefinedListExtras?: { affix?: string diff --git a/src/interfaces/I_OpenedDocument.ts b/src/interfaces/I_OpenedDocument.ts index 3813c8a..33f6971 100644 --- a/src/interfaces/I_OpenedDocument.ts +++ b/src/interfaces/I_OpenedDocument.ts @@ -29,6 +29,7 @@ export interface I_ShortenedDocument{ children: I_ShortenedDocument[] extraFields: I_ExtraDocumentFields[] color?: string + tags?: string[] activeTypeSearch?: boolean filteredOut?: boolean diff --git a/src/pages/DocumentDisplay.vue b/src/pages/DocumentDisplay.vue index 26aafe8..502f4f2 100644 --- a/src/pages/DocumentDisplay.vue +++ b/src/pages/DocumentDisplay.vue @@ -171,6 +171,16 @@ @signal-input="reactToFieldUpdate($event, field)" /> + +
@@ -202,7 +212,7 @@ import Field_MultiSelect from "src/components/fields/Field_MultiSelect.vue" import Field_SingleRelationship from "src/components/fields/Field_SingleRelationship.vue" import Field_MultiRelationship from "src/components/fields/Field_MultiRelationship.vue" import Field_Wysiwyg from "src/components/fields/Field_Wysiwyg.vue" -import console from "console" +import Field_Tags from "src/components/fields/Field_Tags.vue" @Component({ components: { @@ -216,7 +226,8 @@ import console from "console" Field_MultiSelect, Field_SingleRelationship, Field_MultiRelationship, - Field_Wysiwyg + Field_Wysiwyg, + Field_Tags } }) @@ -397,6 +408,18 @@ export default class PageDocumentDisplay extends BaseClass { const dataPass = { doc: dataCopy, treeAction: false } this.SSET_updateOpenedDocument(dataPass) } + + // FIELD - Tags + if (field.type === "tags") { + this.currentData.hasEdits = true + const indexToUpdate = this.currentData.extraFields.findIndex(s => s.id === field.id) + this.currentData.extraFields[indexToUpdate].value = inputData + + const dataCopy: I_OpenedDocument = extend(true, {}, this.currentData) + + const dataPass = { doc: dataCopy, treeAction: false } + this.SSET_updateOpenedDocument(dataPass) + } } toggleEditMode () { diff --git a/src/scripts/databaseManager/blueprints/chapters.ts b/src/scripts/databaseManager/blueprints/chapters.ts index 34c080c..ac92f94 100644 --- a/src/scripts/databaseManager/blueprints/chapters.ts +++ b/src/scripts/databaseManager/blueprints/chapters.ts @@ -62,6 +62,16 @@ export const chaptersBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "content", name: "Chapter content", diff --git a/src/scripts/databaseManager/blueprints/characters.ts b/src/scripts/databaseManager/blueprints/characters.ts index 2286b03..67aa9e3 100644 --- a/src/scripts/databaseManager/blueprints/characters.ts +++ b/src/scripts/databaseManager/blueprints/characters.ts @@ -68,6 +68,16 @@ export const charactersBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/currencies.ts b/src/scripts/databaseManager/blueprints/currencies.ts index c1d7c21..b26c3e1 100644 --- a/src/scripts/databaseManager/blueprints/currencies.ts +++ b/src/scripts/databaseManager/blueprints/currencies.ts @@ -68,6 +68,16 @@ export const currenciesBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/events.ts b/src/scripts/databaseManager/blueprints/events.ts index 92fe169..c3f6ab6 100644 --- a/src/scripts/databaseManager/blueprints/events.ts +++ b/src/scripts/databaseManager/blueprints/events.ts @@ -68,6 +68,16 @@ export const eventsBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/items.ts b/src/scripts/databaseManager/blueprints/items.ts index 3b4b0dd..3a16ca6 100644 --- a/src/scripts/databaseManager/blueprints/items.ts +++ b/src/scripts/databaseManager/blueprints/items.ts @@ -68,6 +68,16 @@ export const itemsBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/languages.ts b/src/scripts/databaseManager/blueprints/languages.ts index 1f4706b..93d3500 100644 --- a/src/scripts/databaseManager/blueprints/languages.ts +++ b/src/scripts/databaseManager/blueprints/languages.ts @@ -68,6 +68,16 @@ export const languagesBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/locations.ts b/src/scripts/databaseManager/blueprints/locations.ts index 4ac0c25..970d44b 100644 --- a/src/scripts/databaseManager/blueprints/locations.ts +++ b/src/scripts/databaseManager/blueprints/locations.ts @@ -68,6 +68,16 @@ export const locationsBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/loreNotes.ts b/src/scripts/databaseManager/blueprints/loreNotes.ts index 401211c..8938037 100644 --- a/src/scripts/databaseManager/blueprints/loreNotes.ts +++ b/src/scripts/databaseManager/blueprints/loreNotes.ts @@ -62,6 +62,16 @@ export const loreNotesBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "notes", name: "Note list", diff --git a/src/scripts/databaseManager/blueprints/magic.ts b/src/scripts/databaseManager/blueprints/magic.ts index 8b5398a..132f5c3 100644 --- a/src/scripts/databaseManager/blueprints/magic.ts +++ b/src/scripts/databaseManager/blueprints/magic.ts @@ -68,6 +68,16 @@ export const magicBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/myths.ts b/src/scripts/databaseManager/blueprints/myths.ts index 1497936..dea2247 100644 --- a/src/scripts/databaseManager/blueprints/myths.ts +++ b/src/scripts/databaseManager/blueprints/myths.ts @@ -68,6 +68,16 @@ export const mythsBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/politicalGroups.ts b/src/scripts/databaseManager/blueprints/politicalGroups.ts index 10291a6..42643a2 100644 --- a/src/scripts/databaseManager/blueprints/politicalGroups.ts +++ b/src/scripts/databaseManager/blueprints/politicalGroups.ts @@ -68,6 +68,16 @@ export const politicalGroupsBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/races.ts b/src/scripts/databaseManager/blueprints/races.ts index 64b6f69..a295c86 100644 --- a/src/scripts/databaseManager/blueprints/races.ts +++ b/src/scripts/databaseManager/blueprints/races.ts @@ -68,6 +68,16 @@ export const racesBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/religions.ts b/src/scripts/databaseManager/blueprints/religions.ts index bb6a660..19bd75e 100644 --- a/src/scripts/databaseManager/blueprints/religions.ts +++ b/src/scripts/databaseManager/blueprints/religions.ts @@ -68,6 +68,16 @@ export const religionsBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/databaseManager/blueprints/scienceTechnology.ts b/src/scripts/databaseManager/blueprints/scienceTechnology.ts index 979843e..386d5a4 100644 --- a/src/scripts/databaseManager/blueprints/scienceTechnology.ts +++ b/src/scripts/databaseManager/blueprints/scienceTechnology.ts @@ -68,6 +68,16 @@ export const techBlueprint: I_Blueprint = { `, sizing: 2 }, + { + id: "tags", + name: "Tags", + type: "tags", + icon: "mdi-tag", + tooltip: + `tags + `, + sizing: 12 + }, { id: "otherNames", name: "Other names & Epithets", diff --git a/src/scripts/utilities/advancedDocumentFilter.ts b/src/scripts/utilities/advancedDocumentFilter.ts index ec912f4..da29097 100644 --- a/src/scripts/utilities/advancedDocumentFilter.ts +++ b/src/scripts/utilities/advancedDocumentFilter.ts @@ -40,20 +40,20 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor const searchWordList = inputString.toLowerCase().split(" ") let categorySeach = false as unknown as string - let tagSeach = false as unknown as string + let tagSearch = false as unknown as string let typeSeach = false as unknown as string const categorySeachIndex = searchWordList.findIndex(w => w.charAt(0) === ">") - const tagSeachIndex = searchWordList.findIndex(w => w.charAt(0) === "#") + const tagSearchIndex = searchWordList.findIndex(w => w.charAt(0) === "#") const typeSeachIndex = searchWordList.findIndex(w => w.charAt(0) === "$") if (categorySeachIndex >= 0) { categorySeach = searchWordList[categorySeachIndex].substring(1) searchWordList[categorySeachIndex] = "" } - if (tagSeachIndex >= 0) { - tagSeach = searchWordList[tagSeachIndex].substring(1) - searchWordList[tagSeachIndex] = "" + if (tagSearchIndex >= 0) { + tagSearch = searchWordList[tagSearchIndex].substring(1) + searchWordList[tagSearchIndex] = "" } if (typeSeachIndex >= 0) { typeSeach = searchWordList[typeSeachIndex].substring(1) @@ -67,7 +67,7 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor /****************************************************************/ if (categorySeach) { - documentList = documentList.filter((doc, index) => { + documentList = documentList.filter(doc => { let stringPath = doc.hierarchicalPath as unknown as string stringPath = stringPath.toLowerCase() stringPath = stringPath.replace(/>/gi, "") @@ -75,12 +75,36 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor stringPath = stringPath.replace(/ /gi, "-") // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - doc.hierarchicalPath = `${doc.hierarchicalPath}` + doc.hierarchicalPath = `${doc.hierarchicalPath}` return (stringPath.includes(categorySeach)) }) } + /****************************************************************/ + // Tag filter + /****************************************************************/ + if (tagSearch) { + documentList = documentList.filter(doc => { + let matchFound = false + + if (doc.tags) { + doc.tags.forEach((tag, index) => { + const ogTag = tag + tag = tag.toLowerCase() + tag = tag.replace(/>/gi, "") + tag = tag.replace(/ {2}/gi, "-") + tag = tag.replace(/ /gi, "-") + if (tag.includes(tagSearch)) { + // @ts-ignore + doc.tags[index] = `${ogTag}` + } + matchFound = (tag.includes(tagSearch) || matchFound) + }) + } + return matchFound + }) + } /****************************************************************/ // Type filter /****************************************************************/ @@ -148,13 +172,21 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor // Color the word if they were found documentWordListColoring = documentWordListColoring.map(docWord => { if (foundWordList.includes(docWord.toLowerCase())) { - return `${docWord}` + return `${docWord}` } return docWord }) doc.label = documentWordListColoring.join(" ") }) + // Cover case of exact match + documentList.map(doc => { + if (doc.exactMatch) { + doc.label = `${doc.label}` + } + return doc + }) + /****************************************************************/ // Sorting /****************************************************************/ diff --git a/src/scripts/utilities/tagListBuilder.ts b/src/scripts/utilities/tagListBuilder.ts new file mode 100644 index 0000000..1d326ad --- /dev/null +++ b/src/scripts/utilities/tagListBuilder.ts @@ -0,0 +1,32 @@ +import { I_Blueprint } from "./../../interfaces/I_Blueprint" +import PouchDB from "pouchdb" +import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument" + +/** + * Build a tag list of all know database documents + */ +export const tagListBuildFromBlueprints = async (blueprintList: I_Blueprint[]) => { + let allTags: string[] = [] + for (const blueprint of blueprintList) { + const CurrentObjectDB = new PouchDB(blueprint._id) + + const dbDocuments = await CurrentObjectDB.allDocs({ include_docs: true }) + const docsTagsArray = dbDocuments.rows.map(singleDocument => { + const doc = singleDocument.doc as unknown as I_ShortenedDocument + const tags: string[] = doc.extraFields.find(e => e.id === "tags")?.value + + return (tags) || [] + }) + + // @ts-ignore + allTags = [...allTags, ...docsTagsArray] as unknown as string[] + } + + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + allTags = allTags.flat() + + return [...new Set([ + ...allTags + ])].sort((a, b) => a.localeCompare(b)) +} diff --git a/tsconfig.json b/tsconfig.json index c6d92da..641d44f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "baseUrl": ".", "experimentalDecorators": true, "allowSyntheticDefaultImports": true, - "suppressImplicitAnyIndexErrors": true, + "suppressImplicitAnyIndexErrors": true }, "include": [ "src"