added a sidebar drawer to improve mobile responsiveness
This commit is contained in:
13
src/App.vue
13
src/App.vue
@@ -5,6 +5,7 @@ import DocumentLocaleSetter from '@/components/locale/DocumentLocaleSetter.vue';
|
||||
import NavBar from '@/components/NavBar.vue';
|
||||
import LocaleSaver from '@/components/locale/LocaleSaver.vue';
|
||||
import StoragePersist from '@/components/StoragePersist.vue';
|
||||
import SideBar from '@/components/SideBar.vue';
|
||||
|
||||
@Options({
|
||||
name: 'App',
|
||||
@@ -13,20 +14,26 @@ import StoragePersist from '@/components/StoragePersist.vue';
|
||||
LocaleSaver,
|
||||
NavBar,
|
||||
RouterView,
|
||||
SideBar,
|
||||
StoragePersist,
|
||||
},
|
||||
})
|
||||
export default class App extends Vue {
|
||||
sidebarToggled = false;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-column h-100 w-100">
|
||||
<div class="h-100 w-100">
|
||||
<LocaleSaver/>
|
||||
<DocumentLocaleSetter/>
|
||||
<StoragePersist/>
|
||||
<NavBar/>
|
||||
<RouterView class="flex-grow-1"/>
|
||||
<SideBar ref="sidebar" class="h-100 w-100" :toggled="sidebarToggled"
|
||||
@close="sidebarToggled=false"/>
|
||||
<div class="d-flex flex-column h-100 w-100">
|
||||
<NavBar @toggleSidebar="sidebarToggled = !sidebarToggled"/>
|
||||
<RouterView class="flex-grow-1"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -13,6 +13,9 @@ import LocaleSelector from '@/components/locale/LocaleSelector.vue';
|
||||
LocaleSelector,
|
||||
MangaUpdatesUpdater,
|
||||
},
|
||||
emits: {
|
||||
'toggleSidebar': undefined,
|
||||
},
|
||||
})
|
||||
export default class NavBar extends Vue {
|
||||
}
|
||||
@@ -20,51 +23,52 @@ export default class NavBar extends Vue {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="navbar navbar-expand border-bottom shadow">
|
||||
<div class="container-fluid">
|
||||
<!-- <a class="navbar-brand" href="#">Navbar</a>-->
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<!-- <ul class="navbar-nav me-auto mb-2 mb-lg-0">-->
|
||||
<!-- <li class="nav-item">-->
|
||||
<!-- <a class="nav-link active" aria-current="page" href="#">Home</a>-->
|
||||
<!-- </li>-->
|
||||
<!-- <li class="nav-item">-->
|
||||
<!-- <a class="nav-link" href="#">Link</a>-->
|
||||
<!-- </li>-->
|
||||
<!-- <li class="nav-item dropdown">-->
|
||||
<!-- <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">-->
|
||||
<!-- Dropdown-->
|
||||
<!-- </a>-->
|
||||
<!-- <ul class="dropdown-menu">-->
|
||||
<!-- <li><a class="dropdown-item" href="#">Action</a></li>-->
|
||||
<!-- <li><a class="dropdown-item" href="#">Another action</a></li>-->
|
||||
<!-- <li>-->
|
||||
<!-- <hr class="dropdown-divider">-->
|
||||
<!-- </li>-->
|
||||
<!-- <li><a class="dropdown-item" href="#">Something else here</a></li>-->
|
||||
<!-- </ul>-->
|
||||
<!-- </li>-->
|
||||
<!-- <li class="nav-item">-->
|
||||
<!-- <a class="nav-link disabled">Disabled</a>-->
|
||||
<!-- </li>-->
|
||||
<!-- </ul>-->
|
||||
<div class="mx-auto">
|
||||
<div class="d-flex flex-row">
|
||||
<AniListUserSearch class="mx-1"/>
|
||||
<MangaUpdatesUpdater class="mx-1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
<LocaleSelector class="ms-2"/>
|
||||
<BootstrapThemeSwitch class="ms-2"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- z-index needed, otherwise shadow not showing -->
|
||||
<nav class="navbar border-bottom shadow flex-nowrap" style="z-index: 1">
|
||||
<div>
|
||||
<div class="navbar-sidebar-toggler mx-1 c-pointer">
|
||||
<i class="fa fa-bars me-2" @click="$emit('toggleSidebar')"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex flex-row">
|
||||
<AniListUserSearch class="me-2"/>
|
||||
<MangaUpdatesUpdater class=""/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
<LocaleSelector class="navbar-locale-select"/>
|
||||
<BootstrapThemeSwitch class="navbar-theme-switch ms-2"/>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
@import 'bootstrap/scss/mixins/breakpoints';
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
nav.navbar {
|
||||
--bs-navbar-padding-x: 0.5rem;
|
||||
}
|
||||
|
||||
nav.navbar .navbar-locale-select,
|
||||
nav.navbar .navbar-theme-switch {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
nav.navbar {
|
||||
--bs-navbar-padding-x: 1rem;
|
||||
}
|
||||
|
||||
nav.navbar .navbar-sidebar-toggler {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
87
src/components/SideBar.vue
Normal file
87
src/components/SideBar.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<script lang="ts">
|
||||
import {Options, Vue} from 'vue-class-component';
|
||||
import SideBarNavItem from '@/components/SideBarNavItem.vue';
|
||||
import {Prop} from 'vue-property-decorator';
|
||||
import LocaleSelector from '@/components/locale/LocaleSelector.vue';
|
||||
import BootstrapThemeSwitch from '@/components/bootstrapThemeSwitch/BootstrapThemeSwitch.vue';
|
||||
import SideBarHead from '@/components/SideBarHead.vue';
|
||||
|
||||
@Options({
|
||||
name: 'SideBar',
|
||||
components: {
|
||||
BootstrapThemeSwitch,
|
||||
LocaleSelector,
|
||||
SideBarHead,
|
||||
SideBarNavItem,
|
||||
},
|
||||
emits: {
|
||||
'close': undefined,
|
||||
},
|
||||
})
|
||||
export default class SideBar extends Vue {
|
||||
@Prop({default: false})
|
||||
toggled!: boolean;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ toggled: toggled }" class="sidebar border-right shadow bg-body">
|
||||
<div class="d-flex flex-column">
|
||||
<ul class="nav flex-column mb-auto">
|
||||
<li>
|
||||
<SideBarHead @close="$emit('close')"/>
|
||||
</li>
|
||||
<SideBarNavItem :text="$t('locale')" faIcon="fa-language">
|
||||
<template #end>
|
||||
<LocaleSelector class="navbar-locale-select me-1"/>
|
||||
</template>
|
||||
</SideBarNavItem>
|
||||
<SideBarNavItem :text="$t('design')" faIcon="fa-moon">
|
||||
<template #end>
|
||||
<BootstrapThemeSwitch class="navbar-theme-switch"/>
|
||||
</template>
|
||||
</SideBarNavItem>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
@import 'bootstrap/scss/mixins/breakpoints';
|
||||
|
||||
$width: 15em;
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: $width;
|
||||
max-width: #{'clamp(0em, '}$width#{', 100%)'};
|
||||
transition: width ease-in-out 0.25s;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
z-index: 10000;
|
||||
height: 100%;
|
||||
|
||||
&:not(.toggled) {
|
||||
width: 0 !important;
|
||||
}
|
||||
|
||||
.sidebar-nav-item {
|
||||
border-top: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.sidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
24
src/components/SideBarHead.vue
Normal file
24
src/components/SideBarHead.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import {Options, Vue} from 'vue-class-component';
|
||||
|
||||
@Options({
|
||||
name: 'SideBar',
|
||||
components: {},
|
||||
emits: {
|
||||
'close': undefined,
|
||||
},
|
||||
})
|
||||
export default class SideBar extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="navbar border-bottom shadow flex-nowrap">
|
||||
<div class="sidebar-closer mx-1 c-pointer">
|
||||
<i class="fa fa-arrow-left me-2" @click="$emit('close')"/>
|
||||
|
||||
<!-- 'hack' to ensure this nav is the same height as the navbar -->
|
||||
<input class="form-control d-inline mx-0 px-0" style="visibility: hidden; width: 0;"/>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
41
src/components/SideBarNavItem.vue
Normal file
41
src/components/SideBarNavItem.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import {Options, Vue} from 'vue-class-component';
|
||||
import {Prop} from 'vue-property-decorator';
|
||||
|
||||
@Options({
|
||||
name: 'SideBarNavItem',
|
||||
components: {},
|
||||
})
|
||||
export default class SideBarNavItem extends Vue {
|
||||
@Prop({required: false})
|
||||
faIcon!: string;
|
||||
@Prop({required: false})
|
||||
text!: string;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li class="nav-item sidebar-nav-item">
|
||||
<slot>
|
||||
<div class="d-flex flex-row p-2 align-items-center">
|
||||
<i :class="[faIcon]" class="sidebar-nav-item-icon text-center fa"></i>
|
||||
<span class="sidebar-nav-item-text me-auto">{{ text }}</span>
|
||||
<slot name="end"/>
|
||||
</div>
|
||||
</slot>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebar-nav-item-text {
|
||||
opacity: 1;
|
||||
overflow: hidden;
|
||||
max-width: 10em;
|
||||
transition: display ease-in-out 0.25s, opacity ease-in-out 0.25s, max-width ease-in-out 0.25s;
|
||||
}
|
||||
|
||||
.sidebar-nav-item-icon {
|
||||
width: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -13,8 +13,8 @@ export default class LocaleSelector extends Vue {
|
||||
|
||||
get supportedLocales(): { value: string, text: string } [] {
|
||||
return [
|
||||
{value: 'en', text: this.$t('locale.en')},
|
||||
{value: 'de', text: this.$t('locale.de')},
|
||||
{value: 'en', text: this.$t('locales.en')},
|
||||
{value: 'de', text: this.$t('locales.de')},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {messagesEn} from '@/locale/en';
|
||||
|
||||
export const messagesDe = {
|
||||
design: 'Design',
|
||||
fetch: {
|
||||
mangaUpdates: {
|
||||
chapters: 'Kapitel',
|
||||
@@ -10,7 +11,8 @@ export const messagesDe = {
|
||||
starting: 'Starte',
|
||||
},
|
||||
},
|
||||
locale: messagesEn.locale,
|
||||
locale: 'Sprache',
|
||||
locales: messagesEn.locales,
|
||||
localStoragePersistNotSupported: 'Lokaler Speicher wird nicht permanent. Das könnte in längere Wartezeiten verursachen!',
|
||||
manga: {
|
||||
chapters: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const messagesEn = {
|
||||
design: 'Design',
|
||||
fetch: {
|
||||
mangaUpdates: {
|
||||
chapters: 'Chapters',
|
||||
@@ -8,7 +9,8 @@ export const messagesEn = {
|
||||
starting: 'Starting',
|
||||
},
|
||||
},
|
||||
locale: {
|
||||
locale: 'Language',
|
||||
locales: {
|
||||
'de': 'Deutsch',
|
||||
'en': 'English',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user