Compare commits

...

10 Commits

Author SHA1 Message Date
fe2ed9d789 first gestalt 2025-01-15 15:04:34 +03:00
64dad0aaf9 assets class 2025-01-09 17:13:22 +03:00
32d1e93e73 Merge branch 'master' of https://git.itguild.info/stasbilay02/MicroFrameWork 2025-01-09 16:27:54 +03:00
dd231b0c07 rest and post 2025-01-09 16:27:34 +03:00
88114ae9f2 fix profile edit route 2025-01-09 14:51:15 +03:00
6a07e5cdde admin themes to ms 2025-01-09 12:17:32 +03:00
7489e999ef add profile routs 2024-12-27 15:16:21 +03:00
1a54003030 some fix 2024-12-27 13:50:37 +03:00
28c8e24847 some 2024-12-26 14:04:35 +03:00
b5b7befd34 user photo add 2024-12-25 16:32:23 +03:00
118 changed files with 1793 additions and 115 deletions

View File

@ -0,0 +1,20 @@
<?php
namespace app\themes\gestalt\assets;
use kernel\Assets;
class GestaltThemeAssets extends Assets
{
protected function createCSS(): void
{
$this->registerCSS(slug: "main", resource: "/_next/static/css/0d3195690bab7456.css");
}
protected function createJS()
{
$this->registerJS(slug: "webpack", resource: "/_next/static/chunks/webpack-079ef2e4659c5b2a.js");
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace app\themes\gestalt\controllers;
use kernel\Controller;
class MainController extends Controller
{
protected function init(): void
{
parent::init();
$this->cgView->viewPath = APP_DIR . "/themes/gestalt/views/main/";
$this->cgView->layout = "main.php";
$this->cgView->layoutPath = APP_DIR . "/themes/gestalt/views/layout/";
$this->cgView->addVarToLayout("resources", "/resources/out");
}
public function actionIndex(): void
{
$this->cgView->render("index.php");
}
}

View File

@ -0,0 +1,10 @@
{
"name": "Gestalt",
"slug": "gestalt",
"version": "0.1",
"author": "ItGuild",
"preview": "preview.png",
"description": "Gestalt theme",
"resource_path": "{RESOURCES}/out",
"routs": "routs/gestalt.php"
}

View File

@ -0,0 +1,13 @@
<?php
use kernel\App;
use kernel\CgRouteCollector;
use Phroute\Phroute\RouteCollector;
App::$collector->get('/', [\app\themes\gestalt\controllers\MainController::class, 'actionIndex']);
//App::$collector->get('/page/{page_number}', [\app\modules\tag\controllers\TagController::class, 'actionIndex']);
//App::$collector->get('/create', [\app\modules\tag\controllers\TagController::class, 'actionCreate']);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,224 @@
<?php
/**
* @var string $resources;
* @var \kernel\CgView $view
*/
$view->setTitle("Донецкое гештальт сообщество");
$view->setMeta([
'description' => 'Донецкое гештальт сообщество'
]);
?>
<div class="flex flex-col container m-auto text-center text-dark gap-[31px]"><h1 class="text-[40px] uppercase">
Донецкое гештальт сообщество</h1>
<p class="text-dark text-[19px] max-w-[832px] mx-auto">это добровольное самоорганизующееся сообщество
специалистов г. Донецка и Донецкого края в области психологического консультирования и гештальт-терапии.</p>
</div>
<div class="flex justify-center mt-[100px] gap-[14px] container mx-auto">
<div class="relative bg-blue border-[1px] border-white rounded-[25px] pr-[48px] max-w-[650px] min-h-[480px] w-full font-[400]">
<img alt="intro" loading="lazy" width="1" height="1" decoding="async" data-nimg="1"
class="w-auto h-auto absolute" style="color:transparent" src="<?= $resources ?>/images/intro.svg"/>
<h3 class="text-white text-[38px] mt-[214px] text-end leading-[41px]"><span
class="bg-darkBlue px-[12px] py-[3px] rounded-[18px]">Цель</span> нашего<br/>объединения:</h3>
<p class="ml-auto mt-[50px] text-start text-white text-[19px] leading-[20px] max-w-[400px] font-[700]">
взаимное обогащение профессиональными знаниями, идеями и опытом на конференциях и семинарах, в учебных
программах и на интенсивах, на специализациях и в супервизорских группах.</p></div>
<div class="flex flex-col gap-[12px] max-w-[368px]">
<div class="flex items-center bg-blue rounded-[25px] min-h-[234px] px-[68px] py-[60px] relative"><p
class="text-white font-[500] leading-[23px] text-[20px]">Через собственное развитие мы развиваем и
популяризируем гештальт-подход</p><img alt="palm" loading="lazy" width="1" height="1" decoding="async"
data-nimg="1" class="w-auto h-auto absolute right-3 bottom-0"
style="color:transparent" src="<?= $resources ?>/images/palm.svg"/></div>
<div class="flex flex-col items-center rounded-[25px] min-h-[234px] px-[68px] pt-[40px] border-[4px] border-white">
<div class="flex relative left-[-20px] bottom-[-10px]"><img alt="avatar" loading="lazy" width="101"
height="100" decoding="async" data-nimg="1"
class="undefined relative"
style="color:transparent"
srcSet="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=128&amp;q=75 1x, <?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75 2x"
src="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75"/><img
alt="avatar" loading="lazy" width="101" height="100" decoding="async" data-nimg="1"
class="right-[55px] z-2 relative" style="color:transparent"
srcSet="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=128&amp;q=75 1x, <?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75 2x"
src="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75"/><img alt="avatar"
loading="lazy"
width="101" height="100"
decoding="async"
data-nimg="1"
class="right-[105px] z-3 relative"
style="color:transparent"
srcSet="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=128&amp;q=75 1x, <?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75 2x"
src="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75"/><img
alt="avatar" loading="lazy" width="101" height="100" decoding="async" data-nimg="1"
class="right-[155px] z-4 relative" style="color:transparent"
srcSet="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=128&amp;q=75 1x, <?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75 2x"
src="<?= $resources ?>/_next/image?url=%2Fimages%2Favatar.png&amp;w=256&amp;q=75"/></div>
<p class="text-blue font-[900] text-[26px]">+ 145 учасников</p></div>
</div>
</div>
<div class="mt-[50px] flex gap-[64px] justify-center container mx-auto">
<div class="flex-col flex gap-[35px] items-center"><img alt="oppgp" loading="lazy" width="140" height="37"
decoding="async" data-nimg="1" style="color:transparent"
src="<?= $resources ?>/images/oppgp.svg"/>
<p class="text-grey max-w-[300px] text-[16px] leading-[17px] text-center font-[700]">Донецкое
гештальт-сообщество является частью Всероссийского общества психологов практикующих гештальт-подход (ОПП
ГП). </p></div>
<div class="flex-col flex gap-[19px] items-center"><img alt="oppgp" loading="lazy" width="177" height="53"
decoding="async" data-nimg="1" style="color:transparent"
src="<?= $resources ?>/images/pmg.svg"/>
<p class="text-grey max-w-[507px] text-[16px] leading-[17px] text-center font-[700]">В своей работе мы
придерживаемся стандартов программы «Московский Гештальт Институт», а также стандартов Европейской
Ассоциации Гештальт Терапии, Этического Кодекса Гештальт Терапевта и принципов гуманизма.</p></div>
</div>
<div class="flex flex-col mt-[100px]">
<div class="flex items-center max-w-[1033px] mx-auto justify-between w-full mb-[50px]">
<div class="undefined px-[25px] py-[10px] max-w-[225px] min-w-[180px] justify-center w-fit cursor-pointer border-blue border-[1px] flex gap-[10px] rounded-[10px]">
<p class="text-blue font-[700] text-[16px]">Конференции</p><img alt="chevronDown" loading="lazy"
width="11" height="8" decoding="async"
data-nimg="1" style="color:transparent"
src="<?= $resources ?>/images/chevronDown.svg"/></div>
<h3 class="text-black text-[26px] uppercase">Мероприятия сообщества</h3>
<button class="flex items-center justify-center whitespace-nowrap rounded-[6px] font-[400] bg-blue text-[16px] text-white max-h-[39px] px-[25px] py-[10px] undefined">
Все мероприятия
</button>
</div>
<div class="flex justify-around"><a
class="border-[1px] border-white rounded-[6px] bg-darkGrey px-[13.5px] pt-[12px] pb-[35px] text-black"
href="events/event-1"><span class="flex w-[288px] h-[177px] bg-white"></span><h5
class="max-w-[267px] font-[500] text-[16px] leading-[18px] mt-[30px] mb-[8px] line-clamp-3 text-ellipsis">
добровольное самоорганизующееся сообщество специалистов ... добровольное самоорганизующееся сообщество
специалистов ...</h5>
<p class="max-w-[267px] text-[15px] leading-[17px] line-clamp-3 text-ellipsis">добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области...</p></a><a
class="border-[1px] border-white rounded-[6px] bg-darkGrey px-[13.5px] pt-[12px] pb-[35px] text-black"
href="events/event-1"><span class="flex w-[288px] h-[177px] bg-white"></span><h5
class="max-w-[267px] font-[500] text-[16px] leading-[18px] mt-[30px] mb-[8px] line-clamp-3 text-ellipsis">
добровольное самоорганизующееся сообщество специалистов ... добровольное самоорганизующееся сообщество
специалистов ...</h5>
<p class="max-w-[267px] text-[15px] leading-[17px] line-clamp-3 text-ellipsis">добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области...</p></a><a
class="border-[1px] border-white rounded-[6px] bg-darkGrey px-[13.5px] pt-[12px] pb-[35px] text-black"
href="events/event-1"><span class="flex w-[288px] h-[177px] bg-white"></span><h5
class="max-w-[267px] font-[500] text-[16px] leading-[18px] mt-[30px] mb-[8px] line-clamp-3 text-ellipsis">
добровольное самоорганизующееся сообщество специалистов ... добровольное самоорганизующееся сообщество
специалистов ...</h5>
<p class="max-w-[267px] text-[15px] leading-[17px] line-clamp-3 text-ellipsis">добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области...</p></a><a
class="border-[1px] border-white rounded-[6px] bg-darkGrey px-[13.5px] pt-[12px] pb-[35px] text-black"
href="events/event-1"><span class="flex w-[288px] h-[177px] bg-white"></span><h5
class="max-w-[267px] font-[500] text-[16px] leading-[18px] mt-[30px] mb-[8px] line-clamp-3 text-ellipsis">
добровольное самоорганизующееся сообщество специалистов ... добровольное самоорганизующееся сообщество
специалистов ...</h5>
<p class="max-w-[267px] text-[15px] leading-[17px] line-clamp-3 text-ellipsis">добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области...</p></a><a
class="border-[1px] border-white rounded-[6px] bg-darkGrey px-[13.5px] pt-[12px] pb-[35px] text-black"
href="events/event-1"><span class="flex w-[288px] h-[177px] bg-white"></span><h5
class="max-w-[267px] font-[500] text-[16px] leading-[18px] mt-[30px] mb-[8px] line-clamp-3 text-ellipsis">
добровольное самоорганизующееся сообщество специалистов ... добровольное самоорганизующееся сообщество
специалистов ...</h5>
<p class="max-w-[267px] text-[15px] leading-[17px] line-clamp-3 text-ellipsis">добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области добровольное
самоорганизующееся сообщество специалистов г. Донецка и Донецкого края в области...</p></a></div>
</div>
<div class="flex flex-col mt-[90px] mb-[80px] gap-[56px]">
<div class="flex items-center max-w-[1033px] mx-auto justify-between w-full">
<div class="undefined px-[25px] py-[10px] max-w-[225px] min-w-[180px] justify-center w-fit cursor-pointer border-blue border-[1px] flex gap-[10px] rounded-[10px]">
<p class="text-blue font-[700] text-[16px]">Тренер</p><img alt="chevronDown" loading="lazy" width="11"
height="8" decoding="async" data-nimg="1"
style="color:transparent"
src="<?= $resources ?>/images/chevronDown.svg"/></div>
<h3 class="text-black text-[26px] uppercase">наше сообщество</h3>
<button class="flex items-center justify-center whitespace-nowrap rounded-[6px] font-[400] bg-blue text-[16px] text-white max-h-[39px] px-[25px] py-[10px] undefined">
Все участники
</button>
</div>
<div class="flex max-w-[1033px] m-auto justify-between w-full"><a
class=" backdrop-blur-custom border-[1px] border-white rounded-[6px] bg-darkWhite p-[10px] text-black w-fit shadow-custom"
href="/participants/1"><img alt="image" loading="lazy" width="221" height="221" decoding="async"
data-nimg="1" class="rotate-[180deg]" style="color:transparent"
src="<?= $resources ?>/images/mok_human.svg"/><h5
class="text-[18px] font-[400] leading-[20px] max-w-[190px] mt-[16px] mb-[20px]">Лукашенко Марина
Анатольевна</h5><span class="text-lightGrey">Работает с темами<p
class="text-black text-[13px] leading-[15px] line-clamp-3 text-ellipsis max-w-[220px] mb-[16px] ">Финансовые изменения, болезнь, своя или близких, разрыв отношений, развод...</p></span>
<div class="flex gap-[5px] max-w-[220px] flex-wrap ">
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Терапевт</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Супервизор</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер-стажер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ассоциированный тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ведущий тренер</span></div>
</div>
</a><a class=" backdrop-blur-custom border-[1px] border-white rounded-[6px] bg-darkWhite p-[10px] text-black w-fit shadow-custom"
href="/participants/1"><img alt="image" loading="lazy" width="221" height="221" decoding="async"
data-nimg="1" class="rotate-[180deg]" style="color:transparent"
src="<?= $resources ?>/images/mok_human.svg"/><h5
class="text-[18px] font-[400] leading-[20px] max-w-[190px] mt-[16px] mb-[20px]">Лукашенко Марина
Анатольевна</h5><span class="text-lightGrey">Работает с темами<p
class="text-black text-[13px] leading-[15px] line-clamp-3 text-ellipsis max-w-[220px] mb-[16px] ">Финансовые изменения, болезнь, своя или близких, разрыв отношений, развод...</p></span>
<div class="flex gap-[5px] max-w-[220px] flex-wrap ">
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Терапевт</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Супервизор</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер-стажер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ассоциированный тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ведущий тренер</span></div>
</div>
</a><a class=" backdrop-blur-custom border-[1px] border-white rounded-[6px] bg-darkWhite p-[10px] text-black w-fit shadow-custom"
href="/participants/1"><img alt="image" loading="lazy" width="221" height="221" decoding="async"
data-nimg="1" class="rotate-[180deg]" style="color:transparent"
src="<?= $resources ?>/images/mok_human.svg"/><h5
class="text-[18px] font-[400] leading-[20px] max-w-[190px] mt-[16px] mb-[20px]">Лукашенко Марина
Анатольевна</h5><span class="text-lightGrey">Работает с темами<p
class="text-black text-[13px] leading-[15px] line-clamp-3 text-ellipsis max-w-[220px] mb-[16px] ">Финансовые изменения, болезнь, своя или близких, разрыв отношений, развод...</p></span>
<div class="flex gap-[5px] max-w-[220px] flex-wrap ">
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Терапевт</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Супервизор</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер-стажер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ассоциированный тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ведущий тренер</span></div>
</div>
</a><a class=" backdrop-blur-custom border-[1px] border-white rounded-[6px] bg-darkWhite p-[10px] text-black w-fit shadow-custom"
href="/participants/1"><img alt="image" loading="lazy" width="221" height="221" decoding="async"
data-nimg="1" class="rotate-[180deg]" style="color:transparent"
src="<?= $resources ?>/images/mok_human.svg"/><h5
class="text-[18px] font-[400] leading-[20px] max-w-[190px] mt-[16px] mb-[20px]">Лукашенко Марина
Анатольевна</h5><span class="text-lightGrey">Работает с темами<p
class="text-black text-[13px] leading-[15px] line-clamp-3 text-ellipsis max-w-[220px] mb-[16px] ">Финансовые изменения, болезнь, своя или близких, разрыв отношений, развод...</p></span>
<div class="flex gap-[5px] max-w-[220px] flex-wrap ">
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Терапевт</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Супервизор</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер-стажер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ассоциированный тренер</span></div>
<div class="flex items-center justify-center font-[400] border-blue w-fit text-[12px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue font-[700]">
<span class="relative top-[2px]">Ведущий тренер</span></div>
</div>
</a></div>
</div>

View File

@ -7,6 +7,7 @@ namespace kernel;
use kernel\helpers\Debug;
use kernel\modules\user\models\User;
use kernel\services\ModuleService;
use kernel\services\ThemeService;
use Phroute\Phroute\Dispatcher;
class App
@ -24,6 +25,8 @@ class App
public ModuleService $moduleService;
public ThemeService $themeService;
public static Database $db;
public function run(): void
@ -39,6 +42,7 @@ class App
public function load(): static
{
$this->moduleService = new ModuleService();
$this->themeService = new ThemeService();
App::$collector = new CgRouteCollector();
$this->setRouting();
@ -53,6 +57,10 @@ class App
foreach ($modules_routs as $rout){
include "$rout";
}
$activeTheme = getConst($this->themeService->getActiveTheme());
if (!empty($activeTheme)){
include $activeTheme . "/" . $this->themeService->getThemeRout($activeTheme);
}
}
public static function create(): App

66
kernel/Assets.php Normal file
View File

@ -0,0 +1,66 @@
<?php
namespace kernel;
class Assets
{
protected array $jsHeader = [];
protected array $jsBody = [];
protected array $css = [];
protected string $resourceURI = "/resource";
public function __construct(string $resourceURI)
{
$this->setResourceURI($resourceURI);
$this->createCSS();
$this->createJS();
}
protected function createCSS(){}
protected function createJS(){}
public function setResourceURI(string $resourceURI): void
{
$this->resourceURI = $resourceURI;
}
public function registerJS(string $slug, string $resource, bool $body = true, bool $addResourceURI = true): void
{
$resource = $addResourceURI ? $this->resourceURI . $resource : $resource;
if ($body) {
$this->jsBody[$slug] = $resource;
} else {
$this->jsHeader[$slug] = $resource;
}
}
public function registerCSS(string $slug, string $resource, bool $addResourceURI = true): void
{
$resource = $addResourceURI ? $this->resourceURI . $resource : $resource;
$this->css[$slug] = $resource;
}
public function getJSAsStr(bool $body = true): void
{
if ($body) {
foreach ($this->jsBody as $key => $item){
echo "<script src='$item'></script>";
}
}
else {
foreach ($this->jsHeader as $key => $item){
echo "<script src='$item'></script>";
}
}
}
public function getCSSAsSTR(): void
{
foreach ($this->css as $key => $item){
echo "<link rel='stylesheet' href='$item'>";
}
}
}

View File

@ -2,6 +2,8 @@
namespace kernel;
use kernel\helpers\Debug;
class CgView
{
public string $viewPath = '';
@ -61,6 +63,13 @@ class CgView
private function createContent(string $viewFile, array $data = []): false|string
{
ob_start();
if ($this->varToLayout){
foreach ($this->varToLayout as $key => $datum) {
${"$key"} = $datum;
}
}
$view = $this;
foreach ($data as $key => $datum) {
${"$key"} = $datum;

View File

@ -36,7 +36,9 @@ class FileUpload
$newFileName = md5(time() . $this->fileName) . '.' . $this->fileExtension;
if (in_array($this->fileExtension, $this->allowedFileExtensions)) {
$this->uploadDir = $uploadDir . mb_substr($newFileName, 0, 2) . '/' . mb_substr($newFileName, 2, 2) . '/';
mkdir(ROOT_DIR . $this->uploadDir, 0777, true);
$oldMask = umask(0);
mkdir(ROOT_DIR . $this->uploadDir, 0775, true);
umask($oldMask);
$uploadFileDir = ROOT_DIR . $this->uploadDir;
$this->destPath = $uploadFileDir . $newFileName;
$this->uploadFile = $this->uploadDir . $newFileName;
@ -49,7 +51,9 @@ class FileUpload
} else {
if (in_array($this->fileExtension, $this->allowedFileExtensions)) {
$this->uploadDir = $uploadDir;
mkdir(ROOT_DIR . $this->uploadDir, 0777, true);
$oldMask = umask(0);
mkdir(ROOT_DIR . $this->uploadDir, 0775, true);
umask($oldMask);
$uploadFileDir = ROOT_DIR . $this->uploadDir;
$this->destPath = $uploadFileDir . $this->fileName;
$this->uploadFile = $this->uploadDir . $this->fileName;

View File

@ -17,13 +17,32 @@ class RestController
return [];
}
protected function filters(): array
{
return [];
}
#[NoReturn] public function actionIndex(): void
{
$request = new Request();
$get = $request->get();
$page = $request->get('page') ?? 1;
$perPage = $request->get('per_page') ?? 10;
$query = $this->model->query();
if ($this->filters()) {
foreach ($this->filters() as $filter){
if (key_exists($filter, $get)){
if (is_numeric($get[$filter])){
$query->where($filter, $get[$filter]);
}
elseif (is_string($get[$filter])){
$query->where($filter,'like', '%' . $get[$filter] . '%');
}
}
}
}
if ($page > 1) {
$query->skip(($page - 1) * $perPage)->take($perPage);
} else {
@ -31,7 +50,7 @@ class RestController
}
$expand = $this->expand();
$expandParams = explode( ",", $request->get('expand') ?? "");
$expandParams = explode(",", $request->get('expand') ?? "");
$finalExpand = array_intersect($expandParams, $expand);
if ($finalExpand) {
$res = $query->get()->load($finalExpand)->toArray();
@ -46,14 +65,14 @@ class RestController
{
$expand = $this->expand();
$request = new Request();
$expandParams = explode( ",", $request->get('expand') ?? "");
$expandParams = explode(",", $request->get('expand') ?? "");
$model = $this->model->where("id", $id)->first();
$finalExpand = array_intersect($expandParams, $expand);
if ($finalExpand){
if ($finalExpand) {
$model->load($finalExpand);
}
$res = [];
if ($model){
if ($model) {
$res = $model->toArray();
}
@ -64,7 +83,7 @@ class RestController
{
$model = $this->model->where("id", $id)->first();
$res = [];
if ($model){
if ($model) {
$res = $model->toArray();
}
@ -78,7 +97,7 @@ class RestController
{
$request = new Request();
$data = $request->post();
foreach ($this->model->getFillable() as $item){
foreach ($this->model->getFillable() as $item) {
$this->model->{$item} = $data[$item] ?? null;
}
$this->model->save();
@ -93,8 +112,8 @@ class RestController
$model = $this->model->where('id', $id)->first();
foreach ($model->getFillable() as $item){
if (!empty($data[$item])){
foreach ($model->getFillable() as $item) {
if (!empty($data[$item])) {
$model->{$item} = $data[$item] ?? null;
}
}
@ -117,5 +136,4 @@ class RestController
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace kernel\admin_themes\default;
use kernel\Assets;
class DefaultAdminThemeAssets extends Assets
{
protected function createJS(): void
{
$this->registerJS(slug: "jquery", resource: "/js/jquery.min.js");
$this->registerJS(slug: "popper", resource: "/js/popper.js");
$this->registerJS(slug: "bootstrap", resource: "/js/bootstrap.min.js");
$this->registerJS(slug: "main", resource: "/js/main.js");
}
protected function createCSS()
{
$this->registerCSS(slug: "font-awesome", resource: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css", addResourceURI: false);
$this->registerCSS(slug: "bootstrap", resource: "/css/bootstrap.min.css");
$this->registerCSS(slug: "style", resource: "/css/style.css");
}
}

View File

@ -6,6 +6,7 @@
* @var \kernel\CgView $view
*/
\Josantonius\Session\Facades\Session::start();
$assets = new \kernel\admin_themes\default\DefaultAdminThemeAssets($resources)
?>
<!doctype html>
<html lang="en">
@ -17,19 +18,21 @@
<link href="https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700,800,900" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css">
<link rel="stylesheet" href="<?= $resources ?>/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= $resources ?>/css/style.css">
<?php $assets->getCSSAsSTR(); ?>
<?php $assets->getJSAsStr(body: false); ?>
</head>
<body>
<div class="wrapper d-flex align-items-stretch">
<nav id="sidebar">
<div class="p-4 pt-5">
<a href="#" class="img logo rounded-circle mb-5"
style="background-image: url(/resources/admin_theme/images/logo.jpg);"></a>
<a href="<?= '/admin/user/profile' ?>" class="img logo rounded-circle mb-5"
style="background-image: url(<?= \kernel\modules\user\service\UserService::getAuthUserPhoto() ?? '/resources/default_user_photo/noPhoto.png' ?>);">
</a>
<p>
<?= \kernel\modules\user\service\UserService::getAuthUsername() ?>
<a href="<?= '/admin/user/profile' ?>">
<?= \kernel\modules\user\service\UserService::getAuthUsername() ?>
</a>
</p>
<?php \kernel\widgets\MenuWidget::create()->run(); ?>
<div class="footer">
@ -74,24 +77,21 @@
</div>
</nav>
<?php if (\kernel\Flash::hasMessage("error")): ?>
<div class="alert alert-danger alert-dismissible mainAlert">
<?= \kernel\Flash::getMessage("error"); ?>
<button type="button" class="btn-close closeAlertBtn"></button>
</div>
<div class="alert alert-danger alert-dismissible mainAlert">
<?= \kernel\Flash::getMessage("error"); ?>
<button type="button" class="btn-close closeAlertBtn"></button>
</div>
<?php endif; ?>
<?php if (\kernel\Flash::hasMessage("success")): ?>
<div class="alert alert-success alert-dismissible">
<?= \kernel\Flash::getMessage("success"); ?>
<button type="button" class="btn-close closeAlertBtn" ></button>
<button type="button" class="btn-close closeAlertBtn"></button>
</div>
<?php endif; ?>
<?= $content ?>
</div>
</div>
<script src="<?= $resources ?>/js/jquery.min.js"></script>
<script src="<?= $resources ?>/js/popper.js"></script>
<script src="<?= $resources ?>/js/bootstrap.min.js"></script>
<script src="<?= $resources ?>/js/main.js"></script>
<?php $assets->getJSAsStr(); ?>
</body>
</html>

View File

@ -6,15 +6,16 @@ use itguild\forms\builders\SelectBuilder;
use Itguild\Tables\Filter\Filter;
use kernel\helpers\Debug;
class CustomSelectFilterForAssociativeArr extends Filter
class BootstrapSelectFilter extends Filter
{
public function fetch(): string
{
$select = SelectBuilder::build($this->name, [
'class' => 'form-control',
'options' => $this->param,
'options' => $this->params['options'],
'value' => $this->value,
'prompt' => $this->params['prompt'] ?? null,
]);
return "<td>" . $select->create()->fetch() . "</td>";

View File

@ -0,0 +1,21 @@
<?php
namespace kernel\filters;
use itguild\forms\builders\TextInputBuilder;
use Itguild\Tables\Filter\Filter;
class BootstrapTextFilter extends Filter
{
public function fetch()
{
$textInput = TextInputBuilder::build($this->name, [
'value' => $this->value,
'class' => "form-control"
]);
return "<td>" . $textInput->create()->fetch() . "</td>";
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace kernel\filters;
use Itguild\Tables\Filter\Filter;
class CustomSelectFilter extends Filter
{
public function fetch()
{
$this->html = "<td><select class='form-control' name='$this->name'>";
foreach ($this->param as $value) {
if ($value === $this->value) {
$this->html .= "<option value='$value' selected>$value</option>";
} else {
$this->html .= "<option value='$value'>$value</option>";
}
}
$this->html .= "value='$this->value'</select></td>";
return $this->html;
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace kernel\helpers;
class ImageGD
{
public \GdImage $img;
public function __construct(string $resource = '', int $width = 200, int $height = 200)
{
if ($resource){
$this->img = imagecreatefrompng($resource);
}
else {
$this->img = imagecreatetruecolor($width, $height);
}
imagesavealpha($this->img, true);
}
public function addText(string $font_size, int $degree, int $x, int $y, string $color, string $font, string $text): void
{
$rgbArr = $this->hexToRgb($color);
$color = imagecolorallocate($this->img, $rgbArr[0], $rgbArr[1], $rgbArr[2]);
imagettftext($this->img, $font_size, $degree, $x, $y, $color, $font, $text);
}
public function addImg(\GdImage $gdImage, int $location_x, int $location_y, int $offset_src_x, int $offset_src_y, int $src_width, int $src_height, int $no_transparent): void
{
imagecopymerge($this->img, $gdImage, $location_x, $location_y, $offset_src_x, $offset_src_y, $src_width, $src_height, $no_transparent);
}
public function getImg()
{
return $this->img;
}
public function save(string $path): void
{
imagepng($this->img, $path);
imagedestroy($this->img);
}
protected function hexToRgb(string $hex)
{
return sscanf($hex, "#%02x%02x%02x");
}
}

View File

@ -1,6 +1,6 @@
{
"name": "Kernel",
"version": "0.1.1",
"version": "0.1.4",
"author": "ITGuild",
"slug": "kernel",
"type": "kernel",

View File

@ -19,12 +19,15 @@ $table = new ListEloquentTable(new EloquentDataProvider(Menu::class, [
'baseUrl' => "/admin/settings/menu",
]));
$table->columns([
'parent_id' => (function ($data) {
'parent_id' => function ($data) {
if ($data == 0) return null;
return Menu::find($data)->label;
}),
},
'icon_file' => function ($data) {
return $data ? "<img src='$data' width='150px'>" : "";
},
'status' => function ($data) {
return Menu::getStatus()[$data];
}
]);
$table->beforePrint(function () {

View File

@ -5,6 +5,7 @@ namespace kernel\modules\module_shop_client\controllers;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use JetBrains\PhpStorm\NoReturn;
use Josantonius\Session\Facades\Session;
use kernel\AdminController;
use kernel\Flash;
use kernel\helpers\Debug;
@ -162,18 +163,22 @@ class ModuleShopClientController extends AdminController
$filters = $request->get();
if ($this->moduleService->issetModuleShopToken()) {
if ($this->moduleService->isServerAvailable()) {
$modules_info = [];
// $modules_info = [];
$per_page = 8;
$modules = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modules = json_decode($modules->getBody()->getContents(), true);
foreach ($modules as $module) {
foreach ($filters as $key => $value) {
$modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modules_info = json_decode($modules_info->getBody()->getContents(), true);
foreach ($modules_info as $key => $module) {
foreach ($filters as $column => $value) {
if ($value === '') continue;
if ($module[$key] !== $value) {
break;
if (is_numeric($value)) {
if ($module[$column] !== $value) {
unset($modules_info[$key]);
}
} elseif (is_string($value)) {
if (!str_contains($module[$column], $value)) {
unset($modules_info[$key]);
}
}
$modules_info[] = $module;
}
}
$module_count = count($modules_info);
@ -187,6 +192,7 @@ class ModuleShopClientController extends AdminController
'per_page' => $per_page,
'kernelService' => new KernelService(),
'adminThemeService' => new AdminThemeService(),
'filterValues' => $filters
]);
} else {
$this->cgView->render("module_shop_error_connection.php");
@ -208,7 +214,7 @@ class ModuleShopClientController extends AdminController
$moduleShopService = new ModuleShopService();
$result = $moduleShopService->email_auth($address);
if ($result['status'] == 'success'){
if ($result['status'] == 'success') {
$this->cgView->render('enter_code.php', ['email' => $address]);
}
@ -223,7 +229,7 @@ class ModuleShopClientController extends AdminController
$moduleShopService = new ModuleShopService();
$result = $moduleShopService->code_check($code);
if (isset($result['access_token'])){
if (isset($result['access_token'])) {
$envFile = \EnvEditor\EnvFile::loadFrom(ROOT_DIR . "/.env");
@ -237,4 +243,56 @@ class ModuleShopClientController extends AdminController
$this->cgView->render('module_shop_error_connection.php');
}
#[NoReturn] public function actionAdminThemeInstall(): void
{
$request = new Request();
$id = $request->get("id");
$adminThemeInfo = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/install/' . $id);
$adminThemeInfo = json_decode($adminThemeInfo->getBody()->getContents(), true);
Files::uploadByUrl($_ENV['MODULE_SHOP_URL'] . $adminThemeInfo['path_to_archive'], RESOURCES_DIR . "/tmp/admin_themes");
if ($this->adminThemeService->install('/resources/tmp/admin_themes/' . basename($adminThemeInfo['path_to_archive']))) {
Flash::setMessage("success", "Тема админ-панели успешно установлена.");
} else {
Session::start();
Session::set("error", implode(";", $this->adminThemeService->getErrors()));
}
$this->redirect('/admin/module_shop_client', 302);
}
#[NoReturn] public function actionAdminThemeUpdate(): void
{
$request = new Request();
$slug = $request->get("slug");
$modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
$modules_info = json_decode($modules_info->getBody()->getContents(), true);
foreach ($modules_info as $module) {
if ($module['slug'] === $slug) {
$path = $module['path_to_archive'];
}
}
if (isset($path)) {
Files::uploadByUrl($_ENV['MODULE_SHOP_URL'] . $path, RESOURCES_DIR . "/tmp/admin_themes");
$this->adminThemeService->update('/resources/tmp/admin_themes/' . basename($path));
Flash::setMessage("success", "Тема админ-панели успешно обновлена.");
} else {
Flash::setMessage("error", "Ошибка обновления темы админ-панели.");
}
$this->redirect('/admin/module_shop_client', 302);
}
#[NoReturn] public function actionAdminThemeDelete(): void
{
$request = new Request();
$slug = $request->get("slug");
$adminThemeInfo = $this->adminThemeService->getAdminThemeInfoBySlug($slug);
$this->adminThemeService->uninstall($adminThemeInfo['path']);
Flash::setMessage("success", "Тема админ-панели успешно удалена.");
$this->redirect('/admin/module_shop_client', 302);
}
}

View File

@ -24,7 +24,9 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){
});
App::$collector->group(["prefix" => "admin_theme"], function (RouteCollector $router) {
App::$collector->get('/install', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeInstall']);
App::$collector->post('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeUpdate']);
App::$collector->get('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeUpdate']);
App::$collector->get('/delete', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAdminThemeDelete']);
});
});
});

View File

@ -7,6 +7,7 @@
* @var \kernel\services\ModuleService $moduleService
* @var \kernel\services\KernelService $kernelService
* @var \kernel\services\AdminThemeService $adminThemeService
* @var array $filterValues
*/
use Itguild\Tables\ListJsonTable;
@ -42,9 +43,15 @@ $table->addAction(function ($row, $url) use ($moduleService) {
$table->columns([
'type' => [
'filter' => [
'class' => \kernel\filters\CustomSelectFilter::class,
'param' => ['kernel', 'entity'],
'value' => "kernel"
'class' => \kernel\filters\BootstrapSelectFilter::class,
'params' => [
'options' => [
'kernel' => 'kernel',
'entity' => 'entity',
],
'prompt' => 'Не выбрано'
],
'value' => $filterValues['type'] ?? ''
],
]
]);
@ -97,7 +104,7 @@ $table->addAction(function ($row, $url) use ($adminThemeService) {
$slug = $row['slug'];
if ($adminThemeService->isInstall($slug)) {
if (!$adminThemeService->isLastVersion($slug)) {
$url = "$url/admin_theme/update/";
$url = "$url/admin_theme/update/?slug=" . $row['slug'];
return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run();
}
@ -107,6 +114,22 @@ $table->addAction(function ($row, $url) use ($adminThemeService) {
return false;
});
$table->addAction(function ($row, $url) use ($adminThemeService) {
if ($row['type'] === 'admin_theme') {
if ($adminThemeService->isInstall($row['slug'])) {
$url = "$url/admin_theme/delete/?slug=" . $row['slug'];
return \kernel\widgets\IconBtn\IconBtnDeleteWidget::create(['url' => $url])->run();
} else {
$url = "$url/admin_theme/install/?id=" . $row['id'];
return \kernel\widgets\IconBtn\IconBtnInstallWidget::create(['url' => $url])->run();
}
}
return false;
});
$table->afterPrint(function () {
return \kernel\IGTabel\btn\PrimaryBtn::create('Сбросить все фильтры', '/admin/module_shop_client')->fetch();
});

View File

@ -23,11 +23,9 @@ $table = new ListEloquentTable(new EloquentDataProvider(Post::class, [
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/post",
'searchPrefix' => "",
'searchParams' => $get
'searchParams' => $get,
]));
//\kernel\helpers\Debug::dd((new \kernel\Request())->get());
$view->setTitle("Список постов");
$view->setMeta([
'description' => 'Список постов системы'
@ -47,13 +45,13 @@ foreach ($additionals as $additional) {
$table->columns([
'title' => [
'filter' => [
'class' => \Itguild\Tables\Filter\InputTextFilter::class,
'class' => \kernel\filters\BootstrapTextFilter::class,
'value' => $get['title'] ?? ''
]
],
'content' => [
'filter' => [
'class' => \Itguild\Tables\Filter\InputTextFilter::class,
'class' => \kernel\filters\BootstrapTextFilter::class,
'value' => $get['content'] ?? ''
]
],
@ -72,10 +70,13 @@ $table->columns([
return User::find($data)->username;
},
'filter' => [
'class' => \kernel\filters\CustomSelectFilterForAssociativeArr::class,
'param' => \kernel\modules\user\service\UserService::createUsernameArr(),
'value' => $get['user_id'] ?? ''
]
'class' => \kernel\filters\BootstrapSelectFilter::class,
'params' => [
'options' => \kernel\modules\user\service\UserService::createUsernameArr(),
'prompt' => 'Не выбрано'
],
'value' => $get['user_id'] ?? '',
],
]
]);

View File

@ -13,21 +13,28 @@ use kernel\services\TokenService;
class SecureService
{
public static function createSecretCode(User $user): void
public static function createSecretCode(User $user): SecretCode
{
$secretCode = new SecretCode();
$secretCode->user_id = $user->id;
$secretCode->code = mt_rand(100000, 999999);
$secretCode->code_expires_at = date("Y-m-d H:i:s", strtotime("+5 minutes"));;
$secretCode->save();
return $secretCode;
}
public static function updateSecretCode(User $user): void
public static function updateSecretCode(User $user): SecretCode
{
$secretCode = SecretCode::where('user_id', $user->id)->first();
if(!$secretCode){
return self::createSecretCode($user);
}
$secretCode->code = mt_rand(100000, 999999);
$secretCode->code_expires_at = date("Y-m-d H:i:s", strtotime("+5 minutes"));;
$secretCode->save();
return $secretCode;
}
public static function getCodeByUserId(int $user_id)

View File

@ -6,6 +6,8 @@ use Exception;
use JetBrains\PhpStorm\NoReturn;
use kernel\AdminController;
use kernel\EntityRelation;
use kernel\FileUpload;
use kernel\helpers\Debug;
use kernel\modules\user\models\forms\CreateUserForm;
use kernel\modules\user\models\User;
use kernel\modules\user\service\UserService;
@ -35,10 +37,17 @@ class UserController extends AdminController
{
$userForm = new CreateUserForm();
$userForm->load($_REQUEST);
if (isset($_FILES['user_photo']) && $_FILES['user_photo']['error'] === UPLOAD_ERR_OK) {
$file = new FileUpload($_FILES['user_photo'], ['jpg', 'jpeg', 'png']);
$file->upload();
$userForm->setItem('user_photo', $file->getUploadFile());
}
if ($userForm->validate()){
$user = $this->userService->create($userForm);
$entityRelation = new EntityRelation();
$entityRelation->saveEntityRelation(entity: "user", model: $user, request: new Request());
@ -98,6 +107,13 @@ class UserController extends AdminController
$userForm = new CreateUserForm();
$userService = new UserService();
$userForm->load($_REQUEST);
if (isset($_FILES['user_photo']) && $_FILES['user_photo']['error'] === UPLOAD_ERR_OK) {
$file = new FileUpload($_FILES['user_photo'], ['jpg', 'jpeg', 'png']);
$file->upload();
$userForm->setItem('user_photo', $file->getUploadFile());
}
if ($userForm->validateForUpdate()){
$user = $userService->update($userForm, $user);
@ -128,4 +144,53 @@ class UserController extends AdminController
$this->redirect("/admin/user/");
}
public function actionProfile(): void
{
$user = UserService::getAuthUser();
if (!$user){
throw new Exception(message: "The user not found");
}
$this->cgView->render("view_profile.php", ['user' => $user]);
}
public function actionProfileUpdate(): void
{
$model = UserService::getAuthUser();
if (!$model){
throw new Exception(message: "The user not found");
}
$this->cgView->render("form_profile.php", ['model' => $model]);
}
public function actionProfileEdit(): void
{
$user = UserService::getAuthUser();
if (!$user){
throw new Exception(message: "The user not found");
}
$userForm = new CreateUserForm();
$userService = new UserService();
$userForm->load($_REQUEST);
if (isset($_FILES['user_photo']) && $_FILES['user_photo']['error'] === UPLOAD_ERR_OK) {
$file = new FileUpload($_FILES['user_photo'], ['jpg', 'jpeg', 'png']);
$file->upload();
$userForm->setItem('user_photo', $file->getUploadFile());
}
if ($userForm->validateForUpdate()){
$user = $userService->update($userForm, $user);
$entityRelation = new EntityRelation();
$entityRelation->saveEntityRelation(entity: "user", model: $user, request: new Request());
if ($user){
$this->redirect("/admin/user/profile");
}
}
$this->redirect("/admin/user/profile/update");
}
}

View File

@ -20,6 +20,7 @@ return new class extends Migration
$table->string('username', 255)->nullable(false);
$table->string('email', 255);
$table->string('password_hash', 255);
$table->string('user_photo', 255)->nullable();
$table->integer('role')->default(1);
$table->string('access_token', 255)->nullable(true);
$table->dateTime('access_token_expires_at')->nullable(true);

View File

@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
* @property string $username
* @property string $email
* @property string $password_hash
* @property string $user_photo
* @property string $access_token
* @property string $access_token_expires_at
* @method static find($id)
@ -17,7 +18,7 @@ class User extends Model {
const ADMIN_USER_ROLE = 9;
protected $table = 'user';
protected $fillable = ['username', 'email', 'password_hash', 'role', 'access_token', 'access_token_expires_at'];
protected $fillable = ['username', 'email', 'password_hash', 'user_photo', 'role', 'access_token', 'access_token_expires_at'];
protected array $dates = ['deleted at'];
public static function labels(): array
@ -25,6 +26,7 @@ class User extends Model {
return [
'username' => 'Логин',
'email' => 'Email',
'user_photo' => 'Фото профиля',
'created_at' => 'Создан',
'updated_at' => 'Обновлен',
];

View File

@ -12,7 +12,8 @@ class CreateUserForm extends FormModel
return [
'username' => 'required|min-str-len:5|max-str-len:30',
'password' => 'required|min-str-len:5|max-str-len:30',
'email' => 'required|email'
'email' => 'required|email',
'user_photo' => ''
];
}
@ -21,7 +22,9 @@ class CreateUserForm extends FormModel
return [
'username' => 'required|min-str-len:5|max-str-len:30',
'password' => '',
'email' => 'required|email'
'email' => 'required|email',
'user_photo' => ''
];
}

View File

@ -17,6 +17,11 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){
App::$collector->any('/update/{id}', [\kernel\modules\user\controllers\UserController::class, 'actionUpdate']);
App::$collector->any("/edit/{id}", [\kernel\modules\user\controllers\UserController::class, 'actionEdit']);
App::$collector->get('/delete/{id}', [\kernel\modules\user\controllers\UserController::class, 'actionDelete']);
App::$collector->group(["prefix" => "profile"], callback: function (RouteCollector $router) {
App::$collector->get('/', [\kernel\modules\user\controllers\UserController::class, 'actionProfile']);
App::$collector->get('/update', [\kernel\modules\user\controllers\UserController::class, 'actionProfileUpdate']);
App::$collector->any('/edit', [\kernel\modules\user\controllers\UserController::class, 'actionProfileEdit']);
});
});
});
});

View File

@ -11,10 +11,15 @@ class UserService
public function create(FormModel $form_model): false|User
{
$model = new User();
$model = User::where("username", $form_model->getItem('username'))->first();
if ($model){
return $model;
}
$model = new User();
$model->username = $form_model->getItem('username');
$model->email = $form_model->getItem('email');
$model->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT);
$model->user_photo = $form_model->getItem('user_photo');
if ($model->save()){
return $model;
}
@ -29,6 +34,7 @@ class UserService
if ($form_model->getItem('password')) {
$user->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT);
}
$user->user_photo = $form_model->getItem('user_photo');
if ($user->save()){
return $user;
}
@ -80,6 +86,28 @@ class UserService
return '';
}
public static function getAuthUserId(): string
{
$user = self::getAuthUser();
if ($user){
return $user->id;
}
return '';
}
public static function getAuthUserPhoto(): string|null
{
$user = self::getAuthUser();
if ($user){
if ($user->user_photo) {
return $user->user_photo;
}
}
return null;
}
public function getByAccessToken(string $token)
{
return $this->getByField("access_token", $token);

View File

@ -32,6 +32,16 @@ $form->field(class: \itguild\forms\inputs\TextInput::class, name: "email", param
->setLabel("Email")
->render();
if (!empty($model->user_photo)){
echo "<div><img src='$model->user_photo' width='200px'></div>";
}
$form->field(class: \itguild\forms\inputs\File::class, name: "user_photo", params: [
'class' => "form-control",
'value' => $model->user_photo ?? ''
])
->setLabel("Фото профиля")
->render();
$entityRelations = new \kernel\EntityRelation();
if (!isset($model)) {
$model = new User();

View File

@ -0,0 +1,74 @@
<?php
/**
* @var User $model
*/
use kernel\modules\user\models\User;
$form = new \itguild\forms\ActiveForm();
$form->beginForm("/admin/user/profile/edit", enctype: 'multipart/form-data');
$form->field(class: \itguild\forms\inputs\TextInput::class, name: "username", params: [
'class' => "form-control",
'placeholder' => 'Логин',
'value' => $model->username ?? ''
])
->setLabel("Логин")
->render();
$form->field(class: \itguild\forms\inputs\TextInput::class, name: "password", params: [
'class' => "form-control",
'type' => "password",
])
->setLabel("Пароль")
->render();
$form->field(class: \itguild\forms\inputs\TextInput::class, name: "email", params: [
'class' => "form-control",
'type' => "email",
'placeholder' => 'test@mail.ru',
'value' => $model->email ?? ''
])
->setLabel("Email")
->render();
if (!empty($model->user_photo)){
echo "<div><img src='$model->user_photo' width='200px'></div>";
}
$form->field(class: \itguild\forms\inputs\File::class, name: "user_photo", params: [
'class' => "form-control",
'value' => $model->user_photo ?? ''
])
->setLabel("Фото профиля")
->render();
$entityRelations = new \kernel\EntityRelation();
if (!isset($model)) {
$model = new User();
}
$entityRelations->renderEntityAdditionalPropertyFormBySlug("user", $model);
?>
<div class="row">
<div class="col-sm-2">
<?php
$form->field(\itguild\forms\inputs\Button::class, name: "btn-submit", params: [
'class' => "btn btn-primary ",
'value' => 'Отправить',
'typeInput' => 'submit'
])
->render();
?>
</div>
<div class="col-sm-2">
<?php
$form->field(\itguild\forms\inputs\Button::class, name: "btn-reset", params: [
'class' => "btn btn-warning",
'value' => 'Сбросить',
'typeInput' => 'reset'
])
->render();
?>
</div>
</div>
<?php
$form->endForm();

View File

@ -17,13 +17,15 @@ use kernel\widgets\IconBtn\IconBtnDeleteWidget;
use kernel\widgets\IconBtn\IconBtnEditWidget;
use kernel\widgets\IconBtn\IconBtnViewWidget;
$get = (new \kernel\Request())->get();
$table = new ListEloquentTable(new EloquentDataProvider(User::class, [
'currentPage' => $page_number,
'perPage' => 3,
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/user",
'filters' => ['email'],
]));
'searchPrefix' => "",
'searchParams' => $get,]));
$entityRelation = new \kernel\EntityRelation();
$additionals = $entityRelation->getEntityRelationsBySlug("user");
@ -37,9 +39,13 @@ foreach ($additionals as $additional) {
$table->columns([
'username' => [
"filter" => [
'class' => \Itguild\Tables\Filter\InputTextFilter::class
'class' => \kernel\filters\BootstrapTextFilter::class,
'value' => $get['username'] ?? null,
]
],
'user_photo' => function ($data) {
return $data ? "<img src='$data' width='150px'>" : "";
},
'created_at' => function ($data) {
if (!$data){
return null;

View File

@ -35,6 +35,9 @@ foreach ($additionals as $key => $additional) {
}
$table->rows([
'user_photo' => function ($data) {
return $data ? "<img src='$data' width='300px'>" : "";
},
'created_at' => function ($data) {
if (!$data){
return null;

View File

@ -0,0 +1,56 @@
<?php
/**
* @var \Illuminate\Database\Eloquent\Collection $user
*/
use kernel\modules\user\models\User;
use Itguild\EloquentTable\ViewEloquentTable;
use Itguild\EloquentTable\ViewJsonTableEloquentModel;
use kernel\IGTabel\btn\DangerBtn;
use kernel\IGTabel\btn\PrimaryBtn;
use kernel\IGTabel\btn\SuccessBtn;
use kernel\widgets\IconBtn\IconBtnDeleteWidget;
use kernel\widgets\IconBtn\IconBtnEditWidget;
use kernel\widgets\IconBtn\IconBtnListWidget;
$table = new ViewEloquentTable(new ViewJsonTableEloquentModel($user, [
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/user",
]));
$table->beforePrint(function () use ($user) {
$btn = IconBtnEditWidget::create(['url' => '/admin/user/profile/edit'])->run();
$btn .= IconBtnDeleteWidget::create(['url' => '/admin/user/delete/' . $user->id])->run();
return $btn;
});
$entityRelation = new \kernel\EntityRelation();
$additionals = $entityRelation->getEntityAdditionalProperty("user", $user);
foreach ($additionals as $key => $additional) {
$table->addRow($key, function () use ($additional) {
return $additional;
}, ['after' => 'email']);
}
$table->rows([
'user_photo' => function ($data) {
return $data ? "<img src='$data' width='300px'>" : "";
},
'created_at' => function ($data) {
if (!$data){
return null;
}
return (new DateTimeImmutable($data))->format("d-m-Y");
},
'updated_at' => function ($data) {
if (!$data){
return null;
}
return (new DateTimeImmutable($data))->format("d-m-Y");
}
]);
$table->create();
$table->render();

View File

@ -82,12 +82,22 @@ class AdminThemeService
return $info;
}
public function getAdminThemeInfoBySlug(string $slug)
public function getAdminThemeInfoBySlug(string $slug): false|array|string
{
// TODO
$dirs = $this->getAdminThemeDirs();
foreach ($dirs as $dir) {
foreach (new DirectoryIterator($dir) as $fileInfo) {
if ($fileInfo->isDot()) continue;
if ($this->getAdminThemeInfo($fileInfo->getPathname())['slug'] === $slug) {
return $this->getAdminThemeInfo($fileInfo->getPathname());
}
}
}
return false;
}
public function isInstall(string $slug): bool
public function getAdminThemeDirs(): array
{
$adminThemePaths = Option::where("key", "admin_theme_paths")->first();
$dirs = [];
@ -97,6 +107,12 @@ class AdminThemeService
$dirs[] = getConst($p);
}
}
return $dirs;
}
public function isInstall(string $slug): bool
{
$dirs = $this->getAdminThemeDirs();
foreach ($dirs as $dir) {
foreach (new DirectoryIterator($dir) as $fileInfo) {
if ($fileInfo->isDot()) continue;
@ -116,8 +132,7 @@ class AdminThemeService
$modulesInfo = json_decode($modulesInfo->getBody()->getContents(), true);
$themeInfo = $this->getAdminThemeInfo($slug);
// Debug::dd($themeInfo);
$themeInfo = $this->getAdminThemeInfoBySlug($slug);
foreach ($modulesInfo as $mod) {
if ($mod['slug'] === $themeInfo['slug'] && $mod['version'] === $themeInfo['version']) {
return true;
@ -195,11 +210,20 @@ class AdminThemeService
$this->setActiveAdminTheme(KERNEL_ADMIN_THEMES_DIR . '/default');
}
$fileHelper = new Files();
if (file_exists(ROOT_DIR . $path)) {
$fileHelper->recursiveRemoveDir(ROOT_DIR . $path);
if (file_exists($path)) {
$fileHelper->recursiveRemoveDir($path);
}
if (file_exists(RESOURCES_DIR . '/' . $themeInfo['slug'])) {
$fileHelper->recursiveRemoveDir(RESOURCES_DIR . '/' . $themeInfo['slug']);
}
}
public function update(string $path): bool
{
if ($this->install($path)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace kernel\services;
use kernel\models\Option;
class ThemeService
{
protected Option $option;
protected string $active_theme = "";
public function __construct()
{
$this->option = new Option();
$this->findActiveAdminTheme();
}
public function findActiveAdminTheme(): void
{
$model = $this->option::where("key", "active_theme")->first();
$this->active_theme = $model->value;
}
public function getActiveTheme(): string
{
return $this->active_theme;
}
public function getThemeRout(string $path)
{
if (file_exists($path . "/manifest.json")){
$manifest = json_decode(file_get_contents($path . "/manifest.json"), true);
if ($manifest['routs']) {
return $manifest['routs'];
}
}
return false;
}
}

View File

@ -51,6 +51,16 @@ $table = new \Itguild\Tables\ListJsonTable(json_encode(
]
));
// Пример фильтра
$table->columns([
'title' => [
'filter' => [
'class' => \Itguild\Tables\Filter\InputTextFilter::class,
'value' => $get['title'] ?? ''
]
],
]
$table->beforePrint(function () {
return IconBtnCreateWidget::create(['url' => '/admin/{slug}/create'])->run();
});

View File

@ -1,9 +1,9 @@
// Responsive images (ensure images don't scale beyond their parents)
// Responsive default_user_photo (ensure default_user_photo don't scale beyond their parents)
//
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
// We previously tried the "default_user_photo are responsive by default" approach in Bootstrap v2,
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
// which weren't expecting the images within themselves to be involuntarily resized.
// which weren't expecting the default_user_photo within themselves to be involuntarily resized.
// See also https://github.com/twbs/bootstrap/issues/18178
.img-fluid {
@include img-fluid;

View File

@ -249,7 +249,7 @@ figure {
img {
vertical-align: middle;
border-style: none; // Remove the border on images inside links in IE 10-.
border-style: none; // Remove the border on default_user_photo inside links in IE 10-.
}
svg {

View File

@ -5,12 +5,12 @@
// Responsive image
//
// Keep images from scaling beyond the width of their parents.
// Keep default_user_photo from scaling beyond the width of their parents.
@mixin img-fluid {
// Part 1: Set a maximum relative to the parent
max-width: 100%;
// Part 2: Override the height to auto, otherwise images will be stretched
// Part 2: Override the height to auto, otherwise default_user_photo will be stretched
// when setting a width and height attribute on the img element.
height: auto;
}

View File

@ -1,9 +1,9 @@
// Responsive images (ensure images don't scale beyond their parents)
// Responsive default_user_photo (ensure default_user_photo don't scale beyond their parents)
//
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
// We previously tried the "default_user_photo are responsive by default" approach in Bootstrap v2,
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
// which weren't expecting the images within themselves to be involuntarily resized.
// which weren't expecting the default_user_photo within themselves to be involuntarily resized.
// See also https://github.com/twbs/bootstrap/issues/18178
.img-fluid {
@include img-fluid;

View File

@ -249,7 +249,7 @@ figure {
img {
vertical-align: middle;
border-style: none; // Remove the border on images inside links in IE 10-.
border-style: none; // Remove the border on default_user_photo inside links in IE 10-.
}
svg {

View File

@ -5,12 +5,12 @@
// Responsive image
//
// Keep images from scaling beyond the width of their parents.
// Keep default_user_photo from scaling beyond the width of their parents.
@mixin img-fluid {
// Part 1: Set a maximum relative to the parent
max-width: 100%;
// Part 2: Override the height to auto, otherwise images will be stretched
// Part 2: Override the height to auto, otherwise default_user_photo will be stretched
// when setting a width and height attribute on the img element.
height: auto;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

1
resources/out/404.html Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(r,e,t,_){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:5,errorRate:1e-4,numBits:96,numHashes:14,bitArray:[1,1,0,0,1,0,e,e,e,r,r,r,r,r,e,e,e,r,e,r,r,r,r,e,e,r,r,e,r,e,e,e,r,e,e,e,r,r,r,r,r,e,e,e,e,e,e,r,e,e,e,e,e,r,e,r,r,e,r,r,r,r,e,r,e,r,e,e,e,r,e,r,r,r,r,r,r,e,r,e,r,r,r,r,e,r,e,r,e,e,r,e,r,r,r,r]},__routerFilterDynamic:{numItems:2,errorRate:1e-4,numBits:39,numHashes:14,bitArray:[e,r,r,r,r,e,r,r,e,e,e,e,e,r,r,e,r,e,e,e,r,e,r,r,e,e,r,r,r,e,e,r,r,e,r,e,e,e,r]},"/_error":["static/chunks/pages/_error-4cc25812257ba5bd.js"],sortedPages:["/_app","/_error"]}}(1,0,0,0),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View File

@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set(["\u002Fevents\u002F[slug]","\u002Fparticipants\u002F[slug]"]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

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

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[492],{3868:(e,t,r)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/_not-found/page",function(){return r(5623)}])},3384:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"HTTPAccessErrorFallback",{enumerable:!0,get:function(){return o}}),r(306);let l=r(5155);r(2115);let n={error:{fontFamily:'system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"',height:"100vh",textAlign:"center",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},desc:{display:"inline-block"},h1:{display:"inline-block",margin:"0 20px 0 0",padding:"0 23px 0 0",fontSize:24,fontWeight:500,verticalAlign:"top",lineHeight:"49px"},h2:{fontSize:14,fontWeight:400,lineHeight:"49px",margin:0}};function o(e){let{status:t,message:r}=e;return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)("title",{children:t+": "+r}),(0,l.jsx)("div",{style:n.error,children:(0,l.jsxs)("div",{children:[(0,l.jsx)("style",{dangerouslySetInnerHTML:{__html:"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}),(0,l.jsx)("h1",{className:"next-error-h1",style:n.h1,children:t}),(0,l.jsx)("div",{style:n.desc,children:(0,l.jsx)("h2",{style:n.h2,children:r})})]})})]})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},5623:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return o}});let l=r(5155),n=r(3384);function o(){return(0,l.jsx)(n.HTTPAccessErrorFallback,{status:404,message:"This page could not be found."})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}},e=>{var t=t=>e(e.s=t);e.O(0,[441,517,358],()=>t(3868)),_N_E=e.O()}]);

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[706],{3062:(e,s,n)=>{Promise.resolve().then(n.bind(n,6919)),Promise.resolve().then(n.t.bind(n,8173,23)),Promise.resolve().then(n.t.bind(n,7970,23))},6919:(e,s,n)=>{"use strict";n.d(s,{default:()=>a});var l=n(5155),r=n(8173),t=n.n(r),i=n(6658);n(2115);let a=()=>{let e=(0,i.usePathname)().split("/").filter(e=>e),s={events:"мероприятия сообщества","event-1":"базовая программа подготовки гештальт-терапевтов - добор",participants:"участники",1:"кириллов кирилл кириллович"};return(0,l.jsx)("nav",{className:"max-w-[1032px] mx-auto",children:(0,l.jsxs)("ol",{className:"flex text-middleGrey font-[350] my-[50px]",children:[(0,l.jsx)("li",{children:(0,l.jsx)(t(),{href:"/",children:"главная"})}),e.map((n,r)=>{let i="/"+e.slice(0,r+1).join("/");return(0,l.jsx)("li",{children:(0,l.jsxs)(t(),{href:i,children:[(0,l.jsx)("span",{className:"mx-[2px]",children:"/"}),s[decodeURIComponent(n)]]})},i)})]})})}}},e=>{var s=s=>e(e.s=s);e.O(0,[742,441,517,358],()=>s(3062)),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[177],{5691:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,9324,23)),Promise.resolve().then(n.t.bind(n,8173,23)),Promise.resolve().then(n.t.bind(n,7970,23))},9324:()=>{}},e=>{var s=s=>e(e.s=s);e.O(0,[722,742,441,517,358],()=>s(5691)),_N_E=e.O()}]);

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[974],{6993:(e,t,r)=>{Promise.resolve().then(r.bind(r,5360)),Promise.resolve().then(r.bind(r,5416)),Promise.resolve().then(r.t.bind(r,8173,23)),Promise.resolve().then(r.t.bind(r,7970,23))},5360:(e,t,r)=>{"use strict";r.d(t,{default:()=>a});var n=r(5155);r(2115);let a=e=>{let{className:t,name:r,variant:a="default",size:l="default"}=e,o={default:"bg-blue text-[16px] text-white",secondary:"text-[16px] text-blue border-[1px] border-blue"},d={default:"max-h-[39px] px-[25px] py-[10px]"},s=o[a]||o.default,u=d[l]||d.default;return(0,n.jsx)("button",{className:"".concat("flex items-center justify-center whitespace-nowrap rounded-[6px] font-[400]"," ").concat(s," ").concat(u," ").concat(t),children:r})}},5416:(e,t,r)=>{"use strict";r.d(t,{default:()=>l});var n=r(5155);r(2115);var a=r(5565);let l=e=>{let{className:t,name:r,variant:l="default"}=e;return(0,n.jsxs)("div",{className:"".concat(t," ").concat({default:"px-[25px] py-[10px]",secondary:"px-[36px] py-[7px] bg-white"}[l]," max-w-[225px] min-w-[180px] justify-center w-fit cursor-pointer border-blue border-[1px] flex gap-[10px] rounded-[10px]"),children:[(0,n.jsx)("p",{className:"text-blue font-[700] text-[16px]",children:r}),(0,n.jsx)(a.default,{src:"/images/chevronDown.svg",alt:"chevronDown",width:11,height:8})]})}},5565:(e,t,r)=>{"use strict";r.d(t,{default:()=>a.a});var n=r(4146),a=r.n(n)},4146:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var r in t)Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}(t,{default:function(){return s},getImageProps:function(){return d}});let n=r(306),a=r(666),l=r(7970),o=n._(r(5514));function d(e){let{props:t}=(0,a.getImgProps)(e,{defaultLoader:o.default,imgConf:{deviceSizes:[640,750,828,1080,1200,1920,2048,3840],imageSizes:[16,32,48,64,96,128,256,384],path:"/_next/image",loader:"default",dangerouslyAllowSVG:!1,unoptimized:!1}});for(let[e,r]of Object.entries(t))void 0===r&&delete t[e];return{props:t}}let s=l.Image}},e=>{var t=t=>e(e.s=t);e.O(0,[742,441,517,358],()=>t(6993)),_N_E=e.O()}]);

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[731],{4585:(e,s,l)=>{Promise.resolve().then(l.bind(l,6919)),Promise.resolve().then(l.t.bind(l,7970,23))},6919:(e,s,l)=>{"use strict";l.d(s,{default:()=>a});var n=l(5155),r=l(8173),t=l.n(r),i=l(6658);l(2115);let a=()=>{let e=(0,i.usePathname)().split("/").filter(e=>e),s={events:"мероприятия сообщества","event-1":"базовая программа подготовки гештальт-терапевтов - добор",participants:"участники",1:"кириллов кирилл кириллович"};return(0,n.jsx)("nav",{className:"max-w-[1032px] mx-auto",children:(0,n.jsxs)("ol",{className:"flex text-middleGrey font-[350] my-[50px]",children:[(0,n.jsx)("li",{children:(0,n.jsx)(t(),{href:"/",children:"главная"})}),e.map((l,r)=>{let i="/"+e.slice(0,r+1).join("/");return(0,n.jsx)("li",{children:(0,n.jsxs)(t(),{href:i,children:[(0,n.jsx)("span",{className:"mx-[2px]",children:"/"}),s[decodeURIComponent(l)]]})},i)})]})})}}},e=>{var s=s=>e(e.s=s);e.O(0,[742,441,517,358],()=>s(4585)),_N_E=e.O()}]);

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

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[358],{4932:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,7033,23)),Promise.resolve().then(n.t.bind(n,4547,23)),Promise.resolve().then(n.t.bind(n,4835,23)),Promise.resolve().then(n.t.bind(n,2328,23)),Promise.resolve().then(n.t.bind(n,5244,23)),Promise.resolve().then(n.t.bind(n,3866,23)),Promise.resolve().then(n.t.bind(n,6213,23))}},e=>{var s=s=>e(e.s=s);e.O(0,[441,517],()=>(s(7200),s(4932))),_N_E=e.O()}]);

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[636],{1788:(_,n,p)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/_app",function(){return p(5203)}])}},_=>{var n=n=>_(_.s=n);_.O(0,[593,792],()=>(n(1788),n(4009))),_N_E=_.O()}]);

View File

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[112],{6194:(_,n,e)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/_error",function(){return e(6218)}])}},_=>{var n=n=>_(_.s=n);_.O(0,[636,593,792],()=>n(6194)),_N_E=_.O()}]);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={exports:{}},i=!0;try{e[o](a,a.exports,r),i=!1}finally{i&&delete t[o]}return a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(o){a=a||0;for(var i=e.length;i>0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[o,n,a];return}for(var u=1/0,i=0;i<e.length;i++){for(var[o,n,a]=e[i],l=!0,c=0;c<o.length;c++)(!1&a||u>=a)&&Object.keys(r.O).every(e=>r.O[e](o[c]))?o.splice(c--,1):(l=!1,a<u&&(u=a));if(l){e.splice(i--,1);var d=n();void 0!==d&&(t=d)}}return t}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var u=2&n&&o;"object"==typeof u&&!~e.indexOf(u);u=t(u))Object.getOwnPropertyNames(u).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>{},r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="_N_E:";r.l=(o,n,a,i)=>{if(e[o]){e[o].push(n);return}if(void 0!==a)for(var u,l,c=document.getElementsByTagName("script"),d=0;d<c.length;d++){var f=c[d];if(f.getAttribute("src")==o||f.getAttribute("data-webpack")==t+a){u=f;break}}u||(l=!0,(u=document.createElement("script")).charset="utf-8",u.timeout=120,r.nc&&u.setAttribute("nonce",r.nc),u.setAttribute("data-webpack",t+a),u.src=r.tu(o)),e[o]=[n];var s=(t,r)=>{u.onerror=u.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],u.parentNode&&u.parentNode.removeChild(u),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=s.bind(null,u.onerror),u.onload=s.bind(null,u.onload),l&&document.head.appendChild(u)}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:e=>e},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("nextjs#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="/_next/",(()=>{var e={68:0,722:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n){if(n)o.push(n[2]);else if(/^(68|722)$/.test(t))e[t]=0;else{var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),u=Error();r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;u.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",u.name="ChunkLoadError",u.type=a,u.request=i,n[1](u)}},"chunk-"+t,t)}}},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,[i,u,l]=o,c=0;if(i.some(t=>0!==e[t])){for(n in u)r.o(u,n)&&(r.m[n]=u[n]);if(l)var d=l(r)}for(t&&t(o);c<i.length;c++)a=i[c],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(d)},o=self.webpackChunk_N_E=self.webpackChunk_N_E||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})()})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

18
resources/out/events.txt 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

File diff suppressed because one or more lines are too long

BIN
resources/out/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 3.7 MiB

View File

@ -0,0 +1,3 @@
<svg width="9" height="7" viewBox="0 0 9 7" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.28321 5.95799C4.88285 6.46232 4.11715 6.46231 3.71679 5.95799L1.0243 2.56633C0.504041 1.91098 0.970754 0.944579 1.80751 0.944579L7.19249 0.94458C8.02925 0.94458 8.49596 1.91098 7.9757 2.56634L5.28321 5.95799Z" fill="#87BFFF"/>
</svg>

After

Width:  |  Height:  |  Size: 338 B

View File

@ -0,0 +1,4 @@
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 19.5C14.9706 19.5 19 15.4706 19 10.5C19 5.52944 14.9706 1.5 10 1.5C5.02944 1.5 1 5.52944 1 10.5C1 15.4706 5.02944 19.5 10 19.5Z" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 5.09998V10.5L13.6 12.3" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 448 B

View File

@ -0,0 +1,6 @@
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.3913 3.06525H3.6087C2.60018 3.06525 1.78261 3.88281 1.78261 4.89133V17.6739C1.78261 18.6825 2.60018 19.5 3.6087 19.5H16.3913C17.3998 19.5 18.2174 18.6825 18.2174 17.6739V4.89133C18.2174 3.88281 17.3998 3.06525 16.3913 3.06525Z" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.5213 1.5V5.41304" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.47861 1.5V5.41304" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.78261 8.54346H18.2174" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 773 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,4 @@
<svg width="17" height="21" viewBox="0 0 17 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.8636 8.86364C15.8636 14.5909 8.5 19.5 8.5 19.5C8.5 19.5 1.13637 14.5909 1.13637 8.86364C1.13637 6.91068 1.91218 5.03771 3.29313 3.65676C4.67408 2.27581 6.54705 1.5 8.5 1.5C10.453 1.5 12.3259 2.27581 13.7069 3.65676C15.0878 5.03771 15.8636 6.91068 15.8636 8.86364Z" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.4996 11.3182C9.85521 11.3182 10.9542 10.2193 10.9542 8.86366C10.9542 7.50806 9.85521 6.40912 8.4996 6.40912C7.144 6.40912 6.04506 7.50806 6.04506 8.86366C6.04506 10.2193 7.144 11.3182 8.4996 11.3182Z" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 760 B

View File

@ -0,0 +1,3 @@
<svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.64294 8.54805L11.0447 4.6533L12.3092 3.7878C12.9087 3.60138 12.8296 4.03191 12.7151 4.27048C11.6171 5.48551 9.13689 8.15192 8.00034 9.09731C6.86379 10.0427 7.52678 10.8117 8.00034 11.078C8.88501 11.6772 11.0665 13.1984 12.7151 14.49C14.3638 15.7816 15.0361 14.3181 15.1662 13.4248C15.7282 9.82965 16.8804 2.3231 16.9928 1.05814C17.1052 -0.20682 15.8739 -0.0792145 15.2443 0.142709L13.5426 0.825122C10.1079 2.3453 2.8047 5.59869 1.06865 6.45088C-0.66739 7.30306 0.0955118 7.90447 0.693968 8.09866L3.03575 8.84765C4.10985 9.35363 5.22142 8.85874 5.64294 8.54805Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 692 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="12" viewBox="0 0 20 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0.412C0.117879 0.129939 0.33851 0.0100359 0.630078 0.0095077C1.43645 0.00792308 2.24335 0.00633847 3.04972 0.0095077C3.39971 0.0110923 3.64642 0.193323 3.77942 0.509718C3.9625 0.944432 4.11689 1.39182 4.29632 1.82865C4.87371 3.23632 5.545 4.59275 6.48437 5.79494C6.66849 6.03105 6.89121 6.23758 7.10663 6.44675C7.18382 6.52175 7.28762 6.57722 7.38881 6.61683C7.6543 6.72194 7.83737 6.62264 7.89005 6.33635C7.92291 6.15676 7.93126 5.97084 7.9323 5.78755C7.93595 4.76653 7.93387 3.74498 7.93439 2.72396C7.93439 2.10437 7.76904 1.54342 7.36481 1.06539C7.28501 0.970842 7.20677 0.871011 7.14679 0.763257C6.97206 0.450031 7.13792 0.0913796 7.48634 0.0206C7.56875 0.00369744 7.65429 0.00105641 7.73879 0.00105641C8.819 0 9.89869 0 10.9789 0C11.0311 0 11.0832 0.00105641 11.1348 0.00581026C11.4713 0.0338052 11.6377 0.197549 11.669 0.541939C11.682 0.686139 11.683 0.831396 11.683 0.976124C11.6841 2.294 11.683 3.61187 11.6846 4.92921C11.6846 5.05387 11.6914 5.17958 11.7081 5.30318C11.7602 5.69881 12.0299 5.85569 12.3548 5.62856C12.6772 5.40302 12.9813 5.13257 13.2384 4.83308C14.1048 3.82262 14.7583 2.66955 15.3425 1.47528C15.4838 1.18688 15.6116 0.891611 15.7446 0.598985C15.9121 0.231354 16.1869 0.0121487 16.5927 0.0095077C17.4189 0.00422565 18.2451 0 19.0708 0.0211282C19.474 0.0316923 19.6503 0.292626 19.5606 0.691421C19.5162 0.88897 19.4651 1.0918 19.3738 1.26981C19.0724 1.85876 18.7798 2.45616 18.4313 3.01658C17.8743 3.91295 17.2818 4.78713 16.6908 5.66184C16.2694 6.28565 16.2866 6.44728 16.8029 7.00295C17.6004 7.86128 18.3927 8.7249 19.16 9.61123C19.4312 9.92446 19.6534 10.2921 19.8422 10.6645C20.2026 11.3744 19.9345 11.8043 19.1506 11.8138C18.4543 11.8223 17.758 11.8096 17.0622 11.8181C16.6585 11.8228 16.3262 11.6718 16.0513 11.386C15.7107 11.0326 15.3769 10.6719 15.0441 10.3106C14.497 9.7174 13.9217 9.15433 13.2603 8.69109C12.939 8.46608 12.6052 8.26114 12.1879 8.27592C11.8703 8.28702 11.7373 8.39847 11.7133 8.72437C11.6903 9.03284 11.6804 9.34237 11.6778 9.6519C11.6736 10.113 11.6893 10.5747 11.6809 11.0353C11.6742 11.424 11.5255 11.6343 11.15 11.7056C10.7885 11.7742 10.4151 11.8096 10.0479 11.8065C8.59837 11.7938 7.30431 11.2846 6.11092 10.4854C4.96603 9.71898 4.05482 8.71751 3.27192 7.58398C2.12077 5.91749 1.10316 4.17863 0.416227 2.25966C0.250884 1.79854 0.137177 1.3184 0 0.846714C0 0.701985 0 0.556729 0 0.412Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.0004 13.5994C11.9886 13.5994 13.6004 11.9876 13.6004 9.99941C13.6004 8.01119 11.9886 6.39941 10.0004 6.39941C8.01216 6.39941 6.40039 8.01119 6.40039 9.99941C6.40039 11.9876 8.01216 13.5994 10.0004 13.5994Z" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.6 6.39944V10.8994C13.6 11.6155 13.8845 12.3023 14.3908 12.8086C14.8972 13.315 15.5839 13.5994 16.3 13.5994C17.0161 13.5994 17.7028 13.315 18.2092 12.8086C18.7155 12.3023 19 11.6155 19 10.8994V9.99944C18.9999 7.96816 18.3126 5.99667 17.0499 4.40552C15.7873 2.81437 14.0235 1.69714 12.0454 1.23551C10.0673 0.773874 7.99115 0.994979 6.15462 1.86287C4.31809 2.73076 2.82917 4.1944 1.92994 6.01579C1.03071 7.83718 0.774078 9.9092 1.20176 11.8949C1.62944 13.8807 2.71629 15.6633 4.28557 16.9531C5.85486 18.2428 7.81429 18.9637 9.84527 18.9987C11.8762 19.0336 13.8593 18.3804 15.472 17.1454" stroke="#6D6D6D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.7 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.7 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 37 KiB

Some files were not shown because too many files have changed in this diff Show More