5 Commits
1.1.0 ... 1.6.0

83 changed files with 3494 additions and 1136 deletions

View File

@@ -32,7 +32,9 @@
"twig/twig": "^3.2",
"twig/extra-bundle": "^3.7",
"twig/intl-extra": "^3.10",
"phpmailer/phpmailer": "^7.0"
"phpmailer/phpmailer": "^7.0",
"mirzaev/record": "^2.2",
"svoboda/time": "^1.0"
},
"suggest": {
"mirzaev/files": "Easy working with files",

77
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3d3b850ebd1027cf1790dfa901746eab",
"content-hash": "15ac0ce9a39edb330d95b578175d5636",
"packages": [
{
"name": "mirzaev/baza",
@@ -141,6 +141,48 @@
},
"time": "2026-04-17T06:08:04+00:00"
},
{
"name": "mirzaev/record",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://git.svoboda.works/mirzaev/record",
"reference": "71360614d6cbab0fe33ec0feca15005ca913397a"
},
"require": {
"mirzaev/baza": "^3.4",
"php": "^8.4",
"svoboda/time": "^1.0"
},
"type": "pattern",
"autoload": {
"psr-4": {
"mirzaev\\record\\": "mirzaev/record/system"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"WTFPL"
],
"authors": [
{
"name": "Arsen Mirzaev Tatyano-Muradovich",
"email": "arsen@mirzaev.sexy",
"homepage": "https://mirzaev.sexy",
"role": "Creator"
}
],
"description": "Active Record pattern for Baza",
"homepage": "https://git.svoboda.works/mirzaev/record",
"keywords": [
"baza"
],
"support": {
"issues": "https://git.svoboda.works/mirzaev/record/issues",
"wiki": "https://git.svoboda.works/mirzaev/record/wiki"
},
"time": "2026-03-08T18:23:49+00:00"
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "4.8.10",
@@ -540,6 +582,39 @@
},
"time": "2021-10-29T13:26:27+00:00"
},
{
"name": "svoboda/time",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://git.svoboda.works/svoboda/time",
"reference": "0764960606d56a9f0865ebb07671d30a7d232b6a"
},
"require": {
"php": "^8.4"
},
"type": "library",
"autoload": {
"psr-4": {
"svoboda\\time\\": "svoboda/time/system"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"WTFPL"
],
"authors": [
{
"name": "Arsen Mirzaev Tatyano-Muradovich",
"email": "arsen@mirzaev.sexy",
"homepage": "https://mirzaev.sexy",
"role": "Programmer"
}
],
"description": "Time since Svoboda was created",
"homepage": "https://git.svoboda.works/svoboda/time",
"time": "2025-02-02T11:04:25+00:00"
},
{
"name": "symfony/cache",
"version": "v8.0.8",

View File

@@ -195,79 +195,62 @@ final class index extends core
'site' => 'Сайт',
'chat_robot' => 'Чат-робот',
'program' => 'Программа',
'module' => 'Модуль',
'parser' => 'Парсер',
'script' => 'Скрипт',
'game' => 'Видеоигра',
/* 'site' => 'Сайты и браузерные расширения',
'chat_robot' => 'Чат-роботы (любой мессенджер)',
'program' => 'Программа (Android, iOS, Windows)',
'module' => 'Модуль для любой программы',
'parser' => 'Парсер данных API, HTTP и эмуляция',
'script' => 'Скрипт (автоматизация процессов)',
'game' => 'Видеоигра (Android, iOS, Windows)' */
'script' => 'Скрипт, парсер, макрос',
'module' => 'Модуль, плагин, расширение',
],
'purposes' => [
'funnel' => 'Воронка',
'contacts' => 'Контакты',
'neural_network' => 'Нейросети',
'gallery' => 'Галерея',
'crm' => 'CRM',
'landing' => 'Лендинг',
'marketplace' => 'Маркетплейс',
'search' => 'Поиск',
'calculate' => 'Расчёты',
'logic' => 'Логика',
'game' => гра',
'special' => 'Особенный',
'funnel' => 'Воронка (обработка пользователя)',
'contacts' => 'Контакты (сбор данных)',
'ai' => 'Внедрение ИИ',
'archive' => 'Архив (галерея, библиотека, реестр)',
'crm' => 'Индивидуальная CRM',
'landing' => 'Лендинг (посадочная страница)',
'marketplace' => 'Маркетплейс, магазин, витрина',
'saas' => 'SaaS проект',
'search' => 'Поиск и анализ',
'calculate' => 'Вычисления (калькулятор)',
'individual' => ндивидуальная разработка',
],
'integrations' => [
'one_c' => '1C',
'bitrix24' => 'Битрикс24',
'moy_sklad' => 'Мой Склад',
'telegram' => 'Телеграм',
'mail' => 'Почта',
'excel' => 'Excel'
]
];
// Initializing contacts data
$this->view->contacts = [
'sim' => [
'requests' => [
'full' => PROJECT_CONTACTS_SIM_REQUESTS ?? 'Ошибка',
'country' => PROJECT_CONTACTS_SIM_REQUESTS_COUNTRY ?? 'Ошибка',
'operator' => PROJECT_CONTACTS_SIM_REQUESTS_OPERATOR ?? 'Ошибка',
'number' => [
PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_1 ?? 'Ошибка',
PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_2 ?? 'Ошибка',
PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_3 ?? 'Ошибка'
]
]
'excel' => 'Excel',
'ozon' => 'OZON',
'wildberries' => 'Wildberries',
'yandex_market' => 'Яндекс Маркет',
'avito' => 'Авито',
'vk' => 'ВКонтакте',
'max' => 'МАКС',
'telegram' => 'Телеграм',
'neural_networks' => 'Нейросети'
]
];
// Initializing contacts data
$this->view->integrations = [
'Вайлдберриз' => 'wildberries',
'ОЗОН' => 'ozon',
'Мой Склад' => 'moy_sklad',
'1С Предприятие' => '1c',
'Битрикс 24' => 'bitrix24',
'ВКонтакте' => 'vk',
'МАКС' => 'max',
/* 'yandex_direct', */
'Яндекс Директ' => 'yandex_market',
'ОЗОН' => 'ozon',
'Вайлдберриз' => 'wildberries',
'Авито' => 'avito',
'YClients' => 'yclients',
'ЮКасса' => 'yookassa',
'OpenAI' => 'openai'
'OpenAI' => 'openai',
/* 'yandex_direct', */
'Яндекс Директ' => 'yandex_market',
];
// Render page
$page = $this->view->render(
'main/index.html',
'pages/index.html',
[
'uri' => 'https://' . DOMAIN,
'smartphone' => $this->request->smartphone,
'tablet' => $this->request->tablet
]

View File

@@ -44,26 +44,11 @@ final class offer extends core
if (str_contains($this->request->headers['accept'] ?? '', content::html->value)) {
// Request for HTML response
// Initializing contacts data
$this->view->contacts = [
'sim' => [
'requests' => [
'full' => PROJECT_CONTACTS_SIM_REQUESTS ?? 'Ошибка',
'country' => PROJECT_CONTACTS_SIM_REQUESTS_COUNTRY ?? 'Ошибка',
'operator' => PROJECT_CONTACTS_SIM_REQUESTS_OPERATOR ?? 'Ошибка',
'number' => [
PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_1 ?? 'Ошибка',
PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_2 ?? 'Ошибка',
PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_3 ?? 'Ошибка'
]
]
]
];
// Render page
$page = $this->view->render(
'main/offer.html',
'pages/offer.html',
[
'uri' => 'https://' . DOMAIN . '/offer',
'smartphone' => $this->request->smartphone,
'tablet' => $this->request->tablet
]

View File

@@ -83,20 +83,20 @@ final class project extends core
$mail->setLanguage('ru');
$mail->CharSet = mail::CHARSET_UTF8;
$mail->isSMTP();
$mail->Host = 'smtp.mail.ru';
$mail->Host = MAIL['host'];
$mail->SMTPAuth = true;
$mail->Username = 'system@kodorvan.tech';
$mail->Password = 'c6oQF2nY0javI312eDS0';
$mail->Username = MAIL['sender']['mail'];
$mail->Password = MAIL['sender']['password'];
$mail->SMTPSecure = mail::ENCRYPTION_SMTPS;
$mail->Port = 465;
$mail->setFrom('system@kodorvan.tech', 'Система');
$mail->addAddress('request@kodorvan.tech', 'Заявки');
$mail->setFrom(MAIL['sender']['mail'], MAIL['sender']['name']);
$mail->addAddress(MAIL['receiver']['mail'], MAIL['receiver']['name']);
// The message
$mail->isHTML(true);
$mail->Subject = empty($request['project']['name']) ? 'Заказ' : 'Заказ: ' . $request['project']['name'];
$mail->Body = $this->view->render('messages/request.html', $request);
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
/* $mail->AltBody = 'This is the body in plain text for non-HTML mail clients'; */
// Attachments
foreach ($files as $name => $file) {

View File

@@ -0,0 +1,184 @@
<?php
declare(strict_types=1);
namespace kodorvan\site\controllers;
// Files of the project
use kodorvan\site\controllers\core,
kodorvan\site\models\superpack as model;
// Framework for PHP
use mirzaev\minimal\http\enumerations\content,
mirzaev\minimal\http\enumerations\method,
mirzaev\minimal\http\enumerations\status;
// Baza database
use mirzaev\baza\database,
mirzaev\baza\column,
mirzaev\baza\record,
mirzaev\baza\enumerations\encoding,
mirzaev\baza\enumerations\type;
/**
* Offer
*
* @package kodorvan\site\controllers
*
* @param array $errors Registry of errors
*
* @method null index() Main page
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class superpack extends core
{
/**
* Errors
*
* @var array $errors Registry of errors
*/
protected array $errors = [
'system' => []
];
/**
* Page: superpack
*
* @return null
*/
public function index(string $urn): null
{
if (str_contains($this->request->headers['accept'] ?? '', content::html->value)) {
// Request for HTML response
// Initializing the superpack
$superpack = new model()->read(filter: fn(record $record) => $record->urn === $urn && $record->active === 1);
if ($superpack instanceof model) {
// Initialized the superpack
// Render page
$page = $this->view->render(
'pages/article.html',
[
'uri' => 'https://' . DOMAIN . "/superpack/$urn",
'article' => [
'urn' => $superpack->urn,
'title' => $superpack->title,
'html' => $superpack->html
],
'smartphone' => $this->request->smartphone,
'tablet' => $this->request->tablet
]
);
} else {
// Not initialized the superpack
}
// Sending response
$this->response
->start()
->clean()
->sse()
->write($page)
->validate($this->request)
?->body()
->end();
// Deinitializing rendered page
unset($page);
// Exit (success)
return null;
}
// Exit (fail)
return null;
}
/**
* Page: superpack
*
* @return null
*/
public function create(
?string $identifier = null,
?string $urn = null,
?string $title = null,
?string $html = null,
?string $text = null,
string|int|float|null $supercost = null
): null {
if ($this->request->method === method::get) {
// GET
if (str_contains($this->request->headers['accept'] ?? '', content::html->value)) {
// Request for HTML response
// Render page
$page = $this->view->render(
'pages/system/superpack/create.html',
[
'uri' => 'https://' . DOMAIN . "/system/superpack/create",
'smartphone' => $this->request->smartphone,
'tablet' => $this->request->tablet
]
);
// Sending response
$this->response
->start()
->clean()
->sse()
->write($page)
->validate($this->request)
?->body()
->end();
// Deinitializing rendered page
unset($page);
// Exit (success)
return null;
}
} else if ($this->request->method === method::put) {
// PUT
// Initializing the superpack
$superpack = new model()->read(filter: fn(record $record) => $record->urn === $urn);
if ($superpack instanceof model) {
// The superpack is already created
} else {
// The superpack is not already created
// Sanitizing
$urn = preg_replace('/[^\w\d\-.]+/', '', $urn);
$title = preg_replace('/[^\w\d\s\-.,!]+/u', '', $title);
$supercost = (float) preg_replace('/[^\d.]+/', '', $supercost);
// Creating the superpack
$superpack = new model()->write(
urn: $urn,
title: $title,
html: $html,
text: $text,
supercost: $supercost
);
if ($superpack instanceof record) {
// Created the superpack
// Sending redirect to the superpack
header('Location: /superpack/' . $urn);
}
}
}
// Exit (fail)
return null;
}
}

View File

@@ -0,0 +1,215 @@
<?php
declare(strict_types=1);
namespace kodorvan\site\models;
// Files of the project
use kodorvan\site\models\core;
// Baza database
use mirzaev\baza\database,
mirzaev\baza\column,
mirzaev\baza\record,
mirzaev\baza\enumerations\encoding,
mirzaev\baza\enumerations\type;
// Active Record pattern
use mirzaev\record\interfaces\record as record_interface,
mirzaev\record\traits\record as record_trait;
// Svoboda time
use svoboda\time\statement as svoboda;
// Built-in libraries
use Exception as exception,
LogicException as exception_logic,
RuntimeException as exception_runtime;
/**
* Project
*
* @package kodorvan\site\models
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class superpack extends core implements record_interface
{
use record_trait;
/**
* File
*
* @var string $file Path to the database file
*/
protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'superpacks.baza';
/**
* Database
*
* @var database $database The database
*/
public protected(set) database $database;
/**
* Serialized
*
* @var bool $serialized Is the implementator object serialized?
*/
private bool $serialized = true;
/**
* Constructor
*
* @method record|null $record The record
*
* @return void
*/
public function __construct(?record $record = null)
{
// Initializing the database
$this->database = new database()
->encoding(encoding::utf8)
->columns(
new column('identifier', type::long_long_unsigned),
/* new column('account', type::long_long_unsigned), */
new column('urn', type::string, ['length' => 64]),
new column('title', type::string, ['length' => 128]),
new column('html', type::string, ['length' => 8192]),
new column('text', type::string, ['length' => 8192]),
new column('supercost', type::float),
new column('active', type::char),
new column('updated', type::integer_unsigned),
new column('created', type::integer_unsigned)
)
->connect($this->file);
// Initializing the record
$record instanceof record and $this->record = $record;
}
/**
* Write
*
* @throws exception_logic when failed to process project integration
*
* @param int $account The account identifier
* @param string $urn URN
* @param string $title Title
* @param string|null $html Content (HTML)
* @param string|null $html Content (text)
* @param int|float|null $supercost Cost
* @param int $active Is the record active?
*
* @return record|false The record, if created
*/
public function write(
/* int $account, */
string $urn,
string $title,
?string $html = null,
?string $text = null,
int|float|null $supercost = null,
bool $active = true,
): record|false {
if (!empty($html) || !empty($text)) {
// Initializing the record
$record = $this->database->record(
$this->database->count() + 1,
/* $account, */
$urn,
$title,
(string) $html,
(string) $text,
(float) $supercost,
(int) $active,
svoboda::timestamp(),
svoboda::timestamp()
);
// Writing the record into the database
$created = $this->database->write($record);
// Exit (success)
return $created ? $record : false;
}
// Exit (fail)
return false;
}
/**
* Serialize
*
* @return self The instance from which the method was called (fluent interface)
*/
public function serialize(): self
{
if ($this->serialized) {
// The record implementor is serialized
// Exit (fail)
throw new exception_runtime('The record implementor is already serialized');
}
// Serializing the record parameters
$this->record->active = (int) $this->record->active;
// Writing the status of serializing
$this->serialized = true;
// Exit (success)
return $this;
}
/**
* Deserialize
*
* @return self The instance from which the method was called (fluent interface)
*/
public function deserialize(): self
{
if (!$this->serialized) {
// The record implementor is deserialized
// Exit (fail)
throw new exception_runtime('The record implementor is already deserialized');
}
// Deserializing the record parameters
$this->record->active = (bool) $this->record->active;
// Writing the status of serializing
$this->serialized = false;
// Exit (success)
return $this;
}
/**
* Account
*
* Search for the account
*
* @return account|null The account
*/
/* public function account(): ?account
{
// Search for the account
$account = new account()->read(filter: fn(record $record) => $record->identifier === $this->account && $record->active === 1);
if ($account instanceof account) {
// Found the account account
// Deserializing the record
$account->deserialize();
// Exit (success)
return $account;
}
// Exit (fail)
return null;
} */
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,71 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="129.54482mm"
height="125.09652mm"
viewBox="0 0 129.54482 125.09652"
version="1.1"
id="svg1"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient3">
<stop
style="stop-color:#0060c6;stop-opacity:1;"
offset="0.20645721"
id="stop3" />
<stop
style="stop-color:#000356;stop-opacity:1;"
offset="0.9989059"
id="stop4" />
</linearGradient>
<linearGradient
id="linearGradient1">
<stop
style="stop-color:#6fc4ff;stop-opacity:1;"
offset="0.17076893"
id="stop1" />
<stop
style="stop-color:#0adf70;stop-opacity:0.63586265;"
offset="1"
id="stop2" />
</linearGradient>
<radialGradient
xlink:href="#linearGradient3"
id="radialGradient4"
cx="69.684677"
cy="90.595695"
fx="69.684677"
fy="90.595695"
r="49.385239"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.4657787,-0.63256258,0.71685408,1.6610996,-96.020968,-9.4714476)" />
<radialGradient
xlink:href="#linearGradient1"
id="radialGradient8"
cx="133.0006"
cy="106.39822"
fx="133.0006"
fy="106.39822"
r="64.772408"
gradientTransform="matrix(-2.5562072,0.53679846,-0.45438206,-2.1637443,446.93777,196.26702)"
gradientUnits="userSpaceOnUse" />
</defs>
<path
style="display:inline;fill:url(#radialGradient4);fill-opacity:0.983988;fill-rule:nonzero;stroke-width:2.22122;paint-order:stroke fill markers"
id="path2"
d="M 114.14959,66.009985 A 49.385239,49.385239 0 0 1 65.162476,115.39362 49.385239,49.385239 0 0 1 15.38553,66.806211 49.385239,49.385239 0 0 1 63.570075,16.639189 49.385239,49.385239 0 0 1 114.12391,64.41774" />
<path
id="path1"
style="display:inline;fill:url(#radialGradient8);stroke-width:2.64583;paint-order:stroke fill markers"
d="m 129.54482,60.324142 c 0,35.56901 -28.68229,64.483468 -64.250152,64.770218 C 29.72681,125.38111 0.58206084,96.932842 0.00858984,61.368452 -0.27814616,43.586256 6.6315828,27.351873 18.057823,15.455519 L 32.789578,50.834474 64.751888,64.645522 63.781478,106.2899 99.850468,58.627162 73.743498,34.999493 88.406328,0 c 7.79332,3.057143 14.862732,7.58429 20.856772,13.249271 5.99404,5.664982 10.91271,12.467797 14.40455,20.076274 3.49183,7.608477 5.55683,16.022617 5.84353,24.910247" />
<path
id="path5"
style="display:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="m 156.03189,48.675988 c 0,0 -0.48124,1.149734 -0.48124,1.149734 7.47158,3.127366 13.76035,8.757556 18.60133,15.033917 3.47372,4.503708 5.77328,8.679785 8.08747,12.343411 1.02716,1.626109 1.99256,3.317001 2.88786,5.073729 5.57385,10.936769 8.27496,24.254811 6.33597,38.307871 -1.81681,13.16752 -7.63944,25.96117 -17.4307,35.65948 -5.03375,4.98596 -10.97996,9.0142 -17.69827,11.85196 -7.22782,3.05296 -15.1235,4.63388 -23.42167,4.73245 -0.85262,0.0108 -1.69223,0.004 -2.51863,-0.0189 -14.1633,-0.39672 -25.57791,-5.05285 -34.17105,-11.0133 C 85.038155,154.03818 77.884734,143.64417 73.765338,134.02513 68.088136,120.76851 67.595266,108.31489 69.031333,98.509565 70.913466,85.658549 76.262275,76.52398 79.737684,71.524371 c 3.696594,-5.317797 5.945701,-7.392864 5.945701,-7.392864 0,0 -2.33932,1.972559 -6.214586,7.199789 -3.636021,4.904518 -9.303495,13.993979 -11.461258,27.018426 -1.64637,9.937638 -1.344521,22.656968 4.328486,36.278968 4.114552,9.87985 11.373099,20.61326 22.855995,28.64738 8.830228,6.17816 20.582878,10.99648 35.149578,11.4045 0.84878,0.0238 1.71085,0.0347 2.58621,0.0316 8.48799,-0.0368 16.67375,-1.34049 24.38977,-4.07858 7.17719,-2.54687 13.78867,-6.28188 19.64994,-11.14174 11.39583,-9.44885 19.35723,-22.68375 22.78331,-37.34635 3.64637,-15.60541 1.86385,-31.494338 -4.58101,-44.839852 -1.02738,-2.127422 -2.16303,-4.170709 -3.39713,-6.124429 -2.75251,-4.35753 -6.99513,-8.511352 -12.19307,-12.129511 -7.56806,-5.267932 -15.28231,-8.267232 -23.06649,-11.525444 0,0 -0.48124,1.149734 -0.48124,1.149734 z"
transform="translate(-67.625562,-48.675988)" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="489.618" height="472.806" viewBox="0 0 129.545 125.097"><defs><radialGradient xlink:href="#a" id="c" cx="69.685" cy="90.596" r="49.385" fx="69.685" fy="90.596" gradientTransform="matrix(1.46578 -.63256 .71685 1.6611 -96.021 -9.471)" gradientUnits="userSpaceOnUse"/><radialGradient xlink:href="#b" id="d" cx="133.001" cy="106.398" r="64.772" fx="133.001" fy="106.398" gradientTransform="matrix(-2.5562 .5368 -.45438 -2.16374 446.938 196.267)" gradientUnits="userSpaceOnUse"/><linearGradient id="a"><stop offset=".206" style="stop-color:#0060c6;stop-opacity:1"/><stop offset=".999" style="stop-color:#000356;stop-opacity:1"/></linearGradient><linearGradient id="b"><stop offset=".171" style="stop-color:#6fc4ff;stop-opacity:1"/><stop offset="1" style="stop-color:#0adf70;stop-opacity:.63586265"/></linearGradient></defs><path d="M114.15 66.01a49.385 49.385 0 0 1-48.988 49.384 49.385 49.385 0 0 1-49.776-48.588A49.385 49.385 0 0 1 63.57 16.64a49.385 49.385 0 0 1 50.554 47.779" style="display:inline;fill:url(#c);fill-opacity:.983988;fill-rule:nonzero;stroke-width:2.22122;paint-order:stroke fill markers"/><path d="M129.545 60.324c0 35.57-28.682 64.484-64.25 64.77S.582 96.933.009 61.368c-.287-17.782 6.623-34.016 18.049-45.912L32.79 50.834l31.962 13.812-.97 41.644L99.85 58.627 73.743 35 88.406 0a64.9 64.9 0 0 1 20.857 13.25 64.9 64.9 0 0 1 14.405 20.076 64.6 64.6 0 0 1 5.843 24.91" style="display:inline;fill:url(#d);stroke-width:2.64583;paint-order:stroke fill markers"/></svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -47,6 +47,13 @@ $core = new core(namespace: __NAMESPACE__);
$core->router
->write('/', new route('index', 'index'), 'GET')
->write('/offer', new route('offer', 'index'), 'GET')
->write('/policy', new route('policy', 'index'), 'GET')
->write('/recomendations', new route('recomendations', 'index'), 'GET')
->write('/system/superpack/create', new route('superpack', 'create'), 'GET')
->write('/system/superpack/create', new route('superpack', 'create'), 'PUT')
->write('/superpack/$urn', new route('superpack', 'index'), 'GET')
->write('/project/request', new route('project', 'request'), 'PUT')
;

View File

@@ -10,15 +10,26 @@
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class core {
/**
* @name Global modules
*
* @type {object}
*/
static global = {};
/**
* @name System modules
*
* @type {object}
*/
static system = {};
// Domain
static domain = window.location.hostname;
// Language
static language = "ru";
// Theme
static theme = window.getComputedStyle(document.getElementById('theme'));
// Window
static window;
@@ -128,7 +139,7 @@ class core {
*
* @return {void}
*/
/* static choose = core.damper(
/* static choose = core.global.damper(
(
title = "Выбор действия",
text = "",
@@ -302,32 +313,50 @@ Object.assign(
/**
* @name Connect modules
*
* @param {(Array|string)} modules Names of modules without extension (`.mjs` only)
* @param {(Array|string)} global Names of global modules without extension (`.mjs` only)
* @param {(Array|string)} system Names of system modules without extenstion (`.mjs` only)
*
* @return {Promise}
*/
async connect(modules) {
async connect(global, system) {
// Normalisation required arguments
if (typeof modules === "string") modules = [modules];
if (modules instanceof Array) {
// Received and validated required arguments
if (typeof global === "string") global = [global];
if (typeof system === "string") system = [system];
// Initializing the registry of connected modules
const connected = [];
const connected = {
system: [],
global: []
};
for (const module of modules) {
// Iterating over modules
if (global?.length > 0) {
// Global
// Downloading, importing and writing the module into a core property and into registry of connected modules
core[module] =
connected[module] =
for (const module of global) {
// Iterating over global modules
// Downloading, importing and writing the global module into a core property and into registry of connected modules
core.global[module] =
connected.global[module] =
await (await import(`./modules/${module}.mjs`)).default;
}
}
if (system?.length > 0) {
// System
for (const module of system) {
// Iterating over system modules
// Downloading, importing and writing the system module into a core property and into registry of connected modules
core.system[module] =
connected.system[module] =
await (await import(`./modules/system/${module}.mjs`)).default;
}
}
// Exit (success)
return connected;
}
},
},
);
@@ -350,7 +379,7 @@ core.modules.connect("damper").then(() => {
*
* @return {Promise}
*/
damper: core.damper(
damper: core.global.damper(
(...variables) => core.buffer.write.system(...variables),
300,
2,

View File

@@ -72,6 +72,37 @@ export default class paginator {
*/
#page = 1;
/**
* @name Page (get)
*
* @return {number}
*
* @public
*/
get page() {
return this.#page;
}
/**
* @name The initial page
*
* @type {number}
*
* @protected
*/
#initial = 1;
/**
* @name The initial page (get)
*
* @return {number}
*
* @public
*/
get initial() {
return this.#initial;
}
/**
* @name Constructor
*
@@ -79,16 +110,14 @@ export default class paginator {
* Initialize a hotline instance
*
* @param {HTMLElement} shell The shell element
* @param {NodeList} pages
* @param {Set} hide_on_the_first_page HTML-elements that will be hidden on the first page
* @param {Set} hide_on_the_last_page HTML-elements that will be hidden on the last page
* @param {NodeList} pages The pages HTML-elements list
* @param {number} initial The initial page identifier
* @param {boolean} [inject=false] Write the hotline instance into the shell element?
**/
constructor(
shell,
pages,
hide_on_the_first_page,
hide_on_the_last_page,
initial,
inject = false
) {
if (shell instanceof HTMLElement) {
@@ -102,11 +131,18 @@ export default class paginator {
}
if (pages instanceof NodeList) {
// Initialized pages
// Initialized the pages HTML-elements list
// Writing the pages
// Writing the pages HTML-elements list
this.#pages = pages;
}
if (typeof initial === 'number') {
// Initialized the initial page identifier
// Writing the initial page identifier
this.#page = this.#initial = initial;
}
}
/**

View File

@@ -340,18 +340,46 @@ export default class project {
symbol: Symbol("moy_sklad"),
coefficient: 3
},
telegram: {
symbol: Symbol("telegram"),
coefficient: 2
},
mail: {
symbol: Symbol("mail"),
coefficient: 1.4
},
excel: {
symbol: Symbol("excel"),
coefficient: 1.6
}
coefficient: 1.8
},
ozon: {
symbol: Symbol("ozon"),
coefficient: 2.8
},
wildberries: {
symbol: Symbol("wildberries"),
coefficient: 2.9
},
yandex_market: {
symbol: Symbol("yandex_market"),
coefficient: 2.6
},
avito: {
symbol: Symbol("avito"),
coefficient: 2.4
},
vk: {
symbol: Symbol("vk"),
coefficient: 2
},
max: {
symbol: Symbol("max"),
coefficient: 2
},
telegram: {
symbol: Symbol("telegram"),
coefficient: 2
},
neural_networks: {
symbol: Symbol("neural_networks"),
coefficient: 2.6
},
});
/**
@@ -399,33 +427,49 @@ export default class project {
* @protected
*/
#purposes = Object.freeze({
project: {
symbol: Symbol("project"),
funnel: {
symbol: Symbol("funnel"),
integrations: new Set([
this.services.telegram,
this.services.max,
this.services.vk,
this.services.mail,
this.services.bitrix24
this.services.bitrix24,
this.services.neural_networks,
]),
coefficient: 2.1
coefficient: 1.2
},
contact: {
symbol: Symbol("contact"),
contacts: {
symbol: Symbol("contacts"),
integrations: new Set([
this.services.telegram,
this.services.max,
this.services.vk,
this.services.mail,
this.services.bitrix24
this.services.bitrix24,
this.services.neural_networks,
]),
coefficient: 1.1
},
neural_network: {
symbol: Symbol("neural_network"),
ai: {
symbol: Symbol("ai"),
integrations: new Set([
this.services.telegram
this.services.telegram,
this.services.max,
this.services.vk,
this.services.one_c,
this.services.bitrix24,
this.services.excel,
this.services.mail,
this.services.ozon,
this.services.wildberries,
this.services.avito,
this.services.yandex_market,
]),
coefficient: 4
coefficient: 3
},
gallery: {
symbol: Symbol("gallery"),
archive: {
symbol: Symbol("archive"),
integrations: new Set([
]),
coefficient: 1
@@ -433,9 +477,16 @@ export default class project {
crm: {
symbol: Symbol("crm"),
integrations: new Set([
this.services.telegram,
this.services.max,
this.services.vk,
this.services.one_c,
this.services.moy_sklad,
this.services.excel
this.services.excel,
this.services.ozon,
this.services.wildberries,
this.services.avito,
this.services.yandex_market,
]),
coefficient: 6
},
@@ -443,8 +494,10 @@ export default class project {
symbol: Symbol("landing"),
integrations: new Set([
this.services.telegram,
this.services.max,
this.services.vk,
this.services.mail,
this.services.bitrix24
this.services.bitrix24,
]),
coefficient: 1.5
},
@@ -453,13 +506,40 @@ export default class project {
integrations: new Set([
this.services.one_c,
this.services.moy_sklad,
this.services.excel
this.services.excel,
this.services.ozon,
this.services.wildberries,
this.services.avito,
this.services.yandex_market,
]),
coefficient: 8
},
saas: {
symbol: Symbol("saas"),
integrations: new Set([
this.services.telegram,
this.services.max,
this.services.vk,
this.services.one_c,
this.services.moy_sklad,
this.services.excel,
this.services.ozon,
this.services.wildberries,
this.services.avito,
this.services.yandex_market,
]),
coefficient: 8
},
search: {
symbol: Symbol("search"),
integrations: new Set([
this.services.telegram,
this.services.max,
this.services.vk,
this.services.ozon,
this.services.wildberries,
this.services.avito,
this.services.yandex_market,
]),
coefficient: 1
},
@@ -468,19 +548,25 @@ export default class project {
integrations: new Set([
this.services.one_c,
this.services.moy_sklad,
this.services.excel
this.services.excel,
this.services.ozon,
this.services.wildberries,
this.services.avito,
this.services.yandex_market,
]),
coefficient: 2
},
logic: {
symbol: Symbol("logic"),
game: {
symbol: Symbol("game"),
integrations: new Set([
]),
coefficient: 1
coefficient: 4
},
special: {
symbol: Symbol("special"),
integrations: this.services,
individual: {
symbol: Symbol("individual"),
// integrations: this.services,
integrations: new Set([
]),
coefficient: 3
}
});
@@ -510,19 +596,22 @@ export default class project {
site: {
symbol: Symbol("site"),
purposes: new Set([
this.purposes.project,
this.purposes.contact,
this.purposes.neural_network,
this.purposes.gallery,
this.purposes.funnel,
this.purposes.landing,
this.purposes.contacts,
this.purposes.archive,
this.purposes.ai,
this.purposes.crm,
this.purposes.calculate,
this.purposes.landing,
this.purposes.marketplace
this.purposes.saas,
this.purposes.marketplace,
this.purposes.search,
this.purposes.individual,
]),
coefficient: 3,
cost: {
usd: 80,
rub: 8000
usd: 120,
rub: 12000
},
team: new Map([
[this.#workers.programmer, 1],
@@ -533,15 +622,16 @@ export default class project {
chat_robot: {
symbol: Symbol("chat_robot"),
purposes: new Set([
this.purposes.project,
this.purposes.contact,
this.purposes.neural_network,
this.purposes.game,
this.purposes.gallery,
this.purposes.funnel,
this.purposes.landing,
this.purposes.contacts,
this.purposes.archive,
this.purposes.ai,
this.purposes.crm,
this.purposes.calculate,
this.purposes.landing,
this.purposes.marketplace
this.purposes.saas,
this.purposes.marketplace,
this.purposes.individual,
]),
coefficient: 3,
cost: {
@@ -551,21 +641,23 @@ export default class project {
team: new Map([
[this.#workers.programmer, 1],
[this.#workers.designer, 0],
[this.#workers.booster, 1]
[this.#workers.booster, 0]
])
},
program: {
symbol: Symbol("program"),
purposes: new Set([
this.purposes.neural_network,
this.purposes.ai,
this.purposes.crm,
this.purposes.calculate,
this.purposes.marketplace
this.purposes.marketplace,
this.purposes.individual,
]),
coefficient: 4,
cost: {
usd: 100,
rub: 10000
usd: 180,
rub: 18000
},
team: new Map([
[this.#workers.programmer, 1],
@@ -573,38 +665,7 @@ export default class project {
[this.#workers.booster, 0]
])
},
parser: {
symbol: Symbol("parser"),
purposes: new Set([
this.purposes.search
]),
coefficient: 2,
cost: {
usd: 35,
rub: 3500
},
team: new Map([
[this.#workers.programmer, 1],
[this.#workers.designer, 0],
[this.#workers.booster, 0]
])
},
script: {
symbol: Symbol("script"),
purposes: new Set([
this.purposes.logic
]),
coefficient: 1,
cost: {
usd: 20,
rub: 2000
},
team: new Map([
[this.#workers.programmer, 1],
[this.#workers.designer, 0],
[this.#workers.booster, 0]
])
},
game: {
symbol: Symbol("game"),
purposes: new Set([
@@ -619,6 +680,39 @@ export default class project {
[this.#workers.programmer, 1],
[this.#workers.designer, 1],
[this.#workers.booster, 1]
])
},
script: {
symbol: Symbol("script"),
purposes: new Set([
this.purposes.search,
this.purposes.individual,
]),
coefficient: 1,
cost: {
usd: 20,
rub: 2000
},
team: new Map([
[this.#workers.programmer, 1],
[this.#workers.designer, 0],
[this.#workers.booster, 0]
])
},
module: {
symbol: Symbol("module"),
purposes: new Set([
this.purposes.individual,
]),
coefficient: 1,
cost: {
usd: 60,
rub: 6000
},
team: new Map([
[this.#workers.programmer, 1],
[this.#workers.designer, 0],
[this.#workers.booster, 0]
])
}
});
@@ -1759,6 +1853,15 @@ export default class project {
// Reloading the page @todo make something smarter
alert("Запрос доставлен, ожидайте обратной связи");
// Initializing the rofls HTML-element
const rofls = document.getElementById('rofls');
// Showing rofls
rofls.style.removeProperty('display');
// Starting the rofls hotline.mjs instance
rofls.hotline.start();
// Exit (success)
resolve();
}
@@ -1793,7 +1896,7 @@ export default class project {
*
* @return {void}
*/
damper: core.damper(
damper: core.global.damper(
(...variables) => this.send.system(...variables),
300,
2,
@@ -2050,21 +2153,33 @@ export default class project {
// Initializing the result HTML-element
const result = this.#elements.get('result');
if (result instanceof HTMLElement) {
// Initialized the result HTML-element
// Showing the result HTML-element
result.style.removeProperty('display');
}
// Initializing the hours HTML-element
const output = this.#elements.get('hours_output');
if (output instanceof HTMLElement) {
// Initialized the hours HTML-element
// Writing into the hours output HTML-element
output.innerText = hours;
}
// Initializing the hours wrap HTML-element
const wrap = this.#elements.get('hours');
if (wrap instanceof HTMLElement) {
// Initialized the hours wrap HTML-element
// Showing the hours wrap HTML-element
wrap.style.removeProperty('display');
}
}
// Exit (success)
return hours;
@@ -2094,9 +2209,13 @@ export default class project {
// Initializing the days HTML-element
const output = this.#elements.get('days_output');
if (output instanceof HTMLElement) {
// Initialized the days HTML-element
// Writing into the days output HTML-element
output.innerText = days;
}
}
// Exit (success)
return days;
@@ -2153,25 +2272,53 @@ export default class project {
// Initializing the result HTML-element
const result = this.#elements.get('result');
if (result instanceof HTMLElement) {
// Initialized the result HTML-element
// Showing the result HTML-element
result.style.removeProperty('display');
}
// Initializing the output HTML-elements
// Initializing the payment output HTML-element
const payment_output = this.#elements.get('payment_output');
if (payment_output instanceof HTMLElement) {
// Initialized the payment output HTML-element
// Writing into the payment output HTML-element
payment_output.innerText = new Intl.NumberFormat("ru-RU", { maximumSignificantDigits: 3 }).format(costs.full);
}
// Initializing the prepayment output HTML-element
const prepayment_output = this.#elements.get('prepayment_output');
// Writing into the output HTML-elements
payment_output.innerText = new Intl.NumberFormat("ru-RU", { maximumSignificantDigits: 3 }).format(costs.full);
prepayment_output.innerText = new Intl.NumberFormat("ru-RU", { maximumSignificantDigits: 3 }).format(costs.prepayment);
if (prepayment_output instanceof HTMLElement) {
// Initialized the prepayment output HTML-element
// Initializing the wrap HTML-elements
// Writing into the prepayment output HTML-element
prepayment_output.innerText = new Intl.NumberFormat("ru-RU", { maximumSignificantDigits: 3 }).format(costs.prepayment);
}
// Initializing the payment wrap HTML-element
const payment_wrap = this.#elements.get('payment');
if (payment_wrap instanceof HTMLElement) {
// Initialized the payment wrap HTML-element
// Showing the payment wrap HTML-element
payment_wrap.style.removeProperty('display');
}
// Initializing the prepayment wrap HTML-element
const prepayment_wrap = this.#elements.get('prepayment');
// Showing the wrap HTML-elements
payment_wrap.style.removeProperty('display');
if (prepayment_wrap instanceof HTMLElement) {
// Initialized the prepayment wrap HTML-element
// Showing the prepayment wrap HTML-element
prepayment_wrap.style.removeProperty('display');
}
}
// Exit (success)
return costs;

View File

@@ -0,0 +1,552 @@
/** @module superpack */
"use strict";
/**
* @name superpack.mjs
*
* @description
* Module for creating superpacks
*
* @class
* @public
*
* {@link https://git.mirzaev.sexy/mirzaev/superpack.mjs}
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
export default class superpack {
/**
* @name Shell
*
* @description
* Shell of all elements, top-level parent HTML-element
*
* @type {HTMLElement}
*
* @protected
*/
#shell;
/**
* @name Elements
*
* @description
* Calculation steps shell elements
*
* @type {Map}
*
* @protected
*/
#elements = new Map();
/**
* @name Elements (get)
*
* @description
* Getter for `this.#elements`
*
* @return {Map}
*
* @public
*/
get elements() {
return this.#elements;
}
/**
* @name stages
*
* @description
* Active stages for guide
*
* @return {Set}
*
* @protected
*/
#stages = new Set();
/**
* @name Stages (get)
*
* @description
* Getter for `this.#stages`
*
* @return {Set}
*
* @public
*/
get stages() {
return this.#stages;
}
/**
* @name Shell (get)
*
* @description
* Getter for `this.#shell`
*
* @return {HTMLElement}
*
* @public
*/
get shell() {
return this.#shell;
}
/**
* @name URN
*
* @description
* The superpack URN (https://kodorvan.tech/superpack/{URN})
*
* @type {string}
*
* @protected
*/
#urn = '';
/**
* @name URN (set)
*
* @description
* Setter for `this.#urn`
*
* @public
*/
set urn(value) {
// Writing into the hour cost
this.#urn = value;
// Dispatching event: "system.superpack.write"
this.#shell.dispatchEvent(
new CustomEvent("system.superpack.write", {
detail: { name: 'urn', value: value }
})
);
if (this.#urn.length > 0) {
// Has a value
// Deleting from the stages registry
this.#stages.delete('urn');
} else {
// Has no value
// Writing into the stages registry
this.#stages.add('urn');
}
// Reinitializing guide HTML-elements
this.guide();
}
/**
* @name Title
*
* @description
* The superpack title
*
* @type {string}
*
* @protected
*/
#title = '';
/**
* @name Title (set)
*
* @description
* Setter for `this.#title`
*
* @public
*/
set title(value) {
// Writing into the hour cost
this.#title = value;
// Dispatching event: "system.superpack.write"
this.#shell.dispatchEvent(
new CustomEvent("system.superpack.write", {
detail: { name: 'title', value: value }
})
);
if (this.#title.length > 0) {
// Has a value
// Deleting from the stages registry
this.#stages.delete('title');
} else {
// Has no value
// Writing into the stages registry
this.#stages.add('title');
}
// Reinitializing guide HTML-elements
this.guide();
}
/**
* @name HTML
*
* @description
* The superpack content (HTML)
*
* @type {string}
*
* @protected
*/
#html = '';
/**
* @name HTML (set)
*
* @description
* Setter for `this.#html`
*
* @public
*/
set html(value) {
// Writing into the hour cost
this.#html = value;
// Dispatching event: "system.superpack.write"
this.#shell.dispatchEvent(
new CustomEvent("system.superpack.write", {
detail: { name: 'html', value: value }
})
);
if (this.#html.length > 0) {
// Has a value
// Deleting from the stages registry
this.#stages.delete('html');
} else {
// Has no value
// Writing into the stages registry
this.#stages.add('html');
}
// Reinitializing guide HTML-elements
this.guide();
}
/**
* @name Text
*
* @description
* The superpack content (text)
*
* @type {string}
*
* @protected
*/
#text = '';
/**
* @name Text (set)
*
* @description
* Setter for `this.#text`
*
* @public
*/
set text(value) {
// Writing into the hour cost
this.#text = value;
// Dispatching event: "system.superpack.write"
this.#shell.dispatchEvent(
new CustomEvent("system.superpack.write", {
detail: { name: 'text', value: value }
})
);
if (this.#text.length > 0) {
// Has a value
// Deleting from the stages registry
this.#stages.delete('text');
} else {
// Has no value
// Writing into the stages registry
this.#stages.add('text');
}
// Reinitializing guide text-elements
this.guide();
}
/**
* @name Supercost
*
* @description
* The superpack content (supercost)
*
* @type {number}
*
* @protected
*/
#supercost = 0;
/**
* @name Supercost (set)
*
* @description
* Setter for `this.#supercost`
*
* @public
*/
set supercost(value) {
// Writing into the hour cost
this.#supercost = value;
// Dispatching event: "system.superpack.write"
this.#shell.dispatchEvent(
new CustomEvent("system.superpack.write", {
detail: { name: 'supercost', value: value }
})
);
if (this.#supercost > 0) {
// Has a value
// Deleting from the stages registry
this.#stages.delete('supercost');
} else {
// Has no value
// Writing into the stages registry
this.#stages.add('supercost');
}
// Reinitializing guide supercost-elements
this.guide();
}
/**
* @name Constructor
*
* @description
* Initialize an instance
*
* @param {HTMLElement} shell The shell element
**/
constructor(
shell,
urn,
title,
html,
text,
supercost
) {
if (shell instanceof HTMLElement) {
// Initialized the shell
// Writing the shell HTML-element
this.#shell = shell;
if (urn instanceof HTMLElement) this.#elements.set('urn', urn);
if (title instanceof HTMLElement) this.#elements.set('title', title);
if (html instanceof HTMLElement) this.#elements.set('html', html);
if (text instanceof HTMLElement) this.#elements.set('text', text);
if (supercost instanceof HTMLElement) this.#elements.set('supercost', supercost);
Object.assign(
this.send,
{
/**
* @name Send (system)
*
* @description
* Send the superpack data to the server
*
* @memberof superpack.send
*
* @return {void}
*/
async system(request, resolve, reject) {
try {
if (
// typeof identifier === "string" ||
true
) {
// Validated all required arguments
return await core.request(
"/system/superpack/create",
request,
"PUT",
).then(
async (json) => {
if (json) {
// Received a JSON-response
if (
json.errors !== null &&
typeof json.errors === "object" &&
json.errors.length > 0
) {
// Fail (received errors)
// Exit (fail)
reject(json);
} else {
// Success (not received errors)
// Reloading the page @todo make something smarter
alert("Запрос доставлен");
// Exit (success)
resolve();
}
}
},
() => reject(),
);
}
} catch (e) {
console.log(e);
}
}
}
);
core?.modules.connect("damper").then((connected) => {
// Imported the damper.mjs module
Object.assign(
this.send,
{
/**
* @name Send (damper)
*
* @description
* Send the superpack data to the server
*
* @memberof superpack.send
*
* @param {booleanean} [force=false] Ignore the damper?
*
* @return {void}
*/
damper: core.damper(
(...variables) => this.send.system(...variables),
300,
2,
),
}
);
});
}
}
/**
* @name Guide
*
* @description
* Set user interface help elements
*
* @param {(string|Set)} stages
*
* @public
**/
guide(stages) {
if (stages !== undefined) {
// Received stages
if (stages instanceof Set) {
// Set
// Reinitializing stages
this.#stages = stages;
} else {
// String (expected)
// Writing into stages
this.#stages.add(stages);
}
}
for (const [parameter, element] of this.#elements) {
// Iterating over elements
// Initializing the guide HTML-element
const guide = element.querySelector('.guide');
if (guide instanceof HTMLElement) {
// Initialized the guide HTML-element
// Initializing the input HTML-element
const input = element.querySelector('.input');
if (input.value == "" || this.#stages.has(parameter)) {
// Requested guide
// Showing the guide
guide.classList.add('active');
} else {
// Not requested guide
// Hiding the guide
guide.classList.remove('active');
}
}
}
}
/**
* @name Pack
*
* @description
* Compose the superpack parameters
*
* @public
*
* @returns {string} Parameters row for `application/x-www-form-urlencoded`
*/
pack() {
// Exit (success)
return "identifier=" + encodeURIComponent(new Date().valueOf())
+ "&urn=" + encodeURIComponent(this.#urn)
+ "&title=" + encodeURIComponent(this.#title)
+ "&html=" + encodeURIComponent(this.#html)
+ "&text=" + encodeURIComponent(this.#text)
+ "&supercost=" + encodeURIComponent(this.#supercost)
;
}
/**
* @name Send
*
* @description
* Compose the superpack and send to the server
*
* @public
*
* @param {boolean} [force=false] Ignore the damper?
*/
send(force = false) {
core.modules.connect("damper").then(
() => {
// Imported the damper module
// Processing under damper
this.send.damper(this.pack(), force);
},
() => {
// Not imported the damper module
// Processing
this.send.system(this.pack());
},
);
}
}

View File

@@ -10,28 +10,28 @@ core.modules.connect(["damper", "project"]).then((connected) => {
const files = document.getElementById("project_files");
// Initializing the instance of the project.mjs
core.project = new connected.project(
document.querySelector('section[data-paginator-page="1"]'),
document.getElementById("architecture"),
document.getElementById("purpose"),
document.getElementById("integrations"),
document.getElementById("team"),
document.getElementById("programmers"),
document.getElementById("designers"),
document.getElementById("boosters"),
document.getElementById("reward"),
document.getElementById("hour"),
document.getElementById("hour_input_number"),
document.getElementById("hour_input_range"),
document.getElementById("result"),
document.getElementById("calculated"),
document.getElementById("hours"),
document.getElementById("hours_output"),
document.getElementById("days_output"),
document.getElementById("payment"),
document.getElementById("payment_output"),
document.getElementById("prepayment"),
document.getElementById("prepayment_output"),
core.global.project = new connected.global.project(
document.querySelector('section[data-paginator-page="2"]'),
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
document.getElementById("project_name"),
document.getElementById("project_description"),
files,
@@ -43,23 +43,6 @@ core.modules.connect(["damper", "project"]).then((connected) => {
true
);
// Initializing the hour input number HTML-element
const hour_number = document.getElementById('hour_input_number');
// Initializing the hour input range HTML-element
const hour_range = document.getElementById('hour_input_range');
hour_range.addEventListener("input", () => {
hour_inputs_syncronize(hour_range, hour_number);
});
function hour_inputs_syncronize(range, number) {
const min = range.min ? range.min : 300;
const max = range.max ? range.max : 5000;
number.value = range.value;
}
// Initializing the "back" button
const back = document.getElementById('back');
@@ -70,17 +53,18 @@ core.modules.connect(["damper", "project"]).then((connected) => {
const pages = document.querySelectorAll('section[data-paginator-page]');
// Initializing the instance of the paginator.mjs
core.paginator = new connected.paginator(
core.global.paginator = new connected.global.paginator(
document.getElementById('buttons'),
pages
pages,
2
);
// Initializing the buttons
const buttons = core.paginator.shell.querySelectorAll('button[data-paginator-page-button]');
const buttons = core.global.paginator.shell.querySelectorAll('button[data-paginator-page-button]');
function menu(identifier) {
// Initializing the target page button HTML-element
const active = core.paginator.shell.querySelector('button[data-paginator-page-button="' + identifier + '"]');
const active = core.global.paginator.shell.querySelector('button[data-paginator-page-button="' + identifier + '"]');
if (active instanceof HTMLElement) {
// Initialized the target page button HTML-element
@@ -95,7 +79,7 @@ core.modules.connect(["damper", "project"]).then((connected) => {
// Showing the target page button HTML-element
active.style.removeProperty('display');
if (identifier > 1) {
if (identifier > core.global.paginator.initial) {
// Second or more page
// Showing the "back" button
@@ -109,58 +93,58 @@ core.modules.connect(["damper", "project"]).then((connected) => {
}
}
// Initializing the page buttons menu
core.global.paginator.shell.addEventListener("paginator.page.opened", function (event) {
// Scrolling to the introdution HTML-element
introdution?.scrollIntoView({ behavior: 'smooth' });
// Initializing the page buttons menu
menu(event.detail.identifier);
});
// Connecting event listener for project calculation
core.project.shell.addEventListener("project.write", function() {
// Initializing the "calculator" page button HTML-element
const calculator = core.paginator.shell.querySelector('button[data-paginator-page-button="1"]');
if (calculator instanceof HTMLElement) {
// Initialized the "calculator" page button HTML-element
// Showing or hiding the "calculator" page button HTML-element
calculator.disabled = !(core.project.architecture != null);
}
core.global.project.shell.addEventListener("project.write", function() {
// Initializing the "project" page button HTML-element
const project = core.paginator.shell.querySelector('button[data-paginator-page-button="2"]');
const project = core.global.paginator.shell.querySelector('button[data-paginator-page-button="2"]');
if (project instanceof HTMLElement) {
// Initialized the "project" page button HTML-element
// Showing or hiding the "project" page button HTML-element
project.disabled =
!(core.project.project.name
!(core.global.project.project.name
&& (
core.project.project.description != null
|| core.project.project.files.length > 0
core.global.project.project.description != null
|| core.global.project.project.files.length > 0
));
}
// Initializing the "requester" page button HTML-element
const requester = core.paginator.shell.querySelector('button[data-paginator-page-button="3"]');
const requester = core.global.paginator.shell.querySelector('button[data-paginator-page-button="3"]');
if (requester instanceof HTMLElement) {
// Initialized the "requester" page button HTML-element
// Showing or hiding the "requester" page button HTML-element
requester.disabled =
!(core.project.requester.personal
!(core.global.project.requester.personal
&& (
core.project.requester.sim != null
|| core.project.requester.mail != null
|| core.project.requester.other != null
core.global.project.requester.sim != null
|| core.global.project.requester.mail != null
|| core.global.project.requester.other != null
));
}
});
// Connecting event listener for project calculation
core.project.shell.addEventListener("project.calculated", function() {
core.global.project.shell.addEventListener("project.calculated", function() {
// Showing the buttons HTML-element
core.paginator.shell?.style.removeProperty('display');
core.global.paginator.shell?.style.removeProperty('display');
});
// Initializing the page buttons menu
core.paginator.shell.addEventListener("paginator.page.opened", function (event) {
core.global.paginator.shell.addEventListener("paginator.page.opened", function (event) {
// Scrolling to the introdution HTML-element
introdution?.scrollIntoView({ behavior: 'smooth' });
@@ -215,7 +199,7 @@ core.modules.connect(["damper", "project"]).then((connected) => {
const index = Array.from(list.children).indexOf(element);
// Initializing the actual list of files
let files = core.project.project.files;
let files = core.global.project.project.files;
// Deleting the file
files.splice(index, 1);
@@ -224,7 +208,7 @@ core.modules.connect(["damper", "project"]).then((connected) => {
element.remove();
// Writing into the project property
core.project.project.files = files;
core.global.project.project.files = files;
})
// Initializing the file label delete button image
@@ -247,5 +231,5 @@ core.modules.connect(["damper", "project"]).then((connected) => {
}
})
core.project.shell.parentElement.classList.remove('loading');
core.global.project.shell.parentElement.classList.remove('loading');
});

View File

@@ -0,0 +1,251 @@
"use strict";
core.modules.connect(["damper", "project"]).then((connected) => {
// Imported modules
// Initializing the introdution HTML-element
const introdution = document.getElementById('introdution');
// Initializing the files input wrap HTML-element
const files = document.getElementById("project_files");
// Initializing the instance of the project.mjs
core.global.project = new connected.global.project(
document.querySelector('section[data-paginator-page="1"]'),
document.getElementById("architecture"),
document.getElementById("purpose"),
document.getElementById("integrations"),
document.getElementById("team"),
document.getElementById("programmers"),
document.getElementById("designers"),
document.getElementById("boosters"),
document.getElementById("reward"),
document.getElementById("hour"),
document.getElementById("hour_input_number"),
document.getElementById("hour_input_range"),
document.getElementById("result"),
document.getElementById("calculated"),
document.getElementById("hours"),
document.getElementById("hours_output"),
document.getElementById("days_output"),
document.getElementById("payment"),
document.getElementById("payment_output"),
document.getElementById("prepayment"),
document.getElementById("prepayment_output"),
document.getElementById("project_name"),
document.getElementById("project_description"),
files,
document.getElementById("requester_name"),
document.getElementById("requester_sim"),
document.getElementById("requester_mail"),
document.getElementById("requester_other"),
document.getElementById("requester_personal"),
true
);
// Initializing the hour input number HTML-element
const hour_number = document.getElementById('hour_input_number');
// Initializing the hour input range HTML-element
const hour_range = document.getElementById('hour_input_range');
hour_range.addEventListener("input", () => {
hour_inputs_syncronize(hour_range, hour_number);
});
function hour_inputs_syncronize(range, number) {
const min = range.min ? range.min : 300;
const max = range.max ? range.max : 5000;
number.value = range.value;
}
// Initializing the "back" button
const back = document.getElementById('back');
core.modules.connect(["paginator"]).then((connected) => {
// Imported the paginator.mjs module
// Initializing pages
const pages = document.querySelectorAll('section[data-paginator-page]');
// Initializing the instance of the paginator.mjs
core.global.paginator = new connected.global.paginator(
document.getElementById('buttons'),
pages
);
// Initializing the buttons
const buttons = core.global.paginator.shell.querySelectorAll('button[data-paginator-page-button]');
function menu(identifier) {
// Initializing the target page button HTML-element
const active = core.global.paginator.shell.querySelector('button[data-paginator-page-button="' + identifier + '"]');
if (active instanceof HTMLElement) {
// Initialized the target page button HTML-element
for (const inactive of buttons) {
// Iteration over pages
// Hiding the page button HTML-element
inactive.style.setProperty('display', 'none');
}
// Showing the target page button HTML-element
active.style.removeProperty('display');
if (identifier > 1) {
// Second or more page
// Showing the "back" button
back.style.removeProperty('display');
} else {
// The first page
// Hiding the "back" button
back.style.setProperty('display', 'none');
}
}
}
// Connecting event listener for project calculation
core.global.project.shell.addEventListener("project.write", function() {
// Initializing the "calculator" page button HTML-element
const calculator = core.global.paginator.shell.querySelector('button[data-paginator-page-button="1"]');
if (calculator instanceof HTMLElement) {
// Initialized the "calculator" page button HTML-element
// Showing or hiding the "calculator" page button HTML-element
calculator.disabled = !(core.global.project.architecture != null);
}
// Initializing the "project" page button HTML-element
const project = core.global.paginator.shell.querySelector('button[data-paginator-page-button="2"]');
if (project instanceof HTMLElement) {
// Initialized the "project" page button HTML-element
// Showing or hiding the "project" page button HTML-element
project.disabled =
!(core.global.project.project.name
&& (
core.global.project.project.description != null
|| core.global.project.project.files.length > 0
));
}
// Initializing the "requester" page button HTML-element
const requester = core.global.paginator.shell.querySelector('button[data-paginator-page-button="3"]');
if (requester instanceof HTMLElement) {
// Initialized the "requester" page button HTML-element
// Showing or hiding the "requester" page button HTML-element
requester.disabled =
!(core.global.project.requester.personal
&& (
core.global.project.requester.sim != null
|| core.global.project.requester.mail != null
|| core.global.project.requester.other != null
));
}
});
// Connecting event listener for project calculation
core.global.project.shell.addEventListener("project.calculated", function() {
// Showing the buttons HTML-element
core.global.paginator.shell?.style.removeProperty('display');
});
// Initializing the page buttons menu
core.global.paginator.shell.addEventListener("paginator.page.opened", function (event) {
// Scrolling to the introdution HTML-element
introdution?.scrollIntoView({ behavior: 'smooth' });
// Initializing the page buttons menu
menu(event.detail.identifier);
});
});
// Initializing the files list HTML-element
const list = files.querySelector('ol.files');
// Initializing the files input HTML-element
const files_input = files.querySelector('.input');
files_input.addEventListener('input', (event) => {
// Deleting every file label from the list
list.innerHTML = '';
if (files_input.files.length > 0) {
// Has files
// Showing the list HTML-element
list.style.removeProperty('display');
// Initializing the file index iterator
let index = 0;
for (const file of files_input.files) {
// Iterating over files
// Initializing the maximum length for the file label name
const maximum = 16;
// Initializing the end tail for the file label name
const tail = 8;
// Initializing the file label name
const name = file.name.length > maximum ? file.name.slice(0, maximum - tail).trim() + '...' + file.name.slice(-tail).trim() : file.name;
// Initializing the file label HTML-element
const element = document.createElement('li');
element.id = "project_files_input_" + index;
element.setAttribute('title', file.name);
element.innerText = name;
// Initializing the file label delete button
const button = document.createElement('button');
button.classList.add('delete');
button.addEventListener('click', (event) => {
// Initializing the file index
const index = Array.from(list.children).indexOf(element);
// Initializing the actual list of files
let files = core.global.project.project.files;
// Deleting the file
files.splice(index, 1);
// Deleting the file label HTML-element
element.remove();
// Writing into the project property
core.global.project.project.files = files;
})
// Initializing the file label delete button image
const image = document.createElement('img');
image.setAttribute('src', '/themes/default/images/icons/close.svg');
// Writing the file label into the list HTML-element
button.appendChild(image);
element.appendChild(button);
list.appendChild(element);
// Recalculating the index (postfix-incrementation)
index++;
}
} else {
// Has no files
// Hiding the list HTML-element
list.style.setProperty('display', 'none');
}
})
core.global.project.shell.parentElement.classList.remove('loading');
});

View File

@@ -0,0 +1,15 @@
"use strict";
core.modules.connect(["damper"], ["superpack"]).then((connected) => {
// Imported modules
// Initializing the instance of the project.mjs
core.system.superpack = new connected.system.superpack(
document.getElementById('superpack'),
document.getElementById('superpack_urn'),
document.getElementById('superpack_title'),
document.getElementById('superpack_html'),
document.getElementById('superpack_text'),
document.getElementById('superpack_supercost'),
);
});

View File

@@ -1 +0,0 @@
../../../../../three.js/build/three.core.js

View File

@@ -1 +0,0 @@
../../../../../three.js/build/three.module.js

View File

@@ -4,8 +4,13 @@
:root {
--text-color: #fff;
--text-color-inverted: #000;
--button-background-color-inverted: #fff;
--button-background-color: #000;
--link-color: #475bf9;
--link-hover-color: #6375ff;
--link-active-color: #3d53f6;
--button-background-color: #fff;
--button-background-color-inverted: #000;
--button-hover-background-color: #abc7c6;
--button-active-background-color: #8fa3a2;
--section-background-color-inverted: #fff;
--section-background-color: #000;
--background-color: #fbfaf6;
@@ -21,9 +26,6 @@
--blue: #0ea5e9;
--paper: var(--white);
--button-plain-hover-background-color: #bdd2c8;
--button-plain-active-background-color: #7d9f8f;
}
/* } */
@@ -56,8 +58,13 @@
:root {
--text-color: #fff;
--text-color-inverted: #000;
--button-background-color-inverted: #fff;
--button-background-color: #000;
--link-color: #475bf9;
--link-hover-color: #6375ff;
--link-active-color: #3d53f6;
--button-background-color: #fff;
--button-background-color-inverted: #000;
--button-hover-background-color: #abc7c6;
--button-active-background-color: #8fa3a2;
--section-background-color-inverted: #fff;
--section-background-color: #000;
--background-color: #fbfaf6;
@@ -72,8 +79,5 @@
--white: #fff;
--paper: var(--white);
--button-plain-hover-background-color: #bdd2c8;
--button-plain-active-background-color: #7d9f8f;
}
}

View File

@@ -1,6 +1,6 @@
@charset "UTF-8";
section#companies {
article#companies {
z-index: 50;
width: 100vw;
height: 70px;

View File

@@ -30,11 +30,12 @@ section#cookies {
}
>div {
padding: 0.8rem 1.2rem 0.7rem;
padding: 0.9rem 1.2rem 0.8rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 0.3rem;
>p {
margin: unset;
@@ -43,6 +44,8 @@ section#cookies {
}
>small {
line-height: 1rem;
text-align: center;
font-family: Nunito;
font-size: 0.9rem;
font-weight: 400;

View File

@@ -1,10 +1,11 @@
@charset "UTF-8";
section#project {
--width: 420px;
--margin-bottom: 0.8rem;
--width: 480px;
z-index: 200;
position: relative;
margin-top: 2rem;
margin-top: 3rem;
margin-bottom: 5rem;
min-width: var(--width);
max-width: var(--width);
@@ -32,6 +33,14 @@ section#project {
margin-bottom: 0.5em;
}
&+span {
margin-top: 0.2em;
margin-bottom: 1em;
text-align: center;
color: #e9e8e2;
text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B;
}
&+small {
margin-bottom: 1em;
text-align: center;
@@ -67,6 +76,7 @@ section#project {
--shadow: 0px 6px 6px -2px rgba(0, 0, 0, 0.5), 0px 0px 14px 5px rgba(0, 0, 0, 0.4);
position: relative;
padding: 2rem 1.4rem;
padding: 1.6rem 1.4rem;
display: flex;
flex-direction: column;
gap: 1.4rem;
@@ -125,8 +135,8 @@ section#project {
display: flex;
flex-direction: column;
gap: 0.8em;
overflow: hidden;
border-radius: 1.125rem;
/* overflow: hidden;
border-radius: 1.125rem; */
/* border: 2px solid;
background-color: #fff;
box-shadow: var(--shadow);
@@ -185,6 +195,8 @@ section#project {
>:is(input, select, textarea) {
grid-column: 2;
grid-row: 2;
width: 100%;
border-radius: 0;
}
>small.guide {
@@ -266,7 +278,7 @@ section#project {
width: 100%;
box-sizing: border-box;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
gap: 0.6em 1em;
/* border-radius: 0.75rem; */
border: 1px solid #000;
@@ -278,11 +290,6 @@ section#project {
font-weight: 400;
}
>div.row {
width: 100%;
display: flex;
justify-content: space-between;
>label {
width: 100%;
display: flex;
@@ -320,7 +327,6 @@ section#project {
}
}
}
}
>section#reward {
padding: 0.4em 0.6em 0;
@@ -703,11 +709,9 @@ section#project {
gap: unset;
>label#requester_personal {
padding: 1em 0.8em;
padding: 0.6em 0.8em;
box-sizing: border-box;
display: grid;
grid-template-columns: 3ch auto;
grid-template-rows: 2ch;
display: flex;
align-items: center;
gap: 0.7ch;
font-size: 0.9rem;
@@ -725,8 +729,7 @@ section#project {
}
>div {
grid-column: 1;
scale: 0.7;
scale: 0.8;
>input {
position: absolute;
@@ -762,7 +765,6 @@ section#project {
}
>span {
grid-column: 2;
margin-top: 0.15ch;
}
}
@@ -858,11 +860,11 @@ section#project {
display: contents;
>button#back {
--diameter: 6ch;
--diameter: 7ch;
--radius: calc(var(--diameter, 4ch) / 2);
position: absolute;
left: calc(-1.2rem - var(--diameter, 4ch));
top: calc(7.4rem - var(--radius, 2ch));
top: calc(10rem - var(--radius, 2ch));
width: var(--diameter, 4ch);
height: var(--diameter, 4ch);
display: flex;
@@ -870,14 +872,14 @@ section#project {
align-items: center;
border-radius: 100%;
border: unset;
background-color: #fff;
background-color: var(--button-background-color, #fff);
&:is(:hover, :focus) {
background-color: var(--button-plain-hover-background-color, #bdd2c8);
background-color: var(--button-hover-background-color, #abc7c6);
}
&:active {
background-color: var(--button-plain-active-background-color, #7d9f8f);
background-color: var(--button-active-background-color, #8fa3a2);
}
>img {
@@ -886,6 +888,7 @@ section#project {
}
>section#buttons {
margin-bottom: var(--margin-bottom, 0.8rem);
flex-direction: row;
justify-content: center;
@@ -894,20 +897,33 @@ section#project {
/* padding: 1.05em 1.3em 1em;
border-radius: 0.75rem; */
box-sizing: border-box;
padding: 1.55em 1.3em 1.5em;
padding: 1.25em 1.3em 1.2em;
font-size: 1rem;
border-radius: 1.25rem;
border: unset;
background-color: #fff;
background-color: var(--button-background-color, #fff);
&:is(:hover, :focus) {
background-color: var(--button-hover-background-color, #abc7c6);
}
&:active {
background-color: var(--button-active-background-color, #8fa3a2);
}
&:is(#send) {
--shadow: 0 4px 5px -4px rgba(0, 0, 0, 0.5);
/* padding: 2.3ch 4.5ch 2.5ch; */
line-height: 0.9em;
font-weight: 600;
font-size: 1rem;
color: #fff;
text-shadow: 0 0 4px #000, 0 3px 1.4rem #0009;
border: unset;
background: #ff5c5c;
background: hsl(var(--button-send-background-color, 120deg) 40% 50%);
box-shadow: var(--shadow);
-webkit-box-shadow: var(--shadow);
-moz-box-shadow: var(--shadow);
transition: background 1.2s ease-out;
&:not(:disabled) {
filter: contrast(1.1);
@@ -934,16 +950,6 @@ section#project {
filter: grayscale(1) brightness(0.8);
}
}
>span {
line-height: 1rem;
font-family: Geologica;
font-weight: 600;
font-size: 1rem;
color: #fff;
text-shadow: 0 0 4px #00000070;
/* mix-blend-mode: overlay; */
}
}
}
@@ -958,6 +964,63 @@ section#project {
}
}
>small.description {
padding: 0.9em 1.2em;
text-align: left;
font-family: Nunito;
font-size: 0.9em;
color: #d6c1c1;
background: #b3ced31a;
border-radius: 1.25rem;
border-top: 1px solid #84d1d526;
backdrop-filter: blur(2px) contrast(1.14);
/* text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B; */
text-shadow: unset;
>:is(strong, b) {
/* display: block; */
font-weight: 600;
color: #ebdada;
}
}
>small.guarantee {
padding: 0.9em 1.2em;
text-align: left;
font-family: Nunito;
font-size: 0.9em;
color: #d6c1c1;
background: #b3ced31a;
border-radius: 1.25rem;
border-top: 1px solid #84d1d526;
backdrop-filter: blur(2px) contrast(1.14);
/* text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B; */
text-shadow: unset;
>:is(strong, b) {
/* display: block; */
font-weight: 600;
color: #ebdada;
}
}
>b.partners {
margin-top: 1.2rem;
padding: 0 1em;
text-align: center;
font-family: Bahnschrift;
font-weight: 600;
font-size: 1.2em;
color: #d6c1c1;
text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B;
>:is(strong, b) {
/* display: block; */
font-weight: 600;
color: #ebdada;
}
}
>small.offer {
margin-top: 1.2rem;
padding: 0 1.5em;
@@ -965,6 +1028,10 @@ section#project {
font-size: 0.8em;
color: #fff;
text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B;
>b {
display: block;
}
}
>section#contacts_shortcut {
@@ -979,13 +1046,10 @@ section#project {
font-weight: 600;
}
>p {
>div.sim {
a.number {
margin: unset;
display: flex;
gap: 0.4rem;
font-family: Bahnschrift;
font-size: 1.4em;
font-weight: 400;
color: #fff;
text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B;
>span {
@@ -999,14 +1063,16 @@ section#project {
}
}
}
}
}
@media (width < 550px) {
@media (width < 700px) {
section#project {
--width: 100vw;
padding: 0 2rem;
>div.adaptive {
margin-bottom: var(--margin-bottom, 0.8rem);
display: flex;
flex-direction: row;
gap: 1rem;
@@ -1022,7 +1088,26 @@ section#project {
margin: unset;
min-width: var(--diameter, 4ch);
width: 30%;
border-radius: 0.75rem;
height: auto;
border-radius: 1.25rem;
}
>section#buttons {
margin-bottom: unset;
}
}
}
}
@media (width < 480px) {
section#project {
>article {
>section[data-paginator-page] {
>section#team {
>fieldset {
flex-flow: row wrap;
}
}
}
}
}

View File

@@ -0,0 +1,65 @@
@charset "UTF-8";
body {
&:has(> article#rofls > img.eye:is(:hover, :focus, :active)) {
>article#rofls {
>img.eye {
cursor: none;
}
>img:not(.eye) {
opacity: 0;
transition: opacity 0.1s ease-in;
}
}
>*:not(section#buttons) {
opacity: 0;
transition: opacity 0.1s ease-in;
}
}
>article#rofls {
z-index: 50;
width: 100vw;
height: 32px;
display: flex;
flex-direction: row;
overflow: hidden;
&:has(> img.colors:is(:hover, :focus, :active)) {
z-index: 9999;
mix-blend-mode: color-dodge;
filter: contrast(50);
}
>img {
margin: unset;
height: 100%;
cursor: grab;
&:is(:active) {
cursor: grabbing;
}
&:is(.noclick) {
cursor: not-allowed;
}
&:is(.antibuttons) {
cursor: pointer;
}
&:is(.construction, .cogs) {
cursor: wait;
}
}
}
}
@media (width < 800px) {
section#rofls {
height: 50px;
padding-bottom: 2.5rem;
}
}

View File

@@ -20,12 +20,24 @@ section#superpacks {
scale: 1.4;
transform-origin: top;
/* &:before {
content: '';
border-bottom: 0.65vw solid #1f5a58;
position: absolute;
bottom: 0;
width: 12.8%;
} */
>img.layer {
z-index: 30;
position: absolute;
padding-left: 3.2vw;
width: 100%;
height: 5vw;
&:is(.packs) {
margin-left: 3px;
}
}
>div.labubumba {
@@ -35,7 +47,8 @@ section#superpacks {
width: 72vw;
height: 17.2vw;
background: red;
background: radial-gradient(circle, red 20vw, #af0000 40vw);
background: radial-gradient(circle, red 12vw, #000 50vw);
background: radial-gradient(circle, hsl(calc(var(--scroll-deg, 0deg) * 12) 100% 50%) 12vw, #000 50vw);
mask: var(--mask);
clip-path: polygon(0 0, 0 100%, 39% 100%, 39% 46.5%, 61% 46.5%, 61% 100%, 100% 100%, 100% 0);
}

View File

@@ -4,7 +4,7 @@
@import url('/css/fonts/nunito.css');
@import url('/css/fonts/cascadia_code.css');
@import url('/css/fonts/geologica.css');
@import url('/css/fonts/commissioner.css');
/* @import url('/css/fonts/commissioner.css'); */
@import url('/css/fonts/mt_sans.css');
/* @import url('/css/fonts/vredina.css'); */
@import url('/css/fonts/gost.css');
@@ -14,5 +14,5 @@
/* @import url('/css/fonts/urban_slavic.css'); */
/* @import url('/css/fonts/slifted.css'); */
/* @import url('/css/fonts/compacta.css'); */
@import url('/css/fonts/industry.css');
/* @import url('/css/fonts/industry.css'); */
/* @import url('/css/fonts/palui.css'); */

View File

@@ -3,42 +3,33 @@
footer {
z-index: 4000;
position: relative;
height: var(--footer-height, 200px);
min-height: 230px;
height: var(--footer-height, 230px);
box-sizing: border-box;
padding: 2rem 10vw;
display: flex;
align-items: self-end;
flex-direction: column;
justify-content: space-between;
gap: 3rem;
/* overflow: hidden; */
gap: 2rem;
color: #fff;
background-color: #000;
>div.sector {
height: 100%;
display: flex;
flex-direction: column;
justify-content: end;
gap: 1rem;
&.company {
flex-direction: row;
justify-content: space-between;
align-items: end;
gap: 2rem;
>article#contacts {
display: flex;
flex-direction: column;
align-items: end;
}
}
>article#office {
width: 250px;
height: 100%;
>article.company {
flex-grow: 1;
display: flex;
gap: 2rem;
>div.map {
width: 100%;
height: 100%;
max-width: 350px;
width: 250px;
flex-grow: 3;
overflow: hidden;
border-radius: 0.75rem;
border: 2px solid #474023;
@@ -70,92 +61,20 @@ footer {
}
}
}
}
nav#links {
flex-grow: 1;
display: inline-flex;
justify-content: center;
gap: 1rem;
>a {
text-decoration: none;
font-family: "Geologica";
font-weight: 400;
font-size: 0.85rem;
color: #807f7f;
transition: color 0.1s ease-out;
&:is(:hover, :focus) {
color: #d5d5d5;
transition: color 0s;
}
&:active {
color: #4b4b4b;
transition: color 0s;
}
}
}
>article#contacts {
>h1.sim {
margin: unset;
display: flex;
gap: 0.4em;
font-size: 1.4em;
>span.country:before {
content: '+';
}
>span.operator:before {
content: '(';
}
>span.operator:after {
content: ')';
}
}
>p.worktime {
margin: unset;
margin-top: 0.6em;
display: flex;
gap: 0.5em;
>span.time.from {
display: flex;
gap: 0.2em;
&:before {
content: var(--contacts-worktime-from, 'from');
}
}
>span.time.to {
display: flex;
gap: 0.2em;
&:before {
content: var(--contacts-worktime-to, 'to');
}
}
}
}
>article#company {
>div.information {
min-width: 230px;
max-width: 250px;
justify-self: end;
width: 160px;
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
font-family: "Bahnschrift";
font-family: "Cascadia Code";
>h1.name {
margin: unset;
display: block;
text-align: right;
font-weight: 600;
font-size: 1rem;
}
@@ -164,15 +83,25 @@ footer {
margin: unset;
display: inline-flex;
flex-direction: column;
text-align: right;
gap: 0.2em;
font-size: 0.8rem;
color: grey;
color: #a3a396;
::selection {
color: #000;
background: #F22;
}
::-moz-selection {
color: #000;
background: #F22;
}
>span.row {
display: inline-flex;
justify-content: end;
font-weight: 400;
gap: 0.6em;
&:before {
margin-right: auto;
@@ -193,6 +122,86 @@ footer {
}
}
}
>p.worktime {
margin: unset;
margin-top: auto;
display: flex;
gap: 0.5em;
font-family: "Bahnschrift";
>span.time.from {
margin-left: auto;
display: flex;
gap: 0.2em;
&:before {
content: var(--contacts-worktime-from, 'from');
}
}
>span.time.to {
display: flex;
gap: 0.2em;
&:before {
content: var(--contacts-worktime-to, 'to');
}
}
}
}
}
>article.contacts {
min-height: 100px;
padding-left: 2rem;
display: flex;
flex-direction: column;
align-items: end;
text-align: right;
>div.media {
margin: unset;
margin-top: auto;
justify-content: end;
}
>div.sim {
a.number {
color: #fff;
}
}
>a.mail {
margin-top: 0.2em;
margin-bottom: 1rem;
font-family: "Cascadia Code";
}
}
}
>nav#links {
display: inline-flex;
justify-content: start;
gap: 1rem;
>a {
text-decoration: none;
font-family: "Geologica";
font-weight: 400;
font-size: 0.85rem;
color: #807f7f;
transition: color 0.1s ease-out;
&:is(:hover, :focus) {
color: #d5d5d5;
transition: color 0s;
}
&:active {
color: #4b4b4b;
transition: color 0s;
}
}
}
@@ -218,32 +227,49 @@ footer {
@media (width < 1200px) {
footer {
height: unset;
flex-direction: column;
align-items: center;
>div.sector {
width: 100%;
flex-direction: column;
>article#office {
>article.company {
>div.map {
max-width: unset;
width: 100%;
height: 100px;
height: 150px;
}
}
nav#links {
display: inline-flex;
justify-content: space-between;
gap: 1rem;
flex-flow: wrap row;
>article.contacts {
padding: unset;
align-items: center;
}
&:is(.company) {
flex-direction: row;
>article#contacts {
align-items: start;
}
}
>nav#links {
display: inline-flex;
/* justify-content: space-between; */
flex-flow: wrap row;
justify-content: center;
gap: 1rem;
}
}
}
@media (width < 800px) {
footer {
>div.sector {
>article.company {
flex-direction: column;
>div.information {
max-width: unset;
}
}
}
>nav#links {
justify-content: space-between;
}
}
}

View File

@@ -0,0 +1,35 @@
h1#logotype {
z-index: 200;
margin: unset;
margin-top: 6rem;
margin-bottom: 2rem;
width: max-content;
display: flex;
flex-direction: column;
text-align: center;
gap: 0.6rem;
font-family: "";
font-size: min(8vw, 4rem);
font-weight: 400;
/* scale: 0.8; */
color: #fff;
>span.slogan {
line-height: 0.8em;
font-family: "GOST";
font-weight: 400;
font-size: 1.24em;
color: #3688a2;
}
>a.kodorvan {
line-height: 0.8em;
font-family: "MT Sans";
font-size: 2em;
text-decoration: unset;
color: #c2ff98;
/* text-shadow:
0px 0px 4px #ffff00b5,
0px 0px 11px #ffff008a */
}
}

View File

@@ -0,0 +1,17 @@
@charset "UTF-8";
div.social.media {
margin: 0.6em 0;
height: 3.5ch;
display: flex;
gap: 1ch;
>a {
display: contents;
>img {
width: auto;
height: 100%;
}
}
}

View File

@@ -0,0 +1,37 @@
@charset "UTF-8";
div.sim {
display: flex;
gap: 0.4em;
>a.number {
display: flex;
gap: 0.4em;
font-family: Bahnschrift;
font-size: 1.5em;
>span.country:before {
content: '+';
}
>span.operator:before {
content: '(';
}
>span.operator:after {
content: ')';
}
}
>button.copy {
margin: unset;
padding: 0 0.2em;
cursor: pointer;
border: unset;
>img.icon {
scale: 0.8;
color: #fff;
}
}
}

View File

@@ -5,12 +5,15 @@ main {
--scroll-px-hundred: calc(var(--scroll-px-ten) / 10);
--scroll-px-thousand: calc(var(--scroll-px-hundred) / 10);
margin-top: var(--menu-height);
min-height: 100vh;
display: flex;
flex-direction: column;
flex-grow: 1;
align-items: center;
transition: 0s;
overflow-x: hidden;
overflow-y: scroll;
overscroll-behavior: none;
&:not(:has(*)) {
display: none;

View File

@@ -1,43 +1,7 @@
@charset "UTF-8";
body {
main {
>h1#title {
z-index: 200;
margin: unset;
margin-top: 4rem;
margin-bottom: 2rem;
width: max-content;
display: flex;
flex-direction: column;
text-align: center;
gap: 0.6rem;
font-family: "";
font-size: min(8vw, 4rem);
font-weight: 400;
/* scale: 0.8; */
color: #fff;
>span.slogan {
line-height: 0.8em;
font-family: "GOST";
font-weight: 400;
font-size: 1.24em;
color: #3688a2;
}
>a.kodorvan {
line-height: 0.8em;
font-family: "MT Sans";
font-size: 2em;
text-decoration: unset;
color: #c2ff98;
/* text-shadow:
0px 0px 4px #ffff00b5,
0px 0px 11px #ffff008a */
}
}
>main {
>section.section {
z-index: 500;
width: 100%;
@@ -59,35 +23,4 @@ body {
}
}
}
>div.vignette {
z-index: 100;
position: fixed;
top: 0;
width: 100vw;
height: 100vh;
justify-self: center;
align-self: center;
pointer-events: none;
background: linear-gradient(90deg, #000B -20%, #0000 50%, #000B 120%);
}
>div.dots {
--dot-bg: #18333f;
--dot-color: #041825;
--dot-size: 23px;
--dot-space: 24px;
z-index: -50;
position: fixed;top: -200%;
left: -200vw;
top: -200%;
justify-self: center;
align-self: center;
width: 400vw;
min-height: 1000px;
height: 800%;
rotate: -16deg;
pointer-events: none;
background: linear-gradient(90deg, var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space), linear-gradient(var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space), var(--dot-color);
}
}

View File

@@ -1,83 +1,36 @@
@charset "UTF-8";
body {
main {
>h1#title {
z-index: 200;
margin: unset;
margin-top: 4rem;
margin-bottom: 2rem;
width: max-content;
display: flex;
flex-direction: column;
text-align: center;
gap: 0.6rem;
font-family: "";
font-size: min(8vw, 4rem);
font-weight: 400;
/* scale: 0.8; */
color: #fff;
>span.slogan {
line-height: 0.8em;
font-family: "GOST";
font-weight: 400;
font-size: 1.24em;
color: #3688a2;
}
>a.kodorvan {
line-height: 0.8em;
font-family: "MT Sans";
font-size: 2em;
text-decoration: unset;
color: #c2ff98;
/* text-shadow:
0px 0px 4px #ffff00b5,
0px 0px 11px #ffff008a */
}
}
>main {
>article#offer {
background: #fff;
z-index: 500;
border-radius: 1.25rem;
margin: 3rem 10vw 8rem;
padding: 1rem 4rem;
margin: 3rem 0 8rem;
width: 880px;
box-sizing: border-box;
padding: 3rem 4rem;
background: #fff;
>h1 {}
>h1 {
margin-top: unset;
margin-bottom: 2.5rem;
text-align: center;
font-family: "MT Sans";
font-size: 3rem;
font-weight: 400;
}
}
}
}
@media (width < 1000px) {
body {
>main {
>article#offer {
margin-bottom: unset;
width: 100%;
border-radius: unset;
}
}
>div.vignette {
z-index: 100;
position: fixed;
top: 0;
width: 100vw;
height: 100vh;
justify-self: center;
align-self: center;
pointer-events: none;
background: linear-gradient(90deg, #000B -20%, #0000 50%, #000B 120%);
}
>div.dots {
--dot-bg: #18333f;
--dot-color: #041825;
--dot-size: 23px;
--dot-space: 24px;
z-index: -50;
position: fixed;
top: -200%;
left: -200vw;
top: -200%;
justify-self: center;
align-self: center;
width: 400vw;
min-height: 1000px;
height: 800%;
rotate: -16deg;
pointer-events: none;
background: linear-gradient(90deg, var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space), linear-gradient(var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space), var(--dot-color);
}
}

View File

@@ -0,0 +1,172 @@
@charset "UTF-8";
body {
>main {
>article#superpack {
z-index: 500;
border-radius: 1.25rem;
margin: 3rem 0 8rem;
width: 540px;
box-sizing: border-box;
padding: 2rem;
display: flex;
flex-direction: column;
gap: 1.4rem;
background: #fff;
>h1 {
margin-top: unset;
margin-bottom: 0.2rem;
text-align: center;
font-family: "MT Sans";
font-size: 2.6rem;
font-weight: 400;
}
&:is(.loading) {
>div.loading {
opacity: 1;
height: 100%;
transition: opacity 0.1s ease-in, height 0s linear 0s;
}
}
>div.loading {
z-index: 1000;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 0%;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
pointer-events: all;
background: #2c2c33d4;
backdrop-filter: blur(1.4px);
transition: opacity 0.2s ease-out, height 0s linear 0.2s;
&:before {
margin-top: 50px;
position: absolute;
content: var(--project-loading, "Loading");
width: max-content;
text-align: center;
font-family: "Geologica";
font-style: normal;
font-weight: 400;
font-size: 0.6rem;
color: #fff;
}
>i.icon.loading.spinner {
color: #fff;
}
}
small.guide {
padding: 0 0.2em;
display: none;
font-family: Bahnschrift;
font-size: 0.75em;
font-weight: 200;
color: #29262b;
&:is(.active) {
display: inline;
}
}
>section {
--shadow: 0px 10px 8px -4px rgba(0, 0, 0, 0.15);
position: relative;
display: flex;
flex-direction: column;
gap: 0.8em;
span {
font-family: Bahnschrift;
font-weight: 300;
}
>span {
font-size: 0.85em;
}
textarea {
margin-top: 0.2em;
min-width: 100%;
max-width: 100%;
width: 100%;
min-height: 8ch;
max-height: 60vh;
resize: vertical;
}
>:is(label, div).input.icon {
--title-height: 0.9em;
display: grid;
grid-template-columns: 1.3em auto;
grid-template-rows: var(--title-height, 1em) repeat(2, auto);
align-items: center;
grid-column-gap: 0.5em;
grid-row-gap: 0.2em;
>img.icon {
grid-column: 1;
grid-row: 2/3;
width: 100%;
}
>span.title {
grid-column: 2;
grid-row: 1;
/* margin-bottom: 0.2em; */
font-size: var(--title-height, 1em);
padding: 0 0.5em;
font-weight: 400;
font-family: 'Cascadia Code';
}
>:is(input, select, textarea) {
grid-column: 2;
grid-row: 2;
width: 100%;
border-radius: 0;
}
>small.guide {
grid-column: 2;
grid-row: 3;
margin-top: 0.2em;
}
}
>button {
padding: 1.2rem 1rem;
font-size: 1.1rem;
/* border: unset; */
&:first-of-type {
margin-top: 2rem;
}
}
}
}
}
}
@media (width < 1000px) {
body {
>main {
>article#offer {
margin-bottom: unset;
width: 100%;
border-radius: unset;
}
}
}
}

View File

@@ -20,26 +20,105 @@
--cookies-width: 24rem;
--cookies-height: 4rem;
font-family: "Commissioner";
font-family: "Share Tech Mono";
font-family: "Montserrat";
font-family: "Alumni Sans Pinstripe";
font-family: "DejaVu";
font-family: "Fira";
font-family: "Hack";
font-family: "Nunito", "DejaVu", sans-serif;
text-decoration: none;
outline: none;
border: none;
transition: 0.1s ease-out;
overscroll-behavior: none;
}
::selection {
color: #000;
background: #FF2;
text-shadow: none;
}
::-moz-selection {
color: #000;
background: #FF2;
text-shadow: none;
}
body {
margin: unset;
width: 100vw;
overflow-x: hidden;
background: var(--background-color, #fff);
background: var(--background-gradient);
/* background: var(--background-color, #fff);
background: var(--background-gradient); */
background-color: #020c13;
>div.vignette {
z-index: 100;
position: fixed;
top: 0;
width: 100vw;
min-height: 5000px;
height: 100vh;
justify-self: center;
align-self: center;
pointer-events: none;
background: linear-gradient(90deg, #000B -20%, #0000 50%, #000B 120%);
transform-origin: top center;
}
>div.dots {
--dot-bg: #18333f;
--dot-color: #041825;
--dot-size: 23px;
--dot-space: 24px;
z-index: -50;
position: fixed;
top: 0;
left: min(-30vw, -300px);
justify-self: center;
align-self: center;
width: max(250vw, 600px);
min-height: 5000px;
height: 200vh;
rotate: -16deg;
pointer-events: none;
background: linear-gradient(90deg, var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space), linear-gradient(var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), transparent 1%) center / var(--dot-space) var(--dot-space), var(--dot-color);
transform-origin: top left;
}
}
a {
text-decoration: unset;
color: var(--link-color);
&:is(:hover, :focus) {
color: var(--link-hover-color);
}
&:active {
color: var(--link-active-color);
}
&::selection {
color: #094ef2;
background: #dbd035;
text-shadow: none;
}
&::-moz-selection {
color: #094ef2;
background: #dbd035;
text-shadow: none;
}
/* &:is(.darked)::selection {
background: #000;
}
&:is(.darked)::-moz-selection {
background: #000;
} */
&:is(.tech) {
font-family: "Cascadia Code";
}
}
.unselectable {
@@ -67,6 +146,7 @@ input:not([type="range"]) {
outline: unset;
border: unset;
border-bottom: 1px solid;
border-radius: unset;
background: unset;
}
@@ -108,14 +188,20 @@ textarea {
}
button {
padding: 0.77em 1.3em 0.6em;
cursor: pointer;
font-family: Bahnschrift;
font-weight: 400;
cursor: pointer;
outline: unset;
background: unset;
&:disabled {
cursor: not-allowed;
}
&:not(.inline) {
padding: 0.77em 1.3em 0.6em;
border-radius: 0.75rem;
border: 1px solid #000;
background: unset;
&:not(:disabled) {
&:is(:hover, :focus) {
@@ -128,8 +214,8 @@ button {
}
&:disabled {
cursor: not-allowed;
background-color: #08111d17;
filter: grayscale(1) brightness(0.8);
filter: grayscale(1) brightness(0.55);
}
}
}

View File

@@ -0,0 +1,17 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M13 7H7V5H13V7Z" fill="currentColor" />
<path d="M13 11H7V9H13V11Z" fill="currentColor" />
<path d="M7 15H13V13H7V15Z" fill="currentColor" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3 19V1H17V5H21V23H7V19H3ZM15 17V3H5V17H15ZM17 7V19H9V21H19V7H17Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 429 B

View File

@@ -1,71 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="129.54482mm"
height="125.09652mm"
viewBox="0 0 129.54482 125.09652"
version="1.1"
id="svg1"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<linearGradient
id="linearGradient3">
<stop
style="stop-color:#0060c6;stop-opacity:1;"
offset="0.20645721"
id="stop3" />
<stop
style="stop-color:#000356;stop-opacity:1;"
offset="0.9989059"
id="stop4" />
</linearGradient>
<linearGradient
id="linearGradient1">
<stop
style="stop-color:#6fc4ff;stop-opacity:1;"
offset="0.17076893"
id="stop1" />
<stop
style="stop-color:#0adf70;stop-opacity:0.63586265;"
offset="1"
id="stop2" />
</linearGradient>
<radialGradient
xlink:href="#linearGradient3"
id="radialGradient4"
cx="69.684677"
cy="90.595695"
fx="69.684677"
fy="90.595695"
r="49.385239"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.4657787,-0.63256258,0.71685408,1.6610996,-96.020968,-9.4714476)" />
<radialGradient
xlink:href="#linearGradient1"
id="radialGradient8"
cx="133.0006"
cy="106.39822"
fx="133.0006"
fy="106.39822"
r="64.772408"
gradientTransform="matrix(-2.5562072,0.53679846,-0.45438206,-2.1637443,446.93777,196.26702)"
gradientUnits="userSpaceOnUse" />
</defs>
<path
style="display:inline;fill:url(#radialGradient4);fill-opacity:0.983988;fill-rule:nonzero;stroke-width:2.22122;paint-order:stroke fill markers"
id="path2"
d="M 114.14959,66.009985 A 49.385239,49.385239 0 0 1 65.162476,115.39362 49.385239,49.385239 0 0 1 15.38553,66.806211 49.385239,49.385239 0 0 1 63.570075,16.639189 49.385239,49.385239 0 0 1 114.12391,64.41774" />
<path
id="path1"
style="display:inline;fill:url(#radialGradient8);stroke-width:2.64583;paint-order:stroke fill markers"
d="m 129.54482,60.324142 c 0,35.56901 -28.68229,64.483468 -64.250152,64.770218 C 29.72681,125.38111 0.58206084,96.932842 0.00858984,61.368452 -0.27814616,43.586256 6.6315828,27.351873 18.057823,15.455519 L 32.789578,50.834474 64.751888,64.645522 63.781478,106.2899 99.850468,58.627162 73.743498,34.999493 88.406328,0 c 7.79332,3.057143 14.862732,7.58429 20.856772,13.249271 5.99404,5.664982 10.91271,12.467797 14.40455,20.076274 3.49183,7.608477 5.55683,16.022617 5.84353,24.910247" />
<path
id="path5"
style="display:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="m 156.03189,48.675988 c 0,0 -0.48124,1.149734 -0.48124,1.149734 7.47158,3.127366 13.76035,8.757556 18.60133,15.033917 3.47372,4.503708 5.77328,8.679785 8.08747,12.343411 1.02716,1.626109 1.99256,3.317001 2.88786,5.073729 5.57385,10.936769 8.27496,24.254811 6.33597,38.307871 -1.81681,13.16752 -7.63944,25.96117 -17.4307,35.65948 -5.03375,4.98596 -10.97996,9.0142 -17.69827,11.85196 -7.22782,3.05296 -15.1235,4.63388 -23.42167,4.73245 -0.85262,0.0108 -1.69223,0.004 -2.51863,-0.0189 -14.1633,-0.39672 -25.57791,-5.05285 -34.17105,-11.0133 C 85.038155,154.03818 77.884734,143.64417 73.765338,134.02513 68.088136,120.76851 67.595266,108.31489 69.031333,98.509565 70.913466,85.658549 76.262275,76.52398 79.737684,71.524371 c 3.696594,-5.317797 5.945701,-7.392864 5.945701,-7.392864 0,0 -2.33932,1.972559 -6.214586,7.199789 -3.636021,4.904518 -9.303495,13.993979 -11.461258,27.018426 -1.64637,9.937638 -1.344521,22.656968 4.328486,36.278968 4.114552,9.87985 11.373099,20.61326 22.855995,28.64738 8.830228,6.17816 20.582878,10.99648 35.149578,11.4045 0.84878,0.0238 1.71085,0.0347 2.58621,0.0316 8.48799,-0.0368 16.67375,-1.34049 24.38977,-4.07858 7.17719,-2.54687 13.78867,-6.28188 19.64994,-11.14174 11.39583,-9.44885 19.35723,-22.68375 22.78331,-37.34635 3.64637,-15.60541 1.86385,-31.494338 -4.58101,-44.839852 -1.02738,-2.127422 -2.16303,-4.170709 -3.39713,-6.124429 -2.75251,-4.35753 -6.99513,-8.511352 -12.19307,-12.129511 -7.56806,-5.267932 -15.28231,-8.267232 -23.06649,-11.525444 0,0 -0.48124,1.149734 -0.48124,1.149734 z"
transform="translate(-67.625562,-48.675988)" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="489.618" height="472.806" viewBox="0 0 129.545 125.097"><defs><radialGradient xlink:href="#a" id="c" cx="69.685" cy="90.596" r="49.385" fx="69.685" fy="90.596" gradientTransform="matrix(1.46578 -.63256 .71685 1.6611 -96.021 -9.471)" gradientUnits="userSpaceOnUse"/><radialGradient xlink:href="#b" id="d" cx="133.001" cy="106.398" r="64.772" fx="133.001" fy="106.398" gradientTransform="matrix(-2.5562 .5368 -.45438 -2.16374 446.938 196.267)" gradientUnits="userSpaceOnUse"/><linearGradient id="a"><stop offset=".206" style="stop-color:#0060c6;stop-opacity:1"/><stop offset=".999" style="stop-color:#000356;stop-opacity:1"/></linearGradient><linearGradient id="b"><stop offset=".171" style="stop-color:#6fc4ff;stop-opacity:1"/><stop offset="1" style="stop-color:#0adf70;stop-opacity:.63586265"/></linearGradient></defs><path d="M114.15 66.01a49.385 49.385 0 0 1-48.988 49.384 49.385 49.385 0 0 1-49.776-48.588A49.385 49.385 0 0 1 63.57 16.64a49.385 49.385 0 0 1 50.554 47.779" style="display:inline;fill:url(#c);fill-opacity:.983988;fill-rule:nonzero;stroke-width:2.22122;paint-order:stroke fill markers"/><path d="M129.545 60.324c0 35.57-28.682 64.484-64.25 64.77S.582 96.933.009 61.368c-.287-17.782 6.623-34.016 18.049-45.912L32.79 50.834l31.962 13.812-.97 41.644L99.85 58.627 73.743 35 88.406 0a64.9 64.9 0 0 1 20.857 13.25 64.9 64.9 0 0 1 14.405 20.076 64.6 64.6 0 0 1 5.843 24.91" style="display:inline;fill:url(#d);stroke-width:2.64583;paint-order:stroke fill markers"/></svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 1000 1000"><defs><linearGradient id="b"><stop offset="0" stop-color="#00f"/><stop offset="1" stop-opacity="0"/><stop offset="1" stop-opacity="0"/></linearGradient><linearGradient id="a"><stop offset="0" stop-color="#4cf"/><stop offset=".662" stop-color="#53e"/><stop offset="1" stop-color="#93d"/></linearGradient><linearGradient id="c" x1="117.847" x2="1000" y1="760.536" y2="500" gradientUnits="userSpaceOnUse" href="#a"/><radialGradient id="d" cx="-87.392" cy="1166.116" r="500" fx="-87.392" fy="1166.116" gradientTransform="rotate(51.356 1551.476 559.302)scale(2.42703 1)" gradientUnits="userSpaceOnUse" href="#b"/></defs><rect width="1000" height="1000" fill="url(#c)" ry="249.681"/><rect width="1000" height="1000" fill="url(#d)" ry="249.681"/><path fill="#fff" fill-rule="evenodd" d="M508.211 878.328c-75.007 0-109.864-10.95-170.453-54.75-38.325 49.275-159.686 87.783-164.979 21.9 0-49.456-10.95-91.248-23.36-136.873-14.782-56.21-31.572-118.807-31.572-209.508 0-216.626 177.754-379.597 388.357-379.597 210.785 0 375.947 171.001 375.947 381.604.707 207.346-166.595 376.118-373.94 377.224m3.103-571.585c-102.564-5.292-182.499 65.7-200.201 177.024-14.6 92.162 11.315 204.398 33.397 210.238 10.585 2.555 37.23-18.98 53.837-35.587a189.8 189.8 0 0 0 92.71 33.032c106.273 5.112 197.08-75.794 204.215-181.95 4.154-106.382-77.67-196.486-183.958-202.574Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,16 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
<title>Artboard</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="99.2583404%" id="linearGradient-1">
<stop stop-color="#2AABEE" offset="0%"></stop>
<stop stop-color="#229ED9" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<circle id="Oval" fill="url(#linearGradient-1)" cx="500" cy="500" r="500"></circle>
<path d="M226.328419,494.722069 C372.088573,431.216685 469.284839,389.350049 517.917216,369.122161 C656.772535,311.36743 685.625481,301.334815 704.431427,301.003532 C708.567621,300.93067 717.815839,301.955743 723.806446,306.816707 C728.864797,310.92121 730.256552,316.46581 730.922551,320.357329 C731.588551,324.248848 732.417879,333.113828 731.758626,340.040666 C724.234007,419.102486 691.675104,610.964674 675.110982,699.515267 C668.10208,736.984342 654.301336,749.547532 640.940618,750.777006 C611.904684,753.448938 589.856115,731.588035 561.733393,713.153237 C517.726886,684.306416 492.866009,666.349181 450.150074,638.200013 C400.78442,605.66878 432.786119,587.789048 460.919462,558.568563 C468.282091,550.921423 596.21508,434.556479 598.691227,424.000355 C599.00091,422.680135 599.288312,417.758981 596.36474,415.160431 C593.441168,412.561881 589.126229,413.450484 586.012448,414.157198 C581.598758,415.158943 511.297793,461.625274 375.109553,553.556189 C355.154858,567.258623 337.080515,573.934908 320.886524,573.585046 C303.033948,573.199351 268.692754,563.490928 243.163606,555.192408 C211.851067,545.013936 186.964484,539.632504 189.131547,522.346309 C190.260287,513.342589 202.659244,504.134509 226.328419,494.722069 Z" id="Path-3" fill="#FFFFFF"></path>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"><defs><linearGradient id="a" x1="50%" x2="50%" y1="0%" y2="99.258%"><stop offset="0%" stop-color="#2AABEE"/><stop offset="100%" stop-color="#229ED9"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><circle cx="500" cy="500" r="500" fill="url(#a)"/><path fill="#FFF" d="M226.328 494.722q218.64-95.258 291.59-125.6c138.855-57.755 167.707-67.787 186.513-68.118 4.137-.073 13.385.952 19.375 5.813 5.059 4.104 6.45 9.649 7.117 13.54s1.495 12.757.836 19.684c-7.525 79.061-40.084 270.924-56.648 359.474-7.009 37.47-20.81 50.033-34.17 51.262-29.036 2.672-51.085-19.189-79.208-37.624-44.006-28.847-68.867-46.804-111.583-74.953-49.366-32.531-17.364-50.411 10.77-79.631C468.281 550.92 596.214 434.556 598.69 424c.31-1.32.597-6.241-2.326-8.84-2.924-2.598-7.239-1.71-10.353-1.003q-6.62 1.503-210.902 139.4-29.933 20.553-54.223 20.028c-17.853-.386-52.194-10.094-77.723-18.393-31.313-10.178-56.2-15.56-54.032-32.846q1.692-13.505 37.196-27.624"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1018 B

View File

@@ -0,0 +1,17 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M13 7H7V5H13V7Z" fill="#fff" />
<path d="M13 11H7V9H13V11Z" fill="#fff" />
<path d="M7 15H13V13H7V15Z" fill="#fff" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3 19V1H17V5H21V23H7V19H3ZM15 17V3H5V17H15ZM17 7V19H9V21H19V7H17Z"
fill="#fff"
/>
</svg>

After

Width:  |  Height:  |  Size: 398 B

View File

@@ -1,15 +1,49 @@
<?php
// Initializing default theme for the views templater
define('THEME', 'default');
define('DOMAIN', 'kodorvan.tech');
define('COMPANY', [
'identifier' => '000000000000000',
'tax' => '000000000000',
'name' => [
'short' => 'ИП Мирзаев',
'full' => 'ИП Мирзаев Арсен Магомедович'
],
'address' => [
'full' => 'Пермь'
],
'worktime' => [
'from' => '10:00',
'to' => '19:00'
],
'contacts' => [
'request' => [
'sim' => [
'full' => '79005004010',
'country' => '7',
'operator' => '900',
'number' => ['500', '40', '10']
],
'mail' => 'request@kodorvan.tech'
]
]
]);
define('MAIL', [
'host' => 'smtp.mail.ru',
'sender' => [
'mail' => 'system@kodorvan.tech',
'name' => 'Система',
'password' => '',
],
'receiver' => [
'mail' => 'request@kodorvan.tech',
'name' => 'Заявки'
]
]);
define('TELEGRAM_ROBOT', [
'domain' => 'kodorvan_bot'
]);
define('PROJECT_CONTACTS_SIM_REQUESTS', '79005004010');
define('PROJECT_CONTACTS_SIM_REQUESTS_COUNTRY', '7');
define('PROJECT_CONTACTS_SIM_REQUESTS_OPERATOR', '900');
define('PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_1', '500');
define('PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_2', '40');
define('PROJECT_CONTACTS_SIM_REQUESTS_NUMBER_3', '10');

View File

@@ -0,0 +1,2 @@
*
!.gitignore

View File

@@ -63,6 +63,8 @@ final class templater extends controller implements array_access
// Initializing global variables
$this->twig->addGlobal('theme', THEME);
$this->twig->addGlobal('domain', DOMAIN);
$this->twig->addGlobal('company', COMPANY);
$this->twig->addGlobal('server', $_SERVER);
$this->twig->addGlobal('cookies', $_COOKIE);
$this->twig->addGlobal('language', $language = $session?->buffer['language'] ?? language::en);

View File

@@ -13,7 +13,7 @@
{% block css %}
{% endblock %}
{% include '/elements/yandex.html' %}
{% include '/metrics/yandex.html' %}
</head>
<body>

View File

@@ -46,12 +46,12 @@
</section>
<script>
document.addEventListener('core.initialized', () =>
document.addEventListener('core.initialized', () =>
core.modules.connect(["hotline"]).then((connected) => {
// Imported the hotline.mjs module
// Initializing an instance of the hotline.mjs
const instance = new connected.hotline(document.getElementById("cases"));
const instance = new connected.global.hotline(document.getElementById("cases"));
// Initializing settings of the hotline instance
instance.alive = true;
@@ -62,5 +62,5 @@ document.addEventListener('core.initialized', () =>
// Starting the hotline instance
instance.start();
})
);
);
</script>

View File

@@ -1,16 +1,16 @@
<section id="companies" class="unselectable">
<article id="companies" class="unselectable">
{% for alt, file in integrations %}
<img class="{{ file }}" src="/themes/{{ theme }}/images/logotypes/{{ file }}.svg" alt="{{ alt }}" ondragstart="return false"/>
{% endfor %}
</section>
</article>
<script>
document.addEventListener('core.initialized', () =>
document.addEventListener('core.initialized', () =>
core.modules.connect(["hotline"]).then((connected) => {
// Imported the hotline.mjs module
// Initializing an instance of the hotline.mjs
const instance = new connected.hotline(document.getElementById("companies"));
const instance = new connected.global.hotline(document.getElementById("companies"));
// Initializing settings of the hotline instance
instance.alive = true;
@@ -18,10 +18,10 @@ document.addEventListener('core.initialized', () =>
instance.movable = false;
instance.hover = false;
instance.delta = 3;
instance.step = 0.2;
instance.step = -0.2;
// Starting the hotline instance
instance.start();
})
);
);
</script>

View File

@@ -1,11 +1,19 @@
<section id="cookies" class="unselectable">
<div class="popup">
<div class="popup" aria-label="Используется технология cookies">
<div>
<p>ИСПОЛЬЗУЕТСЯ ТЕХНОЛОГИЯ COOKIES</p>
<small>№152-ФЗ «О персональных данных»</small>
</div>
</div>
<button onclick="let date = new Date(); document.cookie = 'cookies_popup_closed=true; expires=' + date.setDate(date.getDate() + 7) + '; path=/'; setTimeout(() => this.parentElement.remove(), 700); this.parentElement.style.opacity = 0">
<img class="cookie" src="/themes/default/images/cookie.png" alt="kodorvan cookies" ondragstart="return false" />
<button
onclick="let date = new Date(); document.cookie = 'cookies_popup_closed=true; expires=' + date.setDate(date.getDate() + 7) + '; path=/'; setTimeout(() => this.parentElement.remove(), 700); this.parentElement.style.opacity = 0"
title="Закрыть"
>
<img
class="cookie"
src="/themes/default/images/cookie.png"
alt="kodorvan cookies"
ondragstart="return false"
/>
</button>
</section>

View File

@@ -28,9 +28,9 @@
class="input"
name="architecture_input"
autocomplete="off"
oninput="core.project.architecture = this.value"
oninput="core.global.project.architecture = this.value"
>
<option value="" selected="true" disabled="true" hidden="true" data-paginator-select-title="true">Выберите архитектуру</option>
<option value="" selected="true" disabled="true" hidden="true" data-project-select-title="true">Выберите архитектуру</option>
{% for value, label in project.architectures %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
@@ -45,9 +45,9 @@
class="input"
name="purpose_input"
autocomplete="off"
oninput="core.project.purpose = this.value"
oninput="core.global.project.purpose = this.value"
>
<option value="" selected="true" disabled="true" hidden="true" data-paginator-select-title="true">Выберите назначение</option>
<option value="" selected="true" disabled="true" hidden="true" data-project-select-title="true">Выберите назначение</option>
{% for value, label in project.purposes %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
@@ -67,7 +67,7 @@
type="checkbox"
value=""
autocomplete="off"
onchange="this.checked ? core.project.integrate(this.value) : core.project.desintegrate(this.value)"
onchange="this.checked ? core.global.project.integrate(this.value) : core.global.project.desintegrate(this.value)"
/>
<label for="integration_input_{{ value}}">{{ label }}</label>
</div>
@@ -80,7 +80,6 @@
<section id="team" class="row" style="display: none;">
<fieldset>
<legend>Команда</legend>
<div class="row">
<label for="programmers">
<input
id="programmers"
@@ -90,7 +89,7 @@
max="3"
value="0"
autocomplete="off"
onkeyup="core.project.programmers = this.value"
onkeyup="core.global.project.programmers = this.value"
/>
<span>Программисты</span>
</label>
@@ -103,7 +102,7 @@
max="4"
value="0"
autocomplete="off"
onkeyup="core.project.designers = this.value"
onkeyup="core.global.project.designers = this.value"
/>
<span>Дизайнеры</span>
</label>
@@ -116,11 +115,10 @@
max="2"
value="0"
autocomplete="off"
onkeyup="core.project.boosters = this.value"
onkeyup="core.global.project.boosters = this.value"
/>
<span>Бустеры</span>
</label>
</div>
</fieldset>
<small class="guide">Соберите команду разработчиков проекта</small>
</section>
@@ -137,7 +135,7 @@
max="5000"
value="1800"
autocomplete="off"
oninput="document.getElementById('hour_input_range').value = this.value; core.project.hour = this.value;"
oninput="document.getElementById('hour_input_range').value = this.value; core.global.project.hour = this.value;"
/>
<span class="currency rubles"></span>
<input
@@ -149,7 +147,7 @@
step="100"
value="1800"
autocomplete="off"
oninput="document.getElementById('hour_input_number').value = this.value; core.project.hour = this.value;"
oninput="document.getElementById('hour_input_number').value = this.value; core.global.project.hour = this.value;"
/>
</div>
<small class="guide">Введите предложение оплаты за рабочий час команды</small>
@@ -170,7 +168,7 @@
placeholder="Проект А"
value=""
autocomplete="off"
onkeyup="core.project.project.name = this.value"
onkeyup="core.global.project.project.name = this.value"
/>
<small class="guide active">Введите внутреннее название проекта</small>
</label>
@@ -186,7 +184,7 @@
value=""
autocomplete="off"
placeholder="Сделайте, чтобы всё было красиво, спасибо"
onkeyup="core.project.project.description = this.value"
onkeyup="core.global.project.project.description = this.value"
></textarea>
<small class="guide active">Опишите задачу в свободной форме</small>
</label>
@@ -206,7 +204,7 @@
multiple="true"
value=""
autocomplete="off"
oninput="core.project.project.files = this.files"
oninput="core.global.project.project.files = this.files"
/>
</div>
</div>
@@ -226,7 +224,7 @@
placeholder="Богдан"
value=""
autocomplete="off"
onkeyup="core.project.requester.name = this.value"
onkeyup="core.global.project.requester.name = this.value"
/>
<small class="guide active">Введите ваши инициалы</small>
</label>
@@ -241,7 +239,7 @@
placeholder="7 (000) 000 0000"
value=""
autocomplete="off"
onkeyup="core.project.requester.sim = this.value"
onkeyup="core.global.project.requester.sim = this.value"
/>
<small class="guide active">Введите номер телефона для связи</small>
</label>
@@ -256,7 +254,7 @@
placeholder="project@company.org"
value=""
autocomplete="off"
onkeyup="core.project.requester.mail = this.value"
onkeyup="core.global.project.requester.mail = this.value"
/>
<small class="guide active">Введите почту для связи</small>
</label>
@@ -272,7 +270,7 @@
value=""
autocomplete="off"
placeholder="Синяя программа: @zornhut"
onkeyup="core.project.requester.other = this.value"
onkeyup="core.global.project.requester.other = this.value"
></textarea>
<small class="guide active">Введите дополнительные удобные способы связи</small>
</label>
@@ -288,7 +286,7 @@
type="checkbox"
value=""
autocomplete="off"
oninput="core.project.requester.personal = this.checked"
oninput="core.global.project.requester.personal = this.checked"
/>
<img src="/themes/default/images/icons/circle.svg" alt="lock kodorvan" style="display: var(--display, none)" ondragstart="return false"/>
<img src="/themes/default/images/icons/circle_dot.svg" alt="unlock kodorvan" style="display: var(--display, none)" ondragstart="return false"/>
@@ -308,33 +306,34 @@
</article>
<div class="adaptive">
<button id="back" class="unselectable" onclick="core.paginator.relative(-1)" style="display: none">
<button id="back" class="unselectable" onclick="core.global.paginator.relative(-1)" style="display: none">
<img src="/themes/default/images/icons/arrow_left.svg" alt="back button kodorvan" ondragstart="return false"/>
</button>
<section id="buttons" style="display: none">
<button onclick="core.paginator.relative(1)" data-paginator-page-button="1">ПРОДОЛЖИТЬ</button>
<button onclick="core.paginator.relative(1)" style="display: none" data-paginator-page-button="2" disabled="true">ПРОДОЛЖИТЬ</button>
<button onclick="core.global.paginator.relative(1)" data-paginator-page-button="1">ПРОДОЛЖИТЬ</button>
<button onclick="core.global.paginator.relative(1)" style="display: none" data-paginator-page-button="2" disabled="true">ПРОДОЛЖИТЬ</button>
<button
id="send"
class="gradient"
style="display: none"
onclick="core.project.send();"
onclick="core.global.project.send();"
data-paginator-page-button="3"
disabled="true"
>
<span>НАЧАТЬ РАЗРАБОТКУ</span>
<div class="color yellow"></div>
<div class="color green"></div>
<div class="color blue"></div>
</button>
>СОЗДАТЬ ПРОЕКТ</button>
</section>
<script>
const send = document.getElementById('send');
let deg = 120;
setInterval(() => send.style.setProperty('--button-send-background-color', (deg += 43) + 'deg'), 1200);
</script>
</div>
<small class="offer unselectable">Создан для удобства и <b>не является публичной офертой</b></br>Точная стоимость после изучения задания</small>
<small class="offer unselectable">Создан для удобного планирования и <b>не является <a href="/offer" rel="terms-of-service noopener">публичной офертой</a></b></small>
<section id="contacts_shortcut">
<p class="sim"><span class="country">7</span><span class="operator">901</span><span>592</span><span>4211</span></p>
{% include '/themes/default/interface/media.html' %}
{% include '/themes/default/interface/sim.html' %}
<small class="unselectable">ЗВОНИТЕ ПО НОМЕРУ</small>
</section>
</section>

View File

@@ -0,0 +1,195 @@
<style>
:root {
--project-loading: "{{ language.name == 'ru' or true ? 'Загрузка' : 'Loading' }}";
}
</style>
<section id="project">
<div>
<h1 class="unselectable">СОЗДАНИЕ ПРОЕКТА</h1>
<span class="unselectable">Отправьте заявку и получите бесплатный<br/>расчёт с индивидуальными рекомендациями!</span>
</div>
<noscript>
<b>Калькулятор не загрузится в вашем браузере</b></br>
<i>Оформите заказ через звонок оператору по номеру {{ contacts.sim.requests.full ?? 'Ошибка' }}</i>
</noscript>
<article class="loading" aria-label="Конструктор проекта">
<div class="loading"><i class="icon loading spinner animated"></i></div>
<section data-paginator-page="2" data-paginator-page-focus="name_input" class="unselectable">
<section id="metadata">
<label id="project_name" class="input icon" for="project_name_input">
<img class="icon" src="/themes/default/images/icons/nametag.svg" alt="nametag kodorvan" ondragstart="return false"/>
<span class="title">Название</span>
<input
id="project_name_input"
class="input"
name="project_name_input"
type="text"
placeholder="Проект А"
value=""
autocomplete="off"
onkeyup="core.global.project.project.name = this.value"
/>
<small class="guide active">Введите внутреннее название проекта</small>
</label>
<label id="project_description" class="input icon" for="project_description_input">
<img class="icon" src="/themes/default/images/icons/notes.svg" alt="notes kodorvan" ondragstart="return false"/>
<span class="title">Описание</span>
<textarea
id="project_description_input"
class="input"
name="project_description_input"
cols="100%"
maxlength="4096"
value=""
autocomplete="off"
placeholder="Сделайте, чтобы всё было красиво, спасибо"
onkeyup="core.global.project.project.description = this.value"
></textarea>
<small class="guide active">Опишите задачу в свободной форме</small>
</label>
<div id="project_files" class="input icon">
<img class="icon" src="/themes/default/images/icons/import.svg" alt="import kodorvan" ondragstart="return false"/>
<div>
<span class="title">Импорт</span>
<ol style="display: none;" class="files"></ol>
<small class="guide active">Загрузите документы и изображения</small>
<label class="pseudoinput" for="project_files_input"></label>
<input
id="project_files_input"
class="input"
name="project_files_input"
type="file",
accept="image/*,.pdf,pptx,.doc,.docx,.odt,.word,.pages,.rtf,.txt"
multiple="true"
value=""
autocomplete="off"
oninput="core.global.project.project.files = this.files"
/>
</div>
</div>
</section>
</section>
<section data-paginator-page="3" data-paginator-page-focus="requester_name_input" class="unselectable" style="display: none;">
<section id="requester">
<label id="requester_name" class="input icon" for="requester_name_input">
<img class="icon" src="/themes/default/images/icons/smile.svg" alt="smile kodorvan" ondragstart="return false"/>
<span class="title">Представитель</span>
<input
id="requester_name_input"
class="input"
name="requester_name_input"
type="text"
placeholder="Богдан"
value=""
autocomplete="off"
onkeyup="core.global.project.requester.name = this.value"
/>
<small class="guide active">Введите ваши инициалы</small>
</label>
<label id="requester_sim" class="input icon" for="requester_sim_input">
<img class="icon" src="/themes/default/images/icons/phone.svg" alt="phone kodorvan" ondragstart="return false"/>
<span class="title">SIM-номер</span>
<input
id="requester_sim_input"
class="input"
name="requester_sim_input"
type="text"
placeholder="7 (000) 000 0000"
value=""
autocomplete="off"
onkeyup="core.global.project.requester.sim = this.value"
/>
<small class="guide active">Введите номер телефона для связи</small>
</label>
<label id="requester_mail" class="input icon" for="requester_mail_input">
<img class="icon" src="/themes/default/images/icons/mail.svg" alt="mail kodorvan" ondragstart="return false"/>
<span class="title">Почта</span>
<input
id="requester_mail_input"
class="input"
name="requester_mail_input"
type="email"
placeholder="project@company.org"
value=""
autocomplete="off"
onkeyup="core.global.project.requester.mail = this.value"
/>
<small class="guide active">Введите почту для связи</small>
</label>
<label id="requester_other" class="input icon"for="requester_other_input">
<img class="icon" src="/themes/default/images/icons/comment.svg" alt="comment kodorvan" ondragstart="return false"/>
<span class="title">Дополнительные контакты</span>
<textarea
id="requester_other_input"
class="input"
name="name_input"
cols="100%"
maxlength="2048"
value=""
autocomplete="off"
placeholder="Синяя программа: @zornhut"
onkeyup="core.global.project.requester.other = this.value"
></textarea>
<small class="guide active">Введите дополнительные удобные способы связи</small>
</label>
</section>
<section id="confirmation">
<label id="requester_personal" for="requester_personal_input">
<div>
<input
id="requester_personal_input"
class="input"
name="requester_personal_input"
type="checkbox"
value=""
autocomplete="off"
oninput="core.global.project.requester.personal = this.checked"
/>
<img src="/themes/default/images/icons/circle.svg" alt="lock kodorvan" style="display: var(--display, none)" ondragstart="return false"/>
<img src="/themes/default/images/icons/circle_dot.svg" alt="unlock kodorvan" style="display: var(--display, none)" ondragstart="return false"/>
</div>
<span class="title">Разрешаю запись, обработку и хранение моих персональных данных</span>
</label>
</section>
</section>
</article>
<div class="adaptive">
<button id="back" class="unselectable" onclick="core.global.paginator.relative(-1)" style="display: none">
<img src="/themes/default/images/icons/arrow_left.svg" alt="back button kodorvan" ondragstart="return false"/>
</button>
<section id="buttons">
<button onclick="core.global.paginator.relative(1)" data-paginator-page-button="2" disabled="true">ПРОДОЛЖИТЬ</button>
<button
id="send"
style="display: none"
onclick="core.global.project.send();"
data-paginator-page-button="3"
disabled="true"
>СОЗДАТЬ ПРОЕКТ</button>
</section>
<script>
const send = document.getElementById('send');
let deg = 120;
setInterval(() => send.style.setProperty('--button-send-background-color', (deg += 43) + 'deg'), 1200);
</script>
</div>
<small class="description unselectable"><strong>Команда разработчиков</strong> - мы реальные исполнители из <strong>Перми</strong>! <wbr/>Передача кода заказчику в его полную собственность и подпись <b>NDA</b>. Не используем ИИ в разработке! <wbr/><b>Полная анонимность</b> проектов - никто не узнает кто разработчик. <wbr/><b>Не оставляем</b> блокировки и скрытую рекламу в коде!</small>
<small class="guarantee unselectable"><strong>Гарантия качества</strong><b>:</b> небольшие и простые проекты мы передаём нашим студентам, но за качество кода и соблюдение сроков всегда отвечает наставник!</small>
<b class="partners unselectable">Поддерживаем проекты наших<br/>партнёров с 2014 года!</b>
<section id="contacts_shortcut">
{% include '/themes/default/interface/media.html' %}
{% include '/themes/default/interface/sim.html' %}
<small class="unselectable">ЗВОНИТЕ ПО НОМЕРУ</small>
</section>
</section>

View File

@@ -0,0 +1,67 @@
<article id="rofls" class="unselectable" style="display: none;">
<img class="construction" loading="lazy" src="https://lyra.horse/css-clicker/buttons/construction.gif" width="88px" height="31px"
ondragstart="return false;" />
<img loading="lazy" src="https://lyra.horse/css-clicker/buttons/css2.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://lyra.horse/css-clicker/buttons/dbd.gif" width="88px" height="31px" ondragstart="return false;" />
<!-- <img loading="lazy" src="https://lyra.horse/css-clicker/buttons/gaywebring.gif" width="88px" height="31px" ondragstart="return false;" /> -->
<!-- <img loading="lazy" src="https://lyra.horse/css-clicker/buttons/miku.gif" width="88px" height="31px" ondragstart="return false;" /> -->
<img loading="lazy" src="https://lyra.horse/css-clicker/buttons/mozbutd1.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://lyra.horse/css-clicker/buttons/nofuckingthanks.gif" width="88px" height="31px" ondragstart="return false;" />
<img class="noclick" loading="lazy" src="https://maia.crimew.gay/badges/noclick.gif" width="88px" height="31px" onclick="alert('bruh');"
ondragstart="return false;" />
<img loading="lazy" src="https://cyber.dabamos.de/88x31/zanarkand.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/antinazi.gif" width="88px" height="31px" ondragstart="return false;" />
<img class="hell" loading="lazy" src="https://cyber.dabamos.de/88x31/tohell.gif" width="88px" height="31px" ondragstart="return false;"
ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/say-no-to-web3.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/they-walk-among-us.png" width="88px" height="31px" ondragstart="return false;" />
<img class="eye" loading="lazy" src="https://88x31.nl/gifs/uranohead.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/discord-no-way.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/chat.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/upallnight%20(3).gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://lyra.horse/css-clicker/buttons/free-sex.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/virusalert.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://cyber.dabamos.de/88x31/microsoft_stop.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/linuxnow2.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/vim.vialle.love.anim.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://cyber.dabamos.de/88x31/tummy.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/anybrow%20(3).gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/camtime.png" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/reshirii.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/alien2.gif" width="88px" height="31px" ondragstart="return false;" />
<img class="antibuttons" loading="lazy" src="https://88x31.nl/gifs/anti_button.gif" width="88px" height="31px"
onclick="alert('BUTTONS SUCKS!'); document.getElementById('buttons').remove();" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/fspeech96a.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/saratov.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/thatpays2.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://lyra.horse/css-clicker/buttons/antinft.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/tumblr_ptmmk6djdu1xwjivko5_100.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/ieshit.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/underground.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/volta.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/ocartswap_2.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/f_ckfb.gif" width="88px" height="31px" ondragstart="return false;" />
<img class="cogs" loading="lazy" src="https://88x31.nl/gifs/cogs.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://88x31.nl/gifs/antifa.gif" width="88px" height="31px" ondragstart="return false;" />
<img loading="lazy" src="https://cyber.dabamos.de/88x31/newbuttonone.gif" width="88px" height="31px" ondragstart="return false;" />
<img class="colors" loading="lazy" src="https://88x31.nl/gifs/bestviewed16bit.gif" width="88px" height="31px" ondragstart="return false;" />
</article>
<script>
document.addEventListener('core.initialized', () =>
core.modules.connect(["hotline"]).then((connected) => {
// Imported the hotline.mjs module
// Initializing an instance of the hotline.mjs
const instance = new connected.global.hotline(document.getElementById("rofls"), true);
// Initializing settings of the hotline instance
instance.alive = true;
instance.wheel = true;
instance.movable = true;
instance.hover = true;
instance.delta = 3.2;
instance.step = -0.2;
})
);
</script>

View File

@@ -52,7 +52,7 @@
{% for button in buttons %}
{% set icon = button.icon ?? 'close' %}
<link type="text/css" rel="stylesheet" href="/css/icons/{{ button.icon|replace({' ': '_'}) }}.css" />
<a type="button" href="{{ button.href }}" target="_blank" rel="nofollow noopener noreferrer"><i class="icon {{ button.icon }}"></i></a>
<a type="button" href="{{ button.href }}" target="_blank" rel="external nofollow noopener noreferrer"><i class="icon {{ button.icon }}"></i></a>
{% endfor %}
</div>
{% endif %}

View File

@@ -9,43 +9,53 @@
--company-tax: "{{ language.name == 'ru' or true ? 'ИНН' : 'TAX' }}";
}
</style>
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/rofls.css" />
{% endblock %}
{% block body %}
<footer>
<div class="sector">
<article id="office">
<article class="company">
<div class="map">
<div class="loading">
<i class="icon loading spinner animated"></i>
</div>
</div>
<div class="information">
<h1 class="name">{{ company.name.short }}</h1>
<p class="column">
<span class="tax row">{{ company.tax }}</span>
<span class="identifier row">{{ company.identifier }}</span>
</p>
<p class="worktime unselectable">
{% if company.address.full is not empty %}{{ company.address.full }}{% endif %},
<span class="time from">{{ company.worktime.from }}</span>
<span class="time to">{{ company.worktime.to }}</span>
</p>
</div>
</article>
<article class="contacts">
{% include '/themes/default/interface/sim.html' %}
{% if company.contacts.request.mail is not empty %}
<a class="mail support" href="mailto:{{ company.contacts.request.mail }}" rel="external noreferrer noopener nofollow">{{ company.contacts.request.mail }}</a>
{% endif %}
{% include '/themes/default/interface/media.html' %}
</article>
</div>
<nav id="links" class="unselectable">
<a href="/offer">ПУБЛИЧНАЯ ОФЕРТА</a>
<a href="https://ru.wikipedia.org/wiki/WTFPL">ЛИЦЕНЗИЯ</a>
<a href="https://t.me/kodorvan">КОДОРВАНЬ</a>
<a href="https://t.me/from_mirzaev">МИРЗАЕВ</a>
<a href="https://git.svoboda.works/kodorvan">РЕПОЗИТОРИЙ</a>
<a href="/offer" rel="terms-of-service noopener">ОФЕРТА</a>
<a href="/policy" rel="privacy-policy noopener">ПОЛИТИКА</a>
<a href="https://ru.wikipedia.org/wiki/WTFPL" rel="license external nofollow noopener" >ЛИЦЕНЗИЯ</a>
<a href="https://git.svoboda.works/kodorvan" rel="external nofollow noopener">РЕПОЗИТОРИЙ</a>
<a href="https://t.me/kodorvan" rel="help external nofollow noopener">БЛОГ</a>
<a href="https://t.me/from_mirzaev" rel="author external nofollow noopener">МИРЗАЕВ</a>
</nav>
</div>
<div class="sector company">
<article id="contacts">
<h1 class="sim"><span class="country">7</span><span class="operator">901</span><span>592</span><span>4211</span></h1>
<span class="mail support">support@kodorvan.tech</span>
<p class="worktime unselectable">Пермь, <span class="time from">10:00</span><span class="time to">19:00</span></p>
</article>
<article id="company">
<h1 class="name">ИП Мирзаев</h1>
<p class="column"><span class="tax row">271103176488</span><span class="identifier row">322270000004691</span></p>
</article>
</div>
<!-- <strong class="background unselectable">КОДОРВАНЬ</strong> -->
</footer>
{% include '/themes/default/elements/rofls.html' %}
{% endblock %}
{% block js %}

View File

@@ -1,23 +1,37 @@
{% block meta %}
<meta charset="utf-8" />
<title>{% if head.title != empty %}{{ head.title }}{% else %}Кодорвань - разработка сайтов в Перми{% endif %}</title>
<link rel="canonical" href="{{ uri ?? (domain ? ('https://' ~ domain) : '') }}" />
<title>{{ title ?? 'Кодорвань - разработка сайтов в Перми' }}</title>
<meta name="application-name" content="Кодорвань" />
<meta name="description" content="Чистый код, авангардный дизайн, крепкий бустинг и юридическая броня! Заходи на сайт и посчитай проект за 2 минуты! Рвём шаблоны!" />
<meta name="author" content="Арсен Мирзаев Татьяно-Мурадович" />
<meta name="robots" content="index, follow" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no" />
<meta name="HandheldFriendly" content="true" />
<meta name="MobileOptimized" content="width" />
<meta name="mobile-web-app-capable" content="yes" />
<meta property="og:title" content="Кодорвань - разработка сайтов в Перми" />
<meta property="og:description" content="Чистый код, авангардный дизайн, крепкий бустинг и юридическая броня! Заходи на сайт и посчитай проект за 2 минуты! Рвём шаблоны!" />
<meta property="og:title" content="{{ opengraph.title ?? 'Кодорвань - разработка сайтов в Перми' }}" />
<meta property="og:description" content="{{ opengraph.description ?? 'Чистый код, авангардный дизайн, крепкий бустинг и юридическая броня! Заходи на сайт и посчитай проект за 2 минуты! Рвём шаблоны!' }}" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://kodorvan.tech" />
<meta property="og:logo" content="https://kodorvan.tech/images/kodorvan.png" />
<meta property="og:url" content="{{ uri ?? (domain ? ('https://' ~ domain) : '') }}" />
<meta property="og:logo" content="{{ opengraph.logo ?? 'https://kodorvan.tech/images/kodorvan.png' }}" />
{% if opengraph.image.uri is not empty %}
<meta property="og:image" content="{{ opengraph.image.uri }}" />
{% if opengraph.image.width is not empty %}
<meta property="og:image:width" content="{{ opengraph.image.width }}" />
{% endif %}
{% if opengraph.image.height is not empty %}
<meta property="og:image:height" content="{{ opengraph.image.height }}" />
{% endif %}
{% if opengraph.image.alt is not empty %}
<meta property="og:image:alt" content="{{ opengraph.image.alt }}" />
{% endif %}
{% endif %}
<meta property="og:image" content="https://kodorvan.tech/images/kodorvan_1200_630.webp" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
@@ -30,12 +44,10 @@
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content="@mirzaev_sexy" />
<meta name="twitter:site" content="@mirzaev_sexy" />
<meta name="twitter:url" content="https://kodorvan.tech/" />
<meta name="twitter:title" content="Kodorvan" />
<meta name="twitter:description" content="Programming, design, boosting and legal armor!" />
<meta name="twitter:image" content="https://kodorvan.tech/images/kodorvan_1200_630.webp" />
<link rel="canonical" href="https://kodorvan.tech" />
<meta name="twitter:url" content="{{ uri ?? (domain ? ('https://' ~ domain) : '') }}" />
<meta name="twitter:title" content="{{ twitter.title ?? 'Кодорвань - разработка сайтов в Перми' }}" />
<meta name="twitter:description" content="{{ twitter.description ?? 'Programming, design, boosting and legal armor!' }}" />
<meta name="twitter:image" content="{{ twitter.image.uri ?? 'https://kodorvan.tech/images/kodorvan_1200_630.webp' }}" />
<link rel="apple-touch-icon" sizes="57x57" href="/images/favicon/favicon-57x57.png" />
<link rel="apple-touch-icon" sizes="60x60" href="/images/favicon/favicon-60x60.png" />
@@ -61,17 +73,20 @@
<meta name="theme-color" content="#ffffff" />
{% for meta in head.metas %}
<meta {% for name, value in meta.attributes %}{{ name }}="{{ value }}" {% endfor %} />
<meta {% for name, value in meta.attributes %}{{ name }}="{{ value }}" {% endfor %}/>
{% endfor %}
<script type="application/ld+json">
{% if ldjson is not empty %}
{{ ldjson }}
{% else %}
{
"@context": "https://schema.org",
"@type": "Organization",
"logo": "https://kodorvan.tech/images/kodorvan.png",
"name": "Кодорвань",
"description": "Чистый код, авангардный дизайн, крепкий бустинг и юридическая броня! Заходи на сайт и посчитай проект за 2 минуты! Рвём шаблоны!",
"url": "https://kodorvan.tech"
"url": "https://kodorvan.tech",
"contactPoint": [
{ "@type": "ContactPoint",
"telephone": "+7-901-592-4211",
@@ -81,6 +96,7 @@
}
]
}
{% endif %}
</script>
{% endblock %}
@@ -88,16 +104,18 @@
{% for element in css %}
<link type="text/css" rel="stylesheet" {% if element.href %} href="{{ element.href }}" {% endif %} />
{% endfor %}
<link type="text/css" rel="stylesheet" href="/themes/default/css/fonts.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/colorscheme.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/system.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/header.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/interface/logotype.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/main.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/aside.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/interface/sim.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/interface/media.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/fonts.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/footer.css" />
<style id="theme" />
@import url('/themes/default/css/colorscheme.css');
</style>
<style if="localization" />
<style id="localization" />
:root {
--days: "{{ language.name == 'ru' or true ? 'дн' : 'd' }}";
--hours: "{{ language.name == 'ru' or true ? 'ч' : 'h' }}";

View File

@@ -0,0 +1,10 @@
<h1 id="logotype" class="unselectable">
<span class="slogan">ВСЕХ ШАБЛОНОВ</span>
<a
href="/"
class="kodorvan"
title="Перейти на главную страницу"
rel="noopener"
ondragstart="return false"
>КОДОРВАНЬ</a>
</h1>

View File

@@ -0,0 +1,22 @@
<div class="social media unselectable">
<a href="https://max.ru/id271103176488_biz" title="Канал Кодорвань в МАКС">
<img
src="/themes/{{ theme }}/images/icons/max.svg"
width="50"
height="50"
alt="МАКС"
aria-label="МАКС"
ondragstart="return false"
/>
</a>
<a href="https://t.me/kodorvan" title="Канал Кодорвань в Телеграм">
<img
src="/themes/{{ theme }}/images/icons/telegram.svg"
width="50"
height="50"
alt="Телеграм"
aria-label="Телеграм"
ondragstart="return false"
/>
</a>
</div>

View File

@@ -0,0 +1,29 @@
{% if company.contacts.request.sim is not empty %}
<div class="sim">
<a
class="number"
href="tel:+{{ company.contacts.request.sim.full }}"
rel="external noreferrer noopener nofollow"
title="SIM-номер оператора Кодорвань"
aria-label="SIM-номер оператора Кодорвань"
>
<span class="country">{{ company.contacts.request.sim.country }}</span>
<span class="operator">{{ company.contacts.request.sim.operator }}</span>
<span>{{ company.contacts.request.sim.number[0] }}</span>
<span>{{ company.contacts.request.sim.number[1] ~ company.contacts.request.sim.number[2] }}</span>
</a>
<button
class="copy inline"
onclick="navigator.clipboard.writeText('{{ company.contacts.request.sim.full }}')"
title="Скопировать SIM-номер"
aria-label="Скопировать SIM-номер"
>
<img
class="icon"
src="/themes/{{ theme }}/images/icons/white/copy.svg"
alt="copy kodorvan"
ondragstart="return false"
/>
</button>
</div>
{% endif %}

View File

@@ -1,4 +1,4 @@
{% block js %}
<script src="/js/modules/damper.mjs" type="module"></script>
<link rel="modulepreload" href="/js/modules/damper.mjs" ></script>
<script src="/js/core.js"></script>
{% endblock %}

View File

@@ -1,135 +0,0 @@
{% extends "/themes/default/index.html" %}
{% block css %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="/css/icons/loading_spinner.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/pages/offer.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cookies.css" />
{% endblock %}
{% block before %}
{% endblock %}
{% block main %}
<h1 id="title" class="unselectable">
<span class="slogan">ВСЕХ ШАБЛОНОВ</span>
<a href="/" class="kodorvan">КОДОРВАНЬ</a>
</h1>
<article id="offer" aria-label="Публичная оферта">
<h1>Согласие на обработку электронных пользовательских данных</h1>
<div class="text">
<p>Я даю согласие на&nbsp;обработку моих электронных пользовательских данных АО&nbsp;«ПФ «СКБ&nbsp;Контур»&nbsp;(ИНН
6663003127)&nbsp;и&nbsp;его дочерним обществам (далее вместе&nbsp;— СКБ&nbsp;Контур, группа компаний),
в&nbsp;соответствии с&nbsp;разделом 6&nbsp;<a class="external-link" href="https://kontur.ru/about/policy"
rel="nofollow noopener">Политики&nbsp;обработки персональных данных</a>&nbsp;(далее&nbsp;— Политика),
в&nbsp;следующих целях:</p>
<ul>
<li>обеспечение корректной работы сайтов и&nbsp;программных продуктов СКБ&nbsp;Контур, персонализация, сохранение
настроек пользователя, повышение удобства работы;</li>
<li>сбор, обработка аналитических и&nbsp;статистических данных по&nbsp;тематике деятельности СКБ&nbsp;Контур,
использования информационных ресурсов, программных продуктов, товаров, работ и&nbsp;услуг СКБ&nbsp;Контур
для&nbsp;разработки новых программных продуктов, расширения спектра оказываемых услуг, контроля качества,
противодействия незаконным или&nbsp;несанкционированным действиям, мошенничеству при&nbsp;использовании
программных продуктов, товаров, работ и&nbsp;услуг СКБ&nbsp;Контур, обеспечение информационной безопасности.
</li>
</ul>
<p>Перечень электронных пользовательских данных, которые могут обрабатываться в&nbsp;соответствии с&nbsp;указанными
целями обработки:</p>
<ul>
<li>идентификаторы пользователя;</li>
<li>сетевые адреса;</li>
<li>файлы cookies;</li>
<li>идентификаторы устройств;</li>
<li>размеры и&nbsp;разрешение экрана;</li>
<li>сведения об&nbsp;аппаратном и&nbsp;программном обеспечении, например, браузерах, операционной системе,
установленных приложениях;</li>
<li>геолокация;</li>
<li>языковые настройки;</li>
<li>часовой пояс;</li>
<li>время и&nbsp;статистика использования приложений и&nbsp;информационных ресурсов СКБ&nbsp;Контур;</li>
<li>действия в&nbsp;сервисах СКБ&nbsp;Контур, источники переходов на&nbsp;веб-страницы, отправленные поисковые
и&nbsp;иные запросы, созданный пользователем контент.</li>
</ul>
<p>Кроме обработки данных cookies, установленных самими сайтами СКБ&nbsp;Контур, на&nbsp;моем устройстве могут
устанавливаться cookies, относящиеся к&nbsp;сайтам сторонних организаций, например, в&nbsp;случаях, когда
на&nbsp;сайтах СКБ&nbsp;Контур используются сторонние компоненты и&nbsp;программное обеспечение. Обработка таких
cookies регулируется политиками соответствующих сайтов, к&nbsp;которым они относятся, и&nbsp;может изменяться
без&nbsp;моего предварительного уведомления. К&nbsp;таким случаям может относиться размещение на&nbsp;сайтах:</p>
<ul>
<li><span>счетчиков посещений, аналитических и&nbsp;статистических сервисов для&nbsp;сбора статистики посещаемости
общедоступных страниц сайтов (Яндекс.Метрика, Яндекс.Аудитории, VK.com, Mail.ru);</span></li>
<li><span>виджетов вспомогательных сервисов для&nbsp;сбора обратной связи, организации чатов и&nbsp;иных видов
коммуникаций с&nbsp;пользователями (Carrot Quest, Callibri);</span></li>
<li><span>систем контекстной рекламы, баннерных и&nbsp;иных маркетинговых сетей (VK Ads);</span></li>
<li><span>кнопок авторизации на&nbsp;сайтах с&nbsp;помощью учетных записей в&nbsp;социальных сетях (VK ID, Яндекс
ID, Alfa ID);</span></li>
<li><span>иных сторонних компонент, используемых СКБ&nbsp;Контур на&nbsp;своих сайтах.</span></li>
</ul>
<p>Действия, на&nbsp;которые дается согласие: сбор, запись, систематизация, накопление, хранение, уточнение
(обновление, изменение), извлечение, использование, передача (предоставление, доступ,&nbsp;без&nbsp;осуществления
трансграничной передачи), обезличивание, блокирование, удаление, уничтожение, осуществляемые с&nbsp;использованием
средств автоматизации.</p>
<p>В&nbsp;случае если я не&nbsp;согласен с&nbsp;обработкой cookies, я принимаю на&nbsp;себя риск того,
что&nbsp;в&nbsp;таком случае функции и&nbsp;возможности сайта могут не&nbsp;быть доступны в&nbsp;полном объеме,
и&nbsp;могу выбрать один из&nbsp;следующих вариантов:</p>
<ul>
<li>произвести самостоятельную настройку своего браузера в&nbsp;соответствии с&nbsp;документацией
или&nbsp;справкой к&nbsp;нему таким образом, чтобы он на&nbsp;постоянной основе не&nbsp;разрешал принимать
и&nbsp;отправлять данные cookies для&nbsp;любых сайтов либо для&nbsp;конкретного сайта СКБ&nbsp;Контур
или&nbsp;сайта стороннего компонента;</li>
<li>переключиться в&nbsp;специальный режим «инкогнито» браузера для&nbsp;использования сайтом cookies
до&nbsp;закрытия окна браузера или&nbsp;до&nbsp;переключения обратно в&nbsp;обычный режим;</li>
<li>покинуть сайт во&nbsp;избежание дальнейшей обработки cookies.</li>
</ul>
<p>Я понимаю, что&nbsp;могу самостоятельно через&nbsp;встроенные в&nbsp;браузеры средства работы с&nbsp;данными
cookies управлять сохраненными данными, в&nbsp;том числе, удалять или&nbsp;просматривать сведения
об&nbsp;установленных сайтами cookies, включая:</p>
<ul>
<li>адреса сайтов и&nbsp;пути на&nbsp;них, куда будут отправляться cookies;</li>
<li>названия и&nbsp;значения параметров, хранящихся в&nbsp;cookies;</li>
<li>сроки действия cookies.</li>
</ul>
<p>Срок обработки электронных пользовательских данных&nbsp;— до&nbsp;наступления условий:</p>
<ul>
<li>достижение целей обработки персональных данных или&nbsp;максимальных сроков хранения;</li>
<li>утрата необходимости в&nbsp;достижении целей обработки персональных данных;</li>
<li>предоставление субъектом персональных данных или&nbsp;его законным представителем подтверждения того,
что&nbsp;персональные данные являются незаконно полученными или&nbsp;не&nbsp;являются необходимыми
для&nbsp;заявленной цели обработки;</li>
<li>отзыв согласия на&nbsp;обработку персональных данных, если сохранение персональных данных более
не&nbsp;требуется для&nbsp;целей обработки персональных данных;</li>
<li>законное требование о&nbsp;прекращении обработки персональных данных;</li>
<li>ликвидация (реорганизация) отдельно взятого общества, входящего в&nbsp;СКБ&nbsp;Контур, если обработка
осуществлялась исключительно в&nbsp;интересах данного общества и&nbsp;отсутствует какой-либо правопреемник
общества в&nbsp;СКБ&nbsp;Контур.</li>
</ul>
<p>Я уведомлен, что&nbsp;при&nbsp;необходимости я могу ознакомиться с&nbsp;актуальной версией Политики обработки
персональных данных СКБ&nbsp;Контур по&nbsp;адресу&nbsp;<a class="external-link"
href="https://kontur.ru/about/policy" rel="nofollow noopener">https://kontur.ru/about/policy</a>.</p>
</div>
</article>
{% endblock %}
{% block after %}
<div class="vignette"></div>
<div class="dots"></div>
{% endblock %}
{% block js %}
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% extends "/themes/default/index.html" %}
{% block css %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="/css/icons/loading_spinner.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/pages/offer.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cookies.css" />
{% endblock %}
{% block before %}
{% endblock %}
{% block main %}
{% include '/themes/default/interface/logotype.html' %}
<article id="{{ article.identifier }}" aria-label="{{ article.title }}">
<h1>{{ article.title }}</h1>
{{ article.html|raw }}
</article>
{% endblock %}
{% block after %}
<div class="vignette"></div>
<div class="dots"></div>
{% endblock %}
{% block js %}
{{ parent() }}
{% endblock %}

View File

@@ -2,6 +2,7 @@
{% block css %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="/css/icons/loading_spinner.css" />
<!-- <link type="text/css" rel="stylesheet" href="/css/icons/code_slash.css" />
<link type="text/css" rel="stylesheet" href="/css/icons/coffe.css" />
@@ -21,7 +22,10 @@
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/companies.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/project.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/superpacks.css" />
{% if not smartphone %}
{% if smartphone %}
<link rel="preload expect" as="image" href="/themes/default/images/interface/labubumba_2_mobile.svg" />
{% else %}
<link rel="preload expect" as="image" href="/themes/default/images/interface/labubumba_2.svg" />
<!-- <link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cases.css" /> -->
{% endif %}
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cookies.css" />
@@ -33,12 +37,9 @@
{% endblock %}
{% block main %}
<h1 id="title" class="unselectable">
<span class="slogan">ВСЕХ ШАБЛОНОВ</span>
<a href="/" class="kodorvan">КОДОРВАНЬ</a>
</h1>
{% include '/themes/default/interface/logotype.html' %}
{% include '/themes/default/elements/project.html' %}
{% include '/themes/default/elements/project/short.html' %}
{% include '/themes/default/elements/companies.html' %}
{% include '/themes/default/elements/superpacks.html' %}
@@ -46,7 +47,7 @@
{% if cookies.cookies_popup_closed is empty %}
{% include '/themes/default/elements/cookies.html' %}
{% endif %}
{% endblock %}
{% endblock %}
{% block after %}
<div class="vignette"></div>
@@ -65,8 +66,22 @@
}, 60);
</script>
<script>
const companies = document.getElementById("companies");
companies.style.setProperty('margin-top', '70vh');
companies.style.setProperty('transition', 'margin 0.6s cubic-bezier(0, 1, .45, 1)');
const companies_show = setTimeout(() => companies.style.removeProperty('margin-top'), 2000);
document.addEventListener('load', () => {
clearTimeout(companies_show);
companies.style.removeProperty('margin-top');
});
</script>
<link rel="modulepreload" href="/js/modules/hotline.mjs" ></script>
<script src="/js/modules/project.mjs" type="module"></script>
<script src="/js/modules/paginator.mjs" type="module"></script>
<script src="/js/modules/hotline.mjs" type="module"></script>
<script src="/js/pages/main.js" type="module" defer></script>
{% endblock %}

View File

@@ -0,0 +1,131 @@
{% extends "/themes/default/index.html" %}
{% block css %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="/css/icons/loading_spinner.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/pages/offer.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cookies.css" />
{% endblock %}
{% block before %}
{% endblock %}
{% block main %}
{% include '/themes/default/interface/logotype.html' %}
<article id="offer" aria-label="Публичная оферта">
<h1>Согласие на обработку электронных пользовательских данных</h1>
<div class="text">
<p>Я даю согласие на обработку моих электронных пользовательских данных «{{ company.name.full ?? company.name.short }}» (ИНН
{{ company.tax }}) и его дочерним обществам (далее вместе — {{ company.name.short }}, группа компаний),
в соответствии с разделом 6 <a href="/policy" rel="nofollow noopener">Политики обработки персональных данных</a> (далее — Политика),
в следующих целях:</p>
<ul>
<li>обеспечение корректной работы сайтов и программных продуктов {{ company.name.short }}, персонализация, сохранение
настроек пользователя, повышение удобства работы;</li>
<li>сбор, обработка аналитических и статистических данных по тематике деятельности {{ company.name.short }},
использования информационных ресурсов, программных продуктов, товаров, работ и услуг {{ company.name.short }}
для разработки новых программных продуктов, расширения спектра оказываемых услуг, контроля качества,
противодействия незаконным или несанкционированным действиям, мошенничеству при использовании
программных продуктов, товаров, работ и услуг {{ company.name.short }}, обеспечение информационной безопасности.
</li>
</ul>
<p>Перечень электронных пользовательских данных, которые могут обрабатываться в соответствии с указанными
целями обработки:</p>
<ul>
<li>идентификаторы пользователя;</li>
<li>сетевые адреса;</li>
<li>файлы cookies;</li>
<li>идентификаторы устройств;</li>
<li>размеры и разрешение экрана;</li>
<li>сведения об аппаратном и программном обеспечении, например, браузерах, операционной системе,
установленных приложениях;</li>
<li>геолокация;</li>
<li>языковые настройки;</li>
<li>часовой пояс;</li>
<li>время и статистика использования приложений и информационных ресурсов {{ company.name.short }};</li>
<li>действия в сервисах {{ company.name.short }}, источники переходов на веб-страницы, отправленные поисковые
и иные запросы, созданный пользователем контент.</li>
</ul>
<p>Кроме обработки данных cookies, установленных самими сайтами {{ company.name.short }}, на моем устройстве могут
устанавливаться cookies, относящиеся к сайтам сторонних организаций, например, в случаях, когда
на сайтах {{ company.name.short }} используются сторонние компоненты и программное обеспечение. Обработка таких
cookies регулируется политиками соответствующих сайтов, к которым они относятся, и может изменяться
без моего предварительного уведомления. К таким случаям может относиться размещение на сайтах:</p>
<ul>
<li><span>счетчиков посещений, аналитических и статистических сервисов для сбора статистики посещаемости
общедоступных страниц сайтов (Яндекс.Метрика, Яндекс.Аудитории, VK.com, Mail.ru);</span></li>
<li><span>виджетов вспомогательных сервисов для сбора обратной связи, организации чатов и иных видов
коммуникаций с пользователями (Carrot Quest, Callibri);</span></li>
<li><span>систем контекстной рекламы, баннерных и иных маркетинговых сетей (VK Ads);</span></li>
<li><span>кнопок авторизации на сайтах с помощью учетных записей в социальных сетях (VK ID, Яндекс
ID, Alfa ID);</span></li>
<li><span>иных сторонних компонент, используемых {{ company.name.short }} на своих сайтах.</span></li>
</ul>
<p>Действия, на которые дается согласие: сбор, запись, систематизация, накопление, хранение, уточнение
(обновление, изменение), извлечение, использование, передача (предоставление, доступ, без осуществления
трансграничной передачи), обезличивание, блокирование, удаление, уничтожение, осуществляемые с использованием
средств автоматизации.</p>
<p>В случае если я не согласен с обработкой cookies, я принимаю на себя риск того,
что в таком случае функции и возможности сайта могут не быть доступны в полном объеме,
и могу выбрать один из следующих вариантов:</p>
<ul>
<li>произвести самостоятельную настройку своего браузера в соответствии с документацией
или справкой к нему таким образом, чтобы он на постоянной основе не разрешал принимать
и отправлять данные cookies для любых сайтов либо для конкретного сайта {{ company.name.short }}
или сайта стороннего компонента;</li>
<li>переключиться в специальный режим «инкогнито» браузера для использования сайтом cookies
до закрытия окна браузера или до переключения обратно в обычный режим;</li>
<li>покинуть сайт во избежание дальнейшей обработки cookies.</li>
</ul>
<p>Я понимаю, что могу самостоятельно через встроенные в браузеры средства работы с данными
cookies управлять сохраненными данными, в том числе, удалять или просматривать сведения
об установленных сайтами cookies, включая:</p>
<ul>
<li>адреса сайтов и пути на них, куда будут отправляться cookies;</li>
<li>названия и значения параметров, хранящихся в cookies;</li>
<li>сроки действия cookies.</li>
</ul>
<p>Срок обработки электронных пользовательских данных — до наступления условий:</p>
<ul>
<li>достижение целей обработки персональных данных или максимальных сроков хранения;</li>
<li>утрата необходимости в достижении целей обработки персональных данных;</li>
<li>предоставление субъектом персональных данных или его законным представителем подтверждения того,
что персональные данные являются незаконно полученными или не являются необходимыми
для заявленной цели обработки;</li>
<li>отзыв согласия на обработку персональных данных, если сохранение персональных данных более
не требуется для целей обработки персональных данных;</li>
<li>законное требование о прекращении обработки персональных данных;</li>
<li>ликвидация (реорганизация) отдельно взятого общества, входящего в {{ company.name.short }}, если обработка
осуществлялась исключительно в интересах данного общества и отсутствует какой-либо правопреемник
общества в {{ company.name.short }}.</li>
</ul>
<p>Я уведомлен, что при необходимости я могу ознакомиться с актуальной версией Политики обработки
персональных данных {{ company.name.short }} по адресу <a class="tech" href="/offer" rel="nofollow noopener">https://{{ domain }}/policy</a>.</p>
</div>
</article>
{% endblock %}
{% block after %}
<div class="vignette"></div>
<div class="dots"></div>
{% endblock %}
{% block js %}
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends "/themes/default/index.html" %}
{% block css %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="/css/icons/loading_spinner.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/pages/project.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/project.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cookies.css" />
<link rel="preload" as="image" href="/themes/default/images/icons/close.svg" />
{% endblock %}
{% block before %}
{% endblock %}
{% block main %}
{% include '/themes/default/interface/logotype.html' %}
{% include '/themes/default/elements/project/full.html' %}
{% endblock %}
{% block after %}
<div class="vignette"></div>
<div class="dots"></div>
{% endblock %}
{% block js %}
{{ parent() }}
<script src="/js/pages/project/create.js" type="module" defer></script>
{% endblock %}

View File

@@ -0,0 +1,115 @@
{% extends "/themes/default/index.html" %}
{% block css %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="/css/icons/loading_spinner.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/pages/system/superpack/create.css" />
<link type="text/css" rel="stylesheet" href="/themes/default/css/elements/cookies.css" />
{% endblock %}
{% block before %}
{% endblock %}
{% block main %}
{% include '/themes/default/interface/logotype.html' %}
<article id="superpack" aria-label="Форма создания суперпака">
<h1 class="unselectable">СОЗДАНИЕ СУПЕРПАКА</h1>
<section class="unselectable">
<label id="superpack_urn" class="input icon" for="superpack_urn_input">
<img class="icon" src="/themes/default/images/icons/nametag.svg" alt="nametag kodorvan" ondragstart="return false"/>
<span class="title">URN</span>
<input
id="superpack_urn_input"
class="input domain"
name="superpack_urn_input"
type="text"
placeholder="chat-bot-market"
value=""
autocomplete="off"
onkeyup="core.system.superpack.urn = this.value"
/>
<small class="guide active">Введите URN суперпака</small>
</label>
<label id="superpack_title" class="input icon" for="superpack_title_input">
<img class="icon" src="/themes/default/images/icons/notes.svg" alt="notes kodorvan" ondragstart="return false"/>
<span class="title">Название</span>
<input
id="superpack_title_input"
class="input"
name="superpack_title_input"
type="text"
placeholder="Чат-бот для магазина"
value=""
autocomplete="off"
onkeyup="core.system.superpack.title = this.value"
/>
<small class="guide active">Введите название суперпака</small>
</label>
<label id="superpack_text" class="input icon" for="superpack_text_input">
<img class="icon" src="/themes/default/images/icons/notes.svg" alt="notes kodorvan" ondragstart="return false"/>
<span class="title">Описание</span>
<textarea
id="superpack_text_input"
class="input"
name="superpack_text_input"
cols="100%"
maxlength="4096"
value=""
autocomplete="off"
placeholder="Готовое техническое решение для открытия новой точки продаж в сети"
onkeyup="core.system.superpack.text = this.value"
></textarea>
<small class="guide active">Введите описание суперпака</small>
</label>
<label id="superpack_html" class="input icon" for="superpack_html_input">
<img class="icon" src="/themes/default/images/icons/notes.svg" alt="notes kodorvan" ondragstart="return false"/>
<span class="title">Описание в формате HTML</span>
<textarea
id="superpack_html_input"
class="input"
name="superpack_html_input"
cols="100%"
maxlength="4096"
value=""
autocomplete="off"
placeholder="<p>Готовое техническое решение для открытия новой точки продаж в сети</p>"
onkeyup="core.system.superpack.html = this.value"
></textarea>
<small class="guide active">Введите описание суперпака в формате HTML</small>
</label>
<label id="superpack_supercost" class="input icon" for="superpack_supercost_input">
<img class="icon" src="/themes/default/images/icons/notes.svg" alt="notes kodorvan" ondragstart="return false"/>
<span class="title">Стоимость</span>
<input
id="superpack_supercost_input"
class="input"
name="superpack_supercost_input"
type="number"
placeholder="2000"
value=""
autocomplete="off"
onkeyup="core.system.superpack.supercost = this.value"
/>
<small class="guide active">Введите стоимость суперпака</small>
</label>
<button
id="send"
onclick="core.system.superpack.send();"
>Отправить на сервер</button>
</section>
</article>
{% endblock %}
{% block after %}
<div class="vignette"></div>
<div class="dots"></div>
{% endblock %}
{% block js %}
{{ parent() }}
<script src="/js/pages/system/superpack.js" type="module" defer></script>
{% endblock %}