1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/pixelfed_ynh.git synced 2024-09-03 20:06:04 +02:00

Merge branch 'frontend-ui-refactor' into feat/double-tap-to-like

This commit is contained in:
daniel 2019-05-06 20:47:13 -06:00 committed by GitHub
commit 7ceaa25205
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 748 additions and 237 deletions

View file

@ -1,11 +1,11 @@
APP_NAME="PixelFed Test" APP_NAME="PixelFed Prod"
APP_ENV=local APP_ENV=production
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=false
APP_URL=http://localhost
ADMIN_DOMAIN="localhost" APP_URL=http://localhost
APP_DOMAIN="localhost" APP_DOMAIN="localhost"
ADMIN_DOMAIN="localhost"
SESSION_DOMAIN="localhost" SESSION_DOMAIN="localhost"
SESSION_SECURE_COOKIE=true SESSION_SECURE_COOKIE=true
TRUST_PROXIES="*" TRUST_PROXIES="*"
@ -38,22 +38,14 @@ MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="pixelfed@example.com" MAIL_FROM_ADDRESS="pixelfed@example.com"
MAIL_FROM_NAME="Pixelfed" MAIL_FROM_NAME="Pixelfed"
API_BASE="/api/1/"
API_SEARCH="/api/search"
OPEN_REGISTRATION=true OPEN_REGISTRATION=true
ENFORCE_EMAIL_VERIFICATION=true ENFORCE_EMAIL_VERIFICATION=true
PF_MAX_USERS=1000
MAX_PHOTO_SIZE=15000 MAX_PHOTO_SIZE=15000
MAX_CAPTION_LENGTH=150 MAX_CAPTION_LENGTH=150
MAX_ALBUM_LENGTH=4 MAX_ALBUM_LENGTH=4
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
MIX_APP_URL="${APP_URL}"
MIX_API_BASE="${API_BASE}"
MIX_API_SEARCH="${API_SEARCH}"
ACTIVITY_PUB=false ACTIVITY_PUB=false
REMOTE_FOLLOW=false REMOTE_FOLLOW=false
ACTIVITYPUB_INBOX=false ACTIVITYPUB_INBOX=false

View file

@ -2,10 +2,13 @@ APP_NAME="PixelFed Test"
APP_ENV=local APP_ENV=local
APP_KEY=base64:lwX95GbNWX3XsucdMe0XwtOKECta3h/B+p9NbH2jd0E= APP_KEY=base64:lwX95GbNWX3XsucdMe0XwtOKECta3h/B+p9NbH2jd0E=
APP_DEBUG=true APP_DEBUG=true
APP_URL=https://pixelfed.dev
ADMIN_DOMAIN="pixelfed.dev" APP_URL=https://pixelfed.dev
APP_DOMAIN="pixelfed.dev" APP_DOMAIN="pixelfed.dev"
ADMIN_DOMAIN="pixelfed.dev"
SESSION_DOMAIN="pixelfed.dev"
SESSION_SECURE_COOKIE=true
TRUST_PROXIES="*"
LOG_CHANNEL=stack LOG_CHANNEL=stack
@ -35,28 +38,29 @@ MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="pixelfed@example.com" MAIL_FROM_ADDRESS="pixelfed@example.com"
MAIL_FROM_NAME="Pixelfed" MAIL_FROM_NAME="Pixelfed"
SESSION_DOMAIN="${APP_DOMAIN}" OPEN_REGISTRATION=true
SESSION_SECURE_COOKIE=true ENFORCE_EMAIL_VERIFICATION=false
API_BASE="/api/1/" PF_MAX_USERS=1000
API_SEARCH="/api/search"
OPEN_REGISTRATION=false
ENFORCE_EMAIL_VERIFICATION=true
MAX_PHOTO_SIZE=15000 MAX_PHOTO_SIZE=15000
MAX_CAPTION_LENGTH=150 MAX_CAPTION_LENGTH=150
MAX_ALBUM_LENGTH=4 MAX_ALBUM_LENGTH=4
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" ACTIVITY_PUB=false
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" REMOTE_FOLLOW=false
MIX_APP_URL="${APP_URL}" ACTIVITYPUB_INBOX=false
MIX_API_BASE="${API_BASE}" ACTIVITYPUB_SHAREDINBOX=false
MIX_API_SEARCH="${API_SEARCH}" # Set these "true" to enable federation.
# You might need to also run:
TELESCOPE_ENABLED=false # php artisan cache:clear
PF_MAX_USERS=1000 # php artisan optimize:clear
# php artisan optimize
PF_COSTAR_ENABLED=true PF_COSTAR_ENABLED=true
CS_BLOCKED_DOMAINS='example.org,example.net,example.com' CS_BLOCKED_DOMAINS='example.org,example.net,example.com'
CS_CW_DOMAINS='example.org,example.net,example.com' CS_CW_DOMAINS='example.org,example.net,example.com'
CS_UNLISTED_DOMAINS='example.org,example.net,example.com' CS_UNLISTED_DOMAINS='example.org,example.net,example.com'
## Optional
#HORIZON_DARKMODE=false # Horizon theme darkmode
#HORIZON_EMBED=false # Single Docker Container mode

View file

@ -24,7 +24,8 @@ trait LabsSettings {
$this->validate($request, [ $this->validate($request, [
'profile_layout' => 'nullable', 'profile_layout' => 'nullable',
'dark_mode' => 'nullable', 'dark_mode' => 'nullable',
'profile_suggestions' => 'nullable' 'profile_suggestions' => 'nullable',
'moment_bg' => 'nullable'
]); ]);
$changes = false; $changes = false;
@ -60,6 +61,12 @@ trait LabsSettings {
SuggestionService::del($profile->id); SuggestionService::del($profile->id);
} }
if($request->has('moment_bg') && $profile->profile_layout == 'moment') {
$bg = in_array($request->input('moment_bg'), $this->momentBackgrounds()) ? $request->input('moment_bg') : 'default';
$profile->header_bg = $bg;
$changes = true;
}
if($changes == true) { if($changes == true) {
$profile->save(); $profile->save();
} }
@ -69,4 +76,21 @@ trait LabsSettings {
->cookie($cookie); ->cookie($cookie);
} }
protected function momentBackgrounds()
{
return [
'default',
'azure',
'passion',
'reef',
'lush',
'neon',
'flare',
'morning',
'tranquil',
'mauve',
'argon',
'royal'
];
}
} }

View file

@ -69,19 +69,13 @@ class LikePipeline implements ShouldQueue
$notification->profile_id = $status->profile_id; $notification->profile_id = $status->profile_id;
$notification->actor_id = $actor->id; $notification->actor_id = $actor->id;
$notification->action = 'like'; $notification->action = 'like';
$notification->message = $like->toText(); $notification->message = $like->toText($status->in_reply_to_id ? 'comment' : 'post');
$notification->rendered = $like->toHtml(); $notification->rendered = $like->toHtml($status->in_reply_to_id ? 'comment' : 'post');
$notification->item_id = $status->id; $notification->item_id = $status->id;
$notification->item_type = "App\Status"; $notification->item_type = "App\Status";
$notification->save(); $notification->save();
Cache::forever('notification.'.$notification->id, $notification);
$redis = Redis::connection();
$key = config('cache.prefix').':user.'.$status->profile_id.'.notifications';
$redis->lpush($key, $notification->id);
} catch (Exception $e) { } catch (Exception $e) {
Log::error($e);
} }
} }
} }

View file

@ -27,19 +27,20 @@ class Like extends Model
return $this->belongsTo(Status::class); return $this->belongsTo(Status::class);
} }
public function toText() public function toText($type = 'post')
{ {
$actorName = $this->actor->username; $actorName = $this->actor->username;
$msg = $type == 'post' ? __('notification.likedPhoto') : __('notification.likedComment');
return "{$actorName} ".__('notification.likedPhoto'); return "{$actorName} ".$msg;
} }
public function toHtml() public function toHtml($type = 'post')
{ {
$actorName = $this->actor->username; $actorName = $this->actor->username;
$actorUrl = $this->actor->url(); $actorUrl = $this->actor->url();
$msg = $type == 'post' ? __('notification.likedPhoto') : __('notification.likedComment');
return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> ". return "<a href='{$actorUrl}' class='profile-link'>{$actorName}</a> ".$msg;
__('notification.likedPhoto');
} }
} }

View file

@ -20,6 +20,10 @@ class HorizonServiceProvider extends HorizonApplicationServiceProvider
// Horizon::routeSmsNotificationsTo('15556667777'); // Horizon::routeSmsNotificationsTo('15556667777');
// Horizon::routeMailNotificationsTo('example@example.com'); // Horizon::routeMailNotificationsTo('example@example.com');
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel'); // Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
if(config('horizon.darkmode') == true) {
Horizon::night();
}
} }
/** /**
@ -36,15 +40,4 @@ class HorizonServiceProvider extends HorizonApplicationServiceProvider
}); });
} }
/**
* Register any application services.
*
* @return void
*/
public function register()
{
if(config('horizon.darkmode') == true) {
Horizon::night();
}
}
} }

View file

@ -26,6 +26,7 @@ class AccountTransformer extends Fractal\TransformerAbstract
'avatar_static' => $profile->avatarUrl(), 'avatar_static' => $profile->avatarUrl(),
'header' => null, 'header' => null,
'header_static' => null, 'header_static' => null,
'header_bg' => $profile->header_bg,
'moved' => null, 'moved' => null,
'fields' => null, 'fields' => null,
'bot' => null, 'bot' => null,

View file

@ -18,7 +18,7 @@
"intervention/image": "^2.4", "intervention/image": "^2.4",
"jenssegers/agent": "^2.6", "jenssegers/agent": "^2.6",
"laravel/framework": "5.8.*", "laravel/framework": "5.8.*",
"laravel/horizon": "^3.0", "laravel/horizon": "^3.1",
"laravel/passport": "^7.0", "laravel/passport": "^7.0",
"laravel/tinker": "^1.0", "laravel/tinker": "^1.0",
"league/flysystem-aws-s3-v3": "~1.0", "league/flysystem-aws-s3-v3": "~1.0",

44
composer.lock generated
View file

@ -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": "e7370fab05135d2b5e1161ccfc821f17", "content-hash": "36dce3c2a72bd07cacbd5e9f38e568f4",
"packages": [ "packages": [
{ {
"name": "alchemy/binary-driver", "name": "alchemy/binary-driver",
@ -71,16 +71,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.93.1", "version": "3.93.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "2dce6e4b7295c6ea44392fc8eff421e3651a8725" "reference": "874c1040edab52df3873157aa54ea51833d48c0e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2dce6e4b7295c6ea44392fc8eff421e3651a8725", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/874c1040edab52df3873157aa54ea51833d48c0e",
"reference": "2dce6e4b7295c6ea44392fc8eff421e3651a8725", "reference": "874c1040edab52df3873157aa54ea51833d48c0e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -150,7 +150,7 @@
"s3", "s3",
"sdk" "sdk"
], ],
"time": "2019-05-01T18:10:22+00:00" "time": "2019-05-03T18:07:06+00:00"
}, },
{ {
"name": "beyondcode/laravel-self-diagnosis", "name": "beyondcode/laravel-self-diagnosis",
@ -2262,16 +2262,16 @@
}, },
{ {
"name": "league/oauth2-server", "name": "league/oauth2-server",
"version": "7.3.3", "version": "7.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/oauth2-server.git", "url": "https://github.com/thephpleague/oauth2-server.git",
"reference": "c7f499849704ebe2c60b45b6d6bb231df5601d4a" "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/c7f499849704ebe2c60b45b6d6bb231df5601d4a", "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf",
"reference": "c7f499849704ebe2c60b45b6d6bb231df5601d4a", "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2335,7 +2335,7 @@
"secure", "secure",
"server" "server"
], ],
"time": "2019-03-29T18:19:35+00:00" "time": "2019-05-05T09:22:01+00:00"
}, },
{ {
"name": "mobiledetect/mobiledetectlib", "name": "mobiledetect/mobiledetectlib",
@ -2724,16 +2724,16 @@
}, },
{ {
"name": "opis/closure", "name": "opis/closure",
"version": "3.1.6", "version": "3.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/opis/closure.git", "url": "https://github.com/opis/closure.git",
"reference": "ccb8e3928c5c8181c76cdd0ed9366c5bcaafd91b" "reference": "09b4389715a7eec100176ea58286649181753508"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/opis/closure/zipball/ccb8e3928c5c8181c76cdd0ed9366c5bcaafd91b", "url": "https://api.github.com/repos/opis/closure/zipball/09b4389715a7eec100176ea58286649181753508",
"reference": "ccb8e3928c5c8181c76cdd0ed9366c5bcaafd91b", "reference": "09b4389715a7eec100176ea58286649181753508",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2746,7 +2746,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.1.x-dev" "dev-master": "3.2.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -2781,7 +2781,7 @@
"serialization", "serialization",
"serialize" "serialize"
], ],
"time": "2019-02-22T10:30:00+00:00" "time": "2019-05-05T12:50:25+00:00"
}, },
{ {
"name": "paragonie/constant_time_encoding", "name": "paragonie/constant_time_encoding",
@ -7168,16 +7168,16 @@
}, },
{ {
"name": "sebastian/environment", "name": "sebastian/environment",
"version": "4.2.1", "version": "4.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/environment.git", "url": "https://github.com/sebastianbergmann/environment.git",
"reference": "3095910f0f0fb155ac4021fc51a4a7a39ac04e8a" "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/3095910f0f0fb155ac4021fc51a4a7a39ac04e8a", "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
"reference": "3095910f0f0fb155ac4021fc51a4a7a39ac04e8a", "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -7217,7 +7217,7 @@
"environment", "environment",
"hhvm" "hhvm"
], ],
"time": "2019-04-25T07:55:20+00:00" "time": "2019-05-05T09:05:15+00:00"
}, },
{ {
"name": "sebastian/exporter", "name": "sebastian/exporter",

View file

@ -158,6 +158,7 @@ return [
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class, App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class, // App\Providers\BroadcastServiceProvider::class,
App\Providers\HorizonServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,

View file

@ -2,6 +2,32 @@
return [ return [
/*
|--------------------------------------------------------------------------
| Horizon Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Horizon will be accessible from. If this
| setting is null, Horizon will reside under the same domain as the
| application. Otherwise, this value will serve as the subdomain.
|
*/
'domain' => null,
/*
|--------------------------------------------------------------------------
| Horizon Path
|--------------------------------------------------------------------------
|
| This is the URI path where Horizon will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => 'horizon',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Horizon Redis Connection | Horizon Redis Connection
@ -28,6 +54,19 @@ return [
'prefix' => env('HORIZON_PREFIX', 'horizon-'.str_random(8).':'), 'prefix' => env('HORIZON_PREFIX', 'horizon-'.str_random(8).':'),
/*
|--------------------------------------------------------------------------
| Horizon Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will get attached onto each Horizon route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => ['web'],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Queue Wait Time Thresholds | Queue Wait Time Thresholds
@ -61,6 +100,34 @@ return [
'failed' => 10080, 'failed' => 10080,
], ],
/*
|--------------------------------------------------------------------------
| Fast Termination
|--------------------------------------------------------------------------
|
| When this option is enabled, Horizon's "terminate" command will not
| wait on all of the workers to terminate unless the --wait option
| is provided. Fast termination can shorten deployment delay by
| allowing a new instance of Horizon to start while the last
| instance will continue to terminate each of its workers.
|
*/
'fast_termination' => false,
/*
|--------------------------------------------------------------------------
| Memory Limit (MB)
|--------------------------------------------------------------------------
|
| This value describes the maximum amount of memory the Horizon worker
| may consume before it is terminated and restarted. You should set
| this value according to the resources available to your server.
|
*/
'memory_limit' => 64,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Queue Worker Configuration | Queue Worker Configuration

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddHeaderToProfilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('profiles', function (Blueprint $table) {
$table->string('header_bg')->nullable()->after('profile_layout');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('profiles', function (Blueprint $table) {
$table->dropColumn('header_bg');
});
}
}

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/js/status.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,15 +1,15 @@
{ {
"/js/activity.js": "/js/activity.js?id=7915246c3bc2b7e9770e", "/js/activity.js": "/js/activity.js?id=7915246c3bc2b7e9770e",
"/js/app.js": "/js/app.js?id=1f05f00eec0e86f49dd4", "/js/app.js": "/js/app.js?id=1f05f00eec0e86f49dd4",
"/css/app.css": "/css/app.css?id=b407fd02a5b7526f85b4", "/css/app.css": "/css/app.css?id=3a974ff74b6b5905a73c",
"/css/appdark.css": "/css/appdark.css?id=b4a7cf4f8dd06abe699e", "/css/appdark.css": "/css/appdark.css?id=107806a000e2ca675a3c",
"/css/landing.css": "/css/landing.css?id=d3610108213e88dc080c", "/css/landing.css": "/css/landing.css?id=d3610108213e88dc080c",
"/js/components.js": "/js/components.js?id=25d082643150ee79150c", "/js/components.js": "/js/components.js?id=25d082643150ee79150c",
"/js/compose.js": "/js/compose.js?id=4d8c53b4575f463214f2", "/js/compose.js": "/js/compose.js?id=9ca175b3e11908bd592f",
"/js/developers.js": "/js/developers.js?id=1359f11c7349301903f8", "/js/developers.js": "/js/developers.js?id=1359f11c7349301903f8",
"/js/discover.js": "/js/discover.js?id=75fb12b06ee23fa05186", "/js/discover.js": "/js/discover.js?id=75fb12b06ee23fa05186",
"/js/profile.js": "/js/profile.js?id=b267c34e3f9168a8b307", "/js/profile.js": "/js/profile.js?id=6386a007bdb1796dcc80",
"/js/search.js": "/js/search.js?id=0d3d080dc05f4f49b204", "/js/search.js": "/js/search.js?id=0d3d080dc05f4f49b204",
"/js/status.js": "/js/status.js?id=bf48fe9060a74d1180f2", "/js/status.js": "/js/status.js?id=a95243f92346f1724a35",
"/js/timeline.js": "/js/timeline.js?id=ded47e282e9b3339c1fd" "/js/timeline.js": "/js/timeline.js?id=265d634706cec1b2653d"
} }

View file

@ -34,10 +34,10 @@
</div> </div>
</div> </div>
<div v-else> <div v-else>
<div v-if="ids.length > 0 && ids.length != config.uploader.album_limit" class="card-header py-2 bg-primary m-2 rounded cursor-pointer" v-on:click="addMedia()"> <div v-if="ids.length > 0 && ids.length != config.uploader.album_limit" class="card-header py-2 bg-primary m-2 rounded cursor-pointer" v-on:click="addMedia($event)">
<p class="text-center mb-0 font-weight-bold text-white"><i class="fas fa-plus mr-1"></i> Add Photo</p> <p class="text-center mb-0 font-weight-bold text-white"><i class="fas fa-plus mr-1"></i> Add Photo</p>
</div> </div>
<div v-if="ids.length == 0" class="w-100 h-100 bg-light py-5 cursor-pointer" style="border-bottom: 1px solid #f1f1f1" v-on:click="addMedia()"> <div v-if="ids.length == 0" class="w-100 h-100 bg-light py-5 cursor-pointer" style="border-bottom: 1px solid #f1f1f1" v-on:click="addMedia($event)">
<p class="text-center mb-0 font-weight-bold p-5">Click here to add photos</p> <p class="text-center mb-0 font-weight-bold p-5">Click here to add photos</p>
</div> </div>
<div v-if="ids.length > 0"> <div v-if="ids.length > 0">
@ -316,7 +316,7 @@ export default {
}); });
}, },
addMedia() { addMedia(event) {
let el = $(event.target); let el = $(event.target);
el.attr('disabled', ''); el.attr('disabled', '');
let fi = $('.file-input[name="media"]'); let fi = $('.file-input[name="media"]');

View file

@ -67,7 +67,8 @@
data() { data() {
return { return {
notifications: {}, notifications: {},
notificationCursor: 2 notificationCursor: 2,
notificationMaxId: 0,
}; };
}, },
@ -91,9 +92,12 @@
} }
return true; return true;
}); });
let ids = res.data.map(n => n.id);
this.notificationMaxId = Math.max(...ids);
this.notifications = data; this.notifications = data;
$('.notification-card .loader').addClass('d-none'); $('.notification-card .loader').addClass('d-none');
$('.notification-card .contents').removeClass('d-none'); $('.notification-card .contents').removeClass('d-none');
this.notificationPoll();
}); });
}, },
@ -161,6 +165,32 @@
let username = status.account.username; let username = status.account.username;
let id = status.id; let id = status.id;
return '/p/' + username + '/' + id; return '/p/' + username + '/' + id;
},
notificationPoll() {
let interval = this.notifications.length > 5 ? 15000 : 120000;
let self = this;
setInterval(function() {
axios.get('/api/v1/notifications')
.then(res => {
let data = res.data.filter(n => {
if(n.type == 'share' || self.notificationMaxId >= n.id) {
return false;
}
return true;
});
if(data.length) {
let ids = data.map(n => n.id);
self.notificationMaxId = Math.max(...ids);
self.notifications.unshift(...data);
let beep = new Audio('/static/beep.mp3');
beep.volume = 0.7;
beep.play();
$('.notification-card .far.fa-bell').addClass('fas text-danger').removeClass('far text-muted');
}
});
}, interval);
} }
} }
} }

View file

@ -893,11 +893,11 @@ export default {
let em = event.target.innerText; let em = event.target.innerText;
if(this.replyText.length == 0) { if(this.replyText.length == 0) {
this.reply_to_profile_id = this.status.account.id; this.reply_to_profile_id = this.status.account.id;
this.replyText = '@' + this.status.account.username + ' ' + em; this.replyText = em + ' ';
$('textarea[name="comment"]').focus(); $('textarea[name="comment"]').focus();
} else { } else {
this.reply_to_profile_id = this.status.account.id; this.reply_to_profile_id = this.status.account.id;
this.replyText += em; this.replyText += em + ' ';
$('textarea[name="comment"]').focus(); $('textarea[name="comment"]').focus();
} }
}, },

View file

@ -294,7 +294,7 @@
</div> </div>
<div v-if="profileLayout == 'moment'"> <div v-if="profileLayout == 'moment'">
<div class="w-100 h-100 mt-n3 bg-pixelfed" style="width:100%;min-height:274px;"> <div :class="momentBackground()" style="width:100%;min-height:274px;">
</div> </div>
<div class="bg-white border-bottom"> <div class="bg-white border-bottom">
<div class="container"> <div class="container">
@ -1045,6 +1045,16 @@ export default {
this.profile.following_count--; this.profile.following_count--;
} }
}) })
},
momentBackground() {
let c = 'w-100 h-100 mt-n3 ';
if(this.profile.header_bg) {
c += this.profile.header_bg == 'default' ? 'bg-pixelfed' : 'bg-moment-' + this.profile.header_bg;
} else {
c += 'bg-pixelfed';
}
return c;
} }
} }
} }

View file

@ -8,125 +8,173 @@
<span class="sr-only">Loading...</span> <span class="sr-only">Loading...</span>
</div> </div>
</div> </div>
<div class="card mb-sm-4 status-card card-md-rounded-0" :data-status-id="status.id" v-for="(status, index) in feed" :key="`${index}-${status.id}`"> <div :data-status-id="status.id" v-for="(status, index) in feed" :key="`${index}-${status.id}`">
<div v-if="index == 2 && showSuggestions == true && suggestions.length" class="card mb-sm-4 status-card card-md-rounded-0">
<div class="card-header d-inline-flex align-items-center bg-white"> <div class="card-header d-flex align-items-center justify-content-between bg-white border-0 pb-0">
<img v-bind:src="status.account.avatar" width="32px" height="32px" style="border-radius: 32px;"> <h6 class="text-muted font-weight-bold mb-0">Suggestions For You</h6>
<a class="username font-weight-bold pl-2 text-dark" v-bind:href="status.account.url"> <span class="cursor-pointer text-muted" v-on:click="hideSuggestions"><i class="fas fa-times"></i></span>
{{status.account.username}} </div>
</a> <div class="card-body row mx-0">
<div class="text-right" style="flex-grow:1;"> <div class="col-12 col-md-4 mb-3" v-for="(rec, index) in suggestions">
<button class="btn btn-link text-dark no-caret dropdown-toggle py-0" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Post options"> <div class="card">
<span class="fas fa-ellipsis-v fa-lg text-muted"></span> <div class="card-body text-center pt-3">
</button> <p class="mb-0">
<div class="dropdown-menu dropdown-menu-right"> <a :href="'/'+rec.username">
<a class="dropdown-item font-weight-bold" :href="status.url">Go to post</a> <img :src="rec.avatar" class="img-fluid rounded-circle cursor-pointer" width="45px" height="45px">
<!-- <a class="dropdown-item font-weight-bold" href="#">Share</a> </a>
<a class="dropdown-item font-weight-bold" href="#">Embed</a> --> </p>
<span v-if="statusOwner(status) == false"> <div class="py-3">
<a class="dropdown-item font-weight-bold" :href="reportUrl(status)">Report</a> <p class="font-weight-bold text-dark cursor-pointer mb-0">
<a class="dropdown-item font-weight-bold" v-on:click="muteProfile(status)">Mute Profile</a> <a :href="'/'+rec.username" class="text-decoration-none text-dark">
<a class="dropdown-item font-weight-bold" v-on:click="blockProfile(status)">Block Profile</a> {{rec.username}}
</span> </a>
<span v-if="statusOwner(status) == true"> </p>
<a class="dropdown-item font-weight-bold text-danger" v-on:click="deletePost(status)">Delete</a> <p class="small text-muted mb-0">{{rec.message}}</p>
</span> </div>
<span v-if="profile.is_admin == true && modes.mod == true"> <p class="mb-0">
<div class="dropdown-divider"></div> <a class="btn btn-primary btn-block font-weight-bold py-0" href="#" @click.prevent="expRecFollow(rec.id, index)">Follow</a>
<a v-if="!statusOwner(status)" class="dropdown-item font-weight-bold text-danger" v-on:click="deletePost(status)">Delete</a> </p>
<div class="dropdown-divider"></div> </div>
<h6 class="dropdown-header">Mod Tools</h6> </div>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'autocw')">
<p class="mb-0" data-toggle="tooltip" data-placement="bottom" title="Adds a CW to every post made by this account.">Enforce CW</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'noautolink')">
<p class="mb-0" title="Do not transform mentions, hashtags or urls into HTML.">No Autolinking</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'unlisted')">
<p class="mb-0" title="Removes account from public/network timelines.">Unlisted Posts</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'disable')">
<p class="mb-0" title="Temporarily disable account until next time user log in.">Disable Account</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'suspend')">
<p class="mb-0" title="This prevents any new interactions, without deleting existing data.">Suspend Account</p>
</a>
</span>
</div> </div>
</div> </div>
</div> </div>
<div class="card mb-sm-4 status-card card-md-rounded-0">
<div class="card-header d-inline-flex align-items-center bg-white">
<img v-bind:src="status.account.avatar" width="32px" height="32px" style="border-radius: 32px;">
<a class="username font-weight-bold pl-2 text-dark" v-bind:href="status.account.url">
{{status.account.username}}
</a>
<div class="text-right" style="flex-grow:1;">
<button class="btn btn-link text-dark no-caret dropdown-toggle py-0" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Post options">
<span class="fas fa-ellipsis-v fa-lg text-muted"></span>
</button>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item font-weight-bold" :href="status.url">Go to post</a>
<!-- <a class="dropdown-item font-weight-bold" href="#">Share</a>
<a class="dropdown-item font-weight-bold" href="#">Embed</a> -->
<span v-if="statusOwner(status) == false">
<a class="dropdown-item font-weight-bold" :href="reportUrl(status)">Report</a>
<a class="dropdown-item font-weight-bold" v-on:click="muteProfile(status)">Mute Profile</a>
<a class="dropdown-item font-weight-bold" v-on:click="blockProfile(status)">Block Profile</a>
</span>
<span v-if="statusOwner(status) == true">
<a class="dropdown-item font-weight-bold text-danger" v-on:click="deletePost(status)">Delete</a>
</span>
<span v-if="profile.is_admin == true && modes.mod == true">
<div class="dropdown-divider"></div>
<a v-if="!statusOwner(status)" class="dropdown-item font-weight-bold text-danger" v-on:click="deletePost(status)">Delete</a>
<div class="dropdown-divider"></div>
<h6 class="dropdown-header">Mod Tools</h6>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'autocw')">
<p class="mb-0" data-toggle="tooltip" data-placement="bottom" title="Adds a CW to every post made by this account.">Enforce CW</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'noautolink')">
<p class="mb-0" title="Do not transform mentions, hashtags or urls into HTML.">No Autolinking</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'unlisted')">
<p class="mb-0" title="Removes account from public/network timelines.">Unlisted Posts</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'disable')">
<p class="mb-0" title="Temporarily disable account until next time user log in.">Disable Account</p>
</a>
<a class="dropdown-item font-weight-bold" v-on:click="moderatePost(status, 'suspend')">
<p class="mb-0" title="This prevents any new interactions, without deleting existing data.">Suspend Account</p>
</a>
<div class="postPresenterContainer" v-on:doubletap="likeStatus(status, $event)"> </span>
<div v-if="status.pf_type === 'photo'" class="w-100"> </div>
<photo-presenter :status="status" v-on:lightbox="lightbox"></photo-presenter> </div>
</div> </div>
<div v-else-if="status.pf_type === 'video'" class="w-100"> <div class="postPresenterContainer" v-on:doubletap="likeStatus(status, $event)">
<video-presenter :status="status"></video-presenter> <div v-if="status.pf_type === 'photo'" class="w-100">
<photo-presenter :status="status" v-on:lightbox="lightbox"></photo-presenter>
</div>
<div v-else-if="status.pf_type === 'video'" class="w-100">
<video-presenter :status="status"></video-presenter>
</div>
<div v-else-if="status.pf_type === 'photo:album'" class="w-100">
<photo-album-presenter :status="status" v-on:lightbox="lightbox"></photo-album-presenter>
</div>
<div v-else-if="status.pf_type === 'video:album'" class="w-100">
<video-album-presenter :status="status"></video-album-presenter>
</div>
<div v-else-if="status.pf_type === 'photo:video:album'" class="w-100">
<mixed-album-presenter :status="status" v-on:lightbox="lightbox"></mixed-album-presenter>
</div>
<div v-else class="w-100">
<p class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
</div>
</div> </div>
<div v-else-if="status.pf_type === 'photo:album'" class="w-100"> <div class="card-body">
<photo-album-presenter :status="status" v-on:lightbox="lightbox"></photo-album-presenter> <div class="reactions my-1">
<h3 v-bind:class="[status.favourited ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus(status, $event)"></h3>
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
<h3 v-bind:class="[status.reblogged ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
</div>
<div class="likes font-weight-bold" v-if="expLc(status) == true">
<span class="like-count">{{status.favourites_count}}</span> {{status.favourites_count == 1 ? 'like' : 'likes'}}
</div>
<div class="caption">
<p class="mb-2 read-more" style="overflow: hidden;">
<span class="username font-weight-bold">
<bdi><a class="text-dark" :href="status.account.url">{{status.account.username}}</a></bdi>
</span>
<span v-html="status.content"></span>
</p>
</div>
<div class="comments" v-if="status.id == replyId && !status.comments_disabled">
<p class="mb-0 d-flex justify-content-between align-items-top read-more" style="overflow-y: hidden;" v-for="(reply, index) in replies">
<span>
<a class="text-dark font-weight-bold mr-1" :href="reply.account.url">{{reply.account.username}}</a>
<span v-html="reply.content"></span>
</span>
<span class="mb-0" style="min-width:38px">
<span v-on:click="likeStatus(reply, $event)"><i v-bind:class="[reply.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']"></i></span>
<post-menu :status="reply" :profile="profile" size="sm" :modal="'true'" :feed="feed" class="d-inline-flex pl-2"></post-menu>
</span>
</p>
</div>
<div class="timestamp mt-2">
<p class="small text-uppercase mb-0">
<a :href="status.url" class="text-muted">
<timeago :datetime="status.created_at" :auto-update="60" :converter-options="{includeSeconds:true}" :title="timestampFormat(status.created_at)" v-b-tooltip.hover.bottom></timeago>
</a>
</p>
</div>
</div> </div>
<div v-else-if="status.pf_type === 'video:album'" class="w-100"> <div v-if="status.id == replyId && !status.comments_disabled" class="card-footer bg-white px-2 py-0">
<video-album-presenter :status="status"></video-album-presenter> <ul class="nav align-items-center emoji-reactions" style="overflow-x: scroll;flex-wrap: unset;">
<li class="nav-item" v-on:click="emojiReaction(status)">😂</li>
<li class="nav-item" v-on:click="emojiReaction(status)">💯</li>
<li class="nav-item" v-on:click="emojiReaction(status)"></li>
<li class="nav-item" v-on:click="emojiReaction(status)">🙌</li>
<li class="nav-item" v-on:click="emojiReaction(status)">👏</li>
<li class="nav-item" v-on:click="emojiReaction(status)">😍</li>
<li class="nav-item" v-on:click="emojiReaction(status)">😯</li>
<li class="nav-item" v-on:click="emojiReaction(status)">😢</li>
<li class="nav-item" v-on:click="emojiReaction(status)">😅</li>
<li class="nav-item" v-on:click="emojiReaction(status)">😁</li>
<li class="nav-item" v-on:click="emojiReaction(status)">🙂</li>
<li class="nav-item" v-on:click="emojiReaction(status)">😎</li>
</ul>
</div> </div>
<div v-else-if="status.pf_type === 'photo:video:album'" class="w-100"> <div v-if="status.id == replyId && !status.comments_disabled" class="card-footer bg-white sticky-md-bottom p-0">
<mixed-album-presenter :status="status" v-on:lightbox="lightbox"></mixed-album-presenter> <form class="border-0 rounded-0 align-middle" method="post" action="/i/comment" :data-id="status.id" data-truncate="false">
<textarea class="form-control border-0 rounded-0" name="comment" placeholder="Add a comment…" autocomplete="off" autocorrect="off" style="height:56px;line-height: 18px;max-height:80px;resize: none; padding-right:4.2rem;" v-model="replyText"></textarea>
<input type="button" value="Post" class="d-inline-block btn btn-link font-weight-bold reply-btn text-decoration-none" v-on:click.prevent="commentSubmit(status, $event)"/>
</form>
</div> </div>
<div v-else class="w-100">
<p class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
</div>
</div>
<div class="card-body">
<div class="reactions my-1">
<h3 v-bind:class="[status.favourited ? 'fas fa-heart text-danger pr-3 m-0 cursor-pointer' : 'far fa-heart pr-3 m-0 like-btn cursor-pointer']" title="Like" v-on:click="likeStatus(status, $event)"></h3>
<h3 v-if="!status.comments_disabled" class="far fa-comment pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
<h3 v-bind:class="[status.reblogged ? 'far fa-share-square pr-3 m-0 text-primary cursor-pointer' : 'far fa-share-square pr-3 m-0 share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
</div>
<div class="likes font-weight-bold" v-if="expLc(status) == true">
<span class="like-count">{{status.favourites_count}}</span> {{status.favourites_count == 1 ? 'like' : 'likes'}}
</div>
<div class="caption">
<p class="mb-2 read-more" style="overflow: hidden;">
<span class="username font-weight-bold">
<bdi><a class="text-dark" :href="status.account.url">{{status.account.username}}</a></bdi>
</span>
<span v-html="status.content"></span>
</p>
</div>
<div class="comments" v-if="status.id == replyId && !status.comments_disabled">
<p class="mb-0 d-flex justify-content-between align-items-top read-more" style="overflow-y: hidden;" v-for="(reply, index) in replies">
<span>
<a class="text-dark font-weight-bold mr-1" :href="reply.account.url">{{reply.account.username}}</a>
<span v-html="reply.content"></span>
</span>
<span class="mb-0" style="min-width:38px">
<span v-on:click="likeStatus(reply, $event)"><i v-bind:class="[reply.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']"></i></span>
<post-menu :status="reply" :profile="profile" size="sm" :modal="'true'" :feed="feed" class="d-inline-flex pl-2"></post-menu>
</span>
</p>
</div>
<div class="timestamp mt-2">
<p class="small text-uppercase mb-0">
<a :href="status.url" class="text-muted">
<timeago :datetime="status.created_at" :auto-update="60" :converter-options="{includeSeconds:true}" :title="timestampFormat(status.created_at)" v-b-tooltip.hover.bottom></timeago>
</a>
</p>
</div>
</div>
<div class="card-footer bg-white" v-if="status.id == replyId">
<form class="" v-on:submit.prevent="commentSubmit(status, $event)">
<input type="hidden" name="item" value="">
<input class="form-control status-reply-input" name="comment" placeholder="Add a comment…" autocomplete="off">
</form>
</div> </div>
</div> </div>
<div v-if="modes.infinite == true && !loading && feed.length > 0"> <div v-if="modes.infinite == true && !loading && feed.length > 0">
@ -220,10 +268,12 @@
<notification-card></notification-card> <notification-card></notification-card>
</div> </div>
<div v-show="suggestions.length && config.ab && config.ab.rec == true" class="mb-4"> <div v-show="showSuggestions == true && suggestions.length && config.ab && config.ab.rec == true" class="mb-4">
<div class="card"> <div class="card">
<div class="card-header bg-white text-center"> <div class="card-header bg-white d-flex align-items-center justify-content-between">
<div></div>
<div class="small text-dark text-uppercase font-weight-bold">Suggestions</div> <div class="small text-dark text-uppercase font-weight-bold">Suggestions</div>
<div class="small text-muted cursor-pointer" v-on:click="hideSuggestions"><i class="fas fa-times"></i></div>
</div> </div>
<div class="card-body pt-0"> <div class="card-body pt-0">
<div v-for="(rec, index) in suggestions" class="media align-items-center mt-3"> <div v-for="(rec, index) in suggestions" class="media align-items-center mt-3">
@ -355,6 +405,24 @@
.small .custom-control-label { .small .custom-control-label {
padding-top: 3px; padding-top: 3px;
} }
.reply-btn {
position: absolute;
bottom: 12px;
right: 20px;
width: 60px;
text-align: center;
border-radius: 0 3px 3px 0;
}
.emoji-reactions .nav-item {
font-size: 1.2rem;
padding: 9px;
cursor: pointer;
}
.emoji-reactions::-webkit-scrollbar {
width: 0px;
height: 0px;
background: transparent;
}
</style> </style>
<script type="text/javascript"> <script type="text/javascript">
@ -386,7 +454,11 @@
following: [], following: [],
followingCursor: 1, followingCursor: 1,
followingMore: true, followingMore: true,
lightboxMedia: false lightboxMedia: false,
showSuggestions: false,
showReadMore: true,
replyStatus: {},
replyText: '',
} }
}, },
@ -406,13 +478,27 @@
this.modes.dark = true; this.modes.dark = true;
} }
if(localStorage.getItem('pf_metro_ui.exp.rec') == 'false') {
this.showSuggestions = false;
} else {
this.showSuggestions = true;
}
if(localStorage.getItem('pf_metro_ui.exp.rm') == 'false') {
this.showReadMore = false;
} else {
this.showReadMore = true;
}
this.$nextTick(function () { this.$nextTick(function () {
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
}); });
}, },
updated() { updated() {
pixelfed.readmore(); if(this.showReadMore == true) {
pixelfed.readmore();
}
}, },
methods: { methods: {
@ -462,9 +548,7 @@
this.max_id = Math.min(...ids); this.max_id = Math.min(...ids);
$('.timeline .pagination').removeClass('d-none'); $('.timeline .pagination').removeClass('d-none');
this.loading = false; this.loading = false;
if(window.outerWidth > 767) { this.expRec();
this.expRec();
}
}).catch(err => { }).catch(err => {
}); });
}, },
@ -545,7 +629,10 @@
return; return;
} }
this.replies = {}; this.replies = {};
this.replyStatus = {};
this.replyText = '';
this.replyId = status.id; this.replyId = status.id;
this.replyStatus = status;
this.fetchStatusComments(status, ''); this.fetchStatusComments(status, '');
}, },
@ -677,16 +764,12 @@
commentSubmit(status, $event) { commentSubmit(status, $event) {
let id = status.id; let id = status.id;
let form = $event.target; let comment = this.replyText;
let input = $(form).find('input[name="comment"]');
let comment = input.val();
let comments = form.parentElement.parentElement.getElementsByClassName('comments')[0];
axios.post('/i/comment', { axios.post('/i/comment', {
item: id, item: id,
comment: comment comment: comment
}).then(res => { }).then(res => {
form.reset(); this.replyText = '';
form.blur();
this.replies.push(res.data.entity); this.replies.push(res.data.entity);
}); });
}, },
@ -1006,7 +1089,23 @@
ownerOrAdmin(status) { ownerOrAdmin(status) {
return this.owner(status) || this.admin(); return this.owner(status) || this.admin();
} },
hideSuggestions() {
localStorage.setItem('pf_metro_ui.exp.rec', false);
this.showSuggestions = false;
},
emojiReaction(status) {
let em = event.target.innerText;
if(this.replyText.length == 0) {
this.replyText = em + ' ';
$('textarea[name="comment"]').focus();
} else {
this.replyText += em + ' ';
$('textarea[name="comment"]').focus();
}
},
} }
} }
</script> </script>

View file

@ -24,3 +24,5 @@
@import '~plyr/dist/plyr.css'; @import '~plyr/dist/plyr.css';
@import '~vue-loading-overlay/dist/vue-loading.css'; @import '~vue-loading-overlay/dist/vue-loading.css';
@import "moment";

View file

@ -66,3 +66,5 @@ textarea {
@import '~plyr/dist/plyr.css'; @import '~plyr/dist/plyr.css';
@import '~vue-loading-overlay/dist/vue-loading.css'; @import '~vue-loading-overlay/dist/vue-loading.css';
@import "moment";

98
resources/assets/sass/moment.scss vendored Normal file
View file

@ -0,0 +1,98 @@
/*
red
*/
.bg-moment-passion {
background: #e53935;
background: -webkit-linear-gradient(to left, #e35d5b, #e53935);
background: linear-gradient(to left, #e35d5b, #e53935);
}
/*
teal/purple
*/
.bg-moment-azure {
background: #7F7FD5;
background: -webkit-linear-gradient(to left, #91EAE4, #86A8E7, #7F7FD5);
background: linear-gradient(to left, #91EAE4, #86A8E7, #7F7FD5);
}
/*
blue
*/
.bg-moment-reef {
background: #00d2ff;
background: -webkit-linear-gradient(to right, #3a7bd5, #00d2ff);
background: linear-gradient(to right, #3a7bd5, #00d2ff);
}
/*
lush green
*/
.bg-moment-lush {
background: #56ab2f;
background: -webkit-linear-gradient(to left, #a8e063, #56ab2f);
background: linear-gradient(to left, #a8e063, #56ab2f);
}
/*
neon green
*/
.bg-moment-neon {
background: #B3FFAB;
background: -webkit-linear-gradient(to right, #12FFF7, #B3FFAB);
background: linear-gradient(to right, #12FFF7, #B3FFAB);
}
/*
orange
*/
.bg-moment-flare {
background: #f12711;
background: -webkit-linear-gradient(to left, #f5af19, #f12711);
background: linear-gradient(to left, #f5af19, #f12711);
}
/*
orange/pink
*/
.bg-moment-morning {
background: #FF5F6D;
background: -webkit-linear-gradient(to left, #FFC371, #FF5F6D);
background: linear-gradient(to left, #FFC371, #FF5F6D);
}
/*
pink
*/
.bg-moment-tranquil {
background: #EECDA3;
background: -webkit-linear-gradient(to right, #EF629F, #EECDA3);
background: linear-gradient(to right, #EF629F, #EECDA3);
}
/*
purple
*/
.bg-moment-mauve {
background: #42275a;
background: -webkit-linear-gradient(to left, #734b6d, #42275a);
background: linear-gradient(to left, #734b6d, #42275a);
}
/*
purple
*/
.bg-moment-argon {
background: #03001e;
background: -webkit-linear-gradient(to left, #fdeff9, #ec38bc, #7303c0, #03001e);
background: linear-gradient(to left, #fdeff9, #ec38bc, #7303c0, #03001e);
}
/*
dark blue
*/
.bg-moment-royal {
background: #141E30;
background: -webkit-linear-gradient(to left, #243B55, #141E30);
background: linear-gradient(to left, #243B55, #141E30);
}

View file

@ -2,7 +2,8 @@
return [ return [
'likedPhoto' => 'liked your photo.', 'likedPhoto' => 'liked your post.',
'likedComment' => 'liked your comment.',
'startedFollowingYou' => 'started following you.', 'startedFollowingYou' => 'started following you.',
'commented' => 'commented on your post.', 'commented' => 'commented on your post.',
'mentionedYou' => 'mentioned you.', 'mentionedYou' => 'mentioned you.',

View file

@ -5,7 +5,7 @@
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-lg-5"> <div class="col-lg-5">
<div class="card"> <div class="card">
<div class="card-header">{{ __('Reset Password') }}</div> <div class="card-header bg-white p-3 text-center font-weight-bold">{{ __('Reset Password') }}</div>
<div class="card-body"> <div class="card-body">
<form method="POST" action="{{ route('password.request') }}"> <form method="POST" action="{{ route('password.request') }}">
@ -14,11 +14,8 @@
<input type="hidden" name="token" value="{{ $token }}"> <input type="hidden" name="token" value="{{ $token }}">
<div class="form-group row"> <div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label> <div class="col-md-12">
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ $email ?? old('email') }}" placeholder="{{ __('E-Mail Address') }}" required autofocus>
<div class="col-md-6">
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ $email ?? old('email') }}" required autofocus>
@if ($errors->has('email')) @if ($errors->has('email'))
<span class="invalid-feedback"> <span class="invalid-feedback">
<strong>{{ $errors->first('email') }}</strong> <strong>{{ $errors->first('email') }}</strong>
@ -26,12 +23,10 @@
@endif @endif
</div> </div>
</div> </div>
<hr>
<div class="form-group row"> <div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label> <div class="col-md-12">
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" placeholder="{{ __('Password') }}" required>
<div class="col-md-6">
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>
@if ($errors->has('password')) @if ($errors->has('password'))
<span class="invalid-feedback"> <span class="invalid-feedback">
@ -42,10 +37,8 @@
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label> <div class="col-md-12">
<input id="password-confirm" type="password" class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}" name="password_confirmation" placeholder="{{ __('Confirm Password') }}" required>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}" name="password_confirmation" required>
@if ($errors->has('password_confirmation')) @if ($errors->has('password_confirmation'))
<span class="invalid-feedback"> <span class="invalid-feedback">
@ -56,8 +49,8 @@
</div> </div>
<div class="form-group row mb-0"> <div class="form-group row mb-0">
<div class="col-md-6 offset-md-4"> <div class="col-md-12">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary btn-block py-0 font-weight-bold">
{{ __('Reset Password') }} {{ __('Reset Password') }}
</button> </button>
</div> </div>

View file

@ -31,6 +31,124 @@
</label> </label>
<p class="text-muted small help-text">MomentUI offers an alternative layout for posts and your profile.</p> <p class="text-muted small help-text">MomentUI offers an alternative layout for posts and your profile.</p>
</div> </div>
@if($profile->profile_layout == 'moment')
<div class="form-check pb-3">
<label class="form-check-label font-weight-bold mb-3" for="profile_layout">
{{__('MomentUI Profile Header Color')}}
</label>
<div class="row">
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-pixelfed rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Default</p>
<input class="form-check-input mx-0 pl-0" type="radio" name="moment_bg" value="default" {{$profile->header_bg == 'default' || !$profile->header_bg ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-azure rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Azure</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="azure" {{$profile->header_bg == 'azure' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-passion rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Passion</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="passion" {{$profile->header_bg == 'passion' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-reef rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Reef</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="reef" {{$profile->header_bg == 'reef' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-lush rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Lush</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="lush" {{$profile->header_bg == 'lush' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-neon rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Neon</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="neon" {{$profile->header_bg == 'neon' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-flare rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Flare</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="flare" {{$profile->header_bg == 'flare' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-morning rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Morning</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="morning" {{$profile->header_bg == 'morning' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-tranquil rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Tranquil</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="tranquil" {{$profile->header_bg == 'tranquil' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-mauve rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Mauve</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="mauve" {{$profile->header_bg == 'mauve' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-argon rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Argon</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="argon" {{$profile->header_bg == 'argon' ? 'checked':''}}>
</div>
</div>
<div class="col-6 col-sm-3 pb-5">
<div class="">
<p class="form-check-label">
<div class="bg-moment-royal rounded-circle box-shadow" style="width:60px; height:60px"></div>
</p>
<p class="mb-0 small text-muted">Royal</p>
<input class="form-check-input mx-0" type="radio" name="moment_bg" value="royal" {{$profile->header_bg == 'royal' ? 'checked':''}}>
</div>
</div>
</div>
<p class="text-muted small help-text">Set your MomentUI profile background color. Adding a custom header image will be supported in a future version.</p>
</div>
@endif
<div class="form-check pb-3"> <div class="form-check pb-3">
<input class="form-check-input" type="checkbox" name="dark_mode" id="dark_mode" {{request()->hasCookie('dark-mode') ? 'checked':''}}> <input class="form-check-input" type="checkbox" name="dark_mode" id="dark_mode" {{request()->hasCookie('dark-mode') ? 'checked':''}}>
<label class="form-check-label font-weight-bold" for="dark_mode"> <label class="form-check-label font-weight-bold" for="dark_mode">
@ -38,6 +156,22 @@
</label> </label>
<p class="text-muted small help-text">Use dark mode theme.</p> <p class="text-muted small help-text">Use dark mode theme.</p>
</div> </div>
@if(config('exp.rec') == true)
<div class="form-check pb-3">
<input class="form-check-input" type="checkbox" name="show_suggestions" id="show_suggestions">
<label class="form-check-label font-weight-bold" for="show_suggestions">
{{__('Profile Suggestions')}}
</label>
<p class="text-muted small help-text">Show Profile Suggestions.</p>
</div>
@endif
<div class="form-check pb-3">
<input class="form-check-input" type="checkbox" name="show_readmore" id="show_readmore">
<label class="form-check-label font-weight-bold" for="show_readmore">
{{__('Use Read More')}}
</label>
<p class="text-muted small help-text">Collapses captions/comments more than 3 lines.</p>
</div>
<div class="py-3"> <div class="py-3">
<p class="font-weight-bold text-muted text-center">Discovery</p> <p class="font-weight-bold text-muted text-center">Discovery</p>
<hr> <hr>
@ -59,3 +193,36 @@
</div> </div>
</form> </form>
@endsection @endsection
@push('scripts')
<script type="text/javascript">
$(document).ready(function() {
let showSuggestions = localStorage.getItem('pf_metro_ui.exp.rec') == 'false' ? false : true;
let showReadMore = localStorage.getItem('pf_metro_ui.exp.rm') == 'false' ? false : true;
if(showSuggestions == true) {
$('#show_suggestions').attr('checked', true);
}
if(showReadMore == true) {
$('#show_readmore').attr('checked', true);
}
$('#show_suggestions').on('change', function(e) {
if(e.target.checked) {
localStorage.removeItem('pf_metro_ui.exp.rec');
} else {
localStorage.setItem('pf_metro_ui.exp.rec', false);
}
});
$('#show_readmore').on('change', function(e) {
if(e.target.checked) {
localStorage.removeItem('pf_metro_ui.exp.rm');
} else {
localStorage.setItem('pf_metro_ui.exp.rm', false);
}
});
});
</script>
@endpush