Skip to content

Commit e3eb237

Browse files
committed
cleanup and fixing light/dark mode on load
1 parent 113a573 commit e3eb237

File tree

19 files changed

+118
-110
lines changed

19 files changed

+118
-110
lines changed

resources/js/app.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import '../css/app.css';
2-
import './bootstrap';
32

43
import { createInertiaApp } from '@inertiajs/vue3';
54
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
65
import { createApp, DefineComponent, h } from 'vue';
76
import { ZiggyVue } from '../../vendor/tightenco/ziggy';
7+
import { initializeTheme } from './composables/useAppearance';
88

99
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
1010

@@ -24,4 +24,7 @@ createInertiaApp({
2424
progress: {
2525
color: '#4B5563',
2626
},
27-
});
27+
});
28+
29+
// This will set dark/light mode on load
30+
initializeTheme();

resources/js/bootstrap.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

resources/js/components/AppearanceTabs.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ const props = withDefaults(defineProps<Props>(), {
1313
const { appearance, updateAppearance } = useAppearance()
1414
1515
const tabs = [
16-
{ value: 'light', icon: Sun, label: 'Light' },
17-
{ value: 'dark', icon: Moon, label: 'Dark' },
18-
{ value: 'system', icon: Monitor, label: 'System' }
16+
{ value: 'light', Icon: Sun, label: 'Light' },
17+
{ value: 'dark', Icon: Moon, label: 'Dark' },
18+
{ value: 'system', Icon: Monitor, label: 'System' }
1919
] as const
2020
</script>
2121

@@ -27,7 +27,7 @@ const tabs = [
2727
]"
2828
>
2929
<button
30-
v-for="{ value, icon: Icon, label } in tabs"
30+
v-for="{ value, Icon, label } in tabs"
3131
:key="value"
3232
@click="updateAppearance(value)"
3333
:class="[
@@ -37,7 +37,7 @@ const tabs = [
3737
: 'hover:bg-neutral-200/60 text-neutral-500 hover:text-black dark:hover:bg-neutral-700/60 dark:text-neutral-400'
3838
]"
3939
>
40-
<Icon class="h-4 w-4 -ml-1" />
40+
<component :is="Icon" class="h-4 w-4 -ml-1" />
4141
<span class="ml-1.5 text-sm">{{ label }}</span>
4242
</button>
4343
</div>

resources/js/components/NavFooter.vue

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { type LucideIcon, ExternalLink } from 'lucide-vue-next';
3+
import { type NavItemType } from '@/types'
34
import {
45
SidebarGroup,
56
SidebarGroupContent,
@@ -9,14 +10,8 @@ import {
910
SidebarMenuAction
1011
} from '@/components/ui/sidebar';
1112
12-
interface NavItem {
13-
title: string;
14-
url: string;
15-
icon: any; // Using any for now since Vue's type system handles components differently
16-
}
17-
1813
interface Props {
19-
items: NavItem[];
14+
items: NavItemType[];
2015
class?: string;
2116
}
2217

resources/js/components/NavUser.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const user = page.props.auth.user as User;
4949
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
5050
>
5151
<Avatar class="h-8 w-8 rounded-md bg-sidebar-primary text-sidebar-primary-foreground">
52-
<AvatarImage :src="user.avatar" :alt="user.name" />
52+
<AvatarImage v-if="user.avatar" :src="user.avatar" :alt="user.name" />
5353
<AvatarFallback class="rounded-md">
5454
{{ getInitials(user.name) }}
5555
</AvatarFallback>
@@ -70,7 +70,7 @@ const user = page.props.auth.user as User;
7070
<DropdownMenuLabel class="p-0 font-normal">
7171
<div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
7272
<Avatar class="h-8 w-8 rounded-md bg-sidebar-primary text-sidebar-primary-foreground">
73-
<AvatarImage :src="user.avatar" :alt="user.name" />
73+
<AvatarImage v-if="user.avatar" :src="user.avatar" :alt="user.name" />
7474
<AvatarFallback class="rounded-md">{{ getInitials(user.name) }}</AvatarFallback>
7575
</Avatar>
7676
<div class="grid flex-1 text-left text-sm leading-tight">

resources/js/components/sidebar/NavMain.vue

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { ChevronRight } from 'lucide-vue-next'
33
import type { Component } from 'vue'
4+
import { type NavItemType } from '@/types'
45
import {
56
Collapsible,
67
CollapsibleContent,
@@ -23,16 +24,8 @@
2324
url: string
2425
}
2526
26-
interface NavItem {
27-
title: string
28-
url: string
29-
icon: Component
30-
isActive?: boolean
31-
items?: SubItem[]
32-
}
33-
3427
defineProps<{
35-
items: NavItem[]
28+
items: NavItemType[]
3629
}>()
3730
</script>
3831

resources/js/components/sidebar/NavSecondary.vue

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import type { Component } from 'vue'
3+
import { type NavItemType } from '@/types'
34
import {
45
SidebarGroup,
56
SidebarGroupContent,
@@ -8,14 +9,8 @@
89
SidebarMenuItem,
910
} from '@/components/ui/sidebar'
1011
11-
interface NavItem {
12-
title: string
13-
url: string
14-
icon: Component
15-
}
16-
1712
defineProps<{
18-
items: NavItem[]
13+
items: NavItemType[]
1914
}>()
2015
</script>
2116

resources/js/components/sidebar/Sidebar.vue

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const props = defineProps(['name'])
1818
import NavProjects from '@/components/sidebar/NavProjects.vue'
1919
import NavSecondary from '@/components/sidebar/NavSecondary.vue'
2020
import NavUser from '@/components/sidebar/NavUser.vue'
21+
import { type NavItemType } from '@/types'
2122
import {
2223
Sidebar,
2324
SidebarContent,
@@ -28,14 +29,6 @@ const props = defineProps(['name'])
2829
SidebarMenuItem,
2930
} from '@/components/ui/sidebar'
3031
31-
interface NavItem {
32-
title: string
33-
url: string
34-
icon?: any
35-
isActive?: boolean
36-
items?: { title: string; url: string }[]
37-
}
38-
3932
interface Project {
4033
name: string
4134
url: string
@@ -140,7 +133,7 @@ const props = defineProps(['name'])
140133
},
141134
],
142135
},
143-
] as NavItem[],
136+
] as NavItemType[],
144137
navSecondary: [
145138
{
146139
title: 'Support',
@@ -152,7 +145,7 @@ const props = defineProps(['name'])
152145
url: '#',
153146
icon: Send,
154147
},
155-
] as NavItem[],
148+
] as NavItemType[],
156149
projects: [
157150
{
158151
name: 'Design Engineering',

resources/js/composables/useAppearance.ts

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,51 @@
11
import { ref, watch, onMounted } from 'vue'
22
import { usePage } from '@inertiajs/vue3'
3-
import axios from 'axios'
43

54
type Appearance = 'light' | 'dark' | 'system'
65

6+
export function updateTheme(value: Appearance) {
7+
if (value === 'system') {
8+
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
9+
document.documentElement.classList.toggle('dark', systemTheme === 'dark')
10+
} else {
11+
document.documentElement.classList.toggle('dark', value === 'dark')
12+
}
13+
}
14+
15+
export function initializeTheme() {
16+
// Initialize theme from saved preference or default to system
17+
const savedAppearance = localStorage.getItem('appearance') as Appearance | null
18+
if (savedAppearance) {
19+
updateTheme(savedAppearance)
20+
} else {
21+
updateTheme('system')
22+
}
23+
24+
// Set up system theme change listener
25+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
26+
mediaQuery.addEventListener('change', () => {
27+
const currentAppearance = localStorage.getItem('appearance') as Appearance | null
28+
if (!currentAppearance || currentAppearance === 'system') {
29+
updateTheme('system')
30+
}
31+
})
32+
}
33+
734
export function useAppearance() {
835
const appearance = ref<Appearance>('system')
936

10-
// Initialize appearance from user preferences or system
1137
onMounted(() => {
38+
initializeTheme()
1239
const savedAppearance = localStorage.getItem('appearance') as Appearance | null
1340
if (savedAppearance) {
1441
appearance.value = savedAppearance
15-
updateTheme(savedAppearance)
1642
}
1743
})
1844

19-
// Update theme based on appearance setting
20-
function updateTheme(value: Appearance) {
21-
if (value === 'system') {
22-
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
23-
document.documentElement.classList.toggle('dark', systemTheme === 'dark')
24-
} else {
25-
document.documentElement.classList.toggle('dark', value === 'dark')
26-
}
27-
}
28-
29-
// Handle system theme changes
30-
onMounted(() => {
31-
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
32-
mediaQuery.addEventListener('change', () => {
33-
if (appearance.value === 'system') {
34-
updateTheme('system')
35-
}
36-
})
37-
})
38-
39-
// Update appearance preference
40-
async function updateAppearance(value: Appearance) {
45+
function updateAppearance(value: Appearance) {
4146
appearance.value = value
4247
localStorage.setItem('appearance', value)
4348
updateTheme(value)
44-
45-
// Update user preference in backend if authenticated
46-
const { auth } = usePage().props
47-
if (auth?.user) {
48-
await axios.patch(route('settings.appearance'), { appearance: value })
49-
}
5049
}
5150

5251
return {

resources/js/layouts/AppLayout.vue

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ import {
1717
SidebarTrigger,
1818
} from '@/components/ui/sidebar';
1919
20-
interface BreadcrumbItem {
21-
title: string;
22-
href: string;
23-
}
24-
2520
interface Props {
2621
breadcrumbs?: BreadcrumbItemType[];
2722
}

0 commit comments

Comments
 (0)