1
0
mirror of https://github.com/amir20/dozzle.git synced 2025-12-28 16:06:40 +01:00

Menu resizable (#206)

* Makes side menu resizable

* Fixes hiding of side menu

* Adds mobile menu

* Adds missing file
This commit is contained in:
Amir Raminfar
2019-12-11 13:23:24 -08:00
committed by GitHub
parent 05b26bea9c
commit 1b4a4e626a
5 changed files with 165 additions and 91 deletions

View File

@@ -1,27 +1,32 @@
<template lang="html">
<div class="columns is-marginless">
<side-menu></side-menu>
<div class="column is-offset-3-tablet is-offset-2-widescreen is-9-tablet is-10-widescreen is-paddingless">
<splitpanes>
<pane>
<router-view></router-view>
</pane>
<pane v-for="other in activeContainers" :key="other.id">
<scrollable-view>
<template v-slot:header>
<div class="name columns is-marginless">
<span class="column">{{ other.name }}</span>
<span class="column is-narrow">
<button class="delete is-medium" @click="removeActiveContainer(other)"></button>
</span>
</div>
</template>
<log-viewer-with-source :id="other.id"></log-viewer-with-source>
</scrollable-view>
</pane>
</splitpanes>
</div>
</div>
<main>
<mobile-menu v-if="mobileWidth"></mobile-menu>
<splitpanes>
<pane min-size="10" size="15" v-if="!mobileWidth">
<side-menu></side-menu>
</pane>
<pane size="85">
<splitpanes>
<pane>
<router-view></router-view>
</pane>
<pane v-for="other in activeContainers" :key="other.id">
<scrollable-view>
<template v-slot:header>
<div class="name columns is-marginless">
<span class="column">{{ other.name }}</span>
<span class="column is-narrow">
<button class="delete is-medium" @click="removeActiveContainer(other)"></button>
</span>
</div>
</template>
<log-viewer-with-source :id="other.id"></log-viewer-with-source>
</scrollable-view>
</pane>
</splitpanes>
</pane>
</splitpanes>
</main>
</template>
<script>
@@ -31,12 +36,14 @@ import { Splitpanes, Pane } from "splitpanes";
import LogViewerWithSource from "./components/LogViewerWithSource";
import ScrollableView from "./components/ScrollableView";
import SideMenu from "./components/SideMenu";
import MobileMenu from "./components/MobileMenu";
export default {
name: "App",
components: {
LogViewerWithSource,
SideMenu,
MobileMenu,
ScrollableView,
Splitpanes,
Pane
@@ -58,7 +65,7 @@ export default {
this.title = `${this.containers.length} containers`;
},
computed: {
...mapState(["containers", "activeContainers"])
...mapState(["containers", "activeContainers", "mobileWidth"])
},
methods: {
...mapActions({
@@ -85,5 +92,8 @@ export default {
::v-deep .splitpanes__splitter {
min-width: 4px;
background: #666;
&:hover {
background: rgb(255, 221, 87);
}
}
</style>

View File

@@ -1,26 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<App /> renders correctly 1`] = `
<div
class="columns is-marginless"
>
<side-menu-stub />
<main>
<!---->
<div
class="column is-offset-3-tablet is-offset-2-widescreen is-9-tablet is-10-widescreen is-paddingless"
<splitpanes-stub
dblclicksplitter="true"
pushotherpanes="true"
>
<splitpanes-stub
dblclicksplitter="true"
pushotherpanes="true"
<pane-stub
maxsize="100"
minsize="10"
size="15"
>
<pane-stub
maxsize="100"
minsize="0"
<side-menu-stub />
</pane-stub>
<pane-stub
maxsize="100"
minsize="0"
size="85"
>
<splitpanes-stub
dblclicksplitter="true"
pushotherpanes="true"
>
<router-view-stub />
</pane-stub>
</splitpanes-stub>
</div>
</div>
<pane-stub
maxsize="100"
minsize="0"
>
<router-view-stub />
</pane-stub>
</splitpanes-stub>
</pane-stub>
</splitpanes-stub>
</main>
`;

View File

@@ -0,0 +1,85 @@
<template lang="html">
<aside>
<a
role="button"
class="navbar-burger burger is-white is-hidden-tablet is-pulled-right"
@click="showNav = !showNav"
:class="{ 'is-active': showNav }"
>
<span></span> <span></span> <span></span>
</a>
<h1 class="title has-text-warning is-marginless">Dozzle</h1>
<p class="menu-label is-hidden-mobile" :class="{ 'is-active': showNav }">Containers</p>
<ul class="menu-list is-hidden-mobile" :class="{ 'is-active': showNav }">
<li v-for="item in containers">
<router-link
:to="{ name: 'container', params: { id: item.id, name: item.name } }"
active-class="is-active"
:title="item.name"
>
<div class="hide-overflow">
{{ item.name }}
</div>
</router-link>
</li>
</ul>
</aside>
</template>
<script>
import { mapActions, mapGetters, mapState } from "vuex";
export default {
props: [],
name: "MobileMenu",
data() {
return {
showNav: false
};
},
computed: {
...mapState(["containers"]),
activeContainersById() {
return this.activeContainers.reduce((map, obj) => {
map[obj.id] = obj;
return map;
}, {});
}
},
methods: {
...mapActions({})
}
};
</script>
<style scoped lang="scss">
aside {
padding: 1em;
position: sticky;
top: 0;
left: 0;
right: 0;
background: #222;
.menu-label {
margin-top: 1em;
}
.hide-overflow {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.burger.is-white {
color: #fff;
}
.is-hidden-mobile.is-active {
display: block !important;
}
.navbar-burger {
height: 2.35rem;
}
}
</style>

View File

@@ -1,16 +1,8 @@
<template lang="html">
<aside class="column menu is-3-tablet is-2-widescreen">
<a
role="button"
class="navbar-burger burger is-white is-hidden-tablet is-pulled-right"
@click="showNav = !showNav"
:class="{ 'is-active': showNav }"
>
<span></span> <span></span> <span></span>
</a>
<aside>
<h1 class="title has-text-warning is-marginless">Dozzle</h1>
<p class="menu-label is-hidden-mobile" :class="{ 'is-active': showNav }">Containers</p>
<ul class="menu-list is-hidden-mobile" :class="{ 'is-active': showNav }">
<p class="menu-label is-hidden-mobile">Containers</p>
<ul class="menu-list is-hidden-mobile">
<li v-for="item in containers">
<router-link
:to="{ name: 'container', params: { id: item.id, name: item.name } }"
@@ -40,16 +32,7 @@ export default {
props: [],
name: "SideMenu",
data() {
return {
showNav: false
};
},
methods: {
colorize: value =>
ansiConvertor
.toHtml(value)
.replace("&lt;mark&gt;", "<mark>")
.replace("&lt;/mark&gt;", "</mark>")
return {};
},
computed: {
...mapState(["containers", "activeContainers"]),
@@ -69,30 +52,10 @@ export default {
</script>
<style scoped lang="scss">
aside {
position: fixed;
z-index: 2;
padding: 1em;
height: 100vh;
overflow: auto;
@media screen and (min-width: 769px) {
& {
height: 100vh;
overflow: auto;
}
}
@media screen and (max-width: 768px) {
& {
position: sticky;
top: 0;
left: 0;
right: 0;
background: #222;
}
.menu-label {
margin-top: 1em;
}
}
.hide-overflow {
text-overflow: ellipsis;
white-space: nowrap;
@@ -106,10 +69,6 @@ aside {
.is-hidden-mobile.is-active {
display: block !important;
}
.navbar-burger {
height: 2.35rem;
}
}
.will-append-container.icon {

View File

@@ -1,13 +1,15 @@
import Vue from "vue";
import Vuex from "vuex";
// import storage from "store/dist/store.modern";
const mql = window.matchMedia("(max-width: 770px)");
Vue.use(Vuex);
const state = {
containers: [],
activeContainers: [],
searchFilter: null
searchFilter: null,
mobileWidth: mql.matches
};
const mutations = {
@@ -22,6 +24,9 @@ const mutations = {
},
SET_SEARCH(state, filter) {
state.searchFilter = filter;
},
SET_MOBILE_WIDTH(state, value) {
state.mobileWidth = value;
}
};
@@ -45,6 +50,8 @@ const getters = {};
const es = new EventSource(`${BASE_PATH}/api/events/stream`);
es.addEventListener("containers-changed", e => setTimeout(() => store.dispatch("FETCH_CONTAINERS"), 1000), false);
mql.addListener(e => store.commit("SET_MOBILE_WIDTH", e.matches));
const store = new Vuex.Store({
strict: true,
state,