mirror of
https://github.com/Elvanos/fantasia-archive.git
synced 2024-09-28 15:21:45 +12:00
0.1.4 RC
This commit is contained in:
parent
bf4b787a6d
commit
b01246f78d
63 changed files with 3080 additions and 382 deletions
|
@ -215,7 +215,10 @@ module.exports = configure(function (ctx) {
|
|||
builder: {
|
||||
// https://www.electron.build/configuration/configuration
|
||||
|
||||
appId: "fantasiaarchive"
|
||||
appId: "fantasiaarchive",
|
||||
win: {
|
||||
icon: 'src-electron/icons/icon.ico'
|
||||
}
|
||||
},
|
||||
|
||||
// More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
|
||||
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 46 KiB |
Binary file not shown.
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 44 KiB |
47
src/App.vue
47
src/App.vue
|
@ -7,9 +7,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import BaseClass from "src/BaseClass"
|
||||
import { Component } from "vue-property-decorator"
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
import { defaultKeybinds } from "src/scripts/appSettings/defaultKeybinds"
|
||||
import appWindowButtons from "src/components/appHeader/AppWindowButtons.vue"
|
||||
import PouchDB from "pouchdb"
|
||||
import { OptionsStateInteface } from "./store/module-options/state"
|
||||
import { colors } from "quasar"
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
|
@ -27,7 +30,7 @@ export default class App extends BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
this.registerDefaultKeybinds()
|
||||
this.loadSettings().catch(e => console.log(e))
|
||||
window.addEventListener("keydown", this.triggerKeyPush)
|
||||
}
|
||||
|
||||
|
@ -44,7 +47,7 @@ export default class App extends BaseClass {
|
|||
altKey: e.altKey,
|
||||
ctrlKey: e.ctrlKey,
|
||||
shiftKey: e.shiftKey,
|
||||
keyCode: e.keyCode
|
||||
which: e.which
|
||||
}
|
||||
|
||||
this.SSET_updatePressedKey(ouputKeycombo)
|
||||
|
@ -54,6 +57,7 @@ export default class App extends BaseClass {
|
|||
destroyed () {
|
||||
window.removeEventListener("auxclick", this.reactToMiddleClick)
|
||||
|
||||
this.deregisterCustomKeybinds()
|
||||
this.deregisterDefaultKeybinds()
|
||||
window.removeEventListener("keydown", this.triggerKeyPush)
|
||||
}
|
||||
|
@ -71,5 +75,42 @@ export default class App extends BaseClass {
|
|||
deregisterDefaultKeybinds () {
|
||||
defaultKeybinds.forEach(e => this.SSET_deregisterDefaultKeybind(e))
|
||||
}
|
||||
|
||||
registerCustomKeybinds () {
|
||||
setTimeout(() => {
|
||||
this.SGET_options.userKeybindList.forEach(e => this.SSET_registerUserKeybind(e))
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
deregisterCustomKeybinds () {
|
||||
defaultKeybinds.forEach(e => this.SSET_deregisterUserKeybind(e))
|
||||
}
|
||||
|
||||
async loadSettings () {
|
||||
const SettingsDB = new PouchDB("fa-settings")
|
||||
const settingsData = await SettingsDB.allDocs({ include_docs: true })
|
||||
const settings = settingsData?.rows[0]?.doc as unknown as OptionsStateInteface
|
||||
|
||||
if (settings) {
|
||||
this.SSET_options(settings)
|
||||
}
|
||||
|
||||
this.registerDefaultKeybinds()
|
||||
this.registerCustomKeybinds()
|
||||
}
|
||||
|
||||
@Watch("SGET_options", { deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.$q.dark.set(options.darkMode)
|
||||
if (options.darkMode) {
|
||||
colors.setBrand("dark", "#1b333e")
|
||||
colors.setBrand("primary", "#ffd673")
|
||||
}
|
||||
else {
|
||||
colors.setBrand("dark", "#18303a")
|
||||
colors.setBrand("primary", "#d7ac47")
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
147
src/BaseClass.ts
147
src/BaseClass.ts
|
@ -1,3 +1,4 @@
|
|||
import { OptionsStateInteface } from "./store/module-options/state"
|
||||
import { KeyManagementInterface } from "./store/module-keybinds/state"
|
||||
import { I_OpenedDocument, I_ShortenedDocument } from "./interfaces/I_OpenedDocument"
|
||||
import { Component, Vue } from "vue-property-decorator"
|
||||
|
@ -7,10 +8,13 @@ import { I_NewObjectTrigger } from "src/interfaces/I_NewObjectTrigger"
|
|||
import { uid, colors } from "quasar"
|
||||
import { I_FieldRelationship } from "src/interfaces/I_FieldRelationship"
|
||||
import { I_KeyPressObject } from "src/interfaces/I_KeypressObject"
|
||||
import PouchDB from "pouchdb"
|
||||
|
||||
const Blueprints = namespace("blueprintsModule")
|
||||
const OpenedDocuments = namespace("openedDocumentsModule")
|
||||
const Keybinds = namespace("keybindsModule")
|
||||
const Options = namespace("optionsModule")
|
||||
const Dialogs = namespace("dialogsModule")
|
||||
|
||||
@Component
|
||||
export default class BaseClass extends Vue {
|
||||
|
@ -37,6 +41,10 @@ export default class BaseClass extends Vue {
|
|||
retrieveKeybindString (keybind: I_KeyPressObject): string {
|
||||
let keybindString = ""
|
||||
|
||||
if (!keybind) {
|
||||
return keybindString
|
||||
}
|
||||
|
||||
if (keybind.ctrlKey) {
|
||||
keybindString += "CTRL + "
|
||||
}
|
||||
|
@ -49,33 +57,102 @@ export default class BaseClass extends Vue {
|
|||
keybindString += "SHIFT + "
|
||||
}
|
||||
|
||||
const keybinds = [37, 38, 39, 40, 9, 32, 13]
|
||||
const keybinds = [37, 38, 39, 40, 9, 32, 13, 192, 189, 187, 219, 221, 220, 186, 222, 188, 190, 191, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123]
|
||||
|
||||
if (keybinds.includes(keybind.keyCode)) {
|
||||
if (keybind.keyCode === 13) {
|
||||
if (keybinds.includes(keybind.which)) {
|
||||
if (keybind.which === 13) {
|
||||
keybindString += "ENTER"
|
||||
}
|
||||
if (keybind.keyCode === 9) {
|
||||
if (keybind.which === 9) {
|
||||
keybindString += "TAB"
|
||||
}
|
||||
if (keybind.keyCode === 32) {
|
||||
if (keybind.which === 32) {
|
||||
keybindString += "SPACE"
|
||||
}
|
||||
if (keybind.keyCode === 37) {
|
||||
if (keybind.which === 37) {
|
||||
keybindString += "LEFT ARROW"
|
||||
}
|
||||
if (keybind.keyCode === 38) {
|
||||
if (keybind.which === 38) {
|
||||
keybindString += "UP ARROW"
|
||||
}
|
||||
if (keybind.keyCode === 39) {
|
||||
if (keybind.which === 39) {
|
||||
keybindString += "RIGHT ARROW"
|
||||
}
|
||||
if (keybind.keyCode === 40) {
|
||||
if (keybind.which === 40) {
|
||||
keybindString += "DOWN ARROW"
|
||||
}
|
||||
if (keybind.which === 192) {
|
||||
keybindString += "`"
|
||||
}
|
||||
if (keybind.which === 189) {
|
||||
keybindString += "-"
|
||||
}
|
||||
if (keybind.which === 187) {
|
||||
keybindString += "+"
|
||||
}
|
||||
if (keybind.which === 219) {
|
||||
keybindString += "["
|
||||
}
|
||||
if (keybind.which === 221) {
|
||||
keybindString += "]"
|
||||
}
|
||||
if (keybind.which === 220) {
|
||||
keybindString += "\\"
|
||||
}
|
||||
if (keybind.which === 186) {
|
||||
keybindString += ";"
|
||||
}
|
||||
if (keybind.which === 222) {
|
||||
keybindString += "'"
|
||||
}
|
||||
if (keybind.which === 188) {
|
||||
keybindString += ","
|
||||
}
|
||||
if (keybind.which === 190) {
|
||||
keybindString += "."
|
||||
}
|
||||
if (keybind.which === 191) {
|
||||
keybindString += "/"
|
||||
}
|
||||
if (keybind.which === 112) {
|
||||
keybindString += "F1"
|
||||
}
|
||||
if (keybind.which === 113) {
|
||||
keybindString += "F2"
|
||||
}
|
||||
if (keybind.which === 114) {
|
||||
keybindString += "F3"
|
||||
}
|
||||
if (keybind.which === 115) {
|
||||
keybindString += "F4"
|
||||
}
|
||||
if (keybind.which === 116) {
|
||||
keybindString += "F5"
|
||||
}
|
||||
if (keybind.which === 117) {
|
||||
keybindString += "F6"
|
||||
}
|
||||
if (keybind.which === 118) {
|
||||
keybindString += "F7"
|
||||
}
|
||||
if (keybind.which === 119) {
|
||||
keybindString += "F8"
|
||||
}
|
||||
if (keybind.which === 120) {
|
||||
keybindString += "F9"
|
||||
}
|
||||
if (keybind.which === 121) {
|
||||
keybindString += "F10"
|
||||
}
|
||||
if (keybind.which === 122) {
|
||||
keybindString += "F11"
|
||||
}
|
||||
if (keybind.which === 123) {
|
||||
keybindString += "F12"
|
||||
}
|
||||
}
|
||||
else {
|
||||
keybindString += String.fromCharCode(keybind.keyCode)
|
||||
keybindString += String.fromCharCode(keybind.which)
|
||||
}
|
||||
|
||||
if (keybind.note) {
|
||||
|
@ -107,7 +184,7 @@ export default class BaseClass extends Vue {
|
|||
currentKeyPress.altKey === fieldToCheck.altKey &&
|
||||
currentKeyPress.ctrlKey === fieldToCheck.ctrlKey &&
|
||||
currentKeyPress.shiftKey === fieldToCheck.shiftKey &&
|
||||
currentKeyPress.keyCode === fieldToCheck.keyCode
|
||||
currentKeyPress.which === fieldToCheck.which
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
@ -159,6 +236,14 @@ export default class BaseClass extends Vue {
|
|||
})
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Option management
|
||||
/****************************************************************/
|
||||
|
||||
@Options.Getter("getOptions") SGET_options!: OptionsStateInteface
|
||||
|
||||
@Options.Action("setOptions") SSET_options!: (input: OptionsStateInteface) => void
|
||||
|
||||
/****************************************************************/
|
||||
// Open documents management
|
||||
/****************************************************************/
|
||||
|
@ -237,10 +322,16 @@ export default class BaseClass extends Vue {
|
|||
return fieldValue.length
|
||||
}
|
||||
|
||||
@Dialogs.Getter("getDialogsState") SGET_getDialogsState!: boolean
|
||||
|
||||
/**
|
||||
* Refreshes the route
|
||||
*/
|
||||
refreshRoute () {
|
||||
if (this.SGET_options.disableCloseAftertSelectQuickSearch && this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
|
||||
const remainingDocuments = this.SGET_allOpenedDocuments.docs
|
||||
|
||||
const lastIndex = this.SGET_allOpenedDocuments.lastRemovedIndex
|
||||
|
@ -314,6 +405,40 @@ export default class BaseClass extends Vue {
|
|||
return hierarchicalString
|
||||
}
|
||||
|
||||
async retrieveAllDocuments () {
|
||||
let allDocs = [] as I_ShortenedDocument[]
|
||||
for (const blueprint of this.SGET_allBlueprints) {
|
||||
const CurrentObjectDB = new PouchDB(blueprint._id)
|
||||
|
||||
const dbRows = await CurrentObjectDB.allDocs({ include_docs: true })
|
||||
const dbDocuments = dbRows.rows.map(d => d.doc)
|
||||
const formattedDocuments: I_ShortenedDocument[] = []
|
||||
|
||||
for (const singleDocument of dbDocuments) {
|
||||
const doc = singleDocument as unknown as I_ShortenedDocument
|
||||
const pushValue = {
|
||||
label: doc.extraFields.find(e => e.id === "name")?.value,
|
||||
icon: doc.icon,
|
||||
id: doc._id,
|
||||
url: doc.url,
|
||||
type: doc.type,
|
||||
extraFields: doc.extraFields,
|
||||
// @ts-ignore
|
||||
hierarchicalPath: this.getDocumentHieararchicalPath(doc, dbDocuments),
|
||||
tags: doc.extraFields.find(e => 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
|
||||
formattedDocuments.push(pushValue)
|
||||
}
|
||||
const sortedDocuments = formattedDocuments.sort((a, b) => a.label.localeCompare(b.label))
|
||||
|
||||
// @ts-ignore
|
||||
allDocs = [...allDocs, ...sortedDocuments]
|
||||
}
|
||||
return allDocs
|
||||
}
|
||||
|
||||
retrieveIconColor (document: I_ShortenedDocument): string {
|
||||
// @ts-ignore
|
||||
return (document.activeTypeSearch) ? colors.getBrand("primary") : document.color
|
||||
|
|
BIN
src/assets/appLogo.png
Normal file
BIN
src/assets/appLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 103 KiB |
|
@ -32,7 +32,7 @@
|
|||
@trigger-dialog-close="keybindsDialogClose"
|
||||
/>
|
||||
|
||||
<q-page-sticky position="top-right" class="documentControl">
|
||||
<q-page-sticky position="top-right" class="documentControl bg-dark" v-if="!disableDocumentControlBar">
|
||||
|
||||
<div class="documentControl__blocker"></div>
|
||||
|
||||
|
@ -40,37 +40,39 @@
|
|||
|
||||
<div class="documentControl__left">
|
||||
|
||||
<q-btn
|
||||
icon="mdi-keyboard-settings"
|
||||
color="primary"
|
||||
outline
|
||||
@click="keybindsDialogAssignUID"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
<template v-if="!disableDocumentControlBarGuides">
|
||||
<q-btn
|
||||
icon="mdi-keyboard-settings"
|
||||
color="primary"
|
||||
outline
|
||||
@click="keybindsDialogAssignUID"
|
||||
>
|
||||
Open keybinds cheatsheet
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
>
|
||||
Open keybinds cheatsheet
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-btn
|
||||
icon="mdi-file-question"
|
||||
color="primary"
|
||||
outline
|
||||
@click="advancedSearchGuideAssignUID"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
<q-btn
|
||||
icon="mdi-file-question"
|
||||
color="primary"
|
||||
outline
|
||||
@click="advancedSearchGuideAssignUID"
|
||||
>
|
||||
Open advanced search guide
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
>
|
||||
Open advanced search guide
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-separator vertical inset color="accent" />
|
||||
<q-separator vertical inset color="accent" />
|
||||
</template>
|
||||
|
||||
<q-btn
|
||||
icon="mdi-package-variant-closed"
|
||||
|
@ -232,6 +234,16 @@ export default class DocumentControl extends BaseClass {
|
|||
projectExists: undefined | string | boolean = false
|
||||
projectName = ""
|
||||
|
||||
disableDocumentControlBar = false
|
||||
disableDocumentControlBarGuides = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.disableDocumentControlBar = options.disableDocumentControlBar
|
||||
this.disableDocumentControlBarGuides = options.disableDocumentControlBarGuides
|
||||
}
|
||||
|
||||
async created () {
|
||||
this.projectName = await retrieveCurrentProjectName()
|
||||
this.projectExists = !!(await retrieveCurrentProjectName())
|
||||
|
@ -245,31 +257,37 @@ export default class DocumentControl extends BaseClass {
|
|||
* Local keybinds
|
||||
*/
|
||||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
async processKeyPush () {
|
||||
// Quick new document
|
||||
if (this.determineKeyBind("quickNewDocument")) {
|
||||
if (this.determineKeyBind("quickNewDocument") && !this.SGET_getDialogsState) {
|
||||
this.newObjectAssignUID()
|
||||
}
|
||||
|
||||
// Quick open existing document
|
||||
if (this.determineKeyBind("quickExistingDocument")) {
|
||||
if (this.determineKeyBind("quickExistingDocument") && !this.SGET_getDialogsState) {
|
||||
this.existingObjectAssignUID()
|
||||
}
|
||||
|
||||
// Delete dialog - CTRL + D
|
||||
if (this.determineKeyBind("deleteDocument") && !this.currentlyNew && this.SGET_allOpenedDocuments.docs.length > 0) {
|
||||
if (this.determineKeyBind("deleteDocument") && !this.currentlyNew && this.SGET_allOpenedDocuments.docs.length > 0 && !this.SGET_getDialogsState) {
|
||||
this.deleteObjectAssignUID()
|
||||
}
|
||||
|
||||
// Edit document - CTRL + E
|
||||
if (this.determineKeyBind("editDocument") && this.currentyEditable && this.SGET_allOpenedDocuments.docs.length > 0) {
|
||||
if (this.determineKeyBind("editDocument") && this.currentyEditable && this.SGET_allOpenedDocuments.docs.length > 0 && !this.SGET_getDialogsState) {
|
||||
this.toggleEditMode()
|
||||
}
|
||||
|
||||
// Save document - CTRL + S
|
||||
if (this.determineKeyBind("saveDocument") && !this.currentyEditable && this.SGET_allOpenedDocuments.docs.length > 0) {
|
||||
if (this.determineKeyBind("saveDocument") && !this.currentyEditable && this.SGET_allOpenedDocuments.docs.length > 0 && !this.SGET_getDialogsState) {
|
||||
this.saveCurrentDocument().catch(e => console.log(e))
|
||||
}
|
||||
|
||||
// Add new under parent - CTRL + SHIFT + N
|
||||
if (this.determineKeyBind("addUnderParent") && !this.currentlyNew && this.SGET_allOpenedDocuments.docs.length > 0 && !this.SGET_getDialogsState) {
|
||||
await this.sleep(100)
|
||||
this.addNewUnderParent()
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
@ -472,8 +490,7 @@ export default class DocumentControl extends BaseClass {
|
|||
<style lang="scss">
|
||||
.documentControl {
|
||||
z-index: 999;
|
||||
background-color: $dark;
|
||||
width: calc(100vw - 375px);
|
||||
width: calc(100vw - 380px);
|
||||
margin-top: 2.5px;
|
||||
|
||||
&__blocker {
|
||||
|
@ -487,10 +504,21 @@ export default class DocumentControl extends BaseClass {
|
|||
}
|
||||
|
||||
&__wrapper {
|
||||
width: calc(100vw - 375px);
|
||||
width: calc(100vw - 385px);
|
||||
padding: 8.5px 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: " ";
|
||||
bottom: 1px;
|
||||
right: -5px;
|
||||
left: -5px;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
background-color: rgba($accent, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&__left,
|
||||
|
|
|
@ -1,19 +1,28 @@
|
|||
<template>
|
||||
|
||||
<span>
|
||||
<q-page-sticky position="top-left" class="treeSearchWrapper">
|
||||
<div
|
||||
class="treeSearchWrapper"
|
||||
:class="{'fullWidth': disableDocumentControlBar}"
|
||||
>
|
||||
<q-input
|
||||
ref="treeFilter"
|
||||
filled
|
||||
dark
|
||||
debounce="200"
|
||||
v-model="treeFilter"
|
||||
label="Filter document tree..."
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon name="mdi-text-search" />
|
||||
</template>
|
||||
<template v-slot:prepend>
|
||||
<q-icon v-if="treeFilter !== ''" name="clear" class="cursor-pointer text-secondary" @click="resetTreeFilter" />
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
|
||||
<q-input ref="treeFilter" dark filled v-model="treeFilter" label="Filter document tree...">
|
||||
<template v-slot:append>
|
||||
<q-icon name="mdi-text-search" />
|
||||
</template>
|
||||
<template v-slot:prepend>
|
||||
<q-icon v-if="treeFilter !== ''" name="clear" class="cursor-pointer text-secondary" @click="resetTreeFilter" />
|
||||
</template>
|
||||
</q-input>
|
||||
</q-page-sticky>
|
||||
|
||||
<h6 class="projectTitle text-cultured">
|
||||
<h6 class="projectTitle text-cultured" v-if="!noProjectName">
|
||||
<span>
|
||||
{{projectName}}
|
||||
<q-tooltip
|
||||
|
@ -26,6 +35,7 @@
|
|||
|
||||
<q-tree
|
||||
class="objectTree q-pa-sm"
|
||||
:class="{'hasTextShadow': textShadow}"
|
||||
:nodes="hierarchicalTree"
|
||||
node-key="key"
|
||||
no-connectors
|
||||
|
@ -54,7 +64,7 @@
|
|||
{{ prop.node.label }}
|
||||
<span
|
||||
class="text-primary text-weight-medium q-ml-xs"
|
||||
v-if="prop.node.isRoot">
|
||||
v-if="prop.node.isRoot || prop.node.isTag">
|
||||
({{prop.node.allCount}})
|
||||
<q-tooltip
|
||||
:delay="1000"
|
||||
|
@ -100,7 +110,7 @@
|
|||
</q-btn>
|
||||
<q-btn
|
||||
tabindex="-1"
|
||||
v-if="(!prop.node.specialLabel && !prop.node.isRoot) || (prop.node.isRoot && !prop.node.isTag)"
|
||||
v-if="(!prop.node.specialLabel && !prop.node.isRoot) && !prop.node.isTag"
|
||||
round
|
||||
flat
|
||||
dense
|
||||
|
@ -173,13 +183,13 @@ export default class ObjectTree extends BaseClass {
|
|||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
// Focus left tree search
|
||||
if (this.determineKeyBind("focusHierarchicalTree")) {
|
||||
if (this.determineKeyBind("focusHierarchicalTree") && !this.SGET_getDialogsState) {
|
||||
const treeFilterDOM = this.$refs.treeFilter as unknown as HTMLInputElement
|
||||
treeFilterDOM.focus()
|
||||
}
|
||||
|
||||
// Clear input in the left tree search
|
||||
if (this.determineKeyBind("clearInputHierarchicalTree")) {
|
||||
if (this.determineKeyBind("clearInputHierarchicalTree") && !this.SGET_getDialogsState) {
|
||||
this.resetTreeFilter()
|
||||
}
|
||||
}
|
||||
|
@ -201,6 +211,28 @@ export default class ObjectTree extends BaseClass {
|
|||
|
||||
// Unfuck the rendering by giving the app some time to load first
|
||||
await this.$nextTick()
|
||||
}
|
||||
|
||||
tagsAtTop = false
|
||||
compactTags = false
|
||||
noTags = false
|
||||
noProjectName = false
|
||||
invertTreeSorting = false
|
||||
doNotcollaseTreeOptions = false
|
||||
disableDocumentControlBar = false
|
||||
textShadow = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.tagsAtTop = options.tagsAtTop
|
||||
this.compactTags = options.compactTags
|
||||
this.noTags = options.noTags
|
||||
this.noProjectName = options.noProjectName
|
||||
this.invertTreeSorting = options.invertTreeSorting
|
||||
this.doNotcollaseTreeOptions = options.doNotcollaseTreeOptions
|
||||
this.disableDocumentControlBar = options.disableDocumentControlBar
|
||||
this.textShadow = options.textShadow
|
||||
|
||||
this.buildCurrentObjectTree().catch((e) => {
|
||||
console.log(e)
|
||||
|
@ -289,7 +321,7 @@ export default class ObjectTree extends BaseClass {
|
|||
/**
|
||||
* Holds all currently expanded notes
|
||||
*/
|
||||
expandedTreeNodes = []
|
||||
expandedTreeNodes: string[] = []
|
||||
|
||||
/**
|
||||
* Filter model for the tree
|
||||
|
@ -323,8 +355,17 @@ export default class ObjectTree extends BaseClass {
|
|||
|
||||
// Sort by custom order
|
||||
.sort((a, b) => {
|
||||
const order1 = a.extraFields.find(e => e.id === "order")?.value
|
||||
const order2 = b.extraFields.find(e => e.id === "order")?.value
|
||||
let order1 = 0
|
||||
let order2 = 0
|
||||
|
||||
if (!this.invertTreeSorting) {
|
||||
order1 = a.extraFields.find(e => e.id === "order")?.value
|
||||
order2 = b.extraFields.find(e => e.id === "order")?.value
|
||||
}
|
||||
else {
|
||||
order2 = a.extraFields.find(e => e.id === "order")?.value
|
||||
order1 = b.extraFields.find(e => e.id === "order")?.value
|
||||
}
|
||||
|
||||
if (order1 > order2) {
|
||||
return 1
|
||||
|
@ -393,7 +434,7 @@ export default class ObjectTree extends BaseClass {
|
|||
*/
|
||||
async buildCurrentObjectTree () {
|
||||
const allBlueprings = this.SGET_allBlueprints
|
||||
const treeObject: any[] = []
|
||||
let treeObject: any[] = []
|
||||
let allTreeDocuments: I_ShortenedDocument[] = []
|
||||
|
||||
// Process all documents, build hieararchy out of the and sort them via name and custom order
|
||||
|
@ -481,41 +522,78 @@ export default class ObjectTree extends BaseClass {
|
|||
return 0
|
||||
})
|
||||
|
||||
const tagList = await tagListBuildFromBlueprints(this.SGET_allBlueprints)
|
||||
if (!this.noTags) {
|
||||
const tagList = await tagListBuildFromBlueprints(this.SGET_allBlueprints)
|
||||
|
||||
tagList.forEach((tag: string) => {
|
||||
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) => {
|
||||
let allTags = 0
|
||||
let allTagsCategories = 0
|
||||
let allTagsDocuments = 0
|
||||
|
||||
let tagNodeList = tagList.map((tag: string) => {
|
||||
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))
|
||||
doc.key = `${tag}${doc._id}`
|
||||
// @ts-ignore
|
||||
// doc.isTag = true
|
||||
return doc
|
||||
})
|
||||
.sort((a, b) => a.label.localeCompare(b.label))
|
||||
|
||||
const documentCount = tagDocs.filter(e => !e.isCategory).length
|
||||
const categoryCount = tagDocs.filter(e => e.isCategory).length
|
||||
const allCount = tagDocs.length
|
||||
const documentCount = tagDocs.filter(e => !e.isCategory).length
|
||||
const categoryCount = tagDocs.filter(e => e.isCategory).length
|
||||
const allCount = tagDocs.length
|
||||
|
||||
const tagObject = {
|
||||
label: `${tag}`,
|
||||
icon: "mdi-tag",
|
||||
_id: `tag-${tag}`,
|
||||
key: `tag-${tag}`,
|
||||
allCount: allCount,
|
||||
documentCount: documentCount,
|
||||
categoryCount: categoryCount,
|
||||
isRoot: true,
|
||||
isTag: true,
|
||||
children: tagDocs
|
||||
allTags += allCount
|
||||
allTagsCategories += categoryCount
|
||||
allTagsDocuments += documentCount
|
||||
|
||||
return {
|
||||
label: `${tag}`,
|
||||
icon: "mdi-tag",
|
||||
_id: `tag-${tag}`,
|
||||
key: `tag-${tag}`,
|
||||
allCount: allCount,
|
||||
documentCount: documentCount,
|
||||
categoryCount: categoryCount,
|
||||
isRoot: true,
|
||||
isTag: true,
|
||||
children: tagDocs
|
||||
}
|
||||
})
|
||||
|
||||
if (this.compactTags && tagNodeList.length > 0) {
|
||||
tagNodeList = [
|
||||
{
|
||||
label: "Tags",
|
||||
icon: "mdi-tag",
|
||||
_id: "tagsList",
|
||||
key: "tagList",
|
||||
isRoot: true,
|
||||
allCount: allTags,
|
||||
documentCount: allTagsDocuments,
|
||||
categoryCount: allTagsCategories,
|
||||
isTag: true,
|
||||
// @ts-ignore
|
||||
children: tagNodeList.map(e => {
|
||||
e.isRoot = false
|
||||
return e
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
treeObject.push(tagObject)
|
||||
})
|
||||
|
||||
if (this.tagsAtTop) {
|
||||
treeObject = [...tagNodeList, ...treeObject]
|
||||
}
|
||||
else {
|
||||
treeObject = [...treeObject, ...tagNodeList]
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the finished object to the render model
|
||||
this.hierarchicalTree = treeObject
|
||||
|
@ -548,8 +626,10 @@ export default class ObjectTree extends BaseClass {
|
|||
buildTreeExpands (newDocs: I_OpenedDocument[]) {
|
||||
const expandIDs: string[] = []
|
||||
|
||||
const newDocsSnapshot: I_OpenedDocument[] = extend(true, [], newDocs)
|
||||
|
||||
// Check for parent changes
|
||||
newDocs.forEach(s => {
|
||||
newDocsSnapshot.forEach((s, index) => {
|
||||
const oldParentDoc = this.lastDocsSnapShot.find(doc => doc._id === s._id)
|
||||
// Fizzle if the parent doesn't exist in the old version
|
||||
if (!oldParentDoc) {
|
||||
|
@ -570,13 +650,19 @@ export default class ObjectTree extends BaseClass {
|
|||
})
|
||||
|
||||
// Process top level documents
|
||||
newDocs.forEach(s => {
|
||||
newDocsSnapshot.forEach(s => {
|
||||
const newParentDocField = this.retrieveFieldValue(s, "parentDoc")
|
||||
const oldParentDoc = this.lastDocsSnapShot.find(doc => doc._id === s._id)
|
||||
// @ts-ignore
|
||||
const oldParentDocField = this.retrieveFieldValue(oldParentDoc, "parentDoc")
|
||||
|
||||
// @ts-ignore
|
||||
const oldParentDocID = (oldParentDocField?.value) ? oldParentDocField.value.value : false
|
||||
|
||||
// @ts-ignore
|
||||
const newParentDocID = (newParentDocField?.value) ? newParentDocField.value.value : false
|
||||
|
||||
if (!newParentDocID) {
|
||||
if (!newParentDocID && oldParentDocID !== newParentDocID) {
|
||||
expandIDs.push(s.type)
|
||||
}
|
||||
})
|
||||
|
@ -657,19 +743,38 @@ export default class ObjectTree extends BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
expandeCollapseNode (node: {key: string}) {
|
||||
expandeCollapseNode (node: {key: string, children: []}) {
|
||||
const treeDOM = this.$refs.tree as unknown as {
|
||||
setExpanded: (key:string, state: boolean)=> void,
|
||||
isExpanded: (key:string)=> boolean
|
||||
}
|
||||
|
||||
const isExpanded = treeDOM.isExpanded(node.key)
|
||||
treeDOM.setExpanded(node.key, !isExpanded)
|
||||
|
||||
if (isExpanded) {
|
||||
this.collapseAllNodes(node)
|
||||
}
|
||||
else {
|
||||
treeDOM.setExpanded(node.key, true)
|
||||
}
|
||||
}
|
||||
|
||||
determineNodeColor (node: {color: string, isTag: boolean, isRoot: boolean}) {
|
||||
// @ts-ignore
|
||||
return (node?.isTag && node?.isRoot) ? colors.getBrand("primary") : node.color
|
||||
return (node?.isTag) ? colors.getBrand("primary") : node.color
|
||||
}
|
||||
|
||||
collapseAllNodes (node: {key: string, children: []}) {
|
||||
if (node.children && !this.doNotcollaseTreeOptions) {
|
||||
for (const child of node.children) {
|
||||
if (this.expandedTreeNodes.includes(node.key)) {
|
||||
this.collapseAllNodes(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.expandedTreeNodes.includes(node.key)) {
|
||||
this.expandedTreeNodes = this.expandedTreeNodes.filter(n => n !== node.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -678,10 +783,29 @@ export default class ObjectTree extends BaseClass {
|
|||
|
||||
.projectTitle {
|
||||
margin: 0 0 -5px 0;
|
||||
padding: 65px 10px 0;
|
||||
padding: 10px 10px 0;
|
||||
}
|
||||
|
||||
.objectTree {
|
||||
&.hasTextShadow {
|
||||
.documentLabel {
|
||||
font-weight: 500;
|
||||
$shadowColorOutline: #000;
|
||||
$shadowColorSurround: #000;
|
||||
|
||||
filter: drop-shadow(0 0 4px #000);
|
||||
text-shadow:
|
||||
-2px -2px 0 $shadowColorSurround,
|
||||
2px -2px 0 $shadowColorSurround,
|
||||
-2px 2px 0 $shadowColorSurround,
|
||||
2px 2px 0 $shadowColorSurround,
|
||||
-1px -1px 0 $shadowColorOutline,
|
||||
1px -1px 0 $shadowColorOutline,
|
||||
-1px 1px 0 $shadowColorOutline,
|
||||
1px 1px 0 $shadowColorOutline;
|
||||
}
|
||||
}
|
||||
|
||||
> .q-tree__node {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
@ -758,12 +882,17 @@ export default class ObjectTree extends BaseClass {
|
|||
}
|
||||
|
||||
.treeSearchWrapper {
|
||||
top: -40px;
|
||||
left: -375px;
|
||||
top: -55px;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
width: 375px;
|
||||
z-index: 555;
|
||||
background-color: $dark;
|
||||
|
||||
&.fullWidth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -793,4 +922,16 @@ export default class ObjectTree extends BaseClass {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.body--dark {
|
||||
.objectTree {
|
||||
.documentLabel {
|
||||
color: #dcdcdc;
|
||||
}
|
||||
}
|
||||
|
||||
.projectTitle {
|
||||
color: #dcdcdc;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,6 +3,19 @@
|
|||
<div
|
||||
:class="{'AppControl': isProject}"
|
||||
>
|
||||
|
||||
<!-- New document dialog -->
|
||||
<newDocumentDialog
|
||||
:dialog-trigger="newObjectDialogTrigger"
|
||||
@trigger-dialog-close="newObjectDialogClose"
|
||||
/>
|
||||
|
||||
<!-- Existing document dialog -->
|
||||
<existingDocumentDialog
|
||||
:dialog-trigger="existingObjectDialogTrigger"
|
||||
@trigger-dialog-close="existingObjectDialogClose"
|
||||
/>
|
||||
|
||||
<!-- Project close dialog -->
|
||||
<projectCloseCheckDialog
|
||||
:dialog-trigger="projectCloseCheckDialogTrigger"
|
||||
|
@ -40,6 +53,12 @@
|
|||
@trigger-dialog-close="changeLogDialogClose"
|
||||
/>
|
||||
|
||||
<!-- Program settings dialog -->
|
||||
<programSettingsDialog
|
||||
:dialog-trigger="programSettingsDialogTrigger"
|
||||
@trigger-dialog-close="programSettingsDialogClose"
|
||||
/>
|
||||
|
||||
<!-- Advanced search guide dialog -->
|
||||
<advancedSearchGuideDialog
|
||||
:dialog-trigger="advancedSearchGuideDialogTrigger"
|
||||
|
@ -54,15 +73,22 @@
|
|||
<!-- Options button -->
|
||||
<q-btn
|
||||
flat
|
||||
v-if="true === false"
|
||||
:ripple="false"
|
||||
dark
|
||||
size='md'
|
||||
no-caps
|
||||
@click="programSettingsDialogAssignUID"
|
||||
>
|
||||
Options
|
||||
</q-btn>
|
||||
<q-img
|
||||
:src="appLogo"
|
||||
style="height: 26px; width: 26px; margin: 0 -9px;"
|
||||
/>
|
||||
<q-tooltip anchor="center right" self="center left" :delay="500">
|
||||
Program settings
|
||||
</q-tooltip>
|
||||
|
||||
</q-btn>
|
||||
<q-separator color="primary" vertical dark style="opacity: 0.1;" />
|
||||
<!-- Project button-->
|
||||
<q-btn
|
||||
flat
|
||||
|
@ -82,6 +108,38 @@
|
|||
>
|
||||
<q-list class="bg-gunmetal-light" dark>
|
||||
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
class="noHigh"
|
||||
@click="newObjectAssignUID"
|
||||
:disable="!projectExists || isFrontpage"
|
||||
>
|
||||
<q-item-section>Quick-add new document</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-text-box-plus-outline" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
class="noHigh"
|
||||
@click="existingObjectAssignUID"
|
||||
:disable="!projectExists || isFrontpage"
|
||||
>
|
||||
<q-item-section>Quick-search existing document</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-database-search" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
|
@ -91,6 +149,9 @@
|
|||
@click="newProjectAssignUID"
|
||||
>
|
||||
<q-item-section>New project</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-plus" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
@ -105,6 +166,9 @@
|
|||
:disable="!projectExists"
|
||||
>
|
||||
<q-item-section>Export current project</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-package-variant-closed" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
|
@ -116,6 +180,9 @@
|
|||
@click="importProjectAssignUID"
|
||||
>
|
||||
<q-item-section>Import existing project</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-package-variant" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
@ -130,6 +197,9 @@
|
|||
:disable="!projectExists || isProjectPage"
|
||||
>
|
||||
<q-item-section>Resume project</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-folder-open-outline" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
|
@ -142,6 +212,9 @@
|
|||
:disable="!projectExists || isFrontpage"
|
||||
>
|
||||
<q-item-section>Close project</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-exit-to-app" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
|
@ -155,7 +228,7 @@
|
|||
size='md'
|
||||
no-caps
|
||||
>
|
||||
Help & Info
|
||||
Help, Settings & Info
|
||||
<q-menu
|
||||
anchor="bottom left"
|
||||
class="bg-gunmetal-light"
|
||||
|
@ -163,6 +236,22 @@
|
|||
square
|
||||
>
|
||||
<q-list class="bg-gunmetal-light" dark>
|
||||
<q-item
|
||||
@click="programSettingsDialogAssignUID"
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
class="noHigh"
|
||||
>
|
||||
<q-item-section>Program settings</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-tune" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
||||
<q-item
|
||||
@click="keybindsDialogAssignUID"
|
||||
v-close-popup
|
||||
|
@ -172,6 +261,9 @@
|
|||
class="noHigh"
|
||||
>
|
||||
<q-item-section>Show keybind cheatsheet</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-keyboard-settings" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
|
@ -183,6 +275,9 @@
|
|||
class="noHigh"
|
||||
>
|
||||
<q-item-section>Advanced search guide</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-file-question" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
@ -196,6 +291,9 @@
|
|||
class="noHigh"
|
||||
>
|
||||
<q-item-section>Changelog</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-clipboard-text" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
|
@ -207,6 +305,9 @@
|
|||
class="noHigh"
|
||||
>
|
||||
<q-item-section>About Fantasia Archive</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-information-variant" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
@ -220,6 +321,9 @@
|
|||
class="noHigh"
|
||||
>
|
||||
<q-item-section>Toggle developer tools</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="mdi-code-tags" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
</q-list>
|
||||
|
@ -243,13 +347,19 @@ import importProjectCheckDialog from "src/components/dialogs/ImportProjectCheck.
|
|||
import newProjectCheckDialog from "src/components/dialogs/NewProjectCheck.vue"
|
||||
import aboutAppDialog from "src/components/dialogs/AboutApp.vue"
|
||||
import changeLogDialog from "src/components/dialogs/ChangeLog.vue"
|
||||
import programSettingsDialog from "src/components/dialogs/ProgramSettings.vue"
|
||||
import advancedSearchGuideDialog from "src/components/dialogs/AdvancedSearchGuide.vue"
|
||||
import newDocumentDialog from "src/components/dialogs/NewDocument.vue"
|
||||
import existingDocumentDialog from "src/components/dialogs/ExistingDocument.vue"
|
||||
|
||||
import { Loading, QSpinnerGears } from "quasar"
|
||||
|
||||
import { retrieveCurrentProjectName, exportProject } from "src/scripts/projectManagement/projectManagent"
|
||||
|
||||
import { toggleDevTools } from "src/scripts/utilities/devTools"
|
||||
|
||||
import appLogo from "src/assets/appLogo.png"
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
projectCloseCheckDialog,
|
||||
|
@ -258,7 +368,10 @@ import { toggleDevTools } from "src/scripts/utilities/devTools"
|
|||
newProjectCheckDialog,
|
||||
aboutAppDialog,
|
||||
changeLogDialog,
|
||||
advancedSearchGuideDialog
|
||||
advancedSearchGuideDialog,
|
||||
programSettingsDialog,
|
||||
newDocumentDialog,
|
||||
existingDocumentDialog
|
||||
}
|
||||
})
|
||||
export default class AppControl extends BaseClass {
|
||||
|
@ -271,6 +384,8 @@ export default class AppControl extends BaseClass {
|
|||
isProjectPage = true
|
||||
projectName = ""
|
||||
|
||||
appLogo = appLogo
|
||||
|
||||
created () {
|
||||
this.checkProjectStatus().catch(e => console.log(e))
|
||||
}
|
||||
|
@ -337,9 +452,14 @@ export default class AppControl extends BaseClass {
|
|||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
// Keybind cheatsheet
|
||||
if (this.determineKeyBind("openKeybindsCheatsheet")) {
|
||||
if (this.determineKeyBind("openKeybindsCheatsheet") && !this.SGET_getDialogsState) {
|
||||
this.keybindsDialogAssignUID()
|
||||
}
|
||||
|
||||
// App options
|
||||
if (this.determineKeyBind("openAppOptions") && !this.SGET_getDialogsState) {
|
||||
this.programSettingsDialogAssignUID()
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
@ -381,6 +501,19 @@ export default class AppControl extends BaseClass {
|
|||
this.changeLogDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Program settings dialog
|
||||
/****************************************************************/
|
||||
|
||||
programSettingsDialogTrigger: string | false = false
|
||||
programSettingsDialogClose () {
|
||||
this.programSettingsDialogTrigger = false
|
||||
}
|
||||
|
||||
programSettingsDialogAssignUID () {
|
||||
this.programSettingsDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Advanced search guide dialog
|
||||
/****************************************************************/
|
||||
|
@ -393,6 +526,32 @@ export default class AppControl extends BaseClass {
|
|||
advancedSearchGuideAssignUID () {
|
||||
this.advancedSearchGuideDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// New document dialog
|
||||
/****************************************************************/
|
||||
|
||||
newObjectDialogTrigger: string | false = false
|
||||
newObjectDialogClose () {
|
||||
this.newObjectDialogTrigger = false
|
||||
}
|
||||
|
||||
newObjectAssignUID () {
|
||||
this.newObjectDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Existing document dialog
|
||||
/****************************************************************/
|
||||
|
||||
existingObjectDialogTrigger: string | false = false
|
||||
existingObjectDialogClose () {
|
||||
this.existingObjectDialogTrigger = false
|
||||
}
|
||||
|
||||
existingObjectAssignUID () {
|
||||
this.existingObjectDialogTrigger = this.generateUID()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
<q-tabs
|
||||
v-if="localDocuments.length > 0"
|
||||
:class="{'hasTextShadow': textShadow}"
|
||||
align="left"
|
||||
inline-label
|
||||
outside-arrows
|
||||
mobile-arrows
|
||||
mobile-arrows
|
||||
class="tabsWrapper"
|
||||
dense
|
||||
no-caps>
|
||||
|
@ -78,6 +79,14 @@ import closeDocumentCheckDialog from "src/components/dialogs/CloseDocumentCheck.
|
|||
components: { closeDocumentCheckDialog }
|
||||
})
|
||||
export default class TopTabs extends BaseClass {
|
||||
textShadow = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.textShadow = options.textShadow
|
||||
}
|
||||
|
||||
@Watch("SGET_allOpenedDocuments", { deep: true })
|
||||
reactToDocumentListChange (val: {docs: I_OpenedDocument[]}, oldVal: {docs: I_OpenedDocument[]}) {
|
||||
this.localDocuments = []
|
||||
|
@ -108,18 +117,18 @@ export default class TopTabs extends BaseClass {
|
|||
*/
|
||||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
// Delete dialog
|
||||
if (this.determineKeyBind("closeTab") && this.localDocuments.length > 0) {
|
||||
// Close tab dialog
|
||||
if (this.determineKeyBind("closeTab") && this.localDocuments.length > 0 && !this.SGET_getDialogsState) {
|
||||
this.tryCloseTab()
|
||||
}
|
||||
|
||||
// Next tab
|
||||
if (this.determineKeyBind("nextTab") && this.localDocuments.length > 0) {
|
||||
if (this.determineKeyBind("nextTab") && this.localDocuments.length > 0 && !this.SGET_getDialogsState) {
|
||||
this.goToNextTab()
|
||||
}
|
||||
|
||||
// Previous tab
|
||||
if (this.determineKeyBind("previousTab") && this.localDocuments.length > 0) {
|
||||
if (this.determineKeyBind("previousTab") && this.localDocuments.length > 0 && !this.SGET_getDialogsState) {
|
||||
this.goToPreviousTab()
|
||||
}
|
||||
}
|
||||
|
@ -202,6 +211,25 @@ export default class TopTabs extends BaseClass {
|
|||
.tabsWrapper {
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
&.hasTextShadow {
|
||||
.q-tab__label,
|
||||
.q-tab__icon {
|
||||
$shadowColorOutline: #000;
|
||||
$shadowColorSurround: #000;
|
||||
|
||||
filter: drop-shadow(0 0 4px #000);
|
||||
text-shadow:
|
||||
-2px -2px 0 $shadowColorSurround,
|
||||
2px -2px 0 $shadowColorSurround,
|
||||
-2px 2px 0 $shadowColorSurround,
|
||||
2px 2px 0 $shadowColorSurround,
|
||||
-1px -1px 0 $shadowColorOutline,
|
||||
1px -1px 0 $shadowColorOutline,
|
||||
-1px 1px 0 $shadowColorOutline,
|
||||
1px 1px 0 $shadowColorOutline;
|
||||
}
|
||||
}
|
||||
|
||||
.q-tabs__arrow {
|
||||
text-shadow: none !important;
|
||||
}
|
||||
|
@ -248,4 +276,12 @@ export default class TopTabs extends BaseClass {
|
|||
color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
body.body--dark {
|
||||
.topTabs {
|
||||
.q-tab {
|
||||
color: #dcdcdc;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
outline
|
||||
label="Discard changes"
|
||||
color="secondary"
|
||||
v-close-popup
|
||||
@click="closeDocument(dialogDocument)" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
|
@ -61,6 +60,9 @@ export default class CloseDocumentCheckDialog extends DialogBase {
|
|||
|
||||
closeDocument (input: I_OpenedDocument) {
|
||||
const dataPass = { doc: input, treeAction: false }
|
||||
this.dialogModel = false
|
||||
this.SSET_setDialogState(false)
|
||||
|
||||
this.SSET_removeOpenedDocument(dataPass)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
outline
|
||||
label="Delete document"
|
||||
color="secondary"
|
||||
v-close-popup
|
||||
@click="deleteDocument()" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
|
@ -71,6 +70,10 @@ export default class DeleteDocumentCheckDialog extends DialogBase {
|
|||
await CurrentObjectDB.remove(this.currentDocument)
|
||||
|
||||
const dataPass = { doc: this.currentDocument, treeAction: true }
|
||||
|
||||
this.dialogModel = false
|
||||
this.SSET_setDialogState(false)
|
||||
|
||||
this.SSET_removeOpenedDocument(dataPass)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<q-dialog
|
||||
no-route-dismiss
|
||||
v-model="dialogModel"
|
||||
@hide="triggerDialogClose"
|
||||
>
|
||||
|
@ -14,7 +15,7 @@
|
|||
|
||||
<q-card-section class="column items-center">
|
||||
<div class="q-mb-lg">
|
||||
<q-checkbox dark v-model="includeCategories" label="Include categories in the list?" />
|
||||
<q-checkbox dark color="primary" v-model="includeCategories" label="Include categories in the list?" />
|
||||
</div>
|
||||
<q-select
|
||||
style="width: 400px;"
|
||||
|
@ -26,14 +27,16 @@
|
|||
menu-self="top middle"
|
||||
:options="filteredExistingInput"
|
||||
use-input
|
||||
outlined
|
||||
input-debounce="0"
|
||||
multiple
|
||||
filled
|
||||
input-debounce="200"
|
||||
v-model="existingDocumentModel"
|
||||
@filter="filterExistingSelect"
|
||||
@input="openExistingInput"
|
||||
>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
:class="{'hasTextShadow': textShadow}"
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
:style="`color: ${opt.color}`"
|
||||
|
@ -96,11 +99,12 @@
|
|||
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
|
||||
import PouchDB from "pouchdb"
|
||||
import { advancedDocumentFilter } from "src/scripts/utilities/advancedDocumentFilter"
|
||||
import { extend } from "quasar"
|
||||
import PouchDB from "pouchdb"
|
||||
|
||||
import DialogBase from "src/components/dialogs/_DialogBase"
|
||||
import { I_Blueprint } from "src/interfaces/I_Blueprint"
|
||||
|
||||
@Component({
|
||||
components: { }
|
||||
|
@ -112,46 +116,23 @@ export default class ExistingDocumentDialog extends DialogBase {
|
|||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.isCloseAbleViaKeybind = false
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
|
||||
this.reloadOptions()
|
||||
this.populateExistingObjectDialog().catch(e => console.log(e))
|
||||
}
|
||||
}
|
||||
|
||||
existingObjectsBackupList = [] as I_ShortenedDocument[]
|
||||
existingObjectList = [] as I_ShortenedDocument[]
|
||||
allDocumentBluePrints = [] as I_Blueprint[]
|
||||
|
||||
async populateExistingObjectDialog () {
|
||||
let allDocs = [] as I_ShortenedDocument[]
|
||||
for (const blueprint of this.SGET_allBlueprints) {
|
||||
const CurrentObjectDB = new PouchDB(blueprint._id)
|
||||
this.allDocumentBluePrints = this.SGET_allBlueprints
|
||||
|
||||
const dbRows = await CurrentObjectDB.allDocs({ include_docs: true })
|
||||
const dbDocuments = dbRows.rows.map(d => d.doc)
|
||||
const formattedDocuments: I_ShortenedDocument[] = []
|
||||
|
||||
for (const singleDocument of dbDocuments) {
|
||||
const doc = singleDocument as unknown as I_ShortenedDocument
|
||||
const pushValue = {
|
||||
label: doc.extraFields.find(e => e.id === "name")?.value,
|
||||
icon: doc.icon,
|
||||
id: doc._id,
|
||||
url: doc.url,
|
||||
type: doc.type,
|
||||
// @ts-ignore
|
||||
hierarchicalPath: this.getDocumentHieararchicalPath(doc, dbDocuments),
|
||||
tags: doc.extraFields.find(e => 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
|
||||
formattedDocuments.push(pushValue)
|
||||
}
|
||||
const sortedDocuments = formattedDocuments.sort((a, b) => a.label.localeCompare(b.label))
|
||||
|
||||
// @ts-ignore
|
||||
allDocs = [...allDocs, ...sortedDocuments]
|
||||
}
|
||||
const allDocs = await this.retrieveAllDocuments()
|
||||
|
||||
this.existingObjectsBackupList = allDocs
|
||||
this.filterDocuments()
|
||||
|
@ -164,9 +145,10 @@ export default class ExistingDocumentDialog extends DialogBase {
|
|||
this.$refs.ref_existingDocument.focus()
|
||||
/* eslint-enable */
|
||||
}
|
||||
this.isCloseAbleViaKeybind = true
|
||||
}
|
||||
|
||||
existingDocumentModel = null
|
||||
existingDocumentModel = []
|
||||
|
||||
filteredExistingInput = null as unknown as I_ShortenedDocument[]
|
||||
|
||||
|
@ -194,7 +176,7 @@ export default class ExistingDocumentDialog extends DialogBase {
|
|||
update(() => {
|
||||
const needle = val.toLowerCase()
|
||||
const listCopy : I_ShortenedDocument[] = extend(true, [], this.existingObjectList)
|
||||
this.filteredExistingInput = advancedDocumentFilter(needle, listCopy)
|
||||
this.filteredExistingInput = advancedDocumentFilter(needle, listCopy, this.allDocumentBluePrints, this.existingObjectsBackupList)
|
||||
|
||||
if (this.$refs.ref_existingDocument && this.filteredExistingInput.length > 0) {
|
||||
this.refocusSelect().catch(e => console.log(e))
|
||||
|
@ -202,11 +184,29 @@ export default class ExistingDocumentDialog extends DialogBase {
|
|||
})
|
||||
}
|
||||
|
||||
openExistingInput (e: I_ShortenedDocument) {
|
||||
this.dialogModel = false
|
||||
// @ts-ignore
|
||||
this.openExistingDocumentRoute(e)
|
||||
this.existingDocumentModel = null
|
||||
async openExistingInput (e: I_ShortenedDocument[]) {
|
||||
if (!this.disableCloseAftertSelectQuickSearch) {
|
||||
this.dialogModel = false
|
||||
// @ts-ignore
|
||||
this.openExistingDocumentRoute(e[0])
|
||||
this.existingDocumentModel = []
|
||||
}
|
||||
else {
|
||||
// @ts-ignore
|
||||
this.existingDocumentModel = []
|
||||
|
||||
const CurrentObjectDB = new PouchDB(e[0].type)
|
||||
// @ts-ignore
|
||||
const retrievedObject = await CurrentObjectDB.get(e[0].id)
|
||||
|
||||
const dataPass = {
|
||||
doc: retrievedObject,
|
||||
treeAction: false
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
this.SSET_addOpenedDocument(dataPass)
|
||||
}
|
||||
}
|
||||
|
||||
addNewItemUnderSelected (parent: any) {
|
||||
|
@ -218,6 +218,23 @@ export default class ExistingDocumentDialog extends DialogBase {
|
|||
this.addNewObjectRoute(routeObject)
|
||||
}
|
||||
|
||||
disableCloseAftertSelectQuickSearch = false
|
||||
closeWithSameClick = false
|
||||
textShadow = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
this.reloadOptions()
|
||||
}
|
||||
|
||||
reloadOptions () {
|
||||
const options = this.SGET_options
|
||||
this.closeWithSameClick = options.allowQuickPopupSameKeyClose
|
||||
this.disableCloseAftertSelectQuickSearch = options.disableCloseAftertSelectQuickSearch
|
||||
this.includeCategories = !options.disableQuickSearchCategoryPrecheck
|
||||
this.textShadow = options.textShadow
|
||||
}
|
||||
|
||||
includeCategories = true
|
||||
|
||||
@Watch("includeCategories")
|
||||
|
@ -228,6 +245,22 @@ export default class ExistingDocumentDialog extends DialogBase {
|
|||
filterDocuments () {
|
||||
this.existingObjectList = this.existingObjectsBackupList.filter(e => !((!this.includeCategories && e.isCategory)))
|
||||
}
|
||||
|
||||
isCloseAbleViaKeybind = false
|
||||
|
||||
/**
|
||||
* Local keybinds
|
||||
*/
|
||||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
// Keybind cheatsheet
|
||||
if (this.determineKeyBind("quickExistingDocument") && this.dialogModel && this.closeWithSameClick && this.isCloseAbleViaKeybind && this.SGET_getDialogsState) {
|
||||
this.dialogModel = false
|
||||
this.SSET_setDialogState(false)
|
||||
// @ts-ignore
|
||||
this.existingDocumentModel = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="keybind in SGET_getCurrentKeyBindData.defaults" :key="keybind.id">
|
||||
<tr v-for="keybind in localCheatSheet" :key="keybind.id">
|
||||
<td class="text-left" v-html="keybind.tooltip"/>
|
||||
<td class="text-left" v-html="retrieveKeybindString(keybind)"/>
|
||||
</tr>
|
||||
|
@ -54,6 +54,7 @@
|
|||
import { Component, Watch } from "vue-property-decorator"
|
||||
|
||||
import DialogBase from "src/components/dialogs/_DialogBase"
|
||||
import { I_KeyPressObject } from "src/interfaces/I_KeypressObject"
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
|
@ -66,9 +67,34 @@ export default class KeybindCheatsheet extends DialogBase {
|
|||
}
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
this.localCheatSheet = this.SGET_getCurrentKeyBindData.defaults.map((bind, index) => {
|
||||
const mappedKeybind = (this.SGET_getCurrentKeyBindData.userKeybinds[index] && this.SGET_getCurrentKeyBindData.userKeybinds[index].which)
|
||||
? {
|
||||
altKey: this.SGET_getCurrentKeyBindData.userKeybinds[index].altKey,
|
||||
ctrlKey: this.SGET_getCurrentKeyBindData.userKeybinds[index].ctrlKey,
|
||||
shiftKey: this.SGET_getCurrentKeyBindData.userKeybinds[index].shiftKey,
|
||||
which: this.SGET_getCurrentKeyBindData.userKeybinds[index].which,
|
||||
id: bind.id,
|
||||
tooltip: bind.tooltip,
|
||||
note: bind.note
|
||||
}
|
||||
: {
|
||||
altKey: bind.altKey,
|
||||
ctrlKey: bind.ctrlKey,
|
||||
shiftKey: bind.shiftKey,
|
||||
which: bind.which,
|
||||
id: bind.id,
|
||||
tooltip: bind.tooltip,
|
||||
note: bind.note
|
||||
}
|
||||
|
||||
return mappedKeybind
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
localCheatSheet: I_KeyPressObject[] = []
|
||||
|
||||
thumbStyle ={
|
||||
right: "-40px",
|
||||
borderRadius: "5px",
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
class="newDocumentSelect"
|
||||
:options="filteredNewInput"
|
||||
use-input
|
||||
outlined
|
||||
filled
|
||||
input-debounce="0"
|
||||
v-model="newDocumentModel"
|
||||
@filter="filterNewSelect"
|
||||
|
@ -31,6 +31,7 @@
|
|||
>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
:class="{'hasTextShadow': textShadow}"
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
>
|
||||
|
@ -76,6 +77,7 @@ export default class NewDocumentDialog extends DialogBase {
|
|||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.isCloseAbleViaKeybind = false
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
this.populateNewObjectDialog().catch(e => console.log(e))
|
||||
|
@ -104,6 +106,8 @@ export default class NewDocumentDialog extends DialogBase {
|
|||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.focus()
|
||||
/* eslint-enable */
|
||||
|
||||
this.isCloseAbleViaKeybind = true
|
||||
}
|
||||
|
||||
filteredNewInput = null as unknown as NewObjectDocument[]
|
||||
|
@ -143,6 +147,35 @@ export default class NewDocumentDialog extends DialogBase {
|
|||
this.addNewObjectRoute(e)
|
||||
this.newDocumentModel = null
|
||||
}
|
||||
|
||||
isCloseAbleViaKeybind = false
|
||||
closeWithSameClick = false
|
||||
textShadow = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
this.reloadOptions()
|
||||
}
|
||||
|
||||
reloadOptions () {
|
||||
const options = this.SGET_options
|
||||
this.closeWithSameClick = options.allowQuickPopupSameKeyClose
|
||||
this.textShadow = options.textShadow
|
||||
}
|
||||
|
||||
/**
|
||||
* Local keybinds
|
||||
*/
|
||||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
// Keybind cheatsheet
|
||||
if (this.determineKeyBind("quickNewDocument") && this.dialogModel && this.closeWithSameClick && this.isCloseAbleViaKeybind && this.SGET_getDialogsState) {
|
||||
this.dialogModel = false
|
||||
this.SSET_setDialogState(false)
|
||||
// @ts-ignore
|
||||
this.existingDocumentModel = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
952
src/components/dialogs/ProgramSettings.vue
Normal file
952
src/components/dialogs/ProgramSettings.vue
Normal file
|
@ -0,0 +1,952 @@
|
|||
<template>
|
||||
|
||||
<q-dialog
|
||||
v-model="dialogModel"
|
||||
persistent
|
||||
@hide="triggerDialogClose"
|
||||
>
|
||||
<q-card
|
||||
class="programSettingsDialog"
|
||||
dark
|
||||
>
|
||||
|
||||
<h4 class="programSettingsTitle">Fantasia Archive Settings</h4>
|
||||
<q-card-section horizontal class="programSettingsTabs">
|
||||
<q-tabs
|
||||
v-model="activeTab"
|
||||
class="text-accent"
|
||||
active-color="primary"
|
||||
indicator-color="primary"
|
||||
vertical
|
||||
style="width: 100%;"
|
||||
|
||||
>
|
||||
<q-tab name="uiSettings" label="Visuals & Functionality" />
|
||||
<q-separator dark />
|
||||
|
||||
<q-tab name="keybinds" label="Keybinds" />
|
||||
</q-tabs>
|
||||
|
||||
</q-card-section>
|
||||
<q-separator vertical dark />
|
||||
|
||||
<q-card-section horizontal class="programSettingsTabContent">
|
||||
<q-tab-panels
|
||||
dark
|
||||
v-model="activeTab"
|
||||
animated
|
||||
style="width: 100%;"
|
||||
vertical
|
||||
transition-prev="jump-up"
|
||||
transition-next="jump-down"
|
||||
>
|
||||
|
||||
<q-tab-panel name="uiSettings" dark class="q-pt-sm">
|
||||
<q-scroll-area
|
||||
class="programSettingsScrollArea"
|
||||
visible
|
||||
dark
|
||||
:thumb-style="thumbStyle"
|
||||
>
|
||||
<div class="row justify-start">
|
||||
|
||||
<div class="col-12">
|
||||
<div class="text-h6">
|
||||
Program looks & Accessibility
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-3 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Dark mode
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Turn between light and dark mode of the app
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.darkMode"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-3 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Accessibility - Text shadow
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
This setting toggles text shadows in the hieratchical tree, relationship search popups and in tabs; allowing for most "standout" looks of the text from the background.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.textShadow"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="text-h6 q-mt-lg">
|
||||
Document view settings
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-3 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Disable document control bar
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
In case you wish to maximize you working space on the document, you can disable the top button bar with the setting.
|
||||
<br>
|
||||
The necesarry control buttons will be moved to the top of the main document body while the rest of the functionality will be accesible via keybinds or thought the app menu on the top left.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.disableDocumentControlBar"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-3 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Disable document guides
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Toggles the newbie-friendly guides on/off from the document control bar
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.disableDocumentControlBarGuides"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-3 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Disable document tooltips
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
If you dislike the document-view tooltips, you can turn them off globally here
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.disableDocumentToolTips"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-3 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Hide empty fields
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Hides fields without any filled in value in view (non-edit) mode.
|
||||
<br>
|
||||
Please note that this may result into a relatively wild layout shifts which might make the document look unruly in some cases.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.hideEmptyFields"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="text-h6 q-mt-lg">
|
||||
Quick-search & Quick-add popups
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Stop quick-search close after selection
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Normally the quick-search closes after an item is selected from it.
|
||||
<br>
|
||||
Turning this feature on prevents this behavior; allowing for opening multiple search results one after the other.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.disableCloseAftertSelectQuickSearch"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Don't precheck category filter
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Normally, the categories are included in the quick-search.
|
||||
<br>
|
||||
Enabling this option reverses the behavior.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.disableQuickSearchCategoryPrecheck"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Close quick popups with same key
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
This allows for closing of the quick-search and quick-add popups with the same key combination that was used to open them to begin with.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.allowQuickPopupSameKeyClose"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="text-h6 q-mt-lg">
|
||||
Hierarchy tree
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Stop sublevel collapse in tree
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
This option prevents sub-category closing in the hierarchical tree upon parent category closure
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.doNotcollaseTreeOptions"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Hide project name in tree
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Determines if the the project name shows in the hierarchical tree at all
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.noProjectName"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Invert tree custom order sorting
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Sorts the documents in the hiearachical tree the other way around than normally:
|
||||
<br>
|
||||
From highest to lowest
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.invertTreeSorting"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Hide tags in tree
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Determines if the tags show in the hierarchical tree at all
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.noTags"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Top tags in tree
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Show tags at the top of the hierarchical tree
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.tagsAtTop"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-4 optionWrapper">
|
||||
<div class="optionTitle">
|
||||
Compact tags
|
||||
<q-icon name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
Determine if the tags should be shown as individual categories or they should show as one big category with each tag as a subcategory.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="options.compactTags"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</q-scroll-area>
|
||||
</q-tab-panel>
|
||||
|
||||
<q-tab-panel name="keybinds" dark>
|
||||
<q-table
|
||||
class="keybindsTable"
|
||||
virtual-scroll
|
||||
flat
|
||||
title="Keybinds"
|
||||
:filter="filter"
|
||||
hide-bottom
|
||||
:pagination.sync="pagination"
|
||||
:rows-per-page-options="[0]"
|
||||
:virtual-scroll-sticky-size-start="48"
|
||||
row-key="index"
|
||||
:data="keybindList"
|
||||
:columns="keybindListCollums"
|
||||
>
|
||||
<template v-slot:top-right>
|
||||
<q-input clearable dense debounce="300" v-model="filter" placeholder="Filter the keybinds">
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" />
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props">
|
||||
<q-td
|
||||
key="name"
|
||||
:props="props"
|
||||
v-html="props.row.name"
|
||||
>
|
||||
</q-td>
|
||||
<q-td
|
||||
key="userKeybinds"
|
||||
:props="props"
|
||||
>
|
||||
<template
|
||||
v-if="props.row.editable"
|
||||
>
|
||||
<q-btn
|
||||
:color="(props.row.userKeybind && props.row.userKeybind.which) ? 'accent' : 'primary'"
|
||||
size="12px"
|
||||
outline
|
||||
>
|
||||
{{(props.row.userKeybind && props.row.userKeybind.which) ? retrieveKeybindString(props.row.userKeybind) : 'Add New'}}
|
||||
<q-popup-edit
|
||||
content-class="darkBg"
|
||||
v-model="props.row.userKeybind"
|
||||
@before-show="prepareKeybindSetting(props.row)"
|
||||
@before-hide="processKeybindSetting()"
|
||||
>
|
||||
<q-btn
|
||||
color="dark"
|
||||
round
|
||||
dense
|
||||
flat
|
||||
v-close-popup
|
||||
class="keybindPopupCloseButton"
|
||||
size="md"
|
||||
icon="close"
|
||||
/>
|
||||
<div class="keybindUpdateField">
|
||||
<div class="text-center q-mt-xs q-mb-lg text-dark darkBg__title">{{currentRowData.name}}</div>
|
||||
<q-field filled readonly
|
||||
dense
|
||||
class="q-ml-lg"
|
||||
:dark="false"
|
||||
:label="(tempKeybindString.length === 0)? '> Type your keybind <' : ''"
|
||||
:error="keybindError"
|
||||
:error-message="keybindErrorMessage">
|
||||
<template v-slot:after>
|
||||
<q-icon name="mdi-help-circle" size="23px" class="keybindsTooltipIcon">
|
||||
<q-tooltip :delay="500" content-class="keybindToolTip">
|
||||
Allow keys combination and modifiers:
|
||||
<br>
|
||||
- CTRL + <span class="text-italic text-caption">YOUR KEYBIND HERE</span>
|
||||
<br>
|
||||
- ALT + <span class="text-italic text-caption">YOUR KEYBIND HERE</span>
|
||||
<br>
|
||||
- CTRL + ALT + <span class="text-italic text-caption">YOUR KEYBIND HERE</span>
|
||||
<br>
|
||||
- CTRL + SHIFT + <span class="text-italic text-caption">YOUR KEYBIND HERE</span>
|
||||
<br>
|
||||
- ALT + SHIFT + <span class="text-italic text-caption">YOUR KEYBIND HERE</span>
|
||||
<br>
|
||||
- CTRL + ALT + SHIFT + <span class="text-italic text-caption">YOUR KEYBIND HERE</span>
|
||||
<br>
|
||||
<br>
|
||||
- Your desired keybind can contain any symbol of the alphanumerical part of the keyboard along with all of the F keys and arrow keys.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</template>
|
||||
<template v-slot:control>
|
||||
<div class="self-center full-width no-outline">{{tempKeybindString}}</div>
|
||||
</template>
|
||||
</q-field>
|
||||
<div class="flex justify-around q-mt-md">
|
||||
<q-btn
|
||||
label="Clear keybind"
|
||||
color="secondary"
|
||||
size="14px"
|
||||
v-close-popup
|
||||
@click="resetKeybind"
|
||||
:disable="!(tempKeybindString && tempKeybindString.length > 0)"
|
||||
/>
|
||||
<q-btn
|
||||
label="Set keybind"
|
||||
color="dark"
|
||||
size="14px"
|
||||
v-close-popup
|
||||
@click="setKeybind"
|
||||
:disable="!tempHasChange || (!tempKeybindString || tempKeybindString.length === 0)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</q-popup-edit>
|
||||
</q-btn>
|
||||
|
||||
</template>
|
||||
<template
|
||||
v-if="!props.row.editable"
|
||||
>
|
||||
<span class="text-secondary text-bold">
|
||||
Built-in & uneditable functionality
|
||||
</span>
|
||||
</template>
|
||||
</q-td>
|
||||
<q-td
|
||||
key="defaultKeybinds"
|
||||
:class="{'text-blue-grey-6':props.row.userKeybind && props.row.userKeybind.which}"
|
||||
:props="props"
|
||||
v-html="retrieveKeybindString(props.row.defaultKeybind)"
|
||||
>
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
|
||||
</q-table>
|
||||
</q-tab-panel>
|
||||
|
||||
</q-tab-panels>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right" class="q-mb-lg q-mt-md closeButton">
|
||||
<q-btn flat label="Close without saving" color="accent" class="q-mr-xl" v-close-popup />
|
||||
<q-btn label="Save settings" color="primary" class="q-mx-lg" outline v-close-popup @click="saveSettings" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
|
||||
import DialogBase from "src/components/dialogs/_DialogBase"
|
||||
import { extend } from "quasar"
|
||||
|
||||
import { OptionsStateInteface } from "src/store/module-options/state"
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class ProgramSettings extends DialogBase {
|
||||
/****************************************************************/
|
||||
// DIALOG CONTROL
|
||||
/****************************************************************/
|
||||
|
||||
@Watch("dialogTrigger")
|
||||
openDialog (val: string|false) {
|
||||
if (val) {
|
||||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
this.activeTab = "uiSettings"
|
||||
this.retrieveOptions()
|
||||
this.mapKeybinds()
|
||||
}
|
||||
}
|
||||
|
||||
thumbStyle ={
|
||||
right: "-40px",
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "#61a2bd",
|
||||
width: "5px",
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
activeTab = "uiSettings"
|
||||
|
||||
/****************************************************************/
|
||||
// OPTIONS TAB
|
||||
/****************************************************************/
|
||||
|
||||
options: OptionsStateInteface = {
|
||||
_id: "settings",
|
||||
darkMode: false,
|
||||
textShadow: false,
|
||||
tagsAtTop: false,
|
||||
noTags: false,
|
||||
compactTags: false,
|
||||
noProjectName: false,
|
||||
invertTreeSorting: false,
|
||||
hideEmptyFields: false,
|
||||
disableDocumentToolTips: false,
|
||||
doNotcollaseTreeOptions: false,
|
||||
disableDocumentControlBar: false,
|
||||
disableDocumentControlBarGuides: false,
|
||||
disableCloseAftertSelectQuickSearch: false,
|
||||
disableQuickSearchCategoryPrecheck: false,
|
||||
allowQuickPopupSameKeyClose: false,
|
||||
userKeybindList: []
|
||||
}
|
||||
|
||||
retrieveOptions () {
|
||||
const optionsSnapShot: OptionsStateInteface = extend(true, {}, this.SGET_options)
|
||||
|
||||
this.options = optionsSnapShot
|
||||
}
|
||||
|
||||
saveSettings () {
|
||||
const optionsSnapShot: OptionsStateInteface = extend(true, {}, this.options)
|
||||
optionsSnapShot.userKeybindList = []
|
||||
|
||||
this.keybindList.forEach(e => {
|
||||
this.SSET_deregisterUserKeybind({
|
||||
id: e.id,
|
||||
altKey: e.defaultKeybind.altKey,
|
||||
ctrlKey: e.defaultKeybind.ctrlKey,
|
||||
shiftKey: e.defaultKeybind.shiftKey,
|
||||
which: e.defaultKeybind.which
|
||||
})
|
||||
|
||||
if (e.userKeybind && e.userKeybind.which) {
|
||||
const tempkey = {
|
||||
id: e.id,
|
||||
altKey: e.userKeybind.altKey,
|
||||
ctrlKey: e.userKeybind.ctrlKey,
|
||||
shiftKey: e.userKeybind.shiftKey,
|
||||
which: e.userKeybind.which
|
||||
}
|
||||
|
||||
optionsSnapShot.userKeybindList.push(tempkey)
|
||||
this.SSET_registerUserKeybind(tempkey)
|
||||
}
|
||||
})
|
||||
|
||||
this.SSET_options(optionsSnapShot)
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// KEYBDINS MANAGEMENT
|
||||
/****************************************************************/
|
||||
|
||||
pagination = {
|
||||
rowsPerPage: 0
|
||||
}
|
||||
|
||||
keybindListCollums = [
|
||||
{
|
||||
name: "name",
|
||||
required: true,
|
||||
label: "Action",
|
||||
align: "left",
|
||||
field: (row: {name: string}) => row.name,
|
||||
format: (val: string) => `${val}`,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: "userKeybinds",
|
||||
align: "left",
|
||||
label: "User Keybinds",
|
||||
field: "userKeybind"
|
||||
},
|
||||
{
|
||||
name: "defaultKeybinds",
|
||||
align: "left",
|
||||
label: "Default keybinds",
|
||||
field: "defaultKeybind"
|
||||
}
|
||||
]
|
||||
|
||||
filter = ""
|
||||
|
||||
tempKeybindString = ""
|
||||
tempKeybindData = null as any
|
||||
tempHasChange = false
|
||||
|
||||
keybindList: any[] = []
|
||||
|
||||
keybindError = false
|
||||
keybindErrorMessage = ""
|
||||
|
||||
currentRowData = {} as any
|
||||
|
||||
async resetKeybind () {
|
||||
this.tempKeybindString = ""
|
||||
this.tempKeybindData = null
|
||||
this.keybindError = false
|
||||
|
||||
this.currentRowData.userKeybind = ""
|
||||
|
||||
const temp: any[] = extend(true, [], this.keybindList)
|
||||
|
||||
this.keybindList = []
|
||||
|
||||
await this.$nextTick()
|
||||
|
||||
this.keybindList = temp
|
||||
}
|
||||
|
||||
async setKeybind () {
|
||||
this.currentRowData.userKeybind = this.tempKeybindData
|
||||
const temp: any[] = extend(true, [], this.keybindList)
|
||||
|
||||
this.keybindList = []
|
||||
|
||||
await this.$nextTick()
|
||||
|
||||
this.keybindList = temp
|
||||
}
|
||||
|
||||
processKeybindSetting () {
|
||||
window.removeEventListener("keydown", this.triggerKeyPush)
|
||||
}
|
||||
|
||||
prepareKeybindSetting (row: any) {
|
||||
this.keybindError = false
|
||||
this.tempHasChange = false
|
||||
this.tempKeybindData = (row.userKeybind && row.userKeybind.which) ? this.tempKeybindData : null
|
||||
this.tempKeybindString = (row.userKeybind && row.userKeybind.which) ? this.retrieveKeybindString(row.userKeybind) : ""
|
||||
this.currentRowData = row
|
||||
window.addEventListener("keydown", this.triggerKeyPush)
|
||||
}
|
||||
|
||||
triggerKeyPush (e:any) {
|
||||
this.keybindError = false
|
||||
|
||||
const ignoredKeys = [16, 17, 18, 27]
|
||||
const allowedKeys = [
|
||||
186,
|
||||
187,
|
||||
188,
|
||||
189,
|
||||
190,
|
||||
191,
|
||||
192,
|
||||
219,
|
||||
220,
|
||||
221,
|
||||
222,
|
||||
112,
|
||||
113,
|
||||
114,
|
||||
115,
|
||||
116,
|
||||
117,
|
||||
118,
|
||||
119,
|
||||
120,
|
||||
121,
|
||||
122,
|
||||
123,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
48,
|
||||
49,
|
||||
50,
|
||||
51,
|
||||
52,
|
||||
53,
|
||||
54,
|
||||
55,
|
||||
56,
|
||||
57,
|
||||
65,
|
||||
66,
|
||||
67,
|
||||
68,
|
||||
69,
|
||||
70,
|
||||
71,
|
||||
72,
|
||||
73,
|
||||
74,
|
||||
75,
|
||||
76,
|
||||
77,
|
||||
78,
|
||||
79,
|
||||
80,
|
||||
81,
|
||||
82,
|
||||
83,
|
||||
84,
|
||||
85,
|
||||
86,
|
||||
87,
|
||||
88,
|
||||
89,
|
||||
90
|
||||
]
|
||||
|
||||
// Prevent all non-permitted key presses
|
||||
if ((e?.altKey || e?.ctrlKey) && e?.keyCode && !ignoredKeys.includes(e.which)) {
|
||||
if (allowedKeys.includes(e.which)) {
|
||||
// Check for duplicates already existing in the list
|
||||
const compareList = this.keybindList
|
||||
.filter(e => e.id !== this.currentRowData.id)
|
||||
.map(bind => {
|
||||
const mappedKeybind = (bind.userKeybind && bind.userKeybind.which)
|
||||
? {
|
||||
altKey: bind.userKeybind.altKey,
|
||||
ctrlKey: bind.userKeybind.ctrlKey,
|
||||
shiftKey: bind.userKeybind.shiftKey,
|
||||
which: bind.userKeybind.which,
|
||||
id: this.currentRowData.id
|
||||
}
|
||||
: {
|
||||
altKey: bind.defaultKeybind.altKey,
|
||||
ctrlKey: bind.defaultKeybind.ctrlKey,
|
||||
shiftKey: bind.defaultKeybind.shiftKey,
|
||||
which: bind.defaultKeybind.which,
|
||||
id: this.currentRowData.id
|
||||
}
|
||||
|
||||
return mappedKeybind
|
||||
})
|
||||
|
||||
let duplicate = false
|
||||
compareList.forEach(bind => {
|
||||
if (
|
||||
bind.altKey === e.altKey &&
|
||||
bind.ctrlKey === e.ctrlKey &&
|
||||
bind.shiftKey === e.shiftKey &&
|
||||
bind.which === e.which
|
||||
) {
|
||||
duplicate = true
|
||||
}
|
||||
})
|
||||
|
||||
if (duplicate) {
|
||||
this.keybindError = true
|
||||
this.keybindErrorMessage = "This keybind is already present among the existing ones. Please chose a different one."
|
||||
return
|
||||
}
|
||||
|
||||
// Continue the script if no duplicates were found
|
||||
this.tempHasChange = true
|
||||
this.keybindError = false
|
||||
const keybindString = this.retrieveKeybindString(e)
|
||||
this.tempKeybindString = keybindString
|
||||
this.tempKeybindData = {
|
||||
altKey: e.altKey,
|
||||
ctrlKey: e.ctrlKey,
|
||||
shiftKey: e.shiftKey,
|
||||
which: e.which,
|
||||
id: this.currentRowData.id
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.keybindError = true
|
||||
this.keybindErrorMessage = "Only alphanumerical keys, arrows keys and F keys are allowed for keybinds."
|
||||
}
|
||||
}
|
||||
else if (!ignoredKeys.includes(e.keyCode)) {
|
||||
this.keybindError = true
|
||||
this.keybindErrorMessage = "Only combination containing ALT and/or CTRL allowed."
|
||||
}
|
||||
}
|
||||
|
||||
mapKeybinds () {
|
||||
this.keybindList = this.SGET_getCurrentKeyBindData.defaults.map((keybind, index) => {
|
||||
return {
|
||||
name: keybind.tooltip,
|
||||
id: keybind.id,
|
||||
editable: keybind.editable,
|
||||
defaultKeybind: keybind,
|
||||
userKeybind: (this.options.userKeybindList[index]) || ""
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.keybindsTooltipIcon {
|
||||
right: 0;
|
||||
margin-left: 10px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.keybindToolTip {
|
||||
background-color: white !important;
|
||||
border: 1px solid $dark;
|
||||
}
|
||||
|
||||
.keybindPopupCloseButton {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.keybindUpdateField {
|
||||
width: 550px;
|
||||
padding: 40px;
|
||||
|
||||
.q-field__label {
|
||||
text-align: center;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.q-field__native > div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.q-field__append {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.darkBg {
|
||||
background: $accent;
|
||||
|
||||
.darkBg__title {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.keybindsTable {
|
||||
max-height: calc(100vh - 340px);
|
||||
height: calc(100vh - 340px);
|
||||
margin-top: -25px;
|
||||
|
||||
.q-table__control,
|
||||
.q-table__control label {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.q-table__top,
|
||||
.q-table__bottom,
|
||||
thead tr:first-child th {
|
||||
background-color: var(--q-color-dark);
|
||||
}
|
||||
|
||||
thead tr th {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
thead tr:last-child th {
|
||||
top: 48px;
|
||||
}
|
||||
|
||||
thead tr:first-child th {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
body.body--dark {
|
||||
.programSettingsDialog {
|
||||
.optionTitle,
|
||||
.text-h5,
|
||||
h4 {
|
||||
color: #dcdcdc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.programSettingsDialog {
|
||||
width: 1400px;
|
||||
max-width: calc(100vw - 100px) !important;
|
||||
max-height: calc(100vh - 85px);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.closeButton {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.optionWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
.q-toggle__inner {
|
||||
max-width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
.optionTitle {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.programSettingsTabs {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.programSettingsTabContent {
|
||||
width: calc(100% - 270px);
|
||||
}
|
||||
|
||||
.programSettingsTitle {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.programSettingsScrollArea {
|
||||
max-height: calc(100vh - 357px);
|
||||
margin: auto;
|
||||
height: 740px;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
|
||||
h6 {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md" min="1"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -32,7 +32,8 @@
|
|||
v-model.number="localInput"
|
||||
type="text"
|
||||
@keyup="signalInput"
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
dense
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
|
@ -74,6 +75,16 @@ export default class Field_ColorPicker extends BaseClass {
|
|||
@Prop() readonly editMode!: boolean
|
||||
@Prop() readonly isNew!: boolean
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
changedInput = false
|
||||
localInput = ""
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -16,8 +16,8 @@
|
|||
dense>
|
||||
<q-item v-for="(input,index) in localInput" :key="index">
|
||||
<q-item-section
|
||||
class="fieldList_itemDot"
|
||||
side>
|
||||
class="fieldList_itemDot"
|
||||
side>
|
||||
<q-icon
|
||||
color="primary"
|
||||
name="mdi-menu-right"
|
||||
|
@ -27,7 +27,7 @@
|
|||
<span class="text-weight-medium">
|
||||
{{input.value}}
|
||||
</span>
|
||||
<span v-if="localInput[index].affix" class="inline-block q-ml-xs text-italic">
|
||||
<span v-if="localInput[index].affix" class="inline-block q-ml-xs text-italic listNote">
|
||||
({{localInput[index].affix}})
|
||||
</span>
|
||||
</q-item-section>
|
||||
|
@ -42,9 +42,11 @@
|
|||
<div class="col">
|
||||
<q-input
|
||||
v-model="localInput[index].value"
|
||||
:class="`listField_input${index}_${inputDataBluePrint.id}`"
|
||||
dense
|
||||
@keyup="signalInput"
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
|
@ -59,8 +61,9 @@
|
|||
:options="localExtraInput"
|
||||
use-input
|
||||
:hide-dropdown-icon="!editMode"
|
||||
:outlined="editMode"
|
||||
:outlined="editMode && !isDarkMode"
|
||||
:borderless="!editMode"
|
||||
:filled="editMode && isDarkMode"
|
||||
:readonly="!editMode"
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
|
@ -75,6 +78,7 @@
|
|||
<q-btn
|
||||
v-if="editMode"
|
||||
color="secondary"
|
||||
:outline="isDarkMode"
|
||||
@click="removeFromList(index)"
|
||||
label="Remove" />
|
||||
</div>
|
||||
|
@ -82,7 +86,11 @@
|
|||
|
||||
<div class="row q-mt-xs" v-if="editMode">
|
||||
<div class="col justify-start flex">
|
||||
<q-btn color="primary" :label="`Add new`" @click="addNewInput" />
|
||||
<q-btn
|
||||
color="primary"
|
||||
:outline="isDarkMode"
|
||||
label="Add new"
|
||||
@click="addNewInput" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -122,6 +130,16 @@ export default class Field_List extends BaseClass {
|
|||
|
||||
@Prop() readonly editMode!: boolean
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
changedInput = false
|
||||
localInput = [] as {
|
||||
value: string
|
||||
|
@ -178,11 +196,22 @@ export default class Field_List extends BaseClass {
|
|||
return returnValue
|
||||
}
|
||||
|
||||
addNewInput () {
|
||||
async addNewInput () {
|
||||
this.localInput.push({
|
||||
value: "",
|
||||
affix: ""
|
||||
})
|
||||
|
||||
const targetRefStringNamer = `.listField_input${this.localInput.length - 1}_${this.inputDataBluePrint.id}`
|
||||
|
||||
await this.$nextTick()
|
||||
|
||||
const newInput = document.querySelector(targetRefStringNamer) as HTMLInputElement
|
||||
|
||||
if (newInput) {
|
||||
newInput.focus()
|
||||
}
|
||||
|
||||
this.signalInput()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</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-secondary">WILL NOT</span> have effect on the connected document/s.
|
||||
<q-tooltip :delay="500" v-if="!disableDocumentToolTips">
|
||||
This is a one-way relationship. <br> Editing this value <span class="text-secondary">WILL NOT</span> have any 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.
|
||||
|
@ -19,8 +19,8 @@
|
|||
</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-secondary">WILL</span> also effect the connected document/s.
|
||||
<q-tooltip :delay="500" v-if="!disableDocumentToolTips">
|
||||
This is a two-way relationship. <br> Editing this value <span class="text-secondary">WILL</span> also affect 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.
|
||||
|
@ -79,13 +79,15 @@
|
|||
dark
|
||||
style="flex-grow: 1;"
|
||||
dense
|
||||
@popup-show="reloadAllDocuments"
|
||||
:ref="`multieRelationshipField${this.inputDataBluePrint.id}`"
|
||||
:options="filteredInput"
|
||||
use-input
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
use-chips
|
||||
multiple
|
||||
input-debounce="0"
|
||||
input-debounce="200"
|
||||
v-model="localInput"
|
||||
@filter="filterSelect"
|
||||
@input="signalInput(false)"
|
||||
|
@ -105,6 +107,7 @@
|
|||
</template>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
:class="{'hasTextShadow': textShadow}"
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
>
|
||||
|
@ -152,7 +155,8 @@
|
|||
v-model="singleNote.value"
|
||||
dense
|
||||
@keyup="signalInput(false)"
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
>
|
||||
</q-input>
|
||||
</td>
|
||||
|
@ -200,6 +204,17 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
|
||||
localInput = [] as unknown as I_FieldRelationship[]
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
textShadow = false
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
this.textShadow = options.textShadow
|
||||
}
|
||||
|
||||
@Watch("inputDataValue", { deep: true, immediate: true })
|
||||
reactToInputChanges () {
|
||||
this.localInput = (this.inputDataValue?.value) ? this.inputDataValue.value : []
|
||||
|
@ -248,6 +263,12 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
/* eslint-enable */
|
||||
}
|
||||
|
||||
allDocuments: I_ShortenedDocument[] = []
|
||||
|
||||
async reloadAllDocuments () {
|
||||
this.allDocuments = await this.retrieveAllDocuments()
|
||||
}
|
||||
|
||||
filterSelect (val: string, update: (e: () => void) => void) {
|
||||
if (val === "") {
|
||||
update(() => {
|
||||
|
@ -264,7 +285,7 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
const listCopy : I_ShortenedDocument[] = extend(true, [], this.extraInput)
|
||||
|
||||
// @ts-ignore
|
||||
this.filteredInput = advancedDocumentFilter(needle, listCopy)
|
||||
this.filteredInput = advancedDocumentFilter(needle, listCopy, this.SGET_allBlueprints, this.allDocuments)
|
||||
|
||||
/*eslint-disable */
|
||||
if(this.$refs[`multiRelationshipField${this.inputDataBluePrint.id}`] && this.filteredInput.length > 0){
|
||||
|
@ -321,6 +342,7 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
value: objectDoc._id,
|
||||
type: objectDoc.type,
|
||||
disable: isDisabled,
|
||||
extraFields: objectDoc.extraFields,
|
||||
url: `/project/display-content/${objectDoc.type}/${objectDoc._id}`,
|
||||
label: objectDoc.extraFields.find(e => e.id === "name")?.value,
|
||||
isCategory: objectDoc.extraFields.find(e => e.id === "categorySwitch")?.value,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -43,7 +43,8 @@
|
|||
class="multiSelect"
|
||||
:options="extraInput"
|
||||
use-input
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
use-chips
|
||||
@filter="filterFn"
|
||||
input-debounce="0"
|
||||
|
@ -89,7 +90,6 @@ import { I_ExtraFields } from "src/interfaces/I_Blueprint"
|
|||
})
|
||||
export default class Field_MultiSelect extends BaseClass {
|
||||
@Prop({ default: [] }) readonly inputDataBluePrint!: I_ExtraFields
|
||||
|
||||
@Prop({
|
||||
default: () => {
|
||||
return []
|
||||
|
@ -97,9 +97,18 @@ export default class Field_MultiSelect extends BaseClass {
|
|||
}) readonly inputDataValue!: []
|
||||
|
||||
@Prop() readonly isNew!: boolean
|
||||
|
||||
@Prop() readonly editMode!: boolean
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
changedInput = false
|
||||
localInput = []
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md" min="1"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -28,7 +28,8 @@
|
|||
v-model.number="localInput"
|
||||
type="number"
|
||||
@keyup="signalInput"
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
dense
|
||||
/>
|
||||
|
||||
|
@ -58,6 +59,16 @@ export default class Field_Number extends BaseClass {
|
|||
changedInput = false
|
||||
localInput: null|number = null
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
@Emit()
|
||||
signalInput () {
|
||||
this.changedInput = true
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</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-secondary">WILL NOT</span> have effect on the connected document/s.
|
||||
<q-tooltip :delay="500" v-if="!disableDocumentToolTips">
|
||||
This is a one-way relationship. <br> Editing this value <span class="text-secondary">WILL NOT</span> have any 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.
|
||||
|
@ -19,8 +19,8 @@
|
|||
</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-secondary">WILL</span> also effect the connected document/s.
|
||||
<q-tooltip :delay="500" v-if="!disableDocumentToolTips">
|
||||
This is a two-way relationship. <br> Editing this value <span class="text-secondary">WILL</span> also affect 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.
|
||||
|
@ -79,8 +79,10 @@
|
|||
:ref="`singleRelationshipField${inputDataBluePrint.id}`"
|
||||
:options="filteredInput"
|
||||
use-input
|
||||
outlined
|
||||
input-debounce="0"
|
||||
@popup-show="reloadAllDocuments"
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
input-debounce="200"
|
||||
v-model="localInput"
|
||||
@filter="filterSelect"
|
||||
@input="signalInput(false)"
|
||||
|
@ -102,6 +104,7 @@
|
|||
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
:class="{'hasTextShadow': textShadow}"
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
>
|
||||
|
@ -146,7 +149,8 @@
|
|||
v-model="inputNote.value"
|
||||
dense
|
||||
@keyup="signalInput(false)"
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
>
|
||||
</q-input>
|
||||
</td>
|
||||
|
@ -197,6 +201,17 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
value: ""
|
||||
}
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
textShadow = false
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
this.textShadow = options.textShadow
|
||||
}
|
||||
|
||||
@Watch("inputDataValue", { deep: true, immediate: true })
|
||||
reactToInputChanges () {
|
||||
// @ts-ignore
|
||||
|
@ -232,6 +247,12 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
/* eslint-enable */
|
||||
}
|
||||
|
||||
allDocuments: I_ShortenedDocument[] = []
|
||||
|
||||
async reloadAllDocuments () {
|
||||
this.allDocuments = await this.retrieveAllDocuments()
|
||||
}
|
||||
|
||||
filterSelect (val: string, update: (e: () => void) => void) {
|
||||
if (val === "") {
|
||||
update(() => {
|
||||
|
@ -248,7 +269,7 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
const needle = val.toLowerCase()
|
||||
const listCopy : I_ShortenedDocument[] = extend(true, [], this.extraInput)
|
||||
// @ts-ignore
|
||||
this.filteredInput = advancedDocumentFilter(needle, listCopy)
|
||||
this.filteredInput = advancedDocumentFilter(needle, listCopy, this.SGET_allBlueprints, this.allDocuments)
|
||||
|
||||
if (this.$refs[`singleRelationshipField${this.inputDataBluePrint.id}`] && this.filteredInput.length > 0) {
|
||||
this.refocusSelect().catch(e => console.log(e))
|
||||
|
@ -316,6 +337,7 @@ export default class Field_SingleRelationship extends BaseClass {
|
|||
type: objectDoc.type,
|
||||
icon: objectDoc.icon,
|
||||
disable: isDisabled,
|
||||
extraFields: objectDoc.extraFields,
|
||||
url: `/project/display-content/${objectDoc.type}/${objectDoc._id}`,
|
||||
label: objectDoc.extraFields.find(e => e.id === "name")?.value,
|
||||
color: objectDoc.extraFields.find(e => e.id === "documentColor")?.value,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -32,7 +32,8 @@
|
|||
class="singleSelect"
|
||||
:options="extraInput"
|
||||
use-input
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
@filter="filterFn"
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
|
@ -77,13 +78,20 @@ import { I_ExtraFields } from "src/interfaces/I_Blueprint"
|
|||
})
|
||||
export default class Field_SingleSelect extends BaseClass {
|
||||
@Prop({ default: [] }) readonly inputDataBluePrint!: I_ExtraFields
|
||||
|
||||
@Prop({ default: "" }) readonly inputDataValue!: ""
|
||||
|
||||
@Prop() readonly isNew!: boolean
|
||||
|
||||
@Prop() readonly editMode!: boolean
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
changedInput = false
|
||||
localInput = ""
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md" min="1"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -42,6 +42,16 @@ export default class Field_Switch extends BaseClass {
|
|||
changedInput = false
|
||||
localInput: null|boolean = null
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
@Emit()
|
||||
signalInput () {
|
||||
this.changedInput = true
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -15,7 +15,9 @@
|
|||
>
|
||||
<q-chip
|
||||
v-for="(input,index) in localInput" :key="index"
|
||||
color="gunmetal-light" text-color="satin-sheen-gold-light" class="text-weight-medium">
|
||||
:color="(isDarkMode) ? 'accent' : 'gunmetal-light'"
|
||||
:text-color="(isDarkMode) ? 'dark' :'satin-sheen-gold-light'"
|
||||
:class="(isDarkMode) ? 'text-weight-bold':'text-weight-medium'">
|
||||
{{input}}
|
||||
</q-chip>
|
||||
</div>
|
||||
|
@ -31,7 +33,8 @@
|
|||
class="tagSelect"
|
||||
:options="filteredTags"
|
||||
use-input
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
use-chips
|
||||
@filter="filterFn"
|
||||
input-debounce="0"
|
||||
|
@ -90,6 +93,16 @@ export default class Field_Tags extends BaseClass {
|
|||
|
||||
@Prop() readonly editMode!: boolean
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
changedInput = false
|
||||
localInput: string[] = []
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -27,7 +27,8 @@
|
|||
v-if="editMode"
|
||||
v-model="localInput"
|
||||
@keyup="signalInput"
|
||||
outlined
|
||||
:outlined="!isDarkMode"
|
||||
:filled="isDarkMode"
|
||||
dense
|
||||
:ref="`textField${this.inputDataBluePrint.id}`"
|
||||
>
|
||||
|
@ -60,6 +61,16 @@ export default class Field_Text extends BaseClass {
|
|||
@Prop() readonly editMode!: boolean
|
||||
@Prop() readonly isNew!: boolean
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
changedInput = false
|
||||
localInput = ""
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md">
|
||||
<div class="flex justify-start items-center text-weight-bolder q-mb-sm q-mt-md fieldWysiwygTitle">
|
||||
<q-icon v-if="inputIcon" :name="inputIcon" :size="inputIcon.includes('fas')? '15px': '20px'" class="q-mr-md"/>
|
||||
{{inputDataBluePrint.name}}
|
||||
<q-icon v-if="toolTip" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-icon v-if="toolTip && !disableDocumentToolTips" name="mdi-help-circle" size="16px" class="q-ml-md">
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
|
@ -11,19 +11,22 @@
|
|||
</div>
|
||||
|
||||
<div
|
||||
v-if="!editMode"
|
||||
class="fieldWysiwyg"
|
||||
v-html="localInput">
|
||||
v-if="!editMode"
|
||||
class="fieldWysiwyg"
|
||||
v-html="localInput">
|
||||
</div>
|
||||
|
||||
<q-editor
|
||||
v-model="localInput"
|
||||
:ref="`wysiwygField${this.inputDataBluePrint.id}`"
|
||||
@paste.native="evt => pasteCapture(evt)"
|
||||
:toolbar="wysiwygOptions"
|
||||
:fonts="wysiwygFonts"
|
||||
@input="signalInput"
|
||||
:flat="isDarkMode"
|
||||
v-if="editMode"
|
||||
:definitions="definitions"
|
||||
min-height="250px"
|
||||
min-height="350px"
|
||||
/>
|
||||
|
||||
<div class="separatorWrapper">
|
||||
|
@ -53,6 +56,16 @@ export default class Field_Wysiwyg extends BaseClass {
|
|||
changedInput = false
|
||||
localInput = ""
|
||||
|
||||
isDarkMode = false
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
this.disableDocumentToolTips = options.disableDocumentToolTips
|
||||
}
|
||||
|
||||
@Emit()
|
||||
signalInput () {
|
||||
this.changedInput = true
|
||||
|
@ -72,6 +85,47 @@ export default class Field_Wysiwyg extends BaseClass {
|
|||
this.localInput = this.inputDataValue
|
||||
}
|
||||
|
||||
@Watch("editMode")
|
||||
turnOffFullScreen () {
|
||||
if (!this.editMode && this.$refs[`wysiwygField${this.inputDataBluePrint.id}`]) {
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
this.$refs[`wysiwygField${this.inputDataBluePrint.id}`].exitFullscreen()
|
||||
/* eslint-enable */
|
||||
}
|
||||
}
|
||||
|
||||
pasteCapture (evt: any) {
|
||||
/*eslint-disable */
|
||||
|
||||
// Let inputs do their thing, so we don't break pasting of links.
|
||||
if (evt.target.nodeName === "INPUT") {
|
||||
return
|
||||
}
|
||||
let text, onPasteStripFormattingIEPaste
|
||||
evt.preventDefault()
|
||||
if (evt.originalEvent && evt.originalEvent.clipboardData.getData) {
|
||||
text = evt.originalEvent.clipboardData.getData("text/plain")
|
||||
// @ts-ignore
|
||||
this.$refs[`wysiwygField${this.inputDataBluePrint.id}`].runCmd("insertText", text)
|
||||
}
|
||||
else if (evt.clipboardData && evt.clipboardData.getData) {
|
||||
text = evt.clipboardData.getData("text/plain")
|
||||
// @ts-ignore
|
||||
this.$refs[`wysiwygField${this.inputDataBluePrint.id}`].runCmd("insertText", text)
|
||||
}
|
||||
// @ts-ignore
|
||||
else if (window.clipboardData && window.clipboardData.getData) {
|
||||
if (!onPasteStripFormattingIEPaste) {
|
||||
onPasteStripFormattingIEPaste = true
|
||||
// @ts-ignore
|
||||
this.$refs[`wysiwygField${this.inputDataBluePrint.id}`].runCmd("ms-pasteTextOnly", text)
|
||||
}
|
||||
onPasteStripFormattingIEPaste = false
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
definitions = {
|
||||
fullscreen: { label: "Fullscreen" }
|
||||
}
|
||||
|
@ -150,7 +204,7 @@ export default class Field_Wysiwyg extends BaseClass {
|
|||
|
||||
<style lang='scss'>
|
||||
.fieldWysiwyg {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
|
|
184
src/css/app.scss
184
src/css/app.scss
|
@ -3,15 +3,17 @@
|
|||
@import './app/customColors.scss';
|
||||
|
||||
* {
|
||||
letter-spacing: 0.025em;
|
||||
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
::-webkit-scrollbar-track {
|
||||
background: $dark;
|
||||
background: var(--q-color-dark);
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
|
@ -37,14 +39,145 @@ body {
|
|||
|
||||
/* WebKit/Blink Browsers */
|
||||
::selection {
|
||||
background: lighten($dark, 30);
|
||||
color: white;
|
||||
color: lighten($primary, 25);
|
||||
background: lighten($secondary, 10);
|
||||
}
|
||||
|
||||
/* Gecko Browsers */
|
||||
::-moz-selection {
|
||||
background: lighten($dark, 30);
|
||||
color: white;
|
||||
color: lighten($primary, 25);
|
||||
background: lighten($secondary, 10);
|
||||
}
|
||||
|
||||
&.body--dark {
|
||||
background: #303742;
|
||||
|
||||
/* WebKit/Blink Browsers */
|
||||
::selection {
|
||||
color: lighten($primary, 25);
|
||||
background: lighten($secondary, 7);
|
||||
}
|
||||
|
||||
/* Gecko Browsers */
|
||||
::-moz-selection {
|
||||
color: lighten($primary, 25);
|
||||
background: lighten($secondary, 7);
|
||||
}
|
||||
|
||||
.q-editor {
|
||||
border: none !important;
|
||||
background-color: #303742;
|
||||
color: #dcdcdc;
|
||||
}
|
||||
|
||||
.q-field__control {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.q-markdown {
|
||||
color: #d4d0c9;
|
||||
}
|
||||
|
||||
.existingDocumentSelect,
|
||||
.newDocumentSelect {
|
||||
.q-field__input,
|
||||
.q-icon,
|
||||
.q-field__native span {
|
||||
color: #d4d0c9 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.q-editor__content {
|
||||
background-color: #4c515a;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.q-editor__toolbars-container {
|
||||
background-color: rgba(#000, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.q-editor {
|
||||
background-color: rgba(250, 250, 250, 1);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.fieldWysiwyg,
|
||||
.q-editor__content,
|
||||
.fieldWysiwygTitle,
|
||||
.q-editor__toolbars-container {
|
||||
max-width: 1040px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fieldWysiwyg {
|
||||
font-size: 16px;
|
||||
text-align: justify;
|
||||
|
||||
> div {
|
||||
margin: 12.5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.q-editor__content {
|
||||
padding: 35px 50px;
|
||||
line-height: 1.7;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.25);
|
||||
border-radius: 2px;
|
||||
font-size: 16px;
|
||||
text-align: justify;
|
||||
|
||||
* {
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
> div {
|
||||
margin: 12.5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.q-editor__toolbars-container {
|
||||
padding: 5px;
|
||||
max-width: 1200px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
background-color: rgba($dark, 0.05);
|
||||
}
|
||||
|
||||
.q-editor.fullscreen {
|
||||
top: 40px !important;
|
||||
height: calc(100vh - 40px) !important;
|
||||
padding: 10px 0 15px;
|
||||
|
||||
.q-editor__content {
|
||||
padding: 35px 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.q-editor__toolbar {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.q-item {
|
||||
&.hasTextShadow {
|
||||
$shadowColorOutline: #000;
|
||||
$shadowColorSurround: #000;
|
||||
|
||||
filter: drop-shadow(0 0 4px #000);
|
||||
font-weight: 500;
|
||||
text-shadow:
|
||||
-2px -2px 0 $shadowColorSurround,
|
||||
2px -2px 0 $shadowColorSurround,
|
||||
-2px 2px 0 $shadowColorSurround,
|
||||
2px 2px 0 $shadowColorSurround,
|
||||
-1px -1px 0 $shadowColorOutline,
|
||||
1px -1px 0 $shadowColorOutline,
|
||||
-1px 1px 0 $shadowColorOutline,
|
||||
1px 1px 0 $shadowColorOutline;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,6 +211,14 @@ body {
|
|||
left: calc(100% - 30px);
|
||||
}
|
||||
|
||||
.existingDocumentPopup,
|
||||
.newDocumentPopup {
|
||||
.q-checkbox__bg {
|
||||
border-color: #d4d0c9 !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tagSelect,
|
||||
.singleSelect,
|
||||
.multiSelect,
|
||||
|
@ -120,6 +261,15 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.existingDocumentSelect,
|
||||
.newDocumentSelect {
|
||||
.q-field__input,
|
||||
.q-icon,
|
||||
.q-field__native span {
|
||||
color: #d4d0c9 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.q-menu .q-item {
|
||||
transition: none !important;
|
||||
}
|
||||
|
@ -151,11 +301,6 @@ body {
|
|||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.q-editor.fullscreen {
|
||||
top: 40px !important;
|
||||
height: calc(100vh - 40px) !important;
|
||||
}
|
||||
|
||||
body .q-item--active:not(.noHigh) {
|
||||
color: inherit;
|
||||
|
||||
|
@ -192,6 +337,13 @@ body .q-tooltip {
|
|||
.q-markdown {
|
||||
line-height: 1.75;
|
||||
|
||||
.q-markdown--token {
|
||||
font-weight: 600;
|
||||
padding: 0 5px;
|
||||
background-color: $accent !important;
|
||||
color: $dark !important;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
@ -211,3 +363,15 @@ body .q-tooltip {
|
|||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.q-splitter__before {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.q-splitter__after {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.q-splitter__separator {
|
||||
z-index: 3;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// Tip: Use the "Theme Builder" on Quasar's documentation website.
|
||||
|
||||
$primary : #d7ac47;
|
||||
$secondary : #f72e43;
|
||||
$secondary : #f75746;
|
||||
$accent : #dde4e4;
|
||||
|
||||
$dark : #18303a;
|
||||
|
@ -26,9 +26,10 @@ $warning : #f2c037;
|
|||
$customColors: (
|
||||
'gunmetal': #18303a,
|
||||
'gunmetal-light': lighten(#18303a, 7.5),
|
||||
'gunmetal-lighter': lighten(#18303a, 10),
|
||||
'gunmetal-bright': lighten(#18303a, 50),
|
||||
'gunmetal-shine': lighten(#18303a, 60),
|
||||
'ruby-red': #f72e43,
|
||||
'ruby-red': #f75746,
|
||||
'satin-sheen-gold': #d7ac47,
|
||||
'satin-sheen-gold-dark': darken(#d7ac47, 12.5),
|
||||
'satin-sheen-gold-light': lighten(#d7ac47, 7.5),
|
||||
|
|
|
@ -36,6 +36,9 @@ The search itself works the following: You can search any amount of words and th
|
|||
|
||||
Except for the advanced search functionality, Fantasia Archive also offers instant filtering via multiple attributes for further narrowing search results.
|
||||
|
||||
- **NOTE: All of the following filter values (including the Full-search filtering in the next section) support matching any part of the search-text with any part of the search-term**
|
||||
- Example: `>nada` will match with `Continent > North America > Canada > Toronto`
|
||||
|
||||
### The filtering works in the following ways and follows these rules
|
||||
|
||||
- **Any of the following filter terms will not conflict with the normal word search**
|
||||
|
@ -50,3 +53,31 @@ Except for the advanced search functionality, Fantasia Archive also offers insta
|
|||
- `#` - Symbol for tag search
|
||||
- `>` - Symbol for hierarchical path search
|
||||
|
||||
## Full-search filtering
|
||||
|
||||
This feature is meant mostly for those in need of full-scale search that can crawl through any field in any document to match any value field in almost anywhere. Full-search filtering allows the user to narrow down the search marginally by digging through the whole document database and pinpointing exactly what is needed.
|
||||
|
||||
### A few words of caution
|
||||
|
||||
**The full-search is a very powerful, but also demanding tool - the more your project will grow, the more demanding it will become. This means that if you for example have 2000+ documents in your project and the search algorithm will have to go crawl through all of them, then the full-search might take a few second to reload your search results - please keep this in mind when using this feature: It can potentially be A LOT of data.**
|
||||
|
||||
### The filtering works in the following ways and follows these rules
|
||||
|
||||
- **The full-search can be used in combination with any other filters and/or normal search terms**
|
||||
- **It is possible to have only a single instance of the full-search present in the search at once**
|
||||
- **The filter is case-insensitive, which means that you can type everything in UPPER or lower case, it won't matter**
|
||||
- **In the case of lists and multi-relationships, all the entered values get converted to one big text-line for the sake of searching**
|
||||
- Example with a field called `Local currencies`:
|
||||
- Original values: `Canadian Dollar` `American Dollar` `Euro` `Klingon Darsek`
|
||||
- Converted values: `canadian-dollar-american-dollar-euro-klingon-darsek`
|
||||
- **The following filter terms must be used inside of the search term**
|
||||
- `%` - Symbol for the beginning full-search
|
||||
- `:` - Symbol for the division between the field-name and field value
|
||||
- **If your filter-term contained whitespaces, replace them with the `-` symbol**
|
||||
- Example: You wish to search for a field called `Local Currencies` that contains `Canadian Dollars` as value, to fully match this tag, you will need to type `%local-currencies:canadian-dollars`
|
||||
- **A list of fields/field types the full-search doesn't work with:**
|
||||
- The `Break` field type (these are the big titles present throughout the document)
|
||||
- The `Tags` field type (this one is covered with a more sophisticated tag filter)
|
||||
- The `Switch` field type (this one doesn't contain any text values to even filter)
|
||||
- The `Name` field (this one is the main concern of the search and the normal search is far more advanced for searching through this one)
|
||||
- The `Belongs under` field (this one is covered by a much more advanced hierarchical path search)
|
||||
|
|
|
@ -3,6 +3,67 @@
|
|||
|
||||
---
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### 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 bug that was preventing the text editor field from closing the full-screen view upon saving via the CTRL+S shortcut while in the full-screen mode.
|
||||
- Fixed a bug that was causing top level documents to randomly expand their respect document type when opened in the active tab list
|
||||
- Fixed a small bug causing newly created documents to "bounce around" or scroll roughly to the half of the document on their own
|
||||
- Fixed a bug with filter via the document type that was cuasing the filter to search by document type ID instead of the actual name
|
||||
- Fixed a bug where the big text editor field was also copying input text styles (colors, backgrounds, fonts)
|
||||
- Globally changed a typo in "Connected to myths. legends and stories" field
|
||||
- Globally changed a typo in the tooltip of "Tags" field
|
||||
- Globally changed a typo in the tooltip of "Scientifical" to "Scientific"
|
||||
- Reworded and fixed typos in the Single and Mutli relationship field tooltips
|
||||
- Fixed horizontal scrollbar looks and functionality
|
||||
- Fixed a bug that was causing keybinds to register and affect the UI even if a popup was opened over it
|
||||
|
||||
### New features
|
||||
|
||||
- Added a custom keybind support to the app
|
||||
- Added a resizeable hieararchical tree for all your categorical needs
|
||||
- The app also remembers the tree-size on restart so your prefered width gets transfered between your world-building sessions
|
||||
- Added dark mode
|
||||
- Restyled and pimped-up text editor field to replace most of your MS-word needs (obviously supports both light and dark modes properly)!
|
||||
- Added a specific field/value support for the relationship and quick-search popups
|
||||
- This also means added suppoirt for filtering by document color
|
||||
- Added automatic sub-category closure in the hierarchical tree when closing the parent category
|
||||
- Added new App option keybind
|
||||
- Added App options
|
||||
- Added option: Dark mode
|
||||
- Added option: Accessibility - Text shadow
|
||||
- Added option: Disable document control bar
|
||||
- Added option: Disable document guides
|
||||
- Added option: Disable document tooltips
|
||||
- Added option: Hide empty fields
|
||||
- Added option: Stop quick-search close after selection
|
||||
- Added option: Don't precheck category filter
|
||||
- Added option: Close quick popups with same key
|
||||
- Added option: Stop sublevel collapse in tree
|
||||
- Added option: Hide project name in tree
|
||||
- Added option: Invert tree custom order sorting
|
||||
- Added option: Hide tags in tree
|
||||
- Added option: Top tags in tree
|
||||
- Added option: Compact tags
|
||||
|
||||
### QoL adjustments
|
||||
|
||||
- Globally renamed "Color" field to "Text Color" in order to allow better filtering via field-search for future addition of background color support
|
||||
- Added a more contrasting text-select colors for dark mode
|
||||
- Added Quick add/search popup functionality to the Project menu
|
||||
- Added icons to the app menus
|
||||
- Added a small debounce timer to the relationship searches in order to reduce the of lag it was causing
|
||||
- Lightly touched up on the color scheme
|
||||
- Increased readability of highlit bits of the Advanced search guide
|
||||
- Added an auto-select of the newly added field upon adding new text items in the list field-type
|
||||
|
||||
---
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Known issues
|
||||
|
|
5
src/globals.d.ts
vendored
5
src/globals.d.ts
vendored
|
@ -2,3 +2,8 @@ declare module "*.md"{
|
|||
const content: string
|
||||
export default content
|
||||
}
|
||||
|
||||
declare module "*.png"{
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ export interface I_KeyPressObject {
|
|||
altKey: boolean
|
||||
ctrlKey: boolean
|
||||
shiftKey: boolean
|
||||
keyCode: number
|
||||
which: number
|
||||
editable?: boolean
|
||||
id?: string
|
||||
tooltip?: string
|
||||
|
|
|
@ -1,48 +1,62 @@
|
|||
<template>
|
||||
<q-layout view="hHh LpR lfr">
|
||||
|
||||
<!-- Left drawer -->
|
||||
<q-drawer
|
||||
content-class="bg-dark text-cultured sideWrapper"
|
||||
v-model="leftDrawerOpen"
|
||||
side="left"
|
||||
:width=375
|
||||
show-if-above
|
||||
>
|
||||
|
||||
<objectTree/>
|
||||
|
||||
</q-drawer>
|
||||
|
||||
<!-- Header -->
|
||||
<appHeader
|
||||
:is-project="true"
|
||||
/>
|
||||
|
||||
<q-page-container>
|
||||
<documentControl/>
|
||||
<transition
|
||||
enter-active-class="animated fadeIn"
|
||||
leave-active-class="animated fadeOut"
|
||||
appear
|
||||
:duration="150"
|
||||
<q-splitter
|
||||
v-model="splitterModel"
|
||||
unit="px"
|
||||
emit-immediately
|
||||
:class="splitterClass"
|
||||
@input="onChange"
|
||||
:limits="[374, Infinity]"
|
||||
class="pageSplitter"
|
||||
>
|
||||
<router-view :key="$route.path" />
|
||||
</transition>
|
||||
</q-page-container>
|
||||
|
||||
<template #before>
|
||||
<!-- Left drawer -->
|
||||
<q-drawer
|
||||
content-class="bg-dark text-cultured sideWrapper"
|
||||
v-model="leftDrawerOpen"
|
||||
side="left"
|
||||
:width="drawerWidth"
|
||||
:breakpoint="0"
|
||||
show-if-above
|
||||
>
|
||||
<objectTree/>
|
||||
</q-drawer>
|
||||
</template>
|
||||
<template #after>
|
||||
<q-page-container :style="compPadding">
|
||||
<documentControl/>
|
||||
<transition
|
||||
enter-active-class="animated fadeIn"
|
||||
leave-active-class="animated fadeOut"
|
||||
appear
|
||||
:duration="150"
|
||||
>
|
||||
<router-view :key="$route.path" />
|
||||
</transition>
|
||||
</q-page-container>
|
||||
</template>
|
||||
</q-splitter>
|
||||
</q-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component } from "vue-property-decorator"
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
import BaseClass from "src/BaseClass"
|
||||
|
||||
import objectTree from "src/components/ObjectTree.vue"
|
||||
import appHeader from "src/components/AppHeader.vue"
|
||||
import documentControl from "src/components/DocumentControl.vue"
|
||||
|
||||
import { extend } from "quasar"
|
||||
import { OptionsStateInteface } from "src/store/module-options/state"
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
objectTree,
|
||||
|
@ -59,7 +73,48 @@ export default class DocumentLayout extends BaseClass {
|
|||
* Model for the left drawer of the app containing the hierarchical tree
|
||||
*/
|
||||
leftDrawerOpen = true
|
||||
|
||||
splitterModel = 374
|
||||
|
||||
disableDocumentToolTips = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
if (options.treeWidth) {
|
||||
this.splitterModel = options.treeWidth
|
||||
}
|
||||
}
|
||||
|
||||
get drawerWidth () {
|
||||
return this.splitterModel + 1
|
||||
}
|
||||
|
||||
get splitterClass () {
|
||||
return !this.leftDrawerOpen ? "splitt" : ""
|
||||
}
|
||||
|
||||
get compPadding () {
|
||||
return this.leftDrawerOpen ? { paddingLeft: "0px" } : ""
|
||||
}
|
||||
|
||||
pullTimer = null as any
|
||||
|
||||
onChange (value: number) {
|
||||
this.leftDrawerOpen = value > 0
|
||||
|
||||
const optionsSnapShot: OptionsStateInteface = extend(true, {}, this.SGET_options)
|
||||
|
||||
optionsSnapShot.treeWidth = this.splitterModel
|
||||
|
||||
clearTimeout(this.pullTimer)
|
||||
|
||||
this.pullTimer = setTimeout(() => {
|
||||
this.SSET_options(optionsSnapShot)
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -67,4 +122,25 @@ export default class DocumentLayout extends BaseClass {
|
|||
outline: none !important;
|
||||
}
|
||||
|
||||
.splitt {
|
||||
.q-splitter__before {
|
||||
transition: width 0.2s ease-out;
|
||||
width: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.pageSplitter {
|
||||
aside {
|
||||
height: calc(100% - 55px) !important;
|
||||
margin-top: 55px !important;
|
||||
}
|
||||
|
||||
.q-splitter__separator {
|
||||
background-color: transparent;
|
||||
height: calc(100vh - 95px);
|
||||
bottom: 0;
|
||||
top: 95px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,13 +1,100 @@
|
|||
<template>
|
||||
<q-page class="q-pa-xl"
|
||||
<q-page
|
||||
class="documentDisplay"
|
||||
:class="{
|
||||
'q-pb-xl q-pl-xl q-pr-xl': disableDocumentControlBar,
|
||||
'q-pa-xl': !disableDocumentControlBar,
|
||||
'hiddenFields': hideEmptyFields
|
||||
}"
|
||||
v-if="bluePrintData"
|
||||
>
|
||||
|
||||
<!-- Delele document dialog -->
|
||||
<deleteDocumentCheckDialog
|
||||
:dialog-trigger="deleteObjectDialogTrigger"
|
||||
@trigger-dialog-close="deleteObjectDialogClose"
|
||||
/>
|
||||
|
||||
<div class="row justify-start q-col-gutter-x-xl">
|
||||
|
||||
<div
|
||||
class="flex justify-end localControlRow"
|
||||
v-if="disableDocumentControlBar"
|
||||
>
|
||||
|
||||
<q-btn
|
||||
:color="(hasEdits) ? 'teal-14' : 'primary'"
|
||||
icon="mdi-content-save"
|
||||
@click="saveCurrentDocument"
|
||||
:outline="isDarkMode"
|
||||
class="q-mr-md"
|
||||
v-if="editMode"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
>
|
||||
Save current document
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="mdi-file-document-edit"
|
||||
@click="toggleEditMode"
|
||||
:outline="isDarkMode"
|
||||
class="q-mr-md"
|
||||
v-if="!editMode"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
>
|
||||
Edit current document
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="mdi-file-tree"
|
||||
@click="addNewUnderParent"
|
||||
:outline="isDarkMode"
|
||||
class="q-mr-md"
|
||||
v-if="!currentData.isNew"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom middle"
|
||||
self="top middle"
|
||||
>
|
||||
Add new document with the current one as parent
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-btn
|
||||
color="secondary"
|
||||
icon="mdi-text-box-remove-outline"
|
||||
:outline="isDarkMode"
|
||||
@click="deleteObjectAssignUID"
|
||||
v-if="!currentData.isNew"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
anchor="bottom left"
|
||||
self="top middle"
|
||||
>
|
||||
Delete current document
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="`col-${field.sizing} q-mb-md`"
|
||||
v-for="field in bluePrintData.extraFields"
|
||||
:key="field.id"
|
||||
v-show="determineFieldValue(field) || editMode"
|
||||
>
|
||||
|
||||
<Field_Break
|
||||
|
@ -149,6 +236,7 @@ import PouchDB from "pouchdb"
|
|||
import { extend } from "quasar"
|
||||
|
||||
import { saveDocument } from "src/scripts/databaseManager/documentManager"
|
||||
import deleteDocumentCheckDialog from "src/components/dialogs/DeleteDocumentCheck.vue"
|
||||
|
||||
import Field_Break from "src/components/fields/Field_Break.vue"
|
||||
import Field_Text from "src/components/fields/Field_Text.vue"
|
||||
|
@ -176,7 +264,9 @@ import Field_Tags from "src/components/fields/Field_Tags.vue"
|
|||
Field_SingleRelationship,
|
||||
Field_MultiRelationship,
|
||||
Field_Wysiwyg,
|
||||
Field_Tags
|
||||
Field_Tags,
|
||||
|
||||
deleteDocumentCheckDialog
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -185,15 +275,35 @@ export default class PageDocumentDisplay extends BaseClass {
|
|||
* Watches on changes of the route in order to load proper blueprint and object data
|
||||
*/
|
||||
@Watch("$route", { immediate: true, deep: true })
|
||||
onUrlChange () {
|
||||
this.reloadLocalContent().catch(e => console.log(e))
|
||||
async onUrlChange () {
|
||||
await this.sleep(50)
|
||||
window.scrollTo({ top: 0, behavior: "auto" })
|
||||
|
||||
await this.reloadLocalContent().catch(e => console.log(e))
|
||||
|
||||
window.scrollTo({ top: 0, behavior: "auto" })
|
||||
}
|
||||
|
||||
hasEdits = false
|
||||
|
||||
checkHasEdits () {
|
||||
const currentDocument = this.findRequestedOrActiveDocument()
|
||||
|
||||
if (currentDocument && currentDocument.hasEdits) {
|
||||
this.hasEdits = true
|
||||
}
|
||||
else {
|
||||
this.hasEdits = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watches on changes of the opened documents in order to load proper blueprint and object data
|
||||
*/
|
||||
@Watch("SGET_allOpenedDocuments", { deep: true })
|
||||
@Watch("SGET_allOpenedDocuments", { immediate: true, deep: true })
|
||||
async onDocChange () {
|
||||
this.checkHasEdits()
|
||||
|
||||
await this.sleep(300)
|
||||
|
||||
const matchingDoc = this.findRequestedOrActiveDocument()
|
||||
|
@ -202,6 +312,18 @@ export default class PageDocumentDisplay extends BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
disableDocumentControlBar = false
|
||||
isDarkMode = false
|
||||
hideEmptyFields = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.disableDocumentControlBar = options.disableDocumentControlBar
|
||||
this.isDarkMode = options.darkMode
|
||||
this.hideEmptyFields = options.hideEmptyFields
|
||||
}
|
||||
|
||||
async reloadLocalContent () {
|
||||
// Determine the type and retrieve the right blueprint
|
||||
this.bluePrintData = this.retrieveDocumentBlueprint()
|
||||
|
@ -545,9 +667,100 @@ export default class PageDocumentDisplay extends BaseClass {
|
|||
fieldLimiter (currentFieldID: string) {
|
||||
const isCategory = this.retrieveFieldValue(this.currentData, "categorySwitch")
|
||||
|
||||
const ignoredList = ["breakBasic", "name", "documentColor", "parentDoc", "order", "categorySwitch"]
|
||||
const ignoredList = ["breakBasic", "name", "documentColor", "parentDoc", "order", "categorySwitch", "tags"]
|
||||
return (!isCategory || ignoredList.includes(currentFieldID))
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Delete dialog
|
||||
/****************************************************************/
|
||||
|
||||
deleteObjectDialogTrigger: string | false = false
|
||||
deleteObjectDialogClose () {
|
||||
this.deleteObjectDialogTrigger = false
|
||||
}
|
||||
|
||||
deleteObjectAssignUID () {
|
||||
this.deleteObjectDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Add new document under parent
|
||||
/****************************************************************/
|
||||
addNewUnderParent () {
|
||||
const currentDoc = this.findRequestedOrActiveDocument()
|
||||
if (currentDoc) {
|
||||
const routeObject = {
|
||||
_id: currentDoc.type,
|
||||
parent: currentDoc._id
|
||||
}
|
||||
// @ts-ignore
|
||||
this.addNewObjectRoute(routeObject)
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Toggle edit mode & Save document
|
||||
/****************************************************************/
|
||||
|
||||
toggleEditMode () {
|
||||
const currentDoc = this.findRequestedOrActiveDocument()
|
||||
if (currentDoc && !currentDoc.editMode) {
|
||||
const dataCopy: I_OpenedDocument = extend(true, {}, currentDoc)
|
||||
dataCopy.editMode = true
|
||||
const dataPass = { doc: dataCopy, treeAction: false }
|
||||
this.SSET_updateOpenedDocument(dataPass)
|
||||
}
|
||||
}
|
||||
|
||||
async saveCurrentDocument () {
|
||||
if (document.activeElement) {
|
||||
(document.activeElement as HTMLElement).blur()
|
||||
}
|
||||
|
||||
const currentDoc = this.findRequestedOrActiveDocument()
|
||||
|
||||
const allDocuments = this.SGET_allOpenedDocuments
|
||||
|
||||
const docCopy: I_OpenedDocument[] = extend(true, [], allDocuments.docs)
|
||||
|
||||
if (currentDoc) {
|
||||
// @ts-ignore
|
||||
const savedDocument: {
|
||||
documentCopy: I_OpenedDocument,
|
||||
allOpenedDocuments: I_OpenedDocument[]
|
||||
} = await saveDocument(currentDoc, docCopy)
|
||||
|
||||
// Update the opened document
|
||||
const dataPass = { doc: savedDocument.documentCopy, treeAction: true }
|
||||
this.SSET_updateOpenedDocument(dataPass)
|
||||
|
||||
// Update all others
|
||||
for (const doc of savedDocument.allOpenedDocuments) {
|
||||
// Update the opened document
|
||||
const dataPass = { doc: doc, treeAction: true }
|
||||
this.SSET_updateOpenedDocument(dataPass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
determineFieldValue (field: any) {
|
||||
if (!this.hideEmptyFields) {
|
||||
return true
|
||||
}
|
||||
|
||||
const value = this.retrieveFieldValue(this.currentData, field.id)
|
||||
|
||||
if (!value ||
|
||||
(Array.isArray(value) && value.length === 0) ||
|
||||
// @ts-ignore
|
||||
(value?.value && value.value.length === 0) ||
|
||||
// @ts-ignore
|
||||
(value.value === null)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -573,4 +786,96 @@ export default class PageDocumentDisplay extends BaseClass {
|
|||
.q-field {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.documentDisplay {
|
||||
&.hiddenFields {
|
||||
padding-top: 105px;
|
||||
}
|
||||
|
||||
.localControlRow {
|
||||
position: absolute;
|
||||
right: 48px;
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
/* WebKit/Blink Browsers */
|
||||
::selection {
|
||||
background: lighten($dark, 30);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Gecko Browsers */
|
||||
::-moz-selection {
|
||||
background: lighten($dark, 30);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
body.body--dark {
|
||||
.documentDisplay {
|
||||
|
||||
/* WebKit/Blink Browsers */
|
||||
::selection {
|
||||
color: lighten($primary, 25);
|
||||
background: lighten($secondary, 7);
|
||||
}
|
||||
|
||||
/* Gecko Browsers */
|
||||
::-moz-selection {
|
||||
color: lighten($primary, 25);
|
||||
background: lighten($secondary, 7);
|
||||
}
|
||||
$darkModeText: #dcdcdc;
|
||||
|
||||
color: $darkModeText;
|
||||
|
||||
.connectionList .connectionNote,
|
||||
.listNote {
|
||||
color: $darkModeText;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.q-list--dark,
|
||||
.q-item--dark,
|
||||
.q-field--dark .q-field__native,
|
||||
.q-field--dark .q-field__prefix,
|
||||
.q-field--dark .q-field__suffix,
|
||||
.q-field--dark .q-field__input {
|
||||
color: $darkModeText;
|
||||
}
|
||||
|
||||
.q-separator {
|
||||
opacity: 0.85;
|
||||
background-color: $primary !important;
|
||||
}
|
||||
|
||||
.q-field--dark .q-field__control::before {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
opacity: 0.6;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tagSelect,
|
||||
.singleSelect,
|
||||
.multiSelect,
|
||||
.singleRelashionshipSelect,
|
||||
.multiRelashionshipSelect,
|
||||
.existingDocumentSelect,
|
||||
.newDocumentSelect {
|
||||
&.q-field--dark .q-field__control::before {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.q-field__input,
|
||||
.q-icon,
|
||||
.q-field__native span {
|
||||
color: $darkModeText !important;
|
||||
|
||||
&.q-chip__icon--remove {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
v-if="projectExists"
|
||||
color="primary"
|
||||
size="md"
|
||||
:outline="isDarkMode"
|
||||
class="q-px-xl q-py-xs"
|
||||
to="/project"
|
||||
>
|
||||
|
@ -33,6 +34,7 @@
|
|||
<q-btn
|
||||
color="primary"
|
||||
size="md"
|
||||
:outline="isDarkMode"
|
||||
class="q-px-xl q-py-xs"
|
||||
@click="newProjectAssignUID"
|
||||
>
|
||||
|
@ -43,6 +45,7 @@
|
|||
<div class="col-12 q-mb-lg">
|
||||
<q-btn
|
||||
color="primary"
|
||||
:outline="isDarkMode"
|
||||
size="md"
|
||||
class="q-px-xl q-py-xs"
|
||||
@click="importProjectAssignUID()"
|
||||
|
@ -55,7 +58,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component } from "vue-property-decorator"
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
|
||||
import BaseClass from "src/BaseClass"
|
||||
import importProjectCheckDialog from "src/components/dialogs/ImportProjectCheck.vue"
|
||||
|
@ -71,6 +74,14 @@ import { retrieveCurrentProjectName } from "src/scripts/projectManagement/projec
|
|||
}
|
||||
})
|
||||
export default class WelcomeScreen extends BaseClass {
|
||||
isDarkMode = false
|
||||
|
||||
@Watch("SGET_options", { immediate: true, deep: true })
|
||||
onSettingsChange () {
|
||||
const options = this.SGET_options
|
||||
this.isDarkMode = options.darkMode
|
||||
}
|
||||
|
||||
projectExists: undefined | string | boolean = false
|
||||
newProjectName = ""
|
||||
newProjectDialog = false
|
||||
|
|
|
@ -5,18 +5,29 @@ export const defaultKeybinds = [
|
|||
altKey: true,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 75,
|
||||
which: 75,
|
||||
editable: true,
|
||||
id: "openKeybindsCheatsheet",
|
||||
tooltip: "Open keybind cheatsheet"
|
||||
},
|
||||
|
||||
// Open app options - CTRL + ALT + J
|
||||
{
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
which: 74,
|
||||
editable: true,
|
||||
id: "openAppOptions",
|
||||
tooltip: "Open Fantasia Archive options"
|
||||
},
|
||||
|
||||
// Quick new document - CTRL + N
|
||||
{
|
||||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 78,
|
||||
which: 78,
|
||||
editable: true,
|
||||
id: "quickNewDocument",
|
||||
tooltip: "Quick-add new document"
|
||||
|
@ -27,7 +38,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 81,
|
||||
which: 81,
|
||||
editable: true,
|
||||
id: "quickExistingDocument",
|
||||
tooltip: "Quick-search existing document"
|
||||
|
@ -38,7 +49,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
keyCode: 81,
|
||||
which: 81,
|
||||
editable: true,
|
||||
id: "focusHierarchicalTree",
|
||||
tooltip: "Focus search field in the left hierarchical tree"
|
||||
|
@ -49,10 +60,10 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
keyCode: 87,
|
||||
which: 87,
|
||||
editable: true,
|
||||
id: "clearInputHierarchicalTree",
|
||||
tooltip: "Clears any input in the search field in the left hierarchical tree"
|
||||
tooltip: "Clear any input in the search field in the left hierarchical tree"
|
||||
},
|
||||
|
||||
// Close tab - CTRL + W
|
||||
|
@ -60,7 +71,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 87,
|
||||
which: 87,
|
||||
editable: true,
|
||||
id: "closeTab",
|
||||
tooltip: "Close active document"
|
||||
|
@ -71,7 +82,7 @@ export const defaultKeybinds = [
|
|||
altKey: true,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
keyCode: 39,
|
||||
which: 39,
|
||||
editable: true,
|
||||
id: "nextTab",
|
||||
tooltip: "Next tab"
|
||||
|
@ -82,7 +93,7 @@ export const defaultKeybinds = [
|
|||
altKey: true,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
keyCode: 37,
|
||||
which: 37,
|
||||
editable: true,
|
||||
id: "previousTab",
|
||||
tooltip: "Previous tab"
|
||||
|
@ -93,7 +104,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 83,
|
||||
which: 83,
|
||||
editable: true,
|
||||
id: "saveDocument",
|
||||
tooltip: "Save active document"
|
||||
|
@ -104,18 +115,29 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 69,
|
||||
which: 69,
|
||||
editable: true,
|
||||
id: "editDocument",
|
||||
tooltip: "Edit active document"
|
||||
},
|
||||
|
||||
// Edit document - CTRL + SHIFT + N
|
||||
{
|
||||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
which: 78,
|
||||
editable: true,
|
||||
id: "addUnderParent",
|
||||
tooltip: "Add a new document with currently opened one as parent"
|
||||
},
|
||||
|
||||
// Delete document - CTRL + D
|
||||
{
|
||||
altKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
keyCode: 68,
|
||||
which: 68,
|
||||
editable: true,
|
||||
id: "deleteDocument",
|
||||
tooltip: "Delete active document"
|
||||
|
@ -126,7 +148,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
keyCode: 9,
|
||||
which: 9,
|
||||
editable: false,
|
||||
id: "nextFocus",
|
||||
tooltip: "Focuses next input field/input element/hierarchical tree node",
|
||||
|
@ -138,7 +160,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: false,
|
||||
shiftKey: true,
|
||||
keyCode: 9,
|
||||
which: 9,
|
||||
editable: false,
|
||||
id: "previousFocus",
|
||||
tooltip: "Focuses previous input field/input element/hierarchical tree node",
|
||||
|
@ -150,7 +172,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
keyCode: 13,
|
||||
which: 13,
|
||||
editable: false,
|
||||
id: "openTreeNode",
|
||||
tooltip: "Open the focused document in the left hierarchical tree",
|
||||
|
@ -162,7 +184,7 @@ export const defaultKeybinds = [
|
|||
altKey: false,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
keyCode: 32,
|
||||
which: 32,
|
||||
editable: false,
|
||||
id: "collapseExpandeTreeNode",
|
||||
tooltip: "Collapse or open the focused category in the left hierarchical tree",
|
||||
|
|
|
@ -21,7 +21,7 @@ export const chaptersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const chaptersBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -1199,7 +1199,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectionTechGroup",
|
||||
name: "Connected to scientifical/technological groups",
|
||||
name: "Connected to scientific/technological groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
@ -1210,7 +1210,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedBelongingTechGroup",
|
||||
name: "Member of scientifical/technological groups",
|
||||
name: "Member of scientific/technological groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
@ -1221,7 +1221,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedAllyTechGroup",
|
||||
name: "Ally of scientifical/technological groups",
|
||||
name: "Ally of scientific/technological groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
@ -1232,7 +1232,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedEnemyTechGroup",
|
||||
name: "Enemy of scientifical/technological groups",
|
||||
name: "Enemy of scientific/technological groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
@ -1271,7 +1271,7 @@ export const charactersBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 6,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const currenciesBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const currenciesBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ export const eventsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const eventsBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -251,7 +251,7 @@ export const eventsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "connectedTech",
|
||||
name: "Connected tech/scientifical groups",
|
||||
name: "Connected tech/scientific groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const itemsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const itemsBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ export const languagesBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const languagesBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ export const locationsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const locationsBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -315,7 +315,7 @@ export const locationsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "governTech",
|
||||
name: "Governing tech/scientifical groups",
|
||||
name: "Governing tech/scientific groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
@ -326,7 +326,7 @@ export const locationsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "connectedTech",
|
||||
name: "Connected tech/scientifical groups",
|
||||
name: "Connected tech/scientific groups",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 6,
|
||||
|
@ -354,7 +354,7 @@ export const locationsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 4,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const loreNotesBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const loreNotesBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ export const magicBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const magicBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -405,7 +405,7 @@ export const magicBlueprint: I_Blueprint = {
|
|||
|
||||
{
|
||||
id: "pairedConnectedTechGroups",
|
||||
name: "Connected scientifical/technological groups/teachings",
|
||||
name: "Connected scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -416,7 +416,7 @@ export const magicBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedAllyTechGroups",
|
||||
name: "Allied scientifical/technological groups/teachings",
|
||||
name: "Allied scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -427,7 +427,7 @@ export const magicBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedEnemyTechGroups",
|
||||
name: "Enemy scientifical/technological groups/teachings",
|
||||
name: "Enemy scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -455,7 +455,7 @@ export const magicBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 4,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const mythsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const mythsBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -368,7 +368,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
|
|||
|
||||
{
|
||||
id: "pairedConnectedTechGroups",
|
||||
name: "Connected scientifical/technological groups/teachings",
|
||||
name: "Connected scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -379,7 +379,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedAllyTechGroups",
|
||||
name: "Allied scientifical/technological groups/teachings",
|
||||
name: "Allied scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -390,7 +390,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedEnemyTechGroups",
|
||||
name: "Enemy scientifical/technological groups/teachings",
|
||||
name: "Enemy scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -418,7 +418,7 @@ export const politicalGroupsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 4,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const racesBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const racesBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -426,7 +426,7 @@ export const racesBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 4,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const religionsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const religionsBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -360,7 +360,7 @@ export const religionsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedTechGroups",
|
||||
name: "Connected scientifical/technological groups/teachings",
|
||||
name: "Connected scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -371,7 +371,7 @@ export const religionsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedAllyTechGroups",
|
||||
name: "Allied scientifical/technological groups/teachings",
|
||||
name: "Allied scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -382,7 +382,7 @@ export const religionsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedEnemyTechGroups",
|
||||
name: "Enemy scientifical/technological groups/teachings",
|
||||
name: "Enemy scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -410,7 +410,7 @@ export const religionsBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 4,
|
||||
|
|
|
@ -21,7 +21,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "documentColor",
|
||||
name: "Color",
|
||||
name: "Text Color",
|
||||
type: "colorPicker",
|
||||
icon: "mdi-eyedropper",
|
||||
tooltip:
|
||||
|
@ -80,7 +80,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
<br>
|
||||
This limitation also applies to any variation of lower or upper case iterations of the same tag.
|
||||
<br>
|
||||
Example: A tag called "Player Party" will be consider the same tag as "player party", "PlAyER PaRtY" or any similar.
|
||||
Example: A tag called "Player Party" will be considered the same tag as "player party", "PlAyER PaRtY" or anything similar.
|
||||
`,
|
||||
sizing: 12
|
||||
},
|
||||
|
@ -123,7 +123,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
"Machinery",
|
||||
"Magi-tech creation",
|
||||
"School of technology",
|
||||
"Scientifical/Technological institution",
|
||||
"scientific/Technological institution",
|
||||
"Technique",
|
||||
"Other"
|
||||
]
|
||||
|
@ -389,7 +389,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedTechGroups",
|
||||
name: "Connected scientifical/technological groups/teachings",
|
||||
name: "Connected scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -400,7 +400,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedAllyTechGroups",
|
||||
name: "Allied scientifical/technological groups/teachings",
|
||||
name: "Allied scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -411,7 +411,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedEnemyTechGroups",
|
||||
name: "Enemy scientifical/technological groups/teachings",
|
||||
name: "Enemy scientific/technological groups/teachings",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-wrench",
|
||||
sizing: 4,
|
||||
|
@ -439,7 +439,7 @@ export const techBlueprint: I_Blueprint = {
|
|||
},
|
||||
{
|
||||
id: "pairedConnectedMyths",
|
||||
name: "Connected to myths. legends and stories",
|
||||
name: "Connected to myths, legends and stories",
|
||||
type: "manyToManyRelationship",
|
||||
icon: "fas fa-journal-whills",
|
||||
sizing: 4,
|
||||
|
|
|
@ -74,7 +74,9 @@ export const exportProject = (projectName: string, Loading: any, loadingSetup: a
|
|||
// @ts-ignore
|
||||
const allDBS = await indexedDB.databases()
|
||||
|
||||
const DBnames: string[] = allDBS.map((db: {name: string}) => {
|
||||
const DBnames: string[] = allDBS
|
||||
.filter((d: {name: string}) => d.name !== '_pouch_fa-settings')
|
||||
.map((db: {name: string}) => {
|
||||
return db.name.replace("_pouch_", "")
|
||||
})
|
||||
|
||||
|
@ -108,11 +110,15 @@ export const removeCurrentProject = async () => {
|
|||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
const allDBS = await indexedDB.databases()
|
||||
console.log(allDBS)
|
||||
|
||||
const DBnames: string[] = allDBS.map((db: {name: string}) => {
|
||||
const DBnames: string[] = allDBS
|
||||
.filter((d: {name: string}) => d.name !== '_pouch_fa-settings')
|
||||
.map((db: {name: string}) => {
|
||||
return db.name.replace("_pouch_", "")
|
||||
})
|
||||
|
||||
|
||||
for (const db of DBnames) {
|
||||
const CurrentDB = new PouchDB(db)
|
||||
await CurrentDB.destroy()
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { I_Blueprint } from "src/interfaces/I_Blueprint"
|
||||
import { I_ShortenedDocument } from "./../../interfaces/I_OpenedDocument"
|
||||
|
||||
/**
|
||||
* Handles advanced filtering for any kind of search-field involving documents
|
||||
*/
|
||||
export const advancedDocumentFilter = (inputString: string, documentList: I_ShortenedDocument[]) => {
|
||||
export const advancedDocumentFilter = (inputString: string, currentDocumentList: I_ShortenedDocument[], blueprintList: I_Blueprint[], allDocuments: I_ShortenedDocument[]) => {
|
||||
/****************************************************************/
|
||||
// Data refresh from previous filters
|
||||
/****************************************************************/
|
||||
documentList = documentList.map(doc => {
|
||||
currentDocumentList = currentDocumentList.map(doc => {
|
||||
doc.label = doc.label.replace(/<[^>]+>/g, "")
|
||||
|
||||
// @ts-ignore
|
||||
|
@ -24,7 +25,7 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
/****************************************************************/
|
||||
// Refresh sorting to avoid random reshufling from previous searches
|
||||
/****************************************************************/
|
||||
documentList = documentList.sort((a, b) => {
|
||||
currentDocumentList = currentDocumentList.sort((a, b) => {
|
||||
if (a.type !== b.type) {
|
||||
return a.type.localeCompare(b.type)
|
||||
}
|
||||
|
@ -42,10 +43,12 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
let categorySeach = false as unknown as string
|
||||
let tagSearch = false as unknown as string
|
||||
let typeSeach = false as unknown as string
|
||||
let fieldSearch = false as unknown as string
|
||||
|
||||
const categorySeachIndex = searchWordList.findIndex(w => w.charAt(0) === ">")
|
||||
const tagSearchIndex = searchWordList.findIndex(w => w.charAt(0) === "#")
|
||||
const typeSeachIndex = searchWordList.findIndex(w => w.charAt(0) === "$")
|
||||
const fieldSearchIndex = searchWordList.findIndex(w => w.charAt(0) === "%")
|
||||
|
||||
if (categorySeachIndex >= 0) {
|
||||
categorySeach = searchWordList[categorySeachIndex].substring(1)
|
||||
|
@ -60,14 +63,150 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
searchWordList[typeSeachIndex] = ""
|
||||
}
|
||||
|
||||
if (fieldSearchIndex >= 0) {
|
||||
fieldSearch = searchWordList[fieldSearchIndex].substring(1)
|
||||
searchWordList[fieldSearchIndex] = ""
|
||||
}
|
||||
|
||||
const filteredSearchWordList = searchWordList.filter(w => w !== "")
|
||||
|
||||
/****************************************************************/
|
||||
// Field filter
|
||||
/****************************************************************/
|
||||
|
||||
if (fieldSearch) {
|
||||
currentDocumentList = currentDocumentList.filter(doc => {
|
||||
const documentType = blueprintList.find(bluePrint => bluePrint._id === doc.type)
|
||||
|
||||
if (!documentType) {
|
||||
return
|
||||
}
|
||||
|
||||
const mappedFields = documentType.extraFields
|
||||
.filter(field => field.type !== "break")
|
||||
.filter(field => field.type !== "tags")
|
||||
.filter(field => field.type !== "switch")
|
||||
.filter(field => field.id !== "name")
|
||||
.filter(field => field.id !== "parentDoc")
|
||||
.map(field => {
|
||||
const matchedField = doc.extraFields.find(sub => sub.id === field.id)
|
||||
let returnValue = matchedField?.value
|
||||
|
||||
// Convert numbers to strings
|
||||
if (field.type === "number" && typeof returnValue === "number") {
|
||||
returnValue = returnValue.toString()
|
||||
}
|
||||
|
||||
// Build string out of multi-selects
|
||||
if (field.type === "multiSelect" && Array.isArray(returnValue)) {
|
||||
returnValue = returnValue.join(" ")
|
||||
}
|
||||
|
||||
// Build string out of lists
|
||||
if (field.type === "list" && Array.isArray(returnValue)) {
|
||||
returnValue = returnValue
|
||||
.map((e: {value: string, affix: string}) => `${e.value} ${e.affix}`)
|
||||
.join("")
|
||||
}
|
||||
|
||||
// Build string out of single-relationship
|
||||
if ((
|
||||
field.type === "singleToManyRelationship" ||
|
||||
field.type === "singleToSingleRelationship" ||
|
||||
field.type === "singleToNoneRelationship"
|
||||
) && returnValue && returnValue.value
|
||||
) {
|
||||
const valueToMap = Array.isArray(returnValue.value) ? returnValue.value[0] : returnValue.value
|
||||
|
||||
// @ts-ignore
|
||||
const matchingDocument = allDocuments.find(doc => doc.id === valueToMap._id)
|
||||
if (matchingDocument) {
|
||||
// @ts-ignore
|
||||
returnValue = matchingDocument.extraFields.find(e => e.id === "name")?.value as string
|
||||
}
|
||||
else {
|
||||
returnValue = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Build string out of multi-relationship
|
||||
if ((
|
||||
field.type === "manyToManyRelationship" ||
|
||||
field.type === "manyToSingleRelationship" ||
|
||||
field.type === "manyToNoneRelationship"
|
||||
) && returnValue && returnValue.value
|
||||
) {
|
||||
const valuesToMap = returnValue.value as {_id: string}[]
|
||||
|
||||
const mappedValues = valuesToMap
|
||||
.map(value => {
|
||||
// @ts-ignore
|
||||
const matchingDocument = allDocuments.find(doc => doc.id === value._id)
|
||||
if (matchingDocument) {
|
||||
// @ts-ignore
|
||||
return matchingDocument.extraFields.find(e => e.id === "name")?.value as string
|
||||
}
|
||||
return " "
|
||||
})
|
||||
.filter(e => e !== " ")
|
||||
.join(" ")
|
||||
returnValue = mappedValues
|
||||
}
|
||||
|
||||
// Fix all missing values that slipped through
|
||||
if (!returnValue || returnValue.value === null) {
|
||||
returnValue = ""
|
||||
}
|
||||
|
||||
let returnValueFormat = returnValue as string
|
||||
|
||||
returnValueFormat = returnValueFormat.toLowerCase()
|
||||
returnValueFormat = returnValueFormat.replace(/>/gi, "")
|
||||
returnValueFormat = returnValueFormat.replace(/ {2}/gi, " ")
|
||||
returnValueFormat = returnValueFormat.replace(/ {2}/gi, " ")
|
||||
returnValueFormat = returnValueFormat.replace(/ {2}/gi, " ")
|
||||
returnValueFormat = returnValueFormat.replace(/ /gi, "-")
|
||||
|
||||
let name = field.name
|
||||
|
||||
name = name.toLowerCase()
|
||||
name = name.replace(/>/gi, "")
|
||||
name = name.replace(/ {2}/gi, "-")
|
||||
name = name.replace(/ /gi, "-")
|
||||
|
||||
return {
|
||||
name: name,
|
||||
value: returnValueFormat
|
||||
}
|
||||
})
|
||||
|
||||
let searchString = fieldSearch.toLowerCase()
|
||||
searchString = searchString.replace(/>/gi, "")
|
||||
searchString = searchString.replace(/ {2}/gi, "-")
|
||||
searchString = searchString.replace(/ /gi, "-")
|
||||
const searchDuo = searchString.split(":")
|
||||
|
||||
if (searchDuo.length === 2) {
|
||||
let foundMatch = false
|
||||
mappedFields.forEach(field => {
|
||||
if (field.name.includes(searchDuo[0]) && field.value.includes(searchDuo[1])) {
|
||||
foundMatch = true
|
||||
}
|
||||
})
|
||||
return foundMatch
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Category filter
|
||||
/****************************************************************/
|
||||
|
||||
if (categorySeach) {
|
||||
documentList = documentList.filter(doc => {
|
||||
currentDocumentList = currentDocumentList.filter(doc => {
|
||||
let stringPath = doc.hierarchicalPath as unknown as string
|
||||
stringPath = stringPath.toLowerCase()
|
||||
stringPath = stringPath.replace(/>/gi, "")
|
||||
|
@ -85,7 +224,7 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
// Tag filter
|
||||
/****************************************************************/
|
||||
if (tagSearch) {
|
||||
documentList = documentList.filter(doc => {
|
||||
currentDocumentList = currentDocumentList.filter(doc => {
|
||||
let matchFound = false
|
||||
|
||||
if (doc.tags) {
|
||||
|
@ -110,10 +249,15 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
/****************************************************************/
|
||||
|
||||
if (typeSeach) {
|
||||
documentList = documentList.filter(doc => {
|
||||
let stringPath = doc.type
|
||||
currentDocumentList = currentDocumentList.filter(doc => {
|
||||
let stringPath = blueprintList.find(bluePrint => bluePrint._id === doc.type)?.nameSingular
|
||||
|
||||
stringPath = stringPath.split(/(?=[A-Z])/).join("-")
|
||||
if (!stringPath) {
|
||||
return
|
||||
}
|
||||
stringPath = stringPath.replace(/>/gi, "")
|
||||
stringPath = stringPath.replace(/ {2}/gi, "-")
|
||||
stringPath = stringPath.replace(/ /gi, "-")
|
||||
|
||||
stringPath = stringPath.toLowerCase()
|
||||
|
||||
|
@ -127,13 +271,13 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
// Return list without further lookup for actual text if none is present
|
||||
/****************************************************************/
|
||||
if (filteredSearchWordList.length === 0) {
|
||||
return documentList
|
||||
return currentDocumentList
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Priority search & filtering out non-matching search results
|
||||
/****************************************************************/
|
||||
documentList.forEach(doc => {
|
||||
currentDocumentList.forEach(doc => {
|
||||
// If we have a precise matching letter to letter
|
||||
if (doc.label.toLowerCase() === filteredSearchWordList.join(" ")) {
|
||||
doc.exactMatch = true
|
||||
|
@ -183,7 +327,7 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
})
|
||||
|
||||
// Cover case of exact match
|
||||
documentList.map(doc => {
|
||||
currentDocumentList.map(doc => {
|
||||
if (doc.exactMatch) {
|
||||
doc.label = `<span class="text-primary text-bold">${doc.label}</span>`
|
||||
}
|
||||
|
@ -196,24 +340,24 @@ export const advancedDocumentFilter = (inputString: string, documentList: I_Shor
|
|||
|
||||
// Partial word matching
|
||||
// @ts-ignore
|
||||
documentList = documentList.sort((a, b) => (a?.partialWordMatch > b?.partialWordMatch) ? -1 : 1)
|
||||
currentDocumentList = currentDocumentList.sort((a, b) => (a?.partialWordMatch > b?.partialWordMatch) ? -1 : 1)
|
||||
|
||||
// Full word matching
|
||||
// @ts-ignore
|
||||
documentList = documentList.sort((a, b) => (a?.fullWordMatch > b?.fullWordMatch) ? -1 : 1)
|
||||
currentDocumentList = currentDocumentList.sort((a, b) => (a?.fullWordMatch > b?.fullWordMatch) ? -1 : 1)
|
||||
|
||||
// Exact matching
|
||||
documentList = documentList.sort((a) => (a?.exactMatch) ? -1 : 1)
|
||||
currentDocumentList = currentDocumentList.sort((a) => (a?.exactMatch) ? -1 : 1)
|
||||
|
||||
/****************************************************************/
|
||||
// If there is anything in the search, filter properly
|
||||
/****************************************************************/
|
||||
if (filteredSearchWordList.length > 0) {
|
||||
documentList = documentList.filter(doc => {
|
||||
currentDocumentList = currentDocumentList.filter(doc => {
|
||||
// @ts-ignore
|
||||
return ((doc.exactMatch || doc.fullWordMatch > 0 || doc.partialWordMatch > 0) && !doc.filteredOut)
|
||||
})
|
||||
}
|
||||
|
||||
return documentList
|
||||
return currentDocumentList
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import blueprintsModule from "./module-blueprints"
|
|||
import openedDocumentsModule from "./module-openedDocuments"
|
||||
import keybindsModule from "./module-keybinds"
|
||||
import dialogsModule from "./module-dialogs"
|
||||
import optionsModule from "./module-options"
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
|
@ -30,7 +31,8 @@ export default store(function ({ Vue }) {
|
|||
blueprintsModule,
|
||||
openedDocumentsModule,
|
||||
keybindsModule,
|
||||
dialogsModule
|
||||
dialogsModule,
|
||||
optionsModule
|
||||
// example
|
||||
},
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ const resetCurrentKey = () => {
|
|||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
id: "",
|
||||
keyCode: 99999
|
||||
which: 99999
|
||||
}
|
||||
}
|
||||
const mutation: MutationTree<KeybindsStateInterface> = {
|
||||
|
|
|
@ -22,7 +22,7 @@ function state (): KeybindsStateInterface {
|
|||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
id: "",
|
||||
keyCode: 99999
|
||||
which: 99999
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/store/module-options/actions.ts
Normal file
24
src/store/module-options/actions.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { ActionTree } from "vuex"
|
||||
import { StateInterface } from "../index"
|
||||
import { OptionsStateInteface } from "./state"
|
||||
import PouchDB from "pouchdb"
|
||||
|
||||
const actions: ActionTree<OptionsStateInteface, StateInterface> = {
|
||||
|
||||
async setOptions (state, input: OptionsStateInteface) {
|
||||
const SettingsDB = new PouchDB("fa-settings")
|
||||
const FASettings = input
|
||||
|
||||
let currentSettings = false as unknown as OptionsStateInteface
|
||||
try {
|
||||
currentSettings = await SettingsDB.get("settings")
|
||||
FASettings._rev = currentSettings?._rev
|
||||
}
|
||||
catch (error) {}
|
||||
|
||||
await SettingsDB.put(FASettings)
|
||||
state.commit("setOptions", input)
|
||||
}
|
||||
}
|
||||
|
||||
export default actions
|
11
src/store/module-options/getters.ts
Normal file
11
src/store/module-options/getters.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { GetterTree } from "vuex"
|
||||
import { StateInterface } from "../index"
|
||||
import { OptionsStateInteface } from "./state"
|
||||
|
||||
const getters: GetterTree<OptionsStateInteface, StateInterface> = {
|
||||
getOptions (context) {
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
export default getters
|
16
src/store/module-options/index.ts
Normal file
16
src/store/module-options/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Module } from "vuex"
|
||||
import { StateInterface } from "../index"
|
||||
import state, { OptionsStateInteface } from "./state"
|
||||
import actions from "./actions"
|
||||
import getters from "./getters"
|
||||
import mutations from "./mutations"
|
||||
|
||||
const keybindsModule: Module<OptionsStateInteface, StateInterface> = {
|
||||
namespaced: true,
|
||||
actions,
|
||||
getters,
|
||||
mutations,
|
||||
state
|
||||
}
|
||||
|
||||
export default keybindsModule
|
13
src/store/module-options/mutations.ts
Normal file
13
src/store/module-options/mutations.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { MutationTree } from "vuex"
|
||||
import { OptionsStateInteface } from "./state"
|
||||
|
||||
const mutation: MutationTree<OptionsStateInteface> = {
|
||||
|
||||
setOptions (state: OptionsStateInteface, input: OptionsStateInteface) {
|
||||
for (const [key, value] of Object.entries(input)) {
|
||||
state[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default mutation
|
47
src/store/module-options/state.ts
Normal file
47
src/store/module-options/state.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
export interface OptionsStateInteface {
|
||||
_id: string,
|
||||
_rev?: string,
|
||||
darkMode: boolean
|
||||
textShadow: boolean
|
||||
noTags: boolean
|
||||
tagsAtTop: boolean
|
||||
compactTags: boolean
|
||||
noProjectName: boolean
|
||||
invertTreeSorting: boolean
|
||||
disableDocumentToolTips: boolean
|
||||
doNotcollaseTreeOptions: boolean
|
||||
hideEmptyFields: boolean
|
||||
disableDocumentControlBar: boolean
|
||||
disableDocumentControlBarGuides: boolean
|
||||
disableCloseAftertSelectQuickSearch: boolean
|
||||
disableQuickSearchCategoryPrecheck: boolean
|
||||
allowQuickPopupSameKeyClose: boolean
|
||||
|
||||
userKeybindList: any[]
|
||||
treeWidth?: number
|
||||
}
|
||||
|
||||
function state (): OptionsStateInteface {
|
||||
return {
|
||||
_id: "settings",
|
||||
darkMode: false,
|
||||
textShadow: false,
|
||||
noTags: false,
|
||||
tagsAtTop: false,
|
||||
compactTags: false,
|
||||
noProjectName: false,
|
||||
invertTreeSorting: false,
|
||||
disableDocumentToolTips: false,
|
||||
doNotcollaseTreeOptions: false,
|
||||
disableDocumentControlBar: false,
|
||||
disableDocumentControlBarGuides: false,
|
||||
disableCloseAftertSelectQuickSearch: false,
|
||||
disableQuickSearchCategoryPrecheck: false,
|
||||
allowQuickPopupSameKeyClose: false,
|
||||
hideEmptyFields: false,
|
||||
treeWidth: 374,
|
||||
userKeybindList: []
|
||||
}
|
||||
}
|
||||
|
||||
export default state
|
|
@ -1,28 +1,22 @@
|
|||
|
||||
### App options & Keybinds
|
||||
|
||||
- Add "Document relevance" switch and integrate it into filters
|
||||
- Add "Find field" to quickly navigate the document
|
||||
- Add "Show in search results" checkbox for relationship searches
|
||||
- Add "Related notes"
|
||||
- Add "Predecessors", "Successors", "Date of start", "Date of end" and "How long it lasted" fields to locations and all other groups
|
||||
- Save scroll distance when switching tabs (consider some auto-scroll when opening edit mode)
|
||||
- Fix lag on opening Quick-search popup
|
||||
- Fix tag input hanging after adding new ones
|
||||
- Mass tag rename
|
||||
- Add click-through from chips in edit mode
|
||||
- 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 support for dates in "custom order"... reee
|
||||
|
||||
- Considering multiple "belongs under" category listing
|
||||
- Add intelligent responsive design to the left tree and document body (maybe button to pull the left bar in and out?)
|
||||
- Add top level tags
|
||||
- Context menu: Expand all
|
||||
- Context menu: Collapse all
|
||||
- Context menu: Copy color (text and BG)
|
||||
|
@ -31,33 +25,16 @@
|
|||
- Context menu: Delete
|
||||
- Context menu: Edit/Open
|
||||
- Context menu: Create new doc with parent of THIS
|
||||
- Context menu: Clone tab
|
||||
- Context menu: Pin tab
|
||||
- Context menu: Unpin tab
|
||||
|
||||
- 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: Show tags as a subcategory or as each individually
|
||||
- Option: Show tags on or bottom of the list
|
||||
- Option: Hide non-filled fields in document view mode
|
||||
- Option: Retain opened tabs and their edited contents through sessions
|
||||
- Option: Dark Mode
|
||||
- Option: Quick-search popup determine if "Include categories" is prechecked or not
|
||||
- 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)
|
||||
- Option: Periodical backup (how many, how often, include files or not)
|
||||
|
||||
### Project settings
|
||||
|
||||
|
|
Loading…
Reference in a new issue