diff --git a/README.md b/README.md index 3306bd6..516d248 100755 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # works +Main site of the Svoboda organisation +## Installation + +### NGINX + +1. Create a NGINX server +You can copy an example of server file from here: `/examples/nginx/svoboda.conf` + +2. Add support for javascript modules +Edit the file `/etc/nginx/mime.types`
+`application/javascript js;` -> `application/javascript js mjs;` diff --git a/damper.mjs b/damper.mjs new file mode 160000 index 0000000..68589e9 --- /dev/null +++ b/damper.mjs @@ -0,0 +1 @@ +Subproject commit 68589e968cbc043f35c2948a9c90293b6f5f9cb9 diff --git a/examples/nginx/svoboda.dev.mirzaev.sexy b/examples/nginx/svoboda.conf similarity index 85% rename from examples/nginx/svoboda.dev.mirzaev.sexy rename to examples/nginx/svoboda.conf index ded6ce9..3ca0e77 100644 --- a/examples/nginx/svoboda.dev.mirzaev.sexy +++ b/examples/nginx/svoboda.conf @@ -2,7 +2,7 @@ server { listen 80; listen [::]:80; - server_name svoboda.dev.mirzaev.sexy; + server_name svoboda.works; # 301 302 return 301 https://$server_name$request_uri; @@ -14,7 +14,7 @@ server { listen [::]:443 ssl; listen [::]:443 quic; - server_name svoboda.dev.mirzaev.sexy; + server_name svoboda.works; http2 on; http3 on; @@ -31,7 +31,7 @@ server { keepalive_timeout 60; include snippets/ssl-params.conf; - include snippets/ssl-mirzaev.conf; + include snippets/ssl-svoboda.conf; include snippets/php8_4.conf; location / { @@ -44,7 +44,7 @@ server { add_header Cache-Control "max-age=2629746, public"; } - location ~* \.(?:css|js)$ { + location ~* \.(?:css|js|mjs|min)$ { expires 1y; access_log off; add_header Cache-Control "max-age=31556952, public"; diff --git a/graph.mjs b/graph.mjs new file mode 160000 index 0000000..0300f33 --- /dev/null +++ b/graph.mjs @@ -0,0 +1 @@ +Subproject commit 0300f3376550b9d0a07d1c41db88452af67e366b diff --git a/hotline.mjs b/hotline.mjs new file mode 160000 index 0000000..81aca40 --- /dev/null +++ b/hotline.mjs @@ -0,0 +1 @@ +Subproject commit 81aca4001629e8f3cab8a849c1e892dbac74c88a diff --git a/install.sh b/install.sh index 58c7455..c780dcc 100755 --- a/install.sh +++ b/install.sh @@ -1,10 +1,37 @@ #!/bin/bash +# Renaming project folder if [ -d author/project ]; then mv author/project author/works fi +# Renaming project author folder if [ -d author ]; then mv author svoboda fi +# Initializing the javascript modules folder +if [ ! -d svoboda/works/system/public/js/modules ]; then + mkdir -p ./svoboda/works/system/public/js/modules +fi + +# Updating repositories +cd damper.mjs && git pull +cd ../hotline.mjs && git pull +cd ../graph.mjs && git pull +cd ../ + +# Installing "damper.min.mjs" +if [ ! -h svoboda/works/system/public/js/modules/damper.min.mjs ]; then + ln -s ../../../../../../damper.mjs/damper.min.mjs svoboda/works/system/public/js/modules/damper.min.mjs +fi + +# installing "hotline.min.mjs" +if [ ! -h svoboda/works/system/public/js/modules/hotline.min.mjs ]; then + ln -s ../../../../../../hotline.mjs/hotline.min.mjs svoboda/works/system/public/js/modules/hotline.min.mjs +fi + +# Installing "graph.min.mjs" +if [ ! -h svoboda/works/system/public/js/modules/graph.min.mjs ]; then + ln -s ../../../../../../graph.mjs/graph.min.mjs svoboda/works/system/public/js/modules/graph.min.mjs +fi diff --git a/svoboda/works/system/controllers/index.php b/svoboda/works/system/controllers/index.php index c1b12f7..1a92ab1 100755 --- a/svoboda/works/system/controllers/index.php +++ b/svoboda/works/system/controllers/index.php @@ -9,7 +9,7 @@ use svoboda\works\controllers\core; // Framework for PHP use mirzaev\minimal\http\enumerations\content, -mirzaev\minimal\http\enumerations\status; + mirzaev\minimal\http\enumerations\status; /** * Index @@ -44,6 +44,78 @@ final class index extends core if (str_contains($this->request->headers['accept'], content::any->value)) { // Request for any response + // Initializing distributions + $this->view->distributions = [ + [ + 'identifier' => 1, + 'name' => 'Dreamers', + 'members' => [ + [ + 'identifier' => 1, + 'name' => [ + 'first' => 'Arsen', + 'second' => 'Mirzaev', + 'other' => 'Tatyano-Muradovich' + ] + ], + [ + 'identifier' => 2, + 'name' => [ + 'first' => 'Margarita', + 'second' => 'Esenina', + 'other' => '' + ] + ], + [ + 'identifier' => 5, + 'name' => [ + 'first' => 'Maxim', + 'second' => '', + 'other' => '' + ] + ], + [ + 'identifier' => 6, + 'name' => [ + 'first' => 'Hidden', + 'second' => '', + 'other' => '' + ] + ], + [ + 'identifier' => 7, + 'name' => [ + 'first' => 'Hidden', + 'second' => '', + 'other' => '' + ] + ] + ] + ], + [ + 'identifier' => 2, + 'name' => 'Unnamed', + 'members' => [ + [ + 'identifier' => 3, + 'name' => [ + 'first' => 'Pavel', + 'second' => '', + 'other' => '' + ] + ], + [ + 'identifier' => 4, + 'name' => [ + 'first' => 'Georgiy', + 'second' => '', + 'other' => '' + ] + ] + ] + ] + ]; + // Render page $page = $this->view->render('/pages/statistics/total.html'); diff --git a/svoboda/works/system/public/js/core.js b/svoboda/works/system/public/js/core.js new file mode 100644 index 0000000..1c88851 --- /dev/null +++ b/svoboda/works/system/public/js/core.js @@ -0,0 +1,274 @@ +/** + * @name Core + * + * @description + * Core of the project + * + * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License + * @author Arsen Mirzaev Tatyano-Muradovich + */ +class core { + // Domain + static domain = window.location.hostname; + + // Language + static language = "ru"; + + /** + * Request + * + * @param {string} uri + * @param {string} body + * @param {string} method POST, GET... + * @param {object} headers + * @param {string} type Format of response (json, text...) + * + * @return {Promise} + */ + static async request( + uri = "/", + body, + method = "GET", + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json", + }, + type = "json", + ) { + return await fetch(encodeURI(uri), { method, headers, body }) + .then((response) => type === null || response[type]()); + } + + /** + * @name Modules + * + * @method connect(modules) Connect modules + * + * @return {Array} List of initialized modules + */ + static modules() { + return Object.keys(this).filter((module) => + this[module]?.type === "module" + ); + } + + /** + * Сгенерировать окно выбора действия + * + * @param {string} title Верхний колонтинул + * @param {string} text Основное содержимое окна + * @param {string} left Содержимое левой кнопки + * @param {object} left_css Перечисление CSS-классов левой кнопки (массив) + * @param {function} left_click Действие после нажатия на левую кнопку + * @param {string} right Содержимое правой кнопки + * @param {object} right_css Перечисление CSS-классов правой кнопки (массив) + * @param {function} right_click Действие после нажатия на правую кнопку + * + * @return {void} + */ + /* static choose = core.damper( + ( + title = "Выбор действия", + text = "", + left = "Да", + left_css = ["grass"], + left_click = () => {}, + right = "Нет", + right_css = ["clay"], + right_click = () => {}, + ) => { + // Инициализация оболочки всплывающего окна + this.popup_body.wrap = document.createElement("div"); + this.popup_body.wrap.setAttribute("id", "popup"); + + // Инициализация всплывающего окна + const popup = document.createElement("section"); + popup.classList.add("list", "small"); + + // Инициализация заголовка всплывающего окна + const title_h3 = document.createElement("h3"); + title_h3.classList.add("unselectable"); + title_h3.innerText = title; + + // Инициализация оболочки с основной информацией + const main = document.createElement("section"); + main.classList.add("main"); + + // Инициализация колонки + const column = document.createElement("div"); + column.classList.add("column"); + + // Инициализация текста + const text_p = document.createElement("p"); + text_p.innerText = text; + + // Инициализация строки + const row = document.createElement("div"); + row.classList.add("row", "buttons"); + + // Инициализация левой кнопки + const left_button = document.createElement("button"); + left_button.classList.add(...left_css); + left_button.innerText = left; + left_button.addEventListener("click", left_click); + + // Инициализация правой кнопки + const right_button = document.createElement("button"); + right_button.classList.add(...right_css); + right_button.innerText = right; + right_button.addEventListener("click", right_click); + + // Инициализация окна с ошибками + this.popup_body.errors = document.createElement("section"); + this.popup_body.errors.classList.add( + "errors", + "window", + "list", + "calculated", + "hidden", + ); + this.popup_body.errors.setAttribute("data-errors", true); + + // Инициализация элемента-тела (оболочки) окна с ошибками + const errors = document.createElement("section"); + errors.classList.add("body"); + + // Инициализация элемента-списка ошибок + const dl = document.createElement("dl"); + + // Инициализация активного всплывающего окна + const old = document.getElementById("popup"); + + if (old instanceof HTMLElement) { + // Найдено активное окно + + // Деинициализация быстрых действий по кнопкам + document.removeEventListener("keydown", this.buttons); + + // Сброс блокировки + this.freeze = false; + + // Удаление активного окна + old.remove(); + } + + // Запись в документ + popup.appendChild(title_h3); + + column.appendChild(text_p); + + row.appendChild(left_button); + row.appendChild(right_button); + column.appendChild(row); + + main.appendChild(column); + popup.appendChild(main); + + this.popup_body.wrap.appendChild(popup); + document.body.appendChild(this.popup_body.wrap); + + errors.appendChild(dl); + this.popup_body.errors.appendChild(errors); + this.popup_body.wrap.appendChild(this.popup_body.errors); + + // Инициализация ширины окна с ошибками + this.popup_body.errors.style.setProperty( + "--calculated-width", + popup.offsetWidth + "px", + ); + + // Инициализация переменных для окна с ошибками (12 - это значение gap из div#popup) + function top(errors) { + errors.style.setProperty("transition", "0s"); + errors.style.setProperty( + "--top", + popup.offsetTop + popup.offsetHeight + 12 + "px", + ); + setTimeout(() => errors.style.removeProperty("transition"), 100); + } + top(this.popup_body.errors); + const resize = new ResizeObserver(() => top(this.popup_body.errors)); + resize.observe(this.popup_body.wrap); + + // Инициализация функции закрытия всплывающего окна + const click = () => { + // Блокировка + if (this.freeze) return; + + // Удаление всплывающего окна + this.popup_body.wrap.remove(); + + // Удаление статуса активной строки + row.removeAttribute("data-selected"); + + // Деинициализация быстрых действий по кнопкам + document.removeEventListener("keydown", this.buttons); + + // Сброс блокировки + this.freeze = false; + }; + + // Инициализация функции добавления функции закрытия всплывающего окна + const enable = () => + this.popup_body.wrap.addEventListener("click", click); + + // Инициализация функции удаления функции закрытия всплывающего окна + const disable = () => + this.popup_body.wrap.removeEventListener("click", click); + + // Первичная активация функции удаления всплывающего окна + enable(); + + // Добавление функции удаления всплывающего окна по событиям + popup.addEventListener("mouseenter", disable); + popup.addEventListener("mouseleave", enable); + + // Добавление функции удаления всплывающего окна по кнопкам + left_button.addEventListener("click", click); + right_button.addEventListener("click", click); + + // Фокусировка + right_button.focus(); + }, + 300, + ); */ +} + +Object.assign( + core.modules, + { + /** + * @name Connect modules + * + * @param {(Array|string)} modules Names of modules or name of the module + * @param {boolean} [minified=false] Is this a minified module? (add ".min") + * + * @return {Prommise} + */ + async connect(modules, minified = false) { + // Normalisation required argiments + if (typeof modules === "string") modules = [modules]; + + if (modules instanceof Array) { + // Received and validated required arguments + + // Initializing the registry of loaded modules + const loaded = []; + + for (const module of modules) { + // Iterating over modules + + // Downloading, importing and writing the module into a core property and into registry of loaded modules + core[module] = + loaded[module] = + await (await import( + `./modules/${module}` + (minified ? ".min.mjs" : ".mjs") + )); + } + + // Exit (success) + return loaded; + } + }, + }, +); diff --git a/svoboda/works/system/public/js/elements/aside.js b/svoboda/works/system/public/js/elements/aside.js old mode 100644 new mode 100755 index 688ea29..ed503f7 --- a/svoboda/works/system/public/js/elements/aside.js +++ b/svoboda/works/system/public/js/elements/aside.js @@ -1,11 +1,17 @@ try { - import("https://codepen.io/mirzaev-sexy/pen/gOzBZOP.js").then((hotline) => { - const element = document.getElementsByTagName("aside")[0]; + core.modules.connect("hotline", true).then( + () => { + // Imported the hotline module - element.instance = new hotline.default(element); + const element = document.getElementsByTagName("aside")[0]; - element.instance.step = -1; + element.instance = new core.hotline.hotline(element); - element.instance.start(); - }); + element.instance.step = -1; + + element.instance.start(); + }, + () => { + }, + ); } catch (e) {} diff --git a/svoboda/works/system/public/js/elements/diagram.js b/svoboda/works/system/public/js/elements/diagram.js old mode 100644 new mode 100755 diff --git a/svoboda/works/system/public/js/elements/distributions.js b/svoboda/works/system/public/js/elements/distributions.js new file mode 100755 index 0000000..bb8dfc5 --- /dev/null +++ b/svoboda/works/system/public/js/elements/distributions.js @@ -0,0 +1,87 @@ +try { + // Initializing the graph shell
element + const shell = document.getElementById("distributions"); + + // Initializing the initial node destination coordinates + const destination = { + left: window.innerWidth / 100 * 65, + top: window.innerHeight / 100 * 55, + }; + + // Initializing loading shell + const loading = shell.nextElementSibling; + + if (loading instanceof HTMLElement) { + // Initialized loading shell + + // Writing the initial node destination coordinates + loading.style.setProperty("--left", destination.left + "px"); + loading.style.setProperty("--top", destination.top + "px"); + } + + core.modules.connect("graph", true).then( + () => { + // Imported the damper module + + if (shell instanceof HTMLElement) { + // Initialized the graph shell
element + + // Initializing the graph instance + const instance = new core.graph.core(shell); + + // Writing settings of the graph instance + instance.living = 2000; + // instance.camera = true; + instance.operate = true; + + //instance.left = window.innerWidth * 250; // 250vw (width 500vw) + //instance.top = window.innerHeight * 250; // 250vh (height 500vh) + + // Registering every node + [...shell.children].forEach((node) => + instance.node(new core.graph.node(node)) + ); + + // Writing settings for every node + /* instance.nodes.forEach((node) => { + node.variables.get("inputs").type = "deg"; + }); */ + + // temporary + shell.instance = instance; + const nodes = [...instance.nodes]; + + instance.edge(new core.graph.edge(nodes[1], nodes[0])); + instance.edge(new core.graph.edge(nodes[2], nodes[0])); + instance.edge(new core.graph.edge(nodes[3], nodes[0])); + instance.edge(new core.graph.edge(nodes[4], nodes[0])); + instance.edge(new core.graph.edge(nodes[5], nodes[0])); + instance.edge(new core.graph.edge(nodes[6], nodes[0])); + instance.edge(new core.graph.edge(nodes[7], nodes[6])); + instance.edge(new core.graph.edge(nodes[8], nodes[6])); + + /* var max; + + [...temp0.instance.nodes].forEach((node) => { + if (node.inputs.size > (max?.inputs.size || 0)) max = node; + }); */ + + nodes[0].move( + destination.left - nodes[0].radius, + destination.top - nodes[0].radius, + ); + + nodes[0].interactions.movement.active = false; + // nodes[0].interactions.pushing.active = false; + // nodes[0].interactions.pulling.active = false; + + setTimeout(() => { + shell.classList.add("appearance", "animated"); + nodes[0].interactions.movement.active = true; + }, 3000); + } + }, + () => { + }, + ); +} catch (e) {} diff --git a/svoboda/works/system/public/js/elements/eye.js b/svoboda/works/system/public/js/elements/eye.js old mode 100644 new mode 100755 diff --git a/svoboda/works/system/public/js/modules/damper.min.mjs b/svoboda/works/system/public/js/modules/damper.min.mjs new file mode 120000 index 0000000..881957a --- /dev/null +++ b/svoboda/works/system/public/js/modules/damper.min.mjs @@ -0,0 +1 @@ +../../../../../../damper.mjs/damper.min.mjs \ No newline at end of file diff --git a/svoboda/works/system/public/js/modules/graph.min.mjs b/svoboda/works/system/public/js/modules/graph.min.mjs new file mode 120000 index 0000000..5dcc804 --- /dev/null +++ b/svoboda/works/system/public/js/modules/graph.min.mjs @@ -0,0 +1 @@ +../../../../../../graph.mjs/graph.min.mjs \ No newline at end of file diff --git a/svoboda/works/system/public/js/modules/hotline.min.mjs b/svoboda/works/system/public/js/modules/hotline.min.mjs new file mode 120000 index 0000000..c443ff0 --- /dev/null +++ b/svoboda/works/system/public/js/modules/hotline.min.mjs @@ -0,0 +1 @@ +../../../../../../hotline.mjs/hotline.min.mjs \ No newline at end of file diff --git a/svoboda/works/system/public/themes/default/css/aside.css b/svoboda/works/system/public/themes/default/css/aside.css index 1f5b851..004e171 100755 --- a/svoboda/works/system/public/themes/default/css/aside.css +++ b/svoboda/works/system/public/themes/default/css/aside.css @@ -1,7 +1,7 @@ @charset "UTF-8"; aside { - z-index: 100; + z-index: 200; margin-top: var(--gap); grid-row: 1 / 2; grid-column: 1 / 4; diff --git a/svoboda/works/system/public/themes/default/css/body.css b/svoboda/works/system/public/themes/default/css/body.css index d92245e..5d3cc06 100755 --- a/svoboda/works/system/public/themes/default/css/body.css +++ b/svoboda/works/system/public/themes/default/css/body.css @@ -6,8 +6,12 @@ body { height: 100vh; display: grid; grid-template-rows: max(200px, 20vh) auto; - grid-template-columns: 60px auto 60px; + grid-template-columns: 60px auto 60px auto; gap: var(--gap); overflow: hidden; background-color: var(--background-color); + background: -moz-linear-gradient(180deg, var(--background-color-top) 0%, var(--background-color-bottom) 100%); + background: -webkit-linear-gradient(180deg, var(--background-color-top) 0%, var(--background-color-bottom) 100%); + background: linear-gradient(180deg, var(--background-color-top) 0%, var(--background-color-bottom) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="var(--background-color-top)",endColorstr="var(--background-color-bottom)",GradientType=1); } diff --git a/svoboda/works/system/public/themes/default/css/colors.css b/svoboda/works/system/public/themes/default/css/colors.css index d2f09cf..55ea003 100755 --- a/svoboda/works/system/public/themes/default/css/colors.css +++ b/svoboda/works/system/public/themes/default/css/colors.css @@ -16,14 +16,19 @@ --button-background-color: #9f9b39; --section-border-color: #593535; - --section-background-color: #593535; - --section-block-background-color: #522d2d; + --section-block-background-color: #592727; + /* --section-background-color: #593535; */ + --section-background-color: #4d2323; - --section-menu-background-color: #4b2828; --section-menu-button-color: #fbffb6; --section-menu-button-background-color-hover: #592c2c; --section-menu-button-background-color-active: #412222; - --section-menu-button-background-color-selected: #412222; + /* --section-menu-button-background-color-selected: #412222; */ + /* --section-menu-button-background-color-selected: #220c0c; */ + --section-menu-button-background-color-selected: #5b3d2b; + /* --section-menu-background-color: #4b2828; */ + /* --section-menu-background-color: #311515; */ + --section-menu-background-color: #4f2b22; --section-timeline-background-color: #143531; --section-timeline-button-color: #859779; @@ -37,9 +42,8 @@ --section-aside-button-background-color: rgb(255 237 189 / 30%); --section-aside-button-background-color-hover: rgb(77 9 9 / 70%); --section-aside-button-background-color-active: rgb(77 9 9 / 70%); - --header-background-color: #351d1d; - --footer-background-color: #351d1d; - --background-color: #654949; + --header-background-color: #1e0a0a; + --footer-background-color: #1e0a0a; --diagram-text-color: #c3a275; --diagram-text-color-hover: #e5bb83; @@ -59,6 +63,12 @@ --diagram-legend-color-0: #461d1d; color: var(--text-color); + + /* --background-color: #654949; */ + /* --background-color: #6f3d3d; */ + --background-color: #402821; + --background-color-top: #402821; + --background-color-bottom: #2a1414; } } diff --git a/svoboda/works/system/public/themes/default/css/elements/distributions.css b/svoboda/works/system/public/themes/default/css/elements/distributions.css new file mode 100755 index 0000000..3d323e9 --- /dev/null +++ b/svoboda/works/system/public/themes/default/css/elements/distributions.css @@ -0,0 +1,63 @@ +@charset "UTF-8"; + +/* body:active { + cursor: move; +} */ + +section#distributions { + z-index: 50; + left: var(--graph-shell-left); + top: var(--graph-shell-top); + width: 100vw; + height: 100vh; + position: absolute; +} + +section#distributions>article.node { + z-index: calc(500 + var(--graph-node-layer, 0) - var(--graph-node-inputs, 0)); + left: var(--graph-node-from-left, var(--graph-node-left)); + top: var(--graph-node-from-top, var(--graph-node-top)); + width: var(--graph-node-augmented, 100px); + height: var(--graph-node-augmented, 100px); + position: absolute; + display: flex; + cursor: grab; + border-radius: 100%; + -webkit-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); +} + +section#distributions>article.node.distribution { + background-color: rgb(calc(140 + var(--graph-node-inputs) * 10), 110, 60); +} + +section#distributions>article.node.member { + background-color: rgb(calc(140 + var(--graph-node-inputs) * 10), 100, 70); +} + +section#distributions>article.node:active { + cursor: grabbing; +} + +section#distributions>article.node>a:first-of-type { + margin: auto; + text-align: center; + text-decoration: unset; + font-weight: bold; + cursor: pointer; + color: black; +} + +section#distributions>svg.edge { + z-index: -500; + position: absolute; + width: 100%; + height: 100%; + pointer-events: none; +} + +section#distributions>svg.edge>line { + stroke: #443225; + stroke-width: 8px; +} diff --git a/svoboda/works/system/public/themes/default/css/elements/graph.css b/svoboda/works/system/public/themes/default/css/elements/graph.css new file mode 100755 index 0000000..30a9b1d --- /dev/null +++ b/svoboda/works/system/public/themes/default/css/elements/graph.css @@ -0,0 +1,82 @@ +@charset "UTF-8"; + +@keyframes appearance { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes disappearance { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes node-movement { + 0% { + left: var(--graph-node-from-left); + top: var(--graph-node-from-top); + } + + 100% { + left: var(--graph-node-to-left); + top: var(--graph-node-to-top); + } +} + +section.graph:not(.appearance) { + opacity: 0; +} + +section.graph.appearance:not(.animated) { + opacity: 1; +} + +section.graph.appearance.animated { + animation-name: appearance; + animation-fill-mode: forwards; + animation-duration: 0.2s; + animation-timing-function: ease-in; +} + +section.graph.dissapearance:not(.appearance.animated), +section.graph:not(.dissapearance).appearance.animated + div.loading { + animation-name: appearance; + animation-fill-mode: forwards; + animation-duration: 0.2s; + animation-timing-function: ease-in; + animation-direction: reverse; +} + +section.graph .node.movement { + animation-name: node-movement; + animation-fill-mode: forwards; + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0, 1, 1, 1); +} + +section.graph+div.loading { + z-index: 60; + position: absolute; + width: 100vw; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + pointer-events: none; + background-color: #00000040; +} + +section.graph+div.loading>i.icon.loading { + position: absolute; + left: var(--left, -100vw); + top: var(--top, -100vh); +} diff --git a/svoboda/works/system/public/themes/default/css/elements/total.css b/svoboda/works/system/public/themes/default/css/elements/total.css new file mode 100755 index 0000000..9f7af19 --- /dev/null +++ b/svoboda/works/system/public/themes/default/css/elements/total.css @@ -0,0 +1,35 @@ +@charset "UTF-8"; + +main>section.row>section.main#total>div#diagram.column { + margin-top: auto; + width: 100%; + height: fit-content; + display: flex; + flex-direction: column; + gap: var(--gap); +} + +main>section.row>section.main#total>div#diagram.column:has(svg.chart) { + padding-left: 1rem; +} + +main>section.row>section.main#total>div#diagram.column>svg.pie { + height: min(30%, 300px); +} + +main>section.row>section.main#total>div#diagram.column>small.formula { + margin: 0 1.4rem; + padding-right: 4rem; + font-size: 0.8rem; + color: var(--diagram-legend-text-color); +} + +main>section.row>section.main#total>div#diagram.column>svg.chart { + margin: -2.5rem -1rem -3rem; + width: calc(100% + 1rem); +} + +main>section.row>section.main#total>div#diagram.column>div.background { + width: 100%; + height: 170px; +} diff --git a/svoboda/works/system/public/themes/default/css/icons/loading.css b/svoboda/works/system/public/themes/default/css/icons/loading.css new file mode 100755 index 0000000..82e7b94 --- /dev/null +++ b/svoboda/works/system/public/themes/default/css/icons/loading.css @@ -0,0 +1,39 @@ +@charset "UTF-8"; + +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + + to { + transform: rotate(359deg); + } +} + +i.icon.loading, +i.icon.loading::after, +i.icon.loading::before { + position: relative; + width: 20px; + height: 20px; + display: block; + box-sizing: border-box; +} + +i.icon.loading::after, +i.icon.loading::before { + content: ""; + position: absolute; + border-radius: 100px; +} + +i.icon.loading::before { + border: 3px solid transparent; + border-top-color: currentColor; + animation: spinner 1s cubic-bezier(0.6, 0, 0.4, 1) infinite; +} + +i.icon.loading::after { + opacity: 0.2; + border: 3px solid; +} diff --git a/svoboda/works/system/public/themes/default/css/icons/work.css b/svoboda/works/system/public/themes/default/css/icons/work.css new file mode 100755 index 0000000..72ec38c --- /dev/null +++ b/svoboda/works/system/public/themes/default/css/icons/work.css @@ -0,0 +1,26 @@ +@charset "UTF-8"; + +i.icon.work, +i.icon.work::after { + display: block; + box-sizing: border-box; + box-shadow: 0 0 0 2px; +} + +i.icon.work { + position: relative; + width: 14px; + height: 10px; + border-radius: 1px; +} + +i.icon.work::after { + content: ""; + position: absolute; + left: 4px; + top: -3px; + width: 6px; + height: 1px; + border-top-left-radius: 1px; + border-top-right-radius: 1px; +} diff --git a/svoboda/works/system/public/themes/default/css/main.css b/svoboda/works/system/public/themes/default/css/main.css index 86a35f7..7aabba1 100755 --- a/svoboda/works/system/public/themes/default/css/main.css +++ b/svoboda/works/system/public/themes/default/css/main.css @@ -1,215 +1,207 @@ @charset "UTF-8"; main { - z-index: 200; - margin-bottom: var(--gap); - grid-row: 2 / 3; - grid-column: 2 / 3; - display: grid; - grid-template-rows: 2rem 43px auto; - gap: var(--gap); + z-index: 100; + margin-bottom: var(--gap); + grid-row: 2 / 3; + grid-column: 2 / 3; + display: grid; + grid-template-rows: 2rem 43px auto; + gap: var(--gap); + pointer-events: none; } -main > nav { - z-index: 200; - display: flex; - align-items: center; - overflow: hidden; +main>nav { + z-index: 200; + display: flex; + align-items: center; + overflow: hidden; + pointer-events: all; } -main > nav > * { - display: flex; - flex-direction: column; - justify-content: center; +main>nav>* { + display: flex; + flex-direction: column; + justify-content: center; } -main > nav#timeline { - margin-bottom: -0.3rem; - grid-row: 1 / 2; - padding: 0 0.5rem; - align-items: end; +main>nav#timeline { + margin-bottom: -0.3rem; + grid-row: 1 / 2; + padding: 0 0.5rem; + align-items: end; } -main > nav#timeline > * { - padding: 0.5rem; - font-weight: bold; - color: var(--section-timeline-button-color); +main>nav#timeline>* { + padding: 0.5rem; + font-weight: bold; + color: var(--section-timeline-button-color); } -main > nav#timeline > *:is(:hover, :focus) { - color: var(--section-timeline-button-color-hover); +main>nav#timeline>*:is(:hover, :focus) { + color: var(--section-timeline-button-color-hover); } -main > nav#timeline > *:active { - color: var(--section-timeline-button-color-active); +main>nav#timeline>*:active { + color: var(--section-timeline-button-color-active); } -main > nav#timeline > *.selected { - color: var(--section-timeline-button-selected-color); +main>nav#timeline>*.selected { + color: var(--section-timeline-button-selected-color); } -main > nav#timeline > *.selected:is(:hover, :focus) { - color: var(--section-timeline-button-selected-color-hover); +main>nav#timeline>*.selected:is(:hover, :focus) { + color: var(--section-timeline-button-selected-color-hover); } -main > nav#timeline > *.selected:active { - color: var(--section-timeline-button-selected-color-active); +main>nav#timeline>*.selected:active { + color: var(--section-timeline-button-selected-color-active); } -main > nav#menu { - grid-row: 2 / 3; - border-radius: 0.75rem; - background-color: var(--section-menu-background-color); - -webkit-box-shadow: 0px 0px 12px 2px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0px 0px 12px 2px rgba(0, 0, 0, 0.1); - box-shadow: 0px 0px 12px 2px rgba(0, 0, 0, 0.1); +main>nav#menu { + grid-row: 2 / 3; + max-width: var(--section-main-width); + border-radius: 0.75rem; + background-color: var(--section-menu-background-color); + -webkit-box-shadow: 0px 0px 12px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 0px 12px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0px 0px 12px 2px rgba(0, 0, 0, 0.1); } -main > nav#menu > * { - height: 100%; - padding: 0 1rem; - color: var(--section-menu-button-color); +main>nav#menu>* { + height: 100%; + padding: 0 1rem; + color: var(--section-menu-button-color); } -main > nav#menu > *:first-child { - margin-right: auto; +main>nav#menu>*:first-child { + margin-right: auto; } -main > nav#menu > *.selected:is(:hover, :focus), -main > nav#menu > *:is(:hover, :focus) { - background-color: var(--section-menu-button-background-color-hover); +main>nav#menu>*.selected:is(:hover, :focus), +main>nav#menu>*:is(:hover, :focus) { + background-color: var(--section-menu-button-background-color-hover); } -main > nav#menu > *.selected { - background-color: var(--section-menu-button-background-color-selected); +main>nav#menu>*.selected { + background-color: var(--section-menu-button-background-color-selected); } -main > nav#menu > *.selected:active, -main > nav#menu > *:active { - background-color: var(--section-menu-button-background-color-active); +main>nav#menu>*.selected:active, +main>nav#menu>*:active { + background-color: var(--section-menu-button-background-color-active); } -main > section { - z-index: 200; - grid-row: 3 / 4; - padding: 1rem; - display: flex; - flex-direction: column; - gap: var(--gap); - border-radius: 0.75rem; - background-color: var(--section-background-color); - -webkit-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); - box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); +main>section.row { + z-index: 200; + grid-row: 3 / 4; + gap: var(--gap); + border-radius: 0.75rem; + pointer-events: none; } -main > section > h1 { - margin: 0.5rem 1rem 0.5rem 1rem; - font-size: 1.2rem; +main>section.row>section.main { + --padding: 1rem; + max-width: calc(var(--section-main-width) - var(--padding) * 2); + width: 100%; + padding: var(--padding); + display: flex; + gap: var(--gap); + pointer-events: all; + border-radius: 0.75rem; + background-color: var(--section-background-color); + -webkit-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); } -main > section > h1.row { - align-items: center; - gap: var(--gap); +main>section.row>section.main>h1 { + margin: 0.5rem 1rem 0.5rem 1rem; + font-size: 1.2rem; } -main > section > h1 > a { - min-width: 1rem; - height: 100%; - padding: 0.2rem; - display: inline-flex; - justify-content: start; - align-items: center; +main>section.row>section.main>h1.row { + align-items: center; + gap: var(--gap); } -main > section > h1 > a:first-of-type { - margin-left: auto; +main>section.row>section.main>h1>a { + min-width: 1rem; + height: 100%; + padding: 0.2rem; + display: inline-flex; + justify-content: start; + align-items: center; } -main > section > div.row { - padding: 0rem 1rem; - justify-content: space-between; +main>section.row>section.main>h1>a:first-of-type { + margin-left: auto; } -main > section .block { - background: var(--section-block-background-color); +main>section.row>section.main>div.row { + padding: 0rem 1rem; + justify-content: space-between; } -main > section .block.text { - padding: 0.6rem 0.8rem; - display: inline-flex; - flex-flow: row wrap; +main>section.row>section.main .block { + background: var(--section-block-background-color); } -main > section .block.text > a.continue { - margin-left: auto; - align-self: flex-end; +main>section.row>section.main .block.text { + padding: 0.6rem 0.8rem; + display: inline-flex; + flex-flow: row wrap; } -main > section p.block { - margin: unset; +main>section.row>section.main .block.text>a.continue { + margin-left: auto; + align-self: flex-end; } -main > section ul.block { - min-width: 200px; - height: fit-content; +main>section.row>section.main p.block { + margin: unset; } -main > section > div.footer > small.phrase { - flex-grow: 1; - text-align: center; +main>section.row>section.main ul.block { + min-width: 200px; + height: fit-content; } -main > section > div.footer > small#views { - position: relative; - margin-left: auto; - align-items: center; +main>section.row>section.main>div.footer>small.phrase { + flex-grow: 1; + text-align: center; } -main > section > div.footer > small#views > * { - z-index: 500; +main>section.row>section.main>div.footer>small#views { + position: relative; + margin-left: auto; + align-items: center; } -main > section > div.footer > small#views > div.visibility { - z-index: 300; - position: absolute; - right: calc(-100px + 10.5px + 0rem); - top: calc(-100px + 0.5rem); - width: 200px; - height: 200px; - /* pointer-events: none; */ +main>section.row>section.main>div.footer>small#views>* { + z-index: 500; } -main > section#total > div#diagram.column { - margin-top: auto; - width: 100%; - height: fit-content; - display: flex; - flex-direction: column; - gap: var(--gap); +main>section.row>section.main>div.footer>small#views>div.visibility { + z-index: 300; + position: absolute; + right: calc(-100px + 10.5px + 0rem); + top: calc(-100px + 0.5rem); + width: 200px; + height: 200px; + /* pointer-events: none; */ } -main > section#total > div#diagram.column:has(svg.chart) { - padding-left: 1rem; -} - -main > section#total > div#diagram.column > svg.pie { - height: min(30%, 300px); -} - -main > section#total > div#diagram.column > small.formula { - margin: 0 1.4rem; - padding-right: 4rem; - font-size: 0.8rem; - color: var(--diagram-legend-text-color); -} - -main > section#total > div#diagram.column > svg.chart { - margin: -2.5rem -1rem -3rem; - width: calc(100% + 1rem); -} - -main > section#total > div#diagram.column > div.background { - width: 100%; - height: 170px; +main>section.row>section.second { + --padding: 1rem; + max-width: calc(var(--section-main-width) - var(--padding) * 2); + width: 100%; + padding: var(--padding); + display: flex; + gap: var(--gap); + border-radius: 0.75rem; + background-color: var(--section-background-color); + -webkit-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 12px 2px rgba(0, 0, 0, 0.1); } diff --git a/svoboda/works/system/public/themes/default/css/system.css b/svoboda/works/system/public/themes/default/css/system.css index 9f7d648..36df54d 100755 --- a/svoboda/works/system/public/themes/default/css/system.css +++ b/svoboda/works/system/public/themes/default/css/system.css @@ -1,7 +1,9 @@ @charset "UTF-8"; :root { - --gap: min(12px, 1rem); + --gap: min(12px, 1rem); + --section-main-width: 800px; + transition: 0.1s ease-out; } @@ -16,13 +18,13 @@ /* Selection */ ::selection { - color: var(--text-selected-color); - background: var(--text-selected-background-color); + color: var(--text-selected-color); + background: var(--text-selected-background-color); } ::-moz-selection { - color: var(--text-selected-color); - background: var(--text-selected-background-color); + color: var(--text-selected-color); + background: var(--text-selected-background-color); } .unselectable { @@ -38,78 +40,82 @@ a, *[type="button"] { - cursor: pointer; + cursor: pointer; } a, -a > * { - color: var(--link-color); +a>* { + color: var(--link-color); } a:is(:hover, :focus), -a:is(:hover, :focus) > * { - color: var(--link-color-hover); +a:is(:hover, :focus)>* { + color: var(--link-color-hover); } a:active, -a:active > * { - color: var(--link-color-active); +a:active>* { + color: var(--link-color-active); } /* Wrappers */ :is(.row, .column) { - gap: var(--gap); + gap: var(--gap); } .row:not(.column) { - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; } .column:not(.row) { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } /* Macroses */ .rounded { - border-radius: 0.75rem; + border-radius: 0.75rem; } .grow { - flex-grow: 1; + flex-grow: 1; } /* Lists */ :is(ol, ul) { - margin: unset; - padding: 0.6rem 0.8rem; - gap: 0.3rem; + margin: unset; + padding: 0.6rem 0.8rem; + gap: 0.3rem; } :is(ol, ul):is(.column, .row) { - gap: 0.3rem; + gap: 0.3rem; } li { - display: inline-flex; + display: inline-flex; } -li > span.name:first-child:after { - content: ":"; +li>span.name:first-child:after { + content: ":"; } -li > span.value:last-child { - margin-left: auto; +li>span.value:last-child { + margin-left: auto; } -li > span.value:last-child:before { - content: var(--old); - margin-right: 0.4rem; - font-size: 0.8rem; - text-decoration: line-through; - color: var(--text-notice-color); +li>span.value:last-child:before { + content: var(--old); + margin-right: 0.4rem; + font-size: 0.8rem; + text-decoration: line-through; + color: var(--text-notice-color); +} + +div.loading { + display: none; } diff --git a/svoboda/works/system/views/themes/default/aside.html b/svoboda/works/system/views/themes/default/aside.html index 238f168..0810524 100755 --- a/svoboda/works/system/views/themes/default/aside.html +++ b/svoboda/works/system/views/themes/default/aside.html @@ -61,4 +61,5 @@ {% endblock %} {% block js %} + {% endblock %} diff --git a/svoboda/works/system/views/themes/default/eclipse.html b/svoboda/works/system/views/themes/default/eclipse.html old mode 100644 new mode 100755 diff --git a/svoboda/works/system/views/themes/default/elements/menu.html b/svoboda/works/system/views/themes/default/elements/menu.html old mode 100644 new mode 100755 diff --git a/svoboda/works/system/views/themes/default/elements/timeline.html b/svoboda/works/system/views/themes/default/elements/timeline.html old mode 100644 new mode 100755 diff --git a/svoboda/works/system/views/themes/default/head.html b/svoboda/works/system/views/themes/default/head.html index b14d1e2..e963e57 100755 --- a/svoboda/works/system/views/themes/default/head.html +++ b/svoboda/works/system/views/themes/default/head.html @@ -23,4 +23,5 @@ + {% endblock %} diff --git a/svoboda/works/system/views/themes/default/index.html b/svoboda/works/system/views/themes/default/index.html index d146206..1ea310d 100755 --- a/svoboda/works/system/views/themes/default/index.html +++ b/svoboda/works/system/views/themes/default/index.html @@ -19,6 +19,8 @@ {{ main|raw }} {% endblock %} +{% block graph %} +{% endblock %} {{ block('footer') }} {% endblock %} diff --git a/svoboda/works/system/views/themes/default/js.html b/svoboda/works/system/views/themes/default/js.html index 1d2086e..7a9034d 100755 --- a/svoboda/works/system/views/themes/default/js.html +++ b/svoboda/works/system/views/themes/default/js.html @@ -1,6 +1,6 @@ {% block js %} + {% for element in js %} {% endfor %} - {% endblock %} diff --git a/svoboda/works/system/views/themes/default/pages/statistics/total.html b/svoboda/works/system/views/themes/default/pages/statistics/total.html index 15af1bc..4530b2a 100755 --- a/svoboda/works/system/views/themes/default/pages/statistics/total.html +++ b/svoboda/works/system/views/themes/default/pages/statistics/total.html @@ -8,112 +8,116 @@ + + + {% endblock %} {% block main %} {% include '/themes/default/elements/timeline.html' %} {% include '/themes/default/elements/menu.html' %} -
-

Общие показатели за 2024 год

-
-
+
+
+

Общие показатели за 2024 год

+
-

- здесь потом статья будет - Читать продолжение -

+
+

+ здесь потом статья будет + Читать продолжение +

+
+
+
+ +
    +
  • + Участники + 8 +
  • +
  • + Постройки + 3 +
  • +
  • + Транспорт + 0 +
  • +
-
- -
    -
  • - Участники - 8 -
  • -
  • - Постройки - 3 -
  • -
  • - Транспорт - 0 -
  • -
+
+ участники + постройки + транспорт + сумма ресурсов + завершённые + проекты + + + + + + Время + + Общие показатели + + Январь + + + + Февраль + + + + Март + + + + Апрель + + + + Май + + + + Июнь + + + + Июль + + + + Август + + + + Сентябрь + + + + Октябрь + + + + Ноябрь + + + + Декабрь + + +
-
-
- участники + постройки + транспорт + сумма ресурсов + завершённые - проекты - - - - - - Время - - Общие показатели - - Январь - - - - Февраль - - - - Март - - - - Апрель - - - - Май - - - - Июнь - - - - Июль - - - - Август - - - - Сентябрь - - - - Октябрь - - - - Ноябрь - - - - Декабрь - - - -
- - + 1693 +
+
+
+
{% endblock %} +{% block graph %} +
+ {% for distribution in distributions %} + + {% for member in distribution.members %} + + {% endfor %} + {% endfor %} +
+
+{% endblock %} + {% block js %} +{{ parent() }} + {% endblock %}