feat: implement dynamic viewport theme color management and update meta tag
This commit is contained in:
8
app/components/DynamicViewportTheme.tsx
Normal file
8
app/components/DynamicViewportTheme.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useViewportThemeColor } from '@/hooks/use-viewport-theme-color';
|
||||||
|
|
||||||
|
export default function DynamicViewportTheme() {
|
||||||
|
useViewportThemeColor();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -7,12 +7,8 @@ import { NavidromeConfigProvider } from "./components/NavidromeConfigContext";
|
|||||||
import { ThemeProvider } from "./components/ThemeProvider";
|
import { ThemeProvider } from "./components/ThemeProvider";
|
||||||
import { PostHogProvider } from "./components/PostHogProvider";
|
import { PostHogProvider } from "./components/PostHogProvider";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import type { Viewport } from 'next';
|
|
||||||
import Ihateserverside from './components/ihateserverside';
|
import Ihateserverside from './components/ihateserverside';
|
||||||
|
import DynamicViewportTheme from './components/DynamicViewportTheme';
|
||||||
export const viewport: Viewport = {
|
|
||||||
themeColor: 'black',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
@@ -70,6 +66,17 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set initial theme color based on theme
|
||||||
|
const themeColors = {
|
||||||
|
blue: '#0f0f23',
|
||||||
|
violet: '#0c0a2e'
|
||||||
|
};
|
||||||
|
|
||||||
|
const metaThemeColor = document.createElement('meta');
|
||||||
|
metaThemeColor.name = 'theme-color';
|
||||||
|
metaThemeColor.content = themeColors[theme];
|
||||||
|
document.head.appendChild(metaThemeColor);
|
||||||
})();
|
})();
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
@@ -78,6 +85,7 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased bg-background`}>
|
<body className={`${geistSans.variable} ${geistMono.variable} antialiased bg-background`}>
|
||||||
<PostHogProvider>
|
<PostHogProvider>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
|
<DynamicViewportTheme />
|
||||||
<NavidromeConfigProvider>
|
<NavidromeConfigProvider>
|
||||||
<NavidromeProvider>
|
<NavidromeProvider>
|
||||||
<AudioPlayerProvider>
|
<AudioPlayerProvider>
|
||||||
|
|||||||
29
hooks/use-viewport-theme-color.ts
Normal file
29
hooks/use-viewport-theme-color.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useTheme } from '@/app/components/ThemeProvider';
|
||||||
|
import { getThemeBackgroundColor } from '@/lib/theme-colors';
|
||||||
|
|
||||||
|
export function useViewportThemeColor() {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Update the theme-color meta tag dynamically
|
||||||
|
const updateThemeColor = () => {
|
||||||
|
const themeColor = getThemeBackgroundColor(theme);
|
||||||
|
|
||||||
|
// Find existing theme-color meta tag or create one
|
||||||
|
let metaThemeColor = document.querySelector('meta[name="theme-color"]') as HTMLMetaElement;
|
||||||
|
|
||||||
|
if (!metaThemeColor) {
|
||||||
|
metaThemeColor = document.createElement('meta');
|
||||||
|
metaThemeColor.name = 'theme-color';
|
||||||
|
document.head.appendChild(metaThemeColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
metaThemeColor.content = themeColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
updateThemeColor();
|
||||||
|
}, [theme]);
|
||||||
|
}
|
||||||
29
lib/theme-colors.ts
Normal file
29
lib/theme-colors.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Theme color utilities for dynamic viewport theme color
|
||||||
|
|
||||||
|
export const themeColors = {
|
||||||
|
blue: {
|
||||||
|
background: 'hsl(240, 10%, 3.9%)', // Dark blue background
|
||||||
|
hex: '#0f0f23' // Hex equivalent for theme-color
|
||||||
|
},
|
||||||
|
violet: {
|
||||||
|
background: 'hsl(224, 71.4%, 4.1%)', // Dark violet background
|
||||||
|
hex: '#0c0a2e' // Hex equivalent for theme-color
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type Theme = keyof typeof themeColors;
|
||||||
|
|
||||||
|
export function getThemeBackgroundColor(theme: Theme): string {
|
||||||
|
return themeColors[theme].hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hslToHex(h: number, s: number, l: number): string {
|
||||||
|
l /= 100;
|
||||||
|
const a = s * Math.min(l, 1 - l) / 100;
|
||||||
|
const f = (n: number) => {
|
||||||
|
const k = (n + h / 30) % 12;
|
||||||
|
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
||||||
|
return Math.round(255 * color).toString(16).padStart(2, '0');
|
||||||
|
};
|
||||||
|
return `#${f(0)}${f(8)}${f(4)}`;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user