@@ -2,11 +2,15 @@
 | 
			
		||||
 | 
			
		||||
namespace App;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Database\Eloquent\Model;
 | 
			
		||||
use Illuminate\Support\Facades\Auth;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
 | 
			
		||||
 | 
			
		||||
class Ejaculation extends Model
 | 
			
		||||
{
 | 
			
		||||
    //
 | 
			
		||||
    use HasEagerLimit;
 | 
			
		||||
 | 
			
		||||
    protected $fillable = [
 | 
			
		||||
        'user_id', 'ejaculated_date',
 | 
			
		||||
@@ -34,4 +38,45 @@ class Ejaculation extends Model
 | 
			
		||||
            return $v->name;
 | 
			
		||||
        })->all());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function likes()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->hasMany(Like::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function scopeWithLikes(Builder $query)
 | 
			
		||||
    {
 | 
			
		||||
        if (Auth::check()) {
 | 
			
		||||
            // TODO - このスコープを使うことでlikesが常に直近10件で絞られるのは汚染されすぎ感がある。別名を付与できないか?
 | 
			
		||||
            //      - (ejaculation_id, user_id) でユニークなわけですが、is_liked はサブクエリ発行させるのとLeft JoinしてNULLかどうかで結果を見るのどっちがいいんでしょうね
 | 
			
		||||
            return $query
 | 
			
		||||
                ->with([
 | 
			
		||||
                    'likes' => function ($query) {
 | 
			
		||||
                        $query->latest()->take(10);
 | 
			
		||||
                    },
 | 
			
		||||
                    'likes.user' => function ($query) {
 | 
			
		||||
                        $query->where('is_protected', false)
 | 
			
		||||
                            ->orWhere('id', Auth::id());
 | 
			
		||||
                    }
 | 
			
		||||
                ])
 | 
			
		||||
                ->withCount([
 | 
			
		||||
                    'likes',
 | 
			
		||||
                    'likes as is_liked' => function ($query) {
 | 
			
		||||
                        $query->where('user_id', Auth::id());
 | 
			
		||||
                    }
 | 
			
		||||
                ]);
 | 
			
		||||
        } else {
 | 
			
		||||
            return $query
 | 
			
		||||
                ->with([
 | 
			
		||||
                    'likes' => function ($query) {
 | 
			
		||||
                        $query->latest()->take(10);
 | 
			
		||||
                    },
 | 
			
		||||
                    'likes.user' => function ($query) {
 | 
			
		||||
                        $query->where('is_protected', false);
 | 
			
		||||
                    }
 | 
			
		||||
                ])
 | 
			
		||||
                ->withCount('likes')
 | 
			
		||||
                ->addSelect(DB::raw('0 as is_liked'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								app/Http/Controllers/Api/LikeController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								app/Http/Controllers/Api/LikeController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers\Api;
 | 
			
		||||
 | 
			
		||||
use App\Ejaculation;
 | 
			
		||||
use App\Http\Controllers\Controller;
 | 
			
		||||
use App\Like;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Facades\Auth;
 | 
			
		||||
use Illuminate\Support\Facades\Validator;
 | 
			
		||||
 | 
			
		||||
class LikeController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    public function store(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $request->validate([
 | 
			
		||||
            'id' => 'required|integer|exists:ejaculations'
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $keys = [
 | 
			
		||||
            'user_id' => Auth::id(),
 | 
			
		||||
            'ejaculation_id' => $request->input('id')
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $like = Like::query()->where($keys)->first();
 | 
			
		||||
        if ($like) {
 | 
			
		||||
            $data = [
 | 
			
		||||
                'errors' => [
 | 
			
		||||
                    ['message' => 'このチェックインはすでにいいね済です。']
 | 
			
		||||
                ],
 | 
			
		||||
                'ejaculation' => $like->ejaculation
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            return response()->json($data, 409);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $like = Like::create($keys);
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            'ejaculation' => $like->ejaculation
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function destroy($id)
 | 
			
		||||
    {
 | 
			
		||||
        Validator::make(compact('id'), [
 | 
			
		||||
            'id' => 'required|integer'
 | 
			
		||||
        ])->validate();
 | 
			
		||||
 | 
			
		||||
        $like = Like::query()->where([
 | 
			
		||||
            'user_id' => Auth::id(),
 | 
			
		||||
            'ejaculation_id' => $id
 | 
			
		||||
        ])->first();
 | 
			
		||||
        if ($like === null) {
 | 
			
		||||
            $ejaculation = Ejaculation::find($id);
 | 
			
		||||
 | 
			
		||||
            $data = [
 | 
			
		||||
                'errors' => [
 | 
			
		||||
                    ['message' => 'このチェックインはいいねされていません。']
 | 
			
		||||
                ],
 | 
			
		||||
                'ejaculation' => $ejaculation
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            return response()->json($data, 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $like->delete();
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            'ejaculation' => $like->ejaculation
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -78,7 +78,9 @@ class EjaculationController extends Controller
 | 
			
		||||
 | 
			
		||||
    public function show($id)
 | 
			
		||||
    {
 | 
			
		||||
        $ejaculation = Ejaculation::findOrFail($id);
 | 
			
		||||
        $ejaculation = Ejaculation::where('id', $id)
 | 
			
		||||
            ->withLikes()
 | 
			
		||||
            ->firstOrFail();
 | 
			
		||||
        $user = User::findOrFail($ejaculation->user_id);
 | 
			
		||||
 | 
			
		||||
        // 1つ前のチェックインからの経過時間を求める
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ SQL
 | 
			
		||||
                ->orderBy('ejaculations.ejaculated_date', 'desc')
 | 
			
		||||
                ->select('ejaculations.*')
 | 
			
		||||
                ->with('user', 'tags')
 | 
			
		||||
                ->withLikes()
 | 
			
		||||
                ->take(10)
 | 
			
		||||
                ->get();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ class SearchController extends Controller
 | 
			
		||||
            ->where('is_private', false)
 | 
			
		||||
            ->orderBy('ejaculated_date', 'desc')
 | 
			
		||||
            ->with(['user', 'tags'])
 | 
			
		||||
            ->withLikes()
 | 
			
		||||
            ->paginate(20)
 | 
			
		||||
            ->appends($inputs);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -46,11 +46,12 @@ class SettingController extends Controller
 | 
			
		||||
 | 
			
		||||
    public function updatePrivacy(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $inputs = $request->all(['is_protected', 'accept_analytics']);
 | 
			
		||||
        $inputs = $request->all(['is_protected', 'accept_analytics', 'private_likes']);
 | 
			
		||||
 | 
			
		||||
        $user = Auth::user();
 | 
			
		||||
        $user->is_protected = $inputs['is_protected'] ?? false;
 | 
			
		||||
        $user->accept_analytics = $inputs['accept_analytics'] ?? false;
 | 
			
		||||
        $user->private_likes = $inputs['private_likes'] ?? false;
 | 
			
		||||
        $user->save();
 | 
			
		||||
 | 
			
		||||
        return redirect()->route('setting.privacy')->with('status', 'プライバシー設定を更新しました。');
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ class TimelineController extends Controller
 | 
			
		||||
            ->orderBy('ejaculations.ejaculated_date', 'desc')
 | 
			
		||||
            ->select('ejaculations.*')
 | 
			
		||||
            ->with('user', 'tags')
 | 
			
		||||
            ->withLikes()
 | 
			
		||||
            ->paginate(21);
 | 
			
		||||
 | 
			
		||||
        return view('timeline.public')->with(compact('ejaculations'));
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@ SQL
 | 
			
		||||
        }
 | 
			
		||||
        $ejaculations = $query->orderBy('ejaculated_date', 'desc')
 | 
			
		||||
            ->with('tags')
 | 
			
		||||
            ->withLikes()
 | 
			
		||||
            ->paginate(20);
 | 
			
		||||
 | 
			
		||||
        // よく使っているタグ
 | 
			
		||||
@@ -176,4 +177,19 @@ SQL
 | 
			
		||||
 | 
			
		||||
        return view('user.profile')->with(compact('user', 'ejaculations'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function likes($name)
 | 
			
		||||
    {
 | 
			
		||||
        $user = User::where('name', $name)->first();
 | 
			
		||||
        if (empty($user)) {
 | 
			
		||||
            abort(404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $likes = $user->likes()
 | 
			
		||||
            ->orderBy('created_at', 'desc')
 | 
			
		||||
            ->with('ejaculation.user', 'ejaculation.tags')
 | 
			
		||||
            ->paginate(20);
 | 
			
		||||
 | 
			
		||||
        return view('user.likes')->with(compact('user', 'likes'));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,12 @@ class Kernel extends HttpKernel
 | 
			
		||||
            \App\Http\Middleware\NormalizeLineEnding::class,
 | 
			
		||||
        ],
 | 
			
		||||
 | 
			
		||||
        // 現時点では内部APIしかないので、認証の手間を省くためにステートフルにしている。
 | 
			
		||||
        'api' => [
 | 
			
		||||
            \App\Http\Middleware\EncryptCookies::class,
 | 
			
		||||
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
 | 
			
		||||
            \Illuminate\Session\Middleware\StartSession::class,
 | 
			
		||||
            \App\Http\Middleware\VerifyCsrfToken::class,
 | 
			
		||||
            'throttle:60,1',
 | 
			
		||||
            'bindings',
 | 
			
		||||
        ],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								app/Like.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Like.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Eloquent\Model;
 | 
			
		||||
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
 | 
			
		||||
 | 
			
		||||
class Like extends Model
 | 
			
		||||
{
 | 
			
		||||
    use HasEagerLimit;
 | 
			
		||||
 | 
			
		||||
    protected $fillable = ['user_id', 'ejaculation_id'];
 | 
			
		||||
 | 
			
		||||
    public function user()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsTo(User::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function ejaculation()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsTo(Ejaculation::class)->withLikes();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,6 +20,7 @@ class User extends Authenticatable
 | 
			
		||||
        'is_protected', 'accept_analytics',
 | 
			
		||||
        'display_name', 'description',
 | 
			
		||||
        'twitter_id', 'twitter_name',
 | 
			
		||||
        'private_likes',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -51,4 +52,9 @@ class User extends Authenticatable
 | 
			
		||||
    {
 | 
			
		||||
        return Auth::check() && $this->id === Auth::user()->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function likes()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->hasMany(Like::class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,8 @@
 | 
			
		||||
        "guzzlehttp/guzzle": "^6.3",
 | 
			
		||||
        "laravel/framework": "5.5.*",
 | 
			
		||||
        "laravel/tinker": "~1.0",
 | 
			
		||||
        "misd/linkify": "^1.1"
 | 
			
		||||
        "misd/linkify": "^1.1",
 | 
			
		||||
        "staudenmeir/eloquent-eager-limit": "^1.0"
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
        "barryvdh/laravel-debugbar": "^3.1",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										44
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 | 
			
		||||
        "This file is @generated automatically"
 | 
			
		||||
    ],
 | 
			
		||||
    "content-hash": "79423bebbfa31e28aab2d06ba7e19828",
 | 
			
		||||
    "content-hash": "665f6f5eb180a1295fb60303d2ea5051",
 | 
			
		||||
    "packages": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "anhskohbo/no-captcha",
 | 
			
		||||
@@ -1873,6 +1873,48 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2018-07-19T23:38:55+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "staudenmeir/eloquent-eager-limit",
 | 
			
		||||
            "version": "v1.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/staudenmeir/eloquent-eager-limit.git",
 | 
			
		||||
                "reference": "4ee5c70268b5bc019618c7de66145d7addb3c5dc"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/staudenmeir/eloquent-eager-limit/zipball/4ee5c70268b5bc019618c7de66145d7addb3c5dc",
 | 
			
		||||
                "reference": "4ee5c70268b5bc019618c7de66145d7addb3c5dc",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "illuminate/database": "~5.5.43|~5.6.34|5.7.*",
 | 
			
		||||
                "illuminate/support": "^5.5.14",
 | 
			
		||||
                "php": ">=7.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "laravel/homestead": "^7.18",
 | 
			
		||||
                "phpunit/phpunit": "~6.5"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Staudenmeir\\EloquentEagerLimit\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Jonas Staudenmeir",
 | 
			
		||||
                    "email": "mail@jonas-staudenmeir.de"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Laravel Eloquent eager loading with limit",
 | 
			
		||||
            "time": "2019-01-23T19:25:27+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "swiftmailer/swiftmailer",
 | 
			
		||||
            "version": "v6.1.3",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								database/migrations/2019_03_26_224641_create_likes_table.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								database/migrations/2019_03_26_224641_create_likes_table.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
class CreateLikesTable extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::create('likes', function (Blueprint $table) {
 | 
			
		||||
            $table->increments('id');
 | 
			
		||||
            $table->integer('user_id')->index();
 | 
			
		||||
            $table->integer('ejaculation_id')->index();
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
 | 
			
		||||
            $table->unique(['user_id', 'ejaculation_id']);
 | 
			
		||||
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
 | 
			
		||||
            $table->foreign('ejaculation_id')->references('id')->on('ejaculations')->onDelete('cascade');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::dropIfExists('likes');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
class AddPrivateLikesToUsers extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('users', function (Blueprint $table) {
 | 
			
		||||
            $table->boolean('private_likes')->default(false);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('users', function (Blueprint $table) {
 | 
			
		||||
            $table->dropColumn('private_likes');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								resources/assets/js/app.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								resources/assets/js/app.js
									
									
									
									
										vendored
									
									
								
							@@ -27,4 +27,69 @@ $(() => {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        $deleteCheckinModal.modal('show', this);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $(document).on('click', '[data-href]', function (event) {
 | 
			
		||||
        location.href = $(this).data('href');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $(document).on('click', '.like-button', function (event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
 | 
			
		||||
        const $this = $(this);
 | 
			
		||||
        const targetId = $this.data('id');
 | 
			
		||||
        const isLiked = $this.data('liked');
 | 
			
		||||
 | 
			
		||||
        if (isLiked) {
 | 
			
		||||
            const callback = (data) => {
 | 
			
		||||
                $this.data('liked', false);
 | 
			
		||||
                $this.find('.oi-heart').removeClass('text-danger');
 | 
			
		||||
 | 
			
		||||
                const count = data.ejaculation ? data.ejaculation.likes_count : 0;
 | 
			
		||||
                $this.find('.like-count').text(count ? count : '');
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: '/api/likes/' + encodeURIComponent(targetId),
 | 
			
		||||
                method: 'delete',
 | 
			
		||||
                type: 'json'
 | 
			
		||||
            })
 | 
			
		||||
                .then(callback)
 | 
			
		||||
                .catch(function (xhr) {
 | 
			
		||||
                    if (xhr.status === 404) {
 | 
			
		||||
                        callback(JSON.parse(xhr.responseText));
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    console.error(xhr);
 | 
			
		||||
                    alert('いいねを解除できませんでした。');
 | 
			
		||||
                });
 | 
			
		||||
        } else {
 | 
			
		||||
            const callback = (data) => {
 | 
			
		||||
                $this.data('liked', true);
 | 
			
		||||
                $this.find('.oi-heart').addClass('text-danger');
 | 
			
		||||
 | 
			
		||||
                const count = data.ejaculation ? data.ejaculation.likes_count : 0;
 | 
			
		||||
                $this.find('.like-count').text(count ? count : '');
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: '/api/likes',
 | 
			
		||||
                method: 'post',
 | 
			
		||||
                type: 'json',
 | 
			
		||||
                data: {
 | 
			
		||||
                    id: targetId
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
                .then(callback)
 | 
			
		||||
                .catch(function (xhr) {
 | 
			
		||||
                    if (xhr.status === 409) {
 | 
			
		||||
                        callback(JSON.parse(xhr.responseText));
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    console.error(xhr);
 | 
			
		||||
                    alert('いいねできませんでした。');
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										1
									
								
								resources/assets/sass/app.scss
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								resources/assets/sass/app.scss
									
									
									
									
										vendored
									
									
								
							@@ -12,4 +12,5 @@ $primary: #e53fb1;
 | 
			
		||||
@import "tissue.css";
 | 
			
		||||
 | 
			
		||||
// Components
 | 
			
		||||
@import "components/ejaculation";
 | 
			
		||||
@import "components/link-card";
 | 
			
		||||
							
								
								
									
										21
									
								
								resources/assets/sass/components/_ejaculation.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								resources/assets/sass/components/_ejaculation.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
.ejaculation-actions {
 | 
			
		||||
  & > button:not(:last-child) {
 | 
			
		||||
    margin-right: 24px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.like-button {
 | 
			
		||||
  text-decoration: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.like-count:not(:empty) {
 | 
			
		||||
  padding-left: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.like-users {
 | 
			
		||||
  height: 30px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.like-users-tall {
 | 
			
		||||
  height: 36px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								resources/assets/sass/tissue.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								resources/assets/sass/tissue.css
									
									
									
									
										vendored
									
									
								
							@@ -40,10 +40,6 @@
 | 
			
		||||
    border-top: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.timeline-action-item {
 | 
			
		||||
    margin-left: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tis-global-count-graph {
 | 
			
		||||
    height: 90px;
 | 
			
		||||
    border-bottom: 1px solid rgba(0, 0, 0, .125);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								resources/views/components/ejaculation.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								resources/views/components/ejaculation.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
<!-- span -->
 | 
			
		||||
<div>
 | 
			
		||||
    <h5>
 | 
			
		||||
        <a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> <bdi>{{ $ejaculation->user->display_name }}</bdi></a>
 | 
			
		||||
        <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
 | 
			
		||||
    </h5>
 | 
			
		||||
</div>
 | 
			
		||||
<!-- tags -->
 | 
			
		||||
@if ($ejaculation->tags->isNotEmpty())
 | 
			
		||||
    <p class="mb-2">
 | 
			
		||||
        @foreach ($ejaculation->tags as $tag)
 | 
			
		||||
            <a class="badge badge-secondary" href="{{ route('search', ['q' => $tag->name]) }}"><span class="oi oi-tag"></span> {{ $tag->name }}</a>
 | 
			
		||||
        @endforeach
 | 
			
		||||
    </p>
 | 
			
		||||
@endif
 | 
			
		||||
<!-- okazu link -->
 | 
			
		||||
@if (!empty($ejaculation->link))
 | 
			
		||||
    <div class="row mx-0">
 | 
			
		||||
        @component('components.link-card', ['link' => $ejaculation->link])
 | 
			
		||||
        @endcomponent
 | 
			
		||||
        <p class="d-flex align-items-baseline mb-2 col-12 px-0">
 | 
			
		||||
            <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
 | 
			
		||||
        </p>
 | 
			
		||||
    </div>
 | 
			
		||||
@endif
 | 
			
		||||
<!-- note -->
 | 
			
		||||
@if (!empty($ejaculation->note))
 | 
			
		||||
    <p class="mb-2 text-break">
 | 
			
		||||
        {!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
 | 
			
		||||
    </p>
 | 
			
		||||
@endif
 | 
			
		||||
<!-- likes -->
 | 
			
		||||
@if ($ejaculation->likes_count > 0)
 | 
			
		||||
    <div class="my-2 py-1 border-top border-bottom d-flex align-items-center">
 | 
			
		||||
        <div class="ml-2 mr-3 text-secondary flex-shrink-0"><small><strong>{{ $ejaculation->likes_count }}</strong> 件のいいね</small></div>
 | 
			
		||||
        <div class="like-users flex-grow-1 overflow-hidden">
 | 
			
		||||
            @foreach ($ejaculation->likes as $like)
 | 
			
		||||
                @if ($like->user !== null)
 | 
			
		||||
                    <a href="{{ route('user.profile', ['name' => $like->user->name]) }}"><img src="{{ $like->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded" data-toggle="tooltip" data-placement="bottom" title="{{ $like->user->display_name }}"></a>
 | 
			
		||||
                @endif
 | 
			
		||||
            @endforeach
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@endif
 | 
			
		||||
<!-- actions -->
 | 
			
		||||
<div class="ejaculation-actions">
 | 
			
		||||
    <button type="button" class="btn btn-link text-secondary"
 | 
			
		||||
            data-toggle="tooltip" data-placement="bottom"
 | 
			
		||||
            title="同じオカズでチェックイン" data-href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload"></span></button>
 | 
			
		||||
    <button type="button" class="btn btn-link text-secondary like-button"
 | 
			
		||||
            data-toggle="tooltip" data-placement="bottom" data-trigger="hover"
 | 
			
		||||
            title="いいね" data-id="{{ $ejaculation->id }}" data-liked="{{ (bool)$ejaculation->is_liked }}"><span class="oi oi-heart {{ $ejaculation->is_liked ? 'text-danger' : '' }}"></span><span class="like-count">{{ $ejaculation->likes_count ? $ejaculation->likes_count : '' }}</span></button>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -30,15 +30,8 @@
 | 
			
		||||
                <div class="card">
 | 
			
		||||
                    <div class="card-body">
 | 
			
		||||
                        <!-- span -->
 | 
			
		||||
                        <div class="d-flex justify-content-between">
 | 
			
		||||
                        <div>
 | 
			
		||||
                            <h5>{{ $ejaculatedSpan ?? '精通' }} <small class="text-muted">{{ $ejaculation->before_date }}{{ !empty($ejaculation->before_date) ? ' ~ ' : '' }}{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></h5>
 | 
			
		||||
                            <div>
 | 
			
		||||
                                <a class="text-secondary timeline-action-item" href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン"></span></a>
 | 
			
		||||
                                @if ($user->isMe())
 | 
			
		||||
                                    <a class="text-secondary timeline-action-item" href="{{ route('checkin.edit', ['id' => $ejaculation->id]) }}"><span class="oi oi-pencil" data-toggle="tooltip" data-placement="bottom" title="修正"></span></a>
 | 
			
		||||
                                    <a class="text-secondary timeline-action-item" href="#" data-target="#deleteCheckinModal" data-id="{{ $ejaculation->id }}" data-date="{{ $ejaculation->ejaculated_date }}"><span class="oi oi-trash" data-toggle="tooltip" data-placement="bottom" title="削除"></span></a>
 | 
			
		||||
                                @endif
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <!-- tags -->
 | 
			
		||||
                        @if ($ejaculation->is_private || $ejaculation->tags->isNotEmpty())
 | 
			
		||||
@@ -63,10 +56,32 @@
 | 
			
		||||
                        @endif
 | 
			
		||||
                        <!-- note -->
 | 
			
		||||
                        @if (!empty($ejaculation->note))
 | 
			
		||||
                            <p class="mb-0 text-break">
 | 
			
		||||
                            <p class="mb-2 text-break">
 | 
			
		||||
                                {!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
 | 
			
		||||
                            </p>
 | 
			
		||||
                        @endif
 | 
			
		||||
                        <!-- likes -->
 | 
			
		||||
                        @if ($ejaculation->likes_count > 0)
 | 
			
		||||
                            <div class="my-2 py-1 border-top border-bottom d-flex align-items-center">
 | 
			
		||||
                                <div class="ml-2 mr-3 text-secondary flex-shrink-0"><small><strong>{{ $ejaculation->likes_count }}</strong> 件のいいね</small></div>
 | 
			
		||||
                                <div class="like-users-tall flex-grow-1 overflow-hidden">
 | 
			
		||||
                                    @foreach ($ejaculation->likes as $like)
 | 
			
		||||
                                        @if ($like->user !== null)
 | 
			
		||||
                                            <a href="{{ route('user.profile', ['name' => $like->user->name]) }}"><img src="{{ $like->user->getProfileImageUrl(36) }}" width="36" height="36" class="rounded" data-toggle="tooltip" data-placement="bottom" title="{{ $like->user->display_name }}"></a>
 | 
			
		||||
                                        @endif
 | 
			
		||||
                                    @endforeach
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        @endif
 | 
			
		||||
                        <!-- actions -->
 | 
			
		||||
                        <div class="ejaculation-actions">
 | 
			
		||||
                            <button type="button" class="btn btn-link text-secondary" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン" data-href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload"></span></button>
 | 
			
		||||
                            <button type="button" class="btn btn-link text-secondary like-button" data-toggle="tooltip" data-placement="bottom" data-trigger="hover" title="いいね" data-id="{{ $ejaculation->id }}" data-liked="{{ (bool)$ejaculation->is_liked }}"><span class="oi oi-heart {{ $ejaculation->is_liked ? 'text-danger' : '' }}"></span><span class="like-count">{{ $ejaculation->likes_count ? $ejaculation->likes_count : '' }}</span></button>
 | 
			
		||||
                            @if ($user->isMe())
 | 
			
		||||
                                <button type="button" class="btn btn-link text-secondary" data-toggle="tooltip" data-placement="bottom" title="修正" data-href="{{ route('checkin.edit', ['id' => $ejaculation->id]) }}"><span class="oi oi-pencil"></span></button>
 | 
			
		||||
                                <button type="button" class="btn btn-link text-secondary" data-toggle="tooltip" data-placement="bottom" title="削除" data-target="#deleteCheckinModal" data-id="{{ $ejaculation->id }}" data-date="{{ $ejaculation->ejaculated_date }}"><span class="oi oi-trash"></span></button>
 | 
			
		||||
                            @endif
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            @endif
 | 
			
		||||
 
 | 
			
		||||
@@ -55,40 +55,8 @@
 | 
			
		||||
                <ul class="list-group">
 | 
			
		||||
                    @foreach ($publicLinkedEjaculations as $ejaculation)
 | 
			
		||||
                        <li class="list-group-item no-side-border pt-3 pb-3 text-break">
 | 
			
		||||
                            <!-- span -->
 | 
			
		||||
                            <div class="d-flex justify-content-between">
 | 
			
		||||
                                <h5>
 | 
			
		||||
                                    <a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> <bdi>{{ $ejaculation->user->display_name }}</bdi></a>
 | 
			
		||||
                                    <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
 | 
			
		||||
                                </h5>
 | 
			
		||||
                                <div>
 | 
			
		||||
                                    <a class="text-secondary timeline-action-item" href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン"></span></a>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <!-- tags -->
 | 
			
		||||
                            @if ($ejaculation->tags->isNotEmpty())
 | 
			
		||||
                                <p class="mb-2">
 | 
			
		||||
                                    @foreach ($ejaculation->tags as $tag)
 | 
			
		||||
                                        <a class="badge badge-secondary" href="{{ route('search', ['q' => $tag->name]) }}"><span class="oi oi-tag"></span> {{ $tag->name }}</a>
 | 
			
		||||
                                    @endforeach
 | 
			
		||||
                                </p>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            <!-- okazu link -->
 | 
			
		||||
                            @if (!empty($ejaculation->link))
 | 
			
		||||
                                <div class="row mx-0">
 | 
			
		||||
                                    @component('components.link-card', ['link' => $ejaculation->link])
 | 
			
		||||
                                    @endcomponent
 | 
			
		||||
                                    <p class="d-flex align-items-baseline mb-2 col-12 px-0">
 | 
			
		||||
                                        <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
 | 
			
		||||
                                    </p>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            <!-- note -->
 | 
			
		||||
                            @if (!empty($ejaculation->note))
 | 
			
		||||
                                <p class="mb-0 text-break">
 | 
			
		||||
                                    {!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
 | 
			
		||||
                                </p>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            @component('components.ejaculation', compact('ejaculation'))
 | 
			
		||||
                            @endcomponent
 | 
			
		||||
                        </li>
 | 
			
		||||
                    @endforeach
 | 
			
		||||
                    <li class="list-group-item no-side-border text-right">
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,9 @@
 | 
			
		||||
                            </p>
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <div class="dropdown-divider"></div>
 | 
			
		||||
                        <a href="{{ route('user.profile', ['name' => Auth::user()->name]) }}" class="dropdown-item">プロフィール</a>
 | 
			
		||||
                        <a href="{{ route('user.likes', ['name' => Auth::user()->name]) }}" class="dropdown-item">いいね</a>
 | 
			
		||||
                        <div class="dropdown-divider"></div>
 | 
			
		||||
                        <a href="{{ route('setting') }}" class="dropdown-item">設定</a>
 | 
			
		||||
                        <a href="{{ route('logout') }}" class="dropdown-item" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
@@ -104,6 +107,9 @@
 | 
			
		||||
                                    </p>
 | 
			
		||||
                                </a>
 | 
			
		||||
                                <div class="dropdown-divider"></div>
 | 
			
		||||
                                <a href="{{ route('user.profile', ['name' => Auth::user()->name]) }}" class="dropdown-item">プロフィール</a>
 | 
			
		||||
                                <a href="{{ route('user.likes', ['name' => Auth::user()->name]) }}" class="dropdown-item">いいね</a>
 | 
			
		||||
                                <div class="dropdown-divider"></div>
 | 
			
		||||
                                <a href="{{ route('setting') }}" class="dropdown-item">設定</a>
 | 
			
		||||
                                @can ('admin')
 | 
			
		||||
                                    <a href="{{ route('admin.dashboard') }}" class="dropdown-item">管理</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,43 +7,8 @@
 | 
			
		||||
        <ul class="list-group">
 | 
			
		||||
        @foreach($results as $ejaculation)
 | 
			
		||||
            <li class="list-group-item border-bottom-only pt-3 pb-3 text-break">
 | 
			
		||||
                <!-- span -->
 | 
			
		||||
                <div class="d-flex justify-content-between">
 | 
			
		||||
                    <h5>
 | 
			
		||||
                        <a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> <bdi>{{ $ejaculation->user->display_name }}</bdi></a>
 | 
			
		||||
                        <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
 | 
			
		||||
                    </h5>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <a class="text-secondary timeline-action-item" href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン"></span></a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <!-- tags -->
 | 
			
		||||
                @if ($ejaculation->is_private || $ejaculation->tags->isNotEmpty())
 | 
			
		||||
                    <p class="mb-2">
 | 
			
		||||
                        @if ($ejaculation->is_private)
 | 
			
		||||
                            <span class="badge badge-warning"><span class="oi oi-lock-locked"></span> 非公開</span>
 | 
			
		||||
                        @endif
 | 
			
		||||
                        @foreach ($ejaculation->tags as $tag)
 | 
			
		||||
                            <a class="badge badge-secondary" href="{{ route('search', ['q' => $tag->name]) }}"><span class="oi oi-tag"></span> {{ $tag->name }}</a>
 | 
			
		||||
                        @endforeach
 | 
			
		||||
                    </p>
 | 
			
		||||
                @endif
 | 
			
		||||
                <!-- okazu link -->
 | 
			
		||||
                @if (!empty($ejaculation->link))
 | 
			
		||||
                    <div class="row mx-0">
 | 
			
		||||
                        @component('components.link-card', ['link' => $ejaculation->link])
 | 
			
		||||
                        @endcomponent
 | 
			
		||||
                        <p class="d-flex align-items-baseline mb-2 col-12 px-0">
 | 
			
		||||
                            <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
 | 
			
		||||
                        </p>
 | 
			
		||||
                    </div>
 | 
			
		||||
                @endif
 | 
			
		||||
                <!-- note -->
 | 
			
		||||
                @if (!empty($ejaculation->note))
 | 
			
		||||
                    <p class="mb-0 text-break">
 | 
			
		||||
                        {!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
 | 
			
		||||
                    </p>
 | 
			
		||||
                @endif
 | 
			
		||||
                @component('components.ejaculation', compact('ejaculation'))
 | 
			
		||||
                @endcomponent
 | 
			
		||||
            </li>
 | 
			
		||||
        @endforeach
 | 
			
		||||
        </ul>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,11 @@
 | 
			
		||||
            <div class="custom-control custom-checkbox mb-2">
 | 
			
		||||
                <input id="protected" name="is_protected" class="custom-control-input" type="checkbox" {{ (old('is_protected') ?? Auth::user()->is_protected ) ? 'checked' : '' }}>
 | 
			
		||||
                <label class="custom-control-label" for="protected">全てのチェックイン履歴を非公開にする</label>
 | 
			
		||||
                <small class="form-text text-muted">プロフィール情報を除いて、全ての情報が非公開になります。</small>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="custom-control custom-checkbox mb-2">
 | 
			
		||||
                <input id="private-likes" name="private_likes" class="custom-control-input" type="checkbox" {{ (old('private_likes') ?? Auth::user()->private_likes ) ? 'checked' : '' }}>
 | 
			
		||||
                <label class="custom-control-label" for="private-likes">いいねしたチェックイン一覧を非公開にする</label>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="custom-control custom-checkbox">
 | 
			
		||||
                <input id="accept-analytics" name="accept_analytics" class="custom-control-input" type="checkbox" {{ (old('accept_analytics') ?? Auth::user()->accept_analytics ) ? 'checked' : '' }}>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,43 +11,8 @@
 | 
			
		||||
        <div class="row mx-1">
 | 
			
		||||
            @foreach($ejaculations as $ejaculation)
 | 
			
		||||
                <div class="col-12 col-lg-6 col-xl-4 py-3 text-break border-top">
 | 
			
		||||
                    <!-- span -->
 | 
			
		||||
                    <div class="d-flex justify-content-between">
 | 
			
		||||
                        <h5>
 | 
			
		||||
                            <a href="{{ route('user.profile', ['id' => $ejaculation->user->name]) }}" class="text-dark"><img src="{{ $ejaculation->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded d-inline-block align-bottom"> <bdi>{{ $ejaculation->user->display_name }}</bdi></a>
 | 
			
		||||
                            <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a>
 | 
			
		||||
                        </h5>
 | 
			
		||||
                        <div>
 | 
			
		||||
                            <a class="text-secondary timeline-action-item" href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン"></span></a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <!-- tags -->
 | 
			
		||||
                    @if ($ejaculation->is_private || $ejaculation->tags->isNotEmpty())
 | 
			
		||||
                        <p class="mb-2">
 | 
			
		||||
                            @if ($ejaculation->is_private)
 | 
			
		||||
                                <span class="badge badge-warning"><span class="oi oi-lock-locked"></span> 非公開</span>
 | 
			
		||||
                            @endif
 | 
			
		||||
                            @foreach ($ejaculation->tags as $tag)
 | 
			
		||||
                                <a class="badge badge-secondary" href="{{ route('search', ['q' => $tag->name]) }}"><span class="oi oi-tag"></span> {{ $tag->name }}</a>
 | 
			
		||||
                            @endforeach
 | 
			
		||||
                        </p>
 | 
			
		||||
                    @endif
 | 
			
		||||
                    <!-- okazu link -->
 | 
			
		||||
                    @if (!empty($ejaculation->link))
 | 
			
		||||
                        <div class="row mx-0">
 | 
			
		||||
                            @component('components.link-card', ['link' => $ejaculation->link])
 | 
			
		||||
                            @endcomponent
 | 
			
		||||
                            <p class="d-flex align-items-baseline mb-2 col-12 px-0">
 | 
			
		||||
                                <span class="oi oi-link-intact mr-1"></span><a class="overflow-hidden" href="{{ $ejaculation->link }}" target="_blank" rel="noopener">{{ $ejaculation->link }}</a>
 | 
			
		||||
                            </p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    @endif
 | 
			
		||||
                    <!-- note -->
 | 
			
		||||
                    @if (!empty($ejaculation->note))
 | 
			
		||||
                        <p class="mb-0 text-break">
 | 
			
		||||
                            {!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
 | 
			
		||||
                        </p>
 | 
			
		||||
                    @endif
 | 
			
		||||
                    @component('components.ejaculation', compact('ejaculation'))
 | 
			
		||||
                    @endcomponent
 | 
			
		||||
                </div>
 | 
			
		||||
            @endforeach
 | 
			
		||||
        </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,13 @@
 | 
			
		||||
                    <li class="nav-item">
 | 
			
		||||
                        <a class="nav-link {{ Route::currentRouteName() === 'user.okazu' ? 'active' : '' }}" href="{{ route('user.okazu', ['name' => $user->name]) }}">オカズ</a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li class="nav-item">
 | 
			
		||||
                        <a class="nav-link {{ Route::currentRouteName() === 'user.likes' ? 'active' : '' }}" href="{{ route('user.likes', ['name' => $user->name]) }}">いいね
 | 
			
		||||
                            @if ($user->isMe() || !($user->is_protected || $user->private_likes))
 | 
			
		||||
                                <span class="badge badge-primary">{{ $user->likes()->count() }}</span>
 | 
			
		||||
                            @endif
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                </ul>
 | 
			
		||||
                <div class="tab-content">
 | 
			
		||||
                    @yield('tab-content')
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								resources/views/user/likes.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								resources/views/user/likes.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
@extends('user.base')
 | 
			
		||||
 | 
			
		||||
@section('title', $user->display_name . ' (@' . $user->name . ') さんがいいねしたチェックイン')
 | 
			
		||||
 | 
			
		||||
@section('tab-content')
 | 
			
		||||
@if (($user->is_protected || $user->private_likes) && !$user->isMe())
 | 
			
		||||
    <p class="mt-4">
 | 
			
		||||
        <span class="oi oi-lock-locked"></span> このユーザはいいね一覧を公開していません。
 | 
			
		||||
    </p>
 | 
			
		||||
@else
 | 
			
		||||
    <ul class="list-group">
 | 
			
		||||
        @forelse ($likes as $like)
 | 
			
		||||
            <li class="list-group-item border-bottom-only pt-3 pb-3 text-break">
 | 
			
		||||
                @component('components.ejaculation', ['ejaculation' => $like->ejaculation])
 | 
			
		||||
                @endcomponent
 | 
			
		||||
            </li>
 | 
			
		||||
        @empty
 | 
			
		||||
            <li class="list-group-item border-bottom-only">
 | 
			
		||||
                <p>まだ何もいいと思ったことがありません。</p>
 | 
			
		||||
            </li>
 | 
			
		||||
        @endforelse
 | 
			
		||||
    </ul>
 | 
			
		||||
    {{ $likes->links(null, ['className' => 'mt-4 justify-content-center']) }}
 | 
			
		||||
@endif
 | 
			
		||||
@endsection
 | 
			
		||||
@@ -36,15 +36,8 @@
 | 
			
		||||
        @forelse ($ejaculations as $ejaculation)
 | 
			
		||||
            <li class="list-group-item border-bottom-only pt-3 pb-3 text-break">
 | 
			
		||||
                <!-- span -->
 | 
			
		||||
                <div class="d-flex justify-content-between">
 | 
			
		||||
                <div>
 | 
			
		||||
                    <h5>{{ $ejaculation->ejaculated_span ?? '精通' }} <a href="{{ route('checkin.show', ['id' => $ejaculation->id]) }}" class="text-muted"><small>{{ $ejaculation->before_date }}{{ !empty($ejaculation->before_date) ? ' ~ ' : '' }}{{ $ejaculation->ejaculated_date->format('Y/m/d H:i') }}</small></a></h5>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <a class="text-secondary timeline-action-item" href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン"></span></a>
 | 
			
		||||
                        @if ($user->isMe())
 | 
			
		||||
                            <a class="text-secondary timeline-action-item" href="{{ route('checkin.edit', ['id' => $ejaculation->id]) }}"><span class="oi oi-pencil" data-toggle="tooltip" data-placement="bottom" title="修正"></span></a>
 | 
			
		||||
                            <a class="text-secondary timeline-action-item" href="#" data-target="#deleteCheckinModal" data-id="{{ $ejaculation->id }}" data-date="{{ $ejaculation->ejaculated_date }}"><span class="oi oi-trash" data-toggle="tooltip" data-placement="bottom" title="削除"></span></a>
 | 
			
		||||
                        @endif
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <!-- tags -->
 | 
			
		||||
                @if ($ejaculation->is_private || $ejaculation->tags->isNotEmpty())
 | 
			
		||||
@@ -69,10 +62,32 @@
 | 
			
		||||
                @endif
 | 
			
		||||
                <!-- note -->
 | 
			
		||||
                @if (!empty($ejaculation->note))
 | 
			
		||||
                    <p class="mb-0 text-break">
 | 
			
		||||
                    <p class="mb-2 text-break">
 | 
			
		||||
                        {!! Formatter::linkify(nl2br(e($ejaculation->note))) !!}
 | 
			
		||||
                    </p>
 | 
			
		||||
                @endif
 | 
			
		||||
                <!-- likes -->
 | 
			
		||||
                @if ($ejaculation->likes_count > 0)
 | 
			
		||||
                    <div class="my-2 py-1 border-top border-bottom d-flex align-items-center">
 | 
			
		||||
                        <div class="ml-2 mr-3 text-secondary flex-shrink-0"><small><strong>{{ $ejaculation->likes_count }}</strong> 件のいいね</small></div>
 | 
			
		||||
                        <div class="like-users flex-grow-1 overflow-hidden">
 | 
			
		||||
                            @foreach ($ejaculation->likes as $like)
 | 
			
		||||
                                @if ($like->user !== null)
 | 
			
		||||
                                    <a href="{{ route('user.profile', ['name' => $like->user->name]) }}"><img src="{{ $like->user->getProfileImageUrl(30) }}" width="30" height="30" class="rounded" data-toggle="tooltip" data-placement="bottom" title="{{ $like->user->display_name }}"></a>
 | 
			
		||||
                                @endif
 | 
			
		||||
                            @endforeach
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                @endif
 | 
			
		||||
                <!-- actions -->
 | 
			
		||||
                <div class="ejaculation-actions">
 | 
			
		||||
                    <button type="button" class="btn btn-link text-secondary" data-toggle="tooltip" data-placement="bottom" title="同じオカズでチェックイン" data-href="{{ route('checkin', ['link' => $ejaculation->link, 'tags' => $ejaculation->textTags()]) }}"><span class="oi oi-reload"></span></button>
 | 
			
		||||
                    <button type="button" class="btn btn-link text-secondary like-button" data-toggle="tooltip" data-placement="bottom" data-trigger="hover" title="いいね" data-id="{{ $ejaculation->id }}" data-liked="{{ (bool)$ejaculation->is_liked }}"><span class="oi oi-heart {{ $ejaculation->is_liked ? 'text-danger' : '' }}"></span><span class="like-count">{{ $ejaculation->likes_count ? $ejaculation->likes_count : '' }}</span></button>
 | 
			
		||||
                    @if ($user->isMe())
 | 
			
		||||
                        <button type="button" class="btn btn-link text-secondary" data-toggle="tooltip" data-placement="bottom" title="修正" data-href="{{ route('checkin.edit', ['id' => $ejaculation->id]) }}"><span class="oi oi-pencil"></span></button>
 | 
			
		||||
                        <button type="button" class="btn btn-link text-secondary" data-toggle="tooltip" data-placement="bottom" title="削除" data-target="#deleteCheckinModal" data-id="{{ $ejaculation->id }}" data-date="{{ $ejaculation->ejaculated_date }}"><span class="oi oi-trash"></span></button>
 | 
			
		||||
                    @endif
 | 
			
		||||
                </div>
 | 
			
		||||
            </li>
 | 
			
		||||
        @empty
 | 
			
		||||
            <li class="list-group-item border-bottom-only">
 | 
			
		||||
 
 | 
			
		||||
@@ -16,3 +16,8 @@
 | 
			
		||||
//});
 | 
			
		||||
 | 
			
		||||
Route::get('/checkin/card', 'Api\\CardController@show');
 | 
			
		||||
 | 
			
		||||
Route::middleware('auth')->group(function () {
 | 
			
		||||
    Route::post('/likes', 'Api\\LikeController@store');
 | 
			
		||||
    Route::delete('/likes/{id}', 'Api\\LikeController@destroy');
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ Route::get('/user', 'UserController@redirectMypage')->middleware('auth');
 | 
			
		||||
Route::get('/user/{name?}', 'UserController@profile')->name('user.profile');
 | 
			
		||||
Route::get('/user/{name}/stats', 'UserController@stats')->name('user.stats');
 | 
			
		||||
Route::get('/user/{name}/okazu', 'UserController@okazu')->name('user.okazu');
 | 
			
		||||
Route::get('/user/{name}/likes', 'UserController@likes')->name('user.likes');
 | 
			
		||||
 | 
			
		||||
Route::get('/checkin/{id}', 'EjaculationController@show')->name('checkin.show');
 | 
			
		||||
Route::middleware('auth')->group(function () {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user