diff --git a/app/Http/Controllers/LeaderboardController.php b/app/Http/Controllers/LeaderboardController.php index b61d5260..8ae7c2a2 100644 --- a/app/Http/Controllers/LeaderboardController.php +++ b/app/Http/Controllers/LeaderboardController.php @@ -18,10 +18,10 @@ public function index(Request $request): Response $timeframe = in_array($request->input('timeframe'), ['this_week', 'this_month', 'all_time'], true) ? $request->input('timeframe') - : 'this_week'; + : 'this_month'; $dateFilter = match ($timeframe) { - 'this_week' => Carbon::now()->startOfWeek()->toDateString(), + 'this_week' => Carbon::now()->startOfWeek(Carbon::SATURDAY)->toDateString(), 'this_month' => Carbon::now()->startOfMonth()->toDateString(), 'all_time' => null, }; diff --git a/resources/js/components/navigation/Navigation.tsx b/resources/js/components/navigation/Navigation.tsx index 31bc0064..6bd25cf2 100644 --- a/resources/js/components/navigation/Navigation.tsx +++ b/resources/js/components/navigation/Navigation.tsx @@ -221,7 +221,7 @@ export const SiteRail = defineComponent({ const canAccessAdmin = computed(() => staffAccess(page.props.auth)); const currentUrl = computed(() => String(page.url)); - const { theme, toggle, setTheme } = useDarkMode(); + const { theme, toggle } = useDarkMode(); const showLogoutModal = ref(false); const notifRowRef = ref(null); const { deferredPrompt, isInstalled, promptInstall } = usePwa(); @@ -727,71 +727,13 @@ export const SiteRail = defineComponent({ ) : ( /* Expanded footer (w-[264px]) */
- {/* Appearance */} -
-

- Appearance -

-
- - - -
-
- - {/* Notifications */} + {/* Notifications & Theme Toggle (Inline) */} {user.value && (
- - @@ -811,10 +753,36 @@ export const SiteRail = defineComponent({ ); } }} - class="flex-1 cursor-pointer truncate text-left text-[13px] font-semibold text-slate-600 transition-colors hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-100" + class="flex min-w-0 flex-1 cursor-pointer items-center gap-2.5" > - Notifications - + + + Notifications + +
+ +
)} @@ -837,17 +805,38 @@ export const SiteRail = defineComponent({ {/* Auth */}
{!user.value ? ( - - - Login - +
+ + + Login + + +
) : (
url.startsWith('/chat'), showInBottom: true, }, + { + label: 'Leaderboard', + labelBn: 'লিডারবোর্ড', + href: '/leaderboard', + icon: 'leaderboard', + match: (url) => url.startsWith('/leaderboard'), + showInBottom: false, + }, { label: 'AI', labelBn: 'HSCStack AI', @@ -68,13 +76,6 @@ export const primaryNavItems: NavItem[] = [ ]; export const overflowNavItems: NavItem[] = [ - { - label: 'Leaderboard', - labelBn: 'লিডারবোর্ড', - href: '/leaderboard', - icon: 'leaderboard', - match: (url) => url.startsWith('/leaderboard'), - }, { label: 'Support Center', href: '/support', diff --git a/resources/js/pages/Leaderboard/Index.vue b/resources/js/pages/Leaderboard/Index.vue index 783f82f2..ae91836f 100644 --- a/resources/js/pages/Leaderboard/Index.vue +++ b/resources/js/pages/Leaderboard/Index.vue @@ -2,14 +2,18 @@ import { Head, Link, router } from '@inertiajs/vue3'; import { Award, + Calendar, Clock, Crown, Flame, + Info, Medal, + ShieldCheck, Trophy, UploadCloud, } from 'lucide-vue-next'; -import { computed } from 'vue'; +import { computed, onBeforeUnmount, ref } from 'vue'; +import BaseModal from '@/components/BaseModal.vue'; import VerifiedBadge from '@/components/VerifiedBadge.vue'; import { useAuth } from '@/lib/useAuth'; @@ -105,6 +109,34 @@ const podiumUsers = computed(() => { { user: third, place: 3 }, ]; }); + +const highlightedUserId = ref(null); +let highlightTimeout: ReturnType | null = null; +const showInfoModal = ref(false); + +function highlightUserInList(userId: number) { + highlightedUserId.value = userId; + + if (highlightTimeout) { + clearTimeout(highlightTimeout); + } + + const element = document.getElementById(`leaderboard-row-${userId}`); + + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + + highlightTimeout = setTimeout(() => { + highlightedUserId.value = null; + }, 1800); +} + +onBeforeUnmount(() => { + if (highlightTimeout) { + clearTimeout(highlightTimeout); + } +});
@@ -487,12 +561,15 @@ const podiumUsers = computed(() => { @@ -593,4 +670,162 @@ const podiumUsers = computed(() => {
+ + + + + +
+ +
+
+ +

শীর্ষ শিক্ষার্থী কীভাবে নির্ধারিত হয়?

+
+

+ স্টাডি ট্র্যাকারে (/tracker) স্টপওয়াচ অথবা ম্যানুয়াল সময় লগিংয়ের মাধ্যমে রেকর্ড করা + মোট পড়াশোনার সময় অনুসারে শিক্ষার্থীদের র‍্যাঙ্ক দেওয়া হয়। +

+
+ + +
+
+ +

শীর্ষ কন্ট্রিবিউটর কীভাবে নির্ধারিত হয়?

+
+

+ এইচএসসি ও এসএসসি সিলেবাসের বিভিন্ন অধ্যায়ে সহপাঠীদের জন্য + অনুমোদিত স্টাডি নোট, প্রশ্নব্যাংক ও রিসোর্স আপলোডের সংখ্যার + ভিত্তিতে কন্ট্রিবিউটর তালিকা প্রস্তুত হয়। +

+
+ + +
+
+ +

সময়সীমা গণনা

+
+
    +
  • + এই সপ্তাহ: + বাংলাদেশের ক্যালেন্ডার অনুযায়ী প্রতি + শনিবার রাত ১২:০০ (00:00 AM) থেকে শুরু + হয়ে বর্তমান সময় পর্যন্ত। +
  • +
  • + এই মাস: + চলতি ক্যালেন্ডার মাসের + ১ তারিখ রাত ১২:০০ থেকে বর্তমান সময় + পর্যন্ত (ডিফল্ট ফিল্টার)। +
  • +
  • + সর্বকালের: + অ্যাকাউন্ট তৈরির পর থেকে সম্পূর্ণ মোট রেকর্ড। +
  • +
+
+ + +
+
+ +

র‍্যাঙ্কিং টাই ও সুরক্ষা

+
+
    +
  • + টাই র‍্যাঙ্কিং: + একাধিক শিক্ষার্থীর পড়াশোনার সময় বা রিসোর্স সংখ্যা হুবহু + সমান হলে তারা একই র‍্যাঙ্ক অবস্থান শেয়ার করে। +
  • +
  • + দৈনিক ক্যাপ: + অবাস্তব সময় যোগ রোধ করতে এক ক্যালেন্ডার দিনে সর্বোচ্চ ২৪ + ঘণ্টার বেশি লগ করা সম্ভব নয়। +
  • +
  • + প্রাইভেসি সেটিং: + প্রোফাইল থেকে Activity Privacy ‘Private’ করা থাকলে + লিডারবোর্ডে নাম ও রেকর্ড গোপন রাখা হয়। +
  • +
+
+
+ + +
diff --git a/resources/js/pages/Peers/Index.vue b/resources/js/pages/Peers/Index.vue index 8f91f753..19007350 100644 --- a/resources/js/pages/Peers/Index.vue +++ b/resources/js/pages/Peers/Index.vue @@ -211,32 +211,32 @@ const togglePeerAppreciation = (peer: Peer) => {
-
-
+
+
-
+

Find Peers

- সহপাঠী ও অন্য প্রতিষ্ঠানের শিক্ষার্থীদের সাথে যুক্ত - হোন + সহপাঠী ও অন্য শিক্ষার্থীদের সাথে যুক্ত হোন

Leaderboard