Titlebar and resizable explorebar

This commit is contained in:
Fabio 2020-06-02 19:13:57 +02:00
parent 759bcddfb7
commit f3d165d3f1
15 changed files with 286 additions and 68 deletions

View File

@ -32,6 +32,7 @@
"electron-log": "^4.2.0", "electron-log": "^4.2.0",
"electron-updater": "^4.3.1", "electron-updater": "^4.3.1",
"knex": "^0.21.1", "knex": "^0.21.1",
"lodash": "^4.17.15",
"material-design-icons": "^3.0.1", "material-design-icons": "^3.0.1",
"mssql": "^6.2.0", "mssql": "^6.2.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",

View File

@ -26,7 +26,9 @@ function createMainWindow () {
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
'web-security': false 'web-security': false
} },
frame: false,
backgroundColor: '#1d1d1d'
}); });
if (isDevelopment) if (isDevelopment)

View File

@ -65,7 +65,6 @@ export default () => {
return { status: 'success', response: structure }; return { status: 'success', response: structure };
} }
catch (err) { catch (err) {
console.log(err);
return { status: 'error', response: err.toString() }; return { status: 'error', response: err.toString() };
} }
}); });

View File

@ -5,6 +5,7 @@ export default class {
return connection() return connection()
.select('*') .select('*')
.withSchema('information_schema') .withSchema('information_schema')
.from('TABLES'); .from('TABLES')
.orderBy(['TABLE_SCHEMA', 'TABLE_NAME'], 'asc');
} }
} }

View File

@ -1,26 +1,30 @@
<template> <template>
<div id="wrapper"> <div id="wrapper">
<TheSettingBar /> <TheTitleBar />
<div id="main-content" class="container"> <div id="window-content">
<TheAppWelcome v-if="!connections.length" @newConn="showNewConnModal" /> <TheSettingBar />
<div v-else class="columns col-gapless"> <div id="main-content" class="container">
<DatabaseWorkspace <TheAppWelcome v-if="!connections.length" @newConn="showNewConnModal" />
v-for="connection in connections" <div v-else class="columns col-gapless">
:key="connection.uid" <DatabaseWorkspace
:connection="connection" v-for="connection in connections"
/> :key="connection.uid"
:connection="connection"
/>
</div>
</div> </div>
<TheFooter />
<TheNotificationsBoard />
<ModalNewConnection v-if="isNewConnModal" />
<ModalEditConnection v-if="isEditModal" />
<ModalSettings v-if="isSettingModal" />
</div> </div>
<TheFooter />
<TheNotificationsBoard />
<ModalNewConnection v-if="isNewConnModal" />
<ModalEditConnection v-if="isEditModal" />
<ModalSettings v-if="isSettingModal" />
</div> </div>
</template> </template>
<script> <script>
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import TheTitleBar from '@/components/TheTitleBar';
import TheSettingBar from '@/components/TheSettingBar'; import TheSettingBar from '@/components/TheSettingBar';
import TheFooter from '@/components/TheFooter'; import TheFooter from '@/components/TheFooter';
import TheNotificationsBoard from '@/components/TheNotificationsBoard'; import TheNotificationsBoard from '@/components/TheNotificationsBoard';
@ -33,6 +37,7 @@ import ModalSettings from '@/components/ModalSettings';
export default { export default {
name: 'App', name: 'App',
components: { components: {
TheTitleBar,
TheSettingBar, TheSettingBar,
TheFooter, TheFooter,
TheNotificationsBoard, TheNotificationsBoard,
@ -70,17 +75,22 @@ export default {
} }
#wrapper{ #wrapper{
display: flex;
height: 100vh; height: 100vh;
position: relative; position: relative;
} }
#window-content{
display: flex;
position: relative;
}
#main-content { #main-content {
padding: 0; padding: 0;
justify-content: flex-start; justify-content: flex-start;
height: calc(100vh - #{$excluding-size});
> .columns{ > .columns{
height: 100vh; height: calc(100vh - #{$footer-height});
} }
} }
</style> </style>

View File

@ -1,37 +1,44 @@
<template> <template>
<div class="workspace-explorebar column"> <div class="p-relative">
<div class="workspace-explorebar-header"> <div ref="resizer" class="workspace-explorebar-resizer" />
<span class="workspace-explorebar-title">{{ connectionName }}</span> <div
<span v-if="workspace.connected" class="workspace-explorebar-tools"> ref="explorebar"
<i class="workspace-explorebar column"
class="material-icons md-18 c-hand" :style="{width: localWidth ? localWidth+'px' : ''}"
:class="{'rotate':isRefreshing}" >
:title="$t('word.refresh')" <div class="workspace-explorebar-header">
@click="refresh" <span class="workspace-explorebar-title">{{ connectionName }}</span>
>refresh</i> <span v-if="workspace.connected" class="workspace-explorebar-tools">
<i <i
class="material-icons md-18 c-hand mr-1 ml-2" class="material-icons md-18 c-hand"
:title="$t('word.disconnect')" :class="{'rotate':isRefreshing}"
@click="disconnectWorkspace(connection.uid)" :title="$t('word.refresh')"
>exit_to_app</i> @click="refresh"
</span> >refresh</i>
</div> <i
<DatabaseConnectPanel v-if="!workspace.connected" :connection="connection" /> class="material-icons md-18 c-hand mr-1 ml-2"
<div class="workspace-explorebar-body"> :title="$t('word.disconnect')"
<div @click="disconnectWorkspace(connection.uid)"
v-for="db of workspace.structure" >exit_to_app</i>
:key="db.dbName" </span>
> </div>
<div class="database-name"> <DatabaseConnectPanel v-if="!workspace.connected" :connection="connection" />
<i class="material-icons md-18 mr-1">view_agenda</i>{{ db.dbName }} <div class="workspace-explorebar-body">
</div> <div
<div class="d-block ml-4"> v-for="db of workspace.structure"
<div :key="db.dbName"
v-for="table of db.tables" >
:key="table.TABLE_NAME" <div class="database-name">
> <i class="material-icons md-18 mr-1">view_agenda</i>{{ db.dbName }}
<div class="table-name"> </div>
<i class="material-icons md-18 mr-1">view_headline</i>{{ table.TABLE_NAME }} <div class="d-block ml-4">
<div
v-for="table of db.tables"
:key="table.TABLE_NAME"
>
<div class="table-name">
<i class="material-icons md-18 mr-1">view_headline</i>{{ table.TABLE_NAME }}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -42,6 +49,7 @@
<script> <script>
import { mapGetters, mapActions } from 'vuex'; import { mapGetters, mapActions } from 'vuex';
import _ from 'lodash';
import DatabaseConnectPanel from '@/components/DatabaseConnectPanel'; import DatabaseConnectPanel from '@/components/DatabaseConnectPanel';
export default { export default {
@ -50,16 +58,19 @@ export default {
DatabaseConnectPanel DatabaseConnectPanel
}, },
props: { props: {
connection: Object connection: Object,
isSelected: Boolean
}, },
data () { data () {
return { return {
isRefreshing: false isRefreshing: false,
localWidth: null
}; };
}, },
computed: { computed: {
...mapGetters({ ...mapGetters({
getWorkspace: 'workspaces/getWorkspace', getWorkspace: 'workspaces/getWorkspace',
explorebarSize: 'settings/getExplorebarSize',
getConnectionName: 'connections/getConnectionName' getConnectionName: 'connections/getConnectionName'
}), }),
workspace () { workspace () {
@ -69,24 +80,66 @@ export default {
return this.getConnectionName(this.connection.uid); return this.getConnectionName(this.connection.uid);
} }
}, },
watch: {
localWidth: _.debounce(function (val) {
this.changeExplorebarSize(val);
}, 500),
isSelected (val) {
if (val) this.localWidth = this.explorebarSize;
}
},
created () {
this.localWidth = this.explorebarSize;
},
mounted () {
const resizer = this.$refs.resizer;
resizer.addEventListener('mousedown', (e) => {
e.preventDefault();
window.addEventListener('mousemove', this.resize);
window.addEventListener('mouseup', this.stopResize);
});
},
methods: { methods: {
...mapActions({ ...mapActions({
disconnectWorkspace: 'workspaces/removeConnected', disconnectWorkspace: 'workspaces/removeConnected',
refreshStructure: 'workspaces/refreshStructure' refreshStructure: 'workspaces/refreshStructure',
changeExplorebarSize: 'settings/changeExplorebarSize'
}), }),
async refresh () { async refresh () {
this.isRefreshing = true; this.isRefreshing = true;
await this.refreshStructure(this.connection.uid); await this.refreshStructure(this.connection.uid);
this.isRefreshing = false; this.isRefreshing = false;
},
resize (e) {
const el = this.$refs.explorebar;
let explorebarWidth = e.pageX - el.getBoundingClientRect().left;
if (explorebarWidth > 500) explorebarWidth = 500;
if (explorebarWidth < 150) explorebarWidth = 150;
this.localWidth = explorebarWidth;
},
stopResize () {
window.removeEventListener('mousemove', this.resize);
} }
} }
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.workspace-explorebar-resizer{
position: absolute;
width: 4px;
right: -2px;
top: 0;
height: calc(100vh - #{$excluding-size});
cursor: ew-resize;
z-index: 99;
}
.workspace-explorebar{ .workspace-explorebar{
width: $explorebar-width; width: $explorebar-width;
height: calc(100vh - #{$footer-height}); height: calc(100vh - #{$excluding-size});
overflow: auto; overflow: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -94,7 +147,6 @@ export default {
align-items: center; align-items: center;
text-align: left; text-align: left;
background: $bg-color-gray; background: $bg-color-gray;
margin-bottom: $footer-height;
box-shadow: 0 0 1px 0px #000; box-shadow: 0 0 1px 0px #000;
z-index: 8; z-index: 8;
flex: initial; flex: initial;

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-show="selectedWorkspace === connection.uid" class="workspace column columns"> <div v-show="isSelected" class="workspace column columns">
<DatabaseExploreBar :connection="connection" /> <DatabaseExploreBar :connection="connection" :is-selected="isSelected" />
<div class="workspace-tabs column"> <div class="workspace-tabs column">
<pre>{{ JSON.stringify(workspace.structure, null, 3) }}</pre> <pre>{{ JSON.stringify(workspace.structure, null, 3) }}</pre>
</div> </div>
@ -27,6 +27,9 @@ export default {
}), }),
workspace () { workspace () {
return this.getWorkspace(this.connection.uid); return this.getWorkspace(this.connection.uid);
},
isSelected () {
return this.selectedWorkspace === this.connection.uid;
} }
}, },
async created () { async created () {
@ -53,7 +56,7 @@ export default {
.workspace-tabs{ .workspace-tabs{
overflow: auto; overflow: auto;
height: calc(100vh - #{$footer-height}); height: calc(100vh - #{$excluding-size});
} }
} }
</style> </style>

View File

@ -42,6 +42,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div v-if="selectedTab === 'general'" class="panel-body py-4"> <div v-if="selectedTab === 'general'" class="panel-body py-4">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="col-6 col-sm-12"> <div class="col-6 col-sm-12">
@ -71,19 +72,23 @@
</div> </div>
</form> </form>
</div> </div>
<div v-if="selectedTab === 'themes'" class="panel-body py-4"> <div v-if="selectedTab === 'themes'" class="panel-body py-4">
<!-- --> <!-- -->
</div> </div>
<div v-if="selectedTab === 'update'" class="panel-body py-4"> <div v-if="selectedTab === 'update'" class="panel-body py-4">
<!-- --> <!-- -->
</div> </div>
<div v-if="selectedTab === 'about'" class="panel-body py-4"> <div v-if="selectedTab === 'about'" class="panel-body py-4">
<div class="text-center"> <div class="text-center">
<img :src="require('@/images/logo.svg').default" width="128"> <img :src="require('@/images/logo.svg').default" width="128">
<h4>{{ appName }}</h4> <h4>{{ appName }}</h4>
<p> <p>
{{ $t('word.version') }}: {{ appVersion }}<br> {{ $t('word.version') }}: {{ appVersion }}<br>
<a class="c-hand" @click="openOutside('https://github.com/Fabio286/antares')">GitHub</a> <a class="c-hand" @click="openOutside('https://github.com/Fabio286/antares')">GitHub</a><br>
<small>{{ $t('message.madeWithJS') }}</small>
</p> </p>
</div> </div>
</div> </div>

View File

@ -42,6 +42,6 @@ export default {
position: absolute; position: absolute;
z-index: 9; z-index: 9;
right: 1rem; right: 1rem;
bottom: $footer-height+1rem; bottom: 1rem;
} }
</style> </style>

View File

@ -103,13 +103,13 @@ export default {
<style lang="scss"> <style lang="scss">
#settingbar{ #settingbar{
width: $settingbar-width; width: $settingbar-width;
height: calc(100vh - #{$excluding-size});
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
background: $bg-color-light; background: $bg-color-light;
padding: 0; padding: 0;
margin-bottom: $footer-height;
box-shadow: 0 0 1px 0px #000; box-shadow: 0 0 1px 0px #000;
z-index: 9; z-index: 9;

View File

@ -0,0 +1,133 @@
<template>
<div id="titlebar">
<div class="titlebar-resizer" />
<div class="titlebar-elements">
<img class="titlebar-logo" :src="require('@/images/logo.svg').default">
</div>
<div class="titlebar-elements">
<!-- -->
</div>
<div class="titlebar-elements">
<div
v-if="isDevelopment"
class="titlebar-element"
@click="openDevTools"
>
<i class="material-icons">code</i>
</div>
<div
v-if="isDevelopment"
class="titlebar-element"
@click="reload"
>
<i class="material-icons">refresh</i>
</div>
<div class="titlebar-element" @click="minimizeApp">
<i class="material-icons">remove</i>
</div>
<div class="titlebar-element" @click="toggleFullScreen">
<i v-if="isMaximized" class="material-icons">fullscreen_exit</i>
<i v-else class="material-icons">fullscreen</i>
</div>
<div class="titlebar-element close-button" @click="closeApp">
<i class="material-icons">close</i>
</div>
</div>
</div>
</template>
<script>
import { remote } from 'electron';
export default {
name: 'TheTitleBar',
data () {
return {
w: remote.getCurrentWindow(),
isMaximized: remote.getCurrentWindow().isMaximized(),
isDevelopment: process.env.NODE_ENV === 'development'
};
},
created () {
window.addEventListener('resize', this.onResize);
},
destroyed () {
window.removeEventListener('resize', this.onResize);
},
methods: {
closeApp () {
this.w.close();
},
minimizeApp () {
this.w.minimize();
},
toggleFullScreen () {
if (this.isMaximized)
this.w.unmaximize();
else
this.w.maximize();
},
openDevTools () {
this.w.openDevTools();
},
reload () {
this.w.reload();
},
onResize () {
this.isMaximized = this.w.isMaximized();
}
}
};
</script>
<style lang="scss">
#titlebar{
display: flex;
position: relative;
justify-content: space-between;
background: $bg-color-light;
align-items: center;
height: $titlebar-height;
-webkit-app-region: drag;
user-select: none;
.titlebar-resizer{
position: absolute;
top: 0;
width: 100%;
height: 4px;
z-index: 999;
-webkit-app-region: no-drag;
}
.titlebar-elements{
display: flex;
align-items: center;
.titlebar-logo{
height: $titlebar-height;
padding: 0 .4rem;
}
.titlebar-element{
display: flex;
align-items: center;
height: $titlebar-height;
line-height: 0;
padding: 0 .7rem;
opacity: .7;
transition: opacity .2s;
-webkit-app-region: no-drag;
&:hover{
opacity: 1;
background: rgba($color: #fff, $alpha: .2);
}
&.close-button:hover{
background: red;
}
}
}
}
</style>

View File

@ -39,7 +39,8 @@ module.exports = {
editConnection: 'Edit connection', editConnection: 'Edit connection',
deleteConnection: 'Delete connection', deleteConnection: 'Delete connection',
deleteConnectionCorfirm: 'Do you confirm the cancellation of', deleteConnectionCorfirm: 'Do you confirm the cancellation of',
connectionSuccessfullyMade: 'Connection successfully made!' connectionSuccessfullyMade: 'Connection successfully made!',
madeWithJS: 'Made with 💛 and JavaScript!'
}, },
// Date and Time // Date and Time
short: { short: {

View File

@ -39,7 +39,8 @@ module.exports = {
editConnection: 'Modifica connessione', editConnection: 'Modifica connessione',
deleteConnection: 'Elimina connessione', deleteConnection: 'Elimina connessione',
deleteConnectionCorfirm: 'Confermi l\'eliminazione di', deleteConnectionCorfirm: 'Confermi l\'eliminazione di',
connectionSuccessfullyMade: 'Connessione avvenuta con successo!' connectionSuccessfullyMade: 'Connessione avvenuta con successo!',
madeWithJS: 'Fatto con 💛 e JavaScript!'
}, },
// Date and Time // Date and Time
short: { short: {

View File

@ -9,6 +9,8 @@ $success-color: #32b643;
$error-color: #de3b28; $error-color: #de3b28;
/*Sizes*/ /*Sizes*/
$titlebar-height: 1.5rem;
$settingbar-width: 3rem; $settingbar-width: 3rem;
$explorebar-width: 14rem; $explorebar-width: 14rem;
$footer-height: 1.5rem; $footer-height: 1.5rem;
$excluding-size: $footer-height + $titlebar-height;

View File

@ -5,20 +5,28 @@ export default {
namespaced: true, namespaced: true,
strict: true, strict: true,
state: { state: {
locale: 'en-US' locale: 'en-US',
explorebar_size: null
}, },
getters: { getters: {
getLocale: state => state.locale getLocale: state => state.locale,
getExplorebarSize: state => state.explorebar_size
}, },
mutations: { mutations: {
SET_LOCALE (state, locale) { SET_LOCALE (state, locale) {
state.locale = locale; state.locale = locale;
i18n.locale = locale; i18n.locale = locale;
},
SET_EXPLOREBAR_SIZE (state, size) {
state.explorebar_size = size;
} }
}, },
actions: { actions: {
changeLocale ({ commit }, locale) { changeLocale ({ commit }, locale) {
commit('SET_LOCALE', locale); commit('SET_LOCALE', locale);
},
changeExplorebarSize ({ commit }, size) {
commit('SET_EXPLOREBAR_SIZE', size);
} }
} }
}; };