vibespot 1.1.1 → 1.3.0
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/LICENSE +103 -33
- package/README.md +55 -6
- package/assets/blog-rules.md +251 -0
- package/assets/email-rules.md +390 -0
- package/assets/humanify-guide.md +300 -101
- package/assets/plan-templates/agency-services.md +42 -0
- package/assets/plan-templates/blog-content-hub.md +50 -0
- package/assets/plan-templates/ecommerce-product.md +42 -0
- package/assets/plan-templates/email-announcement.md +41 -0
- package/assets/plan-templates/email-event-invite.md +43 -0
- package/assets/plan-templates/email-newsletter.md +41 -0
- package/assets/plan-templates/email-re-engagement.md +42 -0
- package/assets/plan-templates/email-welcome.md +41 -0
- package/assets/plan-templates/event-registration.md +42 -0
- package/assets/plan-templates/portfolio.md +41 -0
- package/assets/plan-templates/restaurant.md +42 -0
- package/assets/plan-templates/saas-landing.md +42 -0
- package/dist/index.js +1485 -397
- package/dist/index.js.map +1 -1
- package/package.json +11 -7
- package/starters/01-saas-landing.json +43 -0
- package/starters/02-portfolio.json +39 -0
- package/starters/03-restaurant.json +39 -0
- package/starters/04-event.json +39 -0
- package/starters/05-coming-soon.json +32 -0
- package/starters/06-blog-content-hub.json +75 -0
- package/starters/06-email-welcome.json +60 -0
- package/starters/07-email-announcement.json +60 -0
- package/starters/08-email-newsletter.json +52 -0
- package/ui/chat.js +1604 -155
- package/ui/code-editor.js +49 -7
- package/ui/dashboard.js +551 -83
- package/ui/docs/docs.css +29 -0
- package/ui/docs/index.html +274 -117
- package/ui/docs/screenshots/brand-kit-preview.png +0 -0
- package/ui/docs/screenshots/content-type-dropdown.png +0 -0
- package/ui/docs/screenshots/editor-full-layout.png +0 -0
- package/ui/docs/screenshots/inline-wysiwyg-editing.png +0 -0
- package/ui/docs/screenshots/multi-page-tree.png +0 -0
- package/ui/docs/screenshots/onboarding-walkthrough.png +0 -0
- package/ui/docs/screenshots/split-pane-view.png +0 -0
- package/ui/docs/screenshots/visual-controls-toolbar.png +0 -0
- package/ui/docs/screenshots/workspace-tabs.png +0 -0
- package/ui/email-preview.js +109 -0
- package/ui/field-editor.js +71 -0
- package/ui/icons.js +120 -0
- package/ui/index.html +882 -515
- package/ui/inline-edit.js +710 -0
- package/ui/marketplace.js +218 -0
- package/ui/plan.js +0 -0
- package/ui/preview.js +219 -1
- package/ui/section-controls.js +628 -0
- package/ui/settings.js +84 -28
- package/ui/setup.js +1016 -118
- package/ui/styles.css +6119 -2456
- package/ui/upload-panel.js +47 -20
package/LICENSE
CHANGED
|
@@ -1,33 +1,103 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
Functional Source License, Version 1.1, Apache 2.0 Future License
|
|
2
|
+
|
|
3
|
+
Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-Apache-2.0
|
|
6
|
+
|
|
7
|
+
Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2024-2026 Boris Michel
|
|
10
|
+
|
|
11
|
+
Licensed Work
|
|
12
|
+
|
|
13
|
+
vibeSpot — AI-powered HubSpot CMS landing page builder
|
|
14
|
+
|
|
15
|
+
Change Date
|
|
16
|
+
|
|
17
|
+
2031-04-26
|
|
18
|
+
|
|
19
|
+
Change License
|
|
20
|
+
|
|
21
|
+
Apache License, Version 2.0
|
|
22
|
+
|
|
23
|
+
Terms and Conditions
|
|
24
|
+
|
|
25
|
+
Licensor: Boris Michel
|
|
26
|
+
Licensed Work: vibeSpot
|
|
27
|
+
The Licensed Work is copyright 2024-2026 Boris Michel.
|
|
28
|
+
Change Date: 2031-04-26
|
|
29
|
+
Change License: Apache License, Version 2.0
|
|
30
|
+
|
|
31
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
32
|
+
please contact Boris Michel.
|
|
33
|
+
|
|
34
|
+
Notice
|
|
35
|
+
|
|
36
|
+
This license is not an Open Source license. However, the Licensed Work will
|
|
37
|
+
eventually be made available under an Open Source license, as stated in this
|
|
38
|
+
license.
|
|
39
|
+
|
|
40
|
+
License text copyright 2023 MariaDB plc, All Rights Reserved.
|
|
41
|
+
"Functional Source License" is a trademark of MariaDB plc.
|
|
42
|
+
|
|
43
|
+
License Grant
|
|
44
|
+
|
|
45
|
+
Subject to the terms and conditions of this license, Licensor hereby grants
|
|
46
|
+
you a non-exclusive, worldwide, royalty-free, non-sublicensable, non-transferable
|
|
47
|
+
license to use, copy, modify, create derivative works, publicly perform, publicly
|
|
48
|
+
display, and redistribute the Licensed Work and any modified versions of the
|
|
49
|
+
Licensed Work, subject to the conditions in the section below titled
|
|
50
|
+
"Limitations."
|
|
51
|
+
|
|
52
|
+
Limitations
|
|
53
|
+
|
|
54
|
+
You may not make the Licensed Work available to third parties as a hosted or
|
|
55
|
+
managed service, where the service provides users with access to any substantial
|
|
56
|
+
set of the features or functionality of the Licensed Work.
|
|
57
|
+
|
|
58
|
+
You may not move, change, disable, or circumvent the license key functionality
|
|
59
|
+
in the Licensed Work, and you may not remove or obscure any functionality in the
|
|
60
|
+
Licensed Work that is protected by the license key.
|
|
61
|
+
|
|
62
|
+
You may not alter, remove, or obscure any licensing, copyright, or other notices
|
|
63
|
+
of Licensor in the Licensed Work. Any use of Licensor's trademarks is subject
|
|
64
|
+
to applicable law.
|
|
65
|
+
|
|
66
|
+
Patents
|
|
67
|
+
|
|
68
|
+
Licensor grants you a license, under any patent claims Licensor can license,
|
|
69
|
+
or becomes able to license, to make, have made, use, sell, offer for sale,
|
|
70
|
+
import and have imported the Licensed Work, in each case subject to the
|
|
71
|
+
limitations and conditions in this license. This license does not cover any
|
|
72
|
+
patent claims that you cause to be infringed by modifications or additions to
|
|
73
|
+
the Licensed Work. If you or your company make any written claim that the
|
|
74
|
+
Licensed Work (including any additions or modifications by anyone) infringes
|
|
75
|
+
or contributes to infringement of any patent, your patent license for the
|
|
76
|
+
Licensed Work granted under these terms ends immediately. If your company
|
|
77
|
+
makes such a claim, your patent license ends immediately for work on behalf
|
|
78
|
+
of your company.
|
|
79
|
+
|
|
80
|
+
Change Date and Change License
|
|
81
|
+
|
|
82
|
+
On the Change Date, or the fourth anniversary of the first publicly available
|
|
83
|
+
distribution of a specific version of the Licensed Work under this license,
|
|
84
|
+
whichever comes first, the Licensor hereby grants you rights under the terms
|
|
85
|
+
of the Change License, and the rights granted in the sections above titled
|
|
86
|
+
"License Grant" and "Patents" terminate.
|
|
87
|
+
|
|
88
|
+
If there is no specified Change Date and the above condition regarding the
|
|
89
|
+
fourth anniversary is not met, the Change License shall be deemed to be
|
|
90
|
+
the Elastic License 2.0.
|
|
91
|
+
|
|
92
|
+
Disclaimer
|
|
93
|
+
|
|
94
|
+
THE LICENSED WORK IS PROVIDED "AS IS". LICENSOR HEREBY DISCLAIMS ALL
|
|
95
|
+
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
96
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
97
|
+
|
|
98
|
+
Limitation of Liability
|
|
99
|
+
|
|
100
|
+
IN NO EVENT SHALL LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY,
|
|
101
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR
|
|
102
|
+
IN CONNECTION WITH THE LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE
|
|
103
|
+
LICENSED WORK.
|
package/README.md
CHANGED
|
@@ -25,20 +25,33 @@ npx vibespot
|
|
|
25
25
|
|
|
26
26
|
Opens a browser with:
|
|
27
27
|
- **Chat on the left** — describe your landing page in natural language
|
|
28
|
-
- **Live preview on the right** — see your page render in real-time,
|
|
28
|
+
- **Live preview on the right** — see your page render in real-time, with Split, Plan, and Code views
|
|
29
29
|
- **Agentic pipeline** — multi-stage AI generation with real-time progress
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
30
|
+
- **Multi-page sites** — create full HubSpot sites from a single prompt with shared header/footer, per-page layouts, and cross-page navigation validation
|
|
31
|
+
- **Inline WYSIWYG editing** — click text, images, and links directly in the live preview to edit them inline
|
|
32
|
+
- **Per-section visual controls** — hover any module for a floating toolbar with color pickers, spacing sliders, image swap, and font size controls
|
|
33
|
+
- **Plan mode** — toggle on to deliberate before generating: the AI asks elicitation questions, builds a markdown plan in a resizable sidebar, and only generates after you approve. Pre-canned plan templates for common page types skip the cold-start phase.
|
|
34
|
+
- **Onboarding walkthrough** — 3-step intro for first-time users covering what vibeSpot is, how it maps to HubSpot, and a guided first prompt
|
|
35
|
+
- **Workspace tabs** — Pages, Brand, Library, Marketplace, Settings tabs organize the dashboard. Brand tab includes a live visual preview of your brand kit.
|
|
36
|
+
- **Project sidebar** — create, open, resume, or delete projects; page tree shows all templates with type badges and module counts
|
|
32
37
|
- **Module management** — reorder via drag-and-drop, edit fields, delete modules from module list or module library
|
|
33
|
-
- **Starter templates** — SaaS, Portfolio, Restaurant, Event
|
|
38
|
+
- **Starter templates** — SaaS, Portfolio, Restaurant, Event, Coming Soon, Blog — pre-built page bundles for instant preview with no AI wait
|
|
39
|
+
- **Content types** — landing pages, email templates, and blog templates all supported from the UI page type dropdown
|
|
40
|
+
- **Split-pane view** — preview + code editor side by side in a 50/50 layout
|
|
41
|
+
- **Brand kit enforcement** — colors, fonts, and logo are injected as constraints into AI generation; validator warns on off-brand values
|
|
42
|
+
- **Interact mode** — unified mode that auto-detects whether you're editing content inline or referencing modules in chat
|
|
43
|
+
- **Undo/redo** — Ctrl+Z / Ctrl+Y step through version history; a compact timeline strip shows every generation step
|
|
44
|
+
- **Smart suggestions** — contextual suggestion chips appear after pipeline completion, filtered by existing modules
|
|
34
45
|
- **From Figma** *(Beta)* — paste a Figma URL to extract design tokens, text, and assets, then generate a full page that translates the design verbatim
|
|
35
46
|
- **From React** *(Beta)* — convert existing React/Lovable projects from a Git URL
|
|
47
|
+
- **From HubSpot** — fetch an existing theme, then run inverse analysis to extract design tokens, module graph, and round-trip risks
|
|
36
48
|
- **Field editor** — tweak text, colors, images directly
|
|
37
49
|
- **File uploads** — attach images and documents via drag-and-drop or paperclip button
|
|
38
50
|
- **Upload to HubSpot** — per-file progress, auto-fix, celebration popup with direct portal link
|
|
39
|
-
- **Version history** — per-template git commits with rollback
|
|
51
|
+
- **Version history** — per-template git commits with rollback in a collapsible bottom panel
|
|
40
52
|
- **Light/dark mode** — toggle or auto-detect system preference
|
|
41
53
|
- **Tabbed settings** — AI engines (with extended-thinking toggle), HubSpot accounts, Figma, GitHub, vibeSpot config
|
|
54
|
+
- **Mobile responsive** — tablet breakpoint collapses the rail; sub-768px shows a gate dialog
|
|
42
55
|
- **ZIP download** — export your theme as a ZIP file
|
|
43
56
|
|
|
44
57
|
### Agentic Pipeline
|
|
@@ -161,6 +174,9 @@ vibespot wizard # Classic CLI wizard
|
|
|
161
174
|
vibespot init # Check and install required tools
|
|
162
175
|
vibespot convert # Convert a React project (no upload)
|
|
163
176
|
vibespot upload # Upload theme to HubSpot
|
|
177
|
+
vibespot inverse [--path] [--json] [--apply-tokens] # Analyze an imported theme (design tokens, module graph, risks)
|
|
178
|
+
vibespot marketplace check [--fix] [--json] # Audit theme for HubSpot Marketplace submission
|
|
179
|
+
vibespot marketplace edit # Edit Marketplace listing metadata (marketplace.json)
|
|
164
180
|
vibespot doctor # Diagnose environment issues
|
|
165
181
|
```
|
|
166
182
|
|
|
@@ -180,6 +196,39 @@ Settings are managed in the **Settings** panel (tabbed: AI, HubSpot, Figma, GitH
|
|
|
180
196
|
|
|
181
197
|
## What's New
|
|
182
198
|
|
|
199
|
+
### Unreleased
|
|
200
|
+
- **Multi-page sites** — create full HubSpot sites from a single prompt with shared modules, page tree sidebar, and cross-page navigation validation
|
|
201
|
+
- **Inline WYSIWYG editing** — click text, images, and links directly in the live preview to edit inline
|
|
202
|
+
- **Per-section visual controls** — hover toolbar with color pickers, spacing sliders, image swap, and font size controls
|
|
203
|
+
- **Blog template generation** — blog as a content type with HubSpot blog variable support and a Blog Content Hub starter template
|
|
204
|
+
- **Split-pane view** — preview + code editor side by side
|
|
205
|
+
- **Brand kit enforcement** — colors, fonts, and logo injected as AI constraints with off-brand warnings
|
|
206
|
+
- **Workspace tab navigation** — Pages, Brand, Library, Marketplace, Settings tabs replace the flat dashboard
|
|
207
|
+
- **First-visit onboarding** — 3-step walkthrough for new users
|
|
208
|
+
- **CSS token system** — comprehensive design tokens for spacing, typography, z-index, transitions, and component library
|
|
209
|
+
- **HubSpot terminology alignment** — UI copy uses HubSpot's canonical terms (Module, Module Library, Brand Kit)
|
|
210
|
+
|
|
211
|
+
### v1.3.0
|
|
212
|
+
- **Email template generation** — full pipeline support for HubSpot email templates: email-specific prompts, table-based layout, MSO/VML compatibility, 3 email starters, 5 email plan templates, and email validator auto-fix
|
|
213
|
+
|
|
214
|
+
### v1.2.0
|
|
215
|
+
- **Inverse pipeline (HubSpot → vibeSpot)** — reverse-engineer imported HubSpot themes: design token extraction, module graph, field schema flags, and round-trip risk detection
|
|
216
|
+
- **Simplified setup** — returning users land on a recent projects rail; new users see a chat-style prompt as the primary path
|
|
217
|
+
- **Select mode** — click elements in the live preview to reference them in chat
|
|
218
|
+
- **Undo/redo with visual timeline** — Ctrl+Z / Ctrl+Y step through version history with hover tooltips
|
|
219
|
+
- **Smart chat suggestions** — contextual suggestion chips filtered by existing modules
|
|
220
|
+
- **Plan-mode templates** — 7 pre-canned plan structures that skip cold-start elicitation
|
|
221
|
+
- **Starter templates** — 5 bundled page templates for instant preview with no AI wait
|
|
222
|
+
- **HubSpot Marketplace publication path** — rule-based audit, auto-fix, and listing metadata editor
|
|
223
|
+
|
|
224
|
+
### v1.1.3
|
|
225
|
+
- **Model selection persists for Codex CLI, Gemini CLI, and Gemini API** — picking a non-default model used to revert because the `/api/settings/engine` route had no cases for those engines, no config fields existed, and `getCurrentModel` returned `null` (so the dropdown reset to the first option). Added the config fields, route persistence, UI lookup, and runtime `--model`/`-m` flag plumbing into the CLI subprocess invocation.
|
|
226
|
+
|
|
227
|
+
### v1.1.2
|
|
228
|
+
- **Honest model dropdowns** — replaced generic `opus`/`sonnet`/`haiku` aliases in the Claude Code dropdown with specific version IDs (Opus 4.7, Sonnet 4.6, Haiku 4.5, etc.) so picking a version actually pins it. Codex CLI dropdown now lists GPT-5.5, GPT-5.5 Pro, GPT-5.3 Codex, GPT-5.2 Codex, GPT-5.1 Codex Max/Mini, GPT-5.4 Mini/Nano, Codex Mini — no more outdated `o4-mini` / `o3` / `gpt-4o` only.
|
|
229
|
+
- **Live model catalog covers Codex CLI** — when an OpenAI API key is configured, both OpenAI API and Codex CLI dropdowns get populated from `/v1/models` (cached 10 min). New OpenAI releases show up automatically.
|
|
230
|
+
- **Settings dialog opens to AI tab** — fixed a click-handler bug that left the dialog blank on open.
|
|
231
|
+
|
|
183
232
|
### v1.1.0
|
|
184
233
|
- **Plan mode** — deliberation phase before generation. Prominent toggle above chat input; AI asks elicitation questions, builds a markdown plan in a dedicated tab, only generates after Approve. Plan persists to `.vibespot/plan.md` across sessions.
|
|
185
234
|
- **Streamlined Figma import** — replaces the old agentic-pipeline path with a translation pipeline that preserves Figma's exact design tokens, copy, and section order. Image assets copy into the theme automatically.
|
|
@@ -223,4 +272,4 @@ See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
|
223
272
|
|
|
224
273
|
## License
|
|
225
274
|
|
|
226
|
-
|
|
275
|
+
FSL-1.1-Apache-2.0 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# BLOG_RULES.md — HubSpot Blog Template Rules & Variables
|
|
2
|
+
|
|
3
|
+
> Rules for generating HubSpot blog listing and blog post templates. Every variable and pattern here comes from the HubSpot CMS blog documentation and real template validation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Template Types
|
|
8
|
+
|
|
9
|
+
HubSpot blogs require TWO templates:
|
|
10
|
+
|
|
11
|
+
### Blog Post Template
|
|
12
|
+
- `templateType: blog_post` in the template annotation
|
|
13
|
+
- Renders a single blog post
|
|
14
|
+
- `host_template_types: ["BLOG_POST"]` in module meta.json
|
|
15
|
+
|
|
16
|
+
### Blog Listing Template
|
|
17
|
+
- `templateType: blog_listing` in the template annotation
|
|
18
|
+
- Renders the blog index / archive page with post cards
|
|
19
|
+
- `host_template_types: ["BLOG_LISTING"]` in module meta.json
|
|
20
|
+
|
|
21
|
+
Modules can support both: `host_template_types: ["BLOG_POST", "BLOG_LISTING"]`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 2. Blog Post Variables (Required)
|
|
26
|
+
|
|
27
|
+
These HubL variables are available in blog post templates:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
{{ content.name }} — Post title
|
|
31
|
+
{{ content.post_body }} — Full post body HTML (the article content)
|
|
32
|
+
{{ content.featured_image }} — Featured image URL
|
|
33
|
+
{{ content.featured_image_alt_text }} — Featured image alt text
|
|
34
|
+
{{ content.publish_date }} — Publish date (use |datetimeformat)
|
|
35
|
+
{{ content.updated }} — Last updated date
|
|
36
|
+
{{ content.meta_description }} — SEO meta description / excerpt
|
|
37
|
+
{{ content.absolute_url }} — Canonical URL
|
|
38
|
+
{{ content.comment_count }} — Number of comments
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Author Variables
|
|
42
|
+
```
|
|
43
|
+
{{ content.blog_post_author }} — Author display name
|
|
44
|
+
{{ content.author.display_name }} — Author display name (alternative)
|
|
45
|
+
{{ content.author.avatar }} — Author avatar image URL
|
|
46
|
+
{{ content.author.bio }} — Author bio text
|
|
47
|
+
{{ content.author.slug }} — Author URL slug
|
|
48
|
+
{{ content.author.email }} — Author email
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Tag & Topic Variables
|
|
52
|
+
```
|
|
53
|
+
{{ content.tag_list }} — List of tags (iterable)
|
|
54
|
+
{{ content.topic_list }} — List of topics/categories (iterable)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Tag iteration:
|
|
58
|
+
```html
|
|
59
|
+
{% for tag in content.tag_list %}
|
|
60
|
+
<a href="{{ blog_tag_url(group.id, tag.slug) }}">{{ tag.name }}</a>
|
|
61
|
+
{% endfor %}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Date Formatting
|
|
65
|
+
```html
|
|
66
|
+
{{ content.publish_date|datetimeformat('%B %d, %Y') }}
|
|
67
|
+
<!-- Output: April 30, 2026 -->
|
|
68
|
+
|
|
69
|
+
{{ content.publish_date|datetimeformat('%b %d') }}
|
|
70
|
+
<!-- Output: Apr 30 -->
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 3. Blog Listing Variables (Required)
|
|
76
|
+
|
|
77
|
+
These HubL variables are available in blog listing templates:
|
|
78
|
+
|
|
79
|
+
### Post Loop
|
|
80
|
+
```html
|
|
81
|
+
{% for content in contents %}
|
|
82
|
+
<h2><a href="{{ content.absolute_url }}">{{ content.name }}</a></h2>
|
|
83
|
+
<p>{{ content.meta_description|truncate(160) }}</p>
|
|
84
|
+
{% if content.featured_image %}
|
|
85
|
+
<img src="{{ content.featured_image }}" alt="{{ content.featured_image_alt_text }}" />
|
|
86
|
+
{% endif %}
|
|
87
|
+
<span>{{ content.publish_date|datetimeformat('%B %d, %Y') }}</span>
|
|
88
|
+
<span>{{ content.blog_post_author }}</span>
|
|
89
|
+
{% endfor %}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Blog Metadata
|
|
93
|
+
```
|
|
94
|
+
{{ group.public_title }} — Blog name/title
|
|
95
|
+
{{ group.description }} — Blog description
|
|
96
|
+
{{ group.absolute_url }} — Blog listing URL
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Pagination
|
|
100
|
+
```html
|
|
101
|
+
{% if last_page_num > 1 %}
|
|
102
|
+
<nav class="blog-pagination">
|
|
103
|
+
{% if current_page_num > 1 %}
|
|
104
|
+
<a href="{{ blog_page_link(current_page_num - 1) }}">Previous</a>
|
|
105
|
+
{% endif %}
|
|
106
|
+
|
|
107
|
+
{% for page_num in range(1, last_page_num + 1) %}
|
|
108
|
+
{% if page_num == current_page_num %}
|
|
109
|
+
<span class="current">{{ page_num }}</span>
|
|
110
|
+
{% else %}
|
|
111
|
+
<a href="{{ blog_page_link(page_num) }}">{{ page_num }}</a>
|
|
112
|
+
{% endif %}
|
|
113
|
+
{% endfor %}
|
|
114
|
+
|
|
115
|
+
{% if current_page_num < last_page_num %}
|
|
116
|
+
<a href="{{ blog_page_link(current_page_num + 1) }}">Next</a>
|
|
117
|
+
{% endif %}
|
|
118
|
+
</nav>
|
|
119
|
+
{% endif %}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Filtering by Topic/Tag
|
|
123
|
+
```html
|
|
124
|
+
{% set topics = blog_topics(group.id, 250) %}
|
|
125
|
+
{% for topic in topics %}
|
|
126
|
+
<a href="{{ blog_tag_url(group.id, topic.slug) }}"
|
|
127
|
+
class="{% if topic.slug == tag %}active{% endif %}">
|
|
128
|
+
{{ topic.name }}
|
|
129
|
+
</a>
|
|
130
|
+
{% endfor %}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 4. Related Posts & Widgets
|
|
136
|
+
|
|
137
|
+
### Related Posts
|
|
138
|
+
```html
|
|
139
|
+
{% related_blog_posts limit=3 %}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Or manual implementation:
|
|
143
|
+
```html
|
|
144
|
+
{% set recent = blog_recent_posts(group.id, 3) %}
|
|
145
|
+
{% for post in recent %}
|
|
146
|
+
{% if post.absolute_url != content.absolute_url %}
|
|
147
|
+
<a href="{{ post.absolute_url }}">{{ post.name }}</a>
|
|
148
|
+
{% endif %}
|
|
149
|
+
{% endfor %}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Blog Social Sharing
|
|
153
|
+
```html
|
|
154
|
+
{% blog_social_sharing %}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Blog Comments
|
|
158
|
+
```html
|
|
159
|
+
{% blog_comments %}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Blog Subscribe (CTA)
|
|
163
|
+
```html
|
|
164
|
+
{% blog_subscribe "blog_subscribe" overrideable=True, label="Blog Subscribe" %}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 5. Reading-Optimized Design Rules
|
|
170
|
+
|
|
171
|
+
### Typography
|
|
172
|
+
- Body text: 18-20px for long-form readability
|
|
173
|
+
- Line height: 1.6-1.8 for body copy
|
|
174
|
+
- Content width: 680-720px max for article body (optimal reading measure)
|
|
175
|
+
- Heading scale: use a clear hierarchy (h1 > h2 > h3)
|
|
176
|
+
|
|
177
|
+
### Spacing
|
|
178
|
+
- Generous paragraph spacing: 1.5em between paragraphs
|
|
179
|
+
- Section breaks: 3-4rem between major sections
|
|
180
|
+
- Whitespace is critical for readability
|
|
181
|
+
|
|
182
|
+
### Images
|
|
183
|
+
- Featured image: full-width within content area, 16:9 or 3:2 aspect ratio
|
|
184
|
+
- In-article images: max-width: 100% within the content column
|
|
185
|
+
- Always include alt text fields
|
|
186
|
+
- Use lazy loading: `loading="lazy"` on images below the fold
|
|
187
|
+
|
|
188
|
+
### Colors
|
|
189
|
+
- High contrast for body text (WCAG AA minimum)
|
|
190
|
+
- Subtle accent for links (distinguishable but not distracting)
|
|
191
|
+
- Light background for reading (dark text on light bg for articles)
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 6. Module Patterns for Blog
|
|
196
|
+
|
|
197
|
+
### Blog Post Modules (typical set)
|
|
198
|
+
1. **blog-post-header** — Title, featured image, author, date, tags
|
|
199
|
+
2. **blog-post-body** — The `{{ content.post_body }}` wrapper with reading-optimized styles
|
|
200
|
+
3. **author-bio** — Author card with avatar, name, bio, social links
|
|
201
|
+
4. **related-posts** — 3 related post cards
|
|
202
|
+
5. **blog-comments** — Comment section
|
|
203
|
+
6. **share-bar** — Social sharing buttons
|
|
204
|
+
|
|
205
|
+
### Blog Listing Modules (typical set)
|
|
206
|
+
1. **blog-hero** — Blog name, description, featured/pinned post
|
|
207
|
+
2. **topic-filter** — Category/tag navigation pills
|
|
208
|
+
3. **post-grid** — Card grid of posts with pagination
|
|
209
|
+
4. **newsletter-signup** — Email subscription form
|
|
210
|
+
5. **popular-posts** — Sidebar or section with most-read posts
|
|
211
|
+
|
|
212
|
+
### Module meta.json for Blog Post
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"host_template_types": ["BLOG_POST"],
|
|
216
|
+
"is_available_for_new_content": true
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Module meta.json for Blog Listing
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"host_template_types": ["BLOG_LISTING"],
|
|
224
|
+
"is_available_for_new_content": true
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 7. Common Mistakes
|
|
231
|
+
|
|
232
|
+
- Using `{{ content.body }}` instead of `{{ content.post_body }}` — post_body is the correct variable
|
|
233
|
+
- Forgetting pagination on listing templates — always include when more than 1 page
|
|
234
|
+
- Not using `|datetimeformat` on dates — raw dates are ugly
|
|
235
|
+
- Using `now()` — not valid HubL, use `local_dt` instead
|
|
236
|
+
- Hardcoding blog URLs — use `{{ content.absolute_url }}` and `{{ blog_page_link() }}`
|
|
237
|
+
- Missing `{% for content in contents %}` loop on listing pages — this is required
|
|
238
|
+
- Using page-style `{% dnd_area %}` in blog templates — blog templates use fixed module positions
|
|
239
|
+
- Not setting correct `host_template_types` — blog modules need `BLOG_POST` or `BLOG_LISTING`
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 8. SEO Essentials
|
|
244
|
+
|
|
245
|
+
Blog post templates should include:
|
|
246
|
+
- `<title>{{ content.name }} | {{ group.public_title }}</title>` (or via HubSpot settings)
|
|
247
|
+
- `<meta name="description" content="{{ content.meta_description }}" />`
|
|
248
|
+
- `<link rel="canonical" href="{{ content.absolute_url }}" />`
|
|
249
|
+
- Open Graph tags for social sharing
|
|
250
|
+
- Structured data (Article schema) where possible
|
|
251
|
+
- Proper heading hierarchy (single h1 for post title)
|