Skip to content

Commit

Permalink
feat: implemented new navigation bar (#55)
Browse files Browse the repository at this point in the history
* style: made new navbar design

* fix: fixed torrent search and dropdown menu styling

* fix: settings width and input max width

* style: rounded buttons and search to 2xl

* style: made mobile navbar
  • Loading branch information
mickvandijke authored Sep 18, 2022
1 parent 0a9d296 commit 5caa795
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 90 deletions.
24 changes: 13 additions & 11 deletions src/components/Layout.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<template>
<div class="max-w-8xl mx-auto px-4 sm:px-6 md:px-8">
<div class="hidden lg:block fixed z-20 inset-0 pt-4 left-[max(0px,calc(50%-45rem))] right-auto w-[19.5rem] pb-10 px-8 overflow-y-auto border-r border-slate-800" id="main-nav">
<Sidebar />
</div>
<div class="lg:pl-[19.5rem]">
<div class="max-w-3xl mx-auto pt-0 lg:pt-4 xl:max-w-none xl:ml-0">
<Navbar />
<router-view />
<Footer />
<div>
<Navbar />
<div class="max-w-8xl mx-auto px-4 sm:px-6 md:px-8">
<div class="hidden lg:block fixed z-20 inset-0 pt-4 left-[max(0px,calc(50%-45rem))] right-auto w-[19.5rem] pb-10 px-8 overflow-y-auto border-r border-slate-800" id="main-nav">
<Sidebar />
</div>
<div class="lg:pl-[19.5rem]">
<div class="max-w-3xl mx-auto pt-0 lg:pt-4 xl:max-w-none xl:ml-0">
<router-view />
<Footer />
</div>
</div>
<!-- <Footer />-->
<AuthenticationModal />
</div>
<!-- <Footer />-->
<AuthenticationModal />
</div>
</template>

Expand Down
141 changes: 98 additions & 43 deletions src/components/navigation/Navbar.vue
Original file line number Diff line number Diff line change
@@ -1,43 +1,99 @@
<template>
<div class="top-0 z-40 w-full flex-none lg:z-50">
<div class="max-w-8xl mx-auto">
<div class="py-4 border-b lg:border-0 border-slate-300/10">
<div class="relative flex items-center">
<div class="text-2xl font-bold text-slate-100">
{{ $route.name }}
</div>
<div class="relative flex items-center ml-auto">
<div v-if="$store.getters.isLoggedIn" class="flex justify-between items-center space-x-4">
<router-link to="/upload" class="px-4 py-1.5 bg-sky-500 text-sm text-white border border-sky-500 rounded-md transition duration-200 hover:shadow-lg hover:shadow-sky-500/25">
<span class="hidden md:block">Upload torrent</span>
<span class="block md:hidden">+</span>
</router-link>
</div>
<div class="ml-4 flex items-center">
<Profile />
<div class="flex flex-col sticky top-0 h-16 md:h-20 justify-center bg-slate-900/85 border-b lg:border-0 border-slate-800/50 z-50 max-w-full" style="backdrop-filter: blur(20px);">
<div class="px-4 md:px-8 flex flex-col w-full">
<!-- MOBILE -->
<div id="mobile-menu" class="flex md:hidden flex-row items-center max-w-full">

<div id="open-mobile-search-bar-toggle" v-if="mobileState === MobileStates.Navigate" class="px-3.5 h-10 mr-3 flex md:hidden flex-col justify-center items-center bg-white/5 border border-slate-600 rounded-2xl">
<button class="flex flex-col" @click="mobileState = MobileStates.Search">
<SearchIcon size="18" class="text-slate-400" />
</button>
</div>

<div id="extra-options" v-if="mobileState === MobileStates.Navigate" class="flex flex-row flex-1 ml-auto items-center justify-end">
<Profile class="mr-3" />

<router-link to="/upload" class="px-4 h-10 inline-flex flex-nowrap justify-center items-center self-start appearance-none bg-sky-500 hover:bg-sky-600 text-sm text-white font-medium rounded-2xl cursor-pointer duration-200">
<UploadIcon size="24" />
</router-link>
</div>

<div id="mobile-search-bar" v-if="mobileState === MobileStates.Search" class="block md:hidden grow">
<div class="flex flex-col mr-3">
<div class="flex flex-col">
<div class="px-3.5 bg-white/5 border border-slate-600 focus:border-slate-400 rounded-2xl duration-200">
<div class="flex flex-row items-center">
<div class="flex flex-col grow">
<input
@keyup.enter="submitSearch"
v-model="searchQuery"
name="search"
type="text"
class="h-12 bg-transparent outline-0 text-slate-200 text-sm font-medium placeholder-slate-400"
placeholder="Search by torrent, category or user"
>
</div>
</div>
</div>
</div>
</div>
</div>

<div id="close-mobile-search-bar-toggle" v-if="mobileState === MobileStates.Search" class="px-4 h-12 flex md:hidden flex-col justify-center items-center bg-white/5 rounded-2xl">
<button class="flex flex-col" @click="mobileState = MobileStates.Navigate">
<XIcon size="18" class="text-slate-400" />
</button>
</div>

</div>
<div class="flex items-center p-4 border-b lg:hidden text-slate-400 border-slate-50/[0.06]">
<button
@click="toggleSidebar"
type="button"
>
<span class="sr-only">Navigation</span>
<svg width="24" height="24">
<path
d="M5 6h14M5 12h14M5 18h14"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</button>
<Breadcrumb class="ml-6" />

<!-- DESKTOP -->
<div id="desktop-menu" class="hidden md:flex flex-row items-center max-w-full">

<div id="site-name" class="hidden md:flex flex-row flex-1 mr-auto justify-start">
<div class="flex flex-col">
<router-link class="block text-2xl text-white duration-200" to="/">
<div class="flex flex-row flex-nowrap">
<span class="block w-full text-3xl font-semibold">{{ $store.state.settings.website.name }}</span>
</div>
</router-link>
</div>
</div>

<div id="search-bar" class="hidden md:block mx-5 grow max-w-lg">
<div class="flex flex-col">
<div class="flex flex-col">
<div class="px-3.5 bg-white/5 border border-transparent hover:border-slate-600 focus:border-slate-400 rounded-2xl duration-200">
<div class="flex flex-row items-center">
<div class="mr-3 flex flex-col">
<SearchIcon size="18" class="text-slate-400" />
</div>
<div class="flex flex-col grow">
<input
@keyup.enter="submitSearch"
v-model="searchQuery"
name="search"
type="text"
class="h-12 bg-transparent outline-0 text-slate-200 font-medium placeholder-slate-400"
placeholder="Search by torrent, category or user"
>
</div>
</div>
</div>
</div>
</div>
</div>

<div id="extra-options" class="flex flex-row flex-1 ml-auto items-center justify-end">
<Profile class="mr-3" />

<router-link to="/upload" class="px-6 h-10 inline-flex flex-nowrap justify-center items-center self-start appearance-none bg-sky-500 hover:bg-sky-600 text-sm text-white font-medium rounded-2xl cursor-pointer duration-200">
<UploadIcon size="24" class="mr-3" />
<span class="flex flex-nowrap whitespace-nowrap">Upload torrent</span>
</router-link>
</div>

</div>
<Sidebar v-show="$store.state.sideBarOpen" class="block lg:hidden px-4" />
</div>
</div>
</template>
Expand All @@ -48,25 +104,28 @@ import Profile from "./Profile.vue";
import Logo from "../Logo.vue";
import Breadcrumb from "../Breadcrumb.vue";
import Sidebar from "./Sidebar.vue";
import { SearchIcon, UploadIcon, XIcon } from "@vue-hero-icons/outline"
export default {
name: 'Navbar',
components: {Sidebar, Breadcrumb, Profile, Logo},
components: {Sidebar, Breadcrumb, Profile, Logo, SearchIcon, UploadIcon, XIcon},
computed: {
...mapState({})
},
data: () => ({
searchQuery: ''
MobileStates: Object.freeze({
Search: 0,
Navigate: 1,
}),
mobileState: 1,
searchQuery: '',
}),
methods: {
submitSearch() {
if (this.searchQuery) {
this.$router.push(`/torrents?search=${this.searchQuery}`)
}
},
toggleSidebar() {
this.$store.dispatch('toggleSidebar')
}
}
}
</script>
Expand All @@ -75,8 +134,4 @@ export default {
img {
image-rendering: crisp-edges;
}
.button {
@apply h-10 px-4 bg-red-500 text-white rounded-lg;
}
</style>
47 changes: 33 additions & 14 deletions src/components/navigation/Profile.vue
Original file line number Diff line number Diff line change
@@ -1,40 +1,59 @@
<template>
<div class="relative inline-block text-left" v-click-outside="() => (dropdownOpened = false)">

<button v-if="$store.getters.isLoggedIn" class="px-4 py-1.5 rounded-md border border-slate-800 text-sm text-slate-400 flex items-center relative cursor-pointer transition duration-200 hover:text-slate-200 hover:border-slate-200" @click="dropdownOpened = !dropdownOpened">
<UserCircleIcon size="16" class="mr-1 opacity-50" />
{{ user.username }}
<button
v-if="$store.getters.isLoggedIn"
id="profile-button"
class="px-6 h-10 inline-flex justify-center items-center self-start appearance-none bg-white hover:bg-gray-200 text-sm text-black font-medium rounded-2xl cursor-pointer duration-200"
@click="dropdownOpened = !dropdownOpened"
>
<UserCircleIcon size="24" class="mr-3" />
<span class="flex flex-nowrap whitespace-nowrap">{{ user.username }}</span>
<ChevronDownIcon
class="w-5 h-5 ml-2 -mr-1"
aria-hidden="true"
/>
</button>

<button v-else class="px-4 py-1.5 bg-sky-500 text-sm text-white border border-sky-500 rounded-md transition duration-200 hover:shadow-lg hover:shadow-sky-500/25" @click="$store.dispatch('openAuthModal')">
Sign in
<button
v-else
id="sign-in-button"
class="px-6 h-10 inline-flex justify-center items-center self-start appearance-none bg-white hover:bg-gray-200 text-sm text-black font-medium rounded-2xl cursor-pointer duration-200"
@click="$store.dispatch('openAuthModal')"
>
<UserCircleIcon size="24" class="mr-3" />
<span class="flex flex-nowrap whitespace-nowrap">Sign in</span>
</button>

<div class="origin-top-right absolute right-0 mt-2 z-10" :class="{hidden: !dropdownOpened}">
<div @click.prevent="() => (dropdownOpened = false)" class="py-2 px-2 w-48 flex flex-col bg-slate-800 text-sm rounded-md shadow-lg">
<router-link v-if="$store.getters.isAdministrator" to="/settings" replace class="py-1.5 text-center text-slate-100 border border-transparent rounded-md transition duration-200 hover:bg-slate-700 hover:border-slate-700">
<span>Settings</span>
</router-link>
<hr class="my-2 border-slate-700" />
<button @click="$store.dispatch('logout')" class="py-1.5 bg-red-500 bg-opacity-10 text-red-400 border border-transparent rounded-md transition duration-200 hover:text-red-500">Sign out</button>
<div
id="dropdown-menu"
class="origin-top-right absolute right-0 mt-4 z-10"
:class="{hidden: !dropdownOpened}"
>
<div @click.prevent="() => (dropdownOpened = false)" class="w-48 divide-y divide-gray-100 shadow bg-gray-700 rounded-2xl overflow-hidden">
<ul class="py-1 text-sm text-gray-200 font-medium duration-200" aria-labelledby="dropdownDefault">
<li v-if="$store.getters.isAdministrator">
<router-link to="/settings/general" replace class="h-10 inline-flex items-center py-2 px-6 w-full hover:bg-gray-600 hover:text-white duration-200">
<span class="flex flex-nowrap whitespace-nowrap">Settings</span>
</router-link>
</li>
<li>
<a @click="$store.dispatch('logout')" class="h-10 inline-flex items-center py-2 px-6 w-full hover:bg-gray-600 text-red-300 text-left hover:text-red-400 cursor-pointer duration-200">Sign out</a>
</li>
</ul>
</div>
</div>

</div>
</template>

<script>
import {UserIcon} from "@vue-hero-icons/outline";
import { ChevronDownIcon, UserCircleIcon } from '@vue-hero-icons/solid'
import {mapState} from "vuex";
export default {
name: "Profile",
components: {UserIcon, ChevronDownIcon, UserCircleIcon},
components: {ChevronDownIcon, UserCircleIcon},
data: () => ({
dropdownOpened: false,
}),
Expand Down
24 changes: 2 additions & 22 deletions src/components/navigation/Sidebar.vue
Original file line number Diff line number Diff line change
@@ -1,29 +1,8 @@
<template>
<nav class="lg:text-sm lg:leading-6 relative">

<div class="py-4">
<router-link class="block text-2xl text-white" to="/">
<span class="font-semibold text-slate-400 hover:text-white transition duration-200">{{ $store.state.settings.website.name }}</span>
</router-link>
</div>

<!-- search bar -->
<div class="sticky top-0 py-4 -ml-0.5 pointer-events-none">
<div class="relative pointer-events-auto">
<div class="w-full flex items-center text-sm text-slate-400 bg-slate-800/50 rounded-md ring-1 ring-slate-900/10 py-1.5 pl-2 pr-3 transition duration-200 hover:ring-sky-400 focus:ring-sky-400">
<svg width="22" height="22" fill="none" aria-hidden="true" class="mr-2 flex-none">
<path d="m19 19-3.5-3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
<circle cx="11" cy="11" r="6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></circle>
</svg>
<input @keyup.enter="submitSearch" v-model="searchQuery" type="text" name="search" placeholder="Search torrents..."
class="bg-transparent text-white font-light w-full focus:outline-none">
</div>
</div>
<div class="h-4 bg-gradient-to-b from-white dark:from-slate-900"></div>
</div>

<!-- items -->
<ul>
<ul class="mt-24">
<li class="nav">
<button @click="goTo('/torrents/popular')" :class="{ 'active': $route.params.sorting === 'popular' }">
<FireIcon class="h-5 w-5 opacity-50" />
Expand All @@ -48,6 +27,7 @@
</ul>
</li>
</ul>

</nav>
</template>

Expand Down

0 comments on commit 5caa795

Please sign in to comment.