From d7e4a429b9f5b7eaa79879ff9ca6a1dcbb9b941a Mon Sep 17 00:00:00 2001 From: Tahsin Shahriar Date: Thu, 13 Aug 2026 19:32:59 +0600 Subject: [PATCH] feat: add dark mode Because apparently the white background was burning everyone's retinas and someone had to do something about it. - System/Light/Dark toggle in navbar (cycles through all three) - Cross-tab sync via localStorage - Follows OS preference by default - Flash prevention on page load - CSS overrides for dynamic subject colors (those bg-red-50 text-red-600 icons that looked terrible in dark) - Every component, page, layout, modal, toast, and FAQ accordion updated - Light shadow glow fixes (goodbye cringey white halos) Actual redesign and modernization coming soon. This is just the band-aid. --- resources/css/app.css | 81 ++++++++ resources/js/app.ts | 11 + resources/js/components/AIBanner.vue | 10 +- resources/js/components/AppLogo.vue | 17 +- resources/js/components/BlogCard.vue | 28 ++- resources/js/components/BlogRow.vue | 22 +- resources/js/components/BreadcrumbNav.vue | 12 +- resources/js/components/CourseSwitcher.vue | 10 +- resources/js/components/EmptyState.vue | 6 +- resources/js/components/FAQSection.vue | 42 ++-- resources/js/components/Footer.vue | 64 +++--- resources/js/components/HTMLEditor.vue | 25 ++- resources/js/components/HomeHeader.vue | 10 +- resources/js/components/NavBar.vue | 30 ++- resources/js/components/NodeRow.vue | 12 +- resources/js/components/NoticeDialog.vue | 12 +- resources/js/components/PwaInstallPrompt.vue | 28 ++- resources/js/components/ResourceRow.vue | 12 +- resources/js/components/SubjectCard.vue | 10 +- resources/js/components/ToastNotification.vue | 10 +- resources/js/components/UserCard.vue | 38 ++-- .../js/components/admin/DesktopSidebar.vue | 26 +-- .../js/components/admin/MobileSideBar.vue | 18 +- resources/js/components/admin/NodeRow.vue | 10 +- resources/js/components/admin/ResourceRow.vue | 10 +- resources/js/components/admin/SubjectCard.vue | 28 +-- resources/js/components/admin/UserRow.vue | 36 ++-- resources/js/layouts/AdminLayout.vue | 16 +- resources/js/layouts/AppLayout.vue | 10 +- resources/js/lib/useDarkMode.ts | 83 ++++++++ resources/js/pages/Blog/Index.vue | 40 ++-- resources/js/pages/Blog/Show.vue | 56 +++-- resources/js/pages/ContributorGuide.vue | 194 ++++++++++-------- resources/js/pages/Home.vue | 14 +- resources/js/pages/Node.vue | 14 +- resources/js/pages/Resource.vue | 87 ++++---- resources/js/pages/Support.vue | 86 +++++--- resources/js/pages/admin/Blog.vue | 16 +- resources/js/pages/admin/BlogCreateOrEdit.vue | 58 +++--- resources/js/pages/admin/Dashboard.vue | 74 ++++--- resources/js/pages/admin/Index.vue | 16 +- resources/js/pages/admin/Node.vue | 32 +-- resources/js/pages/admin/NodeCreateOrEdit.vue | 56 +++-- resources/js/pages/admin/NoticeEdit.vue | 76 ++++--- .../js/pages/admin/ResourceCreateOrEdit.vue | 72 ++++--- .../js/pages/admin/SubjectCreateOrEdit.vue | 58 +++--- .../pages/admin/resources/BulkImageCreate.vue | 94 +++++---- .../pages/admin/resources/BulkVideoCreate.vue | 94 +++++---- .../js/pages/admin/users/CreateOrEdit.vue | 118 ++++++----- resources/js/pages/admin/users/Index.vue | 24 ++- resources/js/pages/ai/Index.vue | 80 ++++---- resources/js/pages/auth/Login.vue | 40 ++-- resources/js/pages/errors/404.vue | 42 ++-- resources/js/pages/errors/503.vue | 42 ++-- resources/js/pages/legal/ContentPolicy.vue | 118 ++++++----- resources/js/pages/legal/PrivacyPolicy.vue | 90 ++++---- resources/js/pages/legal/TermsConditions.vue | 64 +++--- resources/js/pages/platform/AboutUs.vue | 14 +- resources/js/pages/platform/JoinTeam.vue | 68 +++--- 59 files changed, 1535 insertions(+), 1029 deletions(-) create mode 100644 resources/js/lib/useDarkMode.ts diff --git a/resources/css/app.css b/resources/css/app.css index 9fde97c..f12718b 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -23,8 +23,89 @@ 'Noto Color Emoji'; } +@custom-variant dark (&:where(.dark, .dark *)); + @layer base { body { font-stretch: 96%; + @apply transition-colors duration-300; } } + +.dark .bg-red-50 { + background-color: rgb(239 68 68 / 0.1); +} +.dark .bg-red-100 { + background-color: rgb(239 68 68 / 0.15); +} +.dark .text-red-600 { + color: rgb(248 113 113); +} +.dark .text-red-700 { + color: rgb(252 165 165); +} + +.dark .bg-blue-50 { + background-color: rgb(59 130 246 / 0.1); +} +.dark .bg-blue-100 { + background-color: rgb(59 130 246 / 0.15); +} +.dark .text-blue-600 { + color: rgb(96 165 250); +} +.dark .text-blue-700 { + color: rgb(147 197 253); +} + +.dark .bg-purple-50 { + background-color: rgb(168 85 247 / 0.1); +} +.dark .bg-purple-100 { + background-color: rgb(168 85 247 / 0.15); +} +.dark .text-purple-600 { + color: rgb(192 132 252); +} +.dark .text-purple-700 { + color: rgb(216 180 254); +} + +.dark .bg-emerald-50 { + background-color: rgb(16 185 129 / 0.1); +} +.dark .bg-emerald-100 { + background-color: rgb(16 185 129 / 0.15); +} +.dark .text-emerald-600 { + color: rgb(52 211 153); +} +.dark .text-emerald-700 { + color: rgb(110 231 183); +} + +.dark .bg-amber-50 { + background-color: rgb(245 158 11 / 0.1); +} +.dark .bg-amber-100 { + background-color: rgb(245 158 11 / 0.15); +} +.dark .text-amber-600 { + color: rgb(251 191 36); +} +.dark .text-amber-700 { + color: rgb(252 211 77); +} + +.dark .bg-green-50 { + background-color: rgb(34 197 94 / 0.1); +} +.dark .bg-green-100 { + background-color: rgb(34 197 94 / 0.15); +} +.dark .text-green-600 { + color: rgb(74 222 128); +} +.dark .text-green-700 { + color: rgb(134 239 172); +} diff --git a/resources/js/app.ts b/resources/js/app.ts index 3894fea..787b2ac 100644 --- a/resources/js/app.ts +++ b/resources/js/app.ts @@ -5,6 +5,17 @@ import AppLayout from './layouts/AppLayout.vue'; const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; +// Apply dark mode before paint to prevent flash +const stored = localStorage.getItem('theme'); + +if ( + stored === 'dark' || + (stored !== 'light' && + window.matchMedia('(prefers-color-scheme: dark)').matches) +) { + document.documentElement.classList.add('dark'); +} + registerSW({ immediate: true }); createInertiaApp({ diff --git a/resources/js/components/AIBanner.vue b/resources/js/components/AIBanner.vue index 8fc5b03..e7da5e7 100644 --- a/resources/js/components/AIBanner.vue +++ b/resources/js/components/AIBanner.vue @@ -6,11 +6,11 @@ import { Sparkles, ArrowRight } from 'lucide-vue-next';