diff --git a/.gitattributes b/.gitattributes index f449abc5..d960214c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,17 +1,19 @@ # Files that exist for the repository, not for the shipped theme. Without these, # GitHub's "Download ZIP" (which is git archive) hands users the repo scaffolding. -/.gitattributes export-ignore -/.gitignore export-ignore -/.jscsrc export-ignore -/.jshintrc export-ignore -/.jshintignore export-ignore -/.standard.json export-ignore -/.travis.yml export-ignore -/.github/ export-ignore -/CLAUDE.md export-ignore -/README.md export-ignore -/Gruntfile.js export-ignore -*.map export-ignore -/package.json export-ignore -/phpcs.ruleset.xml export-ignore -/set_tags.sh export-ignore +# npm run build is deny-by-default too (tools/build-zip.mjs). +/.gitattributes export-ignore +/.gitignore export-ignore +/.github/ export-ignore +/.stylelintrc.json export-ignore +/CLAUDE.md export-ignore +/readme.md export-ignore +/eslint.config.mjs export-ignore +/tools/ export-ignore +/tests/ export-ignore +/package.json export-ignore +/package-lock.json export-ignore +/phpcs.xml.dist export-ignore +/composer.json export-ignore +/composer.lock export-ignore +/set_tags.sh export-ignore +*.map export-ignore diff --git a/.github/build-icon-subset.py b/.github/build-icon-subset.py index b5af3e44..4b3c70ba 100644 --- a/.github/build-icon-subset.py +++ b/.github/build-icon-subset.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """Build a Font Awesome subset for one theme: only the glyphs it renders.""" -import re, sys, pathlib, subprocess, json +import re, sys, pathlib, subprocess, json, hashlib theme_dir = pathlib.Path(sys.argv[1]); base = sys.argv[2]; prefix = sys.argv[3] fa = theme_dir / base / 'css' / 'fontawesome' @@ -55,6 +55,7 @@ def icon_map(path): faces = {'fa-solid-900': used_solid, 'fa-brands-400': used_brands, 'fa-regular-400': used_regular} report = {} +font_files = {} for face, cps in faces.items(): src = webfonts / f'{face}.woff2' if not src.exists() or not cps: @@ -63,7 +64,16 @@ def icon_map(path): dst = out / f'{face}.woff2' subprocess.run([sys.executable, '-m', 'fontTools.subset', str(src), f'--unicodes={uni}', '--flavor=woff2', f'--output-file={dst}'], check=True, capture_output=True) - report[face] = {'glyphs': len(cps), 'bytes': dst.stat().st_size, 'from': src.stat().st_size} + digest = hashlib.sha256(dst.read_bytes()).hexdigest()[:12] + name = f'{face}.{digest}.woff2' + hashed = out / name + dst.replace(hashed) + # A stylesheet version cannot invalidate a font cached at the same URL. + # Remove previous generated files after the new one has been written. + for previous in out.glob(f'{face}*.woff2'): + if previous != hashed: previous.unlink() + font_files[face] = name + report[face] = {'glyphs': len(cps), 'bytes': hashed.stat().st_size, 'from': src.stat().st_size} # 3. the CSS: Font Awesome's own non-icon rules, the used icon definitions, subset @font-face full = (fa / 'fontawesome.min.css').read_text() @@ -75,7 +85,7 @@ def icon_map(path): for c in sorted(cps): if c in rev: defs.append(','.join(f'.fa-{n}' for n in sorted(rev[c])) + '{--fa:"\\%s"}' % c) FACE = ('@font-face{font-family:"%s";font-style:normal;font-weight:%s;font-display:block;' - 'src:url(%s.woff2) format("woff2")}') + 'src:url(%s) format("woff2")}') HEADER = re.match(r'/\*!.*?\*/', (fa / 'solid.min.css').read_text(), re.S).group(0) @@ -97,13 +107,13 @@ def style_rules(sheet): ff = [] if used_solid: ff.append(style_rules('solid.min.css')) - ff.append(FACE % ('Font Awesome 7 Free', '900', 'fa-solid-900')) + ff.append(FACE % ('Font Awesome 7 Free', '900', font_files['fa-solid-900'])) if used_regular: ff.append(style_rules('regular.min.css')) - ff.append(FACE % ('Font Awesome 7 Free', '400', 'fa-regular-400')) + ff.append(FACE % ('Font Awesome 7 Free', '400', font_files['fa-regular-400'])) if used_brands: ff.append(style_rules('brands.min.css')) - ff.append(FACE % ('Font Awesome 7 Brands', '400', 'fa-brands-400')) + ff.append(FACE % ('Font Awesome 7 Brands', '400', font_files['fa-brands-400'])) banner = ("/*!\n * Font Awesome 7.3.1 subset for this theme, built by .github/build-icon-subset.py\n" " * Contains only the glyphs the theme renders. Load the complete Font Awesome with:\n" " * add_filter( '%s_full_fontawesome', '__return_true' );\n" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..f7cbb2f6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,107 @@ +name: CI + +# Replaces the .travis.yml pipeline, which targeted PHP 5.4-7.1 and stopped +# running when Travis withdrew free OSS builds. + +on: + push: + branches: [master] + pull_request: + branches: [master] + +permissions: + contents: read + +jobs: + php: + name: PHP ${{ matrix.php }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Floor is the theme's declared "Requires PHP"; ceiling is current stable. + php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + steps: + - uses: actions/checkout@v7 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + + - name: Syntax check every PHP file + run: | + find -L . -name '*.php' -not -path './node_modules/*' -not -path './vendor/*' -print0 \ + | xargs -0 -n1 -P4 php -d error_reporting=E_ALL -l \ + | (! grep -v '^No syntax errors') + + phpcs: + name: WordPress coding standards + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + coverage: none + tools: cs2pr + + # The versions in composer.lock, so CI and `composer lint` agree. + - name: Install PHPCS, WordPress Coding Standards and PHPCompatibilityWP + run: composer install --no-interaction --no-progress + + # phpcs.xml.dist: WordPress-Extra, the sparkling prefix and text domain, + # and PHP 7.4+ compatibility. Any error or warning fails the job. + - name: PHPCS + run: vendor/bin/phpcs -q --report=checkstyle | cs2pr + + js-css: + name: Lint JS + CSS + i18n + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - uses: actions/setup-node@v7 + with: + node-version: '22' + cache: npm + + - run: npm ci + + - name: ESLint + run: npm run lint:js + + - name: Stylelint + run: npm run lint:css + + - name: Text domain check + run: npm run i18n:check + + - name: Frontend and release regression tests + run: npm test + + build: + name: Build theme archive + runs-on: ubuntu-latest + needs: [php, phpcs, js-css] + steps: + - uses: actions/checkout@v7 + + - uses: actions/setup-node@v7 + with: + node-version: '22' + cache: npm + + - run: npm ci + + # `npm run build` runs the text domain check via prebuild. + - name: Build + run: npm run build + + - uses: actions/upload-artifact@v7 + with: + name: sparkling-theme + path: sparkling.zip + if-no-files-found: error diff --git a/.gitignore b/.gitignore index 98c0155d..07b2e28d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,23 @@ -node_modules/* -.idea/* -sparkling.zip -.gitignore +# Dependencies. Anchored: unanchored, "vendor/" also matched assets/js/vendor/, +# which is how the theme's own Bootstrap and FlexSlider scripts once went +# untracked and every git-based build shipped without them. +/node_modules/ +/vendor/ -# macOS +# Build output +/build/ +/sparkling.zip + +# Editors / OS +.idea/ +.vscode/ .DS_Store +*.swp + +# Generated +.sass-cache/ +*.map +.phpcs-cache + +# package-lock.json and composer.lock are committed so `npm ci` and +# `composer install` reproduce the exact toolchain that was tested. diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index e3e4c6c0..00000000 --- a/.jscsrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "preset": "wordpress", - "fileExtensions": [ ".js" ], - "excludeFiles": [ - "assets/js/**.min.js", - "assets/js/vendor/*" - ], - "maxErrors": Infinity -} diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index c7a5c8dc..00000000 --- a/.jshintignore +++ /dev/null @@ -1 +0,0 @@ -**/*.min.js \ No newline at end of file diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 2fd34abb..00000000 --- a/.jshintrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "boss": true, - "curly": true, - "eqeqeq": true, - "eqnull": true, - "es3": true, - "expr": true, - "immed": true, - "noarg": true, - "nonbsp": true, - "onevar": true, - "quotmark": "single", - "trailing": true, - "undef": true, - "unused": false, - "browser": true, - "globals": { - "jQuery": false, - "wp": false, - "sparklingCompanion": false - } -} diff --git a/.standard.json b/.standard.json deleted file mode 100644 index fabc92dd..00000000 --- a/.standard.json +++ /dev/null @@ -1 +0,0 @@ -{"404.php":[],"archive.php":[],"comments.php":[],"footer.php":[],"functions.php":[],"header.php":[],"image.php":[],"inc/class-wp-bootstrap-navwalker.php":[],"inc/custom-header.php":[],"inc/customizer.php":[],"inc/extras.php":[],"inc/jetpack.php":[],"inc/libraries/epsilon-framework/class-epsilon-autoloader.php":[],"inc/libraries/epsilon-framework/class-epsilon-color-coded-categories.php":[],"inc/libraries/epsilon-framework/class-epsilon-color-scheme.php":[],"inc/libraries/epsilon-framework/class-epsilon-framework.php":[],"inc/libraries/epsilon-framework/class-epsilon-notify-system.php":[],"inc/libraries/epsilon-framework/class-epsilon-typography.php":[],"inc/libraries/epsilon-framework/controls/class-epsilon-control-color-scheme.php":[],"inc/libraries/epsilon-framework/controls/class-epsilon-control-slider.php":[],"inc/libraries/epsilon-framework/controls/class-epsilon-control-toggle.php":[],"inc/libraries/epsilon-framework/controls/class-epsilon-control-typography.php":[],"inc/libraries/epsilon-framework/controls/class-epsilon-control-upsell.php":[],"inc/libraries/epsilon-framework/sections/class-epsilon-section-pro.php":[],"inc/libraries/epsilon-framework/sections/class-epsilon-section-recommended-actions.php":[],"inc/metaboxes.php":[],"inc/template-tags.php":[],"inc/welcome-screen/class-sparkling-notify-system.php":[],"inc/welcome-screen/class-sparkling-welcome.php":[],"inc/welcome-screen/sections/actions-required.php":[],"inc/welcome-screen/sections/changelog.php":[],"inc/welcome-screen/sections/getting-started.php":[],"inc/welcome-screen/sections/recommended-plugins.php":[],"inc/welcome-screen/sections/support.php":[],"inc/welcome-screen/welcome-page-setup.php":[{"name":"esc_html__","line":43,"domain":"text-domain","argument":2},{"name":"esc_html__","line":44,"domain":"text-domain","argument":2}],"inc/widgets/class-sparkling-categories.php":[],"inc/widgets/class-sparkling-popular-posts.php":[],"inc/widgets/class-sparkling-social-widget.php":[],"index.php":[],"page-fullwidth.php":[],"page.php":[],"search.php":[],"searchform.php":[],"sidebar-footer.php":[],"sidebar-home.php":[],"sidebar.php":[],"single.php":[],"template-parts/content-none.php":[],"template-parts/content-page.php":[],"template-parts/content-single.php":[],"template-parts/content.php":[]} \ No newline at end of file diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 00000000..bc7b158b --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,73 @@ +{ + "extends": "stylelint-config-standard", + "ignoreFiles": [ + "node_modules/**", + "vendor/**", + "build/**", + "**/*.min.css", + "assets/css/bootstrap.css", + "assets/css/flexslider.css", + "assets/css/academicons.css", + "assets/css/google-fonts.css", + "assets/css/fontawesome/**", + "assets/js/**" + ], + "rules": { + "no-descending-specificity": null, + "font-family-no-missing-generic-family-keyword": null, + "declaration-block-no-redundant-longhand-properties": null, + "shorthand-property-no-redundant-values": null, + "selector-class-pattern": null, + "selector-id-pattern": null, + "keyframes-name-pattern": null, + "custom-property-pattern": null, + "number-max-precision": null, + "comment-empty-line-before": null, + "rule-empty-line-before": null, + "at-rule-empty-line-before": null, + "declaration-empty-line-before": null, + "comment-whitespace-inside": null, + "alpha-value-notation": null, + "color-function-notation": null, + "color-function-alias-notation": null, + "hue-degree-notation": null, + "value-keyword-case": null, + "media-feature-range-notation": null, + "length-zero-no-unit": null, + "selector-not-notation": null, + "selector-pseudo-element-colon-notation": null, + "property-no-vendor-prefix": null, + "value-no-vendor-prefix": null, + "at-rule-no-vendor-prefix": null, + "selector-no-vendor-prefix": null, + "declaration-property-value-no-unknown": null, + "property-no-deprecated": null, + "no-duplicate-selectors": [ + true, + { + "severity": "warning" + } + ], + "block-no-empty": [ + true, + { + "severity": "warning" + } + ], + "declaration-block-no-duplicate-properties": [ + true, + { + "ignore": [ + "consecutive-duplicates-with-different-values" + ], + "severity": "warning" + } + ], + "font-family-no-duplicate-names": [ + true, + { + "severity": "warning" + } + ] + } +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 763b0db5..00000000 --- a/.travis.yml +++ /dev/null @@ -1,74 +0,0 @@ -sudo: false -language: php -dist: trusty -matrix: - fast_finish: true - include: - - php: '5.4' - - php: '5.5' - - php: '5.6' - - php: '7.0' - - php: '7.1' - env: SNIFF=1 - env: DEPLOY=1 -before_script: -- export PHPCS_DIR=/tmp/phpcs -- export SNIFFS_DIR=/tmp/sniffs -- if [[ "$SNIFF" == "1" ]]; then git clone -b 2.9 --depth 1 https://github.com/squizlabs/PHP_CodeSniffer.git - $PHPCS_DIR; fi -- if [[ "$SNIFF" == "1" ]]; then git clone -b master --depth 1 https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git - $SNIFFS_DIR; fi -- if [[ "$SNIFF" == "1" ]]; then git clone -b master --depth 1 https://github.com/wimg/PHPCompatibility.git - $SNIFFS_DIR/PHPCompatibility; fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs --config-set installed_paths - $SNIFFS_DIR; fi -- if [[ "$SNIFF" == "1" ]]; then phpenv rehash; fi -- if [[ "$SNIFF" == "1" ]]; then npm install -g jscs; fi -- if [[ "$SNIFF" == "1" ]]; then npm install -g jshint; fi -- if [[ "$SNIFF" == "1" ]]; then wget https://develop.svn.wordpress.org/trunk/.jshintrc; - fi -- if [[ "$SNIFF" == "1" ]] || [[ "$DEPLOY" == "1" ]]; then npm install -g grunt-cli; - fi -- if [[ "$SNIFF" == "1" ]] || [[ "$DEPLOY" == "1" ]]; then npm install; fi -- if [[ "$SNIFF" == "1" ]] || [[ "$DEPLOY" == "1" ]]; then npm install -g grunt-checktextdomain; - fi -script: -- mkdir -p build/logs -- find -L . -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l -- if [[ "$SNIFF" == "1" ]]; then jshint ./assets/js/*.js; fi -- if [[ "$SNIFF" == "1" ]]; then jscs ./assets/js/*.js; fi -- if [[ "$SNIFF" == "1" ]]; then grunt textdomain; fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs -p -s -v -n ./*.php --standard=./phpcs.ruleset.xml - --extensions=php; fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs -p -s -v -n ./**/*.php --standard=./phpcs.ruleset.xml - --extensions=php --ignore=./inc/plugin-activation.php,./node_modules/*.php; fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs -p -s -v -n ./**/**/*.php - --standard=./phpcs.ruleset.xml --extensions=php --ignore=./node_modules/**/*.php; - fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs -p -s -v -n ./**/**/**/*.php - --standard=./phpcs.ruleset.xml --extensions=php --ignore=./node_modules/**/**/*.php; - fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs -p -s -v -n ./**/**/**/**/*.php - --standard=./phpcs.ruleset.xml --extensions=php --ignore=./node_modules/**/**/**/*.php; - fi -- if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/scripts/phpcs -p -s -v -n ./**/**/**/**/**/*.php - --standard=./phpcs.ruleset.xml --extensions=php --ignore=./node_modules/**/**/**/**/*.php; - fi -notifications: - email: false -cache: - directories: - - node_modules -after_success: -- if [[ "$DEPLOY" == "1" ]]; then grunt build-archive; fi -- if [[ "$DEPLOY" == "1" ]]; then sh set_tags.sh; fi -deploy: - provider: releases - skip_cleanup: true - api_key: - secure: nn7N051EZTGqU6KSxO9TXuZrKG9JZqWQK6SpsCSBvvKITYvveUZGKLN53i/H02YhVGHRjD09KRBXaNPEf/ZhIPnD6NX0fE4Yz7w7zia9q6qwZSz31MwxuVP7o1w+xxweK2wEb2S/VlA4Q7qBw0kWy9GdiBhOKdyAwR5m27f5bI5SwucjcZ6O2gZzlt2BunvQhpfxqaAwSysh6eqYQWQPVxD+lNaCXG2/73RDWNSTKrND1O/BY+VtPl39YWNlU9IFGcEY0y1iTUpNNrQX/GidH2PmATQS22tcRWlhZF7mqSpDQahJnoOUtqXJLbXZjm1LqBC0721hGSoeG0Ox6Gz0Ly6QBZccqSk7h9gQBpizgrZGltHaTHmnt0cIflWtVdg2z4RgDItvjdeHwo2kyorZbA4+pashr4Pq9ctT6lH6Qr4xFrG8OtQ1mRd1+CQWiUVfvcccjVfEleWZgdhuGX9FSKV6MEbBIPz7cB838Wvw/+Rdw/f0PlOqMv8Mc33xpgSanGhLgW/lKxOwNmhoKv0vnywLoLjVF/8iiAIleDJCp8cUua6ncdRcADAPr39382qHrzgfVoMRfCmpaHZC+TKoy4phrEKwJbdFcMhGV6R1wD9xoGAW7RdO62ZUdAPq3z5t5KcTHXfLaM6agATD6uOvFcxOrgIVjN73cSNBc9+bh48= - file: sparkling.zip - on: - repo: puikinsh/Sparkling - branch: 'master' - condition: "$DEPLOY = 1" diff --git a/404.php b/404.php index 5796c8a9..e916d697 100644 --- a/404.php +++ b/404.php @@ -51,8 +51,8 @@
' . sprintf( esc_html__( 'Try looking in the monthly archives. %1$s', 'sparkling' ), convert_smilies( ':)' ) ) . '

'; - the_widget( 'WP_Widget_Archives', 'dropdown=1&title=' . esc_html__( 'Archives', 'sparkling' ), "after_title=$archive_content" ); + $sparkling_archive_content = '

' . sprintf( esc_html__( 'Try looking in the monthly archives. %1$s', 'sparkling' ), convert_smilies( ':)' ) ) . '

'; + the_widget( 'WP_Widget_Archives', 'dropdown=1&title=' . esc_html__( 'Archives', 'sparkling' ), "after_title=$sparkling_archive_content" ); ?>
diff --git a/CLAUDE.md b/CLAUDE.md index 4510adec..6f6b8484 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,101 +4,124 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What this is -Sparkling — a free classic (non-block) WordPress theme by Colorlib, v2.6.0, derived from Underscores (_s) and built on **Bootstrap 3.4.1**. Text domain: `sparkling`. Verified against **WordPress 7.0.2 on PHP 8.5**. +Sparkling — a free classic (non-block) **WordPress theme** by Colorlib, distributed on WordPress.org (slug `sparkling`) and licensed GPLv2+. It is a PHP theme derived from Underscores (`_s`), built on **Bootstrap 3.4.1** (CSS and JS) with Font Awesome 7.3.1 (a subset by default). `style.css` is hand-edited; there is **no SCSS pipeline**. Text domain: `sparkling`. -This directory is a WordPress theme folder, not an application project: there is no `package.json`, `composer.json`, linter config, or test suite committed. Files ship exactly as they sit on disk. +Do not migrate it to Bootstrap 5: users run plugins that emit Bootstrap 3 markup and rely on the theme's Bootstrap 3 (c8908ab reverted a Bootstrap 5 swap for that reason). -## Working on the theme +## Commands -- **No build step.** `style.css` and `assets/css/*.css` are edited directly — there is no SCSS source. The `.min.css`/`.min.js` files are committed alongside their unminified twins and must be regenerated by hand (`npx terser in.js -c -m -o out.min.js`) when the source changes — nothing does it automatically. -- **Which file is actually loaded matters.** `sparkling_scripts()` ([functions.php:311](functions.php#L311)) enqueues the *minified* `bootstrap.min.js` and `skip-link-focus-fix.min.js` but the *unminified* `functions.js`; the Customizer enqueues unminified `customizer.js`. Check the enqueue before editing a `.min` file. -- **Line endings are CRLF** throughout. Keep them — mixing produces noisy diffs and a PHPCS warning. -- **To run it**, copy or symlink this folder into a WordPress install's `wp-content/themes/`. -- **Version** lives in the `style.css` theme header and is read once into the `SPARKLING_VERSION` constant ([functions.php:8](functions.php#L8)), which cache-busts every theme asset. Bump the header and every asset URL follows — never hardcode a version in an enqueue. The About screen's Changelog tab renders `changelog.txt` from the theme root. +```bash +npm ci # install the pinned JS/CSS toolchain +composer install # install the pinned PHPCS, WPCS and PHPCompatibilityWP -## Security model +npm run build # produce sparkling.zip (runs i18n:check and version:check first) +npm run verify # linters + regression tests + text domain + version check +npm test # slider/menu on jQuery 3.7/4.0, contrast and package contents +npm run lint # eslint + stylelint + php -l + phpcs, in parallel +npm run lint:fix # auto-fix what eslint/stylelint/phpcbf can +npm run i18n # regenerate languages/sparkling.pot (WP-CLI on PATH, or WP_CLI=/path/to/wp) +npm run i18n:check # verify every gettext call uses the 'sparkling' text domain +npm run version:check # style.css, readme.txt (Stable tag + changelog), changelog.txt, package.json agree +npm run images # report optimisable PNG/JPEG; add -- --write to apply -The theme was hardened in 2.5.0; keep these invariants when touching it. +composer lint # vendor/bin/phpcs — the whole theme, zero errors and warnings +composer fix # vendor/bin/phpcbf +python3 .github/build-icon-subset.py . assets sparkling # rebuild the Font Awesome subset (needs fontTools) +``` -- **Every AJAX handler needs a capability check *and* `check_ajax_referer()`.** Do not hook privileged work to `admin_init` — `admin-ajax.php` fires `admin_init` *before* its authentication branch, so an `admin_init` callback that acts on `$_GET` is reachable by anonymous requests. That was a real unauthenticated front-page takeover in 2.4.11. -- **Colours printed into the inline ` - Header admin panel. - * - * @see sparkling_custom_header_setup(). - */ - function sparkling_admin_header_style() { - ?> - - Header admin panel. - * - * @see sparkling_custom_header_setup(). - */ - function sparkling_admin_header_image() { - $style = sprintf( ' style="color:#%s;"', esc_attr( get_header_textcolor() ) ); - ?> -
-

onclick="return false;" href="">

-
>
- - - -
- ' . $css . '' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Fixed CSS, or a colour matched against a hex pattern. } -endif; // sparkling_admin_header_image +endif; diff --git a/inc/customizer.php b/inc/customizer.php index 496508f7..b51ad479 100644 --- a/inc/customizer.php +++ b/inc/customizer.php @@ -34,11 +34,12 @@ function sparkling_customizer( $wp_customize ) { /* Main option Settings Panel */ $wp_customize->add_panel( - 'sparkling_main_options', array( + 'sparkling_main_options', + array( 'capability' => 'edit_theme_options', 'theme_supports' => '', 'title' => __( 'Sparkling Options', 'sparkling' ), - 'description' => __( 'Panel to update sparkling theme options', 'sparkling' ), + 'description' => __( 'Layout, colors, typography and other options for the Sparkling theme.', 'sparkling' ), // Include html tags such as

. 'priority' => 10, // Mixed with top-level-section hierarchy. @@ -47,7 +48,8 @@ function sparkling_customizer( $wp_customize ) { // add "Content Options" section $wp_customize->add_section( - 'sparkling_content_section', array( + 'sparkling_content_section', + array( 'title' => esc_html__( 'Content Options', 'sparkling' ), 'priority' => 50, 'panel' => 'sparkling_main_options', @@ -55,7 +57,8 @@ function sparkling_customizer( $wp_customize ) { ); // add setting for excerpts/full posts toggle $wp_customize->add_setting( - 'sparkling_excerpts', array( + 'sparkling_excerpts', + array( 'default' => 0, 'sanitize_callback' => 'sparkling_sanitize_checkbox', ) @@ -63,8 +66,10 @@ function sparkling_customizer( $wp_customize ) { // add checkbox control for excerpts/full posts toggle $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling_excerpts', array( - 'label' => esc_html__( 'Show post excerpts?', 'sparkling' ), + $wp_customize, + 'sparkling_excerpts', + array( + 'label' => esc_html__( 'Show excerpts instead of full posts on the blog', 'sparkling' ), 'section' => 'sparkling_content_section', 'priority' => 10, 'type' => 'sparkling-toggle', @@ -73,15 +78,18 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling_page_comments', array( + 'sparkling_page_comments', + array( 'default' => 1, 'sanitize_callback' => 'sparkling_sanitize_checkbox', ) ); $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling_page_comments', array( - 'label' => esc_html__( 'Display Comments on Static Pages?', 'sparkling' ), + $wp_customize, + 'sparkling_page_comments', + array( + 'label' => esc_html__( 'Show comments on pages', 'sparkling' ), 'section' => 'sparkling_content_section', 'priority' => 20, 'type' => 'sparkling-toggle', @@ -89,16 +97,44 @@ function sparkling_customizer( $wp_customize ) { ) ); + // Which Font Awesome library to load; see inc/fontawesome.php. + $wp_customize->add_setting( + 'sparkling[fontawesome_library]', + array( + 'default' => 'auto', + 'type' => 'option', + 'capability' => 'edit_theme_options', + 'sanitize_callback' => 'sparkling_sanitize_fontawesome_library', + ) + ); + $wp_customize->add_control( + 'sparkling[fontawesome_library]', + array( + 'label' => esc_html__( 'Font Awesome icons', 'sparkling' ), + 'section' => 'sparkling_content_section', + 'priority' => 30, + 'type' => 'select', + 'description' => esc_html__( 'The theme bundles only the icons it displays itself, which keeps pages small. Icons you add to your menus are detected automatically. Choose "Always load the complete library" if you use Font Awesome icons in a widget, in post content or in a page builder and they are not showing.', 'sparkling' ), + 'choices' => array( + 'auto' => esc_html__( 'Automatic (recommended)', 'sparkling' ), + 'full' => esc_html__( 'Always load the complete library', 'sparkling' ), + 'subset' => esc_html__( 'Only the icons the theme uses', 'sparkling' ), + ), + ) + ); + /* Sparkling Main Options */ $wp_customize->add_section( - 'sparkling_slider_options', array( + 'sparkling_slider_options', + array( 'title' => __( 'Slider Options', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', ) ); $wp_customize->add_setting( - 'sparkling[sparkling_slider_checkbox]', array( + 'sparkling[sparkling_slider_checkbox]', + array( 'default' => 0, 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_checkbox', @@ -106,8 +142,10 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling[sparkling_slider_checkbox]', array( - 'label' => esc_html__( 'Check if you want to enable slider', 'sparkling' ), + $wp_customize, + 'sparkling[sparkling_slider_checkbox]', + array( + 'label' => esc_html__( 'Show the slider on the front page', 'sparkling' ), 'section' => 'sparkling_slider_options', 'priority' => 5, 'type' => 'sparkling-toggle', @@ -115,7 +153,8 @@ function sparkling_customizer( $wp_customize ) { ) ); $wp_customize->add_setting( - 'sparkling[sparkling_slider_link_checkbox]', array( + 'sparkling[sparkling_slider_link_checkbox]', + array( 'default' => 1, 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_checkbox', @@ -123,11 +162,14 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling[sparkling_slider_link_checkbox]', array( - 'label' => esc_html__( 'Uncheck this option to remove the link from the slides', 'sparkling' ), - 'section' => 'sparkling_slider_options', - 'priority' => 6, - 'type' => 'sparkling-toggle', + $wp_customize, + 'sparkling[sparkling_slider_link_checkbox]', + array( + 'label' => esc_html__( 'Link each slide to its post', 'sparkling' ), + 'section' => 'sparkling_slider_options', + 'active_callback' => 'sparkling_slider_is_enabled', + 'priority' => 6, + 'type' => 'sparkling-toggle', ) ) ); @@ -135,7 +177,8 @@ function sparkling_customizer( $wp_customize ) { // Pull all the categories into an array global $options_categories; $wp_customize->add_setting( - 'sparkling[sparkling_slide_categories]', array( + 'sparkling[sparkling_slide_categories]', + array( 'default' => '', 'type' => 'option', 'capability' => 'edit_theme_options', @@ -143,33 +186,51 @@ function sparkling_customizer( $wp_customize ) { ) ); $wp_customize->add_control( - 'sparkling[sparkling_slide_categories]', array( - 'label' => __( 'Slider Category', 'sparkling' ), - 'section' => 'sparkling_slider_options', - 'type' => 'select', - 'description' => __( 'Select a category for the featured post slider', 'sparkling' ), - 'choices' => $options_categories, + 'sparkling[sparkling_slide_categories]', + array( + 'label' => __( 'Slider Category', 'sparkling' ), + 'section' => 'sparkling_slider_options', + 'active_callback' => 'sparkling_slider_is_enabled', + 'type' => 'select', + 'description' => __( 'The slider shows posts from this category that have a featured image.', 'sparkling' ), + /* + * The default, '', is "every category" -- which is what the slider + * shows -- but it was not one of the choices, so the control showed + * the first category as selected while the site used all of them. + */ + 'choices' => array( '' => __( 'All categories', 'sparkling' ) ) + (array) $options_categories, ) ); $wp_customize->add_setting( - 'sparkling[sparkling_slide_number]', array( - 'default' => 3, + 'sparkling[sparkling_slide_number]', + array( + // The slider shows five slides until this is saved, so the control + // must say five; it said three. + 'default' => 5, 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_number', ) ); $wp_customize->add_control( - 'sparkling[sparkling_slide_number]', array( - 'label' => __( 'Number of slide items', 'sparkling' ), - 'section' => 'sparkling_slider_options', - 'description' => __( 'Enter the number of slide items', 'sparkling' ), - 'type' => 'text', + 'sparkling[sparkling_slide_number]', + array( + 'label' => __( 'Number of slide items', 'sparkling' ), + 'section' => 'sparkling_slider_options', + 'active_callback' => 'sparkling_slider_is_enabled', + 'description' => __( 'How many posts the slider shows.', 'sparkling' ), + 'type' => 'number', + 'input_attrs' => array( + 'min' => 1, + 'max' => 20, + 'step' => 1, + ), ) ); $wp_customize->add_section( - 'sparkling_layout_options', array( + 'sparkling_layout_options', + array( 'title' => __( 'Layout Options', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', @@ -178,53 +239,60 @@ function sparkling_customizer( $wp_customize ) { // Layout options global $site_layout; $wp_customize->add_setting( - 'sparkling[site_layout]', array( + 'sparkling[site_layout]', + array( 'default' => 'side-pull-left', 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_layout', ) ); $wp_customize->add_control( - 'sparkling[site_layout]', array( + 'sparkling[site_layout]', + array( 'label' => __( 'Website Layout Options', 'sparkling' ), 'section' => 'sparkling_layout_options', 'type' => 'select', - 'description' => __( 'Choose between different layout options to be used as default', 'sparkling' ), + 'description' => __( 'The default sidebar layout. Each post and page can override it.', 'sparkling' ), 'choices' => $site_layout, ) ); if ( class_exists( 'WooCommerce' ) ) { $wp_customize->add_setting( - 'sparkling[woo_site_layout]', array( + 'sparkling[woo_site_layout]', + array( 'default' => 'full-width', 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_layout', ) ); $wp_customize->add_control( - 'sparkling[woo_site_layout]', array( + 'sparkling[woo_site_layout]', + array( 'label' => __( 'WooCommerce Page Layout Options', 'sparkling' ), 'section' => 'sparkling_layout_options', 'type' => 'select', - 'description' => __( 'Choose between different layout options to be used as default for all woocommerce pages', 'sparkling' ), + 'description' => __( 'The sidebar layout of the shop, product, cart, checkout and account pages.', 'sparkling' ), 'choices' => $site_layout, ) ); } $wp_customize->add_setting( - 'sparkling[element_color]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[element_color]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[element_color]', array( + $wp_customize, + 'sparkling[element_color]', + array( 'label' => __( 'Element Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_layout_options', 'settings' => 'sparkling[element_color]', ) @@ -232,7 +300,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[element_color_hover]', array( + 'sparkling[element_color_hover]', + array( 'default' => sanitize_hex_color( '#363636' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -240,9 +309,11 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[element_color_hover]', array( + $wp_customize, + 'sparkling[element_color_hover]', + array( 'label' => __( 'Element color on hover', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_layout_options', 'settings' => 'sparkling[element_color_hover]', ) @@ -251,37 +322,42 @@ function sparkling_customizer( $wp_customize ) { /* Sparkling Action Options */ $wp_customize->add_section( - 'sparkling_action_options', array( + 'sparkling_action_options', + array( 'title' => __( 'Action Button', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', ) ); $wp_customize->add_setting( - 'sparkling[w2f_cfa_text]', array( + 'sparkling[w2f_cfa_text]', + array( 'default' => '', 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_strip_slashes', ) ); $wp_customize->add_control( - 'sparkling[w2f_cfa_text]', array( + 'sparkling[w2f_cfa_text]', + array( 'label' => __( 'Call For Action Text', 'sparkling' ), - 'description' => sprintf( __( 'Enter the text for call for action section', 'sparkling' ) ), + 'description' => __( 'Shown in a bar under the slider on the front page. Leave empty to hide the bar.', 'sparkling' ), 'section' => 'sparkling_action_options', 'type' => 'textarea', ) ); $wp_customize->add_setting( - 'sparkling[w2f_cfa_button]', array( + 'sparkling[w2f_cfa_button]', + array( 'default' => '', 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_nohtml', ) ); $wp_customize->add_control( - 'sparkling[w2f_cfa_button]', array( + 'sparkling[w2f_cfa_button]', + array( 'label' => __( 'Call For Action Button Title', 'sparkling' ), 'section' => 'sparkling_action_options', 'description' => __( 'Enter the title for Call For Action button', 'sparkling' ), @@ -290,39 +366,45 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[w2f_cfa_link]', array( + 'sparkling[w2f_cfa_link]', + array( 'default' => '', 'type' => 'option', 'sanitize_callback' => 'esc_url_raw', ) ); $wp_customize->add_control( - 'sparkling[w2f_cfa_link]', array( - 'label' => __( 'CFA button link', 'sparkling' ), + 'sparkling[w2f_cfa_link]', + array( + 'type' => 'url', + 'label' => __( 'Call For Action Button Link', 'sparkling' ), 'section' => 'sparkling_action_options', 'description' => __( 'Enter the link for Call For Action button', 'sparkling' ), - 'type' => 'text', ) ); $wp_customize->add_setting( - 'sparkling[cfa_color]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[cfa_color]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[cfa_color]', array( + $wp_customize, + 'sparkling[cfa_color]', + array( 'label' => __( 'Call For Action Text Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_action_options', ) ) ); $wp_customize->add_setting( - 'sparkling[cfa_bg_color]', array( + 'sparkling[cfa_bg_color]', + array( 'default' => sanitize_hex_color( '#FFF' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -330,41 +412,49 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[cfa_bg_color]', array( + $wp_customize, + 'sparkling[cfa_bg_color]', + array( 'label' => __( 'Call For Action Background Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_action_options', ) ) ); $wp_customize->add_setting( - 'sparkling[cfa_btn_color]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[cfa_btn_color]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[cfa_btn_color]', array( + $wp_customize, + 'sparkling[cfa_btn_color]', + array( 'label' => __( 'Call For Action Button Border Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_action_options', ) ) ); $wp_customize->add_setting( - 'sparkling[cfa_btn_txt_color]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[cfa_btn_txt_color]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[cfa_btn_txt_color]', array( + $wp_customize, + 'sparkling[cfa_btn_txt_color]', + array( 'label' => __( 'Call For Action Button Text Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_action_options', ) ) @@ -372,98 +462,97 @@ function sparkling_customizer( $wp_customize ) { /* Sparkling Typography Options */ $wp_customize->add_section( - 'sparkling_typography_options', array( + 'sparkling_typography_options', + array( 'title' => __( 'Typography', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', ) ); // Typography Defaults - $typography_defaults = array( - 'size' => '14px', - 'face' => 'Open Sans', - 'style' => 'normal', - 'color' => '#6B6B6B', - ); + $typography_defaults = sparkling_typography_defaults(); // Typography Options global $typography_options; $wp_customize->add_setting( - 'sparkling[main_body_typography][size]', array( + 'sparkling[main_body_typography][size]', + array( 'default' => $typography_defaults['size'], 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_typo_size', ) ); $wp_customize->add_control( - 'sparkling[main_body_typography][size]', array( - 'label' => __( 'Main Body Text', 'sparkling' ), - 'description' => __( 'Used in p tags', 'sparkling' ), + 'sparkling[main_body_typography][size]', + array( + 'label' => __( 'Body font size', 'sparkling' ), + 'description' => __( 'Size, font, weight and color of post and page text.', 'sparkling' ), 'section' => 'sparkling_typography_options', 'type' => 'select', 'choices' => $typography_options['sizes'], ) ); $wp_customize->add_setting( - 'sparkling[main_body_typography][face]', array( + 'sparkling[main_body_typography][face]', + array( 'default' => $typography_defaults['face'], 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_typo_face', ) ); $wp_customize->add_control( - 'sparkling[main_body_typography][face]', array( + 'sparkling[main_body_typography][face]', + array( + 'label' => __( 'Body font', 'sparkling' ), 'section' => 'sparkling_typography_options', 'type' => 'select', 'choices' => $typography_options['faces'], ) ); $wp_customize->add_setting( - 'sparkling[main_body_typography][style]', array( + 'sparkling[main_body_typography][style]', + array( 'default' => $typography_defaults['style'], 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_typo_style', ) ); $wp_customize->add_control( - 'sparkling[main_body_typography][style]', array( + 'sparkling[main_body_typography][style]', + array( + 'label' => __( 'Body font weight', 'sparkling' ), 'section' => 'sparkling_typography_options', 'type' => 'select', 'choices' => $typography_options['styles'], ) ); $wp_customize->add_setting( - 'sparkling[main_body_typography][color]', array( - 'default' => sanitize_hex_color( '#6B6B6B' ), + 'sparkling[main_body_typography][color]', + array( + 'default' => $typography_defaults['color'], 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[main_body_typography][color]', array( + $wp_customize, + 'sparkling[main_body_typography][color]', + array( + 'label' => __( 'Body text color', 'sparkling' ), 'section' => 'sparkling_typography_options', ) ) ); - $wp_customize->add_setting( - 'sparkling[main_body_typography][subset]', array( - 'default' => '', - 'type' => 'option', - 'sanitize_callback' => 'esc_html', - ) - ); - $wp_customize->add_control( - 'sparkling[main_body_typography][subset]', array( - 'label' => __( 'Font Subset', 'sparkling' ), - 'section' => 'sparkling_typography_options', - 'description' => __( 'Enter the Google fonts subset', 'sparkling' ), - 'type' => 'text', - ) - ); + /* + * The "Font Subset" field is gone: it asked for a Google Fonts subset, and + * since 2.6.11 the fonts are bundled with the theme rather than requested + * from Google, so the value was never used. + */ $wp_customize->add_setting( - 'sparkling[heading_color]', array( + 'sparkling[heading_color]', + array( 'default' => sanitize_hex_color( '#444' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -471,7 +560,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[heading_color]', array( + $wp_customize, + 'sparkling[heading_color]', + array( 'label' => __( 'Heading Color', 'sparkling' ), 'description' => __( 'Color for all headings (h1-h6)', 'sparkling' ), 'section' => 'sparkling_typography_options', @@ -479,33 +570,39 @@ function sparkling_customizer( $wp_customize ) { ) ); $wp_customize->add_setting( - 'sparkling[link_color]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[link_color]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[link_color]', array( + $wp_customize, + 'sparkling[link_color]', + array( 'label' => __( 'Link Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_typography_options', ) ) ); $wp_customize->add_setting( - 'sparkling[link_hover_color]', array( - 'default' => sanitize_hex_color( '#DADADA' ), + 'sparkling[link_hover_color]', + array( + 'default' => sanitize_hex_color( '#B02A37' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[link_hover_color]', array( + $wp_customize, + 'sparkling[link_hover_color]', + array( 'label' => __( 'Link:hover Color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_typography_options', ) ) @@ -513,7 +610,8 @@ function sparkling_customizer( $wp_customize ) { /* Sparkling Header Options */ $wp_customize->add_section( - 'sparkling_header_options', array( + 'sparkling_header_options', + array( 'title' => __( 'Header', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', @@ -521,7 +619,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[sticky_header]', array( + 'sparkling[sticky_header]', + array( 'default' => 0, 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_checkbox', @@ -529,9 +628,11 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling[sticky_header]', array( + $wp_customize, + 'sparkling[sticky_header]', + array( 'label' => __( 'Sticky Header', 'sparkling' ), - 'description' => sprintf( __( 'Check to show fixed header', 'sparkling' ) ), + 'description' => __( 'Keep the header at the top of the window while scrolling.', 'sparkling' ), 'section' => 'sparkling_header_options', 'type' => 'sparkling-toggle', ) @@ -539,7 +640,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[nav_bg_color]', array( + 'sparkling[nav_bg_color]', + array( 'default' => sanitize_hex_color( '#363636' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -547,15 +649,18 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_bg_color]', array( + $wp_customize, + 'sparkling[nav_bg_color]', + array( 'label' => __( 'Top nav background color', 'sparkling' ), - 'description' => __( 'Default used if no color is selected', 'sparkling' ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_header_options', ) ) ); $wp_customize->add_setting( - 'sparkling[nav_link_color]', array( + 'sparkling[nav_link_color]', + array( 'default' => sanitize_hex_color( '#F5F7FA' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -563,7 +668,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_link_color]', array( + $wp_customize, + 'sparkling[nav_link_color]', + array( 'label' => __( 'Top nav item color', 'sparkling' ), 'description' => __( 'Link color', 'sparkling' ), 'section' => 'sparkling_header_options', @@ -572,15 +679,18 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[nav_item_hover_color]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[nav_item_hover_color]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_item_hover_color]', array( + $wp_customize, + 'sparkling[nav_item_hover_color]', + array( 'label' => __( 'Top nav item hover color', 'sparkling' ), 'description' => __( 'Link:hover color', 'sparkling' ), 'section' => 'sparkling_header_options', @@ -589,24 +699,28 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[nav_dropdown_bg]', array( - 'default' => sanitize_hex_color( '#da4453' ), + 'sparkling[nav_dropdown_bg]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_dropdown_bg]', array( + $wp_customize, + 'sparkling[nav_dropdown_bg]', + array( 'label' => __( 'Top nav dropdown background color', 'sparkling' ), - 'description' => __( 'Background of dropdown item hover color', 'sparkling' ), + 'description' => __( 'Background of the dropdown menus', 'sparkling' ), 'section' => 'sparkling_header_options', ) ) ); $wp_customize->add_setting( - 'sparkling[nav_dropdown_item]', array( + 'sparkling[nav_dropdown_item]', + array( 'default' => sanitize_hex_color( '#636467' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -614,7 +728,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_dropdown_item]', array( + $wp_customize, + 'sparkling[nav_dropdown_item]', + array( 'label' => __( 'Top nav dropdown item color', 'sparkling' ), 'description' => __( 'Dropdown item color', 'sparkling' ), 'section' => 'sparkling_header_options', @@ -623,7 +739,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[nav_dropdown_item_hover]', array( + 'sparkling[nav_dropdown_item_hover]', + array( 'default' => sanitize_hex_color( '#FFF' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -631,7 +748,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_dropdown_item_hover]', array( + $wp_customize, + 'sparkling[nav_dropdown_item_hover]', + array( 'label' => __( 'Top nav dropdown item hover color', 'sparkling' ), 'description' => __( 'Dropdown item hover color', 'sparkling' ), 'section' => 'sparkling_header_options', @@ -640,17 +759,20 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[nav_dropdown_bg_hover]', array( - 'default' => sanitize_hex_color( '#DA4453' ), + 'sparkling[nav_dropdown_bg_hover]', + array( + 'default' => sanitize_hex_color( '#D83B4B' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[nav_dropdown_bg_hover]', array( + $wp_customize, + 'sparkling[nav_dropdown_bg_hover]', + array( 'label' => __( 'Top nav dropdown item background hover color', 'sparkling' ), - 'description' => __( 'Background of dropdown item hover color', 'sparkling' ), + 'description' => __( 'Background of a dropdown item on hover', 'sparkling' ), 'section' => 'sparkling_header_options', ) ) @@ -658,14 +780,16 @@ function sparkling_customizer( $wp_customize ) { /* Sparkling Footer Options */ $wp_customize->add_section( - 'sparkling_footer_options', array( + 'sparkling_footer_options', + array( 'title' => __( 'Footer', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', ) ); $wp_customize->add_setting( - 'sparkling[footer_widget_bg_color]', array( + 'sparkling[footer_widget_bg_color]', + array( 'default' => sanitize_hex_color( '#313233' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -673,7 +797,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[footer_widget_bg_color]', array( + $wp_customize, + 'sparkling[footer_widget_bg_color]', + array( 'label' => __( 'Footer widget area background color', 'sparkling' ), 'section' => 'sparkling_footer_options', ) @@ -681,7 +807,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[footer_bg_color]', array( + 'sparkling[footer_bg_color]', + array( 'default' => sanitize_hex_color( '#1F1F1F' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -689,7 +816,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[footer_bg_color]', array( + $wp_customize, + 'sparkling[footer_bg_color]', + array( 'label' => __( 'Footer background color', 'sparkling' ), 'section' => 'sparkling_footer_options', ) @@ -697,7 +826,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[footer_text_color]', array( + 'sparkling[footer_text_color]', + array( 'default' => sanitize_hex_color( '#999' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -705,7 +835,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[footer_text_color]', array( + $wp_customize, + 'sparkling[footer_text_color]', + array( 'label' => __( 'Footer text color', 'sparkling' ), 'section' => 'sparkling_footer_options', ) @@ -713,7 +845,8 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[footer_link_color]', array( + 'sparkling[footer_link_color]', + array( 'default' => sanitize_hex_color( '#DADADA' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -721,7 +854,9 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[footer_link_color]', array( + $wp_customize, + 'sparkling[footer_link_color]', + array( 'label' => __( 'Footer link color', 'sparkling' ), 'section' => 'sparkling_footer_options', ) @@ -729,16 +864,18 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[custom_footer_text]', array( + 'sparkling[custom_footer_text]', + array( 'default' => '', 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_strip_slashes', ) ); $wp_customize->add_control( - 'sparkling[custom_footer_text]', array( + 'sparkling[custom_footer_text]', + array( 'label' => __( 'Footer information', 'sparkling' ), - 'description' => sprintf( __( 'Copyright text in footer', 'sparkling' ) ), + 'description' => __( 'Copyright text in footer', 'sparkling' ), 'section' => 'sparkling_footer_options', 'type' => 'textarea', ) @@ -746,14 +883,16 @@ function sparkling_customizer( $wp_customize ) { /* Sparkling Social Options */ $wp_customize->add_section( - 'sparkling_social_options', array( + 'sparkling_social_options', + array( 'title' => __( 'Social', 'sparkling' ), 'priority' => 31, 'panel' => 'sparkling_main_options', ) ); $wp_customize->add_setting( - 'sparkling[social_color]', array( + 'sparkling[social_color]', + array( 'default' => sanitize_hex_color( '#DADADA' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -761,16 +900,19 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[social_color]', array( + $wp_customize, + 'sparkling[social_color]', + array( 'label' => __( 'Social icon color', 'sparkling' ), - 'description' => sprintf( __( 'Default used if no color is selected', 'sparkling' ) ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_social_options', ) ) ); $wp_customize->add_setting( - 'sparkling[social_footer_color]', array( + 'sparkling[social_footer_color]', + array( 'default' => sanitize_hex_color( '#363636' ), 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_hexcolor', @@ -778,16 +920,19 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new WP_Customize_Color_Control( - $wp_customize, 'sparkling[social_footer_color]', array( + $wp_customize, + 'sparkling[social_footer_color]', + array( 'label' => __( 'Footer social icon color', 'sparkling' ), - 'description' => sprintf( __( 'Default used if no color is selected', 'sparkling' ) ), + 'description' => __( 'Clear it to use the theme default.', 'sparkling' ), 'section' => 'sparkling_social_options', ) ) ); $wp_customize->add_setting( - 'sparkling[footer_social]', array( + 'sparkling[footer_social]', + array( 'default' => 0, 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_checkbox', @@ -795,9 +940,11 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling[footer_social]', array( + $wp_customize, + 'sparkling[footer_social]', + array( 'label' => __( 'Footer Social Icons', 'sparkling' ), - 'description' => sprintf( __( 'Check to show social icons in footer', 'sparkling' ) ), + 'description' => __( 'Show the Social menu as icons in the footer.', 'sparkling' ), 'section' => 'sparkling_social_options', 'type' => 'sparkling-toggle', ) @@ -806,7 +953,8 @@ function sparkling_customizer( $wp_customize ) { /* Academicons */ $wp_customize->add_setting( - 'sparkling[academicons]', array( + 'sparkling[academicons]', + array( 'default' => 0, 'type' => 'option', 'sanitize_callback' => 'sparkling_sanitize_checkbox', @@ -815,9 +963,11 @@ function sparkling_customizer( $wp_customize ) { $wp_customize->add_control( new Sparkling_Customize_Toggle_Control( - $wp_customize, 'sparkling[academicons]', array( + $wp_customize, + 'sparkling[academicons]', + array( 'label' => __( 'Enable Academicons', 'sparkling' ), - 'description' => sprintf( __( 'Toggle this to ON to enable the usage of Academicons', 'sparkling' ) ), + 'description' => __( 'Load the Academicons font, for links to academic profiles in the Social menu.', 'sparkling' ), 'section' => 'sparkling_social_options', 'type' => 'sparkling-toggle', ) @@ -826,7 +976,8 @@ function sparkling_customizer( $wp_customize ) { /* Archive pages settings */ $wp_customize->add_section( - 'sparkling_archive_section', array( + 'sparkling_archive_section', + array( 'title' => esc_html__( 'Archive Pages', 'sparkling' ), 'priority' => 50, 'panel' => 'sparkling_main_options', @@ -834,15 +985,17 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[tag_title]', array( + 'sparkling[tag_title]', + array( 'default' => '', 'type' => 'option', - 'sanitize_callback' => 'esc_html', + 'sanitize_callback' => 'sanitize_text_field', ) ); $wp_customize->add_control( - 'sparkling[tag_title]', array( + 'sparkling[tag_title]', + array( 'label' => __( 'Tag Page Title', 'sparkling' ), 'section' => 'sparkling_archive_section', /* translators: %s: tag name */ @@ -852,15 +1005,17 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[category_title]', array( + 'sparkling[category_title]', + array( 'default' => '', 'type' => 'option', - 'sanitize_callback' => 'esc_html', + 'sanitize_callback' => 'sanitize_text_field', ) ); $wp_customize->add_control( - 'sparkling[category_title]', array( + 'sparkling[category_title]', + array( 'label' => __( 'Category Page Title', 'sparkling' ), 'section' => 'sparkling_archive_section', /* translators: %s: category name */ @@ -870,15 +1025,17 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[author_title]', array( + 'sparkling[author_title]', + array( 'default' => '', 'type' => 'option', - 'sanitize_callback' => 'esc_html', + 'sanitize_callback' => 'sanitize_text_field', ) ); $wp_customize->add_control( - 'sparkling[author_title]', array( + 'sparkling[author_title]', + array( 'label' => __( 'Author Page Title', 'sparkling' ), 'section' => 'sparkling_archive_section', /* translators: %s: author name */ @@ -888,15 +1045,17 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[year_title]', array( + 'sparkling[year_title]', + array( 'default' => '', 'type' => 'option', - 'sanitize_callback' => 'esc_html', + 'sanitize_callback' => 'sanitize_text_field', ) ); $wp_customize->add_control( - 'sparkling[year_title]', array( + 'sparkling[year_title]', + array( 'label' => __( 'Year Page Title', 'sparkling' ), 'section' => 'sparkling_archive_section', /* translators: %s: year */ @@ -906,15 +1065,17 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[month_title]', array( + 'sparkling[month_title]', + array( 'default' => '', 'type' => 'option', - 'sanitize_callback' => 'esc_html', + 'sanitize_callback' => 'sanitize_text_field', ) ); $wp_customize->add_control( - 'sparkling[month_title]', array( + 'sparkling[month_title]', + array( 'label' => __( 'Month Page Title', 'sparkling' ), 'section' => 'sparkling_archive_section', /* translators: %s: month */ @@ -924,15 +1085,17 @@ function sparkling_customizer( $wp_customize ) { ); $wp_customize->add_setting( - 'sparkling[day_title]', array( + 'sparkling[day_title]', + array( 'default' => '', 'type' => 'option', - 'sanitize_callback' => 'esc_html', + 'sanitize_callback' => 'sanitize_text_field', ) ); $wp_customize->add_control( - 'sparkling[day_title]', array( + 'sparkling[day_title]', + array( 'label' => __( 'Day Page Title', 'sparkling' ), 'section' => 'sparkling_archive_section', /* translators: %s: day */ @@ -945,17 +1108,46 @@ function sparkling_customizer( $wp_customize ) { add_action( 'customize_register', 'sparkling_customizer' ); +if ( ! function_exists( 'sparkling_typography_defaults' ) ) : + /** + * Defaults for the body typography settings: what style.css renders. + * + * @return array + */ + function sparkling_typography_defaults() { + return array( + 'size' => '14px', + 'face' => 'Open Sans', + 'style' => 'normal', + 'color' => '#6B6B6B', + ); + } +endif; + /** - * Sanitzie checkbox for WordPress customizer + * Sanitize checkbox for WordPress customizer */ function sparkling_sanitize_checkbox( $input ) { - if ( 1 == $input ) { + // The Customizer posts true; older saves hold 1 or '1'. + if ( in_array( $input, array( true, 1, '1' ), true ) ) { return 1; } else { return ''; } } +/** + * Adds sanitization callback function: Font Awesome library choice + * @package Sparkling + */ +function sparkling_sanitize_fontawesome_library( $input ) { + if ( in_array( $input, array( 'auto', 'full', 'subset' ), true ) ) { + return $input; + } + + return 'auto'; +} + /** * Adds sanitization callback function: colors * @package Sparkling @@ -984,12 +1176,17 @@ function sparkling_sanitize_nohtml( $input ) { /** * Adds sanitization callback function: Number - * @package Sparkling + * + * A whole number of at least 1. This returned nothing at all for anything + * non-numeric and let "2.5" or "-3" through. + * + * @param mixed $input Value from the Customizer. + * @return int|string */ function sparkling_sanitize_number( $input ) { - if ( isset( $input ) && is_numeric( $input ) ) { - return $input; - } + $number = absint( $input ); + + return $number ? $number : ''; } /** @@ -1014,7 +1211,13 @@ function sparkling_sanitize_textarea( $input ) { */ function sparkling_sanitize_slidecat( $input ) { global $options_categories; - if ( array_key_exists( $input, $options_categories ) ) { + + // '' is "All categories", the default. + if ( '' === $input || null === $input ) { + return ''; + } + + if ( is_array( $options_categories ) && array_key_exists( absint( $input ), $options_categories ) ) { return $input; } else { return ''; @@ -1027,7 +1230,7 @@ function sparkling_sanitize_slidecat( $input ) { */ function sparkling_sanitize_layout( $input ) { global $site_layout; - if ( array_key_exists( $input, $site_layout ) ) { + if ( is_string( $input ) && is_array( $site_layout ) && array_key_exists( $input, $site_layout ) ) { return $input; } else { return ''; @@ -1039,12 +1242,17 @@ function sparkling_sanitize_layout( $input ) { * @package Sparkling */ function sparkling_sanitize_typo_size( $input ) { - global $typography_options, $typography_defaults; - if ( array_key_exists( $input, $typography_options['sizes'] ) ) { + global $typography_options; + + // $typography_defaults was never a global, so an unknown value came back + // as null with an "array offset on null" warning instead of the default. + if ( is_string( $input ) && array_key_exists( $input, $typography_options['sizes'] ) ) { return $input; - } else { - return $typography_defaults['size']; } + + $defaults = sparkling_typography_defaults(); + + return $defaults['size']; } /** @@ -1052,12 +1260,17 @@ function sparkling_sanitize_typo_size( $input ) { * @package Sparkling */ function sparkling_sanitize_typo_face( $input ) { - global $typography_options, $typography_defaults; - if ( array_key_exists( $input, $typography_options['faces'] ) ) { + global $typography_options; + + // $typography_defaults was never a global, so an unknown value came back + // as null with an "array offset on null" warning instead of the default. + if ( is_string( $input ) && array_key_exists( $input, $typography_options['faces'] ) ) { return $input; - } else { - return $typography_defaults['face']; } + + $defaults = sparkling_typography_defaults(); + + return $defaults['face']; } /** @@ -1065,12 +1278,17 @@ function sparkling_sanitize_typo_face( $input ) { * @package Sparkling */ function sparkling_sanitize_typo_style( $input ) { - global $typography_options, $typography_defaults; - if ( array_key_exists( $input, $typography_options['styles'] ) ) { + global $typography_options; + + // $typography_defaults was never a global, so an unknown value came back + // as null with an "array offset on null" warning instead of the default. + if ( is_string( $input ) && array_key_exists( $input, $typography_options['styles'] ) ) { return $input; - } else { - return $typography_defaults['style']; } + + $defaults = sparkling_typography_defaults(); + + return $defaults['style']; } /** @@ -1083,66 +1301,36 @@ function sparkling_customize_preview_js() { add_action( 'customize_preview_init', 'sparkling_customize_preview_js' ); /** - * Styles for the theme's own Customizer controls. + * Styles and scripts for the theme's own Customizer controls and sections. * - * Carries the on/off switch and tooltip rules that used to come from the bundled - * Epsilon framework's stylesheet, so the controls look unchanged after its removal. + * customizer.css carries the on/off switch that used to come from the bundled + * Epsilon framework, and the link sections' styling. customizer-controls.js + * registers the link section type. */ function sparkling_customize_controls_css() { wp_enqueue_style( 'sparkling-customizer-controls', get_template_directory_uri() . '/assets/css/customizer.css', array(), SPARKLING_VERSION ); + wp_enqueue_script( 'sparkling-customizer-controls', get_template_directory_uri() . '/assets/js/customizer-controls.js', array( 'customize-controls' ), SPARKLING_VERSION, true ); } add_action( 'customize_controls_enqueue_scripts', 'sparkling_customize_controls_css' ); -/** - * Add CSS for custom controls - */ -function sparkling_customizer_custom_control_css() { - ?> - - - - - ID ) ? rand() : $post->ID ); - $o = '

-
-
-

' . esc_html__( 'This post is password protected. To view it please enter your password below:', 'sparkling' ) . '

- -
- - - -
-
-
-
'; - - return $o; +function custom_password_form( $output = '', $post = null, $invalid_password = '' ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Public name since 1.0; child themes remove_filter() it. + $post = get_post( $post ); + $field_id = 'pwbox-' . ( empty( $post->ID ) ? wp_rand() : $post->ID ); + $error = ''; + $describe = ''; + + if ( '' !== (string) $invalid_password ) { + $error = ''; + $describe = ' aria-describedby="error-' . esc_attr( $field_id ) . '"'; + } + + $redirect = empty( $post->ID ) ? '' : ''; + + /* + * One line, with every inline element already inside a block, like core's + * own form: this is returned in place of the post content, so the_content's + * wpautop() runs over it and would otherwise add

and
tags. + */ + return '

' + . '
' + . $error + . '

' . esc_html__( 'This post is password protected. To view it please enter your password below:', 'sparkling' ) . '

' + . '

' . $redirect . '

' + . '
' + . '' + . '' + . '
' + . '
'; } +add_filter( 'the_password_form', 'custom_password_form', 10, 3 ); // Add Bootstrap classes for table add_filter( 'the_content', 'sparkling_add_custom_table_class' ); @@ -92,25 +114,64 @@ function sparkling_add_custom_table_class( $content ) { * @package sparkling */ function sparkling_social_icons() { + static $sparkling_instance = 0; + if ( has_nav_menu( 'social-menu' ) ) { + ++$sparkling_instance; + + /* + * The menu can print several times on one page -- the footer and the + * Sparkling Social widget, in any number of widget areas -- and every + * copy used to carry id="menu-social". The first keeps that id for + * child themes that style it; the rest are numbered. The stylesheet + * matches the .menu-social class at the same specificity. + */ + $sparkling_suffix = 1 === $sparkling_instance ? '' : '-' . $sparkling_instance; + wp_nav_menu( array( - 'theme_location' => 'social-menu', - 'container' => 'nav', - 'container_id' => 'menu-social', - 'container_class' => 'social-icons', - 'menu_id' => 'menu-social-items', - 'menu_class' => 'social-menu', - 'depth' => 1, - 'fallback_cb' => '', - 'link_before' => '', - 'link_after' => '', + 'theme_location' => 'social-menu', + 'container' => 'nav', + 'container_id' => 'menu-social' . $sparkling_suffix, + 'container_class' => 'social-icons menu-social', + 'container_aria_label' => __( 'Social links', 'sparkling' ), + 'menu_id' => 'menu-social-items' . $sparkling_suffix, + 'menu_class' => 'social-menu', + 'depth' => 1, + 'fallback_cb' => '', + 'link_before' => '', + 'link_after' => '', ) ); } } endif; +if ( ! function_exists( 'sparkling_navwalker_is_icon_class' ) ) : + /** + * Whether a menu item's Title Attribute is an icon class list. + * + * The walker prints such a value as an icon before the label, which is how + * sites add Font Awesome or glyphicon icons to menu items. Anything else + * typed there is a tooltip. + * + * @param string $value Title Attribute. + * + * @return bool + */ + function sparkling_navwalker_is_icon_class( $value ) { + $tokens = preg_split( '/\s+/', trim( (string) $value ) ); + + foreach ( $tokens as $token ) { + if ( ! preg_match( '/^(glyphicon(-[\w-]+)?|fa[srbl]?|fa-[\w-]+)$/', $token ) ) { + return false; + } + } + + return '' !== $tokens[0]; + } +endif; + if ( ! function_exists( 'sparkling_header_menu' ) ) : /** * Header menu (should you choose to use one) @@ -122,10 +183,11 @@ function sparkling_header_menu() { 'menu' => 'primary', 'theme_location' => 'primary', 'container' => 'div', + 'container_id' => 'sparkling-navbar', 'container_class' => 'collapse navbar-collapse navbar-ex1-collapse', 'menu_class' => 'nav navbar-nav', - 'fallback_cb' => 'WP_Bootstrap_Navwalker::fallback', - 'walker' => new WP_Bootstrap_Navwalker(), + 'fallback_cb' => 'Sparkling_Bootstrap_Navwalker::fallback', + 'walker' => new Sparkling_Bootstrap_Navwalker(), ) ); } /* end header menu */ @@ -160,7 +222,7 @@ function sparkling_footer_links() { * Call for action text and button displayed above content */ function sparkling_call_for_action() { - if ( is_front_page() && of_get_option( 'w2f_cfa_text' ) != '' ) { + if ( is_front_page() && '' !== (string) of_get_option( 'w2f_cfa_text' ) ) { echo '
'; echo '
'; echo '
'; @@ -180,7 +242,7 @@ function sparkling_call_for_action() { * Featured image slider, displayed on front page for static page and blog */ function sparkling_featured_slider() { - if ( is_front_page() && of_get_option( 'sparkling_slider_checkbox' ) == 1 ) { + if ( is_front_page() && of_get_option( 'sparkling_slider_checkbox' ) ) { $count = absint( of_get_option( 'sparkling_slide_number' ) ); $slidecat = of_get_option( 'sparkling_slide_categories' ); @@ -217,7 +279,7 @@ function sparkling_featured_slider() { // it and close the same tag we opened. Previously '' was // printed unconditionally, leaving a stray closing tag whenever // slide links were switched off. - $sparkling_slide_linked = ( 1 == of_get_option( 'sparkling_slider_link_checkbox', 1 ) ); + $sparkling_slide_linked = (bool) of_get_option( 'sparkling_slider_link_checkbox', 1 ); if ( $sparkling_slide_linked ) { echo '
  • '; @@ -257,10 +319,10 @@ function sparkling_featured_slider() { endif; echo '
    '; - if ( get_the_title() != '' ) { + if ( '' !== get_the_title() ) { echo '

    ' . esc_html( get_the_title() ) . '

    '; } - if ( get_the_excerpt() != '' ) { + if ( '' !== get_the_excerpt() ) { echo '
    ' . esc_html( get_the_excerpt() ) . '
    '; } echo '
    '; @@ -271,7 +333,7 @@ function sparkling_featured_slider() { echo '
  • '; endif; wp_reset_postdata(); - }// End if(). + } } endif; @@ -279,9 +341,8 @@ function sparkling_featured_slider() { * function to show the footer info, copyright information */ function sparkling_footer_info() { - global $sparkling_footer_info; /* translators: 1: Colorlib link, 2: WordPress link */ - printf( esc_html__( 'Theme by %1$s Powered by %2$s', 'sparkling' ), 'Colorlib', 'WordPress' ); + printf( esc_html__( 'Theme by %1$s Powered by %2$s', 'sparkling' ), 'Colorlib', 'WordPress' ); } @@ -309,12 +370,12 @@ function sparkling_css_color( $name ) { return ''; } - // #rgb / #rrggbb + // Hex: #rgb or #rrggbb. if ( preg_match( '/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i', $value ) ) { return $value; } - // rgb() / rgba() + // The rgb() and rgba() functions. if ( preg_match( '/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(?:,\s*(?:0|1|0?\.\d+)\s*)?\)$/', $value ) ) { return $value; } @@ -332,93 +393,100 @@ function sparkling_css_color( $name ) { /** * Get information from Theme Options and add it into wp_head */ - function get_sparkling_theme_options() { - - echo ' - - -
    -
    - - -
    -
    -

    -
    - -

    - -

    -

    support questions and bug reports is via', 'sparkling' ); ?> - . -

    -

    -
      -
    • -
    • -
    • -
    -
    -
    -
    -' . $css . '' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- See above. + } } +add_action( 'wp_head', 'get_sparkling_theme_options', 10 ); /** * Add Bootstrap thumbnail styling to images with captions @@ -539,19 +554,25 @@ function sparkling_caption( $output, $attr, $content ) { $attr = shortcode_atts( $defaults, $attr ); + $width = absint( $attr['width'] ); + // If the width is less than 1 or there is no caption, return the content wrapped between the [caption] tags - if ( $attr['width'] < 1 || empty( $attr['caption'] ) ) { + if ( $width < 1 || empty( $attr['caption'] ) ) { return $content; } - // Set up the attributes for the caption
    + /* + * absint(): a non-numeric width -- "300px", say -- was added to 10 as a + * string, a fatal TypeError on PHP 8. The caption may hold the markup core + * allows in captions, and nothing else. + */ $attributes = ( ! empty( $attr['id'] ) ? ' id="' . esc_attr( $attr['id'] ) . '"' : '' ); $attributes .= ' class="thumbnail wp-caption ' . esc_attr( $attr['align'] ) . '"'; - $attributes .= ' style="width: ' . ( esc_attr( $attr['width'] ) + 10 ) . 'px"'; + $attributes .= ' style="width: ' . ( $width + 10 ) . 'px"'; $output = ''; $output .= do_shortcode( $content ); - $output .= '
    ' . $attr['caption'] . '
    '; + $output .= '
    ' . wp_kses_post( $attr['caption'] ) . '
    '; $output .= '
    '; return $output; @@ -586,8 +607,8 @@ function sparkling_social() { function sparkling_post_nav() { the_post_navigation( array( - 'next_text' => '%title ', - 'prev_text' => ' %title', + 'next_text' => '%title ', + 'prev_text' => ' %title', 'in_same_term' => true, ) ); @@ -602,56 +623,28 @@ function sparkling_post_nav() { function sparkling_paging_nav() { the_posts_pagination( array( - 'prev_text' => ' ' . __( 'Newer posts', 'sparkling' ), - 'next_text' => __( 'Older posts', 'sparkling' ) . ' ', + 'prev_text' => ' ' . __( 'Newer posts', 'sparkling' ), + 'next_text' => __( 'Older posts', 'sparkling' ) . ' ', ) ); } } -/** - * Adds the URL to the top level navigation menu item - */ -function sparkling_add_top_level_menu_url( $atts, $item, $args ) { - if ( ! wp_is_mobile() && isset( $args->has_children ) && $args->has_children ) { - $atts['href'] = ! empty( $item->url ) ? $item->url : ''; - } - - return $atts; -} - -add_filter( 'nav_menu_link_attributes', 'sparkling_add_top_level_menu_url', 99, 3 ); - -/** - * Makes the top level navigation menu item clickable +/* + * sparkling_add_top_level_menu_url() and sparkling_make_top_level_menu_clickable() + * were removed in 2.7.0. The walker already prints every item's URL, and the + * footer script re-ran each top-level click through window.location -- with + * jQuery's deprecated .click(), only on desktop user agents (wp_is_mobile(), + * which also defeats page caching), and sending "#" items to "#". */ -function sparkling_make_top_level_menu_clickable() { - if ( ! wp_is_mobile() ) { - ?> - - '; + printf( '' . "\n", esc_url( get_bloginfo( 'pingback_url' ) ) ); } } -add_action( 'wp_head', '_s_pingback_header' ); +add_action( 'wp_head', 'sparkling_pingback_header' ); diff --git a/inc/fontawesome.php b/inc/fontawesome.php new file mode 100644 index 00000000..db301faf --- /dev/null +++ b/inc/fontawesome.php @@ -0,0 +1,255 @@ + SPARKLING_VERSION, + 'full' => $full, + ), + true + ); + + return $full; +} + +/** + * Scans the assigned nav menus for icons missing from the bundled subset. + * + * Only a class that is a real Font Awesome icon name counts. Sizing and style + * classes (`fa-fw`, `fa-2x`, `fa-spin`, `fa-solid`) are not icon names and are + * ignored, as is any unrelated class that happens to start with `fa-`. + * + * @return bool True if the complete library is needed. + */ +function sparkling_fontawesome_scan_menus() { + $classes = sparkling_fontawesome_menu_icon_classes(); + + if ( empty( $classes ) ) { + return false; + } + + // Anything the subset already carries needs no further work. + $subset = sparkling_fontawesome_icon_names( array( 'subset/fontawesome-subset.min.css' ) ); + $missing = array_diff( $classes, array_keys( $subset ) ); + + if ( empty( $missing ) ) { + return false; + } + + // Only now is it worth reading the complete library to tell an icon name + // from a utility or unrelated class. all.min.css is the file the complete + // set loads, so it is also the authority on what that set can draw. + $complete = sparkling_fontawesome_icon_names( array( 'all.min.css' ) ); + + foreach ( $missing as $class ) { + if ( isset( $complete[ $class ] ) ) { + return true; + } + } + + return false; +} + +/** + * Collects every `fa-` class used in the assigned nav menus. + * + * Reads the Navigation Label, the Title Attribute and the CSS Classes field, + * the three places a menu item can carry an icon. + * + * @return array List of lowercased class names. + */ +function sparkling_fontawesome_menu_icon_classes() { + $locations = get_nav_menu_locations(); + $found = array(); + + foreach ( array_keys( get_registered_nav_menus() ) as $location ) { + if ( empty( $locations[ $location ] ) ) { + continue; + } + + $items = wp_get_nav_menu_items( $locations[ $location ] ); + + if ( ! is_array( $items ) ) { + continue; + } + + foreach ( $items as $item ) { + $haystack = isset( $item->title ) ? $item->title : ''; + + // The primary menu's walker prints an icon class list typed into the + // Title Attribute field as an icon, so it counts too. + if ( ! empty( $item->attr_title ) ) { + $haystack .= ' ' . $item->attr_title; + } + + if ( ! empty( $item->classes ) && is_array( $item->classes ) ) { + $haystack .= ' ' . implode( ' ', $item->classes ); + } + + if ( preg_match_all( '/\bfa-[a-z0-9]+(?:-[a-z0-9]+)*/', strtolower( $haystack ), $matches ) ) { + $found = array_merge( $found, $matches[0] ); + } + } + } + + return array_values( array_unique( $found ) ); +} + +/** + * Reads icon names out of the bundled Font Awesome stylesheets. + * + * An icon is a rule that declares the `--fa` custom property holding its + * glyph; utility classes such as `.fa-fw` declare other properties and are + * skipped. Selectors are read as a group so aliases -- `.fa-edit` alongside + * `.fa-pen-to-square` -- are all collected, and the version 4 compatibility + * layer's `.fa.fa-glass` form counts too, since the complete set draws it. + * + * @param array $files Stylesheet paths relative to the Font Awesome directory. + * @return array Map of icon name to true, for O(1) lookup. + */ +function sparkling_fontawesome_icon_names( $files ) { + $names = array(); + + foreach ( $files as $file ) { + $path = sparkling_fontawesome_dir() . $file; + + if ( ! is_readable( $path ) ) { + continue; + } + + // A theme-owned file on local disk, read once and cached thereafter. + $css = file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + + if ( ! $css ) { + continue; + } + + $css = preg_replace( '#/\*.*?\*/#s', '', $css ); + + if ( ! preg_match_all( '/([^{}]+)\{([^{}]*)\}/', $css, $rules, PREG_SET_ORDER ) ) { + continue; + } + + foreach ( $rules as $rule ) { + if ( ! preg_match( '/--fa\s*:/', $rule[2] ) ) { + continue; + } + + foreach ( explode( ',', $rule[1] ) as $selector ) { + if ( preg_match( '/^\s*(?:\.fa)?\.(fa-[a-z0-9-]+)\s*$/', $selector, $name ) ) { + $names[ $name[1] ] = true; + } + } + } + } + + return $names; +} + +/** + * Drops the cached scan so the next front-end request recomputes it. + */ +function sparkling_fontawesome_clear_cache() { + delete_option( SPARKLING_FONTAWESOME_CACHE ); +} + +add_action( 'wp_update_nav_menu', 'sparkling_fontawesome_clear_cache' ); +add_action( 'wp_delete_nav_menu', 'sparkling_fontawesome_clear_cache' ); +add_action( 'customize_save_after', 'sparkling_fontawesome_clear_cache' ); +add_action( 'after_switch_theme', 'sparkling_fontawesome_clear_cache' ); diff --git a/inc/jetpack.php b/inc/jetpack.php index 5730d465..fde16fb2 100644 --- a/inc/jetpack.php +++ b/inc/jetpack.php @@ -12,7 +12,8 @@ */ function sparkling_jetpack_setup() { add_theme_support( - 'infinite-scroll', array( + 'infinite-scroll', + array( 'type' => 'click', 'container' => 'main', 'footer' => 'page', diff --git a/inc/metaboxes.php b/inc/metaboxes.php index 2c514a6b..6549d4c4 100644 --- a/inc/metaboxes.php +++ b/inc/metaboxes.php @@ -11,25 +11,17 @@ * Add Meta box in page and post post types. */ function sparkling_add_custom_box() { - add_meta_box( - 'siderbar-layout', //Unique ID - __( 'Select layout for this specific Page only ( Note: This setting only reflects if page Template is set as Default Template and Blog Type Templates.)', 'sparkling' ), //Title - 'sparkling_sidebar_layout', //Callback function - 'page' //show metabox in pages - ); - add_meta_box( - 'siderbar-layout', //Unique ID - __( 'Select layout for this specific Post only', 'sparkling' ), //Title - 'sparkling_sidebar_layout', //Callback function - 'post', //show metabox in posts - 'side' - ); - if ( class_exists( 'WooCommerce' ) ) { + foreach ( array( 'page', 'post', 'product' ) as $sparkling_post_type ) { + if ( 'product' === $sparkling_post_type && ! class_exists( 'WooCommerce' ) ) { + continue; + } + + // The ids are unchanged so the boxes keep their saved position and state. add_meta_box( - 'product-siderbar-layout', //Unique ID - __( 'Select layout for this specific Product only', 'sparkling' ), //Title - 'sparkling_sidebar_layout', //Callback function - 'product', //show metabox in posts + 'product' === $sparkling_post_type ? 'product-siderbar-layout' : 'siderbar-layout', + __( 'Layout', 'sparkling' ), + 'sparkling_sidebar_layout', + $sparkling_post_type, 'side' ); } @@ -56,27 +48,19 @@ function sparkling_sidebar_layout( $post ) { // Use nonce for verification wp_nonce_field( basename( __FILE__ ), 'custom_meta_box_nonce' ); ?> - - - - - - - +

    + + + +

    + +

    + %2$s'; - /* - if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) { - $time_string .= ''; - } - */ - $time_string = sprintf( $time_string, esc_attr( get_the_date( 'c' ) ), @@ -49,19 +43,25 @@ function sparkling_posted_on() { esc_html( get_the_modified_date() ) ); + printf( + ' %2$s', + esc_url( get_permalink() ), + $time_string // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Each part escaped above. + ); + + /* + * A post whose author account was deleted, or an attachment uploaded + * by no one, has no author: this printed an empty link to /author/. + */ + $author_name = get_the_author(); + + if ( '' !== (string) $author_name ) { printf( - ' %1$s', - sprintf( - '%2$s', - esc_url( get_permalink() ), - $time_string - ), - sprintf( - '%2$s', - esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ), - esc_html( get_the_author() ) - ) + '', + esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ), + esc_html( $author_name ) ); + } } endif; diff --git a/inc/welcome-screen/class-sparkling-notify-system.php b/inc/welcome-screen/class-sparkling-notify-system.php deleted file mode 100644 index a74d16c0..00000000 --- a/inc/welcome-screen/class-sparkling-notify-system.php +++ /dev/null @@ -1,291 +0,0 @@ -=' ); - } - - /** - * @return bool - */ - public static function is_not_static_page() { - return 'page' == get_option( 'show_on_front' ) ? true : false; - } - - /** - * @return bool - */ - public static function has_widgets() { - if ( ! is_active_sidebar( 'primary-widgets' ) && ! is_active_sidebar( 'secondary-widgets' ) ) { - return false; - } - - return true; - } - - /** - * @return bool - */ - public static function has_posts() { - - $imported = get_option( 'sparkling_importded_demo' ); - if ( $imported ) { - return true; - } - - $count_posts = wp_count_posts( 'post' ); - if ( $count_posts->publish > 4 ) { - add_option( 'sparkling_importded_demo', true ); - return true; - } - - $args = array( - 's' => 'Beautiful Flat Design and Long Shadow Logo Collection', - ); - $query = get_posts( $args ); - if ( ! empty( $query ) ) { - add_option( 'sparkling_importded_demo', true ); - return true; - } - - return false; - } - - /** - * @return bool - */ - public static function has_content() { - $check = array( - 'widgets' => self::has_widgets(), - 'posts' => self::has_posts(), - ); - - if ( $check['widgets'] && $check['posts'] ) { - return true; - } - - return false; - } - - /** - * @return bool - */ - public static function check_wordpress_importer() { - if ( file_exists( ABSPATH . 'wp-content/plugins/wordpress-importer/wordpress-importer.php' ) ) { - include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); - - return is_plugin_active( 'wordpress-importer/wordpress-importer.php' ); - } - - return false; - } - - /** - * @return bool - */ - public static function check_plugin_is_installed( $slug ) { - if ( file_exists( ABSPATH . 'wp-content/plugins/' . $slug . '/' . $slug . '.php' ) ) { - return true; - } - - return false; - } - - /** - * @return bool - */ - public static function check_plugin_is_active( $slug ) { - if ( file_exists( ABSPATH . 'wp-content/plugins/' . $slug . '/' . $slug . '.php' ) ) { - include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); - - return is_plugin_active( $slug . '/' . $slug . '.php' ); - } - } - - public static function has_plugin( $slug = null ) { - - $check = array( - 'installed' => self::check_plugin_is_installed( $slug ), - 'active' => self::check_plugin_is_active( $slug ), - ); - - if ( ! $check['installed'] || ! $check['active'] ) { - return false; - } - - return true; - - } - - public static function has_import_plugin( $slug = null ) { - $return = self::has_content(); - - if ( $return ) { - return true; - } - $check = array( - 'installed' => self::check_plugin_is_installed( $slug ), - 'active' => self::check_plugin_is_active( $slug ), - ); - - if ( ! $check['installed'] || ! $check['active'] ) { - return false; - } - - return true; - } - - public static function has_import_content() { - - $plugin = self::has_import_plugin( 'wordpress-importer' ); - $content = self::has_posts(); - if ( ! $plugin || ! $content ) { - return false; - } - - return true; - - } - - public static function has_import_plugins() { - $check = array( - 'wordpress-importer' => array( - 'installed' => false, - 'active' => false, - ), - 'widget-importer-exporter' => array( - 'installed' => false, - 'active' => false, - ), - ); - - $content = self::has_content(); - $return = false; - if ( $content ) { - return true; - } - - $stop = false; - foreach ( $check as $plugin => $val ) { - if ( $stop ) { - continue; - } - - $check[ $plugin ]['installed'] = self::check_plugin_is_installed( $plugin ); - $check[ $plugin ]['active'] = self::check_plugin_is_active( $plugin ); - - if ( ! $check[ $plugin ]['installed'] || ! $check[ $plugin ]['active'] ) { - $return = true; - $stop = true; - } - } - - return $return; - } - - public static function widget_importer_exporter_title() { - $installed = self::check_plugin_is_installed( 'widget-importer-exporter' ); - if ( ! $installed ) { - return __( 'Install: Widget Importer Exporter Plugin', 'sparkling' ); - } - - $active = self::check_plugin_is_active( 'widget-importer-exporter' ); - if ( $installed && ! $active ) { - return __( 'Activate: Widget Importer Exporter Plugin', 'sparkling' ); - } - - return __( 'Install: Widget Importer Exporter Plugin', 'sparkling' ); - } - - public static function wordpress_importer_title() { - $installed = self::check_plugin_is_installed( 'wordpress-importer' ); - if ( ! $installed ) { - return __( 'Install: WordPress Importer', 'sparkling' ); - } - - $active = self::check_plugin_is_active( 'wordpress-importer' ); - if ( $installed && ! $active ) { - return __( 'Activate: WordPress Importer', 'sparkling' ); - } - - return __( 'Install: WordPress Importer', 'sparkling' ); - } - - /** - * @return string - */ - public static function wordpress_importer_description() { - $installed = self::check_plugin_is_installed( 'wordpress-importer' ); - if ( ! $installed ) { - return __( 'Please install the WordPress Importer to create the demo content.', 'sparkling' ); - } - - $active = self::check_plugin_is_active( 'wordpress-importer' ); - if ( $installed && ! $active ) { - return __( 'Please activate the WordPress Importer to create the demo content.', 'sparkling' ); - } - - return __( 'Please install the WordPress Importer to create the demo content.', 'sparkling' ); - } - - public static function widget_importer_exporter_description() { - $installed = self::check_plugin_is_installed( 'widget-importer-exporter' ); - if ( ! $installed ) { - return __( 'Please install the WordPress widget importer to create the demo content', 'sparkling' ); - } - - $active = self::check_plugin_is_active( 'widget-importer-exporter' ); - if ( $installed && ! $active ) { - return __( 'Please activate the WordPress Widget Importer to create the demo content.', 'sparkling' ); - } - - return __( 'Please install the WordPress widget importer to create the demo content', 'sparkling' ); - - } - - public static function create_plugin_requirement_title( $install_text, $activate_text, $plugin_slug ) { - - if ( '' == $plugin_slug ) { - return; - } - if ( '' == $install_text && '' == $activate_text ) { - return; - } - if ( '' == $install_text && '' == $activate_text ) { - $install_text = $activate_text; - } elseif ( '' == $activate_text && '' == $install_text ) { - $activate_text = $install_text; - } - - $installed = self::check_plugin_is_installed( $plugin_slug ); - if ( ! $installed ) { - return $install_text; - } elseif ( ! self::check_plugin_is_active( $plugin_slug ) && $installed ) { - return $activate_text; - } else { - return ''; - } - - } - - /** - * @return bool - */ - public static function is_not_template_front_page() { - $page_id = get_option( 'page_on_front' ); - - return get_page_template_slug( $page_id ) == 'page-templates/frontpage-template.php' ? true : false; - } - } -}// End if(). diff --git a/inc/welcome-screen/class-sparkling-welcome.php b/inc/welcome-screen/class-sparkling-welcome.php index 5fc9bc34..867f1574 100644 --- a/inc/welcome-screen/class-sparkling-welcome.php +++ b/inc/welcome-screen/class-sparkling-welcome.php @@ -1,562 +1,361 @@ -id ) { - return $classes; - } - - $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'getting_started'; - - if ( in_array( $tab, array( 'recommended_plugins', 'recommended_actions' ), true ) ) { - $classes .= ' plugin-install-php'; - } - - return $classes; - } - - /** - * Look up a published page by title without the deprecated get_page_by_title(). - * - * @param string $title Page title to match. - * @return WP_Post|null - */ - private function get_page_by_title( $title ) { - $query = new WP_Query( - array( - 'post_type' => 'page', - 'title' => $title, - 'post_status' => 'publish', - 'posts_per_page' => 1, - 'no_found_rows' => true, - 'ignore_sticky_posts' => true, - 'update_post_term_cache' => false, - 'update_post_meta_cache' => false, - ) - ); - - return empty( $query->posts ) ? null : $query->posts[0]; - } - - /** - * AJAX: point the front page at the "Homepage" page and the blog at "Blog". - * - * Only ever runs for an authenticated user who can manage options and who - * presents a valid nonce. - */ - public function sparkling_set_pages() { - if ( ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( esc_html__( 'You are not allowed to do that.', 'sparkling' ), 403 ); - } - - check_ajax_referer( 'sparkling_welcome_nonce', 'nonce' ); - - $about = $this->get_page_by_title( 'Homepage' ); - $blog = $this->get_page_by_title( 'Blog' ); - - if ( ! $about instanceof WP_Post ) { - wp_send_json_error( esc_html__( 'No page titled "Homepage" was found.', 'sparkling' ), 404 ); - } - - update_option( 'page_on_front', $about->ID ); - update_option( 'show_on_front', 'page' ); - - if ( $blog instanceof WP_Post ) { - update_option( 'page_for_posts', $blog->ID ); - } - - wp_send_json_success( 'success' ); - } - - /** - * Note: sparkling_activate_plugin() and sparkling_deactivate_plugin() were removed. - * - * They were hooked to admin_init and acted on ?action=activate_plugin / - * ?action=deactivate_plugin without verifying a nonce, which made them - * CSRF-exploitable against any administrator. Nothing in the theme ever - * generated those links: the recommended-plugins tab builds its buttons with - * create_action_link(), which points at core's plugins.php/update.php using - * core's own nonces. The methods were therefore unreachable dead code and - * pure attack surface, so they have been deleted rather than patched. - */ - - /** - * Creates the dashboard page - * - * @see add_theme_page() - * @since 1.8.2.4 - */ - public function sparkling_welcome_register_menu() { - $action_count = $this->count_actions(); - $title = $action_count > 0 ? 'About Sparkling ' . esc_html( $action_count ) . '' : 'About Sparkling'; - - add_theme_page( - 'About Sparkling', $title, 'edit_theme_options', 'sparkling-welcome', array( - $this, - 'sparkling_welcome_screen', - ) - ); - } - - /** - * Adds an admin notice upon successful activation. - * - * @since 1.8.2.4 - */ - public function sparkling_activation_admin_notice() { - global $pagenow; - - if ( is_admin() && ( 'themes.php' == $pagenow ) && isset( $_GET['activated'] ) ) { - add_action( 'admin_notices', array( $this, 'sparkling_welcome_admin_notice' ), 99 ); - } - } - - /** - * Display an admin notice linking to the welcome screen - * - * @since 1.8.2.4 - */ - public function sparkling_welcome_admin_notice() { - ?> -
    -

    ', '' ); ?>

    -

    -
    - base ) { - return; - } - - wp_enqueue_style( 'sparkling-welcome-screen-css', get_template_directory_uri() . '/inc/welcome-screen/css/welcome.css', array(), SPARKLING_VERSION ); - - /* - * The recommended-plugins tab renders core's plugin-card markup. Enqueue - * core's assets here rather than inside the section template, which runs - * after the head has been printed and so only landed via late styles. - */ - if ( $is_welcome_page ) { - wp_enqueue_style( 'plugin-install' ); - wp_enqueue_script( 'plugin-install' ); - wp_enqueue_script( 'updates' ); - add_thickbox(); - } - - if ( 'customize' != $screen->base ) { - wp_enqueue_script( 'sparkling-welcome-screen-js', get_template_directory_uri() . '/inc/welcome-screen/js/welcome.js', array( 'jquery' ), '1.0', true ); - - wp_localize_script( - 'sparkling-welcome-screen-js', 'sparklingWelcomeScreenObject', array( - 'nr_actions_required' => $this->count_actions(), - 'ajaxurl' => admin_url( 'admin-ajax.php' ), - 'template_directory' => get_template_directory_uri(), - 'nonce' => wp_create_nonce( 'sparkling_welcome_nonce' ), - 'no_required_actions_text' => __( 'Hooray! There are no required actions for you right now.', 'sparkling' ), - ) - ); - } - - } - - /** - * Dismiss required actions - * - * @since 1.8.2.4 - */ - public function sparkling_dismiss_required_action_callback() { - global $sparkling_required_actions; - - if ( ! current_user_can( 'edit_theme_options' ) ) { - wp_send_json_error( esc_html__( 'You are not allowed to do that.', 'sparkling' ), 403 ); - } - - check_ajax_referer( 'sparkling_welcome_nonce', 'nonce' ); - - $action_id = isset( $_GET['id'] ) ? sanitize_key( wp_unslash( $_GET['id'] ) ) : 0; - $todo = isset( $_GET['todo'] ) ? sanitize_key( wp_unslash( $_GET['todo'] ) ) : ''; - echo esc_html( $action_id ); /* this is needed and it's the id of the dismissable required action */ - if ( ! empty( $action_id ) ) : - /* if the option exists, update the record for the specified id */ - if ( get_option( 'sparkling_show_required_actions' ) ) : - $sparkling_show_required_actions = get_option( 'sparkling_show_required_actions' ); - switch ( $todo ) { - case 'add': - $sparkling_show_required_actions[ $action_id ] = true; - break; - case 'dismiss': - $sparkling_show_required_actions[ $action_id ] = false; - break; - } - update_option( 'sparkling_show_required_actions', $sparkling_show_required_actions ); - /* create the new option,with false for the specified id */ - else : - $sparkling_show_required_actions_new = array(); - if ( ! empty( $sparkling_required_actions ) ) : - foreach ( $sparkling_required_actions as $sparkling_required_action ) : - if ( $sparkling_required_action['id'] == $action_id ) : - $sparkling_show_required_actions_new[ $sparkling_required_action['id'] ] = false; - else : - $sparkling_show_required_actions_new[ $sparkling_required_action['id'] ] = true; - endif; - endforeach; - update_option( 'sparkling_show_required_actions', $sparkling_show_required_actions_new ); - endif; - endif; - endif; - die(); // this is required to return a proper result - } - - public function sparkling_dismiss_recommended_plugins_callback() { - if ( ! current_user_can( 'edit_theme_options' ) ) { - wp_send_json_error( esc_html__( 'You are not allowed to do that.', 'sparkling' ), 403 ); - } - - check_ajax_referer( 'sparkling_welcome_nonce', 'nonce' ); - - $action_id = isset( $_GET['id'] ) ? sanitize_key( wp_unslash( $_GET['id'] ) ) : 0; - $todo = isset( $_GET['todo'] ) ? sanitize_key( wp_unslash( $_GET['todo'] ) ) : ''; - echo esc_html( $action_id ); /* this is needed and it's the id of the dismissable required action */ - if ( ! empty( $action_id ) ) : - /* if the option exists, update the record for the specified id */ - $sparkling_show_recommended_plugins = get_option( 'sparkling_show_recommended_plugins' ); - - if ( ! is_array( $sparkling_show_recommended_plugins ) ) { - $sparkling_show_recommended_plugins = array(); - } - - switch ( $todo ) { - case 'add': - $sparkling_show_recommended_plugins[ $action_id ] = false; - break; - case 'dismiss': - $sparkling_show_recommended_plugins[ $action_id ] = true; - break; - } - update_option( 'sparkling_show_recommended_plugins', $sparkling_show_recommended_plugins ); - /* create the new option,with false for the specified id */ - endif; - die(); // this is required to return a proper result - } - - /** - * Count the number of required actions - */ - public function count_actions() { - global $sparkling_required_actions; - - $sparkling_show_required_actions = get_option( 'sparkling_show_required_actions' ); - if ( ! is_array( $sparkling_show_required_actions ) ) { - $sparkling_show_required_actions = array(); - } - - if ( ! is_array( $sparkling_required_actions ) ) { - return 0; - } - - $i = 0; - foreach ( $sparkling_required_actions as $action ) { - $true = false; - - if ( ! isset( $action['id'] ) ) { - continue; - } - - if ( empty( $action['check'] ) ) { - $true = true; - } - - if ( ! empty( $sparkling_show_required_actions ) && isset( $sparkling_show_required_actions[ $action['id'] ] ) && ! $sparkling_show_required_actions[ $action['id'] ] ) { - $true = false; - } - - if ( $true ) { - $i ++; - } - } - - return $i; - } - - /** - * Call plugin API to get plugins info - */ - public function call_plugin_api( $slug ) { - include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); - $call_api = get_transient( 'sparkling_plugin_information_transient_' . $slug ); - if ( false === $call_api ) { - $call_api = plugins_api( - 'plugin_information', array( - 'slug' => $slug, - 'fields' => array( - 'downloaded' => false, - 'rating' => false, - 'description' => false, - 'short_description' => true, - 'donate_link' => false, - 'tags' => false, - 'sections' => true, - 'homepage' => true, - 'added' => false, - 'last_updated' => false, - 'compatibility' => false, - 'tested' => false, - 'requires' => false, - 'downloadlink' => false, - 'icons' => true, - ), - ) - ); - set_transient( 'sparkling_plugin_information_transient_' . $slug, $call_api, 30 * MINUTE_IN_SECONDS ); - } - - return $call_api; - } - - /** - * Check if a plugin is active - */ - public function check_active( $slug ) { - if ( file_exists( ABSPATH . 'wp-content/plugins/' . $slug . '/' . $slug . '.php' ) ) { - include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); - - $needs = is_plugin_active( $slug . '/' . $slug . '.php' ) ? 'deactivate' : 'activate'; - - return array( - 'status' => is_plugin_active( $slug . '/' . $slug . '.php' ), - 'needs' => $needs, - ); - } - - return array( - 'status' => false, - 'needs' => 'install', - ); - } - - /** - * Check for icon - */ - public function check_for_icon( $arr ) { - if ( ! empty( $arr['svg'] ) ) { - $plugin_icon_url = $arr['svg']; - } elseif ( ! empty( $arr['2x'] ) ) { - $plugin_icon_url = $arr['2x']; - } elseif ( ! empty( $arr['1x'] ) ) { - $plugin_icon_url = $arr['1x']; - } else { - $plugin_icon_url = $arr['default']; - } - - return $plugin_icon_url; - } - - /** - * Create action link - */ - public function create_action_link( $state, $slug ) { - switch ( $state ) { - case 'install': - return wp_nonce_url( - add_query_arg( - array( - 'action' => 'install-plugin', - 'plugin' => $slug, - ), - network_admin_url( 'update.php' ) - ), - 'install-plugin_' . $slug - ); - break; - case 'deactivate': - return add_query_arg( - array( - 'action' => 'deactivate', - 'plugin' => rawurlencode( $slug . '/' . $slug . '.php' ), - 'plugin_status' => 'all', - 'paged' => '1', - '_wpnonce' => wp_create_nonce( 'deactivate-plugin_' . $slug . '/' . $slug . '.php' ), - ), network_admin_url( 'plugins.php' ) - ); - break; - case 'activate': - return add_query_arg( - array( - 'action' => 'activate', - 'plugin' => rawurlencode( $slug . '/' . $slug . '.php' ), - 'plugin_status' => 'all', - 'paged' => '1', - '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $slug . '/' . $slug . '.php' ), - ), network_admin_url( 'plugins.php' ) - ); - break; - } - } - - /** - * Welcome screen content - * - * @since 1.8.2.4 - */ - public function sparkling_welcome_screen() { - if ( ! current_user_can( 'edit_theme_options' ) ) { - wp_die( esc_html__( 'You are not allowed to access this page.', 'sparkling' ) ); - } - - $sparkling = wp_get_theme( get_template() ); // the parent: a child theme would report its own version - $allowed = array( 'getting_started', 'recommended_actions', 'recommended_plugins', 'changelog', 'support' ); - $active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'getting_started'; - - if ( ! in_array( $active_tab, $allowed, true ) ) { - $active_tab = 'getting_started'; - } - - ?> - -
    - -

    - -
    - - - - - - -
    '; - } - - switch ( $active_tab ) { - case 'getting_started': - get_template_part( 'inc/welcome-screen/sections/getting-started' ); - break; - case 'recommended_actions': - get_template_part( 'inc/welcome-screen/sections/actions-required' ); - break; - case 'recommended_plugins': - get_template_part( 'inc/welcome-screen/sections/recommended-plugins' ); - break; - case 'changelog': - get_template_part( 'inc/welcome-screen/sections/changelog' ); - break; - case 'support': - get_template_part( 'inc/welcome-screen/sections/support' ); - break; - default: - get_template_part( 'inc/welcome-screen/sections/getting-started' ); - break; - } - ?> - - -
    - - About Sparkling. + * + * @package sparkling + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + +if ( ! class_exists( 'Sparkling_Welcome' ) ) : + + /** + * Welcome Screen Class + * + * The "recommended actions" machinery this class used to carry -- a tab, two + * dismiss AJAX handlers, an action counter for the menu badge and an AJAX + * handler that set the front page to a page titled "Homepage" -- was removed + * in 2.7.0. The theme defines no recommended actions, so the counter was + * always 0, nothing linked to the tab, and opening it was a fatal error + * ("Using $this when not in object context"). + */ + class Sparkling_Welcome { + + /** + * The About page's tabs: slug => template part. + * + * @var array + */ + private $tabs = array( + 'getting_started' => 'getting-started', + 'recommended_plugins' => 'recommended-plugins', + 'changelog' => 'changelog', + 'support' => 'support', + ); + + /** + * Constructor for the welcome screen + */ + public function __construct() { + add_action( 'admin_menu', array( $this, 'sparkling_welcome_register_menu' ) ); + add_action( 'load-themes.php', array( $this, 'sparkling_activation_admin_notice' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'sparkling_welcome_style_and_scripts' ) ); + add_filter( 'admin_body_class', array( $this, 'sparkling_admin_body_class' ) ); + } + + /** + * The tab being viewed. + * + * @return string + */ + private function current_tab() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only navigation. + $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'getting_started'; + + return isset( $this->tabs[ $tab ] ) ? $tab : 'getting_started'; + } + + /** + * Borrow core's plugin-install body class on the tab that renders plugin cards. + * + * Core's layout for .plugin-card is scoped to the .plugin-install-php body + * class, which WordPress only sets on plugin-install.php: + * + * .plugin-install-php #the-list { display: flex; flex-wrap: wrap; } + * .plugin-install-php .plugin-card { display: flex; flex-direction: column; + * justify-content: space-between; } + * + * Without it the floated cards never clear, so #the-list collapses to zero + * height and everything after it overlaps. Adding the class gives us core's + * flex grid and equal-height cards without the theme shipping any CSS. + * + * @param string $classes Space-separated admin body classes. + * @return string + */ + public function sparkling_admin_body_class( $classes ) { + $screen = get_current_screen(); + + if ( $screen && 'appearance_page_sparkling-welcome' === $screen->id && 'recommended_plugins' === $this->current_tab() ) { + $classes .= ' plugin-install-php'; + } + + return $classes; + } + + /** + * Creates the dashboard page + * + * @see add_theme_page() + * @since 1.8.2.4 + */ + public function sparkling_welcome_register_menu() { + $title = __( 'About Sparkling', 'sparkling' ); + + add_theme_page( $title, $title, 'edit_theme_options', 'sparkling-welcome', array( $this, 'sparkling_welcome_screen' ) ); + } + + /** + * Adds an admin notice upon successful activation. + * + * @since 1.8.2.4 + */ + public function sparkling_activation_admin_notice() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Core's own "activated" flag. + if ( isset( $_GET['activated'] ) && current_user_can( 'edit_theme_options' ) ) { + add_action( 'admin_notices', array( $this, 'sparkling_welcome_admin_notice' ), 99 ); + } + } + + /** + * Display an admin notice linking to the welcome screen + * + * @since 1.8.2.4 + */ + public function sparkling_welcome_admin_notice() { + ?> +
    +

    + ', + '' + ); + ?> +

    +

    +
    + current_tab() ) { + wp_enqueue_style( 'plugin-install' ); + wp_enqueue_script( 'plugin-install' ); + wp_enqueue_script( 'updates' ); + add_thickbox(); + } + } + + /** + * Call plugin API to get plugins info + * + * @param string $slug Plugin slug on WordPress.org. + * @return object|WP_Error + */ + public function call_plugin_api( $slug ) { + include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; + $call_api = get_transient( 'sparkling_plugin_information_transient_' . $slug ); + if ( false === $call_api ) { + $call_api = plugins_api( + 'plugin_information', + array( + 'slug' => $slug, + 'fields' => array( + 'downloaded' => false, + 'rating' => false, + 'description' => false, + 'short_description' => true, + 'donate_link' => false, + 'tags' => false, + 'sections' => true, + 'homepage' => true, + 'added' => false, + 'last_updated' => false, + 'compatibility' => false, + 'tested' => false, + 'requires' => false, + 'downloadlink' => false, + 'icons' => true, + ), + ) + ); + set_transient( 'sparkling_plugin_information_transient_' . $slug, $call_api, 30 * MINUTE_IN_SECONDS ); + } + + return $call_api; + } + + /** + * The installed plugin file for a WordPress.org slug, e.g. "kali-forms/kali-forms.php". + * + * This used to assume ABSPATH . 'wp-content/plugins//.php', which + * is wrong for a relocated content directory and for any plugin whose main + * file is named differently -- FancyBox for WordPress is fancybox.php -- so + * those always showed "Install" even when installed and active. + * + * @param string $slug Plugin slug, which is its directory name. + * @return string Plugin file relative to the plugins directory, or ''. + */ + public function plugin_file( $slug ) { + include_once ABSPATH . 'wp-admin/includes/plugin.php'; + + foreach ( array_keys( get_plugins( '/' . $slug ) ) as $file ) { + return $slug . '/' . $file; + } + + return ''; + } + + /** + * Check if a plugin is installed and active. + * + * @param string $slug Plugin slug. + * @return array {status: bool active, needs: install|activate|deactivate, file: string} + */ + public function check_active( $slug ) { + $file = $this->plugin_file( $slug ); + + if ( '' === $file ) { + return array( + 'status' => false, + 'needs' => 'install', + 'file' => '', + ); + } + + $active = is_plugin_active( $file ); + + return array( + 'status' => $active, + 'needs' => $active ? 'deactivate' : 'activate', + 'file' => $file, + ); + } + + /** + * Check for icon + * + * @param array $arr Icons from the plugins API. + * @return string + */ + public function check_for_icon( $arr ) { + if ( ! empty( $arr['svg'] ) ) { + $plugin_icon_url = $arr['svg']; + } elseif ( ! empty( $arr['2x'] ) ) { + $plugin_icon_url = $arr['2x']; + } elseif ( ! empty( $arr['1x'] ) ) { + $plugin_icon_url = $arr['1x']; + } else { + $plugin_icon_url = isset( $arr['default'] ) ? $arr['default'] : ''; + } + + return $plugin_icon_url; + } + + /** + * Create action link + * + * @param string $state install, activate or deactivate. + * @param string $slug Plugin slug. + * @return string + */ + public function create_action_link( $state, $slug ) { + $file = $this->plugin_file( $slug ); + + switch ( $state ) { + case 'install': + return wp_nonce_url( + add_query_arg( + array( + 'action' => 'install-plugin', + 'plugin' => $slug, + ), + network_admin_url( 'update.php' ) + ), + 'install-plugin_' . $slug + ); + case 'deactivate': + case 'activate': + return add_query_arg( + array( + 'action' => $state, + 'plugin' => rawurlencode( $file ), + 'plugin_status' => 'all', + 'paged' => '1', + '_wpnonce' => wp_create_nonce( $state . '-plugin_' . $file ), + ), + network_admin_url( 'plugins.php' ) + ); + } + + return ''; + } + + /** + * Welcome screen content + * + * @since 1.8.2.4 + */ + public function sparkling_welcome_screen() { + if ( ! current_user_can( 'edit_theme_options' ) ) { + wp_die( esc_html__( 'You are not allowed to access this page.', 'sparkling' ) ); + } + + $sparkling = wp_get_theme( get_template() ); // The parent: a child theme would report its own version. + $active_tab = $this->current_tab(); + $labels = array( + 'getting_started' => __( 'Getting Started', 'sparkling' ), + 'recommended_plugins' => __( 'Recommended Plugins', 'sparkling' ), + 'changelog' => __( 'Changelog', 'sparkling' ), + 'support' => __( 'Support', 'sparkling' ), + ); + ?> + +
    + +

    get( 'Version' ) ); ?>

    + +
    + + + + + +
    '; + } + + get_template_part( 'inc/welcome-screen/sections/' . $this->tabs[ $active_tab ] ); + ?> + +
    + + About Sparkling * ------------------------------------------------------------------------- */ -/* New Logo */ +/* Logo */ .wp-badge.epsilon-welcome-logo { - color: #fff; - background-image: url(../img/logo.png); - background-position: center center; - background-size: 70%; - background-repeat: no-repeat; + color: #fff; + background-image: url("../img/logo.png"); + background-position: center center; + background-size: 70%; + background-repeat: no-repeat; } -/* proper positioning of the icons */ +/* Proper positioning of the icons */ .epsilon-wrap i.dashicons { - margin-right: 15px; - position: relative; - top: 3px; + margin-right: 15px; + position: relative; + top: 3px; } -.feature-section.action-required { - margin-top: 20px; - padding-bottom: 0; -} - -.action-required span.hooray { - padding: 10px; - display: inline-block; -} - -.action-required span.red { - color: #a00; -} - -.sparkling-action-required-box:last-of-type { - border-bottom: none; -} - -.sparkling-action-required-box { - display: block; - border-left: 3px solid #f8800c; - padding: 10px 25px 5px; - background: #FFFFFF; - box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); - margin-bottom: 15px; - position: relative; -} -.sparkling-required-action-button, -.sparkling-recommended-plugin-button, -.sparkling-dismiss-required-action { - position: absolute; - top: 10px; - right: 10px; - text-decoration: none; - color: #d54e21; - border-radius: 50%; - cursor: pointer; -} -.about-wrap .sparkling-action-required-box h4 { - display: block; - margin-top: 0; - margin-bottom: 0; -} - -.about-wrap .sparkling-action-required-box p { - display: block; - margin-top: 0; - width: 100%; - max-width: 100%; -} -.epsilon-recommeded-actions { - position: relative; -} - -.epsilon-recommeded-actions .sparkling-dismiss-required-action, -.epsilon-recommeded-actions .sparkling-recommended-plugin-button { - top: 0; - right: 0; -} -.epsilon-recommeded-actions #temp_load { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba( 0,0,0,.2 ); - display: flex; - align-items: center; -} -.epsilon-recommeded-actions #temp_load img { - margin: 0 auto; -} - -.badge-action-count { - padding: 0 6px; - display: inline-block; - background-color: #d54e21; - color: #fff; - font-size: 9px; - line-height: 17px; - font-weight: 600; - margin: 1px 0 0 2px; - vertical-align: top; - -webkit-border-radius: 10px; - border-radius: 10px; - z-index: 26; - margin-top: 5px; - margin-left: 5px; -} - -.wp-submenu .badge-action-count { - margin-top: 0; -} - -.sparkling-welcome-task { - display: block; - font-size: 14px; - margin: 10px 0; -} -.sparkling-welcome-task .sparkling-welcome-icon { - color: #888; -} .about-wrap.epsilon-wrap img { - border: 0 none; -} \ No newline at end of file + border: 0 none; +} diff --git a/inc/welcome-screen/css/welcome_customizer.css b/inc/welcome-screen/css/welcome_customizer.css deleted file mode 100644 index 250b62af..00000000 --- a/inc/welcome-screen/css/welcome_customizer.css +++ /dev/null @@ -1,130 +0,0 @@ -.sparkling-actions-count { - padding: 0 6px; - display: inline-block; - background-color: #d54e21; - color: #fff; - font-size: 9px; - line-height: 17px; - font-weight: 600; - margin: 1px 0 0 2px; - vertical-align: top; - -webkit-border-radius: 10px; - border-radius: 10px; - z-index: 26; -} - -.button.change-theme { - display: none; -} - -div.recomended-actions_container { - padding: 0 10px; - margin-bottom: 2em; -} -.recomended-actions_container p.succes { - margin: 1em 0; -} -.epsilon-recommeded-actions p.title { - margin-bottom: 0; - font-size: 14px; - color: #555d66; - font-weight: 600; -} -.epsilon-recommeded-actions div.description { - font-size: 12px; -} -.epsilon-recommeded-actions .custom-action { - border-top: 1px solid #fafafa; - margin-top: 1em; - padding-top: 1em; -} -.epsilon-recommeded-actions .custom-action p { - margin-top: 0; -} -.recomended-actions_container .epsilon-recommeded-actions-container:not(:first-child) { - opacity: 0; - height: 0; - overflow: hidden; -} -.recomended-actions_container .epsilon-recommeded-actions-container:first-child { - height: auto; - opacity: 1; -} -.recomended-actions_container .epsilon-recommeded-actions-container { - -webkit-transition: opacity 2s; /* Safari */ - transition: opacity 2s; -} -.recomended-actions_container .hide { - display: none; -} -.sparkling-actions-count.complete { - background-color: #79ba49; -} -.recomended-actions_container #demo_content .button { - display: block; - margin-bottom: 1em; - text-align: center; -} -.recomended-actions_container .succes a { - width: 100%; - text-align: center; - display: inline-block; -} -.recomended-actions_container .succes a.social { - width: 49%; - margin-bottom: 1em; - line-height: 20px; - padding-top: 4px; -} -.recomended-actions_container .succes a.social span, -.recomended-actions_container .succes a.sparkling-wordpress span { - margin-right: 5px; -} -.recomended-actions_container .succes a.sparkling-wordpress { - line-height: 20px; - padding-top: 4px; -} - -/* Upsell */ -.macho-upsell { - background: #fff; - border-radius: 10px; - padding: 20px; -} -.macho-upsell span.wp-ui-notification { - padding: 2px 8px; - text-transform: uppercase; - font-size: 10px; - font-weight: bold; - border-radius: 5px; - margin-right: 5px; - display: inline-block; -} -.macho-upsell-options li { - margin-bottom: 20px; - display: inline-block; -} -.macho-upsell .button { - display: block; - text-align: center; -} -ul.macho-upsell-requirements { - font-size: 12px; -} -.macho-upsell-requirements li { - line-height: 1.75; - margin-bottom: 10px; - font-style: italic; -} -#accordion-section-sparkling_upsell h3.accordion-section-title, -#customize-controls #accordion-section-sparkling_upsell h3.accordion-section-title:focus, -#customize-controls #accordion-section-sparkling_upsell:hover h3.accordion-section-title { - color: #fff; - background: #0073aa; - border-left-color: #0073aa; -} -#accordion-section-sparkling_upsell h3.accordion-section-title:after, -#customize-controls #accordion-section-sparkling_upsell h3.accordion-section-title:focus:after, -#customize-controls #accordion-section-sparkling_upsell:hover h3.accordion-section-title:after { - color: #fff; -} \ No newline at end of file diff --git a/inc/welcome-screen/img/ajax-loader.gif b/inc/welcome-screen/img/ajax-loader.gif deleted file mode 100644 index b3d9b974..00000000 Binary files a/inc/welcome-screen/img/ajax-loader.gif and /dev/null differ diff --git a/inc/welcome-screen/js/welcome.js b/inc/welcome-screen/js/welcome.js deleted file mode 100644 index 3441d753..00000000 --- a/inc/welcome-screen/js/welcome.js +++ /dev/null @@ -1,84 +0,0 @@ -jQuery(document).ready(function () { - - /* If there are required actions, add an icon with the number of required actions in the About sparkling page -> Actions required tab */ - var sparkling_nr_actions_required = sparklingWelcomeScreenObject.nr_actions_required; - - if ((typeof sparkling_nr_actions_required !== 'undefined') && (sparkling_nr_actions_required != '0')) { - jQuery('li.sparkling-w-red-tab a').append('' + sparkling_nr_actions_required + ''); - } - - - /* Dismiss required actions */ - jQuery(".sparkling-required-action-button").on('click', function () { - - var id = jQuery(this).attr('id'), - action = jQuery(this).attr('data-action'); - jQuery.ajax({ - type : "GET", - data : { action: 'sparkling_dismiss_required_action', id: id, todo: action, nonce: sparklingWelcomeScreenObject.nonce }, - dataType : "html", - url : sparklingWelcomeScreenObject.ajaxurl, - beforeSend: function (data, settings) { - jQuery('.sparkling-tab-pane#actions_required h1').append('
    '); - }, - success : function (data) { - location.reload(); - jQuery("#temp_load").remove(); - /* Remove loading gif */ - }, - error : function (jqXHR, textStatus, errorThrown) { - console.log(jqXHR + " :: " + textStatus + " :: " + errorThrown); - } - }); - }); - - /* Dismiss recommended plugins */ - jQuery(".sparkling-recommended-plugin-button").on('click', function () { - - var id = jQuery(this).attr('id'), - action = jQuery(this).attr('data-action'); - jQuery.ajax({ - type : "GET", - data : { action: 'sparkling_dismiss_recommended_plugins', id: id, todo: action, nonce: sparklingWelcomeScreenObject.nonce }, - dataType : "html", - url : sparklingWelcomeScreenObject.ajaxurl, - beforeSend: function (data, settings) { - jQuery('.sparkling-tab-pane#actions_required h1').append('
    '); - }, - success : function (data) { - location.reload(); - jQuery("#temp_load").remove(); - /* Remove loading gif */ - }, - error : function (jqXHR, textStatus, errorThrown) { - console.log(jqXHR + " :: " + textStatus + " :: " + errorThrown); - } - }); - }); - - - // Add automatic frontpage - jQuery('#set_page_automatic').on('click', function(evt){ - evt.preventDefault(); - var parent = jQuery(this).parent().parent(); - var container = jQuery(this).parent().parent().parent(); - - jQuery.ajax({ - type: "GET", - data: {action: 'sparkling_set_frontpage', nonce: sparklingWelcomeScreenObject.nonce }, - dataType: "html", - url: sparklingWelcomeScreenObject.ajaxurl, - beforeSend: function (data, settings) { - parent.append('
    '); - }, - success: function (data) { - location.reload(); - jQuery("#temp_load").remove(); - }, - error: function (jqXHR, textStatus, errorThrown) { - console.log(jqXHR + " :: " + textStatus + " :: " + errorThrown); - } - }); - }); - -}); diff --git a/inc/welcome-screen/js/welcome_customizer.js b/inc/welcome-screen/js/welcome_customizer.js deleted file mode 100644 index 8a99086e..00000000 --- a/inc/welcome-screen/js/welcome_customizer.js +++ /dev/null @@ -1,123 +0,0 @@ -(function (api) { - // Sections that are a link rather than a panel of controls (see - // inc/class-sparkling-customize-link-section.php). Core hides any section - // with no active controls, so without this they are printed and never shown. - api.sectionConstructor['sparkling-link'] = api.Section.extend({ - attachEvents: function () {}, - isContextuallyActive: function () { - return true; - }, - }); - - // Extends our custom "sparkling-pro-section" section. - api.sectionConstructor['sparkling-recomended-section'] = api.Section.extend({ - // No events for this type of section. - attachEvents: function () {}, - - // Always make the section active. - isContextuallyActive: function () { - return true; - }, - }); -})(wp.customize); - -jQuery(document).ready(function () { - jQuery('.sparkling-dismiss-required-action').on('click', function () { - var id = jQuery(this).attr('id'), - action = jQuery(this).attr('data-action'); - jQuery.ajax({ - type: 'GET', - data: { action: 'sparkling_dismiss_required_action', id: id, todo: action }, - dataType: 'html', - url: sparklingWelcomeScreenObject.ajaxurl, - beforeSend: function (data, settings) { - jQuery('#' + id) - .parent() - .append('
    '); - }, - success: function (data) { - var container = jQuery('#' + data) - .parent() - .parent(); - var index = container.next().data('index'); - jQuery('.sparkling-actions-count .current-index').text(index); - container.slideToggle().remove(); - if (jQuery('.recomended-actions_container > .epsilon-required-actions').length == 0) { - jQuery('#accordion-section-sparkling_recomended-section .sparkling-actions-count').remove(); - - if (jQuery('.recomended-actions_container > .epsilon-recommended-plugins').length == 0) { - jQuery('.recomended-actions_container .succes').removeClass('hide'); - jQuery('#accordion-section-sparkling_recomended-section .section-title').text(jQuery('#accordion-section-sparkling_recomended-section .section-title').data('social')); - } else { - jQuery('#accordion-section-sparkling_recomended-section .section-title').text(jQuery('#accordion-section-sparkling_recomended-section .section-title').data('plugin_text')); - } - } - }, - error: function (jqXHR, textStatus, errorThrown) { - console.log(jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown); - }, - }); - }); - - jQuery('.sparkling-recommended-plugin-button').on('click', function () { - var id = jQuery(this).attr('id'), - action = jQuery(this).attr('data-action'); - jQuery.ajax({ - type: 'GET', - data: { action: 'sparkling_dismiss_recommended_plugins', id: id, todo: action }, - dataType: 'html', - url: sparklingWelcomeScreenObject.ajaxurl, - beforeSend: function (data, settings) { - jQuery('#' + id) - .parent() - .append('
    '); - }, - success: function (data) { - var container = jQuery('#' + data) - .parent() - .parent(); - var index = container.next().data('index'); - jQuery('.sparkling-actions-count .current-index').text(index); - container.slideToggle().remove(); - - if (jQuery('.recomended-actions_container > .epsilon-recommended-plugins').length == 0) { - jQuery('.recomended-actions_container .succes').removeClass('hide'); - jQuery('#accordion-section-sparkling_recomended-section .section-title').text(jQuery('#accordion-section-sparkling_recomended-section .section-title').data('social')); - } - }, - error: function (jqXHR, textStatus, errorThrown) { - console.log(jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown); - }, - }); - }); - - jQuery('#set_page_automatic').on('click', function (evt) { - evt.preventDefault(); - var parent = jQuery(this).parent().parent(); - var container = jQuery(this).parent().parent().parent(); - - jQuery.ajax({ - type: 'GET', - data: { action: 'sparkling_set_frontpage' }, - dataType: 'html', - url: sparklingWelcomeScreenObject.ajaxurl, - beforeSend: function (data, settings) { - parent.append('
    '); - }, - success: function (data) { - var index = container.next().data('index'); - jQuery('.sparkling-actions-count .current-index').text(index); - container.slideToggle().remove(); - if (jQuery('.recomended-actions_container .epsilon-recommeded-actions-container').length == 0) { - jQuery('.recomended-actions_container .succes').removeClass('hide'); - jQuery('#accordion-section-sparkling_recomended-section .sparkling-actions-count').remove(); - jQuery('#accordion-section-sparkling_recomended-section .section-title').text(jQuery('#accordion-section-sparkling_recomended-section .section-title').data('succes')); - } - wp.customize.previewer.refresh(); - }, - error: function (jqXHR, textStatus, errorThrown) { - console.log(jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown); - }, - }); - }); -}); diff --git a/inc/welcome-screen/sections/actions-required.php b/inc/welcome-screen/sections/actions-required.php deleted file mode 100644 index 3bede8e0..00000000 --- a/inc/welcome-screen/sections/actions-required.php +++ /dev/null @@ -1,162 +0,0 @@ - - -
    - - $sparkling_required_action_value ) : - $hidden = false; - if ( isset( $sparkling_show_required_actions[ $sparkling_required_action_value['id'] ] ) && false === $sparkling_show_required_actions[ $sparkling_required_action_value['id'] ] ) { - $hidden = true; - } - if ( isset( $sparkling_required_action_value['check'] ) && $sparkling_required_action_value['check'] ) { - continue; - } - $nr_actions_required ++; - if ( $hidden ) { - $nr_action_dismissed ++; - } - - ?> -
    - - - - - -

    - -

    -

    - - ' . wp_kses_post( $sparkling_required_action_value['help'] ); -endif; -?> -

    - check_active( $sparkling_required_action_value['plugin_slug'] ); - $url = $this->create_action_link( $active['needs'], $sparkling_required_action_value['plugin_slug'] ); - $label = ''; - switch ( $active['needs'] ) { - case 'install': - $class = 'install-now button'; - $label = __( 'Install', 'sparkling' ); - break; - case 'activate': - $class = 'activate-now button button-primary'; - $label = __( 'Activate', 'sparkling' ); - break; - case 'deactivate': - $class = 'deactivate-now button'; - $label = __( 'Deactivate', 'sparkling' ); - break; - } - ?> -

    - -

    - -
    - $plugin_opt ) { - - if ( ! $plugin_opt['recommended'] ) { - continue; - } - - if ( Sparkling_Notify_System::has_plugin( $slug ) ) { - continue; - } - if ( 0 == $nr_recommended_plugins ) { - echo '

    ' . esc_html__( 'Hooray! There are no required actions for you right now. But you can make your theme more powerful with next actions: ', 'sparkling' ) . '

    '; - } - - $nr_recommended_plugins ++; - echo '
    '; - - if ( isset( $sparkling_show_recommended_plugins[ $slug ] ) && $sparkling_show_recommended_plugins[ $slug ] ) : - ?> - - - - check_active( $slug ); - $url = $this->create_action_link( $active['needs'], $slug ); - $info = $this->call_plugin_api( $slug ); - $label = ''; - $class = ''; -switch ( $active['needs'] ) { - case 'install': - $class = 'install-now button'; - $label = __( 'Install', 'sparkling' ); - break; - case 'activate': - $class = 'activate-now button button-primary'; - $label = __( 'Activate', 'sparkling' ); - break; - case 'deactivate': - $class = 'deactivate-now button'; - $label = __( 'Deactivate', 'sparkling' ); - break; -} - ?> -

    name ); ?>

    -

    - short_description ); ?> -

    -

    - -

    - '; - - }// End foreach(). - - endif; - - if ( 0 == $nr_recommended_plugins && 0 == $nr_actions_required ) { - echo '' . esc_html__( 'Hooray! There are no required actions for you right now.', 'sparkling' ) . ''; - } - - ?> - -
    diff --git a/inc/welcome-screen/sections/changelog.php b/inc/welcome-screen/sections/changelog.php index de590f99..bb7b0ca2 100644 --- a/inc/welcome-screen/sections/changelog.php +++ b/inc/welcome-screen/sections/changelog.php @@ -1,10 +1,10 @@ @@ -20,10 +20,12 @@ if ( ! file_exists( $sparkling_changelog_file ) || ! is_readable( $sparkling_changelog_file ) ) { echo '

    ' . esc_html__( 'The changelog file could not be found.', 'sparkling' ) . '

    '; } else { - WP_Filesystem(); - global $wp_filesystem; - - $sparkling_changelog = $wp_filesystem ? $wp_filesystem->get_contents( $sparkling_changelog_file ) : false; + /* + * A plain read of the theme's own file. WP_Filesystem() is for writing + * during upgrades: on a host without direct file access it needs FTP + * credentials, so the tab showed "could not be read". + */ + $sparkling_changelog = file_get_contents( $sparkling_changelog_file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local theme file. if ( false === $sparkling_changelog || '' === $sparkling_changelog ) { echo '

    ' . esc_html__( 'The changelog file could not be read.', 'sparkling' ) . '

    '; diff --git a/inc/welcome-screen/sections/getting-started.php b/inc/welcome-screen/sections/getting-started.php index 1e49f399..cfed4935 100644 --- a/inc/welcome-screen/sections/getting-started.php +++ b/inc/welcome-screen/sections/getting-started.php @@ -1,49 +1,30 @@ count_actions(); - -$customizer_url = admin_url() . 'customize.php'; -$count = $count_actions; ?>
    -
    -

    -

    - -

    - -

    - -

    -

    - -
    +
    +

    +

    +

    +
    -
    -

    -

    -

    - -

    -
    +
    +

    +

    +

    + +

    +
    -
    -

    -

    -

    -

    -
    -
    \ No newline at end of file +
    +

    +

    +

    +
    +
    diff --git a/inc/welcome-screen/sections/recommended-plugins.php b/inc/welcome-screen/sections/recommended-plugins.php index 3a0dbce8..1e2674c1 100644 --- a/inc/welcome-screen/sections/recommended-plugins.php +++ b/inc/welcome-screen/sections/recommended-plugins.php @@ -8,17 +8,10 @@ * on admin_enqueue_scripts. The theme adds no CSS of its own for this tab. */ -global $sparkling_recommended_plugins; - -// Initialize the Sparkling_Welcome class -$sparkling_welcome = new Sparkling_Welcome(); - -// Get the required functions from the class -$call_plugin_api = array( $sparkling_welcome, 'call_plugin_api' ); -$check_for_icon = array( $sparkling_welcome, 'check_for_icon' ); -$check_active = array( $sparkling_welcome, 'check_active' ); -$create_action_link = array( $sparkling_welcome, 'create_action_link' ); +global $sparkling_recommended_plugins, $sparkling_welcome; +$sparkling_can_install = current_user_can( 'install_plugins' ); +$sparkling_can_activate = current_user_can( 'activate_plugins' ); ?>
    @@ -26,44 +19,44 @@
    $prop ) { + foreach ( array_keys( $sparkling_recommended_plugins ) as $sparkling_plugin ) { - $info = call_user_func( $call_plugin_api, $plugin ); + $sparkling_info = $sparkling_welcome->call_plugin_api( $sparkling_plugin ); /* * plugins_api() returns WP_Error when wordpress.org cannot be reached. * Previously the properties below were read straight off it, so an * offline site rendered a broken tab. */ - if ( is_wp_error( $info ) || empty( $info->name ) ) { + if ( is_wp_error( $sparkling_info ) || empty( $sparkling_info->name ) ) { continue; } - $icon = call_user_func( $check_for_icon, $info->icons ); - $active = call_user_func( $check_active, $plugin ); - $url = call_user_func( $create_action_link, $active['needs'], $plugin ); + $sparkling_icon = $sparkling_welcome->check_for_icon( $sparkling_info->icons ); + $sparkling_active = $sparkling_welcome->check_active( $sparkling_plugin ); + $sparkling_url = $sparkling_welcome->create_action_link( $sparkling_active['needs'], $sparkling_plugin ); - $is_active = ( 'install' !== $active['needs'] && $active['status'] ); + $sparkling_is_active = ( 'install' !== $sparkling_active['needs'] && $sparkling_active['status'] ); - switch ( $active['needs'] ) { + switch ( $sparkling_active['needs'] ) { case 'install': - $class = 'install-now button'; - $label = __( 'Install Now', 'sparkling' ); + $sparkling_class = 'install-now button'; + $sparkling_label = __( 'Install Now', 'sparkling' ); break; case 'activate': - $class = 'activate-now button button-primary'; - $label = __( 'Activate', 'sparkling' ); + $sparkling_class = 'activate-now button button-primary'; + $sparkling_label = __( 'Activate', 'sparkling' ); break; default: - $class = 'button'; - $label = __( 'Deactivate', 'sparkling' ); + $sparkling_class = 'button'; + $sparkling_label = __( 'Deactivate', 'sparkling' ); break; } - $details_url = add_query_arg( + $sparkling_details_url = add_query_arg( array( 'tab' => 'plugin-information', - 'plugin' => $plugin, + 'plugin' => $sparkling_plugin, 'TB_iframe' => 'true', 'width' => 600, 'height' => 550, @@ -71,13 +64,13 @@ self_admin_url( 'plugin-install.php' ) ); ?> -
    +
    @@ -85,16 +78,23 @@
    -

    short_description ); ?>

    -

    short_description ); ?>

    +

    + author ) ); - ?>

    + printf( esc_html__( 'By %s', 'sparkling' ), wp_kses_post( $sparkling_info->author ) ); + ?> +

    - version ); ?> + version ); ?>
    - + - + @@ -127,7 +129,7 @@ class=""
    diff --git a/inc/welcome-screen/sections/support.php b/inc/welcome-screen/sections/support.php index 72a0c0be..fe2a5a1f 100644 --- a/inc/welcome-screen/sections/support.php +++ b/inc/welcome-screen/sections/support.php @@ -1,34 +1,41 @@ +
    -

    +

    - +

    -

    +

    -

    +

    - +

    -

    +

    - +

    -
    +
    diff --git a/inc/welcome-screen/welcome-page-setup.php b/inc/welcome-screen/welcome-page-setup.php index ee0819ea..d31fb497 100644 --- a/inc/welcome-screen/welcome-page-setup.php +++ b/inc/welcome-screen/welcome-page-setup.php @@ -36,7 +36,7 @@ function sparkling_welcome_customize_register( $wp_customize ) { $wp_customize, 'sparkling_recommended_actions', array( - 'title' => esc_html__( 'Recommended Actions & Plugins', 'sparkling' ), + 'title' => esc_html__( 'Recommended Plugins', 'sparkling' ), 'url' => admin_url( 'themes.php?page=sparkling-welcome&tab=recommended_plugins' ), 'priority' => 0, ) @@ -56,71 +56,48 @@ function sparkling_welcome_customize_register( $wp_customize ) { ); } -add_action( 'customize_controls_enqueue_scripts', 'sparkling_welcome_scripts_for_customizer', 0 ); - -function sparkling_welcome_scripts_for_customizer() { - wp_enqueue_style( 'sparkling-welcome-screen-customizer-css', get_template_directory_uri() . '/inc/welcome-screen/css/welcome_customizer.css' ); - wp_enqueue_style( 'plugin-install' ); - wp_enqueue_script( 'plugin-install' ); - wp_enqueue_script( 'updates' ); - wp_add_inline_script( 'plugin-install', 'var pagenow = "customizer";' ); - wp_enqueue_script( 'sparkling-welcome-screen-customizer-js', get_template_directory_uri() . '/inc/welcome-screen/js/welcome_customizer.js', array( 'customize-controls' ), '1.0', true ); - - wp_localize_script( - 'sparkling-welcome-screen-customizer-js', 'sparklingWelcomeScreenObject', array( - 'ajaxurl' => admin_url( 'admin-ajax.php' ), - 'template_directory' => get_template_directory_uri(), - ) - ); - -} - -// Load the system checks ( used for notifications ) -require get_template_directory() . '/inc/welcome-screen/class-sparkling-notify-system.php'; +/* + * sparkling_welcome_scripts_for_customizer() was removed in 2.7.0. It loaded + * core's plugin installer scripts into the Customizer for an installer that + * no longer lives there, and a stylesheet whose one live rule hid the + * Customizer's "Change" theme button. The link sections' script and styles + * are in assets/js/customizer-controls.js and assets/css/customizer.css. + */ // Welcome screen if ( is_admin() ) { - global $sparkling_required_actions, $sparkling_recommended_plugins; - $sparkling_recommended_plugins = array( - 'kali-forms' => array( - 'recommended' => true, - ), - 'colorlib-login-customizer' => array( - 'recommended' => true, - ), - 'fancybox-for-wordpress' => array( - 'recommended' => false, - ), - 'simple-custom-post-order' => array( - 'recommended' => true, - ), - 'colorlib-404-customizer' => array( - 'recommended' => true, - ), - 'colorlib-coming-soon-maintenance' => array( - 'recommended' => true, - ), - - ); - /* - * id - unique id; required - * title - * description - * check - check for plugins (if installed) - * plugin_slug - the plugin's slug (used for installing the plugin) - * - */ - + /* + * The plugins the About page recommends. Only the slugs are used now; the + * 'recommended' flag fed the removed "recommended actions" tab. + */ + global $sparkling_recommended_plugins, $sparkling_welcome; + $sparkling_recommended_plugins = array( + 'kali-forms' => array( + 'recommended' => true, + ), + 'colorlib-login-customizer' => array( + 'recommended' => true, + ), + 'fancybox-for-wordpress' => array( + 'recommended' => false, + ), + 'simple-custom-post-order' => array( + 'recommended' => true, + ), + 'colorlib-404-customizer' => array( + 'recommended' => true, + ), + 'colorlib-coming-soon-maintenance' => array( + 'recommended' => true, + ), + ); - $sparkling_required_actions = array(); - require get_template_directory() . '/inc/welcome-screen/class-sparkling-welcome.php'; + require get_template_directory() . '/inc/welcome-screen/class-sparkling-welcome.php'; - /* - * Registers Appearance > About Sparkling. This line was lost between 2.6.4 - * and 2.6.9, and the class is otherwise only instantiated inside the About - * page's own tab templates -- which can never run if the page is never - * registered. So the page had quietly disappeared, and its URL returned - * "Sorry, you are not allowed to access this page". - */ - new Sparkling_Welcome(); -} \ No newline at end of file + /* + * Registers Appearance > About Sparkling. The tab templates use this one + * instance; they used to construct their own, which hooked every handler a + * second time. + */ + $sparkling_welcome = new Sparkling_Welcome(); +} diff --git a/inc/widgets/class-sparkling-categories.php b/inc/widgets/class-sparkling-categories.php index b3db8dcc..dc855fa4 100644 --- a/inc/widgets/class-sparkling-categories.php +++ b/inc/widgets/class-sparkling-categories.php @@ -6,78 +6,71 @@ */ class Sparkling_Categories extends WP_Widget { - function __construct() { + public function __construct() { $widget_ops = array( 'classname' => 'sparkling-cats', 'description' => esc_html__( 'Sparkling Categories', 'sparkling' ), ); - parent::__construct( 'sparkling-cats', esc_html__( 'Sparkling Categories', 'sparkling' ), $widget_ops ); + parent::__construct( 'sparkling-cats', esc_html__( 'Sparkling Categories', 'sparkling' ), $widget_ops ); } - function widget( $args, $instance ) { - $title = isset( $instance['title'] ) ? $instance['title'] : esc_html__( 'Categories', 'sparkling' ); - $enable_count = ''; - if ( isset( $instance['enable_count'] ) ) { - $enable_count = $instance['enable_count'] ? $instance['enable_count'] : 'checked'; - } + /** + * Front-end display of the widget. + * + * @param array $args Widget area arguments. + * @param array $instance Saved settings. + */ + public function widget( $args, $instance ) { + $title = isset( $instance['title'] ) ? $instance['title'] : esc_html__( 'Categories', 'sparkling' ); + $title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core hook. + + /* + * "Enable Posts Count" was read as on whenever the key existed, so + * unticking it and saving still showed the counts. + */ + $show_count = ! empty( $instance['enable_count'] ); // $instance['limit'] is unset until the widget is first saved, which raised // an "Undefined array key" warning on PHP 8. $limit = ! empty( $instance['limit'] ) ? absint( $instance['limit'] ) : 4; - echo $args['before_widget']; - echo $args['before_title']; - echo esc_html( $title ); - echo $args['after_title']; - - /** - * Widget Content - */ - - ?> - + echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget area markup from register_sidebar(). -
    + if ( '' !== trim( (string) $title ) ) { + echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget area markup from register_sidebar(). + } -
      - 0, - 'show_count' => 1, - 'title_li' => '', - 'depth' => 1, - 'orderby' => 'count', - 'order' => 'DESC', - 'number' => $limit, - ); - } else { - $categories_args = array( + $categories = wp_list_categories( + array( 'echo' => 0, - 'show_count' => 0, + 'show_count' => $show_count ? 1 : 0, 'title_li' => '', 'depth' => 1, 'orderby' => 'count', 'order' => 'DESC', 'number' => $limit, - ); - } - $variable = wp_list_categories( $categories_args ); - $variable = str_replace( '(', '', $variable ); - $variable = str_replace( ')', '', $variable ); - echo $variable; + ) + ); + + /* + * Wrap each post count in a for styling. This used to replace + * every "(" and ")" in the list, which broke the markup of any + * category whose name contains a parenthesis. + */ + $categories = preg_replace( '#\s*\(([^()<>]+)\)#', ' $1', $categories ); ?> -
    -
    +
    +
      + +
    +
    -

    +

    -

    +

    -

    +

    -

    +

    -

    -

    +

    'sparkling-popular-posts', 'description' => esc_html__( 'Sparkling Popular Posts Widget', 'sparkling' ), ); - parent::__construct( 'sparkling_popular_posts', esc_html__( 'Sparkling Popular Posts Widget', 'sparkling' ), $widget_ops ); + parent::__construct( 'sparkling_popular_posts', esc_html__( 'Sparkling Popular Posts Widget', 'sparkling' ), $widget_ops ); } /** @@ -41,101 +41,94 @@ public function enqueue( $hook = '' ) { wp_enqueue_media(); wp_enqueue_script( 'sparkling-popular-post-script', get_template_directory_uri() . '/assets/js/widget.js', array( 'jquery' ), SPARKLING_VERSION, true ); $args = array( - 'ajaxurl' => admin_url( 'admin-ajax.php' ), - 'nonce' => wp_create_nonce( 'sparkling_widget_nonce' ), + 'ajaxurl' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'sparkling_widget_nonce' ), + 'frameTitle' => __( 'Select a default image', 'sparkling' ), + 'frameButton' => __( 'Use this image', 'sparkling' ), ); wp_localize_script( 'sparkling-popular-post-script', 'Sparkling', $args ); } - } - function widget( $args, $instance ) { + /** + * Front-end display of the widget. + * + * @param array $args Widget area arguments. + * @param array $instance Saved settings. + */ + public function widget( $args, $instance ) { $title = isset( $instance['title'] ) ? $instance['title'] : esc_html__( 'Popular Posts', 'sparkling' ); - $limit = isset( $instance['limit'] ) ? $instance['limit'] : 5; - $default_image = isset( $instance['default_image'] ) ? $instance['default_image'] : ''; - - echo $args['before_widget']; - echo $args['before_title']; - echo esc_html( $title ); - echo $args['after_title']; - - /** - * Widget Content - */ - ?> - - - -

    - - -

    - -

    - - -

    -

    -

    - - -

    -
    +

    + + +

    + +

    + + +

    +

    +

    + + +

    +
    >
    diff --git a/inc/widgets/class-sparkling-social-widget.php b/inc/widgets/class-sparkling-social-widget.php index dec39338..4192d0e6 100644 --- a/inc/widgets/class-sparkling-social-widget.php +++ b/inc/widgets/class-sparkling-social-widget.php @@ -6,37 +6,38 @@ */ class Sparkling_Social_Widget extends WP_Widget { - function __construct() { - - $widget_ops = array( - 'classname' => 'sparkling-social', - 'description' => esc_html__( 'Sparkling Social Widget', 'sparkling' ), - ); - parent::__construct( 'sparkling-social', esc_html__( 'Sparkling Social Widget', 'sparkling' ), $widget_ops ); + public function __construct() { + $widget_ops = array( + 'classname' => 'sparkling-social', + 'description' => esc_html__( 'Sparkling Social Widget', 'sparkling' ), + ); + parent::__construct( 'sparkling-social', esc_html__( 'Sparkling Social Widget', 'sparkling' ), $widget_ops ); } - function widget( $args, $instance ) { + /** + * Front-end display of the widget. + * + * @param array $args Widget area arguments. + * @param array $instance Saved settings. + */ + public function widget( $args, $instance ) { $title = isset( $instance['title'] ) ? $instance['title'] : esc_html__( 'Follow us', 'sparkling' ); + $title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core hook. - echo $args['before_widget']; - echo $args['before_title']; - echo esc_html( $title ); - echo $args['after_title']; + echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget area markup from register_sidebar(). - /** - * Widget Content - */ ?> + if ( '' !== trim( (string) $title ) ) { + echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget area markup from register_sidebar(). + } + ?> - -
    -

    +

    - -

    " + name="get_field_name( 'title' ) ); ?>" + id="get_field_id( 'title' ) ); ?>" + class="widefat" /> +

    diff --git a/index.php b/index.php index 68095495..223f7fa1 100644 --- a/index.php +++ b/index.php @@ -17,12 +17,12 @@ if ( have_posts() ) : if ( is_home() && ! is_front_page() ) : - ?> + ?>

    - ' ' . __( 'Newer posts', 'sparkling' ), - 'next_text' => __( 'Older posts', 'sparkling' ) . ' ', + 'prev_text' => ' ' . __( 'Newer posts', 'sparkling' ), + 'next_text' => __( 'Older posts', 'sparkling' ) . ' ', ) ); } diff --git a/languages/sparkling.pot b/languages/sparkling.pot index b0837719..844b7148 100644 --- a/languages/sparkling.pot +++ b/languages/sparkling.pot @@ -2,20 +2,21 @@ # This file is distributed under the GNU General Public License v2 or later. msgid "" msgstr "" -"Project-Id-Version: Sparkling 2.6.3\n" +"Project-Id-Version: Sparkling 2.7.1\n" "Report-Msgid-Bugs-To: https://colorlib.com/wp/support/\n" "Last-Translator: Colorlib \n" "Language-Team: Colorlib \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-08-05T12:17:17+00:00\n" +"POT-Creation-Date: 2026-10-13T14:51:35+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: sparkling\n" #. Theme Name of the theme #: style.css +#: inc/block-editor.php:185 msgid "Sparkling" msgstr "" @@ -62,7 +63,7 @@ msgid "Try looking in the monthly archives. %1$s" msgstr "" #: 404.php:55 -#: sidebar.php:12 +#: sidebar.php:20 msgid "Archives" msgstr "" @@ -71,16 +72,16 @@ msgid "Tags" msgstr "" #: archive.php:42 -#: inc/extras.php:605 +#: inc/extras.php:626 #: index.php:46 -#: search.php:40 +#: search.php:42 msgid "Newer posts" msgstr "" #: archive.php:43 -#: inc/extras.php:606 +#: inc/extras.php:627 #: index.php:47 -#: search.php:41 +#: search.php:43 msgid "Older posts" msgstr "" @@ -92,7 +93,7 @@ msgid "One thought to “%s”" msgstr "" #. translators: 1: number of comments, 2: post title -#: comments.php:42 +#: comments.php:43 #, php-format msgctxt "comments title" msgid "%1$s thought to “%2$s”" @@ -100,685 +101,731 @@ msgid_plural "%1$s thoughts to “%2$s”" msgstr[0] "" msgstr[1] "" -#: comments.php:58 -#: comments.php:82 +#: comments.php:60 +#: comments.php:84 msgid "Comment navigation" msgstr "" -#: comments.php:61 -#: comments.php:85 +#: comments.php:63 +#: comments.php:87 msgid "Older Comments" msgstr "" -#: comments.php:62 -#: comments.php:86 +#: comments.php:64 +#: comments.php:88 msgid "Newer Comments" msgstr "" -#: comments.php:100 +#: comments.php:102 msgid "Comments are closed." msgstr "" +#: footer.php:28 +#: inc/customizer.php:785 +msgid "Footer" +msgstr "" + +#: footer.php:37 +msgid "Back to top" +msgstr "" + #: functions.php:84 msgid "Primary Menu" msgstr "" #: functions.php:85 -#: inc/extras.php:144 +#: inc/extras.php:206 msgid "Footer Links" msgstr "" -#: functions.php:168 +#: functions.php:170 +#: sidebar.php:10 msgid "Sidebar" msgstr "" -#: functions.php:180 +#: functions.php:182 msgid "Homepage Widget 1" msgstr "" -#: functions.php:181 -#: functions.php:193 -#: functions.php:205 +#: functions.php:183 +#: functions.php:195 +#: functions.php:207 msgid "Displays on the Home Page" msgstr "" -#: functions.php:192 +#: functions.php:194 msgid "Homepage Widget 2" msgstr "" -#: functions.php:204 +#: functions.php:206 msgid "Homepage Widget 3" msgstr "" -#: functions.php:216 +#: functions.php:218 msgid "Footer Widget 1" msgstr "" -#: functions.php:217 -#: functions.php:229 -#: functions.php:241 +#: functions.php:219 +#: functions.php:231 +#: functions.php:243 msgid "Used for footer widget area" msgstr "" -#: functions.php:228 +#: functions.php:230 msgid "Footer Widget 2" msgstr "" -#: functions.php:240 +#: functions.php:242 msgid "Footer Widget 3" msgstr "" -#: functions.php:303 +#: functions.php:302 msgctxt "yearly archives date format" msgid "Y" msgstr "" -#: functions.php:310 +#: functions.php:305 msgctxt "monthly archives date format" msgid "F Y" msgstr "" -#: functions.php:317 +#: functions.php:308 msgctxt "daily archives date format" msgid "F j, Y" msgstr "" -#: functions.php:472 +#: functions.php:411 +msgid "Previous slide" +msgstr "" + +#: functions.php:412 +msgid "Next slide" +msgstr "" + +#: functions.php:413 +msgid "Pause slideshow" +msgstr "" + +#: functions.php:414 +msgid "Play slideshow" +msgstr "" + +#. translators: %d: slide number +#: functions.php:416 +#, php-format +msgid "Go to slide %d" +msgstr "" + +#: functions.php:494 msgctxt "nav menu location" msgid "Social Menu" msgstr "" -#: functions.php:503 +#: functions.php:528 msgid "Right Sidebar" msgstr "" -#: functions.php:504 +#: functions.php:529 msgid "Left Sidebar" msgstr "" -#: functions.php:505 +#: functions.php:530 msgid "No Sidebar" msgstr "" -#: functions.php:506 +#: functions.php:531 msgid "Full Width" msgstr "" -#: functions.php:692 -#: inc/welcome-screen/class-sparkling-welcome.php:113 -#: inc/welcome-screen/class-sparkling-welcome.php:253 -#: inc/welcome-screen/class-sparkling-welcome.php:294 +#: functions.php:737 msgid "You are not allowed to do that." msgstr "" -#: functions.php:700 +#: functions.php:745 msgid "Invalid attachment." msgstr "" -#: image.php:25 -msgid " Previous" +#: header.php:28 +msgid "Skip to main content" +msgstr "" + +#: header.php:32 +msgid "Primary" +msgstr "" + +#: header.php:59 +msgid "Toggle navigation" +msgstr "" + +#: header.php:83 +msgid "Featured" +msgstr "" + +#: image.php:27 +msgid "Image navigation" +msgstr "" + +#: image.php:28 +msgid " Previous" msgstr "" -#: image.php:26 -msgid "Next " +#: image.php:29 +msgid "Next " msgstr "" -#: image.php:90 -#: template-parts/content-page.php:36 +#: image.php:93 +#: template-blocks.php:32 +#: template-parts/content-page.php:38 #: template-parts/content-single.php:51 -#: template-parts/content-video.php:84 -#: template-parts/content.php:77 +#: template-parts/content-video.php:80 +#: template-parts/content.php:80 msgid "Pages:" msgstr "" -#: inc/class-wp-bootstrap-navwalker.php:206 +#. translators: %s: menu item title +#: inc/class-sparkling-bootstrap-navwalker.php:158 +#, php-format +msgid "Show submenu for %s" +msgstr "" + +#: inc/class-sparkling-bootstrap-navwalker.php:233 msgid "Add a menu" msgstr "" -#: inc/customizer.php:40 -msgid "Sparkling Options" +#: inc/class-sparkling-customize-link-section.php:71 +#: inc/welcome-screen/sections/getting-started.php:21 +#: inc/welcome-screen/sections/support.php:17 +#: inc/welcome-screen/sections/support.php:27 +msgid "(opens in a new tab)" msgstr "" #: inc/customizer.php:41 -msgid "Panel to update sparkling theme options" +msgid "Sparkling Options" msgstr "" -#: inc/customizer.php:51 +#: inc/customizer.php:42 +msgid "Layout, colors, typography and other options for the Sparkling theme." +msgstr "" + +#: inc/customizer.php:53 msgid "Content Options" msgstr "" -#: inc/customizer.php:67 -msgid "Show post excerpts?" +#: inc/customizer.php:72 +msgid "Show excerpts instead of full posts on the blog" +msgstr "" + +#: inc/customizer.php:92 +msgid "Show comments on pages" +msgstr "" + +#: inc/customizer.php:113 +msgid "Font Awesome icons" msgstr "" -#: inc/customizer.php:84 -msgid "Display Comments on Static Pages?" +#: inc/customizer.php:117 +msgid "The theme bundles only the icons it displays itself, which keeps pages small. Icons you add to your menus are detected automatically. Choose \"Always load the complete library\" if you use Font Awesome icons in a widget, in post content or in a page builder and they are not showing." msgstr "" -#: inc/customizer.php:95 +#: inc/customizer.php:119 +msgid "Automatic (recommended)" +msgstr "" + +#: inc/customizer.php:120 +msgid "Always load the complete library" +msgstr "" + +#: inc/customizer.php:121 +msgid "Only the icons the theme uses" +msgstr "" + +#: inc/customizer.php:130 msgid "Slider Options" msgstr "" -#: inc/customizer.php:110 -msgid "Check if you want to enable slider" +#: inc/customizer.php:148 +msgid "Show the slider on the front page" msgstr "" -#: inc/customizer.php:127 -msgid "Uncheck this option to remove the link from the slides" +#: inc/customizer.php:168 +msgid "Link each slide to its post" msgstr "" -#: inc/customizer.php:147 +#: inc/customizer.php:191 msgid "Slider Category" msgstr "" -#: inc/customizer.php:150 -msgid "Select a category for the featured post slider" +#: inc/customizer.php:195 +msgid "The slider shows posts from this category that have a featured image." msgstr "" -#: inc/customizer.php:164 +#: inc/customizer.php:201 +msgid "All categories" +msgstr "" + +#: inc/customizer.php:218 msgid "Number of slide items" msgstr "" -#: inc/customizer.php:166 -msgid "Enter the number of slide items" +#: inc/customizer.php:221 +msgid "How many posts the slider shows." msgstr "" -#: inc/customizer.php:173 +#: inc/customizer.php:234 msgid "Layout Options" msgstr "" -#: inc/customizer.php:189 +#: inc/customizer.php:252 msgid "Website Layout Options" msgstr "" -#: inc/customizer.php:192 -msgid "Choose between different layout options to be used as default" +#: inc/customizer.php:255 +msgid "The default sidebar layout. Each post and page can override it." msgstr "" -#: inc/customizer.php:207 +#: inc/customizer.php:272 msgid "WooCommerce Page Layout Options" msgstr "" -#: inc/customizer.php:210 -msgid "Choose between different layout options to be used as default for all woocommerce pages" +#: inc/customizer.php:275 +msgid "The sidebar layout of the shop, product, cart, checkout and account pages." msgstr "" -#: inc/customizer.php:226 +#: inc/customizer.php:294 msgid "Element Color" msgstr "" -#: inc/customizer.php:227 -#: inc/customizer.php:245 -#: inc/customizer.php:319 -#: inc/customizer.php:335 -#: inc/customizer.php:351 -#: inc/customizer.php:367 -#: inc/customizer.php:492 -#: inc/customizer.php:508 -#: inc/customizer.php:552 -#: inc/customizer.php:766 -#: inc/customizer.php:783 -msgid "Default used if no color is selected" -msgstr "" - -#: inc/customizer.php:244 +#: inc/customizer.php:295 +#: inc/customizer.php:316 +#: inc/customizer.php:400 +#: inc/customizer.php:419 +#: inc/customizer.php:438 +#: inc/customizer.php:457 +#: inc/customizer.php:586 +#: inc/customizer.php:605 +#: inc/customizer.php:656 +#: inc/customizer.php:907 +#: inc/customizer.php:927 +msgid "Clear it to use the theme default." +msgstr "" + +#: inc/customizer.php:315 msgid "Element color on hover" msgstr "" -#: inc/customizer.php:255 +#: inc/customizer.php:327 msgid "Action Button" msgstr "" -#: inc/customizer.php:269 +#: inc/customizer.php:343 msgid "Call For Action Text" msgstr "" -#: inc/customizer.php:270 -msgid "Enter the text for call for action section" +#: inc/customizer.php:344 +msgid "Shown in a bar under the slider on the front page. Leave empty to hide the bar." msgstr "" -#: inc/customizer.php:285 +#: inc/customizer.php:361 msgid "Call For Action Button Title" msgstr "" -#: inc/customizer.php:287 +#: inc/customizer.php:363 msgid "Enter the title for Call For Action button" msgstr "" -#: inc/customizer.php:301 -msgid "CFA button link" +#: inc/customizer.php:380 +msgid "Call For Action Button Link" msgstr "" -#: inc/customizer.php:303 +#: inc/customizer.php:382 msgid "Enter the link for Call For Action button" msgstr "" -#: inc/customizer.php:318 +#: inc/customizer.php:399 msgid "Call For Action Text Color" msgstr "" -#: inc/customizer.php:334 +#: inc/customizer.php:418 msgid "Call For Action Background Color" msgstr "" -#: inc/customizer.php:350 +#: inc/customizer.php:437 msgid "Call For Action Button Border Color" msgstr "" -#: inc/customizer.php:366 +#: inc/customizer.php:456 msgid "Call For Action Button Text Color" msgstr "" -#: inc/customizer.php:376 +#: inc/customizer.php:467 msgid "Typography" msgstr "" -#: inc/customizer.php:400 -msgid "Main Body Text" +#: inc/customizer.php:488 +msgid "Body font size" +msgstr "" + +#: inc/customizer.php:489 +msgid "Size, font, weight and color of post and page text." msgstr "" -#: inc/customizer.php:401 -msgid "Used in p tags" +#: inc/customizer.php:506 +msgid "Body font" msgstr "" -#: inc/customizer.php:458 -msgid "Font Subset" +#: inc/customizer.php:523 +msgid "Body font weight" msgstr "" -#: inc/customizer.php:460 -msgid "Enter the Google fonts subset" +#: inc/customizer.php:542 +msgid "Body text color" msgstr "" -#: inc/customizer.php:475 +#: inc/customizer.php:566 msgid "Heading Color" msgstr "" -#: inc/customizer.php:476 +#: inc/customizer.php:567 msgid "Color for all headings (h1-h6)" msgstr "" -#: inc/customizer.php:491 +#: inc/customizer.php:585 msgid "Link Color" msgstr "" -#: inc/customizer.php:507 +#: inc/customizer.php:604 msgid "Link:hover Color" msgstr "" -#: inc/customizer.php:517 +#: inc/customizer.php:615 msgid "Header" msgstr "" -#: inc/customizer.php:533 +#: inc/customizer.php:634 msgid "Sticky Header" msgstr "" -#: inc/customizer.php:534 -msgid "Check to show fixed header" +#: inc/customizer.php:635 +msgid "Keep the header at the top of the window while scrolling." msgstr "" -#: inc/customizer.php:551 +#: inc/customizer.php:655 msgid "Top nav background color" msgstr "" -#: inc/customizer.php:567 +#: inc/customizer.php:674 msgid "Top nav item color" msgstr "" -#: inc/customizer.php:568 +#: inc/customizer.php:675 msgid "Link color" msgstr "" -#: inc/customizer.php:584 +#: inc/customizer.php:694 msgid "Top nav item hover color" msgstr "" -#: inc/customizer.php:585 +#: inc/customizer.php:695 msgid "Link:hover color" msgstr "" -#: inc/customizer.php:601 +#: inc/customizer.php:714 msgid "Top nav dropdown background color" msgstr "" -#: inc/customizer.php:602 -#: inc/customizer.php:653 -msgid "Background of dropdown item hover color" +#: inc/customizer.php:715 +msgid "Background of the dropdown menus" msgstr "" -#: inc/customizer.php:618 +#: inc/customizer.php:734 msgid "Top nav dropdown item color" msgstr "" -#: inc/customizer.php:619 +#: inc/customizer.php:735 msgid "Dropdown item color" msgstr "" -#: inc/customizer.php:635 +#: inc/customizer.php:754 msgid "Top nav dropdown item hover color" msgstr "" -#: inc/customizer.php:636 +#: inc/customizer.php:755 msgid "Dropdown item hover color" msgstr "" -#: inc/customizer.php:652 +#: inc/customizer.php:774 msgid "Top nav dropdown item background hover color" msgstr "" -#: inc/customizer.php:662 -msgid "Footer" +#: inc/customizer.php:775 +msgid "Background of a dropdown item on hover" msgstr "" -#: inc/customizer.php:677 +#: inc/customizer.php:803 msgid "Footer widget area background color" msgstr "" -#: inc/customizer.php:693 +#: inc/customizer.php:822 msgid "Footer background color" msgstr "" -#: inc/customizer.php:709 +#: inc/customizer.php:841 msgid "Footer text color" msgstr "" -#: inc/customizer.php:725 +#: inc/customizer.php:860 msgid "Footer link color" msgstr "" -#: inc/customizer.php:740 +#: inc/customizer.php:877 msgid "Footer information" msgstr "" -#: inc/customizer.php:741 +#: inc/customizer.php:878 msgid "Copyright text in footer" msgstr "" -#: inc/customizer.php:750 +#: inc/customizer.php:888 msgid "Social" msgstr "" -#: inc/customizer.php:765 +#: inc/customizer.php:906 msgid "Social icon color" msgstr "" -#: inc/customizer.php:782 +#: inc/customizer.php:926 msgid "Footer social icon color" msgstr "" -#: inc/customizer.php:799 +#: inc/customizer.php:946 msgid "Footer Social Icons" msgstr "" -#: inc/customizer.php:800 -msgid "Check to show social icons in footer" +#: inc/customizer.php:947 +msgid "Show the Social menu as icons in the footer." msgstr "" -#: inc/customizer.php:819 +#: inc/customizer.php:969 msgid "Enable Academicons" msgstr "" -#: inc/customizer.php:820 -msgid "Toggle this to ON to enable the usage of Academicons" +#: inc/customizer.php:970 +msgid "Load the Academicons font, for links to academic profiles in the Social menu." msgstr "" -#: inc/customizer.php:830 +#: inc/customizer.php:981 msgid "Archive Pages" msgstr "" -#: inc/customizer.php:846 +#: inc/customizer.php:999 msgid "Tag Page Title" msgstr "" #. translators: %s: tag name -#: inc/customizer.php:849 +#: inc/customizer.php:1002 #, php-format msgid "The headline for your tag pages. You can use %s as a placeholder for the tag. Leave empty for default." msgstr "" -#: inc/customizer.php:864 +#: inc/customizer.php:1019 msgid "Category Page Title" msgstr "" #. translators: %s: category name -#: inc/customizer.php:867 +#: inc/customizer.php:1022 #, php-format msgid "The headline for your category pages. You can use %s as a placeholder for the category. Leave empty for default." msgstr "" -#: inc/customizer.php:882 +#: inc/customizer.php:1039 msgid "Author Page Title" msgstr "" #. translators: %s: author name -#: inc/customizer.php:885 +#: inc/customizer.php:1042 #, php-format msgid "The headline for your author pages. You can use %s as a placeholder for the author's name. Leave empty for default." msgstr "" -#: inc/customizer.php:900 +#: inc/customizer.php:1059 msgid "Year Page Title" msgstr "" #. translators: %s: year -#: inc/customizer.php:903 +#: inc/customizer.php:1062 #, php-format msgid "The headline for your year pages. You can use %s as a placeholder for the year. Leave empty for default." msgstr "" -#: inc/customizer.php:918 +#: inc/customizer.php:1079 msgid "Month Page Title" msgstr "" #. translators: %s: month -#: inc/customizer.php:921 +#: inc/customizer.php:1082 #, php-format msgid "The headline for your month pages. You can use %s as a placeholder for the month. Leave empty for default." msgstr "" -#: inc/customizer.php:936 +#: inc/customizer.php:1099 msgid "Day Page Title" msgstr "" #. translators: %s: day -#: inc/customizer.php:939 +#: inc/customizer.php:1102 #, php-format msgid "The headline for your day pages. You can use %s as a placeholder for the day. Leave empty for default." msgstr "" -#: inc/extras.php:66 +#: inc/extras.php:49 +msgid "Untitled" +msgstr "" + +#: inc/extras.php:92 msgid "This post is password protected. To view it please enter your password below:" msgstr "" -#: inc/extras.php:67 +#: inc/extras.php:93 msgid "Password:" msgstr "" -#: inc/extras.php:70 +#: inc/extras.php:96 msgid "Submit" msgstr "" +#: inc/extras.php:137 +msgid "Social links" +msgstr "" + #. translators: 1: Colorlib link, 2: WordPress link -#: inc/extras.php:284 +#: inc/extras.php:345 #, php-format msgid "Theme by %1$s Powered by %2$s" msgstr "" -#: inc/extras.php:489 -msgid "Support and Documentation" -msgstr "" - -#: inc/extras.php:498 -msgid "Sparkling Documentation" -msgstr "" - -#: inc/extras.php:500 -msgid "The best way to contact us with support questions and bug reports is via" -msgstr "" - -#: inc/extras.php:501 -msgid "Colorlib support forum" -msgstr "" - -#: inc/extras.php:503 -msgid "If you like this theme, I'd appreciate any of the following:" -msgstr "" - -#: inc/extras.php:507 -#: inc/extras.php:508 -msgid "Rate this Theme" -msgstr "" - -#: inc/extras.php:511 -msgid "Like on Facebook" -msgstr "" - -#: inc/extras.php:514 -msgid "Follow on Twitter" -msgstr "" - -#: inc/metaboxes.php:16 -msgid "Select layout for this specific Page only ( Note: This setting only reflects if page Template is set as Default Template and Blog Type Templates.)" -msgstr "" - #: inc/metaboxes.php:22 -msgid "Select layout for this specific Post only" +msgid "Layout" msgstr "" -#: inc/metaboxes.php:30 -msgid "Select layout for this specific Product only" +#: inc/metaboxes.php:52 +msgid "Sidebar layout" msgstr "" -#: inc/metaboxes.php:67 +#: inc/metaboxes.php:55 msgid "Default" msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:122 -msgid "No page titled \"Homepage\" was found." +#: inc/metaboxes.php:62 +msgid "Pages using the Full-width (no sidebar) template ignore this." +msgstr "" + +#: inc/welcome-screen/class-sparkling-welcome.php:94 +#: inc/welcome-screen/class-sparkling-welcome.php:333 +msgid "About Sparkling" msgstr "" #. translators: 1: opening anchor tag, 2: closing anchor tag -#: inc/welcome-screen/class-sparkling-welcome.php:188 +#: inc/welcome-screen/class-sparkling-welcome.php:123 #, php-format msgid "Welcome! Thank you for choosing Sparkling! To fully take advantage of the best our theme can offer please make sure you visit our %1$swelcome page%2$s." msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:190 +#: inc/welcome-screen/class-sparkling-welcome.php:129 msgid "Get started with Sparkling" msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:237 -#: inc/welcome-screen/sections/actions-required.php:157 -msgid "Hooray! There are no required actions for you right now." -msgstr "" - -#: inc/welcome-screen/class-sparkling-welcome.php:485 +#: inc/welcome-screen/class-sparkling-welcome.php:312 msgid "You are not allowed to access this page." msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:500 -msgid "Welcome to Sparkling! - Version " -msgstr "" - -#: inc/welcome-screen/class-sparkling-welcome.php:503 -msgid "Sparkling is now installed and ready to use! Get ready to build something beautiful. We hope you enjoy it! We want to make sure you have the best experience using Sparkling and that is why we gathered here all the necessary information for you. We hope you will enjoy using Sparkling, as much as we enjoy creating great products." -msgstr "" - -#: inc/welcome-screen/class-sparkling-welcome.php:510 +#: inc/welcome-screen/class-sparkling-welcome.php:318 msgid "Getting Started" msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:512 +#: inc/welcome-screen/class-sparkling-welcome.php:319 +#: inc/welcome-screen/welcome-page-setup.php:39 msgid "Recommended Plugins" msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:514 -#: inc/welcome-screen/sections/support.php:25 +#: inc/welcome-screen/class-sparkling-welcome.php:320 +#: inc/welcome-screen/sections/support.php:32 msgid "Changelog" msgstr "" -#: inc/welcome-screen/class-sparkling-welcome.php:516 +#: inc/welcome-screen/class-sparkling-welcome.php:321 +#: patterns/features.php:46 msgid "Support" msgstr "" -#: inc/welcome-screen/sections/actions-required.php:65 -#: inc/welcome-screen/sections/actions-required.php:127 -msgid "Install" -msgstr "" - -#: inc/welcome-screen/sections/actions-required.php:69 -#: inc/welcome-screen/sections/actions-required.php:131 -#: inc/welcome-screen/sections/recommended-plugins.php:55 -msgid "Activate" -msgstr "" - -#: inc/welcome-screen/sections/actions-required.php:73 -#: inc/welcome-screen/sections/actions-required.php:135 -#: inc/welcome-screen/sections/recommended-plugins.php:59 -msgid "Deactivate" +#: inc/welcome-screen/class-sparkling-welcome.php:327 +msgid "Welcome to Sparkling! - Version " msgstr "" -#: inc/welcome-screen/sections/actions-required.php:103 -msgid "Hooray! There are no required actions for you right now. But you can make your theme more powerful with next actions: " +#: inc/welcome-screen/class-sparkling-welcome.php:329 +msgid "Sparkling is now installed and ready to use! Get ready to build something beautiful. We hope you enjoy it! We want to make sure you have the best experience using Sparkling and that is why we gathered here all the necessary information for you. We hope you will enjoy using Sparkling, as much as we enjoy creating great products." msgstr "" #: inc/welcome-screen/sections/changelog.php:21 msgid "The changelog file could not be found." msgstr "" -#: inc/welcome-screen/sections/changelog.php:29 +#: inc/welcome-screen/sections/changelog.php:31 msgid "The changelog file could not be read." msgstr "" -#: inc/welcome-screen/sections/getting-started.php:19 -msgid "Step 1 - Implement recommended actions" +#: inc/welcome-screen/sections/getting-started.php:12 +msgid "Step 1 - Install the recommended plugins" msgstr "" -#: inc/welcome-screen/sections/getting-started.php:20 -msgid "We've compiled a list of steps for you, to take make sure the experience you'll have using one of our products is very easy to follow." +#: inc/welcome-screen/sections/getting-started.php:13 +msgid "Free plugins from the Sparkling team that add contact forms, a custom login page, a maintenance mode and more. None of them is required." msgstr "" -#: inc/welcome-screen/sections/getting-started.php:23 -msgid "No recommended actions left to perform" +#: inc/welcome-screen/sections/getting-started.php:14 +msgid "See the recommended plugins" msgstr "" -#: inc/welcome-screen/sections/getting-started.php:26 -msgid "Check recommended actions" -msgstr "" - -#: inc/welcome-screen/sections/getting-started.php:34 +#: inc/welcome-screen/sections/getting-started.php:18 msgid "Step 2 - Check our documentation" msgstr "" -#: inc/welcome-screen/sections/getting-started.php:35 +#: inc/welcome-screen/sections/getting-started.php:19 msgid "Even if you're a long-time WordPress user, we still believe you should give our documentation a very quick Read." msgstr "" -#: inc/welcome-screen/sections/getting-started.php:38 +#: inc/welcome-screen/sections/getting-started.php:21 msgid "Full documentation" msgstr "" -#: inc/welcome-screen/sections/getting-started.php:43 +#: inc/welcome-screen/sections/getting-started.php:26 msgid "Step 3 - Customize everything" msgstr "" -#: inc/welcome-screen/sections/getting-started.php:44 +#: inc/welcome-screen/sections/getting-started.php:27 msgid "Using the WordPress Customizer you can easily customize every aspect of the theme." msgstr "" -#: inc/welcome-screen/sections/getting-started.php:46 +#: inc/welcome-screen/sections/getting-started.php:28 msgid "Go to Customizer" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:25 +#: inc/welcome-screen/sections/recommended-plugins.php:18 msgid "Recommended plugins list" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:51 +#: inc/welcome-screen/sections/recommended-plugins.php:44 msgid "Install Now" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:89 +#: inc/welcome-screen/sections/recommended-plugins.php:48 +msgid "Activate" +msgstr "" + +#: inc/welcome-screen/sections/recommended-plugins.php:52 +msgid "Deactivate" +msgstr "" + +#: inc/welcome-screen/sections/recommended-plugins.php:82 msgid "Active" msgstr "" @@ -787,76 +834,80 @@ msgid "More Details" msgstr "" #. translators: %s: plugin author name -#: inc/welcome-screen/sections/recommended-plugins.php:108 +#: inc/welcome-screen/sections/recommended-plugins.php:109 #, php-format msgid "By %s" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:115 +#: inc/welcome-screen/sections/recommended-plugins.php:117 msgid "Version:" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:120 +#: inc/welcome-screen/sections/recommended-plugins.php:122 msgid "Installed and active" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:122 +#: inc/welcome-screen/sections/recommended-plugins.php:124 msgid "Installed, not active" msgstr "" -#: inc/welcome-screen/sections/recommended-plugins.php:124 +#: inc/welcome-screen/sections/recommended-plugins.php:126 msgid "Not installed" msgstr "" -#: inc/welcome-screen/sections/support.php:5 -#: inc/welcome-screen/sections/support.php:10 +#: inc/welcome-screen/sections/support.php:13 +#: inc/welcome-screen/sections/support.php:17 msgid "Contact Support" msgstr "" -#: inc/welcome-screen/sections/support.php:7 -msgid "We offer excellent support through our advanced ticketing system. Make sure to register your purchase before contacting support!" +#: inc/welcome-screen/sections/support.php:15 +msgid "Ask your question in the Sparkling support forum on WordPress.org, where the Colorlib team and other users answer." msgstr "" -#: inc/welcome-screen/sections/support.php:15 +#: inc/welcome-screen/sections/support.php:22 msgid "Documentation" msgstr "" -#: inc/welcome-screen/sections/support.php:17 +#: inc/welcome-screen/sections/support.php:24 msgid "This is the place to go to reference different aspects of the theme. Our online documentation is an incredible resource for learning the ins and outs of using Sparkling." msgstr "" -#: inc/welcome-screen/sections/support.php:20 +#: inc/welcome-screen/sections/support.php:27 msgid "See our full documentation" msgstr "" -#: inc/welcome-screen/sections/support.php:27 +#: inc/welcome-screen/sections/support.php:34 msgid "Want to get the gist on the latest theme changes? Just consult our changelog below to get a taste of the recent fixes and features implemented." msgstr "" -#: inc/welcome-screen/sections/support.php:30 +#: inc/welcome-screen/sections/support.php:37 msgid "See changelog" msgstr "" +#: inc/welcome-screen/welcome-page-setup.php:51 +msgid "Sparkling Documentation" +msgstr "" + #: inc/widgets/class-sparkling-categories.php:13 #: inc/widgets/class-sparkling-categories.php:15 msgid "Sparkling Categories" msgstr "" -#: inc/widgets/class-sparkling-categories.php:19 -#: inc/widgets/class-sparkling-categories.php:95 +#: inc/widgets/class-sparkling-categories.php:25 +#: inc/widgets/class-sparkling-categories.php:88 msgid "Categories" msgstr "" -#: inc/widgets/class-sparkling-categories.php:106 -#: inc/widgets/class-sparkling-social-widget.php:58 +#: inc/widgets/class-sparkling-categories.php:99 +#: inc/widgets/class-sparkling-social-widget.php:59 msgid "Title " msgstr "" -#: inc/widgets/class-sparkling-categories.php:114 +#: inc/widgets/class-sparkling-categories.php:107 msgid "Limit Categories " msgstr "" -#: inc/widgets/class-sparkling-categories.php:131 +#: inc/widgets/class-sparkling-categories.php:121 msgid "Enable Posts Count" msgstr "" @@ -865,33 +916,41 @@ msgstr "" msgid "Sparkling Popular Posts Widget" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:33 -#: inc/widgets/class-sparkling-popular-posts.php:138 +#: inc/widgets/class-sparkling-popular-posts.php:46 +msgid "Select a default image" +msgstr "" + +#: inc/widgets/class-sparkling-popular-posts.php:47 +msgid "Use this image" +msgstr "" + +#: inc/widgets/class-sparkling-popular-posts.php:60 +#: inc/widgets/class-sparkling-popular-posts.php:151 msgid "Popular Posts" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:155 +#: inc/widgets/class-sparkling-popular-posts.php:168 msgid "Title" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:163 +#: inc/widgets/class-sparkling-popular-posts.php:176 msgid "Limit Posts Number" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:172 +#: inc/widgets/class-sparkling-popular-posts.php:185 msgid "Default Image" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:180 +#: inc/widgets/class-sparkling-popular-posts.php:193 msgid "No media selected" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:188 +#: inc/widgets/class-sparkling-popular-posts.php:201 msgctxt "label for button in the media widget" msgid "Add Media" msgstr "" -#: inc/widgets/class-sparkling-popular-posts.php:191 +#: inc/widgets/class-sparkling-popular-posts.php:204 msgctxt "label for button in the media widget; should preferably not be longer than ~13 characters long" msgid "Remove Media" msgstr "" @@ -901,8 +960,8 @@ msgstr "" msgid "Sparkling Social Widget" msgstr "" -#: inc/widgets/class-sparkling-social-widget.php:20 -#: inc/widgets/class-sparkling-social-widget.php:54 +#: inc/widgets/class-sparkling-social-widget.php:25 +#: inc/widgets/class-sparkling-social-widget.php:55 msgid "Follow us" msgstr "" @@ -910,58 +969,155 @@ msgstr "" msgid "Full-width(no sidebar)" msgstr "" +#: patterns/about.php +msgctxt "Pattern title" +msgid "About with image" +msgstr "" + +#: patterns/about.php +msgctxt "Pattern description" +msgid "An image beside a heading, a paragraph and a button." +msgstr "" + +#: patterns/about.php:17 +msgid "About us" +msgstr "" + +#: patterns/about.php:21 +msgid "Tell visitors who you are, what you do and why it matters. Replace the empty image area with a photo of your team or your work." +msgstr "" + +#: patterns/about.php:26 +msgid "Read our story" +msgstr "" + +#: patterns/call-to-action.php +msgctxt "Pattern title" +msgid "Call to action band" +msgstr "" + +#: patterns/call-to-action.php +msgctxt "Pattern description" +msgid "A dark band with a line of text and a button, like the call to action under the front page slider." +msgstr "" + +#: patterns/call-to-action.php:18 +msgid "Ready to start your next project? Let us know." +msgstr "" + +#: patterns/call-to-action.php:25 +msgid "Get in touch" +msgstr "" + +#: patterns/features.php +msgctxt "Pattern title" +msgid "Three features" +msgstr "" + +#: patterns/features.php +msgctxt "Pattern description" +msgid "A heading over three columns, each with a title, a short text and a link." +msgstr "" + +#: patterns/features.php:16 +msgid "What we do" +msgstr "" + +#: patterns/features.php:20 +msgid "Say in a sentence what sets your work apart." +msgstr "" + +#: patterns/features.php:26 +msgid "Design" +msgstr "" + +#: patterns/features.php:30 +#: patterns/features.php:40 +#: patterns/features.php:50 +msgid "A short description of this service, what it includes and who it is for." +msgstr "" + +#: patterns/features.php:36 +msgid "Development" +msgstr "" + +#: patterns/testimonial.php +msgctxt "Pattern title" +msgid "Testimonial" +msgstr "" + +#: patterns/testimonial.php +msgctxt "Pattern description" +msgid "A centred customer quote on a light background." +msgstr "" + +#: patterns/testimonial.php:16 +msgid "\"Working with this team was easy from start to finish. The result was better than we hoped.\"" +msgstr "" + +#: patterns/testimonial.php:20 +msgid "Jane Doe, Company name" +msgstr "" + #. translators: %s: search query -#: search.php:20 +#: search.php:21 #, php-format msgid "Search Results for: %s" msgstr "" -#: searchform.php:11 +#: searchform.php:15 msgid "Search for:" msgstr "" -#: searchform.php:12 +#: searchform.php:16 msgctxt "placeholder" msgid "Search…" msgstr "" -#: searchform.php:12 -msgctxt "label" -msgid "Search for:" -msgstr "" - -#: searchform.php:14 +#: searchform.php:18 msgctxt "submit button" msgid "Search" msgstr "" -#: sidebar.php:24 +#: sidebar-footer.php:18 +msgid "Footer widgets" +msgstr "" + +#: sidebar-home.php:18 +msgid "Home page widgets" +msgstr "" + +#: sidebar.php:32 msgid "Meta" msgstr "" -#: template-parts/content-none.php:12 +#. Template Name of the theme +msgid "Blocks (full width, no title)" +msgstr "" + +#: template-parts/content-none.php:16 msgid "Nothing Found" msgstr "" #. translators: %1$s: URL of the new post screen -#: template-parts/content-none.php:28 +#: template-parts/content-none.php:32 #, php-format msgid "Ready to publish your first post? Get started here." msgstr "" -#: template-parts/content-none.php:35 +#: template-parts/content-none.php:39 msgid "Sorry, but nothing matched your search terms. Please try again with some different keywords." msgstr "" -#: template-parts/content-none.php:41 +#: template-parts/content-none.php:45 msgid "It seems we can’t find what you’re looking for. Perhaps searching can help." msgstr "" #. translators: %s: Name of current post -#: template-parts/content-page.php:56 +#: template-parts/content-page.php:58 #: template-parts/content-single.php:34 -#: template-parts/content-video.php:49 -#: template-parts/content.php:42 +#: template-parts/content-video.php:45 +#: template-parts/content.php:45 #, php-format msgid "Edit %s" msgstr "" @@ -971,26 +1127,81 @@ msgstr "" msgid ", " msgstr "" -#: template-parts/content-video.php:41 -#: template-parts/content.php:34 +#: template-parts/content-video.php:37 +#: template-parts/content.php:37 msgid "Leave a comment" msgstr "" -#: template-parts/content-video.php:41 -#: template-parts/content.php:34 +#: template-parts/content-video.php:37 +#: template-parts/content.php:37 msgid "1 Comment" msgstr "" -#: template-parts/content-video.php:41 -#: template-parts/content.php:34 +#: template-parts/content-video.php:37 +#: template-parts/content.php:37 msgid "% Comments" msgstr "" -#: template-parts/content-video.php:65 -#: template-parts/content-video.php:74 -#: template-parts/content-video.php:77 -#: template-parts/content.php:58 -#: template-parts/content.php:67 +#: template-parts/content-video.php:61 +#: template-parts/content-video.php:70 +#: template-parts/content-video.php:73 +#: template-parts/content.php:61 #: template-parts/content.php:70 +#: template-parts/content.php:73 msgid "Read More" msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Primary" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Primary hover" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Button" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Button hover" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Heading" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Body text" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Background" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Light" +msgstr "" + +#: theme.json +msgctxt "Color name" +msgid "Dark" +msgstr "" + +#: theme.json +msgctxt "Font family name" +msgid "Open Sans" +msgstr "" + +#: theme.json +msgctxt "Font family name" +msgid "Roboto Slab" +msgstr "" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..5a551c20 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4158 @@ +{ + "name": "sparkling", + "version": "2.7.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sparkling", + "version": "2.7.1", + "license": "GPL-2.0-or-later", + "devDependencies": { + "@eslint/js": "^10.0.1", + "archiver": "^8.0.0", + "eslint": "^10.8.0", + "globals": "^17.9.0", + "jquery": "^3.7.1", + "jquery4": "npm:jquery@^4.0.0", + "jsdom": "^30.1.2", + "npm-run-all2": "^9.0.3", + "sharp": "^0.35.3", + "stylelint": "^17.14.1", + "stylelint-config-standard": "^40.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-7.1.5.tgz", + "integrity": "sha512-jCpAvj8apa7SKHZYogk0rbXB3Kb0hLFrpkWF+Ap+vBA5rirItnpv9NKyAyEuDuFizvl0qwnj6JWR70RGJ0rOlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.4.3", + "@csstools/css-color-parser": "^4.2.6", + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2", + "lru-cache": "^11.5.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-9.2.4.tgz", + "integrity": "sha512-YnVzxDxLaqL0t7Q4wfcgHZjg55Wm6y5EaO7Bhu3q9J7wq/8iw3PhsnWiOQhYekx4VexnbkgWpTT6n+QIV7kczw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bidi-js": "^1.1.0", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.5.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.3.tgz", + "integrity": "sha512-0GEz8qJWokkUVYQYRukmkSHIFNoBH8QTreeHrAFbvz1XFYc3Y+puhMs8PQ5x8GNugiC2l5jvDBXKLbBIByeSBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.2.1" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.2.tgz", + "integrity": "sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.3.tgz", + "integrity": "sha512-iex20d8CHVkyvg6B7UKV7uHnI2Bqo9g+EFfT9E0y+GvTvhZ/DwONJ+9aKb1dlqm0ZiGsL5RXjp0fCoJYnkeDjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.6.tgz", + "integrity": "sha512-iiPQ3iRWwnJkeEn6RIu6SJPr7hYrLz6XZ9s/QZl+2/LI5KQVjpl2fdmDSZKuD4xP6GMmMPgHFFXg6k1Wkz0Trg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.2", + "@csstools/css-calc": "^3.4.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.2.tgz", + "integrity": "sha512-40cSKyMvK+tq4qz6Awrlye2WGuOKt3FwPgtGg6KTfbHOWNw+Rk1rzbAtZnZ6IBhsY491HLRnDXwoyBAijmmILA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.15.tgz", + "integrity": "sha512-J0u7HkVl2nzSlhsiTOp4AmwcUQ3D+mGEEKfBy/7To5/y7F2OHwyLrXfrhR0SMgr4p5Lo+eaMVSeai24zUcBIxA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.2.tgz", + "integrity": "sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.2.tgz", + "integrity": "sha512-qx19O8AbbLLbDSAcI6YOby/Vq8rV51psgIvlF5OZT/L8fQJDCyQifL6k+kYU4a8ySpzJ4RBzZkIs530bAn8y4Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/selector-resolve-nested": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-4.0.2.tgz", + "integrity": "sha512-JpjNBJFA+4OnAHKRK4AMp8xrYyLhI9XapOeBlP2PhRU/IylSw+1ep3BFNTksBJnrTS3KT6kqKNVfpzLLwZUW5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-6.0.0.tgz", + "integrity": "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.16.0.tgz", + "integrity": "sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-7.0.0.tgz", + "integrity": "sha512-kKvt3m4uwzqL0wlkPd09CmljPJGOZZ4D0fP65sqFSvPkMRKhNi+74MgIJ5QxE6SxqB4t4KyUFGg8+n5zjo6hew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/archiver": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-8.0.0.tgz", + "integrity": "sha512-fV1orZfsnPn9BaSByR/qE67rJCLJEy2Ox5bq7nJh+jquWaNh6Sfec75kJ2T6PtdGUbPQlrVoSVCEOa5SdiTQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "is-stream": "^4.0.0", + "lazystream": "^1.0.0", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^3.0.0", + "tar-stream": "^3.0.0", + "zip-stream": "^7.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/b4a": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.9.0.tgz", + "integrity": "sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bare-events": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz", + "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.8.2.tgz", + "integrity": "sha512-+ZI68KHMUvosXfKbg/UOHK0tbCdRnegbvPEdEcZ3Nd6TetieQsJPRXBRXPdLyy8+3VSEbPXtsumTpEtt78xv9w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.28.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-path": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.1.2.tgz", + "integrity": "sha512-ZyKbsuuqK6Ag0K8pX6V5Txq6XeJRvY+wXucnFGRjiyVYP9YWDpIQugk/b+enRYrEYBJaqLzghRQpXPMR7341Nw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bare-stream": { + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.4.tgz", + "integrity": "sha512-PcrQ8lVLbiJscNm1Kez+Yp4Gy4AHGcN1lzwjvf5NybWen7VvEgUfyfnXYJ2zNqWnzOfCb1Abq6lH8ti0syQszA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.8.1", + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.5.4.tgz", + "integrity": "sha512-Gxa7UVWBr0/edU1b+TJhn/AZvMQUj9OGspvYsaTYQrAbZA4BOTZGL3LiZxvD+CeMlDH4juwD84+eTAp/bLYW5g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bidi-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", + "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.10.0.tgz", + "integrity": "sha512-AidJptpBJmjTclAp9BkLwJi0T93fo5epJnbaZslpg6QVzpHjAiveF55mE9AcUJiGMqRHgMDY8soMsQtuNYMHfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/compress-commons": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-7.0.1.tgz", + "integrity": "sha512-g0S8KAD8qf4+V//pr3BfB1aBnARLXNz2Gx+jmHU0LEriUuoQUOPOulVquHKTJ8+EAIIO7fhseNDr9wK5Q9FKBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^7.0.1", + "is-stream": "^4.0.0", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-7.0.1.tgz", + "integrity": "sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-functions-list": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", + "integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/data-urls": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-8.0.0.tgz", + "integrity": "sha512-JQUCCK+/CAGbGGx618PlFZMXH81Jtj7t73CHv9dd/zVWvxgGT2zLFRjnKb+Ng46GIwcy+f7f88qd4duqllK+WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^17.1.2" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.11.0.tgz", + "integrity": "sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "11.1.5 || >11.1.6 <12", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^6.1.23" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "17.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz", + "integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.4.tgz", + "integrity": "sha512-c8B/VNLmxRcmqqenRA9t+9IyOjf9+V6lTxPaUJLqOCONdQkWZ0ETYgX0qbtJqPsgCNusT9MZ5Jeidw8Eb9tn2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "micromatch": "^4.0.8", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.11.tgz", + "integrity": "sha512-YChdK5txDjwGUvgR7oCJcLGkwi3LDh8Zx8tS7ndYciLEg/oOCL26VUBSUEtgS7EjiybcBqFxh5j0rAdDX7/bbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-encoding-sniffer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-7.0.0.tgz", + "integrity": "sha512-UikN5yr7xsCDAq87Or5or0PAlD3HJJOKVzM05az588WnpDJ4Ux7a2A53Qi6gofGg2/EtvF/H4hCi/TXfCW4Y6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.15.1" + }, + "engines": { + "node": "^22.13.0 || >=24.0.0" + } + }, + "node_modules/html-tags": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-5.1.0.tgz", + "integrity": "sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jquery4": { + "name": "jquery", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-4.0.0.tgz", + "integrity": "sha512-TXCHVR3Lb6TZdtw1l3RTLf8RBWVGexdxL6AC8/e0xZKEpBflBsjh9/8LXw+dkNFuOyW9B7iB3O1sP7hS0Kiacg==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "30.1.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.1.2.tgz", + "integrity": "sha512-0FFE/jE1rppmVfUrJUgxqXjcwolZYIGtAgj1pTussMhNZxIxi7W/PvfWaMNroGi2B36X1IKHbexpZ9DhkoOPiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^7.1.3", + "@asamuzakjp/dom-selector": "^9.2.4", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.15", + "@exodus/bytes": "^1.16.0", + "css-tree": "^3.2.1", + "data-urls": "^8.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^7.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.5.3", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "tough-cookie": "^6.0.2", + "undici": "^8.11.2", + "w3c-xmlserializer": "^6.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^17.2.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "canvas": "^3.2.3" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-6.0.0.tgz", + "integrity": "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/mathml-tag-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-4.0.0.tgz", + "integrity": "sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", + "integrity": "sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-6.0.0.tgz", + "integrity": "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-9.0.3.tgz", + "integrity": "sha512-BQAEdU1PtYc48qYRdghW2BVTQT3VqWCoFQmO87NlM1h1PYwMCKQpUWaNyB20V26caNzFsXQDfyOdznLlHCih6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^7.0.0", + "cross-spawn": "^7.0.6", + "memorystream": "^0.3.1", + "picomatch": "^4.0.2", + "pidtree": "^1.0.0", + "read-package-json-fast": "^6.0.0", + "shell-quote": "^1.8.4", + "which": "^7.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0", + "npm": ">= 10" + } + }, + "node_modules/npm-run-all2/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm-run-all2/node_modules/which": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-7.0.0.tgz", + "integrity": "sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-1.0.0.tgz", + "integrity": "sha512-avfAvjB9Dd0wdj3rjJX//yS+G79OO0KrS5pJHFJENjYGX6N4SMgEDBBI/yFy0lloOYSaC6XQxzpOAMPfSYFV/Q==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-safe-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.1.0.tgz", + "integrity": "sha512-1WzZxRLaAFwEh6Do+zyGpjWV3nGJNxxhuh7Ubu/q1ICImMgZJnLwhoaEpRbG4pJppp2Y1ncL9ffA2f+LhrefQg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", + "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/read-package-json-fast": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-6.0.0.tgz", + "integrity": "sha512-PNaGjoCnw9DBA2Kl8D+8po957z778q/HOPuY2u3Bkw/JO3eC8MDx7jn/PgMtSgpcBbs+6UOjDbwReGpXmRvs0g==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^6.0.0", + "npm-normalize-package-bin": "^6.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdir-glob": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-3.0.0.tgz", + "integrity": "sha512-AhNB2KgKeVJr16nK9LLZbJNWnYoT23ZrumNKFDebHBdkC8KHSqWo871JAUhoWC/RtjEVdqNMFpM6qrwRbaUqpw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/yqnn" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.11.0.tgz", + "integrity": "sha512-JdxDPD0DBTyu08pq0kPC0xSNet/qsU07qT6IsX1AS8oO2ICNRY4ldNa8OAI6PuwAH8tG3lxEhbqmyp4Dw4036g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamx": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", + "integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stylelint": { + "version": "17.16.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.16.0.tgz", + "integrity": "sha512-ejlWnbJ13x1GU32+zZXa6sYQJsKKkwSdv2B4rAdO3OWdEmvhSJKcXi5pOphQYSzyaj1kXpuGJr7pcMBNfDIuPw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.3.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.1.9", + "@csstools/css-tokenizer": "^4.0.0", + "@csstools/media-query-list-parser": "^5.0.0", + "@csstools/selector-resolve-nested": "^4.0.1", + "@csstools/selector-specificity": "^6.0.0", + "colord": "^2.10.0", + "cosmiconfig": "^9.0.2", + "css-functions-list": "^3.3.3", + "css-tree": "^3.2.1", + "debug": "^4.4.3", + "fast-glob": "^3.3.3", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^11.1.5", + "global-modules": "^2.0.0", + "globby": "^16.2.4", + "globjoin": "^0.1.4", + "html-tags": "^5.1.0", + "ignore": "^7.0.6", + "import-meta-resolve": "^4.2.0", + "mathml-tag-names": "^4.0.0", + "meow": "^14.1.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.5.26", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.1.5", + "postcss-value-parser": "^4.2.0", + "string-width": "^8.2.2", + "supports-hyperlinks": "^4.5.0", + "svg-tags": "^1.0.0", + "table": "^6.9.0", + "write-file-atomic": "^7.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz", + "integrity": "sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, + "node_modules/stylelint-config-standard": { + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-40.0.0.tgz", + "integrity": "sha512-EznGJxOUhtWck2r6dJpbgAdPATIzvpLdK9+i5qPd4Lx70es66TkBPljSg4wN3Qnc6c4h2n+WbUrUynQ3fanjHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "stylelint-config-recommended": "^18.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, + "node_modules/stylelint/node_modules/ignore": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.11.tgz", + "integrity": "sha512-YChdK5txDjwGUvgR7oCJcLGkwi3LDh8Zx8tS7ndYciLEg/oOCL26VUBSUEtgS7EjiybcBqFxh5j0rAdDX7/bbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-hyperlinks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.6.0.tgz", + "integrity": "sha512-FL/q/YePS4tFFTNiBOR+zPk2ZrKheqNtmTJ/9OUZ4e1wKHJofDbGQSmSsxS0XNnabSkqexryCaXGvEKz1vf9UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-stream": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.1.tgz", + "integrity": "sha512-nqsEO8zLZJvrOMdEwkA0QdCLFbetHMn95Zqu4fKwX+hkaTWJPZZOrxx/PwtxoK0MMGQmBQNRW3CPs8IFYQz4cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tldts": { + "version": "7.4.18", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.18.tgz", + "integrity": "sha512-somxA8xKAUzlAxl0TX/jMSYIbRNFIVGnI96pVGJPeMc5BsHmfVXn6mOJT6U++ELnl04eGfzpfcEuZe8WiASkXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.18" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.18", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.18.tgz", + "integrity": "sha512-KI2PKvCmvQI/xD6ypPqkU0i7oxNXR/O58RLRaHR4svsgVUQ2JE/XC8BtMbG6PSehD27I8sZJRcC1ASnCy6lp3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-7.0.0.tgz", + "integrity": "sha512-BcDSDW+SIGWVOns1Zm6Yg91q9AEj7eaID0QDY9oIqJD1A8dscNwMcl9Sms2DeuWCNov1X0/oXanHGYQBSLwZsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.1.tgz", + "integrity": "sha512-lzlXPoVB0Uy/FvTaUgX39RbixYiSKoc3JSoSf01+0c2B6FR3qdYIPN7Qjo/AV7n6sqLCk0509cT3LRj1oSZ1+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-6.0.0.tgz", + "integrity": "sha512-4Nsy8K5Tr6SPDH9jhKJOHf7ChDrc1zufZTVSF7x72hwuEXBqxqk9G6cK+K2NRUtB3iELRJqjXb4JPDMBjMTl2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.2.0.tgz", + "integrity": "sha512-IhLIHNcBrzIixC5XXsbr4DxdjajyA5vQ5RwGZMtrUp+GbtE5Nrsge9QKau7jXrC0aTXLYGV0xiW7Tb4YS2aomw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.16.0", + "tr46": "^7.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/write-file-atomic": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", + "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", + "dev": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-7.0.5.tgz", + "integrity": "sha512-dSvYKdvLsAHCDqPOhIwk/q5CvuWtTB3Dgpoe0uVEFjTzIOAmsQpprX25InCvrvJsirEbu1OHyy67n/kAj1Sw/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "compress-commons": "^7.0.0", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/package.json b/package.json index 539c1f6c..f3cc2ef0 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,49 @@ { "name": "sparkling", - "main": "Gruntfile.js", - "version": "3.0", - "homepage": "https://www.colorlib.com", + "version": "2.7.1", + "description": "Build and lint tooling for the Sparkling WordPress theme.", + "homepage": "https://colorlib.com/wp/themes/sparkling/", "author": "Colorlib", - "license": "GPL v3", - "repository": "https://github.com/puikinsh/sparkling", + "license": "GPL-2.0-or-later", + "repository": { + "type": "git", + "url": "git+https://github.com/ColorlibHQ/Sparkling.git" + }, + "private": true, + "type": "module", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + }, + "scripts": { + "lint": "npm-run-all --continue-on-error --parallel lint:js lint:css lint:php lint:phpcs", + "lint:js": "eslint --max-warnings 0", + "lint:css": "stylelint \"**/*.css\" --max-warnings 0", + "lint:php": "node tools/lint-php.mjs", + "lint:phpcs": "composer lint -- -q", + "lint:fix": "npm-run-all lint:js:fix lint:css:fix lint:phpcs:fix", + "lint:phpcs:fix": "composer fix -- -q", + "lint:js:fix": "eslint --fix", + "lint:css:fix": "stylelint \"**/*.css\" --fix", + "i18n": "node tools/make-pot.mjs", + "i18n:check": "node tools/check-textdomain.mjs", + "images": "node tools/optimize-images.mjs", + "prebuild": "npm-run-all i18n:check version:check", + "build": "node tools/build-zip.mjs", + "verify": "npm-run-all lint test i18n:check version:check", + "version:check": "node tools/check-version.mjs", + "test": "node --test tests/*.test.mjs" + }, "devDependencies": { - "grunt": "^1.0.2", - "grunt-checktextdomain": "^1.0.1", - "grunt-cli": "^1.2.0", - "grunt-contrib-clean": "^1.1.0", - "grunt-contrib-compress": "^1.4.3", - "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-imagemin": "^2.0.1", - "grunt-wp-i18n": "^1.0.2", - "load-grunt-tasks": "^3.5.2" + "@eslint/js": "^10.0.1", + "archiver": "^8.0.0", + "eslint": "^10.8.0", + "globals": "^17.9.0", + "jquery": "^3.7.1", + "jquery4": "npm:jquery@^4.0.0", + "jsdom": "^30.1.2", + "npm-run-all2": "^9.0.3", + "sharp": "^0.35.3", + "stylelint": "^17.14.1", + "stylelint-config-standard": "^40.0.0" } } diff --git a/page-fullwidth.php b/page-fullwidth.php index 3f6c3310..b5aa0170 100644 --- a/page-fullwidth.php +++ b/page-fullwidth.php @@ -9,31 +9,31 @@ get_header(); ?> -
    +
    + ?> - + - + ?>
    -
    +
    diff --git a/page.php b/page.php index 32e3720d..d1311748 100644 --- a/page.php +++ b/page.php @@ -19,14 +19,14 @@ + ?> + +
    +
    +

    + + + +

    + + + +
    +
    +
    +
    +
    + diff --git a/patterns/call-to-action.php b/patterns/call-to-action.php new file mode 100644 index 00000000..9537c84c --- /dev/null +++ b/patterns/call-to-action.php @@ -0,0 +1,30 @@ + + +
    +
    +
    +

    +
    + + + +
    +
    +
    +
    +
    +
    +
    + diff --git a/patterns/features.php b/patterns/features.php new file mode 100644 index 00000000..8662b5c2 --- /dev/null +++ b/patterns/features.php @@ -0,0 +1,54 @@ + + +
    +

    + + + +

    + + + +
    +
    +

    + + + +

    +
    + + + +
    +

    + + + +

    +
    + + + +
    +

    + + + +

    +
    +
    +
    + diff --git a/patterns/testimonial.php b/patterns/testimonial.php new file mode 100644 index 00000000..dac91f22 --- /dev/null +++ b/patterns/testimonial.php @@ -0,0 +1,22 @@ + + +
    +

    + + + +

    +
    + diff --git a/phpcs.ruleset.xml b/phpcs.ruleset.xml deleted file mode 100644 index 90a2ad7e..00000000 --- a/phpcs.ruleset.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - A custom set of code standard rules to check for WordPress themes and plugins. - - - - - */node_modules/* - */woocommerce/* - - - diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 00000000..5f94a874 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,39 @@ + + + Coding standard for the Sparkling theme: WordPress-Extra -- formatting, naming and the escaping, nonce and sanitising checks WordPress.org theme review applies -- plus PHP 7.4+ compatibility. + + + . + /node_modules/* + /vendor/* + /build/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.md b/readme.md index 9346630c..14e9e579 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ # Sparkling — Free Responsive WordPress Blog & Business Theme -[![Version](https://img.shields.io/badge/version-2.6.9-blue.svg)](https://github.com/ColorlibHQ/Sparkling/releases) -[![WordPress](https://img.shields.io/badge/WordPress-6.0%20–%207.0-21759b.svg)](https://wordpress.org/themes/sparkling/) +[![Version](https://img.shields.io/badge/version-2.7.1-blue.svg)](https://github.com/ColorlibHQ/Sparkling/releases) +[![WordPress](https://img.shields.io/badge/WordPress-6.0%20–%207.1-21759b.svg)](https://wordpress.org/themes/sparkling/) [![PHP](https://img.shields.io/badge/PHP-7.4%20–%208.5-777bb4.svg)](https://www.php.net/) [![License](https://img.shields.io/badge/license-GPL--2.0--or--later-green.svg)](https://www.gnu.org/licenses/gpl-2.0.html) [![Downloads](https://img.shields.io/wordpress/theme/dt/sparkling.svg)](https://wordpress.org/themes/sparkling/) @@ -33,7 +33,7 @@ four sidebar layouts, dozens of live Customizer options, and translations in ove | | | |---|---| -| WordPress | 6.0 or newer (tested to 7.0) | +| WordPress | 6.0 or newer (tested to 7.1) | | PHP | 7.4 or newer (tested to 8.5) | | Browsers | All current evergreen browsers. Internet Explorer is no longer supported. | @@ -65,8 +65,11 @@ for a guided setup. - **Translation ready**, WPML compatible, with 20+ bundled translations - **WooCommerce ready** - **No jQuery dependency** in the theme's own JavaScript -- **Block editor support** — responsive embeds, block styles, wide blocks and an editor stylesheet -- **Accessibility touches** — skip link, visible keyboard focus, `prefers-reduced-motion` support +- **Block editor support** — a theme.json palette that follows your Customizer colours, an editor sized + like the column the post renders in, four block patterns and a "Blocks (full width, no title)" page template +- **Accessibility** — WCAG AA text contrast, labelled landmarks, one h1 per page, keyboard-operable + submenus and Customizer switches, skip link, `prefers-reduced-motion` support +- **jQuery 4 ready** — works on jQuery 3.7 and on jQuery 4.0 without Migrate ## Customizer options @@ -74,7 +77,7 @@ All settings live under **Appearance → Customize → Sparkling Options**: | Section | What it controls | |---|---| -| Content | Post excerpts, comments on static pages | +| Content | Post excerpts, comments on static pages, which Font Awesome library to load | | Slider | On/off, source category, number of slides, slide links | | Layout | Sidebar position, element colours, WooCommerce page layout | | Call to action | Text, button label, link, colours | @@ -121,14 +124,22 @@ The theme ships ready to run; there is no build step required to use it. ```bash git clone https://github.com/ColorlibHQ/Sparkling.git # symlink or copy into wp-content/themes/sparkling +npm ci && composer install # the pinned lint and build toolchain ``` -`style.css` and the files in `assets/css/` are edited directly. Minified assets are committed alongside -their sources and must be regenerated by hand when the source changes: +`style.css` and the files in `assets/css/` are edited directly. The scripts: -```bash -npx terser assets/js/widget.js -c -m -o assets/js/widget.min.js -``` +| Command | What it does | +|---|---| +| `npm run verify` | Linters at zero warnings, frontend and package regression tests, text domains and version checks | +| `npm test` | Slider and menu regression tests on jQuery 3.7/4.0, default contrast and package contents | +| `npm run build` | `sparkling.zip`, containing only runtime directories and known theme files | +| `npm run i18n` | regenerates `languages/sparkling.pot` (needs WP-CLI) | +| `npm run images` | reports, or with `-- --write` applies, lossless image optimisation | + +GitHub Actions runs the same checks on PHP 7.4–8.5 for every push and pull request. +Development uses Node.js 22.22.2+, 24.15+ or 26+, Composer and Python 3. Python reads the ZIP in the package regression test; fontTools is needed only when rebuilding the icon subset. The theme itself needs none of these tools. +[`CLAUDE.md`](CLAUDE.md) documents the architecture and the gotchas. Bug reports and pull requests are welcome on the [issue tracker](https://github.com/ColorlibHQ/Sparkling/issues). diff --git a/readme.txt b/readme.txt index aa1838fd..0438c7bc 100644 --- a/readme.txt +++ b/readme.txt @@ -2,9 +2,9 @@ Contributors: colorlib Requires at least: 6.0 -Tested up to: 7.0 +Tested up to: 7.1 Requires PHP: 7.4 -Stable tag: 2.6.10 +Stable tag: 2.7.1 License: GNU General Public License v2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Tags: blog, news, e-commerce, one-column, two-columns, left-sidebar, right-sidebar, custom-background, custom-colors, custom-header, editor-style, featured-images, footer-widgets, full-width-template, post-formats, sticky-post, theme-options, block-styles, wide-blocks @@ -66,15 +66,30 @@ Bootstrap v3.4.1 License: MIT Source: https://getbootstrap.com/ -FlexSlider v2.7.0 +Bootstrap Glyphicons Halflings (bundled with Bootstrap 3.4.1) + Copyright Jan Kovarik + License: MIT, as part of Bootstrap + Source: https://glyphicons.com/ + +FlexSlider v2.7.2 Copyright 2012 WooThemes License: GNU General Public License v2 Source: https://github.com/woocommerce/FlexSlider -Font Awesome Free v5.1.1 +Font Awesome Free v7.3.1 (complete set, version 4 shim, and the theme's subset) Copyright Fonticons, Inc. License: Icons CC BY 4.0, Fonts SIL OFL 1.1, Code MIT - Source: https://fontawesome.com/license + Source: https://fontawesome.com/license/free + +Open Sans + Copyright 2020 The Open Sans Project Authors + License: SIL Open Font License 1.1 + Source: https://fonts.google.com/specimen/Open+Sans + +Roboto Slab + Copyright 2018 The Roboto Slab Project Authors + License: Apache License 2.0 + Source: https://fonts.google.com/specimen/Roboto+Slab Academicons v1.8.6 Copyright James Walsh @@ -91,6 +106,37 @@ Screenshot image == Changelog == += 2.7.1 = +* Fixed keyboard focus reaching invisible slider links. Inactive slides are hidden from assistive technologies and their original tab order is restored when they become active. +* Added a slideshow pause/play button, stopped automatic rotation on keyboard focus and hover, and honoured reduced motion. Slider controls support the Space key, stay clickable with mixed-height slides, and announce their purpose and current slide. +* Fixed the call-to-action strip growing excessively tall beneath shorter slides when another slide has a taller image. Slide containment also prevents focus from scrolling the image out of view. +* Fixed Escape leaving desktop submenus visible while their buttons reported them collapsed. Hover, keyboard focus and buttons share the same menu state. Nested submenu buttons support Space and Escape closes only the nearest submenu. +* Darkened the default link hover/focus colour to meet text contrast requirements on light backgrounds. Saved custom colours are retained. +* Content-hashed the subset icon fonts so a cached font from an earlier release cannot hide newly added icons. +* Added frontend regression tests on jQuery 3.7 and 4.0 and restricted theme archives to runtime files. + += 2.7.0 = +* Fixed two fatal errors on PHP 8: an Archive Pages headline containing a % other than %s ("Tagged %s at 100%") took the archive page down, and so did a classic [caption] with a non-numeric width. +* Fixed the mobile menu and the front page slider on jQuery 4 (Bootstrap 3 refused to run, and the slider started through a jQuery API removed in 3.0). The theme works on jQuery 3.7 and on jQuery 4.0 without Migrate. +* Fixed video posts showing an empty box on the blog, archive and search pages: the embed was stripped by the escaping that ran over it. +* Fixed 404 pages and empty searches losing their sidebar to the WooCommerce layout when WooCommerce is active. +* Fixed a fatal "Cannot declare class WP_Bootstrap_Navwalker" with plugins that bundle a nav walker of that name. The theme's walker is Sparkling_Bootstrap_Navwalker; the old name remains an alias. +* Fixed the password form: it lost WordPress's redirect and "Invalid password" message, pre-filled the field with the search query and was broken up by automatic paragraphs. +* Fixed a JavaScript error on every in-page link (the obsolete skip-link focus script), and the sticky header sitting under the admin bar, going stale when the menu wrapped, and hiding anchor targets. +* Fixed the Customizer: the slider category and slide count disagreed with the site, invalid typography values were saved as nothing, the slider's settings fell out of step with its switch, the switches could not be used from the keyboard, the link sections were unstyled, and the theme hid the Customizer's "Change" theme button. +* Fixed the About page: FancyBox and other plugins with differently named files always showed "Install", install buttons were offered to users who could not install plugins, a hidden tab was a fatal error, and the changelog needed FTP credentials on some hosts. +* Fixed the Sparkling Categories widget breaking on category names with parentheses and ignoring "Enable Posts Count", empty image links in Popular Posts and post listings, duplicate ids from the social menu and search forms, and the dropdown colours and nested submenu arrow from 768px up. +* Added theme.json: the block editor gets the theme's palette, which follows your Customizer colours, block buttons use the theme's button colours, and the editor is as wide as the column the post renders in. +* Added four block patterns (call to action, features, about, testimonial) and a "Blocks (full width, no title)" page template to build pages from them. +* Added icons for X, Bluesky, Threads, Mastodon, TikTok, WhatsApp, Discord, Reddit, Twitch and Medium to the social menu, and a generic icon for any other link. +* Accessibility: text meets WCAG AA contrast (the theme red is now #D83B4B, a shade darker; saved colours are kept), links in text are underlined, every page has one h1, landmarks and icon links are named, submenu toggles and the back-to-top control are real buttons. +* Performance: the slider's files load only on the front page, an empty style block is no longer printed, and only the Font Awesome icons the theme uses load unless your content needs more. +* Tested up to WordPress 7.1 and PHP 8.5. Development tooling moved from Grunt to npm scripts with PHPCS, ESLint and Stylelint at zero warnings in CI. + += 2.6.11 = +* Font Awesome icons added to a menu by hand disappeared on update to 2.6.7 or later, which subsetted the bundled Font Awesome to the glyphs the theme draws itself. The theme now detects the icons used in your menus and loads the complete library when one of them needs it, so those menus recover on their own. +* Added "Font Awesome icons" under Content Options in the Customizer, for icons the menu scan cannot see -- a widget, post content, a page builder. The sparkling_full_fontawesome filter still overrides it. + = 2.6.10 = * Fixed the Customizer failing to open with "Class Epsilon_Section_Recommended_Actions not found". The 2.6.x packages shipped an outdated inc/welcome-screen/welcome-page-setup.php that still used classes removed with the Epsilon framework. * Restored Appearance > About Sparkling, which the same outdated file never registered. diff --git a/search.php b/search.php index 57e16897..25873e87 100644 --- a/search.php +++ b/search.php @@ -12,13 +12,15 @@ + ?> ' ' . __( 'Newer posts', 'sparkling' ), - 'next_text' => __( 'Older posts', 'sparkling' ) . ' ', + 'prev_text' => ' ' . __( 'Newer posts', 'sparkling' ), + 'next_text' => __( 'Older posts', 'sparkling' ) . ' ', ) ); diff --git a/searchform.php b/searchform.php index e73925ae..038423a8 100644 --- a/searchform.php +++ b/searchform.php @@ -4,14 +4,18 @@ * * @package sparkling */ + +// A page can hold several search forms (the sidebar widget, the 404 page, the +// "nothing found" message), so each gets its own id for its label. +$sparkling_search_field = wp_unique_id( 'search-field-' ); ?> diff --git a/sidebar-footer.php b/sidebar-footer.php index c3d17f12..875f49d1 100644 --- a/sidebar-footer.php +++ b/sidebar-footer.php @@ -15,21 +15,21 @@ // If we made it this far we must have widgets. ?> -