Update
This commit is contained in:
@@ -71,14 +71,14 @@ public function searchMemes(Request $request)
|
|||||||
->where(function ($q) use ($query) {
|
->where(function ($q) use ($query) {
|
||||||
// Search in name and description using ILIKE for partial matches
|
// Search in name and description using ILIKE for partial matches
|
||||||
$q->where('name', 'ILIKE', "%{$query}%")
|
$q->where('name', 'ILIKE', "%{$query}%")
|
||||||
->orWhere('description', 'ILIKE', "%{$query}%")
|
->orWhere('description', 'ILIKE', "%{$query}%")
|
||||||
// Search in JSON arrays using PostgreSQL JSON operators
|
// Search in JSON arrays using PostgreSQL JSON operators
|
||||||
->orWhereRaw("keywords::text ILIKE ?", ["%{$query}%"])
|
->orWhereRaw('keywords::text ILIKE ?', ["%{$query}%"])
|
||||||
->orWhereRaw("action_keywords::text ILIKE ?", ["%{$query}%"])
|
->orWhereRaw('action_keywords::text ILIKE ?', ["%{$query}%"])
|
||||||
->orWhereRaw("emotion_keywords::text ILIKE ?", ["%{$query}%"])
|
->orWhereRaw('emotion_keywords::text ILIKE ?', ["%{$query}%"])
|
||||||
->orWhereRaw("misc_keywords::text ILIKE ?", ["%{$query}%"]);
|
->orWhereRaw('misc_keywords::text ILIKE ?', ["%{$query}%"]);
|
||||||
})
|
})
|
||||||
->orderByRaw("
|
->orderByRaw('
|
||||||
CASE
|
CASE
|
||||||
WHEN name ILIKE ? THEN 1
|
WHEN name ILIKE ? THEN 1
|
||||||
WHEN description ILIKE ? THEN 2
|
WHEN description ILIKE ? THEN 2
|
||||||
@@ -88,7 +88,7 @@ public function searchMemes(Request $request)
|
|||||||
WHEN misc_keywords::text ILIKE ? THEN 6
|
WHEN misc_keywords::text ILIKE ? THEN 6
|
||||||
ELSE 7
|
ELSE 7
|
||||||
END, name ASC
|
END, name ASC
|
||||||
", ["%{$query}%", "%{$query}%", "%{$query}%", "%{$query}%", "%{$query}%", "%{$query}%"])
|
', ["%{$query}%", "%{$query}%", "%{$query}%", "%{$query}%", "%{$query}%", "%{$query}%"])
|
||||||
->take($limit)
|
->take($limit)
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
@@ -115,12 +115,12 @@ public function searchBackgrounds(Request $request)
|
|||||||
// Search in prompt field using ILIKE for partial matches
|
// Search in prompt field using ILIKE for partial matches
|
||||||
$backgrounds = BackgroundMedia::where('status', 'completed')
|
$backgrounds = BackgroundMedia::where('status', 'completed')
|
||||||
->where('prompt', 'ILIKE', "%{$query}%")
|
->where('prompt', 'ILIKE', "%{$query}%")
|
||||||
->orderByRaw("
|
->orderByRaw('
|
||||||
CASE
|
CASE
|
||||||
WHEN prompt ILIKE ? THEN 1
|
WHEN prompt ILIKE ? THEN 1
|
||||||
ELSE 2
|
ELSE 2
|
||||||
END, prompt ASC
|
END, prompt ASC
|
||||||
", ["%{$query}%"])
|
', ["%{$query}%"])
|
||||||
->take($limit)
|
->take($limit)
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ErrorBoundary } from 'react-error-boundary';
|
|||||||
import { GA4Provider } from '@/plugins/GA4Context.jsx'; // Updated import
|
import { GA4Provider } from '@/plugins/GA4Context.jsx'; // Updated import
|
||||||
import DetailedErrorFallback from './components/custom/detailed-error-fallback'; // Import your component
|
import DetailedErrorFallback from './components/custom/detailed-error-fallback'; // Import your component
|
||||||
import { Toaster } from './components/ui/sonner';
|
import { Toaster } from './components/ui/sonner';
|
||||||
import { initializeTheme } from './hooks/use-appearance';
|
import { useTheme } from './hooks/useTheme';
|
||||||
import AuthDialog from './modules/auth/AuthDialog';
|
import AuthDialog from './modules/auth/AuthDialog';
|
||||||
import { AxiosProvider } from './plugins/AxiosContext';
|
import { AxiosProvider } from './plugins/AxiosContext';
|
||||||
import { MittProvider } from './plugins/MittContext';
|
import { MittProvider } from './plugins/MittContext';
|
||||||
@@ -56,4 +56,4 @@ createInertiaApp({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
initializeTheme();
|
// Theme is now handled by useTheme hook in components
|
||||||
|
|||||||
61
resources/js/hooks/useTheme.js
Normal file
61
resources/js/hooks/useTheme.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export function useTheme() {
|
||||||
|
const [theme, setTheme] = useState('system');
|
||||||
|
const [isDark, setIsDark] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Get theme from session storage or default to system
|
||||||
|
const savedTheme = sessionStorage.getItem('theme') || 'system';
|
||||||
|
setTheme(savedTheme);
|
||||||
|
|
||||||
|
const updateTheme = (themeValue) => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
if (themeValue === 'system') {
|
||||||
|
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
setIsDark(systemPrefersDark);
|
||||||
|
root.classList.toggle('dark', systemPrefersDark);
|
||||||
|
} else {
|
||||||
|
const shouldBeDark = themeValue === 'dark';
|
||||||
|
setIsDark(shouldBeDark);
|
||||||
|
root.classList.toggle('dark', shouldBeDark);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply initial theme
|
||||||
|
updateTheme(savedTheme);
|
||||||
|
|
||||||
|
// Listen for system theme changes when using system theme
|
||||||
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
const handleSystemThemeChange = () => {
|
||||||
|
if (theme === 'system') {
|
||||||
|
updateTheme('system');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mediaQuery.removeEventListener('change', handleSystemThemeChange);
|
||||||
|
};
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
const toggleTheme = () => {
|
||||||
|
const newTheme = isDark ? 'light' : 'dark';
|
||||||
|
setTheme(newTheme);
|
||||||
|
sessionStorage.setItem('theme', newTheme);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetToSystem = () => {
|
||||||
|
setTheme('system');
|
||||||
|
sessionStorage.removeItem('theme');
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
theme,
|
||||||
|
isDark,
|
||||||
|
toggleTheme,
|
||||||
|
resetToSystem,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -77,15 +77,17 @@ const FAQDiscord = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a
|
{import.meta.env.VITE_DISCORD_LINK && (
|
||||||
href="https://discord.gg/YxKPrtPGZ2"
|
<a
|
||||||
target="_blank"
|
href={import.meta.env.VITE_DISCORD_LINK}
|
||||||
rel="noopener noreferrer"
|
target="_blank"
|
||||||
className="inline-flex items-center justify-center gap-2 rounded-full bg-[#5865F2] px-8 py-3 text-lg font-semibold text-white shadow-lg transition-all hover:bg-[#4752C4] hover:shadow-xl focus:ring-2 focus:ring-[#5865F2] focus:ring-offset-2 focus:outline-none"
|
rel="noopener noreferrer"
|
||||||
>
|
className="inline-flex items-center justify-center gap-2 rounded-full bg-[#5865F2] px-8 py-3 text-lg font-semibold text-white shadow-lg transition-all hover:bg-[#4752C4] hover:shadow-xl focus:ring-2 focus:ring-[#5865F2] focus:ring-offset-2 focus:outline-none"
|
||||||
Join Discord
|
>
|
||||||
<ExternalLinkIcon className="h-5 w-5" />
|
Join Discord
|
||||||
</a>
|
<ExternalLinkIcon className="h-5 w-5" />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { useTheme } from '@/hooks/useTheme';
|
||||||
|
import { Sun, Moon } from 'lucide-react';
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
|
const { isDark, toggleTheme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="pt-10">
|
<section className="pt-10">
|
||||||
@@ -7,7 +12,16 @@ const Footer = () => {
|
|||||||
<div className="border-t pt-8">
|
<div className="border-t pt-8">
|
||||||
<div className="flex flex-col items-center justify-between space-y-4 sm:flex-row sm:space-y-0">
|
<div className="flex flex-col items-center justify-between space-y-4 sm:flex-row sm:space-y-0">
|
||||||
<div className="text-muted-foreground text-sm">© {currentYear} MEMEFAST. All rights reserved.</div>
|
<div className="text-muted-foreground text-sm">© {currentYear} MEMEFAST. All rights reserved.</div>
|
||||||
<div className="flex space-x-6">
|
<div className="flex flex-col items-center space-y-4 sm:flex-row sm:space-y-0 sm:space-x-6">
|
||||||
|
{/* Theme Toggle */}
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Sun className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<Switch id="dark-mode" checked={isDark} onCheckedChange={toggleTheme} />
|
||||||
|
<Moon className="h-4 w-4 text-muted-foreground" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Navigation Links */}
|
||||||
|
<div className="flex space-x-6">
|
||||||
<a href="/" className="text-muted-foreground hover:text-foreground text-sm transition-colors">
|
<a href="/" className="text-muted-foreground hover:text-foreground text-sm transition-colors">
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
@@ -17,14 +31,17 @@ const Footer = () => {
|
|||||||
<a href="/privacy" className="text-muted-foreground hover:text-foreground text-sm transition-colors">
|
<a href="/privacy" className="text-muted-foreground hover:text-foreground text-sm transition-colors">
|
||||||
Privacy
|
Privacy
|
||||||
</a>
|
</a>
|
||||||
<a
|
{import.meta.env.VITE_DISCORD_LINK && (
|
||||||
href="https://discord.gg/YxKPrtPGZ2"
|
<a
|
||||||
target="_blank"
|
href={import.meta.env.VITE_DISCORD_LINK}
|
||||||
rel="noopener noreferrer"
|
target="_blank"
|
||||||
className="text-muted-foreground hover:text-foreground text-sm transition-colors"
|
rel="noopener noreferrer"
|
||||||
>
|
className="text-muted-foreground hover:text-foreground text-sm transition-colors"
|
||||||
Discord
|
>
|
||||||
</a>
|
Discord
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,21 +1,22 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
|
{{-- Inline script to detect theme preference and apply it immediately to prevent flash --}}
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
const appearance = '{{ $appearance ?? 'system' }}';
|
const savedTheme = sessionStorage.getItem('theme') || 'system';
|
||||||
|
|
||||||
if (appearance === 'system') {
|
if (savedTheme === 'system') {
|
||||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
if (prefersDark) {
|
if (prefersDark) {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
}
|
}
|
||||||
|
} else if (savedTheme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user