Skip to content

Commit b246309

Browse files
author
Royer Antonio Gomez Jimenez
committed
save-progress
1 parent 0bfef9e commit b246309

16 files changed

+645
-8
lines changed

.eslintignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
components.d.ts
2+
nuxt.d.ts
3+
dist
4+
.nuxt
5+
.output

.eslintrc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"plugin:nuxt/recommended",
1010
"prettier"
1111
],
12-
"plugins": []
13-
// "rules": {
14-
// "vue/multi-word-component-names": "off",
15-
// "vue/no-multiple-template-root": "off",
16-
// "@typescript-eslint/no-unused-vars": "off"
17-
// }
12+
"plugins": [],
13+
"rules": {
14+
"vue/multi-word-component-names": "off"
15+
// "vue/no-multiple-template-root": "off",
16+
// "@typescript-eslint/no-unused-vars": "off"
17+
}
1818
}

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"semi": true,
3+
"singleQuote": false
4+
}

components/BaseNavbar.vue

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<script lang="ts" setup>
2+
import { AppConfigInput } from "@nuxt/schema";
3+
4+
// state
5+
const app = useAppConfig() as AppConfigInput;
6+
const navbar = ref(null);
7+
const showDrawer = useState<boolean>("navbar.showDrawer", () => false);
8+
const showOptions = useState<boolean>("navbar.showOptions", () => false);
9+
10+
// lifecycle
11+
let timer: NodeJS.Timer;
12+
onMounted(() => {
13+
if (!navbar.value) return;
14+
15+
// scroll
16+
const { onScroll } = useSticky(navbar.value, 0);
17+
setTimeout(() => onScroll(), 50);
18+
19+
// on show on mobile
20+
setInterval(() => {
21+
// must in mobile
22+
const minW = 1024;
23+
if (window.innerWidth < minW) {
24+
updateDrawerOptions();
25+
}
26+
}, 100);
27+
});
28+
onBeforeUnmount(() => {
29+
if (timer) clearInterval(timer);
30+
});
31+
32+
// methods
33+
const updateDrawerOptions = () => {
34+
// drawer
35+
if (showDrawer.value || showOptions.value) {
36+
document.body.classList.add("overflow-hidden");
37+
} else {
38+
document.body.classList.remove("overflow-hidden");
39+
}
40+
};
41+
const toggleDrawer = () => (showDrawer.value = !showDrawer.value);
42+
const toggleOptions = (show?: boolean) => {
43+
if (show) {
44+
showOptions.value = show;
45+
} else {
46+
showOptions.value = !showOptions.value;
47+
}
48+
};
49+
</script>
50+
51+
<template>
52+
<div
53+
ref="navbar"
54+
class="backdrop-filter backdrop-blur-md top-0 z-40 w-full flex-none transition-colors duration-300 lg:z-50 border-b border-gray-900/10 dark:border-gray-50/[0.2] bg-white/[0.5] dark:bg-slate-900/[0.5]"
55+
>
56+
<div id="navbar-banner" class="banner">
57+
<slot name="banner" />
58+
</div>
59+
<div class="max-w-8xl w-full mx-auto">
60+
<div class="py-3 lg:px-8 mx-4 lg:mx-0">
61+
<div class="relative flex items-center">
62+
<!-- drawer:toggle -->
63+
<div
64+
v-if="$slots['drawer']"
65+
class="lg:hidden flex items-center self-center justify-center mr-2"
66+
>
67+
<button
68+
class="flex items-center focus:outline-none"
69+
aria-label="Toggle Drawer Menu"
70+
@click="toggleDrawer()"
71+
>
72+
<span
73+
class="flex items-center text-gray-600 dark:text-gray-300 text-lg"
74+
aria-hidden="true"
75+
>
76+
<Icon v-if="!showDrawer" name="uil-bars" />
77+
<Icon v-else name="uil-times" />
78+
</span>
79+
</button>
80+
</div>
81+
<!-- title -->
82+
<slot name="title">
83+
<NuxtLink
84+
tag="a"
85+
class="mr-3 flex-none overflow-hidden md:w-auto text-md font-bold text-gray-900 dark:text-gray-200"
86+
:to="{ name: 'index' }"
87+
>
88+
<span class="sr-only">home</span>
89+
<span class="flex items-center">
90+
<Icon
91+
name="simple-icons:nuxtdotjs"
92+
class="inline-block mr-2 text-lg text-primary-500"
93+
/>
94+
{{ app.name }}
95+
</span>
96+
</NuxtLink>
97+
</slot>
98+
<!-- menu -->
99+
<slot name="menu" />
100+
<!-- options:toggle -->
101+
<div
102+
v-if="$slots['options']"
103+
class="flex-1 flex justify-end lg:hidden"
104+
>
105+
<button
106+
class="flex items-center focus:outline-none"
107+
aria-label="Toggle Options Menu"
108+
@click="toggleOptions()"
109+
>
110+
<span
111+
class="flex items-center text-gray-600 dark:text-gray-300 text-sm"
112+
aria-hidden="true"
113+
>
114+
<icon-fa-solid:ellipsis-v />
115+
</span>
116+
</button>
117+
</div>
118+
</div>
119+
</div>
120+
</div>
121+
<ClientOnly>
122+
<Teleport to="#app-after">
123+
<!-- drawer -->
124+
<Transition name="slide-fade-from-up" mode="out-in">
125+
<div
126+
v-if="showDrawer && $slots['drawer']"
127+
class="fixed lg:hidden bg-gray-100 dark:bg-slate-800 pt-12 top-0 left-0 w-screen h-screen z-30 flex flex-col"
128+
>
129+
<div class="flex-1 flex flex-col relative overflow-y-auto">
130+
<slot name="drawer" :toggle-drawer="toggleDrawer" />
131+
</div>
132+
</div>
133+
</Transition>
134+
135+
<!-- options -->
136+
<div v-if="showOptions && $slots['options']">
137+
<slot
138+
name="options"
139+
:toggle-options="toggleOptions"
140+
:show-options="showOptions"
141+
/>
142+
</div>
143+
</Teleport>
144+
</ClientOnly>
145+
</div>
146+
</template>
147+
148+
<style scoped>
149+
/* .slide-fade-from-up-enter-active {
150+
transition: all 0.3s ease-out;
151+
}
152+
.slide-fade-from-up-leave-active {
153+
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
154+
}
155+
.slide-fade-from-up-enter-from,
156+
.slide-fade-from-up-leave-to {
157+
transform: translateY(-20px);
158+
opacity: 0;
159+
}
160+
161+
a.router-link-active {
162+
font-weight: bold;
163+
} */
164+
/* a.router-link-exact-active {
165+
color: theme("colors.slate.900");
166+
} */
167+
/* html.dark {
168+
a.router-link-exact-active {
169+
color: "white";
170+
}
171+
} */
172+
</style>

components/Footer.vue

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script lang="ts" setup>
2+
import { AppConfigInput } from "@nuxt/schema";
3+
import p from "../package.json";
4+
const app = useAppConfig() as AppConfigInput;
5+
</script>
6+
7+
<template>
8+
<footer class="border-t lg:border-gray-900/10 dark:border-gray-50/[0.2]">
9+
<section
10+
class="max-w-8xl mx-auto px-4 lg:px-8 flex-1 flex w-full space-x-20"
11+
>
12+
<div class="w-full py-4 text-center md:text-left">
13+
<div class="mb-1">
14+
{{ app.name }}
15+
</div>
16+
<div class="text-xs text-gray-600 dark:text-gray-400">
17+
Copyright © 2022 <a :href="app.author.link">{{ app.author.name }}</a
18+
>. All rights reserved. Made with <span class="text-red-500">❤</span>
19+
<div
20+
class="flex flex-col md:flex-row space-x-2 items-center md:float-right"
21+
>
22+
<span class="text-center md:text-right">
23+
design by <a href="https://github.com/viandwi24">viandwi24</a>
24+
</span>
25+
<span
26+
class="block bg-blue-500 rounded px-1 py-0.5 text-white text-xs"
27+
>
28+
{{ p.devDependencies.nuxt }}
29+
</span>
30+
</div>
31+
</div>
32+
</div>
33+
</section>
34+
</footer>
35+
</template>

components/LanguageSwitcher.vue

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<script lang="ts" setup>
2+
import {
3+
Listbox,
4+
ListboxButton,
5+
ListboxLabel,
6+
ListboxOptions,
7+
ListboxOption,
8+
} from '@headlessui/vue'
9+
10+
const availableLocales = {
11+
en: {
12+
name: 'English',
13+
iso: 'en',
14+
flag: '🇺🇸',
15+
},
16+
es: {
17+
name: 'Español',
18+
iso: 'es',
19+
flag: '🇮🇩',
20+
},
21+
}
22+
23+
// micro compiler
24+
const props = defineProps({
25+
type: {
26+
type: String,
27+
default: 'dropdown-right-top',
28+
},
29+
})
30+
31+
// state
32+
const currentStyle = toRef(props, 'type')
33+
const localeSetting = useState<string>('locale.setting')
34+
</script>
35+
36+
<template>
37+
<div class="flex items-center">
38+
<Listbox
39+
v-if="currentStyle === 'dropdown-right-top'"
40+
v-model="localeSetting"
41+
as="div"
42+
class="relative flex items-center"
43+
>
44+
<ListboxLabel class="sr-only">Theme</ListboxLabel>
45+
<ListboxButton
46+
type="button"
47+
title="Change Language"
48+
class="transition-colors duration-300"
49+
>
50+
<span class="justify-center items-center flex">
51+
<IconLa:language />
52+
</span>
53+
</ListboxButton>
54+
<ListboxOptions
55+
class="p-1 absolute z-50 top-full right-0 outline-none bg-white rounded-lg ring-1 ring-gray-900/10 shadow-lg overflow-hidden w-36 py-1 text-sm text-gray-700 font-semibold dark:bg-gray-800 dark:ring-0 dark:highlight-white/5 dark:text-gray-300"
56+
>
57+
<ListboxOption
58+
v-for="lang in availableLocales"
59+
:key="lang.iso"
60+
:value="lang.iso"
61+
:class="{
62+
'py-2 px-2 flex items-center cursor-pointer': true,
63+
'text-sky-500 bg-gray-100 dark:bg-gray-600/30':
64+
localeSetting === lang.iso,
65+
'hover:bg-gray-50 dark:hover:bg-gray-700/30':
66+
localeSetting !== lang.iso,
67+
}"
68+
>
69+
<span class="text-sm mr-2">
70+
{{ lang.flag }}
71+
</span>
72+
<span class="flex-1 truncate">
73+
{{ lang.name }}
74+
<span class="text-xs">({{ lang.iso }})</span>
75+
</span>
76+
</ListboxOption>
77+
</ListboxOptions>
78+
</Listbox>
79+
<select
80+
v-if="currentStyle === 'select-box'"
81+
v-model="localeSetting"
82+
class="w-full px-2 pr-3 py-1 outline-none rounded border bg-transparent text-gray-700 dark:text-gray-300 border-gray-900/10 dark:border-gray-50/[0.2]"
83+
>
84+
<option
85+
v-for="lang in availableLocales"
86+
:key="lang.iso"
87+
:value="lang.iso"
88+
class="flex items-center space-x-2"
89+
>
90+
{{ lang.flag }} {{ lang.name }} ({{ lang.iso }})
91+
</option>
92+
</select>
93+
</div>
94+
</template>

components/Navbar.vue

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<template>
2+
<BaseNavbar>
3+
<template #menu>
4+
<div class="relative hidden lg:flex items-center ml-auto">
5+
<div class="flex items-center justify-center">
6+
<SearchBar />
7+
</div>
8+
<div
9+
class="flex space-x-4 border-l ml-6 pl-6 border-gray-900/10 dark:border-gray-50/[0.2]"
10+
>
11+
<LanguageSwitcher />
12+
<ThemeSwitcher />
13+
<Anchor
14+
class="hover:no-underline hover:text-slate-900 hover:dark:text-white text-lg flex self-center items-center"
15+
href="https://github.com/viandwi24/nuxt3-awesome-starter"
16+
title="Github"
17+
>
18+
<Icon name="mdi-github-face" />
19+
</Anchor>
20+
</div>
21+
</div>
22+
</template>
23+
<!-- <template #options="{ toggleOptions }">
24+
<ActionSheet @on-close="toggleOptions(false)">
25+
<ActionSheetBody>
26+
<ActionSheetHeader text="Menu" />
27+
<div class="mt-6 text-sm font-bold capitalize">
28+
{{ $t("components.theme_switcher.change_theme") }}
29+
</div>
30+
<div class="mt-2">
31+
<ThemeSwitcher type="select-box" />
32+
</div>
33+
<div class="mt-6 text-sm font-bold capitalize">
34+
{{ $t("components.language_switcher.change_language") }}
35+
</div>
36+
<div class="mt-2">
37+
<LanguageSwitcher type="select-box" />
38+
</div>
39+
</ActionSheetBody>
40+
<Button
41+
type="secondary"
42+
title="Github"
43+
href="https://github.com/viandwi24/nuxt3-awesome-starter"
44+
>
45+
<Icon name="mdi-github-face" />
46+
47+
<span class="ml-1">Github</span>
48+
</Button>
49+
<Button
50+
text="Close"
51+
type="secondary"
52+
@click.prevent="toggleOptions(false)"
53+
/>
54+
</ActionSheet>
55+
</template> -->
56+
<template #drawer>
57+
<slot name="drawer" />
58+
</template>
59+
</BaseNavbar>
60+
</template>

0 commit comments

Comments
 (0)