Compare commits
No commits in common. "stable" and "2.0.1" have entirely different histories.
108
README.md
108
README.md
|
@ -173,24 +173,20 @@ You can copy an example of server file from here: `/examples/nginx/server.conf`
|
|||
Edit the file `/etc/nginx/mime.types`<br>
|
||||
`application/javascript js;` -> `application/javascript js mjs;`
|
||||
|
||||
3. **Generate a TLS/SSL sertificate** (via [certbot](http://certbot.eff.org/) for [ubuntu](https://ubuntu.com/))<br>
|
||||
3.1. `sudo apt install certbot python3-certbot-nginx`<br>
|
||||
3.2. `sudo certbot certonly --nginx` (The **domain** must already be **bound** to the **IP-address** of the server by `A-record` or `AAAA-record`)
|
||||
|
||||
5. **Firewall rules for HTTP and HTTPS** (for [ubuntu](https://ubuntu.com/))<br>
|
||||
4.1 `sudo ufw allow "NGINX Full"`<br>
|
||||
4.1.1 `sudo ufw allow 22` (make sure that the port for SSH connection is open)<br>
|
||||
4.2 `sudo ufw enable`
|
||||
3. Generate a TLS/SSL sertificate (via [certbot](http://certbot.eff.org/))<br>
|
||||
3.1. `sudo apt-get install software-properties-common`<br>
|
||||
3.2. `sudo add-apt-repository ppa:certbot/certbot`<br>
|
||||
3.3. `sudo apt-get update`<br>
|
||||
3.4. `sudo apt install certbot python-certbot-nginx`<br>
|
||||
3.5. `sudo certbot certonly --nginx`
|
||||
|
||||
### SystemD (or any alternative you like)
|
||||
You can copy an example of systemd file from here: `/examples/systemd/huesos.service`<br>
|
||||
1. `sudo cp huesos.service /etc/systemd/system/huesos.service && sudo chmod +x /etc/systemd/system/huesos.service`
|
||||
2. `sudo systemctl daemon-reload`
|
||||
3. `sudo systemctl enable huesos`<br>
|
||||
|
||||
You can copy an example of systemd file from here: `/examples/systemd/huesos.service`<br><br>
|
||||
**Execute:** `sudo cp huesos.service /etc/systemd/system/huesos.service && sudo chmod +x /etc/systemd/system/huesos.service`<br><br>
|
||||
*before you execute the command think about **what it does** and whether the **paths** are specified correctly*<br>
|
||||
*the configuration file is very simple and you can remake it for any alternative to SystemD that you like*
|
||||
|
||||
|
||||
## Menu
|
||||
*Menu inside the Web App*<br><br>
|
||||
Make sure you have a **menu** collection (can be created automatically)<br>
|
||||
|
@ -226,9 +222,9 @@ You can copy a clean settings document without comments from here: `/examples/ar
|
|||
|
||||
```json
|
||||
{
|
||||
"status": "active", // Values: "active", "inactive" (string) Status of the settings document?
|
||||
"status": "active",
|
||||
"project": {
|
||||
"name": "PROJECT" // Name of the projext (string)
|
||||
"name": "PROJECT"
|
||||
},
|
||||
"language": "en", // Will be converted to an instance of enumeration `mirzaev\arming_bot\models\enumerations\language`
|
||||
"currency": "usd", // Will be converted to an instance of enumeration `mirzaev\arming_bot\models\enumerations\currency`
|
||||
|
@ -244,94 +240,13 @@ You can copy a clean settings document without comments from here: `/examples/ar
|
|||
"enabled": true, // Enable the search input field?
|
||||
"position": "fixed" // Values: "fixed", "relative"
|
||||
},
|
||||
"catalog": {
|
||||
"categories": {
|
||||
"display": "column", // Values: "row" (flex wrap), "column" (rows) Type of the catalog display
|
||||
"structure": "lists", // Values: "pages" (pages with categories and products), "lists" (all categories as tree lists on the main page)
|
||||
"buttons": {
|
||||
"height": "120px", // Examples: "80px", "120px", "180px" (string|null) Height of buttons
|
||||
"background": "#fafafa", // Examples: "#fafafa", "yellow" (string|null) Color of buttons background
|
||||
"separator": {
|
||||
"enabled": true, // Enable separators?
|
||||
"width": "60%" // Exaples: "100%", "80%", "60%" (string|null) Width of separators over images (relative to image width from the left)
|
||||
},
|
||||
"lists": {
|
||||
"height": "800px", // Examples: "500px", "100%" (string|null) Maximum height of lists (`max-height` for animations working)
|
||||
"background": null, // Examples: "#fafafa", "yellow" (string|null) Color of lists
|
||||
"separator": null, // Examples: "#fafafa", "yellow" (string|null) Color of separators between rows
|
||||
"separated": true, // Separate lists from its buttons?
|
||||
"blocks": true, // Blocks instead of plain text?
|
||||
"arrow": true // Add arrow at the right?
|
||||
},
|
||||
"texts": {
|
||||
"position": {
|
||||
"vertical": "center" // Values: "top", "center", "bottom" (string|null) Position of texts of ascendants categories
|
||||
},
|
||||
"width": "max(8rem, 20%)", // Examples: "60%", "5rem", "max(8rem, 20%)" (string|null) Width of the text section (left side of buttons)
|
||||
"background": false, // Enable wrapping element for texts?
|
||||
"title": {
|
||||
"color": "#020202" // Examples: "#fafafa", "yellow" (string|null) Color of titles
|
||||
},
|
||||
"description": {
|
||||
"color": "#121212" // Examples: "#fafafa", "yellow" (string|null) Color of descriptions
|
||||
}
|
||||
},
|
||||
"images": {
|
||||
"filter": "contrast(1.2)" // Example: "contrast(1.2)" (string|null) Filter for images
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"enabled": true // Enable the cart button?
|
||||
},
|
||||
"css": {
|
||||
"catalog-button-cart-background": "#40a7e3",
|
||||
"product-button-cart-background": "#40a7e3"
|
||||
"catalog-button-cart-added-background": "#90be36",
|
||||
"product-button-cart-added-background": "#90be36"
|
||||
},
|
||||
"account": {
|
||||
"enabled": false // Enable the account section? (works only when opened from telegram `inline-button`)
|
||||
},
|
||||
"menu": {
|
||||
"enabled": true, // Enable the main menu?
|
||||
"position": "fixed" // Values: "fixed" (fixed to the bottom as a solid line), "relative" (at the top as separated buttons) (stirng) Position of the main menu
|
||||
},
|
||||
"header": {
|
||||
"enabled": true, // Enable the header?
|
||||
"position": "fixed" // Values: "fixed" (fixed to the bottom), "relative" (at the top) (stirng) Position of the header
|
||||
},
|
||||
"acquirings": {
|
||||
"robokassa": {
|
||||
"enabled": true, // Enable the Robokassa acquiring?
|
||||
"mode": "test" // Values: "work", "test" (string) Mode of the Robokassa acquiring
|
||||
}
|
||||
},
|
||||
"input": {
|
||||
"deliveries": {
|
||||
"site": [], // Values: "sim", "name", "destination", "address", "commentary"
|
||||
"chat": [
|
||||
"sim",
|
||||
"name",
|
||||
"destination",
|
||||
"address",
|
||||
"commentary"
|
||||
] // Values: "sim", "name", "destination", "address", "commentary"
|
||||
}
|
||||
},
|
||||
"deliveries": {
|
||||
"cdek": {
|
||||
"enabled": true, // Enable CDEK delivery?
|
||||
"label": "CDEK" // Name of the CDEK delivery
|
||||
}
|
||||
},
|
||||
"chats": [
|
||||
{
|
||||
"id": null, // Example: -1002599391893 (int) (negative number) The telegram chat identifier
|
||||
"orders": true // Send orders? (for moderators)
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -365,4 +280,3 @@ You can copy a clean suspension document without comments from here: `/examples/
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,41 +1,37 @@
|
|||
#
|
||||
# This section is commented out to make it possible to run NGINX without errors
|
||||
# to generate TLS/SSL certificate via CertBot (see README.md)
|
||||
#
|
||||
# server {
|
||||
# listen 443 default_server ssl;
|
||||
# listen [::]:443 ssl default_server;
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl ipv6only=on;
|
||||
|
||||
# server_name domain.zone;
|
||||
server_name domain.zone;
|
||||
|
||||
# root /var/www/huesos/mirzaev/huesos/system/public;
|
||||
root /var/www/huesos/mirzaev/huesos/system/public;
|
||||
|
||||
# index index.php;
|
||||
index index.php;
|
||||
|
||||
# ssl_certificate /etc/letsencrypt/live/domain.zone/fullchain.pem;
|
||||
# ssl_certificate_key /etc/letsencrypt/live/domain.zone/privkey.pem;
|
||||
# include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
ssl_certificate /etc/letsencrypt/live/domain.zone/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/domain.zone/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
# location / {
|
||||
# try_files $uri $uri/ /index.php?$query_string;
|
||||
# }
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# location /api/cdek {
|
||||
# rewrite ^/api/cdek(.*)$ /$1 break;
|
||||
# index cdek.php;
|
||||
# }
|
||||
location /api/cdek {
|
||||
rewrite ^/api/cdek(.*)$ /$1 break;
|
||||
index cdek.php;
|
||||
}
|
||||
|
||||
# location ~ /(?<type>categories|products) {
|
||||
# root /var/www/huesos/mirzaev/huesos/system/storage;
|
||||
# try_files $uri =404;
|
||||
# }
|
||||
location ~ /(?<type>categories|products) {
|
||||
root /var/www/huesos/mirzaev/huesos/system/storage;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# location ~ \.php$ {
|
||||
# include snippets/fastcgi-php.conf;
|
||||
# fastcgi_pass unix:/run/php/php8.4-fpm.sock;
|
||||
# }
|
||||
# }
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace mirzaev\huesos\controllers;
|
|||
// Files of the project
|
||||
use mirzaev\huesos\controllers\core,
|
||||
mirzaev\huesos\models\enumerations\language,
|
||||
mirzaev\huesos\models\catalog as model,
|
||||
mirzaev\huesos\models\entry,
|
||||
mirzaev\huesos\models\category,
|
||||
mirzaev\huesos\models\product,
|
||||
|
@ -196,26 +195,31 @@ final class catalog extends core
|
|||
// Write to the response buffer
|
||||
$response['category'] = ['name' => $category->name ?? null];
|
||||
|
||||
// Searching for entries that are descendants of $category
|
||||
$search = model::search(
|
||||
// Search for categories that are descendants of $category
|
||||
$entries = entry::search(
|
||||
document: $category,
|
||||
amount: 200,
|
||||
depth: 100,
|
||||
amount: 50,
|
||||
categories_merge: 'name: v.name.@language',
|
||||
/* products_merge: 'DISTINCT MERGE(d, {name: d.name.@language, description: d.description.@language, compatibility: d.compatibility.@language, brand: d.brand.@language, cost: d.cost.@currency})', */
|
||||
parameters: ['language' => $this->language->name],
|
||||
errors: $this->errors['catalog']
|
||||
);
|
||||
|
||||
if (isset($this->settings->catalog['categories']['structure']) && $this->settings->catalog['categories']['structure'] === 'pages') {
|
||||
// Pages
|
||||
// Initialize buffers of entries (in singular, by parameter from ArangoDB)
|
||||
$category = $product = [];
|
||||
|
||||
// Write to the buffer of global variables of view templater
|
||||
$this->view->categories = $search['categories'];
|
||||
foreach ($entries as $entry) {
|
||||
// Iterate over entries (descendands)
|
||||
|
||||
// Write entry to the buffer of entries (sort by $category and $product)
|
||||
${$entry->_type}[] = $entry;
|
||||
}
|
||||
|
||||
// Write to the buffer of global variables of view templater
|
||||
$this->view->products = $search['products'];
|
||||
$this->view->categories = $category;
|
||||
|
||||
// Write to the buffer of global variables of view templater
|
||||
$this->view->products = $product;
|
||||
|
||||
if (isset($this->view->products) && count($this->view->products) > 0) {
|
||||
// Amount of rendered products is more than 0
|
||||
|
@ -230,51 +234,13 @@ final class catalog extends core
|
|||
} else if (!isset($category)) {
|
||||
// Not received identifier of the category
|
||||
|
||||
if (isset($this->settings->catalog['categories']['structure']) && $this->settings->catalog['categories']['structure'] === 'pages') {
|
||||
// Pages
|
||||
|
||||
// Searching for root ascendants categories
|
||||
// search for root ascendants categories
|
||||
$this->view->categories = entry::ascendants(
|
||||
descendant: new category,
|
||||
return: 'DISTINCT MERGE(d, { name: d.name.@language})',
|
||||
parameters: ['language' => $this->language->name],
|
||||
errors: $this->errors['catalog']
|
||||
) ?? null;
|
||||
} else if (isset($this->settings->catalog['categories']['structure']) && $this->settings->catalog['categories']['structure'] === 'lists') {
|
||||
// Lists
|
||||
|
||||
// Initializing the list of all categories
|
||||
$categories = [];
|
||||
|
||||
// Initializing the structure of the list of all categories
|
||||
$structure = [];
|
||||
|
||||
foreach (
|
||||
entry::ascendants(
|
||||
descendant: new category,
|
||||
return: 'DISTINCT MERGE(d, { name: d.name.@language})',
|
||||
parameters: ['language' => $this->language->name],
|
||||
errors: $this->errors['catalog']
|
||||
) ?? null as $document
|
||||
) {
|
||||
// Iterating over found root ascendants categories
|
||||
|
||||
// Generating the list (entering into recursion)
|
||||
static::list(
|
||||
document: $document,
|
||||
language: $this->language,
|
||||
categories: $categories,
|
||||
structure: $structure,
|
||||
errors: $this->errors['catalog']
|
||||
);
|
||||
}
|
||||
|
||||
// Writing the list of all categories into the templater variable
|
||||
$this->view->categories = $categories;
|
||||
|
||||
// Writing the structure of the list of all categories into the templater variable
|
||||
$this->view->structure = $structure;
|
||||
}
|
||||
}
|
||||
|
||||
// Validating @todo add throwing errors
|
||||
|
@ -427,56 +393,4 @@ final class catalog extends core
|
|||
// Exit (success/fail)
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* List
|
||||
*
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function list(_document $document, language $language, array &$categories = [], array &$structure = [], array &$errors = []): void
|
||||
{
|
||||
// Initializing the object
|
||||
$category = new category;
|
||||
|
||||
if (method_exists($category, '__document')) {
|
||||
// Object can implement a document from ArangoDB
|
||||
|
||||
// Writing the instance of product document from ArangoDB to the implement object
|
||||
$category->__document($document);
|
||||
|
||||
// Writing the category into the list of categories
|
||||
$categories[$category->getId()] = $category;
|
||||
|
||||
// Writing the category into the structure of the list categories
|
||||
$structure[$category->getId()] = [];
|
||||
|
||||
// Searching for entries that are descendants of $category
|
||||
$search = model::search(
|
||||
document: $category,
|
||||
amount: 200,
|
||||
categories_merge: 'name: v.name.@language',
|
||||
parameters: ['language' => $language->name],
|
||||
errors: $errors
|
||||
);
|
||||
|
||||
if (count($search['categories']) > 0) {
|
||||
// Found descendants categories
|
||||
|
||||
foreach ($search['categories'] as $document) {
|
||||
// Iterating over descendants categories
|
||||
|
||||
// Entering into descendant level of the recursion for the list generation
|
||||
static::list(
|
||||
document: $document,
|
||||
language: $language,
|
||||
categories: $categories,
|
||||
structure: $structure[$category->getId()],
|
||||
errors: $errors
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,62 +45,6 @@ final class catalog extends core
|
|||
yandex::list as folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search
|
||||
*
|
||||
* @param category|product $document Ascendant document
|
||||
* @param string|null $filter Expression for filtering (AQL)
|
||||
* @param string|null $sort Expression for sorting (AQL)
|
||||
* @param int $depth Amount of nodes for traversal search (subcategories/products inside subcategories...)
|
||||
* @param int $page Page
|
||||
* @param int $amount Amount of documents per page
|
||||
* @param string|null $categories_merge Expression with paremeters to return for categories (AQL)
|
||||
* @param string|null $products_merge Expression with paremeters to return for products (AQL)
|
||||
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
||||
* @param array &$errors Registry of errors
|
||||
*
|
||||
* @return array [categories => [document::class...], $products => [document::class...]]
|
||||
*/
|
||||
public static function search(
|
||||
category|product $document,
|
||||
?string $filter = 'v.deleted != true && v.hidden != true',
|
||||
?string $sort = 'v.position ASC, v.created DESC',
|
||||
int $depth = 1,
|
||||
int $page = 1,
|
||||
int $amount = 100,
|
||||
?string $categories_merge = null,
|
||||
?string $products_merge = null,
|
||||
array $parameters = [],
|
||||
array &$errors = []
|
||||
): array {
|
||||
// Search for entries that are descendants of $category
|
||||
$entries = entry::search(
|
||||
document: $document,
|
||||
filter: $filter,
|
||||
sort: $sort,
|
||||
depth: $depth,
|
||||
page: $page,
|
||||
amount: $amount,
|
||||
categories_merge: $categories_merge,
|
||||
products_merge: $products_merge,
|
||||
parameters: $parameters,
|
||||
errors: $errors
|
||||
);
|
||||
|
||||
// Initialize buffers of entries (in singular, by parameter from ArangoDB)
|
||||
$category = $product = [];
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
// Iterate over entries (descendands)
|
||||
|
||||
// Write entry to the buffer of entries (sort by $category and $product)
|
||||
${$entry->_type}[] = $entry;
|
||||
}
|
||||
|
||||
// Exit (success)
|
||||
return ['categories' => $category, 'products' => $product];
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect parameter from all products
|
||||
*
|
||||
|
|
|
@ -223,9 +223,8 @@ final class entry extends core implements document_interface, collection_interfa
|
|||
* @param category|product $document Ascendant document
|
||||
* @param string|null $filter Expression for filtering (AQL)
|
||||
* @param string|null $sort Expression for sorting (AQL)
|
||||
* @param int $depth Amount of nodes for traversal search (subcategories/products inside subcategories...)
|
||||
* @param int $page Page
|
||||
* @param int $amount Amount of documents per page
|
||||
* @param int $page Страница
|
||||
* @param int $amount Количество товаров на странице
|
||||
* @param string|null $categories_merge Expression with paremeters to return for categories (AQL)
|
||||
* @param string|null $products_merge Expression with paremeters to return for products (AQL)
|
||||
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
||||
|
@ -237,7 +236,6 @@ final class entry extends core implements document_interface, collection_interfa
|
|||
category|product $document,
|
||||
?string $filter = 'v.deleted != true && v.hidden != true',
|
||||
?string $sort = 'v.position ASC, v.created DESC',
|
||||
int $depth = 1,
|
||||
int $page = 1,
|
||||
int $amount = 100,
|
||||
?string $categories_merge = null,
|
||||
|
@ -254,13 +252,12 @@ final class entry extends core implements document_interface, collection_interfa
|
|||
return is_array($result = collection::execute(
|
||||
sprintf(
|
||||
<<<'AQL'
|
||||
FOR v IN 1..%u INBOUND @document GRAPH @graph
|
||||
FOR v IN 1..1 INBOUND @document GRAPH @graph
|
||||
%s
|
||||
%s
|
||||
LIMIT @offset, @amount
|
||||
RETURN DISTINCT IS_SAME_COLLECTION(@category, v._id) ? MERGE(v, {_type: @category%s}) : MERGE(v, {_type: @product%s})
|
||||
AQL,
|
||||
$depth,
|
||||
empty($filter) ? '' : "FILTER $filter",
|
||||
empty($sort) ? '' : "SORT $sort",
|
||||
empty($categories_merge) ? '' : ", $categories_merge",
|
||||
|
|
|
@ -15,5 +15,5 @@ nav#menu>a#account>img {
|
|||
height: inherit;
|
||||
object-fit: contain;
|
||||
border-radius: 100%;
|
||||
/* border: 2px solid var(--tg-theme-bottom-bar-bg-color); */
|
||||
border: 2px solid var(--tg-theme-bottom-bar-bg-color);
|
||||
}
|
||||
|
|
|
@ -1,66 +1,14 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
main>section#categories:has(a),
|
||||
main>section#categories:not(:has(a))>ul:has(li.category[type="button"]) {
|
||||
main>section#categories {
|
||||
width: var(--width);
|
||||
display: flex;
|
||||
flex-flow: var(--catalog-categories-wrap-flex-wrap, row wrap);
|
||||
flex-direction: var(--catalog-categories-wrap-flex-direction, 'row');
|
||||
}
|
||||
|
||||
main>section#categories:has(a) {
|
||||
flex-flow: row wrap;
|
||||
gap: var(--gap, 5px);
|
||||
}
|
||||
|
||||
main>section#categories:not(:has(a))>ul:has(li.category[type="button"])>ul {
|
||||
margin-bottom: var(--gap, 5px);
|
||||
}
|
||||
|
||||
main>section#categories ul {
|
||||
padding-left: 1.3rem;
|
||||
list-style-type: none;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
main>section#categories>li {
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
main>section#categories li {
|
||||
/* font-family: "Chalet"; */
|
||||
}
|
||||
|
||||
main>section#categories li.openable {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
main>section#categories ul>li:has(+ ul) {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
main>section#categories ul>ul {
|
||||
--offset: 1rem;
|
||||
--padding: 1rem;
|
||||
margin-top: calc(var(--offset, 1rem) * -1);
|
||||
padding-top: calc(var(--offset, 1rem) + var(--padding, 1rem));
|
||||
padding-bottom: var(--padding, 1rem);
|
||||
border-radius: 0 0 0.75rem 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
background: var(--catalog-categories-buttons-lists-background-color, var(--tg-theme-secondary-bg-color));
|
||||
}
|
||||
|
||||
main>section#categories:not(:has(a))>ul:has(li.category[type="button"]) {
|
||||
margin: unset;
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"],
|
||||
main>section#categories>ul>li.category[type="button"] {
|
||||
main>section#categories>a.category[type="button"] {
|
||||
--padding: 0.7rem;
|
||||
z-index: unset;
|
||||
position: relative;
|
||||
height: 23px;
|
||||
padding: var(--padding);
|
||||
|
@ -71,11 +19,10 @@ main>section#categories>ul>li.category[type="button"] {
|
|||
overflow: hidden;
|
||||
border-radius: 0.75rem;
|
||||
color: var(--tg-theme-button-text-color);
|
||||
background: var(--catalog-categories-buttons-background);
|
||||
background: unset;
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]:not(.column):after,
|
||||
main>section#categories>ul>li.category[type="button"]:not(.column):after {
|
||||
main>section#categories>a.category[type="button"]:after {
|
||||
z-index: -100;
|
||||
position: absoulute;
|
||||
left: 0;
|
||||
|
@ -97,28 +44,13 @@ main>section#categories:last-child {
|
|||
padding: unset;
|
||||
} */
|
||||
|
||||
main>section#categories>a.category[type="button"],
|
||||
main>section#categories>ul>li.category[type="button"] {
|
||||
width: var(--catalog-categories-buttons-width, calc(50% - var(--padding) * 2));
|
||||
height: var(--catalog-categories-buttons-height, 180px);
|
||||
main>section#categories>a.category[type="button"] {
|
||||
width: calc(50% - var(--padding) * 2);
|
||||
height: 180px;
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
main>section#categories ul>li[type="button"].opened+ul {
|
||||
max-height: var(--catalog-categories-buttons-lists-height, 500px);
|
||||
transition: max-height 0.15s ease-in 0.1s, margin 0s ease-out 0.1s, padding 0s ease-out 0.1s;
|
||||
}
|
||||
|
||||
main>section#categories ul>li[type="button"]:not(.opened)+ul {
|
||||
max-height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-top: 0;
|
||||
transition: max-height 0.25s ease-out, margin 0s ease-out 0.25s, padding 0s ease-out 0.25s;
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>img,
|
||||
main>section#categories>ul>li.category[type="button"]>img {
|
||||
main>section#categories>a.category[type="button"]>img {
|
||||
position: absolute;
|
||||
left: -5%;
|
||||
top: -5%;
|
||||
|
@ -126,71 +58,26 @@ main>section#categories>ul>li.category[type="button"]>img {
|
|||
height: 110%;
|
||||
object-fit: cover;
|
||||
/* filter: blur(1px); */
|
||||
filter: var(--catalog-categories-buttons-images-filter, contrast(1.2) brightness(60%));
|
||||
filter: contrast(1.2) brightness(60%);
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>img.right,
|
||||
main>section#categories>ul>li.category[type="button"]>img.right {
|
||||
/* position: absolute; */
|
||||
left: unset;
|
||||
top: unset;
|
||||
right: 0;
|
||||
width: calc(100% - var(--catalog-categories-buttons-texts-width, 10rem));
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]:is(:hover, :focus)>img,
|
||||
main>section#categories>ul>li.category[type="button"]:is(:hover, :focus)>img {
|
||||
main>section#categories>a.category[type="button"]:is(:hover, :focus)>img {
|
||||
filter: unset;
|
||||
}
|
||||
|
||||
/* main>section#categories>a.category[type="button"]:has(>img)>p { */
|
||||
main>section#categories>a.category[type="button"]>p,
|
||||
main>section#categories>ul>li.category[type="button"]>p {
|
||||
main>section#categories>a.category[type="button"]>p {
|
||||
position: absolute;
|
||||
left: var(--padding);
|
||||
top: var(--catalog-categories-buttons-texts-top, var(--padding));
|
||||
bottom: var(--catalog-categories-buttons-texts-bottom, var(--padding));
|
||||
bottom: var(--padding);
|
||||
right: var(--padding);
|
||||
margin: unset;
|
||||
width: calc(var(--catalog-categories-buttons-texts-width, 10rem) - 0.7rem * 2);
|
||||
width: min-content;
|
||||
border-radius: 0.75rem;
|
||||
color: var(--catalog-categories-buttons-texts-title-color, var(--tg-theme-text-color));
|
||||
/* background: var(--tg-theme-hint-color); */
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>div.separator.gradient:has(+img.right),
|
||||
main>section#categories>ul>li.category[type="button"]>div.separator.gradient:has(+img.right) {
|
||||
--background: var(--catalog-categories-buttons-background, var(--tg-theme-button-color));
|
||||
z-index: 100;
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: calc(100% - var(--catalog-categories-buttons-texts-width, 10rem));
|
||||
height: 100%;
|
||||
background: var(--background);
|
||||
background: linear-gradient(90deg, var(--background) 0%, transparent var(--catalog-categories-buttons-separator-width, 100%));
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>p,
|
||||
main>section#categories>ul>li.category[type="button"]>p {
|
||||
z-index: 100;
|
||||
padding: 0 calc(var(--padding) / 2);
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>p:not(.background),
|
||||
main>section#categories>ul>li.category[type="button"]>p:not(.background) {
|
||||
font-family: "Cygre";
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>p.background,
|
||||
main>section#categories>ul>li.category[type="button"]>p.background {
|
||||
padding: 8px calc(var(--padding, 0.7rem) * 1.3);
|
||||
width: min-content;
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>p.background:after,
|
||||
main>section#categories>ul>li.category[type="button"]>p.background:after {
|
||||
main>section#categories>a.category[type="button"]>p:after {
|
||||
z-index: -100;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
@ -205,6 +92,11 @@ main>section#categories>ul>li.category[type="button"]>p.background:after {
|
|||
-moz-box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
main>section#categories>a.category[type="button"]>p {
|
||||
z-index: 100;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
main>section#filters {
|
||||
--filters-height: 2rem;
|
||||
width: var(--width);
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
main>section#categories ul>ul {
|
||||
--padding: 1rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>li {
|
||||
--padding-row: calc(var(--gap, 5px) * 1);
|
||||
position: relative;
|
||||
padding: var(--padding-row);
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>li>:is(small, i.icon):last-child {
|
||||
margin-left: auto;
|
||||
margin-right: 0.1rem;
|
||||
rotate: 0deg;
|
||||
transition: rotate 0.1s ease-out;
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>li.opened>:is(small, i.icon):last-child {
|
||||
rotate: 90deg;
|
||||
transition: rotate 0.1s ease-in;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>li:after,
|
||||
main>section#categories>ul ul>li[type="button"].opened+ul:has(+ li)>li:last-of-type:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
bottom: 0px;
|
||||
width: calc(100% - var(--padding-row) * 2);
|
||||
display: block;
|
||||
align-self: center;
|
||||
border-bottom: 1px solid var(--catalog-categories-buttons-lists-separatpr-color, var(--tg-theme-hint-color));
|
||||
transition: bottom 0s linear 0s;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>li:last-of-type:not(.opened):after {
|
||||
bottom: -1rem;
|
||||
transition: bottom 0.1s ease-out 0.25s;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>li:last-of-type.opened:after {
|
||||
bottom: -1px;
|
||||
transition: bottom 0.1s ease-in;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
main>section#categories ul>li:not(.opened):has(+ ul) {
|
||||
margin-bottom: 0;
|
||||
transition: margin 0.1s ease-out 0.25s;
|
||||
}
|
||||
|
||||
main>section#categories>ul>li.opened:has(+ ul) {
|
||||
margin-bottom: var(--gap, 5px);
|
||||
transition: margin 0.1s ease-in;
|
||||
}
|
||||
|
||||
main>section#categories ul>ul {
|
||||
--offset: 0rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
main>section#categories>ul ul>ul {
|
||||
margin-left: var(--gap, 5px);
|
||||
width: calc(100% - var(--gap, 5px));
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
@font-face {
|
||||
font-family: 'Chalet';
|
||||
src: url("/themes/default/fonts/chalet/chalet.otf") format('opentype');
|
||||
font-weight: 600;
|
||||
font-style: bold;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
@font-face {
|
||||
font-family: 'Cygre';
|
||||
src: url("/themes/default/fonts/cygre/Cygre-Bold.ttf");
|
||||
font-weight: 600;
|
||||
font-style: bold;
|
||||
}
|
|
@ -26,7 +26,7 @@ i.icon.arrow:not(.circle, .square)::after {
|
|||
bottom: 7px;
|
||||
}
|
||||
|
||||
i.icon.arrow:not(.circle, .square, .short)::before {
|
||||
i.icon.arrow:not(.circle, .square)::before {
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
bottom: 10px;
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,70 +1,16 @@
|
|||
{% if categories is not empty %}
|
||||
{% if settings.catalog.categories.structure == 'pages' %}
|
||||
<section id="categories" class="unselectable">
|
||||
<section id="categories" class="unselectable">
|
||||
{% for category in categories %}
|
||||
<a id="category_{{ category.identifier }}" data-category-identifier="{{ category.identifier }}"
|
||||
class="category{% if settings.catalog.categories.display == 'column' %} column{% endif %}"
|
||||
<a id="category_{{ category.identifier }}" data-category-identifier="{{ category.identifier }}" class="category"
|
||||
type="button" href="?category={{ category.identifier }}"
|
||||
onclick="core.catalog.parameters.set('category', {{ category.identifier }}); return !core.catalog.search(event);"
|
||||
onkeydown="event.keyCode === 13 && (core.catalog.parameters.set('category', {{ category.identifier }}), core.catalog.search(event))"
|
||||
tabindex="3"
|
||||
>
|
||||
tabindex="3">
|
||||
{% if category.images %}
|
||||
{% if settings.catalog.categories.display == 'column' and settings.catalog.categories.buttons.separator.enabled %}
|
||||
<div class="separator gradient"></div>
|
||||
<img src="{{ category.images.0.storage.400 }}" alt="{{ category.name }}" ondragstart="return false;">
|
||||
{% endif %}
|
||||
<img src="{{ category.images.0.storage.400 }}"
|
||||
class="{% if settings.catalog.categories.display == 'column' %}right{% endif %}" alt="{{ category.name }}" ondragstart="return false;">
|
||||
{% endif %}
|
||||
<p class="{% if settings.catalog.categories.buttons.texts.background %}background{% endif %}">{{ category.name }}{% if category.description %} <small>{{ category.description }}</small>{% endif %}</p>
|
||||
<p>{{ category.name }}</p>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% elseif settings.catalog.categories.structure == 'lists' %}
|
||||
{% macro generate(structure, categories) %}
|
||||
{% for category, descendants in structure %}
|
||||
{% if descendants is empty %}
|
||||
<li id="category_{{ categories[category].identifier }}" type="button"
|
||||
onclick="core.catalog.parameters.set('category', {{ categories[category].identifier }}); return !core.catalog.search(event);">
|
||||
{{ categories[category].name }}</li>
|
||||
{% else %}
|
||||
<li id="category_{{ categories[category].identifier }}" type="button" class="openable" onclick="this.classList.toggle('opened'); for (const sibling of [...this.parentElement.children].filter(children => children !== this)) { sibling.classList.remove('opened'); }">
|
||||
{{ categories[category].name }}
|
||||
{% if settings.catalog.categories.buttons.lists.arrow %}
|
||||
<i class="icon arrow short"></i>
|
||||
{% endif %}
|
||||
</li>
|
||||
<ul>
|
||||
<li id="category_{{ categories[category].identifier }}" type="button"
|
||||
onclick="core.catalog.parameters.set('category', {{ categories[category].identifier }}); return !core.catalog.search(event);">
|
||||
Все товары
|
||||
</li>
|
||||
{{ _self.generate(descendants, categories) }}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
<section id="categories" class="unselectable">
|
||||
{% if structure is not empty %}
|
||||
<ul>
|
||||
{% for category, descendants in structure %}
|
||||
<li id="category_{{ categories[category].identifier }}" class="category openable" type="button" tabindex="3" onclick="this.classList.toggle('opened'); for (const sibling of [...this.parentElement.children].filter(children => children !== this)) { sibling.classList.remove('opened'); }">
|
||||
{% if categories[category].images %}
|
||||
{% if settings.catalog.categories.display == 'column' and settings.catalog.categories.buttons.separator.enabled %}
|
||||
<div class="separator gradient"></div>
|
||||
{% endif %}
|
||||
<img src="{{ categories[category].images.0.storage.400 }}"
|
||||
class="{% if settings.catalog.categories.display == 'column' %}right{% endif %}" alt="{{ categories[category].name }}" ondragstart="return false;">
|
||||
{% endif %}
|
||||
<p class="{% if settings.catalog.categories.buttons.texts.background %}background{% endif %}">{{ categories[category].name }}{% if category.description %} <small>{{ categories[category].description }}</small>{% endif %}</p>
|
||||
</li>
|
||||
<ul>
|
||||
{{ _self.generate(descendants, categories) }}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
{% macro generate(categories, registry) %}
|
||||
{% for category, descendants in categories %}
|
||||
{% if descendants is empty %}
|
||||
<li id="{{ registry[category].getId() }}">{{ registry[category].name }}</li>
|
||||
{% else %}
|
||||
<li id="{{ registry[category].getId() }}">{{ registry[category].name }}</li>
|
||||
<ul>
|
||||
{{ _self.generate(descendants, registry) }}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
{% if registry is not empty and structure is not empty %}
|
||||
<ul>
|
||||
{% for category, descendants in structure %}
|
||||
<li id="{{ registry[category].getId() }}">{{ registry[category].name }}</li>
|
||||
<ul>
|
||||
{{ _self.generate(descendants, registry) }}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
|
@ -3,19 +3,6 @@
|
|||
{% block css %}
|
||||
{{ parent() }}
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/catalog.css" />
|
||||
{% if settings.catalog.categories.display == 'column' and settings.catalog.categories.structure == 'lists' %}
|
||||
{% if settings.catalog.categories.buttons.lists.separated %}
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/catalog/lists/separated.css" />
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.lists.blocks %}
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/catalog/lists/blocks.css" />
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.lists.arrow %}
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/arrow.css" />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/interface/select.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/search.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/shopping_cart.css" />
|
||||
|
|
|
@ -18,14 +18,11 @@
|
|||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/window.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/dejavu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/kabrio.css" rel="preload" />
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/cygre.css" rel="preload" />
|
||||
<!-- <link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/chalet.css" rel="preload" /> -->
|
||||
<style>
|
||||
:root {
|
||||
--currency: "{{ currency.symbol ?? '$' }}";
|
||||
--days: "{{ language.name == 'ru' ? 'дней' : 'days' }}";
|
||||
--days-short: "{{ language.name == 'ru' ? 'дн' : 'd' }}";
|
||||
|
||||
{% if settings.search.enabled and settings.search.position == 'fixed' %}
|
||||
{% if settings.menu.enabled %}
|
||||
{% if settings.menu.position == 'fixed' %}
|
||||
|
@ -37,76 +34,16 @@
|
|||
--header-margin-top: 3rem;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if settings.menu.enabled and settings.menu.position == 'fixed' %}
|
||||
--menu-height: {{ settings.menu.height ?? '3rem' }};
|
||||
--footer-margin-bottom: var(--menu-height);
|
||||
{% endif %}
|
||||
|
||||
{% for parameter, value in settings.css %}
|
||||
--{{ parameter }}: {{ value }};
|
||||
{% endfor %}
|
||||
|
||||
{% if cart.summary.amount > 0 %}
|
||||
--cart-amount: "{{ cart.summary.amount }}";
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.height %}
|
||||
--catalog-categories-buttons-height: {{ settings.catalog.categories.buttons.height }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.background %}
|
||||
--catalog-categories-buttons-background: {{ settings.catalog.categories.buttons.background }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.texts.title.color %}
|
||||
--catalog-categories-buttons-texts-title-color: {{ settings.catalog.categories.buttons.texts.title.color }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.texts.description.color %}
|
||||
--catalog-categories-buttons-texts-description-color: {{ settings.catalog.categories.buttons.texts.description.color }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.images.filter %}
|
||||
--catalog-categories-buttons-images-filter: {{ settings.catalog.categories.buttons.images.filter }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.display == 'column' %}
|
||||
--catalog-categories-wrap-flex-wrap: unset;
|
||||
--catalog-categories-wrap-flex-direction: 'column';
|
||||
--catalog-categories-buttons-width: 100%;
|
||||
|
||||
{% if settings.catalog.categories.buttons.separator.width %}
|
||||
--catalog-categories-buttons-separator-width: {{ settings.catalog.categories.buttons.separator.width }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.lists.background %}
|
||||
--catalog-categories-buttons-lists-background-color: {{ settings.catalog.categories.buttons.lists.background }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.lists.separator %}
|
||||
--catalog-categories-buttons-lists-separator-color: {{ settings.catalog.categories.buttons.lists.separator }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.lists.height %}
|
||||
--catalog-categories-buttons-lists-height: {{ settings.catalog.categories.buttons.lists.height }};
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.texts.position.vertical == 'top' %}
|
||||
--catalog-categories-buttons-texts-bottom: auto;
|
||||
{% elseif settings.catalog.categories.buttons.texts.position.vertical == 'center' %}
|
||||
--catalog-categories-buttons-texts-top: auto;
|
||||
--catalog-categories-buttons-texts-bottom: auto;
|
||||
{% elseif settings.catalog.categories.buttons.texts.position.vertical == 'bottom' %}
|
||||
--catalog-categories-buttons-texts-top: auto;
|
||||
{% endif %}
|
||||
|
||||
{% if settings.catalog.categories.buttons.texts.width %}
|
||||
--catalog-categories-buttons-texts-width: {{ settings.catalog.categories.buttons.texts.width }};
|
||||
{% endif %}
|
||||
{% else %}
|
||||
--catalog-categories-buttons-texts-top: auto;
|
||||
{% endif %}
|
||||
}
|
||||
</style>
|
||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/animations.css" />
|
||||
|
|
Loading…
Reference in New Issue