Skip to content

Commit 23bdb86

Browse files
style: 💎 New Navigation Bar
1 parent c146a22 commit 23bdb86

File tree

12 files changed

+179
-132
lines changed

12 files changed

+179
-132
lines changed

.vscode/extensions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"recommendations": ["nrwl.angular-console", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", "firsttris.vscode-jest-runner", "hollowtree.vue-snippets", "pkief.material-icon-theme", "github.copilot", "nicholashsiang.vscode-vue3-snippets", "dbcode.dbcode", "znck.vue", "dalirnet.vue-sort"]
2+
"recommendations": ["nrwl.angular-console", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", "firsttris.vscode-jest-runner", "hollowtree.vue-snippets", "pkief.material-icon-theme", "github.copilot", "nicholashsiang.vscode-vue3-snippets", "dbcode.dbcode", "dalirnet.vue-sort", "johnsoncodehk.volar", "vue.volar"]
33
}

.vscode/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,10 @@
2525
},
2626
"editor.formatOnSave": true,
2727
"dbcode.connections": [],
28-
"files.autoSave": "onWindowChange"
28+
"files.autoSave": "onWindowChange",
29+
"files.watcherExclude": {
30+
"**/.git/objects/**": true,
31+
"**/.git/subtree-cache/**": true,
32+
"**/node_modules/*/**": true
33+
}
2934
}

apps/wizarr-frontend/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
</head>
1616

1717
<body class="bg-gray-100 dark:bg-gray-900 overflow-x-hidden">
18-
<div id="loading" class="z-index: 10000;"></div>
18+
<div id="loading" style="z-index: 10000"></div>
19+
<div id="setup" style="z-index: 9999"></div>
1920
<div id="app"></div>
2021
<script type="module" src="/src/main.ts"></script>
2122
</body>

apps/wizarr-frontend/src/App.vue

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import ReloadPrompt from "@/components/ReloadPrompt.vue";
2323
import Help from "@/components/Help/Help.vue";
2424
2525
import type { Information as IInformation } from "@wizarrrrr/wizarr-sdk";
26+
import type { Version as IVersion } from "@wizarrrrr/wizarr-sdk";
2627
2728
export default defineComponent({
2829
name: "App",
@@ -75,18 +76,10 @@ export default defineComponent({
7576
this.updateTheme(this.theme);
7677
7778
// Get the server data
78-
const serverData = await this.$axiosRetry<IInformation>("/api/information", {
79-
disableErrorToast: true,
80-
disableInfoToast: true,
81-
});
82-
79+
const serverData = await this.$axiosRetry<IInformation>("/api/information");
8380
this.setServerData(serverData);
8481
85-
const versionData = await this.$axiosRetry("/api/version", {
86-
disableErrorToast: true,
87-
disableInfoToast: true,
88-
});
89-
82+
const versionData = await this.$axiosRetry<IVersion>("/api/version");
9083
this.setVersionData(versionData);
9184
9285
this.$loading.unmount();
20.2 KB
Loading
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
<template>
2-
<button class="text-gray-500 dark:text-gray-400 focus:outline-none text-sm" type="button" @click="$help('Home')">
3-
<div class="w-6 h-6 flex items-center justify-center rounded hover:bg-gray-200 hover:dark:bg-gray-700">
4-
<i class="fa-solid fa-lg fa-circle-info" style="font-size: 15px"></i>
5-
</div>
2+
<button type="button" @click="$help('Home')" class="relative rounded-full text-gray-400 hover:text-white">
3+
<span class="sr-only">View help</span>
4+
<ExclamationCircleIcon class="size-5" aria-hidden="true" />
65
</button>
76
</template>
87

9-
<script lang="ts">
10-
import { defineComponent } from "vue";
11-
12-
export default defineComponent({
13-
name: "HelpButton",
14-
});
8+
<script lang="ts" setup>
9+
import { ExclamationCircleIcon } from "@heroicons/vue/24/outline";
1510
</script>

apps/wizarr-frontend/src/components/Buttons/LanguageSelector.vue

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,21 @@
11
<template>
2-
<button class="text-gray-500 dark:text-gray-400 focus:outline-none text-sm" type="button" @click="createModal">
3-
<div :class="iconClasses" class="flex items-center justify-center rounded hover:bg-gray-200 hover:dark:bg-gray-700">
4-
<i class="fa-solid fa-md fa-globe"></i>
5-
</div>
2+
<button type="button" @click="createModal()" class="relative rounded-full text-gray-400 hover:text-white">
3+
<span class="sr-only">View translations</span>
4+
<LanguageIcon class="size-5" aria-hidden="true" />
65
</button>
76
</template>
87

98
<script lang="ts">
109
import { defineComponent } from "vue";
10+
import { LanguageIcon } from "@heroicons/vue/24/outline";
1111
import LanguageForm from "@/components/Forms/LanguageForm/LanguageForm.vue";
1212
1313
export default defineComponent({
1414
name: "LanguageSelector",
1515
components: {
16+
LanguageIcon,
1617
LanguageForm,
1718
},
18-
props: {
19-
iconClasses: {
20-
type: String,
21-
default: "w-6 h-6",
22-
},
23-
},
24-
computed: {
25-
iconClasses(): string {
26-
return this.iconClasses;
27-
},
28-
},
2919
methods: {
3020
createModal() {
3121
this.$modal.openModal(LanguageForm, {

apps/wizarr-frontend/src/main.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import Tours, { piniaPluginTours } from "./plugins/tours";
2525
import WebShare, { piniaPluginWebShare } from "./plugins/webshare";
2626

2727
import App from "./App.vue";
28+
import Setup from "./modules/setup/views/Setup.vue";
2829
import FullPageLoading from "@/components/Loading/FullPageLoading.vue";
2930
import Analytics from "./plugins/analytics";
3031
import FloatingVue from "floating-vue";
@@ -43,6 +44,10 @@ import i18n from "./i18n";
4344
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
4445
import router from "./router";
4546
import async from "@wizarrrrr/async";
47+
import { axiosRetry } from "./plugins/axiosRetry";
48+
import type { Information } from "@wizarrrrr/wizarr-sdk";
49+
import { useInformationStore } from "./stores/information";
50+
import { GraphQLClient } from "graphql-request";
4651

4752
const startApp = async () => {
4853
// Create the loading component
@@ -51,6 +56,7 @@ const startApp = async () => {
5156

5257
// Create the app instance and pinia
5358
const app = createApp(App);
59+
const setup = createApp(Setup);
5460
const pinia = createPinia();
5561

5662
// Place the loading component on the app's globalProperties
@@ -70,6 +76,25 @@ const startApp = async () => {
7076

7177
app.use(pinia);
7278

79+
setup.use(pinia);
80+
setup.use(i18n);
81+
setup.use(ToastPlugin, ToastOptions);
82+
setup.use(Axios);
83+
setup.use(plugin, defaultConfig(formkitConfig));
84+
setup.use(ToastPlugin, ToastOptions);
85+
setup.use(Toast);
86+
87+
// Get Information from Server
88+
const informationStore = useInformationStore();
89+
const serverData = await axiosRetry<Information>("/api/information");
90+
informationStore.setServerData(serverData);
91+
92+
// If setupRequired then redirect to /setup
93+
if (informationStore.setupRequired === true) {
94+
loading.unmount();
95+
return setup.mount("#setup");
96+
}
97+
7398
// Verify login state
7499
const authStore = useAuthStore();
75100
const [error, undefined] = await async(authStore.refreshToken);
@@ -83,6 +108,9 @@ const startApp = async () => {
83108
NODE_ENV: process.env.NODE_ENV as "development" | "production",
84109
};
85110

111+
const blogClient = new GraphQLClient("https://eu-west-2.cdn.hygraph.com/content/cm794oacz001307w5uvanqvdo/master");
112+
app.config.globalProperties.$blogClient = blogClient;
113+
86114
app.use(router);
87115
app.use(ToastPlugin, ToastOptions);
88116
app.use(Axios);
@@ -121,6 +149,7 @@ declare module "@vue/runtime-core" {
121149
};
122150
$help: (id: string) => void;
123151
$loading: App<Element>;
152+
$blogClient: GraphQLClient;
124153
}
125154

126155
interface GlobalComponents {

apps/wizarr-frontend/src/plugins/axiosRetry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const axiosRetry = async function <T>(url: string, config?: RetryOptions): Promi
5555
return attemptRequest();
5656
};
5757

58+
export { axiosRetry };
59+
5860
export default {
5961
install(app: App) {
6062
app.config.globalProperties.$axiosRetry = axiosRetry;
Lines changed: 93 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,106 @@
11
<template>
2-
<nav class="bg-white dark:bg-gray-900 absolute w-full z-20 top-0 left-0 border-b border-gray-200 dark:border-gray-600 md:h-[64px]">
3-
<div class="max-w-screen-xl flex flex-col md:flex-row items-start md:items-center justify-between mx-auto p-4">
4-
<!-- Left Side -->
5-
<div class="flex md:order-2 text-center justify-between w-full md:w-min">
6-
<router-link to="/" class="flex items-center">
7-
<WizarrLogo class="mr-3" rounded />
8-
<span class="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Wizarr</span>
9-
</router-link>
10-
<button data-collapse-toggle="navbar-default" aria-controls="navbar-default" aria-expanded="false" type="button" class="text-gray-500 dark:text-gray-400 focus:outline-none block md:hidden" @click="expanded = !expanded">
11-
<i class="fa-solid fa-md fa-xl fa-bars"></i>
12-
</button>
13-
</div>
14-
15-
<!-- Right Side -->
16-
<div class="flex md:order-2 text-center overflow-hidden justify-end w-full md:w-min mt-3 md:mt-0 md:block" :class="expanded ? 'block' : 'hidden'">
17-
<ul class="flex flex-col md:flex-row md:space-x-8 md:text-sm md:font-medium w-full md:w-min">
18-
<!-- Page Links -->
19-
<li v-for="page in pages" :key="page.name" class="flex text-center items-center">
20-
<router-link :to="page.url" as="button" class="text-left md:text-center w-full md:w-auto block py-2 pl-3 pr-4 text-gray-700 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-primary md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent" :class="$route.path == page.url || (page.url == '/admin/settings' && $route.path.includes('/admin/settings')) ? 'text-black dark:text-white' : ''">
21-
{{ __(page.name) }}
22-
</router-link>
23-
</li>
24-
25-
<!-- Quick Actions -->
26-
<li class="flex bg-gray-100 dark:bg-gray-800 md:bg-transparent md:dark:bg-transparent rounded text-center p-2 px-3 w-full mt-3 md:mt-0 md:justify-end md:px-0 md:p-0">
27-
<div class="flex flex-column w-full space-x-3 justify-between">
28-
<div class="flex flex-column space-x-1">
29-
<LanguageSelector />
30-
<ThemeToggle />
31-
<HelpButton />
32-
</div>
33-
<span class="inline-flex hidden md:block w-px h-6 bg-gray-200 dark:bg-gray-700"></span>
34-
<LogoutButton />
2+
<Disclosure as="nav" class="z-20 bg-white dark:bg-gray-900 absolute w-full top-0 left-0 right-0 border-b border-gray-200 dark:border-gray-600 md:h-[64px]" v-slot="{ open }">
3+
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
4+
<div class="flex h-16 items-center justify-between">
5+
<div class="flex items-center">
6+
<router-link to="/" class="flex items-center">
7+
<WizarrLogo class="rounded-md" />
8+
</router-link>
9+
<div class="hidden sm:ml-6 sm:block">
10+
<div class="flex space-x-4">
11+
<router-link v-for="page in pages" :key="page.name" :to="page.url" class="rounded-md px-3 py-2 text-sm font-semibold" :class="$route.path == page.url || (page.url == '/admin/settings' && $route.path.includes('/admin/settings')) ? 'bg-gray-800 text-white' : 'text-black dark:text-gray-300 hover:bg-gray-700 hover:text-white'">
12+
{{ __(page.name) }}
13+
</router-link>
3514
</div>
36-
</li>
37-
</ul>
15+
</div>
16+
</div>
17+
<div class="hidden sm:ml-6 sm:block">
18+
<div class="flex items-center space-x-3">
19+
<LanguageSelector />
20+
<ThemeToggle />
21+
<HelpButton />
22+
<button type="button" class="relative rounded-full text-gray-400 hover:text-white focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800">
23+
<span class="sr-only">View notifications</span>
24+
<BellIcon class="size-5" aria-hidden="true" />
25+
</button>
26+
<Menu as="div" class="relative">
27+
<MenuButton class="relative flex rounded-full bg-gray-800 text-sm focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800">
28+
<span class="sr-only">Open user menu</span>
29+
<img class="size-8 rounded-full" src="../../assets/img/profile.jpg" alt="User avatar" />
30+
</MenuButton>
31+
<transition enter-active-class="transition ease-out duration-100" enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100" leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
32+
<MenuItems class="absolute right-0 z-21 mt-2 w-48 origin-top-right rounded-md bg-white dark:bg-gray-800 ring-1 shadow-lg ring-black/5 overflow-hidden">
33+
<MenuItem v-for="item in menuItems" :key="item.text" v-slot="{ active }">
34+
<a href="#" :class="[active ? 'bg-gray-100 dark:bg-gray-700' : '', 'block px-4 py-2 text-sm text-gray-700 dark:text-white flex justify-between items-center']">
35+
<span>{{ item.text }}</span>
36+
<i :class="['fa-solid fa-lg', item.icon]"></i>
37+
</a>
38+
</MenuItem>
39+
</MenuItems>
40+
</transition>
41+
</Menu>
42+
</div>
43+
</div>
44+
<div class="-mr-2 flex sm:hidden">
45+
<DisclosureButton class="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:ring-2 focus:ring-white focus:ring-inset">
46+
<Bars3Icon v-if="!open" class="block size-6" aria-hidden="true" />
47+
<XMarkIcon v-else class="block size-6" aria-hidden="true" />
48+
</DisclosureButton>
49+
</div>
3850
</div>
3951
</div>
40-
</nav>
52+
<DisclosurePanel class="sm:hidden h-[100%]">
53+
<div class="border-y border-gray-700 pt-4 pb-3">
54+
<div class="flex items-center px-5">
55+
<div class="shrink-0">
56+
<img class="size-10 rounded-full" src="../../assets/img/profile.jpg" alt="" />
57+
</div>
58+
<div class="ml-3">
59+
<div class="text-base font-medium text-white">Tom Cook</div>
60+
<div class="text-sm font-medium text-gray-400">tom@example.com</div>
61+
</div>
62+
<!-- <button type="button" class="relative ml-auto shrink-0 rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800 focus:outline-hidden">
63+
<span class="absolute -inset-1.5" />
64+
<span class="sr-only">View notifications</span>
65+
<BellIcon class="size-6" aria-hidden="true" />
66+
</button> -->
67+
</div>
68+
</div>
69+
<div class="space-y-1 px-2 pt-2 pb-3">
70+
<router-link v-for="page in pages" :key="page.name" :to="page.url" class="block rounded-md px-3 py-2 text-base font-medium" :class="$route.path == page.url ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'">
71+
{{ __(page.name) }}
72+
</router-link>
73+
</div>
74+
</DisclosurePanel>
75+
</Disclosure>
4176
</template>
4277

43-
<script lang="ts">
44-
import { defineComponent } from "vue";
45-
import { useUserStore } from "@/stores/user";
46-
import { mapState } from "pinia";
78+
<style>
79+
nav[data-headlessui-state="open"] {
80+
height: 100%;
81+
}
82+
</style>
4783

48-
import WizarrLogo from "@/components/WizarrLogo.vue";
84+
<script setup>
85+
import { Disclosure, DisclosureButton, DisclosurePanel, Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/vue";
86+
import { Bars3Icon, BellIcon, XMarkIcon, ExclamationCircleIcon, LanguageIcon } from "@heroicons/vue/24/outline";
4987
50-
import AccountButton from "@/components/Buttons/AccountButton.vue";
88+
import WizarrLogo from "@/components/WizarrLogo.vue";
5189
import LanguageSelector from "@/components/Buttons/LanguageSelector.vue";
5290
import ThemeToggle from "@/components/Buttons/ThemeToggle.vue";
53-
import ViewToggle from "@/components/Buttons/ViewToggle.vue";
5491
import HelpButton from "@/components/Buttons/HelpButton.vue";
55-
import LogoutButton from "@/components/Buttons/LogoutButton.vue";
5692
57-
export default defineComponent({
58-
name: "AdminNavBar",
59-
components: {
60-
WizarrLogo,
61-
AccountButton,
62-
LanguageSelector,
63-
ThemeToggle,
64-
ViewToggle,
65-
HelpButton,
66-
LogoutButton,
67-
},
68-
computed: {
69-
activeLink() {
70-
return this.$route.path;
71-
},
72-
...mapState(useUserStore, ["user"]),
73-
},
74-
data() {
75-
return {
76-
pages: [
77-
{
78-
name: this.__("Home"),
79-
url: "/admin",
80-
},
81-
{
82-
name: this.__("Invitations"),
83-
url: "/admin/invitations",
84-
},
85-
{
86-
name: this.__("Servers"),
87-
url: "/admin/servers",
88-
},
89-
{
90-
name: this.__("Users"),
91-
url: "/admin/users",
92-
},
93-
{
94-
name: this.__("Settings"),
95-
url: "/admin/settings",
96-
},
97-
],
98-
expanded: false,
99-
};
100-
},
101-
watch: {
102-
"$route.path"() {
103-
this.expanded = false;
104-
},
105-
},
106-
});
93+
const pages = [
94+
{ name: "Home", url: "/admin" },
95+
{ name: "Invitations", url: "/admin/invitations" },
96+
{ name: "Servers", url: "/admin/servers" },
97+
{ name: "Users", url: "/admin/users" },
98+
{ name: "Settings", url: "/admin/settings" },
99+
];
100+
101+
const menuItems = [
102+
{ text: "Your Profile", icon: "fa-user" },
103+
{ text: "Settings", icon: "fa-gear" },
104+
{ text: "Logout", icon: "fa-right-from-bracket" },
105+
];
107106
</script>

0 commit comments

Comments
 (0)