diff --git a/kodorvan/site/system/controllers/index.php b/kodorvan/site/system/controllers/index.php index 7cdc845..ba96f76 100755 --- a/kodorvan/site/system/controllers/index.php +++ b/kodorvan/site/system/controllers/index.php @@ -187,47 +187,7 @@ final class index extends core ]; // Sending the cookie with the team workload (1800 = 30min) - setcookie('workload', $this->view->workload, time() + 1800, '/'); - - // Initializing the project constructor data - $this->view->project = [ - 'architectures' => [ - 'site' => 'Сайт', - 'chat_robot' => 'Чат-робот', - 'program' => 'Программа', - 'game' => 'Видеоигра', - 'script' => 'Скрипт, парсер, макрос', - 'module' => 'Модуль, плагин, расширение', - ], - 'purposes' => [ - 'funnel' => 'Воронка (обработка пользователя)', - 'contacts' => 'Контакты (сбор данных)', - 'ai' => 'Внедрение ИИ', - 'archive' => 'Архив (галерея, библиотека, реестр)', - 'crm' => 'Индивидуальная CRM', - 'landing' => 'Лендинг (посадочная страница)', - 'marketplace' => 'Маркетплейс, магазин, витрина', - 'saas' => 'SaaS проект', - 'search' => 'Поиск и анализ', - 'calculate' => 'Вычисления (калькулятор)', - 'individual' => 'Индивидуальная разработка', - ], - 'integrations' => [ - 'one_c' => '1C', - 'bitrix24' => 'Битрикс24', - 'moy_sklad' => 'Мой Склад', - 'mail' => 'Почта', - 'excel' => 'Excel', - 'ozon' => 'OZON', - 'wildberries' => 'Wildberries', - 'yandex_market' => 'Яндекс Маркет', - 'avito' => 'Авито', - 'vk' => 'ВКонтакте', - 'max' => 'МАКС', - 'telegram' => 'Телеграм', - 'neural_networks' => 'Нейросети' - ] - ]; + /* setcookie('workload', $this->view->workload, time() + 1800, '/'); */ // Initializing contacts data $this->view->integrations = [ diff --git a/kodorvan/site/system/controllers/project.php b/kodorvan/site/system/controllers/project.php index 47f37dc..cb66e86 100755 --- a/kodorvan/site/system/controllers/project.php +++ b/kodorvan/site/system/controllers/project.php @@ -9,6 +9,7 @@ use kodorvan\site\controllers\core; // PHP framework use mirzaev\minimal\http\enumerations\content, + mirzaev\minimal\http\enumerations\method, mirzaev\minimal\http\enumerations\status; // Mail server @@ -40,85 +41,176 @@ final class project extends core ]; /** - * + * Page: calculator + * + * @return null + */ + public function calculator(): null + { + if ($this->request->method === method::get) { + // GET + + if (str_contains($this->request->headers['accept'] ?? '', content::html->value)) { + // Request for HTML response + + // Initializing the project constructor data + $this->view->calculator = [ + 'architectures' => [ + 'site' => 'Сайт', + 'chat_robot' => 'Чат-робот', + 'program' => 'Программа', + 'game' => 'Видеоигра', + 'script' => 'Скрипт, парсер, макрос', + 'module' => 'Модуль, плагин, расширение', + ], + 'purposes' => [ + 'funnel' => 'Воронка (обработка пользователя)', + 'contacts' => 'Контакты (сбор данных)', + 'ai' => 'Внедрение ИИ', + 'archive' => 'Архив (галерея, библиотека, реестр)', + 'crm' => 'Индивидуальная CRM', + 'landing' => 'Лендинг (посадочная страница)', + 'marketplace' => 'Маркетплейс, магазин, витрина', + 'saas' => 'SaaS проект', + 'search' => 'Поиск и анализ', + 'calculate' => 'Вычисления (калькулятор)', + 'individual' => 'Индивидуальная разработка', + ], + 'integrations' => [ + 'one_c' => '1C', + 'bitrix24' => 'Битрикс24', + 'moy_sklad' => 'Мой Склад', + 'mail' => 'Почта', + 'excel' => 'Excel', + 'ozon' => 'OZON', + 'wildberries' => 'Wildberries', + 'yandex_market' => 'Яндекс Маркет', + 'avito' => 'Авито', + 'vk' => 'ВКонтакте', + 'max' => 'МАКС', + 'telegram' => 'Телеграм', + 'neural_networks' => 'Нейросети' + ] + ]; + + // Render page + $page = $this->view->render( + 'pages/project/calculator.html', + [ + 'uri' => 'https://' . DOMAIN . "/project/calculator", + '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; + } + } + + // Exit (fail) + return null; + } + + /** + * Request the project by calculator * * @return null */ public function request(string $request): null { - // Initializing the project identifier (temporary solution) - $identifier = blake3($request, 20); + if ($this->request->method === method::put) { + // PUT + // Initializing the project identifier (temporary solution) + $identifier = blake3($request, 20); - // Initializing the project storage path - $path = STORAGE . DIRECTORY_SEPARATOR . 'projects' . DIRECTORY_SEPARATOR . $identifier; + // Initializing the project storage path + $path = STORAGE . DIRECTORY_SEPARATOR . 'projects' . DIRECTORY_SEPARATOR . $identifier; - // Initializing the project storage directory in the storage - if (!file_exists($path)) mkdir($path, 0775, true); + // Initializing the project storage directory in the storage + if (!file_exists($path)) mkdir($path, 0775, true); - // Declaring the project storage files registry - $files = []; + // Declaring the project storage files registry + $files = []; - foreach ($this->request->files as $file) { - // Iterating over files + foreach ($this->request->files as $file) { + // Iterating over files - // Initializing the file destination path - $destination = $path . DIRECTORY_SEPARATOR . $file['name']; + // Initializing the file destination path + $destination = $path . DIRECTORY_SEPARATOR . $file['name']; - // Writing the file into the project storage - copy($file['tmp_name'], $destination); + // Writing the file into the project storage + copy($file['tmp_name'], $destination); - // Writing the file destination path into the project storage files registry - $files[$file['name']] = $destination; - } - - // Decoding the request JSON argument - $request = json_decode(json: $request, associative: true, depth: 5); - - // Initializing the mail server - $mail = new mail(true); - - try { - // Writing the mail server parameters - /* $mail->SMTPDebug = smtp::DEBUG_SERVER; */ - $mail->setLanguage('ru'); - $mail->CharSet = mail::CHARSET_UTF8; - $mail->isSMTP(); - $mail->Host = MAIL['host']; - $mail->SMTPAuth = true; - $mail->Username = MAIL['sender']['mail']; - $mail->Password = MAIL['sender']['password']; - $mail->SMTPSecure = mail::ENCRYPTION_SMTPS; - $mail->Port = 465; - $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'; */ - - // Attachments - foreach ($files as $name => $file) { - // Iterating of project storage files registry - - // Writing the attachment into the message - $mail->addAttachment($file, $name); + // Writing the file destination path into the project storage files registry + $files[$file['name']] = $destination; } - // Sending the message - $mail->send(); - } catch (mail_exception $exception) { - } + // Decoding the request JSON argument + $request = json_decode(json: $request, associative: true, depth: 5); - // Sending response - $this->response - ->start() - ->clean() - ->sse() - ->validate($this->request) - ?->body() - ->end(); + // Initializing the mail server + $mail = new mail(true); + + try { + // Writing the mail server parameters + /* $mail->SMTPDebug = smtp::DEBUG_SERVER; */ + $mail->setLanguage('ru'); + $mail->CharSet = mail::CHARSET_UTF8; + $mail->isSMTP(); + $mail->Host = MAIL['host']; + $mail->SMTPAuth = true; + $mail->Username = MAIL['sender']['mail']; + $mail->Password = MAIL['sender']['password']; + $mail->SMTPSecure = mail::ENCRYPTION_SMTPS; + $mail->Port = 465; + $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'; */ + + // Attachments + foreach ($files as $name => $file) { + // Iterating of project storage files registry + + // Writing the attachment into the message + $mail->addAttachment($file, $name); + } + + // Sending the message + $mail->send(); + } catch (mail_exception $exception) { + } + + // Sending response + $this->response + ->start() + ->clean() + ->sse() + ->validate($this->request) + ?->body() + ->end(); + + // Exit (success) + return null; + } // Exit (fail) return null; diff --git a/kodorvan/site/system/controllers/superpack.php b/kodorvan/site/system/controllers/superpack.php index d037db2..1668557 100755 --- a/kodorvan/site/system/controllers/superpack.php +++ b/kodorvan/site/system/controllers/superpack.php @@ -66,8 +66,12 @@ final class superpack extends core 'uri' => 'https://' . DOMAIN . "/superpack/$urn", 'article' => [ 'urn' => $superpack->urn, - 'title' => $superpack->title, - 'html' => $superpack->html + 'head' => [ + 'title' => $superpack->title + ], + 'body' => [ + 'html' => $superpack->html + ] ], 'smartphone' => $this->request->smartphone, 'tablet' => $this->request->tablet @@ -172,8 +176,17 @@ final class superpack extends core if ($superpack instanceof record) { // Created the superpack - // Sending redirect to the superpack - header('Location: /superpack/' . $urn); + // Sending response + $this->response + ->start() + ->clean() + ->sse() + ->json([ + 'redirect' => "/superpack/$urn" + ]) + ->validate($this->request) + ?->body() + ->end(); } } } diff --git a/kodorvan/site/system/public/index.php b/kodorvan/site/system/public/index.php index fe26649..0689dfe 100755 --- a/kodorvan/site/system/public/index.php +++ b/kodorvan/site/system/public/index.php @@ -50,11 +50,13 @@ $core->router ->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/calculator', new route('project', 'calculator'), 'GET') ->write('/project/request', new route('project', 'request'), 'PUT') + + ->write('/system/superpack/create', new route('superpack', 'create'), 'GET') + ->write('/system/superpack/create', new route('superpack', 'create'), 'PUT') ; // Handling request diff --git a/kodorvan/site/system/public/js/modules/system/article.mjs b/kodorvan/site/system/public/js/modules/system/article.mjs new file mode 100644 index 0000000..e32d3b5 --- /dev/null +++ b/kodorvan/site/system/public/js/modules/system/article.mjs @@ -0,0 +1,623 @@ +/** @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 + */ +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 Image + * + * @description + * The head image of the article + * + * @type {File} + * + * @protected + */ + #image; + + /** + * @name Image (set) + * + * @public + */ + set image(value) { + if (value instanceof File){ + // File + + // Writing into the property + this.#image = value; + } else { + // Undefined + + // Deleting the property + this.#image = undefined; + } + + if (this.#image.length > 0) { + // Has the image + + // Deleting from the stages registry + this.#stages.delete('image'); + } else { + // Has no image + + // Writing into the stages registry + this.#stages.add('image'); + } + + // Dispatching event: "article.write" + this.shell.dispatchEvent( + new CustomEvent("article.write", { + detail: { name: 'image', value: this.#image } + }) + ); + + // Reinitializing guide HTML-elements + this.guide(); + }; + + /** + * @name Image (get) + * + * @return {File} + * + * @public + */ + get image() { + return this.#image; + } + + /** + * @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("Запрос доставлен"); + + if (json.redirect?.length > 0) { + // Received the redirect + + // Redirect + window.location = json.redirect; + } + + // 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.global.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()); + }, + ); + } +} diff --git a/kodorvan/site/system/public/js/modules/system/superpack.mjs b/kodorvan/site/system/public/js/modules/system/superpack.mjs index 711dffc..9d2a362 100644 --- a/kodorvan/site/system/public/js/modules/system/superpack.mjs +++ b/kodorvan/site/system/public/js/modules/system/superpack.mjs @@ -403,6 +403,13 @@ export default class superpack { // Reloading the page @todo make something smarter alert("Запрос доставлен"); + if (json.redirect?.length > 0) { + // Received the redirect + + // Redirect + window.location = json.redirect; + } + // Exit (success) resolve(); } @@ -437,7 +444,7 @@ export default class superpack { * * @return {void} */ - damper: core.damper( + damper: core.global.damper( (...variables) => this.send.system(...variables), 300, 2, diff --git a/kodorvan/site/system/public/themes/default/css/elements/project.css b/kodorvan/site/system/public/themes/default/css/elements/project.css index 75bb32d..780ec53 100755 --- a/kodorvan/site/system/public/themes/default/css/elements/project.css +++ b/kodorvan/site/system/public/themes/default/css/elements/project.css @@ -2,7 +2,7 @@ section#project { --margin-bottom: 0.8rem; - --width: 480px; + --width: 420px; z-index: 200; position: relative; margin-top: 3rem; @@ -50,6 +50,22 @@ section#project { } } + >section.promotion { + >p { + margin: unset; + margin: 0 0rem 0.4rem 0rem; + padding: 0.5rem 0.7rem; + text-align: center; + font-size: 1.1rem; + font-weight: 600; + color: #45ff01; + border-radius: 1.25rem; + border: 2px solid #45ff01; + text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B; + backdrop-filter: blur(1.2px); + } + } + >noscript { display: flex; flex-direction: column; @@ -75,8 +91,7 @@ section#project { >article { --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; + padding: 2rem 1.7rem; display: flex; flex-direction: column; gap: 1.4rem; @@ -149,7 +164,7 @@ section#project { } >section { - padding: 0 0.6rem; + padding: 0 0.6rem 0 0.2rem; display: flex; flex-direction: column; @@ -857,23 +872,40 @@ section#project { } >div.adaptive { - display: contents; + /* display: contents; */ + margin-bottom: var(--margin-bottom, 0.8rem); + display: flex; + flex-direction: row; + gap: 1rem; + + >* { + width: 100%; + } >button#back { --diameter: 7ch; --radius: calc(var(--diameter, 4ch) / 2); - position: absolute; + /* position: absolute; left: calc(-1.2rem - var(--diameter, 4ch)); - top: calc(10rem - var(--radius, 2ch)); - width: var(--diameter, 4ch); - height: var(--diameter, 4ch); + top: calc(10rem - var(--radius, 2ch)); */ + /* width: var(--diameter, 4ch); */ + /* height: var(--diameter, 4ch); */ display: flex; justify-content: center; align-items: center; - border-radius: 100%; + /* border-radius: 100%; */ border: unset; background-color: var(--button-background-color, #fff); + position: relative; + left: unset; + top: unset; + margin: unset; + min-width: var(--diameter, 4ch); + width: 30%; + height: auto; + border-radius: 1.25rem; + &:is(:hover, :focus) { background-color: var(--button-hover-background-color, #abc7c6); } @@ -884,11 +916,13 @@ section#project { >img { padding-bottom: 0.15em; + scale: 1.2; } } >section#buttons { - margin-bottom: var(--margin-bottom, 0.8rem); + /* margin-bottom: var(--margin-bottom, 0.8rem); */ + margin-bottom: unset; flex-direction: row; justify-content: center; @@ -970,9 +1004,9 @@ section#project { font-family: Nunito; font-size: 0.9em; color: #d6c1c1; - background: #b3ced31a; + background: #a5c2c724; border-radius: 1.25rem; - border-top: 1px solid #84d1d526; + border-top: 1px solid #84d1d52e; backdrop-filter: blur(2px) contrast(1.14); /* text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B; */ text-shadow: unset; @@ -990,9 +1024,9 @@ section#project { font-family: Nunito; font-size: 0.9em; color: #d6c1c1; - background: #b3ced31a; + background: #a5c2c724; border-radius: 1.25rem; - border-top: 1px solid #84d1d526; + border-top: 1px solid #84d1d52e; backdrop-filter: blur(2px) contrast(1.14); /* text-shadow: 0px 1px 3px #000C, 0px 1px 1px #000B; */ text-shadow: unset; @@ -1004,20 +1038,27 @@ section#project { } } - >b.partners { - margin-top: 1.2rem; + >div.partners { + margin-top: 1.4rem; + margin-bottom: 0.5rem; 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; + display: flex; + flex-direction: column; - >:is(strong, b) { - /* display: block; */ + >div.icon { + height: 24px; + scale: 1.2; + background: linear-gradient(#ffe24c 30%, #b89301 80%); + mask: var(--mask-image) no-repeat center bottom; + } + + >b { + text-align: center; + font-family: Bahnschrift; font-weight: 600; - color: #ebdada; + font-size: 1.2em; + color: #d6d327; + text-shadow: 0px 0px 5px #FFB54147, 0px 0px 2px #FFAF313D; } } @@ -1071,7 +1112,7 @@ section#project { --width: 100vw; padding: 0 2rem; - >div.adaptive { + /* >div.adaptive { margin-bottom: var(--margin-bottom, 0.8rem); display: flex; flex-direction: row; @@ -1095,7 +1136,7 @@ section#project { >section#buttons { margin-bottom: unset; } - } + } */ } } diff --git a/kodorvan/site/system/public/themes/default/css/pages/article.css b/kodorvan/site/system/public/themes/default/css/pages/article.css new file mode 100755 index 0000000..4075677 --- /dev/null +++ b/kodorvan/site/system/public/themes/default/css/pages/article.css @@ -0,0 +1,36 @@ +@charset "UTF-8"; + +body { + >main { + >article#article { + z-index: 500; + border-radius: 1.25rem; + margin: 3rem 0 8rem; + width: 880px; + box-sizing: border-box; + padding: 3rem 4rem; + background: #fff; + + >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#article { + margin-bottom: unset; + width: 100%; + border-radius: unset; + } + } + } +} diff --git a/kodorvan/site/system/public/themes/default/css/pages/system/superpack/create.css b/kodorvan/site/system/public/themes/default/css/pages/system/superpack/create.css index 0f12928..5d3b407 100755 --- a/kodorvan/site/system/public/themes/default/css/pages/system/superpack/create.css +++ b/kodorvan/site/system/public/themes/default/css/pages/system/superpack/create.css @@ -145,6 +145,140 @@ body { } } + >div#superpack_image { + >img.icon { + grid-row: 1; + align-self: start; + } + + >div { + --padding-vertical: 1.7em; + grid-row: 1/3; + position: relative; + min-height: 6ch; + height: min-content; + padding: 0 1.3em var(--padding-vertical, 1em); + display: flex; + flex-direction: column; + justify-content: start; + align-items: center; + gap: 0.2rem; + + &:has(>input[type="file"]:is(:hover, :focus)) { + >label.pseudoinput { + background-color: #e7e6e0; + } + } + + &:has(>input[type="file"]:active) { + >label.pseudoinput { + background-color: #c0bfb4; + } + } + + >span.title { + z-index: 60; + margin: unset; + margin-top: calc(var(--padding-vertical, 1em) + 0.3em); + font-family: Bahnschrift; + font-size: 0.9em; + font-weight: 400; + pointer-events: none; + } + + >ol.files { + z-index: 50; + margin: unset; + margin-top: 0.2em; + padding: unset; + display: flex; + flex-direction: column; + gap: 0.2em; + font-size: 0.8em; + list-style: numbered; + + &:empty { + display: none; + } + + >li { + position: relative; + height: 1.3em; + box-sizing: border-box; + line-height: 1.1em; + + &:has(>button:is(:hover, :focus)) { + border-bottom: 1px dashed #000; + } + + &:has(>button:active) { + border-bottom: 1px solid #000; + } + + >button.delete { + position: absolute; + top: -0.05em; + right: -1.7em; + height: 1.3em; + padding: 0.15em; + border: unset; + background: unset; + + >img { + width: 100%; + height: 100%; + display: block; + } + + &:is(:hover, :focus) { + background-color: #3302; + } + + &:active { + background-color: #3304; + } + } + } + } + + >small.guide { + z-index: 60; + text-align: center; + pointer-events: none; + } + + >label.pseudoinput { + z-index: 0; + position: absolute; + width: 100%; + height: 100%; + box-sizing: border-box; + cursor: context-menu; + border: 1px dashed #000; + + &:is(:hover, :focus) { + >label.pseudoinput { + background-color: #e7e6e0; + } + } + + &:active { + >label.pseudoinput { + background-color: #c0bfb4; + } + } + } + + >input[type="file"] { + position: absolute; + width: 0; + height: 0; + opacity: 0; + pointer-events: none; + } + } + } + >button { padding: 1.2rem 1rem; font-size: 1.1rem; @@ -162,7 +296,7 @@ body { @media (width < 1000px) { body { >main { - >article#offer { + >article#superpack { margin-bottom: unset; width: 100%; border-radius: unset; diff --git a/kodorvan/site/system/public/themes/default/css/system.css b/kodorvan/site/system/public/themes/default/css/system.css index 3fe1cc8..0922d21 100755 --- a/kodorvan/site/system/public/themes/default/css/system.css +++ b/kodorvan/site/system/public/themes/default/css/system.css @@ -130,6 +130,10 @@ a { user-select: none; } +.underline { + text-decoration: underline; +} + input[type="range"] { cursor: grab; diff --git a/kodorvan/site/system/public/themes/default/images/icons/crown.svg b/kodorvan/site/system/public/themes/default/images/icons/crown.svg new file mode 100644 index 0000000..f3d677c --- /dev/null +++ b/kodorvan/site/system/public/themes/default/images/icons/crown.svg @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/kodorvan/site/system/public/themes/default/images/icons/white/crown.svg b/kodorvan/site/system/public/themes/default/images/icons/white/crown.svg new file mode 100644 index 0000000..c9064a7 --- /dev/null +++ b/kodorvan/site/system/public/themes/default/images/icons/white/crown.svg @@ -0,0 +1,14 @@ + + + diff --git a/kodorvan/site/system/public/themes/default/images/icons/white/solid/crown.svg b/kodorvan/site/system/public/themes/default/images/icons/white/solid/crown.svg new file mode 100644 index 0000000..21604fe --- /dev/null +++ b/kodorvan/site/system/public/themes/default/images/icons/white/solid/crown.svg @@ -0,0 +1,12 @@ + + + diff --git a/kodorvan/site/system/views/themes/default/elements/project/full.html b/kodorvan/site/system/views/themes/default/elements/project/full.html index 6935fd4..ea370c9 100755 --- a/kodorvan/site/system/views/themes/default/elements/project/full.html +++ b/kodorvan/site/system/views/themes/default/elements/project/full.html @@ -31,7 +31,7 @@ oninput="core.global.project.architecture = this.value" > - {% for value, label in project.architectures %} + {% for value, label in calculator.architectures %} {% endfor %} @@ -48,7 +48,7 @@ oninput="core.global.project.purpose = this.value" > - {% for value, label in project.purposes %} + {% for value, label in calculator.purposes %} {% endfor %} @@ -57,7 +57,7 @@ - Разрешаю запись, обработку и хранение моих персональных данных + Разрешаю запись, обработку и хранение моих персональных данных, без передачи третьим лицам @@ -162,7 +166,7 @@
@@ -183,9 +187,12 @@
- Команда разработчиков - мы реальные исполнители из Перми! Передача кода заказчику в его полную собственность и подпись NDA. Не используем ИИ в разработке! Полная анонимность проектов - никто не узнает кто разработчик. Не оставляем блокировки и скрытую рекламу в коде! - Гарантия качества: небольшие и простые проекты мы передаём нашим студентам, но за качество кода и соблюдение сроков всегда отвечает наставник! - Поддерживаем проекты наших
партнёров с 2014 года!
+ Команда разработчиков - реальные исполнители! Передача кода заказчику в его полную собственность и подпись NDA. Не используем ИИ в разработке! Полная анонимность проектов - никто не узнает кто разработчик. Не оставляем блокировки и скрытую рекламу в коде! Собственные сервера в Перми! + Гарантия качества: небольшие и простые проекты мы передаём нашим студентам, но за качество кода и соблюдение сроков всегда отвечает наставник! +
+
+ Поддерживаем проекты наших
партнёров с 2014 года!
+
{% include '/themes/default/interface/media.html' %} diff --git a/kodorvan/site/system/views/themes/default/pages/article.html b/kodorvan/site/system/views/themes/default/pages/article.html index 07e0755..952dd32 100755 --- a/kodorvan/site/system/views/themes/default/pages/article.html +++ b/kodorvan/site/system/views/themes/default/pages/article.html @@ -4,7 +4,7 @@ {{ parent() }} - + {% endblock %} @@ -14,10 +14,23 @@ {% block main %} {% include '/themes/default/interface/logotype.html' %} -
-

{{ article.title }}

+
+
+

{{ article.head.title }}

+ {% if article.head.image.src is not empty %} + + {% endif %} +
- {{ article.html|raw }} +
+ {{ article.body.html|raw }} +
{% endblock %} diff --git a/kodorvan/site/system/views/themes/default/pages/system/article/create.html b/kodorvan/site/system/views/themes/default/pages/system/article/create.html new file mode 100644 index 0000000..406d71b --- /dev/null +++ b/kodorvan/site/system/views/themes/default/pages/system/article/create.html @@ -0,0 +1,134 @@ +{% extends "/themes/default/index.html" %} + + +{% block css %} + {{ parent() }} + + + + +{% endblock %} + +{% block before %} +{% endblock %} + +{% block main %} + {% include '/themes/default/interface/logotype.html' %} + +
+

СОЗДАНИЕ СУПЕРПАКА

+ +
+ + +
+ import kodorvan +
+ Импорт + + Загрузите фоновое изображение верхнего колонтинула + + +
+
+ + + + +
+
+{% endblock %} + +{% block after %} +
+
+{% endblock %} + +{% block js %} + {{ parent() }} + +{% endblock %}