This commit is contained in:
2024-05-20 15:37:46 +03:00
commit 00b7dbd0b7
10404 changed files with 3285853 additions and 0 deletions

View File

@ -0,0 +1,240 @@
import './style.scss';
import classnames from 'classnames/dedupe';
import $ from 'jquery';
import { Button, Spinner } from '@wordpress/components';
import { Component, RawHTML } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
const { ajaxurl, VPGutenbergVariables } = window;
const cachedOptions = {};
/**
* Component Class
*/
export default class IconsSelector extends Component {
constructor(...args) {
super(...args);
const { callback } = this.props;
this.state = {
options: { ...this.props.options },
ajaxStatus: !!callback,
collapsed: true,
};
cachedOptions[this.props.controlName] = { ...this.props.options };
this.requestAjax = this.requestAjax.bind(this);
}
componentDidMount() {
const { callback } = this.props;
if (callback) {
this.requestAjax({}, (result) => {
if (result.options) {
this.setState({
options: result.options,
});
}
});
}
}
/**
* Request AJAX dynamic data.
*
* @param {Object} additionalData - additional data for AJAX call.
* @param {Function} callback - callback.
* @param {boolean} useStateLoading - use state change when loading.
*/
requestAjax(
additionalData = {},
callback = () => {},
useStateLoading = true
) {
const { controlName, attributes } = this.props;
if (this.isAJAXinProgress) {
return;
}
this.isAJAXinProgress = true;
if (useStateLoading) {
this.setState({
ajaxStatus: 'progress',
});
}
const ajaxData = {
action: 'vp_dynamic_control_callback',
nonce: VPGutenbergVariables.nonce,
vp_control_name: controlName,
vp_attributes: attributes,
...additionalData,
};
$.ajax({
url: ajaxurl,
method: 'POST',
dataType: 'json',
data: ajaxData,
complete: (data) => {
const json = data.responseJSON;
if (callback && json.response) {
if (json.response.options) {
cachedOptions[controlName] = {
...cachedOptions[controlName],
...json.response.options,
};
}
callback(json.response);
}
if (useStateLoading) {
this.setState({
ajaxStatus: true,
});
}
this.isAJAXinProgress = false;
},
});
}
render() {
const { controlName, value, onChange, collapseRows, isSetupWizard } =
this.props;
const { options, ajaxStatus, collapsed } = this.state;
const isLoading = ajaxStatus && ajaxStatus === 'progress';
if (isLoading) {
return (
<div className="vpf-component-icon-selector">
<Spinner />
</div>
);
}
const optionsArray = Object.keys(options);
const fromIndex = optionsArray.indexOf(value);
const itemsPerRow = isSetupWizard ? 5 : 3;
const allowedItems = collapseRows * itemsPerRow;
const allowCollapsing =
collapseRows !== false && optionsArray.length > allowedItems;
const visibleCollapsedItems = allowedItems - 1;
// Move the selected option to the end of collapsed list
// in case this item is not visible.
if (
allowCollapsing &&
collapsed &&
fromIndex >= visibleCollapsedItems
) {
const toIndex = visibleCollapsedItems - 1;
const element = optionsArray[fromIndex];
optionsArray.splice(fromIndex, 1);
optionsArray.splice(toIndex, 0, element);
}
return (
<div
className={classnames(
'vpf-component-icon-selector',
allowCollapsing
? 'vpf-component-icon-selector-allow-collapsing'
: ''
)}
data-control-name={controlName}
>
{optionsArray
.filter((elm, i) => {
if (allowCollapsing) {
return collapsed ? i < visibleCollapsedItems : true;
}
return true;
})
.map((k) => {
const option = options[k];
let { icon } = option;
if (isSetupWizard) {
if (option.image_preview_wizard) {
icon = `<img src="${option.image_preview_wizard}" alt="${option.title} Preview">`;
} else if (option.icon_wizard) {
icon = option.icon_wizard;
}
}
return (
<Button
key={`icon-selector-${option.title}-${option.value}`}
onClick={() => onChange(option.value)}
className={classnames(
'vpf-component-icon-selector-item',
value === option.value
? 'vpf-component-icon-selector-item-active'
: '',
option.className
)}
>
{icon ? <RawHTML>{icon}</RawHTML> : ''}
{option.title ? (
<span>{option.title}</span>
) : (
''
)}
</Button>
);
})}
{allowCollapsing ? (
<Button
onClick={() => {
this.setState({
collapsed: !collapsed,
});
}}
className={classnames(
'vpf-component-icon-selector-item',
'vpf-component-icon-selector-item-collapse',
collapsed
? ''
: 'vpf-component-icon-selector-item-expanded'
)}
>
<div className="vpf-component-icon-selector-item-collapse">
<svg
width="11"
height="6"
viewBox="0 0 11 6"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 1.25L5.5 4.75L1 1.25"
stroke="currentColor"
strokeWidth="1"
/>
</svg>
</div>
<span>
{collapsed
? __('More', 'visual-portfolio')
: __('Less', 'visual-portfolio')}
</span>
</Button>
) : null}
</div>
);
}
}

View File

@ -0,0 +1,45 @@
%vpf-icons-selector-item {
position: relative;
height: auto;
padding: 15px;
margin: 0;
color: #000;
border-radius: 2px;
transition: 0.1s color ease-in-out;
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
content: "";
background: var(--wp-admin-theme-color);
border-radius: 2px;
opacity: 0;
transition: 0.1s opacity ease-in-out;
}
&:hover,
&:focus {
color: var(--wp-admin-theme-color);
&::after {
opacity: 0.04;
}
}
// Remove default Gutenberg box shadow.
&:focus:not(:focus-visible) {
box-shadow: none;
}
}
%vpf-icons-selector-item-active {
color: var(--wp-admin-theme-color);
outline: 1px solid var(--wp-admin-theme-color);
&::after {
opacity: 0.04;
}
}

View File

@ -0,0 +1,99 @@
@import "./selector-placeholder.scss";
.vpf-control-wrap-icons_selector:has(+ .vpf-control-wrap-category_tabs),
.vpf-control-wrap-icons_selector:has(+ .vpf-control-wrap-category_collapse) {
margin-bottom: 0;
}
.vpf-control-wrap-icons_selector:has(+ .vpf-control-wrap-category_navigator) {
margin-bottom: 16px;
}
.vpf-component-icon-selector {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 5px;
width: 100%;
.vpf-component-icon-selector-item {
@extend %vpf-icons-selector-item;
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
cursor: pointer;
transition: 0.2s border, 0.2s background-color, 0.2s box-shadow;
svg {
width: 100%;
max-width: 18px;
height: auto;
color: inherit;
fill: none;
}
&.vpf-component-icon-selector-item-active {
@extend %vpf-icons-selector-item-active;
}
span {
margin-right: -8px;
margin-left: -8px;
font-size: 12px;
word-break: break-word;
}
div + span {
padding-top: 8px;
}
}
.vpf-component-icon-selector-item-collapse {
svg {
width: 14px;
height: 14px;
color: var(--wp-admin-theme-color);
}
.vpf-component-icon-selector-item-collapse {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 23px;
height: 23px;
&::after {
position: absolute;
top: -3px;
right: -3px;
bottom: -3px;
left: -3px;
display: block;
content: "";
background-color: var(--wp-admin-theme-color);
border-radius: 15px;
opacity: 0.05;
transition: 0.1s opacity ease-in-out;
}
}
&:hover,
&:focus {
&::after {
opacity: 0;
}
.vpf-component-icon-selector-item-collapse::after {
opacity: 0.1;
}
}
&.vpf-component-icon-selector-item-expanded {
svg {
transform: rotate(180deg);
}
}
}
}