diff --git a/.github/ISSUE_TEMPLATE/Automated_test.md b/.github/ISSUE_TEMPLATE/Automated_test.md index 4dd921cad5..9ff5bd4758 100644 --- a/.github/ISSUE_TEMPLATE/Automated_test.md +++ b/.github/ISSUE_TEMPLATE/Automated_test.md @@ -1,6 +1,6 @@ --- name: Automated test -about: Suggest a test for a feature or functionality +about: Suggest an automated test for a feature or functionality --- diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index 49ec42918f..78c429093e 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -7,13 +7,18 @@ about: Suggest a feature that we can implement. ### Description: +### Alternatives: + + +--------------- + +_The fields below will be filled by the QA team after the triage phase. Please do not fill or remove them._ ### User story: - -### Alternatives: - +### Checklist Scenarios + -### Gherkin Scenarios - \ No newline at end of file +### Testing instructions + \ No newline at end of file diff --git a/.github/workflows/build-dev-artifacts.yml b/.github/workflows/build-dev-artifacts.yml index b6ec4279d4..9d94e344b4 100644 --- a/.github/workflows/build-dev-artifacts.yml +++ b/.github/workflows/build-dev-artifacts.yml @@ -2,7 +2,7 @@ name: Build and test on: pull_request: - types: [opened, synchronize, ready_for_review] + types: [ opened, synchronize, ready_for_review ] branches-ignore: - "update_dependencies" jobs: @@ -44,9 +44,6 @@ jobs: run: composer install --no-dev --prefer-dist --no-progress --no-suggest - name: Install yarn deps run: yarn install --frozen-lockfile - - name: Install Cypress yarn - working-directory: ./e2e-tests - run: yarn install --frozen-lockfile - name: Build files run: yarn run build - name: Create zip @@ -67,6 +64,16 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} SOURCE_DIR: artifact/ DEST_DIR: ${{ github.event.pull_request.base.repo.name }}-${{ steps.retrieve-branch-name.outputs.branch_name }}-${{ steps.retrieve-git-sha-8.outputs.sha8 }}/ + - name: Upload Branch to S3 + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read --follow-symlinks --delete + env: + AWS_S3_BUCKET: ${{ secrets.AWS_DEV_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SOURCE_DIR: artifact/ + DEST_DIR: ${{ github.event.pull_request.base.repo.name }}-${{ steps.retrieve-branch-name.outputs.branch_name }}/ comment-on-pr: name: Comment on PR with links to plugin ZIPs @@ -140,16 +147,10 @@ jobs: - machines: 1 specs: "editor/classic" envs: "classic-editor" - - machines: 2 - specs: "editor/classic" - envs: "classic-editor" ## 2 machines for modern editor (Gutenberg) - machines: 1 specs: "editor/modern" envs: "default" - - machines: 2 - specs: "editor/modern" - envs: "default" ## 6 machines for customizer tests - machines: 1 specs: "customizer" @@ -178,16 +179,6 @@ jobs: ZIP_URL: "https://verti-artifacts.s3.amazonaws.com/${{ github.event.pull_request.base.repo.name }}-${{ needs.dev-zip.outputs.branch-name }}-${{ needs.dev-zip.outputs.git-sha-8 }}/neve.zip" steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 - id: yarn-and-build-cache - with: - path: | - ~/.cache/Cypress - node_modules - ./e2e-tests/node_modules - key: ${{ runner.os }}-node_modules-build-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-node_modules-build- - name: Install ${{ matrix.envs }} env for ${{ matrix.specs }} specs run: bash ./bin/envs/init.sh ${{ matrix.envs }} latest no "$ZIP_URL" - name: Run ${{ matrix.specs }} Cypress tests @@ -201,7 +192,6 @@ jobs: working-directory: ./e2e-tests env: host=localhost,port=8080 browser: chrome - install: ${{ ! steps.yarn-and-build-cache.outputs.cache-hit }} headless: true parallel: true group: e2e-${{ matrix.specs }} diff --git a/.github/workflows/e2e-storybook.yml b/.github/workflows/e2e-storybook.yml index 82d7dc488b..096ce4c540 100644 --- a/.github/workflows/e2e-storybook.yml +++ b/.github/workflows/e2e-storybook.yml @@ -26,7 +26,7 @@ jobs: ${{ runner.os }}-yarn- - name: Build Cypress working-directory: ./e2e-tests - run: yarn install + run: yarn install --frozen-lockfile - name: Install and Build 🔧 run: | yarn install --frozen-lockfile @@ -35,4 +35,4 @@ jobs: - name: E2E Tests 🚀 working-directory: ./e2e-tests run: | - yarn run cypress:storybook:run --key=${{ secrets.CYPRESS_RECORD_KEY }} + yarn run cypress:storybook:run --record --key=${{ secrets.CYPRESS_RECORD_KEY }} diff --git a/.github/workflows/neve-sync-30.yml b/.github/workflows/neve-sync-branches.yml similarity index 61% rename from .github/workflows/neve-sync-30.yml rename to .github/workflows/neve-sync-branches.yml index c5304e620e..404f432240 100644 --- a/.github/workflows/neve-sync-30.yml +++ b/.github/workflows/neve-sync-branches.yml @@ -1,17 +1,17 @@ -name: Sync 30 branch +name: Sync branches on: push: branches: - - 'development' + - 'master' jobs: sync-branch: runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Merge development -> new/3-0 + - name: Merge master -> development uses: Codeinwp/merge-branch@master with: type: now - from_branch: development - target_branch: new/3-0 + from_branch: master + target_branch: development github_token: ${{ secrets.BOT_TOKEN }} diff --git a/.github/workflows/sync-qa.yml b/.github/workflows/sync-qa.yml index 232f167f65..f3a8ea6e12 100644 --- a/.github/workflows/sync-qa.yml +++ b/.github/workflows/sync-qa.yml @@ -15,7 +15,6 @@ jobs: SSH_PORT: ${{ secrets.SSH_PORT }} SSH_HOST: ${{ secrets.SSH_HOST }} QA_ROOT: ${{ secrets.QA_ROOT }} - STG_DEMOSITES_ROOT: ${{ secrets.STG_DEMOSITES_ROOT }} PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true CYPRESS_INSTALL_BINARY: 0 steps: @@ -53,11 +52,6 @@ jobs: rsync -rc --delete --exclude-from="$GITHUB_WORKSPACE/.distignore" -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" "$GITHUB_WORKSPACE/dist/neve/" $SSH_USERNAME@$SSH_HOST:$QA_ROOT - - name: Deploy to staging of demosites.io env - run: > - rsync -rc --delete --exclude-from="$GITHUB_WORKSPACE/.distignore" -e "ssh -i - $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" - "$GITHUB_WORKSPACE/dist/neve/" "${SSH_USERNAME}@${SSH_HOST}:${STG_DEMOSITES_ROOT}themes/neve/" - name: Rebuild Neve Reference run: > ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no @@ -70,10 +64,11 @@ jobs: target_url: http://qa-neve.themeisle.com/empty-site state: success deployment_id: ${{ steps.deployment.outputs.deployment_id }} - empty-job: - runs-on: ubuntu-latest - if: success() - steps: - - name: Meep - run: | - echo "Nothing to do. This is a fork." + - name: Run staging demosites deploy + uses: pagely/action-deploy@v1 + with: + PAGELY_DEPLOY_DEST: "/httpdocs/wp-content/themes/neve/" + PAGELY_INTEGRATION_SECRET: ${{secrets.PAGELY_INTEGRATION_SECRET}} + PAGELY_INTEGRATION_ID: ${{secrets.PAGELY_INTEGRATION_ID}} + PAGELY_APP_ID: ${{secrets.STG_DEMOSITES_PAGELY_APP_ID}} + PAGELY_WORKING_DIR: "${{github.workspace}}/dist/neve" diff --git a/.github/workflows/test-npm.yml b/.github/workflows/test-npm.yml index a7598e4cf9..29dc39a4f5 100644 --- a/.github/workflows/test-npm.yml +++ b/.github/workflows/test-npm.yml @@ -55,5 +55,3 @@ jobs: env: CI_JOB_NUMBER: 1 run: yarn run size - - name: Check translations - run: git diff --exit-code languages/neve.pot diff --git a/.gitignore b/.gitignore index 52ddda0739..3892625841 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ assets/css/* style-main* dashboard/build/* inc/customizer/controls/react/bundle/* +inc/admin/metabox/build +languages/neve.pot +/e2e-tests/cypress/screenshots/ diff --git a/.storybook/dummy-data.js b/.storybook/dummy-data.js new file mode 100644 index 0000000000..28fbc4229f --- /dev/null +++ b/.storybook/dummy-data.js @@ -0,0 +1,498 @@ +export const BuildersData = { + "header": { + "id": "hfg_header_layout", + "control_id": "hfg_header_layout", + "panel": "hfg_header", + "section": "hfg_header_layout_section", + "title": "Header", + "devices": { + "desktop": "Desktop", + "mobile": "Mobile" + }, + "items": { + "yoast_breadcrumbs": { + "name": "Breadcrumbs", + "description": null, + "id": "yoast_breadcrumbs", + "width": 4, + "section": "yoast_breadcrumbs", + "icon": "editor-ul", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "button_base_3": { + "name": "Button", + "description": null, + "id": "button_base_3", + "width": 2, + "section": "header_button_3", + "icon": "admin-links", + "previewImage": null, + "componentSlug": "hfg-button" + }, + "button_base": { + "name": "Button", + "description": null, + "id": "button_base", + "width": 2, + "section": "header_button", + "icon": "admin-links", + "previewImage": null, + "componentSlug": "hfg-button" + }, + "button_base_2": { + "name": "Button", + "description": null, + "id": "button_base_2", + "width": 2, + "section": "header_button_2", + "icon": "admin-links", + "previewImage": null, + "componentSlug": "hfg-button" + }, + "contact": { + "name": "Contact", + "description": null, + "id": "contact", + "width": 6, + "section": "contact", + "icon": "email", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "custom_layout_4": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_4", + "width": 3, + "section": "custom_layout_4", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_layout_3": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_3", + "width": 3, + "section": "custom_layout_3", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_layout_2": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_2", + "width": 3, + "section": "custom_layout_2", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_html_2": { + "name": "HTML", + "description": null, + "id": "custom_html_2", + "width": 3, + "section": "custom_html_2", + "icon": "welcome-write-blog", + "previewImage": null, + "componentSlug": "hfg-html" + }, + "custom_html_3": { + "name": "HTML", + "description": null, + "id": "custom_html_3", + "width": 3, + "section": "custom_html_3", + "icon": "welcome-write-blog", + "previewImage": null, + "componentSlug": "hfg-html" + }, + "custom_html": { + "name": "HTML", + "description": null, + "id": "custom_html", + "width": 3, + "section": "custom_html", + "icon": "welcome-write-blog", + "previewImage": null, + "componentSlug": "hfg-html" + }, + "logo_2": { + "name": "Logo & Site Identity", + "description": "Display your company logo here or simply use words to describe your business.", + "id": "logo_2", + "width": 3, + "section": "title_tagline_2", + "icon": "admin-appearance", + "previewImage": "http://localhost:8080/wp-content/themes/neve/header-footer-grid/assets/images/customizer/component-site-logo.jpg", + "componentSlug": "hfg-logo" + }, + "logo": { + "name": "Logo & Site Identity", + "description": "Display your company logo here or simply use words to describe your business.", + "id": "logo", + "width": 3, + "section": "title_tagline", + "icon": "admin-appearance", + "previewImage": "http://localhost:8080/wp-content/themes/neve/header-footer-grid/assets/images/customizer/component-site-logo.jpg", + "componentSlug": "hfg-logo" + }, + "nav-icon": { + "name": "Menu Icon", + "description": null, + "id": "nav-icon", + "width": 1, + "section": "header_menu_icon", + "icon": "menu", + "previewImage": null, + "componentSlug": "nav-icon" + }, + "nav-icon_2": { + "name": "Menu Icon", + "description": null, + "id": "nav-icon_2", + "width": 1, + "section": "header_menu_icon_2", + "icon": "menu", + "previewImage": null, + "componentSlug": "nav-icon" + }, + "primary-menu_2": { + "name": "Primary Menu", + "description": null, + "id": "primary-menu_2", + "width": 6, + "section": "header_menu_primary_2", + "icon": "tagcloud", + "previewImage": null, + "componentSlug": "hfg-primary-menu" + }, + "primary-menu": { + "name": "Primary Menu", + "description": null, + "id": "primary-menu", + "width": 6, + "section": "header_menu_primary", + "icon": "tagcloud", + "previewImage": null, + "componentSlug": "hfg-primary-menu" + }, + "header_search_2": { + "name": "Search Form", + "description": null, + "id": "header_search_2", + "width": 2, + "section": "header_search_2", + "icon": "code-standards", + "previewImage": null, + "componentSlug": "hfg-search-form" + }, + "header_search": { + "name": "Search Form", + "description": null, + "id": "header_search", + "width": 2, + "section": "header_search", + "icon": "code-standards", + "previewImage": null, + "componentSlug": "hfg-search-form" + }, + "header_search_responsive": { + "name": "Search Icon", + "description": null, + "id": "header_search_responsive", + "width": 1, + "section": "header_search_responsive", + "icon": "search", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "secondary-menu": { + "name": "Secondary Menu", + "description": null, + "id": "secondary-menu", + "width": 6, + "section": "secondary_menu_primary", + "icon": "tagcloud", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "social_icons": { + "name": "Social Icons", + "description": null, + "id": "social_icons", + "width": 4, + "section": "social_icons", + "icon": "share", + "previewImage": null, + "componentSlug": "hfg-generic-component" + } + }, + "rows": { + "top": { + "title": "Header Top", + "description": "Design your Header by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + }, + "main": { + "title": "Header Main", + "description": "Design your Header by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + }, + "bottom": { + "title": "Header Bottom", + "description": "Design your Header by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + }, + "sidebar": { + "title": "Mobile menu content", + "description": "Design your Header by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + } + } + }, + "footer": { + "id": "hfg_footer_layout", + "control_id": "hfg_footer_layout", + "panel": "hfg_footer", + "section": "hfg_footer_layout_section", + "title": "Footer", + "devices": { + "desktop": "Footer" + }, + "items": { + "footer_copyright": { + "name": "Copyright", + "description": null, + "id": "footer_copyright", + "width": 2, + "section": "footer_copyright", + "icon": "nametag", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "custom_layout_5": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_5", + "width": 3, + "section": "custom_layout_5", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_layout_6": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_6", + "width": 3, + "section": "custom_layout_6", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_layout_7": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_7", + "width": 3, + "section": "custom_layout_7", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "footer-four-widgets": { + "name": "Footer Four", + "description": null, + "id": "footer-four-widgets", + "width": 3, + "section": "sidebar-widgets-footer-four-widgets", + "icon": "welcome-widgets-menus", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "footer-menu": { + "name": "Footer Menu", + "description": null, + "id": "footer-menu", + "width": 6, + "section": "footer_menu_primary", + "icon": "tagcloud", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "footer-one-widgets": { + "name": "Footer One", + "description": null, + "id": "footer-one-widgets", + "width": 3, + "section": "sidebar-widgets-footer-one-widgets", + "icon": "welcome-widgets-menus", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "footer-three-widgets": { + "name": "Footer Three", + "description": null, + "id": "footer-three-widgets", + "width": 3, + "section": "sidebar-widgets-footer-three-widgets", + "icon": "welcome-widgets-menus", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "footer-two-widgets": { + "name": "Footer Two", + "description": null, + "id": "footer-two-widgets", + "width": 3, + "section": "sidebar-widgets-footer-two-widgets", + "icon": "welcome-widgets-menus", + "previewImage": null, + "componentSlug": "hfg-generic-component" + }, + "social_icons_2": { + "name": "Social Icons", + "description": null, + "id": "social_icons_2", + "width": 4, + "section": "social_icons_2", + "icon": "share", + "previewImage": null, + "componentSlug": "hfg-generic-component" + } + }, + "rows": { + "top": { + "title": "Footer Top", + "description": "Design your Footer by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + }, + "bottom": { + "title": "Footer Bottom", + "description": "Design your Footer by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + } + } + }, + "page_header": { + "id": "hfg_page_header_layout", + "control_id": "hfg_page_header_layout", + "panel": "hfg_page_header", + "section": "hfg_page_header_layout_section", + "title": "Page Header", + "devices": { + "desktop": "Desktop", + "mobile": "Mobile" + }, + "items": { + "button_base_4": { + "name": "Button", + "description": null, + "id": "button_base_4", + "width": 2, + "section": "header_button_4", + "icon": "admin-links", + "previewImage": null, + "componentSlug": "hfg-button" + }, + "button_base_5": { + "name": "Button", + "description": null, + "id": "button_base_5", + "width": 2, + "section": "header_button_5", + "icon": "admin-links", + "previewImage": null, + "componentSlug": "hfg-button" + }, + "button_base_6": { + "name": "Button", + "description": null, + "id": "button_base_6", + "width": 2, + "section": "header_button_6", + "icon": "admin-links", + "previewImage": null, + "componentSlug": "hfg-button" + }, + "custom_layout_8": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_8", + "width": 3, + "section": "custom_layout_8", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_layout_9": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_9", + "width": 3, + "section": "custom_layout_9", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_layout_10": { + "name": "Custom Layout", + "description": null, + "id": "custom_layout_10", + "width": 3, + "section": "custom_layout_10", + "icon": "embed-generic", + "previewImage": null, + "componentSlug": "hfg-custom-layout" + }, + "custom_html_4": { + "name": "HTML", + "description": null, + "id": "custom_html_4", + "width": 3, + "section": "custom_html_4", + "icon": "welcome-write-blog", + "previewImage": null, + "componentSlug": "hfg-html" + }, + "custom_html_5": { + "name": "HTML", + "description": null, + "id": "custom_html_5", + "width": 3, + "section": "custom_html_5", + "icon": "welcome-write-blog", + "previewImage": null, + "componentSlug": "hfg-html" + }, + "custom_html_6": { + "name": "HTML", + "description": null, + "id": "custom_html_6", + "width": 3, + "section": "custom_html_6", + "icon": "welcome-write-blog", + "previewImage": null, + "componentSlug": "hfg-html" + }, + "secondary-menu_2": { + "name": "Page Header Menu", + "description": null, + "id": "secondary-menu_2", + "width": 6, + "section": "secondary_menu_primary_2", + "icon": "tagcloud", + "previewImage": null, + "componentSlug": "hfg-generic-component" + } + }, + "rows": { + "top": { + "title": "Page Header Top", + "description": "Design your Page Header by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + }, + "bottom": { + "title": "Page Header Bottom", + "description": "Design your Page Header by dragging, dropping and resizing all the elements in real-time.
Read full documentation." + } + } + } +}; diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index c631ca57d2..45019a7ce6 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -12,3 +12,5 @@ } + +
diff --git a/.storybook/preview.js b/.storybook/preview.js index d07d1b3d68..60de57ba25 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,15 +1,22 @@ import './style.css' -import 'cypress-storybook/react'; +try { + require ('../e2e-tests/node_modules/cypress-storybook/react'); +} catch (ex) { + console.log(ex); +} import '@wordpress/components/build-style/style.css' import '@icon/dashicons/dashicons.css' import {FONTS} from '../stories/utils/values' +import {BuildersData} from "./dummy-data"; -export const parameters = { - actions: {argTypesRegex: "^on[A-Z].*"}, -} +window.NeveReactCustomize = {} +window.NeveReactCustomize.HFG = BuildersData -window.wp = { +const wpObject = { customize: { + bind: (event, callback) => { + callback(); + }, previewedDevice: (device) => { const wrap = document.querySelector('.mock-customize'); @@ -19,13 +26,61 @@ window.wp = { wrap.classList.remove('preview-desktop', 'preview-mobile', 'preview-tablet') wrap.classList.add(`preview-${device}`); }, - previewer : { - refresh : () => { - console.log('REFRESH'); + section: (slug) => ({ + focus: () => console.log(`Focusing Section ${slug}.`), + expanded: (value) => console.log(`Set Expanded for ${slug} to ${value}.`), + params: { + title: `Title: ${slug}`, + } + }), + state: (slug) => ({ + get: () => { + return 'title_tagline' + }, + bind: () => { + } + }), + previewer: { + bind: (e) => { + console.log('Event Bound:', e); + }, + send: (e) => { + console.log(e) + }, + refresh: () => { + console.log('REFRESH PREVIEW'); + } + }, + control: (slug, callback) => { + if (callback) { + callback(window.wp.customize.control(slug)) + } + + if (slug.indexOf('_columns_layout') > -1) { + return { + setting: { + value: 'left-third', + get: () => window.wp.customize.control(slug).setting.value, + set: (value) => {}, + bind: (value) => window.wp.customize.control(slug).setting.value + } + } + } + if (slug.indexOf('_columns_number') > -1) { + return { + setting: { + value: 2, + get: () => window.wp.customize.control(slug).setting.value, + set: (value) => {}, + bind: (value) => window.wp.customize.control(slug).setting.value + } + } } } } -} +}; + +window.wp = wpObject; const head = document.querySelector('#nv-google-fonts'); const families = FONTS.Google.join('|'); diff --git a/assets/js/src/customizer-preview/app.js b/assets/js/src/customizer-preview/app.js index 4f579feee2..f516687d5d 100644 --- a/assets/js/src/customizer-preview/app.js +++ b/assets/js/src/customizer-preview/app.js @@ -1,6 +1,7 @@ /* global neveCustomizePreview, _,jQuery */ import { initNavigation, repositionDropdowns } from '../frontend/navigation'; import { removeClass, addClass } from '../utils.js'; +import { CSSVariablesHandler, addCSS, addTemplateCSS } from './css-var-handler'; function handleResponsiveRadioButtons(args, nextValue) { if (!args.additional) return false; @@ -20,84 +21,6 @@ function handleResponsiveRadioButtons(args, nextValue) { }); } -function addCss(id, content = '') { - let style = document.querySelector('#' + id + '-css-style'); - if (!style) { - style = document.createElement('style'); - style.setAttribute('id', id + '-css-style'); - style.setAttribute('type', 'text/css'); - document.querySelector('head').appendChild(style); - } - style.innerHTML = content; -} - -function addStyle(settingType, id, newValue, args) { - const map = { - mobile: 'max-width: 576px', - tablet: 'min-width: 576px', - desktop: 'min-width: 960px', - }; - - let style = ''; - if (args.directional) { - if (args.responsive) { - for (const device in map) { - let deviceStyle = args.template; - const suffix = newValue[device + '-unit']; - _.each(newValue[device], function (value, direction) { - const directionRegex = new RegExp( - `{{value.${direction}}}`, - 'g' - ); - deviceStyle = deviceStyle.replace( - directionRegex, - value + suffix - ); - }); - style += `@media (${map[device]}) {${deviceStyle}}`; - } - } else { - const directions = ['top', 'right', 'bottom', 'left']; - style = args.template; - _.each(directions, function (dir) { - const directionRegex = new RegExp(`{{value.${dir}}}`, 'g'); - style = style.replace( - directionRegex, - newValue[dir] + newValue.unit - ); - }); - } - addCss(id, style); - return false; - } - - const regex = new RegExp('{{value}}', 'g'); - if (args.responsive) { - const template = args.template; - const value = JSON.parse(newValue); - for (const device in map) { - const suffix = value[device + '-unit'] || ''; - if (value[device] === 0 || value[device] === '0') { - style += `@media (${map[device]}) {${template.replace( - regex, - '0' - )}${suffix}}`; - } else { - style += `@media (${map[device]}) {${template.replace( - regex, - value[device] || 'inherit' - )}${suffix}}`; - } - } - } else if (newValue === 0 || newValue === '0') { - style += args.template.replace(regex, '0'); - } else { - const value = newValue || args.fallback || 'inherit'; - style += args.template.replace(regex, value.toString()); - } - addCss(id, style); -} - /** * Run JS on load. */ @@ -109,6 +32,7 @@ window.addEventListener('load', function () { if (e.detail.partial_id === 'hfg_header_layout_partial') { window.HFG.init(); window.HFG.initSearch(); + repositionDropdowns(); return false; } if (e.detail.partial_id === 'primary-menu_partial') { @@ -144,17 +68,34 @@ window.addEventListener('load', function () { desktop: 'min-width: 961px', }; + const varsHandler = new CSSVariablesHandler(); + _.each(neveCustomizePreview, function (settings, settingType) { _.each(settings, function (args, settingId) { wp.customize(settingId, function (setting) { setting.bind(function (newValue) { - // Handles new template selective refresh. + if ( + neveCustomizePreview.newSkin && + args.additional && + args.additional.cssVar + ) { + varsHandler.run( + settingId, + settingType, + newValue, + args.additional.cssVar + ); + return false; + } if (args.additional && args.additional.template) { - addStyle( + // Handles new template selective refresh. + addTemplateCSS( settingType, settingId, newValue, - args.additional + args.additional, + args.responsive || false, + args.directional || false ); return false; } @@ -176,7 +117,7 @@ window.addEventListener('load', function () { ${i.prop}: ${newValue} !important; }`; }); - addCss(settingId, style); + addCSS(settingId, style); break; case 'neve_background_control': if (newValue.type === 'color') { @@ -196,7 +137,7 @@ window.addEventListener('load', function () { style += `${args.selector}:before{ content: none !important;}`; style += `body ${args.selector}, body ${args.selector} .primary-menu-ul .sub-menu {background-color: ${color}!important;}`; style += `${args.selector} .primary-menu-ul .sub-menu, ${args.selector} .primary-menu-ul .sub-menu li {border-color: ${color}!important;}`; - addCss(settingId, style); + addCSS(settingId, style); return false; } if ( @@ -232,7 +173,9 @@ window.addEventListener('load', function () { .querySelector('.header-menu-sidebar') .classList.contains('dropdown') ) { - style += 'position: absolute;'; + style += neveCustomizePreview.newBuilder + ? '' + : 'position: absolute;'; } style += 'top: 0; bottom: 0; width: 100%; content:"";'; @@ -256,14 +199,13 @@ window.addEventListener('load', function () { style += args.selector + '{ background-color: transparent !important; }'; - addCss(settingId, style); + addCSS(settingId, style); break; case '\\Neve\\Customizer\\Controls\\React\\Responsive_Radio_Buttons': handleResponsiveRadioButtons(args, newValue); break; case '\\Neve\\Customizer\\Controls\\React\\Radio_Buttons': if (!args.additional) return false; - const classes = 'hfg-item-v-top hfg-item-v-middle hfg-item-v-bottom'; const newClass = 'hfg-item-v-' + newValue; @@ -272,8 +214,11 @@ window.addEventListener('load', function () { args.selector ); _.each(itemInner, function (item) { - removeClass(item.parentNode, classes); - addClass(item.parentNode, newClass); + const node = neveCustomizePreview.newBuilder + ? item.parentNode.parentNode + : item.parentNode; + removeClass(node, classes); + addClass(node, newClass); }); break; case '\\Neve\\Customizer\\Controls\\Radio_Image': @@ -335,7 +280,7 @@ window.addEventListener('load', function () { args.additional.prop + ':unset;}}'; } - addCss(settingId, style); + addCSS(settingId, style); break; case '\\Neve\\Customizer\\Controls\\React\\Spacing': for (const device in deviceMap) { @@ -385,7 +330,7 @@ window.addEventListener('load', function () { } style += '}}'; } - addCss(settingId, style); + addCSS(settingId, style); break; case '\\Neve\\Customizer\\Controls\\React\\Typography': style += `html ${args.selector}{`; @@ -456,7 +401,7 @@ window.addEventListener('load', function () { } style += `}}`; } - addCss(settingId, style); + addCSS(settingId, style); break; case '\\Neve\\Customizer\\Controls\\React\\Button_Appearance': const bgColor = newValue.background || 'unset'; @@ -519,7 +464,7 @@ window.addEventListener('load', function () { background-color: ${txtColor}; color: ${txtColor}; }`; - addCss(settingId, style); + addCSS(settingId, style); break; case 'text': const textContainer = document.querySelector( @@ -551,14 +496,14 @@ window.addEventListener('load', function () { width: ${newValue}px; height: ${newValue}px; }`; - addCss(settingId, style); + addCSS(settingId, style); return false; } style += `html ${args.selector} { ${args.additional.type}: ${newValue}px; }`; - addCss(settingId, style); + addCSS(settingId, style); break; case '\\Neve\\Customizer\\Controls\\React\\Color': @@ -567,7 +512,7 @@ window.addEventListener('load', function () { style += `html ${args.selector} { ${args.additional.prop}: ${colorValue}; }`; - addCss(settingId, style); + addCSS(settingId, style); break; case '\\Neve\\Customizer\\Controls\\React\\Font_Family': break; @@ -597,10 +542,45 @@ window.addEventListener('load', function () { }); }); }); + wp.customize.preview.bind('font-selection', function (data) { - let selector = neveCustomizePreview[data.type][data.controlId].selector; + const controlData = neveCustomizePreview[data.type][data.controlId]; + + let selector = controlData.selector; + const source = data.source; const id = data.controlId + '_font_family'; + + if (source.toLowerCase() === 'google') { + const linkNode = document.querySelector('#' + id), + fontValue = data.value.replace(' ', '+'), + url = + '//fonts.googleapis.com/css?family=' + + fontValue + + '%3A100%2C200%2C300%2C400%2C500%2C600%2C700%2C800&display=swap"'; + if (linkNode !== null) { + linkNode.setAttribute('href', url); + } else { + const newNode = document.createElement('link'); + newNode.setAttribute('rel', 'stylesheet'); + newNode.setAttribute('id', id); + newNode.setAttribute('href', url); + newNode.setAttribute('type', 'text/css'); + newNode.setAttribute('media', 'all'); + document.querySelector('head').appendChild(newNode); + } + } + + const { additional = false } = controlData; + + if ( + additional !== false && + additional.cssVar !== undefined && + neveCustomizePreview.newSkin + ) { + return false; + } + const defaultFontface = data.inherit ? 'inherit' : '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'; @@ -613,36 +593,18 @@ window.addEventListener('load', function () { }) .join(','); if (data.value === false) { - addCss( + addCSS( data.controlId, selector + '{font-family: ' + defaultFontface + ';}' ); } else { - addCss( + addCSS( data.controlId, selector + '{font-family: ' + data.value + ' ;}' ); } - if (source.toLowerCase() === 'google') { - const linkNode = document.querySelector('#' + id), - fontValue = data.value.replace(' ', '+'), - url = - '//fonts.googleapis.com/css?family=' + - fontValue + - '%3A100%2C200%2C300%2C400%2C500%2C600%2C700%2C800&display=swap"'; - if (linkNode !== null) { - linkNode.setAttribute('href', url); - return false; - } - const newNode = document.createElement('link'); - newNode.setAttribute('rel', 'stylesheet'); - newNode.setAttribute('id', id); - newNode.setAttribute('href', url); - newNode.setAttribute('type', 'text/css'); - newNode.setAttribute('media', 'all'); - document.querySelector('head').appendChild(newNode); - } }); + wp.customize('background_image', function (value) { value.bind(function (newval) { if (!newval) { @@ -786,9 +748,9 @@ jQuery.neveRangesPreview.init(); }, neve_other_pages_content_width: { content: - 'body:not(.single):not(.archive):not(.blog):not(.search) .neve-main > .container .col', + 'body:not(.single):not(.archive):not(.blog):not(.search) .neve-main > .container .col, body.post-type-archive-course .neve-main > .container .col, body.post-type-archive-llms_membership .neve-main > .container .col', sidebar: - 'body:not(.single):not(.archive):not(.blog):not(.search) .nv-sidebar-wrap', + 'body:not(.single):not(.archive):not(.blog):not(.search) .nv-sidebar-wrap, body.post-type-archive-course .nv-sidebar-wrap, body.post-type-archive-llms_membership .nv-sidebar-wrap', }, }, contentWidthsPreview() { @@ -799,7 +761,7 @@ jQuery.neveRangesPreview.init(); ${args.content} { max-width: ${newval}% !important; } ${args.sidebar} { max-width: ${100 - newval}% !important; } }`; - addCss(id + '-css', style); + addCSS(id + '-css', style); }); }); }); diff --git a/assets/js/src/customizer-preview/css-var-handler.js b/assets/js/src/customizer-preview/css-var-handler.js new file mode 100644 index 0000000000..2d48e6fb3d --- /dev/null +++ b/assets/js/src/customizer-preview/css-var-handler.js @@ -0,0 +1,418 @@ +/* global _ */ + +const directions = ['top', 'right', 'bottom', 'left']; +const devices = ['mobile', 'tablet', 'desktop']; +const mediaQueries = { + mobile: false, + tablet: 'min-width: 576px', + desktop: 'min-width: 961px', +}; + +export class CSSVariablesHandler { + run(id, settingType, value, params) { + const { + selector, + vars, + responsive = false, + suffix = '', + fallback = 'inherit', + } = params; + + //Bail if no selectors or variables. + if (!selector || !vars) { + return false; + } + + this.id = id; + this.settingType = settingType; + this.value = value; + this.vars = vars; + this.selector = `html ${selector}`; + this.suffix = suffix; + this.responsive = responsive; + this.fallback = fallback; + + const css = this.getStyle(); + + addCSS(id, css); + } + + getStyle() { + const { vars, responsive } = this; + + if (vars === 'backgroundControl') { + return this.getBackgroundControlVars(); + } + + if (this.isDirectionalValue(this.value)) { + return this.getDirectionalNonResponsive(); + } + + //We have a simple (non-composed) responsive control. + if (responsive) { + return this.getResponsiveVarCSS( + this.selector, + vars, + this.value, + this.suffix, + this.fallback + ); + } + + if (Array.isArray(vars)) { + let style = ''; + vars.forEach((variable) => { + this.vars = variable; + style += this.getStringVarCSS(); + }); + + return style; + } + + switch (typeof vars) { + case 'string': + return this.getStringVarCSS(); + case 'object': + return this.getComposedVarCSS(); + default: + break; + } + } + + getBackgroundControlVars() { + const { value, selector } = this; + + const { + type, + imageUrl, + focusPoint, + colorValue, + overlayColorValue, + overlayOpacity, + useFeatured, + fixed, + } = value; + + const definitions = { + '--bgImage': 'unset', + '--overlayColor': 'unset', + '--bgOverlayOpacity': 'unset', + '--bgAttachment': 'unset', + '--bgPosition': 'unset', + }; + + if (type === 'color') { + definitions['--bgColor'] = colorValue; + } else { + const { currentFeaturedImage } = window.neveCustomizePreview; + + let finalUrl = imageUrl; + if (useFeatured) { + finalUrl = currentFeaturedImage + ? currentFeaturedImage + : imageUrl; + } + + const hasImage = finalUrl !== ''; + + const { x, y } = focusPoint; + + const focus = `${(x * 100).toFixed(0)}% ${(y * 100).toFixed(0)}%`; + + definitions['--bgImage'] = hasImage ? `url("${finalUrl}")` : 'none'; + definitions['--overlayColor'] = overlayColorValue || 'transparent'; + definitions['--bgOverlayOpacity'] = `${overlayOpacity / 100}`; + definitions['--bgAttachment'] = fixed ? 'fixed' : 'unset'; + definitions['--bgPosition'] = focus; + } + + const properties = Object.entries(definitions) + .map(([prop, val]) => `${prop}:${val}`) + .join(';'); + + return `${selector}{${properties}}`; + } + + getDirectionalNonResponsive() { + const { selector, value, vars, suffix } = this; + const parsedValue = this.maybeParseJson(value); + + let finalSuffix = suffix || ''; + + if (parsedValue.unit !== undefined) { + finalSuffix = parsedValue.unit; + } + + const finalValue = this.parseDirectionalValue(parsedValue, finalSuffix); + + return `${selector}{${vars}:${finalValue};}`; + } + + getResponsiveVarCSS(selector, variable, value, suffix, fallback) { + const parsedValue = this.maybeParseJson(value); + + if (parsedValue === undefined) { + return ''; + } + + let style = ''; + devices.forEach((device) => { + let useFallback = false; + let finalSuffix = suffix; + + if (parsedValue[`${device}-unit`] !== undefined) { + finalSuffix = parsedValue[`${device}-unit`]; + } + + if (parsedValue.suffix && parsedValue.suffix[device]) { + finalSuffix = parsedValue.suffix[device]; + } + + if (!parsedValue[device]) { + useFallback = true; + } + + let singularValue = parsedValue[device]; + singularValue = useFallback + ? fallback + : this.parseDirectionalValue(singularValue, finalSuffix); + + if (mediaQueries[device]) { + style += `@media(${mediaQueries[device]}) {`; + } + style += `${selector}{`; + style += `${variable}:${singularValue};`; + style += '}'; + if (mediaQueries[device]) { + style += '}'; + } + }); + + return style; + } + + getStringVarCSS() { + const { + selector, + vars, + value, + suffix, + fallback, + validateSuffix, + } = this; + if (typeof selector) + if (!value) { + return `${selector} {${vars}:${fallback};}`; + } + return `${selector} {${vars}:${value}${validateSuffix(suffix)};}`; + } + + getComposedVarCSS() { + const { selector, vars, settingType, value, suffix, fallback } = this; + + const isButton = this.isButtonSetting(settingType); + + let style = ''; + + Object.keys(vars).forEach((cssVar) => { + let currentSuffix = suffix; + let settingKey = vars[cssVar]; + + // If we have a key with additional values, we make sure to take them into account. + if (typeof settingKey === 'object') { + if (settingKey.suffix) { + currentSuffix = settingKey.suffix; + } + + // If the setting inside is responsive, we add CSS for the responsive case and bail. + if (settingKey.responsive) { + style += this.getResponsiveVarCSS( + selector, + cssVar, + value[settingKey.key], + currentSuffix, + fallback + ); + return false; + } + + settingKey = settingKey.key; + } + + style += `${selector} {`; + + let newValue = value[settingKey] || null; + + //Account for the button [don't add border width if no need] + if (cssVar.toLowerCase().includes('borderwidth') && isButton) { + if (value.type !== 'outline') { + style += `${cssVar}: 0;`; + return; + } + } + + if (newValue) { + newValue = this.parseDirectionalValue(newValue, currentSuffix); + } else { + newValue = fallback; + } + style += `${cssVar}:${newValue};`; + style += '}'; + }); + + return style; + } + + isButtonSetting(settingId) { + return [ + '\\Neve\\Customizer\\Controls\\React\\Button_Appearance', + 'neve_button_appearance', + ].includes(settingId); + } + + parseDirectionalValue(value, suffix) { + if (typeof value !== 'object') { + return value + this.validateSuffix(suffix); + } + + if (!this.isDirectionalValue(value)) { + return value; + } + + let directionalValue = ''; + directions.forEach((direction) => { + if (value[direction] !== 0 && !value[direction]) { + directionalValue += this.fallback ? `${this.fallback} ` : '0 '; + } else { + directionalValue += `${value[direction]}${this.validateSuffix( + suffix + )} `; + } + }); + + directionalValue = directionalValue.trim(); + + return directionalValue; + } + + isDirectionalValue(value) { + return ( + typeof value.top !== 'undefined' && + typeof value.right !== 'undefined' && + typeof value.bottom !== 'undefined' && + typeof value.left !== 'undefined' + ); + } + + maybeParseJson(input) { + if (typeof input !== 'string') { + return input; + } + try { + JSON.parse(input); + } catch (error) { + return input; + } + return JSON.parse(input); + } + + validateSuffix(val) { + const valid = ['px', 'em', '%', 'vh', 'vw']; + if (!valid.includes(val)) { + return ''; + } + + return val; + } +} + +export const addCSS = (id, content = '') => { + let style = document.querySelector('#' + id + '-css-style'); + + if (!style) { + style = document.createElement('style'); + style.setAttribute('id', id + '-css-style'); + style.setAttribute('type', 'text/css'); + document.querySelector('head').appendChild(style); + } + style.innerHTML = content; +}; + +export const addTemplateCSS = (settingType, id, newValue, args) => { + const map = { + mobile: 'max-width: 576px', + tablet: 'min-width: 576px', + desktop: 'min-width: 960px', + }; + + let style = ''; + if (args.directional) { + if (args.responsive) { + for (const device in map) { + let deviceStyle = args.template; + const suffix = newValue[device + '-unit']; + _.each(newValue[device], function (value, direction) { + const directionRegex = new RegExp( + `{{value.${direction}}}`, + 'g' + ); + deviceStyle = deviceStyle.replace( + directionRegex, + value + suffix + ); + }); + style += `@media (${map[device]}) {${deviceStyle}}`; + } + } else { + style = args.template; + _.each(directions, function (dir) { + const directionRegex = new RegExp(`{{value.${dir}}}`, 'g'); + style = style.replace( + directionRegex, + newValue[dir] + newValue.unit + ); + }); + } + addCSS(id, style); + return false; + } + + const regex = new RegExp('{{value}}', 'g'); + if (args.responsive) { + const template = args.template; + const value = JSON.parse(newValue); + for (const device in map) { + let suffixDefault = ''; + if (args.suffix) { + suffixDefault = args.suffix[device]; + } + + let suffix = suffixDefault; + if (value[device + '-unit']) { + suffix = value[device + '-unit']; + } + + if (value.suffix && value.suffix[device]) { + suffix = value.suffix[device]; + } + + if (value[device] === 0 || value[device] === '0') { + style += `@media (${map[device]}) {${template.replace( + regex, + '0' + suffix + )}}`; + } else { + style += `@media (${map[device]}) {${template.replace( + regex, + value[device] + suffix || 'inherit' + )}}`; + } + } + } else if (newValue === 0 || newValue === '0') { + style += args.template.replace(regex, '0'); + } else { + const value = newValue || args.fallback || 'inherit'; + style += args.template.replace(regex, value.toString()); + } + addCSS(id, style); +}; diff --git a/assets/js/src/frontend/navigation.js b/assets/js/src/frontend/navigation.js index 70c7b66b97..16c7ebaab3 100644 --- a/assets/js/src/frontend/navigation.js +++ b/assets/js/src/frontend/navigation.js @@ -1,7 +1,6 @@ -/* global NeveProperties */ +/* global NeveProperties menuCalcEvent */ /* jshint esversion: 6 */ import { - isMobile, isIe, unhashUrl, toggleClass, @@ -11,6 +10,7 @@ import { } from '../utils.js'; let pageUrl; +const strings = ['dropdown-open', 'active', 'nav-clickaway-overlay']; /** * Initialize nav logic. @@ -36,7 +36,6 @@ export const initNavigation = () => { */ export const repositionDropdowns = () => { const { isRTL } = NeveProperties; - let left, right; const dropDowns = document.querySelectorAll( '.sub-menu, .minimal .nv-nav-search' ); @@ -49,19 +48,18 @@ export const repositionDropdowns = () => { rightDist = bounding.left; if (rightDist < 0) { - left = isRTL ? 'auto' : 0; - right = isRTL ? '-100%' : 'auto'; - dropDown.style.right = right; - dropDown.style.left = left; + dropDown.style.right = isRTL ? '-100%' : 'auto'; + dropDown.style.left = isRTL ? 'auto' : 0; } if (rightDist + bounding.width >= windowWidth) { - right = isRTL ? 0 : '100%'; - left = 'auto'; - dropDown.style.right = right; - dropDown.style.left = left; + dropDown.style.right = isRTL ? 0 : '100%'; + dropDown.style.left = 'auto'; } }); + if (typeof menuCalcEvent !== 'undefined') { + window.dispatchEvent(menuCalcEvent); + } }; /** @@ -94,11 +92,11 @@ function handleMobileDropdowns() { const subMenu = caret.parentNode.parentNode.querySelector( '.sub-menu' ); - toggleClass(caret, 'dropdown-open'); - toggleClass(subMenu, 'dropdown-open'); + toggleClass(caret, strings[0]); + toggleClass(subMenu, strings[0]); createNavOverlay( - document.querySelectorAll('.dropdown-open'), - 'dropdown-open' + document.querySelectorAll(`.${strings[0]}`), + strings[0] ); }); }); @@ -116,16 +114,14 @@ function handleSearch() { searchItem.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); - toggleClass(searchItem, 'active'); + toggleClass(searchItem, strings[1]); setTimeout(() => { searchItem.querySelector('.search-field').focus(); }, 50); - if (!isMobile()) { - createNavOverlay(searchItem, 'active'); - } + createNavOverlay(searchItem, strings[1]); }); }); - // Don't close thee search if interacted with. + // Don't close the search if interacted with. neveEach(navSearch, (item) => { item.addEventListener('click', (e) => { e.stopPropagation(); @@ -136,9 +132,9 @@ function handleSearch() { button.addEventListener('click', (e) => { e.preventDefault(); neveEach(navItem, (search) => { - removeClass(search, 'active'); + removeClass(search, strings[1]); }); - const overlay = document.querySelector('.nav-clickaway-overlay'); + const overlay = document.querySelector(`.${strings[2]}`); if (overlay === null) { return; } @@ -173,12 +169,12 @@ window.addEventListener('resize', handleMiniCartPosition); * @param {string} classToRemove */ function createNavOverlay(item, classToRemove) { - let navClickaway = document.querySelector('.nav-clickaway-overlay'); + let navClickaway = document.querySelector(`.${strings[2]}`); if (navClickaway !== null) { navClickaway.parentNode.removeChild(navClickaway); } navClickaway = document.createElement('div'); - addClass(navClickaway, 'nav-clickaway-overlay'); + addClass(navClickaway, strings[2]); const primaryNav = document.querySelector('header.header'); primaryNav.parentNode.insertBefore(navClickaway, primaryNav); @@ -201,10 +197,10 @@ function handleIeDropdowns() { const parentItem = dropdown.parentNode; parentItem.addEventListener('mouseenter', () => { - addClass(dropdown, 'dropdown-open'); + addClass(dropdown, strings[0]); }); parentItem.addEventListener('mouseleave', () => { - removeClass(dropdown, 'dropdown-open'); + removeClass(dropdown, strings[0]); }); }); } diff --git a/assets/js/src/shop/app.js b/assets/js/src/shop/app.js index b778fed9dc..4676bc1b95 100644 --- a/assets/js/src/shop/app.js +++ b/assets/js/src/shop/app.js @@ -25,7 +25,8 @@ function handleShopSidebar() { const html = document.querySelector('html'); const toggles = document.querySelectorAll('.nv-sidebar-toggle'); neveEach(toggles, (toggle) => { - toggle.addEventListener('click', function () { + toggle.addEventListener('click', function (e) { + e.preventDefault(); sidebar.classList.toggle('sidebar-open'); html.classList.toggle('menu-openend'); }); diff --git a/assets/scss/components/compat/_elementor.scss b/assets/scss/components/compat/_elementor.scss new file mode 100644 index 0000000000..1e564b534e --- /dev/null +++ b/assets/scss/components/compat/_elementor.scss @@ -0,0 +1,10 @@ +//List fixes +.neve-main .elementor-text-editor { + ul, ol { + padding-left: $spacing-sm; + } + + ul { + list-style: inherit; + } +} diff --git a/assets/scss/components/compat/woocommerce/_account.scss b/assets/scss/components/compat/woocommerce/_account.scss new file mode 100644 index 0000000000..2a2a14efa3 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_account.scss @@ -0,0 +1,106 @@ +@import "../../main/variables"; + + +body.woocommerce-account { + .nv-content-wrap > .woocommerce { + display: flex; + flex-direction: column; + } + + .woocommerce > h2 { + font-size: var(--h4FontSize); + margin-bottom: 0; + } + + .form-row { + margin: 0; + padding: 0; + } + + .woocommerce-form-login .form-row:nth-child(3) { + float: left; + display: flex; + flex-direction: row-reverse; + align-items: center; + } + + .woocommerce-form__label-for-checkbox { + --formLabelSpacing: 0; + } + + nav > ul { + list-style: none; + padding: 0; + margin-bottom: $spacing-xl; + + .is-active a { + color: var(--nv-text-color) + } + } + + .woocommerce-LostPassword { + margin: 0; + float: right; + } + + h2 { + --h2FontSize: var(--h3FontSize); + } + + table.my_account_orders { + font-size: var(--bodyFontSize); + } + + table { + border: 0 !important; + --primaryBtnFs: .9em; + --primaryBtnPadding: 8px 30px; + + td { + border: 0 !important; + } + + th, td { + padding: $spacing-md $spacing-sm !important; + + &:last-child { + text-align: right; + } + } + + thead th { + border-bottom: $base-border; + font-size: $text-lg + } + + &.order_details { + tfoot th, td { + border: 0; + } + } + } +} + +@mixin account--tablet() { + body.woocommerce-account { + nav > ul { + display: flex; + width: 100%; + flex-wrap: wrap; + + li { + margin: 0 $spacing-md 0 0; + } + } + + .woocommerce-MyAccount-navigation { + width: 100%; + } + + .woocommerce-MyAccount-content { + width: 100%; + float: none; + } + } +} + diff --git a/assets/scss/components/compat/woocommerce/_blocks.scss b/assets/scss/components/compat/woocommerce/_blocks.scss new file mode 100644 index 0000000000..eb5b79d427 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_blocks.scss @@ -0,0 +1,19 @@ +@import "../../main/variables"; + +.wc-block-grid__product-add-to-cart { + display: inline-flex; +} + +.wc-block-components-product-button .wp-block-button__link.add_to_cart_button, +.wc-block-grid__product-add-to-cart.wp-block-button .wp-block-button__link { + @extend %nv-button; + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } +} + +input.wc-block-product-search__field { + --formFieldSpacing: 0; +} diff --git a/assets/scss/components/compat/woocommerce/_breadcrumbs.scss b/assets/scss/components/compat/woocommerce/_breadcrumbs.scss new file mode 100644 index 0000000000..5126088741 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_breadcrumbs.scss @@ -0,0 +1,28 @@ +@import "../../main/variables"; + +.woocommerce .woocommerce-breadcrumb { + color: var(--nv-text-color); + font-size: 14px; + + a { + color: var(--nv-secondary-accent); + } + + .nv-breadcrumb-delimiter { + padding: 0 $spacing-xxs; + } +} + +.woocommerce { + .woocommerce-result-count { + float: none; + margin: 0; + } +} + +.nv-bc-count-wrap { + margin-bottom: $spacing-md; + display: flex; + font-size: 14px; + justify-content: space-between; +} diff --git a/assets/scss/components/compat/woocommerce/_buttons.scss b/assets/scss/components/compat/woocommerce/_buttons.scss new file mode 100644 index 0000000000..af0a675547 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_buttons.scss @@ -0,0 +1,104 @@ +.ajax_add_to_cart, .single_add_to_cart_button { + &.added { + display: none !important; + } +} + +.woocommerce { + a.added_to_cart { + display: flex; + align-items: center; + justify-content: center; + width: auto; + padding: var(--secondaryBtnPadding) + } + + li a.added_to_cart { + display: inline-block; + margin-top: 1em; + } +} + +.button.button-secondary.more-details, +.woocommerce .price_slider_amount button.button, +a.added_to_cart, +.checkout_coupon button.button, +.woocommerce-mini-cart__buttons.buttons a.button.wc-forward:not(.checkout) { + @extend %nv-button-secondary; + + &:hover { + @extend %nv-button-secondary-hover; + } +} + + +.woocommerce ul.products li.product .button { + white-space: normal; +} + + +// +.woocommerce { + .button.loading { + justify-content: center; + display: inline-flex !important; + padding-right: 15px !important; + + &:after { + margin-left: 5px; + position: unset !important; + } + } +} + +// +#review_form #respond input#submit, +.woocommerce #respond input#submit.disabled, +.woocommerce #respond input#submit:disabled, +.woocommerce #respond input#submit:disabled[disabled], +.woocommerce a.button, +.woocommerce a.button.disabled, +.woocommerce a.button:disabled, +.woocommerce a.button:disabled[disabled], +.woocommerce button.button, +.woocommerce button.button.disabled, +.woocommerce button.button:disabled, +.woocommerce button.button:disabled[disabled], +.woocommerce input.button.disabled, +.woocommerce input.button:disabled, +.woocommerce input.button:disabled[disabled], +#add_payment_method .wc-proceed-to-checkout a.checkout-button, +.woocommerce-cart .wc-proceed-to-checkout a.checkout-button, +.woocommerce-checkout .wc-proceed-to-checkout a.checkout-button, +.woocommerce #respond input#submit.alt, +.woocommerce a.button.alt, +.woocommerce button.button.alt, +.woocommerce input.button.alt, +.woocommerce a.button { + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } +} + + +// alt disabled buttons +.woocommerce #respond input#submit.alt.disabled, +.woocommerce #respond input#submit.alt:disabled, +.woocommerce #respond input#submit.alt:disabled[disabled], +.woocommerce a.button.alt.disabled, +.woocommerce a.button.alt:disabled, +.woocommerce a.button.alt:disabled[disabled], +.woocommerce button.button.alt.disabled, +.woocommerce button.button.alt:disabled, +.woocommerce button.button.alt:disabled[disabled], +.woocommerce input.button.alt.disabled, +.woocommerce input.button.alt:disabled, +.woocommerce input.button.alt:disabled[disabled] { + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } +} diff --git a/assets/scss/components/compat/woocommerce/_cart.scss b/assets/scss/components/compat/woocommerce/_cart.scss new file mode 100644 index 0000000000..c266ea3903 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_cart.scss @@ -0,0 +1,250 @@ +@import "../../main/variables"; + + +// +.woocommerce a.remove { + color: var(--nv-text-color) !important; + margin: 0; +} + +// + +#coupon_code { + @extend %nv-reset-field-spacing; +} + +// +.woocommerce table.cart td.actions .input-text#coupon_code { + width: 200px; + float: none; + flex-grow: 1; + max-height: unset; + margin-right: $spacing-xs; + + + .button { + float: none; + @extend %nv-button-secondary; + + &:hover { + @extend %nv-button-secondary-hover; + } + } +} + +.woocommerce-cart table.cart td.actions .coupon { + display: flex; +} + +// + + +// +.product-thumbnail img { + min-width: 60px !important; +} + +// +.woocommerce table.shop_table.cart { + border: 0; + + a { + color: var(--nv-text-color); + } + + tr { + border-bottom: $base-border; + padding: $spacing-md 0; + + &:last-child { + border: 0; + } + } + + thead tr { + border: 0; + } + + td { + background: transparent !important; + font-size: var(--bodyFontSize); + padding: $spacing-xs 0; + border: 0; + + &:before { + vertical-align: middle; + } + } + + td.actions { + padding: $spacing-xl 0; + } + + .product-remove { + float: left; + } + + .product-thumbnail { + display: block !important; + + &:before { + content: none; + } + } + + thead th { + font-size: $text-lg; + border: 0; + } +} + +.product-name { + .variation { + margin-top: $spacing-xs; + font-size: $text-sm; + opacity: .75; + + dt { + font-weight: 300; + } + } +} + +@mixin cart--tablet() { + .product-thumbnail img { + min-width: 120px !important; + } + + .woocommerce table.shop_table.cart { + border-collapse: collapse; + padding: 0; + + th, td { + padding: $spacing-sm; + + &:last-child { + text-align: right; + } + } + + .product-thumbnail { + width: 150px; + display: table-cell !important; + } + + .product-remove { + float: none; + padding-right: 0; + width: auto; + } + + tr:last-child { + .button { + --secondaryBtnPadding: 15px 40px; + --primaryBtnPadding: 18px 40px; + margin-left: auto; + } + } + } + + .cart_totals { + width: 40%; + } +} + +@mixin cart--laptop() { + .woocommerce table.shop_table.cart { + thead th { + border: 0; + } + + tbody tr:first-child { + border-top: none; + } + + .remove { + margin: 0 auto; + font-size: 30px; + } + } + .woocommerce-cart table.cart td.actions .coupon { + margin-left: $spacing-aired; + margin-bottom: 0; + } +} + +.woocommerce .quantity .qty { + box-sizing: content-box; +} + +// +.woocommerce .cart_totals { + border: 0; + + > h2 { + font-size: var(--h4FontSize); + } + + td, th { + background: 0 !important; + padding: $spacing-md 15px !important; + border-bottom: $base-border; + } + + td { + text-align: right; + } + + .shipping-calculator-form { + text-align: left; + } + + th { + text-align: left; + font-weight: 300 !important; + } + + table.shop_table { + border: 0; + + th { + font-size: $text-sm; + } + } + + .order-total { + font-size: var(--bodyFontSize); + + th { + font-weight: 700 !important; + } + } + + #shipping_method { + text-align: left; + margin-bottom: $spacing-lg; + display: block; + + li { + display: flex; + flex-direction: row-reverse; + + input { + margin-left: $spacing-xs; + } + } + } + + .wc-proceed-to-checkout { + display: flex; + justify-content: flex-end; + --primaryBtnPadding: 15px 40px; + } +} + +// + +.cross-sells { + > h2 { + font-size: var(--h4FontSize); + } +} diff --git a/assets/scss/components/compat/woocommerce/_checkout.scss b/assets/scss/components/compat/woocommerce/_checkout.scss new file mode 100644 index 0000000000..557519cfb0 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_checkout.scss @@ -0,0 +1,190 @@ +@import "../../main/variables"; + +.woocommerce-cart table.cart td.actions .coupon .input-text, +.woocommerce-page .select2-container--default .select2-selection--single, +.woocommerce-page .woocommerce form .form-row input.input-text, +.woocommerce-page .woocommerce form .form-row textarea, +.wc-block-product-search form input.wc-block-product-search__field { + @extend %nv-form-fields; +} + +.woocommerce-checkout { + label { + @extend %nv-form-labels; + } +} + +.woocommerce-checkout { + .addresses { + .woocommerce-column { + margin-bottom: $spacing-xl; + } + + h2 { + font-size: var(--h4FontSize); + } + } + + .col2-set .col-1, .col2-set .col-2 { + width: 100%; + float: none; + } + + form.checkout { + display: grid; + grid-template-columns: 1fr; + } + + .woocommerce-NoticeGroup { + grid-column: 1; + } + + .checkout_coupon { + display: flex; + flex-wrap: wrap; + + p:first-child { + width: 100%; + margin-bottom: $spacing-sm; + } + + button { + width: 100%; + height: 100%; + } + + .form-row { + display: flex; + flex-grow: 1; + } + } + + table.shop_table { + border: 0; + border-collapse: collapse; + + bdi { + font-weight: normal; + } + + th { + font-size: var(--h5FontSize); + font-weight: var(--h5FontWeight); + padding: $spacing-sm; + } + + td { + padding: $spacing-sm; + } + + tfoot, tfoot { + th, td { + border: 0; + font-weight: var(--bodyFontWeight); + font-size: $text-sm; + } + } + + tbody, thead, tfoot { + border-bottom: $base-border; + } + + td { + border: 0; + } + + .order-total { + th, bdi { + font-size: var(--bodyFontSize); + font-weight: 700; + } + } + + .product-total, tfoot td { + text-align: right; + } + + label { + font-size: inherit; + } + } + + #payment { + background: 0; + + div.payment_box { + background: var(--nv-light-bg); + color: var(--nv-text-color); + margin-top: 0; + + &:before { + content: none; + } + } + } + + .payment_methods { + border: 0 !important; + } + + main button { + width: 100%; + } +} + +@mixin checkout--laptop() { + .woocommerce-checkout { + .woocommerce-NoticeGroup { + grid-column: 1 / 3; + } + + .nv-page-title { + margin-bottom: $spacing-xxl; + } + + form.checkout { + grid-template-columns: 3fr 2fr; + grid-column-gap: $spacing-aired; + } + } +} + +.woocommerce-page { + .select2-container { + margin-bottom: var(--formFieldSpacing); + + &.select2-container--open { + outline: 0; + box-shadow: 0 0 3px 0 var(--nv-secondary-accent); + --formFieldBorderColor: var(--nv-secondary-accent); + } + + [data-selected=true] { + background-color: var(--nv-light-bg); + color: var(--nv-text-color); + } + } + + .select2-container--default .select2-selection--single { + height: auto; + @extend %nv-reset-field-spacing; + } + + .select2-container--default .select2-selection--single, + .select2-results__options, + .select2-search, + .select2-search__field { + color: var(--formFieldColor); + background-color: var(--formFieldBgColor); + } + + .select2-selection__rendered { + padding: 0 !important; + color: var(--formFieldColor) !important; + } + + .select2-selection__arrow { + height: 100% !important; + } +} + diff --git a/assets/scss/components/compat/woocommerce/_generic.scss b/assets/scss/components/compat/woocommerce/_generic.scss new file mode 100644 index 0000000000..f7d3b58d11 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_generic.scss @@ -0,0 +1,80 @@ +@import "../../main/variables"; + +main .nv-shop { + margin-top: $spacing-aired; +} + +// === Sale Badge === // +.woocommerce { + span.onsale { + background-color: $success; + border-radius: 0; + line-height: inherit; + min-height: auto; + left: 0; + top: 0; + font-weight: 500; + } + + ul.products li.product .onsale { + top: 0; + left: 0; + right: auto; + margin: 0; + } +} + +// === Pagination === // +.woocommerce nav.woocommerce-pagination ul { + display: flex; + border: 0; + margin: 0; + + li { + margin-right: $spacing-md; + border: 0; + + a, span { + background: var(--nv-light-bg); + border-radius: 3px; + padding: 12px 15px; + color: var(--nv-text-color); + } + + .dots { + background: 0; + } + + a:focus, + a:hover { + background: var(--nv-light-bg); + color: var(--nv-text-color); + } + + span.current { + background: var(--nv-primary-accent); + color: var(--nv-text-dark-bg); + } + } +} + +// === Rating === // +.woocommerce { + .star-rating { + color: #ffb100; + } +} + +// === Woo blocks === // +.nv-content-wrap ul.wc-block-grid__products { + list-style-type: none; + padding-left: 0; +} + +.woocommerce .blockOverlay { + background-color: var(--nv-site-bg) !important; +} + +.woocommerce form .form-row textarea:focus { + box-shadow: 0 0 3px 0 var(--nv-secondary-accent); +} diff --git a/assets/scss/components/compat/woocommerce/_media-queries.scss b/assets/scss/components/compat/woocommerce/_media-queries.scss new file mode 100644 index 0000000000..b5181dd6f7 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_media-queries.scss @@ -0,0 +1,24 @@ +@media (min-width: #{$tablet-sm}) { + @include notices--tablet-sm(); + @include shop-loop--tablet-sm(); +} + +@media (min-width: #{$tablet}) { + @include cart--tablet(); + @include account--tablet(); + @include product--tablet(); +} + +@media (min-width: #{$laptop}) { + @include reviews--laptop(); + @include shop-loop--laptop(); + @include nav-cart--laptop(); + @include shop-sidebar--laptop(); + @include cart--laptop(); + @include checkout--laptop(); +} + +@media (min-width: #{$desktop}) { + +} + diff --git a/assets/scss/components/compat/woocommerce/_nav-cart.scss b/assets/scss/components/compat/woocommerce/_nav-cart.scss new file mode 100644 index 0000000000..90743de1e3 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_nav-cart.scss @@ -0,0 +1,179 @@ +@import "../../main/variables"; + +$cart-width: 360px; + +//Cart icon in menu +.cart-icon-wrapper { + display: flex; + + &:hover { + color: var(--hoverColor, var(--color)); + } + + .nv-cart { + display: flex; + + svg { + width: var(--iconSize); + height: var(--iconSize); + } + } + + .cart-icon-label { + margin-right: $spacing-xxs; + font-size: var(--labelSize); + } + + .cart-count { + background: var(--nv-light-bg); + color: var(--nv-text-color); + position: absolute; + font-size: .6em; + padding: 3px; + bottom: -7px; + right: -13px; + font-weight: 800; + line-height: 1; + border-radius: 3px; + } +} + +// Hide minicart on mobile +.nv-nav-cart { + display: none; + opacity: 0; + visibility: hidden; +} + +//Menu mini cart positioning +.menu-item-nav-cart { + position: relative; + + .nv-nav-cart { + right: 0; + } +} + +.nv-nav-cart { + background: var(--nv-site-bg); + color: var(--nv-text-color); + transition: all .3s; + box-shadow: $soft-box-shadow; + position: absolute; + z-index: 100; + width: $cart-width; + text-align: left; + --primaryBtnPadding: 13px 15px; + --secondaryBtnPadding: 13px 15px; + + .widget { + // Overflow needed to hide scrollbar. + overflow: hidden; + } + + .woocommerce-mini-cart { + // Margin needed to hide scrollbar. + margin-right: -40px !important; + overflow-y: auto; + overflow-x: hidden; + max-height: 300px; + } + + li { + // Padding needed to hide scrollbar. + padding: $spacing-md 40px + $spacing-sm $spacing-md $spacing-sm !important; + + border-bottom: $base-border; + font-size: $text-sm; + + &:last-child { + border: 0; + } + + img { + position: absolute; + left: 35px; + width: 60px !important; + top: 50%; + transform: translateY(-50%); + margin-left: $spacing-xs !important; + } + + .remove { + top: 50% !important; + left: $spacing-sm !important; + transform: translateY(-50%); + } + + .quantity { + opacity: .5; + } + + > *:not(.remove) { + margin-left: 100px !important; + font-weight: inherit !important; + } + + dl { + padding: 0 !important; + border: 0 !important; + + > dd { + margin: 0 !important; + } + } + + > a { + color: var(--nv-text-color); + } + } + + .widget_shopping_cart_content { + .total { + border: 0; + margin: 0; + box-shadow: 0 -3px 9px -9px; + padding: $spacing-sm $spacing-md; + } + + strong { + font-weight: inherit; + margin-right: $spacing-xs; + } + + .buttons { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 $spacing-md; + grid-column-gap: $spacing-md; + margin-bottom: $spacing-md; + + &:before { + content: none !important; + } + + .button { + --btnFs: var(--bodyFontSize); + margin: 0; + display: flex; + align-items: center; + justify-content: center; + } + } + } +} + +@mixin nav-cart--laptop() { + .nv-nav-cart { + display: block; + } + + .menu-item-nav-cart { + &:hover, &:focus-within { + .nv-nav-cart { + opacity: 1; + visibility: visible; + } + } + } +} diff --git a/assets/scss/components/compat/woocommerce/_notices.scss b/assets/scss/components/compat/woocommerce/_notices.scss new file mode 100644 index 0000000000..ba2ec8626c --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_notices.scss @@ -0,0 +1,89 @@ +@import "../../main/variables"; + +.woocommerce-NoticeGroup > ul { + flex-direction: column; + align-items: flex-start; +} + +.woocommerce-info, .woocommerce-error, .woocommerce-message { + display: flex; + align-items: center; + flex-direction: column-reverse; + text-align: center; + padding: 15px; + --btnFs: $text-sm; + --primaryBtnPadding: 10px 15px; + --primaryBtnBorderWidth: 3px; + --primaryBtnColor: #fff; + --primaryBtnHoverColor: #fff; + --primaryBtnHoverBg: transparent; + --primaryBtnBg: transparent; + + &:before { + display: none; + } + + > a { + @extend %nv-button-primary-no-colors; + } + + a, .button { + width: 100%; + margin-top: $spacing-sm; + white-space: normal; + margin-left: auto; + } +} + +$notices: ( + 'message': $success, + 'error': $error, + 'info': var(--nv-primary-accent), +); + +@each $noticeName, $color in $notices { + .woocommerce .woocommerce-#{$noticeName}, + .woocommerce-page .woocommerce-#{$noticeName} { + border-radius: 3px; + background: $color; + border: 0; + color: #fff; + + a, &:before { + color: inherit; + } + } +} + +.woocommerce .woocommerce-error { + padding-left: 3.5em; + + li { + width: 100%; + margin: 0; + } +} + +@mixin notices--tablet-sm() { + .woocommerce-info, .woocommerce-error, .woocommerce-message { + flex-direction: row-reverse; + justify-content: flex-end; + text-align: left; + padding-left: $spacing-aired; + + a, .button { + order: -1; + margin-left: auto !important; + margin-top: 0; + width: auto ; + } + + &:before { + display: flex; + top: 0; + align-items: center; + height: 100%; + color: #fff; + } + } +} diff --git a/assets/scss/components/compat/woocommerce/_product.scss b/assets/scss/components/compat/woocommerce/_product.scss new file mode 100644 index 0000000000..ee14b6e068 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_product.scss @@ -0,0 +1,249 @@ +@import "../../main/variables"; +@import "./single/reviews"; +@import "./single/exclusive-products"; + +.nv-single-product-top { + display: flex; + flex-wrap: wrap; + position: relative; +} + +.qty { + @extend %nv-reset-field-spacing +} + +.woocommerce.single .nv-woo-filters { + display: none; +} + +.woocommerce .cart { + .added_to_cart, + .button, + button { + flex-grow: 1; + display: flex; + justify-content: center; + align-items: center; + } +} + +.woocommerce.single { + .entry-summary, #tab-description { + ul { + list-style-type: circle; + } + + ul, ol { + padding-left: $spacing-sm; + margin-bottom: $spacing-sm; + + li { + margin-bottom: $spacing-xs; + } + } + } + + .woocommerce-variation-add-to-cart { + display: flex; + } + + .quantity input { + box-sizing: border-box; + line-height: normal; + height: 100%; + padding-right: 0; + } + + .entry-summary > form.cart { + display: flex; + flex-wrap: wrap; + border-bottom: $base-border; + margin-bottom: $spacing-lg; + padding-bottom: $spacing-md; + + + .single_variation_wrap { + width: 100%; + } + + .wc-forward { + margin-left: 4px; + flex-basis: 50%; + } + + &.grouped_form { + flex-wrap: wrap; + } + + .group_table td { + vertical-align: middle; + + label { + margin: 0; + } + } + } + + .group_table { + margin-bottom: $spacing-md; + } +} + +.woocommerce table.shop_attributes { + border: 0; + + th, td { + border-bottom: $base-border; + font-style: normal; + font-size: $text-sm; + padding: $spacing-md; + background: 0 !important; + } +} + +.product_meta { + font-size: $text-sm; + + a { + color: var(--nv-text-color); + } + + > span { + font-size: $text-sm; + margin-top: $spacing-md; + display: block; + } +} + + +// === Prices === // +.woocommerce { + ul.products li.product .price ins, + ul.products li.product .price, + div.product p.price bdi, + div.product span.price, + div.product p.price, + li.product ins { + color: var(--nv-text-color); + } + + ul.products li.product .price { + font-size: var(--bodyFontSize); + } +} + +.woocommerce-variation-price { + margin-bottom: $spacing-md; +} + +// === Variations === // +.woocommerce { + div.product form.cart .variations { + td { + padding: 0; + display: block; + width: 100%; + + &.label { + padding: 0; + } + } + + tr:not(:last-child) { + margin-bottom: $spacing-xs; + display: block; + } + } + + .reset_variations { + display: block; + } +} + +.variations select { + width: 100%; + height: auto; +} + +// === Content Tabs === // +.woocommerce-tabs { + width: 100%; + margin: $spacing-xl 0 $spacing-xl; +} + +.woocommerce div.product .woocommerce-tabs ul.tabs li { + background: transparent; + border: 0; + margin: 0 $spacing-xl 0 0; + padding: 0; + + &:before, &:after { + content: none; + } + + &.active { + color: var(--nv-primary-accent); + background: 0; + border-bottom: 3px solid; + } + + a { + color: var(--nv-text-color); + } +} + +.woocommerce #content div.product .woocommerce-tabs ul.tabs { + margin-bottom: $spacing-xl; + padding: 0; + border: 0; + + &:before { + content: none; + } +} + +// === Gallery === // +.woocommerce div.product div.images .flex-control-thumbs { + margin: 5px -5px 0; + + li { + padding: 5px; + } +} + +.woocommerce-product-gallery { + float: none !important; + display: inline-block; +} + +@mixin product--tablet() { + .nv-single-product-top { + .summary { + margin-left: 4%; + } + } + body.single-product .neve-main > .container > .row { + flex-wrap: wrap; + } + + .woocommerce.single { + .entry-summary > form.cart { + .wc-forward { + flex-basis: auto; + } + } + } + .nv-single-image-wrapper { + width: 48%; + + .images { + width: 100% !important; + } + } +} + +.woocommerce ul.products.exclusive-products li.product, +.woocommerce-page ul.products.exclusive-products li.product { + margin: 0; + clear: none; +} diff --git a/assets/scss/components/compat/woocommerce/_shop-loop.scss b/assets/scss/components/compat/woocommerce/_shop-loop.scss new file mode 100644 index 0000000000..bbe49fbfef --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_shop-loop.scss @@ -0,0 +1,68 @@ +@import "../../main/variables"; + +.woocommerce .woocommerce-ordering select { + @extend %nv-reset-field-spacing +} + +.nv-woo-filters { + display: flex; + align-items: center; + margin-bottom: $spacing-xl; + + .woocommerce-ordering { + margin: 0; + } + + .nv-sidebar-toggle + .woocommerce-ordering { + select { + max-width: 155px; + margin-bottom: 0; + } + } +} + +// +.woocommerce ul.products li.product { + margin-bottom: $spacing-xl; + + a.woocommerce-loop-product__link { + > h2, > h3 { + padding-top: 0; + color: var(--nv-text-color); + font-size: #{$text-lg} + } + } +} + +// + +.img-wrap { + position: relative; + + .out-of-stock-badge { + color: var(--nv-text-color); + font-weight: var(--h4FontWeight); + text-transform: uppercase; + position: absolute; + top: 50%; + transform: translateY(-50%); + left: 0; + right: 0; + padding: $spacing-sm 0; + background: var(--nv-light-bg); + text-align: center; + opacity: .9; + z-index: 1; + } +} + +@mixin shop-loop--laptop() { +} + +@mixin shop-loop--tablet-sm() { + .nv-woo-filters .nv-sidebar-toggle + .woocommerce-ordering { + select { + max-width: unset; + } + } +} diff --git a/assets/scss/components/compat/woocommerce/_sidebar.scss b/assets/scss/components/compat/woocommerce/_sidebar.scss new file mode 100644 index 0000000000..215f672ac1 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_sidebar.scss @@ -0,0 +1,55 @@ +@import "../../main/variables"; + +.shop-sidebar { + position: fixed; + top: 0; + left: 0; + bottom: 0; + z-index: 100000; + height: 100vh; + overflow: auto; + width: 100%; + transition: all 0.3s ease-out; + background-color: var(--nv-site-bg); + transform: translateX(-100%); + + &.sidebar-open { + transform: translateX(0) + } +} + +.sidebar-header { + display: flex; + justify-content: flex-end; + margin-bottom: $spacing-md; + + .nv-sidebar-toggle { + @extend %nv-button-secondary; + } +} + +.nv-woo-filters { + .nv-sidebar-toggle { + margin-right: 20px; + } +} + +@mixin shop-sidebar--laptop() { + .nv-sidebar-toggle { + display: none; + } + + .shop-sidebar { + height: auto; + background: transparent; + position: static; + overflow: visible; + max-width: 30%; + transform: none; + z-index: unset; + + .sidebar-header { + display: none; + } + } +} diff --git a/assets/scss/components/compat/woocommerce/_widgets.scss b/assets/scss/components/compat/woocommerce/_widgets.scss new file mode 100644 index 0000000000..83a3fbc131 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/_widgets.scss @@ -0,0 +1,25 @@ +.woocommerce { + .widget_price_filter { + .price_slider_wrapper .ui-widget-content { + background-color: #ccc; + } + .ui-slider .ui-slider-handle { + background: var(--nv-primary-accent); + border: 1px solid #fff; + top: -5px; + &:hover { + transform: scale(1.25); + } + } + .ui-slider .ui-slider-range { + background-color: var(--nv-primary-accent); + } + .price_slider_wrapper .ui-widget-content { + height: 5px; + } + .price_slider_amount .button { + font-size: inherit; + line-height: 1; + } + } +} diff --git a/assets/scss/components/compat/woocommerce/single/_exclusive-products.scss b/assets/scss/components/compat/woocommerce/single/_exclusive-products.scss new file mode 100644 index 0000000000..ba9a2be067 --- /dev/null +++ b/assets/scss/components/compat/woocommerce/single/_exclusive-products.scss @@ -0,0 +1,48 @@ + +section.exclusive { + .nv-card-content-wrapper { + position: relative; + width: 100%; + } + + .dots-nav { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + + .dot { + background: 0; + border: 1px solid #b7b7b7; + margin: 5px; + width: 8px; + height: 8px; + padding: 0; + border-radius: 100%; + + &.tns-nav-active { + background: #404248; + border-color: #404248; + } + } + } + + + .tns-outer { + /* rtl:begin:ignore */ + direction: ltr; + /* rtl:end:ignore */ + overflow: hidden; + position: relative; + } + + .tns-ovh { + padding-right: 4px; + overflow: unset; + margin-bottom: $spacing-sm; + } + + .tns-visually-hidden { + display: none; + } +} diff --git a/assets/scss/components/compat/woocommerce/single/_reviews.scss b/assets/scss/components/compat/woocommerce/single/_reviews.scss new file mode 100644 index 0000000000..93893c412c --- /dev/null +++ b/assets/scss/components/compat/woocommerce/single/_reviews.scss @@ -0,0 +1,97 @@ +@import "../../../main/variables"; + +.woocommerce-review-link { + color: var(--nv-text-color); + font-size: $text-sm; +} + +.woocommerce-Tabs-panel h2 { + font-size: var(--h4FontSize); +} + +.woocommerce { + #reviews { + display: grid; + grid-row-gap: $spacing-xl; + --formFieldSpacing: 10px; + + form { + p { + margin-bottom: 0 !important; + } + } + + .comment-form-cookies-consent { + margin-bottom: $spacing-md !important; + + input { + display: inline; + } + + label { + display: inline; + margin: 0; + } + } + + input[type="text"], input[type="email"] { + width: 100%; + } + } + + .stars { + margin-left: $spacing-xl !important; + + a { + color: #ffb100; + } + } + + .comment-form-rating { + display: flex; + align-items: center; + + } + + #reply-title { + font-size: var(--h4FontSize); + font-weight: var(--h2FontWeight); + line-height: var(--h2LineHeight); + letter-spacing: var(--h2LetterSpacing); + text-transform: var(--h2TextTransform); + margin-bottom: $spacing-lg; + display: block; + } +} + + +.woocommerce #reviews #comments ol.commentlist li { + margin-bottom: $spacing-xl; + + &:last-child { + margin-bottom: 0; + } + + .comment-text { + padding: 0; + border: 0; + } + + img.avatar { + padding: 0; + border: 0; + } + + .meta { + color: var(--nv-text-color); + font-size: $text-sm !important; + } +} + + +@mixin reviews--laptop() { + .woocommerce #reviews { + grid-template-columns: 1fr 1fr; + grid-column-gap: $spacing-xxl; + } +} diff --git a/assets/scss/components/editor/_formatting.scss b/assets/scss/components/editor/_formatting.scss new file mode 100644 index 0000000000..1da9f82505 --- /dev/null +++ b/assets/scss/components/editor/_formatting.scss @@ -0,0 +1,54 @@ +// === Separators === // +.wp-block { + .wp-block-separator { + max-width: 100% !important; + } +} + +.wp-block-separator { + width: unset !important; + height: unset !important; + border-top: 2px solid; + border-bottom: 0; + opacity: 1; +} + +@import "../main/separators"; + +// === Buttons === // +.wp-block-button { + .wp-block-button__link { + @extend %nv-button; + @extend %nv-button-primary-no-colors; + + + &:hover { + opacity: .9; + } + } + + &.is-style-outline, + &.is-style-secondary { + .wp-block-button__link { + @extend %nv-button-secondary; + + &:hover { + @extend %nv-button-secondary-hover; + } + } + } + + &.is-style-primary { + .wp-block-button__link { + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } + } + } +} + +.wp-block-button__link.add_to_cart_button { + @extend %nv-button-primary; +} diff --git a/assets/scss/components/editor/_typography.scss b/assets/scss/components/editor/_typography.scss new file mode 100644 index 0000000000..6fd4e4e909 --- /dev/null +++ b/assets/scss/components/editor/_typography.scss @@ -0,0 +1,179 @@ +@import "../main/global-colors"; +@import "../main/variables"; + +.wp-block { + color: var(--nv-text-color); + font-size: var(--bodyFontSize); + line-height: var(--bodyLineHeight); + letter-spacing: var(--bodyLetterSpacing); + font-family: var(--bodyFontFamily); + text-transform: var(--bodyTextTransform); + font-weight: var(--bodyFontWeight); +} + +h1, h2, h3, h4, h5, h6 { + &.wp-block, & { + font-family: var(--headingsFontFamily, var(--bodyFontFamily)); + } +} + +$headings: [h1,h2,h3,h4,h5,h6]; + +@each $heading in $headings { + #{$heading} { + &.wp-block, & { + font-size: var(--#{$heading}FontSize); + font-weight: var(--#{$heading}FontWeight); + line-height: var(--#{$heading}LineHeight); + letter-spacing: var(--#{$heading}LetterSpacing); + text-transform: var(--#{$heading}TextTransform); + } + } +} + +.editor-post-title__block .editor-post-title__input { + color: var(--nv-text-color); + font-size: var(--h1FontSize); + font-weight: var(--h1FontWeight); + line-height: var(--h1LineHeight); + letter-spacing: var(--h1LetterSpacing); + text-transform: var(--h1TextTransform); +} + +.wp-block { + // Group colors + &.has-text-color .wp-block { + color: inherit; + } + + &.wp-block-group.has-background { + padding: 0; + } + + &.components-placeholder { + color: initial; + } +} + +// Lists +ul, ol { + padding-left: $spacing-md; + margin: $spacing-lg 0; + + li { + margin-top: $spacing-xs; + } +} + +// === Quotes === // +.wp-block-quote { + .wp-block-quote__citation { + font-size: $text-sm; + } + + &.is-style-large { + p { + font-size: $text-lg; + font-style: normal; + } + } +} + +// === Pull Quotes === // +.wp-block-pullquote { + margin-top: $spacing-lg; + margin-bottom: $spacing-lg; + border-top: 4px solid var(--nv-text-color); + border-bottom: 4px solid var(--nv-text-color); + padding: $spacing-lg $spacing-md; + + p { + font-size: $text-xl !important; + } + + &__citation { + font-size: $text-sm; + text-transform: none; + } + + &.is-style-solid-color { + border: 0; + background: var(--nv-light-bg) + } +} + +.wp-block { + &[data-align="left"] .wp-block-pullquote { + max-width: 420px; + text-align: left; + } + + &[data-align="right"] .wp-block-pullquote { + max-width: 420px; + text-align: right; + } +} + +// === Verse === // +.wp-block-verse { + font-size: $text-lg; + background: inherit; +} + +// === Tables === // +th, td { + border: 0; + + // Allow alignment inside the editor but make sure that cells are left-aligned by default. + &:not([class*="has-text-align"]) { + text-align: inherit; + } +} + +.wp-block-table figcaption { + font-size: $text-sm; +} + +@import "../main/tables"; + +// === Preformatted === // +.wp-block-preformatted { + font-family: Courier, monospace; +} + +pre { + display: block; + padding: $spacing-lg; + background: var(--nv-light-bg); + margin: $spacing-md 0; + white-space: pre-wrap; + font-size: $text-sm; + font-family: Courier, monospace; + + code { + border: 0; + background: transparent; + } +} + + +// === Links === // +a { + text-decoration: none; +} + +a:not(.wp-block-button__link) { + color: var(--nv-primary-accent); + + &:hover { + color: var(--nv-secondary-accent); + text-decoration: none; + } +} + +// === Code === // +.wp-block-code { + border: 0; + border-radius: 0; +} + diff --git a/assets/scss/components/elements/_blog.scss b/assets/scss/components/elements/_blog.scss new file mode 100644 index 0000000000..039d3f2714 --- /dev/null +++ b/assets/scss/components/elements/_blog.scss @@ -0,0 +1,10 @@ +@import 'blog/blogpost-meta'; +@import 'blog/blogpost-index'; +@import 'blog/infinite-scroll'; +@import 'blog/blogpost-grid'; +@import 'blog/blogpost-default-alt'; +@import 'blog/blogpost-covers'; +@import 'blog/single'; +@import 'blog/comments'; +@import 'blog/pagination'; +@import 'blog/typography'; diff --git a/assets/scss/components/elements/_breadcrumbs.scss b/assets/scss/components/elements/_breadcrumbs.scss new file mode 100644 index 0000000000..0d2b4ea5ba --- /dev/null +++ b/assets/scss/components/elements/_breadcrumbs.scss @@ -0,0 +1,14 @@ +@import "../main/variables"; + +.nv-title-meta-wrap, .nv-page-title { + .neve-breadcrumbs-wrapper { + margin-bottom: $spacing-lg; + display: block; + } +} + +.neve-breadcrumbs-wrapper { + a { + color: $gray-color; + } +} diff --git a/assets/scss/components/elements/_content.scss b/assets/scss/components/elements/_content.scss new file mode 100644 index 0000000000..2c44abcbdf --- /dev/null +++ b/assets/scss/components/elements/_content.scss @@ -0,0 +1,136 @@ +@import "../main/variables"; + +dl { + margin: $spacing-md 0; + + dd { + padding-left: $spacing-lg; + } + + dt { + font-weight: 600; + } +} + +.nv-iframe-embed { + position: relative; + padding-bottom: 56.25%; /* 16:9 */ + padding-top: 25px; + height: 0; + + iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +figcaption { + font-size: $text-sm; + opacity: .75; +} + +code { + background: #d0effb; + border-radius: 5px; + border: $muted-border; + padding: 0 3px; + color: #333; +} + +pre { + display: block; + padding: $spacing-lg; + background: var(--nv-light-bg); + margin: $spacing-md 0; + white-space: pre-wrap; + font-size: $text-sm; + font-family: Courier, monospace; + + code { + border: 0; + background: transparent; + } +} + +.nv-content-wrap, .excerpt-wrap { + &:after { + content: ""; + clear: both; + display: table; + } + + ul { + list-style-type: initial; + } + + > ul, > ol { + margin: $spacing-lg 0; + } + + ul, ol { + padding-left: $spacing-lg; + } + + li { + margin-top: $spacing-xs; + } +} + +// === Content Floating Alignments === // +.alignleft { + float: left; + margin: $spacing-md $spacing-md $spacing-md 0; +} + +.alignright { + float: right; + margin: $spacing-md 0 $spacing-md $spacing-md; +} + +.aligncenter { + display: block; + text-align: center; + margin: 0 auto; +} + +.wp-caption { + max-width: 100%; +} + +.wp-caption-text { + text-align: center; + font-size: .8em; + font-weight: 500; +} + +.twitter-tweet.twitter-tweet-rendered { + padding: $spacing-sm 0; + margin: auto; +} + +hr { + color: inherit; + height: 0; + border: 0; + border-top: 2px solid; + margin: $spacing-xs 0 $spacing-md; + display: inline-block; + width: 100%; +} + +audio { + display: flex; + height: 50px; +} + +@mixin content--laptop() { + .neve-main > .container .col { + max-width: 70%; + } + .neve-main > .container > .row { + flex-wrap: nowrap; + } +} diff --git a/assets/scss/components/elements/_form-elements.scss b/assets/scss/components/elements/_form-elements.scss new file mode 100644 index 0000000000..d2f0005a78 --- /dev/null +++ b/assets/scss/components/elements/_form-elements.scss @@ -0,0 +1,75 @@ +@import "../main/variables"; +@import "form-elements/inputs"; +@import "form-elements/buttons"; + +.widget-search { + width: 100%; + margin: 0 !important; +} + +.search-form { + display: flex; + max-width: 100%; + line-height: 1; + --formFieldSpacing: 0; + --formLabelSpacing: 0; + --primaryBtnBg: var(--formFieldBgColor); + --primaryBtnHoverBg: var(--formFieldBgColor); + --primaryBtnColor: var(--formFieldBorderColor); + --primaryBtnHoverColor: var(--formFieldBorderColor); + + svg { + fill: var(--formFieldColor); + width: var(--formFieldFontSize); + opacity: .5; + height: auto; + } + + .search-submit { + display: flex; + justify-content: center; + align-items: center; + min-width: 45px; + z-index: 1; + --primaryBtnBorderWidth: var(--formFieldBorderWidth); + --primaryBtnBorderColor: var(--formFieldBorderColor); + --primaryBtnBorderRadius: var(--formFieldBorderRadius); + --primaryBtnPadding: var(--formFieldPadding); + height: var(--height); + border-bottom-left-radius: 0; + border-top-left-radius: 0; + border-left: 0; + position: relative; + + &:before { + content: ""; + display: block; + width: 3px; + height: 100%; + background-color: var(--formFieldBgColor); + left: -3px; + top: 0; + bottom: 0; + position: absolute; + } + } + + .search-field { + overflow: hidden; + text-overflow: ellipsis; + height: var(--height); + border-right: 0; + flex-grow: 1; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + width: calc( 100% - 45px ); + max-width: 100%; + + &:focus ~ { + button { + box-shadow: 0 0 3px 0 var(--nv-secondary-accent); + border-color: var(--nv-secondary-accent); + } + } + } +} diff --git a/assets/scss/components/elements/_gallery.scss b/assets/scss/components/elements/_gallery.scss new file mode 100644 index 0000000000..67ab704e54 --- /dev/null +++ b/assets/scss/components/elements/_gallery.scss @@ -0,0 +1,31 @@ +@for $items from 1 through 9 { + .gallery-columns-#{$items} .gallery-item { + @if ($items == 1) { + width: 100%; + max-width: 100%; + } @else { + max-width: (100%/$items - 2); + width: (100%/$items - 2); + } + } +} + +.gallery { + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} + +.gallery-item { + display: inline-block; + text-align: center; + vertical-align: top; +} + +.nv-content-wrap ul.wp-block-gallery { + padding-left: 0; +} + +.gallery-caption { + box-sizing: border-box +} diff --git a/assets/scss/components/elements/_hfg-alignments.scss b/assets/scss/components/elements/_hfg-alignments.scss new file mode 100644 index 0000000000..40534a8307 --- /dev/null +++ b/assets/scss/components/elements/_hfg-alignments.scss @@ -0,0 +1,87 @@ +.hfg-is-group { + display: flex; + align-items: center; +} +$component-alignments: ( + 'right' : flex-end, + 'left' : flex-start, + 'center': center, +); + +// +@each $alignment, $flex-setting in $component-alignments { + .hfg-is-group.mobile-#{$alignment} { + justify-content: $flex-setting; + } + .mobile-#{$alignment} { + text-align: #{$alignment}; + + .nav-ul, .nv-nav-wrap, .component-wrap, .site-logo, .nv-search-icon-component, .builder-item--footer-menu { + justify-content: $flex-setting; + } + } +} + +.mobile-justify .button { + flex-grow: 1; +} +// + +// +@mixin hfg-alignments--tablet-sm() { + @each $alignment, $flex-setting in $component-alignments { + //mobile-right desktop-left tablet-left + .hfg-is-group.tablet-#{$alignment} { + justify-content: $flex-setting; + } + .tablet-#{$alignment} { + text-align: #{$alignment}; + + .nav-ul, .nv-nav-wrap, .component-wrap, .site-logo, .nv-search-icon-component, .builder-item--footer-menu { + justify-content: $flex-setting; + } + } + } + + .tablet-justify .button { + flex-grow: 1; + } +} +// + +// +@mixin hfg-alignments--laptop() { + @each $alignment, $flex-setting in $component-alignments { + //mobile-right desktop-left tablet-left + .hfg-is-group.desktop-#{$alignment} { + justify-content: $flex-setting; + } + .desktop-#{$alignment} { + text-align: #{$alignment}; + justify-content: $flex-setting; + + .nav-ul, .nv-nav-wrap, .component-wrap, .site-logo, .nv-search-icon-component, .builder-item--footer-menu { + justify-content: $flex-setting; + } + } + } + + .desktop-justify .button { + flex-grow: 1; + } +} +// + +// +$component-v-alignments: ( + 'top' : flex-start, + 'bottom': flex-end, + 'middle': center, +); + +@each $alignment, $align-self in $component-v-alignments { + .hfg-item-v-#{$alignment} { + align-self: $align-self; + } +} +// diff --git a/assets/scss/components/elements/_mega-menu.scss b/assets/scss/components/elements/_mega-menu.scss new file mode 100644 index 0000000000..b7ca2c874c --- /dev/null +++ b/assets/scss/components/elements/_mega-menu.scss @@ -0,0 +1,259 @@ +/* Style mega-menu and its children on mobile */ +.header--row { + .neve-mega-menu > .sub-menu { + cursor: default; + width: var(--container); + max-width: 100%; + } +} + +.nav-ul > .neve-mega-menu { + .sub-menu .sub-menu { + max-height: none; + } + + .neve-mm-col { + text-align: left; + cursor: default; + flex: 1; + + .sub-menu { + border: 0; + padding-left: 0; + + .sub-menu { + left: 0; + top: 100%; + } + } + } + + a { + display: flex; + align-items: center; + + i { + margin-top: 0; + vertical-align: unset; + } + } + + li.neve-mm-divider { + height: 1px; + margin: $spacing-xs auto; + width: 100%; + background-color: currentColor !important; + padding: 0; + cursor: default; + } + + .neve-mm-description { + text-align: left; + justify-content: flex-start; + } + + .neve-mm-heading > span { + padding: 7px 14px; + display: flex; + height: 100%; + cursor: default; + align-items: center; + + i { + margin-right: 10px; + } + } +} + +.neve-mm-description { + font-size: .8em; + padding: 0 0 7px; + width: 100%; + display: flex; + text-align: center; +} + +.neve-mm-heading > span, .neve-mm-heading > a { + font-size: 1.1em; + cursor: pointer; + display: flex; + align-items: center; + white-space: normal; + font-weight: 700; + text-transform: uppercase; +} + +.neve-mm-heading { + i { + margin-right: $spacing-xs; + } +} + +.header-menu-sidebar-inner { + .sub-menu, .sub-menu li { + background-color: transparent !important; + } + + .neve-mega-menu .neve-mm-col > .sub-menu { + .sub-menu { + max-height: 0; + + &.dropdown-open { + max-height: 3000px; + } + } + } + + .nav-ul > .neve-mega-menu .neve-mm-heading { + > span { + padding: 3px 0; + } + } + + .mobile-center { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: center; + justify-content: center; + } + } + + .mobile-left { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: left; + justify-content: flex-start; + } + } + + .mobile-right { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: right; + justify-content: flex-end; + } + } +} + +@mixin mega-menu--tablet() { + .header-menu-sidebar-inner { + .tablet-center { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: center; + justify-content: center; + } + } + + .tablet-left { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: left; + justify-content: flex-start; + } + } + + .tablet-right { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: right; + justify-content: flex-end; + } + } + } +} + +@mixin mega-menu--laptop() { + .header--row .nv-nav-wrap .primary-menu-ul { + .neve-mega-menu > .sub-menu { + left: 50%; + transform: translateX(-50%); + position: absolute; + display: flex; + padding: 20px; + top: auto; + + &:not(.dropdown-open) { + pointer-events: none; + } + } + + .neve-mega-menu:hover > .sub-menu, + .neve-mega-menu:focus > .sub-menu, + .neve-mega-menu:focus-within > .sub-menu { + opacity: 1; + visibility: visible; + pointer-events: all; + } + + .neve-mega-menu { + position: unset; + li > { + > a, > span { + padding: 7px 0; + margin: 0 14px; + } + } + } + + .neve-mega-menu .neve-mm-col > .sub-menu { + visibility: visible; + position: relative; + left: initial; + right: initial; + opacity: 1; + box-shadow: none; + display: flex; + flex-direction: column; + text-align: left; + width: 100%; + + a { + white-space: normal; + justify-content: flex-start; + } + } + + .neve-mega-menu .neve-mm-col { + padding: 0 10px; + align-items: flex-start; + border: 0; + } + + .neve-mega-menu .neve-mm-col:not(:last-child) { + border-right: 1px solid currentColor !important; + } + + .neve-mega-menu .neve-mm-col > .sub-menu { + li:not(.neve-mm-divider) { + border: 0; + } + } + } + .neve-mm-description { + justify-content: center; + padding: 0 12px 7px; + } + + .header-menu-sidebar-inner { + .desktop-center { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: center; + justify-content: center; + } + } + + .desktop-left { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: left; + justify-content: flex-start; + } + } + + .desktop-right { + .neve-mm-heading > a, .neve-mm-heading > span, .neve-mm-description { + text-align: right; + justify-content: flex-end; + } + } + } +} + +// Make sure the component is static if it's in the main rows and has a navigation. +.header--row .builder-item.has-nav { + position: static; +} diff --git a/assets/scss/components/elements/_navigation.scss b/assets/scss/components/elements/_navigation.scss new file mode 100644 index 0000000000..497a9f1b7a --- /dev/null +++ b/assets/scss/components/elements/_navigation.scss @@ -0,0 +1,6 @@ +@import "navigation/nav-brand"; +@import "navigation/nav-menu"; +@import "navigation/nav-icons"; +@import "navigation/nav-search"; +@import "navigation/nav-styles"; +@import "navigation/nav-toggle"; diff --git a/assets/scss/components/elements/_page.scss b/assets/scss/components/elements/_page.scss new file mode 100644 index 0000000000..4c0fcbf038 --- /dev/null +++ b/assets/scss/components/elements/_page.scss @@ -0,0 +1,15 @@ +.wrapper { + display: flex; + min-height: 100vh; + flex-direction: column; + position: relative; + transition: all 0.3s cubic-bezier(0.79, 0.14, 0.15, 0.86) +} + +body > .wrapper:not(.et-fb-iframe-ancestor) { + overflow: hidden; +} + +.neve-main { + flex: 1 auto; +} diff --git a/assets/scss/components/elements/_sidebar.scss b/assets/scss/components/elements/_sidebar.scss new file mode 100644 index 0000000000..f2e24277bc --- /dev/null +++ b/assets/scss/components/elements/_sidebar.scss @@ -0,0 +1,90 @@ +@import "../main/variables"; + +.nv-single-post-wrap, .nv-index-posts { + margin-bottom: $spacing-aired; +} + +.nv-sidebar-wrap { + padding: $spacing-aired 15px; + margin-bottom: $spacing-md; + flex-grow: 1; +} + +.widget { + word-break: break-word; + margin-bottom: $spacing-xl; + + &:last-child { + margin: 0; + } + + select { + max-width: 100%; + width: 100%; + } + + .widget-title { + margin-bottom: $spacing-xs; + font-weight: 700; + font-size: var(--h4FontSize); + } + + @extend %nv-reset-field-spacing; +} + +.wp-block-search .wp-block-search__button { + @extend %nv-button-primary; +} + +.wp-block-search.wp-block-search__button-inside .wp-block-search__inside-wrapper { + @extend %nv-form-fields; +} + + +.post-date { + display: block; + font-size: $text-sm; + opacity: .7; +} + +.widget_recent_entries a { + color: var(--nv-text-color); +} + +.widget { + ul { + padding: 0; + + ul { + padding-left: $spacing-xs; + } + } + + li { + margin-top: $spacing-xs; + } +} + +.widget_media_image img { + width: 100%; +} + +.widget_calendar { + td, th { + padding: $spacing-xs; + } +} + +@mixin sidebar--laptop() { + .nv-sidebar-wrap { + max-width: 30%; + + &.nv-right { + padding-left: 45px; + } + + &.nv-left { + padding-right: 45px; + } + } +} diff --git a/assets/scss/components/elements/blog/_blogpost-covers.scss b/assets/scss/components/elements/blog/_blogpost-covers.scss new file mode 100644 index 0000000000..6c875fa097 --- /dev/null +++ b/assets/scss/components/elements/blog/_blogpost-covers.scss @@ -0,0 +1,55 @@ +@import "../../main/variables"; +$overlay: rgba(0, 0, 0, 0.75); + +.layout-covers { + .article-content-col, + .content, + .cover-post { + height: 100%; + } + + .content { + border: 0; + padding-bottom: 0; + } +} + +.cover-post { + box-shadow: var(--boxShadow, none); + position: relative; + background-size: cover; + display: flex; + background-position: center; + overflow: hidden; + + &:after { + background-color: $overlay; + content: ''; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + } + + amp-img, img { + --boxShadow: none; + } + + .inner { + max-width: 100%; + min-height: 350px; + position: relative; + z-index: 10; + padding: 25px; + display: flex; + flex-direction: column; + justify-content: flex-end; + color: var(--color, #fff); + flex-grow: 1; + + a:not(.button) { + color: var(--color, #fff); + } + } +} diff --git a/assets/scss/components/elements/blog/_blogpost-default-alt.scss b/assets/scss/components/elements/blog/_blogpost-default-alt.scss new file mode 100644 index 0000000000..4a118a2a66 --- /dev/null +++ b/assets/scss/components/elements/blog/_blogpost-default-alt.scss @@ -0,0 +1,41 @@ +.nv-non-grid-article { + display: flex; + align-items: flex-end; + + .nv-post-thumbnail-wrap { + margin-bottom: $spacing-md; + } +} + +@mixin blog-layout-default-alt--laptop() { + .non-grid-content { + padding: var(--padding); + } + .nv-non-grid-article { + .nv-post-thumbnail-wrap { + margin-bottom: 0; + grid-column: var(--thumbGridColumn, 1); + } + + .content { + display: grid; + grid-gap: 20px; + align-items: center; + grid-auto-flow: dense; + } + } + + .posts-wrapper > article { + &.has-post-thumbnail .content { + grid-template-columns: var(--postColTemplate, 35fr 65fr); + } + + &.has-post-thumbnail.layout-alternative:nth-child(even) { + --thumbGridColumn: 2; + + .content { + grid-template-columns: var(--postColTemplate, 65fr 35fr); + } + } + } +} diff --git a/assets/scss/components/elements/blog/_blogpost-grid.scss b/assets/scss/components/elements/blog/_blogpost-grid.scss new file mode 100644 index 0000000000..149833bd77 --- /dev/null +++ b/assets/scss/components/elements/blog/_blogpost-grid.scss @@ -0,0 +1,3 @@ +body .layout-grid > .article-content-col, .layout-grid { + display: flex; +} diff --git a/assets/scss/components/elements/blog/_blogpost-index.scss b/assets/scss/components/elements/blog/_blogpost-index.scss new file mode 100644 index 0000000000..b3d4692c8d --- /dev/null +++ b/assets/scss/components/elements/blog/_blogpost-index.scss @@ -0,0 +1,120 @@ +@import "../../main/variables"; + +.entry-title { + word-wrap: break-word; + + a { + color: var(--nv-text-color); + } +} + +.nv-index-posts { + margin-top: $spacing-aired; + + .nv-page-title-wrap { + margin-top: 0; + } +} + +.nv-post-thumbnail-wrap { + > a, img:not(.photo) { + display: block; + } + + amp-img, img { + box-shadow: var(--boxShadow, none) + } +} + +.posts-wrapper > article { + width: var(--postWidth); +} + +.blog-entry-title { + margin-bottom: $spacing-xs; + word-wrap: break-word; +} + +.article-content-col { + width: 100%; +} + +.article-content-col .content { + width: 100%; + border-bottom: 0 solid; + padding-bottom: $spacing-md; + display: flex; + flex-direction: column; + + .button { + display: inline-block; + align-self: flex-start; + } +} + +.bypostauthor { + display: block; +} + +.posts-wrapper { + display: flex; + flex-wrap: wrap; + margin-bottom: $spacing-xl; +} + +.excerpt-wrap > *:last-child { + margin-bottom: 0; +} + +.layout-grid .content { + > .blog-entry-title { + margin-bottom: $spacing-xs; + } + + > * { + margin-bottom: $spacing-md; + + &:last-child { + margin-bottom: 0; + } + } +} + +.nv-non-grid-article { + margin-bottom: var(--spacing, 60px); + + .non-grid-content { + display: flex; + flex-direction: column; + flex-grow: 1; + + > .blog-entry-title { + margin-bottom: $spacing-xs; + } + + > * { + margin-bottom: $spacing-md; + + &:last-child { + margin-bottom: 0; + } + } + } +} + +article { + word-break: break-word; +} + +// Deny grid wrapper. +body:not(.nv-blog-default) { + .posts-wrapper { + margin-left: calc(-1 * var(--gridSpacing, 30px) / 2); + margin-right: calc(-1 * var(--gridSpacing, 30px) / 2); + + article { + margin-bottom: calc(var(--gridSpacing, 30px)); + padding: 0 calc(var(--gridSpacing, 30px) / 2); + } + } +} diff --git a/assets/scss/components/elements/blog/_blogpost-meta.scss b/assets/scss/components/elements/blog/_blogpost-meta.scss new file mode 100644 index 0000000000..563a2b9ec4 --- /dev/null +++ b/assets/scss/components/elements/blog/_blogpost-meta.scss @@ -0,0 +1,37 @@ +@import "../../main/variables"; + +.nv-meta-list { + margin-bottom: $spacing-md; + font-size: $text-sm; + + li, span { + display: inline; + + &:not(:last-child):after { + content: '/'; + padding: 0 $spacing-xxs; + } + } + + .posted-on:not(.nv-show-updated) .updated { + display: none; + } + + .photo { + width: var(--avatarSize); + height: var(--avatarSize); + border-radius: 50%; + transform: translateY(30%); + margin-right: 3px; + } + +} + +.nv-dynamic-author-meta { + .photo { + width: $spacing-sm; + height: $spacing-sm; + border-radius: 50%; + transform: translateY(30%); + } +} diff --git a/assets/scss/components/elements/blog/_comments.scss b/assets/scss/components/elements/blog/_comments.scss new file mode 100644 index 0000000000..1ac0f3aeb3 --- /dev/null +++ b/assets/scss/components/elements/blog/_comments.scss @@ -0,0 +1,121 @@ +@import "../../main/variables"; + +.nv-comment-content { + margin-bottom: 0 !important; + + > *:last-child { + margin-bottom: 0; + } +} + +#comments { + li.comment { + border-bottom: 2px solid; + padding-bottom: $spacing-xl; + margin-bottom: $spacing-xl; + } + + article { + display: flex; + } + + .avatar { + border-radius: 100%; + margin-right: $spacing-md; + } + + .comment-content { + flex-grow: 1; + } + + input:not([type="submit"]):not([type="checkbox"]) { + width: 100%; + } + + ol { + list-style: none; + + ol li { + padding-left: $spacing-xl + } + } + + textarea { + max-width: 100%; + width: 100%; + display: block; + } + + .comment-reply-title { + margin-bottom: $spacing-sm; + + small { + float: right; + } + } +} + +.nv-comment-header { + display: flex; + align-items: center; + margin-bottom: $spacing-lg; + + .vcard { + display: grid; + + a { + color: var(--color, var(--nv-text-color)); + } + + .author { + font-weight: 700; + } + + time { + font-size: $text-sm; + opacity: .7; + } + } + + .edit-reply { + font-size: $text-sm; + font-weight: 700; + text-transform: uppercase; + margin-left: auto; + } +} + +.comments-title { + margin-bottom: $spacing-xxl; +} + + +.comment-form { + display: grid; + grid-column-gap: $spacing-sm; + grid-row-gap: $spacing-xs; + + > p:not(.comment-notes) { + margin-bottom: 0; + } + + label { + display: inline-block; + } +} + +.nv-comments-list { + margin-bottom: $spacing-xxl; +} + +@mixin comments--tablet() { + #comments { + .comment-form { + grid-template-columns: repeat(3, 1fr); + + > *:not(.comment-form-author):not(.comment-form-url):not(.comment-form-email) { + grid-column: 1/-1; + } + } + } +} diff --git a/assets/scss/components/elements/blog/_infinite-scroll.scss b/assets/scss/components/elements/blog/_infinite-scroll.scss new file mode 100644 index 0000000000..cc2cfe0370 --- /dev/null +++ b/assets/scss/components/elements/blog/_infinite-scroll.scss @@ -0,0 +1,17 @@ +.nv-loader { + height: 40px; + width: 40px; + border-radius: 50%; + border: 3px solid var(--nv-primary-accent); + border-left: 3px solid transparent; + animation: spin 1s linear infinite; + margin: 0 auto; + display: none; +} + +@keyframes spin { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} diff --git a/assets/scss/components/elements/blog/_pagination.scss b/assets/scss/components/elements/blog/_pagination.scss new file mode 100644 index 0000000000..dc340da162 --- /dev/null +++ b/assets/scss/components/elements/blog/_pagination.scss @@ -0,0 +1,27 @@ +ul.page-numbers { + display: flex; + flex-wrap: wrap; + + li{ + margin-bottom: $spacing-sm; + } + + a, span { + line-height: 1; + margin-right: $spacing-md; + background: var(--nv-light-bg); + border-radius: 3px; + padding: 12px 15px; + color: var(--nv-text-color); + display: block; + } + + .dots { + background: 0; + } + + .current { + background: var(--nv-primary-accent); + color: var(--nv-text-dark-bg); + } +} diff --git a/assets/scss/components/elements/blog/_single.scss b/assets/scss/components/elements/blog/_single.scss new file mode 100644 index 0000000000..2e10271f6c --- /dev/null +++ b/assets/scss/components/elements/blog/_single.scss @@ -0,0 +1,163 @@ +@import "../../main/variables"; + +.nv-single-post-wrap { + > div { + &:first-child { + margin-top: $spacing-aired; + } + + &:last-child { + padding-bottom: $spacing-lg; + } + } + + > div:not(:last-child) { + margin-bottom: var(--spacing, $spacing-aired); + } +} + +.nv-page-title-wrap { + margin-top: $spacing-aired; +} + +.entry-header .title { + margin-bottom: $spacing-xs; +} + +.attachment-neve-blog { + display: flex; +} + +.nv-post-navigation { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: $spacing-md; + + span { + display: block; + } + + .nav-direction { + color: var(--nv-text-color); + font-size: 0.8em; + text-transform: uppercase; + } + + a:hover span:last-child { + text-decoration: underline; + } + + .next { + grid-column: 2; + text-align: right; + } +} + +.post-pages-links { + display: flex; + list-style-type: none; + + > a:not(:last-child) span, > span { + padding-right: $spacing-sm; + } +} + +.post-password-form { + margin-bottom: $spacing-md; + text-align: center; + + input[type=submit] { + height: 39px; + margin-left: $spacing-xs; + } + + label { + margin-bottom: 0; + } + + p { + display: flex; + justify-content: center; + align-items: center; + } + + label > input { + margin-left: $spacing-xs; + } +} + +.nv-tags-list, .tagcloud { + a { + margin-left: $spacing-xs; + font-weight: 700; + text-transform: uppercase; + color: #fff; + padding: 10px; + border-radius: 4px; + background: var(--nv-primary-accent); + line-height: 1; + font-size: .75em !important; + display: inline-block; + } +} + +.tagcloud { + display: flex; + flex-wrap: wrap; + + a { + margin: 0 $spacing-xs $spacing-xs 0; + color: #fff !important; + } +} + +.nv-post-cover { + min-height: var(--height); + padding: var(--padding); + display: flex; + position: relative; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + + .nv-title-meta-wrap { + color: var(--color, var(--nv-text-dark-bg)); + display: flex; + flex-direction: column; + z-index: 1; + align-self: var(--vAlign, flex-end); + + > *:last-child { + margin-bottom: 0; + } + + a { + color: var(--color, var(--nv-text-dark-bg)); + } + } + + .container { + display: flex; + } +} + +.nv-is-boxed { + padding: var(--padding); + background: var(--bgColor, var(--nv-light-bg)); + color: var(--color, var(--nv-text-color)); + + a { + color: var(--color, var(--nv-text-color)); + } +} + +.nv-overlay { + background-color: var(--bgColor, var(--nv-dark-bg)); + mix-blend-mode: var(--blendMode, normal); + opacity: calc(var(--opacity) / 100); + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; +} diff --git a/assets/scss/components/elements/blog/_typography.scss b/assets/scss/components/elements/blog/_typography.scss new file mode 100644 index 0000000000..3aa580d1c6 --- /dev/null +++ b/assets/scss/components/elements/blog/_typography.scss @@ -0,0 +1,24 @@ +// === Single Post Title === // +.title.entry-title { + @extend %nv-has-h1-typography +} + +// === Blog Archive Post Title === // +.blog-entry-title { + @extend %nv-has-h3-typography +} + +// === Comment reply title === // +.comment-reply-title { + @extend %nv-has-h4-typography +} + +// === Excerpt === // +.entry-summary { + @extend %nv-has-typography +} + +// === Meta === // +.nv-meta-list li { + @extend %nv-has-typography +} diff --git a/assets/scss/components/elements/form-elements/_buttons.scss b/assets/scss/components/elements/form-elements/_buttons.scss new file mode 100644 index 0000000000..7c84bd1609 --- /dev/null +++ b/assets/scss/components/elements/form-elements/_buttons.scss @@ -0,0 +1,33 @@ +.button { + //noinspection SassScssResolvedByNameOnly + @extend %nv-button; + + &.button-primary { + //noinspection SassScssResolvedByNameOnly + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } + } + + &.button-secondary, & { + //noinspection SassScssResolvedByNameOnly + @extend %nv-button-secondary; + + &:hover { + @extend %nv-button-secondary-hover; + } + } +} + +button, input[type=button], .btn, input[type="submit"] { + //noinspection SassScssResolvedByNameOnly + @extend %nv-button; + //noinspection SassScssResolvedByNameOnly + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } +} diff --git a/assets/scss/components/elements/form-elements/_inputs.scss b/assets/scss/components/elements/form-elements/_inputs.scss new file mode 100644 index 0000000000..cb16f02f13 --- /dev/null +++ b/assets/scss/components/elements/form-elements/_inputs.scss @@ -0,0 +1,82 @@ +input[type="text"], +input[type="password"], +input[type="email"], +input[type="url"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="datetime"], +input[type="datetime-local"], +input[type="week"], +input[type="number"], +input[type="search"], +input[type="tel"], +input[type="color"], +input[type="submit"], +select, +textarea { + display: inline-block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + outline: none; + resize: vertical; +} + +input:read-write, select, textarea, [tabindex="-1"] { + &:focus, &:focus-visible { + outline: 0; + box-shadow: 0 0 3px 0 var(--nv-secondary-accent); + --formFieldBorderColor: var(--nv-secondary-accent); + } +} + +input, textarea, select, button { + line-height: inherit; + box-sizing: border-box; +} + +::placeholder { + color: inherit; + opacity: .5; +} + +select { + min-height: 35px; +} + +label { + display: inline-block; +} + +fieldset { + padding: $spacing-lg - 10px $spacing-lg; + border: 2px solid var(--nv-light-bg); + + legend { + font-weight: 700; + padding: 0 $spacing-sm; + margin-left: -$spacing-sm; + } + + input[type="text"], input[type="search"], input[type="password"], textarea, select { + width: 100%; + } +} + +select { + background-repeat: no-repeat; + background-position: right; + background-size: 18px; + padding-right: 20px !important; + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+PHBhdGggZmlsbD0iIzYyNjI2MiIgZD0iTTE1IDhsLTQgNi00LTZoOHoiLz48L3N2Zz4="); +} + + +form input:read-write, form textarea, form select, form select option, form.wp-block-search input.wp-block-search__input, .widget select { + @extend %nv-form-fields; +} + +form label, .wpforms-container .wpforms-field-label { + @extend %nv-form-labels; +} diff --git a/assets/scss/components/elements/navigation/_nav-brand.scss b/assets/scss/components/elements/navigation/_nav-brand.scss new file mode 100644 index 0000000000..834e6832d6 --- /dev/null +++ b/assets/scss/components/elements/navigation/_nav-brand.scss @@ -0,0 +1,39 @@ +@import "../../main/variables"; + +.site-logo { + align-items: center; + display: flex; + + amp-img img { + max-height: 60px; + } + + img { + max-width: var(--maxWidth); + display: block; + margin: 0 auto; + } + + .title-with-logo { + display: flex; + flex-direction: row; + align-items: center; + + > *:first-child { + margin-right: 10px; + } + } + + h1, p { + font-size: 24px; + font-weight: var(--h1FontWeight); + line-height: var(--bodyLineHeight); + letter-spacing: var(--bodyLetterSpacing); + text-transform: var(--textTransform, var(--bodyTextTransform)); + margin: 0; + } + + small { + display: block; + } +} diff --git a/assets/scss/components/elements/navigation/_nav-icons.scss b/assets/scss/components/elements/navigation/_nav-icons.scss new file mode 100644 index 0000000000..140560e9f8 --- /dev/null +++ b/assets/scss/components/elements/navigation/_nav-icons.scss @@ -0,0 +1,9 @@ +.nv-nav-wrap ul.primary-menu-ul > { + li i { + margin-top: 0; + font-size: inherit; + line-height: inherit; + width: auto; + height: auto; + } +} diff --git a/assets/scss/components/elements/navigation/_nav-menu.scss b/assets/scss/components/elements/navigation/_nav-menu.scss new file mode 100644 index 0000000000..7b7abfdb5b --- /dev/null +++ b/assets/scss/components/elements/navigation/_nav-menu.scss @@ -0,0 +1,214 @@ +@import "../../main/variables"; + +%show-dropdown { + opacity: 1; + visibility: visible; +} + +.caret { + transition: .3s ease; +} + +// === Desktop menu === // +.nav-ul { + display: flex; + flex-wrap: wrap; + margin-right: calc(var(--spacing) / 2 * -1); + margin-left: calc(var(--spacing) / 2 * -1); + + li a { + display: flex; + align-items: center; + min-height: var(--height); + color: var(--color); + position: relative; + } + + a:hover { + color: var(--hoverColor); + } + + > li { + margin: 0 calc(var(--spacing) / 2); + } + + li { + cursor: pointer; + display: block; + position: relative; + + &.current-menu-item > a { + color: var(--activeColor); + } + + &:hover > .sub-menu, + &:focus-within > .sub-menu { + @extend %show-dropdown; + } + } + + .caret { + display: flex; + margin-left: 5px; + justify-content: center; + + svg { + fill: currentColor; + width: .5em; + height: .5em; + } + } + + .sub-menu { + background-color: var(--bgColor, var(--overlayColor)); + z-index: 100; + position: absolute; + top: 100%; + box-shadow: $soft-box-shadow; + visibility: hidden; + opacity: 0; + right: 0; + + li { + min-width: 150px; + } + + a { + padding: $spacing-xs $spacing-md; + white-space: nowrap; + display: flex; + } + + .menu-item-title-wrap { + flex-grow: 1; + } + + .sub-menu { + left: 100%; + top: 0; + right: unset; + } + } +} + +.sub-menu.dropdown-open { + @extend %show-dropdown; +} + + +// === Inside Sidebar === // +.header-menu-sidebar { + .menu-item-title-wrap { + flex-grow: 1; + } + + .nav-ul { + margin: 0 -15px; + flex-direction: column; + + li { + margin: 0; + } + + a { + padding: $spacing-sm 20px; + white-space: unset; + } + + .caret svg { + width: 1em; + height: 1em; + } + + .caret-wrap { + margin: -15px; + padding: 15px 30px 15px 20px; + + &.dropdown-open .caret { + transform: rotateX(180deg); + } + } + + .sub-menu { + // Important because of the different open behaviours of the sidebar. + left: unset !important; + top: unset !important; + right: unset !important; + position: relative; + max-width: 100%; + box-shadow: none; + max-height: 0; + overflow: hidden; + @extend %show-dropdown; + + &.dropdown-open { + max-height: 1300px; + } + + a { + padding-left: $spacing-xl; + } + } + + &.dropdowns-expanded { + > li > .sub-menu { + max-height: 1200px; + } + + > li > a { + .caret-wrap { + display: none; + } + } + } + } +} + +// === AMP === // +.amp-desktop-caret-wrap { + display: none; +} + +.amp-caret-wrap { + svg { + fill: currentColor; + width: 1em + } +} + +.has-caret.amp { + display: flex; + align-items: center; + + .caret-wrap { + margin-left: auto; + } +} + +.sub-menu .has-caret.amp { + padding-right: $spacing-md; +} + +.header-menu-sidebar { + .has-caret.amp { + padding-right: 0; + } + + .amp.dropdown-open + .sub-menu { + max-height: 1300px !important; + } +} + + +@mixin nav-menu--tablet-sm() { +} + +@mixin nav-menu--laptop() { + .amp-desktop-caret-wrap { + display: none; + } + + .amp-caret-wrap { + display: block; + } +} diff --git a/assets/scss/components/elements/navigation/_nav-search.scss b/assets/scss/components/elements/navigation/_nav-search.scss new file mode 100644 index 0000000000..f176aa33ce --- /dev/null +++ b/assets/scss/components/elements/navigation/_nav-search.scss @@ -0,0 +1,133 @@ +@import "../../main/variables"; + +.nv-nav-search { + transition: opacity .3s; + position: absolute; + visibility: hidden; + opacity: 0; + right: 0; + width: auto; + padding: $spacing-xs; + cursor: unset; + z-index: 100; + background-color: var(--nv-site-bg); + box-shadow: $soft-box-shadow; + display: flex; + align-items: center; + + .container { + padding: 0; + } + + .menu-item-nav-search.active & { + opacity: 1; + visibility: visible; + } +} + +.menu-item-nav-search { + .nv-icon:hover { + color: var(--hoverColor) + } + svg { + width: var(--iconSize); + height: var(--iconSize); + } + + &.minimal { + position: relative; + .search-field { + width: 200px; + } + .nv-nav-search { + display: flex; + align-items: center; + right: auto; + left: 0; + top: 100%; + } + } + + &.floating { + .form-wrap { + flex-grow: 1; + } + + .nv-nav-search { + align-items: unset; + transition: top .2s ease-out; + position: fixed; + top: -100%; + left: 0; + } + + &.active { + .nv-nav-search { + top: 0; + } + } + + .close-container { + display: flex; + } + + .close-responsive-search { + display: flex; + align-items: center; + --primaryBtnPadding: 0 20px; + } + } + + .header-menu-sidebar &.floating .nv-nav-search { + position: absolute; + } + + &.canvas .nv-nav-search { + position: fixed; + top: 0; + bottom: 0; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + + .close-container { + position: absolute; + top: $spacing-lg; + text-align: right; + } + } + +} + +.menu-item-nav-search { + cursor: pointer; + outline: 0; +} + +.nav-clickaway-overlay { + position: fixed; + width: 100%; + left: 0; + right: 0; + top: 0; + z-index: 90; + height: 100vh; +} + +.close-responsive-search { + background: 0; + border: 0; + --primaryBtnHoverBg: 0; + + > svg { + fill: var(--nv-text-color); + width: var(--formFieldFontSize); + min-width: 25px; + min-height: 25px; + } +} + + +@mixin nav-search--laptop() { +} diff --git a/assets/scss/components/elements/navigation/_nav-styles.scss b/assets/scss/components/elements/navigation/_nav-styles.scss new file mode 100644 index 0000000000..115f139b8f --- /dev/null +++ b/assets/scss/components/elements/navigation/_nav-styles.scss @@ -0,0 +1,59 @@ +.style-border-bottom { + a:after { + bottom: 0; + } +} + +.style-border-top { + a:after { + top: 0; + } +} + +.style-border-top, .style-border-bottom, .style-full-height { + a:hover { + &:after { + width: 100%; + } + } + + a:after { + position: absolute; + content: ""; + display: block; + margin: 0 auto; + width: 0; + height: 2px; + transition: opacity .3s ease, width .3s ease; + right: 0; + left: 0; + pointer-events: none; + background-color: var(--hoverColor, currentColor); + } +} + + +.style-full-height { + li a:hover { + color: var(--color); + + &:after { + width: calc(100% + var(--spacing)); + } + } + + a { + z-index: 1; + + &:after { + margin: 0 auto; + top: 0; + bottom: 0; + left: calc(var(--spacing) / 2 * -1); + right: calc(var(--spacing) / 2 * -1); + height: 100%; + z-index: -1; + } + } + +} diff --git a/assets/scss/components/elements/navigation/_nav-toggle.scss b/assets/scss/components/elements/navigation/_nav-toggle.scss new file mode 100644 index 0000000000..c350377da7 --- /dev/null +++ b/assets/scss/components/elements/navigation/_nav-toggle.scss @@ -0,0 +1,50 @@ +.nav-toggle-label { + margin-right: 5px; + line-height: 100%; +} + +.navbar-toggle-wrapper { + align-items: center; +} + +.navbar-toggle { + --primaryBtnColor: var(--color); + --primaryBtnHoverColor: var(--color); + --primaryBtnBg: var(--bgColor, transparent); + --primaryBtnHoverBg: var(--bgColor, transparent); + --primaryBtnBorderWidth: var(--borderWidth, 1px); + --primaryBtnBorderRadius: var(--borderRadius, 0); + padding: var(--padding, 10px 15px) ; + box-shadow: none; + display: flex; + align-items: center; +} + +.icon-bar { + background-color: currentColor; + transition: all .1s ease; + position: relative; + display: block; + width: 15px; + height: 2px; + + &:nth-child(2) { + margin: 3px 0; + } +} + +.is-menu-sidebar .navbar-toggle { + .icon-bar:nth-child(1) { + transform: rotate(45deg); + top: 5px; + } + + .icon-bar:nth-child(2) { + opacity: 0; + } + + .icon-bar:nth-child(3) { + transform: rotate(-45deg); + bottom: 5px; + } +} diff --git a/assets/scss/components/hfg/frontend/_mixins.scss b/assets/scss/components/hfg/frontend/_mixins.scss new file mode 100644 index 0000000000..a21b7356a5 --- /dev/null +++ b/assets/scss/components/hfg/frontend/_mixins.scss @@ -0,0 +1,59 @@ +@mixin rtl() { + html[dir="rtl"] & { + @content; + } +} + +// Skin mode +@function black($opacity) { + @return rgba(black, $opacity) +} +@function white($opacity) { + @return rgba(white, $opacity) +} + +// Mobile first responsive +@mixin mq($media) { + @if $media == min-xs { + @media (min-width: $screen_xs) { @content; } + } + @else if $media == max-xs { + @media (max-width: $screen_xs) { @content; } + } + + @if $media == min-sm { + @media (min-width: $screen_sm) { @content; } + } + @else if $media == max-sm { + @media (max-width: $screen_sm) { @content; } + } + + @else if $media == min-md { + @media (min-width: $screen_md) { @content; } + } + @else if $media == max-md { + @media (max-width: $screen_md) { @content; } + } + + @else if $media == min-lg { + @media (min-width: $screen_lg) { @content; } + } + @else if $media == max-lg { + @media (max-width: $screen_lg) { @content; } + } +} + +//Device Query +@mixin for_device( $device_name ){ + @if map-has-key( $gl-devices-list, $device_name) { + @media #{map-get( $gl-devices-list, $device_name)} { + @content; + } + }@else { + @if map-has-key( $gl-mq-list, $device_name) { + @media #{map-get($gl-mq-list, $device_name)} { + @content; + } + } + } +} diff --git a/assets/scss/components/hfg/frontend/_vars.scss b/assets/scss/components/hfg/frontend/_vars.scss new file mode 100644 index 0000000000..610fbbc1f7 --- /dev/null +++ b/assets/scss/components/hfg/frontend/_vars.scss @@ -0,0 +1,10 @@ +$container_width: var(--container); // 1200px; 75em + +// Colors +$gl-devices-list: ( + desktop: "(min-width: 960px)", + tablet: "(max-width: 959px)", + mobile: "(max-width: 576px)" +) !default; + +$menu_sidebar_active_z_index: 999900; diff --git a/assets/scss/components/hfg/frontend/components/_button.scss b/assets/scss/components/hfg/frontend/components/_button.scss new file mode 100644 index 0000000000..31db070feb --- /dev/null +++ b/assets/scss/components/hfg/frontend/components/_button.scss @@ -0,0 +1,23 @@ +.hfg-is-group { + > div:first-of-type .button { + margin-right: 20px; + } + + > div:last-of-type .button { + margin-left: 20px; + } +} + +.header { + .builder-item .item--inner { + &[class*="nav-icon"], + &[class*="button_base"] { + padding: 0 !important; + } + } + + .builder-item [class*="button_base"] .button { + --primaryBtnPadding: var(--padding) + } +} + diff --git a/assets/scss/components/hfg/frontend/layout/_footer.scss b/assets/scss/components/hfg/frontend/layout/_footer.scss new file mode 100644 index 0000000000..f83d1dbd11 --- /dev/null +++ b/assets/scss/components/hfg/frontend/layout/_footer.scss @@ -0,0 +1,35 @@ +.site-footer { + position: relative; + z-index: 10; + + .item--inner.has_menu { + display: flex; + } + + p { + &:last-child { + margin-bottom: 0; + } + } +} + +.footer--row { + .hfg-slot { + display: flex; + flex-direction: column; + } + + .row { + display: grid; + } + + .builder-item { + width: 100%; + } +} + +@media (max-width: 960px) { + footer .footer--row-inner .row { + grid-template-columns: 1fr; + } +} diff --git a/assets/scss/components/hfg/frontend/layout/_general.scss b/assets/scss/components/hfg/frontend/layout/_general.scss new file mode 100644 index 0000000000..cf1b2c2e7b --- /dev/null +++ b/assets/scss/components/hfg/frontend/layout/_general.scss @@ -0,0 +1,100 @@ +.site-header { + position: relative; + + .header--row-inner { + align-items: center; + display: flex; + } +} + +.builder-item { + margin: 4px 0; + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; + + &.hfg-end { + margin-left: auto; + } + + &.hfg-start { + margin-right: auto; + } +} + +$desktop: map-get($gl-devices-list, desktop); +@media #{$desktop}{ + .builder-item { + margin: 8px 0; + } +} + +// +.hfg-slot { + display: flex; + align-items: center; + + &.right { + justify-content: flex-end; + } + + &.center { + justify-content: center; + } +} + + +.layout-fullwidth { + .container { + max-width: 100% !important; + } +} + +.layout-contained { + max-width: $container_width; + margin: 0 auto; +} + +[class*="row-inner"], .header-menu-sidebar-bg { + position: relative; + background-image: var(--bgImage, none); + background-position: var(--bgPosition, center); + background-repeat: no-repeat; + background-size: cover; + background-attachment: var(--bgAttachment); + + &:before { + display: block; + width: 100%; + top: 0; + bottom: 0; + position: absolute; + content: ""; + background-color: var(--overlayColor); + opacity: var(--bgOverlayOpacity) + } +} + +[data-row-id] { + color: var(--color); + background: var(--bgColor); + + a { + color: var(--color); + } + + .row { + display: grid; + grid-template-columns: auto auto; + min-height: var(--height, auto); + } +} + +.has-center .row--wrapper { + grid-template-columns: 1fr auto 1fr; +} + +.hfg_header.site-header { + box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1); +} diff --git a/assets/scss/components/hfg/frontend/layout/_mobile_sidebar.scss b/assets/scss/components/hfg/frontend/layout/_mobile_sidebar.scss new file mode 100644 index 0000000000..61a0ca8031 --- /dev/null +++ b/assets/scss/components/hfg/frontend/layout/_mobile_sidebar.scss @@ -0,0 +1,247 @@ +@import "../vars"; + +.header-menu-sidebar { + padding: 0; + position: fixed; + max-width: 100%; + top: 0; + z-index: $menu_sidebar_active_z_index; + visibility: hidden; + display: flex; + transition: all .3s cubic-bezier(.79, .14, .15, .86); + height: 100vh; +} + +.header-menu-sidebar-bg { + background-color: var(--bgColor); + color: var(--color); + position: relative; + display: flex; + flex-direction: column; + word-wrap: break-word; + width: 100%; +} + +.header-menu-sidebar-inner { + padding: 20px 0; + overflow-x: hidden; + height: 100%; +} + +.menu_sidebar_slide_left { + .header-menu-sidebar { + left: 0; + transform: translateX(-100%); + } +} + +.menu_sidebar_slide_right { + .header-menu-sidebar { + right: 0; + transform: translateX(100%); + } +} + +.menu_sidebar_pull_left .wrapper { + left: 0; + + .header-menu-sidebar { + left: 0; + transform: translateX(-100%); + } +} + +.menu_sidebar_pull_right .wrapper { + right: 0; + + .header-menu-sidebar { + right: 0; + transform: translateX(100%); + } +} + +.menu_sidebar_dropdown { + .header-menu-sidebar-overlay { + display: none; + } + + .header-menu-sidebar { + box-shadow: none; + position: absolute; + top: unset; + width: 100%; + display: block; + + .close-sidebar-panel { + display: none; + } + } + + .header-menu-sidebar-inner { + transition: all .3s cubic-bezier(.79, .14, .15, .86); + max-height: 0; + padding: 0; + } +} + +.menu_sidebar_full_canvas { + .header-menu-sidebar { + width: 100%; + bottom: 0; + right: 0; + opacity: 0; + transition: all .3s cubic-bezier(.79, .14, .15, .86); + } + + .header-menu-sidebar-inner { + flex-grow: 1; + } +} + +/* Hiding Menu Sidebar animation. */ +.hiding-header-menu-sidebar { + .header-menu-sidebar { + transition: all .3s cubic-bezier(.79, .14, .15, .86); + //height: 100%; + } + + &.menu_sidebar_slide_left { + .header-menu-sidebar { + transform: translateX(-100%); + } + } + + &.menu_sidebar_slide_right { + .header-menu-sidebar { + transform: translateX(100%); + } + } + + &.menu_sidebar_dropdown { + .header-menu-sidebar-inner { + height: 0; + padding: 0; + overflow: hidden; + } + } + + &.menu_sidebar_full_canvas { + .header-menu-sidebar { + opacity: 0; + pointer-events: none; + } + } + + .header-menu-sidebar { + visibility: visible; + } +} + +/* Showing Menu Sidebar animation. */ +.is-menu-sidebar { + .header-menu-sidebar { + visibility: visible; + } + + &.menu_sidebar_slide_left { + .header-menu-sidebar { + transform: translate3d(0, 0, 0); + left: 0; + } + } + + &.menu_sidebar_slide_right { + .header-menu-sidebar { + transform: translate3d(0, 0, 0); + right: 0; + } + } + + &.menu_sidebar_pull_left { + .header-menu-sidebar { + transform: translateX(0); + } + } + + &.menu_sidebar_pull_right { + .header-menu-sidebar { + transform: translateX(0); + } + } + + &.menu_sidebar_dropdown { + .header-menu-sidebar { + height: auto; + } + + .header-menu-sidebar-inner { + max-height: 400px; + padding: 20px 0; + } + } + + &.menu_sidebar_full_canvas { + .header-menu-sidebar { + opacity: 1; + } + } +} + +.header-menu-sidebar .menu-item-nav-search { + display: flex; + align-items: center; +} + +/* Close Button */ +.header-menu-sidebar { + .navbar-toggle-wrapper { + display: flex; + justify-content: flex-end; + padding: 8px 10px; + + button.navbar-toggle { + position: relative; + } + } +} + +/* - Item showing animation */ +.header-menu-sidebar { + .item--inner { + transition: transform .3s, opacity .3s; + opacity: 0; + } +} + +.is-menu-sidebar { + .header-menu-sidebar { + .item--inner { + opacity: 1; + } + } +} + +// +.header-menu-sidebar-overlay { + top: 0; + bottom: 0; + right: 0; + left: 0; + background: rgba(0, 0, 0, 0.5); + position: fixed; + transform: translate3d(0, 0, 0); + z-index: $menu_sidebar_active_z_index - 1; + transition: all .3s linear; + visibility: hidden; + opacity: 0; + pointer-events: none; + + .is-menu-sidebar & { + visibility: visible; + opacity: 1; + pointer-events: unset; + } +} + +// + diff --git a/assets/scss/components/hfg/style.scss b/assets/scss/components/hfg/style.scss new file mode 100644 index 0000000000..41e2025a03 --- /dev/null +++ b/assets/scss/components/hfg/style.scss @@ -0,0 +1,40 @@ +@charset "UTF-8"; + +@import "frontend/mixins"; +@import "frontend/vars"; +@import "frontend/layout/mobile_sidebar"; +@import "frontend/layout/footer"; +@import "frontend/layout/general"; + +// COMPONENTS +@import "frontend/components/button"; + +.hfg-grid { + display: flex; +} + +// HIDING COLS FOR DEVICES +@each $mq-key, $mq-value in $gl-devices-list { + @media #{$mq-value} { + .hide-on-#{$mq-key} { + display: none; + } + } +} + +.component-wrap { + display: flex; + margin: 4px 0; +} + +.builder-item .item--inner { + color: var(--color); + font-family: var(--fontFamily, var(--bodyFontFamily)); + font-size: var(--fontSize, var(--bodyFontSize)); + line-height: var(--lineHeight, var(--bodyLineHeight)); + letter-spacing: var(--letterSpacing, var(--bodyLetterSpacing)); + font-weight: var(--fontWeight, var(--bodyFontWeight)); + text-transform: var(--textTransform, var(--bodyTextTransform)); + padding: var(--padding, 0); + margin: var(--margin, 0); +} diff --git a/assets/scss/components/main/_a11y.scss b/assets/scss/components/main/_a11y.scss new file mode 100644 index 0000000000..2c1d789450 --- /dev/null +++ b/assets/scss/components/main/_a11y.scss @@ -0,0 +1,28 @@ +.show-on-focus { + position: absolute; + width: 1px; + height: 1px; + margin: 0; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); + top: 32px; + left: 0; + background: var(--nv-site-bg); + padding: $spacing-xs $spacing-sm; + + &:focus { + z-index: 20; + width: auto; + height: auto; + clip: auto; + } +} + +.screen-reader-text { + position:absolute; + left:-10000px; + top:auto; + width:1px; + height:1px; + overflow:hidden; +} diff --git a/assets/scss/components/main/_extends.scss b/assets/scss/components/main/_extends.scss new file mode 100644 index 0000000000..d13b69122a --- /dev/null +++ b/assets/scss/components/main/_extends.scss @@ -0,0 +1,176 @@ +// Buttons +%nv-button { + cursor: pointer; + box-sizing: border-box; + border-color: currentColor; + text-align: center; + font-family: var(--bodyFontFamily),var(--nv-fallback-ff); +} + +%nv-button-primary { + cursor: pointer; + box-sizing: border-box; + + background-color: var(--primaryBtnBg); + color: var(--primaryBtnColor); + border-style: solid; + border-color: currentColor; + fill: currentColor; + border-width: var(--primaryBtnBorderWidth, 0); + border-radius: var(--primaryBtnBorderRadius, 3px); + padding: var(--primaryBtnPadding, 13px 15px); + + font-weight: var(--btnFontWeight, 700); + font-size: var(--btnFs, var(--bodyFontSize)); + line-height: var(--btnLineHeight, 1.6); + letter-spacing: var(--btnLetterSpacing, var(--bodyLetterSpacing)); + text-transform: var(--btnTextTransform, none); +} + +%nv-button-primary-hover { + background-color: var(--primaryBtnHoverBg); + color: var(--primaryBtnHoverColor); + border-color: var(--primaryBtnHoverColor); +} + +%nv-button-primary-no-border { + cursor: pointer; + box-sizing: border-box; + padding: var(--btnPadding, 13px 15px); + border-radius: var(--primaryBtnBorderRadius, 3px); + font-weight: var(--btnFontWeight, 700); + font-size: var(--btnFs, var(--bodyFontSize)); + line-height: var(--btnLineHeight, 1.6); + letter-spacing: var(--btnLetterSpacing, var(--bodyLetterSpacing)); + text-transform: var(--btnTextTransform, none); +} + +%nv-button-primary-no-colors { + cursor: pointer; + box-sizing: border-box; + + border-style: solid; + border-color: currentColor; + border-width: var(--primaryBtnBorderWidth, 0); + border-radius: var(--primaryBtnBorderRadius, 3px); + padding: var(--primaryBtnPadding, 13px 15px); + + font-weight: var(--btnFontWeight, 700); + font-size: var(--btnFs, var(--bodyFontSize)); + line-height: var(--btnLineHeight, 1.6); + letter-spacing: var(--btnLetterSpacing, var(--bodyLetterSpacing)); + text-transform: var(--btnTextTransform, none); +} + +%nv-button-secondary { + cursor: pointer; + box-sizing: border-box; + + background-color: var(--secondaryBtnBg); + color: var(--secondaryBtnColor); + border-style: solid; + border-color: currentColor; + fill: currentColor; + border-width: var(--secondaryBtnBorderWidth, 0); + border-radius: var(--secondaryBtnBorderRadius, 3px); + padding: var(--secondaryBtnPadding, 7px 12px); + + font-weight: var(--btnFontWeight, 700); + font-size: var(--btnFs, var(--bodyFontSize)); + line-height: var(--btnLineHeight, 1.6); + letter-spacing: var(--btnLetterSpacing); + text-transform: var(--btnTextTransform, none); +} + +%nv-button-secondary-hover { + background-color: var(--secondaryBtnHoverBg); + color: var(--secondaryBtnHoverColor); + border-color: var(--secondaryBtnHoverColor); +} + +%nv-button-secondary-no-colors { + cursor: pointer; + border-radius: var(--secondaryBtnBorderRadius, 3px); + border-style: solid; + border-color: currentColor; + border-width: var(--secondaryBtnBorderWidth, 0); + padding: var(--secondaryBtnPadding, 7px 12px); + + font-weight: var(--btnFontWeight, 700); + font-size: var(--btnFs, var(--bodyFontSize)); + line-height: var(--btnLineHeight, 1.6); + letter-spacing: var(--btnLetterSpacing, var(--bodyLetterSpacing)); + text-transform: var(--btnTextTransform, none); +} + +// Form Fields +%nv-form-fields { + margin-bottom: var(--formFieldSpacing); + border-style: solid; + border-color: var(--formFieldBorderColor); + border-width: var(--formFieldBorderWidth); + border-radius: var(--formFieldBorderRadius, 3px); + background-color: var(--formFieldBgColor); + color: var(--formFieldColor); + padding: var(--formFieldPadding); + + text-transform: var(--formFieldTextTransform); + font-weight: var(--formFieldFontWeight); + font-family: var(--bodyFontFamily); + font-size: var(--formFieldFontSize); + letter-spacing: var(--formFieldLetterSpacing); + line-height: var(--formFieldLineHeight); +} + +%nv-form-labels { + margin-bottom: var(--formLabelSpacing); + font-weight: var(--formLabelFontWeight, var(--bodyFontWeight)); + text-transform: var(--formLabelTextTransform); + letter-spacing: var(--formLabelLetterSpacing); + line-height: var(--formLabelLineHeight); + font-size: var(--formLabelFontSize, var(--bodyFontSize)); +} + +%nv-reset-field-spacing { + --formFieldSpacing: 0; +} + +%nv-has-typography { + font-weight: var(--fontWeight); + text-transform: var(--textTransform); + letter-spacing: var(--letterSpacing); + line-height: var(--lineHeight); + font-size: var(--fontSize); +} + +%nv-has-h1-typography { + font-size: var(--fontSize, var(--h1FontSize)); + font-weight: var(--fontWeight, var(--h1FontWeight)); + line-height: var(--lineHeight, var(--h1LineHeight)); + letter-spacing: var(--letterSpacing, var(--h1LetterSpacing)); + text-transform: var(--textTransform, var(--h1TextTransform)); +} + +%nv-has-h2-typography { + font-size: var(--fontSize, var(--h2FontSize)); + font-weight: var(--fontWeight, var(--h2FontWeight)); + line-height: var(--lineHeight, var(--h2LineHeight)); + letter-spacing: var(--letterSpacing, var(--h2LetterSpacing)); + text-transform: var(--textTransform, var(--h2TextTransform)); +} + +%nv-has-h3-typography { + font-size: var(--fontSize, var(--h3FontSize)); + font-weight: var(--fontWeight, var(--h3FontWeight)); + line-height: var(--lineHeight, var(--h3LineHeight)); + letter-spacing: var(--letterSpacing, var(--h3LetterSpacing)); + text-transform: var(--textTransform, var(--h3TextTransform)); +} + +%nv-has-h4-typography { + font-size: var(--fontSize, var(--h4FontSize)); + font-weight: var(--fontWeight, var(--h4FontWeight)); + line-height: var(--lineHeight, var(--h4LineHeight)); + letter-spacing: var(--letterSpacing, var(--h4LetterSpacing)); + text-transform: var(--textTransform, var(--h4TextTransform)); +} diff --git a/assets/scss/components/main/_global-colors.scss b/assets/scss/components/main/_global-colors.scss new file mode 100644 index 0000000000..adc78ce22e --- /dev/null +++ b/assets/scss/components/main/_global-colors.scss @@ -0,0 +1,21 @@ +$colors: ( + "neve-link-color" :"--nv-primary-accent", + "neve-link-hover-color" : "--nv-secondary-accent", + "neve-text-color" : "--nv-text-color", + "nv-site-bg" : "--nv-site-bg", + "nv-light-bg" : "--nv-light-bg", + "nv-dark-bg" : "--nv-dark-bg", + "nv-text-dark-bg" : "--nv-text-dark-bg", + "nv-c-1" : "--nv-c-1", + "nv-c-2" : "--nv-c-2", +); + +@each $selector, $variable in $colors { + .has-#{$selector}-color { + color: var(#{$variable}) !important; + } + + .has-#{$selector}-background-color { + background-color: var(#{$variable}) !important; + } +} diff --git a/assets/scss/components/main/_grid.scss b/assets/scss/components/main/_grid.scss new file mode 100644 index 0000000000..c7acda76e9 --- /dev/null +++ b/assets/scss/components/main/_grid.scss @@ -0,0 +1,33 @@ +.container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin: 0 auto; + max-width: var(--container); +} + +.w-100 { + width: 100%; +} + +.container-fluid { + width: 100%; + margin: 0 auto; + + > div { + margin: 0 -15px; + } +} + +.row { + display: flex; + flex-wrap: wrap; + margin: 0 -15px; +} + +.col { + padding: 0 15px; + margin: 0 auto; + flex-grow: 1; + max-width: 100%; +} diff --git a/assets/scss/components/main/_gutenberg.scss b/assets/scss/components/main/_gutenberg.scss new file mode 100644 index 0000000000..a2a7bab0bf --- /dev/null +++ b/assets/scss/components/main/_gutenberg.scss @@ -0,0 +1,172 @@ +@import "variables"; +@import "./tables"; +@import "./separators"; + +// === Headings font sizes === // +.has-neve-body-font-size { + font-size: var(--bodyFontSize); +} + +.has-neve-h-1-font-size { + font-size: var(--h1FontSize); +} + +.has-neve-h-2-font-size { + font-size: var(--h2FontSize); +} + +.has-neve-h-3-font-size { + font-size: var(--h3FontSize); +} + +.has-neve-h-4-font-size { + font-size: var(--h4FontSize); +} + +.has-neve-h-5-font-size { + font-size: var(--h5FontSize); +} + + + +// === Buttons === // +.wp-block-button__link { + @extend %nv-button-primary-no-border; + @extend %nv-button; +} + +.is-style-primary .wp-block-button__link { + @extend %nv-button-primary; + + &:hover { + @extend %nv-button-primary-hover; + } +} + +.is-style-secondary .wp-block-button__link { + @extend %nv-button-secondary; + + &:hover { + @extend %nv-button-secondary-hover; + } +} + +// === Alignments === // +.alignfull { + width: 100vw; + max-width: 100vw; + margin-left: calc(50% - 50vw); + margin-right: calc(50% - 50vw); + padding: 0 7.5px; +} + +.alignwide { + width: 98vw; + max-width: 98vw; + margin-left: calc(50% - 49vw); + margin-right: calc(50% - 49vw); +} + +.nv-sidebar-left, +.nv-sidebar-right { + .alignfull, .alignwide { + max-width: 100%; + margin-left: auto; + margin-right: auto; + } +} + +// === Quotes === // +blockquote { + margin: $spacing-xl 0; + border-color: var(--nv-text-color); + border-style: solid; + border-width: 0 0 0 4px; + padding: 0 0 0 $spacing-md; + + p { + margin-bottom: $spacing-xs; + } + + cite { + font-style: normal; + font-size: $text-sm !important; + } + + &.has-text-align-center { + border: 0; + padding: 0; + } + + &.has-text-align-right { + border-width: 0 4px 0 0; + padding: 0 $spacing-md 0 0; + } + + &.is-style-large { + border: 0; + padding: 0; + + &.wp-block-quote > p { + margin-bottom: $spacing-md; + font-style: normal; + font-size: $text-lg; + } + } +} + +// === Pull Quotes === // +.wp-block-pullquote { + margin-top: $spacing-lg; + margin-bottom: $spacing-lg; + border-top: $base-border-strong; + border-bottom: $base-border-strong; + padding: $spacing-lg $spacing-md; + + p { + font-size: $text-xl !important; + } + + blockquote { + padding-left: 0; + border-left: 0; + margin: 0; + } + + &.alignleft { + text-align: left; + } + + &.alignright { + text-align: right; + } + + &.is-style-solid-color { + background-color: var(--nv-light-bg); + + blockquote { + text-align: inherit; + max-width: 90%; + } + } +} + + +// +.wp-block-verse { + background-color: inherit; + font-size: $text-lg; + border: 0; +} + +// + +@mixin gutenberg--laptop() { + .alignwide { + width: 70vw; + max-width: 70vw; + margin-left: calc(50% - 35vw); + margin-right: calc(50% - 35vw); + } +} + diff --git a/assets/scss/components/main/_media-queries.scss b/assets/scss/components/main/_media-queries.scss new file mode 100644 index 0000000000..e6861856ed --- /dev/null +++ b/assets/scss/components/main/_media-queries.scss @@ -0,0 +1,21 @@ +@media (min-width: #{$tablet-sm}) { + @include hfg-alignments--tablet-sm(); + @include nav-menu--tablet-sm(); +} + +@media (min-width: #{$tablet}) { + @include comments--tablet(); +} + +@media (min-width: #{$laptop}) { + @include content--laptop(); + @include nav-menu--laptop(); + @include nav-search--laptop(); + @include blog-layout-default-alt--laptop(); + @include sidebar--laptop(); + @include hfg-alignments--laptop(); + @include gutenberg--laptop(); +} + +//@media (min-width: #{$desktop}) { +//} diff --git a/assets/scss/components/main/_neve-icons.scss b/assets/scss/components/main/_neve-icons.scss new file mode 100644 index 0000000000..7aa50a1210 --- /dev/null +++ b/assets/scss/components/main/_neve-icons.scss @@ -0,0 +1,7 @@ +.nv-icon { + fill: currentColor; +} + +.nv-search { + display: flex; +} diff --git a/assets/scss/components/main/_reset.scss b/assets/scss/components/main/_reset.scss new file mode 100644 index 0000000000..aa22c15c1e --- /dev/null +++ b/assets/scss/components/main/_reset.scss @@ -0,0 +1,91 @@ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +.nv-html-content p, +h6 { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} + +ul { + list-style: none; +} + +button, +input, +select, +textarea { + margin: 0; +} + +html { + box-sizing: border-box; + -ms-overflow-style: scrollbar; +} + +*, *:before, *:after { + box-sizing: border-box; +} + +img, +embed, +object, +audio, +video { + height: auto; + max-width: 100%; +} + +iframe { + border: 0; + max-width: 100%; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; + text-align: left; +} + +abbr, acronym { + text-decoration: none; +} + +mark { + background: 0; + color: var(--nv-text-color) +} diff --git a/assets/scss/components/main/_separators.scss b/assets/scss/components/main/_separators.scss new file mode 100644 index 0000000000..d816ba4f71 --- /dev/null +++ b/assets/scss/components/main/_separators.scss @@ -0,0 +1,17 @@ +// === Separators === // +.wp-block-separator { + border-bottom: 0; + border-top: 2px solid; + + &.is-style-wide { + border-width: 4px; + } + + &.is-style-dots { + border-top: 4px dotted; + + &:before { + content: none; + } + } +} diff --git a/assets/scss/components/main/_tables.scss b/assets/scss/components/main/_tables.scss new file mode 100644 index 0000000000..c9f1f05cd9 --- /dev/null +++ b/assets/scss/components/main/_tables.scss @@ -0,0 +1,43 @@ +@import "variables"; + +table { + border-collapse: separate; + border-spacing: 0; + border-width: 1px 0 0 1px; + margin: 0 0 $spacing-md; + width: 100%; + word-break: initial; +} + +.wp-block-table { + margin-top: $spacing-lg; + margin-bottom: $spacing-lg; + + figcaption { + margin: $spacing-sm auto; + text-align: center; + } + + &.is-style-stripes { + border: 0; + + tbody tr { + &:nth-child(odd) { + background-color: var(--nv-light-bg); + } + } + } +} + +th, td { + padding: $spacing-md; +} + +th { + padding-bottom: $spacing-xs; +} + +td { + font-size: $text-sm; + border-bottom: $base-border; +} diff --git a/assets/scss/components/main/_typography.scss b/assets/scss/components/main/_typography.scss new file mode 100644 index 0000000000..7029d86b48 --- /dev/null +++ b/assets/scss/components/main/_typography.scss @@ -0,0 +1,92 @@ +@import "./variables"; + +html { + font-size: 100%; + overflow-x: hidden; +} + +body { + background-color: var(--nv-site-bg); + color: var(--nv-text-color); + font-size: var(--bodyFontSize); + line-height: var(--bodyLineHeight); + letter-spacing: var(--bodyLetterSpacing); + font-family: var(--bodyFontFamily), var(--nv-fallback-ff); + text-transform: var(--bodyTextTransform); + font-weight: var(--bodyFontWeight); + overflow-x: hidden; + direction: ltr; +} + +h1, h2, h3, h4, h5, h6 { + margin-bottom: $spacing-lg; + font-family: var(--headingsFontFamily), var(--nv-fallback-ff); +} + +p { + margin-bottom: $spacing-lg; +} + +a { + color: var(--nv-primary-accent); + cursor: pointer; + text-decoration: none; + + &:hover, + &:focus { + opacity: .9; + color: var(--nv-secondary-accent); + } +} + +ins { + text-decoration: none; +} + +h1 { + font-size: var(--h1FontSize); + font-weight: var(--h1FontWeight); + line-height: var(--h1LineHeight); + letter-spacing: var(--h1LetterSpacing); + text-transform: var(--h1TextTransform); +} + +h2 { + font-size: var(--h2FontSize); + font-weight: var(--h2FontWeight); + line-height: var(--h2LineHeight); + letter-spacing: var(--h2LetterSpacing); + text-transform: var(--h2TextTransform); +} + +h3 { + font-size: var(--h3FontSize); + font-weight: var(--h3FontWeight); + line-height: var(--h3LineHeight); + letter-spacing: var(--h3LetterSpacing); + text-transform: var(--h3TextTransform); +} + +h4 { + font-size: var(--h4FontSize); + font-weight: var(--h4FontWeight); + line-height: var(--h4LineHeight); + letter-spacing: var(--h4LetterSpacing); + text-transform: var(--h4TextTransform); +} + +h5 { + font-size: var(--h5FontSize); + font-weight: var(--h5FontWeight); + line-height: var(--h5LineHeight); + letter-spacing: var(--h5LetterSpacing); + text-transform: var(--h5TextTransform); +} + +h6 { + font-size: var(--h6FontSize); + font-weight: var(--h6FontWeight); + line-height: var(--h6LineHeight); + letter-spacing: var(--h6LetterSpacing); + text-transform: var(--h6TextTransform); +} diff --git a/assets/scss/components/main/_utilities.scss b/assets/scss/components/main/_utilities.scss new file mode 100644 index 0000000000..5b0275b73a --- /dev/null +++ b/assets/scss/components/main/_utilities.scss @@ -0,0 +1,30 @@ +.hidden-on-mobile { + display: none; +} +.hidden-on-tablet { + display: initial; +} +.show-on-desktop { + display: none; +} + +@mixin hidden-on-mobile--tablet() { + .hidden-on-mobile { + display: initial; + } +} +@mixin hidden-on-tablet--tablet() { + .hidden-on-tablet { + display: none; + } +} +@mixin hidden-on-tablet--laptop() { + .hidden-on-tablet { + display: initial; + } +} +@mixin show-on-desktop--laptop() { + .show-on-desktop { + display: initial; + } +} \ No newline at end of file diff --git a/assets/scss/components/main/_variables.scss b/assets/scss/components/main/_variables.scss new file mode 100644 index 0000000000..1333770e6f --- /dev/null +++ b/assets/scss/components/main/_variables.scss @@ -0,0 +1,39 @@ +$line-height: 1.68421 !default; +$h-font-weight: 700; + +// Font sizes. +$text-sm: .9em; +$text-lg: 1.25em; +$text-xl: 1.5em; + +// Spacing variables. +$spacing-xxs: 8px; +$spacing-xs: 10px; +$spacing-sm: 15px; +$spacing-md: 20px; +$spacing-lg: 30px; +$spacing-xl: 40px; +$spacing-xxl: 80px; +$spacing-aired: 60px; + + +$muted-white: #f0f0f0; +$muted-white-med: #c9c9c9; +$gray-color: #676767; //rgba(0,0,0,.54); + +$body-color: var(--nv-text-color); +$success: var(--nv-c-1); +$error: var(--nv-c-2); + +$muted-border: 1px solid var(--nv-light-bg); +$muted-border-med: 1px solid #c9c9c9; +$soft-box-shadow: rgba(149, 157, 165, 0.2) 0 8px 24px; + +$base-border: 2px solid var(--nv-text-color); +$base-border-strong: 4px solid var(--nv-text-color); + +$tablet-sm: "576px"; +$tablet: "769px"; +$laptop: "960px"; +$desktop: "1200px"; + diff --git a/assets/scss/customizer-preview.scss b/assets/scss/customizer-preview.scss index 02c9e5ae61..6cee8648e7 100644 --- a/assets/scss/customizer-preview.scss +++ b/assets/scss/customizer-preview.scss @@ -1,4 +1,17 @@ /* Customize Preview */ +.edit-row-action { + top: 0; + width: 26px; + height: 26px; + position: absolute; + right: 0; + background: #0073aa; + fill: #FFFFFF; + font-size: 0; + display: none; + cursor: pointer; +} + .customize-previewing { overflow-x: hidden; @@ -13,8 +26,6 @@ } .has-nav .builder-item-focus.item--inner { - position: unset; - .item--preview-name { top: unset; } @@ -25,6 +36,7 @@ position: relative; &.has_menu { + position: unset; .item--preview-name { left: auto; } @@ -32,13 +44,12 @@ } .item--preview-name { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif !important; position: absolute; top: 100%; left: 0; background: #0073aa; - color: #fff; - padding: 5px !important; + color: #fff !important; + padding: 5px !important; font-size: 12px !important; font-weight: 600 !important; line-height: 14px !important; @@ -48,18 +59,6 @@ display: none; } - .edit-row-action { - top: 0; - width: 26px; - position: absolute; - right: 0; - background: #0073aa; - fill: #FFFFFE; - font-size: 0; - display: none; - cursor: pointer; - } - &:hover { &.item--inner, &.row--wrapper { transition-delay: 0s !important; @@ -89,8 +88,16 @@ &:hover { &.item--inner { position: relative; - outline: 1px dashed #ff472e; - outline-offset: -1px; + + .item--preview-name { + top: unset; + bottom: 0; + left:0 !important; + + .dashicons { + color: #fff !important; + } + } } } } diff --git a/assets/scss/elements/_blog.scss b/assets/scss/elements/_blog.scss index 03a507b567..458a73508d 100644 --- a/assets/scss/elements/_blog.scss +++ b/assets/scss/elements/_blog.scss @@ -1,4 +1,3 @@ -@import 'blog/layout'; @import 'blog/blogpost-meta'; @import 'blog/blogpost-index'; @import 'blog/infinite-scroll'; diff --git a/assets/scss/elements/_content.scss b/assets/scss/elements/_content.scss index f62d7696fd..7e56acc194 100644 --- a/assets/scss/elements/_content.scss +++ b/assets/scss/elements/_content.scss @@ -1,3 +1,5 @@ +@import "../main/extends"; + .nv-iframe-embed { position: relative; padding-bottom: 56.25%; /* 16:9 */ diff --git a/assets/scss/elements/_footer.scss b/assets/scss/elements/_footer.scss deleted file mode 100644 index de42222c9d..0000000000 --- a/assets/scss/elements/_footer.scss +++ /dev/null @@ -1,13 +0,0 @@ -footer { - background-color: #fff; -} -// -//.footer-menu { -// display: flex; -// flex-wrap: wrap; -// justify-content: center; -// -// li:not(:last-child) { -// margin-right: $spacing-sm; -// } -//} diff --git a/assets/scss/elements/_hfg-alignments.scss b/assets/scss/elements/_hfg-alignments.scss index d50bad2960..46c708ff55 100644 --- a/assets/scss/elements/_hfg-alignments.scss +++ b/assets/scss/elements/_hfg-alignments.scss @@ -75,6 +75,7 @@ $component-alignments: ( $component-v-alignments: ( 'top' : flex-start, 'bottom': flex-end, + 'middle': center, ); @each $alignment, $align-self in $component-v-alignments { diff --git a/assets/scss/elements/_mega-menu.scss b/assets/scss/elements/_mega-menu.scss index 9c736fa071..a9d1f7d038 100644 --- a/assets/scss/elements/_mega-menu.scss +++ b/assets/scss/elements/_mega-menu.scss @@ -157,7 +157,7 @@ @mixin mega-menu--laptop() { .header--row .nv-nav-wrap .primary-menu-ul { > .neve-mega-menu { - position: static; + position: relative; } .neve-mega-menu > .sub-menu { @@ -192,8 +192,8 @@ .neve-mega-menu .neve-mm-col > .sub-menu { visibility: visible; position: relative; - left: initial; - right: initial; + left: initial !important; + right: initial !important; opacity: 1; box-shadow: none; display: flex; diff --git a/assets/scss/elements/blog/_blogpost-meta.scss b/assets/scss/elements/blog/_blogpost-meta.scss index 63e424d03f..d950dc7825 100644 --- a/assets/scss/elements/blog/_blogpost-meta.scss +++ b/assets/scss/elements/blog/_blogpost-meta.scss @@ -32,7 +32,7 @@ width: $spacing-sm; height: $spacing-sm; border-radius: 50%; - transform: translateY(30%); + vertical-align: middle; } .author-name { @@ -46,6 +46,6 @@ width: $spacing-sm; height: $spacing-sm; border-radius: 50%; - transform: translateY(30%); + vertical-align: middle; } } diff --git a/assets/scss/elements/blog/_comments.scss b/assets/scss/elements/blog/_comments.scss index 13625a4732..1173e2a078 100644 --- a/assets/scss/elements/blog/_comments.scss +++ b/assets/scss/elements/blog/_comments.scss @@ -99,10 +99,6 @@ float: right; } } - - input[type=submit] { - @extend %nv-button-secondary; - } } .comment-form { diff --git a/assets/scss/elements/blog/_layout.scss b/assets/scss/elements/blog/_layout.scss deleted file mode 100644 index f03f8e88f2..0000000000 --- a/assets/scss/elements/blog/_layout.scss +++ /dev/null @@ -1,3 +0,0 @@ -@mixin blog-layout--laptop() { - -} \ No newline at end of file diff --git a/assets/scss/elements/blog/_single.scss b/assets/scss/elements/blog/_single.scss index 4cb1ed45a3..0cf0148843 100644 --- a/assets/scss/elements/blog/_single.scss +++ b/assets/scss/elements/blog/_single.scss @@ -43,7 +43,7 @@ } } .nav-direction { - color: var(--nv-text-color); + color: var(--nv-text-color); display: flex; flex-direction: column; font-size: 0.8em; @@ -100,6 +100,3 @@ border: 1px solid var(--nv-primary-accent); } } - -@mixin single-post--laptop() { -} diff --git a/assets/scss/elements/form-elements/_inputs.scss b/assets/scss/elements/form-elements/_inputs.scss index 6f4947bc80..d4900e144e 100644 --- a/assets/scss/elements/form-elements/_inputs.scss +++ b/assets/scss/elements/form-elements/_inputs.scss @@ -41,8 +41,6 @@ select { input, textarea, select, button { line-height: inherit; - -webkit-box-sizing: border-box; /* For legacy WebKit based browsers */ - -moz-box-sizing: border-box; /* For legacy (Firefox <29) Gecko based browsers */ box-sizing: border-box; } diff --git a/assets/scss/elements/navigation/_nav-brand.scss b/assets/scss/elements/navigation/_nav-brand.scss index 226053658f..455ced117a 100644 --- a/assets/scss/elements/navigation/_nav-brand.scss +++ b/assets/scss/elements/navigation/_nav-brand.scss @@ -32,11 +32,9 @@ } a { - color: $body-color; display: inline; &:hover { - color: $body-color; text-decoration: none; opacity: .9; } diff --git a/assets/scss/gutenberg-editor-legacy-style.scss b/assets/scss/gutenberg-editor-legacy-style.scss new file mode 100644 index 0000000000..639610b076 --- /dev/null +++ b/assets/scss/gutenberg-editor-legacy-style.scss @@ -0,0 +1,29 @@ +.editor-styles-wrapper { + &, > * { + background-color: var(--nv-site-bg); + } + + .editor-post-title__input, .block-list-appender textarea { + &::placeholder { + color: var(--nv-text-color); + opacity: .5; + } + } + .block-list-appender textarea { + color: var(--nv-text-color); + } + @import "main/variables"; + @import "main/mixins"; + @import "gutenberg-editor/typography"; + @import "gutenberg-editor/formatting"; + @import "gutenberg-editor/layout"; + @import "gutenberg-editor/media-queries"; +} + +.neve-meta-button-group { + .components-button-group { + .components-button.is-primary:not(.import) { + z-index: inherit; + } + } +} \ No newline at end of file diff --git a/assets/scss/gutenberg-editor-style.scss b/assets/scss/gutenberg-editor-style.scss index 639610b076..21234e0d98 100644 --- a/assets/scss/gutenberg-editor-style.scss +++ b/assets/scss/gutenberg-editor-style.scss @@ -1,7 +1,10 @@ +@import "components/main/variables"; +@import "components/main/extends"; + .editor-styles-wrapper { - &, > * { - background-color: var(--nv-site-bg); - } + &, > * { + background-color: var(--nv-site-bg); + } .editor-post-title__input, .block-list-appender textarea { &::placeholder { @@ -9,21 +12,19 @@ opacity: .5; } } + .block-list-appender textarea { color: var(--nv-text-color); } - @import "main/variables"; - @import "main/mixins"; - @import "gutenberg-editor/typography"; - @import "gutenberg-editor/formatting"; - @import "gutenberg-editor/layout"; - @import "gutenberg-editor/media-queries"; + + @import "components/editor/typography"; + @import "components/editor/formatting"; } .neve-meta-button-group { .components-button-group { - .components-button.is-primary:not(.import) { - z-index: inherit; - } + .components-button.is-primary:not(.import) { + z-index: inherit; + } } -} \ No newline at end of file +} diff --git a/assets/scss/lifter-legacy.scss b/assets/scss/lifter-legacy.scss new file mode 100644 index 0000000000..41d677202e --- /dev/null +++ b/assets/scss/lifter-legacy.scss @@ -0,0 +1,118 @@ +.nv-content-wrap ul.llms-loop-list{ + padding: 0; +} + +.lms-container { + .nv-page-title-wrap, + .nv-sidebar-wrap { + margin-top: 30px; + } +} + +.llms-pagination { + margin: 10px auto; + ul { + text-align: center; + li{ + float: none; + display: inline; + .page-numbers{ + text-decoration: none; + margin: 10px auto; + display: inline-block; + } + } + } +} + +.llms-loop-link{ + &:hover{ + text-decoration: none; + } +} + +#neve_body .nv-content-wrap { + a{ + &.llms-button-primary, &.llms-sd-link, &.llms-loop-link, &.llms-button-secondary{ + text-decoration: none; + } } +} + +.llms-button-primary, .llms-button-action{ + font-size: .8em; + font-weight: 600; + padding: 8px 12px; + transition: all .15s ease-in-out; + text-align: center; + vertical-align: middle; + border: 1px solid transparent; + border-radius: 3px; + text-transform: uppercase; + cursor: pointer; + line-height: 1.68421; + font-family: inherit; + background-color: #0366d6; + color: #fff; + &:hover{ + text-decoration: none; + background-color: #0366d6; + color: #fff; + opacity: .9; + } +} + +.llms-button-secondary{ + border-radius: 3px; + border: 1px solid #676767; + background-color: transparent; + font-weight: 600; + color: #676767; + &:hover{ + background: transparent; + } +} + +.llms-loop-item-footer { + .avatar, .llms-author-info { + vertical-align: middle; + } +} + +footer.llms-loop-item-footer { + background-color: inherit; +} + +.llms-choice > label { + width: 100%; +} + +.single-course { + .review_box { + input[type="text"], textarea { + display: block; + margin: 10px 0; + width: 100%; + } + + textarea { + height: 200px; + } + } + .llms-lesson-counter { + display: inline-block; + margin-bottom: 0px; + } +} + +.llms-person-login-form-wrapper { + max-width: 100%; +} + +.llms-course-nav .llms-lesson-preview{ + width: 100%; + .llms-main{ + .llms-pre-text, .llms-lesson-title{ + text-align: center; + } + } +} diff --git a/assets/scss/lifter.scss b/assets/scss/lifter.scss index 41d677202e..748e3627de 100644 --- a/assets/scss/lifter.scss +++ b/assets/scss/lifter.scss @@ -1,118 +1,75 @@ -.nv-content-wrap ul.llms-loop-list{ - padding: 0; +@import "./components/main/extends"; + +.llms-loop-list { + padding: 0!important; } -.lms-container { - .nv-page-title-wrap, - .nv-sidebar-wrap { - margin-top: 30px; - } +.llms-sd-section-footer{ + margin-bottom: 25px; } .llms-pagination { margin: 10px auto; - ul { - text-align: center; - li{ - float: none; - display: inline; - .page-numbers{ - text-decoration: none; - margin: 10px auto; - display: inline-block; - } - } + ul{ + list-style-type: none; + padding: 0; + li .page-numbers { + text-decoration: none; + display: inline-block; + padding: 12px 15px; + } } } -.llms-loop-link{ - &:hover{ - text-decoration: none; - } -} - -#neve_body .nv-content-wrap { - a{ - &.llms-button-primary, &.llms-sd-link, &.llms-loop-link, &.llms-button-secondary{ - text-decoration: none; - } } -} - -.llms-button-primary, .llms-button-action{ - font-size: .8em; - font-weight: 600; - padding: 8px 12px; - transition: all .15s ease-in-out; - text-align: center; - vertical-align: middle; - border: 1px solid transparent; - border-radius: 3px; - text-transform: uppercase; - cursor: pointer; - line-height: 1.68421; - font-family: inherit; - background-color: #0366d6; - color: #fff; - &:hover{ - text-decoration: none; - background-color: #0366d6; - color: #fff; - opacity: .9; +.llms-button-primary, .llms-button-action { + display: inline-block; + @extend %nv-button-primary; + &:hover { + @extend %nv-button-primary-hover; } } -.llms-button-secondary{ - border-radius: 3px; - border: 1px solid #676767; - background-color: transparent; - font-weight: 600; - color: #676767; - &:hover{ - background: transparent; +.llms-button-secondary { + display: inline-block; + @extend %nv-button-secondary; + &:hover { + @extend %nv-button-secondary-hover; } } .llms-loop-item-footer { .avatar, .llms-author-info { - vertical-align: middle; + vertical-align: middle; } } -footer.llms-loop-item-footer { - background-color: inherit; -} - .llms-choice > label { width: 100%; } .single-course { .review_box { - input[type="text"], textarea { - display: block; - margin: 10px 0; - width: 100%; - } + background-color: var(--nv-light-bg); + padding: 40px; - textarea { - height: 200px; - } + input:read-write, textarea { + max-width: 100%; + width: 100%; + display: block; + @extend %nv-form-fields; + } + + textarea { + height: 200px; + } } + .llms-lesson-counter { - display: inline-block; - margin-bottom: 0px; + display: inline-block; + margin-bottom: 0; } } -.llms-person-login-form-wrapper { - max-width: 100%; -} - -.llms-course-nav .llms-lesson-preview{ +.llms-course-nav .llms-lesson-preview { width: 100%; - .llms-main{ - .llms-pre-text, .llms-lesson-title{ - text-align: center; - } - } } diff --git a/assets/scss/main/_a11y.scss b/assets/scss/main/_a11y.scss index 4350dbdc7b..8e826ef365 100644 --- a/assets/scss/main/_a11y.scss +++ b/assets/scss/main/_a11y.scss @@ -18,7 +18,6 @@ a.neve-skip-link { padding: $spacing-xs $spacing-sm; - top: 32px; } diff --git a/assets/scss/main/_media-queries.scss b/assets/scss/main/_media-queries.scss index ad515c735d..8d7c9a2968 100644 --- a/assets/scss/main/_media-queries.scss +++ b/assets/scss/main/_media-queries.scss @@ -11,8 +11,6 @@ @include typography--tablet(); @include gutenberg--tablet(); @include comments--tablet(); - @include hidden-on-mobile--tablet(); - @include hidden-on-tablet--tablet(); } @media (min-width: #{$laptop}) { @@ -22,12 +20,8 @@ @include nav-search--laptop(); @include blog-layout-default-alt--laptop(); @include blogpost-index--laptop(); - @include single-post--laptop(); @include page--laptop(); @include sidebar--laptop(); - @include blog-layout--laptop(); - @include hidden-on-tablet--laptop(); - @include show-on-desktop--laptop(); @include hfg-alignments--laptop(); } diff --git a/assets/scss/mega-menu-legacy.scss b/assets/scss/mega-menu-legacy.scss new file mode 100644 index 0000000000..bccd534983 --- /dev/null +++ b/assets/scss/mega-menu-legacy.scss @@ -0,0 +1,14 @@ +@import "./main/variables"; +@import "./elements/mega-menu"; + +@media (min-width: #{$tablet-sm}) { + @include mega-menu--tablet(); +} + +@media (min-width: #{$laptop}) { + @include mega-menu--laptop(); +} + +@media (min-width: #{$desktop}) { + @include mega-menu--desktop(); +} diff --git a/assets/scss/mega-menu.scss b/assets/scss/mega-menu.scss index bccd534983..4d95d973c8 100644 --- a/assets/scss/mega-menu.scss +++ b/assets/scss/mega-menu.scss @@ -1,5 +1,5 @@ -@import "./main/variables"; -@import "./elements/mega-menu"; +@import "./components/main/variables"; +@import "./components/elements/mega-menu"; @media (min-width: #{$tablet-sm}) { @include mega-menu--tablet(); @@ -8,7 +8,3 @@ @media (min-width: #{$laptop}) { @include mega-menu--laptop(); } - -@media (min-width: #{$desktop}) { - @include mega-menu--desktop(); -} diff --git a/assets/scss/style-legacy.scss b/assets/scss/style-legacy.scss new file mode 100644 index 0000000000..32246fc795 --- /dev/null +++ b/assets/scss/style-legacy.scss @@ -0,0 +1,26 @@ +@charset "UTF-8"; +@import "main/variables"; +@import "main/mixins"; +@import "main/extends"; +@import "main/reset"; + +@import "main/grid"; +@import "main/typography"; +@import "main/a11y"; +@import "main/neve-icons"; +@import "main/gutenberg"; + +@import "elements/navigation"; +@import "elements/page"; +@import "elements/form-elements"; +@import "elements/blog"; +@import "elements/content"; +@import "elements/gallery"; +@import "elements/sidebar"; +@import "elements/breadcrumbs"; +@import "elements/hfg-alignments"; + +@import "main/media-queries"; +@import "compat/elementor"; + +@import "../../header-footer-grid/assets/scss/style"; diff --git a/assets/scss/style.scss b/assets/scss/style.scss index 248cfe1187..60268db19d 100644 --- a/assets/scss/style.scss +++ b/assets/scss/style.scss @@ -1,28 +1,24 @@ @charset "UTF-8"; -@import "main/variables"; -@import "main/mixins"; -@import "main/extends"; -@import "main/reset"; +@import "components/main/variables"; +@import "components/main/extends"; +@import "components/main/reset"; -@import "main/grid"; -@import "main/typography"; -@import "main/a11y"; -@import "main/neve-icons"; -@import "main/gutenberg"; -@import "main/utilities"; +@import "components/main/grid"; +@import "components/main/typography"; +@import "components/main/a11y"; +@import "components/main/neve-icons"; +@import "components/main/gutenberg"; +@import "components/main/global-colors"; +@import "components/elements/navigation"; +@import "components/elements/page"; +@import "components/elements/form-elements"; +@import "components/elements/blog"; +@import "components/elements/content"; +@import "components/elements/gallery"; +@import "components/elements/sidebar"; +@import "components/elements/breadcrumbs"; +@import "components/elements/hfg-alignments"; +@import "components/main/media-queries"; +@import "components/compat/elementor"; -@import "elements/navigation"; -@import "elements/footer"; -@import "elements/page"; -@import "elements/form-elements"; -@import "elements/blog"; -@import "elements/content"; -@import "elements/gallery"; -@import "elements/sidebar"; -@import "elements/breadcrumbs"; -@import "elements/hfg-alignments"; - -@import "main/media-queries"; -@import "compat/elementor"; - -@import "../../header-footer-grid/assets/scss/style"; +@import "./components/hfg/style"; diff --git a/assets/scss/woocommerce-legacy.scss b/assets/scss/woocommerce-legacy.scss new file mode 100644 index 0000000000..dea1cb1d47 --- /dev/null +++ b/assets/scss/woocommerce-legacy.scss @@ -0,0 +1,15 @@ +@import "main/variables"; +@import "main/mixins"; +@import "woocommerce/extends"; +@import "woocommerce/generic"; +@import "woocommerce/shop-loop"; +@import "woocommerce/product"; +@import "woocommerce/checkout"; +@import "woocommerce/buttons"; +@import "woocommerce/sidebar"; +@import "woocommerce/widgets"; +@import "woocommerce/nav-cart"; +@import "woocommerce/cart"; +@import "woocommerce/account"; +@import "woocommerce/media-queries"; +@import "woocommerce/breadcrumbs"; diff --git a/assets/scss/woocommerce.scss b/assets/scss/woocommerce.scss index dea1cb1d47..9b689e154d 100644 --- a/assets/scss/woocommerce.scss +++ b/assets/scss/woocommerce.scss @@ -1,15 +1,16 @@ -@import "main/variables"; -@import "main/mixins"; -@import "woocommerce/extends"; -@import "woocommerce/generic"; -@import "woocommerce/shop-loop"; -@import "woocommerce/product"; -@import "woocommerce/checkout"; -@import "woocommerce/buttons"; -@import "woocommerce/sidebar"; -@import "woocommerce/widgets"; -@import "woocommerce/nav-cart"; -@import "woocommerce/cart"; -@import "woocommerce/account"; -@import "woocommerce/media-queries"; -@import "woocommerce/breadcrumbs"; +@import "components/main/variables"; +@import "components/main/extends"; +@import "components/compat/woocommerce/generic"; +@import "components/compat/woocommerce/notices"; +@import "components/compat/woocommerce/shop-loop"; +@import "components/compat/woocommerce/buttons"; +@import "components/compat/woocommerce/product"; +@import "components/compat/woocommerce/cart"; +@import "components/compat/woocommerce/checkout"; +@import "components/compat/woocommerce/sidebar"; +@import "components/compat/woocommerce/widgets"; +@import "components/compat/woocommerce/nav-cart"; +@import "components/compat/woocommerce/account"; +@import "components/compat/woocommerce/media-queries"; +@import "components/compat/woocommerce/breadcrumbs"; +@import "components/compat/woocommerce/blocks"; diff --git a/bin/envs/amp/start.sh b/bin/envs/amp/start.sh index f23f6c84e5..9a8dc118fa 100755 --- a/bin/envs/amp/start.sh +++ b/bin/envs/amp/start.sh @@ -1,6 +1,6 @@ -wp --allow-root plugin is-installed amp && wp --allow-root plugin update amp || wp --allow-root plugin install amp -wp --allow-root plugin activate amp +wp --allow-root plugin install amp --activate wp menu create sample-menu --allow-root wp menu location assign sample-menu primary --allow-root wp menu item add-post sample-menu 1 --title="Parent menu" --allow-root wp menu item add-post sample-menu 1 --title="Submenu Item" --allow-root --parent-id="$(wp menu item list sample-menu --allow-root --format=ids)" +wp --allow-root rewrite structure /%postname%/ \ No newline at end of file diff --git a/bin/envs/cli-setup.sh b/bin/envs/cli-setup.sh index cb8dfe13d3..d0ec66a12f 100755 --- a/bin/envs/cli-setup.sh +++ b/bin/envs/cli-setup.sh @@ -3,22 +3,27 @@ set -e NEVE_LOCATION=$1 WP_VERSION=$2 WP_ENV=$3 -WP_CACHED_ENV="/var/www/html/wp-content/${WP_ENV}.sql" +WP_CACHED_ENV="${WP_SITE_PATH}wp-content/${WP_ENV}.sql" SKIP_CACHE=$4 +export NEVE_REPO_PATH=${NEVE_REPO_PATH:=/tmp/repo/neve} +SITE_URL="${CYPRESS_BASE_URL:=http://localhost:8080}" + init_environment(){ #Setup core wp --allow-root core update --version=$WP_VERSION wp --allow-root core update-db - rm -rf /var/www/html/wp-content/themes/* - chmod 0777 -R /var/www/html/wp-content/ + + if [ $NEVE_LOCATION != "neve" ]; then + rm -rf /var/www/html/wp-content/themes/* + chmod 0777 -R /var/www/html/wp-content/ + fi echo "Installing Neve theme from $NEVE_LOCATION" wp --allow-root theme install --activate $NEVE_LOCATION wp --allow-root option update fresh_site 0 echo "Installing Theme API Plugin" wp --allow-root plugin install https://github.com/Codeinwp/wp-thememods-api/archive/main.zip --force --activate - echo "Installing JWT Auth Plugin" - wp --allow-root plugin install api-bearer-auth --force --activate + wp --allow-root plugin install https://gist.github.com/selul/2f5f76d423f9d44f7b5a927e17001c28/archive/ffe3a56894c9aed005e69268ad50dfb16b8177fb.zip --force --activate } @@ -32,14 +37,19 @@ if [ -f $WP_CACHED_ENV ] && [ $SKIP_CACHE == "no" ]; then exit 0; fi -wp --allow-root core install --url=http://localhost:8080 --title=SandboxSite --admin_user=admin --admin_password=admin --admin_email=admin@admin.com -mkdir -p /var/www/html/wp-content/uploads -rm -rf /var/www/html/wp-content/plugins/akismet +if ! wp core is-installed --allow-root; then + wp --allow-root core install --url="$SITE_URL" --title=SandboxSite --admin_user=admin --admin_password=admin --admin_email=admin@admin.com + mkdir -p /var/www/html/wp-content/uploads + rm -rf /var/www/html/wp-content/plugins/akismet +fi -init_environment +WP_SITE_PATH=$(wp eval 'echo ABSPATH;' --allow-root); + + +init_environment -bash /var/www/html/bin/envs/$WP_ENV/start.sh +bash ${NEVE_REPO_PATH}/bin/envs/$WP_ENV/start.sh wp --allow-root cache flush diff --git a/bin/envs/default/start.sh b/bin/envs/default/start.sh index 6f2317afd3..9d68294043 100755 --- a/bin/envs/default/start.sh +++ b/bin/envs/default/start.sh @@ -1,3 +1,3 @@ #Generic setup -wp --allow-root media import /tmp/repo/neve/e2e-tests/cypress/fixtures/image.jpg -wp --allow-root rewrite structure /%postname%/ \ No newline at end of file +wp --allow-root media import ${NEVE_REPO_PATH}/e2e-tests/cypress/fixtures/image.jpg +wp --allow-root rewrite structure /%postname%/ diff --git a/bin/envs/down.sh b/bin/envs/down.sh new file mode 100755 index 0000000000..2bd14f6524 --- /dev/null +++ b/bin/envs/down.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +export DOCKER_FILE=docker-compose.ci.yml +docker-compose -f $DOCKER_FILE down +docker volume prune --force diff --git a/bin/envs/local.sh b/bin/envs/local.sh new file mode 100755 index 0000000000..c97255c726 --- /dev/null +++ b/bin/envs/local.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +ENV="${1:-default}" +NEVE_REPO_PATH=$(pwd) bash $(pwd)/bin/envs/cli-setup.sh neve latest $ENV yes diff --git a/bin/envs/theme-check/start.sh b/bin/envs/theme-check/start.sh index 317886eb64..9ca40f5f88 100755 --- a/bin/envs/theme-check/start.sh +++ b/bin/envs/theme-check/start.sh @@ -1,3 +1,3 @@ -php -d memory_limit=1024M "$(which wp)" package install anhskohbo/wp-cli-themecheck --allow-root +php -d memory_limit=1024M "$(which wp)" package install anhskohbo/wp-cli-themecheck:dev-master#a53732bf056ee446a4b975d20914d0469e16ea59 --allow-root wp plugin install theme-check --activate --allow-root wp themecheck --theme=neve --no-interactive --allow-root diff --git a/bin/envs/useful-plugins/start.sh b/bin/envs/useful-plugins/start.sh old mode 100644 new mode 100755 index e2640b2183..992a5b0443 --- a/bin/envs/useful-plugins/start.sh +++ b/bin/envs/useful-plugins/start.sh @@ -1,2 +1,2 @@ -wp --allow-root plugin install feedzy-rss-feeds +wp --allow-root plugin install templates-patterns-collection wp --allow-root plugin install weglot --activate \ No newline at end of file diff --git a/bin/envs/woo-sample/start.sh b/bin/envs/woo-sample/start.sh old mode 100644 new mode 100755 diff --git a/comments.php b/comments.php index 740d1b9948..f3b4e54a40 100644 --- a/comments.php +++ b/comments.php @@ -14,6 +14,6 @@ ?> -
+
diff --git a/composer.json b/composer.json index c3caa33bd7..8fec1395a1 100644 --- a/composer.json +++ b/composer.json @@ -28,9 +28,9 @@ ] }, "scripts": { - "format": "phpcbf --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 5.5- ", - "format-fix-exit": "\"vendor/bin/phpcbf-fix-exit-0\" --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 5.5- ", - "phpcs": "phpcs --standard=phpcs.xml -s --runtime-set testVersion 5.5-", + "format": "phpcbf --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 7.0- ", + "format-fix-exit": "\"vendor/bin/phpcbf-fix-exit-0\" --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 7.0- ", + "phpcs": "phpcs --standard=phpcs.xml -s --runtime-set testVersion 7.0-", "lint": "composer run-script phpcs", "phpcs-i": "phpcs -i", "post-install-cmd": [ @@ -46,7 +46,7 @@ "optimize-autoloader": true, "platform-check": false, "platform": { - "php": "5.6" + "php": "7.0" } }, "extra": { diff --git a/composer.lock b/composer.lock index 24e5c9968c..29753241ae 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3cb0f4a5f954b79227468bc5b2f9dfdc", + "content-hash": "74fbabd2bc19d84d6b2675d911b07957", "packages": [ { "name": "codeinwp/themeisle-sdk", - "version": "3.2.19", + "version": "3.2.21", "source": { "type": "git", "url": "https://github.com/Codeinwp/themeisle-sdk.git", - "reference": "abb31e2382fd8c40bcc18d7c9f3501d14bf48e87" + "reference": "cafd016b61ec0928c0234e312046782a77c14318" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/abb31e2382fd8c40bcc18d7c9f3501d14bf48e87", - "reference": "abb31e2382fd8c40bcc18d7c9f3501d14bf48e87", + "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/cafd016b61ec0928c0234e312046782a77c14318", + "reference": "cafd016b61ec0928c0234e312046782a77c14318", "shasum": "" }, "require-dev": { @@ -42,9 +42,9 @@ ], "support": { "issues": "https://github.com/Codeinwp/themeisle-sdk/issues", - "source": "https://github.com/Codeinwp/themeisle-sdk/tree/v3.2.19" + "source": "https://github.com/Codeinwp/themeisle-sdk/tree/v3.2.21" }, - "time": "2021-03-12T08:54:44+00:00" + "time": "2021-06-30T10:55:18+00:00" }, { "name": "wptt/webfont-loader", @@ -95,32 +95,32 @@ "packages-dev": [ { "name": "automattic/vipwpcs", - "version": "2.2.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/Automattic/VIP-Coding-Standards.git", - "reference": "4d0612461232b313d06321f1501c3989bd6aecf9" + "reference": "efacebef421334d54b99afa92fb8fa645336a8a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/VIP-Coding-Standards/zipball/4d0612461232b313d06321f1501c3989bd6aecf9", - "reference": "4d0612461232b313d06321f1501c3989bd6aecf9", + "url": "https://api.github.com/repos/Automattic/VIP-Coding-Standards/zipball/efacebef421334d54b99afa92fb8fa645336a8a7", + "reference": "efacebef421334d54b99afa92fb8fa645336a8a7", "shasum": "" }, "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7", "php": ">=5.4", "sirbrillig/phpcs-variable-analysis": "^2.8.3", "squizlabs/php_codesniffer": "^3.5.5", "wp-coding-standards/wpcs": "^2.3" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "php-parallel-lint/php-console-highlighter": "^0.5", + "php-parallel-lint/php-parallel-lint": "^1.0", "phpcompatibility/php-compatibility": "^9", + "phpcsstandards/phpcsdevtools": "^1.0", "phpunit/phpunit": "^4 || ^5 || ^6 || ^7" }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will manage the PHPCS 'installed_paths' automatically." - }, "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", "license": [ @@ -143,7 +143,7 @@ "source": "https://github.com/Automattic/VIP-Coding-Standards", "wiki": "https://github.com/Automattic/VIP-Coding-Standards/wiki" }, - "time": "2020-09-07T10:45:45+00:00" + "time": "2021-04-28T16:41:50+00:00" }, { "name": "codeinwp/phpcs-ruleset", @@ -151,12 +151,12 @@ "source": { "type": "git", "url": "https://github.com/Codeinwp/phpcs-ruleset.git", - "reference": "e250f9e0221b0bd39122f761de00bc3cfb19fd1f" + "reference": "982f9881312252e6213cde07704b74da47b39475" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeinwp/phpcs-ruleset/zipball/e250f9e0221b0bd39122f761de00bc3cfb19fd1f", - "reference": "e250f9e0221b0bd39122f761de00bc3cfb19fd1f", + "url": "https://api.github.com/repos/Codeinwp/phpcs-ruleset/zipball/982f9881312252e6213cde07704b74da47b39475", + "reference": "982f9881312252e6213cde07704b74da47b39475", "shasum": "" }, "require": { @@ -176,10 +176,9 @@ ], "description": "PHPCS coding standards for Themeisle products.", "support": { - "issues": "https://github.com/Codeinwp/phpcs-ruleset/issues", "source": "https://github.com/Codeinwp/phpcs-ruleset/tree/main" }, - "time": "2021-03-05T12:12:04+00:00" + "time": "2021-05-05T16:55:27+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", @@ -425,16 +424,16 @@ }, { "name": "sirbrillig/phpcs-variable-analysis", - "version": "v2.10.2", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", - "reference": "0775e0c683badad52c03b11c2cd86a9fdecb937a" + "reference": "9df9ade5961a3505d0d24b0e6be2ab82e335f753" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/0775e0c683badad52c03b11c2cd86a9fdecb937a", - "reference": "0775e0c683badad52c03b11c2cd86a9fdecb937a", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/9df9ade5961a3505d0d24b0e6be2ab82e335f753", + "reference": "9df9ade5961a3505d0d24b0e6be2ab82e335f753", "shasum": "" }, "require": { @@ -474,20 +473,20 @@ "source": "https://github.com/sirbrillig/phpcs-variable-analysis", "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" }, - "time": "2021-01-08T16:31:05+00:00" + "time": "2021-06-18T20:54:59+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.8", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", "shasum": "" }, "require": { @@ -530,7 +529,7 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2020-10-23T02:01:07+00:00" + "time": "2021-04-09T00:54:41+00:00" }, { "name": "wp-coding-standards/wpcs", @@ -668,7 +667,7 @@ "platform": [], "platform-dev": [], "platform-overrides": { - "php": "5.6" + "php": "7.0" }, "plugin-api-version": "2.0.0" } diff --git a/dashboard/inc/Main.php b/dashboard/inc/Main.php index 3147c496f4..c7f0a3ef45 100755 --- a/dashboard/inc/Main.php +++ b/dashboard/inc/Main.php @@ -39,11 +39,10 @@ class Main { */ private $useful_plugins = [ 'optimole-wp', + 'wp-cloudflare-page-cache', 'templates-patterns-collection', 'themeisle-companion', - 'feedzy-rss-feeds', 'otter-blocks', - 'elementor', 'weglot', 'visualizer', 'wpforms-lite', diff --git a/dashboard/src/Components/ModuleCard.js b/dashboard/src/Components/ModuleCard.js index 6e43c7ccf5..abf6f79a73 100644 --- a/dashboard/src/Components/ModuleCard.js +++ b/dashboard/src/Components/ModuleCard.js @@ -50,6 +50,7 @@ const ModuleCard = ({ label: labelGroup, type, placeholder, + documentation: documentationOption, choices, } = optionGroup[optionSlug]; return ( @@ -65,6 +66,9 @@ const ModuleCard = ({ )} {'select' === type && ( diff --git a/dashboard/src/Components/Options/Select.js b/dashboard/src/Components/Options/Select.js index 8d605e3026..3a07006af6 100644 --- a/dashboard/src/Components/Options/Select.js +++ b/dashboard/src/Components/Options/Select.js @@ -14,6 +14,7 @@ const Select = ({ return (
{ diff --git a/dashboard/src/Components/Options/Toggle.js b/dashboard/src/Components/Options/Toggle.js index 81b7b3c9d1..2406702295 100644 --- a/dashboard/src/Components/Options/Toggle.js +++ b/dashboard/src/Components/Options/Toggle.js @@ -1,11 +1,19 @@ +/* global neveDash */ import { changeOption as changeSetting } from '../../utils/rest'; -import { ToggleControl, Dashicon } from '@wordpress/components'; +import { ToggleControl, Dashicon, ExternalLink } from '@wordpress/components'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; import { useState } from '@wordpress/element'; -const Toggle = ({ slug, label, getOption, changeOption, setToast }) => { +const Toggle = ({ + slug, + label, + documentation, + getOption, + changeOption, + setToast, +}) => { const [loading, setLoading] = useState(false); return (
@@ -26,6 +34,12 @@ const Toggle = ({ slug, label, getOption, changeOption, setToast }) => { }); }} /> + . {' '} + {!neveDash.whiteLabel && documentation && documentation.url && ( + + {documentation.label} + + )} {loading && ( )} diff --git a/e2e-tests/.eslintrc.json b/e2e-tests/.eslintrc.json index dd287230d5..a9e93a3f4c 100644 --- a/e2e-tests/.eslintrc.json +++ b/e2e-tests/.eslintrc.json @@ -1,4 +1,5 @@ { + "root": true, "extends": [ "plugin:cypress/recommended", "plugin:chai-friendly/recommended", diff --git a/e2e-tests/README.md b/e2e-tests/README.md new file mode 100644 index 0000000000..1e456acfce --- /dev/null +++ b/e2e-tests/README.md @@ -0,0 +1,10 @@ +### How to run cypress tests locally + +* Firs you will need to setup the environment on your local machine and have wp-cli installed. Assuming that your local url is http://neve.test you can `CYPRESS_BASE_URL=http://neve.test bash bin/envs/local.sh` or if you want to install a specific environment you can use `CYPRESS_BASE_URL=http://neve.test bash bin/envs/local.sh amp` where amp is the environment inside `bin/envs/amp` + +* Than you can move to e2e-tests folder and run `yarn install --frozen-lockfile` to install the dependencies. +* After this you will have to open cypress with the proper base url, as `CYPRESS_BASE_URL=http://neve.test npm run cypress:open` and run the spec that you want. + + + + diff --git a/e2e-tests/cypress/fixtures/amp/amp-setup.json b/e2e-tests/cypress/fixtures/amp/amp-setup.json index ab7df9b098..3d8d58ce27 100644 --- a/e2e-tests/cypress/fixtures/amp/amp-setup.json +++ b/e2e-tests/cypress/fixtures/amp/amp-setup.json @@ -1,3 +1,13 @@ { - "hfg_header_layout": "{\"desktop\":{\"top\":[{\"x\":11,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_search_responsive\"}],\"main\":[{\"x\":0,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":4,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}" -} \ No newline at end of file + "neve_ran_builder_migration": true, + "neve_migrated_builders": true, + "neve_migrated_hfg_colors": true, + "nav_menu_locations": { + "primary": 2, + "footer": 0, + "top-bar": 0 + }, + "custom_css_post_id": -1, + "hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"header_search\"}]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}", + "header_search_placeholder": "Upper Search" +} diff --git a/e2e-tests/cypress/fixtures/customizer/hfg/alignment-control-setup.json b/e2e-tests/cypress/fixtures/customizer/hfg/alignment-control-setup.json index d1622c90dd..3b5488eda2 100644 --- a/e2e-tests/cypress/fixtures/customizer/hfg/alignment-control-setup.json +++ b/e2e-tests/cypress/fixtures/customizer/hfg/alignment-control-setup.json @@ -1,5 +1,9 @@ { "center": { + "neve_ran_builder_migration": true, + "neve_migrated_builders": true, + "neve_migrated_hfg_colors": true, + "hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}", "logo_component_align": { "mobile": "left", "tablet": "left", @@ -7,10 +11,14 @@ } }, "right": { - "logo_component_align": { - "mobile": "left", - "tablet": "left", - "desktop": "right" - } + "neve_ran_builder_migration": true, + "neve_migrated_builders": true, + "neve_migrated_hfg_colors": true, + "hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}", + "logo_component_align": { + "mobile": "left", + "tablet": "left", + "desktop": "right" + } } } diff --git a/e2e-tests/cypress/fixtures/customizer/hfg/hfg-palette-switch-component.json b/e2e-tests/cypress/fixtures/customizer/hfg/hfg-palette-switch-component.json new file mode 100644 index 0000000000..9a911c0461 --- /dev/null +++ b/e2e-tests/cypress/fixtures/customizer/hfg/hfg-palette-switch-component.json @@ -0,0 +1,14 @@ +{ + "neve_ran_builder_migration": true, + "neve_migrated_builders": true, + "neve_ran_migrations": true, + "neve_had_old_skin": true, + "neve_migrated_hfg_colors": true, + "nav_menu_locations": { + "primary": 176 + }, + "header_palette_switch_icon_size": "{\"mobile\":16,\"tablet\":16,\"desktop\":44}", + "hfg_header_layout": "{\"desktop\":{\"top\":[{\"x\":7,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_palette_switch\"}],\"main\":[{\"x\":0,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":4,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}", + "hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"header_palette_switch\"}],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}", + "neve_new_skin": "new" +} diff --git a/e2e-tests/cypress/fixtures/customizer/hfg/padding-control.json b/e2e-tests/cypress/fixtures/customizer/hfg/padding-control.json index 5e10dddf98..44f6dae39a 100644 --- a/e2e-tests/cypress/fixtures/customizer/hfg/padding-control.json +++ b/e2e-tests/cypress/fixtures/customizer/hfg/padding-control.json @@ -21,5 +21,6 @@ "mobile-unit": "px", "tablet-unit": "px", "desktop-unit": "px" - } + }, + "neve_ran_migrations": true } diff --git a/e2e-tests/cypress/fixtures/customizer/hfg/row-background-setup.json b/e2e-tests/cypress/fixtures/customizer/hfg/row-background-setup.json index 4a5cb18b31..ee9f417344 100644 --- a/e2e-tests/cypress/fixtures/customizer/hfg/row-background-setup.json +++ b/e2e-tests/cypress/fixtures/customizer/hfg/row-background-setup.json @@ -1,15 +1,16 @@ { - "hfg_header_layout_main_background": { - "type": "image", - "imageUrl": "http://localhost:8080/wp-content/uploads/2021/01/image.png", - "focusPoint": { - "x": 0.5, - "y": 0.5 - }, - "colorValue": "var(--nv-site-bg)", - "overlayColorValue": "", - "overlayOpacity": 50, - "fixed": true, + "hfg_header_layout_main_background": { + "type": "image", + "imageUrl": "https://via.placeholder.com/1500x100", + "focusPoint": { + "x": 0.5, + "y": 0.5 + }, + "colorValue": "var(--nv-site-bg)", + "overlayColorValue": "", + "overlayOpacity": 50, + "fixed": true, "useFeatured": true - } + }, + "neve_ran_migrations": true } diff --git a/e2e-tests/cypress/fixtures/customizer/layout/sidebar-settings.json b/e2e-tests/cypress/fixtures/customizer/layout/sidebar-settings.json index 296da891b6..8d492e7d5a 100644 --- a/e2e-tests/cypress/fixtures/customizer/layout/sidebar-settings.json +++ b/e2e-tests/cypress/fixtures/customizer/layout/sidebar-settings.json @@ -13,7 +13,8 @@ "neve_other_pages_sidebar_layout": "left", "neve_blog_archive_content_width": 20, "neve_single_post_content_width": 70, - "neve_other_pages_content_width": 70 + "neve_other_pages_content_width": 70, + "neve_new_skin": "new" }, "site_wide": { "custom_css_post_id": -1, @@ -22,6 +23,7 @@ }, "neve_migrated_hfg_colors": true, "neve_default_sidebar_layout": "left", - "neve_sitewide_content_width": 50 + "neve_sitewide_content_width": 50, + "neve_new_skin": "new" } } diff --git a/e2e-tests/cypress/fixtures/customizer/layout/single-post-settings.json b/e2e-tests/cypress/fixtures/customizer/layout/single-post-settings.json index 6980f95172..23bea867c0 100644 --- a/e2e-tests/cypress/fixtures/customizer/layout/single-post-settings.json +++ b/e2e-tests/cypress/fixtures/customizer/layout/single-post-settings.json @@ -1,6 +1,60 @@ { - "hidden": { "neve_layout_single_post_elements_order": "[]" }, + "hidden": { "neve_layout_single_post_elements_order": "[]", "neve_new_skin": "new" }, "enabled": { "neve_layout_single_post_elements_order": "[\"post-navigation\",\"tags\",\"content\",\"comments\",\"title-meta\",\"thumbnail\"]" + }, + "cover": { + "neve_ran_builder_migration": true, + "neve_migrated_builders": true, + "neve_migrated_hfg_colors": true, + "nav_menu_locations": { + "primary": 176 + }, + "ti_prev_theme": "twentytwentyone", + "custom_css_post_id": -1, + "neve_post_header_layout": "cover", + "neve_post_cover_height": "{\"mobile\":400,\"tablet\":400,\"desktop\":505}", + "neve_post_cover_padding": { + "mobile": { + "top": 40, + "right": 15, + "bottom": 40, + "left": 15 + }, + "tablet": { + "top": 60, + "right": 15, + "bottom": 60, + "left": 15 + }, + "desktop": { + "top": 60, + "right": 15, + "bottom": 60, + "left": 15 + }, + "mobile-unit": "px", + "tablet-unit": "px", + "desktop-unit": "px" + }, + "neve_layout_single_post_elements_order": "[\"content\",\"tags\",\"comments\"]", + "neve_post_title_position": { + "mobile": "bottom", + "tablet": "bottom", + "desktop": "middle" + }, + "neve_post_title_alignment": { + "mobile": "left", + "tablet": "left", + "desktop": "center" + }, + "neve_post_cover_meta_before_title": false, + "neve_post_cover_background_color": "#c63535", + "neve_post_cover_text_color": "#ffffff", + "neve_post_cover_overlay_opacity": "{\"mobile\":0.5,\"tablet\":0.5,\"desktop\":0.6}", + "neve_post_cover_hide_thumbnail": false, + "neve_post_cover_blend_mode": "normal", + "neve_post_cover_title_boxed_layout": false, + "neve_new_skin": "new" } } diff --git a/e2e-tests/cypress/fixtures/woocommerce/button-setup.json b/e2e-tests/cypress/fixtures/woocommerce/button-setup.json index e4b63df721..008ad1d53b 100644 --- a/e2e-tests/cypress/fixtures/woocommerce/button-setup.json +++ b/e2e-tests/cypress/fixtures/woocommerce/button-setup.json @@ -1,93 +1,96 @@ { - "custom_css_post_id": -1, - "nav_menu_locations": [], - "neve_button_appearance": { - "borderRadius": { - "top": "0", - "right": "0", - "bottom": "0", - "left": "0" - }, - "borderWidth": { - "top": 1, - "right": 1, - "bottom": 1, - "left": 1 - }, - "type": "outline", - "background": "#ffffff", - "backgroundHover": "var(--nv-primary-accent)", - "text": "#04b118", - "textHover": "#ffffff" - }, - "neve_button_typeface": { - "textTransform": "capitalize", - "flag": true, - "lineHeight": { - "suffix": { - "mobile": "em", - "tablet": "em", - "desktop": "em" - }, - "mobile": 1.6, - "tablet": 1.6, - "desktop": 1.6 - }, - "fontSize": { - "suffix": { - "mobile": "px", - "tablet": "px", - "desktop": "px" - }, - "mobile": "", - "tablet": "", - "desktop": "15" - } - }, - "hfg_header_layout": "{\"desktop\":{\"top\":[{\"x\":0,\"y\":1,\"width\":2,\"height\":1,\"id\":\"button_base\"}],\"main\":[{\"x\":0,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":4,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}", - "neve_migrated_hfg_colors": true, - "neve_secondary_button_appearance": { - "borderRadius": { - "top": "10", - "right": "10", - "bottom": "10", - "left": "10" - }, - "borderWidth": { - "top": 1, - "right": 1, - "bottom": 1, - "left": 1 - }, - "type": "outline", - "background": "#b30707", - "backgroundHover": "", - "text": "#ffffff", - "textHover": "var(--nv-text-color)" - }, - "neve_secondary_button_typeface": { - "textTransform": "uppercase", - "flag": true, - "lineHeight": { - "suffix": { - "mobile": "em", - "tablet": "em", - "desktop": "em" - }, - "mobile": 1.6, - "tablet": 1.6, - "desktop": 1.6 - }, - "fontSize": { - "suffix": { - "mobile": "px", - "tablet": "px", - "desktop": "px" - }, - "mobile": "", - "tablet": "", - "desktop": "20" - } - }, - "neve_form_button_type": "secondary" -} \ No newline at end of file + "custom_css_post_id": -1, + "nav_menu_locations": [], + "neve_button_appearance": { + "borderRadius": { + "top": "0", + "right": "0", + "bottom": "0", + "left": "0" + }, + "borderWidth": { + "top": 1, + "right": 1, + "bottom": 1, + "left": 1 + }, + "type": "outline", + "background": "#ffffff", + "backgroundHover": "var(--nv-primary-accent)", + "text": "#04b118", + "textHover": "#ffffff" + }, + "neve_button_typeface": { + "textTransform": "capitalize", + "flag": true, + "lineHeight": { + "suffix": { + "mobile": "em", + "tablet": "em", + "desktop": "em" + }, + "mobile": 1.6, + "tablet": 1.6, + "desktop": 1.6 + }, + "fontSize": { + "suffix": { + "mobile": "px", + "tablet": "px", + "desktop": "px" + }, + "mobile": "", + "tablet": "", + "desktop": "15" + } + }, + "hfg_header_layout_v2": "{\"desktop\":{\"top\":{\"left\":[{\"id\":\"button_base\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"header_search\"}]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}", + "neve_migrated_hfg_colors": true, + "neve_secondary_button_appearance": { + "borderRadius": { + "top": "10", + "right": "10", + "bottom": "10", + "left": "10" + }, + "borderWidth": { + "top": 1, + "right": 1, + "bottom": 1, + "left": 1 + }, + "type": "outline", + "background": "#b30707", + "backgroundHover": "", + "text": "#ffffff", + "textHover": "var(--nv-text-color)" + }, + "neve_secondary_button_typeface": { + "textTransform": "uppercase", + "flag": true, + "lineHeight": { + "suffix": { + "mobile": "em", + "tablet": "em", + "desktop": "em" + }, + "mobile": 1.6, + "tablet": 1.6, + "desktop": 1.6 + }, + "fontSize": { + "suffix": { + "mobile": "px", + "tablet": "px", + "desktop": "px" + }, + "mobile": "", + "tablet": "", + "desktop": "20" + } + }, + "neve_form_button_type": "secondary", + "neve_post_comment_form_button_style": "secondary", + "neve_ran_builder_migration": true, + "neve_migrated_builders": true +} diff --git a/e2e-tests/cypress/integration/amp/amp-test.spec.ts b/e2e-tests/cypress/integration/amp/amp-test.spec.ts index da94659023..0a5ba8fbea 100644 --- a/e2e-tests/cypress/integration/amp/amp-test.spec.ts +++ b/e2e-tests/cypress/integration/amp/amp-test.spec.ts @@ -1,59 +1,25 @@ describe('AMP Check', function () { before('Sets up search icon on menu top row', function () { - cy.goToCustomizer(); - cy.aliasRestRoutes(); - - cy.get('#accordion-panel-hfg_header').should('be.visible').click(); - - cy.get( - '.hfg--builder-show .hfg--panel-desktop .hfg--row-top .row--grid > div:last-child', - ).trigger('mouseover'); - cy.get( - '.hfg--builder-show .hfg--panel-desktop .hfg--row-top .row--grid > div:last-child .add-button--grid', - ).click({ force: true }); - - cy.get('.widgets-panel--visible'); - cy.get( - '.widgets-panel--visible .hfg--widgets-desktop .grid-stack-item.for-s-header_search_responsive', - ).click(); - - cy.get('#save').click({ force: true }); - cy.wait('@customizerSave').then((interception) => { - expect(interception.response.body.success).to.be.true; - expect(interception.response.statusCode).to.equal(200); - }); - cy.visit('/wp-admin'); - cy.get('#wp-admin-bar-logout > a').click({ - force: true, + cy.fixture('amp/amp-setup').then((setup) => { + cy.setCustomizeSettings(setup); }); }); it('Checks the search box from the menu', function () { cy.visit('/?amp'); cy.get( - '.header--row.header-top[data-show-on=desktop] .builder-item--header_search_responsive .nv-search-icon-component .menu-item-nav-search', + '.header-top.hide-on-mobile > .header--row-inner > .container > .row > .right > .builder-item > .item--inner > .component-wrap > .widget > .search-form > .search-submit', ).as('navSearchButton'); - cy.get('a.nv-icon > svg').click(); - cy.get('@navSearchButton').should('have.class', 'active'); - - cy.get('@navSearchButton').find('> .nv-nav-search').as('navSearchForm').should('be.visible'); - - cy.get('@navSearchButton').find('.close-responsive-search').click(); - cy.get('@navSearchButton').should('not.have.class', 'active'); - cy.get('@navSearchForm').should('have.css', 'opacity', '0'); - cy.get('@navSearchButton').click(); - - cy.get('@navSearchForm') - .find('form') - .invoke('removeAttr', 'target') - .invoke('removeAttr', 'action'); - cy.get('@navSearchForm').find('.search-field').as('formField').click(); - cy.get('@navSearchForm').find('.search-submit').as('submitButton'); - cy.get('@formField').should('have.focus').type('Hello'); - cy.get('@submitButton').click(); - cy.url().should('include', '/?s=Hello'); - cy.get('.nv-page-title').find('h1').should('have.text', 'Search Results for: Hello'); + cy.findByPlaceholderText(/upper search/i) + .as('navSearchForm') + .should('be.visible'); + + cy.get('@navSearchForm').should('have.css', 'opacity', '1'); + + cy.get('@navSearchForm').click(); + + cy.get('@navSearchForm').should('have.focus').type('Hello'); }); it('Checks the sidebar menu on mobile', function () { diff --git a/e2e-tests/cypress/integration/customizer/form-fields/form-fields.spec.ts b/e2e-tests/cypress/integration/customizer/form-fields/form-fields.spec.ts index 09bb5fe4e5..5a414b6023 100644 --- a/e2e-tests/cypress/integration/customizer/form-fields/form-fields.spec.ts +++ b/e2e-tests/cypress/integration/customizer/form-fields/form-fields.spec.ts @@ -7,13 +7,18 @@ describe('Form fields', function () { it('Checks up the search field', function () { cy.visit('/'); - cy.get('.search-field') + cy.wait(500); + cy.reload(); + cy.findByRole('searchbox') .should('have.css', 'padding-top', '14px') .and('have.css', 'padding-bottom', '14px') .and('have.css', 'padding-left', '14px') .and('have.css', 'color', 'rgb(3, 102, 214)') .and('have.css', 'background-color', 'rgb(237, 237, 237)') - .and('have.css', 'border-color', 'rgb(20, 23, 28)') + .and('have.css', 'border-bottom-color', 'rgb(20, 23, 28)') + .and('have.css', 'border-top-color', 'rgb(20, 23, 28)') + .and('have.css', 'border-left-color', 'rgb(20, 23, 28)') + .and('have.css', 'border-right-color', 'rgb(20, 23, 28)') .and('have.css', 'border-top-width', '3px') .and('have.css', 'border-bottom-width', '3px') .and('have.css', 'border-left-width', '3px') @@ -30,7 +35,7 @@ describe('Form fields', function () { }); it('Checks up the comment label', function () { cy.visit('/hello-world'); - cy.contains('Name') + cy.get('.comment-form-comment label') .should('have.css', 'font-size', '15px') .and('have.css', 'line-height', '24px') .and('have.css', 'letter-spacing', '1.5px') @@ -40,10 +45,13 @@ describe('Form fields', function () { }); it('Checks up the button', function () { cy.visit('/hello-world'); - cy.get('#submit') + cy.findByRole('button', { name: /post comment/i }) .should('have.css', 'background-color', 'rgb(3, 102, 214)') .and('have.css', 'color', 'rgb(255, 255, 255)') - .and('have.css', 'border-radius', '3px') + .and('have.css', 'border-bottom-left-radius', '3px') + .and('have.css', 'border-bottom-right-radius', '3px') + .and('have.css', 'border-top-left-radius', '3px') + .and('have.css', 'border-top-right-radius', '3px') .and('have.css', 'text-transform', 'uppercase') .and('have.css', 'padding-top', '8px') .and('have.css', 'padding-bottom', '8px') diff --git a/e2e-tests/cypress/integration/customizer/general/color-control.spec.ts b/e2e-tests/cypress/integration/customizer/general/color-control.spec.ts index d9003db0b1..6053951f60 100755 --- a/e2e-tests/cypress/integration/customizer/general/color-control.spec.ts +++ b/e2e-tests/cypress/integration/customizer/general/color-control.spec.ts @@ -1,6 +1,4 @@ describe('Color Control', function () { - const rgbColor = 'rgb(253, 143, 106)'; - before('Setup Color Control - Customizer', function () { cy.fixture('customizer/general/color-control-setup').then((colorSetup) => { cy.setCustomizeSettings(colorSetup); @@ -9,6 +7,6 @@ describe('Color Control', function () { it('Test Color Control - Front End', function () { cy.visit('/'); - cy.get('.header-main-inner').should('have.css', 'color').and('eq', rgbColor); + cy.get('.header-main-inner').should('have.css', 'color', 'rgb(253, 143, 106)'); }); }); diff --git a/e2e-tests/cypress/integration/customizer/general/global-colors-control.spec.ts b/e2e-tests/cypress/integration/customizer/general/global-colors-control.spec.ts index 674de24462..38f5939104 100755 --- a/e2e-tests/cypress/integration/customizer/general/global-colors-control.spec.ts +++ b/e2e-tests/cypress/integration/customizer/general/global-colors-control.spec.ts @@ -52,7 +52,7 @@ describe('Global Colors', function () { cy.get(color).should('have.css', 'background-color').and('eq', 'rgb(0, 0, 0)'); }); cy.get('#save').click({ force: true }); - cy.wait(500); + cy.wait(1000); cy.request('/wp-json/wpthememods/v1/settings').then((themeOptions) => { expect(themeOptions.body).to.contains( `{"base":{"name":"Base","allowDeletion":false,"colors":{"nv-primary-accent":"#000000","nv-secondary-accent":"#000000","nv-site-bg":"#000000","nv-light-bg":"#000000","nv-dark-bg":"#000000","nv-text-color":"#000000","nv-text-dark-bg":"#000000","nv-c-1":"#000000","nv-c-2":"#000000"}`, @@ -61,17 +61,19 @@ describe('Global Colors', function () { }); it('Palette Selector in Color Component', function () { - cy.getCustomizerControl('neve_button_appearance').as('buttonControl'); - cy.wait(100); - cy.get('@buttonControl').find('.global-color-picker').first().click(); - cy.get('.nv-custom-palette-wrap').should('be.visible'); - cy.get('.nv-custom-palette-wrap .nv-custom-palette-color').should('have.length', 9); - - cy.get('.nv-custom-palette-wrap .nv-custom-palette-color').first().click(); + cy.findByRole('heading', { + name: /palette colors/i, + }); + cy.get('.color-array-wrap').should('be.visible'); + cy.get('.color-array-wrap .neve-color-component').should('have.length', 9); - cy.get('@buttonControl').find('.global-color-picker').first().should('have.class', 'active'); + cy.get(':nth-child(2) > .components-dropdown > .components-button').click(); - cy.get('.nv-custom-palette-wrap button').contains('Edit').click(); + cy.get(':nth-child(2) > .components-dropdown > .components-button').should( + 'have.attr', + 'aria-expanded', + 'true', + ); }); it('Palette Reset', function () { diff --git a/e2e-tests/cypress/integration/customizer/hfg/hfg-alignment-control.spec.ts b/e2e-tests/cypress/integration/customizer/hfg/hfg-alignment-control.spec.ts index dea2fff3af..bee1b34a1d 100644 --- a/e2e-tests/cypress/integration/customizer/hfg/hfg-alignment-control.spec.ts +++ b/e2e-tests/cypress/integration/customizer/hfg/hfg-alignment-control.spec.ts @@ -8,12 +8,11 @@ describe('Header Builder Alignment Control', function () { it('Checks alignment for the Logo to Center', function () { cy.visit('/'); - cy.get('.header-main .desktop-center.hfg-item-first') + cy.get('.site-logo') .should('be.visible') .and('not.have.class', 'mobile-left') .and('not.have.class', 'tablet-left') - .find('.site-logo') - .should('be.visible'); + .and('have.css', 'text-align', 'center'); }); }); @@ -26,12 +25,11 @@ describe('Header Builder Alignment Control', function () { it('Checks alignment for the Logo to Right', function () { cy.visit('/'); - cy.get('.header-main .desktop-right.hfg-item-first') + cy.get('.site-logo') .should('be.visible') .and('not.have.class', 'mobile-left') .and('not.have.class', 'tablet-left') - .find('.site-logo') - .should('be.visible'); + .and('have.css', 'text-align', 'right'); }); }); }); diff --git a/e2e-tests/cypress/integration/customizer/hfg/hfg-padding-control.spec.ts b/e2e-tests/cypress/integration/customizer/hfg/hfg-padding-control.spec.ts index c3db6b6168..f01fed8c20 100644 --- a/e2e-tests/cypress/integration/customizer/hfg/hfg-padding-control.spec.ts +++ b/e2e-tests/cypress/integration/customizer/hfg/hfg-padding-control.spec.ts @@ -7,8 +7,8 @@ describe('Header Builder Padding Control', function () { }); it('Sets up Padding for the Logo Component', function () { - cy.get('.site-logo').should('be.visible'); - cy.get('.site-logo').should('have.css', 'padding-top').and('contain', '11px'); - cy.get('.site-logo').should('have.css', 'padding-bottom').and('contain', '9px'); + cy.get('.builder-item--logo').should('be.visible'); + cy.get('.builder-item--logo').should('have.css', 'padding-top').and('contain', '11px'); + cy.get('.builder-item--logo').should('have.css', 'padding-bottom').and('contain', '9px'); }); }); diff --git a/e2e-tests/cypress/integration/customizer/hfg/hfg-palette-switch-component.spec.ts b/e2e-tests/cypress/integration/customizer/hfg/hfg-palette-switch-component.spec.ts new file mode 100644 index 0000000000..9d256369fb --- /dev/null +++ b/e2e-tests/cypress/integration/customizer/hfg/hfg-palette-switch-component.spec.ts @@ -0,0 +1,41 @@ +describe('Palette Switch component', function () { + before('Setup by adding a new palette', function () { + cy.fixture('customizer/hfg/hfg-palette-switch-component').then((setup) => { + cy.setCustomizeSettings(setup); + }); + }); + + it('Changes the color palette by clicking', function () { + cy.visit('/'); + cy.findAllByRole('heading').should('have.css', 'color', 'rgb(39, 38, 38)'); + cy.get('.icon > svg > path').click(); + cy.findAllByRole('heading').should('have.css', 'color', 'rgb(255, 255, 255)'); + }); + + it('Removes color palette from website', function () { + cy.setCustomizeSettings({}); + cy.visit('/'); + cy.get('.icon > svg > path').should('not.exist'); + }); +}); + +describe('Palette Swich auto', function () { + before('Setup', function () { + cy.fixture('customizer/hfg/hfg-palette-switch-component').then((setup) => { + setup.header_palette_switch_auto_adjust_color = 1; + cy.setCustomizeSettings(setup); + }); + }); + + it('Automatically changes the color palette when dark is default', function () { + cy.setLocalStorage('neve_user_theme', 'dark'); + cy.visit('/'); + cy.findAllByRole('heading').should('have.css', 'color', 'rgb(255, 255, 255)'); + }); + + it('Automatically changes the color palette when light is default', function () { + cy.setLocalStorage('neve_user_theme', 'light'); + cy.visit('/'); + cy.findAllByRole('heading').should('have.css', 'color', 'rgb(39, 38, 38)'); + }); +}); diff --git a/e2e-tests/cypress/integration/customizer/hfg/hfg-row-background.spec.ts b/e2e-tests/cypress/integration/customizer/hfg/hfg-row-background.spec.ts index 8e3ea7a222..608112473b 100755 --- a/e2e-tests/cypress/integration/customizer/hfg/hfg-row-background.spec.ts +++ b/e2e-tests/cypress/integration/customizer/hfg/hfg-row-background.spec.ts @@ -14,6 +14,6 @@ describe('Header Row Background Control', function () { cy.get('@row') .should('have.css', 'background-image') .and('contain', 'url(') - .and('contain', 'wp-content/uploads'); + .and('contain', 'placeholder.com'); }); }); diff --git a/e2e-tests/cypress/integration/customizer/hfg/hfg-search-component.spec.ts b/e2e-tests/cypress/integration/customizer/hfg/hfg-search-component.spec.ts index 5cfcb28ca5..98fe790f5a 100644 --- a/e2e-tests/cypress/integration/customizer/hfg/hfg-search-component.spec.ts +++ b/e2e-tests/cypress/integration/customizer/hfg/hfg-search-component.spec.ts @@ -7,12 +7,13 @@ describe('Search Icon Component', function () { it('Canvas Search Works on Front End', function () { cy.visit('/'); + cy.reload(); cy.get('.builder-item--header_search_responsive .menu-item-nav-search').as('searchIcon'); cy.get('@searchIcon').find('.nv-nav-search').should('not.be.visible'); cy.get('@searchIcon').should('have.class', 'canvas'); cy.get('@searchIcon').find('> .nv-search').click(); cy.get('@searchIcon').should('have.class', 'active'); - cy.get('@searchIcon').find('.nv-nav-search').should('be.visible'); + cy.get('.nv-nav-search').should('be.visible'); cy.get('@searchIcon').find('.close-responsive-search').click(); cy.get('@searchIcon').find('.nv-nav-search').should('not.be.visible'); }); @@ -27,13 +28,14 @@ describe('Search Icon Component', function () { it('Minimal Search Works on Front End', function () { cy.visit('/'); + cy.reload(); cy.get('.builder-item--header_search_responsive .menu-item-nav-search').as('searchIcon'); cy.get('@searchIcon').find('.nv-nav-search').should('not.be.visible'); cy.get('@searchIcon').should('have.class', 'minimal'); cy.get('@searchIcon').find('> .nv-search').click(); cy.get('@searchIcon').should('have.class', 'active'); cy.get('@searchIcon').find('.nv-nav-search').should('be.visible'); - cy.get('.nav-clickaway-overlay').should('exist').click(); + cy.get('.nav-clickaway-overlay').click(); cy.get('@searchIcon').find('.nv-nav-search').should('not.be.visible'); cy.get('.nav-clickaway-overlay').should('not.exist'); }); @@ -49,13 +51,14 @@ describe('Search Icon Component', function () { it('Floating Search Works on Front End', function () { cy.visit('/'); + cy.reload(); cy.get('.builder-item--header_search_responsive .menu-item-nav-search').as('searchIcon'); cy.get('@searchIcon').find('.nv-nav-search').should('not.be.visible'); cy.get('@searchIcon').should('have.class', 'floating'); cy.get('@searchIcon').find('> .nv-search').click(); cy.get('@searchIcon').should('have.class', 'active'); cy.get('@searchIcon').find('.nv-nav-search').should('be.visible'); - cy.get('.nav-clickaway-overlay').should('exist'); + cy.get('.nav-clickaway-overlay'); cy.get('@searchIcon').find('.close-responsive-search').click(); cy.get('@searchIcon').find('.nv-nav-search').should('not.be.visible'); cy.get('.nav-clickaway-overlay').should('not.exist'); diff --git a/e2e-tests/cypress/integration/customizer/layout/blog-archive-settings.spec.ts b/e2e-tests/cypress/integration/customizer/layout/blog-archive-settings.spec.ts index 318dd3e844..dc445e4bde 100755 --- a/e2e-tests/cypress/integration/customizer/layout/blog-archive-settings.spec.ts +++ b/e2e-tests/cypress/integration/customizer/layout/blog-archive-settings.spec.ts @@ -7,7 +7,7 @@ describe('Blog/Archive 1 / Default Layout', function () { }); it('Tests Default Layout (List)', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { // Layout classes and styles. cy.get(el).should('have.class', 'layout-default'); cy.get(el).find('.content').should('have.css', 'flex-direction', 'row'); @@ -16,7 +16,7 @@ describe('Blog/Archive 1 / Default Layout', function () { it('Post Content Order', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).find('.excerpt-wrap:first-child').should('exist').and('be.visible'); cy.get(el).find('.nv-meta-list:last-child').should('exist').and('be.visible'); cy.get(el).should('have.descendants', '.nv-meta-list'); @@ -27,7 +27,7 @@ describe('Blog/Archive 1 / Default Layout', function () { it('Meta Order', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).find('.nv-meta-list > .date:first-child').should('exist'); cy.get(el).find('.nv-meta-list > .author:nth-child(2)').should('exist'); cy.get(el).find('.nv-meta-list > .category:last-child').should('exist'); @@ -36,7 +36,7 @@ describe('Blog/Archive 1 / Default Layout', function () { it('No Author Avatar', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).find('.author .photo').should('not.exist'); }); }); @@ -44,7 +44,7 @@ describe('Blog/Archive 1 / Default Layout', function () { it('Excerpt length', function () { cy.visit('/'); let count = 5; - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { if (count === 0) { return false; } @@ -83,7 +83,7 @@ describe('Blog/Archive 1 / Default Layout', function () { cy.visit('/'); let count = 0; - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).should('have.class', 'layout-alternative'); if (count % 2 === 0) { cy.get(el).find('.content').should('have.css', 'flex-direction', 'row-reverse'); @@ -106,7 +106,7 @@ describe('Blog/Archive 2 / Grid Layout', function () { it('Grid layout', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el) .should('have.class', 'layout-grid') .and('have.class', 'col-md-4') @@ -123,7 +123,7 @@ describe('Blog/Archive 2 / Grid Layout', function () { it('Author Avatar', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).find('.author').should('have.descendants', '.photo'); }); }); @@ -139,7 +139,7 @@ describe('Blog/Archive 3 / Covers Layout', function () { it('Covers layout', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).should('have.class', 'layout-covers'); cy.get(el) .find('.cover-post.nv-post-thumbnail-wrap') @@ -151,7 +151,7 @@ describe('Blog/Archive 3 / Covers Layout', function () { it('Thumbnail Box Shadow', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el) .find('.cover-post.nv-post-thumbnail-wrap') .should( @@ -164,7 +164,7 @@ describe('Blog/Archive 3 / Covers Layout', function () { it('Post Content Order', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).find('.entry-title:first-child').should('exist'); cy.get(el).find('.nv-meta-list:last-child').should('exist'); }); @@ -172,7 +172,7 @@ describe('Blog/Archive 3 / Covers Layout', function () { it('Text Color', function () { cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).find('.inner').should('have.css', 'color', 'rgb(186, 218, 85)'); }); }); @@ -182,7 +182,7 @@ describe('Blog/Archive 3 / Covers Layout', function () { expect(response.body).to.contains(`"neve_enable_masonry":true`); }); cy.visit('/'); - cy.get('article').each((el) => { + cy.get('article.post').each((el) => { cy.get(el).should('have.css', 'position', 'absolute'); cy.get(el).should('have.css', 'left'); cy.get(el).should('have.css', 'top'); diff --git a/e2e-tests/cypress/integration/customizer/layout/sidebar-settings.spec.ts b/e2e-tests/cypress/integration/customizer/layout/sidebar-settings.spec.ts index c1122b9351..6e661d6749 100755 --- a/e2e-tests/cypress/integration/customizer/layout/sidebar-settings.spec.ts +++ b/e2e-tests/cypress/integration/customizer/layout/sidebar-settings.spec.ts @@ -1,61 +1,69 @@ describe('Sidebar/Content Settings', function () { - it('Sidebar site wide on front end.', function () { - cy.fixture('customizer/layout/sidebar-settings').then((sidebarSetup) => { - cy.setCustomizeSettings(sidebarSetup.site_wide).then(() => { - cy.visit('/'); + context('Sidebar site wide on front end.', function () { + beforeEach(function () { + cy.fixture('customizer/layout/sidebar-settings').then((sidebarSetup) => { + cy.setCustomizeSettings(sidebarSetup.site_wide); }); }); - //Index - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-index-posts').should('have.css', 'max-width', '50%'); - //Page - cy.visit('/sample-page'); - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-single-page-wrap').should('have.css', 'max-width', '50%'); - - //Author archive - cy.visit('/?author=1'); - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-index-posts').should('have.css', 'max-width', '50%'); - - //Single Post - cy.visit('/hello-world'); - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-single-post-wrap').should('have.css', 'max-width', '50%'); + it('Page', function () { + cy.visit('/sample-page'); + cy.reload(); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-single-page-wrap').should('have.css', 'max-width', '50%'); + }); + it('Author archive', function () { + cy.visit('/?author=1'); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-index-posts').should('have.css', 'max-width', '50%'); + }); + it('Single Post', function () { + cy.visit('/hello-world'); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-single-post-wrap').should('have.css', 'max-width', '50%'); + }); + it.skip('Index', function () { + cy.visit('/'); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '50%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-index-posts').should('have.css', 'max-width', '50%'); + }); }); - it('Sidebar advanced on front end.', function () { - cy.fixture('customizer/layout/sidebar-settings').then((sidebarSetup) => { - cy.setCustomizeSettings(sidebarSetup.advanced).then(() => { - cy.visit('/'); + context('Sidebar advanced on front end.', function () { + beforeEach(function () { + cy.fixture('customizer/layout/sidebar-settings').then((sidebarSetup) => { + cy.setCustomizeSettings(sidebarSetup.advanced); }); }); - //Index - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '80%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-index-posts').should('have.css', 'max-width', '20%'); - //Page - cy.visit('/sample-page'); - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '30%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-single-page-wrap').should('have.css', 'max-width', '70%'); - - //Author archive - cy.visit('/'); - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '80%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); - cy.get('.nv-index-posts').should('have.css', 'max-width', '20%'); - - //Single Post - cy.visit('/hello-world'); - cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '30%'); - cy.get('.nv-sidebar-wrap').should('have.class', 'nv-right'); - cy.get('.nv-single-post-wrap').should('have.css', 'max-width', '70%'); + it('Page', function () { + cy.visit('/sample-page'); + cy.reload(); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '30%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-single-page-wrap').should('have.css', 'max-width', '70%'); + }); + it('Author archive', function () { + cy.visit('/?author=1'); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '80%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-index-posts').should('have.css', 'max-width', '20%'); + }); + it('Single Post', function () { + cy.visit('/hello-world'); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '30%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-right'); + cy.get('.nv-single-post-wrap').should('have.css', 'max-width', '70%'); + }); + it.skip('Index', function () { + cy.visit('/'); + cy.get('.nv-sidebar-wrap').should('have.css', 'max-width', '80%'); + cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); + cy.get('.nv-index-posts').should('have.css', 'max-width', '20%'); + }); }); }); diff --git a/e2e-tests/cypress/integration/customizer/layout/single-post-settings.spec.ts b/e2e-tests/cypress/integration/customizer/layout/single-post-settings.spec.ts index 3bc72c8de2..efd82a84d4 100755 --- a/e2e-tests/cypress/integration/customizer/layout/single-post-settings.spec.ts +++ b/e2e-tests/cypress/integration/customizer/layout/single-post-settings.spec.ts @@ -1,12 +1,21 @@ describe('Single Post Check', function () { before(function () { - cy.loginWithRequest(); - cy.visit('/markup-image-alignment/'); - cy.get('#wp-admin-bar-edit').click(); - cy.clearWelcome(); - cy.get('.components-panel__body').contains('Discussion').click(); - cy.get('label').contains('Allow comments').click(); - cy.get('button').contains('Update').click(); + cy.setCustomizeSettings({ + neve_new_skin: 'new', + }); + }); + + it('Shows all options on customizer', function () { + cy.goToCustomizer(); + cy.get('#accordion-panel-neve_layout > .accordion-section-title').click(); + cy.get('#accordion-section-neve_single_post_layout > .accordion-section-title').click(); + + cy.get('#sub-accordion-section-neve_single_post_layout').contains('Header Layout'); + cy.get('#sub-accordion-section-neve_single_post_layout').contains('Title Alignment'); + cy.get('#sub-accordion-section-neve_single_post_layout').contains('Page Elements'); + cy.get('#sub-accordion-section-neve_single_post_layout').contains('Post Meta'); + cy.get('#sub-accordion-section-neve_single_post_layout').contains('Comments Section'); + cy.get('#sub-accordion-section-neve_single_post_layout').contains('Submit Form Section'); }); context('Hidden', function () { @@ -25,7 +34,7 @@ describe('Single Post Check', function () { '.nv-post-navigation', ]; - cy.visit('/markup-image-alignment/'); + cy.visit('/template-comments/'); HIDDEN.forEach((className) => { cy.get('.nv-single-post-wrap').should('not.have.descendants', className); }); @@ -48,7 +57,7 @@ describe('Single Post Check', function () { 'nv-thumb-wrap', ]; - cy.visit('/markup-image-alignment/'); + cy.visit('/template-comments/'); // eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars ORDER.forEach((className) => { @@ -60,4 +69,22 @@ describe('Single Post Check', function () { }); }); }); + + context('Header Cover', function () { + const urls = ['/hello-world', '/markup-text-alignment', '/scheduled']; + before(function () { + cy.fixture('customizer/layout/single-post-settings').then((setup) => { + cy.setCustomizeSettings(setup.cover); + }); + }); + urls.forEach(function (url) { + it(`Should have the cover layout on the single post ${url} as the setup`, function () { + cy.visit(url); + cy.get('.nv-overlay') + .should('have.css', 'height', '505px') + .and('have.css', 'background-color', 'rgb(198, 53, 53)'); + cy.get('.nv-title-meta-wrap').should('have.css', 'color', 'rgb(255, 255, 255)'); + }); + }); + }); }); diff --git a/e2e-tests/cypress/integration/customizer/typography/font-family.spec.ts b/e2e-tests/cypress/integration/customizer/typography/font-family.spec.ts index 3356fc7f23..20a8a80a52 100755 --- a/e2e-tests/cypress/integration/customizer/typography/font-family.spec.ts +++ b/e2e-tests/cypress/integration/customizer/typography/font-family.spec.ts @@ -25,7 +25,7 @@ describe('Font Family', function () { cy.visit('/markup-html-tags-and-formatting/'); cy.get('#wp-admin-bar-edit > a').click(); cy.clearWelcome(); - cy.get('.editor-styles-wrapper .block-editor-writing-flow p').as('body'); + cy.get('.editor-styles-wrapper.block-editor-writing-flow p').as('body'); cy.get('@body').should('have.css', 'font-family').and('match', new RegExp(fonts.general, 'g')); ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach((heading) => { diff --git a/e2e-tests/cypress/integration/editor/classic/page.spec.ts b/e2e-tests/cypress/integration/editor/classic/page.spec.ts index 011875f7a7..7b74dc15de 100644 --- a/e2e-tests/cypress/integration/editor/classic/page.spec.ts +++ b/e2e-tests/cypress/integration/editor/classic/page.spec.ts @@ -2,24 +2,42 @@ describe('Page meta box settings', function () { const pageSetup = { title: 'Test Page', content: 'The Page Content', - url: null, + url: '/', }; before('Create new page named "' + pageSetup.title + '".', function () { - cy.insertPost(pageSetup.title, pageSetup.content, 'page'); - + cy.insertPostWithRequest(pageSetup.title, pageSetup.content, 'pages') + .then(() => { + pageSetup.url = window.localStorage.getItem('postUrl'); + }) + .then(() => { + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'pages', { + meta: { + neve_meta_sidebar: 'full-width', + neve_meta_enable_content_width: 'on', + neve_meta_content_width: 100, + }, + }); + }); cy.setCustomizeSettings({ - neve_migrated_hfg_colors: true, - nav_menu_locations: [], custom_css_post_id: -1, + nav_menu_locations: [], + neve_migrated_hfg_colors: true, + neve_new_skin: 'new', + neve_ran_migrations: true, + neve_blog_archive_content_width: 50, + neve_other_pages_content_width: 30, + neve_single_post_content_width: 40, }); + }); - cy.get('.post-publish-panel__postpublish-header a') - .contains(pageSetup.title) - .should('have.attr', 'href') - .then((href) => { - pageSetup.url = href; - }); + beforeEach(function () { + cy.restoreLocalStorage(); + }); + + afterEach(function () { + cy.removeLocalStorage('WP_DATA_USER_1'); + cy.saveLocalStorage(); }); context('Deactivated plugin', function () { @@ -59,7 +77,7 @@ describe('Page meta box settings', function () { cy.loginWithRequest(pageSetup.url); cy.get('#wp-admin-bar-edit a').click(); - cy.get('#neve_meta_content_width-range').invoke('val', 70).trigger('change'); + cy.get('#neve_meta_content_width-range').invoke('val', 70).trigger('change', { force: true }); cy.get('#publish').contains('Update').click(); cy.visit(pageSetup.url); @@ -76,11 +94,12 @@ describe('Page meta box settings', function () { cy.get('label[for="neve_meta_disable_title"]').click(); cy.get('label[for="neve_meta_disable_header"]').click(); cy.get('label[for="neve_meta_disable_footer"]').click(); - cy.get('#neve_meta_content_width-range').invoke('val', 70).trigger('change'); + cy.get('#neve_meta_content_width-range').invoke('val', 70).trigger('change', { force: true }); cy.get('#publish').contains('Update').click(); cy.visit(pageSetup.url); + cy.wait(500); cy.reload(); cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left').and('be.visible'); cy.get('.single-page-container').should('have.class', 'container-fluid').and('be.visible'); diff --git a/e2e-tests/cypress/integration/editor/classic/post.spec.ts b/e2e-tests/cypress/integration/editor/classic/post.spec.ts index cc5e490229..8e295717c9 100755 --- a/e2e-tests/cypress/integration/editor/classic/post.spec.ts +++ b/e2e-tests/cypress/integration/editor/classic/post.spec.ts @@ -2,23 +2,44 @@ describe('Posts meta box default settings', function () { const postSetup = { title: 'Test Post', content: 'The Post Content', - url: null, + url: '/', }; before('Create new post named "' + postSetup.title + '".', function () { - cy.insertPost(postSetup.title, postSetup.content, 'post', true); - + cy.getRandomAttachment().then(() => { + cy.insertPostWithRequest( + postSetup.title, + postSetup.content, + 'posts', + parseInt(window.localStorage.getItem('randomAttachmentId')), + ) + .then(() => { + postSetup.url = window.localStorage.getItem('postUrl'); + }) + .then(() => { + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'posts', { + meta: { + neve_meta_content_width: 0, + }, + }); + }); + }); cy.setCustomizeSettings({ neve_migrated_hfg_colors: true, nav_menu_locations: [], custom_css_post_id: -1, + neve_new_skin: 'new', }); - cy.get('.post-publish-panel__postpublish-header a') - .contains(postSetup.title) - .should('have.attr', 'href') - .then((href) => { - postSetup.url = href; - }); + cy.saveLocalStorage(); + }); + + beforeEach(function () { + cy.restoreLocalStorage(); + }); + + afterEach(function () { + cy.removeLocalStorage('WP_DATA_USER_1'); + cy.saveLocalStorage(); }); context('Deactivated Plugin', function () { it('Default meta box settings on front end.', function () { @@ -67,6 +88,7 @@ describe('Posts meta box default settings', function () { cy.get('#publish').contains('Update').click(); cy.visit(postSetup.url); + cy.wait(500); cy.reload(); cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left').and('be.visible'); cy.get('.single-post-container').should('have.class', 'container-fluid').and('be.visible'); diff --git a/e2e-tests/cypress/integration/editor/modern/page-meta-sidebar.spec.ts b/e2e-tests/cypress/integration/editor/modern/page-meta-sidebar.spec.ts index 7bba56fd65..57b7f3c6cb 100644 --- a/e2e-tests/cypress/integration/editor/modern/page-meta-sidebar.spec.ts +++ b/e2e-tests/cypress/integration/editor/modern/page-meta-sidebar.spec.ts @@ -6,23 +6,30 @@ describe('Single page sidebar', function () { }; before('Create new page named "' + pageSetup.title + '".', function () { - cy.insertPost(pageSetup.title, pageSetup.content, 'page'); + cy.insertPostWithRequest(pageSetup.title, pageSetup.content, 'pages') + .then(() => { + pageSetup.url = window.localStorage.getItem('postUrl'); + }) + .then(() => { + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'pages', { + meta: { + neve_meta_sidebar: 'full-width', + neve_meta_enable_content_width: 'on', + neve_meta_content_width: 100, + }, + }); + }); cy.setCustomizeSettings({ - neve_migrated_hfg_colors: true, - nav_menu_locations: [], custom_css_post_id: -1, + nav_menu_locations: [], + neve_migrated_hfg_colors: true, + neve_new_skin: 'new', + neve_ran_migrations: true, + neve_blog_archive_content_width: 50, + neve_other_pages_content_width: 30, + neve_single_post_content_width: 40, }); - cy.get('.post-publish-panel__postpublish-header a') - .contains(pageSetup.title) - .should('have.attr', 'href') - .then((href) => { - pageSetup.url = href.toString(); - }) - .then(() => { - window.localStorage.setItem('pageId', Cypress.$('#post_ID').val().toString()); - cy.getJWT(); - }); cy.saveLocalStorage(); }); @@ -52,7 +59,7 @@ describe('Single page sidebar', function () { }); it('Full-width', function () { - cy.updatePageOrPostByRequest(window.localStorage.getItem('pageId'), 'pages', { + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'pages', { meta: { neve_meta_sidebar: 'full-width', }, @@ -62,7 +69,7 @@ describe('Single page sidebar', function () { cy.get('.nv-sidebar-wrap').should('not.exist'); }); it('Left', function () { - cy.updatePageOrPostByRequest(window.localStorage.getItem('pageId'), 'pages', { + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'pages', { meta: { neve_meta_sidebar: 'left', }, @@ -72,7 +79,7 @@ describe('Single page sidebar', function () { cy.get('.nv-sidebar-wrap').should('have.class', 'nv-left'); }); it('Right', function () { - cy.updatePageOrPostByRequest(window.localStorage.getItem('pageId'), 'pages', { + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'pages', { meta: { neve_meta_sidebar: 'right', }, @@ -109,8 +116,6 @@ describe('Single page sidebar', function () { cy.openNeveSidebar(); - cy.activateCheckbox('.components-toggle-control__label', 'Custom Content Width (%)'); - cy.get('.neve_meta_content_width').find('input[type=number]').type('{selectall}').type('60'); cy.updatePost(); cy.visit(pageSetup.url); diff --git a/e2e-tests/cypress/integration/editor/modern/post-meta-sidebar.spec.ts b/e2e-tests/cypress/integration/editor/modern/post-meta-sidebar.spec.ts index b123f60d60..d42f508ec8 100644 --- a/e2e-tests/cypress/integration/editor/modern/post-meta-sidebar.spec.ts +++ b/e2e-tests/cypress/integration/editor/modern/post-meta-sidebar.spec.ts @@ -6,24 +6,32 @@ describe('Single post meta sidebar', function () { }; before('Create new post named "' + postSetup.title + '".', function () { - cy.insertPost(postSetup.title, postSetup.content, 'post', true, true); - + cy.createTagWithRequest('tag-test' + Math.random()); + cy.getRandomAttachment().then(() => { + cy.insertPostWithRequest( + postSetup.title, + postSetup.content, + 'posts', + parseInt(window.localStorage.getItem('randomAttachmentId')), + ) + .then(() => { + postSetup.url = window.localStorage.getItem('postUrl'); + }) + .then(() => { + const tagId = parseInt(window.localStorage.getItem('tagId')); + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'posts', { + tags: tagId, + }); + }); + }); cy.setCustomizeSettings({ neve_migrated_hfg_colors: true, nav_menu_locations: [], custom_css_post_id: -1, + neve_new_skin: 'new', + neve_ran_migrations: true, }); - cy.get('.post-publish-panel__postpublish-header a') - .contains(postSetup.title) - .should('have.attr', 'href') - .then((href) => { - postSetup.url = href.toString(); - }) - .then(() => { - window.localStorage.setItem('postId', Cypress.$('#post_ID').val().toString()); - cy.getJWT(); - }); cy.saveLocalStorage(); }); @@ -127,56 +135,47 @@ describe('Single post meta sidebar', function () { meta: { neve_meta_title_alignment: 'center', }, + }).then(() => { + cy.visit(postSetup.url); + cy.get('.title').should('have.css', 'text-align', 'center'); }); - cy.visit(postSetup.url); - cy.get('h1.entry-title') - .should('have.class', 'has-text-align-center') - .and('have.css', 'text-align') - .and('eq', 'center'); cy.updatePageOrPostByRequest(postId, 'posts', { meta: { neve_meta_title_alignment: 'right', }, + }).then(() => { + cy.visit(postSetup.url); + cy.get('.title').should('have.css', 'text-align', 'right'); }); - cy.visit(postSetup.url); - cy.get('h1.entry-title') - .should('have.class', 'has-text-align-right') - .and('have.css', 'text-align') - .and('eq', 'right'); - cy.updatePageOrPostByRequest(postId, 'posts', { meta: { neve_meta_title_alignment: 'left', }, + }).then(() => { + cy.visit(postSetup.url); + cy.get('.title').should('have.css', 'text-align', 'left'); }); - cy.visit(postSetup.url); - cy.get('h1.entry-title') - .should('have.class', 'has-text-align-left') - .and('have.css', 'text-align') - .and('eq', 'left'); - cy.get('#wp-admin-bar-edit a').click(); }); it('Check author avatar', function () { cy.loginWithRequest(postSetup.url); cy.clearWelcome(); - cy.get('#wp-admin-bar-edit a').click(); - - cy.get('.interface-complementary-area-header'); - - cy.activateCheckbox('.components-toggle-control__label', 'Author Avatar'); - cy.updatePost(); - - cy.visit(postSetup.url); - cy.get('.nv-meta-list .author .photo').should('exist'); + cy.updatePageOrPostByRequest(window.localStorage.getItem('postId'), 'posts', { + meta: { + neve_meta_author_avatar: 'on', + }, + }).then(() => { + cy.visit(postSetup.url); + cy.get('.nv-meta-list .author .photo').should('exist'); + }); }); it('Check post elements', function () { cy.loginWithRequest(postSetup.url); cy.reload(); cy.get('#wp-admin-bar-edit a').click(); - + cy.clearWelcome(); cy.get('.interface-complementary-area-header'); cy.get('.ti-sortable-item-label').each((el, index) => { diff --git a/e2e-tests/cypress/integration/useful-plugins/useful-plugins.spec.ts b/e2e-tests/cypress/integration/useful-plugins/useful-plugins.spec.ts index fcb6e5f25a..05f4a217c2 100755 --- a/e2e-tests/cypress/integration/useful-plugins/useful-plugins.spec.ts +++ b/e2e-tests/cypress/integration/useful-plugins/useful-plugins.spec.ts @@ -1,5 +1,5 @@ describe('Useful Plugins Tab - Install Optimole Plugin', function () { - beforeEach(function () { + before(function () { cy.loginWithRequest('/wp-admin/themes.php?page=neve-welcome#plugins'); }); @@ -11,7 +11,7 @@ describe('Useful Plugins Tab - Install Optimole Plugin', function () { }); it('Can activates Plugins', function () { - cy.get('.feedzy-rss-feeds > .card-footer > .components-button') + cy.get('.templates-patterns-collection > .card-footer > .components-button') .should('have.text', 'Activate') .and('be.enabled'); }); diff --git a/e2e-tests/cypress/support/commands.ts b/e2e-tests/cypress/support/commands.ts index 7c52bb80c6..dfe897da2c 100755 --- a/e2e-tests/cypress/support/commands.ts +++ b/e2e-tests/cypress/support/commands.ts @@ -2,71 +2,10 @@ /* eslint-disable chai-friendly/no-unused-expressions */ import 'cypress-file-upload'; import '@percy/cypress'; +import 'cypress-nv-commands/index'; import 'cypress-localstorage-commands'; import { scrollToBottom } from 'scroll-to-bottomjs'; - -Cypress.Commands.add('loginWithRequest', (nextRoute = '/wp-admin') => { - let isLoggedIn = false; - cy.getCookies({ log: true }).then((cookies) => { - cookies.forEach((value) => { - if (value.name.includes('wordpress_logged_in_')) { - isLoggedIn = true; - } - }); - if (!isLoggedIn) { - cy.request({ - method: 'POST', - url: '/wp-login.php', - form: true, - body: { - log: Cypress.env('user'), - pwd: Cypress.env('password'), - 'wp-submit': 'Log In', - redirect_to: 'http://localhost:8080/wp-admin', - }, - }); - } - cy.visit(nextRoute); - }); -}); - -Cypress.Commands.add('login', (nextRoute: string = null) => { - cy.getCookies({ - log: true, - }).then((cookies) => { - let isLoggedIn = false; - cookies.forEach((value) => { - if (value.name.includes('wordpress_')) { - isLoggedIn = true; - } - }); - - if (isLoggedIn) { - if (nextRoute !== null) { - cy.visit(nextRoute); - } - return; - } - cy.visit('/wp-admin'); - cy.wait(500); - cy.get('#user_login').type(Cypress.env('user')); - cy.get('#user_pass').type(Cypress.env('password')); - cy.get('#wp-submit').click(); - if (nextRoute === null) { - return; - } - cy.visit(nextRoute); - }); -}); - -Cypress.Commands.add('clearWelcome', () => { - cy.window().then((win) => { - win.wp && - win.wp.data && - win.wp.data.select('core/edit-post').isFeatureActive('welcomeGuide') && - win.wp.data.dispatch('core/edit-post').toggleFeature('welcomeGuide'); - }); -}); +import '@testing-library/cypress/add-commands'; Cypress.Commands.add('insertCoverBlock', () => { const text = @@ -100,60 +39,6 @@ Cypress.Commands.add('insertCoverBlock', () => { cy.updatePost(); }); -Cypress.Commands.add( - 'insertPost', - (title = 'Test', content = 'Content', type = 'post', featured = false, tags = false) => { - let loginRoute = '/wp-admin/post-new.php'; - if (type !== 'post') { - loginRoute += '?post_type=' + type; - } - - cy.loginWithRequest(loginRoute); - cy.clearWelcome(); - if (featured) { - cy.wait(1000); - cy.get('button').contains('Featured image').click(); - cy.get('.editor-post-featured-image__toggle').click(); - cy.get('.media-frame').find('.media-menu-item').contains('Media Library').click({ - force: true, - }); - - cy.get('.attachments-browser .attachments > li.attachment').first().click({ - force: true, - }); - cy.get('.media-button-select').click(); - } - - if (tags) { - cy.get('.components-panel__body-toggle').contains('Tags').click({ force: true }); - cy.get('.components-form-token-field__label') - .contains('Add New Tag') - .parent() - .find('input') - .type('test-tag,', { force: true }); - } - cy.get('.editor-post-title__input').type(title); - cy.get(' textarea.block-editor-default-block-appender__content').click({ - force: true, - }); - cy.get('.block-editor-rich-text__editable').type(content); - cy.get('.editor-post-publish-panel__toggle').click(); - cy.updatePost(); - }, -); - -Cypress.Commands.add('updatePost', () => { - cy.get('.editor-post-publish-button').click(); - cy.wait(500); -}); - -Cypress.Commands.add('getCustomizerControl', (slug: string) => { - cy.window().then((win) => { - win.wp.customize.control(slug).focus(); - }); - return cy.get('#customize-control-' + slug); -}); - Cypress.Commands.add('captureDocument', (generalMaskAndClip = true, screenShotName = false) => { if (generalMaskAndClip) { const maskElement = @@ -197,101 +82,3 @@ Cypress.Commands.add( }); }, ); - -Cypress.Commands.add('setCustomizeSettings', (to) => { - cy.request('POST', '/wp-json/wpthememods/v1/settings', to); -}); - -Cypress.Commands.add('goToCustomizer', () => { - cy.loginWithRequest('/wp-admin/customize.php'); - cy.visit('/wp-admin/customize.php'); - cy.window() - .then((win) => { - //If the customizer is not ready, bind the flag to ready event. - win.wp.customize.bind('ready', () => { - win.appReady = true; - }); - }) - .then(() => { - // If we bind to the ready event too late, we can check the body class 'ready'. - cy.get('body').then(($body) => { - if ($body.hasClass('ready')) { - cy.window().then((win) => { - win.appReady = true; - }); - } - }); - }); - cy.window({ - timeout: 15000, - }).should('have.property', 'appReady', true); -}); - -Cypress.Commands.add('aliasRestRoutes', () => { - cy.intercept('POST', '/wp-admin/admin-ajax.php').as('customizerSave'); -}); - -Cypress.Commands.add('toggleElements', (show: boolean) => { - const icon = show ? 'dashicons-hidden' : 'dashicons-visibility'; - cy.get('.ti-sortable-item-area .ti-sortable-item-toggle').each(function (el) { - cy.get(el) - .find('.dashicon') - .then(($icon) => { - if ($icon.hasClass(icon)) { - cy.get($icon).click(); - } - }); - }); -}); - -Cypress.Commands.add('getControl', (control: string) => { - return cy.get(`label[for=${control}]`).parent(); -}); - -Cypress.Commands.add('activateCheckbox', (checkboxSelector: string, checkboxText: string) => { - cy.get(checkboxSelector) - .contains(checkboxText) - .prev() - .then((checkbox) => { - if (!checkbox.hasClass('is-checked')) { - cy.get(checkbox).click(); - } - }); -}); - -Cypress.Commands.add('openNeveSidebar', () => { - cy.get('button.components-button[aria-label="Neve Options"]').click(); -}); - -Cypress.Commands.add('activateClassicEditorPlugin', () => { - cy.loginWithRequest('/wp-admin/plugins.php'); - cy.get('#activate-classic-editor').contains('Activate').click(); - cy.get('#deactivate-classic-editor').should('exist'); -}); - -Cypress.Commands.add('deactivateClassicEditorPlugin', () => { - cy.loginWithRequest('/wp-admin/plugins.php'); - cy.get('#deactivate-classic-editor').contains('Deactivate').click(); - cy.get('#activate-classic-editor').should('exist'); -}); - -Cypress.Commands.add('getJWT', () => { - cy.request('POST', '/wp-json/api-bearer-auth/v1/login', { - username: 'admin', - password: 'admin', - }).then((response) => { - expect(response.body.access_token).to.exist; - window.localStorage.setItem('jwt', response.body.access_token); - }); -}); - -Cypress.Commands.add('updatePageOrPostByRequest', (postId: string, type: string, body) => { - cy.request({ - method: 'POST', - url: '/wp-json/wp/v2/' + type + '/' + postId, - auth: { - bearer: window.localStorage.getItem('jwt'), - }, - body, - }); -}); diff --git a/e2e-tests/cypress/support/model.d.ts b/e2e-tests/cypress/support/model.d.ts index 1479121a95..647521343e 100644 --- a/e2e-tests/cypress/support/model.d.ts +++ b/e2e-tests/cypress/support/model.d.ts @@ -20,31 +20,6 @@ declare namespace Cypress { options?: Partial, ): Chainable>; - /** - * Login through request - * - * @param nextRoute - the url you want to visit after logging in - * @example - * cy.loginWithRequest('/shop') - */ - loginWithRequest(nextRout?: string): void; - - /** - * Login through UI once and verify if the user is already logged in - * - * @param nextRoute - the url you want to visit after logging in - * @example - * cy.login('/shop') - */ - login(nextRoute?: string): void; - - /** - * Clear the welcome message - * - * @example cy.clearWelcome() - */ - clearWelcome(): void; - /** * Inserts a cover block * @@ -54,42 +29,6 @@ declare namespace Cypress { insertCoverBlock(): void; - /** - * Insert a new post - * - * @param title - * @param content - * @param type - * @param featured - * @param tags - * @example - * cy.insertPost('Title', 'Content', 'post', false, false) - */ - insertPost( - title: string, - content: string, - type: string, - featured?: boolean, - tags?: boolean, - ): void; - - /** - * Click on update button on a published post - * - * @example - * cy.updatePost() - */ - updatePost(): void; - - /** - * Gets the selector from Customizer Control - * - * @param slug - * @example - * cy.getCustomizerControl('neve_global') - */ - getCustomizerControl(slug: string): Chainable; - /** * Capture and compare the fullpage snapshots. * @@ -110,100 +49,5 @@ declare namespace Cypress { * cy.maskAndClip('#mask', '#clip') */ maskAndClip(maskSelectors: string, clipSelectors: string, hideElements?: string); - - /** - * Sets Customizer Settings using UI - * - * @param to - * @example - * cy.setCustomizeSettings({ hfg_header_layout: withSearch }) - */ - setCustomizeSettings(to: unknown): Chainable; - - /** - * Navigates to the customizer UI - * - * @example - * cy.goToCustomizer() - */ - goToCustomizer(): void; - - /** - * Alias POST route to /wp-admin/admin-ajax.php as customizerSave - * - * @example - * cy.aliasRestRoutes() - */ - aliasRestRoutes(): void; - - /** - * Toggle elements on or off - * - * @param show - * @example - * cy.toggleElements(false) - */ - toggleElements(show: boolean): void; - - /** - * Selector for a control - * - * @param control - * @example - * cy.getControl('neve_sidebar') - */ - getControl(control: string): Chainable; - - /** - * Activates a checkbox - * - * @param checkboxSelector - * @param checkboxText - * @example - * cy.activateCheckbox('#neve', 'check text') - */ - activateCheckbox(checkboxSelector: string, checkboxText: string): void; - - /** - * Opens sidebar on Neve Options - * - * @example - * cy.openNeveSidebar() - */ - openNeveSidebar(): Chainable; - - /** - * Activates Classic editor plugin - * - * @example - * cy.activateClassicEditorPlugin() - */ - activateClassicEditorPlugin(): void; - - /** - * Deactivates Classic editor plugin - * - * @example - * cy.deactivateClassicEditorPlugin() - */ - deactivateClassicEditorPlugin(): void; - - /** - * Get a JWT token to send request to Wordpress REST API - * - * @example cy.getJWT() - */ - getJWT(): void; - - /** - * Updates a post or page by request to WP Rest API. - * Needs a valid JWT set on local storage. - * - * @param postId - * @param type - * @param body - * @example cy.updatePageOrPostByRequest('12', { size: '20px' }) - */ - updatePageOrPostByRequest(postId: string, type: string, body): Chainable; } } diff --git a/e2e-tests/package.json b/e2e-tests/package.json index 8999f86c58..943bf1af62 100644 --- a/e2e-tests/package.json +++ b/e2e-tests/package.json @@ -17,17 +17,20 @@ }, "devDependencies": { "@percy/cypress": "^2.3.4", + "@testing-library/cypress": "^7.0.6", "@typescript-eslint/eslint-plugin": "^4.19.0", "@typescript-eslint/parser": "^4.19.0", "@wordpress/scripts": "^14.0.1", "cypress": "^6.8.0", "cypress-file-upload": "^5.0.3", "cypress-localstorage-commands": "^1.4.1", + "cypress-nv-commands": "^1.0.20", "cypress-storybook": "^0.5.1", "eslint": "^7.22.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-chai-friendly": "^0.6.0", "eslint-plugin-cypress": "^2.11.2", + "eslint-plugin-prettier": "^3.4.0", "prettier": "^2.2.1", "scroll-to-bottomjs": "^1.1.0", "typescript": "^4.2.3", @@ -38,7 +41,7 @@ "cypress:open": "cypress open", "cypress:storybook:open": "cypress open --config-file cypress.storybook.json", "cypress:run": "cypress run", - "cypress:storybook:run": "wait-on http://localhost:6006 && cypress run --config-file cypress.storybook.json --record", + "cypress:storybook:run": "wait-on http://localhost:6006 && cypress run --config-file cypress.storybook.json", "visual:test": "percy exec -- cypress run --config baseUrl=https://qa-neve.themeisle.com,video=false --spec 'cypress/integration/visual-regression/**/*.spec.js' --headless" } } diff --git a/e2e-tests/tsconfig.json b/e2e-tests/tsconfig.json index 415e004d6d..33f690139f 100644 --- a/e2e-tests/tsconfig.json +++ b/e2e-tests/tsconfig.json @@ -4,7 +4,7 @@ "target": "es5", "downlevelIteration": true, "lib": ["es5", "dom"], - "types": ["cypress", "node", "cypress-storybook/cypress"] + "types": ["cypress", "node", "cypress-storybook/cypress", "cypress-nv-commands", "@testing-library/cypress"] }, "include": [ "cypress/**/**/*.ts", diff --git a/e2e-tests/yarn.lock b/e2e-tests/yarn.lock index 38e5b7d376..deb28d44bd 100644 --- a/e2e-tests/yarn.lock +++ b/e2e-tests/yarn.lock @@ -16,6 +16,13 @@ dependencies: "@babel/highlight" "^7.12.13" +"@babel/code-frame@^7.10.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + "@babel/compat-data@^7.13.0", "@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.8": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.12.tgz#a8a5ccac19c200f9dd49624cac6e19d7be1236a1" @@ -226,6 +233,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@babel/helper-validator-identifier@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" + integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== + "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" @@ -259,6 +271,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.7.0": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1" @@ -1614,11 +1635,38 @@ "@svgr/plugin-svgo" "^5.5.0" loader-utils "^2.0.0" +"@testing-library/cypress@^7.0.6": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@testing-library/cypress/-/cypress-7.0.6.tgz#5445dac4f4852c26901c356e9d3a69371bd20ccf" + integrity sha512-atnjqlkEt6spU4Mv7evvpA8fMXeRw7AN2uTKOR1dP6WBvBixVwAYMZY+1fMOaZULWAj9vGLCXXvmw++u3TxuCQ== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^7.28.1" + +"@testing-library/dom@^7.28.1": + version "7.31.2" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a" + integrity sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^4.2.0" + aria-query "^4.2.2" + chalk "^4.1.0" + dom-accessibility-api "^0.5.6" + lz-string "^1.4.4" + pretty-format "^26.6.2" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/aria-query@^4.2.0": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" + integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.14" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402" @@ -4047,6 +4095,11 @@ cypress-localstorage-commands@^1.4.1: resolved "https://registry.yarnpkg.com/cypress-localstorage-commands/-/cypress-localstorage-commands-1.4.1.tgz#3df86b88b98919332af7720be2d10314bdb1222d" integrity sha512-rO8/hWu04o9w+gv8l70ew8QWBy3bGUiablQQzm4l3bWkGBVa4+kWXTuokrq6AZdO1/xv4rs4OBjN7sKDRl1JhQ== +cypress-nv-commands@^1.0.20: + version "1.0.24" + resolved "https://registry.yarnpkg.com/cypress-nv-commands/-/cypress-nv-commands-1.0.24.tgz#ba866df04999d41e548917aeaa31fb5146c59a95" + integrity sha512-Md5fxH51osRIigOHjSv2xfhw0BVrbC+npL474MVL3g5YQwpqFcx/k83QQqVj7d6hFjw0Iuy7zu1uqHxWetebmw== + cypress-storybook@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/cypress-storybook/-/cypress-storybook-0.5.1.tgz#e71b14ecfbe16a70b9f003c8294143ef466db78f" @@ -4328,6 +4381,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-accessibility-api@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9" + integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw== + dom-serializer@0: version "0.2.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" @@ -4809,6 +4867,13 @@ eslint-plugin-prettier@^3.3.0: dependencies: prettier-linter-helpers "^1.0.0" +eslint-plugin-prettier@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" + integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-react-hooks@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" @@ -7650,6 +7715,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lz-string@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" + integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= + make-dir@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" diff --git a/functions.php b/functions.php index 2fb55fe5d7..d1d22a6786 100644 --- a/functions.php +++ b/functions.php @@ -26,7 +26,7 @@ $_neve_bootstrap_errors = new WP_Error(); -if ( version_compare( PHP_VERSION, '5.5' ) < 0 ) { +if ( version_compare( PHP_VERSION, '7.0' ) < 0 ) { $_neve_bootstrap_errors->add( 'minimum_php_version', sprintf( @@ -37,7 +37,7 @@ '%s', __( 'upgrading PHP to the latest version', 'neve' ) ), - '5.5+' + '7.0' ) ); } @@ -111,5 +111,27 @@ function neve_filter_sdk( $products ) { require_once 'globals/sanitize-functions.php'; require_once get_template_directory() . '/start.php'; +/** + * If the new widget editor is available, + * we re-assign the widgets to hfg_footer + */ +if ( neve_is_new_widget_editor() ) { + /** + * Re-assign the widgets to hfg_footer + * + * @param array $section_args The section arguments. + * @param string $section_id The section ID. + * @param string $sidebar_id The sidebar ID. + * + * @return mixed + */ + function neve_customizer_custom_widget_areas( $section_args, $section_id, $sidebar_id ) { + if ( strpos( $section_id, 'widgets-footer' ) ) { + $section_args['panel'] = 'hfg_footer'; + } + return $section_args; + } + add_filter( 'customizer_widgets_section_args', 'neve_customizer_custom_widget_areas', 10, 3 ); +} require_once get_template_directory() . '/header-footer-grid/loader.php'; diff --git a/globals/migrations.php b/globals/migrations.php index 98b69cede5..1a53ae9435 100644 --- a/globals/migrations.php +++ b/globals/migrations.php @@ -13,6 +13,51 @@ * @return array */ function neve_get_button_appearance_default( $button = 'button' ) { + $new_skin = neve_is_new_skin(); + if ( $new_skin ) { + if ( $button !== 'button' ) { + return [ + 'type' => 'outline', + 'background' => '', + 'backgroundHover' => '', + 'text' => 'var(--nv-primary-accent)', + 'textHover' => 'var(--nv-primary-accent)', + 'borderRadius' => [ + 'top' => 3, + 'right' => 3, + 'bottom' => 3, + 'left' => 3, + ], + 'borderWidth' => [ + 'top' => 3, + 'right' => 3, + 'bottom' => 3, + 'left' => 3, + ], + ]; + } + + return [ + 'type' => 'fill', + 'background' => 'var(--nv-primary-accent)', + 'backgroundHover' => 'var(--nv-primary-accent)', + 'text' => '#ffffff', + 'textHover' => '#ffffff', + 'borderRadius' => [ + 'top' => 3, + 'right' => 3, + 'bottom' => 3, + 'left' => 3, + ], + 'borderWidth' => [ + 'top' => 1, + 'right' => 1, + 'bottom' => 1, + 'left' => 1, + ], + ]; + } + $defaults = [ 'type' => 'fill', 'background' => '', @@ -20,10 +65,10 @@ function neve_get_button_appearance_default( $button = 'button' ) { 'text' => '', 'textHover' => '', 'borderRadius' => [ - 'top' => 3, - 'right' => 3, - 'botttom' => 3, - 'left' => 3, + 'top' => 3, + 'right' => 3, + 'bottom' => 3, + 'left' => 3, ], 'borderWidth' => [ 'top' => 1, @@ -36,7 +81,12 @@ function neve_get_button_appearance_default( $button = 'button' ) { $defaults['type'] = 'outline'; $defaults['text'] = get_theme_mod( 'neve_secondary_button_color' ) ? get_theme_mod( 'neve_secondary_button_color' ) : 'var(--nv-text-color)'; $defaults['textHover'] = get_theme_mod( 'neve_secondary_button_hover_color' ) ? get_theme_mod( 'neve_secondary_button_hover_color' ) : 'var(--nv-text-color)'; - $defaults['borderRadius'] = get_theme_mod( 'neve_secondary_button_border_radius' ) ? get_theme_mod( 'neve_secondary_button_border_radius' ) : 3; + $defaults['borderRadius'] = get_theme_mod( 'neve_secondary_button_border_radius' ) ? get_theme_mod( 'neve_secondary_button_border_radius' ) : [ + 'top' => 3, + 'right' => 3, + 'bottom' => 3, + 'left' => 3, + ]; return $defaults; } @@ -44,7 +94,12 @@ function neve_get_button_appearance_default( $button = 'button' ) { $defaults['backgroundHover'] = get_theme_mod( 'neve_button_hover_color' ) ? get_theme_mod( 'neve_button_hover_color' ) : 'var(--nv-primary-accent)'; $defaults['text'] = get_theme_mod( 'neve_button_text_color' ) ? get_theme_mod( 'neve_button_text_color' ) : '#ffffff'; $defaults['textHover'] = get_theme_mod( 'neve_button_hover_text_color' ) ? get_theme_mod( 'neve_button_hover_text_color' ) : '#ffffff'; - $defaults['borderRadius'] = get_theme_mod( 'neve_button_border_radius' ) ? get_theme_mod( 'neve_button_border_radius' ) : 3; + $defaults['borderRadius'] = get_theme_mod( 'neve_button_border_radius' ) ? get_theme_mod( 'neve_button_border_radius' ) : [ + 'top' => 3, + 'right' => 3, + 'bottom' => 3, + 'left' => 3, + ]; return $defaults; } diff --git a/globals/sanitize-functions.php b/globals/sanitize-functions.php index a3e1ddffe6..07203937ad 100644 --- a/globals/sanitize-functions.php +++ b/globals/sanitize-functions.php @@ -91,9 +91,9 @@ function neve_sanitize_range_value( $input ) { return floatval( $input ); } $range_value = json_decode( $input, true ); - $range_value['desktop'] = is_numeric( $range_value['desktop'] ) ? floatval( $range_value['desktop'] ) : ''; - $range_value['tablet'] = is_numeric( $range_value['tablet'] ) ? floatval( $range_value['tablet'] ) : ''; - $range_value['mobile'] = is_numeric( $range_value['mobile'] ) ? floatval( $range_value['mobile'] ) : ''; + $range_value['desktop'] = isset( $range_value['desktop'] ) && is_numeric( $range_value['desktop'] ) ? floatval( $range_value['desktop'] ) : ''; + $range_value['tablet'] = isset( $range_value['tablet'] ) && is_numeric( $range_value['tablet'] ) ? floatval( $range_value['tablet'] ) : ''; + $range_value['mobile'] = isset( $range_value['mobile'] ) && is_numeric( $range_value['mobile'] ) ? floatval( $range_value['mobile'] ) : ''; return wp_json_encode( $range_value ); } @@ -206,3 +206,132 @@ function neve_sanitize_typography_control( $value ) { return $value; } + +/** + * Sanitize alignment. + * + * @param array $input alignment responsive array. + * + * @return array + */ +function neve_sanitize_alignment( $input ) { + $default = [ + 'mobile' => 'left', + 'tablet' => 'left', + 'desktop' => 'left', + ]; + $allowed = [ 'left', 'center', 'right', 'justify' ]; + + if ( ! is_array( $input ) ) { + return $default; + } + + foreach ( $input as $device => $alignment ) { + if ( ! in_array( $alignment, $allowed ) ) { + $input[ $device ] = 'left'; + } + } + + return $input; +} + +/** + * Sanitize position. + * + * @param array $input alignment responsive array. + * + * @return array + */ +function neve_sanitize_position( $input ) { + $default = [ + 'mobile' => 'center', + 'tablet' => 'center', + 'desktop' => 'center', + ]; + $allowed = [ 'flex-start', 'center', 'flex-end' ]; + + if ( ! is_array( $input ) ) { + return $default; + } + + foreach ( $input as $device => $alignment ) { + if ( ! in_array( $alignment, $allowed ) ) { + $input[ $device ] = 'center'; + } + } + + return $input; +} + +/** + * Sanitize meta order control. + */ +function neve_sanitize_meta_ordering( $value ) { + $allowed = array( + 'author', + 'category', + 'date', + 'comments', + 'reading', + ); + + if ( empty( $value ) ) { + return $allowed; + } + + $decoded = json_decode( $value, true ); + + foreach ( $decoded as $val ) { + if ( ! in_array( $val, $allowed, true ) ) { + return $allowed; + } + } + + return $value; +} + +/** + * Sanitize blend mode option. + * + * @param string $input Control input. + * + * @return string + */ +function neve_sanitize_blend_mode( $input ) { + $blend_mode_options = [ 'normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'saturation', 'color', 'difference', 'exclusion', 'hue', 'luminosity' ]; + if ( ! in_array( $input, $blend_mode_options, true ) ) { + return 'normal'; + } + return $input; +} + +/** + * Sanitize the container layout value + * + * @param string $value value from the control. + * + * @return bool + */ +function neve_sanitize_container_layout( $value ) { + $allowed_values = array( 'contained', 'full-width' ); + if ( ! in_array( $value, $allowed_values, true ) ) { + return 'contained'; + } + + return esc_html( $value ); +} + +/** + * Sanitize Button Type option. + * + * @param string $value the control value. + * + * @return string + */ +function neve_sanitize_button_type( $value ) { + if ( ! in_array( $value, [ 'primary', 'secondary' ], true ) ) { + return 'primary'; + } + + return $value; +} diff --git a/globals/utilities.php b/globals/utilities.php index c339330bb3..1f3590b0a2 100644 --- a/globals/utilities.php +++ b/globals/utilities.php @@ -1328,19 +1328,92 @@ function neve_get_headings_selectors() { ); } +/** + * Return ready to use external anchor tag. + * + * This should be used only in admin context, i.e options page, customizer + * and it will automatically be switched off if the whitelabel is on. + * + * @param string $link Link url. + * @param string $text Link text. + * @param bool $echo Echo the result. + * + * @return string Full anchor tag. + */ +function neve_external_link( $link, $text = '', $echo = false ) { + $text = empty( $text ) ? __( 'Learn More', 'neve' ) : $text; + $return = sprintf( + '%s%s', + esc_html__( '(opens in a new tab)', 'neve' ), + esc_html( $text ) + ); + $is_whitelabel = apply_filters( 'neve_is_theme_whitelabeled', false ) || apply_filters( 'neve_is_plugin_whitelabeled', false ); + if ( $is_whitelabel ) { + return ''; + } + if ( ! $echo ) { + return $return; + } + echo $return; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, Already escaped. + return ''; +} + +add_filter( 'neve_external_link', 'neve_external_link', 10, 3 ); /** * Get Global Colors Default * * @param bool $migrated get with migrated colors. + * * @return array */ function neve_get_global_colors_default( $migrated = false ) { + if ( neve_is_new_skin() ) { + return [ + 'activePalette' => 'base', + 'palettes' => [ + 'base' => [ + 'name' => __( 'Base', 'neve' ), + 'allowDeletion' => false, + 'colors' => [ + 'nv-primary-accent' => '#2f5aae', + 'nv-secondary-accent' => '#2f5aae', + 'nv-site-bg' => '#ffffff', + 'nv-light-bg' => '#f4f5f7', + 'nv-dark-bg' => '#121212', + 'nv-text-color' => '#272626', + 'nv-text-dark-bg' => '#ffffff', + 'nv-c-1' => '#9463ae', + 'nv-c-2' => '#be574b', + ], + ], + 'darkMode' => [ + 'name' => __( 'Dark Mode', 'neve' ), + 'allowDeletion' => false, + 'colors' => [ + 'nv-primary-accent' => '#00c2ff', + 'nv-secondary-accent' => '#00c2ff', + 'nv-site-bg' => '#121212', + 'nv-light-bg' => '#1a1a1a', + 'nv-dark-bg' => '#000000', + 'nv-text-color' => '#ffffff', + 'nv-text-dark-bg' => '#ffffff', + 'nv-c-1' => '#198754', + 'nv-c-2' => '#be574b', + ], + ], + ], + ]; + } $old_link_color = get_theme_mod( 'neve_link_color', '#0366d6' ); $old_link_hover_color = get_theme_mod( 'neve_link_hover_color', '#0e509a' ); $old_text_color = get_theme_mod( 'neve_text_color', '#393939' ); - $old_bg_color = '#' . get_theme_mod( 'background_color', 'ffffff' ); + // We use a static var to avoid calling get_theme_mod multiple times due to the filter used to alter the value. + static $old_bg_color; + if ( ! isset( $old_bg_color ) ) { + $old_bg_color = '#' . get_theme_mod( 'background_color', 'ffffff' ); + } add_filter( 'theme_mod_background_color', '__return_empty_string' ); return [ @@ -1379,3 +1452,62 @@ function neve_get_global_colors_default( $migrated = false ) { ], ]; } + +/** + * Checks that we are using the new builder. + * + * @return bool + * @since 3.0.0 + */ +function neve_is_new_builder() { + return get_theme_mod( 'neve_migrated_builders', true ); +} + +/** + * Checks that we are using the new skin. + * + * @return bool + * @since 3.0.0 + */ +function neve_is_new_skin() { + return get_theme_mod( 'neve_new_skin', 'new' ) !== 'old'; +} + +/** + * Check that we can use conditional headers in PRO. + * + * @return bool + * @since 3.0.0 + */ +function neve_can_use_conditional_header() { + return defined( 'NEVE_PRO_COMPATIBILITY_FEATURES' ) && isset( NEVE_PRO_COMPATIBILITY_FEATURES['headerv2'] ) && neve_is_new_builder(); +} + +/** + * Check that we had old builder. + * + * @return bool + * @since 3.0.0 + */ +function neve_had_old_hfb() { + return ( get_theme_mod( 'hfg_header_layout' ) !== false || get_theme_mod( 'hfg_footer_layout' ) ) !== false; +} + +/** + * Check if we have pro support. + * + * @param string $feature feature to check support for. + */ +function neve_pro_has_support( $feature ) { + return ( defined( 'NEVE_PRO_COMPATIBILITY_FEATURES' ) && isset( NEVE_PRO_COMPATIBILITY_FEATURES[ $feature ] ) ); +} + +/** + * Check that if new widget editor is available. + * + * @return bool + * @since 3.0.0 + */ +function neve_is_new_widget_editor() { + return ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '10.6.2', '>' ) ) || version_compare( substr( get_bloginfo( 'version' ), 0, 3 ), '5.8', '>=' ); +} diff --git a/grunt/cssmin.js b/grunt/cssmin.js index 0a597dd53e..38ace8fa59 100644 --- a/grunt/cssmin.js +++ b/grunt/cssmin.js @@ -8,25 +8,65 @@ module.exports = { keepSpecialComments: 0, level: { 1: { - specialComments: 0 - } - } + specialComments: 0, + }, + }, }, customizerStyle: { files: { - 'assets/css/customizer-style.min.css': ['assets/css/customizer-style.css'], - 'assets/css/customizer-style-rtl.min.css': ['assets/css/customizer-style-rtl.css'], + 'assets/css/customizer-style.min.css': [ + 'assets/css/customizer-style.css', + ], + 'assets/css/customizer-style-rtl.min.css': [ + 'assets/css/customizer-style-rtl.css', + ], + + 'assets/css/mega-menu-legacy.min.css': [ + 'assets/css/mega-menu-legacy.css', + ], 'assets/css/mega-menu.min.css': ['assets/css/mega-menu.css'], - 'assets/css/mega-menu-rtl.min.css': ['assets/css/mega-menu-rtl.css'], + 'assets/css/mega-menu-rtl.min.css': [ + 'assets/css/mega-menu-rtl.css', + ], + 'assets/css/mega-menu-legacy-rtl.min.css': [ + 'assets/css/mega-menu-legacy-rtl.css', + ], + 'style-main-rtl.min.css': ['style-main-rtl.css'], - 'header-footer-grid/assets/css/style-rtl.min.css': ['header-footer-grid/assets/css/style-rtl.css'], - 'header-footer-grid/assets/css/style.min.css': ['header-footer-grid/assets/css/style.css'], + 'assets/css/style-legacy-rtl.min.css': [ + 'assets/css/style-legacy-rtl.css', + ], + 'header-footer-grid/assets/css/style-rtl.min.css': [ + 'header-footer-grid/assets/css/style-rtl.css', + ], + 'header-footer-grid/assets/css/style.min.css': [ + 'header-footer-grid/assets/css/style.css', + ], 'style-main.min.css': ['style-main.css'], - 'assets/css/customizer-preview.min.css': ['assets/css/customizer-preview.css'], + 'assets/css/style-legacy.min.css': ['assets/css/style-legacy.css'], + 'assets/css/customizer-preview.min.css': [ + 'assets/css/customizer-preview.css', + ], 'assets/css/woocommerce.min.css': ['assets/css/woocommerce.css'], - 'assets/css/woocommerce-rtl.min.css': ['assets/css/woocommerce-rtl.css'], + 'assets/css/woocommerce-rtl.min.css': [ + 'assets/css/woocommerce-rtl.css', + ], + 'assets/css/woocommerce-legacy.min.css': [ + 'assets/css/woocommerce-legacy.css', + ], + 'assets/css/woocommerce-legacy-rtl.min.css': [ + 'assets/css/woocommerce-legacy-rtl.css', + ], 'assets/css/lifter.min.css': ['assets/css/lifter.css'], - 'assets/css/gutenberg-editor-style.min.css': ['assets/css/gutenberg-editor-style.css'], - } - } + 'assets/css/lifter-legacy.min.css': [ + 'assets/css/lifter-legacy.css', + ], + 'assets/css/gutenberg-editor-style.min.css': [ + 'assets/css/gutenberg-editor-style.css', + ], + 'assets/css/gutenberg-editor-legacy-style.min.css': [ + 'assets/css/gutenberg-editor-legacy-style.css', + ], + }, + }, }; diff --git a/grunt/rtlcss.js b/grunt/rtlcss.js index 06a3fb252f..cc9809c624 100644 --- a/grunt/rtlcss.js +++ b/grunt/rtlcss.js @@ -12,8 +12,8 @@ const options = { { name: 'left-right', priority: 100, - search: [ 'left', 'Left', 'LEFT' ], - replace: [ 'right', 'Right', 'RIGHT' ], + search: ['left', 'Left', 'LEFT'], + replace: ['right', 'Right', 'RIGHT'], options: { scope: '*', ignoreCase: false, @@ -22,8 +22,8 @@ const options = { { name: 'ltr-rtl', priority: 100, - search: [ 'ltr', 'Ltr', 'LTR' ], - replace: [ 'rtl', 'Rtl', 'RTL' ], + search: ['ltr', 'Ltr', 'LTR'], + replace: ['rtl', 'Rtl', 'RTL'], options: { scope: '*', ignoreCase: false, @@ -39,7 +39,15 @@ module.exports = { cwd: './', dest: './', ext, - src: [ 'style-main.css' ], + src: ['style-main.css'], + }, + styleLegacy: { + options, + expand: true, + cwd: './assets/css', + dest: './assets/css', + ext, + src: ['style-legacy.css'], }, woocommerce: { options, @@ -47,7 +55,15 @@ module.exports = { cwd: './assets/css/', dest: './assets/css/', ext, - src: [ 'woocommerce.css' ], + src: ['woocommerce.css'], + }, + woocommerceLegacy: { + options, + expand: true, + cwd: './assets/css/', + dest: './assets/css/', + ext, + src: ['woocommerce-legacy.css'], }, customizerStyle: { options, @@ -55,7 +71,7 @@ module.exports = { cwd: './assets/css/', dest: './assets/css/', ext, - src: [ 'customizer-style.css' ], + src: ['customizer-style.css'], }, reactControls: { options, @@ -63,7 +79,7 @@ module.exports = { cwd: './inc/customizer/controls/react/bundle', dest: './inc/customizer/controls/react/bundle', ext, - src: [ 'style-controls.css' ], + src: ['style-controls.css'], }, megaMenu: { options, @@ -71,7 +87,15 @@ module.exports = { cwd: './assets/css/', dest: './assets/css/', ext, - src: [ 'mega-menu.css' ], + src: ['mega-menu.css'], + }, + megaMenuLegacy: { + options, + expand: true, + cwd: './assets/css/', + dest: './assets/css/', + ext, + src: ['mega-menu-legacy.css'], }, hfg: { options, @@ -79,7 +103,7 @@ module.exports = { cwd: './header-footer-grid/assets/css/', dest: './header-footer-grid/assets/css/', ext, - src: [ 'style.css' ], + src: ['style.css'], }, dashboard: { options, @@ -87,6 +111,6 @@ module.exports = { cwd: './dashboard/build/', dest: './dashboard/build/', ext, - src: [ 'style-dashboard.css' ], + src: ['style-dashboard.css'], }, }; diff --git a/grunt/sass.js b/grunt/sass.js index ebab51ff24..881988c50a 100644 --- a/grunt/sass.js +++ b/grunt/sass.js @@ -10,13 +10,26 @@ module.exports = { outputStyle: 'expanded', sourceMap: true, }, - files: [ { - 'style-main.css': 'assets/scss/style.scss', - 'assets/css/customizer-preview.css': 'assets/scss/customizer-preview.scss', - 'assets/css/mega-menu.css': 'assets/scss/mega-menu.scss', - 'assets/css/woocommerce.css': 'assets/scss/woocommerce.scss', - 'assets/css/lifter.css': 'assets/scss/lifter.scss', - 'assets/css/gutenberg-editor-style.css': 'assets/scss/gutenberg-editor-style.scss', - } ] + files: [ + { + 'style-main.css': 'assets/scss/style.scss', + 'assets/css/style-legacy.css': 'assets/scss/style-legacy.scss', + 'assets/css/customizer-preview.css': + 'assets/scss/customizer-preview.scss', + 'assets/css/mega-menu.css': 'assets/scss/mega-menu.scss', + 'assets/css/mega-menu-legacy.css': + 'assets/scss/mega-menu-legacy.scss', + 'assets/css/woocommerce.css': 'assets/scss/woocommerce.scss', + 'assets/css/woocommerce-legacy.css': + 'assets/scss/woocommerce-legacy.scss', + 'assets/css/lifter.css': 'assets/scss/lifter.scss', + 'assets/css/lifter-legacy.css': + 'assets/scss/lifter-legacy.scss', + 'assets/css/gutenberg-editor-style.css': + 'assets/scss/gutenberg-editor-style.scss', + 'assets/css/gutenberg-editor-legacy-style.css': + 'assets/scss/gutenberg-editor-legacy-style.scss', + }, + ], }, }; diff --git a/header-footer-grid/Core/Builder/Abstract_Builder.php b/header-footer-grid/Core/Builder/Abstract_Builder.php index ac633fe0ba..87edb4bd9b 100644 --- a/header-footer-grid/Core/Builder/Abstract_Builder.php +++ b/header-footer-grid/Core/Builder/Abstract_Builder.php @@ -13,16 +13,14 @@ use HFG\Core\Components\Abstract_Component; use HFG\Core\Css_Generator; -use HFG\Core\Customizer\Instructions_Section; use HFG\Core\Interfaces\Builder; use HFG\Core\Interfaces\Component; use HFG\Core\Settings; use HFG\Core\Settings\Manager as SettingsManager; use HFG\Traits\Core; use Neve\Core\Settings\Config; -use Neve\Core\Styles\Css_Prop; use Neve\Core\Styles\Dynamic_Selector; -use Neve_Pro\Modules\Blog_Pro\Dynamic_Style; +use Neve\Customizer\Controls\React\Instructions_Section; use WP_Customize_Manager; /** @@ -34,6 +32,8 @@ abstract class Abstract_Builder implements Builder { use Core; const LAYOUT_SETTING = 'layout'; + const COLUMNS_NUMBER = 'columns_number'; + const COLUMNS_LAYOUT = 'columns_layout'; const HEIGHT_SETTING = 'height'; const SKIN_SETTING = 'skin'; const TEXT_COLOR = 'new_text_color'; @@ -65,6 +65,13 @@ abstract class Abstract_Builder implements Builder { */ public static $current_row = null; + /** + * Internal pointer for current slot id. + * + * @var null|string Slot id. + */ + public static $current_slot = null; + /** * Internal pointer for current component id. * @@ -86,6 +93,14 @@ abstract class Abstract_Builder implements Builder { * @var string $control_id */ protected $control_id; + /** + * Holds the layout control id. + * + * @since 3.0.0 + * @access protected + * @var string $layout_control_id + */ + protected $layout_control_id; /** * Holds the panel id. * @@ -191,6 +206,13 @@ abstract class Abstract_Builder implements Builder { */ protected $instructions_array = array(); + /** + * Does this layout have columns? + * + * @var boolean + */ + protected $columns_layout = false; + /** * Abstract_Builder constructor. * @@ -198,19 +220,21 @@ abstract class Abstract_Builder implements Builder { * @access public */ public function __construct() { - $this->set_property( 'control_id', 'hfg_' . $this->get_id() . '_layout' ); + $this->set_property( 'layout_control_id', $this->control_id . ( neve_is_new_builder() ? '_v2' : '' ) ); $this->set_property( 'panel', 'hfg_' . $this->get_id() ); $this->set_property( 'section', $this->control_id . '_section' ); $this->init(); add_action( 'hfg_' . $this->get_id() . '_render', [ $this, 'load_template' ] ); - $this->define_builder_settings(); foreach ( $this->get_rows() as $row_id => $row_name ) { $this->define_row_settings( $row_id ); } + + add_filter( 'hfg_header_row_classes', [ $this, 'add_header_row_utility_classes' ], 10, 2 ); + add_filter( 'hfg_page_header_row_classes', [ $this, 'add_header_row_utility_classes' ], 10, 2 ); } /** @@ -236,20 +260,28 @@ protected function set_property( $key = '', $value = '' ) { * Define builder settings. */ public function define_builder_settings() { + $is_new_builder = neve_is_new_builder(); SettingsManager::get_instance()->add( [ - 'id' => $this->control_id, - 'group' => $this->control_id, - 'noformat' => true, - 'transport' => 'post' . $this->get_id(), - 'sanitize_callback' => [ $this, 'sanitize_json' ], - 'default' => '', - 'label' => '', - 'type' => 'text', - 'section' => $this->section, + 'id' => $this->layout_control_id, + 'group' => $this->control_id, + 'tab' => false, + 'noformat' => true, + 'transport' => 'post' . $this->get_id(), + 'sanitize_callback' => [ $this, 'sanitize_json' ], + 'default' => '', + 'label' => '', + 'type' => $is_new_builder ? '\Neve\Customizer\Controls\React\Builder' : 'text', + 'options' => [ + 'builder_type' => $this->get_id(), + 'columns_layout' => $this->columns_layout, + ], + 'conditional_header' => $this->get_id() === 'header', + 'section' => $this->section, ] ); + do_action( 'hfg_row_settings', $this->get_id(), $this->control_id ); } @@ -316,6 +348,7 @@ public function define_row_settings( $row_id ) { 'default' => 'layout-full-contained', ] ); + SettingsManager::get_instance()->add( [ 'id' => self::HEIGHT_SETTING, @@ -325,22 +358,28 @@ public function define_row_settings( $row_id ) { 'label' => __( 'Row height', 'neve' ), 'type' => '\Neve\Customizer\Controls\React\Responsive_Range', 'live_refresh_selector' => $row_class, - 'live_refresh_css_prop' => array( - 'prop' => 'height', - 'unit' => 'px', - ), + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--height', + 'suffix' => 'px', + 'fallback' => 'auto', + 'selector' => $row_class, + ], + 'prop' => 'height', + 'unit' => 'px', + ], 'options' => [ 'input_attrs' => [ - 'step' => 1, - 'min' => 0, - 'max' => 700, - 'defaultVal' => [ + 'step' => 1, + 'min' => 0, + 'max' => 700, + 'defaultVal' => [ 'mobile' => 0, 'tablet' => 0, 'desktop' => 0, ], - 'units' => [ 'px' ], - 'hideResponsive' => true, + 'units' => [ 'px' ], ], ], 'transport' => 'postMessage', @@ -351,6 +390,10 @@ public function define_row_settings( $row_id ) { ); } + if ( $this->columns_layout && neve_is_new_builder() ) { + $this->add_columns_layout_controls( $row_setting_id ); + } + $default_colors = $this->get_default_row_colors( $row_id ); SettingsManager::get_instance()->add( [ @@ -361,7 +404,13 @@ public function define_row_settings( $row_id ) { 'label' => __( 'Row Background', 'neve' ), 'type' => 'neve_background_control', 'live_refresh_selector' => $row_id === 'sidebar' ? $row_class . ' .header-menu-sidebar-bg' : $row_class, - 'live_refresh_css_prop' => [ 'partial' => $row_id === 'sidebar' ? 'hfg_header_layout_partial' : $row_setting_id . '_partial' ], + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => 'backgroundControl', + 'selector' => $row_id === 'sidebar' ? '.header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_id, + ], + 'partial' => $row_id === 'sidebar' ? 'hfg_header_layout_partial' : $row_setting_id . '_partial', + ], 'options' => [ 'priority' => 100, ], @@ -389,6 +438,10 @@ public function define_row_settings( $row_id ) { 'transport' => 'postMessage', 'live_refresh_selector' => $row_class, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => $row_class, + ], 'partial' => $row_id === 'sidebar' ? 'hfg_header_layout_partial' : $row_setting_id . '_partial', ], 'sanitize_callback' => 'wp_filter_nohtml_kses', @@ -520,7 +573,7 @@ public function customize_register( WP_Customize_Manager $wp_customize ) { $wp_customize, $this->section . '_quick_links', array( - 'priority' => -100, + 'priority' => - 100, 'panel' => $this->panel, 'type' => 'hfg_instructions', 'options' => $this->instructions_array, @@ -622,6 +675,15 @@ public function get_current_row_index() { return self::$current_row; } + /** + * Return current slot in the loop. + * + * @return null|string Current slot. + */ + public function get_current_slot_index() { + return self::$current_slot; + } + /** * Render markup for builder. */ @@ -654,7 +716,9 @@ public function get_layout_data() { if ( ! empty( $this->layout_data ) ) { return $this->layout_data; } - $this->layout_data = wp_parse_args( json_decode( SettingsManager::get_instance()->get( 'hfg_' . $this->get_id() . '_layout' ), true ), array_fill_keys( array_keys( $this->devices ), array_fill_keys( array_keys( $this->get_rows() ), [] ) ) ); + $mod_value = json_decode( SettingsManager::get_instance()->get( $this->layout_control_id ), true ); + + $this->layout_data = wp_parse_args( $mod_value, array_fill_keys( array_keys( $this->devices ), array_fill_keys( array_keys( $this->get_rows() ), [] ) ) ); return $this->layout_data; } @@ -686,13 +750,28 @@ public function is_row_used( $row_id ) { public function is_component_active( $component_id ) { if ( empty( $this->active_components ) ) { $components = []; + foreach ( $this->get_layout_data() as $devices ) { - foreach ( $devices as $row ) { - if ( empty( $row ) ) { + foreach ( $devices as $row_index => $row ) { + if ( neve_is_new_builder() && $row_index !== 'sidebar' ) { + foreach ( $row as $slot ) { + if ( empty( $slot ) || ! is_array( $slot ) ) { + continue; + } + + $components = array_merge( $components, array_combine( wp_list_pluck( $slot, 'id' ), array_fill( 0, count( $slot ), true ) ) ); + } continue; } - $components = array_merge( $components, array_combine( wp_list_pluck( $row, 'id' ), array_fill( 0, count( $row ), true ) ) ); + // Legacy + $row_components = []; + foreach ( $row as $component ) { + if ( isset( $component['id'] ) ) { + $row_components[ $component['id'] ] = true; + } + } + $components = array_merge( $components, $row_components ); } } $this->active_components = $components; @@ -735,17 +814,16 @@ public function add_style( array $css_array = array() ) { } /** - * Method to generate css array for each row. + * Add legacy row styles. * - * @param string $row_index The row index. - * @param array $css_array The css array. + * @param array $css_array css array. + * @param string $row_index row index. * * @return array - * @since 1.0.0 - * @access private */ - private function add_row_style( $row_index, $css_array = array() ) { - $selector = $row_index === 'sidebar' ? '.header-menu-sidebar .header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_index . '-inner'; + private function add_legacy_row_styles( $css_array, $row_index ) { + $selector = $row_index === 'sidebar' ? '.header-menu-sidebar .header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_index . '-inner'; + $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => $selector, Dynamic_Selector::KEY_RULES => [ @@ -913,6 +991,148 @@ private function add_row_style( $row_index, $css_array = array() ) { return $css_array; } + /** + * Method to generate css array for each row. + * + * @param string $row_index The row index. + * @param array $css_array The css array. + * + * @return array + * @since 1.0.0 + * @access private + */ + private function add_row_style( $row_index, $css_array = array() ) { + if ( neve_is_new_builder() ) { + $css_array = $this->add_new_builder_styles( $css_array, $row_index ); + } + + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_row_styles( $css_array, $row_index ); + } + + $rules = []; + $selector = $row_index === 'sidebar' ? '.header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_index; + $default_colors = $this->get_default_row_colors( $row_index ); + + if ( $row_index !== 'sidebar' ) { + $rules['--height'] = [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_height', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + $value = (int) $value; + if ( $value > 0 ) { + return sprintf( '%s:%s;', $css_prop, $value . 'px' ); + } + + return ''; + }, + Dynamic_Selector::META_DEFAULT => '{ desktop: 0, tablet: 0, mobile: 0 }', + ]; + } + + $rules['--color'] = [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_' . self::TEXT_COLOR, + Dynamic_Selector::META_DEFAULT => $default_colors['text'], + ]; + + // If there is no default, use site background. + $default_color = isset( $default_colors['background'] ) ? $default_colors['background'] : 'var(--nv-site-bg)'; + + $background = get_theme_mod( + $this->control_id . '_' . $row_index . '_background', + [ + 'type' => 'color', + 'colorValue' => $default_color, + ] + ); + + if ( $background['type'] === 'color' && ! empty( $background['colorValue'] ) ) { + $rules = array_merge( + $rules, + [ + '--bgColor' => [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background.colorValue', + Dynamic_Selector::META_DEFAULT => $default_color, + ], + ] + ); + } + + if ( $background['type'] === 'image' ) { + $rules = array_merge( + $rules, + [ + '--overlayColor' => [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background.overlayColorValue', + ], + '--bgImage' => [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background', + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + $image = 'none'; + if ( isset( $value['useFeatured'] ) && $value['useFeatured'] === true && is_singular() ) { + $featured_image = get_the_post_thumbnail_url(); + if ( ! empty( $featured_image ) ) { + $image = sprintf( 'url("%s")', esc_url( $featured_image ) ); + } else { + $image = sprintf( 'url("%s")', esc_url( $value['imageUrl'] ) ); + } + } elseif ( ! empty( $value['imageUrl'] ) ) { + $image = sprintf( 'url("%s")', esc_url( $value['imageUrl'] ) ); + } + + return sprintf( '%s:%s;', $css_prop, $image ); + }, + ], + '--bgPosition' => [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background', + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + if ( empty( $value['focusPoint'] ) || empty( $value['focusPoint']['x'] ) || empty( $value['focusPoint']['y'] ) ) { + return ''; + } + + $parsed_position = round( $value['focusPoint']['x'] * 100 ) . '% ' . round( $value['focusPoint']['y'] * 100 ) . '%;'; + + return sprintf( '%s:%s;', $css_prop, $parsed_position ); + }, + ], + '--bgAttachment' => [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background', + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + if ( ! isset( $value['fixed'] ) || $value['fixed'] !== true ) { + return ''; + } + + return sprintf( '%s:fixed;', $css_prop ); + }, + ], + '--bgOverlayOpacity' => [ + Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background', + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + if ( ! isset( $value['overlayOpacity'] ) ) { + return ''; + } + + return sprintf( '%s:%s;', $css_prop, $value['overlayOpacity'] / 100 ); + }, + ], + ] + ); + } + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $selector, + Dynamic_Selector::KEY_RULES => $rules, + ]; + + + if ( $row_index === 'sidebar' ) { + $css_array = $this->add_sidebar_styles( $css_array ); + } + + + return $css_array; + } + /** * Render device markup. * @@ -920,12 +1140,292 @@ private function add_row_style( $row_index, $css_array = array() ) { * @param array $device_details Device meta. */ public function render_device( $device_name, $device_details ) { - foreach ( $device_details as $index => $row ) { - if ( empty( $row ) ) { + // Make sure we hold the defined order. + $default_order = array_keys( $this->get_rows() ); + foreach ( $default_order as $row_index ) { + if ( ! isset( $device_details[ $row_index ] ) ) { + continue; + } + $row = $device_details[ $row_index ]; + if ( neve_is_new_builder() ) { + $used = []; + foreach ( $row as $components ) { + $used = array_merge( $used, $components ); + } + + if ( empty( $used ) ) { + continue; + } + } elseif ( empty( $row ) ) { + continue; + } + self::$current_row = $row_index; + $this->render_row( $device_name, $row_index, $row ); + } + } + + /** + * Get the component alignment. + * + * @param string $id component id. + * @param false $vertical should get vertical alignment. + * + * @return array + */ + private function get_component_alignment( $id, $vertical = false ) { + if ( $vertical ) { + return SettingsManager::get_instance()->get( $id . '_' . Abstract_Component::VERTICAL_ALIGN_ID, null ); + } + + $alignment = SettingsManager::get_instance()->get( $id . '_' . Abstract_Component::ALIGNMENT_ID, null ); + + // Make sure we migrate old alignment values. + if ( is_array( $alignment ) ) { + return $alignment; + } + + $is_menu_component = strpos( $id, 'primary-menu' ) > - 1 || strpos( $id, 'secondary-menu' ); + $tmp_align = ( is_string( $alignment ) && in_array( + $alignment, + [ + 'left', + 'right', + 'center', + 'justify', + ] + ) ) ? $alignment : 'left'; + + return [ + 'desktop' => $tmp_align, + 'tablet' => $is_menu_component ? 'left' : $tmp_align, + 'mobile' => $is_menu_component ? 'left' : $tmp_align, + ]; + } + + /** + * Checks if a row has items inside a slot. + * + * @param string $slot slot to check in row. + * + * @return bool + */ + private function row_has_slot( $slot ) { + $current_row = $this->get_current_row_index(); + $layout_data = $this->get_layout_data(); + $device = $this->get_current_device(); + + if ( ! isset( $layout_data[ $device ] ) ) { + return false; + } + + if ( ! isset( $layout_data[ $device ][ $current_row ] ) ) { + return false; + } + + $row_data = $layout_data[ $device ][ $current_row ]; + + if ( ! isset( $row_data[ $slot ] ) || empty( $row_data[ $slot ] ) ) { + return false; + } + + return true; + } + + /** + * Add row utility classes. + * + * @param string $classes footer classes. + * @param string $row_index row index. + * + * @return mixed + */ + public function add_header_row_utility_classes( $classes, $row_index ) { + if ( $this->get_id() !== self::$current_builder ) { + return $classes; + } + + if ( $this->row_has_slot( 'center' ) ) { + $classes[] = 'has-center'; + } + + return $classes; + } + + /** + * Render the builder components. + * + * @param string $device the device [desktop|mobile]. + * @param string $row the row id. + */ + public function new_render_components( $device, $row ) { + $row_index = 0; + if ( $device === null && $row === null ) { + $device = self::$current_device; + $row_index = self::$current_row; + } + + $builder_id = $this->get_id(); + $data = $this->get_layout_data()[ $device ][ $row_index ]; + + // Remap sidebar data so we can use it as a slot. + if ( $row_index === 'sidebar' ) { + $data = [ 'sidebar' => $data ]; + } + + $render_buffer = [ + 'left' => [], + 'c-left' => [], + 'center' => [], + 'c-right' => [], + 'right' => [], + ]; + + foreach ( $data as $slot => $slot_data ) { + $is_side_slot = in_array( $slot, [ 'right', 'left' ], true ); + if ( ! ( $this->row_has_slot( 'center' ) && $is_side_slot ) && empty( $slot_data ) && $builder_id !== 'footer' ) { continue; } - self::$current_row = $index; - $this->render_row( $device_name, $index, $row ); + + $render_index = 0; + $was_previous_mergeable = false; + + foreach ( $slot_data as $component_index => $component ) { + if ( ! isset( $component['id'] ) ) { + continue; + } + + if ( ! isset( $this->builder_components[ $component['id'] ] ) ) { + continue; + } + + /** + * An instance of Abstract_Component + * + * @var Abstract_Component $component_instance + */ + $component_instance = $this->builder_components[ $component['id'] ]; + $is_mergeable = $component_instance->get_property( 'is_auto_width' ); + + if ( ! $is_mergeable && ! $was_previous_mergeable ) { + $render_index ++; + } + + if ( $row_index === 'sidebar' ) { + $render_index ++; + } + + $align = $this->get_component_alignment( $component['id'] ); + + $vertical_align = $this->get_component_alignment( $component['id'], true ); + $classes = [ 'builder-item' ]; + + if ( strpos( $component['id'], 'primary-menu' ) > - 1 ) { + $classes[] = 'has-nav'; + } + + foreach ( $align as $device_slug => $align_slug ) { + $alignment_is_mobile = in_array( $device_slug, [ 'tablet', 'mobile' ], true ); + $is_header_sidebar = $builder_id === 'header' && $row_index === 'sidebar'; + // Make sure we don't apply device-specific classes if the rows aren't visible on respective device. + // Footer has same rows on all devices. + if ( $builder_id === 'footer' || $is_header_sidebar || ( $device === $device_slug || ( $alignment_is_mobile && $device === 'mobile' ) ) ) { + $classes[] = $device_slug . '-' . $align_slug; + } + } + + // If we don't have anything at render index, make sure we do. + if ( ! isset( $render_buffer[ $slot ][ $render_index ] ) ) { + $render_buffer[ $slot ][ $render_index ] = [ + 'classes' => $classes, + 'components' => [], + ]; + if ( $builder_id === 'footer' && ! empty( $vertical_align ) ) { + $render_buffer[ $slot ][ $render_index ]['vertical-align'] = 'hfg-item-v-' . $vertical_align; + } + } + $render_buffer[ $slot ][ $render_index ]['components'][] = $component['id']; + + if ( $is_mergeable ) { + $was_previous_mergeable = true; + continue; + } + $was_previous_mergeable = false; + } + + if ( isset( $render_buffer[ $slot ] ) && is_array( $render_buffer[ $slot ] ) ) { + $render_buffer[ $slot ] = array_values( $render_buffer[ $slot ] ); + } + } + + if ( ! $this->columns_layout ) { + if ( $slot === 'c-left' && $component_index === 0 ) { + $classes[] = 'hfg-end'; + } + if ( $slot === 'c-right' && $component_index === count( $slot_data ) - 1 ) { + $classes[] = 'hfg-start'; + } + } + + if ( ! $this->columns_layout ) { + // Move center-side-slot components inside the side slots. + if ( isset( $render_buffer['c-right'] ) ) { + $length = count( $render_buffer['c-right'] ) - 1; + if ( $length >= 0 ) { + $render_buffer['c-right'][ $length ]['classes'][] = 'hfg-start'; + } + $render_buffer['right'] = array_merge( $render_buffer['c-right'], $render_buffer['right'] ); + } + if ( isset( $render_buffer['c-left'] ) ) { + $render_buffer['c-left'][0]['classes'][] = 'hfg-end'; + $render_buffer['left'] = array_merge( $render_buffer['left'], $render_buffer['c-left'] ); + } + unset( $render_buffer['c-left'] ); + unset( $render_buffer['c-right'] ); + } else { + // Drop the unused columns for columned layout. + $columns = SettingsManager::get_instance()->get( 'hfg_footer_layout_' . $row_index . '_' . self::COLUMNS_NUMBER, 3 ); + array_splice( $render_buffer, absint( $columns ) ); + } + + foreach ( $render_buffer as $slot => $slot_data ) { + if ( $slot === 'center' && empty( $slot_data ) && ! $this->columns_layout ) { + continue; + } + + $slot_classes = [ 'hfg-slot', $slot ]; + + if ( count( $slot_data ) === 1 ) { + $slot_classes[] = 'single'; + if ( isset( $slot_data[0]['vertical-align'] ) ) { + $slot_classes[] = $slot_data[0]['vertical-align']; + } + } + + if ( $row_index !== 'sidebar' ) { + echo sprintf( '
', esc_attr( join( ' ', $slot_classes ) ) ); + } + + self::$current_slot = $slot; + + foreach ( $slot_data as $group_index => $component_group ) { + if ( ! isset( $component_group['components'] ) ) { + continue; + } + if ( count( $component_group['components'] ) > 1 ) { + $component_group['classes'][] = 'hfg-is-group'; + } + echo sprintf( '
', esc_attr( join( ' ', $component_group['classes'] ) ) ); + foreach ( $component_group['components'] as $component ) { + self::$current_component = $component; + $instance = $this->builder_components[ $component ]; + $instance->render(); + } + echo '
'; + } + + if ( $row_index !== 'sidebar' ) { + echo '
'; + } } } @@ -936,6 +1436,11 @@ public function render_device( $device_name, $device_details ) { * @param null|array $row Row details. */ public function render_components( $device = null, $row = null ) { + if ( neve_is_new_builder() ) { + $this->new_render_components( $device, $row ); + + return; + } $row_index = 0; if ( $device === null && $row === null ) { @@ -954,7 +1459,7 @@ function ( $item1, $item2 ) { return 0; } - return $item1['x'] < $item2['x'] ? -1 : 1; + return $item1['x'] < $item2['x'] ? - 1 : 1; } ); @@ -979,19 +1484,8 @@ function ( $item1, $item2 ) { $component = $this->builder_components[ $component_location['id'] ]; $x = intval( $component_location['x'] ); $width = intval( $component_location['width'] ); - $align = SettingsManager::get_instance()->get( $component_location['id'] . '_' . Abstract_Component::ALIGNMENT_ID, null ); - $vertical_align = SettingsManager::get_instance()->get( $component_location['id'] . '_' . Abstract_Component::VERTICAL_ALIGN_ID, null ); - - // Make sure we migrate old alignment values. - if ( is_string( $align ) || ! is_array( $align ) ) { - $is_menu_component = strpos( $component_location['id'], 'primary-menu' ) > -1 || strpos( $component_location['id'], 'secondary-menu' ); - $tmp_align = ( is_string( $align ) && in_array( $align, [ 'left', 'right', 'center', 'justify' ] ) ) ? $align : 'left'; - $align = [ - 'desktop' => $tmp_align, - 'tablet' => $is_menu_component ? 'left' : $tmp_align, - 'mobile' => $is_menu_component ? 'left' : $tmp_align, - ]; - } + $align = $this->get_component_alignment( $component_location['id'] ); + $vertical_align = $this->get_component_alignment( $component_location['id'], true ); if ( ! $collection->hasNext() && ( $x + $width < $max_columns ) ) { $width += $max_columns - ( $x + $width ); @@ -1024,15 +1518,15 @@ function ( $item1, $item2 ) { // If there is a gap between components, build new group. if ( $last_item !== null && ! $is_near_prev ) { - $render_index++; + $render_index ++; } // If there are two neighbours and none of them have auto_width, build new group. if ( $is_near_prev && ! $last_item['is_auto_width'] && ! $is_auto_width ) { - $render_index++; + $render_index ++; } // If there are neighbours prev and next, always group with the next on. if ( $is_near_prev && $is_near_next && ! $last_item['is_auto_width'] && $is_auto_width && ! isset( $render_buffer[ $render_index ] ) ) { - $render_index++; + $render_index ++; } // Use alignment only of non-auto width element. @@ -1072,7 +1566,7 @@ function ( $item1, $item2 ) { 'is_last' => false, ]; } - if ( strpos( $component_location['id'], 'primary-menu' ) > -1 ) { + if ( strpos( $component_location['id'], 'primary-menu' ) > - 1 ) { $render_buffer[ $render_index ]['has_primary_nav'] = true; } $render_buffer[ $render_index ]['is_last'] = $is_last; @@ -1235,7 +1729,8 @@ function ( $a, $b ) { if ( $a['name'] === $b['name'] ) { return 0; } - return $a['name'] > $b['name'] ? 1 : -1; + + return $a['name'] > $b['name'] ? 1 : - 1; } ); @@ -1246,6 +1741,7 @@ function ( $a, $b ) { * Get the default row colors based on the old settings. * * @param string $row_id the row id. + * * @return array */ private function get_default_row_colors( $row_id ) { @@ -1260,6 +1756,22 @@ private function get_default_row_colors( $row_id ) { ], ]; + $is_footer_bottom = $this->get_id() === 'footer' && $row_id === 'bottom'; + + // On the new skin, the bottom footer row should be dark by default. + if ( neve_is_new_skin() && $is_footer_bottom ) { + $bg_color_map = [ + 'background' => [ + 'dark-mode' => 'var(--nv-site-bg)', + 'light-mode' => 'var(--nv-dark-bg)', + ], + 'text' => [ + 'dark-mode' => 'var(--nv-text-color)', + 'light-mode' => 'var(--nv-text-dark-bg)', + ], + ]; + } + $row_setting_id = $this->control_id . '_' . $row_id; $background = $bg_color_map['background']['light-mode']; $text = $bg_color_map['text']['light-mode']; @@ -1269,6 +1781,7 @@ private function get_default_row_colors( $row_id ) { $background = $bg_color_map['background'][ $old_skin ]; $text = $bg_color_map['text'][ $old_skin ]; } + return [ 'background' => $background, 'text' => $text, @@ -1319,7 +1832,16 @@ private function add_sidebar_controls( $row_setting_id ) { 'default' => '{ "mobile": "350", "tablet": "350", "desktop": "350" }', 'options' => [ 'active_callback' => function () { - return in_array( get_theme_mod( $this->control_id . '_sidebar_' . self::LAYOUT_SETTING, 'slide_left' ), [ 'slide_left', 'slide_right', 'pull_left', 'pull_right' ], true ); + return in_array( + get_theme_mod( $this->control_id . '_sidebar_' . self::LAYOUT_SETTING, 'slide_left' ), + [ + 'slide_left', + 'slide_right', + 'pull_left', + 'pull_right', + ], + true + ); }, 'input_attrs' => [ 'min' => 1, @@ -1345,10 +1867,85 @@ private function add_sidebar_controls( $row_setting_id ) { ); } + /** + * Adds Column Layout Controls. + * + * @param string $row_setting_id row id. + */ + private function add_columns_layout_controls( $row_setting_id ) { + $choices = []; + + for ( $i = 1; $i <= 5; $i ++ ) { + $choices[ $i ] = [ + 'tooltip' => $i, + 'icon' => 'text', + ]; + } + + SettingsManager::get_instance()->add( + [ + 'id' => self::COLUMNS_NUMBER, + 'group' => $row_setting_id, + 'tab' => SettingsManager::TAB_LAYOUT, + 'label' => __( 'Number of Columns', 'neve' ), + 'type' => '\Neve\Customizer\Controls\React\Radio_Buttons', + 'section' => $row_setting_id, + 'options' => [ + 'choices' => $choices, + ], + 'transport' => 'post' . $row_setting_id, + 'sanitize_callback' => 'absint', + 'default' => '3', + ] + ); + + SettingsManager::get_instance()->add( + [ + 'id' => self::COLUMNS_LAYOUT, + 'group' => $row_setting_id, + 'tab' => SettingsManager::TAB_LAYOUT, + 'label' => __( 'Columns Layout', 'neve' ), + 'type' => '\Neve\Customizer\Controls\React\Builder_Columns', + 'section' => $row_setting_id, + 'options' => [ + 'columns_control' => $row_setting_id . '_' . self::COLUMNS_NUMBER, + ], + 'transport' => 'post' . $row_setting_id, + 'sanitize_callback' => [ $this, 'sanitize_columns' ], + 'default' => 'equal', + ] + ); + } + + /** + * Sanitize builder columns + * + * @param string $value control value. + * + * @return string + */ + public function sanitize_columns( $value ) { + $allowed = [ + 'equal', + 'right-third', + 'left-third', + 'left-half', + 'right-half', + 'center-half', + 'center-two-thirds', + ]; + if ( ! in_array( $value, $allowed ) ) { + return 'equal'; + } + + return $value; + } + /** * Adds sidebar styles. * * @param array $css_array array of styles. + * * @return array */ private function add_sidebar_styles( $css_array ) { @@ -1391,6 +1988,68 @@ private function add_sidebar_styles( $css_array ) { ], ]; } + + return $css_array; + } + + /** + * Adds the new builder row styles. + * + * @param array $css_array array of styles. + * + * @return array + */ + private function add_new_builder_styles( $css_array, $row ) { + if ( ! $this->columns_layout ) { + return $css_array; + } + + $builder = $this->get_id(); + + $mods_prefix = 'hfg_' . $builder . '_layout_' . $row . '_'; + $columns = SettingsManager::get_instance()->get( $mods_prefix . self::COLUMNS_NUMBER, 3 ); + $layout = SettingsManager::get_instance()->get( $mods_prefix . self::COLUMNS_LAYOUT, 'equal' ); + + $styles_map = [ + 1 => [ + 'equal' => '1fr', + ], + 2 => [ + 'equal' => '1fr 1fr', + 'right-third' => '2fr 1fr', + 'left-third' => '1fr 2fr', + ], + 3 => [ + 'equal' => '1fr 1fr 1fr', + 'left-half' => '2fr 1fr 1fr', + 'right-half' => '1fr 1fr 2fr', + 'center-half' => '1fr 2fr 1fr', + 'center-two-thirds' => '1fr 3fr 1fr', + ], + 4 => [ + 'equal' => 'repeat(4, 1fr)', + 'left-half' => '3fr 1fr 1fr 1fr', + 'right-half' => '1fr 1fr 1fr 3fr', + ], + 5 => [ + 'equal' => 'repeat(5, 1fr)', + ], + ]; + + $layout = $styles_map[ $columns ][ $layout ]; + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.' . $builder . '-' . $row . '-inner .row', + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_GRID_TEMPLATE_COLS => [ + Dynamic_Selector::META_KEY => $mods_prefix . self::COLUMNS_LAYOUT, + Dynamic_Selector::META_DEFAULT => 'auto', + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) use ( $layout ) { + return sprintf( '%s:%s;', $css_prop, $layout ); + }, + ], + ], + ]; + return $css_array; } } diff --git a/header-footer-grid/Core/Builder/Footer.php b/header-footer-grid/Core/Builder/Footer.php index 8645e679dd..0d8f08673a 100644 --- a/header-footer-grid/Core/Builder/Footer.php +++ b/header-footer-grid/Core/Builder/Footer.php @@ -32,6 +32,7 @@ class Footer extends Abstract_Builder { */ public function init() { $this->set_property( 'title', __( 'Footer', 'neve' ) ); + $this->set_property( 'columns_layout', true ); $this->set_property( 'description', apply_filters( @@ -115,6 +116,22 @@ public function get_id() { * @access protected */ protected function get_rows() { + if ( neve_is_new_builder() ) { + return [ + 'top' => array( + 'title' => __( 'Footer Top', 'neve' ), + 'description' => $this->get_property( 'description' ), + ), + 'main' => array( + 'title' => __( 'Footer Main', 'neve' ), + 'description' => $this->get_property( 'description' ), + ), + 'bottom' => array( + 'title' => __( 'Footer Bottom', 'neve' ), + 'description' => $this->get_property( 'description' ), + ), + ]; + } return [ 'top' => array( diff --git a/header-footer-grid/Core/Builder/Header.php b/header-footer-grid/Core/Builder/Header.php index 7dfa20caef..4bed4470b2 100644 --- a/header-footer-grid/Core/Builder/Header.php +++ b/header-footer-grid/Core/Builder/Header.php @@ -54,11 +54,13 @@ public function init() { ) ) ); + $migrated_hfg = neve_is_new_builder(); + $this->set_property( 'instructions_array', array( - 'description' => __( 'Build your own header or choose from preset options.', 'neve' ), - 'quickLinks' => array( + 'description' => __( 'Build your own header or choose from preset options.', 'neve' ), + 'quickLinks' => array( 'custom_logo' => array( 'label' => esc_html__( 'Change Logo', 'neve' ), 'icon' => 'dashicons-editor-customchar', @@ -72,6 +74,8 @@ public function init() { 'icon' => 'dashicons-menu', ), ), + 'builderMigrated' => $migrated_hfg, + 'hadOldBuilder' => neve_had_old_hfb() && ! neve_is_new_skin(), ) ); } @@ -86,6 +90,15 @@ public function init() { * @access public */ public function customize_register( WP_Customize_Manager $wp_customize ) { + if ( ! neve_is_new_builder() ) { + return parent::customize_register( $wp_customize ); + } + + $section = $wp_customize->get_section( 'neve_pro_global_header_settings' ); + if ( ! empty( $section ) ) { + $section->priority = 201; + } + $wp_customize->add_section( 'neve_header_presets', [ @@ -102,6 +115,7 @@ public function customize_register( WP_Customize_Manager $wp_customize ) { 'label' => __( 'Header Presets', 'neve' ), ] ); + $wp_customize->add_control( new Presets_Selector( $wp_customize, @@ -111,11 +125,11 @@ public function customize_register( WP_Customize_Manager $wp_customize ) { 'transport' => 'postMessage', 'priority' => 30, 'presets' => $this->get_header_presets(), + 'builder' => $this->layout_control_id, ] ) ); - return parent::customize_register( $wp_customize ); } @@ -142,8 +156,8 @@ public function get_id() { /** * Render builder row. * - * @param string $device_id The device id. - * @param string $row_id The row id. + * @param string $device_id The device id. + * @param string $row_id The row id. * @param array $row_details Row data. */ public function render_row( $device_id, $row_id, $row_details ) { @@ -181,7 +195,7 @@ protected function get_rows() { 'description' => $this->get_property( 'description' ), ), 'sidebar' => array( - 'title' => esc_html__( 'Mobile menu content', 'neve' ), + 'title' => esc_html__( 'Mobile Sidebar', 'neve' ), 'description' => $this->get_property( 'description' ), ), ]; @@ -194,45 +208,44 @@ protected function get_rows() { * @return array */ private function get_header_presets() { - return apply_filters( - 'neve_header_presets', + $presets = [ [ - [ - 'label' => 'Classic', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/Classic.jpg', - 'setup' => '{"hfg_header_layout":"{\"desktop\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":4,\"y\":1,\"width\":7,\"height\":1,\"id\":\"primary-menu\"},{\"x\":11,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_search_responsive\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}", "primary-menu_component_align":"right","logo_component_align":"left","header_search_responsive_icon_size":"15"}', - ], - [ - 'label' => 'Inverted', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/Inverted.jpg', - 'setup' => '{"hfg_header_layout":"{\"desktop\":{\"top\":[],\"main\":[{\"x\":6,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_search_responsive\"},{\"x\":0,\"y\":1,\"width\":6,\"height\":1,\"id\":\"primary-menu\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}","primary-menu_component_align":"left","logo_component_align":"right","header_search_responsive_icon_size":"15"}', - ], - [ - 'label' => 'Centered', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/Centered.jpg', - 'setup' => '{"hfg_header_layout": "{\"desktop\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":12,\"height\":1,\"id\":\"logo\"}],\"bottom\":[{\"x\":0,\"y\":1,\"width\":12,\"height\":1,\"id\":\"primary-menu\"}]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}","primary-menu_component_align":"center","logo_component_align":"center","header_search_responsive_icon_size":"15"}', - ], - [ - 'label' => 'Spaced', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/Spaced.jpg', - 'setup' => '{"hfg_header_layout": "{\"desktop\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_search_responsive\"},{\"x\":4,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":11,\"y\":1,\"width\":1,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}","nav-icon_component_align": "right","logo_component_align": "center","header_search_responsive_icon_size":"25"}', - ], - [ - 'label' => 'Collapsed', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/ClassicCollapsed.jpg', - 'setup' => '{"hfg_header_layout":"{\"desktop\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":10,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_search_responsive\"},{\"x\":11,\"y\":1,\"width\":1,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":6,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":1,\"height\":1,\"id\":\"header_search_responsive\"},{\"x\":9,\"y\":1,\"width\":3,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}","nav-icon_component_align":"right"}', - ], - [ - 'label' => 'Search Field', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/SearchField.jpg', - 'setup' => '{"hfg_header_layout":"{\"desktop\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":3,\"height\":1,\"id\":\"logo\"},{\"x\":3,\"y\":1,\"width\":6,\"height\":1,\"id\":\"primary-menu\"},{\"x\":9,\"y\":1,\"width\":3,\"height\":1,\"id\":\"header_search\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}","primary-menu_component_align":"left"}', - ], - [ - 'label' => 'Button Item', - 'image' => NEVE_ASSETS_URL . 'img/header-presets/ButtonItem.jpg', - 'setup' => '{"hfg_header_layout":"{\"desktop\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":4,\"height\":1,\"id\":\"logo\"},{\"x\":4,\"y\":1,\"width\":6,\"height\":1,\"id\":\"primary-menu\"},{\"x\":10,\"y\":1,\"width\":2,\"height\":1,\"id\":\"button_base\"}],\"bottom\":[]},\"mobile\":{\"top\":[],\"main\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"logo\"},{\"x\":8,\"y\":1,\"width\":4,\"height\":1,\"id\":\"nav-icon\"}],\"bottom\":[],\"sidebar\":[{\"x\":0,\"y\":1,\"width\":8,\"height\":1,\"id\":\"primary-menu\"}]}}", "primary-menu_component_align":"right"}', - ], - ] - ); + 'label' => 'Classic', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/Classic.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"},{\"id\":\"header_search_responsive\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"},{\"id\":\"header_search_responsive\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}"}', + ], + [ + 'label' => 'Inverted', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/Inverted.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"primary-menu\"},{\"id\":\"header_search_responsive\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"logo\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"nav-icon\"},{\"id\":\"header_search_responsive\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"logo\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}","logo_component_align":{"mobile":"right","tablet":"right","desktop":"right"}}', + ], + [ + 'label' => 'Centered', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/Centered.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"logo\"}],\"c-right\":[],\"right\":[]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"primary-menu\"}],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"logo\"}],\"c-right\":[],\"right\":[]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[{\"id\":\"nav-icon\"}],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}","logo_component_align":{"mobile":"center","tablet":"center","desktop":"center"}}', + ], + [ + 'label' => 'Spaced', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/Spaced.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"header_search_responsive\"}],\"c-left\":[],\"center\":[{\"id\":\"logo\"}],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"header_search_responsive\"}],\"c-left\":[],\"center\":[{\"id\":\"logo\"}],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}","logo_component_align":{"mobile":"center","tablet":"center","desktop":"center"}}', + ], + [ + 'label' => 'Collapsed', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/ClassicCollapsed.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"header_search_responsive\"},{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"header_search_responsive\"},{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}"}', + ], + [ + 'label' => 'Search Field', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/SearchField.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"},{\"id\":\"primary-menu\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"header_search\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"},{\"id\":\"nav-icon\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"header_search_responsive\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"}]}}"}', + ], + [ + 'label' => 'Button Item', + 'image' => NEVE_ASSETS_URL . 'img/header-presets/ButtonItem.jpg', + 'setup' => '{"hfg_header_layout_v2":"{\"desktop\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"primary-menu\"},{\"id\":\"button_base\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]}},\"mobile\":{\"top\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"main\":{\"left\":[{\"id\":\"logo\"}],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[{\"id\":\"nav-icon\"}]},\"bottom\":{\"left\":[],\"c-left\":[],\"center\":[],\"c-right\":[],\"right\":[]},\"sidebar\":[{\"id\":\"primary-menu\"},{\"id\":\"button_base\"}]}}"}', + ], + ]; + + return apply_filters( 'neve_header_presets_v2', $presets ); } } diff --git a/header-footer-grid/Core/Components/Abstract_Component.php b/header-footer-grid/Core/Components/Abstract_Component.php index da11b4e146..75b5681249 100644 --- a/header-footer-grid/Core/Components/Abstract_Component.php +++ b/header-footer-grid/Core/Components/Abstract_Component.php @@ -455,71 +455,14 @@ public function get_property( $key = '' ) { */ public function define_settings() { $this->add_settings(); - $padding_selector = '.builder-item--' . $this->get_id() . ' > :not(.customize-partial-edit-shortcut):not(.item--preview-name):first-of-type'; + + $padding_selector = '.builder-item--' . $this->get_id(); + if ( $this->default_selector !== null ) { $padding_selector = $this->default_selector; } - $margin_selector = '.builder-item--' . $this->get_id(); - $align_choices = [ - 'left' => [ - 'tooltip' => __( 'Left', 'neve' ), - 'icon' => 'editor-alignleft', - ], - 'center' => [ - 'tooltip' => __( 'Center', 'neve' ), - 'icon' => 'editor-aligncenter', - ], - 'right' => [ - 'tooltip' => __( 'Right', 'neve' ), - 'icon' => 'editor-alignright', - ], - ]; - if ( strpos( $this->get_id(), Button::COMPONENT_ID ) > -1 ) { - $align_choices['justify'] = [ - 'tooltip' => __( 'Justify', 'neve' ), - 'icon' => 'editor-justify', - ]; - } - - if ( $this->get_id() !== Search::COMPONENT_ID ) { - SettingsManager::get_instance()->add( - [ - 'id' => self::ALIGNMENT_ID, - 'group' => $this->get_id(), - 'tab' => SettingsManager::TAB_LAYOUT, - 'transport' => $this->is_auto_width ? 'post' . $this->get_builder_id() : 'postMessage', - 'sanitize_callback' => [ $this, 'sanitize_alignment' ], - 'default' => [ - 'desktop' => $this->default_align, - 'tablet' => $this->default_align, - 'mobile' => $this->default_align, - ], - 'label' => __( 'Alignment', 'neve' ), - 'type' => '\Neve\Customizer\Controls\React\Responsive_Radio_Buttons', - 'live_refresh_selector' => $this->is_auto_width ? null : $margin_selector, - 'live_refresh_css_prop' => [ - 'remove_classes' => [ - 'mobile-left', - 'mobile-right', - 'mobile-center', - 'tablet-left', - 'tablet-right', - 'tablet-center', - 'desktop-left', - 'desktop-right', - 'desktop-center', - ], - 'is_for' => 'horizontal', - ], - 'options' => [ - 'choices' => $align_choices, - ], - 'section' => $this->section, - 'conditional_header' => $this->get_builder_id() === 'header', - ] - ); - } + $this->add_horizontal_alignment_control(); $this->add_vertical_alignment_control(); SettingsManager::get_instance()->add( @@ -539,9 +482,14 @@ public function define_settings() { 'default' => $this->default_padding_value, ], 'live_refresh_selector' => $padding_selector, - 'live_refresh_css_prop' => array( - 'prop' => 'padding', - ), + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--padding', + 'responsive' => true, + 'selector' => '.builder-item--' . $this->get_id(), + ], + 'prop' => 'padding', + ], 'section' => $this->section, 'conditional_header' => $this->get_builder_id() === 'header', ] @@ -557,9 +505,14 @@ public function define_settings() { 'default' => $this->default_margin_value, 'label' => __( 'Margin', 'neve' ), 'type' => '\Neve\Customizer\Controls\React\Spacing', - 'live_refresh_selector' => $margin_selector, + 'live_refresh_selector' => '.builder-item--' . $this->get_id(), 'live_refresh_css_prop' => array( - 'prop' => 'margin', + 'cssVar' => [ + 'vars' => '--margin', + 'responsive' => true, + 'selector' => '.builder-item--' . $this->get_id(), + ], + 'prop' => 'margin', ), 'section' => $this->section, 'conditional_header' => $this->get_builder_id() === 'header', @@ -632,15 +585,13 @@ public function render() { } /** - * Method to add Component css styles. + * Add legacy style. * - * @param array $css_array An array containing css rules. + * @param array $css_array the styles css array. * * @return array - * @since 1.0.0 - * @access public */ - public function add_style( array $css_array = array() ) { + private function add_legacy_style( array $css_array ) { if ( $this->has_font_family_control || $this->has_typeface_control ) { $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => $this->default_typography_selector, @@ -742,6 +693,101 @@ public function add_style( array $css_array = array() ) { ], ]; + return $css_array; + } + + /** + * Method to add Component css styles. + * + * @param array $css_array An array containing css rules. + * + * @return array + * @since 1.0.0 + * @access public + */ + public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $rules = [ + '--padding' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::PADDING_ID, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::PADDING_ID ), + 'directional-prop' => Config::CSS_PROP_PADDING, + ], + '--margin' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::MARGIN_ID, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::MARGIN_ID ), + 'directional-prop' => Config::CSS_PROP_MARGIN, + ], + ]; + + if ( $this->has_font_family_control || $this->has_typeface_control ) { + $rules = array_merge( + $rules, + [ + '--fontFamily' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FONT_FAMILY_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FONT_FAMILY_ID ), + ], + '--fontSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::TYPEFACE_ID . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'em', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::TYPEFACE_ID, 'fontSize' ), + ], + '--lineHeight' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::TYPEFACE_ID . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::TYPEFACE_ID, 'lineHeight' ), + ], + '--letterSpacing' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::TYPEFACE_ID . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::TYPEFACE_ID, 'letterSpacing' ), + ], + '--fontWeight' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::TYPEFACE_ID . '.fontWeight', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::TYPEFACE_ID, 'fontWeight' ), + 'font' => 'mods_' . $this->get_id() . '_' . self::FONT_FAMILY_ID, + ], + '--textTransform' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::TYPEFACE_ID . '.textTransform', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::TYPEFACE_ID, 'textTransform' ), + ], + '--iconSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::TYPEFACE_ID . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'responsive_suffix', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::TYPEFACE_ID, 'fontSize' ), + ], + ] + ); + + /* + Attempt to match the font family for cart icon. + if ( strpos( $this->get_id(), Nav::COMPONENT_ID ) > - 1 ) { + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id() . ' ~ .builder-item--header_cart_icon', + Dynamic_Selector::KEY_RULES => [ + '--fontFamily' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FONT_FAMILY_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FONT_FAMILY_ID ), + ], + ], + ]; + } + */ + } + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), + Dynamic_Selector::KEY_RULES => $rules, + ]; return $css_array; } @@ -801,6 +847,12 @@ private function add_typography_controls() { 'priority' => $priority + 1, 'type' => '\Neve\Customizer\Controls\React\Font_Family', 'live_refresh_selector' => $this->default_typography_selector, + 'live_refresh_css_prop' => array( + 'cssVar' => [ + 'vars' => '--fontFamily', + 'selector' => '.builder-item--' . $this->get_id(), + ], + ), 'section' => $this->section, 'options' => [ 'input_attrs' => [ @@ -819,7 +871,29 @@ private function add_typography_controls() { 'transport' => 'postMessage', 'priority' => $priority + 2, 'type' => '\Neve\Customizer\Controls\React\Typography', - 'live_refresh_selector' => $this->default_typography_selector, + 'live_refresh_selector' => neve_is_new_skin() ? true : $this->default_typography_selector, + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => [ + '--textTransform' => 'textTransform', + '--fontWeight' => 'fontWeight', + '--fontSize' => [ + 'key' => 'fontSize', + 'responsive' => true, + ], + '--lineHeight' => [ + 'key' => 'lineHeight', + 'responsive' => true, + ], + '--letterSpacing' => [ + 'key' => 'letterSpacing', + 'suffix' => 'px', + 'responsive' => true, + ], + ], + 'selector' => '.builder-item--' . $this->get_id(), + ], + ], 'section' => $this->section, 'default' => $this->typography_default, 'sanitize_callback' => 'neve_sanitize_typography_control', @@ -911,6 +985,7 @@ protected function get_default_for_responsive_from_intval( $old_val_const, $defa 'desktop' => $default_int_val, ]; } + return [ 'mobile' => $old, 'tablet' => $old, @@ -918,31 +993,76 @@ protected function get_default_for_responsive_from_intval( $old_val_const, $defa ]; } + /** - * Sanitize alignment. - * - * @param array $input alignment responsive array. - * - * @return array + * Add horizontal alignment to component. */ - public function sanitize_alignment( $input ) { - $default = [ - 'mobile' => 'left', - 'tablet' => 'left', - 'desktop' => 'left', - ]; - $allowed = [ 'left', 'center', 'right', 'justify' ]; + private function add_horizontal_alignment_control() { + if ( strpos( $this->get_id(), Search::COMPONENT_ID ) > - 1 ) { + return; + } - if ( ! is_array( $input ) ) { - return $default; + // New skin drops alignment for navigation + if ( neve_is_new_skin() && strpos( $this->get_id(), Nav::COMPONENT_ID ) > - 1 ) { + return; } - foreach ( $input as $device => $alignment ) { - if ( ! in_array( $alignment, $allowed ) ) { - $input[ $device ] = 'left'; - } + $align_choices = [ + 'left' => [ + 'tooltip' => __( 'Left', 'neve' ), + 'icon' => 'editor-alignleft', + ], + 'center' => [ + 'tooltip' => __( 'Center', 'neve' ), + 'icon' => 'editor-aligncenter', + ], + 'right' => [ + 'tooltip' => __( 'Right', 'neve' ), + 'icon' => 'editor-alignright', + ], + ]; + if ( strpos( $this->get_id(), Button::COMPONENT_ID ) > - 1 ) { + $align_choices['justify'] = [ + 'tooltip' => __( 'Justify', 'neve' ), + 'icon' => 'editor-justify', + ]; } - return $input; + SettingsManager::get_instance()->add( + [ + 'id' => self::ALIGNMENT_ID, + 'group' => $this->get_id(), + 'tab' => SettingsManager::TAB_LAYOUT, + 'transport' => $this->is_auto_width ? 'post' . $this->get_builder_id() : 'postMessage', + 'sanitize_callback' => 'neve_sanitize_alignment', + 'default' => [ + 'desktop' => $this->default_align, + 'tablet' => $this->default_align, + 'mobile' => $this->default_align, + ], + 'label' => __( 'Alignment', 'neve' ), + 'type' => '\Neve\Customizer\Controls\React\Responsive_Radio_Buttons', + 'live_refresh_selector' => $this->is_auto_width ? null : '.builder-item--' . $this->get_id(), + 'live_refresh_css_prop' => [ + 'remove_classes' => [ + 'mobile-left', + 'mobile-right', + 'mobile-center', + 'tablet-left', + 'tablet-right', + 'tablet-center', + 'desktop-left', + 'desktop-right', + 'desktop-center', + ], + 'is_for' => 'horizontal', + ], + 'options' => [ + 'choices' => $align_choices, + ], + 'section' => $this->section, + 'conditional_header' => $this->get_builder_id() === 'header', + ] + ); } } diff --git a/header-footer-grid/Core/Components/Button.php b/header-footer-grid/Core/Components/Button.php index 1dd9936994..8da37a6ae5 100644 --- a/header-footer-grid/Core/Components/Button.php +++ b/header-footer-grid/Core/Components/Button.php @@ -64,6 +64,11 @@ class Button extends Abstract_Component { */ public function __construct( $panel ) { parent::__construct( $panel ); + if ( neve_is_new_skin() ) { + $this->default_selector = '.builder-item--' . $this->get_id(); + + return; + } $this->default_selector = '.builder-item > .item--inner.builder-item--' . $this->get_id() . ' > .component-wrap > a.button.button-primary'; } @@ -105,6 +110,7 @@ public function add_settings() { 'conditional_header' => $this->get_builder_id() === 'header', ] ); + SettingsManager::get_instance()->add( [ 'id' => self::TEXT_ID, @@ -123,29 +129,47 @@ public function add_settings() { SettingsManager::get_instance()->add( [ - 'id' => self::STYLE_ID, - 'group' => $this->get_class_const( 'COMPONENT_ID' ), - 'tab' => SettingsManager::TAB_STYLE, - 'transport' => 'post' . $this->get_class_const( 'COMPONENT_ID' ), - 'sanitize_callback' => 'neve_sanitize_button_appearance', - 'label' => __( 'Appearance', 'neve' ), - 'type' => 'neve_button_appearance', - 'section' => $this->section, - 'conditional_header' => $this->get_builder_id() === 'header', + 'id' => self::STYLE_ID, + 'group' => $this->get_class_const( 'COMPONENT_ID' ), + 'tab' => SettingsManager::TAB_STYLE, + 'transport' => 'post' . $this->get_class_const( 'COMPONENT_ID' ), + 'sanitize_callback' => 'neve_sanitize_button_appearance', + 'label' => __( 'Appearance', 'neve' ), + 'type' => 'neve_button_appearance', + 'section' => $this->section, + 'conditional_header' => $this->get_builder_id() === 'header', + 'live_refresh_selector' => true, + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => [ + '--primaryBtnBg' => 'background', + '--primaryBtnColor' => 'text', + '--primaryBtnHoverBg' => 'backgroundHover', + '--primaryBtnHoverColor' => 'textHover', + '--primaryBtnBorderRadius' => [ + 'key' => 'borderRadius', + 'suffix' => 'px', + ], + '--primaryBtnBorderWidth' => [ + 'key' => 'borderWidth', + 'suffix' => 'px', + ], + ], + 'selector' => '.builder-item--' . $this->get_id(), + ], + ], ] ); } /** - * Method to add Component css styles. + * Add legacy style. * - * @param array $css_array An array containing css rules. + * @param array $css_array css array. * * @return array - * @since 1.0.0 - * @access public */ - public function add_style( array $css_array = array() ) { + private function add_legacy_style( $css_array ) { $id = $this->get_id() . '_' . self::STYLE_ID; $css_array[] = [ @@ -155,7 +179,6 @@ public function add_style( array $css_array = array() ) { Config::CSS_PROP_COLOR => $id . '.text', Config::CSS_PROP_BORDER_RADIUS => [ Dynamic_Selector::META_KEY => $id . '.borderRadius', - // Dynamic_Selector::META_DEFAULT => '3', ], Config::CSS_PROP_CUSTOM_BTN_TYPE => [ Dynamic_Selector::META_KEY => $id . '.type', @@ -177,6 +200,49 @@ public function add_style( array $css_array = array() ) { return parent::add_style( $css_array ); } + /** + * Method to add Component css styles. + * + * @param array $css_array An array containing css rules. + * + * @return array + * @since 1.0.0 + * @access public + */ + public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $id = $this->get_id() . '_' . self::STYLE_ID; + $value = get_theme_mod( $id ); + + $rules = [ + '--primaryBtnBg' => [ Dynamic_Selector::META_KEY => $id . '.background' ], + '--primaryBtnColor' => [ Dynamic_Selector::META_KEY => $id . '.text' ], + '--primaryBtnHoverBg' => [ Dynamic_Selector::META_KEY => $id . '.backgroundHover' ], + '--primaryBtnHoverColor' => [ Dynamic_Selector::META_KEY => $id . '.textHover' ], + '--primaryBtnBorderRadius' => [ + Dynamic_Selector::META_KEY => $id . '.borderRadius', + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + ]; + + if ( isset( $value['type'] ) && $value['type'] === 'outline' ) { + $rules['--primaryBtnBorderWidth'] = [ + Dynamic_Selector::META_KEY => $id . '.borderWidth', + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ]; + } + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $this->default_selector, + Dynamic_Selector::KEY_RULES => $rules, + ]; + + return parent::add_style( $css_array ); + } + /** * The render method for the component. * diff --git a/header-footer-grid/Core/Components/CartIcon.php b/header-footer-grid/Core/Components/CartIcon.php index 2bc67c9f44..b724c5b028 100644 --- a/header-footer-grid/Core/Components/CartIcon.php +++ b/header-footer-grid/Core/Components/CartIcon.php @@ -29,7 +29,6 @@ class CartIcon extends Abstract_Component { const COLOR_ID = 'color'; const HOVER_COLOR_ID = 'hover_color'; const ICON_SELECTOR = 'icon_selector'; - const CART_TOTAL = 'cart_total'; const CART_LABEL = 'cart_label'; const CART_FOCUS = 'cart_focus'; const MINI_CART_STYLE = 'mini_cart_style'; @@ -123,10 +122,15 @@ public function add_settings() { ], ], 'live_refresh_selector' => $this->default_selector . ' span.nv-icon.nv-cart svg', - 'live_refresh_css_prop' => array( + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--iconSize', + 'selector' => '.builder-item--' . $this->get_id(), + 'suffix' => 'px', + ], 'type' => 'svg-icon-size', 'default' => 15, - ), + ], 'section' => $this->section, 'conditional_header' => true, ] @@ -144,6 +148,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_selector . ' svg', 'prop' => 'fill', @@ -170,6 +178,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--hoverColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_selector . ':hover svg', 'prop' => 'fill', @@ -186,15 +198,13 @@ public function add_settings() { } /** - * Method to add Component css styles. + * Add legacy style. * - * @param array $css_array An array containing css rules. + * @param array $css_array css array. * * @return array - * @since 1.0.0 - * @access public */ - public function add_style( array $css_array = array() ) { + private function add_legacy_style( $css_array ) { $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => $this->default_selector . ' span.nv-icon.nv-cart svg', Dynamic_Selector::KEY_RULES => [ @@ -258,6 +268,49 @@ public function add_style( array $css_array = array() ) { return parent::add_style( $css_array ); } + /** + * Method to add Component css styles. + * + * @param array $css_array An array containing css rules. + * + * @return array + * @since 1.0.0 + * @access public + */ + public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $rules = [ + '--iconSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SIZE_ID, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::SIZE_ID ), + ], + '--labelSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::LABEL_SIZE_ID, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::LABEL_SIZE_ID ), + ], + '--color' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::COLOR_ID ), + ], + '--hoverColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::HOVER_COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::HOVER_COLOR_ID ), + ], + ]; + + $css_array[] = [ + Dynamic_Selector::KEY_RULES => $rules, + Dynamic_Selector::KEY_SELECTOR => $this->default_selector, + ]; + + return parent::add_style( $css_array ); + } + /** * The render method for the component. * diff --git a/header-footer-grid/Core/Components/Copyright.php b/header-footer-grid/Core/Components/Copyright.php index 403e7056a4..dc84e2ced3 100644 --- a/header-footer-grid/Core/Components/Copyright.php +++ b/header-footer-grid/Core/Components/Copyright.php @@ -86,6 +86,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_typography_selector . ', ' . $this->default_typography_selector . ' *:not(a)', 'prop' => 'color', @@ -96,7 +100,6 @@ public function add_settings() { ); } - /** * Method to add Component css styles. * @@ -107,10 +110,24 @@ public function add_settings() { * @access public */ public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $this->default_typography_selector . ', ' . $this->default_typography_selector . ' *', + Dynamic_Selector::KEY_RULES => [ + \Neve\Core\Settings\Config::CSS_PROP_COLOR => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::COLOR_ID ), + ], + ], + ]; + + return parent::add_style( $css_array ); + } + $css_array[] = [ - Dynamic_Selector::KEY_SELECTOR => $this->default_typography_selector . ', ' . $this->default_typography_selector . ' *', + Dynamic_Selector::KEY_SELECTOR => '.item--inner.builder-item--' . $this->get_id(), Dynamic_Selector::KEY_RULES => [ - \Neve\Core\Settings\Config::CSS_PROP_COLOR => [ + '--color' => [ Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::COLOR_ID ), ], diff --git a/header-footer-grid/Core/Components/CustomHtml.php b/header-footer-grid/Core/Components/CustomHtml.php index f8cbad8427..a215af853c 100644 --- a/header-footer-grid/Core/Components/CustomHtml.php +++ b/header-footer-grid/Core/Components/CustomHtml.php @@ -45,7 +45,7 @@ public function init() { /** * Add form and input tag to allowed tags in header_footer_grid context. * - * @param array $tags HTML Tags. + * @param array $tags HTML Tags. * @param string|array $context The context for which to retrieve tags. * * @return array @@ -165,6 +165,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_typography_selector . ', ' . $this->default_typography_selector . ' *:not(a)', 'prop' => 'color', @@ -186,15 +190,30 @@ public function add_settings() { * @access public */ public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $this->default_typography_selector . ', ' . $this->default_typography_selector . ' *', + Dynamic_Selector::KEY_RULES => [ + \Neve\Core\Settings\Config::CSS_PROP_COLOR => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::COLOR_ID ), + ], + ], + ]; + + return parent::add_style( $css_array ); + } + $css_array[] = [ - Dynamic_Selector::KEY_SELECTOR => $this->default_typography_selector . ', ' . $this->default_typography_selector . ' *', + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), Dynamic_Selector::KEY_RULES => [ - \Neve\Core\Settings\Config::CSS_PROP_COLOR => [ + '--color' => [ Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::COLOR_ID ), ], ], ]; + return parent::add_style( $css_array ); } diff --git a/header-footer-grid/Core/Components/FooterWidgetFour.php b/header-footer-grid/Core/Components/FooterWidgetFour.php index 31e89b576a..eeec5cfae0 100644 --- a/header-footer-grid/Core/Components/FooterWidgetFour.php +++ b/header-footer-grid/Core/Components/FooterWidgetFour.php @@ -35,6 +35,11 @@ public function init() { $this->set_property( 'width', 3 ); $this->set_property( 'section', 'sidebar-widgets-footer-four-widgets' ); + if ( neve_is_new_widget_editor() ) { + if ( strpos( $this->section, 'widgets-footer' ) !== false ) { + $this->set_property( 'section', 'neve_' . $this->section ); + } + } add_filter( 'customize_section_active', array( $this, 'footer_widgets_show' ), 15, 2 ); } @@ -46,13 +51,15 @@ public function init() { * @access public */ public function add_settings() { - SettingsManager::get_instance()->add_controls_to_tabs( - self::COMPONENT_ID, - array( - SettingsManager::TAB_GENERAL => array( - 'sidebars_widgets-footer-four-widgets' => array(), - ), - ) - ); + if ( ! neve_is_new_widget_editor() ) { + SettingsManager::get_instance()->add_controls_to_tabs( + self::COMPONENT_ID, + array( + SettingsManager::TAB_GENERAL => array( + 'sidebars_widgets-footer-four-widgets' => array(), + ), + ) + ); + } } } diff --git a/header-footer-grid/Core/Components/FooterWidgetOne.php b/header-footer-grid/Core/Components/FooterWidgetOne.php index a7dfd882ee..7852e5e150 100644 --- a/header-footer-grid/Core/Components/FooterWidgetOne.php +++ b/header-footer-grid/Core/Components/FooterWidgetOne.php @@ -34,6 +34,11 @@ public function init() { $this->set_property( 'width', 3 ); $this->set_property( 'section', 'sidebar-widgets-footer-one-widgets' ); + if ( neve_is_new_widget_editor() ) { + if ( strpos( $this->section, 'widgets-footer' ) !== false ) { + $this->set_property( 'section', 'neve_' . $this->section ); + } + } add_filter( 'customize_section_active', array( $this, 'footer_widgets_show' ), 15, 2 ); } @@ -45,13 +50,15 @@ public function init() { * @access public */ public function add_settings() { - SettingsManager::get_instance()->add_controls_to_tabs( - self::COMPONENT_ID, - array( - SettingsManager::TAB_GENERAL => array( - 'sidebars_widgets-footer-one-widgets' => array(), - ), - ) - ); + if ( ! neve_is_new_widget_editor() ) { + SettingsManager::get_instance()->add_controls_to_tabs( + self::COMPONENT_ID, + array( + SettingsManager::TAB_GENERAL => array( + 'sidebar_widgets-footer-one-widgets' => array(), + ), + ) + ); + } } } diff --git a/header-footer-grid/Core/Components/FooterWidgetThree.php b/header-footer-grid/Core/Components/FooterWidgetThree.php index adcb22511b..c8efb0d3be 100644 --- a/header-footer-grid/Core/Components/FooterWidgetThree.php +++ b/header-footer-grid/Core/Components/FooterWidgetThree.php @@ -32,6 +32,11 @@ public function init() { $this->set_property( 'id', self::COMPONENT_ID ); $this->set_property( 'width', 3 ); $this->set_property( 'section', 'sidebar-widgets-footer-three-widgets' ); + if ( neve_is_new_widget_editor() ) { + if ( strpos( $this->section, 'widgets-footer' ) !== false ) { + $this->set_property( 'section', 'neve_' . $this->section ); + } + } add_filter( 'customize_section_active', array( $this, 'footer_widgets_show' ), 15, 2 ); } @@ -43,13 +48,15 @@ public function init() { * @access public */ public function add_settings() { - SettingsManager::get_instance()->add_controls_to_tabs( - self::COMPONENT_ID, - array( - SettingsManager::TAB_GENERAL => array( - 'sidebars_widgets-footer-three-widgets' => array(), - ), - ) - ); + if ( ! neve_is_new_widget_editor() ) { + SettingsManager::get_instance()->add_controls_to_tabs( + self::COMPONENT_ID, + array( + SettingsManager::TAB_GENERAL => array( + 'sidebars_widgets-footer-three-widgets' => array(), + ), + ) + ); + } } } diff --git a/header-footer-grid/Core/Components/FooterWidgetTwo.php b/header-footer-grid/Core/Components/FooterWidgetTwo.php index 98260d4392..177419701b 100644 --- a/header-footer-grid/Core/Components/FooterWidgetTwo.php +++ b/header-footer-grid/Core/Components/FooterWidgetTwo.php @@ -33,6 +33,11 @@ public function init() { $this->set_property( 'id', self::COMPONENT_ID ); $this->set_property( 'width', 3 ); $this->set_property( 'section', 'sidebar-widgets-footer-two-widgets' ); + if ( neve_is_new_widget_editor() ) { + if ( strpos( $this->section, 'widgets-footer' ) !== false ) { + $this->set_property( 'section', 'neve_' . $this->section ); + } + } add_filter( 'customize_section_active', array( $this, 'footer_widgets_show' ), 15, 2 ); } @@ -44,13 +49,15 @@ public function init() { * @access public */ public function add_settings() { - SettingsManager::get_instance()->add_controls_to_tabs( - self::COMPONENT_ID, - array( - SettingsManager::TAB_GENERAL => array( - 'sidebars_widgets-footer-two-widgets' => array(), - ), - ) - ); + if ( ! neve_is_new_widget_editor() ) { + SettingsManager::get_instance()->add_controls_to_tabs( + self::COMPONENT_ID, + array( + SettingsManager::TAB_GENERAL => array( + 'sidebars_widgets-footer-two-widgets' => array(), + ), + ) + ); + } } } diff --git a/header-footer-grid/Core/Components/Logo.php b/header-footer-grid/Core/Components/Logo.php index 11f55929d5..42d6ac8833 100644 --- a/header-footer-grid/Core/Components/Logo.php +++ b/header-footer-grid/Core/Components/Logo.php @@ -207,6 +207,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_selector . ' .brand .nv-title-tagline-wrap', 'prop' => 'color', @@ -235,7 +239,36 @@ public function render_component() { * @access public */ public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), + Dynamic_Selector::KEY_RULES => [ + '--maxWidth' => [ + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::MAX_WIDTH, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => '{ "mobile": "120", "tablet": "120", "desktop": "120" }', + ], + '--color' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + ], + ], + ]; + + return parent::add_style( $css_array ); + } + /** + * Add legacy style. + * + * @param array $css_array css array. + * + * @return array + */ + private function add_legacy_style( $css_array ) { $selector = '.builder-item--' . $this->get_id() . ' .site-logo img'; $css_array[] = [ diff --git a/header-footer-grid/Core/Components/MenuIcon.php b/header-footer-grid/Core/Components/MenuIcon.php index ccdb50c8e0..eaa11bd4cd 100644 --- a/header-footer-grid/Core/Components/MenuIcon.php +++ b/header-footer-grid/Core/Components/MenuIcon.php @@ -14,6 +14,7 @@ use HFG\Core\Settings\Manager as SettingsManager; use HFG\Main; use Neve\Core\Settings\Config; +use Neve\Core\Settings\Mods; use Neve\Core\Styles\Dynamic_Selector; /** @@ -118,7 +119,7 @@ public function add_settings() { 'transport' => 'postMessage', 'tab' => SettingsManager::TAB_GENERAL, 'sanitize_callback' => 'wp_filter_nohtml_kses', - 'type' => '\HFG\Core\Customizer\Instructions_Control', + 'type' => '\Neve\Customizer\Controls\React\Instructions_Control', 'section' => $this->section, 'options' => [ 'options' => array( @@ -137,42 +138,71 @@ public function add_settings() { ] ); + $new_skin = neve_is_new_skin(); + $mod_key = self::BUTTON_APPEARANCE; + $default = $new_skin ? [ + 'type' => 'outline', + 'borderRadius' => [ + 'top' => 0, + 'left' => 0, + 'bottom' => 0, + 'right' => 0, + ], + ] : [ 'type' => 'outline' ]; + SettingsManager::get_instance()->add( [ - 'id' => self::BUTTON_APPEARANCE, + 'id' => $mod_key, 'group' => $this->get_id(), 'transport' => 'postMessage', 'tab' => SettingsManager::TAB_STYLE, 'sanitize_callback' => 'neve_sanitize_button_appearance', - 'default' => [ 'type' => 'outline' ], + 'default' => $default, 'label' => __( 'Appearance', 'neve' ), 'type' => '\Neve\Customizer\Controls\React\Button_Appearance', 'section' => $this->section, 'options' => [ - 'no_hover' => true, + 'no_hover' => true, + 'default_vals' => $default, ], 'live_refresh_selector' => $this->default_selector, - 'live_refresh_css_prop' => array( + 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => [ + '--bgColor' => 'background', + '--color' => 'text', + '--borderRadius' => [ + 'key' => 'borderRadius', + 'suffix' => 'px', + ], + '--borderWidth' => [ + 'key' => 'borderWidth', + 'suffix' => 'px', + ], + ], + 'selector' => '.builder-item--' . $this->get_id(), + ], 'additional_buttons' => $this->get_class_const( 'COMPONENT_ID' ) !== 'header_menu_icon' ? [] : [ [ 'button' => $this->close_button, 'text' => '.icon-bar', ], ], - ), + ], 'conditional_header' => true, ] ); } + /** - * Add CSS style for the component. + * Add legacy style. * - * @param array $css_array the css style array. + * @param array $css_array css array. * * @return array */ - public function add_style( array $css_array = array() ) { + private function add_legacy_style( $css_array ) { $id = $this->get_id() . '_' . self::BUTTON_APPEARANCE; $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => $this->default_selector . ', ' . $this->close_button, @@ -192,6 +222,47 @@ public function add_style( array $css_array = array() ) { ], ]; + return parent::add_style( $css_array ); + } + + /** + * Add CSS style for the component. + * + * @param array $css_array the css style array. + * + * @return array + */ + public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $id = $this->get_id() . '_' . self::BUTTON_APPEARANCE; + + $rules = [ + '--bgColor' => $id . '.background', + '--color' => $id . '.text', + '--borderRadius' => [ + Dynamic_Selector::META_KEY => $id . '.borderRadius', + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + '--borderWidth' => [ + Dynamic_Selector::META_KEY => $id . '.borderWidth', + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ], + ]; + + $value = SettingsManager::get_instance()->get( $id ); + + + if ( isset( $value['type'] ) && $value['type'] !== 'outline' ) { + $rules ['--borderWidth']['override'] = 0; + } + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id() . ',' . $this->close_button, + Dynamic_Selector::KEY_RULES => $rules, + ]; return parent::add_style( $css_array ); } diff --git a/header-footer-grid/Core/Components/Nav.php b/header-footer-grid/Core/Components/Nav.php index 69019bc8b9..5120cd8e11 100644 --- a/header-footer-grid/Core/Components/Nav.php +++ b/header-footer-grid/Core/Components/Nav.php @@ -110,13 +110,17 @@ public function add_settings() { 'tab' => SettingsManager::TAB_STYLE, 'transport' => 'postMessage', 'sanitize_callback' => 'neve_sanitize_colors', - 'default' => 'var(--nv-text-color)', + 'default' => neve_is_new_skin() ? '' : 'var(--nv-text-color)', 'label' => __( 'Items Color', 'neve' ), 'type' => 'neve_color_control', 'section' => $this->section, 'conditional_header' => true, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => $selector . ' li:not(.current_page_item):not(.current-menu-item):not(.woocommerce-mini-cart-item) > a,' . $selector . ' li.neve-mm-heading span { color: {{value}}; @@ -138,6 +142,10 @@ public function add_settings() { 'conditional_header' => true, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--activeColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => $selector . ' li.current_page_item > a,' . $selector . ' li.current-menu-item > a { color: {{value}} !important; @@ -159,6 +167,10 @@ public function add_settings() { 'conditional_header' => true, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--hoverColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => '.builder-item--' . $this->get_id() . ' .nav-menu-primary:not(.style-full-height) > .nav-ul li:not(.woocommerce-mini-cart-item):hover > a { color: {{value}} !important; @@ -344,6 +356,55 @@ public function render_component() { * @return array */ public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $selector = '.builder-item--' . $this->get_id(); + + $rules = [ + '--color' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + ], + '--hoverColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::HOVER_COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::HOVER_COLOR_ID ), + ], + '--activeColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::ACTIVE_COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::ACTIVE_COLOR_ID ), + ], + '--spacing' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SPACING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => $this->get_default_for_responsive_from_intval( self::SPACING, 20 ), + ], + '--height' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::ITEM_HEIGHT, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => $this->get_default_for_responsive_from_intval( self::ITEM_HEIGHT, 25 ), + ], + ]; + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $selector, + Dynamic_Selector::KEY_RULES => $rules, + ]; + + + return parent::add_style( $css_array ); + } + + /** + * Add legacy style. + * + * @param array $css_array the styles css array. + * + * @return array + */ + private function add_legacy_style( array $css_array ) { $selector = '.builder-item--' . $this->get_id() . ' .nav-menu-primary > .nav-ul '; $css_array[] = [ @@ -432,7 +493,8 @@ public function add_style( array $css_array = array() ) { return ''; } $value = absint( $value ); - return sprintf( 'left:%s;right:%s', -$value / 2 . 'px', -$value / 2 . 'px' ); + + return sprintf( 'left:%s;right:%s', - $value / 2 . 'px', - $value / 2 . 'px' ); }, Dynamic_Selector::META_DEFAULT => $this->get_default_for_responsive_from_intval( self::SPACING, 20 ), ], diff --git a/header-footer-grid/Core/Components/NavFooter.php b/header-footer-grid/Core/Components/NavFooter.php index 96400036db..ca2c38c93f 100644 --- a/header-footer-grid/Core/Components/NavFooter.php +++ b/header-footer-grid/Core/Components/NavFooter.php @@ -82,12 +82,16 @@ public function add_settings() { 'tab' => SettingsManager::TAB_STYLE, 'transport' => 'postMessage', 'sanitize_callback' => 'neve_sanitize_colors', - 'default' => 'var(--nv-text-color)', + 'default' => neve_is_new_skin() ? '' : 'var(--nv-text-color)', 'label' => __( 'Items Color', 'neve' ), 'type' => 'neve_color_control', 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_typography_selector, 'prop' => 'color', @@ -110,6 +114,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--hoverColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_typography_selector . ':after', 'prop' => 'background-color', @@ -208,13 +216,13 @@ public function render_component() { } /** - * Add styles to the component. + * Add legacy style. * - * @param array $css_array rules array. + * @param array $css_array css array. * * @return array */ - public function add_style( array $css_array = array() ) { + private function add_legacy_style( $css_array ) { $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => '.nav-menu-footer #footer-menu > li > a', Dynamic_Selector::KEY_RULES => [ @@ -309,4 +317,46 @@ public function add_style( array $css_array = array() ) { return parent::add_style( $css_array ); } + /** + * Add styles to the component. + * + * @param array $css_array rules array. + * + * @return array + */ + public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $rules = [ + '--color' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + ], + '--hoverColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::HOVER_COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::HOVER_COLOR_ID ), + ], + '--spacing' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SPACING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::SPACING ), + ], + '--height' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::ITEM_HEIGHT, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::ITEM_HEIGHT ), + ], + ]; + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), + Dynamic_Selector::KEY_RULES => $rules, + ]; + + return parent::add_style( $css_array ); + } + } diff --git a/header-footer-grid/Core/Components/PaletteSwitch.php b/header-footer-grid/Core/Components/PaletteSwitch.php new file mode 100644 index 0000000000..de4a6b2590 --- /dev/null +++ b/header-footer-grid/Core/Components/PaletteSwitch.php @@ -0,0 +1,449 @@ + + * + * @version 1.0.0 + * @package HFG + */ + +namespace HFG\Core\Components; + +use HFG\Core\Settings\Manager as SettingsManager; +use HFG\Main; +use Neve\Core\Dynamic_Css; +use Neve\Core\Settings\Config; +use Neve\Core\Settings\Mods; +use Neve\Core\Styles\Dynamic_Selector; + +/** + * Class PaletteSwitch + * + * @package HFG\Core\Components + */ +class PaletteSwitch extends Abstract_Component { + + const COMPONENT_ID = 'header_palette_switch'; + const DARK_PALETTE_ID = 'dark_palette'; + const LIGHT_PALETTE_ID = 'light_palette_description'; + const TOGGLE_ICON_ID = 'toggle_icon'; + const PLACEHOLDER_ID = 'placeholder'; + const AUTO_ADJUST = 'auto_adjust_color'; + const SIZE_ID = 'icon_size'; + const DEFAULT_ICON_SIZE = 16; + + /** + * The section icon. + * + * @access protected + * @var string $icon + */ + protected $icon = 'buddicons-topics'; + /** + * The component default width. + * + * @since 1.0.0 + * @access protected + * @var int $width + */ + protected $width = 1; + /** + * The component slug. + * + * @since 1.0.0 + * @access protected + * @var string $section + */ + protected $component_slug = 'hfg-palette-icon'; + + /** + * Return a svg icon for the provided string. + * + * @param string $icon The icon string. + * + * @return string + */ + public static function get_icon( $icon ) { + $available_icons = [ + 'contrast' => '', + 'night' => '', + 'toggle' => '', + 'accessibility' => '', + ]; + + if ( in_array( $icon, array_keys( $available_icons ), true ) ) { + return $available_icons[ $icon ]; + } + + return $available_icons['contrast']; + } + + /** + * PaletteSwitch constructor + * + * @return void + */ + public function init() { + $this->set_property( 'label', __( 'Palette Switch', 'neve' ) ); + $this->set_property( 'id', $this->get_class_const( 'COMPONENT_ID' ) ); + $this->set_property( 'default_selector', '.builder-item--' . $this->get_id() ); + $this->set_property( 'is_auto_width', true ); + + add_filter( 'neve_after_css_root', [ $this, 'toggle_css' ], 10, 1 ); + add_action( 'wp_enqueue_scripts', [ $this, 'load_scripts' ] ); + + add_filter( + 'language_attributes', + function ( $output ) { + if ( neve_is_amp() ) { + return $output . " [class]=\"isDark ? 'neve-dark-theme' : 'neve-light-theme'\" class=\"neve-dark-theme\" "; + } + + return $output; + } + ); + } + + /** + * Load Component Scripts + * + * @return void + */ + public function load_scripts() { + if ( $this->is_component_active() || is_customize_preview() ) { + wp_add_inline_style( 'neve-style', $this->toggle_style() ); + wp_add_inline_script( 'neve-script', $this->toggle_script() ); + } + } + + /** + * Method to check that the component is active. + * + * @return bool + */ + private function is_component_active() { + $builders = Main::get_instance()->get_builders(); + foreach ( $builders as $builder ) { + if ( $builder->is_component_active( $this->get_id() ) ) { + return true; + } + } + + return false; + } + + /** + * Get CSS to use as inline script + * + * @return string + */ + public function toggle_style() { + $css = '.toggle-palette a { + display: flex; + align-items: center; + } + .toggle-palette .icon { + display: flex; + width: var(--iconSize); + height: var(--iconSize); + } + .toggle-palette .label { + font-size: 0.85em; + margin-left: 5px; + }'; + + return Dynamic_Css::minify_css( $css ); + } + + /** + * Get JS contents from file to use as inline script. + * + * @return string + */ + public function toggle_script() { + $auto_adjust = Mods::get( $this->get_id() . '_' . self::AUTO_ADJUST, 0 ); + $default_state = '"light"'; + if ( $auto_adjust ) { + $default_state = 'window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"'; + } + + return '!function(){"use strict";const e="data-neve-theme",t="neve_user_theme";function r(){let n=' . $default_state . ',r=localStorage.getItem(t);"dark"===r&&(n="dark"),"light"===r&&(n="light"),document.documentElement.setAttribute(e,n)}r();const a=document.getElementById("neve_body");function n(n){if(n.srcElement&&(n.srcElement.matches("a.palette-icon-wrapper")||n.srcElement.parentElement&&n.srcElement.parentElement.matches("a.palette-icon-wrapper")||n.srcElement.parentElement&&n.srcElement.parentElement.parentElement.matches("a.palette-icon-wrapper")||n.srcElement.parentElement&&n.srcElement.parentElement.parentElement.parentElement.matches("a.palette-icon-wrapper"))){if(n.preventDefault(),"dark"===document.documentElement.getAttribute(e))return localStorage.setItem(t,"light"),void document.documentElement.setAttribute(e,"light");localStorage.setItem(t,"dark"),document.documentElement.setAttribute(e,"dark")}}a&&a.addEventListener("click",n,!1);}();'; + } + + /** + * Methods used to filter CSS global colors + * + * @param string $css The CSS string. + * + * @return string + */ + public function toggle_css( $css ) { + if ( ! $this->is_component_active() && ! is_customize_preview() ) { + return ''; + } + + $css .= ' '; + $default_light = 'base'; + $default_dark = 'darkMode'; + + $auto_adjust = Mods::get( $this->get_id() . '_' . self::AUTO_ADJUST, 0 ); + + $customizer = Mods::get( 'neve_global_colors', neve_get_global_colors_default( true ) ); + $defined_palettes = $customizer['palettes']; + $active_light = $customizer['activePalette']; + $active_dark = Mods::get( $this->get_id() . '_' . self::DARK_PALETTE_ID, $default_dark ); + + $palette_light = $defined_palettes[ $default_light ]; + if ( isset( $defined_palettes[ $active_light ] ) ) { + $palette_light = $defined_palettes[ $active_light ]; + } + $light_css = ''; + foreach ( $palette_light['colors'] as $slug => $color ) { + $light_css .= '--' . $slug . ':' . $color . ';'; + } + + $palette_dark = $defined_palettes[ $default_dark ]; + if ( isset( $defined_palettes[ $active_dark ] ) ) { + $palette_dark = $defined_palettes[ $active_dark ]; + } + $dark_css = ''; + foreach ( $palette_dark['colors'] as $slug => $color ) { + $dark_css .= '--' . $slug . ':' . $color . ';'; + } + + if ( $auto_adjust && ! is_customize_preview() ) { + $css .= ' + /* Light mode */ + @media (prefers-color-scheme: light) { + :root{ + ' . $light_css . ' + } + } + + /* Dark mode */ + @media (prefers-color-scheme: dark) { + :root{ + ' . $dark_css . ' + } + } + '; + } + + return $css . ' + [data-neve-theme="light"], html.neve-light-theme { + ' . $light_css . ' + } + [data-neve-theme="dark"], html.neve-dark-theme ~ * { + ' . $dark_css . ' + } + '; + } + + /** + * PaletteSwitch register settings controls + * + * @return void + */ + public function add_settings() { + + $customizer = Mods::get( 'neve_global_colors', neve_get_global_colors_default( true ) ); + $defined_palettes = $customizer['palettes']; + $dark_palette_default = isset( $customizer['palettes']['darkMode'] ) ? 'darkMode' : array_keys( $customizer['palettes'] )[1]; + + $available_palettes = []; + foreach ( $defined_palettes as $key => $palette_data ) { + $available_palettes[ $key ] = $palette_data['name']; + } + + SettingsManager::get_instance()->add( + [ + 'id' => self::LIGHT_PALETTE_ID, + 'group' => $this->get_id(), + 'tab' => SettingsManager::TAB_GENERAL, + 'transport' => 'postMessage', + 'section' => $this->section, + 'label' => __( 'Light Palette', 'neve' ), + /* translators: %s: Link to Edit global color customizer. */ + 'description' => sprintf( __( 'The base palette is used for light mode. %1$sEdit color palettes%2$s.', 'neve' ), '
', '' ), + 'type' => 'hidden', + 'default' => '', + ] + ); + + SettingsManager::get_instance()->add( + [ + 'id' => self::DARK_PALETTE_ID, + 'group' => $this->get_id(), + 'tab' => SettingsManager::TAB_GENERAL, + 'transport' => 'refresh', + 'sanitize_callback' => 'wp_filter_nohtml_kses', + 'label' => __( 'Dark Palette', 'neve' ), + 'description' => __( 'Dark Palette', 'neve' ), + 'type' => 'Neve\Customizer\Controls\React\Inline_Select', + 'default' => $dark_palette_default, + 'options' => [ + 'options' => $available_palettes, + 'default' => $dark_palette_default, + 'changes_on' => 'neve_global_colors', + ], + 'section' => $this->section, + ] + ); + + SettingsManager::get_instance()->add( + [ + 'id' => self::TOGGLE_ICON_ID, + 'group' => $this->get_id(), + 'tab' => SettingsManager::TAB_GENERAL, + 'transport' => 'post' . $this->get_class_const( 'COMPONENT_ID' ), + 'sanitize_callback' => 'wp_filter_nohtml_kses', + 'label' => __( 'Select icon', 'neve' ), + 'description' => __( 'Select icon', 'neve' ), + 'type' => 'Neve\Customizer\Controls\React\Radio_Buttons', + 'default' => 'contrast', + 'options' => [ + 'is_for' => 'palette_switch', + ], + 'section' => $this->section, + ] + ); + + $default_size_values = [ + 'mobile' => self::DEFAULT_ICON_SIZE, + 'tablet' => self::DEFAULT_ICON_SIZE, + 'desktop' => self::DEFAULT_ICON_SIZE, + ]; + + SettingsManager::get_instance()->add( + [ + 'id' => self::SIZE_ID, + 'group' => $this->get_id(), + 'tab' => SettingsManager::TAB_GENERAL, + 'transport' => 'post' . $this->get_class_const( 'COMPONENT_ID' ), + 'sanitize_callback' => array( $this, 'sanitize_responsive_int_json' ), + 'label' => __( 'Icon Size', 'neve' ), + 'type' => 'Neve\Customizer\Controls\React\Responsive_Range', + 'default' => $default_size_values, + 'options' => [ + 'input_attrs' => [ + 'step' => 1, + 'min' => 8, + 'max' => 120, + 'defaultVal' => $default_size_values, + 'units' => [ 'px' ], + ], + ], + 'live_refresh_selector' => $this->default_selector . ' div.component-wrap .palette-icon-wrapper svg', + 'live_refresh_css_prop' => array( + 'cssVar' => [ + 'vars' => '--iconSize', + 'responsive' => true, + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], + 'type' => 'svg-icon-size', + 'default' => self::DEFAULT_ICON_SIZE, + ), + 'section' => $this->section, + 'conditional_header' => true, + ] + ); + + SettingsManager::get_instance()->add( + [ + 'id' => self::PLACEHOLDER_ID, + 'group' => $this->get_class_const( 'COMPONENT_ID' ), + 'tab' => SettingsManager::TAB_GENERAL, + 'transport' => 'post' . $this->get_class_const( 'COMPONENT_ID' ), + 'sanitize_callback' => 'wp_filter_nohtml_kses', + 'default' => '', + 'label' => __( 'Label', 'neve' ), + 'options' => [ + 'input_attrs' => array( + 'placeholder' => __( 'Leave blank for no label ...', 'neve' ), + ), + ], + 'type' => 'text', + 'section' => $this->section, + 'conditional_header' => true, + ] + ); + + SettingsManager::get_instance()->add( + [ + 'id' => self::AUTO_ADJUST, + 'group' => $this->get_class_const( 'COMPONENT_ID' ), + 'tab' => SettingsManager::TAB_GENERAL, + 'transport' => 'refresh', + 'sanitize_callback' => 'absint', + 'default' => 0, + 'label' => __( 'Automatically adjust color scheme', 'neve' ), + /* translators: %s: Link to Learn More page. */ + 'description' => sprintf( __( 'Adjust default color scheme based on the user device preferences. %1$sLearn More%2$s.', 'neve' ), '', '(opens in a new tab)' ), + 'type' => 'neve_toggle_control', + 'section' => $this->section, + 'conditional_header' => true, + ] + ); + } + + /** + * Method to add Component css styles. + * + * @param array $css_array An array containing css rules. + * + * @return array + * @since 1.0.0 + * @access public + */ + public function add_style( array $css_array = array() ) { + if ( neve_is_new_skin() ) { + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), + Dynamic_Selector::KEY_RULES => [ + '--iconSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SIZE_ID, + Dynamic_Selector::META_DEFAULT => '{ "mobile": "' . self::DEFAULT_ICON_SIZE . '", "tablet": "' . self::DEFAULT_ICON_SIZE . '", "desktop": "' . self::DEFAULT_ICON_SIZE . '" }', + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + ], + ]; + + return parent::add_style( $css_array ); + } + + $selector = '.builder-item--' . $this->get_id() . ' .toggle-palette a.toggle span.icon'; + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $selector, + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_WIDTH => [ + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SIZE_ID, + Dynamic_Selector::META_DEFAULT => '{ "mobile": "' . self::DEFAULT_ICON_SIZE . '", "tablet": "' . self::DEFAULT_ICON_SIZE . '", "desktop": "' . self::DEFAULT_ICON_SIZE . '" }', + ], + Config::CSS_PROP_HEIGHT => [ + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SIZE_ID, + Dynamic_Selector::META_DEFAULT => '{ "mobile": "' . self::DEFAULT_ICON_SIZE . '", "tablet": "' . self::DEFAULT_ICON_SIZE . '", "desktop": "' . self::DEFAULT_ICON_SIZE . '" }', + ], + ], + ]; + + return parent::add_style( $css_array ); + } + + /** + * Render the component + * + * @return void + */ + public function render_component() { + Main::get_instance()->load( 'components/component-palette-switch' ); + } + + +} diff --git a/header-footer-grid/Core/Components/Search.php b/header-footer-grid/Core/Components/Search.php index 04f30bffe9..bb399ac296 100644 --- a/header-footer-grid/Core/Components/Search.php +++ b/header-footer-grid/Core/Components/Search.php @@ -81,6 +81,12 @@ public function add_settings() { 'type' => '\Neve\Customizer\Controls\React\Responsive_Range', 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--height', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'template' => 'body ' . $this->default_selector . ' input[type=search] { @@ -121,6 +127,12 @@ public function add_settings() { 'type' => '\Neve\Customizer\Controls\React\Responsive_Range', 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--formFieldFontSize', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'template' => 'body ' . $this->default_selector . ' input[type=search] { @@ -159,28 +171,26 @@ public function add_settings() { ] ); + $new_skin = neve_is_new_skin(); + + $per_device = $new_skin ? [ + 'top' => 2, + 'right' => 2, + 'bottom' => 2, + 'left' => 2, + ] : [ + 'top' => 1, + 'right' => 1, + 'bottom' => 1, + 'left' => 1, + ]; $default_border_width = [ 'desktop-unit' => 'px', 'tablet-unit' => 'px', 'mobile-unit' => 'px', - 'desktop' => [ - 'top' => 1, - 'right' => 1, - 'bottom' => 1, - 'left' => 1, - ], - 'tablet' => [ - 'top' => 1, - 'right' => 1, - 'bottom' => 1, - 'left' => 1, - ], - 'mobile' => [ - 'top' => 1, - 'right' => 1, - 'bottom' => 1, - 'left' => 1, - ], + 'desktop' => $per_device, + 'tablet' => $per_device, + 'mobile' => $per_device, ]; SettingsManager::get_instance()->add( @@ -203,6 +213,12 @@ public function add_settings() { ], 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--formFieldBorderWidth', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'directional' => true, 'template' => @@ -260,6 +276,12 @@ public function add_settings() { ], 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--formFieldBorderRadius', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'directional' => true, 'template' => @@ -286,6 +308,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--formFieldBgColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' input[type=search] { background-color: {{value}} !important; @@ -308,6 +334,13 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => [ + '--formFieldColor', + '--formFieldBorderColor', + ], + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' input[type=search], body ' . $this->default_selector . ' input::placeholder { color: {{value}}; @@ -325,15 +358,13 @@ public function add_settings() { } /** - * Method to add Component css styles. + * Add legacy style. * - * @param array $css_array An array containing css rules. + * @param array $css_array css array. * * @return array - * @since 1.0.0 - * @access public */ - public function add_style( array $css_array = array() ) { + private function add_legacy_style( $css_array ) { $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => $this->default_selector . ' input[type=submit],' . $this->default_selector . ' .nv-search-icon-wrap', Dynamic_Selector::KEY_RULES => [ @@ -372,6 +403,7 @@ public function add_style( array $css_array = array() ) { if ( ! empty( $fs ) ) { $style = sprintf( 'padding-right:%spx;', $padding ); } + return $style; }, ], @@ -432,6 +464,68 @@ public function add_style( array $css_array = array() ) { return parent::add_style( $css_array ); } + /** + * Method to add Component css styles. + * + * @param array $css_array An array containing css rules. + * + * @return array + * @since 1.0.0 + * @access public + */ + public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $rules = [ + '--height' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_HEIGHT, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_HEIGHT ), + ], + '--formFieldFontSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_FONT_SIZE, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--formFieldBorderWidth' => [ + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_BORDER_WIDTH, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_BORDER_WIDTH ), + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ], + '--formFieldBorderRadius' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_BORDER_RADIUS, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_BORDER_RADIUS ), + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + '--formFieldBgColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_BG, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_BG ), + ], + '--formFieldBorderColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_TEXT_COLOR, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_TEXT_COLOR ), + ], + '--formFieldColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_TEXT_COLOR, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_TEXT_COLOR ), + ], + ]; + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), + Dynamic_Selector::KEY_RULES => $rules, + ]; + + + return parent::add_style( $css_array ); + } + /** * The render method for the component. * @@ -439,30 +533,19 @@ public function add_style( array $css_array = array() ) { * @access public */ public function render_component() { - add_filter( 'get_search_form', [ $this, 'change_placeholder' ] ); + add_filter( 'nv_search_placeholder', [ $this, 'change_placeholder' ] ); Main::get_instance()->load( 'components/component-search' ); - remove_filter( 'get_search_form', [ $this, 'change_placeholder' ] ); + remove_filter( 'nv_search_placeholder', [ $this, 'change_placeholder' ] ); } /** * Change the form placeholder. * - * @param string $form form markup. + * @param string $placeholder placeholder string. * * @return string */ - public function change_placeholder( $form ) { - $form = ''; - $placeholder = get_theme_mod( $this->get_id() . '_placeholder', __( 'Search for...', 'neve' ) ); - - $form .= ''; - - return $form; + public function change_placeholder( $placeholder ) { + return get_theme_mod( $this->get_id() . '_placeholder', __( 'Search for...', 'neve' ) ); } } diff --git a/header-footer-grid/Core/Components/SearchResponsive.php b/header-footer-grid/Core/Components/SearchResponsive.php index ad1f9a5cad..c7bf7e9137 100644 --- a/header-footer-grid/Core/Components/SearchResponsive.php +++ b/header-footer-grid/Core/Components/SearchResponsive.php @@ -162,6 +162,11 @@ public function add_settings() { ], 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--iconSize', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' a.nv-search.nv-icon > svg { width: {{value}}px; @@ -186,6 +191,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' a.nv-search.nv-icon > svg { fill: {{value}}; @@ -207,6 +216,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--hoverColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' a.nv-search.nv-icon:hover > svg { fill: {{value}}; @@ -245,6 +258,12 @@ public function add_settings() { 'type' => '\Neve\Customizer\Controls\React\Responsive_Range', 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--height', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'template' => 'body ' . $this->default_selector . ' .nv-nav-search .search-form input[type=search] { @@ -285,6 +304,12 @@ public function add_settings() { 'type' => '\Neve\Customizer\Controls\React\Responsive_Range', 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--formFieldFontSize', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'template' => 'body ' . $this->default_selector . ' .nv-nav-search .search-form input[type=search] { @@ -323,28 +348,26 @@ public function add_settings() { ] ); + $new_skin = neve_is_new_skin(); + $per_device = $new_skin ? [ + 'top' => 2, + 'right' => 2, + 'bottom' => 2, + 'left' => 2, + ] : [ + 'top' => 1, + 'right' => 1, + 'bottom' => 1, + 'left' => 1, + ]; + $default_border_width = [ 'desktop-unit' => 'px', 'tablet-unit' => 'px', 'mobile-unit' => 'px', - 'desktop' => [ - 'top' => 1, - 'right' => 1, - 'bottom' => 1, - 'left' => 1, - ], - 'tablet' => [ - 'top' => 1, - 'right' => 1, - 'bottom' => 1, - 'left' => 1, - ], - 'mobile' => [ - 'top' => 1, - 'right' => 1, - 'bottom' => 1, - 'left' => 1, - ], + 'desktop' => $per_device, + 'tablet' => $per_device, + 'mobile' => $per_device, ]; SettingsManager::get_instance()->add( @@ -367,6 +390,12 @@ public function add_settings() { ], 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--formFieldBorderWidth', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'directional' => true, 'template' => @@ -424,6 +453,12 @@ public function add_settings() { ], 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'responsive' => true, + 'vars' => '--formFieldBorderRadius', + 'suffix' => 'px', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'responsive' => true, 'directional' => true, 'template' => @@ -450,6 +485,10 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--formFieldBgColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' .nv-nav-search .search-form input[type=search] { background-color: {{value}}; @@ -472,6 +511,13 @@ public function add_settings() { 'section' => $this->section, 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => [ + '--formFieldColor', + '--formFieldBorderColor', + ], + 'selector' => '.builder-item--' . $this->get_id(), + ], 'template' => 'body ' . $this->default_selector . ' .nv-nav-search .search-form input[type=search], body ' . $this->default_selector . ' input::placeholder { color: {{value}}; @@ -488,20 +534,15 @@ public function add_settings() { ); } + /** - * Method to add Component css styles. + * Add legacy style. * - * @param array $css_array An array containing css rules. + * @param array $css_array css array. * * @return array - * @since 1.0.0 - * @access public */ - public function add_style( array $css_array = array() ) { - if ( is_admin_bar_showing() ) { - wp_add_inline_style( 'neve-style', 'body.admin-bar .floating .nv-nav-search {margin-top: 32px;}' ); - } - + private function add_legacy_style( $css_array ) { $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => $this->default_selector . ' a.nv-search.nv-icon > svg', Dynamic_Selector::KEY_RULES => [ @@ -568,6 +609,7 @@ public function add_style( array $css_array = array() ) { if ( ! empty( $fs ) ) { $style = sprintf( 'padding-right:%spx;', $padding ); } + return $style; }, ], @@ -646,6 +688,85 @@ public function add_style( array $css_array = array() ) { return parent::add_style( $css_array ); } + /** + * Method to add Component css styles. + * + * @param array $css_array An array containing css rules. + * + * @return array + * @since 1.0.0 + * @access public + */ + public function add_style( array $css_array = array() ) { + if ( is_admin_bar_showing() ) { + wp_add_inline_style( 'neve-style', 'body.admin-bar .floating .nv-nav-search {margin-top: 32px;}' ); + } + + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + + $rules = [ + '--iconSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SIZE_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::SIZE_ID ), + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--color' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::COLOR_ID ), + ], + '--hoverColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::HOVER_COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::HOVER_COLOR_ID ), + ], + '--formFieldFontSize' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_FONT_SIZE, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_FONT_SIZE ), + ], + '--formFieldBorderWidth' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_BORDER_WIDTH, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_BORDER_WIDTH ), + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ], + '--formFieldBorderRadius' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_BORDER_RADIUS, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_BORDER_RADIUS ), + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + '--formFieldBgColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_BG, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_BG ), + ], + '--formFieldBorderColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_TEXT_COLOR, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_TEXT_COLOR ), + ], + '--formFieldColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_TEXT_COLOR, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_TEXT_COLOR ), + ], + '--height' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::FIELD_HEIGHT, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::FIELD_HEIGHT ), + Dynamic_Selector::META_SUFFIX => 'px', + ], + ]; + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => $this->default_selector, + Dynamic_Selector::KEY_RULES => $rules, + ]; + + return parent::add_style( $css_array ); + } + /** * The render method for the component. * @@ -653,30 +774,19 @@ public function add_style( array $css_array = array() ) { * @access public */ public function render_component() { - add_filter( 'get_search_form', [ $this, 'change_placeholder' ] ); + add_filter( 'nv_search_placeholder', [ $this, 'change_placeholder' ] ); Main::get_instance()->load( 'components/component-search-responsive' ); - remove_filter( 'get_search_form', [ $this, 'change_placeholder' ] ); + remove_filter( 'nv_search_placeholder', [ $this, 'change_placeholder' ] ); } /** * Change the form placeholder. * - * @param string $form form markup. + * @param string $placeholder placeholder string. * * @return string */ - public function change_placeholder( $form ) { - $form = ''; - $placeholder = get_theme_mod( $this->id . '_placeholder', __( 'Search for...', 'neve' ) ); - - $form .= ''; - - return $form; + public function change_placeholder( $placeholder ) { + return get_theme_mod( $this->id . '_placeholder', __( 'Search for...', 'neve' ) ); } } diff --git a/header-footer-grid/Core/Components/SecondNav.php b/header-footer-grid/Core/Components/SecondNav.php index 23e5d95590..8916147a0d 100644 --- a/header-footer-grid/Core/Components/SecondNav.php +++ b/header-footer-grid/Core/Components/SecondNav.php @@ -82,13 +82,17 @@ public function add_settings() { 'tab' => SettingsManager::TAB_STYLE, 'transport' => 'postMessage', 'sanitize_callback' => 'neve_sanitize_colors', - 'default' => 'var(--nv-text-color)', + 'default' => neve_is_new_skin() ? '' : 'var(--nv-text-color)', 'label' => __( 'Items Color', 'neve' ), 'type' => 'neve_color_control', 'section' => $this->section, 'conditional_header' => $this->get_builder_id() === 'header', 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--color', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_typography_selector, 'prop' => 'color', @@ -112,6 +116,10 @@ public function add_settings() { 'conditional_header' => $this->get_builder_id() === 'header', 'live_refresh_selector' => true, 'live_refresh_css_prop' => [ + 'cssVar' => [ + 'vars' => '--hoverColor', + 'selector' => '.builder-item--' . $this->get_id(), + ], [ 'selector' => $this->default_typography_selector . ':after', 'prop' => 'background-color', @@ -218,6 +226,50 @@ public function render_component() { * @return array */ public function add_style( array $css_array = array() ) { + if ( ! neve_is_new_skin() ) { + return $this->add_legacy_style( $css_array ); + } + + $rules = [ + '--color' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::COLOR_ID, + ], + '--hoverColor' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::HOVER_COLOR_ID, + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::HOVER_COLOR_ID ), + ], + '--spacing' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::SPACING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => SettingsManager::get_instance()->get_default( $this->get_id() . '_' . self::SPACING ), + ], + '--height' => [ + Dynamic_Selector::META_KEY => $this->get_id() . '_' . self::ITEM_HEIGHT, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => $this->get_default_for_responsive_from_intval( self::ITEM_HEIGHT, 25 ), + ], + ]; + + $css_array[] = [ + Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id(), + Dynamic_Selector::KEY_RULES => $rules, + ]; + + return parent::add_style( $css_array ); + } + + + /** + * Add legacy style. + * + * @param array $css_array the styles css array. + * + * @return array + */ + private function add_legacy_style( array $css_array ) { + $css_array[] = [ Dynamic_Selector::KEY_SELECTOR => '.builder-item--' . $this->get_id() . ' .nav-ul#secondary-menu li > a', Dynamic_Selector::KEY_RULES => [ @@ -272,7 +324,8 @@ public function add_style( array $css_array = array() ) { return ''; } $value = absint( $value ); - return sprintf( 'left:%s;right:%s', -$value / 2 . 'px', -$value / 2 . 'px' ); + + return sprintf( 'left:%s;right:%s', - $value / 2 . 'px', - $value / 2 . 'px' ); }, Dynamic_Selector::META_DEFAULT => $this->get_default_for_responsive_from_intval( self::SPACING, 20 ), ], @@ -304,7 +357,6 @@ public function add_style( array $css_array = array() ) { ], ]; - return parent::add_style( $css_array ); } } diff --git a/header-footer-grid/Core/Customizer.php b/header-footer-grid/Core/Customizer.php index 6036b6f7e7..83494e2c66 100644 --- a/header-footer-grid/Core/Customizer.php +++ b/header-footer-grid/Core/Customizer.php @@ -66,7 +66,7 @@ public function __construct() { } } - if ( is_admin() ) { + if ( ! neve_is_new_builder() ) { add_action( 'customize_controls_enqueue_scripts', array( $this, 'scripts' ) ); add_action( 'customize_controls_print_footer_scripts', array( $this, 'template' ) ); } @@ -77,7 +77,7 @@ public function __construct() { } add_filter( 'body_class', array( $this, 'hfg_body_classes' ) ); - add_filter( 'neve_react_controls_localization', array( $this, 'add_dynamic_tags_options' ) ); + add_filter( 'neve_react_controls_localization', array( $this, 'add_builders_and_dynamic_tags' ) ); } /** @@ -85,9 +85,10 @@ public function __construct() { * * @param array $array the localized array. * - * @return mixed + * @return array */ - public function add_dynamic_tags_options( $array ) { + public function add_builders_and_dynamic_tags( $array ) { + $array['HFG'] = $this->get_builders_data(); $array['dynamicTags']['options'] = Magic_Tags::get_instance()->get_options(); return $array; @@ -242,10 +243,10 @@ public function register( WP_Customize_Manager $wp_customize ) { $builder->customize_register( $wp_customize ); } - $wp_customize->register_section_type( '\HFG\Core\Customizer\Instructions_Section' ); - $wp_customize->register_control_type( '\HFG\Core\Customizer\Instructions_Control' ); + $wp_customize->register_section_type( '\Neve\Customizer\Controls\React\Instructions_Section' ); } + /** * The Customizer templates. * @@ -265,21 +266,21 @@ public function template() { <# } #> @@ -287,7 +288,7 @@ public function template() { + style="margin-top: 4px;"> {{ data.title }} @@ -318,6 +319,9 @@ public function template() {
{{ data.name }} + <# if(data.section.indexOf('neve_') !== -1) { #> + + <# } #>
@@ -329,7 +333,7 @@ public function template() {
"},addDevicePanels:function(){var i=this;_.each(i.devices,function(e,t){var n=i.addPanel(t);mi(".hfg--cb-devices-switcher",i.container).append(''+e+""),mi(".hfg--cb-body",i.container).append(n),mi(".hfg-widgets-panel-inner",i.widgetSidebarContainer).append('
')});var e=mi("#hfg-upsell-tmpl");e.length&&mi(e.html()).insertAfter(mi(".hfg--cb-devices-switcher",i.container)),mi(i.container).find(".welcome-notice").removeClass("hidden"),mi(i.container).find(".conditional-header").addClass("hidden")},addItem:function(e,t){var n=this.getTemplate(),i="tmpl-hfg--cb-item";if(0!==mi("#"+i).length){e.elementOrder=t;var r=n(e,i);return mi(r)}},addAvailableItems:function(){var a=this;_.each(a.devices,function(e,o){_.each(a.items,function(e,t){var n=!0;if(!_.isUndefined(e.devices)&&!_.isEmpty(e.devices))if(_.isString(e.devices))e.devices!==o&&(n=!1);else{var i=!1;_.each(e.devices,function(e){o===e&&(i=!0)}),i||(n=!1)}if(n){t=Object.keys(a.items).indexOf(t);var r=a.addItem(e,t);mi(".hfg--widgets-"+o,a.widgetSidebarContainer).prepend(r)}})})},switchToDevice:function(e,t){var n=this;1<_.size(n.devices)?(mi(".hfg--cb-devices-switcher a",n.container).removeClass("hfg--tab-active"),mi(".hfg--cb-devices-switcher .switch-to-"+e,n.container).addClass("hfg--tab-active"),mi(".hfg--device-panel",n.container).addClass("hfg--panel-hide"),mi(".hfg--device-panel.hfg--panel-"+e,n.container).removeClass("hfg--panel-hide"),n.activePanel=e,mi(".hfg--device-panel .hfg-available-items .item-from-list").each(function(e,t){mi("#accordion-section-"+mi(t)[0].dataset.section).removeClass("hfg-section-inactive")}),mi(".hfg--device-panel.hfg--panel-"+e+" .hfg-available-items .item-from-list").each(function(e,t){mi("#accordion-section-"+mi(t)[0].dataset.section).addClass("hfg-section-inactive")})):(mi(".hfg--device-panel.hfg--panel-"+e+" .hfg-available-items .item-from-list").each(function(e,t){mi("#accordion-section-"+mi(t)[0].dataset.section).addClass("hfg-section-inactive")}),mi(".hfg--cb-devices-switcher a",n.container).addClass("hfg--tab-active")),(_.isUndefined(t)||t)&&("desktop"===e?mi("#customize-footer-actions .preview-desktop").trigger("click"):mi("#customize-footer-actions .preview-mobile").trigger("click"))},addExistingRowsItems:function(){var a=this,t=!1;bi.control(a.controlId).setting.get()&&(t=JSON.parse(bi.control(a.controlId).setting.get())),_.isObject(t)||(t={}),_.each(a.panels,function(r,o){var e={};_.isObject(t[o])&&(e=t[o]),_.each(e,function(e,i){_.isUndefined(e)||_.each(e,function(e,t){var n=mi('.hfg--widgets[data-device="'+o+'"] .grid-stack-item[data-id="'+e.id+'"]').first();n.attr("data-gs-width",e.width),n.attr("data-gs-x",e.x),n.removeClass("item-from-list"),a.addNewWidget(n,r[i]),mi("#accordion-section-"+e.id).removeClass("hfg-section-inactive")})}),a.hideDuplicates(o)}),a.ready=!0},focus:function(){this.container.on("click",".hfg--cb-item-setting, .hfg--cb-item-name, .item-tooltip",function(e){e.preventDefault();var t=mi(this).data("section")||"",n=mi(this).attr("data-control")||"",i=!1;n&&(_.isUndefined(bi.control(n))||(bi.control(n).focus(),i=!0)),i||t&&!_.isUndefined(bi.section(t))&&bi.section(t).focus()}),this.container.on("click",".hfg--cb-row-settings",function(e){e.preventDefault();var t=mi(this).attr("data-id")||"",n=s.id+"_"+t;_.isUndefined(bi.section(n))||bi.section(n).focus()})},closeComponentsSidebar:function(){mi(".widgets-panel--visible").removeClass("widgets-panel--visible"),mi(".hfg--widgets.widgets--visible").removeClass("widgets--visible"),mi(this.widgetSidebarContainer).find(".component-search").val("").trigger("keyup"),mi(this.widgetSidebarContainer).removeClass("preview-right preview-left"),mi("body").removeClass("hfg--widgets-open"),mi(".hfg--component-preview.visible").removeClass("visible")},initComponentsSidebar:function(){var l=this;mi(l.container).on("click",".add-button--grid",function(e){l.insertPoint=mi(this).data("slot"),l.insertRow=mi(this).closest(".hfg--row-inner").find(".hfg--cb-items").data("id"),e.preventDefault(),l.closeComponentsSidebar();var t=e.target.getBoundingClientRect(),n=mi(".wp-full-overlay").hasClass("collapsed")?0:mi("#customize-controls").outerWidth(),i=mi(l.widgetSidebarContainer).outerWidth(),r=mi(l.widgetSidebarContainer).outerHeight(),o={top:t.top-(r+5)};6t.x?1:0});for(var s=0;so[s+1].x&&(o[s].width=o[s+1].x-o[s].x,mi(this).attr("data-gs-width",o[s].width)));var c=mi(this).find(".grid-stack-item-content");c.addClass("hfg-highlight"),setTimeout(function(){c.removeClass("hfg-highlight")},3500),mi("#_sid_"+n+"-"+l.insertRow,l.container[0]).append(this),l.addNewWidget(mi(this),mi(l.container[0]).find(" #_sid_"+n+"-"+l.insertRow)),bi.section(this.getAttribute("data-section")).focus(),l.save(),l.insertRow=null,l.insertPoint=null,l.hideDuplicates(n)})},remove:function(){var i=this;mi(i.container).on("click",".hfg--device-panel .hfg--cb-item-remove",function(e){e.preventDefault();var t=mi(this).closest(".grid-stack-item"),n=t.closest(".hfg--device-panel")[0].getAttribute("data-device");t.attr("data-gs-x",0),t.removeAttr("style"),mi(i.widgetSidebarContainer).find(".hfg--widgets-"+n).prepend(t),mi("#accordion-section-"+t[0].dataset.section).addClass("hfg-section-inactive"),i.updateAllGrids(),i.hideDuplicates(n),i.save()})},removeAllItems:function(){var i=this;mi(i.container).find(".grid-stack-item").each(function(e,t){var n=mi(t).closest(".hfg--device-panel")[0].getAttribute("data-device");mi(t).attr("data-gs-x",0),mi(t).removeAttr("style"),mi(i.widgetSidebarContainer).find(".hfg--widgets-"+n).prepend(t),i.updateAllGrids(),i.hideDuplicates(n)})},hideDuplicates:function(e){var t=mi(this.widgetSidebarContainer).find(".hfg--widgets-"+e+" .grid-stack-item"),n={};_.each(t,function(e){var t=mi(e).data("slug");if("hfg-generic-component"===t)return!1;void 0===n[t]&&(n[t]=[]),n[t].push(e)}),_.each(n,function(e,t){if(e.length<2)return mi(e[0]).removeClass("duplicate"),!1;_.each(e,function(e,t){if(0===t)return mi(e).removeClass("duplicate"),!1;mi(e).addClass("duplicate")})})},encodeValue:function(e){return JSON.stringify(e)},listenForLayoutSideloading:function(){var t=this;document.addEventListener("neve-changed-builder-value",function(e){return!!e.detail&&(e.detail.id===t.id&&(bi.control(t.controlId).setting.set(t.encodeValue(e.detail.value)),t.removeAllItems(),void t.addExistingRowsItems()))})},decodeValue:function(e){return JSON.parse(e)},save:function(){var i=this;if(i.ready){var r={};_.each(i.panels,function(e,n){r[n]={},_.each(e,function(e,t){r[n][t]=_.map(mi(" > .grid-stack-item",e),function(e){return e=mi(e),{x:i.getX(e),y:1,width:i.getW(e),height:1,id:e.data("id")||""}})})}),bi.control(i.controlId).setting.set(i.encodeValue(r))}},showPanel:function(){var t=this;this.container.find(".add-button--grid").addClass("hfg-highlight"),setTimeout(function(){t.container.find(".add-button--grid").removeClass("hfg-highlight")},1e3),this.container.removeClass("hfg--builder--hide").addClass("hfg--builder-show"),setTimeout(function(){var e=t.container.height();mi("#customize-preview").addClass("cb--preview-panel-show").css({bottom:e-1,"margin-top":"0px"})},100)},hidePanel:function(){this.container.removeClass("hfg--builder-show"),mi("#customize-preview").removeClass("cb--preview-panel-show").removeAttr("style")},togglePanel:function(){var t=this;bi.state("expandedPanel").bind(function(e){bi.panel(s.panel).expanded()?(wi.trigger("hfg_panel_builder_open",[s.panel]),top._current_builder_panel=c,t.showPanel()):(t.hidePanel(),t.closeComponentsSidebar())}),t.container.on("click",".hfg--panel-close",function(e){e.preventDefault(),t.container.toggleClass("hfg--builder--hide"),t.container.hasClass("hfg--builder--hide")?mi("#customize-preview").removeClass("cb--preview-panel-show"):mi("#customize-preview").addClass("cb--preview-panel-show")})},panelLayoutCSS:function(){var e=mi("#customize-controls").width();bi.state("paneVisible").get()||(e=0),yi?this.container.find(".hfg--cb-inner").css({"margin-right":e}):this.container.find(".hfg--cb-inner").css({"margin-left":e})},populateComponentPreviews:function(){var n=this,i=n.getTemplate();_.each(n.devices,function(e,t){_.each(n.items,function(e){if(null===e.description)return!1;var t=i(e,"tmpl-hfg--widgets-preview");mi(n.widgetSidebarContainer).append(t)})})},init:function(e,t,n){var i=this,r=i.getTemplate(),o=r(s,"tmpl-hfg--builder-panel"),a=r(s,"tmpl-hfg--widgets-sidebar");i.container=mi(o),i.widgetSidebarContainer=mi(a),mi("body .wp-full-overlay").append(i.container).append(i.widgetSidebarContainer),i.controlId=e,i.items=t,i.devices=n,s.section&&bi.section(s.section).container.addClass("hfg--hide"),i.addDevicePanels(),i.switchToDevice(i.activePanel),i.addAvailableItems(),i.populateComponentPreviews(),i.switchToDevice(i.activePanel),i.drag_drop(),i.initComponentsSidebar(),i.focus(),i.remove(),i.addExistingRowsItems(),i.listenForLayoutSideloading(),bi.panel(s.panel).expanded()?i.showPanel():(i.hidePanel(),i.closeComponentsSidebar()),bi.previewedDevice.bind(function(e){"desktop"===e?i.switchToDevice("desktop",!1):i.switchToDevice("mobile",!1)}),i.togglePanel(),bi.state("paneVisible").get()&&i.panelLayoutCSS(),bi.state("paneVisible").bind(function(){i.panelLayoutCSS()}),mi(window).resize(_.throttle(function(){i.panelLayoutCSS()},100)),i.container.on("click",".hfg--cb-devices-switcher a.switch-to",function(e){e.preventDefault();var t=mi(this).data("device");i.switchToDevice(t);var n=new CustomEvent("neveChangedRepsonsivePreview",{detail:t});document.dispatchEvent(n)}),wi.trigger("hfg_builder_panel_loaded",[c,i])}};return e.init(s.control_id,s.items,s.devices),e},xi=jQuery,_i=wp.customize||null,Si=xi(document),_i.bind("ready",function(e,t){_.each(HFG_Layout_Builder.builders,function(e,t){Ci[t]=new ii(e,t)}),_i.bind("pane-contents-reflowed",function(){setTimeout(function(){0===xi("#sub-accordion-panel-widgets .no-widget-areas-rendered-notice .footer_moved_widgets_text").length&&xi("#sub-accordion-panel-widgets .no-widget-areas-rendered-notice").append('")},1e3)}),_i.state("expandedSection").bind(function(e){xi(".hfg--device-panel .grid-stack-item").removeClass("item-active"),xi(".hfg--cb-row").removeClass("row-active"),e&&(xi('.hfg--cb-row[data-id="'+e.id+'"]').addClass("row-active"),xi(".hfg--device-panel .grid-stack-item.for-s-"+e.id).addClass("item-active"))})}),Si.on("click",".focus-section",function(e){e.preventDefault();var t=xi(this).attr("data-id")||"";(t=t||(t=xi(this).attr("href")||"").replace("#",""))&&_i.section(t)&&_i.section(t).focus()}),Si.on("click",".focus-control",function(e){e.preventDefault();var t=xi(this).attr("data-id")||"";(t=t||(t=xi(this).attr("href")||"").replace("#",""))&&_i.control(t)&&_i.control(t).focus()}),Si.on("click",".focus-panel",function(e){e.preventDefault();var t=xi(this).attr("data-id")||"";(t=t||(t=xi(this).attr("href")||"").replace("#",""))&&_i.panel(t)&&_i.panel(t).focus()}),Si.on("mouseover",".hfg--widgets .grid-stack-item",function(e){var t=xi(this),n=t.attr("data-id");xi(t).closest(".hfg--widgets-panel").find('[data-for-component="'+n+'"]').addClass("visible")}),Si.on("mouseleave",".hfg--widgets .grid-stack-item",function(e){var t=xi(this),n=t.attr("data-id");xi(t).closest(".hfg--widgets-panel").find('[data-for-component="'+n+'"]').removeClass("visible")}),Si.on("mouseover",".hfg--cb-row .grid-stack-item",function(e){var t=xi(this),n=xi(".hfg--cb-item-remove",t).outerWidth()+xi(".hfg--cb-item-setting",t).outerWidth();xi(".grid-stack-item-content",t).innerWidth()-50r;)l(i,n=t[r++])&&(~Se(o,n)||o.push(n));return o}function se(e,t){for(var n=Ae(t),i=k.f,r=P.f,o=0;o"+e+""}var ge,he={set:F,get:N,has:W,enforce:function(e){return W(e)?N(e):F(e,{})},getterFor:function(n){return function(e){var t;if(!v(e)||(t=N(e)).type!==n)throw TypeError("Incompatible receiver, "+n+" required");return t}}},ve=t(function(e){var t=he.get,s=he.enforce,c=String(String).split("String");(e.exports=function(e,t,n,i){var r=!!i&&!!i.unsafe,o=!!i&&!!i.enumerable,a=!!i&&!!i.noTargetGet;"function"==typeof n&&("string"!=typeof t||l(n,"name")||T(n,"name",t),s(n).source=c.join("string"==typeof t?t:"")),e!==u?(r?!a&&e[t]&&(o=!0):delete e[t],o?e[t]=n:T(e,t,n)):o?e[t]=n:f(t,n)})(Function.prototype,"toString",function(){return"function"==typeof this&&t(this).source||L(this)})}),pe=u,me=Math.ceil,we=Math.floor,be=Math.min,ye=Math.max,xe=Math.min,_e={includes:oe(!0),indexOf:oe(!1)},Se=_e.indexOf,Ce=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Oe=Ce.concat("length","prototype"),Ee={f:Object.getOwnPropertyNames||function(e){return ae(e,Oe)}},Pe={f:Object.getOwnPropertySymbols},Ae=te("Reflect","ownKeys")||function(e){var t=Ee.f(I(e)),n=Pe.f;return n?t.concat(n(e)):t},Ie=/#|\.prototype\./,ke=ce.normalize=function(e){return String(e).replace(Ie,".").toLowerCase()},Te=ce.data={},je=ce.NATIVE="N",Re=ce.POLYFILL="P",De=ce,ze=P.f,Me=!!Object.getOwnPropertySymbols&&!d(function(){return!String(Symbol())}),Fe=Me&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Ne=Array.isArray||function(e){return"Array"==r(e)},We=Object.keys||function(e){return ae(e,Ce)},Le=m?Object.defineProperties:function(e,t){I(e);for(var n,i=We(t),r=i.length,o=0;o")}),ai="$0"==="a".replace(/./,"$0"),si=Ve("replace"),ci=!!/./[si]&&""===/./[si]("a","$0"),li=!d(function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}),fi={codeAt:ti(!1),charAt:ti(!0)}.charAt,di=Math.max,ui=Math.min,gi=Math.floor,hi=/\$([$&'`]|\d\d?|<[^>]*>)/g,vi=/\$([$&'`]|\d\d?)/g;function pi(e){return(pi="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}!function(n,e,t,i){var r=Ve(n),o=!d(function(){var e={};return e[r]=function(){return 7},7!=""[n](e)}),a=o&&!d(function(){var e=!1,t=/a/;return"split"===n&&((t={constructor:{}}).constructor[ri]=function(){return t},t.flags="",t[r]=/./[r]),t.exec=function(){return e=!0,null},t[r](""),!e});if(!o||!a||"replace"===n&&(!oi||!ai||ci)||"split"===n&&!li){var s=/./[r],c=t(r,""[n],function(e,t,n,i,r){return t.exec===ei?o&&!r?{done:!0,value:s.call(t,n,i)}:{done:!0,value:e.call(n,t,i)}:{done:!1}},{REPLACE_KEEPS_$0:ai,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:ci}),l=c[0],f=c[1];ve(String.prototype,n,l),ve(RegExp.prototype,r,2==e?function(e,t){return f.call(e,this,t)}:function(e){return f.call(e,this)})}i&&T(RegExp.prototype[r],"sham",!0)}("replace",2,function(r,S,C,e){var O=e.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,E=e.REPLACE_KEEPS_$0,P=O?"$":"$0";return[function(e,t){var n=c(this),i=null==e?void 0:e[r];return void 0!==i?i.call(e,n,t):S.call(String(n),e,t)},function(e,t){if(!O&&E||"string"==typeof t&&-1===t.indexOf(P)){var n=C(S,e,this,t);if(n.done)return n.value}var i=I(e),r=String(this),o="function"==typeof t;o||(t=String(t));var a=i.global;if(a){var s=i.unicode;i.lastIndex=0}for(var c,l,f=[];;){var d=ni(i,r);if(null===d)break;if(f.push(d),!a)break;""===String(d[0])&&(i.lastIndex=(c=r,(l=ie(i.lastIndex))+(s?fi(c,l).length:1)))}for(var u,g="",h=0,v=0;v/g,interpolate:/{{{([\s\S]+?)}}}/g,escape:/{{([^}]+?)}}(?!})/g,variable:"data"};return function(e,t,n){return _.isUndefined(t)&&(t="tmpl-customize-control-"+i.type),!_.isUndefined(n)&&_.isString(n)?r.variable=n:r.variable="data",_.template(mi("#"+t).html(),null,r)(e)}}),drag_drop:function(){var r=this;mi(".hfg--device-panel",r.container).each(function(){var n=mi(this),i=n.data("device");r.panels[i]={},mi(".hfg--cb-items",n).each(function(e){var t=mi(this).attr("data-id")||"",n="_sid_"+i+e;t&&(n="_sid_"+i+"-"+t),mi(this).attr("id",n)}),mi(".grid-stack, .hfg--sidebar-items",n).each(function(){var e=mi(this).attr("data-id")||"";r.panels[i][e]=mi(this),mi(this).droppable({out:function(){},over:function(){},drop:function(e,t){var n=mi(this);r.gridster(n,t,e),r.save()}})});var e=mi("#_sid_mobile-sidebar",n),t=e.attr("id")||!1;mi(".grid-stack-item",n).draggable({revert:"invalid",connectToSortable:!!t&&"#"+t,start:function(e,t){mi("body").addClass("builder-item-moving"),mi(".hfg--cb-items",n).css("z-index",""),t.helper.parent().css("z-index",9999)},stop:function(e,t){mi("body").removeClass("builder-item-moving"),mi(".hfg--cb-items",n).css("z-index",""),t.helper.parent().css("z-index","")}}),0d.x+Math.floor(d.w/2)&&f>d.x&&(n=d.x+d.w,c<=(i=h(n,!0))))return g({el:e.el,x:n,w:c}),e.el.attr("data-gs-x",n),e.el.attr("data-gs-width",c),!0}}console.log("--------------------------------------------------------"),function(e,t){var n,i,r,o,a=0,s=!1;if(console.log("insert at x",t),console.log("insert node",e),p(t)){if(console.log("empty_at_X",t),n=w(t),i=b(t),-1=e.w)if(m(t,e.w))console.log("found",e),f=t,s=!0;else if(e.ox>t)for(r=n.x+n.w,o=(o=v(r))<=e.w?e.w-o:e.w,x(r+1,o),a=h(r),console.log("loop_start_i",r);r>n.x+n.w&&!s;)m(r,e.w)&&(console.log("found_in_loop__i",r),f=r,s=!0),r--;if(!s&&e.oxe.w&&(o=e.w),o-=2,y(n.x,o),console.log("try_move_items_to_left_flag",C),console.log("el2",o),r-=a=h(r),i=b(t);var c=n.x+n.w;for(-1=e.w?e.w:a;for(x(t,l),r=i.x,console.log("loop_start Right",r);0<=r&&!s;)m(r,e.w)&&(f=r,e.x=f,s=!0,console.log("found_in_while_r",r)),r--;s||(f=t,e.w=a,e.x=f,console.log("resize_r_new_w",a),console.log("resize_r_new_x",f))}}else if(console.log("x is not empty"),n=w(t),e.oxE.cols&&(f=E.cols-1),e.x=f,console.log("new node x",f)}(e,_.clone(f));var u=0;for(f+c>E.cols-1&&(u=v(f,!0),console.log("le",u),0E.cols&&(T=E.cols),k=o=j,yi){if(!p(k))for(;k=E.cols){for(R=!0,k=o;k+a>E.cols&&R;)p(k)?k--:(k++,R=!1);o=k}var D={el:t.draggable,x:o,w:a,ox:I,ow:s};D.x<=0&&(D.x=0);(d?(D.x=parseInt(t.draggable.attr("data-gs-x")||0),D.w=parseInt(t.draggable.attr("data-gs-width")||1),function(e,t){var n=e.w;c(e);var i=w(t),r=0;if(-1=o.x)for(var a=_.clone(t);rE.cols){var s=E.cols-n;if(m(s,n))return g({el:e.el,x:s,w:n})}return g({el:e.el,x:r,w:n})}e.x=t,l(e,!0)}(D,o),!0):l(D))?(t.draggable.removeClass("item-from-list"),e.append(t.draggable),t.draggable.removeAttr("style"),console.log("DID Flag: ",C),E.draggingItem=null):(t.draggable.removeAttr("style"),console.log("Can not insert"),C=i),S(),E.updateAllGrids()},updateAllGrids:function(){var n=this;_.each(n.panels[n.activePanel],function(e,t){n.updateGridFlag(e)})},setGridWidth:function(e,t){var n,i,r=this,o=t.element,a=e.width(),s=t.size.width,c=t.originalSize.width,l=Math.ceil(a/r.cols)-1;i=yi?(n=t.originalPosition.left>t.position.left,c!==s):(n=t.originalPosition.left>t.position.left,t.originalPosition.leftm.after&&(f=m.after),u=g+f,o.attr("data-gs-x",h).removeAttr("style")):((f=h-(d=Math.floor((t.position.left-1)/l)))>m.before&&(f=m.before),d=h-f,u=g+f,o.attr("data-gs-x",d).removeAttr("style")),o.attr("data-gs-width",u).removeAttr("style"),void r.updateGridFlag(e);if(i)return yi?t.originalPosition.left!==t.position.left?(d=Math.floor((t.position.left-1)/l),g<(f=g+h-(d=r.cols-d))&&(f=0),u=g-f,(d=h)<=0&&(d=0),console.log("diffRight_RTL_COL_New __left")):(d=Math.ceil((t.position.left+t.size.width-11)/l),(f=h-(d=r.cols-d))>m.before&&(f=m.before),d=h-f,u=g+f):((u=g-(f=(d=Math.round((t.position.left-1)/l))-h))<=0&&(u=1,f=0),d=h+f),o.attr("data-gs-x",d).removeAttr("style"),o.attr("data-gs-width",u).removeAttr("style"),void r.updateGridFlag(e);var w,b=m.x;w=Math.ceil((t.position.left+t.size.width-11)/l),v=m.w+(w-(b+m.w)),m.x+v>m.x+m.w+m.after&&(v=m.w+m.after),s'+t({device:e,id:s.id,rows:s.rows},n)+""},addDevicePanels:function(){var i=this;_.each(i.devices,function(e,t){var n=i.addPanel(t);mi(".hfg--cb-devices-switcher",i.container).append(''+e+""),mi(".hfg--cb-body",i.container).append(n),mi(".hfg-widgets-panel-inner",i.widgetSidebarContainer).append('
')});var e=mi("#hfg-upsell-tmpl");e.length&&mi(e.html()).insertAfter(mi(".hfg--cb-devices-switcher",i.container)),mi(i.container).find(".welcome-notice").removeClass("hidden"),mi(i.container).find(".conditional-header").addClass("hidden")},addItem:function(e,t){var n=this.getTemplate(),i="tmpl-hfg--cb-item";if(0!==mi("#"+i).length){e.elementOrder=t;var r=n(e,i);return mi(r)}},addAvailableItems:function(){var a=this;_.each(a.devices,function(e,o){_.each(a.items,function(e,t){var n=!0;if(!_.isUndefined(e.devices)&&!_.isEmpty(e.devices))if(_.isString(e.devices))e.devices!==o&&(n=!1);else{var i=!1;_.each(e.devices,function(e){o===e&&(i=!0)}),i||(n=!1)}if(n){t=Object.keys(a.items).indexOf(t);var r=a.addItem(e,t);mi(".hfg--widgets-"+o,a.widgetSidebarContainer).prepend(r)}})})},switchToDevice:function(e,t){var n=this;1<_.size(n.devices)?(mi(".hfg--cb-devices-switcher a",n.container).removeClass("hfg--tab-active"),mi(".hfg--cb-devices-switcher .switch-to-"+e,n.container).addClass("hfg--tab-active"),mi(".hfg--device-panel",n.container).addClass("hfg--panel-hide"),mi(".hfg--device-panel.hfg--panel-"+e,n.container).removeClass("hfg--panel-hide"),n.activePanel=e,mi(".hfg--device-panel .hfg-available-items .item-from-list").each(function(e,t){mi("#accordion-section-"+mi(t)[0].dataset.section).removeClass("hfg-section-inactive")}),mi(".hfg--device-panel.hfg--panel-"+e+" .hfg-available-items .item-from-list").each(function(e,t){mi("#accordion-section-"+mi(t)[0].dataset.section).addClass("hfg-section-inactive")})):(mi(".hfg--device-panel.hfg--panel-"+e+" .hfg-available-items .item-from-list").each(function(e,t){mi("#accordion-section-"+mi(t)[0].dataset.section).addClass("hfg-section-inactive")}),mi(".hfg--cb-devices-switcher a",n.container).addClass("hfg--tab-active")),(_.isUndefined(t)||t)&&("desktop"===e?mi("#customize-footer-actions .preview-desktop").trigger("click"):mi("#customize-footer-actions .preview-mobile").trigger("click"))},addExistingRowsItems:function(){var a=this,t=!1;bi.control(a.controlId).setting.get()&&(t=JSON.parse(bi.control(a.controlId).setting.get())),_.isObject(t)||(t={}),_.each(a.panels,function(r,o){var e={};_.isObject(t[o])&&(e=t[o]),_.each(e,function(e,i){_.isUndefined(e)||_.each(e,function(e,t){var n=mi('.hfg--widgets[data-device="'+o+'"] .grid-stack-item[data-id="'+e.id+'"]').first();n.attr("data-gs-width",e.width),n.attr("data-gs-x",e.x),n.removeClass("item-from-list"),a.addNewWidget(n,r[i]),mi("#accordion-section-"+e.id).removeClass("hfg-section-inactive")})}),a.hideDuplicates(o)}),a.ready=!0},focus:function(){this.container.on("click",".hfg--cb-item-setting, .hfg--cb-item-admin-setting, .hfg--cb-item-name, .item-tooltip",function(e){e.preventDefault();var t=mi(this).data("section")||"";console.log("Clicked section",t),-1!==t.indexOf("neve_")&&(t=t.replace("neve_",""),console.log("New section",t));var n=mi(this).data("widget")||"";n&&(console.log("Clicked widget",n),t=n);var i=mi(this).attr("data-control")||"",r=!1;i&&(_.isUndefined(bi.control(i))||(bi.control(i).focus(),r=!0)),r||t&&!_.isUndefined(bi.section(t))&&(console.log("Before focus section"),bi.section(t).focus())}),this.container.on("click",".hfg--cb-row-settings",function(e){e.preventDefault();var t=mi(this).attr("data-id")||"",n=s.id+"_"+t;_.isUndefined(bi.section(n))||bi.section(n).focus()})},closeComponentsSidebar:function(){mi(".widgets-panel--visible").removeClass("widgets-panel--visible"),mi(".hfg--widgets.widgets--visible").removeClass("widgets--visible"),mi(this.widgetSidebarContainer).find(".component-search").val("").trigger("keyup"),mi(this.widgetSidebarContainer).removeClass("preview-right preview-left"),mi("body").removeClass("hfg--widgets-open"),mi(".hfg--component-preview.visible").removeClass("visible")},initComponentsSidebar:function(){var l=this;mi(l.container).on("click",".add-button--grid",function(e){l.insertPoint=mi(this).data("slot"),l.insertRow=mi(this).closest(".hfg--row-inner").find(".hfg--cb-items").data("id"),e.preventDefault(),l.closeComponentsSidebar();var t=e.target.getBoundingClientRect(),n=mi(".wp-full-overlay").hasClass("collapsed")?0:mi("#customize-controls").outerWidth(),i=mi(l.widgetSidebarContainer).outerWidth(),r=mi(l.widgetSidebarContainer).outerHeight(),o={top:t.top-(r+5)};6t.x?1:0});for(var s=0;so[s+1].x&&(o[s].width=o[s+1].x-o[s].x,mi(this).attr("data-gs-width",o[s].width)));var c=mi(this).find(".grid-stack-item-content");c.addClass("hfg-highlight"),setTimeout(function(){c.removeClass("hfg-highlight")},3500),mi("#_sid_"+n+"-"+l.insertRow,l.container[0]).append(this),l.addNewWidget(mi(this),mi(l.container[0]).find(" #_sid_"+n+"-"+l.insertRow)),bi.section(this.getAttribute("data-section")).focus(),l.save(),l.insertRow=null,l.insertPoint=null,l.hideDuplicates(n)})},remove:function(){var i=this;mi(i.container).on("click",".hfg--device-panel .hfg--cb-item-remove",function(e){e.preventDefault();var t=mi(this).closest(".grid-stack-item"),n=t.closest(".hfg--device-panel")[0].getAttribute("data-device");t.attr("data-gs-x",0),t.removeAttr("style"),mi(i.widgetSidebarContainer).find(".hfg--widgets-"+n).prepend(t),mi("#accordion-section-"+t[0].dataset.section).addClass("hfg-section-inactive"),i.updateAllGrids(),i.hideDuplicates(n),i.save()})},removeAllItems:function(){var i=this;mi(i.container).find(".grid-stack-item").each(function(e,t){var n=mi(t).closest(".hfg--device-panel")[0].getAttribute("data-device");mi(t).attr("data-gs-x",0),mi(t).removeAttr("style"),mi(i.widgetSidebarContainer).find(".hfg--widgets-"+n).prepend(t),i.updateAllGrids(),i.hideDuplicates(n)})},hideDuplicates:function(e){var t=mi(this.widgetSidebarContainer).find(".hfg--widgets-"+e+" .grid-stack-item"),n={};_.each(t,function(e){var t=mi(e).data("slug");if("hfg-generic-component"===t)return!1;void 0===n[t]&&(n[t]=[]),n[t].push(e)}),_.each(n,function(e,t){if(e.length<2)return mi(e[0]).removeClass("duplicate"),!1;_.each(e,function(e,t){if(0===t)return mi(e).removeClass("duplicate"),!1;mi(e).addClass("duplicate")})})},encodeValue:function(e){return JSON.stringify(e)},listenForLayoutSideloading:function(){var t=this;document.addEventListener("neve-changed-builder-value",function(e){return!!e.detail&&(e.detail.id===t.id&&(bi.control(t.controlId).setting.set(t.encodeValue(e.detail.value)),t.removeAllItems(),void t.addExistingRowsItems()))})},decodeValue:function(e){return JSON.parse(e)},save:function(){var i=this;if(i.ready){var r={};_.each(i.panels,function(e,n){r[n]={},_.each(e,function(e,t){r[n][t]=_.map(mi(" > .grid-stack-item",e),function(e){return e=mi(e),{x:i.getX(e),y:1,width:i.getW(e),height:1,id:e.data("id")||""}})})}),bi.control(i.controlId).setting.set(i.encodeValue(r))}},showPanel:function(){var t=this;this.container.find(".add-button--grid").addClass("hfg-highlight"),setTimeout(function(){t.container.find(".add-button--grid").removeClass("hfg-highlight")},1e3),this.container.removeClass("hfg--builder--hide").addClass("hfg--builder-show"),setTimeout(function(){var e=t.container.height();mi("#customize-preview").addClass("cb--preview-panel-show").css({bottom:e-1,"margin-top":"0px"})},100)},hidePanel:function(){this.container.removeClass("hfg--builder-show"),mi("#customize-preview").removeClass("cb--preview-panel-show").removeAttr("style")},togglePanel:function(){var t=this;bi.state("expandedPanel").bind(function(e){bi.panel(s.panel).expanded()?(wi.trigger("hfg_panel_builder_open",[s.panel]),top._current_builder_panel=c,t.showPanel()):(t.hidePanel(),t.closeComponentsSidebar())}),t.container.on("click",".hfg--panel-close",function(e){e.preventDefault(),t.container.toggleClass("hfg--builder--hide"),t.container.hasClass("hfg--builder--hide")?mi("#customize-preview").removeClass("cb--preview-panel-show"):mi("#customize-preview").addClass("cb--preview-panel-show")})},panelLayoutCSS:function(){var e=mi("#customize-controls").width();bi.state("paneVisible").get()||(e=0),yi?this.container.find(".hfg--cb-inner").css({"margin-right":e}):this.container.find(".hfg--cb-inner").css({"margin-left":e})},populateComponentPreviews:function(){var n=this,i=n.getTemplate();_.each(n.devices,function(e,t){_.each(n.items,function(e){if(null===e.description)return!1;var t=i(e,"tmpl-hfg--widgets-preview");mi(n.widgetSidebarContainer).append(t)})})},init:function(e,t,n){var i=this,r=i.getTemplate(),o=r(s,"tmpl-hfg--builder-panel"),a=r(s,"tmpl-hfg--widgets-sidebar");i.container=mi(o),i.widgetSidebarContainer=mi(a),mi("body .wp-full-overlay").append(i.container).append(i.widgetSidebarContainer),i.controlId=e,i.items=t,i.devices=n,s.section&&bi.section(s.section).container.addClass("hfg--hide"),i.addDevicePanels(),i.switchToDevice(i.activePanel),i.addAvailableItems(),i.populateComponentPreviews(),i.switchToDevice(i.activePanel),i.drag_drop(),i.initComponentsSidebar(),i.focus(),i.remove(),i.addExistingRowsItems(),i.listenForLayoutSideloading(),bi.panel(s.panel).expanded()?i.showPanel():(i.hidePanel(),i.closeComponentsSidebar()),bi.previewedDevice.bind(function(e){"desktop"===e?i.switchToDevice("desktop",!1):i.switchToDevice("mobile",!1)}),i.togglePanel(),bi.state("paneVisible").get()&&i.panelLayoutCSS(),bi.state("paneVisible").bind(function(){i.panelLayoutCSS()}),mi(window).resize(_.throttle(function(){i.panelLayoutCSS()},100)),i.container.on("click",".hfg--cb-devices-switcher a.switch-to",function(e){e.preventDefault();var t=mi(this).data("device");i.switchToDevice(t)}),wi.trigger("hfg_builder_panel_loaded",[c,i])}};return e.init(s.control_id,s.items,s.devices),e},xi=jQuery,_i=wp.customize||null,Si=xi(document),_i.bind("ready",function(e,t){_.each(HFG_Layout_Builder.builders,function(e,t){Ci[t]=new ii(e,t)}),_i.bind("pane-contents-reflowed",function(){setTimeout(function(){0===xi("#sub-accordion-panel-widgets .no-widget-areas-rendered-notice .footer_moved_widgets_text").length&&xi("#sub-accordion-panel-widgets .no-widget-areas-rendered-notice").append('")},1e3)}),_i.state("expandedSection").bind(function(e){xi(".hfg--device-panel .grid-stack-item").removeClass("item-active"),xi(".hfg--cb-row").removeClass("row-active"),e&&(xi('.hfg--cb-row[data-id="'+e.id+'"]').addClass("row-active"),xi(".hfg--device-panel .grid-stack-item.for-s-"+e.id).addClass("item-active"))})}),Si.on("click",".focus-section",function(e){e.preventDefault();var t=xi(this).attr("data-id")||"";(t=t||(t=xi(this).attr("href")||"").replace("#",""))&&_i.section(t)&&_i.section(t).focus()}),Si.on("click",".focus-control",function(e){e.preventDefault();var t=xi(this).attr("data-id")||"";(t=t||(t=xi(this).attr("href")||"").replace("#",""))&&_i.control(t)&&_i.control(t).focus()}),Si.on("click",".focus-panel",function(e){e.preventDefault();var t=xi(this).attr("data-id")||"";(t=t||(t=xi(this).attr("href")||"").replace("#",""))&&_i.panel(t)&&_i.panel(t).focus()}),Si.on("mouseover",".hfg--widgets .grid-stack-item",function(e){var t=xi(this),n=t.attr("data-id");xi(t).closest(".hfg--widgets-panel").find('[data-for-component="'+n+'"]').addClass("visible")}),Si.on("mouseleave",".hfg--widgets .grid-stack-item",function(e){var t=xi(this),n=t.attr("data-id");xi(t).closest(".hfg--widgets-panel").find('[data-for-component="'+n+'"]').removeClass("visible")}),Si.on("mouseover",".hfg--cb-row .grid-stack-item",function(e){var t=xi(this),n=xi(".hfg--cb-item-remove",t).outerWidth()+xi(".hfg--cb-item-setting",t).outerWidth();xi(".grid-stack-item-content",t).innerWidth()-50o;)s(r,n=t[o++])&&(~Ee(i,n)||i.push(n));return i}function ce(e,t){for(var n=Te(t),r=T.f,o=C.f,i=0;i"+e+""}var me,he={set:D,get:L,has:N,enforce:function(e){return N(e)?L(e):D(e,{})},getterFor:function(n){return function(e){var t;if(!i(e)||(t=L(e)).type!==n)throw TypeError("Incompatible receiver, "+n+" required");return t}}},ve=t(function(e){var t=he.get,u=he.enforce,a=String(String).split("String");(e.exports=function(e,t,n,r){var o=!!r&&!!r.unsafe,i=!!r&&!!r.enumerable,c=!!r&&!!r.noTargetGet;"function"==typeof n&&("string"!=typeof t||s(n,"name")||k(n,"name",t),u(n).source=a.join("string"==typeof t?t:"")),e!==p?(o?!c&&e[t]&&(i=!0):delete e[t],i?e[t]=n:k(e,t,n)):i?e[t]=n:d(t,n)})(Function.prototype,"toString",function(){return"function"==typeof this&&t(this).source||W(this)})}),ye=p,ge=Math.ceil,we=Math.floor,_e=Math.min,Oe=Math.max,Se=Math.min,je={includes:oe(!0),indexOf:oe(!1)},Ee=je.indexOf,ze=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],xe=ze.concat("length","prototype"),Ce={f:Object.getOwnPropertyNames||function(e){return ie(e,xe)}},Pe={f:Object.getOwnPropertySymbols},Te=te("Reflect","ownKeys")||function(e){var t=Ce.f(l(e)),n=Pe.f;return n?t.concat(n(e)):t},ke=/#|\.prototype\./,Ae=ue.normalize=function(e){return String(e).replace(ke,".").toLowerCase()},Me=ue.data={},Fe=ue.NATIVE="N",Ie=ue.POLYFILL="P",Re=ue,De=C.f,Le=Array.isArray||function(e){return"Array"==o(e)},Ne=!!Object.getOwnPropertySymbols&&!c(function(){return!String(Symbol())}),We=Ne&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Ke=q("wks"),Ue=p.Symbol,qe=We?Ue:Ue&&Ue.withoutSetter||I,Ge=fe("species"),He=[].push,Qe={forEach:de(0),map:de(1),filter:de(2),some:de(3),every:de(4),find:de(5),findIndex:de(6)},Ve=Object.keys||function(e){return ie(e,ze)},Xe=b?Object.defineProperties:function(e,t){l(e);for(var n,r=Ve(t),o=r.length,i=0;i .header-menu-sidebar, #page > .header-menu-sidebar").remove(),n?(i("#masthead").append(i("#header-menu-sidebar")),i("body").hasClass("is-menu-sidebar")&&i("#header-menu-sidebar").css({display:"block",height:"auto"})):i("body").prepend(i("#header-menu-sidebar"))}var r=i("#masthead");if(i(".search-form--mobile",r).length){t&&i(".mobile-search-form-sidebar").remove();var o=i(".search-form--mobile").eq(0);o.addClass("mobile-search-form-sidebar").removeClass("hide-on-mobile hide-on-tablet"),i("body").prepend(o)}c(document,"header_builder_panel_changed",{bubbles:!0,detail:{partial_id:e}})}var o=i(document);wp.customize("header_textcolor",function(e){e.bind(function(e){"blank"===e?i(".site-title, .site-description").css({clip:"rect(1px, 1px, 1px, 1px)",position:"absolute"}):(i(".site-title, .site-description").css({clip:"auto",position:"relative"}),i(".site-title a, .site-description").css({color:e}))})}),e.bind("preview-ready",function(){e.preview.bind("header_builder_panel_changed",function(){c(document,"header_builder_panel_changed",{bubbles:!0,detail:"open"})}),e.preview.bind("header_sidebar_open",function(){c(document,"customize_control_sidebar",{bubbles:!0,detail:"open"})}),e.preview.bind("header_sidebar_close",function(){c(document,"customize_control_sidebar",{bubbles:!0,detail:"close"})})}),wp.customize("header_sidebar_animate",function(e){console.log("header_sidebar_animate -- triggered"),e.bind(function(e){t("header_builder_panel",!1),c(document,"customize_section_opened",{bubbles:!0,detail:"header_sidebar"}),1o;)s(r,n=t[o++])&&(~be(i,n)||i.push(n));return i}(e,me)}},ve={f:Object.getOwnPropertySymbols},ge=function(e,t){return arguments.length<2?X(ce[e])||X(d[e]):ce[e]&&ce[e][t]||d[e]&&d[e][t]}("Reflect","ownKeys")||function(e){var t=he.f(c(e)),n=ve.f;return n?t.concat(n(e)):t},ye=/#|\.prototype\./,_e=te.normalize=function(e){return String(e).replace(ye,".").toLowerCase()},we=te.data={},Oe=te.NATIVE="N",Se=te.POLYFILL="P",ze=te,Ee=E.f,je=Object.defineProperty,xe={},Ce=pe.indexOf,Pe=[].indexOf,Te=!!Pe&&1/[1].indexOf(1,-0)<0,ke=!!(oe=[]["indexOf"])&&a(function(){oe.call(null,re||function(){throw 1},1)}),Me=function(e,t){if(s(xe,e))return xe[e];var n=[][e],r=!!s(t=t||{},"ACCESSORS")&&t.ACCESSORS,o=s(t,0)?t[0]:ne,i=s(t,1)?t[1]:void 0;return xe[e]=!!n&&!a(function(){if(r&&!u)return!0;var e={length:-1};r?je(e,1,{enumerable:!0,get:ne}):e[1]=1,n.call(e,o,i)})}("indexOf",{ACCESSORS:!0,1:0});!function(e,t){var n,r,o,i,a,c=e.target,u=e.global,s=e.stat;if(n=u?d:s?d[c]||f(c,{}):(d[c]||{}).prototype)for(r in t){if(i=t[r],o=e.noTargetGet?(a=Ee(n,r))&&a.value:n[r],!ze(u?r:c+(s?".":"#")+r,e.forced)&&void 0!==o){if(typeof i==typeof o)continue;ee(i,o)}(e.sham||o&&o.sham)&&C(i,"sham",!0),ae(n,r,i,e)}}({target:"Array",proto:!0,forced:Te||!ke||!Me},{indexOf:function(e,t){return Te?Pe.apply(this,arguments)||0:Ce(this,e,1 .header-menu-sidebar, #page > .header-menu-sidebar").remove(),n?(i("#masthead").append(i("#header-menu-sidebar")),i("body").hasClass("is-menu-sidebar")&&i("#header-menu-sidebar").css({display:"block",height:"auto"})):i("body").prepend(i("#header-menu-sidebar"))}var r=i("#masthead");if(i(".search-form--mobile",r).length){t&&i(".mobile-search-form-sidebar").remove();var o=i(".search-form--mobile").eq(0);o.addClass("mobile-search-form-sidebar").removeClass("hide-on-mobile hide-on-tablet"),i("body").prepend(o)}a(document,"header_builder_panel_changed",{bubbles:!0,detail:{partial_id:e}})}var r=i(document);wp.customize("header_textcolor",function(e){e.bind(function(e){"blank"===e?i(".site-title, .site-description").css({clip:"rect(1px, 1px, 1px, 1px)",position:"absolute"}):(i(".site-title, .site-description").css({clip:"auto",position:"relative"}),i(".site-title a, .site-description").css({color:e}))})}),e.bind("preview-ready",function(){e.preview.bind("header_builder_panel_changed",function(){a(document,"header_builder_panel_changed",{bubbles:!0,detail:"open"})}),e.preview.bind("header_sidebar_open",function(){a(document,"customize_control_sidebar",{bubbles:!0,detail:"open"})}),e.preview.bind("header_sidebar_close",function(){a(document,"customize_control_sidebar",{bubbles:!0,detail:"close"})})}),wp.customize("header_sidebar_animate",function(e){console.log("header_sidebar_animate -- triggered"),e.bind(function(e){t("header_builder_panel",!1),a(document,"customize_section_opened",{bubbles:!0,detail:"header_sidebar"}),1 li.accordion-section:not(.panel-meta) { display: none !important; } -.hfg-instructions-section { - display: list-item !important; - - video { - border-radius: 5px; - border: 1px solid #ccc; - box-sizing: border-box; - } - - .quick-links { - font-size: 14px; - font-weight: 500; - - a { - text-decoration: none; - } - } - - .quick-links-wrap { - margin: 10px 0; - display: block; - background: #fff; - border-radius: 3px; - padding: 10px 20px; - - span { - margin-right: 10px; - } - } -} - .hfg--device-panel.hfg--panel-mobile .hfg--cp-sidebar .hfg--cb-row .hfg--row-inner .hfg--cb-items.hfg--sidebar-items { height: calc(100% - 30px); } diff --git a/header-footer-grid/assets/scss/frontend/components/_button.scss b/header-footer-grid/assets/scss/frontend/components/_button.scss index 39e0b2382f..2a30d3a728 100644 --- a/header-footer-grid/assets/scss/frontend/components/_button.scss +++ b/header-footer-grid/assets/scss/frontend/components/_button.scss @@ -1,11 +1,11 @@ -.hfg-is-group > div:first-of-type { - .button { - margin-right: 20px; +.hfg-is-group { + > div:first-of-type .button { + margin-right: 20px; } -} -.hfg-is-group > div:last-of-type { - .button { - margin-left: 20px; + > div:last-of-type .button { + margin-left: 20px; } } + + diff --git a/header-footer-grid/assets/scss/frontend/components/_nav-cart.scss b/header-footer-grid/assets/scss/frontend/components/_nav-cart.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/header-footer-grid/assets/scss/frontend/components/_search-field.scss b/header-footer-grid/assets/scss/frontend/components/_search-field.scss index ecaa1c942b..74002df9db 100644 --- a/header-footer-grid/assets/scss/frontend/components/_search-field.scss +++ b/header-footer-grid/assets/scss/frontend/components/_search-field.scss @@ -1,3 +1,8 @@ +// Fixes the layout issue on canvas display, elements should not have height forced to 100% +.container.responsive-search, .row { + height: inherit; +} + .search-field { line-height: 1; flex-grow: 1; diff --git a/header-footer-grid/assets/scss/frontend/layout/_footer.scss b/header-footer-grid/assets/scss/frontend/layout/_footer.scss index 0f7a4dc448..25f575e615 100644 --- a/header-footer-grid/assets/scss/frontend/layout/_footer.scss +++ b/header-footer-grid/assets/scss/frontend/layout/_footer.scss @@ -26,21 +26,7 @@ } } - -// Footer Main -.footer-main { - .footer--row-inner { - padding-top: 2.5em; - padding-bottom: 2.5em; - } -} - .footer--row { - &.layout-fullwidth { - .hfg-container { - max-width: initial; - } - } .builder-item--group { justify-content: flex-start; .item--inner { diff --git a/header-footer-grid/assets/scss/frontend/layout/_main.scss b/header-footer-grid/assets/scss/frontend/layout/_main.scss index f227b5a4e3..2707aa0ba6 100644 --- a/header-footer-grid/assets/scss/frontend/layout/_main.scss +++ b/header-footer-grid/assets/scss/frontend/layout/_main.scss @@ -1,11 +1,5 @@ .site-header { position: relative; - - .hfg-container { - display: flex; - flex-direction: column; - justify-content: center; - } } .builder-item { diff --git a/header-footer-grid/assets/scss/frontend/layout/_new_main.scss b/header-footer-grid/assets/scss/frontend/layout/_new_main.scss new file mode 100644 index 0000000000..0d24671f3a --- /dev/null +++ b/header-footer-grid/assets/scss/frontend/layout/_new_main.scss @@ -0,0 +1,112 @@ +.site-header { + position: relative; + + .header--row-inner { + align-items: center; + display: flex; + } +} + +.builder-item { + margin-top: 4px; + margin-bottom: 4px; + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; + + &.hfg-end { + margin-left: auto; + } + + &.hfg-start { + margin-right: auto; + } +} + +$desktop: map-get($gl-devices-list, desktop); +@media #{$desktop}{ + .builder-item { + margin-top: 8px; + margin-bottom: 8px; + } +} + +// +.hfg-slot { + display: flex; + align-items: center; + + &.right { + justify-content: flex-end; + } + + &.center { + justify-content: center; + } +} + + +.layout-fullwidth { + .container { + max-width: 100% !important; + } +} + +.layout-contained { + max-width: $container_width; + margin: 0 auto; +} + +// Page Header and Header specific alignments. +[data-row-id] { + .row { + display: grid; + grid-template-columns: auto auto; + } +} + +.has-center .row--wrapper { + grid-template-columns: 1fr auto 1fr; +} + +.footer--row { + .hfg-slot { + display: flex; + flex-direction: column; + } + + .row { + display: grid; + } + + .builder-item { + width: 100%; + } +} + +// + +// +.hfg_header.site-header { + box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1); +} + +// + +@media (max-width: 960px) { + footer .footer--row-inner .row { + grid-template-columns: 1fr; + } +} + +// Fixes for background, overlays and vertical alignments +[class*=--row-inner] { + position: relative; + align-items: center; + display: flex; + + .container, .row { + height: auto; + } +} diff --git a/header-footer-grid/assets/scss/style.scss b/header-footer-grid/assets/scss/style.scss index 295560b4c4..f3a81404cf 100644 --- a/header-footer-grid/assets/scss/style.scss +++ b/header-footer-grid/assets/scss/style.scss @@ -2,9 +2,10 @@ @import "frontend/mixins"; @import "frontend/vars"; -@import "frontend/layout/main"; +//@import "frontend/layout/main"; @import "frontend/layout/mobile_sidebar"; @import "frontend/layout/footer"; +@import "frontend/layout/new_main"; // COMPONENTS diff --git a/header-footer-grid/functions-migration.php b/header-footer-grid/functions-migration.php index 69e54f63af..32d734689e 100644 --- a/header-footer-grid/functions-migration.php +++ b/header-footer-grid/functions-migration.php @@ -111,61 +111,88 @@ function neve_self_heal_mods() { * @return array Migration schema. */ function neve_hfg_footer_settings() { - $builder = [ + + $empty_row = [ + 'left' => [], + 'c-left' => [], + 'center' => [], + 'c-right' => [], + 'right' => [], + ]; + + $builder = [ 'desktop' => [ - 'top' => [], - 'bottom' => [], + 'top' => $empty_row, + 'main' => $empty_row, + 'bottom' => $empty_row, ], ]; - $sidebars = (int) get_theme_mod( 'neve_footer_widget_columns', '0' ); - $sidebars_names = array( - 'footer-one-widgets', - 'footer-two-widgets', - 'footer-three-widgets', - 'footer-four-widgets', - ); - for ( $i = 0; $i < $sidebars; $i ++ ) { - $builder['desktop']['top'][ $sidebars_names[ $i ] ] = [ - 'id' => $sidebars_names[ $i ], - 'width' => 12 / $sidebars, - 'x' => $i * ( 12 / $sidebars ), - ]; - } - $components = []; - $content_type = get_theme_mod( 'neve_footer_content_type', 'text' ); - if ( $content_type === 'text' ) { - $builder['desktop']['bottom']['footer_copyright'] = [ - 'id' => 'footer_copyright', - 'width' => 12, - 'x' => 0, - ]; - $components['footer_copyright']['component_align'] = 'center'; - } + $builder['desktop']['bottom']['left'][] = [ + 'id' => 'footer_copyright', + ]; - $components['hfg_footer_layout_bottom']['skin'] = 'dark-mode'; + return [ + 'builder' => $builder, + 'components' => [], + ]; +} - if ( $content_type === 'footer_menu' ) { - $builder['desktop']['bottom']['footer-menu'] = [ - 'id' => 'footer-menu', - 'width' => 12, - 'x' => 0, - ]; - $components['footer-menu']['component_align'] = 'center'; - } +/** + * Define migration logic for header. + * + * @return array Migration schema. + */ +function neve_hfg_header_settings() { + $empty_row = [ + 'left' => [], + 'c-left' => [], + 'center' => [], + 'c-right' => [], + 'right' => [], + ]; + $builder = [ + 'desktop' => [ + 'top' => $empty_row, + 'main' => $empty_row, + 'bottom' => $empty_row, + ], + 'mobile' => [ + 'top' => $empty_row, + 'main' => $empty_row, + 'bottom' => $empty_row, + 'sidebar' => [], + ], + ]; + + $builder['desktop']['main']['left'][] = [ + 'id' => 'logo', + ]; + $builder['desktop']['main']['right'][] = [ + 'id' => 'primary-menu', + ]; + $builder['mobile']['main']['left'][] = [ + 'id' => 'logo', + ]; + $builder['mobile']['main']['right'][] = [ + 'id' => 'nav-icon', + ]; + $builder['mobile']['sidebar'][] = [ + 'id' => 'primary-menu', + ]; return [ 'builder' => $builder, - 'components' => $components, + 'components' => [], ]; } /** * Define migration logic for header. * - * @return array Migratoin schema. + * @return array Migration schema. */ -function neve_hfg_header_settings() { +function neve_hfg_legacy_header_settings() { $builder = [ 'desktop' => [ 'top' => [], @@ -301,11 +328,99 @@ function neve_hfg_header_settings() { ]; } +/** + * Define migration logic for footer. + * + * @return array Migration schema. + */ +function neve_hfg_legacy_footer_settings() { + $builder = [ + 'desktop' => [ + 'top' => [], + 'bottom' => [], + ], + ]; + $sidebars = (int) get_theme_mod( 'neve_footer_widget_columns', '0' ); + + $sidebars_names = array( + 'footer-one-widgets', + 'footer-two-widgets', + 'footer-three-widgets', + 'footer-four-widgets', + ); + for ( $i = 0; $i < $sidebars; $i ++ ) { + $builder['desktop']['top'][ $sidebars_names[ $i ] ] = [ + 'id' => $sidebars_names[ $i ], + 'width' => 12 / $sidebars, + 'x' => $i * ( 12 / $sidebars ), + ]; + } + $components = []; + $content_type = get_theme_mod( 'neve_footer_content_type', 'text' ); + if ( $content_type === 'text' ) { + $builder['desktop']['bottom']['footer_copyright'] = [ + 'id' => 'footer_copyright', + 'width' => 12, + 'x' => 0, + ]; + $components['footer_copyright']['component_align'] = 'center'; + } + + $components['hfg_footer_layout_bottom']['skin'] = 'dark-mode'; + + if ( $content_type === 'footer_menu' ) { + $builder['desktop']['bottom']['footer-menu'] = [ + 'id' => 'footer-menu', + 'width' => 12, + 'x' => 0, + ]; + $components['footer-menu']['component_align'] = 'center'; + } + + return [ + 'builder' => $builder, + 'components' => $components, + ]; +} + + add_filter( 'hfg_settings_schema', function ( $old_schema ) { - $header = neve_hfg_header_settings(); - $footer = neve_hfg_footer_settings(); + $is_new_builder = neve_is_new_builder(); + $header = $is_new_builder ? neve_hfg_header_settings() : neve_hfg_legacy_header_settings(); + $footer = $is_new_builder ? neve_hfg_footer_settings() : neve_hfg_legacy_footer_settings(); + + $empty_row = [ + 'left' => [], + 'c-left' => [], + 'center' => [], + 'c-right' => [], + 'right' => [], + ]; + $page_header = $is_new_builder ? + [ + 'desktop' => [ + 'top' => $empty_row, + 'bottom' => $empty_row, + ], + 'mobile' => [ + 'top' => $empty_row, + 'bottom' => $empty_row, + ], + ] + : + [ + 'desktop' => [ + 'top' => [], + 'bottom' => [], + ], + 'mobile' => [ + 'top' => [], + 'bottom' => [], + ], + ]; + $components = array_merge( $header['components'], $footer['components'] ); $defaults = []; foreach ( $components as $id => $settings ) { @@ -314,15 +429,28 @@ function ( $old_schema ) { } } + if ( $is_new_builder ) { + return array_merge( + [ + 'hfg_header_layout_v2' => wp_json_encode( $header['builder'] ), + 'hfg_footer_layout_v2' => wp_json_encode( $footer['builder'] ), + 'hfg_page_header_layout_v2' => wp_json_encode( $page_header ), + ], + $defaults + ); + }; + return array_merge( [ - 'hfg_header_layout' => wp_json_encode( $header['builder'] ), - 'hfg_footer_layout' => wp_json_encode( $footer['builder'] ), + 'hfg_header_layout' => wp_json_encode( $header['builder'] ), + 'hfg_footer_layout' => wp_json_encode( $footer['builder'] ), + 'hfg_page_header_layout' => wp_json_encode( $page_header ), ], $defaults ); - } + }, + 101 ); diff --git a/header-footer-grid/loader.php b/header-footer-grid/loader.php index d91b6de1de..7fe8a667a1 100644 --- a/header-footer-grid/loader.php +++ b/header-footer-grid/loader.php @@ -10,6 +10,7 @@ 'HFG\Core\Components\Nav', 'HFG\Core\Components\Button', 'HFG\Core\Components\CustomHtml', + 'HFG\Core\Components\PaletteSwitch', 'HFG\Core\Components\Search', 'HFG\Core\Components\SearchResponsive', 'HFG\Core\Components\SecondNav', diff --git a/header-footer-grid/templates/components/component-cart-icon.php b/header-footer-grid/templates/components/component-cart-icon.php index dc5ee44f1c..5f56725b7e 100644 --- a/header-footer-grid/templates/components/component-cart-icon.php +++ b/header-footer-grid/templates/components/component-cart-icon.php @@ -20,10 +20,10 @@ $cart_is_empty = WC()->cart->get_cart_contents_count() === 0; $off_canvas_closing_button = ''; -$mini_cart_classes = array( 'nv-nav-cart', 'widget' ); +$mini_cart_classes = [ 'nv-nav-cart', 'widget' ]; if ( $cart_style === 'off-canvas' ) { - $mini_cart_classes = array( 'cart-off-canvas', 'col-sm-12', 'col-sm-12' ); - $off_canvas_closing_button = '
' . __( 'Close', 'neve' ) . '
'; + $mini_cart_classes = neve_is_new_skin() ? [ 'nv-nav-cart', 'cart-off-canvas', 'widget' ] : [ 'cart-off-canvas', 'col-sm-12' ]; + $off_canvas_closing_button = ''; } if ( (bool) $expand_enabled === false ) { $mini_cart_classes[] = 'expand-disable'; diff --git a/header-footer-grid/templates/components/component-palette-switch.php b/header-footer-grid/templates/components/component-palette-switch.php new file mode 100644 index 0000000000..c125ae93ba --- /dev/null +++ b/header-footer-grid/templates/components/component-palette-switch.php @@ -0,0 +1,30 @@ + + diff --git a/header-footer-grid/templates/components/component-search-responsive.php b/header-footer-grid/templates/components/component-search-responsive.php index 115aace9c6..07688d0610 100644 --- a/header-footer-grid/templates/components/component-search-responsive.php +++ b/header-footer-grid/templates/components/component-search-responsive.php @@ -35,11 +35,11 @@ '; // .nv-single-page-wrap .col close - } - /** * Register LifterLMS Catalog Sidebar. */ @@ -329,7 +347,7 @@ public function render_catalog_sidebar() { return; } - $sidebar_position = get_theme_mod( 'neve_default_sidebar_layout', 'right' ); + $sidebar_position = $this->get_sidebar_position(); echo '
'; dynamic_sidebar( 'llms_shop' ); echo '
'; diff --git a/inc/compatibility/starter-content/theme-mods.php b/inc/compatibility/starter-content/theme-mods.php index d0af959db0..f8c32e808b 100644 --- a/inc/compatibility/starter-content/theme-mods.php +++ b/inc/compatibility/starter-content/theme-mods.php @@ -569,7 +569,7 @@ 'tablet' => 'left', 'mobile' => 'left', ), - 'hfg_header_layout' => '{"desktop":{"top":[],"main":[{"x":0,"y":1,"width":3,"height":1,"id":"logo"},{"x":3,"y":1,"width":6,"height":1,"id":"primary-menu"},{"x":9,"y":1,"width":1,"height":1,"id":"header_search_responsive"},{"x":10,"y":1,"width":2,"height":1,"id":"button_base"}],"bottom":[]},"mobile":{"top":[],"main":[{"x":0,"y":1,"width":8,"height":1,"id":"logo"},{"x":8,"y":1,"width":4,"height":1,"id":"nav-icon"}],"bottom":[],"sidebar":[{"x":0,"y":1,"width":1,"height":1,"id":"header_search"},{"x":1,"y":1,"width":8,"height":1,"id":"primary-menu"},{"x":9,"y":1,"width":1,"height":1,"id":"button_base"}]}}', + 'hfg_header_layout_v2' => '{"desktop":{"top":{"left":[],"c-left":[],"center":[],"c-right":[],"right":[]},"main":{"left":[{"id":"logo"}],"c-left":[],"center":[],"c-right":[],"right":[{"id":"primary-menu"},{"id":"header_search_responsive"},{"id":"button_base"}]},"bottom":{"left":[],"c-left":[],"center":[],"c-right":[],"right":[]}},"mobile":{"top":{"left":[],"c-left":[],"center":[],"c-right":[],"right":[]},"main":{"left":[{"id":"logo","width":8,"x":0}],"c-left":[],"center":[],"c-right":[],"right":[{"id":"nav-icon","width":4,"x":8}]},"bottom":{"left":[],"c-left":[],"center":[],"c-right":[],"right":[]},"sidebar":[{"id":"header_search"},{"id":"primary-menu"},{"id":"button_base"}]}}', 'button_base_component_padding' => array( 'mobile' => @@ -701,35 +701,13 @@ 'header_search_responsive_field_text_color' => 'var(--nv-primary-accent)', 'footer_copyright_color' => 'var(--nv-primary-accent)', 'footer_copyright_component_vertical_align' => 'middle', - 'hfg_footer_layout_bottom_height' => '{"mobile":0,"tablet":0,"desktop":50}', - 'footer_copyright_component_margin' => + 'footer_copyright_component_align' => array( - 'mobile' => - array( - 'top' => 0, - 'right' => 0, - 'bottom' => 0, - 'left' => 0, - ), - 'tablet' => - array( - 'top' => 0, - 'right' => 0, - 'bottom' => 0, - 'left' => 0, - ), - 'desktop' => - array( - 'top' => '-10', - 'right' => '0', - 'bottom' => '20', - 'left' => '0', - ), - 'mobile-unit' => 'px', - 'tablet-unit' => 'px', - 'desktop-unit' => 'px', + 'mobile' => 'center', + 'tablet' => 'center', + 'desktop' => 'center', ), - 'hfg_footer_layout' => '{"desktop":{"top":[],"bottom":[{"x":0,"y":1,"width":12,"height":1,"id":"footer_copyright"}]}}', + 'hfg_footer_layout_v2' => '{"desktop":{"top":{"left":[],"c-left":[],"center":[],"c-right":[],"right":[]},"bottom":{"left":[],"c-left":[{"id":"footer_copyright"}],"center":[],"c-right":[],"right":[]}}}', 'primary-menu_component_padding' => array( 'mobile' => @@ -758,5 +736,19 @@ 'desktop-unit' => 'px', ), 'button_base_link_setting' => '/?pagename=contact', - + 'hfg_footer_layout_bottom_background' => + array( + 'type' => 'color', + 'colorValue' => 'var(--nv-site-bg)', + 'imageUrl' => '', + 'focusPoint' => + array( + 'x' => 0.5, + 'y' => 0.5, + ), + 'overlayColorValue' => '', + 'overlayOpacity' => 50, + 'fixed' => false, + 'useFeatured' => false, + ), ); diff --git a/inc/compatibility/woocommerce.php b/inc/compatibility/woocommerce.php index adbdbb4564..f8d60838d2 100644 --- a/inc/compatibility/woocommerce.php +++ b/inc/compatibility/woocommerce.php @@ -11,6 +11,7 @@ use HFG\Core\Components\CartIcon; use HFG\Core\Magic_Tags; use Neve\Core\Settings\Config; +use Neve\Customizer\Defaults\Layout; use Neve\Views\Layouts\Layout_Sidebar; /** @@ -20,6 +21,8 @@ */ class Woocommerce { + use Layout; + /** * Primary button selectors. * @@ -189,6 +192,39 @@ public function register_hooks() { $this->move_checkout_coupon(); $this->add_inline_selectors(); add_action( 'wp', [ $this, 'setup_form_buttons' ] ); + + if ( neve_is_new_skin() ) { + add_action( + 'woocommerce_checkout_before_order_review_heading', + function () { + echo '
'; + } + ); + add_action( 'woocommerce_checkout_after_order_review', [ $this, 'close_div' ] ); + + add_action( + 'woocommerce_before_single_product_summary', + function () { + echo '
'; + + }, + 11 + ); + add_action( 'woocommerce_after_single_product_summary', [ $this, 'close_div' ] ); + // Change default for shop columns WooCommerce option. + add_filter( 'default_option_woocommerce_catalog_columns', [ $this, 'change_default_shop_cols' ] ); + } + } + + /** + * Change default for catalog columns. + * + * @param int $default default value -> 4. + * + * @return int + */ + public function change_default_shop_cols( $default ) { + return 3; } /** @@ -256,6 +292,12 @@ public function update_woo_width() { * @return mixed */ public function change_breadcrumbs_delimiter( $default ) { + if ( neve_is_new_skin() ) { + $default['delimiter'] = '\'; + + return $default; + } + $default['delimiter'] = '»'; return $default; @@ -377,9 +419,19 @@ public function sidebar_toggle() { return; } - $button_text = apply_filters( 'neve_filter_woo_sidebar_open_button_text', __( 'Filter', 'neve' ) . '»' ); $button_attrs = apply_filters( 'neve_woocommerce_sidebar_filter_btn_data_attrs', '' ); - echo '' . esc_html( $button_text ) . ''; + + + if ( neve_is_new_skin() ) { + echo ''; + echo ''; + echo ''; + + return; + } + + $button_text = apply_filters( 'neve_filter_woo_sidebar_open_button_text', __( 'Filter', 'neve' ) . '»' ); + echo '' . esc_html( $button_text ) . ''; } /** @@ -502,7 +554,7 @@ public function add_inputs_selectors( $selectors ) { .woocommerce-page .select2-container--default .select2-selection--single, .woocommerce-page .woocommerce form .form-row input.input-text, .woocommerce-page .woocommerce form .form-row textarea, - .wc-block-product-search form input.wc-block-product-search__field'; + input.wc-block-product-search__field'; } /** @@ -516,7 +568,6 @@ public function add_inputs_spacing_selectors( $selectors ) { return $selectors . ', .woocommerce-page .select2'; } - /** * Add checkout labels to style. * @@ -677,17 +728,16 @@ private function should_render_sidebar_toggle() { if ( ! is_active_sidebar( 'shop-sidebar' ) ) { return false; } - if ( is_shop() ) { - $theme_mod = apply_filters( 'neve_sidebar_position', get_theme_mod( 'neve_shop_archive_sidebar_layout', 'right' ) ); - if ( $theme_mod !== 'right' && $theme_mod !== 'left' ) { - return false; - } - } + + $mod = 'neve_shop_archive_sidebar_layout'; if ( is_product() ) { - $theme_mod = apply_filters( 'neve_sidebar_position', get_theme_mod( 'neve_single_product_sidebar_layout', 'right' ) ); - if ( $theme_mod !== 'right' && $theme_mod !== 'left' ) { - return false; - } + $mod = 'neve_single_product_sidebar_layout'; + } + + $default = $this->sidebar_layout_alignment_default( $mod ); + $theme_mod = apply_filters( 'neve_sidebar_position', get_theme_mod( $mod, $default ) ); + if ( $theme_mod !== 'right' && $theme_mod !== 'left' ) { + return false; } return true; @@ -784,9 +834,11 @@ public function add_buttons_hover_selectors( $selector ) { } /** - * Setup Form Buttons Type + * Setup legacy form buttons. + * + * @since 3.0.0 */ - public function setup_form_buttons() { + private function setup_legacy_form_buttons() { $form_buttons_type = get_theme_mod( 'neve_form_button_type', 'primary' ); if ( $form_buttons_type === 'primary' ) { add_filter( @@ -829,4 +881,39 @@ public function setup_form_buttons() { 1 ); } + + /** + * Setup Form Buttons Type + */ + public function setup_form_buttons() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_form_buttons(); + + return; + } + add_filter( + 'neve_selectors_' . Config::CSS_SELECTOR_FORM_BUTTON, + function ( $selectors ) { + return $selectors . ' + ,#review_form #respond input#submit, + .woocommerce-cart .wc-proceed-to-checkout a.checkout-button, + .woocommerce-checkout #payment .place-order button#place_order, + .woocommerce-account .woocommerce [type="submit"]'; + }, + 10, + 1 + ); + add_filter( + 'neve_selectors_' . Config::CSS_SELECTOR_FORM_BUTTON_HOVER, + function ( $selectors ) { + return $selectors . ' + ,#review_form #respond input#submit:hover, + .woocommerce-cart .wc-proceed-to-checkout a.checkout-button:hover, + .woocommerce-checkout #payment .place-order button#place_order:hover, + .woocommerce-account .woocommerce [type="submit"]:hover'; + }, + 10, + 1 + ); + } } diff --git a/inc/core/admin.php b/inc/core/admin.php index b3c3ac7868..7932318740 100644 --- a/inc/core/admin.php +++ b/inc/core/admin.php @@ -10,6 +10,8 @@ namespace Neve\Core; +use Neve\Core\Settings\Mods_Migrator; + /** * Class Admin * @@ -70,6 +72,158 @@ function () { add_filter( 'all_plugins', array( $this, 'change_plugin_names' ) ); add_action( 'after_switch_theme', array( $this, 'migrate_options' ) ); + + add_action( 'init', [ $this, 'run_skin_and_builder_switches' ] ); + add_filter( 'ti_tpc_theme_mods_pre_import', [ $this, 'migrate_theme_mods_for_new_skin' ] ); + + add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] ); + add_filter( 'neve_pro_react_controls_localization', [ $this, 'adapt_conditional_headers' ] ); + if ( class_exists( '\Neve_Pro\Modules\Header_Footer_Grid\Customizer\Conditional_Headers' ) ) { + \Neve_Pro\Modules\Header_Footer_Grid\Customizer\Conditional_Headers::$theme_mods_keys[] = 'hfg_header_layout_v2'; + } + } + + /** + * Switch to the new 3.0 features. + * + * @return void + * + * @since 3.0.0 + */ + public function run_skin_and_builder_switches() { + $flag = 'neve_ran_migrations'; + + if ( get_theme_mod( $flag ) === true ) { + return; + } + + set_theme_mod( $flag, true ); + + if ( neve_had_old_hfb() ) { + set_theme_mod( 'neve_migrated_builders', false ); + } + + $all_mods = get_theme_mods(); + + $mods = [ + 'hfg_header_layout', + 'hfg_footer_layout', + 'neve_blog_archive_layout', + 'neve_headings_font_family', + 'neve_body_font_family', + 'neve_global_colors', + 'neve_button_appearance', + 'neve_secondary_button_appearance', + 'neve_typeface_general', + 'neve_form_fields_padding', + 'neve_default_sidebar_layout', + 'neve_advanced_layout_options', + ]; + + $should_switch = false; + foreach ( $mods as $mod_to_check ) { + if ( isset( $all_mods[ $mod_to_check ] ) ) { + $should_switch = true; + break; + } + } + + if ( ! $should_switch ) { + return; + } + + set_theme_mod( 'neve_new_skin', 'old' ); + set_theme_mod( 'neve_had_old_skin', true ); + } + + /** + * Filter out old HFG values if the new builder is active. + * + * @param array $theme_mods the theme mods array. + * + * @return array + * @since 3.0.0 + */ + public function migrate_theme_mods_for_new_skin( $theme_mods ) { + if ( ! neve_is_new_skin() ) { + return $theme_mods; + } + $migrator = new Mods_Migrator( $theme_mods ); + return $migrator->get_migrated_mods(); + } + + /** + * Filter localization data to adapt to the new builder. + * + * @param array $array localization array. + * + * @return array + */ + public function adapt_conditional_headers( $array ) { + if ( ! neve_is_new_builder() ) { + return $array; + } + + if ( isset( $array['headerControls'] ) ) { + $array['headerControls'][] = 'hfg_header_layout_v2'; + } + + $array['currentValues'] = [ 'hfg_header_layout_v2' => json_decode( get_theme_mod( 'hfg_header_layout_v2', wp_json_encode( neve_hfg_header_settings() ) ), true ) ]; + + return $array; + } + + /** + * Register Rest Routes. + */ + public function register_rest_routes() { + register_rest_route( + 'nv/migration', + '/new_header_builder', + array( + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'migrate_builders_data' ], + 'permission_callback' => function () { + return current_user_can( 'manage_options' ); + }, + ) + ); + } + + /** + * Migration routine request. + * + * @param \WP_REST_Request $request the received request. + * + * @return \WP_REST_Response + * + * @since 3.0.0 + */ + public function migrate_builders_data( \WP_REST_Request $request ) { + $is_rollback = $request->get_header( 'rollback' ); + $is_dismiss = $request->get_header( 'dismiss' ); + + if ( $is_dismiss === 'yes' ) { + remove_theme_mod( 'hfg_header_layout' ); + remove_theme_mod( 'hfg_footer_layout' ); + + return new \WP_REST_Response( [ 'success' => true ], 200 ); + } + + if ( $is_rollback === 'yes' ) { + set_theme_mod( 'neve_migrated_builders', false ); + + return new \WP_REST_Response( [ 'success' => true ], 200 ); + } + + $migrator = new Builder_Migrator(); + $response = $migrator->run(); + + if ( $response === true ) { + set_theme_mod( 'neve_migrated_builders', true ); + } + + return new \WP_REST_Response( [ 'success' => $response ], 200 ); } /** @@ -159,6 +313,7 @@ public function admin_notice() { if ( ! empty( $activated_time ) ) { if ( time() - intval( $activated_time ) > WEEK_IN_SECONDS ) { update_option( $this->dismiss_notice_key, 'yes' ); + return; } } @@ -390,7 +545,10 @@ public function enqueue_gutenberg_scripts() { NEVE_VERSION, true ); - wp_enqueue_style( 'neve-gutenberg-style', NEVE_ASSETS_URL . 'css/gutenberg-editor-style' . ( ( NEVE_DEBUG ) ? '' : '.min' ) . '.css', array(), NEVE_VERSION ); + + $path = neve_is_new_skin() ? 'gutenberg-editor-style' : 'gutenberg-editor-legacy-style'; + + wp_enqueue_style( 'neve-gutenberg-style', NEVE_ASSETS_URL . 'css/' . $path . ( ( NEVE_DEBUG ) ? '' : '.min' ) . '.css', array(), NEVE_VERSION ); } /** @@ -462,6 +620,7 @@ public function change_plugin_names( $plugins ) { if ( array_key_exists( 'otter-blocks/otter-blocks.php', $plugins ) ) { $plugins['otter-blocks/otter-blocks.php']['Name'] = 'Gutenberg Blocks and Template Library by Neve theme'; } + return $plugins; } diff --git a/inc/core/builder_migrator.php b/inc/core/builder_migrator.php new file mode 100644 index 0000000000..52de4c9500 --- /dev/null +++ b/inc/core/builder_migrator.php @@ -0,0 +1,478 @@ + [ 'top', 'main', 'bottom', 'sidebar' ], + 'footer' => [ 'top', 'main', 'bottom' ], + 'page_header' => [ 'top', 'bottom' ], + ]; + + /** + * Current device migrating. + * + * @var string + */ + private static $current_device = null; + + /** + * Current builder migrating. + * + * @var string + */ + private static $current_builder = null; + + /** + * Current Row Migrating + * + * @var string + */ + private static $current_row = null; + + /** + * Row slots. + * + * @var string[] + */ + private $row_slots = [ 'left', 'c-left', 'center', 'c-right', 'right' ]; + + /** + * Migrate row for columned builder. + * + * @param array $old_row old row values. + * @param array $next_row empty row array. + * + * @return array + */ + private function migrate_columns_row( $old_row, $next_row ) { + $items_no = count( $old_row ); + $columns_setting = 'hfg_' . self::$current_builder . '_layout_' . self::$current_row . '_columns_number'; + + if ( $items_no > 5 ) { + $items_no = 5; + } + + set_theme_mod( $columns_setting, $items_no ); + + foreach ( $old_row as $index => $item ) { + $slot = $this->row_slots[ $index ]; + + $next_row[ $slot ][] = [ 'id' => $item['id'] ]; + } + + return $next_row; + } + + /** + * Get the component horizontal alignment on currently migrating device. + * + * @param string $component_id the component id. + * + * @return string + */ + private function get_component_alignment( $component_id ) { + $default = [ + 'desktop' => 'left', + 'mobile' => 'left', + 'tablet' => 'left', + ]; + + if ( strpos( $component_id, 'primary-menu' ) !== false ) { + $default['desktop'] = 'right'; + } + + $alignment = get_theme_mod( $component_id . '_component_align', $default ); + + + if ( ! isset( $alignment[ self::$current_device ] ) ) { + return 'left'; + } + + $allowed = [ 'left', 'right', 'center' ]; + + if ( ! in_array( $alignment[ self::$current_device ], $allowed ) ) { + return 'left'; + } + + return $alignment[ self::$current_device ]; + } + + /** + * Migrate row for fluid builder. + * + * @param array $next_row empty row array. + * @param array $old_items old row values. + * + * @return array + */ + private function migrate_fluid_row( $next_row, $old_items ) { + $items_no = count( $old_items ); + + // We have only one item. + if ( $items_no === 1 ) { + $alignment = $this->get_component_alignment( $old_items[0]['id'] ); + $width = $old_items[0]['width']; + $start_position = $old_items[0]['x']; + $next_row_content = [ 'id' => $old_items[0]['id'] ]; + + // Item is at start of row. Slot it according to the alignment. + // In the previous version, if the item was alone and started at the beginning of the row, it spanned the whole width. + if ( $start_position === 0 ) { + $next_row[ $alignment ][] = $next_row_content; + + return $next_row; + } + + // Item is not at start or end. It spans until the end of the row. + if ( $start_position > 0 ) { + if ( $alignment === 'right' ) { + $next_row['right'][] = $next_row_content; + + return $next_row; + } + + $next_row['center'][] = $next_row_content; + + return $next_row; + } + + // Item is at end of row. Slot it to the right. + if ( $width + $start_position === 12 ) { + $next_row['right'][] = $next_row_content; + + return $next_row; + } + + // Item is not at start or end. Slot it at center. + $next_row['center'][] = $next_row_content; + + return $next_row; + } + + // Check if items fill the whole row so we can know if it has gaps. + $filled_columns = array_reduce( + $old_items, + function ( $columns, $item ) { + $columns += $item['width']; + + return $columns; + } + ); + $no_gaps = $filled_columns === 12; + + // There are no gaps so we will only slot left and right; + if ( $no_gaps ) { + foreach ( $old_items as $item ) { + $width = $item['width']; + $start_position = $item['x']; + $next_item_content = [ 'id' => $item['id'] ]; + $alignment = $this->get_component_alignment( $item['id'] ); + + // Item touches right. Slot it to the right. + if ( $start_position + $width === 12 ) { + $next_row['right'][] = $next_item_content; + continue; + } + + // Item is before center. Slot it to the left only if it isn't aligned to the right. + if ( $start_position < 5 ) { + if ( $alignment === 'right' ) { + $next_row['right'][] = $next_item_content; + continue; + } + + $next_row['left'][] = $next_item_content; + continue; + } + + // Item is after center. Slot it to the right. + if ( $start_position >= 5 ) { + $next_row['right'][] = $next_item_content; + continue; + } + } + + return $next_row; + } + + $previous_item = null; + $previous_slot = null; + + foreach ( $old_items as $index => $item ) { + $width = $item['width']; + $start_position = $item['x']; + $item_value = [ 'id' => $item['id'] ]; + + // Item starts at the most left point. Slot it to the left. + if ( $start_position === 0 ) { + $next_row['left'][] = $item_value; + $previous_item = $item; + $previous_slot = 'left'; + continue; + } + + // If we already had an item, check if it touches the new one. + if ( $previous_item && $previous_slot ) { + // Slot it inside the same slot if it does and there is no gap. + if ( $previous_item['x'] + $previous_item['width'] === $start_position ) { + $next_row[ $previous_slot ][] = $item_value; + $previous_item = $item; + continue; + } + + // If item is at the end slot it right. + // Accounts for previous but where items were extending the whole row when last. + if ( $item['x'] + $item['width'] === 12 || $index === count( $old_items ) - 1 ) { + $next_row['right'][] = $item_value; + $previous_item = $item; + $previous_slot = 'right'; + continue; + } + + // Move to center slot if there is a gap and previous slotted was left. + if ( $previous_slot === 'left' ) { + $next_row['center'][] = $item_value; + $previous_item = $item; + $previous_slot = 'center'; + continue; + } + + // All other cases fall inside the right slot. + $next_row['right'][] = $item_value; + $previous_item = $item; + $previous_slot = 'right'; + continue; + } + + // Item touches end. Slot it to the right. + if ( $start_position + $width === 12 ) { + $next_row['right'][] = $item_value; + $previous_item = $item; + $previous_slot = 'right'; + continue; + } + + // Item is first but doesn't start at the left most point. Slot it to the center. + if ( $index === 0 ) { + $next_row['center'][] = $item_value; + $previous_item = $item; + $previous_slot = 'center'; + continue; + } + + // Does not touch sides. Is not nearby previous. + $next_row['center'][] = $item_value; + $previous_slot = 'center'; + $previous_item = $item; + } + + return $next_row; + } + + /** + * Migrate single row of the builder. + * + * @param array $old_items old items inside the row. + * + * @return array + */ + private function migrate_single_row( $old_items ) { + $next_row_value = array_fill_keys( $this->row_slots, [] ); + + if ( count( $old_items ) === 0 ) { + return $next_row_value; + } + + if ( self::$current_builder === 'footer' ) { + return $this->migrate_columns_row( $old_items, $next_row_value ); + } + + return $this->migrate_fluid_row( $next_row_value, $old_items ); + } + + /** + * Migrate single builder value. + * + * @return bool + */ + private function migrate_single_builder() { + $old_value = $this->get_builder_value( self::$current_builder ); + + if ( empty( $old_value ) ) { + return true; + } + + $old_value = json_decode( $old_value, true ); + + $new_value = $this->get_new_builder_value_from_old( $old_value ); + + set_theme_mod( $this->get_new_builder_mod_slug( self::$current_builder ), wp_json_encode( $new_value ) ); + + return true; + } + + /** + * Migrate old builder value to new format. + * + * @param array $old_value old builder value. + * + * @return array|boolean + */ + public function get_new_builder_value_from_old( $old_value ) { + if ( ! is_array( $old_value ) ) { + return false; + } + + $empty_row = array_fill_keys( $this->row_slots, [] ); + + $new_value = []; + + foreach ( $old_value as $device => $rows ) { + + self::$current_device = $device; + + // Setup the builders for each device. + $new_value[ $device ] = array_fill_keys( $this->builders[ self::$current_builder ], $empty_row ); + + // Sidebar is available only on mobile. We should remove it on other devices. + if ( $device !== 'mobile' && isset( $new_value[ $device ]['sidebar'] ) ) { + unset( $new_value[ $device ]['sidebar'] ); + } + + foreach ( $rows as $row_slug => $items ) { + self::$current_row = $row_slug; + // Sidebar row is treated differently. + if ( $row_slug === 'sidebar' ) { + // Make sure we have an empty array for the sidebar. + $new_value[ $device ]['sidebar'] = []; + // Push items inside the sidebar. + foreach ( $items as $item ) { + $new_value[ $device ]['sidebar'][] = [ 'id' => $item['id'] ]; + } + continue; + } + + // Proceed with normal migration for each row. + $new_value[ $device ][ $row_slug ] = $this->migrate_single_row( $items ); + } + self::$current_row = null; + } + + self::$current_device = null; + + return $new_value; + } + + /** + * Get the new theme mod slug for the specified builder. + * + * @param string $builder builder slug. + * + * @return string + */ + private function get_new_builder_mod_slug( $builder ) { + return 'hfg_' . $builder . '_layout_v2'; + } + + /** + * Get individual builder value. + * + * @param string $builder builder slug. + * + * @return string + */ + private function get_builder_value( $builder ) { + return get_theme_mod( 'hfg_' . $builder . '_layout' ); + } + + /** + * Main run function of the migrator. + * + * @return bool + */ + public function run() { + $expected_builders = array_keys( $this->builders ); + + foreach ( $expected_builders as $builder ) { + // Attempt migration for every builder. + self::$current_builder = $builder; + $success = $this->migrate_single_builder(); + + // If it fails for one, it failed. + if ( ! $success ) { + return false; + } + } + self::$current_builder = null; + + $success = $this->migrate_conditional_headers(); + + if ( ! $success ) { + return false; + } + + // Migration success. + return true; + } + + /** + * Migrate conditional headers + * + * @return boolean + */ + private function migrate_conditional_headers() { + if ( ! class_exists( '\Neve_Pro\Admin\Custom_Layouts_Cpt' ) ) { + return true; + } + + if ( ! method_exists( '\Neve_Pro\Admin\Custom_Layouts_Cpt', 'get_conditional_headers' ) ) { + return true; + } + + $headers = \Neve_Pro\Admin\Custom_Layouts_Cpt::get_conditional_headers(); + + self::$current_builder = 'header'; + + foreach ( $headers as $cpt_id => $header ) { + $decoded = json_decode( $header, true ); + + if ( ! is_array( $decoded ) || empty( $decoded ) ) { + continue; + } + if ( ! isset( $decoded['hfg_header_layout'] ) ) { + continue; + } + + + $migrated_value = $this->get_new_builder_value_from_old( $decoded['hfg_header_layout'] ); + $new_mod_key = $this->get_new_builder_mod_slug( 'header' ); + $decoded[ $new_mod_key ] = $migrated_value; + + update_post_meta( $cpt_id, 'theme-mods', wp_json_encode( $decoded ) ); + delete_transient( 'custom_layouts_post_map_v2' ); + } + + self::$current_builder = null; + + return true; + } +} diff --git a/inc/core/dynamic_css.php b/inc/core/dynamic_css.php index fb5211f841..60d3930be0 100644 --- a/inc/core/dynamic_css.php +++ b/inc/core/dynamic_css.php @@ -99,7 +99,10 @@ public static function minify_css( $css ) { public function add_customize_vars_tag() { wp_register_style( 'nv-css-vars', false ); wp_enqueue_style( 'nv-css-vars' ); - wp_add_inline_style( 'nv-css-vars', self::minify_css(':root{' . $this->get_css_vars() . '}' ) ); + + $css = ':root{' . $this->get_css_vars() . '}'; + $css .= apply_filters( 'neve_after_css_root', $css ); + wp_add_inline_style( 'nv-css-vars', self::minify_css($css ) ); } /** @@ -115,6 +118,8 @@ public function get_root_css() { $css .= '}'; + $css .= apply_filters( 'neve_after_css_root', $css ); + return self::minify_css($css); } diff --git a/inc/core/front_end.php b/inc/core/front_end.php index 8b9bb5e321..bb284bf14c 100644 --- a/inc/core/front_end.php +++ b/inc/core/front_end.php @@ -21,8 +21,6 @@ */ class Front_End { - - /** * Theme setup. */ @@ -286,13 +284,17 @@ public function enqueue_scripts() { */ private function add_styles() { if ( class_exists( 'WooCommerce', false ) ) { - wp_register_style( 'neve-woocommerce', NEVE_ASSETS_URL . 'css/woocommerce' . ( ( NEVE_DEBUG ) ? '' : '.min' ) . '.css', array(), apply_filters( 'neve_version_filter', NEVE_VERSION ) ); + $style_path = neve_is_new_skin() ? 'css/woocommerce' : 'css/woocommerce-legacy'; + + wp_register_style( 'neve-woocommerce', NEVE_ASSETS_URL . $style_path . ( ( NEVE_DEBUG ) ? '' : '.min' ) . '.css', array(), apply_filters( 'neve_version_filter', NEVE_VERSION ) ); wp_style_add_data( 'neve-woocommerce', 'rtl', 'replace' ); wp_style_add_data( 'neve-woocommerce', 'suffix', '.min' ); wp_enqueue_style( 'neve-woocommerce' ); } - wp_register_style( 'neve-style', get_template_directory_uri() . '/style-main' . ( ( NEVE_DEBUG ) ? '' : '.min' ) . '.css', array(), apply_filters( 'neve_version_filter', NEVE_VERSION ) ); + $style_path = neve_is_new_skin() ? '/style-main' : '/assets/css/style-legacy'; + + wp_register_style( 'neve-style', get_template_directory_uri() . $style_path . ( ( NEVE_DEBUG ) ? '' : '.min' ) . '.css', array(), apply_filters( 'neve_version_filter', NEVE_VERSION ) ); wp_style_add_data( 'neve-style', 'rtl', 'replace' ); wp_style_add_data( 'neve-style', 'suffix', '.min' ); wp_enqueue_style( 'neve-style' ); diff --git a/inc/core/settings/config.php b/inc/core/settings/config.php index 1f95ea0a8b..1526902269 100644 --- a/inc/core/settings/config.php +++ b/inc/core/settings/config.php @@ -79,6 +79,27 @@ class Config { const MODS_FORM_FIELDS_COLOR = 'neve_input_text_color'; const MODS_FORM_FIELDS_LABELS_TYPEFACE = 'neve_label_typeface'; + const MODS_ARCHIVE_POST_META_AUTHOR_AVATAR_SIZE = 'neve_author_avatar_size'; + const MODS_SINGLE_POST_META_AUTHOR_AVATAR_SIZE = 'neve_single_post_avatar_size'; + const MODS_SINGLE_POST_ELEMENTS_SPACING = 'neve_single_post_elements_spacing'; + + const MODS_POST_COVER_HEIGHT = 'neve_post_cover_height'; + const MODS_POST_COVER_PADDING = 'neve_post_cover_padding'; + const MODS_POST_COVER_BACKGROUND_COLOR = 'neve_post_cover_background_color'; + const MODS_POST_COVER_OVERLAY_OPACITY = 'neve_post_cover_overlay_opacity'; + const MODS_POST_COVER_TEXT_COLOR = 'neve_post_cover_text_color'; + const MODS_POST_COVER_BLEND_MODE = 'neve_post_cover_blend_mode'; + const MODS_POST_COVER_TITLE_POSITION = 'neve_post_title_position'; + const MODS_POST_COVER_BOXED_TITLE_PADDING = 'neve_post_cover_title_boxed_padding'; + const MODS_POST_COVER_BOXED_TITLE_BACKGROUND = 'neve_post_cover_title_boxed_background_color'; + + const MODS_POST_COMMENTS_PADDING = 'neve_comments_boxed_padding'; + const MODS_POST_COMMENTS_BACKGROUND_COLOR = 'neve_comments_boxed_background_color'; + const MODS_POST_COMMENTS_TEXT_COLOR = 'neve_comments_boxed_text_color'; + const MODS_POST_COMMENTS_FORM_PADDING = 'neve_comments_form_boxed_padding'; + const MODS_POST_COMMENTS_FORM_BACKGROUND_COLOR = 'neve_comments_form_boxed_background_color'; + const MODS_POST_COMMENTS_FORM_TEXT_COLOR = 'neve_comments_form_boxed_text_color'; + const CSS_PROP_BORDER_COLOR = 'border-color'; const CSS_PROP_BACKGROUND_COLOR = 'background-color'; const CSS_PROP_COLOR = 'color'; @@ -112,6 +133,9 @@ class Config { const CSS_PROP_TEXT_TRANSFORM = 'text-transform'; const CSS_PROP_FONT_FAMILY = 'font-family'; const CSS_PROP_BOX_SHADOW = 'box-shadow'; + const CSS_PROP_MIX_BLEND_MODE = 'mix-blend-mode'; + const CSS_PROP_OPACITY = 'opacity'; + const CSS_PROP_GRID_TEMPLATE_COLS = 'grid-template-columns'; const CSS_PROP_CUSTOM_BTN_TYPE = 'btn-type'; const CSS_PROP_CUSTOM_FONT_WEIGHT_FAMILY = 'btn-type'; @@ -144,9 +168,18 @@ class Config { const CSS_SELECTOR_FORM_INPUTS = 'form_inputs'; const CSS_SELECTOR_FORM_INPUTS_LABELS = 'form_labels'; const CSS_SELECTOR_FORM_BUTTON = 'form_buttons'; + const CSS_SELECTOR_FORM_BUTTON_HOVER = 'form_buttons_hover'; const CSS_SELECTOR_FORM_SEARCH_INPUTS = 'search_form_inputs'; const CONTENT_DEFAULT_PADDING = 30; + + /** + * Keys for directional values. + * + * @var string[] + */ + public static $directional_keys = [ 'top', 'right', 'bottom', 'left' ]; + /** * Holds tag->css selector mapper. * @@ -184,7 +217,8 @@ class Config { self::CSS_SELECTOR_FORM_INPUTS_WITH_SPACING => 'form:not([role="search"]):not(.woocommerce-cart-form):not(.woocommerce-ordering):not(.cart) input:read-write:not(#coupon_code), form textarea, form select, .widget select', self::CSS_SELECTOR_FORM_INPUTS => 'form input:read-write, form textarea, form select, form select option, form.wp-block-search input.wp-block-search__input, .widget select', self::CSS_SELECTOR_FORM_INPUTS_LABELS => 'form label, .wpforms-container .wpforms-field-label', - self::CSS_SELECTOR_FORM_BUTTON => 'form input[type="submit"]', + self::CSS_SELECTOR_FORM_BUTTON => 'form input[type="submit"], form button[type="submit"], form *[value*="ubmit"], #comments input[type="submit"]', + self::CSS_SELECTOR_FORM_BUTTON_HOVER => 'form input[type="submit"]:hover, form button[type="submit"]:hover, form *[value*="ubmit"]:hover, #comments input[type="submit"]:hover', self::CSS_SELECTOR_FORM_SEARCH_INPUTS => 'form.search-form input:read-write', ]; } diff --git a/inc/core/settings/mods.php b/inc/core/settings/mods.php index c880d57ef5..7fd0cd7ad4 100644 --- a/inc/core/settings/mods.php +++ b/inc/core/settings/mods.php @@ -64,7 +64,7 @@ public static function get( $key, $default = false ) { return isset( $value[ $subkey ] ) ? $value[ $subkey ] : $default; } - /*** + /** * Forced defaults. * * @param string $key Key name. @@ -78,7 +78,7 @@ private static function defaults( $key ) { case Config::MODS_BUTTON_PRIMARY_STYLE: return neve_get_button_appearance_default(); case Config::MODS_BUTTON_SECONDARY_STYLE: - return neve_get_button_appearance_default( 'secondary_button' ); + return neve_get_button_appearance_default( 'secondary' ); case Config::MODS_TYPEFACE_GENERAL: $defaults = self::get_typography_defaults( [ @@ -203,4 +203,200 @@ public static function to_json( $key, $default = false, $as_array = true ) { return json_decode( self::get( $key, $default ), $as_array ); } + /** + * Get alternative mod default. + * + * @param string $key theme mod key. + * + * @return string | array + */ + public static function get_alternative_mod_default( $key ) { + $new = neve_is_new_skin(); + $headings_generic_setup = [ + 'fontWeight' => $new ? '700' : '600', + 'textTransform' => 'none', + 'letterSpacing' => [ + 'mobile' => 0, + 'tablet' => 0, + 'desktop' => 0, + ], + ]; + $headings_sufix = [ + 'mobile' => $new ? 'px' : 'em', + 'tablet' => $new ? 'px' : 'em', + 'desktop' => $new ? 'px' : 'em', + ]; + switch ( $key ) { + case Config::MODS_FONT_GENERAL: + return $new ? 'Arial, Helvetica, sans-serif' : false; + case Config::MODS_TYPEFACE_GENERAL: + return [ + 'fontSize' => [ + 'suffix' => [ + 'mobile' => 'px', + 'tablet' => 'px', + 'desktop' => 'px', + ], + 'mobile' => 15, + 'tablet' => 16, + 'desktop' => 16, + ], + 'lineHeight' => [ + 'mobile' => 1.6, + 'tablet' => 1.6, + 'desktop' => $new ? 1.7 : 1.6, + ], + 'letterSpacing' => [ + 'mobile' => 0, + 'tablet' => 0, + 'desktop' => 0, + ], + 'fontWeight' => '400', + 'textTransform' => 'none', + ]; + case Config::MODS_TYPEFACE_H1: + return array_merge( + $headings_generic_setup, + array( + 'fontSize' => [ + 'mobile' => $new ? '36' : '1.5', + 'tablet' => $new ? '38' : '1.5', + 'desktop' => $new ? '40' : '2', + 'suffix' => $headings_sufix, + ], + 'lineHeight' => [ + 'mobile' => $new ? 1.2 : 1.6, + 'tablet' => $new ? 1.2 : 1.6, + 'desktop' => $new ? 1.1 : 1.6, + ], + ) + ); + case Config::MODS_TYPEFACE_H2: + return array_merge( + $headings_generic_setup, + array( + 'fontSize' => [ + 'mobile' => $new ? '28' : '1.3', + 'tablet' => $new ? '30' : '1.3', + 'desktop' => $new ? '32' : '1.75', + 'suffix' => $headings_sufix, + ], + 'lineHeight' => [ + 'mobile' => $new ? 1.3 : 1.6, + 'tablet' => $new ? 1.2 : 1.6, + 'desktop' => $new ? 1.2 : 1.6, + ], + ) + ); + case Config::MODS_TYPEFACE_H3: + return array_merge( + $headings_generic_setup, + array( + 'fontSize' => [ + 'mobile' => $new ? '24' : '1.1', + 'tablet' => $new ? '26' : '1.1', + 'desktop' => $new ? '28' : '1.5', + 'suffix' => $headings_sufix, + ], + 'lineHeight' => [ + 'mobile' => $new ? 1.4 : 1.6, + 'tablet' => $new ? 1.4 : 1.6, + 'desktop' => $new ? 1.4 : 1.6, + ], + ) + ); + case Config::MODS_TYPEFACE_H4: + return array_merge( + $headings_generic_setup, + array( + 'fontSize' => [ + 'mobile' => $new ? '20' : '1', + 'tablet' => $new ? '22' : '1', + 'desktop' => $new ? '24' : '1.25', + 'suffix' => $headings_sufix, + ], + 'lineHeight' => [ + 'mobile' => 1.6, + 'tablet' => $new ? 1.5 : 1.6, + 'desktop' => $new ? 1.5 : 1.6, + ], + ) + ); + case Config::MODS_TYPEFACE_H5: + return array_merge( + $headings_generic_setup, + array( + 'fontSize' => [ + 'mobile' => $new ? '16' : '0.75', + 'tablet' => $new ? '18' : '0.75', + 'desktop' => $new ? '20' : '1', + 'suffix' => $headings_sufix, + ], + 'lineHeight' => [ + 'mobile' => 1.6, + 'tablet' => 1.6, + 'desktop' => 1.6, + ], + ) + ); + case Config::MODS_TYPEFACE_H6: + return array_merge( + $headings_generic_setup, + array( + 'fontSize' => [ + 'mobile' => $new ? '14' : '0.75', + 'tablet' => $new ? '14' : '0.75', + 'desktop' => $new ? '16' : '1', + 'suffix' => $headings_sufix, + ], + 'lineHeight' => [ + 'mobile' => 1.6, + 'tablet' => 1.6, + 'desktop' => 1.6, + ], + ) + ); + case Config::MODS_BUTTON_PRIMARY_PADDING: + $device = $new ? [ + 'top' => 13, + 'right' => 15, + 'bottom' => 13, + 'left' => 15, + ] : [ + 'top' => 8, + 'right' => 12, + 'bottom' => 8, + 'left' => 12, + ]; + + return [ + 'desktop' => $device, + 'tablet' => $device, + 'mobile' => $device, + 'desktop-unit' => 'px', + 'tablet-unit' => 'px', + 'mobile-unit' => 'px', + ]; + case Config::MODS_FORM_FIELDS_SPACING: + return $new ? 40 : 10; + case Config::MODS_FORM_FIELDS_PADDING: + return [ + 'top' => $new ? 10 : 7, + 'bottom' => $new ? 10 : 7, + 'left' => 12, + 'right' => 12, + 'unit' => 'px', + ]; + case Config::MODS_FORM_FIELDS_BORDER_WIDTH: + return [ + 'top' => $new ? 2 : 1, + 'right' => $new ? 2 : 1, + 'left' => $new ? 2 : 1, + 'bottom' => $new ? 2 : 1, + 'unit' => 'px', + ]; + default: + return false; + } + } } diff --git a/inc/core/settings/mods_migrator.php b/inc/core/settings/mods_migrator.php new file mode 100644 index 0000000000..4cde93e8d1 --- /dev/null +++ b/inc/core/settings/mods_migrator.php @@ -0,0 +1,236 @@ + [ + 'neve_h6_font_size' => 'fontSize', + 'neve_h6_line_height' => 'lineHeight', + ], + Config::MODS_TYPEFACE_H5 => [ + 'neve_h5_font_size' => 'fontSize', + 'neve_h5_line_height' => 'lineHeight', + ], + Config::MODS_TYPEFACE_H4 => [ + 'neve_h4_font_size' => 'fontSize', + 'neve_h4_line_height' => 'lineHeight', + ], + Config::MODS_TYPEFACE_H3 => [ + 'neve_h3_font_size' => 'fontSize', + 'neve_h3_line_height' => 'lineHeight', + ], + Config::MODS_TYPEFACE_H2 => [ + 'neve_h2_font_size' => 'fontSize', + 'neve_h2_line_height' => 'lineHeight', + ], + Config::MODS_TYPEFACE_H1 => [ + 'neve_h1_font_size' => 'fontSize', + 'neve_h1_line_height' => 'lineHeight', + ], + ]; + + /** + * Builders + * + * @var string[] + */ + private $builder_map = [ 'hfg_header_layout', 'hfg_footer_layout', 'hfg_page_header_layout' ]; + + /** + * Mods array. + * + * @var array + */ + private $mods = []; + + /** + * Mods to migrate. + * + * @var array + */ + private $mods_to_migrate_to = [ + Config::MODS_TYPEFACE_GENERAL, + Config::MODS_TYPEFACE_H1, + Config::MODS_TYPEFACE_H2, + Config::MODS_TYPEFACE_H3, + Config::MODS_TYPEFACE_H4, + Config::MODS_TYPEFACE_H5, + Config::MODS_TYPEFACE_H6, + ]; + + /** + * Mods_Migrator constructor. + * + * @param array $incoming_mods the incoming mods from import. + */ + public function __construct( $incoming_mods ) { + $this->mods = $incoming_mods; + } + + /** + * Get migrated mods. + * + * @return array + */ + public function get_migrated_mods() { + $this->migrate_mods(); + $this->attempt_builders_migration(); + $this->unset_unused(); + + return $this->mods; + } + + /** + * Migrate mods. + * + * @return void + */ + private function migrate_mods() { + foreach ( $this->mods_to_migrate_to as $new_mod_key ) { + // If the new mod is already in use, we don't need to migrate anything. + if ( isset( $this->mods[ $new_mod_key ] ) ) { + continue; + } + + $next_value = $this->transform_to_new_value( $new_mod_key ); + + if ( empty( $next_value ) ) { + continue; + } + + $this->mods[ $new_mod_key ] = $next_value; + } + } + + /** + * Attempt to migrate builders. + * + * @return void + */ + private function attempt_builders_migration() { + $hfg_migrator = new Builder_Migrator(); + + foreach ( $this->builder_map as $builder ) { + $new_builder_mod = $builder . '_v2'; + if ( isset( $this->mods[ $new_builder_mod ] ) ) { + continue; + } + + if ( ! isset( $this->mods[ $builder ] ) ) { + continue; + } + + $new_value = $hfg_migrator->get_new_builder_value_from_old( json_decode( $this->mods[ $builder ], true ) ); + + if ( $new_value === false ) { + continue; + } + + $this->mods[ $new_builder_mod ] = wp_json_encode( $new_value ); + unset( $this->mods[ $builder ] ); + } + } + + /** + * Get the array of old values that will match the new values. + * + * @param string $new_mod_key the new mod key. + * + * @return array + */ + private function transform_to_new_value( $new_mod_key ) { + $defaults = Mods::get_alternative_mod_default( $new_mod_key ); + + switch ( $new_mod_key ) { + case Config::MODS_TYPEFACE_GENERAL: + $old_value = $this->get_composed_value( + [ + 'neve_body_line_height' => 'lineHeight', + 'neve_body_letter_spacing' => 'letterSpacing', + 'neve_body_font_weight' => 'fontWeight', + 'neve_body_text_transform' => 'textTransform', + 'neve_body_font_size' => 'fontSize', + ] + ); + + return array_merge( $defaults, $old_value ); + + case Config::MODS_TYPEFACE_H1: + case Config::MODS_TYPEFACE_H2: + case Config::MODS_TYPEFACE_H3: + case Config::MODS_TYPEFACE_H4: + case Config::MODS_TYPEFACE_H5: + case Config::MODS_TYPEFACE_H6: + $partial = [ + 'neve_headings_line_height' => 'lineHeight', + 'neve_headings_letter_spacing' => 'letterSpacing', + 'neve_headings_font_weight' => 'fontWeight', + 'neve_headings_text_transform' => 'textTransform', + ]; + + $keys = array_merge( $partial, self::LEGACY_HEADINGS[ $new_mod_key ] ); + $old_value = $this->get_composed_value( $keys ); + + return array_merge( $defaults, $old_value ); + } + } + + /** + * Get the old values for the new mod. + * + * @param array $args args array [$old_mod => $key_on_new_mod]. + * + * @return array + */ + private function get_composed_value( $args ) { + $new_values = []; + foreach ( $args as $old_mod => $new_key ) { + if ( ! isset( $this->mods[ $old_mod ] ) ) { + continue; + } + + $final_value = $this->mods[ $old_mod ]; + // If the value is either font-size or line-height we should migrate it from previous json format. + if ( in_array( $new_key, [ 'fontSize', 'lineHeight' ] ) ) { + $final_value = json_decode( $final_value, true ); + } + + $new_values[ $new_key ] = $final_value; + + unset( $this->mods[ $old_mod ] ); + } + + return $new_values; + } + + /** + * Unset unused theme mods. + * + * @return void + */ + private function unset_unused() { + $to_remove = array_merge( $this->builder_map, [ 'background_color' ] ); + + foreach ( $to_remove as $slug ) { + if ( isset( $this->mods[ $slug ] ) ) { + unset( $this->mods[ $slug ] ); + } + } + } +} diff --git a/inc/core/styles/css_prop.php b/inc/core/styles/css_prop.php index 1d44ccbe2e..93c6120a90 100644 --- a/inc/core/styles/css_prop.php +++ b/inc/core/styles/css_prop.php @@ -14,12 +14,43 @@ class Css_Prop { */ public static function minus_100( $css_prop, $value, $meta, $device ) { return sprintf( "%s: %s%s;", - ($css_prop), - (100 - $value), + ( $css_prop ), + ( 100 - $value ), isset( $meta[ Dynamic_Selector::META_SUFFIX ] ) ? $meta[ Dynamic_Selector::META_SUFFIX ] : 'px' ); } + /** + * Get suffix from controls that store data in the following format: + * { desktop: value, tablet: value, mobile: value, deskotp-unit: px, tablet-unit: px, mobile-unit: px } + * + * @param array $meta Subscribers meta data. + */ + public static function get_unit_responsive( $meta, $device ) { + $all_value = Mods::get( $meta['key'], isset( $meta[ Dynamic_Selector::META_DEFAULT ] ) ? $meta[ Dynamic_Selector::META_DEFAULT ] : null ); + $suffix = 'px'; + if ( isset( $all_value[ $device . '-unit' ] ) ) { + $suffix = $all_value[ $device . '-unit' ]; + } elseif ( isset( $all_value['unit'] ) ) { + $suffix = $all_value['unit']; + } + + return $suffix; + } + + /** + * Get suffix from controls that store data in the following format: + * { desktop: value, tablet: value, mobile: value, suffix : { deskop: px, tablet: px, mobile: px} } + * + * @param array $meta Subscribers meta data. + */ + public static function get_suffix_responsive( $meta, $device ) { + $default_value = isset( $meta[ Dynamic_Selector::META_DEFAULT ] ) ? $meta[ Dynamic_Selector::META_DEFAULT ] : null; + $all_value = isset( $meta[ Dynamic_Selector::META_AS_JSON ] ) ? Mods::to_json( $meta['key'], $default_value ) : Mods::get( $meta['key'], $default_value ); + + return isset( $all_value['suffix'][ $device ] ) ? $all_value['suffix'][ $device ] : ( isset( $all_value['suffix'] ) && is_string( $all_value['suffix'] ) ? $all_value['suffix'] : 'px' );; + } + /** * Transform rule meta into CSS rule string. * @@ -32,32 +63,34 @@ public static function minus_100( $css_prop, $value, $meta, $device ) { */ public static function transform( $css_prop, $value, $meta, $device ) { //If we have a custom filter, let's call it. - if ( isset( $meta[ 'filter' ] ) ) { - if ( is_callable( $meta[ 'filter' ] ) ) { - return call_user_func_array( $meta[ 'filter' ], [ $css_prop, $value, $meta, $device ] ); + if ( isset( $meta['filter'] ) ) { + if ( is_callable( $meta['filter'] ) ) { + return call_user_func_array( $meta['filter'], [ $css_prop, $value, $meta, $device ] ); } - if ( method_exists( __CLASS__, $meta[ 'filter' ] ) ) { - return call_user_func_array( [ __CLASS__, $meta[ 'filter' ] ], [ $css_prop, $value, $meta, $device ] ); + if ( method_exists( __CLASS__, $meta['filter'] ) ) { + return call_user_func_array( [ __CLASS__, $meta['filter'] ], [ $css_prop, $value, $meta, $device ] ); } return ''; } + if ( isset( $meta['override'] ) ) { + return sprintf( '%s:%s;', $css_prop, $meta['override'] ); + } switch ( $css_prop ) { case Config::CSS_PROP_BACKGROUND_COLOR: case Config::CSS_PROP_COLOR: case Config::CSS_PROP_FILL_COLOR: case Config::CSS_PROP_BORDER_COLOR: - $mode = (false === strpos( $value, 'rgba' )) ? 'hex' : 'rgba'; - $is_var = (strpos( $value, 'var' ) !== false); + $mode = ( false === strpos( $value, 'rgba' ) ) ? 'hex' : 'rgba'; + $is_var = ( strpos( $value, 'var' ) !== false ); if ( $mode === 'hex' && ! $is_var ) { $value = strpos( $value, "#" ) === 0 ? $value : '#' . $value; } - return sprintf( "%s: %s%s;", ($css_prop), neve_sanitize_colors( $value ), isset( $meta[ 'important' ] ) && $meta[ 'important' ] ? '!important' : '' ); - break; + return sprintf( "%s: %s%s;", ( $css_prop ), neve_sanitize_colors( $value ), isset( $meta['important'] ) && $meta['important'] ? '!important' : '' ); case Config::CSS_PROP_MAX_WIDTH: case Config::CSS_PROP_WIDTH: case Config::CSS_PROP_FLEX_BASIS: @@ -72,18 +105,16 @@ public static function transform( $css_prop, $value, $meta, $device ) { case Config::CSS_PROP_LEFT: case Config::CSS_PROP_RIGHT: $suffix = isset( $meta[ Dynamic_Selector::META_SUFFIX ] ) ? $meta[ Dynamic_Selector::META_SUFFIX ] : 'px'; - if ( $suffix === 'responsive_suffix' ) { - $all_value = Mods::get( $meta[ 'key' ], isset( $meta[ Dynamic_Selector::META_DEFAULT ] ) ? $meta[ Dynamic_Selector::META_DEFAULT ] : null ); - $suffix = isset( $all_value[ 'suffix' ] ) ? $all_value[ 'suffix' ][ $device ] : (isset( $all_value[ 'suffix' ] ) ? $all_value[ 'suffix' ] : 'px');; + if ( $suffix === 'responsive_suffix' ) { + $suffix = self::get_suffix_responsive( $meta, $device ); } return sprintf( "%s: %s%s;", - ($css_prop), - ($value), + ( $css_prop ), + ( $value ), $suffix ); - break; case Config::CSS_PROP_BORDER_RADIUS: case Config::CSS_PROP_BORDER_WIDTH: case Config::CSS_PROP_PADDING: @@ -100,29 +131,24 @@ public static function transform( $css_prop, $value, $meta, $device ) { } if ( $suffix === 'responsive_unit' ) { - $all_value = Mods::get( $meta['key'], isset( $meta[ Dynamic_Selector::META_DEFAULT ] ) ? $meta[ Dynamic_Selector::META_DEFAULT ] : null ); - $suffix = 'px'; - if ( isset( $all_value[ $device . '-unit' ] ) ) { - $suffix = $all_value[ $device . '-unit' ]; - } elseif ( isset( $all_value['unit'] ) ) { - $suffix = $all_value['unit']; - } + $suffix = self::get_unit_responsive( $meta, $device ); } + $non_empty_values = array_filter( $value, 'strlen' ); if ( count( $non_empty_values ) === 4 ) { return sprintf( "%s:%s%s %s%s %s%s %s%s;", $css_prop, - (int) $value[ 'top' ], + (int) $value['top'], $suffix, - (int) $value[ 'right' ], + (int) $value['right'], $suffix, - (int) $value[ 'bottom' ], + (int) $value['bottom'], $suffix, - (int) $value[ 'left' ], + (int) $value['left'], $suffix ); } - $rule = ''; + $rule = ''; $patterns = [ Config::CSS_PROP_MARGIN => 'margin-%s', Config::CSS_PROP_PADDING => 'padding-%s', @@ -135,20 +161,19 @@ public static function transform( $css_prop, $value, $meta, $device ) { ], ]; - if( isset( $non_empty_values['unit'] ) ) { - unset ($non_empty_values['unit']); + if ( isset( $non_empty_values['unit'] ) ) { + unset ( $non_empty_values['unit'] ); } foreach ( $non_empty_values as $position => $position_value ) { $rule .= sprintf( "%s:%s%s;", - sprintf( (is_array( $patterns[ $css_prop ] ) ? $patterns[ $css_prop ][ $position ] : $patterns[ $css_prop ]), $position ), + sprintf( ( is_array( $patterns[ $css_prop ] ) ? $patterns[ $css_prop ][ $position ] : $patterns[ $css_prop ] ), $position ), (int) $position_value, $suffix ); } return $rule; - break; //Line height uses an awkward format saved, and we can't define it as responsive because we would need to use the suffix part. case Config::CSS_PROP_LINE_HEIGHT: case Config::CSS_PROP_FONT_SIZE: @@ -156,46 +181,178 @@ public static function transform( $css_prop, $value, $meta, $device ) { $suffix = isset( $meta[ Dynamic_Selector::META_SUFFIX ] ) ? $meta[ Dynamic_Selector::META_SUFFIX ] : 'em'; // We consider the provided suffix as default, in case that we have a responsive setting with responsive suffix. if ( isset( $meta[ Dynamic_Selector::META_IS_RESPONSIVE ] ) && $meta[ Dynamic_Selector::META_IS_RESPONSIVE ] ) { - $all_value = Mods::get( $meta[ 'key' ] ); - $suffix = isset( $all_value[ 'suffix' ][ $device ] ) ? $all_value[ 'suffix' ][ $device ] : (isset( $all_value[ 'suffix' ] ) ? $all_value[ 'suffix' ] : $suffix); + $all_value = Mods::get( $meta['key'] ); + $suffix = isset( $all_value['suffix'][ $device ] ) ? $all_value['suffix'][ $device ] : ( isset( $all_value['suffix'] ) ? $all_value['suffix'] : $suffix ); } - return sprintf( ' %s: %s%s; ', $css_prop, $value, $suffix ); - break; + return sprintf( ' %s: %s%s;', $css_prop, $value, $suffix ); //Letter spacing has a legacy value of non-responsive which we need to take into consideration. case Config::CSS_PROP_LETTER_SPACING: - return sprintf( ' %s: %spx; ', $css_prop, $value ); - break; + return sprintf( ' %s: %spx;', $css_prop, $value ); case Config::CSS_PROP_CUSTOM_BTN_TYPE: if ( $value !== 'outline' ) { return 'border:none;'; } return "border:1px solid;"; - break; case Config::CSS_PROP_FONT_WEIGHT: - if ( isset( $meta[ 'font' ] ) ) { - $font = strpos( $meta[ 'font' ], 'mods_' ) === 0 ? Mods::get( str_replace( 'mods_', '', $meta[ 'font' ] ) ) : $meta[ 'font' ]; + if ( isset( $meta['font'] ) ) { + $font = strpos( $meta['font'], 'mods_' ) === 0 ? Mods::get( str_replace( 'mods_', '', $meta['font'] ) ) : $meta['font']; Font_Manager::add_google_font( $font, strval( $value ) ); } return sprintf( ' %s: %s;', $css_prop, intval( $value ) ); - break; case Config::CSS_PROP_FONT_FAMILY: if ( $value === 'default' ) { return ''; } Font_Manager::add_google_font( $value ); - return sprintf( ' %s: %s, var(--nv-fallback-ff); ', $css_prop, $value ); - - break; + return sprintf( ' %s: %s, var(--nv-fallback-ff);', $css_prop, $value ); case Config::CSS_PROP_TEXT_TRANSFORM: case Config::CSS_PROP_BOX_SHADOW: - return sprintf( ' %s: %s; ', $css_prop, $value ); + case Config::CSS_PROP_MIX_BLEND_MODE: + case Config::CSS_PROP_OPACITY: + case Config::CSS_PROP_GRID_TEMPLATE_COLS: + return sprintf( ' %s: %s;', $css_prop, $value ); + default: + $is_font_family_var = strpos( strtolower( $css_prop ), 'fontfamily' ) > - 1; + + if ( $is_font_family_var ) { + Font_Manager::add_google_font( $value ); + } + + if ( isset( $meta['directional-prop'] ) ) { + return self::transform_directional_prop( $meta, $device, $value, $css_prop, $meta['directional-prop'] ); + } + + $suffix = self::get_suffix( $meta, $device, $value, $css_prop ); + + return sprintf( ' %s: %s%s;', $css_prop, $value, $suffix ); break; } return ''; } + + /** + * Get suffix for generic settings. + * + * @param array $meta Meta array. + * @param string $device Current device. + * @param string $value Value. + * + * @return string + * + * @since 3.0.0 + */ + public static function get_suffix( $meta, $device, $value, $css_prop ) { + $suffix = isset( $meta[ Dynamic_Selector::META_SUFFIX ] ) ? $meta[ Dynamic_Selector::META_SUFFIX ] : ''; + + // If not responsive, most controls use 'unit' key inside value. + if ( ! isset( $meta['is_responsive'] ) || $meta['is_responsive'] === false ) { + $suffix = isset( $value['unit'] ) ? $value['unit'] : $suffix; + } + + // If responsive, try to find the suffix. + if ( isset( $meta[ Dynamic_Selector::META_IS_RESPONSIVE ] ) && $meta[ Dynamic_Selector::META_IS_RESPONSIVE ] ) { + $all_value = Mods::get( $meta['key'] ); + $suffix = isset( $all_value['suffix'][ $device ] ) ? $all_value['suffix'][ $device ] : ( isset( $all_value['suffix'] ) ? $all_value['suffix'] : $suffix ); + } + + if ( $suffix === 'responsive_unit' ) { + $suffix = self::get_unit_responsive( $meta, $device ); + } + + if ( $suffix === 'responsive_suffix' ) { + $suffix = self::get_suffix_responsive( $meta, $device ); + } + + // Enqueue any google fonts we might be missing. + if ( isset ( $meta['font'] ) ) { + $font = strpos( $meta['font'], 'mods_' ) === 0 ? Mods::get( str_replace( 'mods_', '', $meta['font'] ) ) : $meta['font']; + Font_Manager::add_google_font( $font, strval( $value ) ); + } + + return $suffix; + } + + /** + * Transforms the directional properties. + * + * @param array $meta Meta array. + * @param string $device Current device. + * @param string $value Value. + * @param string $css_prop Css Property. + * @param string $type Type of directional property. + * + * @return string + */ + public static function transform_directional_prop( $meta, $device, $value, $css_prop, $type ) { + + $suffix = self::get_suffix( $meta, $device, $value, $css_prop ); + $suffix = $suffix ? $suffix : 'px'; + $template = ''; + + + // Make sure that this is directional, even if an int value is provided. + if ( is_int( $value ) ) { + $directions = Config::$directional_keys; + $value = array_fill_keys( $directions, $value ); + } + + // If we still don't have an array. Make sure to drop this setting. + if ( ! is_array( $value ) ) { + return ''; + } + + // Directional array without any other keys than the actual directions. + $filtered = array_filter( $value, function ( $key ) { + return in_array( $key, Config::$directional_keys, true ); + }, ARRAY_FILTER_USE_KEY ); + + if ( count( array_unique( $filtered ) ) === 1 ) { + if ( absint( $value['top'] ) === 0 ) { + $suffix = ''; + } + + if ( empty( $value['top'] ) && absint( $value['top'] ) !== 0 ) { + return ''; + } + + $template .= $value['top'] . $suffix; + + return $css_prop . ':' . $template . ';'; + } + + if ( count( array_unique( $filtered ) ) === 2 && $value['top'] === $value['bottom'] && $value['right'] === $value['left'] ) { + $top_suffix = absint( $value['top'] ) === 0 ? '' : $suffix; + $right_suffix = absint( $value['right'] ) === 0 ? '' : $suffix; + + if ( empty( $value['top'] ) && absint( $value['top'] ) !== 0 && empty( $value['right'] ) && absint( $value['right'] ) ) { + return ''; + } + + $template .= $value['top'] . $top_suffix . ' ' . $value['right'] . $right_suffix; + + return $css_prop . ':' . $template . ';'; + } + + foreach ( Config::$directional_keys as $direction ) { + if ( ! isset( $value[ $direction ] ) || absint( $value[ $direction ] ) === 0 ) { + $template .= '0 '; + + continue; + } + $template .= $value[ $direction ] . $suffix . ' '; + } + + if ( empty( $template ) ) { + return ''; + } + + $template = trim( $template ) . ';'; + + return $css_prop . ':' . $template . ';'; + } } diff --git a/inc/core/styles/css_vars.php b/inc/core/styles/css_vars.php new file mode 100644 index 0000000000..6eebd1002b --- /dev/null +++ b/inc/core/styles/css_vars.php @@ -0,0 +1,256 @@ + [ + Dynamic_Selector::META_KEY => Config::MODS_CONTAINER_WIDTH, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => '{ "mobile": 748, "tablet": 992, "desktop": 1170 }', + ], + ]; + } + + /** + * Get button rules. + * + * @return array + */ + public function get_button_rules() { + $mod_key_primary = Config::MODS_BUTTON_PRIMARY_STYLE; + $default_primary = neve_get_button_appearance_default(); + $mod_key_secondary = Config::MODS_BUTTON_SECONDARY_STYLE; + $default_secondary = neve_get_button_appearance_default( 'secondary' ); + + $rules = [ + '--primaryBtnBg' => [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.background', + ], + '--secondaryBtnBg' => [ + Dynamic_Selector::META_KEY => $mod_key_secondary . '.background', + ], + '--primaryBtnHoverBg' => [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.backgroundHover', + ], + '--secondaryBtnHoverBg' => [ + Dynamic_Selector::META_KEY => $mod_key_secondary . '.backgroundHover', + ], + '--primaryBtnColor' => [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.text', + ], + '--secondaryBtnColor' => [ + Dynamic_Selector::META_KEY => $mod_key_secondary . '.text', + ], + '--primaryBtnHoverColor' => [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.textHover', + ], + '--secondaryBtnHoverColor' => [ + Dynamic_Selector::META_KEY => $mod_key_secondary . '.textHover', + ], + '--primaryBtnBorderRadius' => [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.borderRadius', + Dynamic_Selector::META_SUFFIX => 'px', + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + '--secondaryBtnBorderRadius' => [ + Dynamic_Selector::META_KEY => $mod_key_secondary . '.borderRadius', + Dynamic_Selector::META_SUFFIX => 'px', + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + ]; + + + $primary_values = get_theme_mod( $mod_key_primary, $default_primary ); + $secondary_values = get_theme_mod( $mod_key_secondary, $default_secondary ); + + // Border Width + if ( isset( $primary_values['type'] ) && $primary_values['type'] === 'outline' ) { + $rules['--primaryBtnBorderWidth'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.borderWidth', + Dynamic_Selector::META_SUFFIX => 'px', + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ]; + } + if ( isset( $secondary_values['type'] ) && $secondary_values['type'] === 'outline' ) { + $rules['--secondaryBtnBorderWidth'] = [ + Dynamic_Selector::META_KEY => $mod_key_secondary . '.borderWidth', + Dynamic_Selector::META_SUFFIX => 'px', + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ]; + } + + $mod_key_primary = Config::MODS_BUTTON_PRIMARY_PADDING; + $default_primary = Mods::get_alternative_mod_default( Config::MODS_BUTTON_PRIMARY_PADDING ); + $rules['--btnPadding'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary, + Dynamic_Selector::META_DEFAULT => $default_primary, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + $mod_key_primary = Config::MODS_BUTTON_PRIMARY_STYLE; + $default_primary = neve_get_button_appearance_default(); + + $mod_key_secondary = Config::MODS_BUTTON_SECONDARY_STYLE; + $default_secondary = neve_get_button_appearance_default( 'secondary' ); + + $values = [ + 'primary' => get_theme_mod( $mod_key_primary, $default_primary ), + 'secondary' => get_theme_mod( $mod_key_secondary, $default_secondary ), + ]; + $paddings = [ + 'primary' => $value, + 'secondary' => $value, + ]; + + foreach ( $values as $btn_type => $appearance_values ) { + if ( ! isset( $appearance_values['type'] ) || $appearance_values['type'] !== 'outline' ) { + continue; + } + + $border_width = $appearance_values['borderWidth']; + + foreach ( $paddings[ $btn_type ] as $direction => $padding_value ) { + if ( ! isset( $border_width[ $direction ] ) || absint( $border_width[ $direction ] ) === 0 ) { + continue; + } + + $paddings[ $btn_type ][ $direction ] = $padding_value - $border_width[ $direction ]; + } + } + $final_value_default = Css_Prop::transform_directional_prop( $meta, $device, $value, '--btnPadding', Config::CSS_PROP_PADDING ); + $final_value_primary = Css_Prop::transform_directional_prop( $meta, $device, $paddings['primary'], '--primaryBtnPadding', Config::CSS_PROP_PADDING ); + $final_value_secondary = Css_Prop::transform_directional_prop( $meta, $device, $paddings['secondary'], '--secondaryBtnPadding', Config::CSS_PROP_PADDING ); + + return $final_value_default . $final_value_primary . $final_value_secondary; + }, + 'directional-prop' => Config::CSS_PROP_PADDING, + ]; + + $mod_key_primary = Config::MODS_BUTTON_TYPEFACE; + $rules['--btnFs'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ]; + $rules['--btnLineHeight'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ]; + $rules['--btnLetterSpacing'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ]; + $rules['--btnTextTransform'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.textTransform', + Dynamic_Selector::META_IS_RESPONSIVE => false, + ]; + $rules['--btnFontWeight'] = [ + Dynamic_Selector::META_KEY => $mod_key_primary . '.fontWeight', + ]; + + return $rules; + } + + /** + * Get the common typography rules + * + * @retun array + */ + public function get_typography_rules() { + $default = Mods::get_alternative_mod_default( Config::MODS_TYPEFACE_GENERAL ); + $mod_key = Config::MODS_TYPEFACE_GENERAL; + + $rules = [ + '--bodyFontFamily' => [ + Dynamic_Selector::META_KEY => Config::MODS_FONT_GENERAL, + Dynamic_Selector::META_DEFAULT => Mods::get_alternative_mod_default( Config::MODS_FONT_GENERAL ), + ], + '--bodyFontSize' => [ + Dynamic_Selector::META_KEY => $mod_key . '.fontSize', + Dynamic_Selector::META_DEFAULT => $default['fontSize'], + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--bodyLineHeight' => [ + Dynamic_Selector::META_KEY => $mod_key . '.lineHeight', + Dynamic_Selector::META_DEFAULT => $default['lineHeight'], + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => '', + ], + '--bodyLetterSpacing' => [ + Dynamic_Selector::META_KEY => $mod_key . '.letterSpacing', + Dynamic_Selector::META_DEFAULT => $default['letterSpacing'], + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--bodyFontWeight' => [ + Dynamic_Selector::META_KEY => $mod_key . '.fontWeight', + Dynamic_Selector::META_DEFAULT => $default['fontWeight'], + 'font' => 'mods_' . Config::MODS_FONT_HEADINGS, + ], + '--bodyTextTransform' => [ + Dynamic_Selector::META_KEY => $mod_key . '.textTransform', + ], + '--headingsFontFamily' => [ + Dynamic_Selector::META_KEY => Config::MODS_FONT_HEADINGS, + ], + ]; + foreach ( neve_get_headings_selectors() as $id => $heading_selector ) { + $composed_key = sprintf( 'neve_%s_typeface_general', $id ); + $mod_key = $composed_key; + $default = Mods::get_alternative_mod_default( $composed_key ); + + $rules[ '--' . $id . 'FontSize' ] = [ + Dynamic_Selector::META_KEY => $mod_key . '.fontSize', + Dynamic_Selector::META_DEFAULT => $default['fontSize'], + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ]; + + $rules[ '--' . $id . 'FontWeight' ] = [ + Dynamic_Selector::META_KEY => $mod_key . '.fontWeight', + Dynamic_Selector::META_DEFAULT => $default['fontWeight'], + 'font' => 'mods_' . Config::MODS_FONT_HEADINGS, + ]; + + $rules[ '--' . $id . 'LineHeight' ] = [ + Dynamic_Selector::META_KEY => $mod_key . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $default['lineHeight'], + Dynamic_Selector::META_SUFFIX => '', + ]; + + $rules[ '--' . $id . 'LetterSpacing' ] = [ + Dynamic_Selector::META_KEY => $mod_key . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $default['letterSpacing'], + ]; + + $rules[ '--' . $id . 'TextTransform' ] = [ + Dynamic_Selector::META_KEY => $mod_key . '.textTransform', + Dynamic_Selector::META_DEFAULT => $default['textTransform'], + ]; + } + + return $rules; + } + +} diff --git a/inc/core/styles/dynamic_selector.php b/inc/core/styles/dynamic_selector.php index 3585410ef8..54e490248f 100644 --- a/inc/core/styles/dynamic_selector.php +++ b/inc/core/styles/dynamic_selector.php @@ -27,6 +27,7 @@ class Dynamic_Selector { const META_DEFAULT = 'default'; const META_DEVICE_ONLY = 'device_only'; const META_FILTER = 'filter'; + const META_AS_JSON = 'as_json'; const KEY_SELECTOR = 'selectors'; const KEY_RULES = 'rules'; @@ -138,9 +139,10 @@ public function transform_selectors() { } if ( $this->get_context() === self::CONTEXT_GUTENBERG ) { $expanded_selectors = explode( ',', $expanded_selectors ); + $expanded_selectors = array_map( function ( $value ) { - return '.editor-styles-wrapper ' . $value; + return $value === ':root' ? $value : '.editor-styles-wrapper ' . $value; }, $expanded_selectors ); diff --git a/inc/core/styles/frontend.php b/inc/core/styles/frontend.php index fe54ad6bfc..d5104dc0ba 100644 --- a/inc/core/styles/frontend.php +++ b/inc/core/styles/frontend.php @@ -9,6 +9,8 @@ use Neve\Core\Settings\Config; use Neve\Core\Settings\Mods; +use Neve\Customizer\Defaults\Layout; +use Neve\Customizer\Defaults\Single_Post; /** * Class Generator for Frontend. @@ -16,26 +18,62 @@ * @package Neve\Core\Styles */ class Frontend extends Generator { + use Css_Vars; + use Single_Post; + use Layout; + + /** + * Box shadow map values + * + * @var string[] + */ + private $box_shadow_map = [ + 1 => '0 1px 3px -2px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.1)', + 2 => '0 3px 6px -5px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.1)', + 3 => '0 10px 20px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.1)', + 4 => '0 14px 28px rgba(0, 0, 0, 0.12), 0 10px 10px rgba(0, 0, 0, 0.12)', + 5 => '0 16px 38px -12px rgba(0,0,0,0.56), 0 4px 25px 0 rgba(0,0,0,0.12), 0 8px 10px -5px rgba(0,0,0,0.2)', + ]; + /** * Generator constructor. */ public function __construct() { - $this->_subscribers = [ - '.container' => [ - Config::CSS_PROP_MAX_WIDTH => [ - Dynamic_Selector::META_KEY => Config::MODS_CONTAINER_WIDTH, - Dynamic_Selector::META_IS_RESPONSIVE => true, - ], - ], - ]; - $this->setup_form_buttons(); + $this->_subscribers = []; + $this->setup_container(); + $this->setup_blog_layout(); $this->setup_legacy_gutenberg_palette(); $this->setup_layout_subscribers(); $this->setup_buttons(); $this->setup_typography(); + $this->setup_blog_meta(); $this->setup_blog_typography(); $this->setup_blog_colors(); $this->setup_form_fields_style(); + $this->setup_single_post_style(); + } + + /** + * Setup the container styles. + * + * @return false + */ + private function setup_container() { + if ( ! neve_is_new_skin() ) { + $this->_subscribers['.container'] = [ + Config::CSS_PROP_MAX_WIDTH => [ + Dynamic_Selector::META_KEY => Config::MODS_CONTAINER_WIDTH, + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + ]; + + return false; + } + + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => ':root', + Dynamic_Selector::KEY_RULES => $this->get_container_rules(), + ]; } /** @@ -66,9 +104,9 @@ private function setup_legacy_gutenberg_palette() { } /** - * Add css for blog colors. + * Setup legacy blog colors. */ - public function setup_blog_colors() { + private function setup_legacy_blog_colors() { $this->_subscribers['.cover-post .inner, .cover-post .inner a:not(.button), .cover-post .inner a:not(.button):hover, .cover-post .inner a:not(.button):focus, .cover-post .inner li'] = [ Config::CSS_PROP_COLOR => [ Dynamic_Selector::META_KEY => 'neve_blog_covers_text_color', @@ -84,18 +122,47 @@ public function setup_blog_colors() { if ( absint( $value ) === 0 ) { return ''; } - $map = [ - 1 => '0 1px 3px -2px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.1)', - 2 => '0 3px 6px -5px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.1)', - 3 => '0 10px 20px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.1)', - 4 => '0 14px 28px rgba(0, 0, 0, 0.12), 0 10px 10px rgba(0, 0, 0, 0.12)', - 5 => '0 16px 38px -12px rgba(0,0,0,0.56), 0 4px 25px 0 rgba(0,0,0,0.12), 0 8px 10px -5px rgba(0,0,0,0.2)', - ]; - if ( ! array_key_exists( absint( $value ), $map ) ) { + + if ( ! array_key_exists( absint( $value ), $this->box_shadow_map ) ) { return ''; } - return sprintf( '%s:%s;', $css_prop, $map[ $value ] ); + return sprintf( '%s:%s;', $css_prop, $this->box_shadow_map[ $value ] ); + }, + ], + ]; + } + + /** + * Add css for blog colors. + */ + public function setup_blog_colors() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_blog_colors(); + + return; + } + + $layout = get_theme_mod( 'neve_blog_archive_layout', 'grid' ); + if ( $layout === 'covers' ) { + $this->_subscribers['.cover-post'] = [ + '--color' => 'neve_blog_covers_text_color', + ]; + } + + $this->_subscribers['.nv-post-thumbnail-wrap'] = [ + '--boxShadow' => [ + Dynamic_Selector::META_KEY => 'neve_post_thumbnail_box_shadow', + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + if ( absint( $value ) === 0 ) { + return ''; + } + + if ( ! array_key_exists( absint( $value ), $this->box_shadow_map ) ) { + return ''; + } + + return sprintf( '%s:%s;', $css_prop, $this->box_shadow_map[ $value ] ); }, ], ]; @@ -105,42 +172,105 @@ public function setup_blog_colors() { * Add css for blog typography. */ public function setup_blog_typography() { - $archive_typography = array( - Config::CSS_SELECTOR_ARCHIVE_POST_TITLE => Config::MODS_TYPEFACE_ARCHIVE_POST_TITLE, - Config::CSS_SELECTOR_ARCHIVE_POST_EXCERPT => Config::MODS_TYPEFACE_ARCHIVE_POST_EXCERPT, - Config::CSS_SELECTOR_ARCHIVE_POST_META => Config::MODS_TYPEFACE_ARCHIVE_POST_META, - Config::CSS_SELECTOR_SINGLE_POST_TITLE => Config::MODS_TYPEFACE_SINGLE_POST_TITLE, - Config::CSS_SELECTOR_SINGLE_POST_META => Config::MODS_TYPEFACE_SINGLE_POST_META, - Config::CSS_SELECTOR_SINGLE_POST_COMMENT_TITLE => Config::MODS_TYPEFACE_SINGLE_POST_COMMENT_TITLE, - ); - foreach ( $archive_typography as $selector => $mod ) { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_blog_typography(); + + return; + } + + $archive_typography = [ + Config::CSS_SELECTOR_ARCHIVE_POST_TITLE => [ + 'mod' => Config::MODS_TYPEFACE_ARCHIVE_POST_TITLE, + 'font' => Config::MODS_FONT_HEADINGS, + ], + Config::CSS_SELECTOR_ARCHIVE_POST_EXCERPT => [ + 'mod' => Config::MODS_TYPEFACE_ARCHIVE_POST_EXCERPT, + 'font' => Config::MODS_FONT_GENERAL, + ], + Config::CSS_SELECTOR_ARCHIVE_POST_META => [ + 'mod' => Config::MODS_TYPEFACE_ARCHIVE_POST_META, + 'font' => Config::MODS_FONT_GENERAL, + ], + Config::CSS_SELECTOR_SINGLE_POST_TITLE => [ + 'mod' => Config::MODS_TYPEFACE_SINGLE_POST_TITLE, + 'font' => Config::MODS_FONT_HEADINGS, + ], + Config::CSS_SELECTOR_SINGLE_POST_META => [ + 'mod' => Config::MODS_TYPEFACE_SINGLE_POST_META, + 'font' => Config::MODS_FONT_GENERAL, + ], + Config::CSS_SELECTOR_SINGLE_POST_COMMENT_TITLE => [ + 'mod' => Config::MODS_TYPEFACE_SINGLE_POST_COMMENT_TITLE, + 'font' => Config::MODS_FONT_HEADINGS, + ], + ]; + foreach ( $archive_typography as $selector => $args ) { $this->_subscribers[ $selector ] = [ - Config::CSS_PROP_FONT_SIZE => [ - Dynamic_Selector::META_KEY => $mod . '.fontSize', + '--fontSize' => [ + Dynamic_Selector::META_KEY => $args['mod'] . '.fontSize', Dynamic_Selector::META_IS_RESPONSIVE => true, Dynamic_Selector::META_SUFFIX => 'px', ], - Config::CSS_PROP_LINE_HEIGHT => [ - Dynamic_Selector::META_KEY => $mod . '.lineHeight', + '--lineHeight' => [ + Dynamic_Selector::META_KEY => $args['mod'] . '.lineHeight', Dynamic_Selector::META_IS_RESPONSIVE => true, Dynamic_Selector::META_SUFFIX => '', ], - Config::CSS_PROP_LETTER_SPACING => [ - Dynamic_Selector::META_KEY => $mod . '.letterSpacing', + '--letterSpacing' => [ + Dynamic_Selector::META_KEY => $args['mod'] . '.letterSpacing', Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', ], - Config::CSS_PROP_FONT_WEIGHT => [ - Dynamic_Selector::META_KEY => $mod . '.fontWeight', + '--fontWeight' => [ + Dynamic_Selector::META_KEY => $args['mod'] . '.fontWeight', + 'font' => 'mods_' . $args['font'], ], - Config::CSS_PROP_TEXT_TRANSFORM => $mod . '.textTransform', + '--textTransform' => $args['mod'] . '.textTransform', ]; } } /** - * Setup typography subscribers. + * Add css for blog layout. + * + * Removed grid in new skin CSS so this should handle the grid. + * + * @since 3.0.0 + * + * @return bool|void */ - public function setup_typography() { + public function setup_blog_layout() { + if ( ! neve_is_new_skin() ) { + return false; + } + + $this->_subscribers[':root'] = [ + '--postWidth' => [ + Dynamic_Selector::META_KEY => 'neve_grid_layout', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $this->grid_columns_default(), + Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { + $blog_layout = get_theme_mod( 'neve_blog_archive_layout', 'grid' ); + if ( ! in_array( $blog_layout, [ 'grid', 'covers' ], true ) ) { + return sprintf( '%s:%s;', $css_prop, '100%' ); + } + + if ( $value < 1 ) { + $value = 1; + } + + return sprintf( '%s:%s;', $css_prop, 100 / $value . '%' ); + }, + ], + ]; + } + + /** + * Setups the legacy typography, used before 3.0. + * + * @since 3.0.0 + */ + public function setup_legacy_typography() { $this->_subscribers[ Config::CSS_SELECTOR_TYPEFACE_GENERAL ] = [ Config::CSS_PROP_FONT_SIZE => [ Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.fontSize', @@ -199,8 +329,8 @@ public function setup_typography() { ]; } - $extra_selectors_body = apply_filters( 'neve_body_font_family_selectors', '' ); + if ( ! empty( $extra_selectors_body ) ) { $extra_selectors_body = ltrim( $extra_selectors_body, ', ' ); $this->_subscribers[ $extra_selectors_body ] = [ @@ -219,9 +349,25 @@ public function setup_typography() { } /** - * Setup button subscribers. + * Setup typography subscribers. */ - public function setup_buttons() { + public function setup_typography() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_typography(); + + return; + } + $rules = $this->get_typography_rules(); + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => ':root', + Dynamic_Selector::KEY_RULES => $rules, + ]; + } + + /** + * Setup legacy button. + */ + private function setup_legacy_buttons() { // Primary button config. $this->_subscribers[] = [ Dynamic_Selector::KEY_SELECTOR => Config::CSS_SELECTOR_BTN_PRIMARY_NORMAL, @@ -431,6 +577,23 @@ public function setup_buttons() { ]; } + /** + * Setup button subscribers. + */ + public function setup_buttons() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_buttons(); + + return; + } + + $rules = $this->get_button_rules(); + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => ':root', + Dynamic_Selector::KEY_RULES => $rules, + ]; + } + /** * Setup settings subscribers for layout. * @@ -438,7 +601,7 @@ public function setup_buttons() { * TODO: Better exclude classes when Woo is not present, i.e shop-sidebar class is added even when Woo is not used. */ public function setup_layout_subscribers() { - $is_advanced_on = Mods::get( Config::MODS_ADVANCED_LAYOUT_OPTIONS, false ); + $is_advanced_on = Mods::get( Config::MODS_ADVANCED_LAYOUT_OPTIONS, neve_is_new_skin() ); if ( ! $is_advanced_on ) { $this->_subscribers['#content .container .col, #content .container-fluid .col'] = [ @@ -487,16 +650,18 @@ public function setup_layout_subscribers() { return; } // Others content width. - $this->_subscribers['body:not(.single):not(.archive):not(.blog):not(.search) .neve-main > .container .col'] = [ + $this->_subscribers['body:not(.single):not(.archive):not(.blog):not(.search) .neve-main > .container .col, body.post-type-archive-course .neve-main > .container .col, body.post-type-archive-llms_membership .neve-main > .container .col'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_OTHERS_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_OTHERS_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_SUFFIX => '%', ], ]; - $this->_subscribers['body:not(.single):not(.archive):not(.blog):not(.search) .nv-sidebar-wrap'] = [ + $this->_subscribers['body:not(.single):not(.archive):not(.blog):not(.search) .nv-sidebar-wrap, body.post-type-archive-course .nv-sidebar-wrap, body.post-type-archive-llms_membership .nv-sidebar-wrap'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_OTHERS_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_OTHERS_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => 'minus_100', Dynamic_Selector::META_SUFFIX => '%', @@ -506,6 +671,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.neve-main > .archive-container .nv-index-posts.col'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_ARCHIVE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_ARCHIVE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_SUFFIX => '%', ], @@ -513,6 +679,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.neve-main > .archive-container .nv-sidebar-wrap'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_ARCHIVE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_ARCHIVE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => 'minus_100', Dynamic_Selector::META_SUFFIX => '%', @@ -522,6 +689,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.neve-main > .single-post-container .nv-single-post-wrap.col'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SINGLE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_SUFFIX => '%', ], @@ -530,7 +698,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.single-post-container .alignfull > [class*="__inner-container"], .single-post-container .alignwide > [class*="__inner-container"]'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SINGLE_CONTENT_WIDTH, - Dynamic_Selector::META_DEFAULT => 70, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_IS_RESPONSIVE => true, Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { $width = Mods::to_json( Config::MODS_CONTAINER_WIDTH ); @@ -543,6 +711,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.container-fluid.single-post-container .alignfull > [class*="__inner-container"], .container-fluid.single-post-container .alignwide > [class*="__inner-container"]'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SINGLE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { return sprintf( 'max-width:calc(%s%% + %spx)', $value, Config::CONTENT_DEFAULT_PADDING / 2 ); @@ -553,6 +722,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.neve-main > .single-post-container .nv-sidebar-wrap'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SINGLE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => 'minus_100', Dynamic_Selector::META_SUFFIX => '%', @@ -567,6 +737,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.archive.woocommerce .neve-main > .shop-container .nv-shop.col'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SHOP_ARCHIVE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SHOP_ARCHIVE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_SUFFIX => '%', ], @@ -574,6 +745,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.archive.woocommerce .neve-main > .shop-container .nv-sidebar-wrap'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SHOP_ARCHIVE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SHOP_ARCHIVE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => 'minus_100', Dynamic_Selector::META_SUFFIX => '%', @@ -584,6 +756,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.single-product .neve-main > .shop-container .nv-shop.col'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SHOP_SINGLE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SHOP_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_SUFFIX => '%', ], @@ -592,7 +765,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.single-product .alignfull > [class*="__inner-container"], .single-product .alignwide > [class*="__inner-container"]'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SHOP_SINGLE_CONTENT_WIDTH, - Dynamic_Selector::META_DEFAULT => 70, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SHOP_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_IS_RESPONSIVE => true, Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { $width = Mods::to_json( Config::MODS_CONTAINER_WIDTH ); @@ -605,6 +778,7 @@ public function setup_layout_subscribers() { $this->_subscribers['.single-product .container-fluid .alignfull > [class*="__inner-container"], .single-product .alignwide > [class*="__inner-container"]'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SHOP_SINGLE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SHOP_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) { return sprintf( 'max-width:calc(%s%% + %spx)', $value, Config::CONTENT_DEFAULT_PADDING / 2 ); @@ -614,18 +788,261 @@ public function setup_layout_subscribers() { $this->_subscribers['.single-product .neve-main > .shop-container .nv-sidebar-wrap'] = [ Config::CSS_PROP_MAX_WIDTH => [ Dynamic_Selector::META_KEY => Config::MODS_SHOP_SINGLE_CONTENT_WIDTH, + Dynamic_Selector::META_DEFAULT => $this->sidebar_layout_width_default( Config::MODS_SHOP_SINGLE_CONTENT_WIDTH ), Dynamic_Selector::META_DEVICE_ONLY => Dynamic_Selector::DESKTOP, Dynamic_Selector::META_FILTER => 'minus_100', Dynamic_Selector::META_SUFFIX => '%', ], ]; - } /** * Adds form field styles */ private function setup_form_fields_style() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_form_fields_style(); + + return; + } + + $border_width_default = array_fill_keys( Config::$directional_keys, '2' ); + $border_radius_default = array_fill_keys( Config::$directional_keys, '3' ); + + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => ':root', + Dynamic_Selector::KEY_RULES => [ + '--formFieldSpacing' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_SPACING, + Dynamic_Selector::META_DEFAULT => Mods::get_alternative_mod_default( Config::MODS_FORM_FIELDS_SPACING ), + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--formFieldBorderWidth' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_BORDER_WIDTH, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => $border_width_default, + 'directional-prop' => Config::CSS_PROP_BORDER_WIDTH, + ], + '--formFieldBorderRadius' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_BORDER_RADIUS, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => $border_radius_default, + 'directional-prop' => Config::CSS_PROP_BORDER_RADIUS, + ], + '--formFieldBgColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_BACKGROUND_COLOR, + Dynamic_Selector::META_DEFAULT => 'var(--nv-site-bg)', + ], + '--formFieldBorderColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_BORDER_COLOR, + Dynamic_Selector::META_DEFAULT => '#dddddd', + ], + '--formFieldColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_COLOR, + Dynamic_Selector::META_DEFAULT => 'var(--nv-text-color)', + ], + '--formFieldPadding' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_PADDING, + Dynamic_Selector::META_DEFAULT => Mods::get_alternative_mod_default( Config::MODS_FORM_FIELDS_PADDING ), + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_IS_RESPONSIVE => false, + 'directional-prop' => Config::CSS_PROP_PADDING, + ], + '--formFieldTextTransform' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_TYPEFACE . '.textTransform', + Dynamic_Selector::META_IS_RESPONSIVE => false, + ], + '--formFieldFontSize' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_TYPEFACE . '.fontSize', + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + '--formFieldLineHeight' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_TYPEFACE . '.lineHeight', + Dynamic_Selector::META_SUFFIX => '', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + '--formFieldLetterSpacing' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_TYPEFACE . '.letterSpacing', + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + '--formFieldFontWeight' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_TYPEFACE . '.fontWeight', + ], + // Form Labels + '--formLabelSpacing' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_LABELS_SPACING, + Dynamic_Selector::META_DEFAULT => 10, + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--formLabelFontSize' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_LABELS_TYPEFACE . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + '--formLabelLineHeight' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_LABELS_TYPEFACE . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => '', + ], + '--formLabelLetterSpacing' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_LABELS_TYPEFACE . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + '--formLabelFontWeight' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_LABELS_TYPEFACE . '.fontWeight', + ], + '--formLabelTextTransform' => [ + Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_LABELS_TYPEFACE . '.textTransform', + ], + ], + ]; + + // Form button style. Override if needed. + $form_buttons_type = get_theme_mod( 'neve_form_button_type', 'primary' ); + + if ( $form_buttons_type === 'primary' ) { + return; + } + + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON ]['background-color'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnBg, transparent)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON ]['color'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnColor)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON ]['padding'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnPadding, 7px 12px)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON ]['border-radius'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnBorderRadius, 3px)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON_HOVER ]['background-color'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnHoverBg, transparent)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON_HOVER ]['color'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnHoverColor)', + ]; + + $mod_key_secondary = Config::MODS_BUTTON_SECONDARY_STYLE; + $default_secondary = Mods::get_alternative_mod_default( Config::MODS_BUTTON_SECONDARY_STYLE ); + $secondary_values = get_theme_mod( $mod_key_secondary, $default_secondary ); + + if ( ! isset( $secondary_values['type'] ) || $secondary_values['type'] !== 'outline' ) { + return; + } + + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON ]['border-width'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnBorderWidth, 3px)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON ]['border-color'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnHoverColor)', + ]; + $this->_subscribers[ Config::CSS_SELECTOR_FORM_BUTTON_HOVER ]['border-color'] = [ + 'key' => 'neve_form_button_type', + 'override' => 'var(--secondaryBtnHoverColor)', + ]; + } + + /** + * Add form buttons selectors to the Buttons selector. + * + * @param string $selector the CSS selector received from the filter. + * + * @return string + */ + public function add_form_buttons( $selector ) { + return ( $selector . ', form input[type="submit"], form button[type="submit"]' ); + } + + /** + * Add form buttons hover selectors to the Buttons selector. + * + * @param string $selector the CSS selector received from the filter. + * + * @return string + */ + public function add_form_buttons_hover( $selector ) { + return ( $selector . ', form input[type="submit"]:hover, form button[type="submit"]:hover' ); + } + + /** + * Add css for blog meta. + */ + public function setup_blog_meta() { + if ( ! neve_is_new_skin() ) { + $this->setup_blog_meta_legacy(); + + return; + } + + $rules = [ + '--avatarSize' => [ + Dynamic_Selector::META_KEY => Config::MODS_ARCHIVE_POST_META_AUTHOR_AVATAR_SIZE, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => '{ "mobile": 20, "tablet": 20, "desktop": 20 }', + ], + ]; + + $rules_single = [ + '--avatarSize' => [ + Dynamic_Selector::META_KEY => Config::MODS_SINGLE_POST_META_AUTHOR_AVATAR_SIZE, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + Dynamic_Selector::META_DEFAULT => Mods::get( 'neve_author_avatar_size', '{ "mobile": 20, "tablet": 20, "desktop": 20 }' ), + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-meta-list', + 'rules' => $rules, + ]; + + $this->_subscribers[] = [ + 'selectors' => '.single .nv-meta-list', + 'rules' => $rules_single, + ]; + } + + /** + * Add css for blog meta. + */ + public function setup_blog_meta_legacy() { + + $meta_key = Config::MODS_ARCHIVE_POST_META_AUTHOR_AVATAR_SIZE; + if ( is_singular( 'post' ) ) { + $meta_key = Config::MODS_SINGLE_POST_META_AUTHOR_AVATAR_SIZE; + } + + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => '.nv-meta-list .meta.author img.photo', + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_HEIGHT => [ + Dynamic_Selector::META_KEY => $meta_key, + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + Config::CSS_PROP_WIDTH => [ + Dynamic_Selector::META_KEY => $meta_key, + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + ], + ]; + } + + /** + * Setup legacy form field styles. + */ + private function setup_legacy_form_fields_style() { $this->_subscribers[ Config::CSS_SELECTOR_FORM_INPUTS_WITH_SPACING ] = [ Config::CSS_PROP_MARGIN_BOTTOM => [ Dynamic_Selector::META_KEY => Config::MODS_FORM_FIELDS_SPACING, @@ -712,93 +1129,198 @@ private function setup_form_fields_style() { ], Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_GENERAL, ]; - } - /** - * Setup Form Buttons Type - */ - private function setup_form_buttons() { + /** + * Form buttons. + */ $form_buttons_type = get_theme_mod( 'neve_form_button_type', 'primary' ); if ( $form_buttons_type === 'primary' ) { - add_filter( - 'neve_selectors_' . Config::CSS_SELECTOR_BTN_PRIMARY_NORMAL, - array( - $this, - 'add_form_buttons', - ), - 10, - 1 - ); - add_filter( - 'neve_selectors_' . Config::CSS_SELECTOR_BTN_PRIMARY_PADDING, - array( - $this, - 'add_form_buttons', - ), - 10, - 1 - ); + add_filter( 'neve_selectors_' . Config::CSS_SELECTOR_BTN_PRIMARY_NORMAL, [ $this, 'add_form_buttons' ] ); + add_filter( 'neve_selectors_' . Config::CSS_SELECTOR_BTN_PRIMARY_PADDING, [ $this, 'add_form_buttons' ] ); add_filter( 'neve_selectors_' . Config::CSS_SELECTOR_BTN_PRIMARY_HOVER, - array( + [ $this, 'add_form_buttons_hover', - ), - 10, - 1 + ] ); return; } - add_filter( - 'neve_selectors_' . Config::CSS_SELECTOR_BTN_SECONDARY_NORMAL, - array( - $this, - 'add_form_buttons', - ), - 10, - 1 - ); - add_filter( - 'neve_selectors_' . Config::CSS_SELECTOR_BTN_SECONDARY_PADDING, - array( - $this, - 'add_form_buttons', - ), - 10, - 1 - ); - add_filter( - 'neve_selectors_' . Config::CSS_SELECTOR_BTN_SECONDARY_HOVER, - array( - $this, - 'add_form_buttons_hover', - ), - 10, - 1 - ); + + add_filter( 'neve_selectors_' . Config::CSS_SELECTOR_BTN_SECONDARY_NORMAL, [ $this, 'add_form_buttons' ] ); + add_filter( 'neve_selectors_' . Config::CSS_SELECTOR_BTN_SECONDARY_PADDING, [ $this, 'add_form_buttons' ] ); + add_filter( 'neve_selectors_' . Config::CSS_SELECTOR_BTN_SECONDARY_HOVER, [ $this, 'add_form_buttons_hover' ] ); } /** - * Add form buttons selectors to the Buttons selector. - * - * @param string $selector the CSS selector received from the filter. - * - * @return string + * Add css for single post. */ - public function add_form_buttons( $selector ) { - return ( $selector . ', form input[type="submit"], form button[type="submit"], #comments input[type="submit"]' ); + private function setup_single_post_style() { + if ( ! neve_is_new_skin() ) { + return; + } + + $cover_rules = [ + '--height' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_HEIGHT, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_AS_JSON => true, + Dynamic_Selector::META_SUFFIX => 'responsive_suffix', + Dynamic_Selector::META_DEFAULT => '{ "mobile": "400", "tablet": "400", "desktop": "400" }', + ], + '--padding' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_PADDING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $this->padding_default( 'cover' ), + 'directional-prop' => Config::CSS_PROP_PADDING, + ], + '--vAlign' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_TITLE_POSITION, + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-post-cover', + 'rules' => $cover_rules, + ]; + + $title_rules = [ + '--color' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_TEXT_COLOR, + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-post-cover .nv-title-meta-wrap', + 'rules' => $title_rules, + ]; + + $boxed_title_rules = [ + '--padding' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_BOXED_TITLE_PADDING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $this->padding_default( 'cover' ), + 'directional-prop' => Config::CSS_PROP_PADDING, + ], + '--bgColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_BOXED_TITLE_BACKGROUND, + Dynamic_Selector::META_DEFAULT => 'var(--nv-dark-bg)', + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-is-boxed.nv-title-meta-wrap', + 'rules' => $boxed_title_rules, + ]; + + $overlay_rules = [ + '--bgColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_BACKGROUND_COLOR, + ], + '--blendMode' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_BLEND_MODE, + ], + '--opacity' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COVER_OVERLAY_OPACITY, + Dynamic_Selector::META_DEFAULT => 50, + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-overlay', + 'rules' => $overlay_rules, + ]; + + $boxed_comments_rules = [ + '--padding' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COMMENTS_PADDING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $this->padding_default(), + 'directional-prop' => Config::CSS_PROP_PADDING, + ], + '--bgColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COMMENTS_BACKGROUND_COLOR, + ], + '--color' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COMMENTS_TEXT_COLOR, + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-is-boxed.nv-comments-wrap', + 'rules' => $boxed_comments_rules, + ]; + + $boxed_comment_form_rules = [ + '--padding' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COMMENTS_FORM_PADDING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_DEFAULT => $this->padding_default(), + 'directional-prop' => Config::CSS_PROP_PADDING, + ], + '--bgColor' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COMMENTS_FORM_BACKGROUND_COLOR, + ], + '--color' => [ + Dynamic_Selector::META_KEY => Config::MODS_POST_COMMENTS_FORM_TEXT_COLOR, + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-is-boxed.comment-respond', + 'rules' => $boxed_comment_form_rules, + ]; + + $spacing_rules = [ + '--spacing' => [ + Dynamic_Selector::META_KEY => Config::MODS_SINGLE_POST_ELEMENTS_SPACING, + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + ]; + + $this->_subscribers[] = [ + 'selectors' => '.nv-single-post-wrap', + 'rules' => $spacing_rules, + ]; } /** - * Add form buttons hover selectors to the Buttons selector. - * - * @param string $selector the CSS selector received from the filter. - * - * @return string + * Setup legacy blog typography. */ - public function add_form_buttons_hover( $selector ) { - return ( $selector . ', form input[type="submit"]:hover, form button[type="submit"]:hover, #comments input[type="submit"]:hover' ); + private function setup_legacy_blog_typography() { + $archive_typography = array( + Config::CSS_SELECTOR_ARCHIVE_POST_TITLE => Config::MODS_TYPEFACE_ARCHIVE_POST_TITLE, + Config::CSS_SELECTOR_ARCHIVE_POST_EXCERPT => Config::MODS_TYPEFACE_ARCHIVE_POST_EXCERPT, + Config::CSS_SELECTOR_ARCHIVE_POST_META => Config::MODS_TYPEFACE_ARCHIVE_POST_META, + Config::CSS_SELECTOR_SINGLE_POST_TITLE => Config::MODS_TYPEFACE_SINGLE_POST_TITLE, + Config::CSS_SELECTOR_SINGLE_POST_META => Config::MODS_TYPEFACE_SINGLE_POST_META, + Config::CSS_SELECTOR_SINGLE_POST_COMMENT_TITLE => Config::MODS_TYPEFACE_SINGLE_POST_COMMENT_TITLE, + ); + foreach ( $archive_typography as $selector => $mod ) { + $this->_subscribers[ $selector ] = [ + Config::CSS_PROP_FONT_SIZE => [ + Dynamic_Selector::META_KEY => $mod . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + Config::CSS_PROP_LINE_HEIGHT => [ + Dynamic_Selector::META_KEY => $mod . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => '', + ], + Config::CSS_PROP_LETTER_SPACING => [ + Dynamic_Selector::META_KEY => $mod . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + Config::CSS_PROP_FONT_WEIGHT => [ + Dynamic_Selector::META_KEY => $mod . '.fontWeight', + ], + Config::CSS_PROP_TEXT_TRANSFORM => $mod . '.textTransform', + ]; + } } } diff --git a/inc/core/styles/generator.php b/inc/core/styles/generator.php index 4a7db4c85d..462844c0f5 100644 --- a/inc/core/styles/generator.php +++ b/inc/core/styles/generator.php @@ -49,23 +49,28 @@ public function generate( $echo = false ) { if ( $this->context === null ) { $this->context = Dynamic_Selector::CONTEXT_FRONTEND; } + /** * Neve try to build the CSS as mobile first. - * Based on this fact, the general CSS is considere the mobile one. + * Based on this fact, the general CSS is considered the mobile one. */ $dynamic_selectors = new Dynamic_Selector( $this->_subscribers, $this->context ); - $all_css .= $dynamic_selectors->for_mobile(); - $tablet_css .= $dynamic_selectors->for_tablet(); - $desktop_css .= $dynamic_selectors->for_desktop(); + + $all_css .= $dynamic_selectors->for_mobile(); + $tablet_css .= $dynamic_selectors->for_tablet(); + $desktop_css .= $dynamic_selectors->for_desktop(); if ( ! empty( $tablet_css ) ) { $all_css .= sprintf( '@media(min-width: 576px){ %s }', $tablet_css ); } if ( ! empty( $desktop_css ) ) { $all_css .= sprintf( '@media(min-width: 960px){ %s }', $desktop_css ); } + if ( ! $echo ) { return $all_css; } + + echo $all_css; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } diff --git a/inc/core/styles/gutenberg.php b/inc/core/styles/gutenberg.php index 0340642199..791ea5ae97 100644 --- a/inc/core/styles/gutenberg.php +++ b/inc/core/styles/gutenberg.php @@ -17,6 +17,8 @@ * @package Neve\Core\Styles */ class Gutenberg extends Generator { + use Css_Vars; + /** * Generator constructor. */ @@ -27,118 +29,82 @@ public function __construct() { $this->add_editor_color_palette_styles(); } - /** * Setup typography subscribers. */ public function setup_typography() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_typography(); + return; + } - // Gutenberg Typography. - + $rules = $this->get_typography_rules(); $this->_subscribers[] = [ - Dynamic_Selector::KEY_SELECTOR => '.editor-post-title__block .editor-post-title__input, - .wp-block h1, h1.wp-block - .wp-block h2, h2.wp-block - .wp-block h3, h3.wp-block - .wp-block h4, h4.wp-block - .wp-block h5, h5.wp-block - .wp-block h6, h6.wp-block', - Dynamic_Selector::KEY_RULES => [ - Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_HEADINGS, - ], + Dynamic_Selector::KEY_SELECTOR => ':root', + Dynamic_Selector::KEY_RULES => $rules, Dynamic_Selector::KEY_CONTEXT => [ Dynamic_Selector::CONTEXT_GUTENBERG => true, ], ]; + } + + /** + * Setup button subscribers. + */ + public function setup_buttons() { + if ( ! neve_is_new_skin() ) { + $this->setup_legacy_buttons(); + + return; + } + + $rules = $this->get_button_rules(); $this->_subscribers[] = [ - Dynamic_Selector::KEY_SELECTOR => '.editor-styles-wrapper', - Dynamic_Selector::KEY_RULES => [ - Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_GENERAL, - ], + Dynamic_Selector::KEY_SELECTOR => ':root', + Dynamic_Selector::KEY_RULES => $rules, Dynamic_Selector::KEY_CONTEXT => [ Dynamic_Selector::CONTEXT_GUTENBERG => true, ], ]; + } - $this->_subscribers[] = [ - Dynamic_Selector::KEY_SELECTOR => ' .wp-block, - [data-type="core/paragraph"] p', - Dynamic_Selector::KEY_RULES => [ - Config::CSS_PROP_FONT_SIZE => [ - Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.fontSize', - Dynamic_Selector::META_IS_RESPONSIVE => true, - Dynamic_Selector::META_SUFFIX => 'px', - ], - Config::CSS_PROP_LINE_HEIGHT => [ - Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.lineHeight', - Dynamic_Selector::META_IS_RESPONSIVE => true, - Dynamic_Selector::META_SUFFIX => '', - ], - Config::CSS_PROP_LETTER_SPACING => [ - Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.letterSpacing', - Dynamic_Selector::META_IS_RESPONSIVE => true, - ], - Config::CSS_PROP_FONT_WEIGHT => [ - Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.fontWeight', - 'font' => 'mods_' . Config::MODS_FONT_GENERAL, + /** + * Adds colors from the editor-color-palette theme support. + */ + private function add_editor_color_palette_styles() { + $is_new_user = get_option( 'neve_new_user' ); + $imported_starter_site = get_option( 'neve_imported_demo' ); + if ( $is_new_user === 'yes' && $imported_starter_site !== 'yes' ) { + return; + } + + $this->_subscribers['.has-neve-button-color-color'] = [ + Config::CSS_PROP_COLOR => [ + Dynamic_Selector::META_KEY => Config::MODS_BUTTON_PRIMARY_STYLE . '.background', + Dynamic_Selector::META_IMPORTANT => true, + Dynamic_Selector::META_DEFAULT => 'var(--nv-primary-accent)', + Dynamic_Selector::KEY_CONTEXT => [ + Dynamic_Selector::CONTEXT_GUTENBERG => true, ], - Config::CSS_PROP_TEXT_TRANSFORM => Config::MODS_TYPEFACE_GENERAL . '.textTransform', - Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_GENERAL, - ], - Dynamic_Selector::KEY_CONTEXT => [ - Dynamic_Selector::CONTEXT_GUTENBERG => true, ], ]; - foreach ( - [ - 'neve_h1_typeface_general' => ' - .wp-block h1, h1.wp-block, - .editor-post-title__block .editor-post-title__input', - 'neve_h2_typeface_general' => ' .wp-block h2, h2.wp-block', - 'neve_h3_typeface_general' => '.wp-block h3, h3.wp-block', - 'neve_h4_typeface_general' => '.wp-block h4, h4.wp-block', - 'neve_h5_typeface_general' => '.wp-block h5, h5.wp-block', - 'neve_h6_typeface_general' => '.wp-block h6, h6.wp-block', - ] as $heading_mod => $heading_selector - ) { - $this->_subscribers[] = [ - Dynamic_Selector::KEY_RULES => [ - Config::CSS_PROP_FONT_SIZE => [ - Dynamic_Selector::META_KEY => $heading_mod . '.fontSize', - Dynamic_Selector::META_IS_RESPONSIVE => true, - Dynamic_Selector::META_SUFFIX => 'em', - ], - Config::CSS_PROP_LINE_HEIGHT => [ - Dynamic_Selector::META_KEY => $heading_mod . '.lineHeight', - Dynamic_Selector::META_IS_RESPONSIVE => true, - Dynamic_Selector::META_SUFFIX => '', - ], - Config::CSS_PROP_LETTER_SPACING => [ - Dynamic_Selector::META_KEY => $heading_mod . '.letterSpacing', - Dynamic_Selector::META_IS_RESPONSIVE => true, - ], - Config::CSS_PROP_FONT_WEIGHT => [ - Dynamic_Selector::META_KEY => $heading_mod . '.fontWeight', - 'font' => 'mods_' . Config::MODS_FONT_HEADINGS, - ], - Config::CSS_PROP_TEXT_TRANSFORM => $heading_mod . '.textTransform', - Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_HEADINGS, - ], - Dynamic_Selector::KEY_SELECTOR => $heading_selector, - Dynamic_Selector::KEY_CONTEXT => [ + $this->_subscribers['.has-neve-button-color-background-color'] = [ + Config::CSS_PROP_BACKGROUND_COLOR => [ + Dynamic_Selector::META_KEY => Config::MODS_BUTTON_PRIMARY_STYLE . '.background', + Dynamic_Selector::META_IMPORTANT => true, + Dynamic_Selector::META_DEFAULT => 'var(--nv-primary-accent)', + Dynamic_Selector::KEY_CONTEXT => [ Dynamic_Selector::CONTEXT_GUTENBERG => true, ], - ]; - } + ], + ]; } /** - * Setup button subscribers. + * Setup legacy buttons selectors. */ - public function setup_buttons() { - - + private function setup_legacy_buttons() { // Gutenberg $this->_subscribers[] = [ Dynamic_Selector::KEY_SELECTOR => '.wp-block-button.is-style-primary .wp-block-button__link, .wc-block-grid .wp-block-button .wp-block-button__link', @@ -186,9 +152,7 @@ public function setup_buttons() { Dynamic_Selector::CONTEXT_GUTENBERG => true, ], ]; - - - $this->_subscribers[] = [ + $this->_subscribers[] = [ Dynamic_Selector::KEY_SELECTOR => '.wp-block-button.is-style-primary .wp-block-button__link, .wc-block-grid .wp-block-button .wp-block-button__link', Dynamic_Selector::KEY_RULES => [ Config::CSS_PROP_PADDING => [ @@ -219,7 +183,7 @@ public function setup_buttons() { Dynamic_Selector::CONTEXT_GUTENBERG => true, ], ]; - $this->_subscribers[] = [ + $this->_subscribers[] = [ Dynamic_Selector::KEY_SELECTOR => '.wp-block-button.is-style-secondary .wp-block-button__link', Dynamic_Selector::KEY_RULES => [ Config::CSS_PROP_PADDING => [ @@ -253,34 +217,111 @@ public function setup_buttons() { } /** - * Adds colors from the editor-color-palette theme support. + * Setup legacy typography. */ - private function add_editor_color_palette_styles() { - $is_new_user = get_option( 'neve_new_user' ); - $imported_starter_site = get_option( 'neve_imported_demo' ); - if ( $is_new_user === 'yes' && $imported_starter_site !== 'yes' ) { - return; - } - - $this->_subscribers['.has-neve-button-color-color'] = [ - Config::CSS_PROP_COLOR => [ - Dynamic_Selector::META_KEY => Config::MODS_BUTTON_PRIMARY_STYLE . '.background', - Dynamic_Selector::META_IMPORTANT => true, - Dynamic_Selector::META_DEFAULT => 'var(--nv-primary-accent)', - Dynamic_Selector::KEY_CONTEXT => [ - Dynamic_Selector::CONTEXT_GUTENBERG => true, + private function setup_legacy_typography() { + // Gutenberg Typography. + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => '.editor-post-title__block .editor-post-title__input, + .wp-block h1, h1.wp-block + .wp-block h2, h2.wp-block + .wp-block h3, h3.wp-block + .wp-block h4, h4.wp-block + .wp-block h5, h5.wp-block + .wp-block h6, h6.wp-block', + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_HEADINGS, + ], + Dynamic_Selector::KEY_CONTEXT => [ + Dynamic_Selector::CONTEXT_GUTENBERG => true, + ], + ]; + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => '.editor-styles-wrapper', + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_FONT_FAMILY => [ + Dynamic_Selector::META_KEY => Config::MODS_FONT_GENERAL, + Dynamic_Selector::META_DEFAULT => Mods::get_alternative_mod_default( Config::MODS_FONT_GENERAL ), ], ], + Dynamic_Selector::KEY_CONTEXT => [ + Dynamic_Selector::CONTEXT_GUTENBERG => true, + ], ]; - $this->_subscribers['.has-neve-button-color-background-color'] = [ - Config::CSS_PROP_BACKGROUND_COLOR => [ - Dynamic_Selector::META_KEY => Config::MODS_BUTTON_PRIMARY_STYLE . '.background', - Dynamic_Selector::META_IMPORTANT => true, - Dynamic_Selector::META_DEFAULT => 'var(--nv-primary-accent)', - Dynamic_Selector::KEY_CONTEXT => [ - Dynamic_Selector::CONTEXT_GUTENBERG => true, + + $this->_subscribers[] = [ + Dynamic_Selector::KEY_SELECTOR => ' .wp-block, + [data-type="core/paragraph"] p', + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_FONT_SIZE => [ + Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'px', + ], + Config::CSS_PROP_LINE_HEIGHT => [ + Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => '', + ], + Config::CSS_PROP_LETTER_SPACING => [ + Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + Config::CSS_PROP_FONT_WEIGHT => [ + Dynamic_Selector::META_KEY => Config::MODS_TYPEFACE_GENERAL . '.fontWeight', + 'font' => 'mods_' . Config::MODS_FONT_GENERAL, + ], + Config::CSS_PROP_TEXT_TRANSFORM => Config::MODS_TYPEFACE_GENERAL . '.textTransform', + Config::CSS_PROP_FONT_FAMILY => [ + Dynamic_Selector::META_KEY => Config::MODS_FONT_GENERAL, + Dynamic_Selector::META_DEFAULT => Mods::get_alternative_mod_default( Config::MODS_FONT_GENERAL ), ], ], + Dynamic_Selector::KEY_CONTEXT => [ + Dynamic_Selector::CONTEXT_GUTENBERG => true, + ], ]; + foreach ( + [ + 'neve_h1_typeface_general' => ' + .wp-block h1, h1.wp-block, + .editor-post-title__block .editor-post-title__input', + 'neve_h2_typeface_general' => ' .wp-block h2, h2.wp-block', + 'neve_h3_typeface_general' => '.wp-block h3, h3.wp-block', + 'neve_h4_typeface_general' => '.wp-block h4, h4.wp-block', + 'neve_h5_typeface_general' => '.wp-block h5, h5.wp-block', + 'neve_h6_typeface_general' => '.wp-block h6, h6.wp-block', + ] as $heading_mod => $heading_selector + ) { + + $this->_subscribers[] = [ + Dynamic_Selector::KEY_RULES => [ + Config::CSS_PROP_FONT_SIZE => [ + Dynamic_Selector::META_KEY => $heading_mod . '.fontSize', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => 'em', + ], + Config::CSS_PROP_LINE_HEIGHT => [ + Dynamic_Selector::META_KEY => $heading_mod . '.lineHeight', + Dynamic_Selector::META_IS_RESPONSIVE => true, + Dynamic_Selector::META_SUFFIX => '', + ], + Config::CSS_PROP_LETTER_SPACING => [ + Dynamic_Selector::META_KEY => $heading_mod . '.letterSpacing', + Dynamic_Selector::META_IS_RESPONSIVE => true, + ], + Config::CSS_PROP_FONT_WEIGHT => [ + Dynamic_Selector::META_KEY => $heading_mod . '.fontWeight', + 'font' => 'mods_' . Config::MODS_FONT_HEADINGS, + ], + Config::CSS_PROP_TEXT_TRANSFORM => $heading_mod . '.textTransform', + Config::CSS_PROP_FONT_FAMILY => Config::MODS_FONT_HEADINGS, + ], + Dynamic_Selector::KEY_SELECTOR => $heading_selector, + Dynamic_Selector::KEY_CONTEXT => [ + Dynamic_Selector::CONTEXT_GUTENBERG => true, + ], + ]; + } } } diff --git a/inc/customizer/base_customizer.php b/inc/customizer/base_customizer.php index 3811bf4ac6..de586c05ba 100644 --- a/inc/customizer/base_customizer.php +++ b/inc/customizer/base_customizer.php @@ -14,6 +14,7 @@ use Neve\Customizer\Types\Panel; use Neve\Customizer\Types\Partial; use Neve\Customizer\Types\Section; +use HFG\Traits\Core; use WP_Customize_Manager; /** @@ -22,6 +23,8 @@ * @package Neve\Customizer\Abstracts */ abstract class Base_Customizer { + use Core; + /** * WP_Customize object * @@ -165,7 +168,7 @@ private function register_controls() { $new_control = $this->wpc->add_control( $control->id, $control->control_args ); $control_type = isset( $control->control_args['type'] ) ? $control->control_args['type'] : $new_control->type; } - if ( isset( $control->control_args['live_refresh_selector'] ) ) { + if ( isset( $control->control_args['live_refresh_selector'] ) && $control->control_args['live_refresh_selector'] !== false ) { $control_args = array( 'selector' => $control->control_args['live_refresh_selector'], 'id' => $control->id, @@ -323,4 +326,154 @@ public function change_customizer_object( $type, $id, $property, $value ) { $object->$property = $value; } + + /** + * Function to add controls that form the boxed layout. + * + * @param string $id Controls short id. + * @param array $settings Controls settings. + */ + public function add_boxed_layout_controls( $id, $settings ) { + $this->add_control( + new Control( + 'neve_' . $id . '_boxed_layout', + [ + 'sanitize_callback' => 'neve_sanitize_checkbox', + 'default' => array_key_exists( 'is_boxed_default', $settings ) ? $settings['is_boxed_default'] : false, + ], + [ + 'label' => esc_html__( 'Boxed layout', 'neve' ), + 'section' => $settings['section'], + 'type' => 'neve_toggle_control', + 'priority' => $settings['priority'], + 'active_callback' => array_key_exists( 'toggle_active_callback', $settings ) ? $settings['toggle_active_callback'] : '__return_true', + ], + 'Neve\Customizer\Controls\Checkbox' + ) + ); + + $padding_live_refresh_settings = [ + 'responsive' => true, + 'directional' => true, + 'template' => + $settings['boxed_selector'] . '{ + padding-top: {{value.top}}; + padding-right: {{value.right}}; + padding-bottom: {{value.bottom}}; + padding-left: {{value.left}}; + }', + ]; + + $background_live_refresh_settings = [ + 'template' => + $settings['boxed_selector'] . '{ + background-color: {{value}}; + }', + + ]; + + $has_text_color = isset( $settings['has_text_color'] ) ? $settings['has_text_color'] : true; + if ( $has_text_color ) { + $template = $settings['text_color_css_selector'] . '{ color: {{value}}; }'; + if ( array_key_exists( 'border_color_css_selector', $settings ) ) { + $template .= $settings['border_color_css_selector'] . '{ border-color: {{value}}; }'; + } + $color_live_refresh_settings = [ + 'template' => $template, + ]; + } + + if ( neve_is_new_skin() ) { + $padding_live_refresh_settings = [ + 'cssVar' => array( + 'vars' => '--padding', + 'selector' => $settings['boxed_selector'], + 'responsive' => true, + ), + ]; + + $background_live_refresh_settings = [ + 'cssVar' => array( + 'vars' => '--bgColor', + 'selector' => $settings['boxed_selector'], + ), + ]; + + if ( $has_text_color ) { + $color_live_refresh_settings = [ + 'cssVar' => array( + 'vars' => '--color', + 'selector' => $settings['boxed_selector'], + ), + ]; + } + } + + $this->add_control( + new Control( + 'neve_' . $id . '_boxed_padding', + [ + 'sanitize_callback' => [ $this, 'sanitize_spacing_array' ], + 'transport' => $this->selective_refresh, + 'default' => array_key_exists( 'padding_default', $settings ) ? $settings['padding_default'] : false, + ], + [ + 'label' => esc_html__( 'Section padding', 'neve' ), + 'section' => $settings['section'], + 'input_attrs' => [ + 'units' => [ 'em', 'px' ], + 'min' => 0, + ], + 'default' => array_key_exists( 'padding_default', $settings ) ? $settings['padding_default'] : false, + 'priority' => $settings['priority'], + 'live_refresh_selector' => true, + 'live_refresh_css_prop' => $padding_live_refresh_settings, + 'active_callback' => array_key_exists( 'active_callback', $settings ) ? $settings['active_callback'] : false, + ], + '\Neve\Customizer\Controls\React\Spacing' + ) + ); + + $this->add_control( + new Control( + 'neve_' . $id . '_boxed_background_color', + [ + 'sanitize_callback' => 'neve_sanitize_colors', + 'transport' => $this->selective_refresh, + 'default' => array_key_exists( 'background_default', $settings ) ? $settings['background_default'] : false, + ], + [ + 'label' => esc_html__( 'Background color', 'neve' ), + 'section' => $settings['section'], + 'priority' => $settings['priority'], + 'live_refresh_selector' => true, + 'live_refresh_css_prop' => $background_live_refresh_settings, + 'active_callback' => array_key_exists( 'active_callback', $settings ) ? $settings['active_callback'] : false, + ], + 'Neve\Customizer\Controls\React\Color' + ) + ); + + if ( $has_text_color ) { + $this->add_control( + new Control( + 'neve_' . $id . '_boxed_text_color', + [ + 'sanitize_callback' => 'neve_sanitize_colors', + 'transport' => $this->selective_refresh, + 'default' => array_key_exists( 'color_default', $settings ) ? $settings['color_default'] : false, + ], + [ + 'label' => esc_html__( 'Text color', 'neve' ), + 'section' => $settings['section'], + 'priority' => $settings['priority'], + 'live_refresh_selector' => true, + 'live_refresh_css_prop' => $color_live_refresh_settings, + 'active_callback' => array_key_exists( 'active_callback', $settings ) ? $settings['active_callback'] : false, + ], + 'Neve\Customizer\Controls\React\Color' + ) + ); + } + } } diff --git a/inc/customizer/controls/react/builder.php b/inc/customizer/controls/react/builder.php new file mode 100644 index 0000000000..c726129b61 --- /dev/null +++ b/inc/customizer/controls/react/builder.php @@ -0,0 +1,48 @@ +builder_type; + $json['columnsLayout'] = $this->columns_layout; + + return $json; + } +} diff --git a/inc/customizer/controls/react/builder_columns.php b/inc/customizer/controls/react/builder_columns.php new file mode 100644 index 0000000000..b805b96664 --- /dev/null +++ b/inc/customizer/controls/react/builder_columns.php @@ -0,0 +1,98 @@ +choices = [ + 1 => [ + 'equal' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + ], + 2 => [ + 'equal' => [ + 'url' => 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAA8AFsDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+6KT/AFkn++3/AKEa1MhlABQAUAFABQAUAFABQAUAFAHa6R/yD7f/ALa/+j5ah7jONk/1kn++3/oRqxDKACgAoAKACgAoAKACgAoAKAO10j/kH2//AG1/9Hy1D3GcbJ/rJP8Afb/0I1YhlABQAUAFABQAUAFABQAUAFAHa6R/yD7f/tr/AOj5ah7jODvbhreQ7bW5ud7yZ+zLCdm1hjf5s0P3t3y7d33WzjjNgU/7Rl/6BWp/98Wf/wAmUX8n+H+YfNfj/kH9oy/9ArU/++LP/wCTKL+T/D/MPmvx/wAg/tGX/oFan/3xZ/8AyZRfyf4f5h81+P8AkH9oy/8AQK1P/viz/wDkyi/k/wAP8w+a/H/IP7Rl/wCgVqf/AHxZ/wDyZRfyf4f5h81+P+Qf2jL/ANArU/8Aviz/APkyi/k/w/zD5r8f8g/tGX/oFan/AN8Wf/yZRfyf4f5h81+P+Qf2jL/0CtT/AO+LP/5Mov5P8P8AMPmvx/yD+0Zf+gVqf/fFn/8AJlF/J/h/mHzX4/5D4r6SSRUOnX8QY4Mkq2ojT3YpdO2P91WPtR8n+H+YfP8AP/I9F0j/AJB9v/21/wDR8tQ9wPBviL4v1LwodNbToLGY30t+JvtsVxIFFt9mKeX5FzbYz57792/OFxtwc/YcK5Dg88ljli6mJprDRw7p/V50oX9q6ylz+1o1r29nHlty2u730t85xBm+JylYR4eFCft3WU/bRqSt7NUuXl5KtO1+d3vfpa2t/Mv+Fw+Jv+fHQv8AwG1D/wCWdfYf6g5P/wBBOZ/+DsL/APMZ81/rhmf/AD4wP/grEf8AzUH/AAuHxN/z46F/4Dah/wDLOj/UHJ/+gnM//B2F/wDmMP8AXDM/+fGB/wDBWI/+ag/4XD4m/wCfHQv/AAG1D/5Z0f6g5P8A9BOZ/wDg7C//ADGH+uGZ/wDPjA/+CsR/81B/wuHxN/z46F/4Dah/8s6P9Qcn/wCgnM//AAdhf/mMP9cMz/58YH/wViP/AJqPU/BninUPEXh7UdWvYbOK5s7u7gjS1jnSBkt7G1uULrLcTyFjJO4YrIoKBQApBY/FcQ5LhcpzXCYHDVMROlXoUKs5V505VFKria9GSi6dKnFJRpxavBvmbbbVkvqcmzTEZjl+IxdeFGNSjWrU4xpRnGDVOhSqJyU6k5NuU2naSVrWSd2/LP8AhcPib/nx0L/wG1D/AOWdfa/6g5P/ANBOZ/8Ag7C//MZ8t/rhmf8Az4wP/grEf/NQf8Lh8Tf8+Ohf+A2of/LOj/UHJ/8AoJzP/wAHYX/5jD/XDM/+fGB/8FYj/wCag/4XD4m/58dC/wDAbUP/AJZ0f6g5P/0E5n/4Owv/AMxh/rhmf/PjA/8AgrEf/NQf8Lh8Tf8APjoX/gNqH/yzo/1Byf8A6Ccz/wDB2F/+Yw/1wzP/AJ8YH/wViP8A5qNvw58T9f1jXNM0y5tNHSC9uVhleC3vVmVSrEmNpNQlQNx1aNx7V52b8GZXgMtxmMo18fKrh6LqQjVq4d03JNK0lHCwk1r0lF+Z25bxPj8ZjsNhqtHBxp1qqhJ06dZTSab91yxEop6dYv0PqvSP+Qfb/wDbX/0fLX5g9z7s+XPjZ00D/rtq/wD7YV+l+Hnx5t/gwX54o+H40+HLv8WK/LDng1fpp8GFABQAUAfQnwu/5ErXP+wjqX/pp0+vynjT/kocu/7A8H/6nYo/Q+Fv+RLjf+wnE/8AqJhz57r9WPzwKACgAoA6rwP/AMjboP8A1/p/6A9eHxJ/yIsz/wCwWX/pUT1sj/5G+A/6/r/0mR95aR/yD7f/ALa/+j5a/A3ufrx81fF/TNS1L+xRp2n31+YZtUMwsrS4ujEJPsWwyeRHJs37H2bsbtrYztOP0LgXGYPBzzN4vF4bCqpHCez+sV6VDn5Xiebk9rKPNy80ea17XV90fHcW4XE4mOA+r4eviOSWJ5/Y0qlXl5lQ5ebkjLlvZ2va9nbZnin/AAi/ib/oXdd/8FGof/I9fof9tZP/ANDbLP8Awvwv/wAtPi/7LzP/AKF2O/8ACTEf/Kw/4RfxN/0Luu/+CjUP/kej+2sn/wChtln/AIX4X/5aH9l5n/0Lsd/4SYj/AOVh/wAIv4m/6F3Xf/BRqH/yPR/bWT/9DbLP/C/C/wDy0P7LzP8A6F2O/wDCTEf/ACsP+EX8Tf8AQu67/wCCjUP/AJHo/trJ/wDobZZ/4X4X/wCWh/ZeZ/8AQux3/hJiP/lZ7r8ONO1Cx8I6xbXtjeWdzLf6g8dvdWs9vPIj6ZYxo6RSokjq8iOisqkM6soJKkD804uxeFxOe4CthsTh8RShhcLGdWhWp1acJRxmJlKMp05SjFxjKMmm01GSb0aPuuG8PiKGUYynXoVqNSWIxEo06tKdOclLDUIpxhOKk05JxTSs2mlqmeFf8Iv4m/6F3Xf/AAUah/8AI9fpf9tZP/0Nss/8L8L/APLT4X+y8z/6F2O/8JMR/wDKw/4RfxN/0Luu/wDgo1D/AOR6P7ayf/obZZ/4X4X/AOWh/ZeZ/wDQux3/AISYj/5WH/CL+Jv+hd13/wAFGof/ACPR/bWT/wDQ2yz/AML8L/8ALQ/svM/+hdjv/CTEf/Kw/wCEX8Tf9C7rv/go1D/5Ho/trJ/+htln/hfhf/lof2Xmf/Qux3/hJiP/AJWdN4O8Pa/a+KNFuLnQ9Yt4Ir1Hlnn029hhjUK+WkkkhVEXnqzAe9ePxBmuV1smzGlRzLAVas8PKMKdLGYepUnLmjpGEajlJ+STZ6eTZfj6WaYKpVwOMp04Vk5TqYatCEVZ6ylKCil5to+2tI/5B9v/ANtf/R8tfiT3P1I42T/WSf77f+hGrEMoAKACgAoAKACgAoAKACgAoA7XSP8AkH2//bX/ANHy1D3GAP/Z', + ], + 'right-third' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'left-third' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + ], + 3 => [ + 'equal' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'left-half' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'right-half' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'center-half' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'center-two-thirds' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + ], + 4 => [ + 'equal' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'left-half' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + 'right-half' => [ + 'url' => 'data:image/jpeg;base64,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', + ], + ], + 5 => [ + 'equal' => [ + 'url' => 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAA8AFsDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+6KT/AFkn++3/AKEa1MhlABQAUAFABQAUAFABQAUAFAHa6R/yD7f/ALa/+j5ah7jONk/1kn++3/oRqxDKACgAoAKACgAoAKACgAoAKAO10j/kH2//AG1/9Hy1D3GcbJ/rJP8Afb/0I1YhlABQAUAFABQAUAFABQAUAFAHa6R/yD7f/tr/AOj5ah7jODvbhreQ7bW5ud7yZ+zLCdm1hjf5s0P3t3y7d33WzjjNgU/7Rl/6BWp/98Wf/wAmUX8n+H+YfNfj/kH9oy/9ArU/++LP/wCTKL+T/D/MPmvx/wAg/tGX/oFan/3xZ/8AyZRfyf4f5h81+P8AkH9oy/8AQK1P/viz/wDkyi/k/wAP8w+a/H/IP7Rl/wCgVqf/AHxZ/wDyZRfyf4f5h81+P+Qf2jL/ANArU/8Aviz/APkyi/k/w/zD5r8f8g/tGX/oFan/AN8Wf/yZRfyf4f5h81+P+Qf2jL/0CtT/AO+LP/5Mov5P8P8AMPmvx/yD+0Zf+gVqf/fFn/8AJlF/J/h/mHzX4/5D4r6SSRUOnX8QY4Mkq2ojT3YpdO2P91WPtR8n+H+YfP8AP/I9F0j/AJB9v/21/wDR8tQ9wPBviL4v1LwodNbToLGY30t+JvtsVxIFFt9mKeX5FzbYz57792/OFxtwc/YcK5Dg88ljli6mJprDRw7p/V50oX9q6ylz+1o1r29nHlty2u730t85xBm+JylYR4eFCft3WU/bRqSt7NUuXl5KtO1+d3vfpa2t/Mv+Fw+Jv+fHQv8AwG1D/wCWdfYf6g5P/wBBOZ/+DsL/APMZ81/rhmf/AD4wP/grEf8AzUdpc+PtYh8D6f4lW200393qj2MkTQ3RtFiU3wDJGLwTCT/Ro8lp2Xl/k5G356jwvgKnEmKyd1sYsNQwUcTCaqUfbubWHbUpPDum4fvpaKknpH3tHf2amf4yGR4fM1Tw3t6uKlQlBwq+xUE6+sY+2U1L93HV1GtXptbi/wDhcPib/nx0L/wG1D/5Z19D/qDk/wD0E5n/AODsL/8AMZ43+uGZ/wDPjA/+CsR/81HaaV4+1i+8JeINemttMW80qeCO3jjhuhbOsrW4YzI148rECVsbJoxwuQcHPz2O4Xy/DZ7leV062MeHx1OpOrOdSi60XBVWvZyWHjBL92r81Oe71WlvZwmf4yvlGYY+dPDKthJwjTjGFVUpKTpp86dZyb9925Zx6fPi/wDhcPib/nx0L/wG1D/5Z19D/qDk/wD0E5n/AODsL/8AMZ43+uGZ/wDPjA/+CsR/81HaeE/H2sa9beIZry20yNtJ0qS+thbQ3SK8qRzsFnEt5MWjzEuRGY2wT844x89nvC+X5ZWymnQrYyax2NjhqzrVKMnGDlSi3T5MPTSnab1kprb3d7+zlOf4zH08xnWp4aLwmFlXp+zhVSlNRqO0+atO8fdWkXF76nF/8Lh8Tf8APjoX/gNqH/yzr6H/AFByf/oJzP8A8HYX/wCYzxv9cMz/AOfGB/8ABWI/+ajrfBXxD1rxJrsemX1rpcUD21xMXtIbtJt0KhlAaa9nTaSfmHlknsRXhcRcKZdlGWzxmGrY2dWNalTUa9ShKnapJptqnhqUrrp71u6Z62ScQ43MsdHDV6WFhTdOpO9KFWM7wSa1nXqRt3935o5m5+LniSG5uIVstDKxTyxqWtr8sVSRlBYjUgCSBzgAZ6AV7NHgTKKlKlUeJzJOdOE2lWwtryim7XwbdrvS7fqeZV4uzKFSpBUMDaE5xV6de9oyaV/9pWumuiNTw58T9f1jXNM0y5tNHSC9uVhleC3vVmVSrEmNpNQlQNx1aNx7VxZvwZleAy3GYyjXx8quHoupCNWrh3Tck0rSUcLCTWvSUX5nVlvE+PxmOw2Gq0cHGnWqqEnTp1lNJpv3XLESinp1i/Q+q9I/5B9v/wBtf/R8tfmD3Puz5c+NnTQP+u2r/wDthX6X4efHm3+DBfnij4fjT4cu/wAWK/LDng1fpp8Gep33/JJtF/7GCX/0LVq+Jw3/ACXOYf8AYqh/6TgT6qv/AMkng/8AsYS/PFnllfbHyp6l4d/5Jv4z/wCvqz/9GWVfFZt/yV/D/wD14r/+k4k+qy7/AJJvOf8Ar7S/OgeW19qfKnqXw4/48fGv/YvTf+ibuviuLv8AeeHP+xrT/wDTmHPquG/4Gd/9i+f/AKRWPLa+1PlT0f4Vf8jdB/1433/ota+R43/5EVT/ALCcN/6Uz6ThX/kbw/68V/8A0lHBX/8Ax/Xn/X3cf+jnr6fDf7th/wDrxS/9NxPBr/x63/X2p/6WzoPA/wDyNug/9f6f+gPXlcSf8iLM/wDsFl/6VE9DI/8Akb4D/r+v/SZH3lpH/IPt/wDtr/6Plr8De5+vHzV8X9M1LUv7FGnaffX5hm1QzCytLi6MQk+xbDJ5EcmzfsfZuxu2tjO04/QuBcZg8HPM3i8XhsKqkcJ7P6xXpUOfleJ5uT2so83LzR5rXtdX3R8dxbhcTiY4D6vh6+I5JYnn9jSqVeXmVDl5uSMuW9na9r2dtmeKf8Iv4m/6F3Xf/BRqH/yPX6H/AG1k/wD0Nss/8L8L/wDLT4v+y8z/AOhdjv8AwkxH/wArPSb3RdYf4Y6TYLpOpNfx65JNJZLYXRu44i2p4le2EXnJGfMjw7IF+dOfmGfkMPmGAjxljsU8dg1hp5bCnDEPE0VQlNLB3hGs5+zlP3Ze6pN+7LTRn0lbBYx8MYTDrCYl1446U5UFQqutGF8T70qfJzqPvR95xt7y11R5t/wi/ib/AKF3Xf8AwUah/wDI9fX/ANtZP/0Nss/8L8L/APLT5v8AsvM/+hdjv/CTEf8Ays9I0HRdYh8AeLbKbSdTivLm5tWt7SSwukuZ1V7Qs0MDRCWUKFYkorAbWz0NfI5nmOX1OKcjxFPHYOeHo0ayq14YmjKjSbjXsqlVTcIN3VlKSvdd0fSYDBYyHD+bUZ4TExrVKtJ06UqFWNWok6N3Cm4KUkrO7inaz7Hm/wDwi/ib/oXdd/8ABRqH/wAj19d/bWT/APQ2yz/wvwv/AMtPm/7LzP8A6F2O/wDCTEf/ACs9I8A6LrFnZ+L1vNJ1O1a50KWG2W5sLqBriUxXQEUAliUyyEsoCR7mJYDHIr5HijMcvxGIyGVDHYOuqOZQqVnRxNGqqUFOg3Oo4TkoQSTfNKy0eujPpMgwWMo0c3VbCYmk6uBlCmqlCrB1J8lVcsFKC55ar3Y3eq01PN/+EX8Tf9C7rv8A4KNQ/wDkevrv7ayf/obZZ/4X4X/5afN/2Xmf/Qux3/hJiP8A5Wd/8NdD1qw8UQ3F9pGqWcAs7xTPd6fd28IZkUKpkmiRAzHhRuye1fL8YZll2JyWpSw2PwWIqvEYeSp0MVQq1Goyd2oU6kpWXV2sup7/AA1gcbQzSFSvg8VRpqjWXPVw9WnC7SsuacFG76K+pxV74Z8SPeXbL4f1xla5nZWXSb8qymVyGUi3IIIOQRwRyK+iw+c5RGhQTzXLU1Rppp47CppqEU006t009GnseJWyzMnWqtZfjmnVqNNYSu005uzT9nqn0ZueDvD2v2vijRbi50PWLeCK9R5Z59NvYYY1CvlpJJIVRF56swHvXm8QZrldbJsxpUcywFWrPDyjCnSxmHqVJy5o6RhGo5Sfkk2d+TZfj6WaYKpVwOMp04Vk5TqYatCEVZ6ylKCil5to+2tI/wCQfb/9tf8A0fLX4k9z9SONk/1kn++3/oRqxDKACgAoAKACgAoAKACgAoAKAO10j/kH2/8A21/9Hy1D3GD/2Q==', + ], + ], + ]; + + $this->json['choices'] = $this->choices; + $this->json['columnsControl'] = $this->columns_control; + } +} diff --git a/inc/customizer/controls/react/builder_section.php b/inc/customizer/controls/react/builder_section.php new file mode 100644 index 0000000000..190acf60b0 --- /dev/null +++ b/inc/customizer/controls/react/builder_section.php @@ -0,0 +1,58 @@ + '', + 'builder_type' => '', + // 'quickLinks' => [], + ]; + + /** + * Options passed to section. + * + * @var array + */ + public $options = []; + + + /** + * Gather the parameters passed to client JavaScript via JSON. + * + * @return array The array to be exported to the client as JSON. + */ + public function json() { + $json = parent::json(); + $json['options'] = wp_parse_args( $this->options, $this->default_options ); + + return $json; + } +} + + diff --git a/inc/customizer/controls/react/button_appearance.php b/inc/customizer/controls/react/button_appearance.php index 54eeb58f53..dd5324fa14 100644 --- a/inc/customizer/controls/react/button_appearance.php +++ b/inc/customizer/controls/react/button_appearance.php @@ -25,12 +25,19 @@ class Button_Appearance extends \WP_Customize_Control { * @var array */ public $no_hover = false; + /** + * Default values. + * + * @var array + */ + public $default_vals = []; /** * Send to JS. */ public function to_json() { parent::to_json(); - $this->json['no_hover'] = $this->no_hover; + $this->json['no_hover'] = $this->no_hover; + $this->json['defaultVals'] = $this->default_vals; } } diff --git a/inc/customizer/controls/react/heading.php b/inc/customizer/controls/react/heading.php new file mode 100644 index 0000000000..59462dd920 --- /dev/null +++ b/inc/customizer/controls/react/heading.php @@ -0,0 +1,112 @@ +class; + $json['accordion'] = $this->accordion; + $json['categoryLabel'] = $this->category_label; + + if ( $this->accordion === true ) { + $json['classes'] .= ' accordion'; + } + + $json['style'] = $this->print_style(); + + return $json; + } + + /** + * Render the control. + */ + protected function render() { + $id = 'customize-control-' . str_replace( array( '[', ']' ), array( '-', '' ), $this->id ); + $class = 'customize-control customize-control-' . $this->type; + $class .= ' ' . $this->class; + if ( $this->accordion ) { + $class .= ' accordion'; + } + + if ( $this->expanded ) { + $class .= ' expanded'; + } + + echo '
  • '; + echo '
  • '; + } + + /** + * Print the style for the accordion. + */ + protected function print_style() { + $style = ''; + for ( $i = 1; $i <= $this->controls_to_wrap; $i ++ ) { + $style .= '.accordion.' . $this->class . ':not(.expanded)'; + for ( $j = 1; $j <= $i; $j ++ ) { + $style .= ' + li'; + } + if ( $i !== $this->controls_to_wrap ) { + $style .= ','; + } + } + $style .= '{max-height: 0;opacity: 0;margin: 0; overflow: hidden; padding:0 !important;}'; + + return $style; + } +} diff --git a/inc/customizer/controls/react/inline_select.php b/inc/customizer/controls/react/inline_select.php index 1cb6f614d6..7a04ae300a 100644 --- a/inc/customizer/controls/react/inline_select.php +++ b/inc/customizer/controls/react/inline_select.php @@ -41,6 +41,12 @@ class Inline_Select extends \WP_Customize_Control { */ public $link; + /** + * Allows listening to other components. + * + * @var string + */ + public $changes_on; /** * Send to JS. */ @@ -49,5 +55,6 @@ public function to_json() { $this->json['options'] = $this->options; $this->json['defaultVal'] = $this->default; $this->json['link'] = $this->link; + $this->json['changesOn'] = $this->changes_on; } } diff --git a/inc/customizer/controls/react/instructions_control.php b/inc/customizer/controls/react/instructions_control.php new file mode 100644 index 0000000000..ba55c45b95 --- /dev/null +++ b/inc/customizer/controls/react/instructions_control.php @@ -0,0 +1,61 @@ + '', + 'image' => '', + 'quickLinks' => [], + ]; + + /** + * Options passed to control. + * + * @var array + */ + public $options = []; + + + + /** + * Gather the parameters passed to client JavaScript via JSON. + * + * @since 4.1.0 + * + * @return array The array to be exported to the client as JSON. + */ + public function json() { + $json = parent::json(); + $json['options'] = wp_parse_args( $this->options, $this->default_options ); + + return $json; + } +} + + diff --git a/header-footer-grid/Core/Customizer/Instructions_Section.php b/inc/customizer/controls/react/instructions_section.php similarity index 51% rename from header-footer-grid/Core/Customizer/Instructions_Section.php rename to inc/customizer/controls/react/instructions_section.php index 1154b4c958..04fc730488 100644 --- a/header-footer-grid/Core/Customizer/Instructions_Section.php +++ b/inc/customizer/controls/react/instructions_section.php @@ -5,8 +5,7 @@ * * @package Neve */ - -namespace HFG\Core\Customizer; +namespace Neve\Customizer\Controls\React; /** * Customizer section. @@ -17,7 +16,6 @@ * @see WP_Customize_Section */ class Instructions_Section extends \WP_Customize_Section { - /** * Type of this section. * @@ -30,71 +28,38 @@ class Instructions_Section extends \WP_Customize_Section { * @var array */ public $default_options = [ - 'description' => '', - 'image' => '', - 'quickLinks' => [], + 'description' => '', + 'image' => '', + 'quickLinks' => [], + 'hadOldBuilder' => false, + 'builderMigrated' => false, ]; - /** * Options passed to control. * * @var array */ public $options = []; - - /** * Gather the parameters passed to client JavaScript via JSON. * - * @since 4.1.0 - * * @return array The array to be exported to the client as JSON. + * @since 4.1.0 */ public function json() { $json = parent::json(); $json['options'] = wp_parse_args( $this->options, $this->default_options ); - return $json; } - - /** * Render template. */ protected function render_template() { ?>
  • - - <# if( data.options.description ) { #> -

    {{data.options.description}}

    - <# } #> -
    - <# if( data.options.quickLinks ) { #> - - <# } #> - - <# if( data.options.image ) { #> -
    - -
    - <# } #> + data-slug="{{data.id}}" + class="control-section control-section-{{ data.type }} neve-quick-links">
  • json['presets'] = $this->presets; + $this->json['builder'] = $this->builder; } } diff --git a/inc/customizer/controls/react/radio_image.php b/inc/customizer/controls/react/radio_image.php index e7c41b9272..21304a44b8 100644 --- a/inc/customizer/controls/react/radio_image.php +++ b/inc/customizer/controls/react/radio_image.php @@ -25,11 +25,18 @@ class Radio_Image extends \WP_Customize_Control { * @var array */ public $choices = []; + /** + * Additional arguments passed to JS. + * + * @var array + */ + public $documentation = []; /** * Send to JS. */ public function to_json() { parent::to_json(); - $this->json['choices'] = $this->choices; + $this->json['choices'] = $this->choices; + $this->json['documentation'] = $this->documentation; } } diff --git a/inc/customizer/controls/react/src/.eslintrc b/inc/customizer/controls/react/src/.eslintrc new file mode 100644 index 0000000000..b577443159 --- /dev/null +++ b/inc/customizer/controls/react/src/.eslintrc @@ -0,0 +1,42 @@ +{ + "root": true, + "extends": [ + "plugin:@wordpress/eslint-plugin/recommended" + ], + "ignorePatterns": [ + "**/vendor/**" + ], + "rules": { + "@wordpress/no-global-event-listener": "off" + }, + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx" + ], + "extends": [ + "plugin:@wordpress/eslint-plugin/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/typescript" + ], + "rules": { + "@typescript-eslint/ban-ts-comment": "off", + "@wordpress/no-global-event-listener": "off" + }, + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [ + ".ts", + ".tsx" + ] + }, + "import/resolver": { + "typescript": { + "alwaysTryTypes": true + } + } + } + } + ] +} diff --git a/inc/customizer/controls/react/src/@types/classnames.d.ts b/inc/customizer/controls/react/src/@types/classnames.d.ts new file mode 100644 index 0000000000..c5f9b4742e --- /dev/null +++ b/inc/customizer/controls/react/src/@types/classnames.d.ts @@ -0,0 +1 @@ +declare module 'classnames'; diff --git a/inc/customizer/controls/react/src/@types/customizer-control.d.ts b/inc/customizer/controls/react/src/@types/customizer-control.d.ts new file mode 100644 index 0000000000..af72a35b88 --- /dev/null +++ b/inc/customizer/controls/react/src/@types/customizer-control.d.ts @@ -0,0 +1,16 @@ +import { StringObjectKeys } from './utils'; +type WPCustomizeControlSetting = { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + set: (value: any) => void; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + get: () => any; + // eslint-disable-next-line no-undef + bind: (value: unknown) => void; +}; + +export type WPCustomizeControl = { + active: () => boolean; + id: string; + setting: WPCustomizeControlSetting; + params: StringObjectKeys; +}; diff --git a/inc/customizer/controls/react/src/@types/utils.d.ts b/inc/customizer/controls/react/src/@types/utils.d.ts new file mode 100644 index 0000000000..e4885bbd77 --- /dev/null +++ b/inc/customizer/controls/react/src/@types/utils.d.ts @@ -0,0 +1,119 @@ +import { ItemInterface } from 'react-sortablejs'; +import { Dispatch, SetStateAction } from 'react'; + +interface StringObjectKeys { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + [key: string]: any; +} + +export type RowTypes = 'top' | 'main' | 'bottom' | 'sidebar'; +export type SlotTypes = + | 'left' + | 'c-left' + | 'center' + | 'c-right' + | 'right' + | 'sidebar'; + +export type DeviceTypes = string & (keyof BuilderContentInterface | 'tablet'); + +export type BuilderItemType = { + height?: number; + id: string; + width?: number; + x?: number; + y?: number; +}; + +export interface BuilderRowInterface extends StringObjectKeys { + left: BuilderItemType[]; + 'c-left': BuilderItemType[]; + center: BuilderItemType[]; + 'c-right': BuilderItemType[]; + right: BuilderItemType[]; +} + +export interface BuilderRowsInterface extends StringObjectKeys { + top: BuilderRowInterface; + main: BuilderRowInterface; + bottom: BuilderRowInterface; + sidebar?: BuilderItemType[]; +} + +export interface BuilderContentInterface extends StringObjectKeys { + desktop: BuilderRowsInterface; + mobile?: BuilderRowsInterface; +} + +type HFGLayoutBuilderComponentProps = { + componentSlug: string; + description: string | null; + elementOrder: number; + icon: string; + id: string; + name: string; + previewImage: string | null; + section: string; + width: number; +}; + +type HFGLayoutBuilderRowProps = { + description: string; + title: string; +}; + +type HFGLayoutBuilderProps = { + // eslint-disable-next-line camelcase + control_id: string; + devices: { desktop: 'Desktop'; mobile?: 'Mobile' }; + id: string; + items: { + [componentId: string]: HFGLayoutBuilderComponentProps; + }; + panel: string; + rows: { + [rowId: string]: HFGLayoutBuilderRowProps; + }; + section: string; + title: string; +}; + +type HFGLayoutBuilder = { + [key: string]: HFGLayoutBuilderProps; +}; + +type LayoutUpdate = ( + rowId: string, + slotId: string, + nextItems: BuilderItemType[] +) => void; + +type RemoveItem = (rowId: string, slotId: string, itemIndex: number) => void; + +type BuilderActions = { + updateLayout: LayoutUpdate; + onDragStart: () => void; + onDragEnd: () => void; + removeItem: RemoveItem; + setDevice: Dispatch>; + setSidebarItems: (value: ItemInterface[]) => void; + togglePreviewSidebar: (value: boolean) => void; +}; + +declare global { + interface Window { + wp: StringObjectKeys; + NeveReactCustomize: { + HFG: HFGLayoutBuilder; + instructionalVid: string; + nonce: string; + hideConditionalHeaderSelector: boolean; + dashUpdatesMessage: string; + }; + NeveProReactCustomize: undefined | StringObjectKeys; + } +} + +interface BuilderChangeEvent extends Event { + detail?: { id: string; value: string | BuilderContentInterface }; +} diff --git a/inc/customizer/controls/react/src/background/Background.js b/inc/customizer/controls/react/src/background/Background.js index 7cd791cdcc..7a22040da8 100644 --- a/inc/customizer/controls/react/src/background/Background.js +++ b/inc/customizer/controls/react/src/background/Background.js @@ -194,8 +194,8 @@ Background.propTypes = { type: PropTypes.string, imageUrl: PropTypes.string, focusPoint: PropTypes.shape({ - x: PropTypes.number, - y: PropTypes.number, + x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + y: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), }), colorValue: PropTypes.string, overlayColorValue: PropTypes.string, diff --git a/inc/customizer/controls/react/src/background/BackgroundComponent.js b/inc/customizer/controls/react/src/background/BackgroundComponent.js index 23684a97ae..ea19530613 100644 --- a/inc/customizer/controls/react/src/background/BackgroundComponent.js +++ b/inc/customizer/controls/react/src/background/BackgroundComponent.js @@ -27,7 +27,7 @@ const BackgroundComponent = ({ control }) => { }; useEffect(() => { - global.addEventListener('neve-changed-customizer-value', (e) => { + document.addEventListener('neve-changed-customizer-value', (e) => { if (!e.detail) return false; if (e.detail.id !== control.id) return false; updateValue(e.detail.value); diff --git a/inc/customizer/controls/react/src/builder-columns/BuilderColumns.tsx b/inc/customizer/controls/react/src/builder-columns/BuilderColumns.tsx new file mode 100644 index 0000000000..4222bf5f62 --- /dev/null +++ b/inc/customizer/controls/react/src/builder-columns/BuilderColumns.tsx @@ -0,0 +1,31 @@ +/* jshint esversion: 6 */ +import React from 'react'; +// @ts-ignore +import RadioImage from '../radio-image/RadioImage'; + +type Props = { + label: string; + value: string; + onChange: (val: string) => void; + columns: number; + choices: Record>; +}; + +const BuilderColumns: React.FC = (props) => { + const { label, value, onChange, columns, choices } = props; + + const visibleChoices = choices[columns]; + + return ( +
    + {label && {label}} + +
    + ); +}; + +export default BuilderColumns; diff --git a/inc/customizer/controls/react/src/builder-columns/BuilderColumnsComponent.tsx b/inc/customizer/controls/react/src/builder-columns/BuilderColumnsComponent.tsx new file mode 100644 index 0000000000..4e0cad49b8 --- /dev/null +++ b/inc/customizer/controls/react/src/builder-columns/BuilderColumnsComponent.tsx @@ -0,0 +1,63 @@ +/* jshint esversion: 6 */ +import React from 'react'; +import { useEffect, useState } from '@wordpress/element'; +import { WPCustomizeControl } from '../@types/customizer-control'; +import BuilderColumns from './BuilderColumns'; + +type Props = { + control: WPCustomizeControl; +}; + +const BuilderColumnsComponent: React.FC = ({ control }) => { + const { setting, params } = control; + const { label, choices, columnsControl } = params; + const [value, setValue] = useState(setting.get()); + const [columnsNo, setColumnsNo] = useState(1); + + const onChange = (nextValue: string) => { + setValue(nextValue); + control.setting.set(nextValue); + }; + + useEffect(() => { + window.wp.customize.bind('ready', () => { + const colNumber = window.wp.customize + .control(columnsControl) + .setting.get(); + setColumnsNo(parseInt(colNumber)); + }); + + window.wp.customize.control( + columnsControl, + (customizeControl: WPCustomizeControl) => { + customizeControl.setting.bind((nextColNumber: string) => { + const colNumberInt = parseInt(nextColNumber); + const currentValue = setting.get(); + if ( + !Object.keys(choices[colNumberInt]).includes( + currentValue + ) + ) { + const firstValue = Object.keys( + choices[colNumberInt] + )[0]; + onChange(firstValue); + } + setColumnsNo(colNumberInt); + }); + } + ); + }); + + return ( + + ); +}; + +export default BuilderColumnsComponent; diff --git a/inc/customizer/controls/react/src/builder-columns/Control.js b/inc/customizer/controls/react/src/builder-columns/Control.js new file mode 100644 index 0000000000..3ffb6326d8 --- /dev/null +++ b/inc/customizer/controls/react/src/builder-columns/Control.js @@ -0,0 +1,10 @@ +/* jshint esversion: 6 */ +import BuilderColumnsComponent from './BuilderColumnsComponent.tsx'; +import { render } from '@wordpress/element'; +import React from 'react'; + +export const BuilderColumns = wp.customize.Control.extend({ + renderContent() { + render(, this.container[0]); + }, +}); diff --git a/inc/customizer/controls/react/src/builder-instructions/Control.js b/inc/customizer/controls/react/src/builder-instructions/Control.js new file mode 100644 index 0000000000..43327b2b8e --- /dev/null +++ b/inc/customizer/controls/react/src/builder-instructions/Control.js @@ -0,0 +1,9 @@ +/* jshint esversion: 6 */ +import { render } from '@wordpress/element'; +import Instructions from './Instructions.tsx'; + +export const InstructionsControl = wp.customize.Control.extend({ + renderContent() { + render(, this.container[0]); + }, +}); diff --git a/inc/customizer/controls/react/src/builder-instructions/HFGMigrationNotice.tsx b/inc/customizer/controls/react/src/builder-instructions/HFGMigrationNotice.tsx new file mode 100644 index 0000000000..7c1ccf9d79 --- /dev/null +++ b/inc/customizer/controls/react/src/builder-instructions/HFGMigrationNotice.tsx @@ -0,0 +1,211 @@ +import React from 'react'; +import { __ } from '@wordpress/i18n'; +import apiFetch from '@wordpress/api-fetch'; +import { + cancelCircleFilled, + rotateRight, + starFilled, + undo, +} from '@wordpress/icons'; +import { Button } from '@wordpress/components'; +import { useState, useEffect } from '@wordpress/element'; +import { StringObjectKeys } from '../@types/utils'; + +interface MigrationResponse { + success: boolean; +} + +type Props = { + alreadyMigrated: boolean; + hadOldBuilder: boolean; +}; + +export const HFGMigrationNotice: React.FC = ({ + alreadyMigrated, + hadOldBuilder, +}) => { + const [error, setError] = useState(false); + const [isCustomizerSaved, setCustomizerSaved] = useState(true); + + useEffect(() => { + if (alreadyMigrated && !hadOldBuilder) { + return; + } + window.wp.customize.bind('ready', () => { + window.wp.customize.state('saved').bind((status: boolean) => { + setCustomizerSaved(status); + }); + }); + }, []); + + if (typeof window.NeveProReactCustomize !== 'undefined') { + const { whiteLabel } = window.NeveProReactCustomize; + + if (whiteLabel) { + return null; + } + } + + if (!hadOldBuilder) { + return null; + } + + const { nonce } = window.NeveReactCustomize; + + const getReloadUrl = () => { + const location = window.location.href; + const currentPanel = window.wp.customize.state('expandedPanel').get(); + + if (!currentPanel) return location; + + const panelId = currentPanel.id; + + if (!panelId) return location; + + const url = new URL(location); + + url.searchParams.set('autofocus[panel]', panelId); + + return url.href; + }; + + const runMigration = (rollback = false, dismiss = false) => { + let message = __('Migrating builder data', 'neve'); + + if (rollback) { + message = __('Rolling back builder', 'neve'); + } + + if (dismiss) { + message = __('Removing old data', 'neve'); + } + + window.wp.customize.notifications.add( + new window.wp.customize.OverlayNotification( + 'neve_migrating_builders', + { + message: message + '...', + type: 'success', + loading: true, + } + ) + ); + + const headers: StringObjectKeys = { 'X-WP-Nonce': nonce }; + if (rollback) { + headers.rollback = 'yes'; + } + + if (dismiss) { + headers.dismiss = 'yes'; + } + + apiFetch({ + path: '/nv/migration/new_header_builder', + method: 'GET', + headers, + }).then((response: unknown) => { + if (!(response as MigrationResponse).success) { + window.wp.customize.notifications.remove( + 'neve_migrating_builders' + ); + setError(true); + return false; + } + reloadPage(); + }); + }; + + const reloadPage = () => { + const url = getReloadUrl(); + if (window.location.href === url) { + window.location.reload(); + return false; + } + window.location.href = url; + }; + + const renderErrors = () => { + return ( + <> + {!isCustomizerSaved && !error && ( +

    + {__( + 'You must save the current customizer values before running the migration.', + 'neve' + )} +

    + )} + + {error && ( +

    + {__( + 'Something went wrong. Please reload the page and try again.', + 'neve' + )} +

    + )} + + ); + }; + + if (alreadyMigrated && hadOldBuilder) { + return ( + <> +
    +

    {__('Want to roll back to the old builder?', 'neve')}

    + + + {renderErrors()} + + ); + } + + return ( + <> +
    +

    + {__( + "We've created a new Header/Footer Builder experience! You can always roll back to the old builder from right here.", + 'neve' + )} +

    +

    + + {__('Some manual adjustments may be required.', 'neve')} + +

    + + {renderErrors()} + + ); +}; diff --git a/inc/customizer/controls/react/src/builder-instructions/Instructions.tsx b/inc/customizer/controls/react/src/builder-instructions/Instructions.tsx new file mode 100644 index 0000000000..6b7aaf9d02 --- /dev/null +++ b/inc/customizer/controls/react/src/builder-instructions/Instructions.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { __ } from '@wordpress/i18n'; +import { Button } from '@wordpress/components'; +import { WPCustomizeControl } from '../@types/customizer-control'; +import { HFGMigrationNotice } from './HFGMigrationNotice'; + +type Props = { + control: WPCustomizeControl; +}; + +const Instructions: React.FC = ({ control }) => { + const { params, id } = control; + const { options } = params; + const { description, quickLinks, builderMigrated, hadOldBuilder } = options; + + const linkKeys = Object.keys(quickLinks); + + const expandEventHeaders = (slug: string): void => { + const { type } = window.wp.customize.control(slug).params; + if (type === 'neve_customizer_heading') { + window.wp.customize.control(slug).triggerExpandHeader(); + } + }; + + const focusControl = (slug: string): void => { + if (slug === 'toggle_sidebar') { + window.wp.customize.previewer.send('header_sidebar_open'); + return; + } + window.wp.customize.control(slug).focus({ + completeCallback: () => { + expandEventHeaders(slug); + }, + }); + }; + + return ( +
    + {description &&

    {description}

    } +
    + {linkKeys.length && ( +
    + + {__('Quick Links', 'neve')} + +
      + {linkKeys.map((settingSlug, index) => { + const { label, icon } = quickLinks[settingSlug]; + return ( +
    • + +
    • + ); + })} +
    + {id === 'hfg_header_layout_section_quick_links' && ( + + )} +
    + )} +
    + ); +}; + +export default Instructions; diff --git a/inc/customizer/controls/react/src/builder-instructions/Section.js b/inc/customizer/controls/react/src/builder-instructions/Section.js new file mode 100644 index 0000000000..b2f1a3ecac --- /dev/null +++ b/inc/customizer/controls/react/src/builder-instructions/Section.js @@ -0,0 +1,6 @@ +export const InstructionsSection = wp.customize.Section.extend({ + // No events for this type of section. + attachEvents: () => null, + // Always make the section active. + isContextuallyActive: () => true, +}); diff --git a/inc/customizer/controls/react/src/builder/BuilderContext.tsx b/inc/customizer/controls/react/src/builder/BuilderContext.tsx new file mode 100644 index 0000000000..93639da6f5 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/BuilderContext.tsx @@ -0,0 +1,18 @@ +import { createContext } from '@wordpress/element'; +import { BuilderActions, DeviceTypes } from '../@types/utils'; +import { ItemInterface } from 'react-sortablejs'; + +type BuilderContext = { + actions: BuilderActions; + sidebarItems: ItemInterface[]; + builder: string; + currentSection: string; + dragging: boolean; + hasColumns: boolean; + device: DeviceTypes; + previewSidebar: boolean; +}; + +const BuilderContext = createContext({} as BuilderContext); + +export default BuilderContext; diff --git a/inc/customizer/controls/react/src/builder/Control.js b/inc/customizer/controls/react/src/builder/Control.js new file mode 100644 index 0000000000..d9a7c644a6 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/Control.js @@ -0,0 +1,28 @@ +/* jshint esversion: 6 */ +import HFGBuilderComponent from './HFGBuilderComponent.tsx'; +import { render } from '@wordpress/element'; +import React from 'react'; + +export const BuilderControl = wp.customize.Control.extend({ + renderContent() { + const customizePreview = document.getElementById('customize-controls'); + const where = document.querySelector( + `#accordion-section-${this.params.section}` + ); + + const builderPortalMount = document.createElement('div'); + builderPortalMount.classList.add( + 'neve-builder-portal-wrap', + 'neve-hfg-builder' + ); + customizePreview.appendChild(builderPortalMount); + + render( + , + where + ); + }, +}); diff --git a/inc/customizer/controls/react/src/builder/HFGBuilder.tsx b/inc/customizer/controls/react/src/builder/HFGBuilder.tsx new file mode 100644 index 0000000000..9ca22cb94f --- /dev/null +++ b/inc/customizer/controls/react/src/builder/HFGBuilder.tsx @@ -0,0 +1,304 @@ +import React from 'react'; +import { + createPortal, + lazy, + Suspense, + useEffect, + useState, +} from '@wordpress/element'; +import { Spinner } from '@wordpress/components'; + +import { + BuilderActions, + BuilderContentInterface, + BuilderItemType, + DeviceTypes, + LayoutUpdate, + RemoveItem, + StringObjectKeys, +} from '../@types/utils'; + +import { + arraysAreIdentical, + getUsedItemsFromItems, + ROW_SCHEMA, +} from './common/utils'; +import { ItemInterface } from 'react-sortablejs'; +import BuilderContext from './BuilderContext'; + +const Builder = lazy( + () => import(/* webpackChunkName: "builder" */ './components/Builder') +); + +const SidebarContent = lazy( + () => + import(/* webpackChunkName: "sidebar" */ './components/SidebarContent') +); + +type Props = { + hasColumns: boolean; + onChange: (nextValue: BuilderContentInterface) => void; + value: BuilderContentInterface; + builder: string; + portalMount: HTMLElement; + hidden: boolean; +}; + +const HFGBuilder: React.FC = ({ + hasColumns, + builder, + onChange, + value, + hidden, + portalMount, +}) => { + const [device, setDevice] = useState('desktop'); + const [dragging, setDragging] = useState(false); + const [previewSidebar, togglePreviewSidebar] = useState(false); + const [currentSection, setCurrentSection] = useState(''); + + const getSidebarItems = () => { + const allItems = window.NeveReactCustomize.HFG[builder].items; + const usedItems = + value && value[device] + ? getUsedItemsFromItems(value[device]) + : Object.keys(allItems); + return Object.keys(allItems) + .filter((key) => !usedItems.includes(key)) + .map((itemId) => { + return { id: itemId }; + }) + .sort((a, b) => { + return a.id < b.id ? -1 : 1; + }); + }; + + const [sidebarItems, setSidebarItems] = useState( + getSidebarItems() + ); + + const onDragStart = () => { + setDragging(true); + }; + const onDragEnd = () => { + setDragging(false); + }; + + const updateLayout: LayoutUpdate = (row, slot, items) => { + onDragEnd(); + + if (row === 'sidebar') { + updateSidebar(items); + + return false; + } + + const nextItems = { ...value[device] }; + + // Make sure row exists and has slots. + if (!nextItems[row]) { + nextItems[row] = ROW_SCHEMA; + } + + if (arraysAreIdentical(items, nextItems[row][slot])) { + return false; + } + + const update = nextItems[row]; + const updateItems: Array = []; + + if (items.length > 0) { + items.forEach((item) => { + updateItems.push(item); + }); + } + + if (slot === 'center' && items.length === 0 && !hasColumns) { + const sideSlots = ['c-left', 'c-right']; + sideSlots.forEach((sideSlot) => { + if (!Array.isArray(update[sideSlot])) { + return false; + } + if (update[sideSlot].length < 1) { + return false; + } + + const nextSlot = sideSlot === 'c-left' ? 'left' : 'right'; + + update[sideSlot].forEach((itemToMove: StringObjectKeys) => { + if (nextSlot === 'left') { + nextItems[row][nextSlot].push(itemToMove); + } else { + nextItems[row][nextSlot].unshift(itemToMove); + } + }); + nextItems[row][sideSlot] = []; + }); + } + + update[slot] = updateItems; + nextItems[row][slot] = updateItems; + + const finalValue = { ...value, [device]: nextItems }; + + onChange(finalValue); + }; + + const updateSidebar = (items: BuilderItemType[]) => { + if (arraysAreIdentical(items, value[device].sidebar)) { + return false; + } + + const nextItems = { ...value[device] }; + const updateItems: Array = []; + + if (items.length > 0) { + items.forEach((item) => { + updateItems.push(item); + }); + } + + nextItems.sidebar = updateItems; + const finalValue = { ...value, [device]: nextItems }; + + onChange(finalValue); + }; + + const removeItem: RemoveItem = (row, slot, indexToRemove) => { + const nextItems = { ...value[device] }; + if (row === 'sidebar') { + nextItems[row].splice(indexToRemove, 1); + const finalValue = { ...value, [device]: nextItems }; + onChange(finalValue); + return false; + } + + nextItems[row][slot].splice(indexToRemove, 1); + + if ( + slot === 'center' && + nextItems[row][slot].length === 0 && + !hasColumns + ) { + const sideSlots = ['c-left', 'c-right']; + sideSlots.forEach((sideSlot) => { + if (!Array.isArray(nextItems[row][sideSlot])) { + return false; + } + if (nextItems[row][sideSlot].length < 1) { + return false; + } + + const nextSlot = sideSlot === 'c-left' ? 'left' : 'right'; + + nextItems[row][sideSlot].forEach( + (itemToMove: StringObjectKeys) => { + if (nextSlot === 'left') { + nextItems[row][nextSlot].push(itemToMove); + } else { + nextItems[row][nextSlot].unshift(itemToMove); + } + } + ); + nextItems[row][sideSlot] = []; + }); + } + const finalValue = { ...value, [device]: nextItems }; + onChange(finalValue); + }; + + /* + * Bind the device switchers to the device state. + */ + useEffect(() => { + bindDeviceSwitching(); + }, []); + + /* + * Make sure we update the sidebar. + */ + useEffect(() => { + setSidebarItems(getSidebarItems()); + }, [device, value[device]]); + + const bindDeviceSwitching = () => { + window.wp.customize.bind('ready', () => { + window.wp.customize.previewedDevice.bind( + (newDevice: DeviceTypes) => { + // No tablet context existent on builders. + if (newDevice === 'tablet') { + newDevice = 'mobile'; + } + + // If we don't have a value, don't switch context. + if (!value[newDevice]) { + return false; + } + + setDevice(newDevice); + } + ); + + window.wp.customize + .state('expandedSection') + .bind((expandedSection: StringObjectKeys) => { + if (!expandedSection) { + setCurrentSection(''); + return; + } + + if (!expandedSection.id) { + setCurrentSection(''); + return; + } + + setCurrentSection(expandedSection.id); + }); + }); + }; + + const actions: BuilderActions = { + updateLayout, + onDragStart, + onDragEnd, + removeItem, + setDevice, + setSidebarItems, + togglePreviewSidebar, + }; + + return ( + +
    + }> + <> +
    + +
    + {createPortal( +
    +
    +
    + ); +}; + +export default HFGBuilder; diff --git a/inc/customizer/controls/react/src/builder/HFGBuilderComponent.tsx b/inc/customizer/controls/react/src/builder/HFGBuilderComponent.tsx new file mode 100644 index 0000000000..69dd970d29 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/HFGBuilderComponent.tsx @@ -0,0 +1,145 @@ +/* jshint esversion: 6 */ +import React from 'react'; +import { useEffect, useState } from '@wordpress/element'; +import { WPCustomizeControl } from '../@types/customizer-control'; +import { BuilderChangeEvent, BuilderContentInterface } from '../@types/utils'; +import { maybeParseJson } from './common/utils'; +import HFGBuilder from './HFGBuilder'; + +type Props = { + control: WPCustomizeControl; + portalMount: HTMLElement; +}; + +const HFGBuilderComponent: React.FC = ({ control, portalMount }) => { + const { setting, params } = control; + + const builder: string = params.builderType; + const hasColumns: boolean = params.columnsLayout; + + const [value, setValue] = useState( + // @ts-ignore + maybeParseJson(setting.get()) + ); + const [isHidden, setHidden] = useState(true); + + const onChange = (nextValue: BuilderContentInterface) => { + const next = JSON.stringify(nextValue); + const prev = setting.get(); + + if (next === prev) { + return; + } + + setValue(nextValue); + control.setting.set(next); + }; + + /** + * Toggles builder visibility based on the migration notification. + */ + const bindOverlayNotificationHiding = () => { + window.wp.customize.notifications.bind( + 'add', + (data: { code: string }) => { + if (data.code !== 'neve_migrating_builders') { + return false; + } + + setHidden(true); + } + ); + + window.wp.customize.notifications.bind( + 'removed', + (data: { code: string }) => { + if (data.code !== 'neve_migrating_builders') { + return false; + } + + setHidden(false); + } + ); + }; + + /** + * Shows builder when its panel is expanded. + */ + const bindShowOnExpand = () => { + window.wp.customize + .state('expandedPanel') + .bind((panel: Record) => { + if (panel.id && panel.id === `hfg_${builder}` && isHidden) { + setHidden(false); + return false; + } + setHidden(true); + }); + }; + + /** + * Hides builder when customizer is collapsed. + */ + const bindHideOnPaneCollapse = () => { + window.wp.customize.bind('ready', () => { + window.wp.customize + .state('paneVisible') + .bind((nextValue: boolean) => { + const currentPanel = window.wp.customize + .state('expandedPanel') + .get(); + if (nextValue) { + if ( + currentPanel.id && + currentPanel.id === `hfg_${builder}` && + isHidden + ) { + setHidden(false); + } + return false; + } + + setHidden(true); + }); + }); + }; + + useEffect(() => { + bindShowOnExpand(); + bindOverlayNotificationHiding(); + bindHideOnPaneCollapse(); + + document.addEventListener( + 'neve-changed-builder-value', + (e: BuilderChangeEvent) => { + const { detail } = e; + if (!detail) return false; + const { id, value: builderValue } = detail; + let actualValue = builderValue; + + if (!actualValue) { + actualValue = { ...value }; + } + + if (!id || `hfg_${id}_layout_v2` !== control.id) return false; + onChange( + maybeParseJson(actualValue) as BuilderContentInterface + ); + return false; + } + ); + }, []); + + return ( +
    +
    + ); +}; + +export default BuilderItem; diff --git a/inc/customizer/controls/react/src/builder/components/ResponsiveSwitches.tsx b/inc/customizer/controls/react/src/builder/components/ResponsiveSwitches.tsx new file mode 100644 index 0000000000..29066e281d --- /dev/null +++ b/inc/customizer/controls/react/src/builder/components/ResponsiveSwitches.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import classnames from 'classnames'; + +import { __ } from '@wordpress/i18n'; +import { Button } from '@wordpress/components'; +import { useContext } from '@wordpress/element'; +import { DeviceTypes } from '../../@types/utils'; +import BuilderContext from '../BuilderContext'; +import BuilderHeaderNotification from './BuilderHeaderNotification'; + +type ButtonProps = { + title: string; + icon: string; + slug: DeviceTypes; +}; + +type Props = { + device: DeviceTypes; +}; + +const ResponsiveSwitches: React.FC = ({ device }) => { + const { actions, builder } = useContext(BuilderContext); + const { setDevice } = actions; + const buttons: ButtonProps[] = [ + { title: __('Desktop', 'neve'), icon: 'desktop', slug: 'desktop' }, + { title: __('Mobile', 'neve'), icon: 'smartphone', slug: 'mobile' }, + ]; + const { devices, title: builderName } = window.NeveReactCustomize.HFG[ + builder + ]; + + const shownButtons = buttons.filter(({ slug }) => + Object.keys(devices).includes(slug) + ); + + const switchDevice = (nextDevice: DeviceTypes) => { + if (device === nextDevice) { + return false; + } + window.wp.customize.previewedDevice(nextDevice); + setDevice(nextDevice); + }; + + return ( +
    +
    + {shownButtons.map((button, index) => { + const { title, icon, slug } = button; + const buttonClasses = classnames('device-switcher', { + active: slug === device, + }); + return ( + + ); + })} +
    + +
    + ); +}; + +export default ResponsiveSwitches; diff --git a/inc/customizer/controls/react/src/builder/components/Row.tsx b/inc/customizer/controls/react/src/builder/components/Row.tsx new file mode 100644 index 0000000000..db22fc08d1 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/components/Row.tsx @@ -0,0 +1,255 @@ +import React from 'react'; +import { + BuilderItemType, + BuilderRowInterface, + RowTypes, + SlotTypes, + StringObjectKeys, +} from '../../@types/utils'; +import { Button } from '@wordpress/components'; +import { cog } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; +import { useContext, useEffect, useState } from '@wordpress/element'; +import classnames from 'classnames'; + +import Slot from './Slot'; +import { WPCustomizeControl } from '../../@types/customizer-control'; +import BuilderContext from '../BuilderContext'; + +type Props = { + items: BuilderRowInterface & BuilderItemType[]; + rowId: RowTypes; +}; + +const Row: React.FC = ({ items, rowId }) => { + const { + actions, + dragging, + builder, + hasColumns, + previewSidebar, + } = useContext(BuilderContext); + const { updateLayout, togglePreviewSidebar } = actions; + const slots: SlotTypes[] = ['left', 'c-left', 'center', 'c-right', 'right']; + + const section = `hfg_${builder}_layout_${rowId}`; + const columnsSetting = `${section}_columns_number`; + const columnsLayoutSetting = `${section}_columns_layout`; + + const [columns, setColumns] = useState(0); + const [colLayout, setColLayout] = useState('equal'); + const [currentRow, setCurrentRow] = useState(false); + + const focusRowSection = () => { + if (rowId === 'sidebar') { + toggleThemeSidebar(true); + } + window.wp.customize.section(section).focus(); + }; + + /** + * Check if the section is active when sections are expanded. + */ + useEffect(() => { + bindRowSettingsButton(); + + if (!hasColumns) { + return; + } + + bindColumnsSync(); + }, []); + + const bindRowSettingsButton = () => { + window.wp.customize + .state('expandedSection') + .bind((expandedSection: StringObjectKeys) => { + if (!expandedSection || expandedSection.id !== section) { + setCurrentRow(false); + return false; + } + + if (expandedSection.id === section) { + setCurrentRow(true); + } + }); + }; + + const bindColumnsSync = () => { + const colNumber = window.wp.customize + .control(columnsSetting) + .setting.get(); + setColumns(parseInt(colNumber)); + setColLayout( + window.wp.customize.control(columnsLayoutSetting).setting.get() + ); + + const syncColNumber = (nextValue: string) => { + const parsedColNumber = parseInt(nextValue); + slots.forEach((slot, index) => { + if (index + 1 > parsedColNumber) { + updateLayout(rowId, slot, []); + } + }); + setColumns(parsedColNumber); + }; + + window.wp.customize.control( + columnsSetting, + (control: WPCustomizeControl) => { + control.setting.bind((nextValue: string) => { + syncColNumber(nextValue); + }); + } + ); + window.wp.customize.control( + columnsLayoutSetting, + (control: WPCustomizeControl) => { + control.setting.bind((nextValue: string) => { + setColLayout(nextValue); + }); + } + ); + }; + + useEffect(() => { + if (rowId !== 'sidebar') { + return; + } + // Toggle sidebar button when sidebar is toggled from preview. + window.wp.customize.previewer.bind( + 'neve-toggle-navbar', + (e: { status: boolean }) => { + const { status } = e; + togglePreviewSidebar(status); + } + ); + + // Toggle theme sidebar if it was previously opened on customizer refresh. + window.wp.customize.previewer.bind('ready', () => { + togglePreviewSidebar(false); + }); + }, []); + + // Toggle sidebar in preview. + const toggleThemeSidebar = (status: boolean) => { + window.wp.customize.previewer.send( + status ? 'header_sidebar_open' : 'header_sidebar_close' + ); + togglePreviewSidebar(status); + }; + + if (rowId === 'sidebar') { + const hasItems = items && items.length > 0; + const rowClasses = classnames('row', rowId, { 'has-items': hasItems }); + + return ( +
    +
    +
    + +
    + +
    +
    + ); + } + + const hasCenterItems = items.center && items.center.length > 0; + const centerItemsClass = + hasCenterItems || hasColumns ? 'has-center' : 'no-center'; + const centerWrapClass = classnames('slots-wrap', 'slots-center-wrap', { + expanded: dragging, + }); + return ( +
    +
    + ); +}; + +export default Row; diff --git a/inc/customizer/controls/react/src/builder/components/SidebarContent.tsx b/inc/customizer/controls/react/src/builder/components/SidebarContent.tsx new file mode 100644 index 0000000000..9decf62c98 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/components/SidebarContent.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { ReactSortable } from 'react-sortablejs'; +import { Icon } from '@wordpress/components'; +import { dragHandle } from '@wordpress/icons'; + +import { __ } from '@wordpress/i18n'; +import { useContext } from '@wordpress/element'; +import BuilderContext from '../BuilderContext'; + +const SidebarContent: React.FC = () => { + const { sidebarItems: items, builder, actions, dragging } = useContext( + BuilderContext + ); + + const { onDragStart, onDragEnd, setSidebarItems } = actions; + const allItems = window.NeveReactCustomize.HFG[builder].items; + + return ( +
    + + {__('Available Components', 'neve')} + + {items && items.length > 0 && ( +
    + { + const nextItems = [...next] + .map((i) => { + return { id: i.id }; + }) + .sort((a, b) => { + return a.id < b.id ? -1 : 1; + }); + + setSidebarItems(nextItems); + }} + > + {items.map((item, index) => { + const { name } = allItems[item.id]; + return ( +
    + + {name} +
    + ); + })} +
    +
    + )} + {!items.length && ( +
    + + {__( + 'All available components are used inside the builder', + 'neve' + )} + +
    + )} +
    + ); +}; + +export default SidebarContent; diff --git a/inc/customizer/controls/react/src/builder/components/Slot.tsx b/inc/customizer/controls/react/src/builder/components/Slot.tsx new file mode 100644 index 0000000000..1ac1441960 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/components/Slot.tsx @@ -0,0 +1,175 @@ +import React, { ChangeEvent } from 'react'; +import { BuilderItemType, RowTypes, SlotTypes } from '../../@types/utils'; +import { ReactSortable } from 'react-sortablejs'; +import BuilderItem from './BuilderItem'; +import classnames from 'classnames'; +import { Button, Popover, Icon } from '@wordpress/components'; +import { useContext, useState } from '@wordpress/element'; +import { close, plus, search } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; +import BuilderContext from '../BuilderContext'; + +type Props = { + rowId: RowTypes; + slotId: SlotTypes; + items: BuilderItemType[]; + className?: string; +}; + +const Slot: React.FC = ({ items, slotId, rowId, className }) => { + const { + currentSection, + builder, + actions, + dragging, + sidebarItems, + } = useContext(BuilderContext); + + const { updateLayout, onDragStart } = actions; + const [popupOpen, setPopupOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(''); + const slotClasses = classnames('droppable-wrap', slotId, className, { + 'has-popover': popupOpen, + overflowed: items.length >= 3 && rowId !== 'sidebar', + }); + + const addItemToSlot = (itemId: string) => { + const itemSection = + window.NeveReactCustomize.HFG[builder].items[itemId].section; + window.wp.customize.section(itemSection).focus(); + const nextItems = [...items]; + nextItems.push({ id: itemId }); + updateLayout(rowId, slotId, nextItems); + setPopupOpen(false); + }; + + const runSearch = (e: ChangeEvent) => { + setSearchQuery(e.target.value.toLowerCase()); + }; + + const allItems = window.NeveReactCustomize.HFG[builder].items; + + return ( +
    + { + const nextState = newState.map((item) => { + const { id } = item; + return { id }; + }); + updateLayout(rowId, slotId, nextState); + }} + > + {items && + items.length > 0 && + items.map((item, index) => { + return ( + + ); + })} + + {!dragging && ( +
    +
    + {sidebarItems.length < 1 && ( +
    + + All available components are used inside the + builder + +
    + )} + + {sidebarItems.length > 0 && ( +
    + {sidebarItems + .filter((item) => { + const { name } = allItems[item.id]; + + return ( + name + .toLowerCase() + .indexOf(searchQuery) > -1 || + item.id + .toString() + .indexOf(searchQuery) > -1 + ); + }) + .map((item, index) => { + const { id } = item; + if (!id) { + return null; + } + + return ( + + ); + })} +
    + )} +
    + + )} + + ); +}; + +export default Slot; diff --git a/inc/customizer/controls/react/src/builder/oldData.tsx b/inc/customizer/controls/react/src/builder/oldData.tsx new file mode 100644 index 0000000000..13106635d0 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/oldData.tsx @@ -0,0 +1,60 @@ +export const Header = { + desktop: { + top: [], + main: [ + { x: 0, y: 1, width: 4, height: 1, id: 'logo' }, + { x: 4, y: 1, width: 8, height: 1, id: 'primary-menu' }, + ], + bottom: [], + }, + mobile: { + top: [ + { x: 0, y: 1, width: 2, height: 1, id: 'button_base' }, + { x: 8, y: 1, width: 1, height: 1, id: 'header_search_responsive' }, + { x: 9, y: 1, width: 3, height: 1, id: 'custom_html' }, + ], + main: [ + { x: 0, y: 1, width: 8, height: 1, id: 'logo' }, + { x: 8, y: 1, width: 4, height: 1, id: 'nav-icon' }, + ], + bottom: [], + sidebar: [{ x: 0, y: 1, width: 8, height: 1, id: 'primary-menu' }], + }, +}; + +export const NewHeader = { + desktop: { + top: {}, + main: { + left: [{ x: 0, y: 1, width: 4, height: 1, id: 'logo' }], + 'c-left': [], + center: [{ x: 4, y: 1, width: 8, height: 1, id: 'primary-menu' }], + 'c-right': [], + right: [], + }, + bottom: {}, + }, + mobile: { + top: { + left: [ + { x: 0, y: 1, width: 2, height: 1, id: 'button_base' }, + { + x: 8, + y: 1, + width: 1, + height: 1, + id: 'header_search_responsive', + }, + { x: 9, y: 1, width: 3, height: 1, id: 'custom_html' }, + ], + }, + main: { + center: [ + { x: 0, y: 1, width: 8, height: 1, id: 'logo' }, + { x: 8, y: 1, width: 4, height: 1, id: 'nav-icon' }, + ], + }, + bottom: {}, + sidebar: [{ x: 0, y: 1, width: 8, height: 1, id: 'primary-menu' }], + }, +}; diff --git a/inc/customizer/controls/react/src/builder/scss/_builder-item.scss b/inc/customizer/controls/react/src/builder/scss/_builder-item.scss new file mode 100644 index 0000000000..062b024936 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_builder-item.scss @@ -0,0 +1,97 @@ +@import "vars"; + +.builder-item { + display: flex; + align-items: center; + background-color: #fff; + border: $wp-grey-border; + min-width: 90px; + white-space: nowrap; + cursor: grab; + margin: 0 2px; + border-radius: 3px; + box-sizing: border-box; + height: $rows-height - 7; + color: $item-text-color; + z-index: 1; + + button { + padding: 0; + min-width: 30px; + + .settings { + padding: 5px; + } + + .remove { + padding: 5px; + } + } + + &.active { + background-color: $wp-blue; + color: #fff; + + svg { + fill: #fff; + } + } + + .handle { + width: 15px; + padding: 0 2px 0 5px; + } + + svg { + fill: $item-icons-color; + } + + .actions { + margin-left: auto; + } + + &.sortable-ghost { + border: $droppable-border; + padding-right: 10px; + } +} + +.droppable-wrap { + &.sidebar { + padding: 4px; + width: 100%; + box-sizing: border-box; + + .builder-item { + min-width: unset; + max-width: 100%; + width: 100%; + margin: 0 0 4px; + + .name { + max-width: 90%; + overflow: hidden; + text-overflow: ellipsis; + } + + &:last-child { + margin-bottom: 0; + } + } + } + &.overflowed { + .builder-item { + .name { + max-width: 35px; + text-overflow: ellipsis; + overflow: hidden; + transition: max-width .2s ease; + } + &:hover { + .name { + max-width: 250px; + } + } + } + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_columns-builder.scss b/inc/customizer/controls/react/src/builder/scss/_columns-builder.scss new file mode 100644 index 0000000000..2497c39a81 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_columns-builder.scss @@ -0,0 +1,71 @@ +.neve-builder.columns-builder { + .row { + .slots-wrap { + width: 100%; + + .droppable-wrap { + box-sizing: border-box; + + &.hide { + display: none; + } + + &.last .droppable { + border: none; + } + + .droppable { + justify-content: center; + flex-direction: column; + height: 100%; + box-sizing: border-box; + align-items: center; + padding: 2px 4px; + + .builder-item { + margin: 2px 2px; + width: 100%; + } + } + } + + &.col-2 { + &.right-third .droppable-wrap.left { + flex-grow: 2; + } + + &.left-third .droppable-wrap.c-left { + flex-grow: 2; + } + } + + &.col-3 { + &.right-half .droppable-wrap.center { + flex-grow: 2; + } + + &.left-half .droppable-wrap.left { + flex-grow: 2; + } + + &.center-half .droppable-wrap.c-left { + flex-grow: 2; + } + + &.center-two-thirds .droppable-wrap.c-left { + flex-grow: 3; + } + } + + &.col-4 { + &.left-half .droppable-wrap.left { + flex-grow: 2; + } + + &.right-half .droppable-wrap.c-right { + flex-grow: 2; + } + } + } + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_customizer-adjustments.scss b/inc/customizer/controls/react/src/builder/scss/_customizer-adjustments.scss new file mode 100644 index 0000000000..a69f4e2baf --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_customizer-adjustments.scss @@ -0,0 +1,13 @@ +ul[id^="sub-accordion-panel-hfg_"] { + .control-subsection { + display: none !important; + } + + li[id*="accordion-section-hfg_"] { + display: block !important; + } + + #accordion-section-neve_header_presets { + margin-top: 20px; + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_instructional-section.scss b/inc/customizer/controls/react/src/builder/scss/_instructional-section.scss new file mode 100644 index 0000000000..87506df658 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_instructional-section.scss @@ -0,0 +1,30 @@ +.control-section-hfg_instructions { + display: list-item !important; + + .quick-links-inner { + padding: 0 15px; + } +} + +.quick-links-inner { + .quick-links { + font-size: 14px; + font-weight: 500; + + button { + text-decoration: none; + } + } + + .quick-links-wrap { + margin: 10px 0; + display: block; + background: #fff; + border-radius: 3px; + padding: 10px 20px; + + span { + margin-right: 10px; + } + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_items-popover.scss b/inc/customizer/controls/react/src/builder/scss/_items-popover.scss new file mode 100644 index 0000000000..de6bea250b --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_items-popover.scss @@ -0,0 +1,69 @@ +.items-popover { + box-shadow: 0 3px 30px rgba(25, 30, 35, .1); + border-radius: 4px; + z-index: 100000; + + .popover-header { + display: flex; + padding: 5px 10px; + position: relative; + border-bottom: 1px solid #e1e4e7; + + input { + appearance: none; + width: 100%; + height: 35px; + border: 1px solid #8d96a0; + outline: none; + box-shadow: none; + font-size: 13px; + margin: 16px; + padding: 11px 16px 11px 30px; + border-radius: 4px; + } + + > svg { + position: absolute; + fill: #8d96a0; + left: 30px; + top: 50%; + transform: translateY(-50%); + } + } + + .items-popover-content { + width: 400px; + padding: 10px; + overflow-y: auto; + max-height: 375px; + height: 375px; + background-color: #fff; + } + + .items-popover-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 10px; + } + + .popover-item { + width: 100%; + height: auto; + cursor: pointer; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + box-sizing: border-box; + padding: 7px; + color: #545d66; + line-height: 1.4em; + font-size: 13px; + &:hover { + background: #f3f3f5; + } + .dashicon { + margin: 0 0 10px; + } + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_main.scss b/inc/customizer/controls/react/src/builder/scss/_main.scss new file mode 100644 index 0000000000..99b7fba743 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_main.scss @@ -0,0 +1,44 @@ +@import "vars"; + +.neve-hfg-builder { + .neve-builder { + position: fixed; + bottom: 0; + left: 0; + right: 0; + margin-left: 300px; + padding: 10px 20px 20px; + background-color: $wp-light-grey; + border-top: $wp-grey-border; + transition: all .18s; + + &.hide { + transition: bottom .2s ease; + bottom: -100%; + } + + @media screen and (min-width: 1667px) { + margin-left: 18%; + } + } + + @import 'rows'; + @import 'builder-item'; + @import 'responsive-switches'; + @import 'sidebar-items'; + @import 'columns-builder'; + @import 'items-popover'; +} + +@import 'customizer-adjustments'; +@import 'instructional-section'; + + +.neve-builder-portal-wrap { + z-index: 10; + position: relative; +} + +.collapsed .neve-builder { + margin-left: 0; +} diff --git a/inc/customizer/controls/react/src/builder/scss/_responsive-switches.scss b/inc/customizer/controls/react/src/builder/scss/_responsive-switches.scss new file mode 100644 index 0000000000..d9ca8529f1 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_responsive-switches.scss @@ -0,0 +1,48 @@ +@import "vars"; + +.responsive-switches { + display: inline-flex; + width: auto; + + .device-switcher { + border-bottom: 2px solid $wp-grey; + border-radius: 0; + font-weight: 600; + color: $item-text-color; + padding: 5px 15px; + opacity: .85; + + .dashicons { + color: $item-icons-color; + } + + &.active { + opacity: 1; + border-bottom-color: $wp-blue; + + &.dashicons { + color: $wp-blue; + } + } + } +} + +.builder-header { + display: flex; + align-items: center; + margin-bottom: 15px; +} + +.builder-instructions { + margin-left: 20px; + display: flex; + align-items: center; + + p { + margin: 0; + } + + strong { + margin-right: 5px; + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_rows.scss b/inc/customizer/controls/react/src/builder/scss/_rows.scss new file mode 100644 index 0000000000..7de0bfbe0d --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_rows.scss @@ -0,0 +1,194 @@ +@import 'vars'; + +.rows-wrapper { + display: flex; + + .vertical-rows { + margin-right: 10px; + + .row { + height: 100%; + } + } + + .horizontal-rows { + flex-grow: 1; + } +} + +.row { + display: flex; + border-radius: 3px; + margin-bottom: 10px; + background-color: #fff; + border: $wp-grey-border; + flex-wrap: nowrap; + &:last-child { + margin-bottom: 0; + } + + .row-settings { + width: 32px; + display: flex; + padding: 0 2px; + min-width: unset; + align-items: center; + height: auto; + flex-grow: 1; + justify-content: center; + border-right: $wp-grey-border; + } + + .inner-row { + display: flex; + width: 100%; + align-items: stretch; + } + + .droppable-wrap { + flex: 1; + position: relative; + + &.right, &.c-left { + .droppable { + justify-content: flex-end; + } + } + + &.center { + .droppable { + justify-content: center; + transition: .3s ease; + width: auto; + } + } + } + + .droppable { + display: flex; + padding: 0 2px; + align-items: center; + min-height: $rows-height; + border-right: $droppable-border; + flex: 1; + } + + &.c-left, &.right { + .builder-item:first-child { + margin-left: auto; + } + } +} + +.row.sidebar .row-inner { + width: 200px; + + .droppable-wrap { + height: 100%; + } + + .droppable { + flex-direction: column; + justify-content: flex-start; + height: 100%; + border: 0; + flex-grow: 1; + } +} + +.sidebar-actions { + .row-settings { + height: 100%; + border-radius: 0; + + &:not(:first-child) { + border-top: $wp-grey-border; + } + } + + .dashicon { + font-size: 15px; + margin: 0 !important; + } +} + +.has-items .sidebar-actions { + .row-settings { + height: 50%; + } +} + +.slots-wrap { + display: flex; + width: 50%; + + &:last-child .droppable-wrap:last-child .droppable { + border: 0; + } + + &.slots-center-wrap { + width: auto; + transition: .3s ease; + + &.expanded .droppable:empty { + min-width: 150px; + border-right: $droppable-border; + } + + &:hover .droppable:empty { + min-width: 150px; + border-right: $droppable-border; + } + } +} + +.no-center { + .center .droppable:empty { + border-right: 0; + padding: 0; + } + + .slots-center-wrap .droppable:empty { + min-width: 0; + transition: .3s ease; + } + + &:hover { + .slots-center-wrap .droppable:empty { + min-width: 150px; + border-right: $droppable-border; + } + } + + .has-popover.center .droppable:empty { + min-width: 150px; + border-right: $droppable-border; + } + + .c-left, .c-right { + display: none; + } +} + +.open-popover { + top: 0; + left: 0; + right: 0; + bottom: 0; + opacity: 0; + z-index: 0; + padding: 0; + height: unset; + min-width: unset; + border-radius: 0; + position: absolute; + width: 100%; +} + +.droppable-wrap { + &:hover, &.has-popover { + .open-popover { + opacity: .25; + } + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_sidebar-items.scss b/inc/customizer/controls/react/src/builder/scss/_sidebar-items.scss new file mode 100644 index 0000000000..dd1d6840f2 --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_sidebar-items.scss @@ -0,0 +1,37 @@ +@import "vars"; + +.neve-builder-sidebar-content { + padding: 15px; + + .no-components { + border: $droppable-border; + color: $item-text-color; + margin-top: 10px; + padding: 15px; + } +} + +.sidebar-items { + margin-top: 10px; + + .droppable { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-gap: 10px 5px; + + .builder-item { + margin: 0; + padding-right: 10px; + + svg { + flex-shrink: 0; + } + + span { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + } + } + } +} diff --git a/inc/customizer/controls/react/src/builder/scss/_vars.scss b/inc/customizer/controls/react/src/builder/scss/_vars.scss new file mode 100644 index 0000000000..7fc5a2948d --- /dev/null +++ b/inc/customizer/controls/react/src/builder/scss/_vars.scss @@ -0,0 +1,9 @@ +$wp-light-grey: #EDEDED; +$wp-grey: #D9D9D9; +$wp-grey-border: 1px solid #D9D9D9; +$wp-blue: #0073AA; +$droppable-border: 1px dashed #cecece; +$rows-height: 45px; +$item-text-color: #555D66; +$item-icons-color: #7D838A; + diff --git a/inc/customizer/controls/react/src/button-appearance/ButtonAppearance.js b/inc/customizer/controls/react/src/button-appearance/ButtonAppearance.js index 4f651e0919..e561396781 100644 --- a/inc/customizer/controls/react/src/button-appearance/ButtonAppearance.js +++ b/inc/customizer/controls/react/src/button-appearance/ButtonAppearance.js @@ -79,6 +79,10 @@ const ButtonAppearance = ({ label, value, onChange, noHover, defaultVals }) => { settings[optionType] .controls[controlSlug] } + defaultValue={ + defaultVals[controlSlug] || + null + } selectedColor={ value[controlSlug] } diff --git a/inc/customizer/controls/react/src/button-appearance/ButtonAppearanceComponent.js b/inc/customizer/controls/react/src/button-appearance/ButtonAppearanceComponent.js index 0d0750459a..9c579b1936 100755 --- a/inc/customizer/controls/react/src/button-appearance/ButtonAppearanceComponent.js +++ b/inc/customizer/controls/react/src/button-appearance/ButtonAppearanceComponent.js @@ -6,7 +6,6 @@ import { useState, useEffect } from '@wordpress/element'; const ButtonAppearanceComponent = ({ control }) => { const controlValue = control.setting.get(); - const defaultsFromControl = { borderRadius: { top: 3, @@ -43,8 +42,8 @@ const ButtonAppearanceComponent = ({ control }) => { const defaultVals = control.params.defaultVals ? { - ...control.params.defaultVals, ...defaultsFromControl, + ...control.params.defaultVals, } : defaultsFromControl; @@ -62,7 +61,7 @@ const ButtonAppearanceComponent = ({ control }) => { const { label, no_hover } = control.params; useEffect(() => { - global.addEventListener('neve-changed-customizer-value', (e) => { + document.addEventListener('neve-changed-customizer-value', (e) => { if (!e.detail) return false; if (e.detail.id !== control.id) return false; // Migrate border-radius and border-width diff --git a/inc/customizer/controls/react/src/color/ColorComponent.js b/inc/customizer/controls/react/src/color/ColorComponent.js index 13901705f6..a8a4300b17 100644 --- a/inc/customizer/controls/react/src/color/ColorComponent.js +++ b/inc/customizer/controls/react/src/color/ColorComponent.js @@ -13,7 +13,7 @@ const ColorComponent = ({ control }) => { }; useEffect(() => { - global.addEventListener('neve-changed-customizer-value', (e) => { + document.addEventListener('neve-changed-customizer-value', (e) => { if (!e.detail) return false; if (e.detail.id !== control.id) return false; updateValues(e.detail.value); diff --git a/inc/customizer/controls/react/src/common/InlineSelect.js b/inc/customizer/controls/react/src/common/InlineSelect.js index 1a0a70a7a4..b3db3d01e1 100644 --- a/inc/customizer/controls/react/src/common/InlineSelect.js +++ b/inc/customizer/controls/react/src/common/InlineSelect.js @@ -1,10 +1,17 @@ import { SelectControl } from '@wordpress/components'; -const InlineSelect = ({ value, onChange, options, label }) => { +const InlineSelect = ({ + value, + onChange, + options, + label, + disabled = false, +}) => { return (
    {label && {label}} { - const [open, setOpen] = useState(false); - useEffect(() => { - if (!openAttr) return false; - global.addEventListener('DOMContentLoaded', () => { - const outsideTrigger = document.querySelectorAll( - `[data-open-nv-modal=${openAttr}]` - ); - if (!outsideTrigger) return false; - outsideTrigger.forEach((item) => { - item.addEventListener('click', (e) => { - e.preventDefault(); - setOpen(true); - }); - }); - }); - }, []); - - const dismiss = () => { - setOpen(false); - }; - - if (!open && !opened) { - return null; - } - - return ( - <> - {trigger} - - {children} - - - ); -}; - -NeveModal.propTypes = { - children: PropTypes.element.isRequired, - opened: PropTypes.bool, - trigger: PropTypes.element, - openAttr: PropTypes.string, - title: PropTypes.string, -}; - -export default NeveModal; diff --git a/inc/customizer/controls/react/src/common/RadioIcons.js b/inc/customizer/controls/react/src/common/RadioIcons.js index 60e74a5b2c..1bcfa88823 100644 --- a/inc/customizer/controls/react/src/common/RadioIcons.js +++ b/inc/customizer/controls/react/src/common/RadioIcons.js @@ -18,10 +18,9 @@ const RadioIcons = ({ return (