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-updater": "^4.3.1",
"knex": "^0.21.1",
"lodash": "^4.17.15",
"material-design-icons": "^3.0.1",
"mssql": "^6.2.0",
"mysql": "^2.18.1",

View File

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

View File

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

View File

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

View File

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

View File

@ -1,37 +1,44 @@
<template>
<div class="workspace-explorebar column">
<div class="workspace-explorebar-header">
<span class="workspace-explorebar-title">{{ connectionName }}</span>
<span v-if="workspace.connected" class="workspace-explorebar-tools">
<i
class="material-icons md-18 c-hand"
:class="{'rotate':isRefreshing}"
:title="$t('word.refresh')"
@click="refresh"
>refresh</i>
<i
class="material-icons md-18 c-hand mr-1 ml-2"
:title="$t('word.disconnect')"
@click="disconnectWorkspace(connection.uid)"
>exit_to_app</i>
</span>
</div>
<DatabaseConnectPanel v-if="!workspace.connected" :connection="connection" />
<div class="workspace-explorebar-body">
<div
v-for="db of workspace.structure"
:key="db.dbName"
>
<div class="database-name">
<i class="material-icons md-18 mr-1">view_agenda</i>{{ db.dbName }}
</div>
<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 class="p-relative">
<div ref="resizer" class="workspace-explorebar-resizer" />
<div
ref="explorebar"
class="workspace-explorebar column"
:style="{width: localWidth ? localWidth+'px' : ''}"
>
<div class="workspace-explorebar-header">
<span class="workspace-explorebar-title">{{ connectionName }}</span>
<span v-if="workspace.connected" class="workspace-explorebar-tools">
<i
class="material-icons md-18 c-hand"
:class="{'rotate':isRefreshing}"
:title="$t('word.refresh')"
@click="refresh"
>refresh</i>
<i
class="material-icons md-18 c-hand mr-1 ml-2"
:title="$t('word.disconnect')"
@click="disconnectWorkspace(connection.uid)"
>exit_to_app</i>
</span>
</div>
<DatabaseConnectPanel v-if="!workspace.connected" :connection="connection" />
<div class="workspace-explorebar-body">
<div
v-for="db of workspace.structure"
:key="db.dbName"
>
<div class="database-name">
<i class="material-icons md-18 mr-1">view_agenda</i>{{ db.dbName }}
</div>
<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>
@ -42,6 +49,7 @@
<script>
import { mapGetters, mapActions } from 'vuex';
import _ from 'lodash';
import DatabaseConnectPanel from '@/components/DatabaseConnectPanel';
export default {
@ -50,16 +58,19 @@ export default {
DatabaseConnectPanel
},
props: {
connection: Object
connection: Object,
isSelected: Boolean
},
data () {
return {
isRefreshing: false
isRefreshing: false,
localWidth: null
};
},
computed: {
...mapGetters({
getWorkspace: 'workspaces/getWorkspace',
explorebarSize: 'settings/getExplorebarSize',
getConnectionName: 'connections/getConnectionName'
}),
workspace () {
@ -69,24 +80,66 @@ export default {
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: {
...mapActions({
disconnectWorkspace: 'workspaces/removeConnected',
refreshStructure: 'workspaces/refreshStructure'
refreshStructure: 'workspaces/refreshStructure',
changeExplorebarSize: 'settings/changeExplorebarSize'
}),
async refresh () {
this.isRefreshing = true;
await this.refreshStructure(this.connection.uid);
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>
<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{
width: $explorebar-width;
height: calc(100vh - #{$footer-height});
height: calc(100vh - #{$excluding-size});
overflow: auto;
display: flex;
flex-direction: column;
@ -94,7 +147,6 @@ export default {
align-items: center;
text-align: left;
background: $bg-color-gray;
margin-bottom: $footer-height;
box-shadow: 0 0 1px 0px #000;
z-index: 8;
flex: initial;

View File

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

View File

@ -42,6 +42,7 @@
</li>
</ul>
</div>
<div v-if="selectedTab === 'general'" class="panel-body py-4">
<form class="form-horizontal">
<div class="col-6 col-sm-12">
@ -71,19 +72,23 @@
</div>
</form>
</div>
<div v-if="selectedTab === 'themes'" class="panel-body py-4">
<!-- -->
</div>
<div v-if="selectedTab === 'update'" class="panel-body py-4">
<!-- -->
</div>
<div v-if="selectedTab === 'about'" class="panel-body py-4">
<div class="text-center">
<img :src="require('@/images/logo.svg').default" width="128">
<h4>{{ appName }}</h4>
<p>
{{ $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>
</div>
</div>

View File

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

View File

@ -103,13 +103,13 @@ export default {
<style lang="scss">
#settingbar{
width: $settingbar-width;
height: calc(100vh - #{$excluding-size});
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
background: $bg-color-light;
padding: 0;
margin-bottom: $footer-height;
box-shadow: 0 0 1px 0px #000;
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',
deleteConnection: 'Delete connection',
deleteConnectionCorfirm: 'Do you confirm the cancellation of',
connectionSuccessfullyMade: 'Connection successfully made!'
connectionSuccessfullyMade: 'Connection successfully made!',
madeWithJS: 'Made with 💛 and JavaScript!'
},
// Date and Time
short: {

View File

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

View File

@ -9,6 +9,8 @@ $success-color: #32b643;
$error-color: #de3b28;
/*Sizes*/
$titlebar-height: 1.5rem;
$settingbar-width: 3rem;
$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,
strict: true,
state: {
locale: 'en-US'
locale: 'en-US',
explorebar_size: null
},
getters: {
getLocale: state => state.locale
getLocale: state => state.locale,
getExplorebarSize: state => state.explorebar_size
},
mutations: {
SET_LOCALE (state, locale) {
state.locale = locale;
i18n.locale = locale;
},
SET_EXPLOREBAR_SIZE (state, size) {
state.explorebar_size = size;
}
},
actions: {
changeLocale ({ commit }, locale) {
commit('SET_LOCALE', locale);
},
changeExplorebarSize ({ commit }, size) {
commit('SET_EXPLOREBAR_SIZE', size);
}
}
};