chore: add docs, mockup, docker config, and source materials
- Презентация портала (md + docx) - HTML-мокап всех страниц - docker-compose.yml + setup-wp.sh - Исходные документы (брендбук, концепция, референсы)
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/>
|
||||
<path d="M13.73 21a2 2 0 0 1-3.46 0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 290 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
|
||||
<line x1="16" y1="2" x2="16" y2="6"/>
|
||||
<line x1="8" y1="2" x2="8" y2="6"/>
|
||||
<line x1="3" y1="10" x2="21" y2="10"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 369 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="23 7 16 12 23 17 23 7"/>
|
||||
<rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 294 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="16" y1="13" x2="8" y2="13"/>
|
||||
<line x1="16" y1="17" x2="8" y2="17"/>
|
||||
<polyline points="10 9 9 9 8 9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 420 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
||||
<polyline points="7 10 12 15 17 10"/>
|
||||
<line x1="12" y1="15" x2="12" y2="3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 328 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 281 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 10v6M2 10l10-5 10 5-10 5z"/>
|
||||
<path d="M6 12v5c0 2 4 3 6 3s6-1 6-3v-5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 280 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 12 19.79 19.79 0 0 1 1.58 3.43 2 2 0 0 1 3.55 1.25h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.91 8.78a16 16 0 0 0 6 6l.91-.91a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 21.73 16z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 495 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="22" y1="2" x2="11" y2="13"/>
|
||||
<polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 280 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="none">
|
||||
<path d="M21.579 6.855c.14-.465 0-.806-.662-.806h-2.193c-.558 0-.813.295-.953.62 0 0-1.115 2.719-2.695 4.482-.512.512-.743.675-1.022.675-.14 0-.341-.163-.341-.628V6.855c0-.558-.162-.806-.626-.806H9.642c-.348 0-.557.258-.557.504 0 .528.79.65.871 2.138v3.228c0 .707-.128.836-.407.836-.743 0-2.551-2.729-3.624-5.853-.209-.607-.42-.852-.98-.852H2.752c-.627 0-.752.295-.752.62 0 .582.743 3.462 3.461 7.271 1.812 2.601 4.363 4.012 6.687 4.012 1.393 0 1.565-.313 1.565-.852v-1.966c0-.626.133-.751.574-.751.325 0 .883.163 2.183 1.417 1.487 1.487 1.731 2.152 2.567 2.152h2.192c.626 0 .939-.313.759-.931-.198-.616-.907-1.51-1.849-2.569-.512-.604-1.277-1.254-1.51-1.579-.325-.418-.232-.604 0-.976.001 0 2.672-3.761 2.95-5.042z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 846 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 9l9-7 9 7v11a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 297 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" fill="#E50071"/>
|
||||
<text x="50%" y="50%" dominant-baseline="central" text-anchor="middle" font-family="Arial, sans-serif" font-weight="700" font-size="20" fill="#FFFFFF">Б</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 302 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 30" height="30" role="img" aria-label="первыйБит">
|
||||
<title>первыйБит</title>
|
||||
<!-- Pink accent square -->
|
||||
<rect x="0" y="5" width="20" height="20" fill="#E50071"/>
|
||||
<!-- Wordmark text -->
|
||||
<text x="28" y="22" font-family="Arial, sans-serif" font-size="16" font-weight="700" fill="#000000" letter-spacing="-0.3">первый</text>
|
||||
<text x="100" y="22" font-family="Arial, sans-serif" font-size="16" font-weight="700" fill="#E50071" letter-spacing="-0.3">Бит</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 558 B |
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* БИТ.WMS Child Theme — js/ajax-filter.js
|
||||
*
|
||||
* Handles filter button clicks and "Load more" for the content feed section.
|
||||
* Communicates with the WordPress AJAX handler (bitwms_ajax_filter_handler).
|
||||
*
|
||||
* Global: bitwmsAjax { url: string, nonce: string }
|
||||
*/
|
||||
|
||||
( function () {
|
||||
'use strict';
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded', function () {
|
||||
var filterBar = document.querySelector( '.filter-bar' );
|
||||
var contentGrid = document.getElementById( 'content-grid' );
|
||||
var loadMoreBtn = document.getElementById( 'load-more-btn' );
|
||||
|
||||
if ( ! filterBar || ! contentGrid ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentFilter = 'all';
|
||||
var currentPage = 1;
|
||||
var isLoading = false;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Filter button click
|
||||
// ---------------------------------------------------------------
|
||||
filterBar.addEventListener( 'click', function ( e ) {
|
||||
var btn = e.target.closest( '.filter-bar__btn' );
|
||||
if ( ! btn ) return;
|
||||
|
||||
var filter = btn.getAttribute( 'data-filter' );
|
||||
if ( filter === currentFilter ) return;
|
||||
|
||||
// Update active state.
|
||||
filterBar.querySelectorAll( '.filter-bar__btn' ).forEach( function ( b ) {
|
||||
b.classList.remove( 'filter-bar__btn--active' );
|
||||
b.setAttribute( 'aria-selected', 'false' );
|
||||
} );
|
||||
btn.classList.add( 'filter-bar__btn--active' );
|
||||
btn.setAttribute( 'aria-selected', 'true' );
|
||||
|
||||
currentFilter = filter;
|
||||
currentPage = 1;
|
||||
|
||||
loadContent( false );
|
||||
} );
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Load more button click
|
||||
// ---------------------------------------------------------------
|
||||
if ( loadMoreBtn ) {
|
||||
loadMoreBtn.addEventListener( 'click', function () {
|
||||
if ( isLoading ) return;
|
||||
currentPage += 1;
|
||||
loadContent( true );
|
||||
} );
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// loadContent( append )
|
||||
// append === false: replace grid content
|
||||
// append === true: append to existing grid content
|
||||
// ---------------------------------------------------------------
|
||||
function loadContent( append ) {
|
||||
if ( isLoading ) return;
|
||||
isLoading = true;
|
||||
|
||||
if ( loadMoreBtn ) {
|
||||
loadMoreBtn.disabled = true;
|
||||
loadMoreBtn.textContent = loadMoreBtn.getAttribute( 'data-loading' ) || 'Загрузка…';
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append( 'action', 'bitwms_filter' );
|
||||
formData.append( 'nonce', bitwmsAjax.nonce );
|
||||
formData.append( 'post_type', currentFilter );
|
||||
formData.append( 'page', currentPage );
|
||||
|
||||
fetch( bitwmsAjax.url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
} )
|
||||
.then( function ( response ) {
|
||||
return response.json();
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( ! data.success ) return;
|
||||
|
||||
var html = data.data.html;
|
||||
var hasMore = data.data.has_more;
|
||||
|
||||
if ( append ) {
|
||||
contentGrid.insertAdjacentHTML( 'beforeend', html );
|
||||
} else {
|
||||
contentGrid.innerHTML = html || '<p>Материалы не найдены.</p>';
|
||||
}
|
||||
|
||||
// Show/hide load-more button.
|
||||
if ( loadMoreBtn ) {
|
||||
if ( hasMore ) {
|
||||
loadMoreBtn.style.display = '';
|
||||
loadMoreBtn.disabled = false;
|
||||
loadMoreBtn.textContent = 'Загрузить ещё';
|
||||
} else {
|
||||
loadMoreBtn.style.display = 'none';
|
||||
}
|
||||
}
|
||||
} )
|
||||
.catch( function ( err ) {
|
||||
console.error( 'bitwms filter error:', err );
|
||||
if ( loadMoreBtn ) {
|
||||
loadMoreBtn.disabled = false;
|
||||
loadMoreBtn.textContent = 'Загрузить ещё';
|
||||
}
|
||||
} )
|
||||
.finally( function () {
|
||||
isLoading = false;
|
||||
} );
|
||||
}
|
||||
} );
|
||||
} )();
|
||||
@@ -0,0 +1,38 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var modal = document.getElementById('gated-modal');
|
||||
if (!modal) return;
|
||||
|
||||
var overlay = modal.querySelector('.gated-modal__overlay');
|
||||
var closeBtn = modal.querySelector('.gated-modal__close');
|
||||
|
||||
// Open modal on [data-gated] click
|
||||
document.addEventListener('click', function (e) {
|
||||
var trigger = e.target.closest('[data-gated]');
|
||||
if (!trigger) return;
|
||||
e.preventDefault();
|
||||
var materialId = trigger.dataset.gated;
|
||||
var downloadUrl = trigger.dataset.downloadUrl;
|
||||
// Set hidden field + store download URL
|
||||
var hiddenField = modal.querySelector('input[name="material-id"]');
|
||||
if (hiddenField) hiddenField.value = materialId;
|
||||
modal.dataset.downloadUrl = downloadUrl || '';
|
||||
modal.classList.add('gated-modal--open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
});
|
||||
|
||||
function closeModal() {
|
||||
modal.classList.remove('gated-modal--open');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
if (closeBtn) closeBtn.addEventListener('click', closeModal);
|
||||
if (overlay) overlay.addEventListener('click', closeModal);
|
||||
|
||||
// After CF7 successful submit — trigger download
|
||||
document.addEventListener('wpcf7mailsent', function () {
|
||||
if (modal.classList.contains('gated-modal--open') && modal.dataset.downloadUrl) {
|
||||
window.open(modal.dataset.downloadUrl, '_blank');
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* БИТ.WMS Child Theme — js/sidebar-nav.js
|
||||
*
|
||||
* Sidebar navigation toggle behaviour.
|
||||
* Placeholder for Task 3 — full sidebar implementation will extend this file.
|
||||
*
|
||||
* Behaviour:
|
||||
* - Clicking the hamburger button toggles `.sidebar-nav--open` on the sidebar.
|
||||
* - Simultaneously toggles `.sidebar-overlay` on <body> to show the dim overlay.
|
||||
* - Clicking the overlay closes the sidebar.
|
||||
*/
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded', function () {
|
||||
'use strict';
|
||||
|
||||
// Guard: abort if there is no sidebar on this page.
|
||||
var sidebar = document.querySelector( '.sidebar-nav' );
|
||||
if ( ! sidebar ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hamburger = document.querySelector( '.sidebar-nav__toggle' );
|
||||
var body = document.body;
|
||||
|
||||
/**
|
||||
* Open the sidebar and show the overlay.
|
||||
*/
|
||||
function openSidebar() {
|
||||
sidebar.classList.add( 'sidebar-nav--open' );
|
||||
body.classList.add( 'sidebar-overlay' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the sidebar and hide the overlay.
|
||||
*/
|
||||
function closeSidebar() {
|
||||
sidebar.classList.remove( 'sidebar-nav--open' );
|
||||
body.classList.remove( 'sidebar-overlay' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle sidebar state.
|
||||
*/
|
||||
function toggleSidebar() {
|
||||
if ( sidebar.classList.contains( 'sidebar-nav--open' ) ) {
|
||||
closeSidebar();
|
||||
} else {
|
||||
openSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
// Attach toggle to hamburger button (if present).
|
||||
if ( hamburger ) {
|
||||
hamburger.addEventListener( 'click', function ( e ) {
|
||||
e.preventDefault();
|
||||
toggleSidebar();
|
||||
} );
|
||||
}
|
||||
|
||||
// Close sidebar when the overlay (body::after pseudo-element area) is clicked.
|
||||
// We detect clicks on <body> that land outside the sidebar itself.
|
||||
body.addEventListener( 'click', function ( e ) {
|
||||
if (
|
||||
body.classList.contains( 'sidebar-overlay' ) &&
|
||||
! sidebar.contains( e.target ) &&
|
||||
( ! hamburger || ! hamburger.contains( e.target ) )
|
||||
) {
|
||||
closeSidebar();
|
||||
}
|
||||
} );
|
||||
} );
|
||||