Skip to content

Commit efaef93

Browse files
committed
feat: [LAR-150] add forum leaderboard page
1 parent aa3ab10 commit efaef93

File tree

27 files changed

+397
-166
lines changed

27 files changed

+397
-166
lines changed

app/Livewire/Reactions.php renamed to app/Livewire/Components/Reactions.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace App\Livewire;
5+
namespace App\Livewire\Components;
66

77
use App\Contracts\ReactableInterface;
88
use App\Models\Reaction;
@@ -40,6 +40,6 @@ public function userReacted(string $reaction): void
4040

4141
public function render(): View
4242
{
43-
return view('livewire.reactions');
43+
return view('livewire.components.reactions');
4444
}
4545
}

app/Livewire/ReportSpam.php renamed to app/Livewire/Components/ReportSpam.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace App\Livewire;
5+
namespace App\Livewire\Components;
66

77
use App\Actions\ReportSpamAction;
88
use App\Contracts\SpamReportableContract;

app/Livewire/Pages/Forum/Index.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ final class Index extends Component
2424
use WithoutUrlPagination;
2525
use WithPagination;
2626

27-
#[Url(as: 'channel')]
27+
#[Url]
2828
public ?string $channel = null;
2929

30-
#[Url(as: 'solved')]
30+
#[Url]
3131
public ?string $solved = null;
3232

3333
#[Url(as: 'me')]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Livewire\Pages\Forum;
6+
7+
use App\Models\User;
8+
use Illuminate\Contracts\View\View;
9+
use Illuminate\Support\Facades\Cache;
10+
use Livewire\Attributes\Layout;
11+
use Livewire\Component;
12+
13+
#[Layout('layouts.forum')]
14+
final class Leaderboard extends Component
15+
{
16+
public function render(): View
17+
{
18+
return view('livewire.pages.forum.leaderboard', [
19+
'leaderboard' => Cache::remember(
20+
key: 'leaderboard',
21+
ttl: now()->addWeek(),
22+
callback: fn () => User::mostSolutionsInLastDays(365)
23+
->take(30)
24+
->get()
25+
->reject(fn ($leaderboard) => $leaderboard->solutions_count === 0) // @phpstan-ignore-line
26+
),
27+
]);
28+
}
29+
}

app/Models/User.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ public function countThreads(): int
420420
public function scopeMostSolutions(Builder $query, ?int $inLastDays = null): Builder
421421
{
422422
return $query->withCount(['replyAble as solutions_count' => function ($query) use ($inLastDays) {
423-
$query->where('replyable_type', 'threads')
423+
$query->where('replyable_type', 'thread')
424424
->join('threads', 'threads.solution_reply_id', '=', 'replies.id');
425425

426426
if ($inLastDays) {

app/View/Composers/TopMembersComposer.php

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

lang/en/global.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,10 @@
107107
'language' => 'Language',
108108
'french' => 'French',
109109
'english' => 'English',
110+
'experience' => 'Experience',
111+
'last_active' => 'Last active',
112+
'first_place' => '1st place',
113+
'second_place' => '2nd place',
114+
'third_place' => '3rd place',
110115

111116
];

lang/fr/global.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,10 @@
107107
'language' => 'Langue',
108108
'french' => 'Français',
109109
'english' => 'Anglais',
110+
'experience' => 'Expérience',
111+
'last_active' => 'Dernière activité',
112+
'first_place' => '1ere place',
113+
'second_place' => '2e place',
114+
'third_place' => '3e place',
115+
110116
];

resources/css/app.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66
@import 'tag.css';
77
@import 'forms.css';
88
@import 'torchlight.css';
9-
@import 'toc.css';
9+
@import 'forum.css';
1010
@import 'header.css';
1111

12+
@property --border-angle {
13+
inherits: false;
14+
initial-value: 0deg;
15+
syntax: '<angle>';
16+
}
17+
1218
:root {
1319
--laravel: #F56857;
1420
--livewire: #fb70a9;

resources/css/file-upload.css

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

resources/css/forum.css

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#leaderboard {
2+
*, *::before, *::after {
3+
box-sizing: border-box;
4+
transform-style: preserve-3d;
5+
}
6+
7+
.leaderboard {
8+
place-items: center;
9+
transform: perspective(400px);
10+
transform-style: preserve-3d;
11+
}
12+
13+
.leaderboard > .stage {
14+
@apply relative w-full rounded-t-lg;
15+
transform: rotateX(70deg);
16+
}
17+
18+
.leaderboard > .stage > .stage-front {
19+
@apply absolute w-full rounded-b-lg origin-top top-full;
20+
transform: rotateX(-80deg);
21+
}
22+
}

resources/css/toc.css

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
@props([
2+
'user',
3+
'position',
4+
])
5+
6+
@php
7+
$icon = match ($position) {
8+
1 => 'icon.trophies.first',
9+
2 => 'icon.trophies.second',
10+
3 => 'icon.trophies.third',
11+
default => 'phosphor-trophy-duotone',
12+
};
13+
14+
$ranking = match ($position) {
15+
1 => __('global.first_place'),
16+
2 => __('global.second_place'),
17+
3 => __('global.third_place'),
18+
default => 'N/A',
19+
};
20+
21+
$color = match ($position) {
22+
1 => 'success',
23+
2 => 'warning',
24+
3 => 'danger',
25+
default => 'gray',
26+
};
27+
@endphp
28+
29+
<div class="bg-white divide-y divide-gray-200 rounded-lg ring-1 ring-gray-200 dark:bg-gray-800 dark:ring-white/10 dark:divide-white/10">
30+
<div class="flex gap-4 p-4">
31+
<div class="relative flex-1 flex items-center gap-2">
32+
<x-filament::badge :color="$color" class="absolute -top-7 !rounded-full">
33+
{{ $ranking }}
34+
</x-filament::badge>
35+
<x-user.avatar :user="$user" class="size-7" />
36+
<div class="text-sm truncate">
37+
<h5 class="font-medium text-gray-900 truncate dark:text-white">
38+
{{ $user->name }}
39+
</h5>
40+
<span class="text-gray-500 dark:text-gray-400">
41+
{{ '@' . $user->username }}
42+
</span>
43+
</div>
44+
</div>
45+
<div>
46+
<x-dynamic-component :component="$icon" class="size-10" aria-hidden="true" />
47+
</div>
48+
</div>
49+
<div class="flex divide-x divide-gray-200 dark:divide-white/10">
50+
<div class="flex flex-col px-4 py-2.5">
51+
<span class="text-xs/4 text-gray-400 capitalize dark:text-gray-500">
52+
{{ __('global.experience') }}
53+
</span>
54+
<span class="font-medium text-sm text-gray-700 dark:text-gray-300">
55+
{{ $user->getPoints() }}
56+
</span>
57+
</div>
58+
<div class="flex flex-col px-4 py-2.5">
59+
<span class="text-xs/4 text-gray-400 capitalize dark:text-gray-500">
60+
{{ __('global.answers') }}
61+
</span>
62+
<span class="font-medium text-sm text-gray-700 dark:text-gray-300">
63+
{{ $user->solutions_count }}
64+
</span>
65+
</div>
66+
@if($position === 1)
67+
<div class="flex flex-col px-4 py-2.5">
68+
<span class="text-xs/4 text-gray-400 capitalize dark:text-gray-500">
69+
{{ __('global.last_active') }}
70+
</span>
71+
72+
<span class="font-medium text-sm text-gray-700 dark:text-gray-300">
73+
{{ $user->last_active_at?->diffForHumans() }}
74+
</span>
75+
</div>
76+
@else
77+
<div class="flex flex-col px-4 py-2.5 lg:hidden">
78+
<span class="text-xs/4 text-gray-400 capitalize dark:text-gray-500">
79+
{{ __('global.last_active') }}
80+
</span>
81+
82+
<span class="font-medium text-sm text-gray-700 dark:text-gray-300">
83+
{{ $user->last_active_at?->diffForHumans() }}
84+
</span>
85+
</div>
86+
@endif
87+
</div>
88+
</div>

resources/views/components/forum/thread.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class="inline-flex items-center rounded-xl gap-1 px-2 py-0.5 font-medium bg-prim
3636
</span>
3737
</x-link>
3838
<span class="flex items-center text-xs text-gray-500 flex-wrap gap-1 dark:text-gray-400">
39-
<span>{{ __('global.ask') }}</span>
39+
<span class="hidden lg:inline">{{ __('global.ask') }}</span>
4040
<time datetime="{{ $thread->created_at }}">
4141
{{ $thread->created_at->diffForHumans() }}
4242
</time>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<svg {{ $attributes }} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
2+
<path style="fill:#eebf00" d="M226.716 185.146a7.793 7.793 0 0 1-7.426-5.447c-.412-1.255-10.945-31.918-55.359-46.907-47.912-16.167-70.235-51.221-61.245-96.171C107.46 12.756 127.613 1.07 145.469.075c19.917-1.106 36.542 9.99 42.375 28.279 4.403 13.804.808 23.239-2.983 28.722-11.089 16.042-36.005 17.793-38.81 17.938-4.309.25-7.962-3.075-8.187-7.371a7.789 7.789 0 0 1 7.366-8.186c5.534-.316 21.11-2.952 26.831-11.265 2.646-3.846 2.954-8.787.939-15.105-4.376-13.722-16.644-18.012-26.665-17.458-11.861.662-25.235 8.353-28.373 24.045-5.227 26.137-.631 60.948 50.949 78.353 52.277 17.642 64.73 55.38 65.234 56.978a7.79 7.79 0 0 1-5.083 9.774 7.634 7.634 0 0 1-2.346.367zM285.285 185.146a7.732 7.732 0 0 1-2.347-.364 7.79 7.79 0 0 1-5.084-9.774c.505-1.598 12.958-39.336 65.234-56.978 51.581-17.406 56.178-52.216 50.95-78.353-3.138-15.693-16.511-23.385-28.372-24.045-10.042-.572-22.289 3.736-26.665 17.457-2.015 6.319-1.709 11.26.938 15.107 5.724 8.317 21.316 10.951 26.841 11.264 4.289.243 7.58 3.914 7.345 8.202-.235 4.289-3.869 7.603-8.177 7.355-2.803-.146-27.719-1.897-38.808-17.938-3.79-5.483-7.385-14.918-2.982-28.722C329.99 10.07 346.625-1.025 366.532.078c17.856.995 38.011 12.682 42.783 36.546 8.989 44.95-13.334 80.003-61.245 96.171-44.866 15.14-55.259 46.591-55.359 46.907a7.792 7.792 0 0 1-7.426 5.444z"/>
3+
<path style="fill:#eebf00" d="m281.113 188.275 56.718-179.64H171.616l56.717 179.64c-25.937 10.457-44.251 35.845-44.251 65.526h141.282c0-29.681-18.314-55.069-44.251-65.526z"/>
4+
<path style="opacity:.11;fill:#640;enable-background:new" d="m281.113 188.275 56.718-179.64h-31.118l-56.717 179.64c25.937 10.457 44.251 35.845 44.251 65.526h31.118c-.001-29.681-18.315-55.069-44.252-65.526z"/>
5+
<path style="fill:#640" d="M375.108 285.818h-240.77c-10.401 0-18.911-8.509-18.911-18.911 0-10.401 8.51-18.911 18.911-18.911h240.771c10.401 0 18.911 8.51 18.911 18.911 0 10.401-8.511 18.911-18.912 18.911z"/>
6+
<path style="fill:#56361d" d="M385.523 251.107c.504 1.698.786 3.489.786 5.345 0 10.401-8.51 18.911-18.911 18.911h-240.77a18.755 18.755 0 0 1-10.341-3.111c2.321 7.818 9.58 13.567 18.125 13.567h240.771c10.401 0 18.911-8.51 18.911-18.911 0-6.591-3.423-12.413-8.571-15.801z"/>
7+
<path style="fill:#640" d="M375.108 511.943h-240.77c-10.401 0-18.911-8.51-18.911-18.911 0-10.401 8.51-18.911 18.911-18.911h240.771c10.401 0 18.911 8.509 18.911 18.911 0 10.401-8.511 18.911-18.912 18.911z"/>
8+
<path style="fill:#266659" d="M152.659 285.822h200.975v188.304H152.659z"/>
9+
<g style="opacity:.08">
10+
<path style="fill:#640" d="M337.831 8.635H171.616l8.806 27.891h148.602z"/>
11+
</g>
12+
<path style="fill:#eebf00" d="M187.807 348.327h130.774v56.91H187.807z"/>
13+
<path style="fill:#1f544a" d="M187.802 332.768a7.79 7.79 0 0 1-7.79-7.79v-13.837a7.79 7.79 0 1 1 15.58 0v13.837a7.788 7.788 0 0 1-7.79 7.79zM231.395 332.768a7.79 7.79 0 0 1-7.79-7.79v-13.837a7.79 7.79 0 1 1 15.58 0v13.837a7.79 7.79 0 0 1-7.79 7.79zM274.986 332.768a7.79 7.79 0 0 1-7.79-7.79v-13.837a7.79 7.79 0 0 1 7.79-7.79 7.79 7.79 0 0 1 7.79 7.79v13.837a7.788 7.788 0 0 1-7.79 7.79zM318.58 332.768a7.79 7.79 0 0 1-7.79-7.79v-13.837c0-4.303 3.487-7.79 7.79-7.79s7.79 3.487 7.79 7.79v13.837a7.788 7.788 0 0 1-7.79 7.79zM187.802 452.696a7.79 7.79 0 0 1-7.79-7.79v-13.838a7.79 7.79 0 1 1 15.58 0v13.838a7.79 7.79 0 0 1-7.79 7.79zM231.395 452.696a7.79 7.79 0 0 1-7.79-7.79v-13.838a7.79 7.79 0 1 1 15.58 0v13.838a7.79 7.79 0 0 1-7.79 7.79zM274.986 452.696a7.79 7.79 0 0 1-7.79-7.79v-13.838a7.79 7.79 0 0 1 7.79-7.79 7.79 7.79 0 0 1 7.79 7.79v13.838a7.79 7.79 0 0 1-7.79 7.79zM318.58 452.696a7.79 7.79 0 0 1-7.79-7.79v-13.838c0-4.303 3.487-7.79 7.79-7.79s7.79 3.487 7.79 7.79v13.838a7.79 7.79 0 0 1-7.79 7.79z"/>
14+
<g style="opacity:.16">
15+
<path style="fill:#640" d="M211.154 255.82c-4.141 0-7.591-3.292-7.78-7.471-.039-.867-.751-21.454 17.803-40.239a7.79 7.79 0 0 1 11.084 10.948c-13.567 13.736-13.337 28.05-13.32 28.653.195 4.299-3.133 7.906-7.43 8.101-.121.005-.24.008-.357.008z"/>
16+
</g>
17+
<path style="opacity:.5;fill:#1f544a;enable-background:new" d="M332.392 285.818H152.663v16.138h179.729v172.165h21.243V285.818z"/>
18+
<path style="opacity:.27;fill:#640;enable-background:new" d="M187.807 386.788h130.774v18.446H187.807z"/>
19+
<path style="fill:#56361d" d="M385.523 477.289c.504 1.698.786 3.489.786 5.345 0 10.401-8.51 18.911-18.911 18.911h-240.77a18.755 18.755 0 0 1-10.341-3.111c2.321 7.818 9.58 13.567 18.125 13.567h240.771c10.401 0 18.911-8.509 18.911-18.911 0-6.591-3.423-12.413-8.571-15.801z"/>
20+
</svg>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<svg {{ $attributes }} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" xml:space="preserve">
2+
<path style="fill:#eebf00" d="M237.159 209.657h38.446v73.467h-38.446z"/>
3+
<g style="opacity:.39">
4+
<path style="fill:#640" d="M237.159 209.657h38.446v28.185h-38.446z"/>
5+
</g>
6+
<circle style="fill:#cca400" cx="256.383" cy="110.723" r="110.723"/>
7+
<circle style="fill:#eebf00" cx="256.383" cy="110.723" r="82.452"/>
8+
<path style="fill:#ffda44" d="m275.544 77.51 19.175 33.213-19.175 33.213h-38.35l-19.175-33.213 19.175-33.213z"/>
9+
<g style="opacity:.37">
10+
<path style="fill:#640" d="m237.024 143.936-22.044 38.183a82.04 82.04 0 0 0 41.229 11.06 82.05 82.05 0 0 0 41.215-11.051l-22.049-38.19h-38.351v-.002z"/>
11+
</g>
12+
<path style="fill:#ffeb99" d="m275.379 77.51 22.044-38.183a82.04 82.04 0 0 0-41.229-11.06 82.05 82.05 0 0 0-41.215 11.051l22.049 38.19h38.351v.002z"/>
13+
<path style="fill:#640" d="M160.022 268.371h192.711v29.526H160.022zM160.022 452.952h192.711v29.526H160.022zM135.241 482.478h241.524v29.526H135.241z"/>
14+
<path style="fill:#eebf00" d="M178.476 297.898H333.53v155.054H178.476z"/>
15+
<path style="fill:#266659" d="M178.476 337.969H333.53v66.434H178.476z"/>
16+
<g style="opacity:.37">
17+
<path style="fill:#640" d="M297.636 39.345 275.601 77.51l19.175 33.213h44.056c0-30.502-16.574-57.115-41.196-71.378z"/>
18+
</g>
19+
<path style="fill:#ffe477" d="m215.12 39.345 22.035 38.166-19.175 33.213h-44.056c0-30.503 16.574-57.116 41.196-71.379z"/>
20+
<g style="opacity:.59">
21+
<path style="fill:#640" d="m297.636 182.101-22.035-38.166 19.175-33.213h44.056c0 30.503-16.574 57.116-41.196 71.379z"/>
22+
</g>
23+
<path style="opacity:.3;fill:#640;enable-background:new" d="M318.071 18.77c11.852 17.63 18.77 38.853 18.77 61.694 0 61.151-49.572 110.723-110.723 110.723-22.841 0-44.064-6.919-61.694-18.77 19.88 29.571 53.643 49.029 91.953 49.029 61.151 0 110.723-49.572 110.723-110.723.002-38.31-19.457-72.074-49.029-91.953z"/>
24+
<path style="fill:#56361d" d="M333.528 268.367v5.209a8.827 8.827 0 0 1-8.828 8.828H160.02v15.489h192.716v-29.527h-19.208v.001zM329.518 452.948v3.077c0 6.053-4.908 10.961-10.961 10.961H160.02v15.489H352.736v-29.527h-23.218zM353.545 482.474v3.077c0 6.053-4.908 10.961-10.961 10.961H135.239V512h241.524v-29.527h-23.218z"/>
25+
<path style="opacity:.21;fill:#640;enable-background:new" d="M284.76 297.898h48.771v155.054H284.76z"/>
26+
</svg>

0 commit comments

Comments
 (0)