Merge pull request #358 from shikorism/feature/remake-user-page
グラフページの再編
This commit is contained in:
commit
ced289b95d
@ -5,9 +5,11 @@ namespace App\Http\Controllers;
|
|||||||
use App\Ejaculation;
|
use App\Ejaculation;
|
||||||
use App\User;
|
use App\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Carbon\CarbonInterface;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Validator;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
@ -60,7 +62,18 @@ SQL
|
|||||||
->limit(10)
|
->limit(10)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
return view('user.profile')->with(compact('user', 'ejaculations', 'tags'));
|
// シコ草
|
||||||
|
$countByDayQuery = $this->countEjaculationByDay($user)
|
||||||
|
->where('ejaculated_date', '>=', now()->startOfMonth()->subMonths(9))
|
||||||
|
->where('ejaculated_date', '<', now()->addMonth()->startOfMonth())
|
||||||
|
->get();
|
||||||
|
$countByDay = [];
|
||||||
|
foreach ($countByDayQuery as $data) {
|
||||||
|
$date = Carbon::createFromFormat('Y/m/d', $data->date);
|
||||||
|
$countByDay[$date->timestamp] = $data->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('user.profile')->with(compact('user', 'ejaculations', 'tags', 'countByDay'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stats($name)
|
public function stats($name)
|
||||||
@ -70,73 +83,72 @@ SQL
|
|||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dateUntil = now()->addMonth()->startOfMonth();
|
$availableMonths = $this->makeStatsAvailableMonths($user);
|
||||||
|
$graphData = $this->makeGraphData($user);
|
||||||
|
|
||||||
$groupByDay = Ejaculation::select(DB::raw(
|
return view('user.stats.index')->with(compact('user', 'graphData', 'availableMonths'));
|
||||||
<<<'SQL'
|
}
|
||||||
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
|
|
||||||
count(*) AS "count"
|
|
||||||
SQL
|
|
||||||
))
|
|
||||||
->where('user_id', $user->id)
|
|
||||||
->where('ejaculated_date', '<', $dateUntil)
|
|
||||||
->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
|
|
||||||
->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
|
|
||||||
->get();
|
|
||||||
|
|
||||||
$groupByHour = Ejaculation::select(DB::raw(
|
public function statsYearly($name, $year)
|
||||||
<<<'SQL'
|
{
|
||||||
to_char(ejaculated_date, 'HH24') AS "hour",
|
$user = User::where('name', $name)->first();
|
||||||
count(*) AS "count"
|
if (empty($user)) {
|
||||||
SQL
|
abort(404);
|
||||||
))
|
|
||||||
->where('user_id', $user->id)
|
|
||||||
->where('ejaculated_date', '<', $dateUntil)
|
|
||||||
->groupBy(DB::raw("to_char(ejaculated_date, 'HH24')"))
|
|
||||||
->orderBy(DB::raw('1'))
|
|
||||||
->get();
|
|
||||||
|
|
||||||
$dailySum = [];
|
|
||||||
$monthlySum = [];
|
|
||||||
$yearlySum = [];
|
|
||||||
$dowSum = array_fill(0, 7, 0);
|
|
||||||
$hourlySum = array_fill(0, 24, 0);
|
|
||||||
|
|
||||||
// 年間グラフ用の配列初期化
|
|
||||||
if ($groupByDay->first() !== null) {
|
|
||||||
$year = Carbon::createFromFormat('Y/m/d', $groupByDay->first()->date)->year;
|
|
||||||
$currentYear = date('Y');
|
|
||||||
for (; $year <= $currentYear; $year++) {
|
|
||||||
$yearlySum[$year] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($groupByDay as $data) {
|
$validator = Validator::make(compact('year'), [
|
||||||
$date = Carbon::createFromFormat('Y/m/d', $data->date);
|
'year' => 'required|date_format:Y'
|
||||||
$yearAndMonth = $date->format('Y/m');
|
]);
|
||||||
|
if ($validator->fails()) {
|
||||||
$dailySum[$date->timestamp] = $data->count;
|
return redirect()->route('user.stats', compact('name'));
|
||||||
$yearlySum[$date->year] += $data->count;
|
|
||||||
$dowSum[$date->dayOfWeek] += $data->count;
|
|
||||||
$monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($groupByHour as $data) {
|
$availableMonths = $this->makeStatsAvailableMonths($user);
|
||||||
$hour = (int)$data->hour;
|
if (!isset($availableMonths[$year])) {
|
||||||
$hourlySum[$hour] += $data->count;
|
return redirect()->route('user.stats', compact('name'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$graphData = [
|
$graphData = $this->makeGraphData(
|
||||||
'dailySum' => $dailySum,
|
$user,
|
||||||
'dowSum' => $dowSum,
|
Carbon::createFromDate($year, 1, 1, config('app.timezone'))->startOfDay(),
|
||||||
'monthlySum' => $monthlySum,
|
Carbon::createFromDate($year, 1, 1, config('app.timezone'))->addYear()->startOfDay()
|
||||||
'yearlyKey' => array_keys($yearlySum),
|
);
|
||||||
'yearlySum' => array_values($yearlySum),
|
|
||||||
'hourlyKey' => array_keys($hourlySum),
|
|
||||||
'hourlySum' => array_values($hourlySum),
|
|
||||||
];
|
|
||||||
|
|
||||||
return view('user.stats')->with(compact('user', 'graphData'));
|
return view('user.stats.yearly')
|
||||||
|
->with(compact('user', 'graphData', 'availableMonths'))
|
||||||
|
->with('currentYear', (int) $year);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statsMonthly($name, $year, $month)
|
||||||
|
{
|
||||||
|
$user = User::where('name', $name)->first();
|
||||||
|
if (empty($user)) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = Validator::make(compact('year', 'month'), [
|
||||||
|
'year' => 'required|date_format:Y',
|
||||||
|
'month' => 'required|date_format:m'
|
||||||
|
]);
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return redirect()->route('user.stats.yearly', compact('name', 'year'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$availableMonths = $this->makeStatsAvailableMonths($user);
|
||||||
|
if (!isset($availableMonths[$year]) || !in_array($month, $availableMonths[$year], false)) {
|
||||||
|
return redirect()->route('user.stats.yearly', compact('name', 'year'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$graphData = $this->makeGraphData(
|
||||||
|
$user,
|
||||||
|
Carbon::createFromDate($year, $month, 1, config('app.timezone'))->startOfDay(),
|
||||||
|
Carbon::createFromDate($year, $month, 1, config('app.timezone'))->addMonth()->startOfDay()
|
||||||
|
);
|
||||||
|
|
||||||
|
return view('user.stats.monthly')
|
||||||
|
->with(compact('user', 'graphData', 'availableMonths'))
|
||||||
|
->with('currentYear', (int) $year)
|
||||||
|
->with('currentMonth', (int) $month);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function okazu($name)
|
public function okazu($name)
|
||||||
@ -191,4 +203,104 @@ SQL
|
|||||||
|
|
||||||
return view('user.likes')->with(compact('user', 'likes'));
|
return view('user.likes')->with(compact('user', 'likes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function makeStatsAvailableMonths(User $user): array
|
||||||
|
{
|
||||||
|
$availableMonths = [];
|
||||||
|
$oldest = $user->ejaculations()->orderBy('ejaculated_date')->first();
|
||||||
|
if (isset($oldest)) {
|
||||||
|
$oldestMonth = $oldest->ejaculated_date->startOfMonth();
|
||||||
|
$currentMonth = now()->startOfMonth();
|
||||||
|
for ($month = $currentMonth; $oldestMonth <= $currentMonth; $month = $month->subMonth()) {
|
||||||
|
if (!isset($availableMonths[$month->year])) {
|
||||||
|
$availableMonths[$month->year] = [];
|
||||||
|
}
|
||||||
|
$availableMonths[$month->year][] = $month->month;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $availableMonths;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function makeGraphData(User $user, CarbonInterface $dateSince = null, CarbonInterface $dateUntil = null): array
|
||||||
|
{
|
||||||
|
if ($dateUntil === null) {
|
||||||
|
$dateUntil = now()->addMonth()->startOfMonth();
|
||||||
|
}
|
||||||
|
$dateCondition = [
|
||||||
|
['ejaculated_date', '<', $dateUntil],
|
||||||
|
];
|
||||||
|
if ($dateSince !== null) {
|
||||||
|
$dateCondition[] = ['ejaculated_date', '>=', $dateSince];
|
||||||
|
}
|
||||||
|
|
||||||
|
$groupByDay = $this->countEjaculationByDay($user)
|
||||||
|
->where($dateCondition)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$groupByHour = Ejaculation::select(DB::raw(
|
||||||
|
<<<'SQL'
|
||||||
|
to_char(ejaculated_date, 'HH24') AS "hour",
|
||||||
|
count(*) AS "count"
|
||||||
|
SQL
|
||||||
|
))
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->where($dateCondition)
|
||||||
|
->groupBy(DB::raw("to_char(ejaculated_date, 'HH24')"))
|
||||||
|
->orderBy(DB::raw('1'))
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$dailySum = [];
|
||||||
|
$monthlySum = [];
|
||||||
|
$yearlySum = [];
|
||||||
|
$dowSum = array_fill(0, 7, 0);
|
||||||
|
$hourlySum = array_fill(0, 24, 0);
|
||||||
|
|
||||||
|
// 年間グラフ用の配列初期化
|
||||||
|
if ($groupByDay->first() !== null) {
|
||||||
|
$year = Carbon::createFromFormat('Y/m/d', $groupByDay->first()->date)->year;
|
||||||
|
$currentYear = date('Y');
|
||||||
|
for (; $year <= $currentYear; $year++) {
|
||||||
|
$yearlySum[$year] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($groupByDay as $data) {
|
||||||
|
$date = Carbon::createFromFormat('Y/m/d', $data->date);
|
||||||
|
$yearAndMonth = $date->format('Y/m');
|
||||||
|
|
||||||
|
$dailySum[$date->timestamp] = $data->count;
|
||||||
|
$yearlySum[$date->year] += $data->count;
|
||||||
|
$dowSum[$date->dayOfWeek] += $data->count;
|
||||||
|
$monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($groupByHour as $data) {
|
||||||
|
$hour = (int)$data->hour;
|
||||||
|
$hourlySum[$hour] += $data->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'dailySum' => $dailySum,
|
||||||
|
'dowSum' => $dowSum,
|
||||||
|
'monthlySum' => $monthlySum,
|
||||||
|
'yearlyKey' => array_keys($yearlySum),
|
||||||
|
'yearlySum' => array_values($yearlySum),
|
||||||
|
'hourlyKey' => array_keys($hourlySum),
|
||||||
|
'hourlySum' => array_values($hourlySum),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function countEjaculationByDay(User $user)
|
||||||
|
{
|
||||||
|
return Ejaculation::select(DB::raw(
|
||||||
|
<<<'SQL'
|
||||||
|
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
|
||||||
|
count(*) AS "count"
|
||||||
|
SQL
|
||||||
|
))
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
|
||||||
|
->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
15
resources/assets/js/user/profile.js
vendored
Normal file
15
resources/assets/js/user/profile.js
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import CalHeatMap from 'cal-heatmap';
|
||||||
|
|
||||||
|
if (document.getElementById('cal-heatmap')) {
|
||||||
|
new CalHeatMap().init({
|
||||||
|
itemSelector: '#cal-heatmap',
|
||||||
|
domain: 'month',
|
||||||
|
subDomain: 'day',
|
||||||
|
domainLabelFormat: '%Y/%m',
|
||||||
|
weekStartOnMonday: false,
|
||||||
|
start: new Date().setMonth(new Date().getMonth() - 9),
|
||||||
|
range: 10,
|
||||||
|
data: JSON.parse(document.getElementById('count-by-day').textContent),
|
||||||
|
legend: [1, 2, 3, 4]
|
||||||
|
});
|
||||||
|
}
|
78
resources/assets/js/user/stats.js
vendored
78
resources/assets/js/user/stats.js
vendored
@ -1,6 +1,6 @@
|
|||||||
import CalHeatMap from 'cal-heatmap';
|
import CalHeatMap from 'cal-heatmap';
|
||||||
import Chart from 'chart.js';
|
import Chart from 'chart.js';
|
||||||
import {addMonths, format, startOfMonth, subMonths} from 'date-fns';
|
import {addMonths, format} from 'date-fns';
|
||||||
|
|
||||||
const graphData = JSON.parse(document.getElementById('graph-data').textContent);
|
const graphData = JSON.parse(document.getElementById('graph-data').textContent);
|
||||||
|
|
||||||
@ -90,53 +90,35 @@ function createMonthlyGraphData(from) {
|
|||||||
return {keys, values};
|
return {keys, values};
|
||||||
}
|
}
|
||||||
|
|
||||||
new CalHeatMap().init({
|
function getCurrentYear() {
|
||||||
itemSelector: '#cal-heatmap',
|
const year = location.pathname.split('/').pop();
|
||||||
domain: 'month',
|
return /^(20[0-9]{2})$/.test(year) ? year : null;
|
||||||
subDomain: 'day',
|
|
||||||
domainLabelFormat: '%Y/%m',
|
|
||||||
weekStartOnMonday: false,
|
|
||||||
start: new Date().setMonth(new Date().getMonth() - 9),
|
|
||||||
range: 10,
|
|
||||||
data: graphData.dailySum,
|
|
||||||
legend: [1, 2, 3, 4]
|
|
||||||
});
|
|
||||||
|
|
||||||
// 直近1年の月間グラフのデータを準備
|
|
||||||
const monthlyTermFrom = subMonths(startOfMonth(new Date()), 11);
|
|
||||||
const {keys: monthlyKey, values: monthlySum} = createMonthlyGraphData(monthlyTermFrom);
|
|
||||||
|
|
||||||
const monthlyGraph = createLineGraph('monthly-graph', monthlyKey, monthlySum);
|
|
||||||
createLineGraph('yearly-graph', graphData.yearlyKey, graphData.yearlySum);
|
|
||||||
createBarGraph('hourly-graph', graphData.hourlyKey, graphData.hourlySum);
|
|
||||||
createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], graphData.dowSum);
|
|
||||||
|
|
||||||
// 月間グラフの期間セレクターを準備
|
|
||||||
const monthlyTermSelector = document.getElementById('monthly-term');
|
|
||||||
const earliestYear = [...new Set(Object.keys(graphData.monthlySum).map(v => v.substr(0, 4)))].shift();
|
|
||||||
for (let year = earliestYear; year <= new Date().getFullYear(); year++) {
|
|
||||||
const opt = document.createElement('option');
|
|
||||||
opt.setAttribute('value', year);
|
|
||||||
opt.textContent = `${year}年`;
|
|
||||||
monthlyTermSelector.insertBefore(opt, monthlyTermSelector.firstChild);
|
|
||||||
}
|
|
||||||
if (monthlyTermSelector.children.length) {
|
|
||||||
monthlyTermSelector.selectedIndex = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
monthlyTermSelector.addEventListener('change', function (e) {
|
if (document.getElementById('cal-heatmap')) {
|
||||||
let monthlyTermFrom;
|
new CalHeatMap().init({
|
||||||
if (e.target.selectedIndex === 0) {
|
itemSelector: '#cal-heatmap',
|
||||||
// 今年のデータを表示する時は、直近12ヶ月を表示
|
domain: 'month',
|
||||||
monthlyTermFrom = subMonths(startOfMonth(new Date()), 11);
|
subDomain: 'day',
|
||||||
} else {
|
domainLabelFormat: '%Y/%m',
|
||||||
// 過去のデータを表示する時は、選択年の1〜12月を表示
|
weekStartOnMonday: false,
|
||||||
monthlyTermFrom = new Date(e.target.value, 0, 1);
|
start: new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0),
|
||||||
}
|
range: 12,
|
||||||
|
data: graphData.dailySum,
|
||||||
|
legend: [1, 2, 3, 4]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const {keys, values} = createMonthlyGraphData(monthlyTermFrom);
|
if (document.getElementById('monthly-graph')) {
|
||||||
|
const {keys: monthlyKey, values: monthlySum} = createMonthlyGraphData(new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0));
|
||||||
monthlyGraph.data.labels = keys;
|
createLineGraph('monthly-graph', monthlyKey, monthlySum);
|
||||||
monthlyGraph.data.datasets[0].data = values;
|
}
|
||||||
monthlyGraph.update();
|
if (document.getElementById('yearly-graph')) {
|
||||||
});
|
createLineGraph('yearly-graph', graphData.yearlyKey, graphData.yearlySum);
|
||||||
|
}
|
||||||
|
if (document.getElementById('hourly-graph')) {
|
||||||
|
createBarGraph('hourly-graph', graphData.hourlyKey, graphData.hourlySum);
|
||||||
|
}
|
||||||
|
if (document.getElementById('dow-graph')) {
|
||||||
|
createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], graphData.dowSum);
|
||||||
|
}
|
||||||
|
14
resources/views/components/profile-mini.blade.php
Normal file
14
resources/views/components/profile-mini.blade.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<div class="d-flex flex-row align-items-end {{ $class ?? '' }}">
|
||||||
|
<img src="{{ $user->getProfileImageUrl(48) }}" srcset="{{ Formatter::profileImageSrcSet($user, 48) }}" class="rounded mr-2">
|
||||||
|
<div class="d-flex flex-column overflow-hidden">
|
||||||
|
<h5 class="card-title text-truncate">
|
||||||
|
<a class="text-dark" href="{{ route('user.profile', ['name' => $user->name]) }}">{{ $user->display_name }}</a>
|
||||||
|
</h5>
|
||||||
|
<h6 class="card-subtitle">
|
||||||
|
<a class="text-muted" href="{{ route('user.profile', ['name' => $user->name]) }}">@{{ $user->name }}</a>
|
||||||
|
@if ($user->is_protected)
|
||||||
|
<span class="oi oi-lock-locked text-muted"></span>
|
||||||
|
@endif
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -9,20 +9,8 @@
|
|||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex flex-row align-items-end mb-4">
|
@component('components.profile-mini', ['user' => Auth::user(), 'class' => 'mb-4'])
|
||||||
<img src="{{ Auth::user()->getProfileImageUrl(48) }}" srcset="{{ Formatter::profileImageSrcSet(Auth::user(), 48) }}" class="rounded mr-2">
|
@endcomponent
|
||||||
<div class="d-flex flex-column overflow-hidden">
|
|
||||||
<h5 class="card-title text-truncate">
|
|
||||||
<a class="text-dark" href="{{ route('user.profile', ['name' => Auth::user()->name]) }}">{{ Auth::user()->display_name }}</a>
|
|
||||||
</h5>
|
|
||||||
<h6 class="card-subtitle">
|
|
||||||
<a class="text-muted" href="{{ route('user.profile', ['name' => Auth::user()->name]) }}">@{{ Auth::user()->name }}</a>
|
|
||||||
@if (Auth::user()->is_protected)
|
|
||||||
<span class="oi oi-lock-locked text-muted"></span>
|
|
||||||
@endif
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@component('components.profile-stats', ['user' => Auth::user()])
|
@component('components.profile-stats', ['user' => Auth::user()])
|
||||||
@endcomponent
|
@endcomponent
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,8 +4,17 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
@component('components.profile', ['user' => $user])
|
@if (Route::currentRouteName() === 'user.profile')
|
||||||
@endcomponent
|
@component('components.profile', ['user' => $user])
|
||||||
|
@endcomponent
|
||||||
|
@else
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
@component('components.profile-mini', ['user' => $user])
|
||||||
|
@endcomponent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
@section('sidebar')
|
@section('sidebar')
|
||||||
@show
|
@show
|
||||||
</div>
|
</div>
|
||||||
@ -15,7 +24,7 @@
|
|||||||
<a class="nav-link {{ Route::currentRouteName() === 'user.profile' ? 'active' : '' }}" href="{{ route('user.profile', ['name' => $user->name]) }}">タイムライン</a>
|
<a class="nav-link {{ Route::currentRouteName() === 'user.profile' ? 'active' : '' }}" href="{{ route('user.profile', ['name' => $user->name]) }}">タイムライン</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ Route::currentRouteName() === 'user.stats' ? 'active' : '' }}" href="{{ route('user.stats', ['name' => $user->name]) }}">グラフ</a>
|
<a class="nav-link {{ stripos(Route::currentRouteName(), 'user.stats') === 0 ? 'active' : '' }}" href="{{ route('user.stats', ['name' => $user->name]) }}">グラフ</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{ Route::currentRouteName() === 'user.okazu' ? 'active' : '' }}" href="{{ route('user.okazu', ['name' => $user->name]) }}">オカズ</a>
|
<a class="nav-link {{ Route::currentRouteName() === 'user.okazu' ? 'active' : '' }}" href="{{ route('user.okazu', ['name' => $user->name]) }}">オカズ</a>
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
@section('title', $user->display_name . ' (@' . $user->name . ')')
|
@section('title', $user->display_name . ' (@' . $user->name . ')')
|
||||||
|
|
||||||
|
@push('head')
|
||||||
|
@if (Route::currentRouteName() === 'user.profile')
|
||||||
|
<link rel="stylesheet" href="//cdn.jsdelivr.net/cal-heatmap/3.3.10/cal-heatmap.css" />
|
||||||
|
@endif
|
||||||
|
@endpush
|
||||||
|
|
||||||
@section('sidebar')
|
@section('sidebar')
|
||||||
{{-- TODO: タイムラインとオカズのテンプレを分けたら条件外す --}}
|
{{-- TODO: タイムラインとオカズのテンプレを分けたら条件外す --}}
|
||||||
@if (Route::currentRouteName() === 'user.profile')
|
@if (Route::currentRouteName() === 'user.profile')
|
||||||
@ -32,6 +38,11 @@
|
|||||||
<span class="oi oi-lock-locked"></span> このユーザはチェックイン履歴を公開していません。
|
<span class="oi oi-lock-locked"></span> このユーザはチェックイン履歴を公開していません。
|
||||||
</p>
|
</p>
|
||||||
@else
|
@else
|
||||||
|
@if ($ejaculations->count() !== 0 && $ejaculations->currentPage() === 1)
|
||||||
|
<h5 class="mx-4 my-3">Shikontributions</h5>
|
||||||
|
<div id="cal-heatmap" class="tis-contribution-graph mx-4 mt-3"></div>
|
||||||
|
<hr class="mt-4 mb-2">
|
||||||
|
@endif
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
@forelse ($ejaculations as $ejaculation)
|
@forelse ($ejaculations as $ejaculation)
|
||||||
<li class="list-group-item border-bottom-only pt-3 pb-3 text-break">
|
<li class="list-group-item border-bottom-only pt-3 pb-3 text-break">
|
||||||
@ -116,3 +127,10 @@
|
|||||||
@endslot
|
@endslot
|
||||||
@endcomponent
|
@endcomponent
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@push('script')
|
||||||
|
<script id="count-by-day" type="application/json">@json($countByDay)</script>
|
||||||
|
<script src="{{ mix('js/vendor/chart.js') }}"></script>
|
||||||
|
<script src="{{ mix('js/user/profile.js') }}"></script>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
70
resources/views/user/stats/base.blade.php
Normal file
70
resources/views/user/stats/base.blade.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
@extends('user.base')
|
||||||
|
|
||||||
|
@section('sidebar')
|
||||||
|
@if (!$user->is_protected || $user->isMe())
|
||||||
|
<div class="nav d-none d-lg-flex flex-column nav-pills" aria-orientation="vertical">
|
||||||
|
<a class="nav-link {{ Route::currentRouteName() === 'user.stats' ? 'active' : '' }}"
|
||||||
|
href="{{ route('user.stats', ['name' => $user->name]) }}">全期間</a>
|
||||||
|
@foreach ($availableMonths as $year => $months)
|
||||||
|
<div class="border-top mt-1">
|
||||||
|
<a class="nav-link mt-1 {{ Route::currentRouteName() === 'user.stats.yearly' && $currentYear === $year ? 'active' : '' }}"
|
||||||
|
href="{{ route('user.stats.yearly', ['name' => $user->name, 'year' => $year]) }}">{{ $year }}年</a>
|
||||||
|
@foreach ($months as $month)
|
||||||
|
<a class="nav-link ml-3 {{ Route::currentRouteName() === 'user.stats.monthly' && $currentYear === $year && $currentMonth === $month ? 'active' : '' }}"
|
||||||
|
href="{{ route('user.stats.monthly', ['name' => $user->name, 'year' => $year, 'month' => $month]) }}">{{ $month }}月</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('tab-content')
|
||||||
|
@if ($user->is_protected && !$user->isMe())
|
||||||
|
<p class="mt-4">
|
||||||
|
<span class="oi oi-lock-locked"></span> このユーザはチェックイン履歴を公開していません。
|
||||||
|
</p>
|
||||||
|
@else
|
||||||
|
<div class="row my-2 d-lg-none">
|
||||||
|
<div class="col-12 text-secondary font-weight-bold small">グラフの対象期間</div>
|
||||||
|
<div class="col-6 text-secondary small">年</div>
|
||||||
|
<div class="col-6 text-secondary small">月</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<ul class="nav nav-pills nav-fill">
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||||
|
{{ Route::currentRouteName() === 'user.stats' ? '全期間' : "{$currentYear}年" }}
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a href="{{ route('user.stats', ['name' => $user->name]) }}" class="dropdown-item">全期間</a>
|
||||||
|
@foreach ($availableMonths as $year => $months)
|
||||||
|
<a href="{{ route('user.stats.yearly', ['name' => $user->name, 'year' => $year]) }}" class="dropdown-item">{{ $year }}年</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
@if (Route::currentRouteName() === 'user.stats')
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle disabled"
|
||||||
|
href="#" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">全期間</a>
|
||||||
|
</li>
|
||||||
|
@else
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle"
|
||||||
|
href="#" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||||
|
{{ Route::currentRouteName() === 'user.stats.yearly' ? '全期間' : "{$currentMonth}月" }}
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a href="{{ route('user.stats.yearly', ['name' => $user->name, 'year' => $currentYear]) }}" class="dropdown-item">全期間</a>
|
||||||
|
@foreach ($availableMonths[$currentYear] as $month)
|
||||||
|
<a href="{{ route('user.stats.monthly', ['name' => $user->name, 'year' => $currentYear, 'month' => $month]) }}" class="dropdown-item">{{ $month }}月</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row d-lg-none no-gutters border-bottom"></div>
|
||||||
|
@yield('stats-content')
|
||||||
|
@endif
|
||||||
|
@endsection
|
20
resources/views/user/stats/index.blade.php
Normal file
20
resources/views/user/stats/index.blade.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@extends('user.stats.base')
|
||||||
|
|
||||||
|
@section('title', $user->display_name . ' さんのグラフ')
|
||||||
|
|
||||||
|
@section('stats-content')
|
||||||
|
<h5 class="my-4">年間チェックイン回数</h5>
|
||||||
|
<canvas id="yearly-graph" class="w-100"></canvas>
|
||||||
|
<hr class="my-4">
|
||||||
|
<h5 class="my-4">時間別チェックイン回数</h5>
|
||||||
|
<canvas id="hourly-graph" class="w-100"></canvas>
|
||||||
|
<hr class="my-4">
|
||||||
|
<h5 class="my-4">曜日別チェックイン回数</h5>
|
||||||
|
<canvas id="dow-graph" class="w-100"></canvas>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('script')
|
||||||
|
<script id="graph-data" type="application/json">@json($graphData)</script>
|
||||||
|
<script src="{{ mix('js/vendor/chart.js') }}"></script>
|
||||||
|
<script src="{{ mix('js/user/stats.js') }}"></script>
|
||||||
|
@endpush
|
17
resources/views/user/stats/monthly.blade.php
Normal file
17
resources/views/user/stats/monthly.blade.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@extends('user.stats.base')
|
||||||
|
|
||||||
|
@section('title', $user->display_name . ' さんのグラフ')
|
||||||
|
|
||||||
|
@section('stats-content')
|
||||||
|
<h5 class="my-4">時間別チェックイン回数</h5>
|
||||||
|
<canvas id="hourly-graph" class="w-100"></canvas>
|
||||||
|
<hr class="my-4">
|
||||||
|
<h5 class="my-4">曜日別チェックイン回数</h5>
|
||||||
|
<canvas id="dow-graph" class="w-100"></canvas>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('script')
|
||||||
|
<script id="graph-data" type="application/json">@json($graphData)</script>
|
||||||
|
<script src="{{ mix('js/vendor/chart.js') }}"></script>
|
||||||
|
<script src="{{ mix('js/user/stats.js') }}"></script>
|
||||||
|
@endpush
|
@ -1,4 +1,4 @@
|
|||||||
@extends('user.base')
|
@extends('user.stats.base')
|
||||||
|
|
||||||
@section('title', $user->display_name . ' さんのグラフ')
|
@section('title', $user->display_name . ' さんのグラフ')
|
||||||
|
|
||||||
@ -6,34 +6,18 @@
|
|||||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/cal-heatmap/3.3.10/cal-heatmap.css" />
|
<link rel="stylesheet" href="//cdn.jsdelivr.net/cal-heatmap/3.3.10/cal-heatmap.css" />
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('tab-content')
|
@section('stats-content')
|
||||||
@if ($user->is_protected && !$user->isMe())
|
|
||||||
<p class="mt-4">
|
|
||||||
<span class="oi oi-lock-locked"></span> このユーザはチェックイン履歴を公開していません。
|
|
||||||
</p>
|
|
||||||
@else
|
|
||||||
<h5 class="my-4">Shikontribution graph</h5>
|
<h5 class="my-4">Shikontribution graph</h5>
|
||||||
<div id="cal-heatmap" class="tis-contribution-graph"></div>
|
<div id="cal-heatmap" class="tis-contribution-graph"></div>
|
||||||
<hr class="my-4">
|
<hr class="my-4">
|
||||||
<div class="row my-4">
|
<h5 class="my-4">月間チェックイン回数</h5>
|
||||||
<div class="col-12 col-lg-6 d-flex align-items-center">
|
|
||||||
<h5 class="my-0">月間チェックイン回数</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-6 mt-2 mt-lg-0">
|
|
||||||
<select id="monthly-term" class="form-control"></select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<canvas id="monthly-graph" class="w-100"></canvas>
|
<canvas id="monthly-graph" class="w-100"></canvas>
|
||||||
<hr class="my-4">
|
<hr class="my-4">
|
||||||
<h5 class="my-4">年間チェックイン回数</h5>
|
|
||||||
<canvas id="yearly-graph" class="w-100"></canvas>
|
|
||||||
<hr class="my-4">
|
|
||||||
<h5 class="my-4">時間別チェックイン回数</h5>
|
<h5 class="my-4">時間別チェックイン回数</h5>
|
||||||
<canvas id="hourly-graph" class="w-100"></canvas>
|
<canvas id="hourly-graph" class="w-100"></canvas>
|
||||||
<hr class="my-4">
|
<hr class="my-4">
|
||||||
<h5 class="my-4">曜日別チェックイン回数</h5>
|
<h5 class="my-4">曜日別チェックイン回数</h5>
|
||||||
<canvas id="dow-graph" class="w-100"></canvas>
|
<canvas id="dow-graph" class="w-100"></canvas>
|
||||||
@endif
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@push('script')
|
@push('script')
|
@ -18,6 +18,8 @@ Route::get('/', 'HomeController@index')->name('home');
|
|||||||
Route::get('/user', 'UserController@redirectMypage')->middleware('auth');
|
Route::get('/user', 'UserController@redirectMypage')->middleware('auth');
|
||||||
Route::get('/user/{name?}', 'UserController@profile')->name('user.profile');
|
Route::get('/user/{name?}', 'UserController@profile')->name('user.profile');
|
||||||
Route::get('/user/{name}/stats', 'UserController@stats')->name('user.stats');
|
Route::get('/user/{name}/stats', 'UserController@stats')->name('user.stats');
|
||||||
|
Route::get('/user/{name}/stats/{year}', 'UserController@statsYearly')->name('user.stats.yearly');
|
||||||
|
Route::get('/user/{name}/stats/{year}/{month}', 'UserController@statsMonthly')->name('user.stats.monthly');
|
||||||
Route::get('/user/{name}/okazu', 'UserController@okazu')->name('user.okazu');
|
Route::get('/user/{name}/okazu', 'UserController@okazu')->name('user.okazu');
|
||||||
Route::get('/user/{name}/likes', 'UserController@likes')->name('user.likes');
|
Route::get('/user/{name}/likes', 'UserController@likes')->name('user.likes');
|
||||||
|
|
||||||
|
1
webpack.mix.js
vendored
1
webpack.mix.js
vendored
@ -14,6 +14,7 @@ require('laravel-mix-bundle-analyzer')
|
|||||||
|
|
||||||
mix.js('resources/assets/js/app.js', 'public/js')
|
mix.js('resources/assets/js/app.js', 'public/js')
|
||||||
.js('resources/assets/js/home.js', 'public/js')
|
.js('resources/assets/js/home.js', 'public/js')
|
||||||
|
.js('resources/assets/js/user/profile.js', 'public/js/user')
|
||||||
.js('resources/assets/js/user/stats.js', 'public/js/user')
|
.js('resources/assets/js/user/stats.js', 'public/js/user')
|
||||||
.js('resources/assets/js/setting/privacy.js', 'public/js/setting')
|
.js('resources/assets/js/setting/privacy.js', 'public/js/setting')
|
||||||
.js('resources/assets/js/setting/import.js', 'public/js/setting')
|
.js('resources/assets/js/setting/import.js', 'public/js/setting')
|
||||||
|
Loading…
Reference in New Issue
Block a user