Skip to content

Commit 7614962

Browse files
committed
New Layouts, settings pages, WIP
1 parent 008c0f1 commit 7614962

29 files changed

+774
-330
lines changed

package-lock.json

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"eslint-plugin-vue": "^9.32.0",
2525
"nprogress": "^0.2.0",
2626
"pinia": "^2.1.7",
27-
"primeicons": "^7.0.0",
2827
"primevue": "^4.3.0",
2928
"tailwindcss": "^4.1.0",
3029
"tailwindcss-primeui": "^0.5.0",

src/app.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import './assets/css/app.css';
22
import './assets/css/tailwind.css';
33
import 'nprogress/nprogress.css';
4-
import 'primeicons/primeicons.css';
54

6-
import { useDark } from '@vueuse/core';
5+
import { useColorMode } from '@vueuse/core';
76
import customThemePreset from './theme/noir-preset';
87

98
import { createApp } from 'vue';
@@ -20,9 +19,9 @@ import PageTitleSection from '@/components/PageTitleSection.vue';
2019

2120
const app = createApp(App);
2221
const pinia = createPinia();
23-
const darkMode = useDark(); // set Light/Dark Mode
22+
const colorMode = useColorMode({ emitAuto: true });
2423

25-
app.provide('darkMode', darkMode)
24+
app.provide('colorMode', colorMode)
2625
.use(pinia)
2726
.use(router)
2827
.use(PrimeVue, {

src/assets/css/app.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,9 @@ body {
1111
#nprogress .bar {
1212
background: var(--p-primary-500) !important;
1313
z-index: 9999999 !important;
14+
}
15+
16+
.lucide {
17+
width: 16px;
18+
height: 16px;
1419
}

src/components/DeleteUserModal.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script setup>
2+
import { useTemplateRef } from 'vue';
3+
4+
const modalOpen = defineModel(false, {
5+
type: Boolean,
6+
});
7+
const passwordInput = useTemplateRef('password-input');
8+
9+
function focusPasswordInput() {
10+
passwordInput.value.$el.focus();
11+
}
12+
</script>
13+
14+
<template>
15+
<Dialog
16+
v-model:visible="modalOpen"
17+
position="center"
18+
header="Are you sure you want to delete your account?"
19+
:style="{ width: '40rem' }"
20+
:draggable="false"
21+
dismissableMask
22+
modal
23+
@show="focusPasswordInput"
24+
>
25+
26+
</Dialog>
27+
</template>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script setup lang="ts">
2+
import { useTemplateRef } from 'vue';
3+
import Breadcrumb from 'primevue/breadcrumb';
4+
import { ChevronRight } from 'lucide-vue-next';
5+
import type { ExtendedMenuItem } from '@/types';
6+
7+
const componentProps = defineProps<{
8+
model: ExtendedMenuItem[]
9+
}>();
10+
11+
type BreadcrumbType = InstanceType<typeof Breadcrumb>;
12+
const childRef = useTemplateRef<BreadcrumbType>('child-ref');
13+
defineExpose({
14+
childRef,
15+
});
16+
</script>
17+
18+
<template>
19+
<Breadcrumb
20+
ref="child-ref"
21+
:model="componentProps.model"
22+
pt:root:class="p-0 bg-transparent"
23+
>
24+
<template #item="{ item, props }">
25+
<RouterLink
26+
v-if="item.route"
27+
v-slot="{ href, navigate }"
28+
:to="item.route"
29+
custom
30+
>
31+
<a
32+
:href="href"
33+
v-bind="props.action"
34+
class="p-breadcrumb-item-link"
35+
@click="navigate"
36+
>
37+
<i
38+
v-if="item.icon"
39+
:class="item.icon"
40+
class="p-breadcrumb-item-icon"
41+
/>
42+
<component
43+
:is="item.lucideIcon"
44+
v-else-if="item.lucideIcon"
45+
class="p-breadcrumb-item-icon"
46+
/>
47+
<span class="p-breadcrumb-item-label">{{ item.label }}</span>
48+
</a>
49+
</RouterLink>
50+
<a
51+
v-else
52+
:href="item.url"
53+
:target="item.target"
54+
v-bind="props.action"
55+
>
56+
<i
57+
v-if="item.icon"
58+
:class="item.icon"
59+
class="p-breadcrumb-item-icon"
60+
/>
61+
<component
62+
:is="item.lucideIcon"
63+
v-else-if="item.lucideIcon"
64+
class="p-breadcrumb-item-icon"
65+
/>
66+
<span class="p-breadcrumb-item-label">{{ item.label }}</span>
67+
</a>
68+
</template>
69+
<template #separator>
70+
<ChevronRight />
71+
</template>
72+
</Breadcrumb>
73+
</template>
File renamed without changes.

src/composables/useAppLayout.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { ref, computed, onMounted, onUnmounted, watchEffect } from 'vue';
2+
import { useRoute } from 'vue-router';
3+
import { LayoutGrid, House, Info, Github, Code, Settings, LogOut } from 'lucide-vue-next';
4+
import { useAuthStore } from '@/stores/auth';
5+
6+
export function useAppLayout() {
7+
const authStore = useAuthStore();
8+
const route = useRoute();
9+
const currentRoute = computed(() => route.name);
10+
11+
const userName = computed(() => authStore?.user?.name ?? 'User');
12+
13+
// Menu items
14+
const menuItems = computed(() => [
15+
{
16+
label: 'Home',
17+
lucideIcon: House,
18+
route: { name: 'welcome' },
19+
active: currentRoute.value == 'welcome',
20+
},
21+
{
22+
label: 'Dashboard',
23+
lucideIcon: LayoutGrid,
24+
route: { name: 'dashboard' },
25+
active: currentRoute.value == 'dashboard',
26+
},
27+
{
28+
label: 'Info',
29+
lucideIcon: Info,
30+
items: [
31+
{
32+
label: 'PrimeVue Docs',
33+
url: 'https://primevue.org/',
34+
lucideIcon: Code,
35+
},
36+
{
37+
label: 'Starter Kit Repo',
38+
url: 'https://github.com/connorabbas/laravel-primevue-starter-kit',
39+
lucideIcon: Github,
40+
},
41+
],
42+
},
43+
]);
44+
45+
// User menu and logout functionality.
46+
const userMenuItems = [
47+
{
48+
label: 'Settings',
49+
route: { name: 'settings.profile.edit' },
50+
lucideIcon: Settings,
51+
},
52+
{
53+
separator: true,
54+
},
55+
{
56+
label: 'Log Out',
57+
lucideIcon: LogOut,
58+
command: () => authStore.logout(),
59+
},
60+
];
61+
62+
// Mobile menu
63+
const mobileMenuOpen = ref(false);
64+
const windowWidth = ref(window.innerWidth);
65+
const updateWidth = () => {
66+
windowWidth.value = window.innerWidth;
67+
};
68+
onMounted(() => {
69+
window.addEventListener('resize', updateWidth);
70+
});
71+
onUnmounted(() => {
72+
window.removeEventListener('resize', updateWidth);
73+
});
74+
watchEffect(() => {
75+
if (windowWidth.value > 1024) {
76+
mobileMenuOpen.value = false;
77+
}
78+
});
79+
80+
return {
81+
userName,
82+
currentRoute,
83+
menuItems,
84+
userMenuItems,
85+
mobileMenuOpen,
86+
};
87+
}

0 commit comments

Comments
 (0)