mirror of
https://github.com/Elvanos/fantasia-archive.git
synced 2024-09-28 15:21:45 +12:00
0.1.2 release
This commit is contained in:
parent
c23cba9f60
commit
64b3eae526
59 changed files with 1594 additions and 709 deletions
15
changelog.md
15
changelog.md
|
@ -4,16 +4,25 @@
|
|||
|
||||
### Bugfixes
|
||||
|
||||
- Fixed a safeguard for opening multiple overlapping dialogs unintentionally
|
||||
|
||||
### New features
|
||||
|
||||
- Reworked hierarchical left tree
|
||||
- Added "Add under parent" button the hiearachical tree
|
||||
- Added mouse button and improved keyboard support to the hierarchical tree
|
||||
- Added "Add under parent" button to the hierarchical tree, document page view, and quick search existing documents
|
||||
- Added mouse button support and improved keyboard support to the hierarchical tree
|
||||
- Reworked the top bar of the app to include tabs, window control elements, and basic menus of the app
|
||||
- Added a check upon closing the app to avoid unintentional loss of data due to unsaved documents
|
||||
|
||||
### QoL adjustments
|
||||
|
||||
- Added middle-click closing for the tabs
|
||||
- Reversed default custom sorting for "Order" field in the left side tree
|
||||
- Added automatical opening of the project page after opening an existing project from a folder
|
||||
- Reversed default custom sorting for the "Order" field in the left side tree
|
||||
- Modified auto-closing behavior of hierarchical left tree nodes when moving/adding/removing documents
|
||||
- Added a delay for tooltip popups on fields of documents
|
||||
- Remove persistence from the document with an active edits confirmation dialog
|
||||
- Unified graphical interface coloring of Quick-add and Quick-search dialogs to work consistently with the coloring of individual documents/document types same as the left hierarchical tre
|
||||
|
||||
## 0.1.1
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fantasiaarchive",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"description": "A database manager for world building",
|
||||
"productName": "Fantasia archive",
|
||||
"author": "Elvanos <elvanos66@gmail.com>",
|
||||
|
|
|
@ -22,13 +22,14 @@ function createWindow () {
|
|||
*/
|
||||
mainWindow = new BrowserWindow({
|
||||
useContentSize: true,
|
||||
frame: false,
|
||||
|
||||
webPreferences: {
|
||||
// Change from /quasar.conf.js > electron > nodeIntegration;
|
||||
// More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
|
||||
nodeIntegration: process.env.QUASAR_NODE_INTEGRATION,
|
||||
nodeIntegrationInWorker: process.env.QUASAR_NODE_INTEGRATION,
|
||||
enableRemoteModule: true
|
||||
|
||||
enableRemoteModule: true,
|
||||
// More info: /quasar-cli/developing-electron-apps/electron-preload-script
|
||||
// preload: path.resolve(__dirname, 'electron-preload.js')
|
||||
}
|
||||
|
|
27
src/App.vue
27
src/App.vue
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<div id="q-app">
|
||||
<appWindowButtons />
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -7,8 +8,15 @@
|
|||
<script lang="ts">
|
||||
import BaseClass from "src/BaseClass"
|
||||
import { Component } from "vue-property-decorator"
|
||||
import { defaultKeybinds } from "src/appSettings/defaultKeybinds"
|
||||
@Component
|
||||
import { defaultKeybinds } from "src/scripts/appSettings/defaultKeybinds"
|
||||
import appWindowButtons from "src/components/appHeader/AppWindowButtons.vue"
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
appWindowButtons: appWindowButtons
|
||||
|
||||
}
|
||||
})
|
||||
export default class App extends BaseClass {
|
||||
created () {
|
||||
window.addEventListener("auxclick", this.reactToMiddleClick)
|
||||
|
@ -21,12 +29,27 @@ export default class App extends BaseClass {
|
|||
}
|
||||
|
||||
this.registerDefaultKeybinds()
|
||||
window.addEventListener("keyup", this.triggerKeyPush)
|
||||
}
|
||||
|
||||
triggerKeyPush (e:any) {
|
||||
if (e?.altKey === true || e?.ctrlKey || e?.shiftKey) {
|
||||
const ouputKeycombo = {
|
||||
altKey: e.altKey,
|
||||
ctrlKey: e.ctrlKey,
|
||||
shiftKey: e.shiftKey,
|
||||
keyCode: e.keyCode
|
||||
}
|
||||
|
||||
this.SSET_updatePressedKey(ouputKeycombo)
|
||||
}
|
||||
}
|
||||
|
||||
destroyed () {
|
||||
window.removeEventListener("auxclick", this.reactToMiddleClick)
|
||||
|
||||
this.deregisterDefaultKeybinds()
|
||||
window.removeEventListener("keyup", this.triggerKeyPush)
|
||||
}
|
||||
|
||||
reactToMiddleClick (e: {button: number, preventDefault: ()=> void}) {
|
||||
|
|
136
src/BaseClass.ts
136
src/BaseClass.ts
|
@ -2,15 +2,6 @@ import { KeyManagementInterface } from "./store/module-keybinds/state"
|
|||
import { I_OpenedDocument } from "./interfaces/I_OpenedDocument"
|
||||
import { Component, Vue } from "vue-property-decorator"
|
||||
import { namespace } from "vuex-class"
|
||||
import { remote } from "electron"
|
||||
// @ts-ignore
|
||||
import replicationStream from "pouchdb-replication-stream/dist/pouchdb.replication-stream.min.js"
|
||||
// @ts-ignore
|
||||
import load from "pouchdb-load"
|
||||
import PouchDB from "pouchdb"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
|
||||
import { I_Blueprint } from "src/interfaces/I_Blueprint"
|
||||
import { I_NewObjectTrigger } from "src/interfaces/I_NewObjectTrigger"
|
||||
import { uid } from "quasar"
|
||||
|
@ -23,6 +14,10 @@ const Keybinds = namespace("keybindsModule")
|
|||
|
||||
@Component
|
||||
export default class BaseClass extends Vue {
|
||||
generateUID () : string {
|
||||
return uid()
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Keybinds management
|
||||
/****************************************************************/
|
||||
|
@ -121,128 +116,6 @@ export default class BaseClass extends Vue {
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Project management
|
||||
/****************************************************************/
|
||||
|
||||
/**
|
||||
* Creates a brand new project and deleted any present data avaiable right now
|
||||
* @param projectName The name of the new project
|
||||
*/
|
||||
async createNewProject (projectName: string) {
|
||||
await this.removeCurrentProject()
|
||||
|
||||
const ProjectDB = new PouchDB("project-data")
|
||||
const newProject = { _id: projectName }
|
||||
await ProjectDB.put(newProject)
|
||||
|
||||
this.$router.push({ path: "/project" }).catch((e: {name: string}) => {
|
||||
const errorName : string = e.name
|
||||
if (errorName === "NavigationDuplicated") {
|
||||
return
|
||||
}
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an file dialog asking the use for location where to export the project
|
||||
* @param projectName The name of the project to export
|
||||
*/
|
||||
exportProject (projectName: string) {
|
||||
remote.dialog.showOpenDialog({
|
||||
properties: ["openDirectory"]
|
||||
}).then(async (result) => {
|
||||
/*eslint-disable */
|
||||
const folderPath = result.filePaths[0]
|
||||
|
||||
PouchDB.plugin(replicationStream.plugin)
|
||||
// @ts-ignore
|
||||
PouchDB.adapter("writableStream", replicationStream.adapters.writableStream)
|
||||
|
||||
// @ts-ignore
|
||||
const allDBS = await indexedDB.databases()
|
||||
|
||||
const DBnames: string[] = allDBS.map((db: {name: string}) => {
|
||||
return db.name.replace("_pouch_", "")
|
||||
})
|
||||
|
||||
for (const db of DBnames) {
|
||||
const CurrentDB = new PouchDB(db)
|
||||
|
||||
if (!fs.existsSync(`${folderPath}/${projectName}`)) {
|
||||
fs.mkdirSync(`${folderPath}/${projectName}`)
|
||||
}
|
||||
const ws = fs.createWriteStream(`${folderPath}/${projectName}/${db}.txt`)
|
||||
|
||||
// @ts-ignore
|
||||
await CurrentDB.dump(ws)
|
||||
}
|
||||
/* eslint-enable */
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current project and all its data
|
||||
*/
|
||||
async removeCurrentProject () {
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
const allDBS = await indexedDB.databases()
|
||||
|
||||
const DBnames: string[] = allDBS.map((db: {name: string}) => {
|
||||
return db.name.replace("_pouch_", "")
|
||||
})
|
||||
|
||||
for (const db of DBnames) {
|
||||
const CurrentDB = new PouchDB(db)
|
||||
await CurrentDB.destroy()
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
openExistingProject () {
|
||||
/*eslint-disable */
|
||||
remote.dialog.showOpenDialog({
|
||||
properties: ["openDirectory"]
|
||||
}).then(async (result) => {
|
||||
|
||||
const folderPath = result.filePaths[0]
|
||||
|
||||
if(!folderPath){return}
|
||||
|
||||
await this.removeCurrentProject()
|
||||
|
||||
//@ts-ignore
|
||||
PouchDB.plugin({
|
||||
loadIt: load.load
|
||||
})
|
||||
|
||||
const allFiles = fs.readdirSync(folderPath)
|
||||
|
||||
for (const file of allFiles) {
|
||||
const currentDBName = path.parse(file).name
|
||||
const CurrentDB = new PouchDB(currentDBName)
|
||||
|
||||
const fileContents = fs.readFileSync(`${folderPath}/${file}`, {encoding: 'utf8'})
|
||||
// @ts-ignore
|
||||
await CurrentDB.loadIt(fileContents)
|
||||
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
async retrieveCurrentProjectName () {
|
||||
const ProjectDB = new PouchDB("project-data")
|
||||
const projectData = await ProjectDB.allDocs({ include_docs: true })
|
||||
return projectData?.rows[0]?.id
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
// Blueprint management
|
||||
/****************************************************************/
|
||||
|
@ -296,6 +169,7 @@ export default class BaseClass extends Vue {
|
|||
@OpenedDocuments.Mutation("addDocument") SSET_addOpenedDocument!: (input: I_OpenedDocument) => void
|
||||
@OpenedDocuments.Mutation("updateDocument") SSET_updateOpenedDocument!: (input: I_OpenedDocument) => void
|
||||
@OpenedDocuments.Mutation("removeDocument") SSET_removeOpenedDocument!: (input: I_OpenedDocument) => void
|
||||
@OpenedDocuments.Mutation("resetDocuments") SSET_resetDocuments!: () => void
|
||||
|
||||
/**
|
||||
* Retrieves value of requested field. If the field doesn't exist, returns false instead
|
||||
|
|
64
src/components/AppHeader.vue
Normal file
64
src/components/AppHeader.vue
Normal file
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
|
||||
<q-header
|
||||
elevated
|
||||
class="bg-dark text-cultured"
|
||||
>
|
||||
|
||||
<div class="appHeaderInner">
|
||||
<appControl
|
||||
class="appControl"
|
||||
:is-project="isProject"
|
||||
/>
|
||||
<topTabs
|
||||
class="topTabs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</q-header>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Prop } from "vue-property-decorator"
|
||||
|
||||
import BaseClass from "src/BaseClass"
|
||||
import topTabs from "src/components/appHeader/TopTabs.vue"
|
||||
import appControl from "src/components/appHeader/AppControl.vue"
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
topTabs: topTabs,
|
||||
appControl: appControl
|
||||
}
|
||||
})
|
||||
export default class AppHeader extends BaseClass {
|
||||
@Prop() readonly isProject!: boolean
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.appHeaderInner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
|
||||
.appControl {
|
||||
width: 375px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.topTabs {
|
||||
max-width: calc(100% - 535px);
|
||||
}
|
||||
|
||||
.appWindowButtons {
|
||||
//width: 200px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -19,18 +19,19 @@
|
|||
dark
|
||||
:filter="treeFilter"
|
||||
:selected.sync="selectedTreeNode"
|
||||
:expanded.sync="expandedTreeNodes"
|
||||
>
|
||||
<template v-slot:default-header="prop">
|
||||
<div class="row items-center col-grow" @click.stop.prevent="processNodeClick(prop.node)">
|
||||
<q-icon
|
||||
:style="`color: ${prop.node.color}; width: 22px !important;`"
|
||||
:size="(prop.node.icon.includes('fas')? '16px': '21px')"
|
||||
:name="prop.node.icon"
|
||||
class="q-mr-sm" />
|
||||
<div class="documentLabel"
|
||||
:style="`color: ${prop.node.color}`"
|
||||
@click.stop.prevent.middle="processNodeLabelMiddleClick(prop.node)"
|
||||
>
|
||||
<q-icon
|
||||
:style="`color: ${prop.node.color}; width: 22px !important;`"
|
||||
:size="(prop.node.icon.includes('fas')? '16px': '21px')"
|
||||
:name="prop.node.icon"
|
||||
class="q-mr-sm self-center" />
|
||||
{{ prop.node.label }}
|
||||
<span
|
||||
class="text-primary text-weight-medium q-ml-xs"
|
||||
|
@ -38,47 +39,56 @@
|
|||
({{prop.node.documentCount}})
|
||||
</span>
|
||||
<q-badge
|
||||
class="q-ml-xs"
|
||||
style="font-size: 12px;"
|
||||
class="treeBadge"
|
||||
v-if="prop.node.sticker"
|
||||
color="primary"
|
||||
outline
|
||||
align="top">{{prop.node.sticker}}
|
||||
<q-tooltip>
|
||||
floating
|
||||
>
|
||||
{{prop.node.sticker}}
|
||||
<q-tooltip
|
||||
:delay="500"
|
||||
>
|
||||
Order priority of the document
|
||||
</q-tooltip>
|
||||
</q-badge>
|
||||
<div class="treeButtonGroup">
|
||||
<q-btn
|
||||
tabindex="-1"
|
||||
v-if="!prop.node.specialLabel || prop.node.isRoot"
|
||||
round
|
||||
dense
|
||||
color="primary"
|
||||
class="z-1 q-ml-sm treeButton treeButton--add"
|
||||
icon="mdi-plus"
|
||||
size="8px"
|
||||
@click.stop.prevent="processNodeNewDocumentButton(prop.node)"
|
||||
>
|
||||
<q-tooltip>
|
||||
Add a new document belonging under {{ prop.node.label }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
tabindex="-1"
|
||||
v-if="prop.node.children && prop.node.children.length > 0 && !prop.node.isRoot"
|
||||
round
|
||||
flat
|
||||
dense
|
||||
color="primary"
|
||||
color="dark"
|
||||
class="z-1 q-ml-sm treeButton treeButton--edit"
|
||||
icon="mdi-pencil"
|
||||
size="8px"
|
||||
@click.stop.prevent="openExistingDocumentRoute(prop.node)"
|
||||
>
|
||||
<q-tooltip>
|
||||
<q-tooltip
|
||||
:delay="300"
|
||||
>
|
||||
Open/Edit {{ prop.node.label }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
tabindex="-1"
|
||||
v-if="!prop.node.specialLabel || prop.node.isRoot"
|
||||
round
|
||||
flat
|
||||
dense
|
||||
color="dark"
|
||||
class="z-1 q-ml-sm treeButton treeButton--add"
|
||||
icon="mdi-plus"
|
||||
size="8px"
|
||||
@click.stop.prevent="processNodeNewDocumentButton(prop.node)"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="300"
|
||||
>
|
||||
Add a new document belonging under {{ prop.node.label }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -120,8 +130,8 @@ import BaseClass from "src/BaseClass"
|
|||
import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
|
||||
import { I_NewObjectTrigger } from "src/interfaces/I_NewObjectTrigger"
|
||||
import PouchDB from "pouchdb"
|
||||
import { engageBlueprints, retrieveAllBlueprints } from "src/databaseManager/blueprintManager"
|
||||
// import { cleanDatabases } from "src/databaseManager/cleaner"
|
||||
import { engageBlueprints, retrieveAllBlueprints } from "src/scripts/databaseManager/blueprintManager"
|
||||
// import { cleanDatabases } from "src/scripts/databaseManager/cleaner"
|
||||
import { I_Blueprint } from "src/interfaces/I_Blueprint"
|
||||
|
||||
@Component({
|
||||
|
@ -236,6 +246,11 @@ export default class ObjectTree extends BaseClass {
|
|||
*/
|
||||
selectedTreeNode = null
|
||||
|
||||
/**
|
||||
* Holds all currently expanded notes
|
||||
*/
|
||||
expandedTreeNodes = []
|
||||
|
||||
/**
|
||||
* Filter model for the tree
|
||||
*/
|
||||
|
@ -500,7 +515,7 @@ export default class ObjectTree extends BaseClass {
|
|||
.objectTree {
|
||||
.q-tree__arrow {
|
||||
margin-right: 0;
|
||||
padding: 4px;
|
||||
padding: 4px 4px 4px 0;
|
||||
}
|
||||
|
||||
.q-tree__node-header {
|
||||
|
@ -508,11 +523,10 @@ export default class ObjectTree extends BaseClass {
|
|||
}
|
||||
|
||||
.documentLabel {
|
||||
max-width: calc(100% - 30px);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 4px 4px 4px 0;
|
||||
padding: 4px 4px 4px 4px;
|
||||
}
|
||||
|
||||
.treeButtonGroup {
|
||||
|
@ -525,27 +539,33 @@ export default class ObjectTree extends BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
.treeButton {
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
.treeBadge {
|
||||
left: inherit;
|
||||
right: calc(100% + 3px);
|
||||
padding: 3px 2px;
|
||||
border: none;
|
||||
background: rgba($primary, 0.15);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
min-width: 24px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.treeButton {
|
||||
.q-focus-helper{}
|
||||
|
||||
&--add {
|
||||
.q-icon {
|
||||
font-size: 20px;
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
&--edit {
|
||||
.q-icon {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.q-icon {
|
||||
color: $dark;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
177
src/components/appHeader/AppControl.vue
Normal file
177
src/components/appHeader/AppControl.vue
Normal file
|
@ -0,0 +1,177 @@
|
|||
<template>
|
||||
|
||||
<div
|
||||
:class="{'AppControl': isProject}"
|
||||
>
|
||||
<projectCloseCheckDialog
|
||||
:dialog-trigger="projectCloseCheckDialogTrigger"
|
||||
:dialog-mode="'projectClose'"
|
||||
@trigger-dialog-close="projectCloseCheckDialogClose"
|
||||
/>
|
||||
|
||||
<q-btn-group
|
||||
flat
|
||||
class="AppControl__buttons"
|
||||
>
|
||||
|
||||
<!-- Options button -->
|
||||
<q-btn
|
||||
flat
|
||||
v-if="true === false"
|
||||
:ripple="false"
|
||||
dark
|
||||
size='md'
|
||||
no-caps
|
||||
>
|
||||
Options
|
||||
</q-btn>
|
||||
|
||||
<!-- Project button-->
|
||||
<q-btn
|
||||
flat
|
||||
:ripple="false"
|
||||
dark
|
||||
size='md'
|
||||
no-caps
|
||||
>
|
||||
Project
|
||||
|
||||
<q-menu
|
||||
@show="checkProjectStatus"
|
||||
anchor="bottom left"
|
||||
class="bg-gunmetal-light"
|
||||
dark
|
||||
>
|
||||
<q-list class="bg-gunmetal-light" dark>
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
@click="navigateToProjectPage"
|
||||
:disable="!projectExists || isProjectPage"
|
||||
>
|
||||
<q-item-section>Go to project screen</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
@click="exportProject(projectName)"
|
||||
:disable="!projectExists"
|
||||
>
|
||||
<q-item-section>Export project</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator dark />
|
||||
|
||||
<q-item
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
@click="projectCloseCheckDialogAssignUID"
|
||||
:disable="!projectExists || isFrontpage"
|
||||
>
|
||||
<q-item-section>Close project</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
|
||||
<!-- Help button-->
|
||||
<q-btn
|
||||
flat
|
||||
:ripple="false"
|
||||
dark
|
||||
size='md'
|
||||
no-caps
|
||||
>
|
||||
Help
|
||||
|
||||
<q-menu anchor="bottom left" class="bg-gunmetal-light" dark>
|
||||
<q-list class="bg-gunmetal-light" dark>
|
||||
<q-item
|
||||
@click="toggleDevTools"
|
||||
v-close-popup
|
||||
clickable
|
||||
active
|
||||
active-class="bg-gunmetal-light text-cultured"
|
||||
>
|
||||
<q-item-section>Toggle developer tools</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
|
||||
</q-btn>
|
||||
</q-btn-group>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Prop } from "vue-property-decorator"
|
||||
|
||||
import BaseClass from "src/BaseClass"
|
||||
import projectCloseCheckDialog from "src/components/dialogs/ProjectCloseCheck.vue"
|
||||
|
||||
import { retrieveCurrentProjectName, exportProject } from "src/scripts/projectManagement/projectManagent"
|
||||
|
||||
import { toggleDevTools } from "src/scripts/utilities/devTools"
|
||||
@Component({
|
||||
components: { projectCloseCheckDialog }
|
||||
})
|
||||
export default class AppControl extends BaseClass {
|
||||
@Prop() readonly isProject!: boolean
|
||||
|
||||
toggleDevTools = toggleDevTools
|
||||
retrieveCurrentProjectName = retrieveCurrentProjectName
|
||||
exportProject = exportProject
|
||||
projectExists: undefined | string | boolean = false
|
||||
isFrontpage = true
|
||||
isProjectPage = true
|
||||
projectName = ""
|
||||
|
||||
created () {
|
||||
this.checkProjectStatus().catch(e => console.log(e))
|
||||
}
|
||||
|
||||
async checkProjectStatus () {
|
||||
this.projectName = await retrieveCurrentProjectName()
|
||||
this.projectExists = !!(await retrieveCurrentProjectName())
|
||||
this.isFrontpage = (this.$route.path === "/")
|
||||
this.isProjectPage = (this.$route.path === "/project")
|
||||
}
|
||||
|
||||
projectCloseCheckDialogTrigger: string | false = false
|
||||
projectCloseCheckDialogClose () {
|
||||
this.projectCloseCheckDialogTrigger = false
|
||||
}
|
||||
|
||||
projectCloseCheckDialogAssignUID () {
|
||||
this.projectCloseCheckDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
navigateToProjectPage () {
|
||||
this.$router.push({ path: "/project" }).catch((e: {name: string}) => {
|
||||
if (e && e.name !== "NavigationDuplicated") {
|
||||
console.log(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppControl {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
|
||||
&__buttons {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
</style>
|
124
src/components/appHeader/AppWindowButtons.vue
Normal file
124
src/components/appHeader/AppWindowButtons.vue
Normal file
|
@ -0,0 +1,124 @@
|
|||
<template>
|
||||
|
||||
<q-btn-group
|
||||
flat
|
||||
class="appWindowButtons"
|
||||
>
|
||||
|
||||
<projectCloseCheckDialog
|
||||
:dialog-trigger="projectCloseCheckDialogTrigger"
|
||||
:dialog-mode="'appClose'"
|
||||
@trigger-dialog-close="projectCloseCheckDialogClose"
|
||||
/>
|
||||
|
||||
<!-- Minimize button-->
|
||||
<q-btn
|
||||
flat
|
||||
:ripple="false"
|
||||
:class="{'minimize': osSystem === 'darwin'}"
|
||||
dark
|
||||
size='sm'
|
||||
@click="minimize">
|
||||
<q-icon name="mdi-window-minimize"></q-icon>
|
||||
</q-btn>
|
||||
|
||||
<!-- MinMax button-->
|
||||
<q-btn
|
||||
flat
|
||||
:ripple="false"
|
||||
:class="{'minMax': osSystem === 'darwin'}"
|
||||
dark
|
||||
size='sm'
|
||||
@click="maximize">
|
||||
<q-icon :name="(isMaximized)? 'mdi-window-restore' : 'mdi-window-maximize'"></q-icon>
|
||||
</q-btn>
|
||||
|
||||
<!-- Close button-->
|
||||
<q-btn
|
||||
flat
|
||||
:ripple="false"
|
||||
dark
|
||||
size='sm'
|
||||
@click="projectCloseCheckDialogAssignUID"
|
||||
:class="[{'close': osSystem === 'darwin'}]"
|
||||
>
|
||||
<q-icon name="mdi-window-close"></q-icon>
|
||||
</q-btn>
|
||||
|
||||
</q-btn-group>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component } from "vue-property-decorator"
|
||||
import { remote } from "electron"
|
||||
|
||||
import BaseClass from "src/BaseClass"
|
||||
import projectCloseCheckDialog from "src/components/dialogs/ProjectCloseCheck.vue"
|
||||
|
||||
@Component({
|
||||
components: { projectCloseCheckDialog }
|
||||
})
|
||||
export default class AppWindowButtons extends BaseClass {
|
||||
isMaximized = false
|
||||
|
||||
osSystem = remote.process.platform
|
||||
|
||||
created () {
|
||||
window.addEventListener("resize", this.checkMaximized)
|
||||
this.checkMaximized()
|
||||
}
|
||||
|
||||
destroyed () {
|
||||
window.addEventListener("resize", this.checkMaximized)
|
||||
}
|
||||
|
||||
checkMaximized () {
|
||||
this.isMaximized = remote.getCurrentWindow().isMaximized()
|
||||
}
|
||||
|
||||
minimize () {
|
||||
remote.getCurrentWindow().minimize()
|
||||
}
|
||||
|
||||
maximize () {
|
||||
const win = remote.getCurrentWindow()
|
||||
|
||||
if (win.isMaximized()) {
|
||||
win.unmaximize()
|
||||
}
|
||||
else {
|
||||
win.maximize()
|
||||
}
|
||||
}
|
||||
|
||||
projectCloseCheckDialogTrigger: string | false = false
|
||||
projectCloseCheckDialogClose () {
|
||||
this.projectCloseCheckDialogTrigger = false
|
||||
}
|
||||
|
||||
projectCloseCheckDialogAssignUID () {
|
||||
this.projectCloseCheckDialogTrigger = this.generateUID()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.appWindowButtons {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 40px;
|
||||
z-index: 99999999;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" >
|
||||
|
||||
.appWindowButtons__closeDialogList {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,20 +1,11 @@
|
|||
<template>
|
||||
|
||||
<transition
|
||||
enter-active-class="animated slideInDown"
|
||||
leave-active-class="animated slideOutUp"
|
||||
appear
|
||||
:duration="600"
|
||||
>
|
||||
<q-header
|
||||
v-if="localDocuments.length > 0"
|
||||
elevated
|
||||
class="bg-dark text-cultured"
|
||||
>
|
||||
<span>
|
||||
|
||||
<q-dialog
|
||||
v-if="currentlyCheckedDocument"
|
||||
v-model="documentCloseDialogConfirm"
|
||||
persistent>
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section class="row items-center">
|
||||
<span class="q-ml-sm">Discard changes to {{retrieveFieldValue(currentlyCheckedDocument,'name')}}?</span>
|
||||
|
@ -25,7 +16,7 @@
|
|||
<q-btn
|
||||
flat
|
||||
label="Discard changes"
|
||||
color="primary"
|
||||
color="red"
|
||||
v-close-popup
|
||||
@click="closeDocument(currentlyCheckedDocument)" />
|
||||
</q-card-actions>
|
||||
|
@ -33,9 +24,13 @@
|
|||
</q-dialog>
|
||||
|
||||
<q-tabs
|
||||
v-if="localDocuments.length > 0"
|
||||
align="left"
|
||||
inline-label
|
||||
outside-arrows
|
||||
mobile-arrows
|
||||
class="tabsWrapper"
|
||||
dense
|
||||
no-caps>
|
||||
<transition-group
|
||||
name="list"
|
||||
|
@ -44,7 +39,7 @@
|
|||
enter-active-class="animated fadeIn"
|
||||
leave-active-class="animated fadeOut"
|
||||
appear
|
||||
:duration="300">
|
||||
:duration="150">
|
||||
|
||||
<q-route-tab
|
||||
:ripple="false"
|
||||
|
@ -53,15 +48,21 @@
|
|||
:key="document.type+document._id"
|
||||
:icon="(retrieveFieldValue(document,'categorySwitch') ? 'fas fa-folder-open' : document.icon)"
|
||||
:label="retrieveFieldValue(document,'name')"
|
||||
:style="`color: ${retrieveFieldValue(document,'documentColor')}`"
|
||||
:style="`color: ${retrieveFieldValue(document,'documentColor')};`"
|
||||
:class="[{'isBold': (retrieveFieldValue(document,'documentColor') !== '#ffffff' && retrieveFieldValue(document,'documentColor') !== '#fff') && retrieveFieldValue(document,'documentColor') !== ''}]"
|
||||
:alert="document.hasEdits"
|
||||
alert-icon="mdi-feather"
|
||||
@click.prevent.middle="checkForCloseOpenedDocument(document)"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="700"
|
||||
>
|
||||
{{retrieveFieldValue(document,'name')}}
|
||||
</q-tooltip>
|
||||
<q-btn
|
||||
round
|
||||
dense
|
||||
class="z-max q-ml-sm"
|
||||
class="z-max q-ml-auto"
|
||||
:class="{'q-mr-sm': document.hasEdits}"
|
||||
size="xs"
|
||||
icon="close"
|
||||
|
@ -73,8 +74,7 @@
|
|||
</transition-group>
|
||||
</q-tabs>
|
||||
|
||||
</q-header>
|
||||
</transition>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
|
||||
|
@ -90,7 +90,7 @@ import { I_OpenedDocument } from "src/interfaces/I_OpenedDocument"
|
|||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class TppTabs extends BaseClass {
|
||||
export default class TopTabs extends BaseClass {
|
||||
documentCloseDialogConfirm = false
|
||||
currentlyCheckedDocument = null as unknown as I_OpenedDocument
|
||||
|
||||
|
@ -212,12 +212,60 @@ export default class TppTabs extends BaseClass {
|
|||
}
|
||||
|
||||
.tabsWrapper .fas {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tabsWrapper .mdi {
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.tabsWrapper .fas {
|
||||
.tabsWrapper {
|
||||
.q-tabs__arrow {
|
||||
text-shadow: none !important;
|
||||
}
|
||||
|
||||
.isBold .q-tab__label {
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.q-tab {
|
||||
padding: 0 10px;
|
||||
|
||||
&__content {
|
||||
min-width: 170px;
|
||||
width: 170px;
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__label {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-top: 2px;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.fas {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mdi {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
&.q-tabs--dense .q-tab {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.q-tab__alert-icon {
|
||||
font-size: 16px;
|
||||
top: 4px;
|
||||
right: -10px;
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
</style>
|
209
src/components/dialogs/ExistingDocument.vue
Normal file
209
src/components/dialogs/ExistingDocument.vue
Normal file
|
@ -0,0 +1,209 @@
|
|||
<template>
|
||||
<q-dialog
|
||||
v-model="dialogModel"
|
||||
@hide="triggerDialogClose"
|
||||
>
|
||||
<q-card
|
||||
dark
|
||||
class="existingDocumentPopup"
|
||||
>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<h6 class="text-center q-my-sm">Open existing document</h6>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<q-select
|
||||
ref="ref_existingDocument"
|
||||
style="flex-grow: 1;"
|
||||
dense
|
||||
dark
|
||||
:options="filteredExistingInput"
|
||||
use-input
|
||||
outlined
|
||||
input-debounce="0"
|
||||
v-model="existingDocumentModel"
|
||||
@filter="filterExistingSelect"
|
||||
@input="openExistingInput"
|
||||
>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
:style="`color: ${opt.color}`"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon
|
||||
:style="`color: ${opt.color}`"
|
||||
:name="(opt.isCategory) ? 'fas fa-folder-open' : opt.icon"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label v-html="opt.label" ></q-item-label>
|
||||
</q-item-section>
|
||||
<q-btn
|
||||
tabindex="-1"
|
||||
round
|
||||
flat
|
||||
dense
|
||||
dark
|
||||
color="primary"
|
||||
class="z-1 q-ml-md"
|
||||
icon="mdi-plus"
|
||||
size="md"
|
||||
@click.stop.prevent="addNewItemUnderSelected(opt)"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="300"
|
||||
>
|
||||
Add a new document belonging under {{ opt.label }}
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-card-actions align="center" class="q-mb-sm">
|
||||
<q-btn flat label="Close window" color="primary" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
|
||||
import PouchDB from "pouchdb"
|
||||
|
||||
import DialogBase from "src/components/dialogs/_DialogBase"
|
||||
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class ExistingDocumentDialog extends DialogBase {
|
||||
@Watch("dialogTrigger")
|
||||
openDialog (val: string|false) {
|
||||
if (val) {
|
||||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
|
||||
this.populateExistingObjectDialog().catch(e => console.log(e))
|
||||
}
|
||||
}
|
||||
|
||||
existingObjectList = [] as I_ShortenedDocument[]
|
||||
|
||||
async populateExistingObjectDialog () {
|
||||
let allDocs = [] as I_ShortenedDocument[]
|
||||
for (const blueprint of this.SGET_allBlueprints) {
|
||||
const CurrentObjectDB = new PouchDB(blueprint._id)
|
||||
|
||||
const dbDocuments = await CurrentObjectDB.allDocs({ include_docs: true })
|
||||
const formattedDocuments = dbDocuments.rows.map(singleDocument => {
|
||||
const doc = singleDocument.doc as unknown as I_ShortenedDocument
|
||||
return {
|
||||
label: doc.extraFields.find(e => e.id === "name")?.value,
|
||||
icon: doc.icon,
|
||||
id: doc._id,
|
||||
url: doc.url,
|
||||
type: doc.type,
|
||||
color: doc.extraFields.find(e => e.id === "documentColor")?.value,
|
||||
isCategory: doc.extraFields.find(e => e.id === "categorySwitch")?.value
|
||||
} as unknown as I_ShortenedDocument
|
||||
}).sort((a, b) => a.label.localeCompare(b.label))
|
||||
// @ts-ignore
|
||||
allDocs = [...allDocs, ...formattedDocuments]
|
||||
}
|
||||
|
||||
this.existingObjectList = allDocs
|
||||
|
||||
this.$nextTick(function () {
|
||||
/*eslint-disable */
|
||||
setTimeout( () =>{
|
||||
if(this.$refs.ref_existingDocument){
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.focus()
|
||||
}
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
})
|
||||
}
|
||||
|
||||
existingDocumentModel = null
|
||||
|
||||
filteredExistingInput = null as unknown as I_ShortenedDocument[]
|
||||
|
||||
filterExistingSelect (val: string, update: (e: () => void) => void) {
|
||||
if (val === "") {
|
||||
update(() => {
|
||||
this.filteredExistingInput = this.existingObjectList
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_existingDocument && this.filteredExistingInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
update(() => {
|
||||
const needle = val.toLowerCase()
|
||||
this.filteredExistingInput = this.existingObjectList.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_existingDocument && this.filteredExistingInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
openExistingInput (e: I_ShortenedDocument) {
|
||||
this.dialogModel = false
|
||||
// @ts-ignore
|
||||
this.openExistingDocumentRoute(e)
|
||||
this.existingDocumentModel = null
|
||||
}
|
||||
|
||||
addNewItemUnderSelected (parent: any) {
|
||||
const routeObject = {
|
||||
_id: parent.type,
|
||||
parent: parent.id
|
||||
}
|
||||
// @ts-ignore
|
||||
this.addNewObjectRoute(routeObject)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.existingDocumentPopup {
|
||||
min-width: 600px;
|
||||
margin-top: 100px;
|
||||
align-self: flex-start;
|
||||
|
||||
h6 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
62
src/components/dialogs/KeybindCheatsheet.vue
Normal file
62
src/components/dialogs/KeybindCheatsheet.vue
Normal file
|
@ -0,0 +1,62 @@
|
|||
<template>
|
||||
|
||||
<q-dialog
|
||||
v-model="dialogModel"
|
||||
@hide="triggerDialogClose"
|
||||
>
|
||||
<q-card
|
||||
class="keyBindsDialog"
|
||||
>
|
||||
<q-card-section class="row items-center">
|
||||
<h6 class="text-center q-my-sm">Keybind list</h6>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-markup-table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-left">Action</th>
|
||||
<th class="text-left">Keybind</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="keybind in SGET_getCurrentKeyBindData.defaults" :key="keybind.id">
|
||||
<td class="text-left" v-html="keybind.tooltip"/>
|
||||
<td class="text-left" v-html="retrieveKeybindString(keybind)"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</q-markup-table>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="center" class="q-mb-lg q-mt-md">
|
||||
<q-btn flat label="Close window" color="primary" v-close-popup />
|
||||
</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"
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class KeybindCheatsheet extends DialogBase {
|
||||
@Watch("dialogTrigger")
|
||||
openDialog (val: string|false) {
|
||||
if (val) {
|
||||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
165
src/components/dialogs/NewDocument.vue
Normal file
165
src/components/dialogs/NewDocument.vue
Normal file
|
@ -0,0 +1,165 @@
|
|||
<template>
|
||||
<q-dialog
|
||||
v-model="dialogModel"
|
||||
@hide="triggerDialogClose"
|
||||
>
|
||||
<q-card
|
||||
dark
|
||||
class="newDocumentPopup"
|
||||
>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<h6 class="text-center q-my-sm">Add new document</h6>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<q-select
|
||||
dark
|
||||
ref="ref_newDocument"
|
||||
style="flex-grow: 1;"
|
||||
dense
|
||||
:options="filteredNewInput"
|
||||
use-input
|
||||
outlined
|
||||
input-debounce="0"
|
||||
v-model="newDocumentModel"
|
||||
@filter="filterNewSelect"
|
||||
@input="triggerNewInput"
|
||||
>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="opt.icon" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label v-html="opt.label" ></q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-card-actions align="center" class="q-mb-sm">
|
||||
<q-btn flat label="Close window" color="primary" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
interface NewObjectDocument {
|
||||
label: string
|
||||
icon: string
|
||||
order: number
|
||||
_id: string
|
||||
specialLabel: string
|
||||
}
|
||||
import DialogBase from "src/components/dialogs/_DialogBase"
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class NewDocumentDialog extends DialogBase {
|
||||
@Watch("dialogTrigger")
|
||||
openDialog (val: string|false) {
|
||||
if (val) {
|
||||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.SSET_setDialogState(true)
|
||||
this.dialogModel = true
|
||||
this.populateNewObjectDialog()
|
||||
}
|
||||
}
|
||||
|
||||
newObjectList = [] as NewObjectDocument[]
|
||||
|
||||
newDocumentModel = null
|
||||
|
||||
populateNewObjectDialog () {
|
||||
// @ts-ignore
|
||||
this.newObjectList = this.SGET_allBlueprints.map(blueprint => {
|
||||
return {
|
||||
label: blueprint.namePlural,
|
||||
icon: blueprint.icon,
|
||||
order: blueprint.order,
|
||||
_id: blueprint._id,
|
||||
specialLabel: blueprint.nameSingular.toLowerCase()
|
||||
}
|
||||
})
|
||||
|
||||
this.$nextTick(function () {
|
||||
/*eslint-disable */
|
||||
setTimeout( () =>{
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.focus()
|
||||
}, 100)
|
||||
/* eslint-enable */
|
||||
})
|
||||
}
|
||||
|
||||
filteredNewInput = null as unknown as NewObjectDocument[]
|
||||
|
||||
filterNewSelect (val: string, update: (e: () => void) => void) {
|
||||
if (val === "") {
|
||||
update(() => {
|
||||
this.filteredNewInput = this.newObjectList
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_newDocument && this.filteredNewInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
update(() => {
|
||||
const needle = val.toLowerCase()
|
||||
this.filteredNewInput = this.newObjectList.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_newDocument && this.filteredNewInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
}
|
||||
/* eslint-enable */
|
||||
})
|
||||
}
|
||||
|
||||
triggerNewInput (e: NewObjectDocument) {
|
||||
this.dialogModel = false
|
||||
this.addNewObjectRoute(e)
|
||||
this.newDocumentModel = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.newDocumentPopup {
|
||||
width: 600px;
|
||||
margin-top: 100px;
|
||||
align-self: flex-start;
|
||||
|
||||
h6 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
118
src/components/dialogs/ProjectCloseCheck.vue
Normal file
118
src/components/dialogs/ProjectCloseCheck.vue
Normal file
|
@ -0,0 +1,118 @@
|
|||
<template>
|
||||
<q-dialog
|
||||
v-model="dialogModel"
|
||||
@hide="triggerDialogClose"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section class="row justify-center">
|
||||
<h6 class="text-center q-my-sm">You have unsaved documents opened!</h6>
|
||||
</q-card-section>
|
||||
<q-card-section class="row justify-center q-mx-lg">
|
||||
All unsaved data will be lost upon closing the app unless the documents are saved first.
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row q-mx-lg">
|
||||
<div class="q-mb-md text-bold">Affected documents:</div>
|
||||
<q-list class="appWindowButtons__closeDialogList">
|
||||
<q-item
|
||||
v-for=" doc in openedDocs"
|
||||
:key="doc._id"
|
||||
clickable
|
||||
v-ripple
|
||||
active
|
||||
active-class="bg-primary-1 text-primary"
|
||||
v-close-popup
|
||||
:to="doc.url">
|
||||
<q-item-section avatar>
|
||||
<q-icon color="black" :name="doc.icon" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section class="text-primary">{{retrieveFieldValue(doc,'name')}}</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="around" class="q-mx-xl q-mt-lg q-mb-md">
|
||||
<q-btn flat label="Cancel" color="primary" v-close-popup />
|
||||
<q-btn
|
||||
flat
|
||||
:label="exitLabelText"
|
||||
color="red"
|
||||
v-close-popup
|
||||
@click="checkModeAction" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Watch, Prop } from "vue-property-decorator"
|
||||
|
||||
import DialogBase from "src/components/dialogs/_DialogBase"
|
||||
import { I_OpenedDocument } from "src/interfaces/I_OpenedDocument"
|
||||
import { remote } from "electron"
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class ProjectCloseCheck extends DialogBase {
|
||||
@Prop() readonly dialogMode!: "appClose" | "projectClose"
|
||||
|
||||
get exitLabelText () {
|
||||
if (this.dialogMode === "appClose") {
|
||||
return "Exit app without saving"
|
||||
}
|
||||
|
||||
if (this.dialogMode === "projectClose") {
|
||||
return "Close project without saving"
|
||||
}
|
||||
}
|
||||
|
||||
@Watch("dialogTrigger")
|
||||
openDialog (val: string|false) {
|
||||
if (val) {
|
||||
if (this.SGET_getDialogsState) {
|
||||
return
|
||||
}
|
||||
this.SSET_setDialogState(true)
|
||||
this.checkForDocumentsWithEdits()
|
||||
}
|
||||
}
|
||||
|
||||
openedDocs: I_OpenedDocument[]= []
|
||||
|
||||
checkForDocumentsWithEdits () {
|
||||
this.openedDocs = this.SGET_allOpenedDocuments.docs.filter(doc => doc.hasEdits)
|
||||
|
||||
if (this.openedDocs.length > 0) {
|
||||
this.dialogModel = true
|
||||
}
|
||||
else {
|
||||
this.checkModeAction()
|
||||
}
|
||||
}
|
||||
|
||||
checkModeAction () {
|
||||
if (this.dialogMode === "appClose") {
|
||||
this.closeApp()
|
||||
}
|
||||
if (this.dialogMode === "projectClose") {
|
||||
this.SSET_resetDocuments()
|
||||
this.triggerDialogClose()
|
||||
this.$router.push({ path: "/" }).catch((e: {name: string}) => {
|
||||
if (e && e.name !== "NavigationDuplicated") {
|
||||
console.log(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeApp () {
|
||||
remote.getCurrentWindow().destroy()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
27
src/components/dialogs/_DialogBase.ts
Normal file
27
src/components/dialogs/_DialogBase.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { Component, Prop, Emit } from "vue-property-decorator"
|
||||
import BaseClass from "src/BaseClass"
|
||||
|
||||
import { namespace } from "vuex-class"
|
||||
|
||||
const Dialogs = namespace("dialogsModule")
|
||||
|
||||
@Component
|
||||
export default class DialogBase extends BaseClass {
|
||||
@Dialogs.Getter("getDialogsState") SGET_getDialogsState!: boolean
|
||||
@Dialogs.Mutation("setDialogState") SSET_setDialogState!: (input: boolean) => void
|
||||
|
||||
dialogModel = false
|
||||
|
||||
@Prop() readonly dialogTrigger!: string
|
||||
|
||||
@Emit()
|
||||
triggerDialogClose () {
|
||||
this.SSET_setDialogState(false)
|
||||
return true
|
||||
}
|
||||
|
||||
@Emit()
|
||||
triggerDialogSubmit (val:string) {
|
||||
return val
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
<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-tooltip>
|
||||
<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>
|
||||
<q-tooltip :delay="500">
|
||||
This is a one-way relationship. <br> Editing this value <b>will not</b> have effect on the connected document/s.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-if="!isOneWayRelationship" name="mdi-arrow-left-right-bold" size="16px" class="q-ml-md">
|
||||
<q-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
This is a two-way relationship. <br> Editing this value <b>will</b> also effect the connected document/s.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
<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-tooltip>
|
||||
<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>
|
||||
<q-tooltip :delay="500">
|
||||
This is a one-way relationship. <br> Editing this value <b>will not</b> have effect on the connected document/s.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-if="!isOneWayRelationship" name="mdi-arrow-left-right-bold" size="16px" class="q-ml-md">
|
||||
<q-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
This is a two-way relationship. <br> Editing this value <b>will</b> also effect the connected document/s.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<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-tooltip>
|
||||
<q-tooltip :delay="500">
|
||||
<span v-html="toolTip"/>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
|
|
|
@ -25,6 +25,7 @@ $warning : #f2c037;
|
|||
|
||||
$customColors: (
|
||||
'gunmetal': #19323c,
|
||||
'gunmetal-light': lighten(#19323c, 7.5),
|
||||
'ruby-red': #a4031f,
|
||||
'satin-sheen-gold': #d2a334,
|
||||
'gainsboro': #dde4e4,
|
||||
|
|
|
@ -1,138 +1,23 @@
|
|||
<template>
|
||||
<q-layout view="lHh LpR lfr"
|
||||
>
|
||||
<q-layout view="hHh LpR lfr">
|
||||
|
||||
<q-dialog
|
||||
v-model="keyBindsDialog"
|
||||
>
|
||||
<q-card
|
||||
class="keyBindsDialog"
|
||||
>
|
||||
<q-card-section class="row items-center">
|
||||
<h6 class="text-center q-my-sm">Keybind list</h6>
|
||||
</q-card-section>
|
||||
<!-- Keybind dialog -->
|
||||
<keybindCheatsheetDialog
|
||||
:dialog-trigger="keybindsDialogTrigger"
|
||||
@trigger-dialog-close="keybindsDialogClose"
|
||||
/>
|
||||
|
||||
<q-card-section>
|
||||
<q-markup-table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-left">Action</th>
|
||||
<th class="text-left">Keybind</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="keybind in SGET_getCurrentKeyBindData.defaults" :key="keybind.id">
|
||||
<td class="text-left" v-html="keybind.tooltip"/>
|
||||
<td class="text-left" v-html="retrieveKeybindString(keybind)"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</q-markup-table>
|
||||
</q-card-section>
|
||||
<!-- New document dialog -->
|
||||
<newDocumentDialog
|
||||
:dialog-trigger="newObjectDialogTrigger"
|
||||
@trigger-dialog-close="newObjectDialogClose"
|
||||
/>
|
||||
|
||||
<q-card-actions align="center" class="q-mb-lg q-mt-md">
|
||||
<q-btn flat label="Close window" color="primary" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog
|
||||
v-model="newDocumentDialog"
|
||||
>
|
||||
<q-card
|
||||
class="newDocumentPopup"
|
||||
>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<h6 class="text-center q-my-sm">Add new document</h6>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<q-select
|
||||
ref="ref_newDocument"
|
||||
style="flex-grow: 1;"
|
||||
dense
|
||||
:options="filteredNewInput"
|
||||
use-input
|
||||
outlined
|
||||
input-debounce="0"
|
||||
v-model="newDocumentModel"
|
||||
@filter="filterNewSelect"
|
||||
@input="triggerNewInput"
|
||||
>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="opt.icon" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label v-html="opt.label" ></q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-card-actions align="center" class="q-mb-sm">
|
||||
<q-btn flat label="Close window" color="primary" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog
|
||||
v-model="existingDocumentDialog"
|
||||
>
|
||||
<q-card
|
||||
class="newDocumentPopup"
|
||||
>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<h6 class="text-center q-my-sm">Open existing document</h6>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row items-center">
|
||||
<q-select
|
||||
ref="ref_existingDocument"
|
||||
style="flex-grow: 1;"
|
||||
dense
|
||||
:options="filteredExistingInput"
|
||||
use-input
|
||||
outlined
|
||||
input-debounce="0"
|
||||
v-model="existingDocumentModel"
|
||||
@filter="filterExistingSelect"
|
||||
@input="openExistingInput"
|
||||
>
|
||||
<template v-slot:option="{ itemProps, itemEvents, opt }">
|
||||
<q-item
|
||||
v-bind="itemProps"
|
||||
v-on="itemEvents"
|
||||
:style="`background-color: ${opt.color}99`"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="(opt.isCategory) ? 'fas fa-folder-open' : opt.icon" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label v-html="opt.label" ></q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-card-actions align="center" class="q-mb-sm">
|
||||
<q-btn flat label="Close window" color="primary" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
<!-- Existing document dialog -->
|
||||
<existingDocumentDialog
|
||||
:dialog-trigger="existingObjectDialogTrigger"
|
||||
@trigger-dialog-close="existingObjectDialogClose"
|
||||
/>
|
||||
|
||||
<!-- Left drawer -->
|
||||
<q-drawer
|
||||
|
@ -150,7 +35,7 @@
|
|||
<q-btn
|
||||
icon="mdi-note-plus-outline"
|
||||
color="primary"
|
||||
@click="populateNewObjectDialog"
|
||||
@click="newObjectAssignUID"
|
||||
>
|
||||
<q-tooltip>
|
||||
Quick-add a new document.
|
||||
|
@ -160,7 +45,7 @@
|
|||
<q-btn
|
||||
icon="mdi-database-search"
|
||||
color="primary"
|
||||
@click="populateExistingObjectDialog"
|
||||
@click="existingObjectAssignUID"
|
||||
>
|
||||
<q-tooltip>
|
||||
Quick-search an existing document.
|
||||
|
@ -170,7 +55,7 @@
|
|||
<q-btn
|
||||
icon="mdi-keyboard-outline"
|
||||
color="primary"
|
||||
@click="keyBindsDialog = true"
|
||||
@click="keybindsDialogAssignUID"
|
||||
>
|
||||
<q-tooltip>
|
||||
Show keybind cheatsheet.
|
||||
|
@ -181,15 +66,9 @@
|
|||
</q-drawer>
|
||||
|
||||
<!-- Header -->
|
||||
<topTabs/>
|
||||
|
||||
<!-- Right drawer -->
|
||||
<q-drawer
|
||||
v-model="rightDrawerOpen"
|
||||
side="right"
|
||||
elevated>
|
||||
<!-- drawer content -->
|
||||
</q-drawer>
|
||||
<appHeader
|
||||
:is-project="true"
|
||||
/>
|
||||
|
||||
<q-page-container>
|
||||
<transition
|
||||
|
@ -209,226 +88,95 @@
|
|||
|
||||
import { Component, Watch } from "vue-property-decorator"
|
||||
import BaseClass from "src/BaseClass"
|
||||
import PouchDB from "pouchdb"
|
||||
|
||||
import objectTree from "src/components/ObjectTree.vue"
|
||||
import topTabs from "src/components/TopTabs.vue"
|
||||
import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
|
||||
|
||||
interface NewObjectDocument {
|
||||
label: string
|
||||
icon: string
|
||||
order: number
|
||||
_id: string
|
||||
specialLabel: string
|
||||
}
|
||||
import appHeader from "src/components/AppHeader.vue"
|
||||
import keybindCheatsheetDialog from "src/components/dialogs/KeybindCheatsheet.vue"
|
||||
import newDocumentDialog from "src/components/dialogs/NewDocument.vue"
|
||||
import existingDocumentDialog from "src/components/dialogs/ExistingDocument.vue"
|
||||
|
||||
@Component({
|
||||
components: { objectTree, topTabs }
|
||||
components: {
|
||||
objectTree,
|
||||
appHeader,
|
||||
keybindCheatsheetDialog,
|
||||
newDocumentDialog,
|
||||
existingDocumentDialog
|
||||
}
|
||||
})
|
||||
export default class MainLayout extends BaseClass {
|
||||
leftDrawerOpen = true
|
||||
rightDrawerOpen = false
|
||||
/****************************************************************/
|
||||
// Local settings
|
||||
/****************************************************************/
|
||||
|
||||
/**
|
||||
* Model for the left drawer of the app containing the hierarchical tree
|
||||
*/
|
||||
leftDrawerOpen = true
|
||||
|
||||
/****************************************************************/
|
||||
// Keybinds management
|
||||
/****************************************************************/
|
||||
|
||||
/**
|
||||
* Local keybinds
|
||||
*/
|
||||
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
||||
processKeyPush () {
|
||||
// Keybind cheatsheet
|
||||
if (this.determineKeyBind("openKeybindsCheatsheet")) {
|
||||
this.keyBindsDialog = true
|
||||
this.keybindsDialogAssignUID()
|
||||
}
|
||||
|
||||
// Quick new document
|
||||
if (this.determineKeyBind("quickNewDocument")) {
|
||||
this.populateNewObjectDialog()
|
||||
this.newObjectAssignUID()
|
||||
}
|
||||
|
||||
// Quick open existing document
|
||||
if (this.determineKeyBind("quickExistingDocument")) {
|
||||
this.populateExistingObjectDialog().catch(e => console.log(e))
|
||||
this.existingObjectAssignUID()
|
||||
}
|
||||
}
|
||||
|
||||
created () {
|
||||
window.addEventListener("keyup", this.triggerKeyPush)
|
||||
/****************************************************************/
|
||||
// Keybings cheatsheet dialog
|
||||
/****************************************************************/
|
||||
|
||||
keybindsDialogTrigger: string | false = false
|
||||
keybindsDialogClose () {
|
||||
this.keybindsDialogTrigger = false
|
||||
}
|
||||
|
||||
destroyed () {
|
||||
window.removeEventListener("keyup", this.triggerKeyPush)
|
||||
keybindsDialogAssignUID () {
|
||||
this.keybindsDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
triggerKeyPush (e) {
|
||||
if (this.newDocumentDialog || this.existingDocumentDialog || this.keyBindsDialog) {
|
||||
return false
|
||||
}
|
||||
if (e?.altKey === true || e?.ctrlKey || e?.shiftKey) {
|
||||
const ouputKeycombo = {
|
||||
altKey: e.altKey,
|
||||
ctrlKey: e.ctrlKey,
|
||||
shiftKey: e.shiftKey,
|
||||
keyCode: e.keyCode
|
||||
/****************************************************************/
|
||||
// New document dialog
|
||||
/****************************************************************/
|
||||
|
||||
newObjectDialogTrigger: string | false = false
|
||||
newObjectDialogClose () {
|
||||
this.newObjectDialogTrigger = false
|
||||
}
|
||||
|
||||
this.SSET_updatePressedKey(ouputKeycombo)
|
||||
}
|
||||
newObjectAssignUID () {
|
||||
this.newObjectDialogTrigger = this.generateUID()
|
||||
}
|
||||
|
||||
newDocumentDialog = false
|
||||
/****************************************************************/
|
||||
// Existing document dialog
|
||||
/****************************************************************/
|
||||
|
||||
newObjectList = [] as NewObjectDocument[]
|
||||
|
||||
newDocumentModel = null
|
||||
|
||||
populateNewObjectDialog () {
|
||||
this.newDocumentDialog = true
|
||||
// @ts-ignore
|
||||
this.newObjectList = this.SGET_allBlueprints.map(blueprint => {
|
||||
return {
|
||||
label: blueprint.namePlural,
|
||||
icon: blueprint.icon,
|
||||
order: blueprint.order,
|
||||
_id: blueprint._id,
|
||||
specialLabel: blueprint.nameSingular.toLowerCase()
|
||||
}
|
||||
})
|
||||
|
||||
this.$nextTick(function () {
|
||||
/*eslint-disable */
|
||||
setTimeout( () =>{
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.focus()
|
||||
}, 100)
|
||||
/* eslint-enable */
|
||||
})
|
||||
existingObjectDialogTrigger: string | false = false
|
||||
existingObjectDialogClose () {
|
||||
this.existingObjectDialogTrigger = false
|
||||
}
|
||||
|
||||
filteredNewInput = null as unknown as NewObjectDocument[]
|
||||
|
||||
filterNewSelect (val: string, update: (e: () => void) => void) {
|
||||
if (val === "") {
|
||||
update(() => {
|
||||
this.filteredNewInput = this.newObjectList
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_newDocument && this.filteredNewInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
existingObjectAssignUID () {
|
||||
this.existingObjectDialogTrigger = this.generateUID()
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
update(() => {
|
||||
const needle = val.toLowerCase()
|
||||
this.filteredNewInput = this.newObjectList.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_newDocument && this.filteredNewInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_newDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
}
|
||||
/* eslint-enable */
|
||||
})
|
||||
}
|
||||
|
||||
triggerNewInput (e: NewObjectDocument) {
|
||||
this.newDocumentDialog = false
|
||||
this.addNewObjectRoute(e)
|
||||
this.newDocumentModel = null
|
||||
}
|
||||
|
||||
existingObjectList = [] as I_ShortenedDocument[]
|
||||
|
||||
async populateExistingObjectDialog () {
|
||||
this.existingDocumentDialog = true
|
||||
let allDocs = [] as I_ShortenedDocument[]
|
||||
for (const blueprint of this.SGET_allBlueprints) {
|
||||
const CurrentObjectDB = new PouchDB(blueprint._id)
|
||||
|
||||
const dbDocuments = await CurrentObjectDB.allDocs({ include_docs: true })
|
||||
const formattedDocuments = dbDocuments.rows.map(singleDocument => {
|
||||
const doc = singleDocument.doc as unknown as I_ShortenedDocument
|
||||
return {
|
||||
label: doc.extraFields.find(e => e.id === "name")?.value,
|
||||
icon: doc.icon,
|
||||
url: doc.url,
|
||||
color: doc.extraFields.find(e => e.id === "documentColor")?.value,
|
||||
isCategory: doc.extraFields.find(e => e.id === "categorySwitch")?.value
|
||||
} as unknown as I_ShortenedDocument
|
||||
}).sort((a, b) => a.label.localeCompare(b.label))
|
||||
// @ts-ignore
|
||||
allDocs = [...allDocs, ...formattedDocuments]
|
||||
}
|
||||
|
||||
this.existingObjectList = allDocs
|
||||
|
||||
this.$nextTick(function () {
|
||||
/*eslint-disable */
|
||||
setTimeout( () =>{
|
||||
if(this.$refs.ref_existingDocument){
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.focus()
|
||||
}
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
})
|
||||
}
|
||||
|
||||
existingDocumentDialog = false
|
||||
|
||||
existingDocumentModel = null
|
||||
|
||||
filteredExistingInput = null as unknown as I_ShortenedDocument[]
|
||||
|
||||
filterExistingSelect (val: string, update: (e: () => void) => void) {
|
||||
if (val === "") {
|
||||
update(() => {
|
||||
this.filteredExistingInput = this.existingObjectList
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_existingDocument && this.filteredExistingInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
update(() => {
|
||||
const needle = val.toLowerCase()
|
||||
this.filteredExistingInput = this.existingObjectList.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
|
||||
/*eslint-disable */
|
||||
if(this.$refs.ref_existingDocument && this.filteredExistingInput.length > 0){
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.setOptionIndex(-1)
|
||||
// @ts-ignore
|
||||
this.$refs.ref_existingDocument.moveOptionSelection(1, true)
|
||||
}, 300)
|
||||
/* eslint-enable */
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
openExistingInput (e: I_ShortenedDocument) {
|
||||
this.existingDocumentDialog = false
|
||||
// @ts-ignore
|
||||
this.openExistingDocumentRoute(e)
|
||||
this.existingDocumentModel = null
|
||||
}
|
||||
|
||||
keyBindsDialog = false
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -437,18 +185,6 @@ export default class MainLayout extends BaseClass {
|
|||
outline: none !important;
|
||||
}
|
||||
|
||||
.newDocumentPopup {
|
||||
width: 400px;
|
||||
margin-top: 100px;
|
||||
align-self: flex-start;
|
||||
|
||||
h6 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.keyBindsDialog {
|
||||
width: 100%;
|
||||
max-width: 1000px !important;
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
<template>
|
||||
<q-layout view="lHh LpR lfr">
|
||||
|
||||
<!-- Header -->
|
||||
<appHeader
|
||||
:is-project="false"
|
||||
/>
|
||||
|
||||
<q-page-container>
|
||||
<transition
|
||||
enter-active-class="animated fadeIn"
|
||||
|
@ -17,9 +23,10 @@
|
|||
|
||||
import { Component } from "vue-property-decorator"
|
||||
import BaseClass from "src/BaseClass"
|
||||
import appHeader from "src/components/AppHeader.vue"
|
||||
|
||||
@Component({
|
||||
components: { }
|
||||
components: { appHeader }
|
||||
})
|
||||
export default class ProjectManagementLayout extends BaseClass {
|
||||
|
||||
|
|
|
@ -25,6 +25,13 @@
|
|||
</q-dialog>
|
||||
|
||||
<div class="col-12 flex justify-end q-mb-lg q-mt-md">
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="`Add a new ${bluePrintData.nameSingular} belonging under ${retrieveFieldValue(currentData, 'name')}`"
|
||||
@click="addNewUnderParent"
|
||||
class="q-mr-xl"
|
||||
v-if="!currentData.isNew"
|
||||
/>
|
||||
<q-btn
|
||||
color="primary"
|
||||
:label="`Save ${bluePrintData.nameSingular}`"
|
||||
|
@ -179,8 +186,8 @@ import BaseClass from "src/BaseClass"
|
|||
import { I_Blueprint, I_ExtraFields } from "src/interfaces/I_Blueprint"
|
||||
import { I_OpenedDocument } from "src/interfaces/I_OpenedDocument"
|
||||
import PouchDB from "pouchdb"
|
||||
// import { cleanDatabases } from "src/databaseManager/cleaner"
|
||||
import { single_changeRelationshipToAnotherObject, many_changeRelationshipToAnotherObject } from "src/databaseManager/relationshipManager"
|
||||
// import { cleanDatabases } from "src/scripts/databaseManager/cleaner"
|
||||
import { single_changeRelationshipToAnotherObject, many_changeRelationshipToAnotherObject } from "src/scripts/databaseManager/relationshipManager"
|
||||
|
||||
import { extend } from "quasar"
|
||||
|
||||
|
@ -579,8 +586,6 @@ export default class PageDocumentDisplay extends BaseClass {
|
|||
}
|
||||
catch (error) {}
|
||||
|
||||
console.log(retrievedObject)
|
||||
|
||||
currentExtraFields.push(
|
||||
{
|
||||
id: "parentDoc",
|
||||
|
@ -641,6 +646,15 @@ export default class PageDocumentDisplay extends BaseClass {
|
|||
const ignoredList = ["breakBasic", "name", "documentColor", "parentDoc", "order", "categorySwitch"]
|
||||
return (!isCategory || ignoredList.includes(currentFieldID))
|
||||
}
|
||||
|
||||
addNewUnderParent () {
|
||||
const routeObject = {
|
||||
_id: this.currentData.type,
|
||||
parent: this.currentData._id
|
||||
}
|
||||
// @ts-ignore
|
||||
this.addNewObjectRoute(routeObject)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -5,16 +5,6 @@
|
|||
<h3>Project screen for {{projectName}}</h3>
|
||||
</div>
|
||||
|
||||
<div class="col-12 q-mb-lg">
|
||||
<q-btn
|
||||
color="primary"
|
||||
size="md"
|
||||
label="Go to title screen"
|
||||
class="q-px-xl q-py-xs"
|
||||
to="/"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-12 q-mb-lg">
|
||||
<q-btn
|
||||
color="primary"
|
||||
|
@ -32,14 +22,18 @@ import { Component } from "vue-property-decorator"
|
|||
|
||||
import BaseClass from "src/BaseClass"
|
||||
|
||||
import { retrieveCurrentProjectName, exportProject } from "src/scripts/projectManagement/projectManagent"
|
||||
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
export default class ProjectScreen extends BaseClass {
|
||||
projectName = ""
|
||||
|
||||
exportProject = exportProject
|
||||
|
||||
async created () {
|
||||
this.projectName = await this.retrieveCurrentProjectName()
|
||||
this.projectName = await retrieveCurrentProjectName()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
color="primary"
|
||||
v-close-popup
|
||||
:disable="newProjectName.length === 0"
|
||||
@click="createNewProject(newProjectName)" />
|
||||
@click="createNewProject(newProjectName, $router)" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
@ -56,7 +56,7 @@
|
|||
color="primary"
|
||||
size="md"
|
||||
class="q-px-xl q-py-xs"
|
||||
@click="openExistingProject"
|
||||
@click="openExistingProject($router)"
|
||||
>
|
||||
<div>Open existing project</div>
|
||||
<q-icon
|
||||
|
@ -93,27 +93,16 @@
|
|||
</q-btn>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<q-btn
|
||||
color="primary"
|
||||
size="md"
|
||||
class="q-px-xl q-py-xs"
|
||||
@click="toggleDevTools"
|
||||
>
|
||||
<div>Toggle dev tools</div>
|
||||
|
||||
</q-btn>
|
||||
</div>
|
||||
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component } from "vue-property-decorator"
|
||||
import { remote } from "electron"
|
||||
|
||||
import BaseClass from "src/BaseClass"
|
||||
|
||||
import { openExistingProject, createNewProject, retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent"
|
||||
|
||||
@Component({
|
||||
components: { }
|
||||
})
|
||||
|
@ -122,23 +111,11 @@ export default class WelcomeScreen extends BaseClass {
|
|||
newProjectName = ""
|
||||
newProjectDialog = false
|
||||
|
||||
toggleDevTools () {
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
const devToolsOpened: boolean = remote.getCurrentWindow().isDevToolsOpened()
|
||||
|
||||
if (devToolsOpened) {
|
||||
// @ts-ignore
|
||||
remote.getCurrentWindow().closeDevTools()
|
||||
} else {
|
||||
// @ts-ignore
|
||||
remote.getCurrentWindow().openDevTools()
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
openExistingProject = openExistingProject
|
||||
createNewProject = createNewProject
|
||||
|
||||
async created () {
|
||||
this.projectExists = await this.retrieveCurrentProjectName()
|
||||
this.projectExists = await retrieveCurrentProjectName()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import { I_Blueprint } from "./../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
|
||||
import PouchDB from "pouchdb"
|
||||
import _ from "lodash"
|
||||
|
||||
import { charactersBlueprint } from "src/databaseManager/blueprints/characters"
|
||||
import { chaptersBlueprint } from "src/databaseManager/blueprints/chapters"
|
||||
import { currenciesBlueprint } from "src/databaseManager/blueprints/currencies"
|
||||
import { eventsBlueprint } from "src/databaseManager/blueprints/events"
|
||||
import { languagesBlueprint } from "src/databaseManager/blueprints/languages"
|
||||
import { locationsBlueprint } from "src/databaseManager/blueprints/locations"
|
||||
import { loreNotesBlueprint } from "src/databaseManager/blueprints/loreNotes"
|
||||
import { politicalGroupsBlueprint } from "src/databaseManager/blueprints/politicalGroups"
|
||||
import { racesBlueprint } from "src/databaseManager/blueprints/races"
|
||||
import { religionsBlueprint } from "src/databaseManager/blueprints/religions"
|
||||
import { mythsBlueprint } from "src/databaseManager/blueprints/myths"
|
||||
import { magicBlueprint } from "src/databaseManager/blueprints/magic"
|
||||
import { techBlueprint } from "src/databaseManager/blueprints/scienceTechnology"
|
||||
import { itemsBlueprint } from "src/databaseManager/blueprints/items"
|
||||
import { charactersBlueprint } from "src/scripts/databaseManager/blueprints/characters"
|
||||
import { chaptersBlueprint } from "src/scripts/databaseManager/blueprints/chapters"
|
||||
import { currenciesBlueprint } from "src/scripts/databaseManager/blueprints/currencies"
|
||||
import { eventsBlueprint } from "src/scripts/databaseManager/blueprints/events"
|
||||
import { languagesBlueprint } from "src/scripts/databaseManager/blueprints/languages"
|
||||
import { locationsBlueprint } from "src/scripts/databaseManager/blueprints/locations"
|
||||
import { loreNotesBlueprint } from "src/scripts/databaseManager/blueprints/loreNotes"
|
||||
import { politicalGroupsBlueprint } from "src/scripts/databaseManager/blueprints/politicalGroups"
|
||||
import { racesBlueprint } from "src/scripts/databaseManager/blueprints/races"
|
||||
import { religionsBlueprint } from "src/scripts/databaseManager/blueprints/religions"
|
||||
import { mythsBlueprint } from "src/scripts/databaseManager/blueprints/myths"
|
||||
import { magicBlueprint } from "src/scripts/databaseManager/blueprints/magic"
|
||||
import { techBlueprint } from "src/scripts/databaseManager/blueprints/scienceTechnology"
|
||||
import { itemsBlueprint } from "src/scripts/databaseManager/blueprints/items"
|
||||
|
||||
/**
|
||||
* Loads all the blueprints and processes them apropriatelly
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const chaptersBlueprint: I_Blueprint = {
|
||||
_id: "chapters",
|
||||
order: 20,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "./../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const charactersBlueprint: I_Blueprint = {
|
||||
_id: "characters",
|
||||
order: 18,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const currenciesBlueprint: I_Blueprint = {
|
||||
_id: "currencies",
|
||||
order: 8,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const eventsBlueprint: I_Blueprint = {
|
||||
_id: "events",
|
||||
order: 16,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const itemsBlueprint: I_Blueprint = {
|
||||
_id: "items",
|
||||
order: 10,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const languagesBlueprint: I_Blueprint = {
|
||||
_id: "languages",
|
||||
order: 9,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const locationsBlueprint: I_Blueprint = {
|
||||
_id: "locations",
|
||||
order: 17,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const loreNotesBlueprint: I_Blueprint = {
|
||||
_id: "loreNotes",
|
||||
order: 19,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const magicBlueprint: I_Blueprint = {
|
||||
_id: "magic",
|
||||
order: 13,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const mythsBlueprint: I_Blueprint = {
|
||||
_id: "myths",
|
||||
order: 7,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const politicalGroupsBlueprint: I_Blueprint = {
|
||||
_id: "politicalGroups",
|
||||
order: 15,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const racesBlueprint: I_Blueprint = {
|
||||
_id: "races",
|
||||
order: 11,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const religionsBlueprint: I_Blueprint = {
|
||||
_id: "religions",
|
||||
order: 14,
|
|
@ -1,4 +1,4 @@
|
|||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import { I_Blueprint } from "../../../interfaces/I_Blueprint"
|
||||
export const techBlueprint: I_Blueprint = {
|
||||
_id: "tech",
|
||||
order: 12,
|
|
@ -1,5 +1,5 @@
|
|||
import { retrieveAllBlueprints } from "src/databaseManager/blueprintManager"
|
||||
import { I_Blueprint } from "../interfaces/I_Blueprint"
|
||||
import { retrieveAllBlueprints } from "src/scripts/databaseManager/blueprintManager"
|
||||
import { I_Blueprint } from "../../interfaces/I_Blueprint"
|
||||
import PouchDB from "pouchdb"
|
||||
|
||||
export const cleanDatabases = async () => {
|
|
@ -2,7 +2,7 @@ import PouchDB from "pouchdb"
|
|||
import { I_Blueprint } from "src/interfaces/I_Blueprint"
|
||||
import { I_FieldRelationship } from "src/interfaces/I_FieldRelationship"
|
||||
|
||||
import { I_ExtraDocumentFields, I_OpenedDocument } from "./../interfaces/I_OpenedDocument"
|
||||
import { I_ExtraDocumentFields, I_OpenedDocument } from "../../interfaces/I_OpenedDocument"
|
||||
|
||||
export const single_changeRelationshipToAnotherObject = async (
|
||||
field: I_ExtraDocumentFields,
|
148
src/scripts/projectManagement/projectManagent.ts
Normal file
148
src/scripts/projectManagement/projectManagent.ts
Normal file
|
@ -0,0 +1,148 @@
|
|||
import { remote } from "electron"
|
||||
// @ts-ignore
|
||||
import replicationStream from "pouchdb-replication-stream/dist/pouchdb.replication-stream.min.js"
|
||||
// @ts-ignore
|
||||
import load from "pouchdb-load"
|
||||
import PouchDB from "pouchdb"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
|
||||
/**
|
||||
* Creates a brand new project and deleted any present data avaiable right now
|
||||
* @param projectName The name of the new project
|
||||
* @praram vueRouter The vue router object
|
||||
*/
|
||||
export const createNewProject = async (projectName: string, vueRouter: any) => {
|
||||
await removeCurrentProject()
|
||||
|
||||
const ProjectDB = new PouchDB("project-data")
|
||||
const newProject = { _id: projectName }
|
||||
await ProjectDB.put(newProject)
|
||||
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
vueRouter.push({ path: "/project" }).catch((e: {name: string}) => {
|
||||
const errorName : string = e.name
|
||||
if (errorName === "NavigationDuplicated") {
|
||||
return
|
||||
}
|
||||
console.log(e)
|
||||
})
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an file dialog asking the use for location where to export the project
|
||||
* @param projectName The name of the project to export
|
||||
*/
|
||||
export const exportProject = (projectName: string) => {
|
||||
remote.dialog.showOpenDialog({
|
||||
properties: ["openDirectory"]
|
||||
}).then(async (result) => {
|
||||
/*eslint-disable */
|
||||
const folderPath = result.filePaths[0]
|
||||
|
||||
PouchDB.plugin(replicationStream.plugin)
|
||||
// @ts-ignore
|
||||
PouchDB.adapter("writableStream", replicationStream.adapters.writableStream)
|
||||
|
||||
// @ts-ignore
|
||||
const allDBS = await indexedDB.databases()
|
||||
|
||||
const DBnames: string[] = allDBS.map((db: {name: string}) => {
|
||||
return db.name.replace("_pouch_", "")
|
||||
})
|
||||
|
||||
for (const db of DBnames) {
|
||||
const CurrentDB = new PouchDB(db)
|
||||
|
||||
if (!fs.existsSync(`${folderPath}/${projectName}`)) {
|
||||
fs.mkdirSync(`${folderPath}/${projectName}`)
|
||||
}
|
||||
const ws = fs.createWriteStream(`${folderPath}/${projectName}/${db}.txt`)
|
||||
|
||||
// @ts-ignore
|
||||
await CurrentDB.dump(ws)
|
||||
}
|
||||
/* eslint-enable */
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current project and all its data
|
||||
*/
|
||||
export const removeCurrentProject = async () => {
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
const allDBS = await indexedDB.databases()
|
||||
|
||||
const DBnames: string[] = allDBS.map((db: {name: string}) => {
|
||||
return db.name.replace("_pouch_", "")
|
||||
})
|
||||
|
||||
for (const db of DBnames) {
|
||||
const CurrentDB = new PouchDB(db)
|
||||
await CurrentDB.destroy()
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a dialog to let user pick whatever project they wish to open and lets them select a directory
|
||||
* @param vueRouter The vue router object
|
||||
*/
|
||||
export const openExistingProject = (vueRouter: any) => {
|
||||
/*eslint-disable */
|
||||
remote.dialog.showOpenDialog({
|
||||
properties: ["openDirectory"]
|
||||
}).then(async (result) => {
|
||||
const folderPath = result.filePaths[0]
|
||||
|
||||
if (!folderPath) {
|
||||
return
|
||||
}
|
||||
|
||||
await removeCurrentProject()
|
||||
|
||||
// @ts-ignore
|
||||
PouchDB.plugin({
|
||||
loadIt: load.load
|
||||
})
|
||||
|
||||
const allFiles = fs.readdirSync(folderPath)
|
||||
|
||||
for (const file of allFiles) {
|
||||
const currentDBName = path.parse(file).name
|
||||
const CurrentDB = new PouchDB(currentDBName)
|
||||
|
||||
const fileContents = fs.readFileSync(`${folderPath}/${file}`, { encoding: "utf8" })
|
||||
// @ts-ignore
|
||||
await CurrentDB.loadIt(fileContents)
|
||||
}
|
||||
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
vueRouter.push({ path: "/project" }).catch((e: {name: string}) => {
|
||||
const errorName : string = e.name
|
||||
if (errorName === "NavigationDuplicated") {
|
||||
return
|
||||
}
|
||||
console.log(e)
|
||||
})
|
||||
/* eslint-enable */
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves current project name
|
||||
*/
|
||||
export const retrieveCurrentProjectName = async () => {
|
||||
const ProjectDB = new PouchDB("project-data")
|
||||
const projectData = await ProjectDB.allDocs({ include_docs: true })
|
||||
return projectData?.rows[0]?.id
|
||||
}
|
19
src/scripts/utilities/devTools.ts
Normal file
19
src/scripts/utilities/devTools.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { remote } from "electron"
|
||||
|
||||
/**
|
||||
* Toggles dev tools in the current window
|
||||
*/
|
||||
export const toggleDevTools = () => {
|
||||
/*eslint-disable */
|
||||
// @ts-ignore
|
||||
const devToolsOpened: boolean = remote.getCurrentWindow().isDevToolsOpened()
|
||||
|
||||
if (devToolsOpened) {
|
||||
// @ts-ignore
|
||||
remote.getCurrentWindow().closeDevTools()
|
||||
} else {
|
||||
// @ts-ignore
|
||||
remote.getCurrentWindow().openDevTools()
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
|
@ -8,6 +8,7 @@ import Vuex from "vuex"
|
|||
import blueprintsModule from "./module-blueprints"
|
||||
import openedDocumentsModule from "./module-openedDocuments"
|
||||
import keybindsModule from "./module-keybinds"
|
||||
import dialogsModule from "./module-dialogs"
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
|
@ -28,7 +29,8 @@ export default store(function ({ Vue }) {
|
|||
modules: {
|
||||
blueprintsModule,
|
||||
openedDocumentsModule,
|
||||
keybindsModule
|
||||
keybindsModule,
|
||||
dialogsModule
|
||||
// example
|
||||
},
|
||||
|
||||
|
|
11
src/store/module-dialogs/actions.ts
Normal file
11
src/store/module-dialogs/actions.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { ActionTree } from "vuex"
|
||||
import { StateInterface } from "../index"
|
||||
import { DialogsStateInterface } from "./state"
|
||||
|
||||
const actions: ActionTree<DialogsStateInterface, StateInterface> = {
|
||||
// someAction (context) {
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
export default actions
|
12
src/store/module-dialogs/getters.ts
Normal file
12
src/store/module-dialogs/getters.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { GetterTree } from "vuex"
|
||||
import { StateInterface } from "../index"
|
||||
import { DialogsStateInterface } from "./state"
|
||||
|
||||
const getters: GetterTree<DialogsStateInterface, StateInterface> = {
|
||||
|
||||
getDialogsState (state) {
|
||||
return state.dialogExists
|
||||
}
|
||||
}
|
||||
|
||||
export default getters
|
16
src/store/module-dialogs/index.ts
Normal file
16
src/store/module-dialogs/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Module } from "vuex"
|
||||
import { StateInterface } from "../index"
|
||||
import state, { DialogsStateInterface } from "./state"
|
||||
import actions from "./actions"
|
||||
import getters from "./getters"
|
||||
import mutations from "./mutations"
|
||||
|
||||
const openedDocumentsModule: Module<DialogsStateInterface, StateInterface> = {
|
||||
namespaced: true,
|
||||
actions,
|
||||
getters,
|
||||
mutations,
|
||||
state
|
||||
}
|
||||
|
||||
export default openedDocumentsModule
|
11
src/store/module-dialogs/mutations.ts
Normal file
11
src/store/module-dialogs/mutations.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { MutationTree } from "vuex"
|
||||
import { DialogsStateInterface } from "./state"
|
||||
|
||||
const mutation: MutationTree<DialogsStateInterface> = {
|
||||
setDialogState (state: DialogsStateInterface, input: boolean) {
|
||||
state.dialogExists = input
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default mutation
|
11
src/store/module-dialogs/state.ts
Normal file
11
src/store/module-dialogs/state.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export interface DialogsStateInterface {
|
||||
dialogExists: boolean
|
||||
}
|
||||
|
||||
function state (): DialogsStateInterface {
|
||||
return {
|
||||
dialogExists: false
|
||||
}
|
||||
}
|
||||
|
||||
export default state
|
|
@ -25,6 +25,11 @@ const mutation: MutationTree<OpenDocumentsStateInterface> = {
|
|||
const toRemoveIndex = state.documents.docs.findIndex(doc => doc.type === input.type && doc._id === input._id)
|
||||
state.documents.docs.splice(toRemoveIndex, 1)
|
||||
state.documents.timestamp = uid()
|
||||
},
|
||||
|
||||
resetDocuments (state: OpenDocumentsStateInterface) {
|
||||
state.documents.docs = []
|
||||
state.documents.timestamp = uid()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue