0.1.3 - RC 6

This commit is contained in:
Elvanos 2021-03-07 23:07:40 +01:00
parent c4a31f17ab
commit 65305a1860
49 changed files with 946 additions and 171 deletions

View file

@ -26,7 +26,8 @@ module.exports = configure(function (ctx) {
// https://quasar.dev/quasar-cli/boot-files
boot: [
"i18n",
"axios"
"axios",
'notify-defaults'
],
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css

View file

@ -17,6 +17,7 @@ if (process.env.PROD) {
let mainWindow
function createWindow () {
app.commandLine.appendSwitch('disable-software-rasterizer', 'true')
/**
* Initial window options
*/

View file

@ -28,10 +28,17 @@ export default class App extends BaseClass {
}
this.registerDefaultKeybinds()
window.addEventListener("keyup", this.triggerKeyPush)
window.addEventListener("keydown", this.triggerKeyPush)
}
triggerKeyPush (e:any) {
// console.log("")
// console.log(`Key: ${e.key}`)
// console.log(`Ctrl: ${e.ctrlKey}`)
// console.log(`Shift: ${e.shiftKey}`)
// console.log(`Alt: ${e.altKey}`)
// console.log(e)
if (e?.altKey === true || e?.ctrlKey || e?.shiftKey) {
const ouputKeycombo = {
altKey: e.altKey,
@ -48,7 +55,7 @@ export default class App extends BaseClass {
window.removeEventListener("auxclick", this.reactToMiddleClick)
this.deregisterDefaultKeybinds()
window.removeEventListener("keyup", this.triggerKeyPush)
window.removeEventListener("keydown", this.triggerKeyPush)
}
reactToMiddleClick (e: {button: number, preventDefault: ()=> void}) {

View file

@ -163,7 +163,13 @@ export default class BaseClass extends Vue {
// Open documents management
/****************************************************************/
@OpenedDocuments.Getter("getAllDocuments") SGET_allOpenedDocuments !: {treeAction: boolean, timestamp: string, docs: I_OpenedDocument[]}
@OpenedDocuments.Getter("getAllDocuments") SGET_allOpenedDocuments !: {
treeAction: boolean,
lastRemovedIndex: number,
timestamp: string,
docs: I_OpenedDocument[]
}
@OpenedDocuments.Getter("getDocument") SGET_openedDocument!: (id: string) => I_OpenedDocument
@OpenedDocuments.Action("addDocument") SSET_addOpenedDocument!: (input: {
@ -183,6 +189,7 @@ export default class BaseClass extends Vue {
@OpenedDocuments.Action("triggerTreeAction") SSET_triggerTreeAction!: () => void
@OpenedDocuments.Action("resetDocuments") SSET_resetDocuments!: () => void
@OpenedDocuments.Action("resetRemoveIndex") SSET_resetRemoveIndex!: () => void
findRequestedOrActiveDocument (doc?: I_OpenedDocument) {
if (doc) {
@ -236,9 +243,17 @@ export default class BaseClass extends Vue {
refreshRoute () {
const remainingDocuments = this.SGET_allOpenedDocuments.docs
const lastIndex = this.SGET_allOpenedDocuments.lastRemovedIndex
const newIndex = (lastIndex > -1 && lastIndex < remainingDocuments.length) ? lastIndex : remainingDocuments.length - 1
if (lastIndex > -1) {
this.SSET_resetRemoveIndex()
}
// Assuming there are any documents in the current list
if (remainingDocuments.length > 0) {
const lastDocument = remainingDocuments[remainingDocuments.length - 1]
const lastDocument = remainingDocuments[newIndex]
const currentRoute = this.$router.currentRoute.path
const existingDocument = this.SGET_allOpenedDocuments.docs.find(e => {
return e.url === currentRoute

View file

@ -0,0 +1,8 @@
import { Notify } from "quasar"
Notify.setDefaults({
position: "bottom-right",
timeout: 4000,
progress: true,
textColor: "cultured"
})

View file

@ -142,7 +142,7 @@
<q-btn
icon="mdi-content-save"
color="primary"
:color="(!hasEdits) ? 'teal-14' : 'primary'"
outline
@click="saveCurrentDocument"
v-if="!currentyEditable && SGET_allOpenedDocuments.docs.length > 0"
@ -214,7 +214,7 @@ import advancedSearchGuideDialog from "src/components/dialogs/AdvancedSearchGuid
import keybindCheatsheetDialog from "src/components/dialogs/KeybindCheatsheet.vue"
import { I_OpenedDocument } from "src/interfaces/I_OpenedDocument"
import { extend } from "quasar"
import { extend, Loading, QSpinnerGears } from "quasar"
import { saveDocument } from "src/scripts/databaseManager/documentManager"
import { retrieveCurrentProjectName, exportProject } from "src/scripts/projectManagement/projectManagent"
@ -257,17 +257,17 @@ export default class DocumentControl extends BaseClass {
}
// Delete dialog - CTRL + D
if (this.determineKeyBind("deleteDocument")) {
if (this.determineKeyBind("deleteDocument") && !this.currentlyNew && this.SGET_allOpenedDocuments.docs.length > 0) {
this.deleteObjectAssignUID()
}
// Edit document - CTRL + E
if (this.determineKeyBind("editDocument") && this.currentyEditable) {
if (this.determineKeyBind("editDocument") && this.currentyEditable && this.SGET_allOpenedDocuments.docs.length > 0) {
this.toggleEditMode()
}
// Save document
if (this.determineKeyBind("saveDocument") && !this.currentyEditable) {
// Save document - CTRL + S
if (this.determineKeyBind("saveDocument") && !this.currentyEditable && this.SGET_allOpenedDocuments.docs.length > 0) {
this.saveCurrentDocument().catch(e => console.log(e))
}
}
@ -342,11 +342,18 @@ export default class DocumentControl extends BaseClass {
/****************************************************************/
retrieveCurrentProjectName = retrieveCurrentProjectName
exportProject = exportProject
async commenceExport () {
const projectName = await retrieveCurrentProjectName()
this.exportProject(projectName)
const setup = {
message: "<h4>Exporting current project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
}
exportProject(projectName, Loading, setup, this.$q)
}
/****************************************************************/
@ -378,6 +385,10 @@ export default class DocumentControl extends BaseClass {
}
async saveCurrentDocument () {
if (document.activeElement) {
(document.activeElement as HTMLElement).blur()
}
const currentDoc = this.findRequestedOrActiveDocument()
const allDocuments = this.SGET_allOpenedDocuments
@ -408,12 +419,27 @@ export default class DocumentControl extends BaseClass {
onUrlChange () {
this.checkEditability()
this.checkNew()
this.checkHasEdits()
}
@Watch("SGET_allOpenedDocuments", { deep: true })
onDocChange () {
this.checkEditability()
this.checkNew()
this.checkHasEdits()
}
hasEdits = false
checkHasEdits () {
const currentDocument = this.findRequestedOrActiveDocument()
if (currentDocument && !currentDocument.hasEdits) {
this.hasEdits = true
}
else {
this.hasEdits = false
}
}
checkEditability () {

View file

@ -13,6 +13,17 @@
</q-input>
</q-page-sticky>
<h6 class="projectTitle text-cultured">
<span>
{{projectName}}
<q-tooltip
:delay="1000"
>
This is your currently opened project's name.
</q-tooltip>
</span>
</h6>
<q-tree
class="objectTree q-pa-sm"
:nodes="hierarchicalTree"
@ -20,15 +31,20 @@
no-connectors
ref="tree"
dark
:duration="200"
:filter="treeFilter"
:selected.sync="selectedTreeNode"
:expanded.sync="expandedTreeNodes"
no-nodes-label="Loading your project..."
no-results-label="Nothing matches your request"
>
<template v-slot:default-header="prop">
<div class="row items-center col-grow" @click.stop.prevent="processNodeClick(prop.node)">
<div class="row items-center col-grow"
@click.stop.prevent="processNodeClick(prop.node)"
@click.stop.prevent.middle="processNodeLabelMiddleClick(prop.node)"
>
<div class="documentLabel"
:style="`color: ${prop.node.color}`"
@click.stop.prevent.middle="processNodeLabelMiddleClick(prop.node)"
>
<q-icon
:style="`color: ${determineNodeColor(prop.node)}; width: 22px !important;`"
@ -43,9 +59,9 @@
<q-tooltip
:delay="1000"
>
Document count: <span class="text-bold text-gunmetal-bright">{{prop.node.documentCount}}</span>
Document count: <span class="text-bold text-satin-sheen-gold-dark">{{prop.node.documentCount}}</span>
<br>
Category count: <span class="text-bold text-gunmetal-bright">{{prop.node.categoryCount}}</span>
Category count: <span class="text-bold text-satin-sheen-gold-dark">{{prop.node.categoryCount}}</span>
</q-tooltip>
</span>
<q-badge
@ -139,13 +155,13 @@ import { Component, Watch } from "vue-property-decorator"
import BaseClass from "src/BaseClass"
import { I_OpenedDocument, I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
import { I_NewObjectTrigger } from "src/interfaces/I_NewObjectTrigger"
import PouchDB from "pouchdb"
import { engageBlueprints, retrieveAllBlueprints } from "src/scripts/databaseManager/blueprintManager"
// import { cleanDatabases } from "src/scripts/databaseManager/cleaner"
import { I_Blueprint } from "src/interfaces/I_Blueprint"
import { extend, colors } from "quasar"
import { tagListBuildFromBlueprints } from "src/scripts/utilities/tagListBuilder"
import { retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent"
@Component({
components: { }
@ -172,10 +188,14 @@ export default class ObjectTree extends BaseClass {
// GENERIC FUNCTIONALITY
/****************************************************************/
projectName = ""
/**
* Load all blueprints and build the tree out of them
*/
async created () {
this.projectName = await retrieveCurrentProjectName()
// await cleanDatabases()
await this.processBluePrints()
@ -218,12 +238,15 @@ export default class ObjectTree extends BaseClass {
// HIERARCHICAL TREE - HELPERS AND MODELS
/****************************************************************/
/**
* Since we are using the object tree as URLs intead of selecting, this resets the select every time a node is clicked
*/
@Watch("selectedTreeNode")
onNodeChange (val: I_NewObjectTrigger) {
if (val !== null) {
@Watch("$route", { deep: true })
async reactToRouteChange () {
// Wait for animations
await this.sleep(200)
if (this.SGET_allOpenedDocuments.docs.length > 0) {
const currentDoc = this.findRequestedOrActiveDocument() as unknown as I_OpenedDocument
this.selectedTreeNode = currentDoc._id
}
else {
this.selectedTreeNode = null
}
}
@ -261,7 +284,7 @@ export default class ObjectTree extends BaseClass {
/**
* A resetter for the currently selected node
*/
selectedTreeNode = null
selectedTreeNode = null as null | string
/**
* Holds all currently expanded notes
@ -600,8 +623,6 @@ export default class ObjectTree extends BaseClass {
isTag: boolean
specialLabel: string|boolean
}) {
this.selectedTreeNode = null
if (node.isRoot && node.isTag) {
return
}
@ -655,12 +676,25 @@ export default class ObjectTree extends BaseClass {
<style lang="scss">
.projectTitle {
margin: 0 0 -5px 0;
padding: 65px 10px 0;
}
.objectTree {
padding-top: 60px;
> .q-tree__node {
padding-left: 0 !important;
}
.q-tree__children {
padding-left: 5px;
}
.q-tree__arrow {
margin-right: 0;
padding: 4px 4px 4px 0;
position: absolute;
pointer-events: none;
}
.q-tree__node {
@ -669,13 +703,32 @@ export default class ObjectTree extends BaseClass {
.q-tree__node-header {
padding: 0;
&:focus {
> .q-focus-helper {
opacity: 0 !important;
}
}
&:hover {
> .q-focus-helper {
opacity: 0.15 !important;
}
}
&.q-tree__node--selected {
> .q-focus-helper {
opacity: 0.22 !important;
}
}
}
.documentLabel {
width: 100%;
display: flex;
justify-content: space-between;
padding: 4px 4px 4px 4px;
padding: 4px 4px 4px 25px;
align-items: center;
}
.treeButtonGroup {
@ -700,7 +753,7 @@ export default class ObjectTree extends BaseClass {
justify-content: center;
&.noChilden {
right: calc(100% + 23px);
right: calc(100% + 3px);
}
}

View file

@ -101,7 +101,7 @@
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="exportProject(projectName)"
@click="commenceExport"
:disable="!projectExists"
>
<q-item-section>Export current project</q-item-section>
@ -245,6 +245,8 @@ import aboutAppDialog from "src/components/dialogs/AboutApp.vue"
import changeLogDialog from "src/components/dialogs/ChangeLog.vue"
import advancedSearchGuideDialog from "src/components/dialogs/AdvancedSearchGuide.vue"
import { Loading, QSpinnerGears } from "quasar"
import { retrieveCurrentProjectName, exportProject } from "src/scripts/projectManagement/projectManagent"
import { toggleDevTools } from "src/scripts/utilities/devTools"
@ -264,7 +266,6 @@ export default class AppControl extends BaseClass {
toggleDevTools = toggleDevTools
retrieveCurrentProjectName = retrieveCurrentProjectName
exportProject = exportProject
projectExists: undefined | string | boolean = false
isFrontpage = true
isProjectPage = true
@ -274,6 +275,20 @@ export default class AppControl extends BaseClass {
this.checkProjectStatus().catch(e => console.log(e))
}
async commenceExport () {
const projectName = await retrieveCurrentProjectName()
const setup = {
message: "<h4>Exporting current project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
}
exportProject(projectName, Loading, setup, this.$q)
}
async checkProjectStatus () {
this.projectName = await retrieveCurrentProjectName()
this.projectExists = !!(await retrieveCurrentProjectName())

View file

@ -79,7 +79,7 @@ import closeDocumentCheckDialog from "src/components/dialogs/CloseDocumentCheck.
})
export default class TopTabs extends BaseClass {
@Watch("SGET_allOpenedDocuments", { deep: true })
reactToDocumentListChange (val: {docs: I_OpenedDocument[]}) {
reactToDocumentListChange (val: {docs: I_OpenedDocument[]}, oldVal: {docs: I_OpenedDocument[]}) {
this.localDocuments = []
this.localDocuments = val.docs

View file

@ -55,15 +55,13 @@ export default class CloseDocumentCheckDialog extends DialogBase {
this.dialogModel = true
}
else {
this.closeDocument(input).catch(e => console.log(e))
this.closeDocument(input)
}
}
async closeDocument (input: I_OpenedDocument) {
closeDocument (input: I_OpenedDocument) {
const dataPass = { doc: input, treeAction: false }
this.SSET_removeOpenedDocument(dataPass)
await this.$nextTick()
this.refreshRoute()
}
}
</script>

View file

@ -157,7 +157,6 @@ export default class ExistingDocumentDialog extends DialogBase {
this.filterDocuments()
await this.$nextTick()
await this.sleep(200)
if (this.$refs.ref_existingDocument) {
/*eslint-disable */

View file

@ -45,6 +45,7 @@ import { Component, Watch } from "vue-property-decorator"
import DialogBase from "src/components/dialogs/_DialogBase"
import { retrieveCurrentProjectName, exportProject, importExistingProject } from "src/scripts/projectManagement/projectManagent"
import { Loading, QSpinnerGears } from "quasar"
@Component({
components: { }
@ -73,12 +74,31 @@ export default class ImportProjectCheckDialog extends DialogBase {
}
importProject () {
importExistingProject(this.$router)
const setup = {
message: "<h4>Importing selected project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
}
importExistingProject(this.$router, Loading, setup, this.$q, this)
}
async commenceExport () {
const projectName = await retrieveCurrentProjectName()
exportProject(projectName)
const setup = {
message: "<h4>Exporting current project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
}
exportProject(projectName, Loading, setup, this.$q)
}
}
</script>

View file

@ -62,6 +62,8 @@ import { Component, Watch } from "vue-property-decorator"
import DialogBase from "src/components/dialogs/_DialogBase"
import { retrieveCurrentProjectName, exportProject, createNewProject } from "src/scripts/projectManagement/projectManagent"
import { Loading, QSpinnerGears } from "quasar"
@Component({
components: { }
})
@ -89,12 +91,31 @@ export default class ImportProjectCheckDialog extends DialogBase {
newProjectName = ""
createNewProject () {
createNewProject(this.newProjectName, this.$router).catch(e => console.log(e))
Loading.show({
message: "<h4>Setting up a new project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
})
createNewProject(this.newProjectName, this.$router, this.$q, this).catch(e => console.log(e))
}
async commenceExport () {
const projectName = await retrieveCurrentProjectName()
exportProject(projectName)
const setup = {
message: "<h4>Exporting current project...</h4>",
spinnerColor: "primary",
messageColor: "cultured",
spinnerSize: 120,
backgroundColor: "dark",
// @ts-ignore
spinner: QSpinnerGears
}
exportProject(projectName, Loading, setup, this.$q)
}
}
</script>

View file

@ -1,6 +1,6 @@
<template>
<div>
<h4 class="flex justify-start items-center text-weight-bolder q-mb-lg q-mt-xl">
<h4 class="flex justify-start items-center text-weight-bolder q-mb-xs q-mt-xl">
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
{{inputDataBluePrint.name}}
</h4>

View file

@ -18,7 +18,9 @@
<div class="colorIndicatorWrapper">
<div class="colorIndicator" :style="`background-color: ${localInput}`">
</div>
{{localInput}}
<span class="text-weight-medium">
{{localInput}}
</span>
</div>
</q-item-section>
@ -50,7 +52,7 @@
</q-input>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>

View file

@ -12,18 +12,24 @@
<q-list
v-if="!editMode"
class="fieldList_list"
dense>
<q-item v-for="(input,index) in localInput" :key="index">
<q-item-section side>
<q-icon name="mdi-menu-right" />
<q-item-section
class="fieldList_itemDot"
side>
<q-icon
color="primary"
name="mdi-menu-right"
/>
</q-item-section>
<q-item-section>
<span>
<span class="text-weight-medium">
{{input.value}}
<span v-if="localInput[index].affix" class="inline-block q-ml-xs text-italic">
</span>
<span v-if="localInput[index].affix" class="inline-block q-ml-xs text-italic">
({{localInput[index].affix}})
</span>
</span>
</q-item-section>
</q-item>
</q-list>
@ -58,6 +64,8 @@
:readonly="!editMode"
input-debounce="0"
new-value-mode="add"
@input="signalInput"
@keydown="signalInput"
:label="(inputAffix) ? inputAffix : ''"
v-model="localInput[index].affix"
/>
@ -80,7 +88,7 @@
</div>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -164,3 +172,24 @@ export default class Field_List extends BaseClass {
}
}
</script>
<style lang="scss">
.fieldList_list {
.q-item {
padding-right: 10px;
padding-left: 0;
}
.q-item__section {
position: relative;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.fieldList_itemDot {
padding-right: 10px;
}
}
</style>

View file

@ -9,13 +9,23 @@
</q-tooltip>
</q-icon>
<q-icon v-if="isOneWayRelationship" name="mdi-arrow-right-bold" size="16px" class="q-ml-md">
<q-tooltip :delay="500">
This is a one-way relationship. <br> Editing this value <span class="text-gunmetal-bright">will not</span> have effect on the connected document/s.
<q-tooltip :delay="500">
This is a one-way relationship. <br> Editing this value <span class="text-secondary">WILL NOT</span> have effect on the connected document/s.
<br>
<br>
Left-clicking the linked document in non-edit mode will open it in new tab and focuses on it.
<br>
Middle-clicking the linked document in non-edit mode will open it in new tab and not focus on it.
</q-tooltip>
</q-icon>
<q-icon v-if="!isOneWayRelationship" name="mdi-arrow-left-right-bold" size="16px" class="q-ml-md">
<q-tooltip :delay="500">
This is a two-way relationship. <br> Editing this value <span class="text-gunmetal-bright">will</span> also effect the connected document/s.
This is a two-way relationship. <br> Editing this value <span class="text-secondary">WILL</span> also effect the connected document/s.
<br>
<br>
Left-clicking the linked document in non-edit mode will open it in new tab and focuses on it.
<br>
Middle-clicking the linked document in non-edit mode will open it in new tab and not focus on it.
</q-tooltip>
</q-icon>
@ -30,12 +40,33 @@
:key="single._id"
clickable
class="text-primary"
@click="openExistingDocumentRoute(single)">
<q-item-section>
{{stripTags(single.label)}}
<span class="inline-block q-ml-xs text-italic connectionNote">
{{retrieveNoteText(single._id)}}
</span>
>
<q-item-section
@click.left="openExistingDocumentRoute(single)"
@click.middle="openNewTab(single)"
>
<span class="text-weight-medium">
{{stripTags(single.label)}}
</span>
<span class="inline-block q-ml-xs text-italic connectionNote">
{{retrieveNoteText(single._id)}}
</span>
<q-btn
tabindex="-1"
round
flat
dense
dark
color="primary"
icon="mdi-open-in-new"
size="12px"
class="relationshipOpeningButton"
@click.stop.prevent.left="openNewTab(single)"
>
<q-tooltip :delay="500">
Open in new tab without leaving this one
</q-tooltip>
</q-btn>
</q-item-section>
</q-item>
</q-list>
@ -131,7 +162,7 @@
</div>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -189,6 +220,19 @@ export default class Field_SingleRelationship extends BaseClass {
return this.inputDataBluePrint?.tooltip
}
async openNewTab (input: I_FieldRelationship) {
const CurrentObjectDB = new PouchDB(input.type)
const retrievedObject = await CurrentObjectDB.get(input._id)
const dataPass = {
doc: retrievedObject,
treeAction: false
}
// @ts-ignore
this.SSET_addOpenedDocument(dataPass)
}
extraInput: I_FieldRelationship[] = []
filteredInput: I_FieldRelationship[] = []
@ -266,7 +310,7 @@ export default class Field_SingleRelationship extends BaseClass {
const pairedFieldObject = objectDoc.extraFields.find(f => f.id === pairedField)
const pairingType = this.inputDataBluePrint.type
if (typeof pairedFieldObject?.value !== "string" && pairedFieldObject?.value !== null && pairingType === "manyToSingleRelationship") {
if (pairedFieldObject !== undefined && typeof pairedFieldObject?.value !== "string" && pairedFieldObject?.value !== null && pairingType === "manyToSingleRelationship") {
isDisabled = true
}
}
@ -352,10 +396,23 @@ table {
</style>
<style lang="scss">
.connectionList .q-item__section {
flex-direction: row;
justify-content: flex-start;
align-items: center;
.connectionList {
.q-item {
padding-right: 30px;
padding-left: 10px;
}
.q-item__section {
position: relative;
flex-direction: row;
justify-content: flex-start;
align-items: center;
.relationshipOpeningButton {
position: absolute;
right: -30px;
}
}
}
.connectionList .connectionNote {

View file

@ -12,13 +12,22 @@
<q-list
v-if="!editMode"
class="fieldMultiSelect_list"
dense>
<q-item v-for="(input,index) in localInput" :key="index">
<q-item-section side>
<q-icon name="mdi-menu-right" />
<q-item-section
class="fieldMultiSelect_itemDot"
side
>
<q-icon
color="primary"
name="mdi-menu-right"
/>
</q-item-section>
<q-item-section>
{{input}}
<span class="text-weight-medium">
{{input}}
</span>
</q-item-section>
</q-item>
</q-list>
@ -61,7 +70,7 @@
</q-select>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -151,3 +160,24 @@ export default class Field_MultiSelect extends BaseClass {
}
}
</script>
<style lang="scss">
.fieldMultiSelect_list {
.q-item {
padding-right: 10px;
padding-left: 0;
}
.q-item__section {
position: relative;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.fieldMultiSelect_itemDot {
padding-right: 10px;
}
}
</style>

View file

@ -12,10 +12,13 @@
<q-list
v-if="!editMode"
class="fieldNumber_list"
dense>
<q-item>
<q-item-section>
<span class="text-weight-medium">
{{localInput}}
</span>
</q-item-section>
</q-item>
</q-list>
@ -30,7 +33,7 @@
/>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -75,3 +78,11 @@ export default class Field_Number extends BaseClass {
}
}
</script>
<style lang='scss'>
.fieldNumber_list {
.q-item {
padding-right: 10px;
padding-left: 10px;
}
}
</style>

View file

@ -10,12 +10,22 @@
</q-icon>
<q-icon v-if="isOneWayRelationship" name="mdi-arrow-right-bold" size="16px" class="q-ml-md">
<q-tooltip :delay="500">
This is a one-way relationship. <br> Editing this value <span class="text-gunmetal-bright">will not</span> have effect on the connected document/s.
This is a one-way relationship. <br> Editing this value <span class="text-secondary">WILL NOT</span> have effect on the connected document/s.
<br>
<br>
Left-clicking the linked document in non-edit mode will open it in new tab and focuses on it.
<br>
Middle-clicking the linked document in non-edit mode will open it in new tab and not focus on it.
</q-tooltip>
</q-icon>
<q-icon v-if="!isOneWayRelationship" name="mdi-arrow-left-right-bold" size="16px" class="q-ml-md">
<q-tooltip :delay="500">
This is a two-way relationship. <br> Editing this value <span class="text-gunmetal-bright">will</span> also effect the connected document/s.
This is a two-way relationship. <br> Editing this value <span class="text-secondary">WILL</span> also effect the connected document/s.
<br>
<br>
Left-clicking the linked document in non-edit mode will open it in new tab and focuses on it.
<br>
Middle-clicking the linked document in non-edit mode will open it in new tab and not focus on it.
</q-tooltip>
</q-icon>
</div>
@ -27,12 +37,33 @@
<q-item
clickable
class="text-primary"
@click="openExistingDocumentRoute(localInput)">
<q-item-section>
>
<q-item-section
@click.left="openExistingDocumentRoute(localInput)"
@click.middle="openNewTab(localInput)"
>
<span class="text-weight-medium">
{{stripTags(localInput.label)}}
<span class="inline-block q-ml-xs text-italic connectionNote">
{{retrieveNoteText()}}
</span>
</span>
<span class="inline-block q-ml-xs text-italic connectionNote">
{{retrieveNoteText()}}
</span>
<q-btn
tabindex="-1"
round
flat
dense
dark
color="primary"
icon="mdi-open-in-new"
size="12px"
class="relationshipOpeningButton"
@click.stop.prevent.left="openNewTab(localInput)"
>
<q-tooltip :delay="500">
Open in new tab without leaving this one
</q-tooltip>
</q-btn>
</q-item-section>
</q-item>
</q-list>
@ -126,7 +157,7 @@
</div>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -244,6 +275,19 @@ export default class Field_SingleRelationship extends BaseClass {
return (this.inputDataBluePrint.type === "singleToNoneRelationship" || this.inputDataBluePrint.type === "manyToNoneRelationship")
}
async openNewTab (input: I_FieldRelationship) {
const CurrentObjectDB = new PouchDB(input.type)
const retrievedObject = await CurrentObjectDB.get(input._id)
const dataPass = {
doc: retrievedObject,
treeAction: false
}
// @ts-ignore
this.SSET_addOpenedDocument(dataPass)
}
async reloadObjectListAndCheckIfValueExists () {
if (this.inputDataBluePrint?.relationshipSettings && this.currentId.length > 0) {
const CurrentObjectDB = new PouchDB(this.inputDataBluePrint.relationshipSettings.connectedObjectType)
@ -260,9 +304,8 @@ export default class Field_SingleRelationship extends BaseClass {
if (pairedField.length > 0) {
const pairedFieldObject = objectDoc.extraFields.find(f => f.id === pairedField)
const pairingType = this.inputDataBluePrint.type
if (
(typeof pairedFieldObject?.value !== "string" && pairedFieldObject?.value !== null && pairingType === "singleToSingleRelationship") ||
(typeof pairedFieldObject?.value !== "string" && pairedFieldObject?.value !== null && pairingType === "singleToSingleRelationship")) {
if (pairedFieldObject !== undefined && typeof pairedFieldObject?.value !== "string" && pairedFieldObject?.value !== null && pairingType === "singleToSingleRelationship") {
isDisabled = true
}
}
@ -333,10 +376,23 @@ table {
</style>
<style lang="scss">
.connectionList .q-item__section {
flex-direction: row;
justify-content: flex-start;
align-items: center;
.connectionList {
.q-item {
padding-right: 30px;
padding-left: 10px;
}
.q-item__section {
position: relative;
flex-direction: row;
justify-content: flex-start;
align-items: center;
.relationshipOpeningButton {
position: absolute;
right: -30px;
}
}
}
.connectionList .connectionNote {

View file

@ -12,9 +12,10 @@
<q-list
v-if="!editMode"
class="fieldSingleSelect_list"
dense>
<q-item>
<q-item-section>
<q-item-section class="text-weight-medium">
{{localInput}}
</q-item-section>
</q-item>
@ -57,7 +58,7 @@
</q-select>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -143,3 +144,20 @@ export default class Field_SingleSelect extends BaseClass {
}
}
</script>
<style lang="scss">
.fieldSingleSelect_list {
.q-item {
padding-right: 10px;
padding-left: 10px;
}
.q-item__section {
position: relative;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
}
</style>

View file

@ -17,7 +17,7 @@
/>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>

View file

@ -57,7 +57,7 @@
</q-select>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>

View file

@ -12,10 +12,13 @@
<q-list
v-if="!editMode"
class="fieldText_list"
dense>
<q-item>
<q-item-section>
<span class="text-weight-medium">
{{localInput}}
</span>
</q-item-section>
</q-item>
</q-list>
@ -34,7 +37,7 @@
</q-input>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -102,3 +105,11 @@ export default class Field_Text extends BaseClass {
}
}
</script>
<style lang='scss'>
.fieldText_list {
.q-item {
padding-right: 10px;
padding-left: 10px;
}
}
</style>

View file

@ -10,7 +10,10 @@
</q-icon>
</div>
<div v-if="!editMode" v-html="localInput">
<div
v-if="!editMode"
class="fieldWysiwyg"
v-html="localInput">
</div>
<q-editor
@ -24,7 +27,7 @@
/>
<div class="separatorWrapper">
<q-separator color="grey q-mt-lg" />
<q-separator color="grey q-mt-md" />
</div>
</div>
@ -144,3 +147,10 @@ export default class Field_Wysiwyg extends BaseClass {
]
}
</script>
<style lang='scss'>
.fieldWysiwyg {
padding-right: 10px;
padding-left: 10px;
}
</style>

View file

@ -33,6 +33,7 @@ html {
body {
background-color: rgba($primary, 0.025);
overflow-y: scroll;
color: darken($dark, 12.5);
/* WebKit/Blink Browsers */
::selection {
@ -47,6 +48,20 @@ body {
}
}
.q-icon::after,
.q-icon::before {
backface-visibility: hidden;
}
.q-notification__message {
font-size: 16px;
font-weight: 500;
}
.q-loading::before {
opacity: 1 !important;
}
.q-drawer-container * {
user-select: none !important;
}
@ -136,6 +151,11 @@ body {
padding-top: 6px;
}
.q-editor.fullscreen {
top: 40px !important;
height: calc(100vh - 40px) !important;
}
body .q-item--active:not(.noHigh) {
color: inherit;

View file

@ -18,7 +18,7 @@ $accent : #dde4e4;
$dark : #18303a;
$positive : #21ba45;
$positive : #35a14e;
$negative : #c10015;
$info : #31ccec;
$warning : #f2c037;
@ -26,10 +26,11 @@ $warning : #f2c037;
$customColors: (
'gunmetal': #18303a,
'gunmetal-light': lighten(#18303a, 7.5),
'gunmetal-bright': lighten(#18303a, 30),
'gunmetal-bright': lighten(#18303a, 50),
'gunmetal-shine': lighten(#18303a, 60),
'ruby-red': #f72e43,
'satin-sheen-gold': #d7ac47,
'satin-sheen-gold-dark': darken(#d7ac47, 12.5),
'gainsboro': #dde4e4,
'cultured': #f5f5f5
);

View file

@ -5,21 +5,49 @@
## 0.1.3
### Known issues
- When creating a brand new project, Fantasia Archive sometimes doesn't load the default categories in the left hierarchical tree. A temporary workaround before the issue is fixed is restarting the program - the project stays intact, can be normally edited no data loss occurs.
### Bugfixes
- Fixed a MASSIVE two-way relationship bug that would have prevented a future integration of user-defined addition fields and document types
- Hopefully fixed a bug with keybinds not registering sometimes
- Added a missing row of connected "Sciences/Technologies" (connected, ally and enemy) to the "Sciences/Technologies" document type
- Added a missing row of connected "Religions/Teachings" (connected, ally and enemy) to the "Religions/Teachings" document type
- Added a missing row of connected "Magic/Spell" (connected, ally and enemy) to the "Magic/Spell" document type
- Fixed an occasional wrong click register on the document tree (opening document instead of expanding/collapsing)
- Fixed the "Name" field disappearing upon full deletion of text
- Fixed a bug with single/multi-select fields working unintuitively for adding new values (eg: Character personality traits field or Sex field)
- Fixed a tiny glitch when the hierarchical tree arrow was sometimes creating new documents instead of opening the category
- Fixed a bug of persisting opened tabs when creating new projects/importing existing project over already opened ones
- Added an auto-remover of no longer existing relationships filled in within single and multi relationship fields
- Fixed a typo with "Sciences/Technologies" missing the plural form
- Adjusted the naming of "Other/Notes" to "Lore notes/Other notes" to be functional with the new search engine (apologies for this one, a new solution might be implemented later)
- Adjusted the naming of "Myths/Legends" to "Myths/Legends/Stories" to cover a wider area of content
- Fixed a bug with a full-screen text editor overlapping the menu
- Fixed a bug where list-typed fields were properly saving temporary data when switching between tabs in the note fields
- Fixed broken padding of the document in "Chapters" and "Lore notes/Other notes"
- Fixed a broken field "Practitioners/Engineers" in the category "Sciences/Technologies"
- Fixed a typo in the "Connected Locations" field inside the "Magic/Spell" document type
- Fixed a visual glitch with icons sometimes "bouncing" or "flickering" when hovered over with the mouse
### New features
- Massive improvement to rendering and performance of the app by leveraging some of the workloads to the GPU from the CPU
- Added a safeguard dialog for new project creation in case an opened project exists
- Added a safeguard dialog for project importing in case an opened project exists
- Added automatic redirecting to the project screen upon importing an existing project or creating a new one (better transition effect will be added later)
- Added automatic redirecting to the project screen upon importing an existing project or creating a new one
- Added loading transition for longer action (export, import, and creating a new project)
- Added toast messaging informing the user of how the long actions went
- Added a project title above the hierarchical tree
- Added a new 2-way relationship field "Connected characters" for all kinds of groups (Political, Religious, Magical, and Technological) that connect with 4 new respect character fields.
- This change was done due to some characters having relationships with certain ground that didn't necessarily count as memberships, alliances, or hostilities.
- Added support for opening connected document in single and multi-relationships without focusing on the document itself and instead just open it in the tab list
- Added continuous closing of tabs via holding down CTRL + W
- Added an "Advanced search guide" dialog with a manual on how to use the advanced search
- Added a "Changelog" dialog - you might be reading it right now!
- Added an option of "Raw magical energy manipulation" to "General schools of magic" in "Magic/Spell" document type (for those of us who like our characters throwing half a city at each other anime-style!)
- Added "About Fantasia Archive" dialog showing current app version (more details will be added in the future)
- New control bar added for documents and project control along with a more intelligent button redesign
- A new logo added to the app (better visibility of the logo in small scales and icons)
@ -27,16 +55,26 @@
- 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
- Removed "Practitioners/Engineers" field from "Sciences/Technologies" document type as it was a duplicate of another one and was causing issues
- Added automatic opening of hierarchical tree branches upon adding/moving documents under/among them
- Added tags support
### QoL adjustments
- Adjusted animations through the app to make it feel a bit more responsive
- Lightly modified the app color-scheme to offer better readability of contrast
- Adjusted document display screen for easier legibility, quicker navigation, and fancy-schmancy look
- Changed icon for the button triggering quick-adding of new documents
- Reworked the way tab closing works - now mimicks the functionality of how web-browsers handle it
- Added syncing of opened tabs to the matching item in the hierarchical tree
- Changed "Character traits" field name to "Traits & Characteristics" in the "Character" document type
- Hierarchical tree looks optimized for more streamlined looks and better space-usage
- Changed the looks of tooltips, relationship fields, and selects to go well with the current app looks
- Adjusted tab-list width to allow for more content to show
- Improved scroll behavior in the keybind cheatsheet dialog (looks a little strange now, but will work better as more keybinds are added)
- Improved response time from the Quick-search popup upon opening
- Renamed "Notable practitioners/scientists" to "Technology/Science users" from "Sciences/Technologies" document type
- Added a highlight for the save document button in case the current document has edits
- Added a tooltip showing how many of the objects in the hierarchical tree are documents and how many are categories
- Hierarchical tree search bar is now attached on the top of the tree and no longer scrolls along with the rest of the content of the tree to allow better useability. The search now also expands to full app width on focus via user's interaction. The search icon was moved to the right and the field reset icon was moved to the left.
- Modified selected and activity indicators for already selected/active items in dropdown lists to not clash with the highlighting from the filter results

View file

@ -25,7 +25,7 @@
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
appear
:duration="300"
:duration="150"
>
<router-view :key="$route.path" />
</transition>

View file

@ -11,7 +11,7 @@
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
appear
:duration="300"
:duration="150"
>
<router-view :key="$route.path" />
</transition>

View file

@ -552,7 +552,7 @@ export default class PageDocumentDisplay extends BaseClass {
<style lang="scss" scoped>
.inputWrapper {
min-height: 105px;
min-height: 95px;
display: flex;
flex-direction: column;
justify-content: flex-start;

View file

@ -12,6 +12,7 @@
import { Component } from "vue-property-decorator"
import BaseClass from "src/BaseClass"
import { Loading } from "quasar"
import { retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent"
@ -23,6 +24,7 @@ export default class ProjectScreen extends BaseClass {
async created () {
this.projectName = await retrieveCurrentProjectName()
Loading.hide()
}
}
</script>

View file

@ -6,6 +6,12 @@ export const chaptersBlueprint: I_Blueprint = {
nameSingular: "Chapter",
icon: "mdi-file-outline",
extraFields: [
{
id: "breakBasic",
name: "Basic information",
type: "break",
sizing: 12
},
{
id: "name",
name: "Name",

View file

@ -274,7 +274,7 @@ export const charactersBlueprint: I_Blueprint = {
},
{
id: "personalityTraits",
name: "Personality traits",
name: "Traits & Characteristics",
type: "multiSelect",
icon: "mdi-head-cog",
sizing: 6,
@ -1059,12 +1059,23 @@ export const charactersBlueprint: I_Blueprint = {
type: "break",
sizing: 12
},
{
id: "pairedConnectionPolGroup",
name: "Connected to political groups/ideologies",
type: "manyToManyRelationship",
icon: "mdi-bank-outline",
sizing: 6,
relationshipSettings: {
connectedObjectType: "politicalGroups",
connectedField: "pairedConnectionCharacter"
}
},
{
id: "pairedBelongingPolGroup",
name: "Member of political groups/ideologies",
type: "manyToManyRelationship",
icon: "mdi-bank-outline",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "politicalGroups",
connectedField: "pairedBelongingCharacter"
@ -1075,7 +1086,7 @@ export const charactersBlueprint: I_Blueprint = {
name: "Ally of political groups/ideologies",
type: "manyToManyRelationship",
icon: "mdi-bank-outline",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "politicalGroups",
connectedField: "pairedAllyCharacter"
@ -1086,18 +1097,29 @@ export const charactersBlueprint: I_Blueprint = {
name: "Enemy of political groups/ideologies",
type: "manyToManyRelationship",
icon: "mdi-bank-outline",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "politicalGroups",
connectedField: "pairedEnemyCharacter"
}
},
{
id: "pairedConnectionRelGroup",
name: "Connected to religious groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 6,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedConnectionCharacter"
}
},
{
id: "pairedBelongingRelGroup",
name: "Member of religious groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedBelongingCharacter"
@ -1108,7 +1130,7 @@ export const charactersBlueprint: I_Blueprint = {
name: "Ally of religious groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedAllyCharacter"
@ -1119,18 +1141,29 @@ export const charactersBlueprint: I_Blueprint = {
name: "Enemy of religious groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedEnemyCharacter"
}
},
{
id: "pairedConnectionMagicGroup",
name: "Connected to magical groups",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 6,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedConnectionCharacter"
}
},
{
id: "pairedBelongingMagicGroup",
name: "Member of magical groups",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedBelongingCharacter"
@ -1141,7 +1174,7 @@ export const charactersBlueprint: I_Blueprint = {
name: "Ally of magical groups",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedAllyCharacter"
@ -1152,18 +1185,29 @@ export const charactersBlueprint: I_Blueprint = {
name: "Enemy of magical groups",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedEnemyCharacter"
}
},
{
id: "pairedConnectionTechGroup",
name: "Connected to scientifical/technological groups",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 6,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedConnectionCharacter"
}
},
{
id: "pairedBelongingTechGroup",
name: "Member of scientifical/technological groups",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedBelongingCharacter"
@ -1174,7 +1218,7 @@ export const charactersBlueprint: I_Blueprint = {
name: "Ally of scientifical/technological groups",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedAllyCharacter"
@ -1185,7 +1229,7 @@ export const charactersBlueprint: I_Blueprint = {
name: "Enemy of scientifical/technological groups",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedEnemyCharacter"
@ -1221,7 +1265,7 @@ export const charactersBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 6,

View file

@ -348,7 +348,7 @@ export const locationsBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 4,

View file

@ -6,6 +6,12 @@ export const loreNotesBlueprint: I_Blueprint = {
nameSingular: "Lore notes/Other note",
icon: "mdi-script-text-outline",
extraFields: [
{
id: "breakBasic",
name: "Basic information",
type: "break",
sizing: 12
},
{
id: "name",
name: "Name",

View file

@ -97,7 +97,7 @@ export const magicBlueprint: I_Blueprint = {
},
{
id: "users",
name: "Magic users amount",
name: "Member/user amount",
type: "text",
icon: "mdi-account-group",
sizing: 2
@ -121,6 +121,7 @@ export const magicBlueprint: I_Blueprint = {
predefinedSelectValues: [
"Magical institution",
"Magical teaching",
"Magical technique",
"Ritual",
"School of magic",
"Spell",
@ -143,6 +144,7 @@ export const magicBlueprint: I_Blueprint = {
"Necromancy",
"Transmutation",
"World alteration",
"Raw magical energy manipulation",
"Other"
]
},
@ -152,6 +154,11 @@ export const magicBlueprint: I_Blueprint = {
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
tooltip:
`This field is meant to be used as a way to map out spell-users and their respected spells.
<br>
For diplomatic/ideological connections between magical groups/institutions and characters, use the field below in the "Diplomatic relationships & Influences" section.
`,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedMagic"
@ -159,10 +166,15 @@ export const magicBlueprint: I_Blueprint = {
},
{
id: "pairedSpells",
name: "Connected Spells/Rituals/Institutions",
name: "Connected Spells/Rituals",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
tooltip:
`This field is meant to be used as a way to map out connection between different spells/rituals to each other.
<br>
For diplomatic/ideological connections between magical groups/institutions, use the field below in the "Diplomatic relationships & Influences" section.
`,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedSpells"
@ -170,7 +182,7 @@ export const magicBlueprint: I_Blueprint = {
},
{
id: "pairedItems",
name: "Useable through the use of items/artifacts",
name: "Usable through the use of items/artifacts",
type: "manyToManyRelationship",
icon: "mdi-sword-cross",
sizing: 4,
@ -192,7 +204,7 @@ export const magicBlueprint: I_Blueprint = {
},
{
id: "localLanguages",
name: "Common languages",
name: "Common languages among the practitioners",
type: "manyToManyRelationship",
icon: "mdi-book-alphabet",
sizing: 6,
@ -232,7 +244,7 @@ export const magicBlueprint: I_Blueprint = {
},
{
id: "connectedLocations",
name: "Conected locations",
name: "Connected locations",
type: "manyToManyRelationship",
icon: "mdi-map-marker-radius",
sizing: 6,
@ -241,12 +253,23 @@ export const magicBlueprint: I_Blueprint = {
connectedField: "connectedMagical"
}
},
{
id: "pairedConnectionCharacter",
name: "Connected characters",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedConnectionMagicGroup"
}
},
{
id: "pairedBelongingCharacter",
name: "Prominent members",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedBelongingMagicGroup"
@ -257,7 +280,7 @@ export const magicBlueprint: I_Blueprint = {
name: "Prominent allies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedAllyMagicGroup"
@ -268,7 +291,7 @@ export const magicBlueprint: I_Blueprint = {
name: "Prominent enemies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedEnemyMagicGroup"
@ -340,6 +363,40 @@ export const magicBlueprint: I_Blueprint = {
connectedField: "pairedEnemyMagicGroups"
}
},
{
id: "pairedConnectedMagicalGroups",
name: "Connected magical groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedConnectedMagicalGroups"
}
},
{
id: "pairedAllyMagicalGroups",
name: "Allied magical groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedAllyMagicalGroups"
}
},
{
id: "pairedEnemyMagicalGroups",
name: "Enemy magical groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-hat-wizard",
sizing: 4,
relationshipSettings: {
connectedObjectType: "magic",
connectedField: "pairedEnemyMagicalGroups"
}
},
{
id: "pairedConnectedTechGroups",
name: "Connected scientifical/technological groups/teachings",
@ -392,7 +449,7 @@ export const magicBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 4,

View file

@ -2,8 +2,8 @@ import { I_Blueprint } from "../../../interfaces/I_Blueprint"
export const mythsBlueprint: I_Blueprint = {
_id: "myths",
order: 7,
namePlural: "Myths/Legends",
nameSingular: "Myth/Legend",
namePlural: "Myths/Legends/Stories",
nameSingular: "Myth/Legend/Story",
icon: "fas fa-journal-whills",
extraFields: [
{

View file

@ -216,12 +216,23 @@ export const politicalGroupsBlueprint: I_Blueprint = {
connectedField: "connectedPolitical"
}
},
{
id: "pairedConnectionCharacter",
name: "Connected characters",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedConnectionPolGroup"
}
},
{
id: "pairedBelongingCharacter",
name: "Prominent members",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedBelongingPolGroup"
@ -232,7 +243,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
name: "Prominent allies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedAllyPolGroup"
@ -243,7 +254,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
name: "Prominent enemies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedEnemyPolGroup"
@ -315,7 +326,6 @@ export const politicalGroupsBlueprint: I_Blueprint = {
connectedField: "pairedEnemyPolGroups"
}
},
{
id: "pairedConnectedMagicalGroups",
name: "Connected magical groups/teachings",
@ -402,7 +412,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 4,

View file

@ -420,7 +420,7 @@ export const racesBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 4,

View file

@ -209,12 +209,23 @@ export const religionsBlueprint: I_Blueprint = {
connectedField: "connectedReligious"
}
},
{
id: "pairedConnectionCharacter",
name: "Connected characters",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedConnectionRelGroup"
}
},
{
id: "pairedBelongingCharacter",
name: "Prominent members",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedBelongingRelGroup"
@ -225,7 +236,7 @@ export const religionsBlueprint: I_Blueprint = {
name: "Prominent allies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedAllyRelGroup"
@ -236,7 +247,7 @@ export const religionsBlueprint: I_Blueprint = {
name: "Prominent enemies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedEnemyRelGroup"
@ -275,7 +286,39 @@ export const religionsBlueprint: I_Blueprint = {
connectedField: "pairedEnemyReligiousGroups"
}
},
{
id: "pairedConnectedReligiousGroups",
name: "Connected religious groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 4,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedConnectedReligiousGroups"
}
},
{
id: "pairedAllyReligoiusGroups",
name: "Allied religious groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 4,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedAllyReligoiusGroups"
}
},
{
id: "pairedEnemyReligiousGroups",
name: "Enemy religious groups/teaching",
type: "manyToManyRelationship",
icon: "fas fa-ankh",
sizing: 4,
relationshipSettings: {
connectedObjectType: "religions",
connectedField: "pairedEnemyReligiousGroups"
}
},
{
id: "pairedConnectedMagicGroups",
name: "Connected magical groups/ideologies",
@ -361,7 +404,7 @@ export const religionsBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 4,

View file

@ -90,18 +90,11 @@ export const techBlueprint: I_Blueprint = {
name: "Headquarters",
type: "singleToNoneRelationship",
icon: "mdi-map-marker-radius",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "locations"
}
},
{
id: "users",
name: "Practitioners/Engineers",
type: "text",
icon: "mdi-account-group",
sizing: 2
},
{
id: "leaders",
name: "Leading figures",
@ -161,7 +154,7 @@ export const techBlueprint: I_Blueprint = {
},
{
id: "pairedCharacter",
name: "Noteable practitioners/scientists",
name: "Technogy/Science users",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 6,
@ -244,12 +237,23 @@ export const techBlueprint: I_Blueprint = {
connectedField: "connectedTech"
}
},
{
id: "pairedConnectionCharacter",
name: "Connected characters",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedConnectionTechGroup"
}
},
{
id: "pairedBelongingCharacter",
name: "Prominent members",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedBelongingTechGroup"
@ -260,7 +264,7 @@ export const techBlueprint: I_Blueprint = {
name: "Prominent allies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedAllyTechGroup"
@ -271,7 +275,7 @@ export const techBlueprint: I_Blueprint = {
name: "Prominent enemies",
type: "manyToManyRelationship",
icon: "mdi-account",
sizing: 4,
sizing: 6,
relationshipSettings: {
connectedObjectType: "characters",
connectedField: "pairedEnemyTechGroup"
@ -377,6 +381,39 @@ export const techBlueprint: I_Blueprint = {
connectedField: "pairedEnemyTechGroups"
}
},
{
id: "pairedConnectedTechGroups",
name: "Connected scientifical/technological groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 4,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedConnectedTechGroups"
}
},
{
id: "pairedAllyTechGroups",
name: "Allied scientifical/technological groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 4,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedAllyTechGroups"
}
},
{
id: "pairedEnemyTechGroups",
name: "Enemy scientifical/technological groups/teachings",
type: "manyToManyRelationship",
icon: "fas fa-wrench",
sizing: 4,
relationshipSettings: {
connectedObjectType: "tech",
connectedField: "pairedEnemyTechGroups"
}
},
{
id: "breakOther",
name: "Other details",
@ -396,7 +433,7 @@ export const techBlueprint: I_Blueprint = {
},
{
id: "pairedConnectedMyths",
name: "Connected to myths and legends",
name: "Connected to myths. legends and stories",
type: "manyToManyRelationship",
icon: "fas fa-journal-whills",
sizing: 4,

View file

@ -101,3 +101,30 @@ export const saveDocument = async (document: I_OpenedDocument, allOpenedDocument
return { documentCopy, allOpenedDocuments }
}
export const addFieldToDocument = async (targetDocumentID: string, fieldID: string, blueprintID: string) => {
const BlueprintsDB = new PouchDB("blueprints")
const currentBlueprint: {extraFields: I_ExtraFields[], _id: string} = await BlueprintsDB.get(blueprintID)
// @ts-ignore
// const fieldBluePrint: I_ExtraFields = currentBlueprint.extraFields.find(e => e.id === fieldID)
const TargetObjectTypDB = new PouchDB(currentBlueprint._id)
const targetDocument: { extraFields: any[]} = await TargetObjectTypDB.get(targetDocumentID)
const newField = {
id: fieldID,
value: ""
}
// singleToNoneRelationship
// singleToManyRelationship
// singleToSingleRelationship
// manyToNoneRelationship
// manyToSingleRelationship
// manyToManyRelationship
targetDocument.extraFields.push(newField)
await TargetObjectTypDB.put(targetDocument)
}

View file

@ -1,3 +1,4 @@
import { addFieldToDocument } from "./documentManager"
import PouchDB from "pouchdb"
import { I_Blueprint } from "src/interfaces/I_Blueprint"
import { I_FieldRelationship } from "src/interfaces/I_FieldRelationship"
@ -63,9 +64,19 @@ export const single_addRelationShipToAnotherObject = async (
const idToFind = currentValue._id
const PairedObjectDB = new PouchDB(typeToFind)
const pairedDocument = await PairedObjectDB.get(idToFind) as I_OpenedDocument
let pairedDocument = await PairedObjectDB.get(idToFind) as I_OpenedDocument
const pairedField = currentValue.pairedField
const pairedFieldIndex = pairedDocument.extraFields.findIndex(e => e.id === pairedField)
let pairedFieldIndex = pairedDocument.extraFields.findIndex(e => e.id === pairedField)
let targetPairedField = pairedDocument.extraFields[pairedFieldIndex]
// Fix non-existant fields
if (!targetPairedField) {
await addFieldToDocument(pairedDocument._id, pairedField, typeToFind)
pairedDocument = await PairedObjectDB.get(idToFind) as I_OpenedDocument
pairedFieldIndex = pairedDocument.extraFields.findIndex(e => e.id === pairedField)
targetPairedField = pairedDocument.extraFields[pairedFieldIndex]
}
if (!pairedDocument.extraFields[pairedFieldIndex].value) {
pairedDocument.extraFields[pairedFieldIndex].value = { value: "", addedValues: "" }
@ -157,11 +168,21 @@ export const many_addRelationShipToAnotherObject = async (
const idToFind = currentValue._id
const PairedObjectDB = new PouchDB(typeToFind)
const pairedDocument = await PairedObjectDB.get(idToFind) as I_OpenedDocument
let pairedDocument = await PairedObjectDB.get(idToFind) as I_OpenedDocument
const pairedField = currentValue.pairedField
const pairedFieldIndex = pairedDocument.extraFields.findIndex(e => e.id === pairedField)
let pairedFieldIndex = pairedDocument.extraFields.findIndex(e => e.id === pairedField)
let pairedFieldValue: I_FieldRelationship[] = pairedDocument.extraFields[pairedFieldIndex].value.value
let targetPairedField = pairedDocument.extraFields[pairedFieldIndex]
// Fix non-existant fields
if (!targetPairedField) {
await addFieldToDocument(pairedDocument._id, pairedField, typeToFind)
pairedDocument = await PairedObjectDB.get(idToFind) as I_OpenedDocument
pairedFieldIndex = pairedDocument.extraFields.findIndex(e => e.id === pairedField)
targetPairedField = pairedDocument.extraFields[pairedFieldIndex]
}
let pairedFieldValue: I_FieldRelationship[] = targetPairedField.value.value
const newValue = {
_id: currentDocument._id,

View file

@ -12,7 +12,7 @@ import path from "path"
* @param projectName The name of the new project
* @praram vueRouter The vue router object
*/
export const createNewProject = async (projectName: string, vueRouter: any) => {
export const createNewProject = async (projectName: string, vueRouter: any, quasar: any, vueInstance: any) => {
await removeCurrentProject()
const ProjectDB = new PouchDB("project-data")
@ -41,6 +41,12 @@ export const createNewProject = async (projectName: string, vueRouter: any) => {
}
console.log(e)
})
quasar.notify({
type: 'positive',
message: `New project succesfully created`
})
vueInstance.SSET_resetDocuments()
/* eslint-enable */
}
@ -48,13 +54,19 @@ export const createNewProject = async (projectName: string, vueRouter: any) => {
* Open an file dialog asking the use for location where to export the project
* @param projectName The name of the project to export
*/
export const exportProject = (projectName: string) => {
export const exportProject = (projectName: string, Loading: any, loadingSetup: any, quasar: any) => {
remote.dialog.showOpenDialog({
properties: ["openDirectory"]
}).then(async (result) => {
/*eslint-disable */
const folderPath = result.filePaths[0]
if (!folderPath) {
return
}
Loading.show(loadingSetup)
PouchDB.plugin(replicationStream.plugin)
// @ts-ignore
PouchDB.adapter("writableStream", replicationStream.adapters.writableStream)
@ -77,6 +89,12 @@ export const exportProject = (projectName: string) => {
// @ts-ignore
await CurrentDB.dump(ws)
}
Loading.hide()
quasar.notify({
type: 'positive',
message: `Project succesfully exported`
})
/* eslint-enable */
}).catch(err => {
console.log(err)
@ -106,7 +124,7 @@ export const removeCurrentProject = async () => {
* Opens a dialog to let user pick whatever project they wish to open and lets them select a directory
* @param vueRouter The vue router object
*/
export const importExistingProject = (vueRouter: any) => {
export const importExistingProject = (vueRouter: any, Loading: any, loadingSetup: any, quasar: any, vueInstance: any) => {
/*eslint-disable */
remote.dialog.showOpenDialog({
properties: ["openDirectory"]
@ -117,6 +135,8 @@ export const importExistingProject = (vueRouter: any) => {
return
}
Loading.show(loadingSetup)
await removeCurrentProject()
// @ts-ignore
@ -157,6 +177,13 @@ export const importExistingProject = (vueRouter: any) => {
}
console.log(e)
})
quasar.notify({
type: 'positive',
message: `Project succesfully imported`
})
vueInstance.SSET_resetDocuments()
/* eslint-enable */
}).catch(err => {
console.log(err)

View file

@ -42,6 +42,10 @@ const actions: ActionTree<OpenDocumentsStateInterface, StateInterface> = {
setTimeout(() => {
state.commit("resetTreeAction")
}, 200)
},
resetRemoveIndex (state) {
state.commit("resetRemoveIndex")
}
}

View file

@ -36,9 +36,13 @@ const mutation: MutationTree<OpenDocumentsStateInterface> = {
const toRemoveIndex = state.documents.docs.findIndex(doc => doc.type === input.doc.type && doc._id === input.doc._id)
state.documents.docs.splice(toRemoveIndex, 1)
state.documents.treeAction = input.treeAction
state.documents.lastRemovedIndex = toRemoveIndex
state.documents.timestamp = uid()
},
resetRemoveIndex (state: OpenDocumentsStateInterface) {
state.documents.lastRemovedIndex = -1
},
resetTreeAction (state: OpenDocumentsStateInterface) {
state.documents.treeAction = false
},

View file

@ -7,6 +7,7 @@ export interface OpenDocumentsStateInterface {
export interface InnerOpenDocumentsStateInterface {
timestamp: string,
treeAction: boolean,
lastRemovedIndex: number
docs: I_OpenedDocument[]
}
@ -15,6 +16,7 @@ function state (): OpenDocumentsStateInterface {
documents: {
timestamp: "",
treeAction: false,
lastRemovedIndex: -1,
docs: []
}
}

View file

@ -1,22 +1,60 @@
- !!!FIX 2-WAY BUG!!!
- Add "Related notes"
- Add "Predecessors", "Successors", "Date of start", "Date of end" and "How long it lasted" fields to locations and all other groups
- Add "Ctrl + F" finding in the document (fields/data)
- Fix filtering via the document type in advanced search
- Add advanced search capabilities to the hierarchical tree
- Add "is dead" or some similar switch to documents and show strike-through/etc on items in lists, tombstone icon or overlay crossed out icon
- Custom icons/images to documents
- Add colored backgrounds to documents (along with already existing colored texts)
- Add filtering by color and BG color (weird, but could work)
- "Save all" keybind and "Save all and exit" option on the exiting
- Add intelligent responsive design to the left tree and document body (maybe button to pull the left bar in and out?)
### Document & Project setting
- Pinned tabs (save through program closing)
- Dark mode
- Add "Open all search matches" button in the Quick-search that opens a new page with a list of items
- Custom order document types
- Option: Retain opened tabs and their edited contents through sessions
- Option: Dark Mode
- Option: Show tags in the tree
- Option: Periodical backup (how many, how often, include files or not)
- Option: Disable tooltips in the document body
- Option: Single tab option coupled with pinned tabs
- Option: Sorting order via custom order number in the hiearachical tree
- Option: Wider sidebar
- Option: Show document as tabs or as one long documents
- Option: Dont close Quick-search after opening a search result
- Option: Also collapse subcategories
- Option: Disable project name in the tree
- Option: Close Quick-search and Quick-add dialogs with second keypress of the keybind instead of escape
- Option: Disable tags showing in the sidebar
- Option: Hide top navbar and move the document buttons back in the document body (top)
- Tag management (coloring)
- Simple data imports (maybe?)
- Dynamic table field
- Add on-the-fly generation of non-existent 2-way relationships
- Automatic thumnail generation AND re-checking based on date
- Option: Custom background for project
- Check fonts offered in the WYSIWYG and add new
- Add subtabs (character stats, general info, etc)
- Add colored backgrounds to documents (along with already existingt colored texts)
- Custom icons/images to documents
- Add option to make the command buttons for document sticky (save/delete/edit)
- Allow/Disallow default document types
- Dark mode
- Drag/drop tree list
- Calendar field
- Custom order document types
- Auto-export (save) at X time cycle with X saves iterations
- Add tags field & search functionality from it
- Disable tabs option
- Add detailed family relationship fields to characters
- Global text find/replace
- Mass document editing (not sure about this one...)
- Detailed language editor support
- Calendar field
- Add detailed family relationship fields to characters
- Allow/Disallow default document types
- Timeline/Calendar support
- AFMG support
- Add printing support