@sociallane/elements 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/install-new-instance.md +5 -5
- package/docs/npm-widget-cheatsheet.md +33 -14
- package/docs/package-installation.md +8 -7
- package/package.json +1 -1
- package/packages/widgets/card-hover-reveal/data/view.php +1 -1
- package/packages/widgets/grid-components/data/view.php +6 -1
- package/packages/widgets/widget-filter/data/view.php +2 -2
- package/scripts/install.js +193 -26
- package/scripts/postinstall.js +11 -8
- package/scripts/widget-installer.js +17 -51
- package/widgets/card-hover-reveal/data/view.php +1 -1
- package/widgets/grid-components/data/view.php +1 -1
|
@@ -55,13 +55,13 @@ cd wp-content/plugins/sociallane-elements && npm install && npm run build
|
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
57
|
# From your WordPress root (directory that contains wp-content)
|
|
58
|
-
npx @sociallane/elements --
|
|
58
|
+
npx @sociallane/elements --base
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Then add widgets by slug (no manual `widgets.json` editing):
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
npx @sociallane/elements add hero-split faq content-block widget-filter
|
|
64
|
+
npx @sociallane/elements add hero-split faq-stacked content-block widget-filter
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Each `add` updates `widgets.json` and runs the build. You can run `add` anytime to add more widgets.
|
|
@@ -77,8 +77,8 @@ This copies the full plugin to `wp-content/plugins/sociallane-elements`, runs `n
|
|
|
77
77
|
**Custom path:**
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
|
-
npx @sociallane/elements --
|
|
81
|
-
npx @sociallane/elements add hero-split faq
|
|
80
|
+
npx @sociallane/elements --base path/to/wp-content/plugins/sociallane-elements
|
|
81
|
+
npx @sociallane/elements add --target path/to/wp-content/plugins/sociallane-elements hero-split faq-stacked
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
**Single widget (per-widget packages):**
|
|
@@ -87,7 +87,7 @@ You can install one widget at a time via its own package. This installs the Soci
|
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
89
|
# From your WordPress root or wp-content/plugins
|
|
90
|
-
npx @sociallane/widget-
|
|
90
|
+
npx @sociallane/widget-content-block
|
|
91
91
|
npx @sociallane/widget-faq-stacked
|
|
92
92
|
```
|
|
93
93
|
|
|
@@ -7,8 +7,11 @@ Quick reference for loading widgets via npm workspaces.
|
|
|
7
7
|
## One-liners
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
#
|
|
11
|
-
|
|
10
|
+
# Base install (no widgets imported yet)
|
|
11
|
+
npx @sociallane/elements --base
|
|
12
|
+
|
|
13
|
+
# Add selected widgets
|
|
14
|
+
npx @sociallane/elements add hero-split faq-stacked content-block
|
|
12
15
|
|
|
13
16
|
# Dev watch (rebuilds on file change)
|
|
14
17
|
npm run dev
|
|
@@ -28,7 +31,7 @@ Edit `widgets.json` at plugin root:
|
|
|
28
31
|
"hero-split",
|
|
29
32
|
"hero-overlay",
|
|
30
33
|
"content-block",
|
|
31
|
-
"faq"
|
|
34
|
+
"faq-stacked"
|
|
32
35
|
]
|
|
33
36
|
}
|
|
34
37
|
```
|
|
@@ -39,7 +42,10 @@ Only slugs listed here are loaded. Add or remove as needed.
|
|
|
39
42
|
|
|
40
43
|
## Widget → npm package & command
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
Common widgets and their npm package / add command:
|
|
46
|
+
|
|
47
|
+
> Note: per-widget packages may not all be published at the same time.
|
|
48
|
+
> The most reliable flow is `npx @sociallane/elements --base` then `npx @sociallane/elements add ...`.
|
|
43
49
|
|
|
44
50
|
| Widget | Package | Command |
|
|
45
51
|
|--------|---------|---------|
|
|
@@ -52,7 +58,9 @@ Every widget and its npm package / add command:
|
|
|
52
58
|
| cta-banner | `@sociallane/widget-cta-banner` | `npm install @sociallane/widget-cta-banner` |
|
|
53
59
|
| cta-notify | `@sociallane/widget-cta-notify` | `npm install @sociallane/widget-cta-notify` |
|
|
54
60
|
| cta-split | `@sociallane/widget-cta-split` | `npm install @sociallane/widget-cta-split` |
|
|
55
|
-
| faq | `@sociallane/widget-faq` | `npm install @sociallane/widget-faq` |
|
|
61
|
+
| faq-stacked | `@sociallane/widget-faq-stacked` | `npm install @sociallane/widget-faq-stacked` |
|
|
62
|
+
| faq-split | `@sociallane/widget-faq-split` | `npm install @sociallane/widget-faq-split` |
|
|
63
|
+
| faq-centered | `@sociallane/widget-faq-centered` | `npm install @sociallane/widget-faq-centered` |
|
|
56
64
|
| feature-grid | `@sociallane/widget-feature-grid` | `npm install @sociallane/widget-feature-grid` |
|
|
57
65
|
| feature-list | `@sociallane/widget-feature-list` | `npm install @sociallane/widget-feature-list` |
|
|
58
66
|
| feature-list-cta | `@sociallane/widget-feature-list-cta` | `npm install @sociallane/widget-feature-list-cta` |
|
|
@@ -62,25 +70,34 @@ Every widget and its npm package / add command:
|
|
|
62
70
|
| form-contact | `@sociallane/widget-form-contact` | `npm install @sociallane/widget-form-contact` |
|
|
63
71
|
| grid-case-studies | `@sociallane/widget-grid-case-studies` | `npm install @sociallane/widget-grid-case-studies` |
|
|
64
72
|
| grid-components | `@sociallane/widget-grid-components` | `npm install @sociallane/widget-grid-components` |
|
|
65
|
-
| grid
|
|
73
|
+
| posts-grid | `@sociallane/widget-posts-grid` | `npm install @sociallane/widget-posts-grid` |
|
|
74
|
+
| posts-grid-overlay | `@sociallane/widget-posts-grid-overlay` | `npm install @sociallane/widget-posts-grid-overlay` |
|
|
66
75
|
| grid-team | `@sociallane/widget-grid-team` | `npm install @sociallane/widget-grid-team` |
|
|
67
|
-
| grid
|
|
76
|
+
| testimonials-grid | `@sociallane/widget-testimonials-grid` | `npm install @sociallane/widget-testimonials-grid` |
|
|
77
|
+
| testimonials-masonry | `@sociallane/widget-testimonials-masonry` | `npm install @sociallane/widget-testimonials-masonry` |
|
|
78
|
+
| testimonials-bento | `@sociallane/widget-testimonials-bento` | `npm install @sociallane/widget-testimonials-bento` |
|
|
68
79
|
| hero-announcement | `@sociallane/widget-hero-announcement` | `npm install @sociallane/widget-hero-announcement` |
|
|
69
80
|
| hero-centered-image | `@sociallane/widget-hero-centered-image` | `npm install @sociallane/widget-hero-centered-image` |
|
|
70
81
|
| hero-collage | `@sociallane/widget-hero-collage` | `npm install @sociallane/widget-hero-collage` |
|
|
71
82
|
| hero-overlay | `@sociallane/widget-hero-overlay` | `npm install @sociallane/widget-hero-overlay` |
|
|
72
|
-
| hero-saas | `@sociallane/widget-hero-saas` | `npm install @sociallane/widget-hero-saas` |
|
|
83
|
+
| hero-saas-split | `@sociallane/widget-hero-saas-split` | `npm install @sociallane/widget-hero-saas-split` |
|
|
84
|
+
| hero-saas-stacked | `@sociallane/widget-hero-saas-stacked` | `npm install @sociallane/widget-hero-saas-stacked` |
|
|
85
|
+
| hero-saas-centered | `@sociallane/widget-hero-saas-centered` | `npm install @sociallane/widget-hero-saas-centered` |
|
|
73
86
|
| hero-split | `@sociallane/widget-hero-split` | `npm install @sociallane/widget-hero-split` |
|
|
74
87
|
| hero-stacked-image | `@sociallane/widget-hero-stacked-image` | `npm install @sociallane/widget-hero-stacked-image` |
|
|
75
88
|
| intro-pattern | `@sociallane/widget-intro-pattern` | `npm install @sociallane/widget-intro-pattern` |
|
|
76
89
|
| intro-text | `@sociallane/widget-intro-text` | `npm install @sociallane/widget-intro-text` |
|
|
77
|
-
| logo-grid | `@sociallane/widget-logo-grid` | `npm install @sociallane/widget-logo-grid` |
|
|
90
|
+
| logo-grid-centered | `@sociallane/widget-logo-grid-centered` | `npm install @sociallane/widget-logo-grid-centered` |
|
|
91
|
+
| logo-grid-row | `@sociallane/widget-logo-grid-row` | `npm install @sociallane/widget-logo-grid-row` |
|
|
92
|
+
| logo-grid-split | `@sociallane/widget-logo-grid-split` | `npm install @sociallane/widget-logo-grid-split` |
|
|
78
93
|
| nav-default | `@sociallane/widget-nav-default` | `npm install @sociallane/widget-nav-default` |
|
|
79
94
|
| nav-centered | `@sociallane/widget-nav-centered` | `npm install @sociallane/widget-nav-centered` |
|
|
80
95
|
| nav-minimal | `@sociallane/widget-nav-minimal` | `npm install @sociallane/widget-nav-minimal` |
|
|
81
96
|
| nav-compact | `@sociallane/widget-nav-compact` | `npm install @sociallane/widget-nav-compact` |
|
|
82
97
|
| nav-floating | `@sociallane/widget-nav-floating` | `npm install @sociallane/widget-nav-floating` |
|
|
83
98
|
| newsletter | `@sociallane/widget-newsletter` | `npm install @sociallane/widget-newsletter` |
|
|
99
|
+
| newsletter-card | `@sociallane/widget-newsletter-card` | `npm install @sociallane/widget-newsletter-card` |
|
|
100
|
+
| newsletter-section | `@sociallane/widget-newsletter-section` | `npm install @sociallane/widget-newsletter-section` |
|
|
84
101
|
| outreach-dashboard | `@sociallane/widget-outreach-dashboard` | `npm install @sociallane/widget-outreach-dashboard` |
|
|
85
102
|
| pipeline-dashboard | `@sociallane/widget-pipeline-dashboard` | `npm install @sociallane/widget-pipeline-dashboard` |
|
|
86
103
|
| pricing-table | `@sociallane/widget-pricing-table` | `npm install @sociallane/widget-pricing-table` |
|
|
@@ -89,7 +106,9 @@ Every widget and its npm package / add command:
|
|
|
89
106
|
| services | `@sociallane/widget-services` | `npm install @sociallane/widget-services` |
|
|
90
107
|
| simple-page-hero | `@sociallane/widget-simple-page-hero` | `npm install @sociallane/widget-simple-page-hero` |
|
|
91
108
|
| social-proof | `@sociallane/widget-social-proof` | `npm install @sociallane/widget-social-proof` |
|
|
109
|
+
| social-proof-trust | `@sociallane/widget-social-proof-trust` | `npm install @sociallane/widget-social-proof-trust` |
|
|
92
110
|
| testimonial-quote | `@sociallane/widget-testimonial-quote` | `npm install @sociallane/widget-testimonial-quote` |
|
|
111
|
+
| widget-filter | `@sociallane/widget-widget-filter` | `npm install @sociallane/widget-widget-filter` |
|
|
93
112
|
|
|
94
113
|
Then add the slug to `widgets.json`.
|
|
95
114
|
|
|
@@ -99,12 +118,12 @@ Then add the slug to `widgets.json`.
|
|
|
99
118
|
|
|
100
119
|
| Category | Slugs |
|
|
101
120
|
|----------|-------|
|
|
102
|
-
| Heroes | `hero-split`, `hero-overlay`, `hero-saas`, `hero-collage`, `hero-centered-image`, `hero-stacked-image`, `hero-announcement`, `simple-page-hero` |
|
|
103
|
-
| Content | `content-block`, `intro-text`, `intro-pattern`, `faq`, `feature-list`, `feature-list-cta`, `feature-grid` |
|
|
104
|
-
| Cards & Grids | `card-hover-reveal`, `bento-grid`, `bento-portfolio`, `grid-
|
|
105
|
-
| Forms & CTAs | `cta-banner`, `cta-split`, `cta-notify`, `newsletter`, `form-contact`, `pricing-table` |
|
|
121
|
+
| Heroes | `hero-split`, `hero-overlay`, `hero-overlay-single`, `hero-overlay-slider`, `hero-saas-split`, `hero-saas-stacked`, `hero-saas-centered`, `hero-collage`, `hero-centered-image`, `hero-stacked-image`, `hero-announcement`, `simple-page-hero`, `page-hero-left`, `page-hero-center` |
|
|
122
|
+
| Content | `content-block`, `intro-text`, `intro-pattern`, `faq-stacked`, `faq-split`, `faq-centered`, `feature-list`, `feature-list-cta`, `feature-grid` |
|
|
123
|
+
| Cards & Grids | `card-hover-reveal`, `bento-grid`, `bento-portfolio`, `posts-grid`, `posts-grid-overlay`, `grid-team`, `testimonials-grid`, `testimonials-masonry`, `testimonials-bento`, `grid-case-studies`, `grid-components`, `logo-grid-centered`, `logo-grid-row`, `logo-grid-split`, `client-logos` |
|
|
124
|
+
| Forms & CTAs | `cta-banner`, `cta-split`, `cta-notify`, `newsletter`, `newsletter-card`, `newsletter-section`, `form-contact`, `pricing-table` |
|
|
106
125
|
| Navigation | `nav-default`, `nav-centered`, `nav-minimal`, `nav-compact`, `nav-floating`, `footer`, `footer-brand`, `footer-links-contact` |
|
|
107
|
-
| Other | `section-stats`, `social-proof`, `services`, `blog-grid`, `outreach-dashboard`, `pipeline-dashboard`, `sales-dashboard`, `testimonial-quote` |
|
|
126
|
+
| Other | `section-stats`, `social-proof`, `social-proof-trust`, `services`, `blog-grid`, `outreach-dashboard`, `pipeline-dashboard`, `sales-dashboard`, `testimonial-quote`, `widget-filter` |
|
|
108
127
|
|
|
109
128
|
---
|
|
110
129
|
|
|
@@ -29,7 +29,8 @@ Edit `widgets.json` to include only the widget slugs you want. You can also let
|
|
|
29
29
|
|
|
30
30
|
Adding or removing widget directories is reflected in `widgets.json` automatically:
|
|
31
31
|
|
|
32
|
-
- **On `npm install`** — The postinstall script runs `sync-widgets` then `build
|
|
32
|
+
- **On `npm install`** — The postinstall script runs `sync-widgets` then `build` by default. Any new folder under `packages/widgets/{slug}` with `{slug}.php` is added to `widgets.json`; removed folders are removed from the list. Existing order is preserved; new slugs are appended sorted.
|
|
33
|
+
The installers use `SOCIALLANE_SKIP_SYNC_WIDGETS=1` for base/cherry-pick flows so `widgets.json` is not expanded unintentionally.
|
|
33
34
|
- **Manual sync** — From the plugin root run:
|
|
34
35
|
```bash
|
|
35
36
|
npm run sync-widgets
|
|
@@ -42,7 +43,7 @@ Adding or removing widget directories is reflected in `widgets.json` automatical
|
|
|
42
43
|
"hero-split",
|
|
43
44
|
"hero-overlay",
|
|
44
45
|
"content-block",
|
|
45
|
-
"faq"
|
|
46
|
+
"faq-stacked"
|
|
46
47
|
]
|
|
47
48
|
}
|
|
48
49
|
```
|
|
@@ -65,10 +66,10 @@ Use submodules so each WordPress instance only has the core package and the widg
|
|
|
65
66
|
|
|
66
67
|
# Add only the widgets you want
|
|
67
68
|
git submodule add <url-to-widget-hero-split> packages/widgets/hero-split
|
|
68
|
-
git submodule add <url-to-widget-faq> packages/widgets/faq
|
|
69
|
+
git submodule add <url-to-widget-faq-stacked> packages/widgets/faq-stacked
|
|
69
70
|
```
|
|
70
71
|
|
|
71
|
-
3. Update **widgets.json** so its `widgets` array lists only the slugs you added (e.g. `hero-split`, `faq`).
|
|
72
|
+
3. Update **widgets.json** so its `widgets` array lists only the slugs you added (e.g. `hero-split`, `faq-stacked`).
|
|
72
73
|
|
|
73
74
|
4. Install and build from plugin root (both required for styled widgets):
|
|
74
75
|
|
|
@@ -123,13 +124,13 @@ The plugin is published as `@sociallane/elements`. To publish:
|
|
|
123
124
|
|
|
124
125
|
## Per-widget npm packages
|
|
125
126
|
|
|
126
|
-
Individual widgets are published as `@sociallane/widget-<slug>` (
|
|
127
|
+
Individual widgets are published as `@sociallane/widget-<slug>` (for example `@sociallane/widget-faq-stacked`). Run from your WordPress root or `wp-content/plugins`:
|
|
127
128
|
|
|
128
129
|
```bash
|
|
129
|
-
npx @sociallane/widget-
|
|
130
|
+
npx @sociallane/widget-faq-stacked
|
|
130
131
|
```
|
|
131
132
|
|
|
132
|
-
The installer installs the base plugin (`@sociallane/elements`) with `--
|
|
133
|
+
The installer installs the base plugin (`@sociallane/elements`) with `--base` if it is not present, then delegates to `npx @sociallane/elements add --target <pluginDir> <slug>`. Use these when you want a one-command install for a single widget. To add multiple widgets, `npx @sociallane/elements add --target <pluginDir> slug1 slug2` is usually simpler.
|
|
133
134
|
|
|
134
135
|
## Adding a new widget package
|
|
135
136
|
|
package/package.json
CHANGED
|
@@ -77,7 +77,7 @@ function prepare_card_hover_reveal_view( array $settings, string $widget_id ): a
|
|
|
77
77
|
$aspect_map = [ '16/9' => 'aspect-video', '4/3' => 'aspect-[4/3]', '3/2' => 'aspect-[3/2]', '1/1' => 'aspect-square', '3/4' => 'aspect-[3/4]' ];
|
|
78
78
|
$aspect_class = $aspect_map[ $aspect_ratio ] ?? 'aspect-video';
|
|
79
79
|
$columns = sociallane_validate_option( $settings['columns'] ?? '3', [ '2', '3' ], '3' );
|
|
80
|
-
$grid_class = sociallane_grid_cols( $columns, [ '2' => 'grid-cols-1 sm:grid-cols-2', '3' => 'grid-cols-1 sm:grid-cols-2
|
|
80
|
+
$grid_class = sociallane_grid_cols( $columns, [ '2' => 'grid-cols-1 sm:grid-cols-2', '3' => 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3' ] );
|
|
81
81
|
|
|
82
82
|
$animation = sociallane_animation_view_data( $settings, [ 'headline' => true, 'stagger' => true ] );
|
|
83
83
|
|
|
@@ -23,7 +23,12 @@ function prepare_grid_components_view( array $settings, string $widget_id ): arr
|
|
|
23
23
|
$fields = sociallane_extract_fields( $settings, [ 'headline' => [] ] );
|
|
24
24
|
$headline_tag = sociallane_validate_heading_tag( $settings, 'headline_tag', 'h2' );
|
|
25
25
|
$columns = sociallane_validate_option( $settings['columns'] ?? '4', [ '2', '3', '4' ], '4' );
|
|
26
|
-
$grid_class = sociallane_grid_cols(
|
|
26
|
+
$grid_class = sociallane_grid_cols(
|
|
27
|
+
$columns,
|
|
28
|
+
[
|
|
29
|
+
'3' => 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',
|
|
30
|
+
]
|
|
31
|
+
);
|
|
27
32
|
$placeholder_src = \Elementor\Utils::get_placeholder_image_src();
|
|
28
33
|
|
|
29
34
|
$components = sociallane_process_repeater( $settings['components'] ?? [], function ( $item ) use ( $placeholder_src ) {
|
|
@@ -484,8 +484,8 @@ function prepare_widget_filter_view( array $settings, string $widget_id ): array
|
|
|
484
484
|
// Grid columns class
|
|
485
485
|
$grid_columns = [
|
|
486
486
|
'2' => 'grid-cols-1 sm:grid-cols-2',
|
|
487
|
-
'3' => 'grid-cols-1 sm:grid-cols-2
|
|
488
|
-
'4' => 'grid-cols-1 sm:grid-cols-2
|
|
487
|
+
'3' => 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',
|
|
488
|
+
'4' => 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4',
|
|
489
489
|
];
|
|
490
490
|
$grid_class = $grid_columns[ $columns ] ?? $grid_columns['3'];
|
|
491
491
|
|
package/scripts/install.js
CHANGED
|
@@ -2,23 +2,60 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* SocialLane Elements CLI
|
|
4
4
|
*
|
|
5
|
+
* Install (base): npx @sociallane/elements --base [path]
|
|
5
6
|
* Install (full): npx @sociallane/elements [path]
|
|
6
7
|
* Add widgets: npx @sociallane/elements add <slug> [slug...]
|
|
7
8
|
*
|
|
8
9
|
* Install: copies package to wp-content/plugins/sociallane-elements (or path), runs npm install.
|
|
10
|
+
* Base install: installs core/deps and keeps widgets.json empty (no widgets loaded by default).
|
|
9
11
|
* Add: copies selected widget folders into an existing plugin, updates widgets.json, runs npm install.
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, writeFileSync } from 'fs';
|
|
14
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'fs';
|
|
13
15
|
import { spawnSync } from 'child_process';
|
|
14
16
|
import path from 'path';
|
|
15
17
|
import { fileURLToPath } from 'url';
|
|
16
18
|
|
|
17
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
20
|
const packageRoot = path.resolve(__dirname, '..');
|
|
19
|
-
const
|
|
21
|
+
const packageJsonPath = path.join(packageRoot, 'package.json');
|
|
22
|
+
|
|
23
|
+
function getCliVersion() {
|
|
24
|
+
try {
|
|
25
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
26
|
+
return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
|
|
27
|
+
} catch {
|
|
28
|
+
return '0.0.0';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function printHelp() {
|
|
33
|
+
console.log('SocialLane Elements CLI');
|
|
34
|
+
console.log('');
|
|
35
|
+
console.log('Usage:');
|
|
36
|
+
console.log(' npx @sociallane/elements [--base|--minimal] [target]');
|
|
37
|
+
console.log(' npx @sociallane/elements add [--only] [--target <path>] <slug> [slug...]');
|
|
38
|
+
console.log(' npx @sociallane/elements --help');
|
|
39
|
+
console.log(' npx @sociallane/elements --version');
|
|
40
|
+
console.log('');
|
|
41
|
+
console.log('Options:');
|
|
42
|
+
console.log(' --base, --minimal Install core/deps only, keep widgets.json empty');
|
|
43
|
+
console.log(' --only With add: replace widgets.json with exactly provided slugs');
|
|
44
|
+
console.log(' --target <path> With add: explicit plugin directory target');
|
|
45
|
+
console.log(' --help Show this help text');
|
|
46
|
+
console.log(' --version Show CLI version');
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log('Examples:');
|
|
49
|
+
console.log(' npx @sociallane/elements --base');
|
|
50
|
+
console.log(' npx @sociallane/elements add faq-stacked hero-split');
|
|
51
|
+
console.log(' npx @sociallane/elements add --only --target wp-content/plugins/sociallane-elements content-block');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resolvePluginDir(targetPath = '') {
|
|
55
|
+
if (targetPath) {
|
|
56
|
+
return path.resolve(process.cwd(), targetPath);
|
|
57
|
+
}
|
|
20
58
|
|
|
21
|
-
function resolvePluginDir() {
|
|
22
59
|
const cwd = process.cwd();
|
|
23
60
|
const normalized = path.normalize(cwd);
|
|
24
61
|
const pluginsSegment = 'wp-content' + path.sep + 'plugins';
|
|
@@ -41,9 +78,59 @@ function resolvePluginDir() {
|
|
|
41
78
|
return path.join(cwd, 'wp-content', 'plugins', 'sociallane-elements');
|
|
42
79
|
}
|
|
43
80
|
|
|
44
|
-
function
|
|
45
|
-
const
|
|
81
|
+
function getWidgetsSourceDir() {
|
|
82
|
+
const candidates = [
|
|
83
|
+
path.join(packageRoot, 'packages', 'widgets'),
|
|
84
|
+
path.join(packageRoot, 'widgets'),
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
for (const dir of candidates) {
|
|
88
|
+
if (!existsSync(dir)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const available = readdirSync(dir, { withFileTypes: true })
|
|
92
|
+
.filter((d) => d.isDirectory() && existsSync(path.join(dir, d.name, `${d.name}.php`)))
|
|
93
|
+
.map((d) => d.name);
|
|
94
|
+
if (available.length > 0) {
|
|
95
|
+
return dir;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return candidates[0];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function updateWidgetsJson(pluginDir, slugsToAdd, replaceAll = false) {
|
|
102
|
+
const widgetsJsonPath = path.join(pluginDir, 'widgets.json');
|
|
103
|
+
let existing = [];
|
|
104
|
+
|
|
105
|
+
if (!replaceAll && existsSync(widgetsJsonPath)) {
|
|
106
|
+
try {
|
|
107
|
+
const raw = readFileSync(widgetsJsonPath, 'utf8');
|
|
108
|
+
const parsed = JSON.parse(raw);
|
|
109
|
+
if (Array.isArray(parsed?.widgets)) {
|
|
110
|
+
existing = parsed.widgets.filter((slug) => typeof slug === 'string');
|
|
111
|
+
}
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.warn('Could not parse widgets.json, recreating it:', err.message);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const merged = [...existing];
|
|
118
|
+
const existingSet = new Set(existing);
|
|
119
|
+
for (const slug of slugsToAdd) {
|
|
120
|
+
if (!existingSet.has(slug)) {
|
|
121
|
+
merged.push(slug);
|
|
122
|
+
existingSet.add(slug);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
writeFileSync(widgetsJsonPath, JSON.stringify({ widgets: merged }, null, 2) + '\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function addWidgets(slugs, options = {}) {
|
|
130
|
+
const replaceAll = options.replaceAll === true;
|
|
131
|
+
const pluginDir = resolvePluginDir(options.targetPath || '');
|
|
46
132
|
const widgetsDest = path.join(pluginDir, 'packages', 'widgets');
|
|
133
|
+
const widgetsSource = getWidgetsSourceDir();
|
|
47
134
|
|
|
48
135
|
if (!existsSync(path.join(pluginDir, 'sociallane-elements.php'))) {
|
|
49
136
|
console.error('Plugin not found at', pluginDir);
|
|
@@ -56,8 +143,10 @@ function addWidgets(slugs) {
|
|
|
56
143
|
process.exit(1);
|
|
57
144
|
}
|
|
58
145
|
|
|
146
|
+
console.log('Target plugin:', pluginDir);
|
|
147
|
+
|
|
59
148
|
const available = readdirSync(widgetsSource, { withFileTypes: true })
|
|
60
|
-
.filter((d) => d.isDirectory())
|
|
149
|
+
.filter((d) => d.isDirectory() && existsSync(path.join(widgetsSource, d.name, `${d.name}.php`)))
|
|
61
150
|
.map((d) => d.name);
|
|
62
151
|
|
|
63
152
|
const missing = slugs.filter((s) => !available.includes(s));
|
|
@@ -84,17 +173,16 @@ function addWidgets(slugs) {
|
|
|
84
173
|
console.log('Added:', slug);
|
|
85
174
|
}
|
|
86
175
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
stdio: 'inherit',
|
|
91
|
-
});
|
|
92
|
-
if (result.status !== 0) {
|
|
93
|
-
process.exit(result.status || 1);
|
|
94
|
-
}
|
|
176
|
+
updateWidgetsJson(pluginDir, slugs, replaceAll);
|
|
177
|
+
console.log('Updated widgets.json and installing dependencies...');
|
|
178
|
+
|
|
95
179
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
96
180
|
const installResult = spawnSync(npmCmd, ['install'], {
|
|
97
181
|
cwd: pluginDir,
|
|
182
|
+
env: {
|
|
183
|
+
...process.env,
|
|
184
|
+
SOCIALLANE_SKIP_SYNC_WIDGETS: '1',
|
|
185
|
+
},
|
|
98
186
|
stdio: 'inherit',
|
|
99
187
|
shell: true,
|
|
100
188
|
});
|
|
@@ -108,6 +196,14 @@ function addWidgets(slugs) {
|
|
|
108
196
|
console.log('Done. Widgets added:', slugs.join(', '));
|
|
109
197
|
}
|
|
110
198
|
|
|
199
|
+
function prepareBaseMode(pluginDir) {
|
|
200
|
+
const widgetsDest = path.join(pluginDir, 'packages', 'widgets');
|
|
201
|
+
if (!existsSync(widgetsDest)) {
|
|
202
|
+
mkdirSync(widgetsDest, { recursive: true });
|
|
203
|
+
}
|
|
204
|
+
updateWidgetsJson(pluginDir, [], true);
|
|
205
|
+
}
|
|
206
|
+
|
|
111
207
|
function copyPackage(toDir, filter) {
|
|
112
208
|
if (!existsSync(toDir)) {
|
|
113
209
|
mkdirSync(toDir, { recursive: true });
|
|
@@ -154,12 +250,21 @@ function install(targetPath, minimal) {
|
|
|
154
250
|
const targetResolved = path.resolve(target);
|
|
155
251
|
const isSelf = targetResolved === path.resolve(packageRoot) || targetResolved.startsWith(packageRoot + path.sep);
|
|
156
252
|
|
|
157
|
-
console.log(
|
|
253
|
+
console.log(
|
|
254
|
+
'SocialLane Elements installer' +
|
|
255
|
+
(minimal ? ' (base mode – add widgets with: npx @sociallane/elements add <slug> ...)' : '')
|
|
256
|
+
);
|
|
158
257
|
console.log('Target:', target);
|
|
159
258
|
|
|
160
259
|
if (isSelf) {
|
|
260
|
+
if (minimal) {
|
|
261
|
+
prepareBaseMode(packageRoot);
|
|
262
|
+
}
|
|
161
263
|
console.log('Target is the current package. Running npm install here...');
|
|
162
264
|
} else if (existsSync(target) && existsSync(path.join(target, 'package.json'))) {
|
|
265
|
+
if (minimal) {
|
|
266
|
+
prepareBaseMode(target);
|
|
267
|
+
}
|
|
163
268
|
console.log('Target already exists. Running npm install only...');
|
|
164
269
|
} else {
|
|
165
270
|
console.log('Copying package...');
|
|
@@ -168,16 +273,18 @@ function install(targetPath, minimal) {
|
|
|
168
273
|
const rel = path.relative(packageRoot, src).split(path.sep).join('/');
|
|
169
274
|
// Exclude node_modules within the package (not in parent path)
|
|
170
275
|
if (rel.includes('node_modules')) return false;
|
|
171
|
-
//
|
|
276
|
+
// Base install should not ship widget sources; users add explicitly via `add`.
|
|
172
277
|
if (rel === 'packages/widgets' || rel.startsWith('packages/widgets/')) return false;
|
|
278
|
+
// Exclude legacy widgets directory and generated npm-widget package folders.
|
|
279
|
+
if (rel === 'widgets' || rel.startsWith('widgets/')) return false;
|
|
280
|
+
if (rel === 'packages/npm-widgets' || rel.startsWith('packages/npm-widgets/')) return false;
|
|
173
281
|
return true;
|
|
174
282
|
});
|
|
175
283
|
const widgetsDest = path.join(target, 'packages', 'widgets');
|
|
176
284
|
if (!existsSync(widgetsDest)) {
|
|
177
285
|
mkdirSync(widgetsDest, { recursive: true });
|
|
178
286
|
}
|
|
179
|
-
|
|
180
|
-
writeFileSync(widgetsJson, JSON.stringify({ widgets: [] }, null, 2));
|
|
287
|
+
updateWidgetsJson(target, [], true);
|
|
181
288
|
} else {
|
|
182
289
|
copyPackage(target);
|
|
183
290
|
}
|
|
@@ -186,8 +293,15 @@ function install(targetPath, minimal) {
|
|
|
186
293
|
const installDir = isSelf ? packageRoot : target;
|
|
187
294
|
console.log('Running npm install in', installDir + '...');
|
|
188
295
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
296
|
+
const installEnv = {
|
|
297
|
+
...process.env,
|
|
298
|
+
};
|
|
299
|
+
if (minimal) {
|
|
300
|
+
installEnv.SOCIALLANE_SKIP_SYNC_WIDGETS = '1';
|
|
301
|
+
}
|
|
189
302
|
const result = spawnSync(npmCmd, ['install'], {
|
|
190
303
|
cwd: installDir,
|
|
304
|
+
env: installEnv,
|
|
191
305
|
stdio: 'inherit',
|
|
192
306
|
shell: true,
|
|
193
307
|
});
|
|
@@ -209,19 +323,72 @@ function install(targetPath, minimal) {
|
|
|
209
323
|
|
|
210
324
|
function main() {
|
|
211
325
|
const args = process.argv.slice(2);
|
|
212
|
-
const minimal = args.includes('--minimal');
|
|
213
|
-
const installArgs = args.filter((a) => a !== '--minimal');
|
|
214
326
|
|
|
215
|
-
if (
|
|
216
|
-
|
|
327
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
328
|
+
printHelp();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
333
|
+
console.log(getCliVersion());
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (args[0] === 'add') {
|
|
338
|
+
const addArgs = args.slice(1).filter(Boolean);
|
|
339
|
+
const knownAddFlags = new Set(['--only', '--target']);
|
|
340
|
+
let targetPath = '';
|
|
341
|
+
const slugs = [];
|
|
342
|
+
for (let i = 0; i < addArgs.length; i++) {
|
|
343
|
+
const arg = addArgs[i];
|
|
344
|
+
if (arg === '--target') {
|
|
345
|
+
const next = addArgs[i + 1];
|
|
346
|
+
if (!next || next.startsWith('-')) {
|
|
347
|
+
console.error('Missing value for --target');
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
targetPath = next;
|
|
351
|
+
i++;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
if (arg.startsWith('-')) {
|
|
355
|
+
if (!knownAddFlags.has(arg)) {
|
|
356
|
+
console.error('Unknown option for add:', arg);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
slugs.push(arg);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const replaceAll = addArgs.includes('--only');
|
|
217
365
|
if (slugs.length === 0) {
|
|
218
|
-
console.error('Usage: npx @sociallane/elements add <slug> [slug...]');
|
|
219
|
-
console.error('Example: npx @sociallane/elements add hero-split faq content-block');
|
|
366
|
+
console.error('Usage: npx @sociallane/elements add [--only] <slug> [slug...]');
|
|
367
|
+
console.error('Example: npx @sociallane/elements add --only hero-split faq-stacked content-block');
|
|
220
368
|
process.exit(1);
|
|
221
369
|
}
|
|
222
|
-
addWidgets(slugs);
|
|
370
|
+
addWidgets(slugs, { replaceAll, targetPath });
|
|
223
371
|
} else {
|
|
224
|
-
|
|
372
|
+
let minimal = false;
|
|
373
|
+
const positionals = [];
|
|
374
|
+
for (const arg of args) {
|
|
375
|
+
if (arg === '--minimal' || arg === '--base') {
|
|
376
|
+
minimal = true;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (arg.startsWith('-')) {
|
|
380
|
+
console.error('Unknown option:', arg);
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
positionals.push(arg);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (positionals.length > 1) {
|
|
387
|
+
console.error('Too many positional arguments. Expected at most one target path.');
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
install(positionals[0], minimal);
|
|
225
392
|
}
|
|
226
393
|
}
|
|
227
394
|
|
package/scripts/postinstall.js
CHANGED
|
@@ -54,14 +54,17 @@ function ensureLocalCliShim() {
|
|
|
54
54
|
|
|
55
55
|
ensureLocalCliShim();
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
const skipSyncWidgets = process.env.SOCIALLANE_SKIP_SYNC_WIDGETS === '1';
|
|
58
|
+
if (!skipSyncWidgets) {
|
|
59
|
+
// Run sync-widgets
|
|
60
|
+
console.log('Running sync-widgets...');
|
|
61
|
+
const syncResult = spawnSync('node', [path.join(__dirname, 'sync-widgets.js')], {
|
|
62
|
+
cwd: pluginRoot,
|
|
63
|
+
stdio: 'inherit',
|
|
64
|
+
});
|
|
65
|
+
if (syncResult.status !== 0) {
|
|
66
|
+
process.exit(syncResult.status || 1);
|
|
67
|
+
}
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
// Run build
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Per-widget installer: run from a @sociallane/widget-<slug> package (npx).
|
|
4
|
-
* Ensures SocialLane Elements plugin is installed
|
|
5
|
-
*
|
|
4
|
+
* Ensures SocialLane Elements plugin is installed in base mode, then delegates
|
|
5
|
+
* widget import to the main CLI add command.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { existsSync, readFileSync } from 'fs';
|
|
9
9
|
import { spawnSync } from 'child_process';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
|
|
13
13
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
14
|
const packageRoot = path.resolve(__dirname);
|
|
15
|
-
const widgetDir = path.join(packageRoot, 'widget');
|
|
16
15
|
|
|
17
16
|
function getSlugFromPackage() {
|
|
18
17
|
const pkgPath = path.join(packageRoot, 'package.json');
|
|
@@ -56,62 +55,29 @@ function resolvePluginDir() {
|
|
|
56
55
|
return path.join(cwd, 'wp-content', 'plugins', 'sociallane-elements');
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
function
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
process.exit(1);
|
|
58
|
+
function runNpx(args, cwd) {
|
|
59
|
+
const r = spawnSync('npx', ['--yes', ...args], {
|
|
60
|
+
cwd,
|
|
61
|
+
stdio: 'inherit',
|
|
62
|
+
shell: true,
|
|
63
|
+
});
|
|
64
|
+
if (r.status !== 0) {
|
|
65
|
+
process.exit(r.status ?? 1);
|
|
68
66
|
}
|
|
67
|
+
}
|
|
69
68
|
|
|
69
|
+
function main() {
|
|
70
|
+
const slug = getSlugFromPackage();
|
|
70
71
|
const pluginDir = resolvePluginDir();
|
|
71
|
-
const widgetsDest = path.join(pluginDir, 'packages', 'widgets');
|
|
72
72
|
const pluginExists = existsSync(path.join(pluginDir, 'sociallane-elements.php'));
|
|
73
73
|
|
|
74
74
|
if (!pluginExists) {
|
|
75
75
|
console.log('SocialLane Elements not found. Installing base plugin...');
|
|
76
|
-
|
|
77
|
-
cwd: path.dirname(pluginDir),
|
|
78
|
-
stdio: 'inherit',
|
|
79
|
-
shell: true,
|
|
80
|
-
});
|
|
81
|
-
if (r.status !== 0) {
|
|
82
|
-
process.exit(r.status ?? 1);
|
|
83
|
-
}
|
|
76
|
+
runNpx(['@sociallane/elements', '--base', pluginDir], path.dirname(pluginDir));
|
|
84
77
|
}
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const dest = path.join(widgetsDest, slug);
|
|
91
|
-
cpSync(widgetDir, dest, { recursive: true, force: true });
|
|
92
|
-
console.log('Added widget:', slug);
|
|
93
|
-
|
|
94
|
-
console.log('Updating widgets.json and building...');
|
|
95
|
-
const syncResult = spawnSync('node', [path.join(pluginDir, 'scripts', 'sync-widgets.js')], {
|
|
96
|
-
cwd: pluginDir,
|
|
97
|
-
stdio: 'inherit',
|
|
98
|
-
});
|
|
99
|
-
if (syncResult.status !== 0) {
|
|
100
|
-
process.exit(syncResult.status ?? 1);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
104
|
-
const installResult = spawnSync(npmCmd, ['install'], {
|
|
105
|
-
cwd: pluginDir,
|
|
106
|
-
stdio: 'inherit',
|
|
107
|
-
shell: true,
|
|
108
|
-
});
|
|
109
|
-
if (installResult.status !== 0) {
|
|
110
|
-
if (installResult.error) {
|
|
111
|
-
console.error('Failed to run npm:', installResult.error.message);
|
|
112
|
-
}
|
|
113
|
-
process.exit(installResult.status ?? 1);
|
|
114
|
-
}
|
|
79
|
+
console.log('Adding widget:', slug);
|
|
80
|
+
runNpx(['@sociallane/elements', 'add', '--target', pluginDir, slug], path.dirname(pluginDir));
|
|
115
81
|
|
|
116
82
|
console.log('');
|
|
117
83
|
console.log('Done. Widget', slug, 'installed. Activate the plugin in WordPress → Plugins if needed.');
|
|
@@ -108,7 +108,7 @@ function prepare_card_hover_reveal_view( array $settings, string $widget_id ): a
|
|
|
108
108
|
$columns = in_array( $settings['columns'] ?? '3', [ '2', '3' ], true ) ? $settings['columns'] : '3';
|
|
109
109
|
$grid_class = $columns === '2'
|
|
110
110
|
? 'grid-cols-1 sm:grid-cols-2'
|
|
111
|
-
: 'grid-cols-1 sm:grid-cols-2
|
|
111
|
+
: 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3';
|
|
112
112
|
|
|
113
113
|
$animation = sociallane_animation_view_data( $settings, [ 'headline' => true, 'stagger' => true ] );
|
|
114
114
|
|
|
@@ -30,7 +30,7 @@ function prepare_grid_components_view( array $settings, string $widget_id ): arr
|
|
|
30
30
|
$columns = in_array( $settings['columns'] ?? '4', [ '2', '3', '4' ], true ) ? $settings['columns'] : '4';
|
|
31
31
|
$grid_class = [
|
|
32
32
|
'2' => 'grid-cols-1 sm:grid-cols-2',
|
|
33
|
-
'3' => 'grid-cols-1 sm:grid-cols-2
|
|
33
|
+
'3' => 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',
|
|
34
34
|
'4' => 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
|
35
35
|
][ $columns ];
|
|
36
36
|
|