planiverse

A minimalist, no-JS front-end for Mastodon.
git clone https://git.stjo.hn/planiverse
Log | Files | Refs | README | LICENSE

commit 3902114ac0b9f0dce6b4b23f1156a6e38b466c0d
parent 0143d70112d3224be416591dd2b0ac4ad2efcfd4
Author: St John Karp <stjohn@fuzzjunket.com>
Date:   Sun, 12 Aug 2018 16:28:45 -0700

Introduce pagination and action icons

Added action icons (reply, favourite, etc.) to the bottom of
every status. Implemented pagination on the timeline views.

Diffstat:
Mapp/Http/Controllers/LoginController.php | 2+-
Mapp/Http/Controllers/TimelineController.php | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mpublic/css/styles.css | 8++++++++
Mresources/views/status.blade.php | 22++++++++++++++++++++++
Mresources/views/timeline.blade.php | 12+++++++++++-
Mroutes/web.php | 13++++++++++---
6 files changed, 131 insertions(+), 11 deletions(-)

diff --git a/app/Http/Controllers/LoginController.php b/app/Http/Controllers/LoginController.php @@ -68,6 +68,6 @@ class LoginController extends Controller $user = Socialite::driver('mastodon')->user(); session(['user' => $user]); - return redirect()->route('friends'); + return redirect()->route('home'); } } diff --git a/app/Http/Controllers/TimelineController.php b/app/Http/Controllers/TimelineController.php @@ -4,29 +4,102 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Mastodon; +use GuzzleHttp\Psr7; +use Illuminate\Http\Request; class TimelineController extends Controller { - public function public_timeline() + public function public_timeline(Request $request) { + $params = $this->compile_params($request); + $params['local'] = true; + $timeline = Mastodon::domain(env('MASTODON_DOMAIN')) - ->get('/timelines/public', ['local' => true]); + ->get('/timelines/public', $params); + + $vars = [ + 'statuses' => $timeline, + 'mastodon_domain' => explode('//', env('MASTODON_DOMAIN'))[1], + 'timeline' => 'Public Timeline', + 'links' => $this->compile_links('public') + ]; - return view('timeline', ['statuses' => $timeline]); + return view('timeline', $vars); } - public function home_timeline() + public function home_timeline(Request $request) { if (!session()->has('user')) { return redirect()->route('login'); } + $params = $this->compile_params($request); + $user = session('user'); $timeline = Mastodon::domain(env('MASTODON_DOMAIN')) ->token($user->token) - ->get('/timelines/home'); + ->get('/timelines/home', $params); + + $vars = [ + 'statuses' => $timeline, + 'mastodon_domain' => explode('//', env('MASTODON_DOMAIN'))[1], + 'timeline' => 'Timeline', + 'links' => $this->compile_links('home') + ]; + + return view('timeline', $vars); + } + + private function compile_links(string $route) + { + $links = [ + 'next' => null, + 'prev' => null + ]; + + # Parse out the links header returned from the Mastodon API. + $links_header = Mastodon::getResponse()->getHeader('link'); + foreach (Psr7\parse_header($links_header) as $link) + { + # Find the prev and next links. + if ($link['rel'] === 'prev' || $link['rel'] === 'next') + { + $url = parse_url(trim($link[0], '<>')); + foreach (explode('&', $url['query']) as $query_param) + { + # Grab the ID query parameters from the link. + if (strpos($query_param, 'max_id=') === 0 + || strpos($query_param, 'since_id=') === 0) + { + # Construct new links with the correct offset. + $links[$link['rel']] = route($route) . '?' . $query_param; + } + } + } + } + + return $links; + } + + private function compile_params(Request $request) + { + $params = []; + + if ($request->has('max_id') && $request->has('since_id')) + { + # This scenario makes no sense. Someone's trying to dicker with the URL. + abort(400); + } + elseif ($request->has('max_id')) + { + $params['max_id'] = $request->max_id; + } + elseif ($request->has('since_id')) + { + $params['since_id'] = $request->since_id; + } - return view('timeline', ['statuses' => $timeline]); + return $params; } } diff --git a/public/css/styles.css b/public/css/styles.css @@ -46,6 +46,14 @@ div.status img.avatar { max-width: 48px; } +.favourited { + color: gold; +} + +div.actions span { + margin-right: 1em; +} + /* Tooltip container */ .tooltip { position: relative; diff --git a/resources/views/status.blade.php b/resources/views/status.blade.php @@ -30,4 +30,26 @@ @component('status', ['status' => $status['reblog']]) @endcomponent @endif + + <div class="actions"> + <!-- Reply --> + <span> + &#8629; + </span> + + <!-- Reblog --> + <span> + &#8644; {{ $status['reblogs_count'] }} + </span> + + <!-- Favourite --> + <span> + @if ($status['favourited'] === true) + <span class="favourited">&#9733;</span> + @else + &#9734; + @endif + {{ $status['favourites_count'] }} + </span> + </div> </div> diff --git a/resources/views/timeline.blade.php b/resources/views/timeline.blade.php @@ -5,14 +5,24 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>jank.town | Public Timeline</title> + <title>{{ $mastodon_domain }} | {{ $timeline }}</title> <link rel="stylesheet" href="/css/styles.css" /> </head> <body> + <h1>{{ $mastodon_domain }} | {{ $timeline }}</h1> + @foreach ($statuses as $status) @component('status', ['status' => $status]) @endcomponent @endforeach + + @if ($links['prev'] !== null) + <span><a href="{{ $links['prev'] }}">Previous</a></span> + @endif + + @if ($links['next'] !== null) + <span><a href="{{ $links['next'] }}">Next</a></span> + @endif </body> </html> diff --git a/routes/web.php b/routes/web.php @@ -12,14 +12,21 @@ */ Route::get('/', function() { - return redirect()->route('public'); + if (!session()->has('user')) + { + return redirect()->route('public'); + } + else + { + return redirect()->route('home'); + } }); Route::get('/timeline/public', 'TimelineController@public_timeline') ->name('public'); -Route::get('/timeline/friends', 'TimelineController@home_timeline') - ->name('friends'); +Route::get('/timeline/home', 'TimelineController@home_timeline') + ->name('home'); Route::get('/login', 'LoginController@login') ->name('login');