Add l-lacker social-styled page backrops (#805)

чокопай
This commit is contained in:
celestora 2022-12-12 01:23:42 +02:00 committed by GitHub
parent 8700ad8179
commit f9083edfc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 327 additions and 7 deletions

View file

@ -360,5 +360,6 @@ class Club extends RowModel
return $this->getRecord()->alert; return $this->getRecord()->alert;
} }
use Traits\TBackDrops;
use Traits\TSubscribable; use Traits\TSubscribable;
} }

View file

@ -0,0 +1,44 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities\Traits;
use openvk\Web\Models\Entities\Photo;
use openvk\Web\Models\Repositories\Photos;
trait TBackDrops {
function getBackDropPictureURLs(): ?array
{
$photo1 = $this->getRecord()->backdrop_1;
$photo2 = $this->getRecord()->backdrop_2;
if(is_null($photo1) && is_null($photo2))
return NULL;
$photo1obj = $photo2obj = NULL;
if(!is_null($photo1))
$photo1obj = (new Photos)->get($photo1);
if(!is_null($photo2))
$photo2obj = (new Photos)->get($photo2);
if(is_null($photo1obj) && is_null($photo2obj))
return NULL;
return [
is_null($photo1obj) ? "" : $photo1obj->getURL(),
is_null($photo2obj) ? "" : $photo2obj->getURL(),
];
}
function setBackDropPictures(?Photo $first, ?Photo $second): void
{
if(!is_null($first))
$this->stateChanges("backdrop_1", $first->getId());
if(!is_null($second))
$this->stateChanges("backdrop_2", $second->getId());
}
function unsetBackDropPictures(): void
{
$this->stateChanges("backdrop_1", NULL);
$this->stateChanges("backdrop_2", NULL);
}
}

View file

@ -5,7 +5,7 @@ use openvk\Web\Themes\{Themepack, Themepacks};
use openvk\Web\Util\DateTime; use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel; use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift}; use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Gifts, Notifications}; use openvk\Web\Models\Repositories\{Photos, Users, Clubs, Albums, Gifts, Notifications};
use openvk\Web\Models\Exceptions\InvalidUserNameException; use openvk\Web\Models\Exceptions\InvalidUserNameException;
use Nette\Database\Table\ActiveRow; use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection; use Chandler\Database\DatabaseConnection;
@ -1044,5 +1044,6 @@ class User extends RowModel
return true; return true;
} }
use Traits\TBackDrops;
use Traits\TSubscribable; use Traits\TSubscribable;
} }

View file

@ -1,6 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{Club, Photo}; use openvk\Web\Models\Entities\{Club, Photo};
use Nette\InvalidStateException;
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification; use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics}; use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics};
use Chandler\Security\Authenticator; use Chandler\Security\Authenticator;
@ -191,7 +192,7 @@ final class GroupPresenter extends OpenVKPresenter
$this->willExecuteWriteAction(); $this->willExecuteWriteAction();
$club = $this->clubs->get($id); $club = $this->clubs->get($id);
if(!$club->canBeModifiedBy($this->user->identity)) if(!$club || !$club->canBeModifiedBy($this->user->identity))
$this->notFound(); $this->notFound();
else else
$this->template->club = $club; $this->template->club = $club;
@ -250,6 +251,45 @@ final class GroupPresenter extends OpenVKPresenter
} }
} }
function renderEditBackdrop(int $id): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$club = $this->clubs->get($id);
if(!$club || !$club->canBeModifiedBy($this->user->identity))
$this->notFound();
else
$this->template->club = $club;
if($_SERVER["REQUEST_METHOD"] !== "POST")
return;
if($this->postParam("subact") === "remove") {
$club->unsetBackDropPictures();
$club->save();
$this->flashFail("succ", tr("backdrop_succ_rem"), tr("backdrop_succ_desc")); # will exit
}
$pic1 = $pic2 = NULL;
try {
if($_FILES["backdrop1"]["error"] !== UPLOAD_ERR_NO_FILE)
$pic1 = Photo::fastMake($this->user->id, "Profile backdrop (system)", $_FILES["backdrop1"]);
if($_FILES["backdrop2"]["error"] !== UPLOAD_ERR_NO_FILE)
$pic2 = Photo::fastMake($this->user->id, "Profile backdrop (system)", $_FILES["backdrop2"]);
} catch(InvalidStateException $e) {
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
}
if($pic1 == $pic2 && is_null($pic1))
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
$club->setBackDropPictures($pic1, $pic2);
$club->save();
$this->flashFail("succ", tr("backdrop_succ"), tr("backdrop_succ_desc"));
}
function renderStatistics(int $id): void function renderStatistics(int $id): void
{ {
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use Nette\InvalidStateException;
use openvk\Web\Util\Sms; use openvk\Web\Util\Sms;
use openvk\Web\Themes\Themepacks; use openvk\Web\Themes\Themepacks;
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification}; use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
@ -208,6 +209,30 @@ final class UserPresenter extends OpenVKPresenter
$user->setFav_Books(empty($this->postParam("fav_books")) ? NULL : ovk_proc_strtr($this->postParam("fav_books"), 300)); $user->setFav_Books(empty($this->postParam("fav_books")) ? NULL : ovk_proc_strtr($this->postParam("fav_books"), 300));
$user->setFav_Quote(empty($this->postParam("fav_quote")) ? NULL : ovk_proc_strtr($this->postParam("fav_quote"), 300)); $user->setFav_Quote(empty($this->postParam("fav_quote")) ? NULL : ovk_proc_strtr($this->postParam("fav_quote"), 300));
$user->setAbout(empty($this->postParam("about")) ? NULL : ovk_proc_strtr($this->postParam("about"), 300)); $user->setAbout(empty($this->postParam("about")) ? NULL : ovk_proc_strtr($this->postParam("about"), 300));
} elseif($_GET["act"] === "backdrop") {
if($this->postParam("subact") === "remove") {
$user->unsetBackDropPictures();
$user->save();
$this->flashFail("succ", tr("backdrop_succ_rem"), tr("backdrop_succ_desc")); # will exit
}
$pic1 = $pic2 = NULL;
try {
if($_FILES["backdrop1"]["error"] !== UPLOAD_ERR_NO_FILE)
$pic1 = Photo::fastMake($user->getId(), "Profile backdrop (system)", $_FILES["backdrop1"]);
if($_FILES["backdrop2"]["error"] !== UPLOAD_ERR_NO_FILE)
$pic2 = Photo::fastMake($user->getId(), "Profile backdrop (system)", $_FILES["backdrop2"]);
} catch(InvalidStateException $e) {
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
}
if($pic1 == $pic2 && is_null($pic1))
$this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
$user->setBackDropPictures($pic1, $pic2);
$user->save();
$this->flashFail("succ", tr("backdrop_succ"), tr("backdrop_succ_desc"));
} elseif($_GET['act'] === "status") { } elseif($_GET['act'] === "status") {
if(mb_strlen($this->postParam("status")) > 255) { if(mb_strlen($this->postParam("status")) > 255) {
$statusLength = (string) mb_strlen($this->postParam("status")); $statusLength = (string) mb_strlen($this->postParam("status"));
@ -235,7 +260,7 @@ final class UserPresenter extends OpenVKPresenter
} }
$this->template->mode = in_array($this->queryParam("act"), [ $this->template->mode = in_array($this->queryParam("act"), [
"main", "contacts", "interests", "avatar" "main", "contacts", "interests", "avatar", "backdrop"
]) ? $this->queryParam("act") ]) ? $this->queryParam("act")
: "main"; : "main";

View file

@ -49,6 +49,12 @@
<div class="notifications_global_wrap"></div> <div class="notifications_global_wrap"></div>
<div class="dimmer"></div> <div class="dimmer"></div>
{if isset($backdrops) && !is_null($backdrops)}
<div id="backdrop" style="background-image: url('{$backdrops[0]|noescape}'), url('{$backdrops[1]|noescape}');">
<div id="backdropDripper"></div>
</div>
{/if}
<div class="toTop"> <div class="toTop">
⬆ {_to_top} ⬆ {_to_top}
</div> </div>

View file

@ -12,6 +12,11 @@
{_main} {_main}
</a> </a>
</div> </div>
<div class="tab">
<a href="/club{$club->getId()}/backdrop">
{_backdrop_short}
</a>
</div>
<div class="tab"> <div class="tab">
<a href="/club{$club->getId()}/followers"> <a href="/club{$club->getId()}/followers">
{_followers} {_followers}

View file

@ -0,0 +1,63 @@
{extends "../@layout.xml"}
{var $backdrops = $club->getBackDropPictureURLs()}
{block title}{$club->getName()} | {_backdrop}{/block}
{block header}
<a href="{$club->getURL()}">{$club->getName()}</a> » {_backdrop}
{/block}
{block content}
<div class="tabs">
<div class="tab">
<a href="/club{$club->getId()}/edit">
{_main}
</a>
</div>
<div id="activetabs" class="tab">
<a id="act_tab_a" href="/club{$club->getId()}/backdrop">
{_backdrop_short}
</a>
</div>
<div class="tab">
<a href="/club{$club->getId()}/followers">
{_followers}
</a>
</div>
<div class="tab">
<a href="javascript:void(0)">
{_statistics}
</a>
</div>
</div>
<div class="container_gray">
<h4>{_backdrop}</h4>
<p>{_backdrop_desc}</p>
<form method="POST" enctype="multipart/form-data">
<div id="backdropEditor">
<div id="backdropFilePicker">
<input type="file" accept="image/*" name="backdrop1" />
<div id="spacer"></div>
<input type="file" accept="image/*" name="backdrop2" />
</div>
</div>
<p>
<span class="nobold">{_backdrop_warn}</span>
</p>
<p>
<span class="nobold">{_backdrop_about_adding}</span>
</p>
<p><br/></p>
<input type="hidden" name="hash" value="{$csrfToken}" />
<div>
<center>
<button name="subact" value="save" class="button">{_backdrop_save}</button>
<button name="subact" value="remove" class="button">{_backdrop_remove}</button>
</center>
</div>
</form>
</div>
{/block}

View file

@ -23,6 +23,11 @@
{_main} {_main}
</a> </a>
</div> </div>
<div class="tab">
<a href="/club{$club->getId()}/backdrop">
{_backdrop_short}
</a>
</div>
<div id="activetabs" class="tab"> <div id="activetabs" class="tab">
<a id="act_tab_a" href="/club{$club->getId()}/followers"> <a id="act_tab_a" href="/club{$club->getId()}/followers">
{_followers} {_followers}

View file

@ -12,6 +12,11 @@
{_main} {_main}
</a> </a>
</div> </div>
<div class="tab">
<a href="/club{$club->getId()}/backdrop">
{_backdrop_short}
</a>
</div>
<div class="tab"> <div class="tab">
<a href="/club{$club->getId()}/followers"> <a href="/club{$club->getId()}/followers">
{_followers} {_followers}

View file

@ -1,4 +1,5 @@
{extends "../@layout.xml"} {extends "../@layout.xml"}
{var $backdrops = $club->getBackDropPictureURLs()}
{block title}{$club->getName()}{/block} {block title}{$club->getName()}{/block}

View file

@ -1,4 +1,8 @@
{extends "../@layout.xml"} {extends "../@layout.xml"}
{if $mode === 'backdrop'}
{var $backdrops = $user->getBackDropPictureURLs()}
{/if}
{block title}{_edit_page}{/block} {block title}{_edit_page}{/block}
{block header} {block header}
@ -6,11 +10,12 @@
{/block} {/block}
{block content} {block content}
{var $isMain = $mode === 'main'} {var $isMain = $mode === 'main'}
{var $isContacts = $mode === 'contacts'} {var $isContacts = $mode === 'contacts'}
{var $isInterests = $mode === 'interests'} {var $isInterests = $mode === 'interests'}
{var $isAvatar = $mode === 'avatar'} {var $isAvatar = $mode === 'avatar'}
{var $isBackDrop = $mode === 'backdrop'}
<div n:if="$user->hasPendingNumberChange()" class="msg"> <div n:if="$user->hasPendingNumberChange()" class="msg">
<b>Подтверждение номера телефона</b><br/> <b>Подтверждение номера телефона</b><br/>
Введите код для подтверждения смены номера: <a href="/edit/verify_phone">ввести код</a>. Введите код для подтверждения смены номера: <a href="/edit/verify_phone">ввести код</a>.
@ -29,6 +34,9 @@
<div n:attr="id => ($isAvatar ? 'activetabs' : 'ki')" class="tab"> <div n:attr="id => ($isAvatar ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($isAvatar ? 'act_tab_a' : 'ki')" href="/edit?act=avatar">{_avatar}</a> <a n:attr="id => ($isAvatar ? 'act_tab_a' : 'ki')" href="/edit?act=avatar">{_avatar}</a>
</div> </div>
<div n:attr="id => ($isBackDrop ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($isBackDrop ? 'act_tab_a' : 'ki')" href="/edit?act=backdrop">{_backdrop_short}</a>
</div>
</div> </div>
<div class="container_gray"> <div class="container_gray">
@ -326,6 +334,36 @@
</table> </table>
</form> </form>
{elseif $isBackDrop}
<h4>{_backdrop}</h4>
<p>{_backdrop_desc}</p>
<form method="POST" enctype="multipart/form-data">
<div id="backdropEditor">
<div id="backdropFilePicker">
<input type="file" accept="image/*" name="backdrop1" />
<div id="spacer"></div>
<input type="file" accept="image/*" name="backdrop2" />
</div>
</div>
<p>
<span class="nobold">{_backdrop_warn}</span>
</p>
<p>
<span class="nobold">{_backdrop_about_adding}</span>
</p>
<p><br/></p>
<input type="hidden" name="hash" value="{$csrfToken}" />
<div>
<center>
<button name="subact" value="save" class="button">{_backdrop_save}</button>
<button name="subact" value="remove" class="button">{_backdrop_remove}</button>
</center>
</div>
</form>
{/if} {/if}
</div> </div>

View file

@ -1,5 +1,9 @@
{extends "../@layout.xml"} {extends "../@layout.xml"}
{if !$user->isBanned()}
{var $backdrops = $user->getBackDropPictureURLs()}
{/if}
{block title}{$user->getCanonicalName()}{/block} {block title}{$user->getCanonicalName()}{/block}
{block headIncludes} {block headIncludes}

View file

@ -187,6 +187,8 @@ routes:
club: "club|public|event" club: "club|public|event"
- url: "/club{num}/edit" - url: "/club{num}/edit"
handler: "Group->edit" handler: "Group->edit"
- url: "/club{num}/backdrop"
handler: "Group->editBackdrop"
- url: "/club{num}/stats" - url: "/club{num}/stats"
handler: "Group->statistics" handler: "Group->statistics"
- url: "/club{num}/followers" - url: "/club{num}/followers"

View file

@ -190,6 +190,54 @@ p {
border-top: 1px solid #CCCCCC; border-top: 1px solid #CCCCCC;
} }
#backdrop {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: -100;
background-repeat: no-repeat;
background-size: contain;
background-position: center left, center right;
pointer-events: none;
opacity: .8;
}
#backdropDripper {
width: 800px;
height: 100%;
margin: auto;
background-color: #fff;
box-shadow: -30px 0px 20px 20px #fff, -50px 0px 20px 20px hsl(0deg 0% 100% / 59%), -70px 0px 20px 20px hsl(0deg 0% 100% / 43%), -90px 0px 20px 20px hsl(0deg 0% 100% / 35%), -110px 0px 20px 20px hsl(0deg 0% 100% / 28%), -130px 0px 20px 20px hsl(0deg 0% 100% / 16%), 30px 0px 20px 20px #fff, 50px 0px 20px 20px hsl(0deg 0% 100% / 59%), 70px 0px 20px 20px hsl(0deg 0% 100% / 43%), 90px 0px 20px 20px hsl(0deg 0% 100% / 35%), 110px 0px 20px 20px hsl(0deg 0% 100% / 28%), 130px 0px 20px 20px hsl(0deg 0% 100% / 16%);
}
#backdropEditor {
position: relative;
border: 4px inset #cfcfcf;
padding: 8px;
width: 550px;
height: 270px;
margin: 8px auto;
background-image: url("../img/backdrop-editor.gif");
background-size: cover;
}
#backdropFilePicker {
position: absolute;
top: 140px;
padding: 0 19px;
}
#backdropFilePicker > input {
width: 90px;
}
#backdropFilePicker > #spacer {
display: inline-block;
width: calc(550px - 16px - 38px - 171px);
}
.page_body { .page_body {
width: 632px; width: 632px;
float: right; float: right;

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -0,0 +1,7 @@
ALTER TABLE `profiles`
ADD COLUMN `backdrop_1` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `birthday_privacy`,
ADD COLUMN `backdrop_2` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `backdrop_1`;
ALTER TABLE `groups`
ADD COLUMN `backdrop_1` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `alert`,
ADD COLUMN `backdrop_2` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `backdrop_1`;

View file

@ -531,6 +531,19 @@
"end_all_sessions_done" = "All sessions was ended, including mobile apps"; "end_all_sessions_done" = "All sessions was ended, including mobile apps";
"backdrop_short" = "Backdrop";
"backdrop" = "Page backdrop";
"backdrop_desc" = "Вы можете установить два изображения в качестве фона вашей страницы. Они будут отображаться по бокам у тех, кто зайдёт на вашу страницу. С помощью этой возможности вы можете добавить своему профилю больше индивидуальности.";
"backdrop_warn" = "You can set two pictures as your profile or group backdrop. They will be displayed on left and right edges of page. You can customize your profile with this feature, but use it responsibly."
"backdrop_about_adding" = "You can upload only one picture, although depending on design, the ending result may look ugly. You can also change only one pic: if you already have two images set up and you want to change one - upload only one, the other won't be removed. To remove both images press the button below, you can't remove pictures individually."
"backdrop_save" = "Save backdrop picture(s)";
"backdrop_remove" = "Remove all backdrop pictures";
"backdrop_error_title" = "Error saving backdrop settings";
"backdrop_error_no_media" = "Images are corrupted or haven't been uploaded in their entirety";
"backdrop_succ" = "Backdrop settings saved";
"backdrop_succ_rem" = "Backdrop images have been removed";
"backdrop_succ_desc" = "Users will start seeing changes in 5 minutes.";
/* Two-factor authentication */ /* Two-factor authentication */
"two_factor_authentication" = "Two-factor authentication"; "two_factor_authentication" = "Two-factor authentication";

View file

@ -491,6 +491,18 @@
"end_all_sessions" = "Сбросить все сессии"; "end_all_sessions" = "Сбросить все сессии";
"end_all_sessions_description" = "Если вы хотите выйти из $1 со всех устройств, нажмите на кнопку ниже"; "end_all_sessions_description" = "Если вы хотите выйти из $1 со всех устройств, нажмите на кнопку ниже";
"end_all_sessions_done" = "Все сессии сброшены, включая мобильные приложения"; "end_all_sessions_done" = "Все сессии сброшены, включая мобильные приложения";
"backdrop_short" = "Фон";
"backdrop" = "Фон страницы";
"backdrop_desc" = "Вы можете установить два изображения в качестве фона вашей страницы. Они будут отображаться по бокам у тех, кто зайдёт на вашу страницу. С помощью этой возможности вы можете добавить своему профилю больше индивидуальности.";
"backdrop_warn" = "Изображения будут расположены так, как на схеме выше, их высота будет автоматически увеличена чтобы они занимали 100% высоты экрана, посередине будет размытие, заменить фон основного интерфейса OpenVK или добавить аудиозапись нельзя.";
"backdrop_about_adding" = "Вы можете установить только 1 изображение (но будет некрасиво), а так же заменить только одно: если у вас уже стоит два, а вы хотите заменить второе - то загружайте только второе, первое сохранится, а чтобы удалить надо нажать на соответствующую кнопку внизу, удалять по одной нельзя.";
"backdrop_save" = "Сохранить фон";
"backdrop_remove" = "Удалить фон";
"backdrop_error_title" = "Не удалось сохранить фон";
"backdrop_error_no_media" = "Изображения повреждены или загружены не полностью";
"backdrop_succ" = "Фон сохранён";
"backdrop_succ_rem" = "Фон удалён";
"backdrop_succ_desc" = "Изменения будут заметны другим пользователям через 5 минут.";
/* Two-factor authentication */ /* Two-factor authentication */