29 changes: 29 additions & 0 deletions src/interfaces/I_OpenedDocument.ts
@@ -0,0 +1,29 @@
export interface I_ExtraDocumentFields{
id: string
value: any
type?: string
}

export interface I_OpenedDocument{
_id: string
_rev?: string
editMode: boolean
type: string
icon: string
hasEdits: boolean
isNew: boolean
url: string
extraFields: I_ExtraDocumentFields[]
}

export interface I_ShortenedDocument{
label: string
icon: string
type: string
url: string
expandable?: boolean
_id: string
parentDoc: string | false
children: I_ShortenedDocument[]
extraFields: I_ExtraDocumentFields[]
}
8 changes: 8 additions & 0 deletions src/interfaces/I_PouchCustomError.ts
@@ -0,0 +1,8 @@
export interface I_PouchCustomError{
docId: string
error: boolean
id: string
message: string
name: string
status: number
}
57 changes: 57 additions & 0 deletions src/layouts/MainLayout.vue
@@ -0,0 +1,57 @@
<template>
<q-layout view="lHh LpR lfr">

<!-- Left drawer -->
<q-drawer
class=""
content-class="bg-dark text-cultured"
v-model="leftDrawerOpen"
side="left"
show-if-above
bordered>

<objectTree/>

</q-drawer>

<!-- Header -->
<topTabs/>

<!-- Right drawer -->
<q-drawer
v-model="rightDrawerOpen"
side="right"
elevated>
<!-- drawer content -->
</q-drawer>

<q-page-container>
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
appear
:duration="300"
>
<router-view :key="$route.path" />
</transition>
</q-page-container>

</q-layout>
</template>

<script lang="ts">
import { Component } from "vue-property-decorator"
import BaseClass from "src/BaseClass"
import objectTree from "src/components/ObjectTree.vue"
import topTabs from "src/components/TopTabs.vue"
@Component({
components: { objectTree, topTabs }
})
export default class MainLayout extends BaseClass {
leftDrawerOpen = true
rightDrawerOpen = false
}
</script>
32 changes: 32 additions & 0 deletions src/layouts/ProjectManagentLayout.vue
@@ -0,0 +1,32 @@
<template>
<q-layout view="lHh LpR lfr">
<q-page-container>
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
appear
:duration="300"
>
<router-view :key="$route.path" />
</transition>
</q-page-container>
</q-layout>
</template>

<script lang="ts">
import { Component } from "vue-property-decorator"
import BaseClass from "src/BaseClass"
import PouchDB from "pouchdb"
@Component({
components: { }
})
export default class ProjectManagementLayout extends BaseClass {
}
</script>

<style lang="scss" scoped>
</style>
495 changes: 495 additions & 0 deletions src/pages/DocumentDisplay.vue

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions src/pages/Error404.vue
@@ -0,0 +1,30 @@
<template>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div>
<div style="font-size: 30vh;">
404
</div>

<div class="text-h2" style="opacity: 0.4;">
Oops. Nothing here...
</div>

<q-btn
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
/>
</div>
</div>
</template>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator"
@Component
export default class Error404 extends Vue {}
</script>
46 changes: 46 additions & 0 deletions src/pages/ProjectScreen.vue
@@ -0,0 +1,46 @@
<template>
<q-page class="column items-center justify-center">

<div class="col-12">
<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"
size="md"
label="Export project"
class="q-px-xl q-py-xs"
@click="exportProject(projectName)"
/>
</div>
</q-page>
</template>

<script lang="ts">
import { Component } from "vue-property-decorator"
import BaseClass from "src/BaseClass"
import PouchDB from "pouchdb"
@Component({
components: { }
})
export default class ProjectScreen extends BaseClass {
projectName = ""
async created () {
this.projectName = await this.retrieveCurrentProjectName()
}
}
</script>
116 changes: 116 additions & 0 deletions src/pages/WelcomeScreen.vue
@@ -0,0 +1,116 @@
<template>
<q-page class="column items-center justify-center">

<q-dialog
v-model="newProjectDialog"
persistent>
<q-card style="width: 500px;">
<q-card-section class="col items-center">
<div>
<h4>
New project
</h4>
</div>
<div>
<q-input
placeholder="Project name"
v-model="newProjectName"
outlined
dense
/>
</div>

</q-card-section>

<q-card-actions align="between">
<q-btn flat label="Cancel" color="red" v-close-popup />
<q-btn
label="Create"
color="primary"
v-close-popup
:disable="newProjectName.length === 0"
@click="createNewProject(newProjectName)" />
</q-card-actions>
</q-card>
</q-dialog>

<div class="col-12">
<h3>Welcome to Fantasia Archive</h3>
</div>

<div class="col-12 q-mb-lg">
<q-btn
v-if="projectExists"
color="primary"
size="md"
class="q-px-xl q-py-xs"
to="/project"
>
<div>Resume project </div>
</q-btn>

</div>

<div class="col-12 q-mb-lg">
<q-btn
color="primary"
size="md"
class="q-px-xl q-py-xs"
@click="openExistingProject"
>
<div>Open existing project</div>
<q-icon
v-if="projectExists"
color="red"
right
size="30px"
name="mdi-alert-circle" >
<q-tooltip>
All data of the currently opened project will be lost unless it is exported first if an existing project is opened beforehand!
</q-tooltip>
</q-icon>
</q-btn>
</div>

<div class="col-12">
<q-btn
color="primary"
size="md"
class="q-px-xl q-py-xs"
@click="newProjectDialog = true"
>
<div>New Project</div>
<q-icon
v-if="projectExists"
color="red"
right
size="30px"
name="mdi-alert-circle" >
<q-tooltip>
All data of the currently opened project will be lost unless it is exported first if a new project is created beforehand!
</q-tooltip>
</q-icon>
</q-btn>
</div>

</q-page>
</template>

<script lang="ts">
import { Component } from "vue-property-decorator"
import BaseClass from "src/BaseClass"
@Component({
components: { }
})
export default class WelcomeScreen extends BaseClass {
projectExists: undefined | string | boolean = false
newProjectName = ""
newProjectDialog = false
async created () {
this.projectExists = await this.retrieveCurrentProjectName()
}
}
</script>
27 changes: 27 additions & 0 deletions src/router/index.ts
@@ -0,0 +1,27 @@
import { route } from "quasar/wrappers"
import VueRouter from "vue-router"
import { Store } from "vuex"
import { StateInterface } from "../store"
import routes from "./routes"

/*
* If not building with SSR mode, you can
* directly export the Router instantiation
*/

export default route<Store<StateInterface>>(function ({ Vue }) {
Vue.use(VueRouter)

const Router = new VueRouter({
scrollBehavior: () => ({ x: 0, y: 0 }),
routes,

// Leave these as is and change from quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
})

return Router
})
30 changes: 30 additions & 0 deletions src/router/routes.ts
@@ -0,0 +1,30 @@
import { RouteConfig } from "vue-router"
import MainLayout from "layouts/MainLayout.vue"
import ProjectManagentLayout from "layouts/ProjectManagentLayout.vue"

const routes: RouteConfig[] = [
{
path: "/",
component: ProjectManagentLayout,
children: [
{ path: "", component: () => import("pages/WelcomeScreen.vue") }
]
},
{
path: "/project",
component: MainLayout,
children: [
{ path: "/project", component: () => import("pages/ProjectScreen.vue") },
{ path: "/project/display-content/:type/:id", component: () => import("pages/DocumentDisplay.vue") }
]
},

// Always leave this as last one,
// but you can also remove it
{
path: "*",
component: () => import("pages/Error404.vue")
}
]

export default routes
5 changes: 5 additions & 0 deletions src/shims-vue.d.ts
@@ -0,0 +1,5 @@
// Mocks all files ending in `.vue` showing them as plain Vue instances
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
39 changes: 39 additions & 0 deletions src/store/index.ts
@@ -0,0 +1,39 @@
import { BlueprintStateInterface } from "./module-blueprints/state"
import { store } from "quasar/wrappers"
import Vuex from "vuex"

// import example from './module-example';
// import { ExampleStateInterface } from './module-example/state';

import blueprintsModule from "./module-blueprints"
import openedDocumentsModule from "./module-openedDocuments"

/*
* If not building with SSR mode, you can
* directly export the Store instantiation
*/

export interface StateInterface {
// Define your own store structure, using submodules if needed
// example: ExampleStateInterface;
// Declared as unknown to avoid linting issue. Best to strongly type as per the line above.
blueprintsModule: BlueprintStateInterface;
}

export default store(function ({ Vue }) {
Vue.use(Vuex)

const Store = new Vuex.Store<StateInterface>({
modules: {
blueprintsModule,
openedDocumentsModule
// example
},

// enable strict mode (adds overhead!)
// for dev mode only
strict: !!process.env.DEBUGGING
})

return Store
})
11 changes: 11 additions & 0 deletions src/store/module-blueprints/actions.ts
@@ -0,0 +1,11 @@
import { ActionTree } from "vuex"
import { StateInterface } from "../index"
import { BlueprintStateInterface } from "./state"

const actions: ActionTree<BlueprintStateInterface, StateInterface> = {
// someAction (context) {

// }
}

export default actions
15 changes: 15 additions & 0 deletions src/store/module-blueprints/getters.ts
@@ -0,0 +1,15 @@
import { GetterTree } from "vuex"
import { StateInterface } from "../index"
import { BlueprintStateInterface } from "./state"

const getters: GetterTree<BlueprintStateInterface, StateInterface> = {
getAllBlueprints (context) {
return context.blueprints
},

getBlueprint: (state) => (type: string) => {
return state.blueprints.find(blueprint => blueprint._id === type)
}
}

export default getters
16 changes: 16 additions & 0 deletions src/store/module-blueprints/index.ts
@@ -0,0 +1,16 @@
import { Module } from "vuex"
import { StateInterface } from "../index"
import state, { BlueprintStateInterface } from "./state"
import actions from "./actions"
import getters from "./getters"
import mutations from "./mutations"

const blueprintsModule: Module<BlueprintStateInterface, StateInterface> = {
namespaced: true,
actions,
getters,
mutations,
state
}

export default blueprintsModule
11 changes: 11 additions & 0 deletions src/store/module-blueprints/mutations.ts
@@ -0,0 +1,11 @@
import { I_Blueprint } from "./../../interfaces/I_Blueprint"
import { MutationTree } from "vuex"
import { BlueprintStateInterface } from "./state"

const mutation: MutationTree<BlueprintStateInterface> = {
setAllBlueprints (state: BlueprintStateInterface, blueprints: I_Blueprint[]) {
state.blueprints = blueprints
}
}

export default mutation
12 changes: 12 additions & 0 deletions src/store/module-blueprints/state.ts
@@ -0,0 +1,12 @@
import { I_Blueprint } from "./../../interfaces/I_Blueprint"
export interface BlueprintStateInterface {
blueprints: I_Blueprint[]
}

function state (): BlueprintStateInterface {
return {
blueprints: []
}
}

export default state
11 changes: 11 additions & 0 deletions src/store/module-openedDocuments/actions.ts
@@ -0,0 +1,11 @@
import { ActionTree } from "vuex"
import { StateInterface } from "../index"
import { OpenDocumentsStateInterface } from "./state"

const actions: ActionTree<OpenDocumentsStateInterface, StateInterface> = {
// someAction (context) {

// }
}

export default actions
15 changes: 15 additions & 0 deletions src/store/module-openedDocuments/getters.ts
@@ -0,0 +1,15 @@
import { GetterTree } from "vuex"
import { StateInterface } from "../index"
import { OpenDocumentsStateInterface } from "./state"

const getters: GetterTree<OpenDocumentsStateInterface, StateInterface> = {
getAllDocuments (context) {
return context.documents
},

getDocument: (state) => (id: string) => {
return state.documents.docs.find(doc => doc._id === id)
}
}

export default getters
16 changes: 16 additions & 0 deletions src/store/module-openedDocuments/index.ts
@@ -0,0 +1,16 @@
import { Module } from "vuex"
import { StateInterface } from "../index"
import state, { OpenDocumentsStateInterface } from "./state"
import actions from "./actions"
import getters from "./getters"
import mutations from "./mutations"

const openedDocumentsModule: Module<OpenDocumentsStateInterface, StateInterface> = {
namespaced: true,
actions,
getters,
mutations,
state
}

export default openedDocumentsModule
31 changes: 31 additions & 0 deletions src/store/module-openedDocuments/mutations.ts
@@ -0,0 +1,31 @@
import { MutationTree } from "vuex"
import { OpenDocumentsStateInterface } from "./state"
import { I_OpenedDocument } from "./../../interfaces/I_OpenedDocument"

import { uid } from "quasar"

const mutation: MutationTree<OpenDocumentsStateInterface> = {
addDocument (state: OpenDocumentsStateInterface, input: I_OpenedDocument) {
if (!state.documents.docs.find(doc => {
return doc.type === input.type && doc._id === input._id
})) {
state.documents.docs.push(input)
state.documents.timestamp = uid()
}
},

updateDocument (state: OpenDocumentsStateInterface, input: I_OpenedDocument) {
const toUpdateDocIndex = state.documents.docs.findIndex(doc => doc.type === input.type && doc._id === input._id)

state.documents.docs[toUpdateDocIndex] = input
state.documents.timestamp = uid()
},

removeDocument (state: OpenDocumentsStateInterface, input: I_OpenedDocument) {
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()
}
}

export default mutation
19 changes: 19 additions & 0 deletions src/store/module-openedDocuments/state.ts
@@ -0,0 +1,19 @@
import { I_OpenedDocument } from "./../../interfaces/I_OpenedDocument"

export interface OpenDocumentsStateInterface {
documents: {
timestamp: string,
docs: I_OpenedDocument[]
}
}

function state (): OpenDocumentsStateInterface {
return {
documents: {
timestamp: "",
docs: []
}
}
}

export default state
9 changes: 9 additions & 0 deletions src/store/store-flag.d.ts
@@ -0,0 +1,9 @@
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import "quasar/dist/types/feature-flag";

declare module "quasar/dist/types/feature-flag" {
interface QuasarFeatureFlags {
store: true;
}
}
12 changes: 12 additions & 0 deletions tsconfig.json
@@ -0,0 +1,12 @@
{
"extends": "@quasar/app/tsconfig-preset",
"compilerOptions": {
"baseUrl": ".",
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"suppressImplicitAnyIndexErrors": true,
},
"include": [
"src"
],
}