mirror of
https://github.com/pixelfed/pixelfed.git
synced 2025-01-11 14:40:46 +00:00
Merge branch 'dev' into patch-4
This commit is contained in:
commit
f69dfb0364
48 changed files with 4662 additions and 275 deletions
|
@ -1,6 +1,7 @@
|
||||||
storage
|
storage
|
||||||
data
|
data
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
docker-compose*.yml
|
||||||
.dockerignore
|
.dockerignore
|
||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
|
|
38
Dockerfile
38
Dockerfile
|
@ -1,17 +1,31 @@
|
||||||
FROM php:7.2-fpm-alpine
|
FROM php:7.2.6-fpm-alpine
|
||||||
|
|
||||||
RUN apk add --no-cache git imagemagick \
|
ARG COMPOSER_VERSION="1.6.5"
|
||||||
&& apk add --no-cache --virtual .build build-base autoconf imagemagick-dev libtool \
|
ARG COMPOSER_CHECKSUM="67bebe9df9866a795078bb2cf21798d8b0214f2e0b2fd81f2e907a8ef0be3434"
|
||||||
&& docker-php-ext-install pdo_mysql pcntl \
|
|
||||||
&& pecl install imagick \
|
|
||||||
&& docker-php-ext-enable imagick \
|
|
||||||
&& apk del --purge .build
|
|
||||||
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php \
|
RUN apk add --no-cache --virtual .build build-base autoconf imagemagick-dev libtool && \
|
||||||
&& mv composer.phar /usr/local/bin/ \
|
apk --no-cache add imagemagick git && \
|
||||||
&& ln -s /usr/local/bin/composer.phar /usr/local/bin/composer
|
docker-php-ext-install pdo_mysql pcntl && \
|
||||||
|
pecl install imagick && \
|
||||||
|
docker-php-ext-enable imagick pcntl imagick && \
|
||||||
|
curl -LsS https://getcomposer.org/download/${COMPOSER_VERSION}/composer.phar -o /tmp/composer.phar && \
|
||||||
|
echo "${COMPOSER_CHECKSUM} /tmp/composer.phar" | sha256sum -c - && \
|
||||||
|
install -m0755 -o root -g root /tmp/composer.phar /usr/bin/composer.phar && \
|
||||||
|
ln -sf /usr/bin/composer.phar /usr/bin/composer && \
|
||||||
|
rm /tmp/composer.phar && \
|
||||||
|
apk --no-cache del --purge .build
|
||||||
|
|
||||||
|
COPY . /var/www/html/
|
||||||
|
|
||||||
WORKDIR /var/www/html
|
WORKDIR /var/www/html
|
||||||
COPY . .
|
RUN install -d -m0755 -o www-data -g www-data \
|
||||||
RUN composer install --prefer-source --no-interaction
|
/var/www/html/storage \
|
||||||
|
/var/www/html/storage/framework \
|
||||||
|
/var/www/html/storage/logs \
|
||||||
|
/var/www/html/storage/framework/sessions \
|
||||||
|
/var/www/html/storage/framework/views \
|
||||||
|
/var/www/html/storage/framework/cache && \
|
||||||
|
composer install --prefer-source --no-interaction
|
||||||
|
|
||||||
|
VOLUME ["/var/www/html"]
|
||||||
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"
|
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"
|
||||||
|
|
|
@ -16,7 +16,9 @@ class AccountController extends Controller
|
||||||
public function notifications(Request $request)
|
public function notifications(Request $request)
|
||||||
{
|
{
|
||||||
$profile = Auth::user()->profile;
|
$profile = Auth::user()->profile;
|
||||||
$notifications = $this->fetchNotifications($profile->id);
|
//$notifications = $this->fetchNotifications($profile->id);
|
||||||
|
$notifications = Notification::whereProfileId($profile->id)
|
||||||
|
->orderBy('id','desc')->take(30)->simplePaginate();
|
||||||
return view('account.activity', compact('profile', 'notifications'));
|
return view('account.activity', compact('profile', 'notifications'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
app/Http/Controllers/ApiController.php
Normal file
32
app/Http/Controllers/ApiController.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use App\Like;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ApiController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hydrateLikes(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'min' => 'nullable|integer|min:1',
|
||||||
|
'max' => 'nullable|integer',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$profile = Auth::user()->profile;
|
||||||
|
|
||||||
|
$likes = Like::whereProfileId($profile->id)
|
||||||
|
->orderBy('id', 'desc')
|
||||||
|
->take(1000)
|
||||||
|
->pluck('status_id');
|
||||||
|
|
||||||
|
return response()->json($likes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,12 +3,21 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use App\Jobs\CommentPipeline\CommentPipeline;
|
||||||
use App\Jobs\StatusPipeline\NewStatusPipeline;
|
use App\Jobs\StatusPipeline\NewStatusPipeline;
|
||||||
use Auth, Hashids;
|
use Auth, Hashids;
|
||||||
use App\{Comment, Profile, Status};
|
use App\{Comment, Profile, Status};
|
||||||
|
|
||||||
class CommentController extends Controller
|
class CommentController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function show(Request $request, $username, int $id, int $cid)
|
||||||
|
{
|
||||||
|
$user = Profile::whereUsername($username)->firstOrFail();
|
||||||
|
$status = Status::whereProfileId($user->id)->whereInReplyToId($id)->findOrFail($cid);
|
||||||
|
return view('status.reply', compact('user', 'status'));
|
||||||
|
}
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
if(Auth::check() === false) { abort(403); }
|
if(Auth::check() === false) { abort(403); }
|
||||||
|
@ -32,9 +41,10 @@ class CommentController extends Controller
|
||||||
$reply->save();
|
$reply->save();
|
||||||
|
|
||||||
NewStatusPipeline::dispatch($reply, false);
|
NewStatusPipeline::dispatch($reply, false);
|
||||||
|
CommentPipeline::dispatch($status, $reply);
|
||||||
|
|
||||||
if($request->ajax()) {
|
if($request->ajax()) {
|
||||||
$response = ['code' => 200, 'msg' => 'Comment saved'];
|
$response = ['code' => 200, 'msg' => 'Comment saved', 'username' => $profile->username, 'url' => $reply->url(), 'profile' => $profile->url()];
|
||||||
} else {
|
} else {
|
||||||
$response = redirect($status->url());
|
$response = redirect($status->url());
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,21 +21,30 @@ class LikeController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$profile = Auth::user()->profile;
|
$profile = Auth::user()->profile;
|
||||||
$status = Status::findOrFail($request->input('item'));
|
$status = Status::withCount('likes')->findOrFail($request->input('item'));
|
||||||
|
|
||||||
|
$count = $status->likes_count;
|
||||||
|
|
||||||
if($status->likes()->whereProfileId($profile->id)->count() !== 0) {
|
if($status->likes()->whereProfileId($profile->id)->count() !== 0) {
|
||||||
$like = Like::whereProfileId($profile->id)->whereStatusId($status->id)->firstOrFail();
|
$like = Like::whereProfileId($profile->id)->whereStatusId($status->id)->firstOrFail();
|
||||||
$like->delete();
|
$like->delete();
|
||||||
return redirect()->back();
|
$count--;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
$like = new Like;
|
$like = new Like;
|
||||||
$like->profile_id = $profile->id;
|
$like->profile_id = $profile->id;
|
||||||
$like->status_id = $status->id;
|
$like->status_id = $status->id;
|
||||||
$like->save();
|
$like->save();
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
|
||||||
LikePipeline::dispatch($like);
|
LikePipeline::dispatch($like);
|
||||||
|
|
||||||
return redirect($status->url());
|
if($request->ajax()) {
|
||||||
|
$response = ['code' => 200, 'msg' => 'Like saved', 'count' => $count];
|
||||||
|
} else {
|
||||||
|
$response = redirect($status->url());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,12 @@ class ProfileController extends Controller
|
||||||
// TODO: refactor this mess
|
// TODO: refactor this mess
|
||||||
$owner = Auth::check() && Auth::id() === $user->user_id;
|
$owner = Auth::check() && Auth::id() === $user->user_id;
|
||||||
$following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
|
$following = ($owner == false && Auth::check()) ? $user->followedBy(Auth::user()->profile) : false;
|
||||||
$timeline = $user->statuses()->whereHas('media')->whereNull('in_reply_to_id')->orderBy('id','desc')->paginate(21);
|
$timeline = $user->statuses()
|
||||||
|
->whereHas('media')
|
||||||
|
->whereNull('in_reply_to_id')
|
||||||
|
->orderBy('id','desc')
|
||||||
|
->withCount(['comments', 'likes'])
|
||||||
|
->simplePaginate(21);
|
||||||
|
|
||||||
return view('profile.show', compact('user', 'owner', 'following', 'timeline'));
|
return view('profile.show', compact('user', 'owner', 'following', 'timeline'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,11 @@ class StatusController extends Controller
|
||||||
public function show(Request $request, $username, int $id)
|
public function show(Request $request, $username, int $id)
|
||||||
{
|
{
|
||||||
$user = Profile::whereUsername($username)->firstOrFail();
|
$user = Profile::whereUsername($username)->firstOrFail();
|
||||||
$status = Status::whereProfileId($user->id)->findOrFail($id);
|
$status = Status::whereProfileId($user->id)
|
||||||
|
->withCount('likes')
|
||||||
|
->findOrFail($id);
|
||||||
if(!$status->media_path && $status->in_reply_to_id) {
|
if(!$status->media_path && $status->in_reply_to_id) {
|
||||||
return view('status.reply', compact('user', 'status'));
|
return redirect($status->url());
|
||||||
}
|
}
|
||||||
return view('status.show', compact('user', 'status'));
|
return view('status.show', compact('user', 'status'));
|
||||||
}
|
}
|
||||||
|
@ -30,8 +32,8 @@ class StatusController extends Controller
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'photo' => 'required|image|max:15000',
|
'photo' => 'required|mimes:jpeg,png,bmp,gif|max:' . config('pixelfed.max_photo_size'),
|
||||||
'caption' => 'string|max:150'
|
'caption' => 'string|max:' . config('pixelfed.max_caption_length')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$monthHash = hash('sha1', date('Y') . date('m'));
|
$monthHash = hash('sha1', date('Y') . date('m'));
|
||||||
|
|
|
@ -17,14 +17,24 @@ class TimelineController extends Controller
|
||||||
{
|
{
|
||||||
// TODO: Use redis for timelines
|
// TODO: Use redis for timelines
|
||||||
$following = Follower::whereProfileId(Auth::user()->profile->id)->pluck('following_id');
|
$following = Follower::whereProfileId(Auth::user()->profile->id)->pluck('following_id');
|
||||||
$timeline = Status::whereHas('media')->whereNull('in_reply_to_id')->whereIn('profile_id', $following)->orderBy('id','desc')->simplePaginate(10);
|
$following->push(Auth::user()->profile->id);
|
||||||
|
$timeline = Status::whereHas('media')
|
||||||
|
->whereNull('in_reply_to_id')
|
||||||
|
->whereIn('profile_id', $following)
|
||||||
|
->orderBy('id','desc')
|
||||||
|
->withCount(['comments', 'likes'])
|
||||||
|
->simplePaginate(10);
|
||||||
return view('timeline.personal', compact('timeline'));
|
return view('timeline.personal', compact('timeline'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function local()
|
public function local()
|
||||||
{
|
{
|
||||||
// TODO: Use redis for timelines
|
// TODO: Use redis for timelines
|
||||||
$timeline = Status::whereHas('media')->whereNull('in_reply_to_id')->orderBy('id','desc')->simplePaginate(10);
|
$timeline = Status::whereHas('media')
|
||||||
|
->whereNull('in_reply_to_id')
|
||||||
|
->orderBy('id','desc')
|
||||||
|
->withCount(['comments', 'likes'])
|
||||||
|
->simplePaginate(10);
|
||||||
return view('timeline.public', compact('timeline'));
|
return view('timeline.public', compact('timeline'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
69
app/Jobs/CommentPipeline/CommentPipeline.php
Normal file
69
app/Jobs/CommentPipeline/CommentPipeline.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\CommentPipeline;
|
||||||
|
|
||||||
|
use Cache, Log, Redis;
|
||||||
|
use App\{Like, Notification, Status};
|
||||||
|
use App\Util\Lexer\Hashtag as HashtagLexer;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CommentPipeline implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $status;
|
||||||
|
protected $comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Status $status, Status $comment)
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
$this->comment = $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$status = $this->status;
|
||||||
|
$comment = $this->comment;
|
||||||
|
|
||||||
|
$target = $status->profile;
|
||||||
|
$actor = $comment->profile;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$notification = new Notification;
|
||||||
|
$notification->profile_id = $target->id;
|
||||||
|
$notification->actor_id = $actor->id;
|
||||||
|
$notification->action = 'comment';
|
||||||
|
$notification->message = $comment->replyToText();
|
||||||
|
$notification->rendered = $comment->replyToHtml();
|
||||||
|
$notification->item_id = $comment->id;
|
||||||
|
$notification->item_type = "App\Status";
|
||||||
|
$notification->save();
|
||||||
|
|
||||||
|
Cache::forever('notification.' . $notification->id, $notification);
|
||||||
|
|
||||||
|
$redis = Redis::connection();
|
||||||
|
|
||||||
|
$nkey = config('cache.prefix').':user.' . $target->id . '.notifications';
|
||||||
|
$redis->lpush($nkey, $notification->id);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,8 @@ class FollowPipeline implements ShouldQueue
|
||||||
$notification->action = 'follow';
|
$notification->action = 'follow';
|
||||||
$notification->message = $follower->toText();
|
$notification->message = $follower->toText();
|
||||||
$notification->rendered = $follower->toHtml();
|
$notification->rendered = $follower->toHtml();
|
||||||
|
$notification->item_id = $target->id;
|
||||||
|
$notification->item_type = "App\Profile";
|
||||||
$notification->save();
|
$notification->save();
|
||||||
|
|
||||||
Cache::forever('notification.' . $notification->id, $notification);
|
Cache::forever('notification.' . $notification->id, $notification);
|
||||||
|
|
|
@ -49,6 +49,8 @@ class LikePipeline implements ShouldQueue
|
||||||
$notification->action = 'like';
|
$notification->action = 'like';
|
||||||
$notification->message = $like->toText();
|
$notification->message = $like->toText();
|
||||||
$notification->rendered = $like->toHtml();
|
$notification->rendered = $like->toHtml();
|
||||||
|
$notification->item_id = $status->id;
|
||||||
|
$notification->item_type = "App\Status";
|
||||||
$notification->save();
|
$notification->save();
|
||||||
|
|
||||||
Cache::forever('notification.' . $notification->id, $notification);
|
Cache::forever('notification.' . $notification->id, $notification);
|
||||||
|
|
|
@ -17,4 +17,14 @@ class Notification extends Model
|
||||||
return $this->belongsTo(Profile::class, 'profile_id', 'id');
|
return $this->belongsTo(Profile::class, 'profile_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function status()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Status::class, 'item_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ class AppServiceProvider extends ServiceProvider
|
||||||
});
|
});
|
||||||
|
|
||||||
Blade::directive('prettySize', function($expression) {
|
Blade::directive('prettySize', function($expression) {
|
||||||
|
|
||||||
$size = intval($expression);
|
$size = intval($expression);
|
||||||
$precision = 0;
|
$precision = 0;
|
||||||
$short = true;
|
$short = true;
|
||||||
|
@ -51,6 +50,11 @@ class AppServiceProvider extends ServiceProvider
|
||||||
$res = round($size, $precision).$units[$i];
|
$res = round($size, $precision).$units[$i];
|
||||||
return "<?php echo '$res'; ?>";
|
return "<?php echo '$res'; ?>";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Blade::directive('maxFileSize', function() {
|
||||||
|
$value = config('pixelfed.max_photo_size');
|
||||||
|
return \App\Util\Lexer\PrettyNumber::size($value, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,7 +32,12 @@ class Status extends Model
|
||||||
{
|
{
|
||||||
$id = $this->id;
|
$id = $this->id;
|
||||||
$username = $this->profile->username;
|
$username = $this->profile->username;
|
||||||
return url(config('app.url') . "/p/{$username}/{$id}");
|
$path = config('app.url') . "/p/{$username}/{$id}";
|
||||||
|
if(!is_null($this->in_reply_to_id)) {
|
||||||
|
$pid = $this->in_reply_to_id;
|
||||||
|
$path = config('app.url') . "/p/{$username}/{$pid}/c/{$id}";
|
||||||
|
}
|
||||||
|
return url($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mediaUrl()
|
public function mediaUrl()
|
||||||
|
@ -96,4 +101,17 @@ class Status extends Model
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function replyToText()
|
||||||
|
{
|
||||||
|
$actorName = $this->profile->username;
|
||||||
|
return "{$actorName} " . __('notification.commented');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replyToHtml()
|
||||||
|
{
|
||||||
|
$actorName = $this->profile->username;
|
||||||
|
$actorUrl = $this->profile->url();
|
||||||
|
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> " .
|
||||||
|
__('notification.commented');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,4 +17,20 @@ class PrettyNumber {
|
||||||
return $expression;
|
return $expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function size($expression, $kb = false)
|
||||||
|
{
|
||||||
|
if($kb) {
|
||||||
|
$expression = $expression * 1024;
|
||||||
|
}
|
||||||
|
$size = intval($expression);
|
||||||
|
$precision = 0;
|
||||||
|
$short = true;
|
||||||
|
$units = $short ?
|
||||||
|
['B','k','M','G','T','P','E','Z','Y'] :
|
||||||
|
['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
|
||||||
|
for($i = 0; ($size / 1024) > 0.9; $i++, $size /= 1024) {}
|
||||||
|
$res = round($size, $precision).$units[$i];
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -105,42 +105,25 @@ class Image {
|
||||||
$orientation = $ratio['orientation'];
|
$orientation = $ratio['orientation'];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$img = Intervention::make($file);
|
$img = Intervention::make($file)->orientate();
|
||||||
$img->resize($aspect['width'], $aspect['height'], function ($constraint) {
|
$img->resize($aspect['width'], $aspect['height'], function ($constraint) {
|
||||||
$constraint->aspectRatio();
|
$constraint->aspectRatio();
|
||||||
});
|
});
|
||||||
$converted = $this->convertPngToJpeg($path, $thumbnail, $img->extension);
|
$converted = $this->setBaseName($path, $thumbnail, $img->extension);
|
||||||
$newPath = storage_path('app/'.$converted['path']);
|
$newPath = storage_path('app/'.$converted['path']);
|
||||||
$is_png = false;
|
|
||||||
|
|
||||||
if($img->extension == 'png' || $converted['png'] == true) {
|
|
||||||
\Log::info('PNG detected, ' . json_encode([$img, $converted]));
|
|
||||||
$is_png = true;
|
|
||||||
$newPath = str_replace('.png', '.jpeg', $newPath);
|
|
||||||
$img->encode('jpg', 80)->save($newPath);
|
|
||||||
if(!$thumbnail) {
|
|
||||||
@unlink($file);
|
|
||||||
}
|
|
||||||
\Log::info('PNG SAVED, ' . json_encode([$img, $newPath]));
|
|
||||||
} else {
|
|
||||||
\Log::info('PNG not detected, ' . json_encode([$img, $converted]));
|
|
||||||
$img->save($newPath, 75);
|
$img->save($newPath, 75);
|
||||||
}
|
|
||||||
|
|
||||||
if(!$thumbnail) {
|
if(!$thumbnail) {
|
||||||
$media->orientation = $orientation;
|
$media->orientation = $orientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($is_png == true) {
|
|
||||||
if($thumbnail == false) {
|
|
||||||
$media->media_path = $converted['path'];
|
|
||||||
$media->mime = $img->mime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($thumbnail == true) {
|
if($thumbnail == true) {
|
||||||
$media->thumbnail_path = $converted['path'];
|
$media->thumbnail_path = $converted['path'];
|
||||||
$media->thumbnail_url = url(Storage::url($converted['path']));
|
$media->thumbnail_url = url(Storage::url($converted['path']));
|
||||||
|
} else {
|
||||||
|
$media->media_path = $converted['path'];
|
||||||
|
$media->mime = $img->mime;
|
||||||
}
|
}
|
||||||
|
|
||||||
$media->save();
|
$media->save();
|
||||||
|
@ -150,18 +133,14 @@ class Image {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertPngToJpeg($basePath, $thumbnail = false, $extension)
|
public function setBaseName($basePath, $thumbnail = false, $extension)
|
||||||
{
|
{
|
||||||
$png = false;
|
$png = false;
|
||||||
$path = explode('.', $basePath);
|
$path = explode('.', $basePath);
|
||||||
$name = ($thumbnail == true) ? $path[0] . '_thumb' : $path[0];
|
$name = ($thumbnail == true) ? $path[0] . '_thumb' : $path[0];
|
||||||
$ext = last($path);
|
$ext = last($path);
|
||||||
$basePath = "{$name}.{$ext}";
|
$basePath = "{$name}.{$ext}";
|
||||||
if($extension == 'png' || $ext == 'png') {
|
|
||||||
$ext = 'jpeg';
|
|
||||||
$basePath = "{$name}.{$ext}";
|
|
||||||
$png = true;
|
|
||||||
}
|
|
||||||
return ['path' => $basePath, 'png' => $png];
|
return ['path' => $basePath, 'png' => $png];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"php": "^7.1.3",
|
"php": "^7.1.3",
|
||||||
"99designs/http-signatures-guzzlehttp": "^2.0",
|
"99designs/http-signatures-guzzlehttp": "^2.0",
|
||||||
"bitverse/identicon": "^1.1",
|
"bitverse/identicon": "^1.1",
|
||||||
|
"doctrine/dbal": "^2.7",
|
||||||
"fideloper/proxy": "^4.0",
|
"fideloper/proxy": "^4.0",
|
||||||
"greggilbert/recaptcha": "dev-master",
|
"greggilbert/recaptcha": "dev-master",
|
||||||
"intervention/image": "^2.4",
|
"intervention/image": "^2.4",
|
||||||
|
|
359
composer.lock
generated
359
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "7be7e27683f56b7ec28eeef962cf2437",
|
"content-hash": "bb2590c6fbf5fbc46642f6cbccf7969f",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "99designs/http-signatures",
|
"name": "99designs/http-signatures",
|
||||||
|
@ -244,6 +244,363 @@
|
||||||
"description": "implementation of xdg base directory specification for php",
|
"description": "implementation of xdg base directory specification for php",
|
||||||
"time": "2014-10-24T07:27:01+00:00"
|
"time": "2014-10-24T07:27:01+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/annotations",
|
||||||
|
"version": "v1.6.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/annotations.git",
|
||||||
|
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
|
||||||
|
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/lexer": "1.*",
|
||||||
|
"php": "^7.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/cache": "1.*",
|
||||||
|
"phpunit/phpunit": "^6.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.6.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Docblock Annotations Parser",
|
||||||
|
"homepage": "http://www.doctrine-project.org",
|
||||||
|
"keywords": [
|
||||||
|
"annotations",
|
||||||
|
"docblock",
|
||||||
|
"parser"
|
||||||
|
],
|
||||||
|
"time": "2017-12-06T07:11:42+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/cache",
|
||||||
|
"version": "v1.7.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/cache.git",
|
||||||
|
"reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/cache/zipball/b3217d58609e9c8e661cd41357a54d926c4a2a1a",
|
||||||
|
"reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~7.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/common": ">2.2,<2.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"alcaeus/mongo-php-adapter": "^1.1",
|
||||||
|
"mongodb/mongodb": "^1.1",
|
||||||
|
"phpunit/phpunit": "^5.7",
|
||||||
|
"predis/predis": "~1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.7.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Caching library offering an object-oriented API for many cache backends",
|
||||||
|
"homepage": "http://www.doctrine-project.org",
|
||||||
|
"keywords": [
|
||||||
|
"cache",
|
||||||
|
"caching"
|
||||||
|
],
|
||||||
|
"time": "2017-08-25T07:02:50+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/collections",
|
||||||
|
"version": "v1.5.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/collections.git",
|
||||||
|
"reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf",
|
||||||
|
"reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "~0.1@dev",
|
||||||
|
"phpunit/phpunit": "^5.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Doctrine\\Common\\Collections\\": "lib/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Collections Abstraction library",
|
||||||
|
"homepage": "http://www.doctrine-project.org",
|
||||||
|
"keywords": [
|
||||||
|
"array",
|
||||||
|
"collections",
|
||||||
|
"iterator"
|
||||||
|
],
|
||||||
|
"time": "2017-07-22T10:37:32+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/common",
|
||||||
|
"version": "v2.8.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/common.git",
|
||||||
|
"reference": "f68c297ce6455e8fd794aa8ffaf9fa458f6ade66"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/common/zipball/f68c297ce6455e8fd794aa8ffaf9fa458f6ade66",
|
||||||
|
"reference": "f68c297ce6455e8fd794aa8ffaf9fa458f6ade66",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/annotations": "1.*",
|
||||||
|
"doctrine/cache": "1.*",
|
||||||
|
"doctrine/collections": "1.*",
|
||||||
|
"doctrine/inflector": "1.*",
|
||||||
|
"doctrine/lexer": "1.*",
|
||||||
|
"php": "~7.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^5.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.8.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\": "lib/Doctrine/Common"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common Library for Doctrine projects",
|
||||||
|
"homepage": "http://www.doctrine-project.org",
|
||||||
|
"keywords": [
|
||||||
|
"annotations",
|
||||||
|
"collections",
|
||||||
|
"eventmanager",
|
||||||
|
"persistence",
|
||||||
|
"spl"
|
||||||
|
],
|
||||||
|
"time": "2017-08-31T08:43:38+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/dbal",
|
||||||
|
"version": "v2.7.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/dbal.git",
|
||||||
|
"reference": "11037b4352c008373561dc6fc836834eed80c3b5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/dbal/zipball/11037b4352c008373561dc6fc836834eed80c3b5",
|
||||||
|
"reference": "11037b4352c008373561dc6fc836834eed80c3b5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/common": "^2.7.1",
|
||||||
|
"ext-pdo": "*",
|
||||||
|
"php": "^7.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^4.0",
|
||||||
|
"phpunit/phpunit": "^7.0",
|
||||||
|
"phpunit/phpunit-mock-objects": "!=3.2.4,!=3.2.5",
|
||||||
|
"symfony/console": "^2.0.5||^3.0",
|
||||||
|
"symfony/phpunit-bridge": "^3.4.5|^4.0.5"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/doctrine-dbal"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.7.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Doctrine\\DBAL\\": "lib/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Database Abstraction Layer",
|
||||||
|
"homepage": "http://www.doctrine-project.org",
|
||||||
|
"keywords": [
|
||||||
|
"database",
|
||||||
|
"dbal",
|
||||||
|
"persistence",
|
||||||
|
"queryobject"
|
||||||
|
],
|
||||||
|
"time": "2018-04-07T18:44:18+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/inflector",
|
"name": "doctrine/inflector",
|
||||||
"version": "v1.3.0",
|
"version": "v1.3.0",
|
||||||
|
|
|
@ -77,4 +77,24 @@ return [
|
||||||
|
|
||||||
'activitypub_enabled' => env('ACTIVITY_PUB', false),
|
'activitypub_enabled' => env('ACTIVITY_PUB', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Photo file size limit
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Update the max photo size, in KB.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'max_photo_size' => env('MAX_PHOTO_SIZE', 15000),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Caption limit
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Change the caption length limit for new local posts.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'max_caption_length' => env('MAX_CAPTION_LENGTH', 150),
|
||||||
|
|
||||||
];
|
];
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class UpdateNotificationsTableAddPolymorphicRelationship extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('notifications', function (Blueprint $table) {
|
||||||
|
$table->bigInteger('item_id')->unsigned()->nullable()->after('actor_id');
|
||||||
|
$table->string('item_type')->nullable()->after('item_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,37 +3,62 @@ version: '3'
|
||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- external
|
||||||
ports:
|
ports:
|
||||||
- 3000:80
|
- 3000:80
|
||||||
volumes:
|
volumes:
|
||||||
- .:/var/www/html
|
- "php-storage:/var/www/html"
|
||||||
- ./contrib/nginx.conf:/etc/nginx/conf.d/default.conf
|
- ./contrib/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||||
depends_on:
|
depends_on:
|
||||||
- php
|
- php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
build: .
|
build: .
|
||||||
|
image: pixelfed
|
||||||
volumes:
|
volumes:
|
||||||
- ./storage:/var/www/html/storage
|
- "php-storage:/var/www/html"
|
||||||
depends_on:
|
networks:
|
||||||
- mysql
|
- internal
|
||||||
- redis
|
|
||||||
environment:
|
environment:
|
||||||
- DB_HOST=mysql
|
- DB_HOST=mysql
|
||||||
- DB_DATABASE=pixelfed
|
- DB_DATABASE=pixelfed
|
||||||
- DB_USERNAME=${DB_USERNAME}
|
- DB_USERNAME=${DB_USERNAME:-pixelfed}
|
||||||
- DB_PASSWORD=${DB_PASSWORD}
|
- DB_PASSWORD=${DB_PASSWORD:-pixelfed}
|
||||||
- REDIS_HOST=redis
|
- REDIS_HOST=redis
|
||||||
- APP_KEY=${APP_KEY}
|
- APP_KEY=${APP_KEY}
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:5.7
|
image: mysql:5.7
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_DATABASE=pixelfed
|
- MYSQL_DATABASE=pixelfed
|
||||||
- MYSQL_USER=${DB_USERNAME}
|
- MYSQL_USER=${DB_USERNAME:-pixelfed}
|
||||||
- MYSQL_PASSWORD=${DB_PASSWORD}
|
- MYSQL_PASSWORD=${DB_PASSWORD:-pixelfed}
|
||||||
|
- MYSQL_RANDOM_ROOT_PASSWORD="true"
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker-volumes/mysql:/var/lib/mysql
|
- "mysql-data:/var/lib/mysql"
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker-volumes/redis:/data
|
- "redis-data:/data"
|
||||||
...
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis-data:
|
||||||
|
mysql-data:
|
||||||
|
php-storage:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
internal: true
|
||||||
|
external:
|
||||||
|
driver: bridge
|
||||||
|
|
BIN
public/css/app.css
vendored
BIN
public/css/app.css
vendored
Binary file not shown.
BIN
public/js/app.js
vendored
BIN
public/js/app.js
vendored
Binary file not shown.
BIN
public/js/timeline.js
vendored
BIN
public/js/timeline.js
vendored
Binary file not shown.
Binary file not shown.
6
resources/assets/js/bootstrap.js
vendored
6
resources/assets/js/bootstrap.js
vendored
|
@ -9,6 +9,7 @@ window.Popper = require('popper.js').default;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
window.pixelfed = {};
|
||||||
window.$ = window.jQuery = require('jquery');
|
window.$ = window.jQuery = require('jquery');
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
window.InfiniteScroll = require('infinite-scroll');
|
window.InfiniteScroll = require('infinite-scroll');
|
||||||
|
@ -16,9 +17,10 @@ try {
|
||||||
window.typeahead = require('./lib/typeahead');
|
window.typeahead = require('./lib/typeahead');
|
||||||
window.Bloodhound = require('./lib/bloodhound');
|
window.Bloodhound = require('./lib/bloodhound');
|
||||||
|
|
||||||
|
require('./lib/fontawesome-all');
|
||||||
require('./components/localstorage');
|
require('./components/localstorage');
|
||||||
//require('./components/likebutton');
|
require('./components/likebutton');
|
||||||
//require('./components/commentform');
|
require('./components/commentform');
|
||||||
require('./components/searchform');
|
require('./components/searchform');
|
||||||
require('./components/bookmarkform');
|
require('./components/bookmarkform');
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
37
resources/assets/js/components/commentform.js
vendored
37
resources/assets/js/components/commentform.js
vendored
|
@ -1,6 +1,11 @@
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
$('.comment-form').submit(function(e, data) {
|
$('.status-comment-focus').on('click', function(el) {
|
||||||
|
var el = $(this).parents().eq(2).find('input[name="comment"]');
|
||||||
|
el.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('submit', '.comment-form', function(e, data) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
let el = $(this);
|
let el = $(this);
|
||||||
|
@ -8,18 +13,32 @@ $(document).ready(function() {
|
||||||
let commentform = el.find('input[name="comment"]');
|
let commentform = el.find('input[name="comment"]');
|
||||||
let commenttext = commentform.val();
|
let commenttext = commentform.val();
|
||||||
let item = {item: id, comment: commenttext};
|
let item = {item: id, comment: commenttext};
|
||||||
try {
|
|
||||||
axios.post('/i/comment', item);
|
axios.post('/i/comment', item)
|
||||||
var comments = el.parent().parent().find('.comments');
|
.then(function (res) {
|
||||||
var comment = '<p class="mb-0"><span class="font-weight-bold pr-1">' + pixelfed.user.username + '</span><span class="comment-text">'+ commenttext + '</span></p>';
|
|
||||||
|
var username = res.data.username;
|
||||||
|
var permalink = res.data.url;
|
||||||
|
var profile = res.data.profile;
|
||||||
|
|
||||||
|
if($('.status-container').length == 1) {
|
||||||
|
var comments = el.parents().eq(3).find('.comments');
|
||||||
|
} else {
|
||||||
|
var comments = el.parents().eq(1).find('.comments');
|
||||||
|
}
|
||||||
|
|
||||||
|
var comment = '<p class="mb-0"><span class="font-weight-bold pr-1"><bdi><a class="text-dark" href="' + profile + '">' + username + '</a></bdi></span><span class="comment-text">'+ commenttext + '</span><span class="float-right"><a href="' + permalink + '" class="text-dark small font-weight-bold">1s</a></span></p>';
|
||||||
|
|
||||||
comments.prepend(comment);
|
comments.prepend(comment);
|
||||||
|
|
||||||
commentform.val('');
|
commentform.val('');
|
||||||
commentform.blur();
|
commentform.blur();
|
||||||
return true;
|
|
||||||
} catch(e) {
|
})
|
||||||
return false;
|
.catch(function (res) {
|
||||||
}
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
47
resources/assets/js/components/likebutton.js
vendored
47
resources/assets/js/components/likebutton.js
vendored
|
@ -1,29 +1,60 @@
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
if(!ls.get('likes')) {
|
if(!ls.get('likes')) {
|
||||||
|
axios.get('/api/v1/likes')
|
||||||
|
.then(function (res) {
|
||||||
|
ls.set('likes', res.data);
|
||||||
|
console.log(res);
|
||||||
|
})
|
||||||
|
.catch(function (res) {
|
||||||
ls.set('likes', []);
|
ls.set('likes', []);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.like-form').submit(function(e) {
|
|
||||||
|
pixelfed.hydrateLikes = function() {
|
||||||
|
var likes = ls.get('likes');
|
||||||
|
$('.like-form').each(function(i, el) {
|
||||||
|
var el = $(el);
|
||||||
|
var id = el.data('id');
|
||||||
|
var heart = el.find('.status-heart');
|
||||||
|
|
||||||
|
if(likes.indexOf(id) != -1) {
|
||||||
|
heart.addClass('fas fa-heart').removeClass('far fa-heart');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
pixelfed.hydrateLikes();
|
||||||
|
|
||||||
|
$(document).on('submit', '.like-form', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var el = $(this);
|
var el = $(this);
|
||||||
var id = el.data('id');
|
var id = el.data('id');
|
||||||
var res = axios.post('/i/like', {item: id});
|
axios.post('/i/like', {item: id})
|
||||||
|
.then(function (res) {
|
||||||
var likes = ls.get('likes');
|
var likes = ls.get('likes');
|
||||||
var action = false;
|
var action = false;
|
||||||
var counter = el.parent().parent().find('.like-count');
|
var counter = el.parents().eq(1).find('.like-count');
|
||||||
var count = parseInt(counter.text());
|
var count = res.data.count;
|
||||||
|
var heart = el.find('.status-heart');
|
||||||
|
|
||||||
if(likes.indexOf(id) > -1) {
|
if(likes.indexOf(id) > -1) {
|
||||||
likes.splice(id, 1);
|
heart.addClass('far fa-heart').removeClass('fas fa-heart');
|
||||||
count--;
|
likes = likes.filter(function(item) {
|
||||||
|
return item !== id
|
||||||
|
});
|
||||||
counter.text(count);
|
counter.text(count);
|
||||||
action = 'unlike';
|
action = 'unlike';
|
||||||
} else {
|
} else {
|
||||||
|
heart.addClass('fas fa-heart').removeClass('far fa-heart');
|
||||||
likes.push(id);
|
likes.push(id);
|
||||||
count++;
|
|
||||||
counter.text(count);
|
counter.text(count);
|
||||||
action = 'like';
|
action = 'like';
|
||||||
}
|
}
|
||||||
|
|
||||||
ls.set('likes', likes);
|
ls.set('likes', likes);
|
||||||
console.log(action + ' - ' + $(this).data('id') + ' like event');
|
console.log(action + ' - ' + id + ' like event');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
3271
resources/assets/js/lib/fontawesome-all.js
vendored
Normal file
3271
resources/assets/js/lib/fontawesome-all.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
resources/assets/js/timeline.js
vendored
3
resources/assets/js/timeline.js
vendored
|
@ -6,4 +6,7 @@ $(document).ready(function() {
|
||||||
append: '.timeline-feed',
|
append: '.timeline-feed',
|
||||||
history: false,
|
history: false,
|
||||||
});
|
});
|
||||||
|
infScroll.on( 'append', function( response, path, items ) {
|
||||||
|
pixelfed.hydrateLikes();
|
||||||
|
});
|
||||||
});
|
});
|
1
resources/assets/sass/app.scss
vendored
1
resources/assets/sass/app.scss
vendored
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
@import "fonts";
|
@import "fonts";
|
||||||
|
@import "lib/fontawesome";
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
111
resources/assets/sass/custom.scss
vendored
111
resources/assets/sass/custom.scss
vendored
|
@ -56,39 +56,14 @@ body, button, input, textarea {
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.status-container .status-photo {
|
.card.status-container .status-photo {
|
||||||
display: -webkit-box !important;
|
|
||||||
display: -ms-flexbox !important;
|
|
||||||
display: flex !important;
|
|
||||||
margin: auto !important;
|
margin: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.status-container .status-comments {
|
.card.status-container .status-comments {
|
||||||
height: 220px;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
border-bottom:1px solid rgba(0, 0, 0, 0.1);
|
border-bottom:1px solid rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.status-container.orientation-square .status-comments {
|
|
||||||
height: 360px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.card.status-container.orientation-portrait .status-comments {
|
|
||||||
height: 528px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.status-container.orientation-landscape .status-photo img {
|
|
||||||
max-height: 451px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.status-container.orientation-square .status-photo img {
|
|
||||||
max-height: 601px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.status-container.orientation-portrait .status-photo img {
|
|
||||||
max-height: 772px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-caret.dropdown-toggle {
|
.no-caret.dropdown-toggle {
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
@ -105,3 +80,89 @@ body, button, input, textarea {
|
||||||
.notification-page .list-group-item:first-child {
|
.notification-page .list-group-item:first-child {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-topbar {
|
||||||
|
border-top: 1px solid $gray-300;
|
||||||
|
}
|
||||||
|
.nav-topbar .nav-item {
|
||||||
|
margin: -1px 1.5rem 0;
|
||||||
|
}
|
||||||
|
.nav-topbar .nav-link {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
color: $gray-300;
|
||||||
|
padding: 0.75rem 0;
|
||||||
|
}
|
||||||
|
.nav-topbar .nav-link:focus, .nav-topbar .nav-link:hover {
|
||||||
|
border-top-color: $gray-300;
|
||||||
|
}
|
||||||
|
.nav-topbar .nav-link.disabled {
|
||||||
|
color: $gray-300;
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
.nav-topbar .nav-item.show .nav-link, .nav-topbar .nav-link.active {
|
||||||
|
color: $gray-600;
|
||||||
|
border-top-color: $gray-600;
|
||||||
|
}
|
||||||
|
.nav-topbar .dropdown-menu {
|
||||||
|
margin-top:-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-overlay {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-overlay .info-overlay-text {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-overlay:hover .info-overlay-text {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-overlay-text {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-weight-ultralight {
|
||||||
|
font-weight: 200 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square-content {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fas, .far {
|
||||||
|
font-size: 25px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.far.fa-heart {
|
||||||
|
color: #343a40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-heart.fa-w-16.status-heart.fa-2x {
|
||||||
|
color: #f70ec4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fas.fa-heart {
|
||||||
|
}
|
345
resources/assets/sass/lib/fontawesome.scss
vendored
Normal file
345
resources/assets/sass/lib/fontawesome.scss
vendored
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
/*!
|
||||||
|
* Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
*/
|
||||||
|
svg:not(:root).svg-inline--fa {
|
||||||
|
overflow: visible; }
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: inherit;
|
||||||
|
height: 1em;
|
||||||
|
overflow: visible;
|
||||||
|
vertical-align: -.125em; }
|
||||||
|
.svg-inline--fa.fa-lg {
|
||||||
|
vertical-align: -.225em; }
|
||||||
|
.svg-inline--fa.fa-w-1 {
|
||||||
|
width: 0.0625em; }
|
||||||
|
.svg-inline--fa.fa-w-2 {
|
||||||
|
width: 0.125em; }
|
||||||
|
.svg-inline--fa.fa-w-3 {
|
||||||
|
width: 0.1875em; }
|
||||||
|
.svg-inline--fa.fa-w-4 {
|
||||||
|
width: 0.25em; }
|
||||||
|
.svg-inline--fa.fa-w-5 {
|
||||||
|
width: 0.3125em; }
|
||||||
|
.svg-inline--fa.fa-w-6 {
|
||||||
|
width: 0.375em; }
|
||||||
|
.svg-inline--fa.fa-w-7 {
|
||||||
|
width: 0.4375em; }
|
||||||
|
.svg-inline--fa.fa-w-8 {
|
||||||
|
width: 0.5em; }
|
||||||
|
.svg-inline--fa.fa-w-9 {
|
||||||
|
width: 0.5625em; }
|
||||||
|
.svg-inline--fa.fa-w-10 {
|
||||||
|
width: 0.625em; }
|
||||||
|
.svg-inline--fa.fa-w-11 {
|
||||||
|
width: 0.6875em; }
|
||||||
|
.svg-inline--fa.fa-w-12 {
|
||||||
|
width: 0.75em; }
|
||||||
|
.svg-inline--fa.fa-w-13 {
|
||||||
|
width: 0.8125em; }
|
||||||
|
.svg-inline--fa.fa-w-14 {
|
||||||
|
width: 0.875em; }
|
||||||
|
.svg-inline--fa.fa-w-15 {
|
||||||
|
width: 0.9375em; }
|
||||||
|
.svg-inline--fa.fa-w-16 {
|
||||||
|
width: 1em; }
|
||||||
|
.svg-inline--fa.fa-w-17 {
|
||||||
|
width: 1.0625em; }
|
||||||
|
.svg-inline--fa.fa-w-18 {
|
||||||
|
width: 1.125em; }
|
||||||
|
.svg-inline--fa.fa-w-19 {
|
||||||
|
width: 1.1875em; }
|
||||||
|
.svg-inline--fa.fa-w-20 {
|
||||||
|
width: 1.25em; }
|
||||||
|
.svg-inline--fa.fa-pull-left {
|
||||||
|
margin-right: .3em;
|
||||||
|
width: auto; }
|
||||||
|
.svg-inline--fa.fa-pull-right {
|
||||||
|
margin-left: .3em;
|
||||||
|
width: auto; }
|
||||||
|
.svg-inline--fa.fa-border {
|
||||||
|
height: 1.5em; }
|
||||||
|
.svg-inline--fa.fa-li {
|
||||||
|
width: 2em; }
|
||||||
|
.svg-inline--fa.fa-fw {
|
||||||
|
width: 1.25em; }
|
||||||
|
|
||||||
|
.fa-layers svg.svg-inline--fa {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0; }
|
||||||
|
|
||||||
|
.fa-layers {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: -.125em;
|
||||||
|
width: 1em; }
|
||||||
|
.fa-layers svg.svg-inline--fa {
|
||||||
|
-webkit-transform-origin: center center;
|
||||||
|
transform-origin: center center; }
|
||||||
|
|
||||||
|
.fa-layers-text, .fa-layers-counter {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center; }
|
||||||
|
|
||||||
|
.fa-layers-text {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
-webkit-transform-origin: center center;
|
||||||
|
transform-origin: center center; }
|
||||||
|
|
||||||
|
.fa-layers-counter {
|
||||||
|
background-color: #ff253a;
|
||||||
|
border-radius: 1em;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #fff;
|
||||||
|
height: 1.5em;
|
||||||
|
line-height: 1;
|
||||||
|
max-width: 5em;
|
||||||
|
min-width: 1.5em;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: .25em;
|
||||||
|
right: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
top: 0;
|
||||||
|
-webkit-transform: scale(0.25);
|
||||||
|
transform: scale(0.25);
|
||||||
|
-webkit-transform-origin: top right;
|
||||||
|
transform-origin: top right; }
|
||||||
|
|
||||||
|
.fa-layers-bottom-right {
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
top: auto;
|
||||||
|
-webkit-transform: scale(0.25);
|
||||||
|
transform: scale(0.25);
|
||||||
|
-webkit-transform-origin: bottom right;
|
||||||
|
transform-origin: bottom right; }
|
||||||
|
|
||||||
|
.fa-layers-bottom-left {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
top: auto;
|
||||||
|
-webkit-transform: scale(0.25);
|
||||||
|
transform: scale(0.25);
|
||||||
|
-webkit-transform-origin: bottom left;
|
||||||
|
transform-origin: bottom left; }
|
||||||
|
|
||||||
|
.fa-layers-top-right {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-transform: scale(0.25);
|
||||||
|
transform: scale(0.25);
|
||||||
|
-webkit-transform-origin: top right;
|
||||||
|
transform-origin: top right; }
|
||||||
|
|
||||||
|
.fa-layers-top-left {
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
top: 0;
|
||||||
|
-webkit-transform: scale(0.25);
|
||||||
|
transform: scale(0.25);
|
||||||
|
-webkit-transform-origin: top left;
|
||||||
|
transform-origin: top left; }
|
||||||
|
|
||||||
|
.fa-lg {
|
||||||
|
font-size: 1.33333em;
|
||||||
|
line-height: 0.75em;
|
||||||
|
vertical-align: -.0667em; }
|
||||||
|
|
||||||
|
.fa-xs {
|
||||||
|
font-size: .75em; }
|
||||||
|
|
||||||
|
.fa-sm {
|
||||||
|
font-size: .875em; }
|
||||||
|
|
||||||
|
.fa-1x {
|
||||||
|
font-size: 1em; }
|
||||||
|
|
||||||
|
.fa-2x {
|
||||||
|
font-size: 2em; }
|
||||||
|
|
||||||
|
.fa-3x {
|
||||||
|
font-size: 3em; }
|
||||||
|
|
||||||
|
.fa-4x {
|
||||||
|
font-size: 4em; }
|
||||||
|
|
||||||
|
.fa-5x {
|
||||||
|
font-size: 5em; }
|
||||||
|
|
||||||
|
.fa-6x {
|
||||||
|
font-size: 6em; }
|
||||||
|
|
||||||
|
.fa-7x {
|
||||||
|
font-size: 7em; }
|
||||||
|
|
||||||
|
.fa-8x {
|
||||||
|
font-size: 8em; }
|
||||||
|
|
||||||
|
.fa-9x {
|
||||||
|
font-size: 9em; }
|
||||||
|
|
||||||
|
.fa-10x {
|
||||||
|
font-size: 10em; }
|
||||||
|
|
||||||
|
.fa-fw {
|
||||||
|
text-align: center;
|
||||||
|
width: 1.25em; }
|
||||||
|
|
||||||
|
.fa-ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left: 2.5em;
|
||||||
|
padding-left: 0; }
|
||||||
|
.fa-ul > li {
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
.fa-li {
|
||||||
|
left: -2em;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
width: 2em;
|
||||||
|
line-height: inherit; }
|
||||||
|
|
||||||
|
.fa-border {
|
||||||
|
border: solid 0.08em #eee;
|
||||||
|
border-radius: .1em;
|
||||||
|
padding: .2em .25em .15em; }
|
||||||
|
|
||||||
|
.fa-pull-left {
|
||||||
|
float: left; }
|
||||||
|
|
||||||
|
.fa-pull-right {
|
||||||
|
float: right; }
|
||||||
|
|
||||||
|
.fa.fa-pull-left,
|
||||||
|
.fas.fa-pull-left,
|
||||||
|
.far.fa-pull-left,
|
||||||
|
.fal.fa-pull-left,
|
||||||
|
.fab.fa-pull-left {
|
||||||
|
margin-right: .3em; }
|
||||||
|
|
||||||
|
.fa.fa-pull-right,
|
||||||
|
.fas.fa-pull-right,
|
||||||
|
.far.fa-pull-right,
|
||||||
|
.fal.fa-pull-right,
|
||||||
|
.fab.fa-pull-right {
|
||||||
|
margin-left: .3em; }
|
||||||
|
|
||||||
|
.fa-spin {
|
||||||
|
-webkit-animation: fa-spin 2s infinite linear;
|
||||||
|
animation: fa-spin 2s infinite linear; }
|
||||||
|
|
||||||
|
.fa-pulse {
|
||||||
|
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||||
|
animation: fa-spin 1s infinite steps(8); }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg); }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg); } }
|
||||||
|
|
||||||
|
@keyframes fa-spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg); }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg); } }
|
||||||
|
|
||||||
|
.fa-rotate-90 {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
|
||||||
|
-webkit-transform: rotate(90deg);
|
||||||
|
transform: rotate(90deg); }
|
||||||
|
|
||||||
|
.fa-rotate-180 {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
|
||||||
|
-webkit-transform: rotate(180deg);
|
||||||
|
transform: rotate(180deg); }
|
||||||
|
|
||||||
|
.fa-rotate-270 {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
|
||||||
|
-webkit-transform: rotate(270deg);
|
||||||
|
transform: rotate(270deg); }
|
||||||
|
|
||||||
|
.fa-flip-horizontal {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
|
||||||
|
-webkit-transform: scale(-1, 1);
|
||||||
|
transform: scale(-1, 1); }
|
||||||
|
|
||||||
|
.fa-flip-vertical {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||||
|
-webkit-transform: scale(1, -1);
|
||||||
|
transform: scale(1, -1); }
|
||||||
|
|
||||||
|
.fa-flip-horizontal.fa-flip-vertical {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||||
|
-webkit-transform: scale(-1, -1);
|
||||||
|
transform: scale(-1, -1); }
|
||||||
|
|
||||||
|
:root .fa-rotate-90,
|
||||||
|
:root .fa-rotate-180,
|
||||||
|
:root .fa-rotate-270,
|
||||||
|
:root .fa-flip-horizontal,
|
||||||
|
:root .fa-flip-vertical {
|
||||||
|
-webkit-filter: none;
|
||||||
|
filter: none; }
|
||||||
|
|
||||||
|
.fa-stack {
|
||||||
|
display: inline-block;
|
||||||
|
height: 2em;
|
||||||
|
position: relative;
|
||||||
|
width: 2em; }
|
||||||
|
|
||||||
|
.fa-stack-1x,
|
||||||
|
.fa-stack-2x {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0; }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-1x {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em; }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-2x {
|
||||||
|
height: 2em;
|
||||||
|
width: 2em; }
|
||||||
|
|
||||||
|
.fa-inverse {
|
||||||
|
color: #fff; }
|
||||||
|
|
||||||
|
.sr-only {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px; }
|
||||||
|
|
||||||
|
.sr-only-focusable:active, .sr-only-focusable:focus {
|
||||||
|
clip: auto;
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
position: static;
|
||||||
|
width: auto; }
|
|
@ -4,5 +4,6 @@ return [
|
||||||
|
|
||||||
'likedPhoto' => 'liked your photo.',
|
'likedPhoto' => 'liked your photo.',
|
||||||
'startedFollowingYou' => 'started following you.',
|
'startedFollowingYou' => 'started following you.',
|
||||||
|
'commented' => 'commented on your post.',
|
||||||
|
|
||||||
];
|
];
|
|
@ -18,8 +18,12 @@
|
||||||
<span class="text-muted notification-timestamp pl-1">{{$notification->created_at->diffForHumans(null, true, true, true)}}</span>
|
<span class="text-muted notification-timestamp pl-1">{{$notification->created_at->diffForHumans(null, true, true, true)}}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="float-right notification-action">
|
<span class="float-right notification-action">
|
||||||
|
@if($notification->item_id)
|
||||||
|
<a href="{{$notification->status->url()}}"><img src="{{$notification->status->thumb()}}" width="32px" height="32px"></a>
|
||||||
|
@endif
|
||||||
</span>
|
</span>
|
||||||
@break
|
@break
|
||||||
|
|
||||||
@case('follow')
|
@case('follow')
|
||||||
<span class="notification-icon pr-3">
|
<span class="notification-icon pr-3">
|
||||||
<img src="{{$notification->actor->avatarUrl()}}" width="32px" class="rounded-circle">
|
<img src="{{$notification->actor->avatarUrl()}}" width="32px" class="rounded-circle">
|
||||||
|
@ -38,6 +42,22 @@
|
||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
@break
|
@break
|
||||||
|
|
||||||
|
@case('comment')
|
||||||
|
<span class="notification-icon pr-3">
|
||||||
|
<img src="{{$notification->actor->avatarUrl()}}" width="32px" class="rounded-circle">
|
||||||
|
</span>
|
||||||
|
<span class="notification-text">
|
||||||
|
{!! $notification->rendered !!}
|
||||||
|
<span class="text-muted notification-timestamp pl-1">{{$notification->created_at->diffForHumans(null, true, true, true)}}</span>
|
||||||
|
</span>
|
||||||
|
<span class="float-right notification-action">
|
||||||
|
@if($notification->item_id)
|
||||||
|
<a href="{{$notification->status->parent()->url()}}"><img src="{{$notification->status->parent()->thumb()}}" width="32px" height="32px"></a>
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
@break
|
||||||
|
|
||||||
@endswitch
|
@endswitch
|
||||||
</li>
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
|
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
|
||||||
<link rel="dns-prefetch" href="https://cdnjs.cloudflare.com">
|
<link rel="dns-prefetch" href="https://cdnjs.cloudflare.com">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css" integrity="sha256-7O1DfUu4pybYI7uAATw34eDrgQaWGOfMV/8erfDQz/Q=" crossorigin="anonymous" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css" integrity="sha256-7O1DfUu4pybYI7uAATw34eDrgQaWGOfMV/8erfDQz/Q=" crossorigin="anonymous" />
|
||||||
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
|
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
|
||||||
@stack('styles')
|
@stack('styles')
|
||||||
</head>
|
</head>
|
||||||
<body class="">
|
<body class="">
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
<div class="align-items-end">
|
<div class="align-items-end">
|
||||||
@include('layouts.partial.footer')
|
@include('layouts.partial.footer')
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="{{ asset('js/app.js') }}"></script>
|
<script type="text/javascript" src="{{ mix('js/app.js') }}"></script>
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<footer class="pt-5 mt-5">
|
<footer>
|
||||||
<div class="container mt-5 pt-5">
|
<div class="container mt-5">
|
||||||
<p class="mt-5 text-uppercase font-weight-bold small">
|
<p class="text-uppercase font-weight-bold small">
|
||||||
<a href="{{route('site.about')}}" class="text-primary pr-2">About Us</a>
|
<a href="{{route('site.about')}}" class="text-primary pr-2">About Us</a>
|
||||||
<a href="{{route('site.help')}}" class="text-primary pr-2">Support</a>
|
<a href="{{route('site.help')}}" class="text-primary pr-2">Support</a>
|
||||||
<a href="" class="text-primary pr-2">API</a>
|
<a href="" class="text-primary pr-2">API</a>
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
<nav class="navbar navbar-expand-md navbar-light navbar-laravel">
|
<nav class="navbar navbar-expand navbar-light navbar-laravel sticky-top">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand d-flex align-items-center" href="{{ url('/timeline') }}">
|
<a class="navbar-brand d-flex align-items-center" href="{{ url('/timeline') }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle></svg>
|
||||||
<strong class="font-weight-bold">{{ config('app.name', 'Laravel') }}</strong>
|
<strong class="font-weight-bold">{{ config('app.name', 'Laravel') }}</strong>
|
||||||
</a>
|
</a>
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto d-none d-md-block">
|
||||||
<form class="form-inline search-form">
|
<form class="form-inline search-form">
|
||||||
<input class="form-control mr-sm-2 search-form-input" type="search" placeholder="Search" aria-label="Search">
|
<input class="form-control mr-sm-2 search-form-input" type="search" placeholder="Search" aria-label="Search">
|
||||||
</form>
|
</form>
|
||||||
|
@ -64,3 +61,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
<nav class="breadcrumb d-md-none d-flex">
|
||||||
|
<form class="form-inline search-form mx-auto">
|
||||||
|
<input class="form-control mr-sm-2 search-form-input" type="search" placeholder="Search" aria-label="Search">
|
||||||
|
</form>
|
||||||
|
</nav>
|
||||||
|
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
<div class="container following-page" style="min-height: 60vh;">
|
<div class="container following-page" style="min-height: 60vh;">
|
||||||
|
|
||||||
<div class="profile-header row my-5 offset-md-1">
|
<div class="profile-header row my-5">
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-4 d-flex">
|
||||||
<div class="profile-avatar">
|
<div class="profile-avatar mx-auto">
|
||||||
<img class="img-thumbnail" src="{{$profile->avatarUrl()}}" style="border-radius:100%;" width="172px">
|
<img class="img-thumbnail" src="{{$profile->avatarUrl()}}" style="border-radius:100%;" width="172px">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
<div class="col-12 col-md-8 d-flex align-items-center">
|
||||||
<div class="profile-details">
|
<div class="profile-details">
|
||||||
<div class="username-bar pb-2 d-flex align-items-center">
|
<div class="username-bar pb-2 d-flex align-items-center">
|
||||||
<span class="font-weight-light h1">{{$profile->username}}</span>
|
<span class="font-weight-ultralight h1">{{$profile->username}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile-stats pb-3 d-inline-flex lead">
|
<div class="profile-stats pb-3 d-inline-flex lead">
|
||||||
<div class="font-weight-light pr-5">
|
<div class="font-weight-light pr-5">
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-md-8 offset-2">
|
<div class="col-12 col-md-8 offset-md-2">
|
||||||
@if($followers->count() !== 0)
|
@if($followers->count() !== 0)
|
||||||
<ul class="list-group mt-4">
|
<ul class="list-group mt-4">
|
||||||
@foreach($followers as $user)
|
@foreach($followers as $user)
|
||||||
|
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
<div class="container following-page" style="min-height: 60vh;">
|
<div class="container following-page" style="min-height: 60vh;">
|
||||||
|
|
||||||
<div class="profile-header row my-5 offset-md-1">
|
<div class="profile-header row my-5">
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-4 d-flex">
|
||||||
<div class="profile-avatar">
|
<div class="profile-avatar mx-auto">
|
||||||
<img class="img-thumbnail" src="{{$profile->avatarUrl()}}" style="border-radius:100%;" width="172px">
|
<img class="img-thumbnail" src="{{$profile->avatarUrl()}}" style="border-radius:100%;" width="172px">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
<div class="col-12 col-md-8 d-flex align-items-center">
|
||||||
<div class="profile-details">
|
<div class="profile-details">
|
||||||
<div class="username-bar pb-2 d-flex align-items-center">
|
<div class="username-bar pb-2 d-flex align-items-center">
|
||||||
<span class="font-weight-light h1">{{$profile->username}}</span>
|
<span class="font-weight-ultralight h1">{{$profile->username}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile-stats pb-3 d-inline-flex lead">
|
<div class="profile-stats pb-3 d-inline-flex lead">
|
||||||
<div class="font-weight-light pr-5">
|
<div class="font-weight-light pr-5">
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-md-8 offset-2">
|
<div class="col-12 col-md-8 offset-md-2">
|
||||||
@if($following->count() !== 0)
|
@if($following->count() !== 0)
|
||||||
<ul class="list-group mt-4">
|
<ul class="list-group mt-4">
|
||||||
@foreach($following as $user)
|
@foreach($following as $user)
|
||||||
|
|
|
@ -4,19 +4,19 @@
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div class="profile-header row my-5 offset-md-1">
|
<div class="profile-header row my-5">
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-4 d-flex">
|
||||||
<div class="profile-avatar">
|
<div class="profile-avatar mx-auto">
|
||||||
<img class="img-thumbnail" src="{{$user->avatarUrl()}}" style="border-radius:100%;" width="172px">
|
<img class="img-thumbnail" src="{{$user->avatarUrl()}}" style="border-radius:100%;" width="172px">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
<div class="col-12 col-md-8 d-flex align-items-center">
|
||||||
<div class="profile-details">
|
<div class="profile-details">
|
||||||
<div class="username-bar pb-2 d-flex align-items-center">
|
<div class="username-bar pb-2 d-flex align-items-center">
|
||||||
<span class="font-weight-light h1">{{$user->username}}</span>
|
<span class="font-weight-ultralight h1">{{$user->username}}</span>
|
||||||
@if($owner == true)
|
@if($owner == true)
|
||||||
<span class="pl-4">
|
<span class="h5 pl-2 b-0">
|
||||||
<a class="btn btn-outline-secondary font-weight-bold px-4 py-0" href="{{route('settings')}}">Settings</a>
|
<a class="icon-settings text-muted" href="{{route('settings')}}"></a>
|
||||||
</span>
|
</span>
|
||||||
@elseif ($following == true)
|
@elseif ($following == true)
|
||||||
<span class="pl-4">
|
<span class="pl-4">
|
||||||
|
@ -80,8 +80,8 @@
|
||||||
<div class="profile-timeline mt-5 row">
|
<div class="profile-timeline mt-5 row">
|
||||||
@if($owner == true)
|
@if($owner == true)
|
||||||
<div class="col-12 mb-5">
|
<div class="col-12 mb-5">
|
||||||
<ul class="nav nav-tabs d-flex justify-content-center">
|
<ul class="nav nav-topbar d-flex justify-content-center">
|
||||||
<li class="nav-item mr-3">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{request()->is('*/saved') ? '':'active'}} font-weight-bold text-uppercase" href="{{$user->url()}}">Posts</a>
|
<a class="nav-link {{request()->is('*/saved') ? '':'active'}} font-weight-bold text-uppercase" href="{{$user->url()}}">Posts</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
@ -100,8 +100,20 @@
|
||||||
@if($timeline->count() > 0)
|
@if($timeline->count() > 0)
|
||||||
@foreach($timeline as $status)
|
@foreach($timeline as $status)
|
||||||
<div class="col-12 col-md-4 mb-4">
|
<div class="col-12 col-md-4 mb-4">
|
||||||
<a class="card" href="{{$status->url()}}">
|
<a class="card info-overlay" href="{{$status->url()}}">
|
||||||
<img class="card-img-top" src="{{$status->thumb()}}" width="300px" height="300px">
|
<div class="square">
|
||||||
|
<div class="square-content" style="background-image: url('{{$status->thumb()}}')"></div>
|
||||||
|
<div class="info-overlay-text">
|
||||||
|
<h5 class="text-white m-auto font-weight-bold">
|
||||||
|
<span class="pr-4">
|
||||||
|
<span class="icon-heart pr-1"></span> {{$status->likes_count}}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span class="icon-speech pr-1"></span> {{$status->comments_count}}
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@ -126,3 +138,4 @@
|
||||||
<meta property="og:description" content="{{$user->bio}}">
|
<meta property="og:description" content="{{$user->bio}}">
|
||||||
<meta property="og:image" content="{{$user->avatarUrl()}}">
|
<meta property="og:image" content="{{$user->avatarUrl()}}">
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,30 @@
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
<div class="container">
|
<div class="container px-0 mt-md-4">
|
||||||
<div class="col-12 mt-4">
|
|
||||||
|
|
||||||
<div class="card status-container orientation-{{$status->firstMedia()->orientation ?? 'unknown'}}">
|
<div class="card status-container orientation-{{$status->firstMedia()->orientation ?? 'unknown'}}">
|
||||||
<div class="card-body p-0">
|
<div class="row mx-0">
|
||||||
<div class="row">
|
<div class="col-12 col-md-8 status-photo px-0">
|
||||||
<div class="col-12 col-md-8 status-photo">
|
|
||||||
<img src="{{$status->mediaUrl()}}" width="100%">
|
<img src="{{$status->mediaUrl()}}" width="100%">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4" style="height:100%">
|
<div class="col-12 col-md-4 px-0 d-flex flex-column">
|
||||||
<div class="status-username d-inline-flex align-items-center pr-3 pt-3">
|
<div class="d-flex align-items-center justify-content-between card-header">
|
||||||
|
<div class="d-flex align-items-center status-username">
|
||||||
<div class="status-avatar mr-2">
|
<div class="status-avatar mr-2">
|
||||||
<img class="img-thumbnail" src="{{$user->avatarUrl()}}" width="50px" height="50px" style="border-radius:40px;">
|
<img class="img-thumbnail" src="{{$user->avatarUrl()}}" width="24px" height="24px" style="border-radius:12px;">
|
||||||
</div>
|
</div>
|
||||||
<div class="username">
|
<div class="username">
|
||||||
<a href="{{$user->url()}}" class="username-link font-weight-bold text-dark">{{$user->username}}</a>
|
<a href="{{$user->url()}}" class="username-link font-weight-bold text-dark">{{$user->username}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<div class="timestamp mb-0">
|
||||||
<div class="pr-3 mb-2 status-comments">
|
<p class="small text-uppercase mb-0"><a href="{{$status->url()}}" class="text-muted">{{$status->created_at->diffForHumans(null, true, true, true)}}</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body status-comments">
|
||||||
<div class="status-comment">
|
<div class="status-comment">
|
||||||
<span class="font-weight-bold pr-1">{{$status->profile->username}}</span>
|
|
||||||
<p class="mb-1">
|
<p class="mb-1">
|
||||||
|
<span class="font-weight-bold pr-1">{{$status->profile->username}}</span>
|
||||||
<span class="comment-text">{!! $status->rendered ?? e($status->caption) !!}</span>
|
<span class="comment-text">{!! $status->rendered ?? e($status->caption) !!}</span>
|
||||||
</p>
|
</p>
|
||||||
<div class="comments">
|
<div class="comments">
|
||||||
|
@ -37,40 +38,43 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="card-body flex-grow-0">
|
||||||
<div class="reactions h3 pr-3 mb-0">
|
<div class="reactions h3 mb-0">
|
||||||
<form class="like-form pr-3" method="post" action="/i/like" style="display: inline;" data-id="{{$status->id}}" data-action="like">
|
<form class="d-inline-flex like-form pr-3" method="post" action="/i/like" style="display: inline;" data-id="{{$status->id}}" data-action="like">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="item" value="{{$status->id}}">
|
<input type="hidden" name="item" value="{{$status->id}}">
|
||||||
<button class="btn btn-link text-dark p-0" type="submit"><span class="icon-heart" style="font-size:25px;"></span></button>
|
<button class="btn btn-link text-dark p-0" type="submit">
|
||||||
|
<span class="far fa-heart fa-lg mb-0"></span>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<span class="icon-speech pr-3"></span>
|
<span class="far fa-comment fa-lg pt-1 pr-3"></span>
|
||||||
@if(Auth::check())
|
@if(Auth::check())
|
||||||
@if(Auth::user()->profile->id === $status->profile->id || Auth::user()->is_admin == true)
|
@if(Auth::user()->profile->id === $status->profile->id || Auth::user()->is_admin == true)
|
||||||
<form method="post" action="/i/delete" class="d-inline-flex">
|
<form method="post" action="/i/delete" class="d-inline-flex">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="type" value="post">
|
<input type="hidden" name="type" value="post">
|
||||||
<input type="hidden" name="item" value="{{$status->id}}">
|
<input type="hidden" name="item" value="{{$status->id}}">
|
||||||
<button type="submit" class="btn btn-link text-dark p-0"><span class="icon-trash" style="font-size:25px;"></span></button>
|
<button type="submit" class="btn btn-link text-dark p-0">
|
||||||
|
<span class="far fa-trash-alt fa-lg mb-0"></span>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
<span class="float-right">
|
<span class="float-right">
|
||||||
<form class="bookmark-form" method="post" action="/i/bookmark" style="display: inline;" data-id="{{$status->id}}" data-action="bookmark">
|
<form class="d-inline-flex bookmark-form" method="post" action="/i/bookmark" style="display: inline;" data-id="{{$status->id}}" data-action="bookmark">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="item" value="{{$status->id}}">
|
<input type="hidden" name="item" value="{{$status->id}}">
|
||||||
<button class="btn btn-link text-dark p-0" type="submit"><span class="icon-notebook" style="font-size:25px;"></span></button>
|
<button class="btn btn-link text-dark p-0" type="submit">
|
||||||
|
<span class="far fa-bookmark fa-lg mb-0"></span>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="likes font-weight-bold mb-0">
|
<div class="likes font-weight-bold mb-0">
|
||||||
<span class="like-count">{{$status->likes()->count()}}</span> likes
|
<span class="like-count" data-count="{{$status->likes_count}}">{{$status->likes_count}}</span> likes
|
||||||
</div>
|
</div>
|
||||||
<div class="timestamp mb-0">
|
|
||||||
<p class="small text-uppercase mb-0"><a href="{{$status->url()}}" class="text-muted">{{$status->created_at->diffForHumans()}}</a></p>
|
|
||||||
</div>
|
</div>
|
||||||
<hr class="my-2">
|
<div class="card-footer">
|
||||||
<div class="pr-3 pb-2">
|
|
||||||
<form class="comment-form" method="post" action="/i/comment" data-id="{{$status->id}}" data-truncate="false">
|
<form class="comment-form" method="post" action="/i/comment" data-id="{{$status->id}}" data-truncate="false">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="item" value="{{$status->id}}">
|
<input type="hidden" name="item" value="{{$status->id}}">
|
||||||
|
@ -80,8 +84,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
@ -33,22 +33,24 @@
|
||||||
</a>
|
</a>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="reactions h3">
|
<div class="reactions h3">
|
||||||
<form class="like-form pr-3" method="post" action="/i/like" style="display: inline;" data-id="{{$item->id}}" data-action="like">
|
<form class="like-form pr-3" method="post" action="/i/like" style="display: inline;" data-id="{{$item->id}}" data-action="like" data-count="{{$item->likes_count}}">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="item" value="{{$item->id}}">
|
<input type="hidden" name="item" value="{{$item->id}}">
|
||||||
<button class="btn btn-link text-dark p-0" type="submit"><span class="icon-heart" style="font-size:25px;"></span></button>
|
<button class="btn btn-link text-dark p-0" type="submit">
|
||||||
|
<span class="far fa-heart status-heart fa-2x"></span>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<span class="icon-speech"></span>
|
<span class="far fa-comment status-comment-focus"></span>
|
||||||
<span class="float-right">
|
<span class="float-right">
|
||||||
<form class="bookmark-form" method="post" action="/i/bookmark" style="display: inline;" data-id="{{$item->id}}" data-action="bookmark">
|
<form class="bookmark-form" method="post" action="/i/bookmark" style="display: inline;" data-id="{{$item->id}}" data-action="bookmark">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="item" value="{{$item->id}}">
|
<input type="hidden" name="item" value="{{$item->id}}">
|
||||||
<button class="btn btn-link text-dark p-0" type="submit"><span class="icon-notebook" style="font-size:25px;"></span></button>
|
<button class="btn btn-link text-dark p-0" type="submit"><span class="far fa-bookmark" style="font-size:25px;"></span></button>
|
||||||
</form>
|
</form>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="likes font-weight-bold">
|
<div class="likes font-weight-bold">
|
||||||
<span class="like-count">{{$item->likes()->count()}}</span> likes
|
<span class="like-count">{{$item->likes_count}}</span> likes
|
||||||
</div>
|
</div>
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<p class="mb-1">
|
<p class="mb-1">
|
||||||
|
@ -95,7 +97,7 @@
|
||||||
<form class="comment-form" method="post" action="/i/comment" data-id="{{$item->id}}" data-truncate="true">
|
<form class="comment-form" method="post" action="/i/comment" data-id="{{$item->id}}" data-truncate="true">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="item" value="{{$item->id}}">
|
<input type="hidden" name="item" value="{{$item->id}}">
|
||||||
<input class="form-control" name="comment" placeholder="Add a comment...">
|
<input class="form-control status-reply-input" name="comment" placeholder="Add a comment...">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
23
resources/views/timeline/partial/new-form.blade.php
Normal file
23
resources/views/timeline/partial/new-form.blade.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header font-weight-bold">New Post</div>
|
||||||
|
<div class="card-body" id="statusForm">
|
||||||
|
<form method="post" action="/timeline" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="font-weight-bold text-muted small">Upload Image</label>
|
||||||
|
<input type="file" class="form-control-file" name="photo" accept="image/*">
|
||||||
|
<small class="form-text text-muted">
|
||||||
|
Max Size: @maxFileSize(). Supported formats: jpeg, png, gif, bmp.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="font-weight-bold text-muted small">Caption</label>
|
||||||
|
<input type="text" class="form-control" name="caption" placeholder="Add a caption here">
|
||||||
|
<small class="form-text text-muted">
|
||||||
|
Max length: {{config('pixelfed.max_caption_length')}} characters.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-outline-primary btn-block">Post</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -17,23 +17,8 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="card">
|
|
||||||
<div class="card-header font-weight-bold">New Post</div>
|
@include('timeline.partial.new-form')
|
||||||
<div class="card-body" id="statusForm">
|
|
||||||
<form method="post" action="/timeline" enctype="multipart/form-data">
|
|
||||||
@csrf
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="font-weight-bold text-muted small">Upload Image</label>
|
|
||||||
<input type="file" class="form-control-file" name="photo" accept="image/*">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="font-weight-bold text-muted small">Caption</label>
|
|
||||||
<input type="text" class="form-control" name="caption" placeholder="Add a caption here">
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-outline-primary btn-block">Post</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="timeline-feed my-5" data-timeline="personal">
|
<div class="timeline-feed my-5" data-timeline="personal">
|
||||||
@foreach($timeline as $item)
|
@foreach($timeline as $item)
|
||||||
|
|
|
@ -17,23 +17,8 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="card">
|
|
||||||
<div class="card-header font-weight-bold">New Post</div>
|
@include('timeline.partial.new-form')
|
||||||
<div class="card-body" id="statusForm">
|
|
||||||
<form method="post" action="/timeline" enctype="multipart/form-data">
|
|
||||||
@csrf
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="font-weight-bold text-muted small">Upload Image</label>
|
|
||||||
<input type="file" class="form-control-file" name="photo" accept="image/*">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="font-weight-bold text-muted small">Caption</label>
|
|
||||||
<input type="text" class="form-control" name="caption" placeholder="Add a caption here">
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-outline-primary btn-block">Post</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="timeline-feed my-5" data-timeline="public">
|
<div class="timeline-feed my-5" data-timeline="public">
|
||||||
@foreach($timeline as $item)
|
@foreach($timeline as $item)
|
||||||
|
|
|
@ -47,6 +47,7 @@ Route::domain(config('pixelfed.domain.app'))->group(function() {
|
||||||
Route::get('search/{tag}', 'SearchController@searchAPI')
|
Route::get('search/{tag}', 'SearchController@searchAPI')
|
||||||
->where('tag', '[A-Za-z0-9]+');
|
->where('tag', '[A-Za-z0-9]+');
|
||||||
Route::get('nodeinfo/2.0.json', 'FederationController@nodeinfo');
|
Route::get('nodeinfo/2.0.json', 'FederationController@nodeinfo');
|
||||||
|
Route::get('v1/likes', 'ApiController@hydrateLikes');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('discover/tags/{hashtag}', 'DiscoverController@showTags');
|
Route::get('discover/tags/{hashtag}', 'DiscoverController@showTags');
|
||||||
|
@ -124,6 +125,7 @@ Route::domain(config('pixelfed.domain.app'))->group(function() {
|
||||||
Route::view('libraries', 'site.libraries')->name('site.libraries');
|
Route::view('libraries', 'site.libraries')->name('site.libraries');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::get('p/{username}/{id}/c/{cid}', 'CommentController@show');
|
||||||
Route::get('p/{username}/{id}', 'StatusController@show');
|
Route::get('p/{username}/{id}', 'StatusController@show');
|
||||||
Route::get('{username}/saved', 'ProfileController@savedBookmarks');
|
Route::get('{username}/saved', 'ProfileController@savedBookmarks');
|
||||||
Route::get('{username}/followers', 'ProfileController@followers');
|
Route::get('{username}/followers', 'ProfileController@followers');
|
||||||
|
|
Loading…
Reference in a new issue