1
0
Fork 0

Merge pull request #1500 from pixelfed/frontend-ui-refactor

Add Profile Sponsors
This commit is contained in:
daniel 2019-07-11 21:15:58 -06:00 committed by GitHub
commit d2d7f07c35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1945 additions and 1422 deletions

View File

@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\ProfileSponsor;
use Auth;
class ProfileSponsorController extends Controller
{
public function get(Request $request, $id)
{
$res = ProfileSponsor::whereProfileId($id)->firstOrFail()->sponsors;
return response($res)->header('Content-Type', 'application/json');
}
}

View File

@ -4,11 +4,13 @@ namespace App\Http\Controllers;
use App\AccountLog;
use App\Following;
use App\ProfileSponsor;
use App\Report;
use App\UserFilter;
use Auth, Cookie, DB, Cache, Purify;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Http\Controllers\Settings\{
ExportSettings,
LabsSettings,
@ -166,5 +168,49 @@ class SettingsController extends Controller
return response()->json([200])->cookie($cookie);
}
public function sponsor()
{
$default = [
'patreon' => null,
'liberapay' => null,
'opencollective' => null
];
$sponsors = ProfileSponsor::whereProfileId(Auth::user()->profile->id)->first();
$sponsors = $sponsors ? json_decode($sponsors->sponsors, true) : $default;
return view('settings.sponsor', compact('sponsors'));
}
public function sponsorStore(Request $request)
{
$this->validate($request, [
'patreon' => 'nullable|string',
'liberapay' => 'nullable|string',
'opencollective' => 'nullable|string'
]);
$patreon = Str::startsWith($request->input('patreon'), 'patreon.com/') ? e($request->input('patreon')) : null;
$liberapay = Str::startsWith($request->input('liberapay'), 'liberapay.com/') ? e($request->input('liberapay')) : null;
$opencollective = Str::startsWith($request->input('opencollective'), 'opencollective.com/') ? e($request->input('opencollective')) : null;
if(empty($patreon) && empty($liberapay) && empty($opencollective)) {
return redirect(route('settings'))->with('error', 'An error occured. Please try again later.');;
}
$res = [
'patreon' => $patreon,
'liberapay' => $liberapay,
'opencollective' => $opencollective
];
$sponsors = ProfileSponsor::firstOrCreate([
'profile_id' => Auth::user()->profile_id ?? Auth::user()->profile->id
]);
$sponsors->sponsors = json_encode($res);
$sponsors->save();
$sponsors = $res;
return redirect(route('settings'))->with('status', 'Sponsor settings successfully updated!');;
}
}

15
app/ProfileSponsor.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ProfileSponsor extends Model
{
public $fillable = ['profile_id'];
public function profile()
{
return $this->belongsTo(Profile::class);
}
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProfileSponsorsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('profile_sponsors', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('profile_id')->unsigned()->unique()->index();
$table->json('sponsors')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('profile_sponsors');
}
}

1069
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,26 +15,26 @@
"bootstrap": ">=4.3.1",
"cross-env": "^5.2.0",
"jquery": "^3.4.1",
"lodash": "^4.17.11",
"lodash": ">=4.17.13",
"popper.js": "^1.15.0",
"resolve-url-loader": "^2.3.2",
"sass": "^1.21.0",
"sass": "^1.22.3",
"sass-loader": "^7.1.0",
"vue": "^2.6.10",
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"bootstrap-vue": "^2.0.0-rc.23",
"bootstrap-vue": "^2.0.0-rc.26",
"emoji-mart-vue": "^2.6.6",
"filesize": "^3.6.1",
"howler": "^2.1.2",
"infinite-scroll": "^3.0.6",
"laravel-echo": "^1.5.4",
"laravel-mix": "^4.0.16",
"laravel-mix": "^4.1.2",
"node-sass": "^4.12.0",
"opencollective": "^1.0.3",
"opencollective-postinstall": "^2.0.2",
"plyr": "^3.5.4",
"plyr": "^3.5.6",
"promise-polyfill": "8.1.0",
"pusher-js": "^4.4.0",
"quill": "^1.3.6",

4
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

2
public/js/ace.js vendored

File diff suppressed because one or more lines are too long

1
public/js/collectioncompose.js vendored Normal file

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

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/loops.js 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

2
public/js/quill.js vendored

File diff suppressed because one or more lines are too long

2
public/js/search.js vendored

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

View File

@ -1 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{14:function(e,a,o){e.exports=o("YMO/")},"YMO/":function(e,a,o){(function(e){function o(e){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}ace.define("ace/theme/monokai",["require","exports","module","ace/lib/dom"],function(e,a,o){a.isDark=!0,a.cssClass="ace-monokai",a.cssText=".ace-monokai .ace_gutter {background: #2F3129;color: #8F908A}.ace-monokai .ace_print-margin {width: 1px;background: #555651}.ace-monokai {background-color: #272822;color: #F8F8F2}.ace-monokai .ace_cursor {color: #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection {background: #49483E}.ace-monokai.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #272822;}.ace-monokai .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active-line {background: #202020}.ace-monokai .ace_gutter-active-line {background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected-word {border: 1px solid #49483E}.ace-monokai .ace_invisible {color: #52524d}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta.ace_tag,.ace-monokai .ace_storage {color: #F92672}.ace-monokai .ace_punctuation,.ace-monokai .ace_punctuation.ace_tag {color: #fff}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other {color: #AE81FF}.ace-monokai .ace_invalid {color: #F8F8F0;background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function {color: #66D9EF}.ace-monokai .ace_fold {background-color: #A6E22E;border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type {font-style: italic;color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable {color: #A6E22E}.ace-monokai .ace_variable.ace_parameter {font-style: italic;color: #FD971F}.ace-monokai .ace_string {color: #E6DB74}.ace-monokai .ace_comment {color: #75715E}.ace-monokai .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y}",e("../lib/dom").importCssString(a.cssText,a.cssClass)}),ace.require(["ace/theme/monokai"],function(c){"object"==o(e)&&"object"==o(a)&&e&&(e.exports=c)})}).call(this,o("YuTi")(e))},YuTi:function(e,a){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}}},[[14,0]]]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{14:function(e,a,o){e.exports=o("YMO/")},"YMO/":function(e,a,o){(function(e){function o(e){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}ace.define("ace/theme/monokai",["require","exports","module","ace/lib/dom"],function(e,a,o){a.isDark=!0,a.cssClass="ace-monokai",a.cssText=".ace-monokai .ace_gutter {background: #2F3129;color: #8F908A}.ace-monokai .ace_print-margin {width: 1px;background: #555651}.ace-monokai {background-color: #272822;color: #F8F8F2}.ace-monokai .ace_cursor {color: #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection {background: #49483E}.ace-monokai.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #272822;}.ace-monokai .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active-line {background: #202020}.ace-monokai .ace_gutter-active-line {background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected-word {border: 1px solid #49483E}.ace-monokai .ace_invisible {color: #52524d}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta.ace_tag,.ace-monokai .ace_storage {color: #F92672}.ace-monokai .ace_punctuation,.ace-monokai .ace_punctuation.ace_tag {color: #fff}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other {color: #AE81FF}.ace-monokai .ace_invalid {color: #F8F8F0;background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function {color: #66D9EF}.ace-monokai .ace_fold {background-color: #A6E22E;border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type {font-style: italic;color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable {color: #A6E22E}.ace-monokai .ace_variable.ace_parameter {font-style: italic;color: #FD971F}.ace-monokai .ace_string {color: #E6DB74}.ace-monokai .ace_comment {color: #75715E}.ace-monokai .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y}",e("../lib/dom").importCssString(a.cssText,a.cssClass)}),ace.require(["ace/theme/monokai"],function(c){"object"==o(e)&&"object"==o(a)&&e&&(e.exports=c)})}).call(this,o("YuTi")(e))},YuTi:function(e,a){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}}},[[14,0]]]);

File diff suppressed because one or more lines are too long

2
public/js/vendor.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,24 +1,25 @@
{
"/js/manifest.js": "/js/manifest.js?id=01c8731923a46c30aaed",
"/js/vendor.js": "/js/vendor.js?id=8ea306403cb5cfa88c2b",
"/js/ace.js": "/js/ace.js?id=72ae94b2a68487d22caf",
"/js/vendor.js": "/js/vendor.js?id=6e7489157aac9e82dbbe",
"/js/ace.js": "/js/ace.js?id=4a28163d5fd63e64d6af",
"/js/activity.js": "/js/activity.js?id=7405cc1a22814a5b2a70",
"/js/app.js": "/js/app.js?id=2f034c84c06dbb3e511d",
"/css/app.css": "/css/app.css?id=461b8782fc167f734ffa",
"/css/appdark.css": "/css/appdark.css?id=34cd81dd9c8bc68cfd51",
"/css/landing.css": "/css/landing.css?id=1ea686af4c64df5018fc",
"/css/app.css": "/css/app.css?id=56642158bfe8b6469355",
"/css/appdark.css": "/css/appdark.css?id=1b13fc163fa4deb9233f",
"/css/landing.css": "/css/landing.css?id=31de3e75de8690f7ece5",
"/css/quill.css": "/css/quill.css?id=81604d62610b0dbffad6",
"/js/components.js": "/js/components.js?id=0b7b6f606e590f4df10f",
"/js/compose.js": "/js/compose.js?id=aca2cd178a7ca454713d",
"/js/developers.js": "/js/developers.js?id=e4a227c87d1b09fc2dd9",
"/js/discover.js": "/js/discover.js?id=772fbc6c176aaa9039ec",
"/js/hashtag.js": "/js/hashtag.js?id=32c3a6b1a04949d390ab",
"/js/loops.js": "/js/loops.js?id=cacf532da1e0d50ec014",
"/js/mode-dot.js": "/js/mode-dot.js?id=7d248d684a37f3eb88de",
"/js/profile.js": "/js/profile.js?id=8b6af927d424cb58203e",
"/js/quill.js": "/js/quill.js?id=a8a0855cb59d6a2f7aee",
"/js/search.js": "/js/search.js?id=27506b08cf8c889e3f7f",
"/js/status.js": "/js/status.js?id=665fb54127ca484a1692",
"/js/theme-monokai.js": "/js/theme-monokai.js?id=1bc564c4661eb0fa30b6",
"/js/timeline.js": "/js/timeline.js?id=90a01cbe86e6dff2b5c3"
"/js/collectioncompose.js": "/js/collectioncompose.js?id=ec48ebc94ae6b1ec70ea",
"/js/components.js": "/js/components.js?id=d64d41a2defb1a205865",
"/js/compose.js": "/js/compose.js?id=488b24bf2f2168540449",
"/js/developers.js": "/js/developers.js?id=ba029a560f0c30c5efc9",
"/js/discover.js": "/js/discover.js?id=627f0a106fd359ae3b80",
"/js/hashtag.js": "/js/hashtag.js?id=0f7e529e8128cc17638b",
"/js/loops.js": "/js/loops.js?id=19112dc8663fc43db735",
"/js/mode-dot.js": "/js/mode-dot.js?id=c7c83849e6bba99f1c33",
"/js/profile.js": "/js/profile.js?id=273e21d1f85a097b18e4",
"/js/quill.js": "/js/quill.js?id=c2b060eaf87ef63eb5c1",
"/js/search.js": "/js/search.js?id=3186ccb02c7fad43c701",
"/js/status.js": "/js/status.js?id=4b9a52b586880e264f05",
"/js/theme-monokai.js": "/js/theme-monokai.js?id=a4da64fc6e2f406a616d",
"/js/timeline.js": "/js/timeline.js?id=a3c3e38470108fa5df42"
}

View File

@ -19,7 +19,12 @@
<div class="d-block d-md-none">
<div class="row">
<div class="col-5">
<img class="rounded-circle box-shadow mr-5" :src="profile.avatar" width="77px" height="77px">
<img class="rounded-circle box-shadow mr-2" :src="profile.avatar" width="77px" height="77px">
<p v-if="sponsorList.patreon || sponsorList.liberapay || sponsorList.opencollective" class="text-center mt-1 mr-2">
<button type="button" @click="showSponsorModal" class="btn btn-sm btn-outline-secondary font-weight-bold py-0">
Sponsor
</button>
</p>
</div>
<div class="col-7 pl-2">
<p class="align-middle">
@ -45,6 +50,12 @@
</div>
<div class="d-none d-md-block">
<img class="rounded-circle box-shadow" :src="profile.avatar" width="172px" height="172px">
<p v-if="sponsorList.patreon || sponsorList.liberapay || sponsorList.opencollective" class="text-center mt-3">
<button type="button" @click="showSponsorModal" class="btn btn-outline-secondary font-weight-bold py-0">
<i class="fas fa-heart text-danger"></i>
Sponsor
</button>
</p>
</div>
</div>
</div>
@ -97,7 +108,7 @@
<span class="font-weight-bold pr-3">{{profile.display_name}}</span>
</p>
<div v-if="profile.note" class="mb-0 lead" v-html="profile.note"></div>
<p v-if="profile.website" class="mb-0"><a :href="profile.website" class="font-weight-bold" rel="me external nofollow noopener" target="_blank">{{profile.website}}</a></p>
<p v-if="profile.website" class=""><a :href="profile.website" class="font-weight-bold" rel="me external nofollow noopener" target="_blank">{{profile.website}}</a></p>
</div>
</div>
</div>
@ -475,6 +486,26 @@
</div>
</div>
</b-modal>
<b-modal ref="sponsorModal"
id="sponsor-modal"
hide-footer
:title="'Sponsor ' + profileUsername"
centered
size="md"
body-class="px-5">
<div>
<p class="font-weight-bold">External Links</p>
<p v-if="sponsorList.patreon" class="pt-2">
<a :href="'https://' + sponsorList.patreon" rel="nofollow" class="font-weight-bold">{{sponsorList.patreon}}</a>
</p>
<p v-if="sponsorList.liberapay" class="pt-2">
<a :href="'https://' + sponsorList.liberapay" rel="nofollow" class="font-weight-bold">{{sponsorList.liberapay}}</a>
</p>
<p v-if="sponsorList.opencollective" class="pt-2">
<a :href="'https://' + sponsorList.opencollective" rel="nofollow" class="font-weight-bold">{{sponsorList.opencollective}}</a>
</p>
</div>
</b-modal>
</div>
</template>
<!-- <style type="text/css" scoped="">
@ -536,7 +567,8 @@ export default {
following: [],
followingCursor: 1,
followingMore: true,
warning: false
warning: false,
sponsorList: [],
}
},
beforeMount() {
@ -588,6 +620,7 @@ export default {
this.timeline = data;
this.ownerCheck();
this.loading = false;
this.loadSponsor();
}).catch(err => {
swal(
'Oops, something went wrong',
@ -1085,6 +1118,17 @@ export default {
c += 'bg-pixelfed';
}
return c;
},
loadSponsor() {
axios.get('/api/local/profile/sponsor/' + this.profileId)
.then(res => {
this.sponsorList = res.data;
});
},
showSponsorModal() {
this.$refs.sponsorModal.show();
}
}
}

View File

@ -33,6 +33,9 @@
<li class="nav-item pl-3 {{request()->is('settings/security*')?'active':''}}">
<a class="nav-link font-weight-light text-muted" href="{{route('settings.security')}}">Security</a>
</li>
<li class="nav-item pl-3 {{request()->is('settings/sponsor*')?'active':''}}">
<a class="nav-link font-weight-light text-muted" href="{{route('settings.sponsor')}}">Sponsor</a>
</li>
<li class="nav-item">
<hr>
</li>

View File

@ -0,0 +1,48 @@
@extends('settings.template')
@section('section')
<div class="title">
<h3 class="font-weight-bold">Sponsor</h3>
<p class="lead">Add crowdfunding links to your profile.</p>
</div>
<hr>
<form method="post" action="{{route('settings.sponsor')}}">
@csrf
<div class="form-group row">
<label for="patreon" class="col-sm-3 col-form-label font-weight-bold text-right">Patreon</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="patreon" name="patreon" placeholder="patreon.com/dansup" value="{{$sponsors['patreon']}}">
<p class="help-text small text-muted font-weight-bold">
Example: patreon.com/dansup
</p>
</div>
</div>
<div class="form-group row">
<label for="liberapay" class="col-sm-3 col-form-label font-weight-bold text-right">Liberapay</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="liberapay" name="liberapay" placeholder="liberapay.com/pixelfed" value="{{$sponsors['liberapay']}}">
<p class="help-text small text-muted font-weight-bold">
Example: liberapay.com/pixelfed
</p>
</div>
</div>
<div class="form-group row">
<label for="opencollective" class="col-sm-3 col-form-label font-weight-bold text-right">OpenCollective</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="opencollective" name="opencollective" placeholder="opencollective.com/pixelfed" value="{{$sponsors['opencollective']}}">
<p class="help-text small text-muted font-weight-bold">
Example: opencollective.com/pixelfed
</p>
</div>
</div>
<hr>
<div class="form-group row">
<div class="col-12 text-right">
<button type="submit" class="btn btn-primary font-weight-bold float-right">Submit</button>
</div>
</div>
</form>
@endsection

View File

@ -114,6 +114,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('exp/rec', 'ApiController@userRecommendations');
Route::post('discover/tag/subscribe', 'HashtagFollowController@store')->middleware('throttle:maxHashtagFollowsPerHour,60')->middleware('throttle:maxHashtagFollowsPerDay,1440');;
Route::get('discover/tag/list', 'HashtagFollowController@getTags');
Route::get('profile/sponsor/{id}', 'ProfileSponsorController@get');
});
});
@ -261,6 +262,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('invites/create', 'UserInviteController@create')->name('settings.invites.create');
Route::post('invites/create', 'UserInviteController@store');
Route::get('invites', 'UserInviteController@show')->name('settings.invites');
Route::get('sponsor', 'SettingsController@sponsor')->name('settings.sponsor');
Route::post('sponsor', 'SettingsController@sponsorStore');
});
Route::group(['prefix' => 'site'], function () {